Logo Search packages:      
Sourcecode: fhist version File versions

main.c

/*
 *    fhist - file history and comparison tools
 *    Copyright (C) 1991-1994, 1998-2000, 2002 Peter Miller;
 *    All rights reserved.
 *
 *    Derived from a work
 *    Copyright (C) 1990 David I. Bell.
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 2 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with this program; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
 *
 * MANIFEST: operating system entry point, and parse arguments
 *
 * fcomp - a file comparison program
 */

#include <ac/errno.h>
#include <ac/stdio.h>
#include <ac/stdlib.h>
#include <ac/string.h>

#include <arglex.h>
#include <cmalloc.h>
#include <compare.h>
#include <error_intl.h>
#include <fileio.h>
#include <help.h>
#include <isdir.h>
#include <progname.h>
#include <quit.h>
#include <sub.h>
#include <version.h>


enum
{
      arglex_token_binary,
      arglex_token_blank,
      arglex_token_context,
      arglex_token_debug,
      arglex_token_edit,
      arglex_token_failures,
      arglex_token_join,
      arglex_token_line_numbers,
      arglex_token_matching,
      arglex_token_output,
      arglex_token_quiet,
      arglex_token_spaces,
      arglex_token_upcase,
      arglex_token_verbose,
      arglex_token_what,
};

static arglex_table_ty argtab[] =
{
      { "-BINary",      arglex_token_binary,          },
      { "-Blank", arglex_token_blank,           },
      { "-Context",     arglex_token_context,         },
      { "-Debug", arglex_token_debug,           },
      { "-Edit",  arglex_token_edit,            },
      { "-Failures",    arglex_token_failures,        },
      { "-Join",  arglex_token_join,            },
      { "-Number",      arglex_token_line_numbers,    },
      { "-Matching",    arglex_token_matching,        },
      { "-Output",      arglex_token_output,          },
      { "-Quiet", arglex_token_quiet,           },
      { "-Spaces",      arglex_token_spaces,          },
      { "-Upcase",      arglex_token_upcase,          },
      { "-Verbose",     arglex_token_verbose,         },
      { "-What",  arglex_token_what,            },
      { 0, 0, }, /* end marker */
};


/*
 * Type out the possible commands.
 */

static void
usage(void)
{
      char        *progname;

      progname = progname_get();
      fprintf(stderr, "usage: %s [ <option>... ] <fileA> <fileB>\n", progname);
      fprintf(stderr, "       %s -Help\n", progname);
      fprintf(stderr, "       %s -VERSion\n", progname);
      quit(1);
}


/*
 * give the user some help
 */

static void
main_help(void)
{
      help(NULL, usage);
}


/*
 * Expand a global variable name.
 * Returns original argument if string is not a global variable,
 * or returns copied value of global variable.
 */

static char *
expand(char *cp)
{
      char  *var;       /* variable value */

      if (!cp || *cp != '.')
            return cp;
      var = getenv(cp);
      if (!var || !*var)
            return cp;
      cp = r_alloc_and_check(strlen(var) + 1);
      strcpy(cp, var);
      return cp;
}


/*
 * Make a directory name into a file name by applying the last
 * component of the second name to it.  For example:
 *    dirfile("/etc", "/foo/bar")
 * results in "/etc/bar".
 */

static char *
dirfile(char *dir_name, char *filename)
{
      char  *cp;
      char  *endname;

      endname = strrchr(filename, '/');
      if (!endname)
            endname = filename;
      cp = r_alloc_and_check(strlen(dir_name) + strlen(endname) + 2);
      strcpy(cp, dir_name);
      strcat(cp, "/");
      strcat(cp, endname);
      return cp;
}


/*
 * This is the main program.
 * This performs all of the parsing of the command line, and then
 * calls a subroutine to do all the work.  This allows the subroutine
 * to be loaded with other programs and called by them easily.
 */

