/*	$NetBSD: cmp.c,v 1.20 2016/10/30 19:33:49 christos Exp $	*/

/*
 * Copyright (c) 1987, 1990, 1993, 1994
 *	The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#define _DEFAULT_SOURCE

#include <sys/stat.h>
#include <sys/types.h>

#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "extern.h"

typedef unsigned char u_char;

int lflag, sflag;
static const char * __progname;

static void usage(void);

int main(int argc, char *argv[]) {
  struct stat sb1, sb2;
  off_t skip1 = 0, skip2 = 0;
  int ch, fd1, fd2, special;
  const char *file1, *file2;
  __progname = basename(argv[0]);

  setlocale(LC_ALL, "");

  special = 0;
  while ((ch = getopt(argc, argv, "cls")) != -1)
    switch (ch) {
    case 'c':
      special = 1; /* careful!  Don't use mmap() */
      break;
    case 'l': /* print all differences */
      lflag = 1;
      break;
    case 's': /* silent run */
      sflag = 1;
      break;
    case '?':
    default:
      usage();
    }
  argv += optind;
  argc -= optind;

  if (lflag && sflag)
    errx(ERR_EXIT, "only one of -l and -s may be specified");

  if (argc < 2 || argc > 4)
    usage();

  /* Backward compatibility -- handle "-" meaning stdin. */
  if (strcmp(file1 = argv[0], "-") == 0) {
    special = 1;
    fd1 = 0;
    file1 = "stdin";
  } else if ((fd1 = open(file1, O_RDONLY, 0)) < 0) {
    if (!sflag)
      warn("%s", file1);
    exit(ERR_EXIT);
  }
  if (strcmp(file2 = argv[1], "-") == 0) {
    if (special)
      errx(ERR_EXIT, "standard input may only be specified once");
    special = 1;
    fd2 = 0;
    file2 = "stdin";
  } else if ((fd2 = open(file2, O_RDONLY, 0)) < 0) {
    if (!sflag)
      warn("%s", file2);
    exit(ERR_EXIT);
  }

  if (argc > 2) {
    char *ep;

    errno = 0;
    skip1 = (off_t)strtoll(argv[2], &ep, 0);
    if (errno || ep == argv[2])
      usage();

    if (argc == 4) {
      skip2 = (off_t)strtoll(argv[3], &ep, 0);
      if (errno || ep == argv[3])
        usage();
    }
  }

  if (!special) {
    if (fstat(fd1, &sb1))
      err(ERR_EXIT, "%s", file1);
    if (!S_ISREG(sb1.st_mode))
      special = 1;
    else {
      if (fstat(fd2, &sb2))
        err(ERR_EXIT, "%s", file2);
      if (!S_ISREG(sb2.st_mode))
        special = 1;
    }
  }

  if (special)
    c_special(fd1, file1, skip1, fd2, file2, skip2);
  else
    c_regular(fd1, file1, skip1, sb1.st_size, fd2, file2, skip2, sb2.st_size);
  exit(0);
}

static void usage(void) {

  (void)fprintf(stderr,
                "Usage: %s [-c] [-l | -s] file1 file2 [skip1 [skip2]]\n",
                __progname);
  exit(ERR_EXIT);
}
