home *** CD-ROM | disk | FTP | other *** search
/ Gold Fish 3 / goldfish_volume_3.bin / files / text / misc / cvt / source / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-02  |  14.6 KB  |  634 lines

  1. /*                                                               -*- C -*-
  2.  *  MAIN.C
  3.  *
  4.  *  (c)Copyright 1991-93 by Tobias Ferber,  All Rights Reserved
  5.  */
  6.  
  7. #include <stdarg.h>
  8. #include <string.h>
  9. #include <stdlib.h>
  10. #include <stdio.h>
  11.  
  12. #include "cvt.h"
  13. #include "filecopy.h"
  14.  
  15.  
  16. /*** / GLOBALS / ***/
  17.  
  18. int global_numchars= 256;   /* #of different chars in the local charset.
  19.                              * This number is also used to decide whether
  20.                              * an octal character code in a string runs
  21.                              * out of range */
  22.  
  23. int global_maxhexdigits= 2; /* max. #of hexadecimal digits needed to express
  24.                              * 'global_numchars' */
  25. int global_maxoctdigits= 3; /* max. #of octal digits needed to express
  26.                              * 'global_numchars */
  27.  
  28. int global_numerrors= 0;    /* global error counter */
  29. int global_maxerrors= 5;    /* #of errors until we abort */
  30. int global_checkexists= 0;  /* flag for read_flist() */
  31. char *whoami;               /* copy of argv[0] */
  32.  
  33. /* input, output and error stream */
  34. FILE *fin, *fout, *ferr;
  35.  
  36. #ifdef DEBUG
  37. int debuglevel;
  38. #endif
  39.  
  40. static void display_version_information(void)
  41. {
  42.   puts("CVT Version " VERSION " (compiled " __DATE__ ", " __TIME__ ")\n"
  43.        "(c)Copyright 1991-93 by Tobias Ferber,  All Rights Reserved.\n");
  44. }
  45.  
  46.  
  47. /*** / MAIN / ***/
  48.  
  49. int main(int argc, char *argv[])
  50. {
  51.   char *rulefile, *outfmt, *errfile, *tmpfile;
  52.  
  53.   int badopt, err, dryrun, silent;
  54.   fnode_t *fn;
  55.  
  56. #ifdef _DCC /* Dice */
  57.   expand_args(argc,argv, &argc,&argv);
  58. #endif /* _DCC */
  59.  
  60.   /* initialize globals */
  61.  
  62.   rulefile= outfmt= errfile= tmpfile= (char *)0L;
  63.   badopt= err= dryrun= silent= 0;
  64.  
  65. #ifdef __MSDOS__
  66.  
  67.   /* filenames on MS-DOG systems look very ugly: all uppercase and
  68.    * backslashes.  Perform some cosmetics. */
  69.  
  70.   whoami= "cvt";
  71.  
  72. #else /* !__MSDOS__ */
  73.   whoami= argv[0];
  74.  
  75. #endif /* __MSDOS__ */
  76.  
  77.   fin  = stdin;
  78.   fout = stdout;
  79.   ferr = stderr;
  80.  
  81.   while(--argc>0 && badopt<=0)
  82.   {
  83.     char *arg= *++argv;
  84.  
  85.     if(*arg=='-')
  86.     {
  87.       /* remember the original command-line option string */
  88.       char *opt= arg;
  89.  
  90.       if(arg[1]=='-')
  91.         arg= convert_args(*argv);
  92.  
  93.       switch(*++arg)
  94.       {
  95.  
  96. /*-c*/  case 'c':
  97.           if(arg[1]) ++arg;
  98.           else arg= (--argc > 0) ? *(++argv) : (char *)0L;
  99.  
  100.           if(arg && *arg)
  101.           { int r= atoi(arg);
  102.             if(0<r) global_numchars= r;
  103.             else echo("iIllegal charset size: %d"
  104.                        " (using `-c%d')",r,global_numchars);
  105.  
  106.             global_maxhexdigits= numdigits(global_numchars, 0x10);
  107.             global_maxoctdigits= numdigits(global_numchars, 010);
  108.           }
  109.           else
  110.           { echo("missing charset size after `%s' option",opt);
  111.             badopt= 1;
  112.           }
  113.           break;
  114.  
  115. /*-d*/  case 'd':
  116.  
  117.           if(arg[1]) ++arg;
  118.           else arg= (--argc > 0) ? *(++argv) : (char *)0L;
  119.  
  120. #ifdef DEBUG
  121.           if(arg && *arg)
  122.           { debuglevel= atoi(arg);
  123.             if(debuglevel < 0 || debuglevel > 4)
  124.             { echo("debug level %d is not in [0..4].  (using `-d1')", debuglevel);
  125.               debuglevel= 1;
  126.             }
  127.           }
  128.           else
  129.           { echo("missing debug level after `%s' option.",opt);
  130.             badopt= 1;
  131.           }
  132. #else
  133.           echo("not compiled w/ -DDEBUG.  No debug information available -- Sorry.");
  134.           /* no error */
  135.  
  136. #endif /* DEBUG */
  137.  
  138.           break;
  139.  
  140. /*-E*/  case 'E':
  141.           if(arg[1]) ++arg;
  142.           else arg= (--argc > 0) ? *(++argv) : (char *)0L;
  143.  
  144.           if(arg && *arg)
  145.           { if(errfile)
  146.             { echo("option `%s' has already been seen!",opt);
  147.               echo("more than one error filename in your command line");
  148.               badopt= 1;
  149.             }
  150.             else errfile= arg;
  151.           }
  152.           else
  153.           { echo("missing filename after `%s' option",opt);
  154.             badopt= 1;
  155.           }
  156.           break;
  157.  
  158. /*-e*/  case 'e':
  159.           if(arg[1]) ++arg;
  160.           else arg= (--argc > 0) ? *(++argv) : (char *)0L;
  161.  
  162.           if(arg && *arg)
  163.           { int e= atoi(arg);
  164.             if(0<e) global_maxerrors= e;
  165.             else echo("illegal maximum #of errors: %d"
  166.                        " (using `-e%d')",e,global_maxerrors);
  167.           }
  168.           else
  169.           { echo("missing maximum #of errors after `%s' option",opt);
  170.             badopt= 1;
  171.           }
  172.           break;
  173.  
  174. /*-f*/  case 'f':
  175.           if(arg[1]) ++arg;
  176.           else arg= (--argc > 0) ? *(++argv) : (char *)0L;
  177.  
  178.           if(arg && *arg)
  179.           { if(rulefile)
  180.             { echo("option `%s' has already been seen!",opt);
  181.               echo("more than one script filename in your command line");
  182.               badopt= 1;
  183.             }
  184.             else rulefile= arg;
  185.           }
  186.           else
  187.           { echo("missing filename after `%s' option",opt);
  188.             badopt= 1;
  189.           }
  190.           break;
  191.  
  192. /*-?*/  case '?':
  193. /*-h*/  case 'h':
  194.           fprintf(stderr,
  195.             "usage: %s [options] [-f rulefile] [-o outfile] [infiles]\n\n",
  196.             whoami);
  197.  
  198.           display_args();
  199.           badopt= -1; /* negative means exit w/o error */
  200.           break;
  201.  
  202. /*-l*/  case 'l':
  203.           if(arg[1]) ++arg;
  204.           else arg= (--argc > 0) ? *(++argv) : (char *)0L;
  205.  
  206.           if(arg && *arg)
  207.           {
  208.             if( read_flist(arg) != 0)
  209.               badopt= 1;
  210.           }
  211.           else
  212.           { echo("missing filename after `%s' option",opt);
  213.             badopt= 1;
  214.           }
  215.           break;
  216.  
  217. /*-n*/  case 'n':
  218.           dryrun= 1;
  219.           break;
  220.  
  221. /*-o*/  case 'o':
  222.           if(arg[1]) ++arg;
  223.           else arg= (--argc > 0) ? *(++argv) : (char *)0L;
  224.  
  225.           if(arg && *arg)
  226.           {
  227.             if(outfmt)
  228.             { echo("option `%s' has already been seen!",opt);
  229.               echo("more than one output filename in your command line");
  230.               badopt= 1;
  231.             }
  232.             else outfmt= arg;
  233.           }
  234.           else
  235.           { echo("missing output filename after `%s' option",opt);
  236.             badopt= 1;
  237.           }
  238.           break;
  239.  
  240. /*-s*/  case 's':
  241.           silent= 1;
  242.           break;
  243.  
  244. /*-t*/  case 't':
  245.           if(arg[1]) ++arg;
  246.           else arg= (--argc > 0) ? *(++argv) : (char *)0L;
  247.  
  248.           if(arg && *arg)
  249.           { if(tmpfile)
  250.             { echo("option `%s' has already been seen!",opt);
  251.               echo("more than one temporary output filename in your command line");
  252.               badopt= 1;
  253.             }
  254.             else
  255.             { if( tmpfile= (char *)malloc((strlen(arg)+1) * sizeof(char)) )
  256.                 strcpy(tmpfile,arg);
  257.               else
  258.               { echo("out of memory... aaaiiiiiieeeeeeeee!");
  259.                 badopt= 1;
  260.               }
  261.             }
  262.           }
  263.           else
  264.           { echo("missing filename after `%s' option",opt);
  265.             badopt= 1;
  266.           }
  267.           break;
  268.  
  269. /*-v*/  case 'v':
  270.           display_version_information();
  271.           badopt= -1;
  272.           break;
  273.  
  274. /*-x*/  case 'x':
  275.           global_checkexists= 1;
  276.           break;
  277.  
  278. /*??*/  default:
  279.           echo("unrecognized option `%s'",opt);
  280.           badopt= 1;
  281.           break;
  282.       }
  283.     }
  284.     else if(*arg=='@')
  285.     {
  286.       if(arg[1]) ++arg;
  287.       else arg= (--argc > 0) ? *(++argv) : (char *)0L;
  288.  
  289.       if(arg && *arg)
  290.       {
  291.         if( read_flist(arg) != 0)
  292.           badopt= 1;
  293.       }
  294.       else
  295.       { echo("missing filename after `@'");
  296.         badopt= 1;
  297.       }
  298.     }
  299.     else
  300.     {
  301.       if(global_checkexists)
  302.       {
  303.         FILE *fp= fopen(arg,"r");
  304.  
  305.         if(fp)
  306.           fclose(fp);
  307.  
  308.         else
  309.         { perror(arg);
  310.           badopt= 1;
  311.         }
  312.       }
  313.  
  314.       if(!badopt)
  315.       {
  316.         if( chain_fname(0L,arg) )
  317.         {
  318.           echo("out of memory... bzzzzzzzz!");
  319.           badopt= 1;
  320.         }
  321.       }
  322.     }
  323.   }
  324.  
  325.   if(badopt == 0)
  326.   {
  327.     FILE *fp;
  328.  
  329. #ifdef DEBUG
  330.     if(debuglevel >= 1)
  331.       print_flist();
  332. #endif
  333.  
  334.     /*
  335.      * open error stream
  336.      */
  337.  
  338.     if(errfile)
  339.     {
  340.       if( !(ferr= fopen(errfile,"w")) )
  341.       { perror(errfile);
  342.         echo("can't direct error output to `%s' -- will use stderr",
  343.           errfile);
  344.         ferr= stderr;
  345.       }
  346.     }
  347.  
  348.     err= init_rules();
  349.  
  350.     if(!err)
  351.     {
  352.       /*
  353.        * In --dryrun mode the explicit use of the --file keyword
  354.        * is not needed.  Instead we treat all input files as script
  355.        * files and try to parse them respectively.
  356.        * If however there was a --file <rulefile> in the command-line
  357.        * we will ignore futher input files (if any).
  358.        */
  359.  
  360.       if(dryrun)
  361.       {
  362.         if(rulefile)
  363.         {
  364.  
  365. #ifdef DEBUG
  366.           if(flist) /* global_numfiles is >= 1 */
  367.           { echo("debug-warning: %d input files ignored.\n"
  368.                    "(They make no sense w/ options --dryrun --file \"%s\")",
  369.               global_numfiles, rulefile );
  370.           }
  371. #endif /* DEBUG */
  372.  
  373.           if( fp= cvtopen(rulefile) )
  374.           {
  375.             err= parsefile(fp);
  376.             fclose(fp);
  377.           }
  378.           else perror(rulefile);
  379.         }
  380.         else /* !rulefile */
  381.         {
  382.           if(flist) /* global_numfiles is >= 1 */
  383.           {
  384.             fnode_t *fn;
  385.  
  386.             for(fn= flist; fn && !err; fn= fn->next)
  387.             {
  388.               if( fp= cvtopen(rulefile= fn->filename) )
  389.               {
  390.                 err= parsefile(fp);
  391.                 fclose(fp);
  392.  
  393.                 if(!err && fn->next)
  394.                 {
  395.                   fprintf(ferr, "%s: %ld rules, no errors.\n",
  396.                     rulefile, global_numrules);
  397.  
  398.                   exit_rules();
  399.                   err= init_rules();
  400.                 }
  401.               }
  402.               else err++;
  403.             }
  404.           }
  405.           else /* !flist */
  406.           { rulefile= "stdin";  /* filename for messages */
  407.             err= parsefile(stdin);
  408.           }
  409.         }
  410.       }
  411.       else /* !dryrun */
  412.       {
  413.         if(rulefile)
  414.           fp= cvtopen(rulefile);
  415.         else
  416.         { echo("warning: no conversion file... copying...");
  417.           fp= (FILE *)0L;
  418.         }
  419.  
  420.         if(fp)
  421.         {
  422.           err= parsefile(fp);
  423.  
  424.           if(fp!=stdin)
  425.             fclose(fp);
  426.  
  427.           if(!err)
  428.           {
  429. #ifdef DEBUG
  430.             if(debuglevel >= 3)
  431.               dump_crules();
  432. #endif
  433.             if(global_numrules==0)
  434.             { echo("warning: file '%s' contains no rules... copying...",
  435.                 rulefile);
  436.             }
  437.           }
  438.         }
  439.         else if(rulefile)
  440.         { echo("no conversion file similar or equal to `%s' -- Sorry.",
  441.             rulefile);
  442.           err= 1;
  443.         }
  444.       }
  445.     }
  446.     else
  447.     { echo("not enough memory for a %d character charset!", global_numchars);
  448.       err= 1;
  449.     }
  450.   }
  451.   else /* badopt != 0 */
  452.     err= badopt;
  453.  
  454.   /*
  455.    *  convert
  456.    */
  457.  
  458.   fn= flist;
  459.  
  460.   if(!dryrun && !err) do
  461.   {
  462.     char *infile, *outfile= (char *)0L;
  463.  
  464.     if(fn)
  465.     {
  466.       infile= fn->filename;
  467.  
  468.       if( !(fin= fopen(infile,"rb")) )
  469.       { perror(infile);
  470.         echo("can't access your input file `%s'",infile);
  471.         err= 1;
  472.       }
  473.     }
  474.     else
  475.     { infile= "stdin";
  476.       fin= stdin;
  477.     }
  478.  
  479.     if(!err)
  480.     {
  481.       if(outfmt)
  482.       {
  483.         outfile= (char *)malloc(strlen(infile)+strlen(outfmt));
  484.  
  485.         if(!tmpfile)
  486.           tmpfile= tfname(TEMPFILE_FORMAT);
  487.  
  488.         if(!outfile || !tmpfile)
  489.         {
  490.           echo("out of memory... aaaaarrrgggghhhh!");
  491.           err= 1;
  492.         }
  493.         else
  494.         {
  495.           sprintf(outfile,outfmt,infile);
  496.  
  497.           if(!silent)
  498.             printf("  %s\n",outfile);
  499.  
  500. #ifdef DEBUG
  501.           if(debuglevel >= 1)
  502.             printf("%d chars for output filename `%s' allocated,\n"
  503.                    "writing temporary data on `%s'.\n",
  504.               (int)(strlen(infile)+strlen(outfmt)), outfile, tmpfile);
  505. #endif /* DEBUG */
  506.         }
  507.       }
  508.       else outfile= (char *)0L; /* use stdout */
  509.  
  510.       /* Wenn wir nach stdout konvertieren sollen, dann brauchen wir
  511.        * kein tempor"ares File, denn wenn wir an die console schicken
  512.        * machen wir eh' nix kaputt und wenn 'stdin' redirected ist,
  513.        * hat die Shell das File auch schon zerschossen...
  514.        * Wir tun dem Benutzer aber den Gefallen und puffern die Ausgabe
  515.        * trotzdem, wenn er es explizit (mittels `-t' Option) w"unscht. */
  516.  
  517.       if(!err && tmpfile)
  518.       {
  519.         if( !(fout= fopen(tmpfile, "wb")) )
  520.         { perror(tmpfile);
  521.           echo("can't access temporary output file `%s'",tmpfile);
  522.           err= 1;
  523.         }
  524.       }
  525.     }
  526.  
  527.     if(!err)
  528.       dothehardpart(); /* let's roll! */
  529.  
  530.     if(fin && fin!=stdin)
  531.       fclose(fin);
  532.  
  533.     if(fout && fout!=stdout)
  534.       fclose(fout);
  535.  
  536.     if(!err)
  537.     {
  538.       long n;
  539.  
  540.       /* Wenn wir in ein tempor"ares File geschrieben haben, (was immer
  541.        * der Fall ist, wenn wir nicht nach stdout geschrieben haben)
  542.        * dann m"ussen wir jetzt noch kopieren.  Wir k"onnen das tmpfile
  543.        * nicht einfach renamen, weil es nicht im aktuellen Verzeichnis
  544.        * stehen mu\3. */
  545.  
  546.       if(outfile)
  547.       {
  548.         if(fin= fopen(tmpfile,"rb"))
  549.         {
  550.           if(fout= fopen(outfile,"wb"))
  551.           {
  552.             if( (n= filecopy(fin,fout,0L)) < 0L )
  553.             {
  554.               if(n==-1)
  555.               { perror(tmpfile);
  556.                 echo("couldn't re-open temporary file");
  557.               }
  558.               else
  559.               { perror(outfile);
  560.                 echo("error writing output to `%s'",outfile);
  561.                 echo("temporary output written on `%s'",tmpfile);
  562.               }
  563.               err= 1;
  564.             }
  565. #ifdef DEBUG
  566.             else if(debuglevel >= 1)
  567.               printf("%ld byte(s) of output\n",n);
  568. #endif
  569.             fclose(fout);
  570.           }
  571.           fclose(fin);
  572.         }
  573.       }
  574.       else if(tmpfile) /* but !outfile */
  575.       {
  576.         FILE *fp;
  577.  
  578.         /* Wir haben in ein tempor"ares File geschrieben und m"ussen die
  579.          * Ausgabe auf die Console umleiten.  Wir machen das Zeichen f"ur
  580.          * Zeichen... */
  581.  
  582.         if( fp= fopen(tmpfile, "rb") )
  583.         { for(n=0; !feof(fp); n++)
  584.           { char c= fgetc(fp);
  585.             if(!feof(fp))
  586.               fputc(c,stdout);
  587.           }
  588.           fclose(fp);
  589.         }
  590.         else
  591.         { perror(tmpfile);
  592.           echo("couldn't re-open temporary file");
  593.           err= 1;
  594.         }
  595.       }
  596.       /* otherwise we wrote to <stdout> directly */
  597.     }
  598.  
  599.     if(tmpfile)
  600.     { if(!err)
  601.         remove(tmpfile);
  602.       free(tmpfile);
  603.       tmpfile= (char *)0L;
  604.     }
  605.  
  606.     if(fn)
  607.       fn= fn->next;
  608.  
  609.     if(outfile)
  610.     { free(outfile);
  611.       outfile= (char *)0L;
  612.     }
  613.  
  614.   } while(fn && !err);
  615.  
  616.   if(err > 0)
  617.   { echo("*** [%s] exit code %d.",
  618.       (rulefile && *rulefile) ? rulefile : "no rules", err);
  619.   }
  620.   else if(err==0 && dryrun && rulefile)
  621.     fprintf(ferr, "%s: %ld rules, no errors.\n",rulefile, global_numrules);
  622.  
  623.   if(flist)
  624.     purge_flist();
  625.  
  626.   if(crules)
  627.     exit_rules();
  628.  
  629.   if(ferr && ferr!=stderr)
  630.     fclose(ferr);
  631.   
  632.   return (err>0) ? 1:0;
  633. }
  634.