int
main(int argc, char **argv)
{
      char        *cp;
      char        *nameA;
      char        *nameB;
      char        *ofile;
      int         dirA;
      int         dirB;
      sub_context_ty    *scp;

      arglex_init(argc, argv, argtab);
      switch (arglex())
      {
      case arglex_token_help:
            main_help();
            quit(0);

      case arglex_token_version:
            version();
            quit(0);

      default:
            break;
      }
      nameA = NULL;
      nameB = NULL;
      ofile = NULL;
      fc.verbosity = VERBOSE_DEFAULT;
      fc.maxchanges = INFINITY;
      while (arglex_token != arglex_token_eoln)
      {
            switch (arglex_token)
            {
            default:
                  bad_argument(usage);
                  /* NOTREACHED */

            case arglex_token_string:
                  /* a file name */
                  cp = expand(arglex_value.alv_string);
                  if (!nameA)
                        nameA = cp;
                  else if (!nameB)
                        nameB = cp;
                  else
                  {
                        fatal_intl
                        (
                              0,
                              i18n("only two input files allowed")
                        );
                  }
                  break;

            case arglex_token_binary:
                  /* compare binary bytes */
                  if (fc.hexify_flag)
                        goto duplicate;
                  fc.hexify_flag = 1;
                  break;

            case arglex_token_blank:
                  /* ignore blank lines */
                  if (fc.blankflag)
                  {
                        duplicate:
                        scp = sub_context_new();
                        sub_var_set_charstar(scp, "Name", arglex_value.alv_string);
                        fatal_intl
                        (
                              scp,
                             i18n("duplicate $name command line option")
                        );
                        /* NOTREACHED */
                        sub_context_delete(scp);
                  }
                  fc.blankflag = 1;
                  break;

            case arglex_token_debug:
                  /* type debugging information */
                  if (fc.debugflag)
                        goto duplicate;
                  fc.debugflag = 1;
                  break;

            case arglex_token_edit:
                  /* output an edit script */
                  if (fc.editscriptflag)
                        goto duplicate;
                  fc.editscriptflag = 1;
                  break;

            case arglex_token_matching:
                  /* show lines which match */
                  if (fc.matchflag)
                        goto duplicate;
                  fc.matchflag = 1;
                  break;

            case arglex_token_line_numbers:
                  /* show line numbers */
                  if (fc.numflag)
                        goto duplicate;
                  fc.numflag = 1;
                  break;

            case arglex_token_quiet:
                  /* display quick summary */
                  if (fc.quickflag)
                        goto duplicate;
                  fc.quickflag = 1;
                  break;

            case arglex_token_spaces:
                  /* ignore extra spaces or tabs */
                  if (fc.spaceflag)
                        goto duplicate;
                  fc.spaceflag = 1;
                  break;

            case arglex_token_upcase:
                  /* translate to upper case */
                  if (fc.upcaseflag)
                        goto duplicate;
                  fc.upcaseflag = 1;
                  break;

            case arglex_token_verbose:
                  /* be verbose */
                  if (fc.verbosity != VERBOSE_DEFAULT)
                        goto duplicate;
                  fc.verbosity = VERBOSE_FULL;
                  break;

            case arglex_token_what:
                  /* show what changes are */
                  if (fc.whatflag)
                        goto duplicate;
                  fc.whatflag = 1;
                  break;

            case arglex_token_context:
                  if (fc.context)
                        goto duplicate;
                  if (arglex() != arglex_token_number)
                  {
                        scp = sub_context_new();
                        sub_var_set_charstar(scp, "Name", "-Context");
                        fatal_intl
                        (
                              scp,
                         i18n("numeric value required for $name option")
                        );
                        /* NOTREACHED */
                        sub_context_delete(scp);
                  }
                  fc.context = arglex_value.alv_number;
                  if (fc.context < 1)
                  {
                        scp = sub_context_new();
                        sub_var_set_format(scp, "Number", "%d", fc.context);
                        fatal_intl
                        (
                              scp,
                              i18n("context of $number is out of range")
                        );
                        /* NOTREACHED */
                        sub_context_delete(scp);
                  }
                  break;

            case arglex_token_failures:
                  if (fc.maxchanges != INFINITY)
                        goto duplicate;
                  if (arglex() != arglex_token_number)
                  {
                        scp = sub_context_new();
                        sub_var_set_charstar(scp, "Name", "-Failures");
                        fatal_intl
                        (
                              scp,
                         i18n("numeric value required for $name option")
                        );
                  }
                  fc.maxchanges = arglex_value.alv_number;
                  if (fc.maxchanges < 0)
                  {
                        scp = sub_context_new();
                        sub_var_set_format(scp, "Number", "%d", fc.maxchanges);
                        fatal_intl
                        (
                              scp,
                        i18n("maximum changes of $number is out of range")
                        );
                        /* NOTREACHED */
                        sub_context_delete(scp);
                  }
                  break;

            case arglex_token_join:
                  if (fc.maxjoin)
                        goto duplicate;
                  if (arglex() != arglex_token_number)
                  {
                        scp = sub_context_new();
                        sub_var_set_charstar(scp, "Name", "-Join");
                        fatal_intl
                        (
                              scp,
                         i18n("numeric value required for $name option")
                        );
                  }
                  fc.maxjoin = arglex_value.alv_number;
                  if (fc.maxjoin < 1)
                  {
                        scp = sub_context_new();
                        sub_var_set_format(scp, "Number", "%d", fc.maxjoin);
                        fatal_intl
                        (
                              scp,
                              i18n("join of $number is out of range")
                        );
                        /* NOTREACHED */
                        sub_context_delete(scp);
                  }
                  break;

            case arglex_token_output:
                  /* specify output file */
                  if (ofile)
                        goto duplicate;
                  switch (arglex())
                  {
                  default:
                        fatal_intl(0, i18n("file name required after -Output option"));

                  case arglex_token_string:
                        ofile = expand(arglex_value.alv_string);
                        break;

                  case arglex_token_stdio:
                        ofile = "";
                        break;
                  }
                  break;
            }
            arglex();
      }
      if (nameA && !*nameA)
            nameA = 0;
      if (nameB && !*nameB)
            nameB = 0;
      if (!nameA || !nameB)
            error_intl(0, i18n("must have two input files"));
      if (ofile && !*ofile)
            ofile = 0;
      if (fc.matchflag + fc.whatflag + fc.editscriptflag >= 2)
            fatal_intl(0, i18n("too many output formats specified"));

      /*
       * If just one argument is a directory, then modify it by using
       * the other argument so as to reference a corresponding file
       * within the directory.
       */
      dirA = isdir(nameA);
      dirB = isdir(nameB);
      if (dirA && dirB)
      {
            scp = sub_context_new();
            sub_var_set_charstar(scp, "Name1", nameA);
            sub_var_set_charstar(scp, "Name2", nameB);
            fatal_intl
            (
                  scp,
            i18n("arguments \"$name1\" and \"$name2\" are both directories")
            );
            /* NOTREACHED */
            sub_context_delete(scp);
      }
      if (dirA)
            nameA = dirfile(nameA, nameB);
      if (dirB)
            nameB = dirfile(nameB, nameA);

      /*
       * compare the two files
       */
      fcomp(nameA, nameB);

      /*
       * report the difference
       */
      if (fc.whatflag)
            dumpwhat(ofile);
      else if (fc.matchflag)
            dumpmatch(ofile);
      else if (fc.editscriptflag)
            dumplines(ofile);
      else
            dumpnormal(ofile);
      quit(0);
      return 0;
}

Generated by  Doxygen 1.6.0   Back to index