home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume7 / flip / flip.c < prev    next >
C/C++ Source or Header  |  1989-07-08  |  13KB  |  551 lines

  1. /* ::[[ @(#) flip.c 1.18 89/07/04 16:07:16 ]]:: */
  2. #ifndef LINT
  3. static char sccsid[]="::[[ @(#) flip.c 1.18 89/07/04 16:07:16 ]]::";
  4. #endif
  5.  
  6. /*
  7. Copyright 1989 Rahul Dhesi, All rights reserved.
  8.  
  9. Checksum: 1217582374 (check or update with "brik")
  10. */
  11.  
  12. /*
  13. Does newline conversions between **IX and MS-DOS conventions.  Uses a state
  14. machine, so repeated conversions on the same file will do no harm.
  15. Assumes the US ASCII character set in some places (search for 'ASCII').
  16. */
  17.  
  18. /* change contents of flip.h as needed */
  19. #include "flip.h"
  20.  
  21. enum choices   { MSTOIX, IXTOMS, NEITHER };           /* conversion choices */
  22. enum state     { NONE, SAWCR, SAWLF, SAWCRLF, SAWCTRLZ };
  23.  
  24. void usage PARMS ((void));
  25. void give_help PARMS ((void));
  26. void flip_exit PARMS ((int));
  27. int getopt PARMS ((int argc, char **argv, char *options));
  28. void doarg PARMS ((char *, enum choices));
  29. int dofile PARMS ((char *, enum choices));
  30. char *nextfile PARMS ((int, char *, int));
  31. int ixtoms PARMS ((FILE *, FILE *));
  32. int mstoix PARMS ((FILE *, FILE *));
  33. void error PARMS ((char *, char *));
  34. void setup_sigs PARMS ((void));
  35. void cleanup PARMS ((int));
  36. char *mktemp PARMS ((char *));
  37.  
  38. #ifdef STDINCLUDE
  39. # include <stdlib.h>
  40. # include <string.h>
  41. #else
  42. void exit PARMS ((int));
  43. char *strcpy PARMS ((char *, char *));
  44. #endif
  45.  
  46. #ifdef NDEBUG
  47. # define assert(c)
  48. #else
  49. # ifdef STDINCLUDE
  50. #  include <assert.h>
  51. # else
  52. #  define assert(c)  if(!(c)) \
  53.                   fprintf(stderr,"assert error %s:%d\n",__FILE__,__LINE__)
  54. # endif /* STDINCLUDE */
  55. #endif /* NDEBUG */
  56.  
  57. #ifdef USE_TABLE
  58. char *bintab;
  59. #endif
  60.  
  61. #ifdef USE_SIG
  62. int got_sig;               /* will indicate if signal received */
  63. #endif
  64.  
  65. char *myname = NULL;
  66.  
  67. int exitstat = 0;          /* exit status */
  68. int verbose = 0;           /* set by -v option */
  69. int touch = 0;             /* set by -t option */
  70. int strip = 0;             /* set by -s option */
  71. int bintoo = 0;            /* set by -b option */
  72. int ztrunc = 0;            /* set by -z option */
  73.  
  74. main (argc, argv)
  75. int argc;
  76. char **argv;
  77.  
  78. {
  79.    int option;
  80.    extern int optind;
  81.    int i;
  82.    enum choices which = NEITHER;
  83. #ifdef USE_TABLE
  84. #define TABSIZ    256
  85.    char table[TABSIZ];
  86. #endif
  87.  
  88. #ifdef PICKNAME
  89.    register char *p; /* temp pointer for finding our name */
  90.    register char *arg0 = *argv;
  91. #endif /* PICKNAME */
  92.  
  93.    SPEC_INIT            /* optional initialization */
  94.  
  95. #ifdef USE_SIG
  96.    setup_sigs();
  97. #endif
  98.  
  99. #ifdef PICKNAME
  100. # define STRCMP(a,op,b)    (strcmp(a,b) op 0)
  101.    p = arg0 + strlen(arg0);
  102.  
  103.    if (p != arg0) {     /* if program name is defined */
  104.       while (p != arg0 && *p != '/' && *p != '\\')
  105.          p--;
  106.       assert ((p - arg0) <= strlen (arg0));
  107.       if (p != arg0)
  108.          p++;
  109.  
  110.       /* p now points to trailing name component, or nothing */
  111.       myname = p;
  112.       while (*p != '\0' && *p != '.') {   /* ASCII convert to lowercase */
  113.          if (*p >= 'A' && *p <= 'Z') {
  114.             *p = (*p - 'A' + 'a');
  115.          }
  116.          p++;
  117.       }
  118.       if (p != myname && *p == '.')
  119.          *p = '\0';     /* remove trailing .exe or .com under MS-DOS etc. */
  120.  
  121.       if (STRCMP(myname,==,"toix"))
  122.          which = MSTOIX;
  123.       else if (STRCMP(myname,==,"toms"))
  124.          which = IXTOMS;
  125.    } else
  126.    myname = "flip";
  127. #else
  128.    myname = "flip";
  129. #endif /* PICKNAME */
  130.  
  131. argv[0] = myname;                /* for use by getopt */
  132.  
  133. #ifdef USE_TABLE
  134. /* table to find out which characters are binary */
  135.    for (i = 0;  i < TABSIZ;  i++) {
  136.       if ( (i < 7) || (i > 13 && i < 26) || (i > 126)) /*ASCII binary chars*/
  137.          table[i] = 1;
  138.       else
  139.          table[i] = 0;
  140.    }
  141.    bintab = table;
  142. #endif /* USE_TABLE */
  143.  
  144.    if (argc < 2) {
  145.       usage();
  146.       flip_exit (1);
  147.    }
  148.  
  149.    while ((option = getopt (argc, argv, "umhvtsbz")) != EOF) {
  150.       switch (option) {
  151.        case 'u': which = MSTOIX;  break;
  152.        case 'm': which = IXTOMS; break;
  153.        case 'h': give_help(); flip_exit (0);
  154.        case 'v': verbose = 1;  break;
  155.        case 't': touch = 1;  break;
  156.        case 's': strip = 1;  break;
  157.        case 'b': bintoo = 1;  break;
  158.        case 'z': ztrunc = 1;  break;
  159.        default:  usage(); flip_exit (1);
  160.       }
  161.    }
  162.  
  163.    switch (which) {
  164.     case MSTOIX:
  165.       /* printf ("converting to **ix format\n"); */
  166.       break;
  167.     case IXTOMS:
  168.       /* printf ("converting to msdos format\n"); */
  169.       break;
  170.     default:
  171.       fprintf (stderr, "%s: error: -u or -m is required\n", myname);
  172.       flip_exit (1);
  173.       break;
  174.    }
  175.  
  176.    if (argc <= optind) {
  177.       fprintf (stderr, "%s: error: filenames are needed\n", myname);
  178.       flip_exit (1);
  179.    }
  180.  
  181.    for (i = optind;  i < argc;  i++)
  182.       doarg (argv[i], which);
  183.  
  184.    return (exitstat);
  185. }
  186.  
  187.  
  188. /*
  189. Does conversion for one argument, calling dofile with wildcards
  190. expanded.  Updates exitstat in case of error.
  191. */
  192.  
  193. void doarg (arg, which)
  194. char *arg;
  195. enum choices which;
  196. {
  197. #ifdef WILDCARD
  198.    char *this_file;
  199.  
  200.    nextfile (0, arg, 0);
  201.    while ((this_file = nextfile(1, (char *) NULL, 0)) != NULL) {
  202.       exitstat |= dofile (this_file, which);
  203.    }
  204. #else
  205.    exitstat |= dofile (arg, which);
  206. #endif /* WILDCARD */
  207. }
  208.  
  209. #ifdef USE_SIG
  210. # include <signal.h>
  211. #endif
  212.  
  213. FILE *outfile;       /* make it visible to both dofile and cleanup */
  214.  
  215. /*
  216. Here we have filename and an option.  We call a different routine
  217. for each type of conversion.  This way more types of conversions
  218. can be easily added in the future.
  219. */
  220.  
  221. int dofile (fname, which)
  222. char *fname;
  223. enum choices which;
  224. {
  225.    FILE *infile;
  226.    char tfname[PATHSIZE];
  227.    SGFTIME timestamp;  /* save file timestamp here, restore later */
  228.    int errstat = 0;
  229.    char *p;             /* temp file ptr */
  230.  
  231. #ifdef USE_SIG
  232.    if (got_sig)
  233.       flip_exit (INT_EXIT);
  234. #endif
  235.  
  236.    /* if writable, open for reading */
  237.    if ((infile = fopen (fname, R_PL_B)) != NULL) {
  238.       fclose (infile);
  239.       infile = fopen (fname, RB);
  240.    }
  241.  
  242.    if (infile == NULL) {
  243.       error (fname, ": can't open");
  244.       return (1);
  245.    }
  246.  
  247.    /*
  248.    to make temp file in same dir as original, we make p point to the filename
  249.    component of fname, put '\0' there, and strcat the temp name to it
  250.    */
  251.    strcpy (tfname, fname);
  252.    p = tfname + strlen(tfname);
  253.  
  254.    while (p != tfname && *p != '/' && *p != '\\')
  255.       p--;
  256.    if (p != tfname)
  257.       p++;
  258.    *p = '\0';
  259.  
  260. #define  TEMPLATE    "XXXXXX"
  261.    {
  262.       char template[7];
  263.       strcpy (template, TEMPLATE);
  264.       strcat (tfname, mktemp (template));
  265.    }
  266.  
  267.    outfile = fopen (tfname, WB);
  268.  
  269.    if (outfile == NULL) {
  270.       fclose (infile);
  271.       error (fname, ": skipped, could not open temporary file");
  272.       return (1);
  273.    }
  274.  
  275.    if (!touch)
  276.       GETFT (infile, fname, timestamp);      /* save current timestamp */
  277.  
  278.    assert (which == IXTOMS || which == MSTOIX);
  279.  
  280. #ifdef BIGBUF
  281.    setvbuf (infile,  (char *) NULL, _IOFBF, BIGBUF);
  282.    setvbuf (outfile, (char *) NULL, _IOFBF, BIGBUF);
  283. #endif /* BIGBUF */
  284.  
  285.    switch (which) {
  286.     case IXTOMS:
  287.       errstat = ixtoms (infile, outfile);
  288.       break;
  289.     case MSTOIX:
  290.       errstat = mstoix (infile, outfile);
  291.       break;
  292.    }
  293.  
  294.    fclose (infile);
  295.  
  296.    switch (errstat) {
  297.     case ERRBINF:
  298.       fclose (outfile);
  299.       DELFILE (tfname);
  300.       fprintf (stderr, "%s: binary file, not converted\n", fname);
  301.       return (1);
  302.       /* break; */  /* unreachable code */
  303. #ifdef USE_SIG
  304.     case ERRSIG:
  305.       fclose (outfile);
  306.       DELFILE (tfname);
  307.       flip_exit (INT_EXIT);
  308.       break;
  309. #endif
  310.     default:
  311.       ;
  312.    }
  313.  
  314.    assert (errstat == 0);
  315.  
  316.    if (!ferror(outfile) && fflush(outfile) != EOF && fclose(outfile) != EOF) {
  317.       int moved;
  318.       DELFILE (fname);
  319.       moved = MVFILE (tfname, fname);
  320.       if (moved == 0) {
  321.          FILE *fptr;
  322.          if (!touch && (fptr = fopen (fname, RB)) != NULL) {
  323.             SETFT (fptr, fname, timestamp);
  324.             fclose (fptr);
  325.          }
  326.          if (verbose) {
  327.             printf ("%s\n", fname);
  328.             fflush (stdout);
  329.          }
  330.          return (0);
  331.       } else {
  332.          error (fname, ": not converted, could not rename temp file");
  333.          DELFILE (tfname);
  334.          return (1);
  335.       }
  336.    } else {
  337.       fclose (outfile); /* outfile was not closed, so close it here */
  338.       return (1);
  339.    }
  340. }
  341.  
  342. /* convert from ms-dos to **ix format */
  343. int mstoix (infile, outfile)
  344. FILE *infile;           /* input file   */
  345. FILE *outfile;          /* output file  */
  346. {
  347.    int c;
  348.    enum state state = NONE;
  349.  
  350.    /* lone LF => unchanged, lone CR => unchanged,
  351.       CR LF => LF, ^Z at end means EOF; ^Z elsewhere => unchanged */
  352.  
  353.    while (1) {       /* break out on EOF only */
  354.       while ((c = getc (infile)) != EOF) {
  355. #ifdef USE_SIG
  356.          if (got_sig)
  357.             return (ERRSIG);
  358. #endif
  359.          if (!bintoo && BINCHAR(c))
  360.             return (ERRBINF);
  361.          if (strip)
  362.             STRIP(c);
  363.          switch (c) {
  364.           case LF:
  365.             CHECK_BREAK
  366.             putc (c, outfile); if (state == SAWCR) state = NONE; break;
  367.           case CR:
  368.             state = SAWCR; break;
  369.           case CTRLZ:
  370.             if (state == SAWCR) putc (CR, outfile);
  371.             state = SAWCTRLZ; goto saweof;
  372.           default:
  373.             if (state == SAWCR) { state = NONE; putc (CR, outfile); }
  374.             putc (c, outfile);
  375.             break;
  376.          }
  377.       }
  378.  saweof:
  379.       /* exit outer loop only on EOF or ^Z as last char */
  380.       if (
  381.           ztrunc && state == SAWCTRLZ
  382.           || (c = getc (infile)) == EOF
  383.          )
  384.          break;
  385.       else
  386.          ungetc (c, infile);
  387.       if (state == SAWCTRLZ)
  388.          putc (CTRLZ, outfile);
  389.    }
  390.    return (0);
  391. }
  392.  
  393. /* convert from **ix to ms-dos format */
  394. int ixtoms (infile, outfile)
  395. FILE *infile;           /* input file   */
  396. FILE *outfile;          /* output file  */
  397. {
  398.    int c;
  399.    enum state state = NONE;
  400.  
  401.    /* LF => CR LF, but leave CR LF alone */
  402.    while ((c = getc (infile)) != EOF) {
  403. #ifdef USE_SIG
  404.       if (got_sig)
  405.          return (ERRSIG);
  406. #endif
  407.       if (!bintoo && BINCHAR(c))
  408.          return (ERRBINF);
  409.       if (strip)
  410.          STRIP(c);
  411.       switch (c) {
  412.        case LF:
  413.          CHECK_BREAK
  414.          if (state == SAWCR)
  415.             state = NONE;
  416.          else
  417.             putc (CR, outfile);
  418.          putc (LF, outfile);
  419.          break;
  420.        case CR:
  421.          state = SAWCR; putc (c, outfile); break;
  422.        case CTRLZ:
  423.          if (ztrunc)
  424.             return (0);
  425.          /* FALL THROUGH */
  426.        default:
  427.          state = NONE; putc (c, outfile); break;
  428.       }
  429.    }
  430.    return (0);
  431. }
  432.  
  433. /* set up signal handler for selected signals */
  434. #ifdef USE_SIG
  435. void setup_sigs ()
  436. {
  437. # ifdef SIGPIPE
  438.    if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
  439.       signal (SIGPIPE, cleanup);
  440. # endif
  441. # ifdef SIGHUP
  442.    if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
  443.       signal (SIGHUP, cleanup);
  444. # endif
  445. # ifdef SIGQUIT
  446.    if (signal (SIGQUIT, SIG_IGN) != SIG_IGN)
  447.       signal (SIGQUIT, cleanup);
  448. # endif
  449. # ifdef SIGINT
  450.    if (signal (SIGINT, SIG_IGN) != SIG_IGN)
  451.       signal (SIGINT, cleanup);
  452. # endif
  453. # ifdef SIGTERM
  454.    if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
  455.       signal (SIGTERM, cleanup);
  456. # endif
  457. }
  458.  
  459. /* set flag on signal */
  460. void cleanup(sig)
  461. int sig;
  462. {
  463.    signal (sig, SIG_IGN);     /* needed for flaky System V Release 2 */
  464.    got_sig = 1;
  465.    signal (sig, cleanup);     /* ditto */
  466. }
  467. #endif /* USE_SIG */
  468.  
  469. #define  ERRSIZE     200
  470.  
  471. /* prints error message via perror */
  472. void error (msg1, msg2)
  473. char *msg1, *msg2;
  474. {
  475.    char buf[ERRSIZE];
  476.    strcpy (buf, myname);
  477.    strcat (buf, ": ");
  478.    strcat (buf, msg1);
  479.    strcat (buf, msg2);
  480.    perror (buf);
  481.    fflush (stderr);
  482. }
  483.  
  484. /* gives brief usage message */
  485. void usage()
  486. {
  487.    fprintf (stderr,
  488. "usage:  %s [-u | -m] [other options] file ...  (or \"%s -h\" for more help)\n",
  489.  myname, myname);
  490. }
  491.  
  492. /* gives help screen */
  493.  
  494. void give_help()
  495. {
  496. printf ("\
  497. File interchange program flip version 1.00.  Copyright 1989 Rahul Dhesi,\n\
  498. All rights reserved.  Both noncommercial and commercial copying, use, and\n\
  499. creation of derivative works are permitted in accordance with the\n\
  500. requirements of the GNU license.  This program does newline conversions.\n");
  501.  
  502. printf ("\n\
  503.    Usage:     flip -umhvtsbz file ...\n\
  504. \n\
  505. One of -u, -m, or -h is required;  others are optional.  See user manual.\n");
  506.  
  507. printf ("\n\
  508.    -u     convert to **IX format (CR LF => LF, lone CR or LF unchanged,\n\
  509.           trailing control Z removed, embedded control Z unchanged)\n\
  510.    -m     convert to MS-DOS format (lone LF => CR LF, lone CR unchanged)\n\
  511.    -h     give this help message\n\
  512.    -v     be verbose, print filenames as they are processed\n\
  513.    -t     touch files (don't preserve timestamps)\n\
  514.    -s     strip high bit\n\
  515.    -b     convert binary files too (else binary files are left unchanged)\n\
  516.    -z     truncate file at first control Z encountered\n\
  517. ");
  518. #ifdef PICKNAME
  519. printf ("\n\
  520. May be invoked as \"toix\" (same as \"flip -u\") or \"toms\" (same as \"flip -m\").\n\
  521. ");
  522. #endif
  523. return;
  524. }
  525.  
  526. /* normal exits go through here -- atexit would be nice but not portable */
  527. void flip_exit(stat)
  528. int stat;
  529. {
  530.    SPEC_EXIT
  531.    exit (stat);
  532. }
  533.  
  534. /*
  535. special code for **IX -- not in use because can't properly handle
  536. SIGINT while /bin/mv is executing
  537. */
  538.  
  539. #ifdef NIX
  540. # ifndef MVFILE
  541. int MVFILE (src, dest)
  542. char *dest;
  543. char *src;
  544. {
  545.    char cmd[2 * PATHSIZE];
  546.    sprintf (cmd, "/bin/mv %s %s", src, dest);
  547.    return (system(cmd));
  548. }
  549. # endif /* MVFILE */
  550. #endif /* NIX */
  551.