home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume21 / filterfile / filterfile.c < prev    next >
C/C++ Source or Header  |  1990-02-05  |  9KB  |  287 lines

  1. /*
  2. filterfile.c: Pipe a file through a filter into another file.
  3.  
  4. This program is an obnoxious example of how to check return codes.
  5. */
  6.  
  7. static char filterfileauthor[] =
  8. "filterfile was written by Daniel J. Bernstein.\n\
  9. Internet address: brnstnd@acf10.nyu.edu.\n";
  10.  
  11. static char filterfileversion[] = 
  12. "filterfile version 1.201, October 28, 1989.\n\
  13. Copyright (c) 1989, Daniel J. Bernstein.\n\
  14. All rights reserved.\n";
  15.  
  16. static char filterfilecopyright[] =
  17. "filterfile version 1.201, October 28, 1989.\n\
  18. Copyright (c) 1989, Daniel J. Bernstein.\n\
  19. All rights reserved.\n\
  20. \n\
  21. You are granted the following rights: A. To make copies of this work in\n\
  22. original form, so long as (1) the copies are exact and complete; (2) the\n\
  23. copies include the copyright notice, this paragraph, and the disclaimer\n\
  24. of warranty in their entirety. B. To distribute this work, or copies made\n\
  25. under the provisions above, so long as (1) this is the original work and\n\
  26. not a derivative form; (2) you do not charge a fee for copying or for\n\
  27. distribution; (3) you ensure that the distributed form includes the\n\
  28. copyright notice, this paragraph, and the disclaimer of warranty in their\n\
  29. entirety. These rights are temporary and revocable upon written, oral, or\n\
  30. other notice by Daniel J. Bernstein. This copyright notice shall be\n\
  31. governed by the laws of the state of New York.\n\
  32. \n\
  33. If you have questions about filterfile or about this copyright notice,\n\
  34. or if you would like additional rights beyond those granted above,\n\
  35. please feel free to contact the author at brnstnd@acf10.nyu.edu\n\
  36. on the Internet.\n";
  37.  
  38. static char filterfilewarranty[] =
  39. "To the extent permitted by applicable law, Daniel J. Bernstein disclaims\n\
  40. all warranties, explicit or implied, including but not limited to the\n\
  41. implied warranties of merchantability and fitness for a particular purpose.\n\
  42. Daniel J. Bernstein is not and shall not be liable for any damages,\n\
  43. incidental or consequential, arising from the use of this program, even\n\
  44. if you inform him of the possibility of such damages. This disclaimer\n\
  45. shall be governed by the laws of the state of New York.\n\
  46. \n\
  47. In other words, use this program at your own risk.\n\
  48. \n\
  49. If you have questions about filterfile or about this disclaimer of warranty,\n\
  50. please feel free to contact the author at brnstnd@acf10.nyu.edu\n\
  51. on the Internet.\n";
  52.  
  53. static char filterfileusage[] =
  54. "Usage: filterfile [ -dDpPtTACHUVW ] [ -oout ] [ -eext ]\n\
  55.                   file /path/filter [ arg ... ]\n\
  56. Help:  filterfile -H\n";
  57.  
  58. static char filterfilehelp[] =
  59. "filterfile applies a filter to a file, placing the output in a new file.\n\
  60. \n\
  61. filterfile -A: print authorship notice\n\
  62. filterfile -C: print copyright notice\n\
  63. filterfile -H: print this notice\n\
  64. filterfile -U: print short usage summary\n\
  65. filterfile -V: print version number\n\
  66. filterfile -W: print disclaimer of warranty\n\
  67. \n\
  68. filterfile [ -dDpPtT ] [ -oout ] [ -eext ]\n\
  69.            file /path/filter [ arg ... ]: apply filter to file\n\
  70.   -d: delete input file\n\
  71.   -D: do not delete input file (default)\n\
  72.   -p: preserve protection of file\n\
  73.   -P: do not preserve protection of file (default)\n\
  74.   -t: preserve access and modification times of file\n\
  75.   -T: do not preserve times (default)\n\
  76.   -eext: sent output to file.ext, or if ext begins with . remove it from name\n\
  77.   -oout: send output to out (overrides -e)\n\
  78. \n\
  79. If you have questions about or suggestions for filterfile, please feel free\n\
  80. to contact the author, Daniel J. Bernstein, at brnstnd@acf10.nyu.edu\n\
  81. on the Internet.\n";
  82.  
  83. #include <stdio.h>
  84. #include <sys/types.h>
  85. #include <sys/stat.h>
  86. #include <sys/file.h>
  87. #ifdef BSD
  88. #include <limits.h>
  89. #endif
  90. #include <sys/wait.h>
  91. #include <sys/time.h>
  92.  
  93. extern char *getenv(); 
  94. extern char *malloc(); 
  95.  
  96. int flagdelete = 0;
  97. int flagprotect = 0;
  98. int flagtimes = 0;
  99.  
  100. int flagunappend = 0;
  101.  
  102. char *fnout = 0;
  103. char *fnin = 0;
  104. char **filter = 0;
  105. char *fnappend = 0;
  106.  
  107. main(argc,argv,envp)
  108. int argc;
  109. char *argv[];
  110. char *envp[];
  111. {
  112.  char *s;
  113.  int f;
  114.  int fdin;
  115.  int fdout;
  116.  union wait wstat;
  117.  struct stat stinold;
  118.  struct stat stoutold;
  119.  struct stat stin;
  120.  struct stat stout;
  121.  struct timeval tvp[2];
  122.  
  123.  fnappend = getenv("FILTERFILEEXT");
  124.  
  125.  while (*(++argv))
  126.    if (**argv == '-')
  127.      while (*(++(*argv)))
  128.        switch(**argv)
  129.         {
  130.      case 'd': flagdelete = 1; break;
  131.      case 'D': flagdelete = 0; break;
  132.      case 'p': flagprotect = 1; break;
  133.      case 'P': flagprotect = 0; break;
  134.      case 't': flagtimes = 1; break;
  135.      case 'T': flagtimes = 0; break;
  136.      case 'e': fnappend = *argv + 1;
  137.            while (*(++(*argv))) /* null */ ;
  138.            --(*argv); break; /* we really want breakbreak here */
  139.      case 'o': fnout = *argv + 1;
  140.            while (*(++(*argv))) /* null */ ;
  141.            --(*argv); break; /* we really want breakbreak here */
  142.      case 'A': printf(filterfileauthor); exit(0);
  143.          case 'C': printf(filterfilecopyright); exit(0);
  144.          case 'V': printf(filterfileversion); exit(0);
  145.          case 'W': printf(filterfilewarranty); exit(0);
  146.          case 'H': printf(filterfilehelp); exit(0);
  147.          case 'U': printf(filterfileusage); exit(0);
  148.          default: ;
  149.     }
  150.    else 
  151.      if (fnin == 0) 
  152.        fnin = *argv;
  153.      else
  154.        if (filter == 0) 
  155.         {
  156.          filter = argv;
  157.      break;
  158.         }
  159.  
  160.  if ((fnin == 0) || (filter == 0))
  161.   {
  162.    printf(filterfileusage); exit(1);
  163.   }
  164.  if (fnout == 0)
  165.   {
  166.    flagunappend = (*fnappend == '.');
  167.    for (s = fnappend;*s;s++)
  168.      if (*s == '/')
  169.        *s = '.'; 
  170.    fnout = malloc((unsigned) (strlen(fnin) + strlen(fnappend) + 2));
  171.    if (fnout == 0)
  172.     {
  173.      fprintf(stderr,"filterfile: fatal: cannot create output file name: \
  174. out of memory\n");
  175.      exit(1);
  176.     }
  177.    (void) strcpy(fnout,fnin);
  178.    if (flagunappend && (strlen(fnout) > strlen(fnappend)) &&
  179.     (strcmp(fnout + strlen(fnout) - strlen(fnappend),fnappend) == 0))
  180.      fnout[strlen(fnout) - strlen(fnappend)] = 0;
  181.    else
  182.     {
  183.      (void) strcat(fnout,".");
  184.      if (fnappend != NULL)
  185.        (void) strcat(fnout,fnappend);
  186.     }
  187.   }
  188.  
  189.  /* Okay. Now we have fnin, fnout, and filter. */
  190.  
  191.  fdin = open(fnin,O_RDONLY);
  192.  if (fdin == -1)
  193.   { fprintf(stderr,"filterfile: fatal: cannot open input file ");
  194.    perror(fnin); exit(1); }
  195.  if (fstat(fdin,&stinold) == -1)
  196.   { perror("filterfile: fatal: cannot stat input file"); exit(1); }
  197.  if (flagdelete && (stinold.st_nlink > 1))
  198.   { fprintf(stderr,"filterfile: fatal: will not proceed: \
  199. input file %s has extra links\n",fnin); exit(1); }
  200.  
  201.  tvp[0].tv_sec = stinold.st_atime;
  202.  tvp[0].tv_usec = 0;
  203.  tvp[1].tv_sec = stinold.st_mtime;
  204.  tvp[1].tv_usec = 0;
  205.  
  206.  fdout = open(fnout,O_WRONLY | O_CREAT | O_EXCL,0600);
  207.  if (fdout == -1)
  208.   { fprintf(stderr,"filterfile: fatal: cannot create output file ");
  209.    perror(fnout); exit(1); }
  210.  if (fstat(fdout,&stoutold) == -1)
  211.   { perror("filterfile: fatal: cannot stat output file"); exit(1); }
  212.  
  213.  if (flagprotect)
  214.    if (fchmod(fdout,stinold.st_mode & 0777) == -1)
  215.      perror("filterfile: warning: cannot change protections of output file");
  216.  
  217.  if ((f = fork()) == 0) /* child */
  218.   {
  219.    if (dup2(fdin,0) == -1)
  220.     { perror("filterfile: fatal: cannot prepare input"); exit(1); }
  221.    if (dup2(fdout,1) == -1)
  222.     { perror("filterfile: fatal: cannot prepare output"); exit(1); }
  223.    execvp(*filter,filter);
  224.    fprintf(stderr,"filterfile: fatal: cannot execute filter\n");
  225.    exit(1);
  226.   }
  227.  else if (f == -1) /* fork failed */
  228.   { perror("filterfile: fatal: cannot fork"); exit(1); }
  229.  
  230.  /* parent */
  231.  close(fdin);
  232.  close(fdout);
  233.  if (wait(&wstat) == -1) 
  234.   { perror("filterfile: fatal: can't find filter process"); exit(1); }
  235.  if (wstat.w_T.w_Termsig)
  236.    exit(1); 
  237.  if (wstat.w_T.w_Retcode)
  238.    exit((int) wstat.w_T.w_Retcode); 
  239.  if (wstat.w_T.w_Coredump)
  240.    exit(1); 
  241.  
  242.  /* Filter exited happily. */
  243.  
  244.  if (flagdelete)
  245.   {
  246.    /* Race! Race! Race! */
  247.    fdin = open(fnin,O_RDONLY);
  248.    if (fdin == -1)
  249.     { fprintf(stderr,"filterfile: fatal: cannot reopen input file ");
  250.      perror(fnin); exit(1); }
  251.    if (fstat(fdin,&stin) == -1)
  252.     { fprintf(stderr,"filterfile: fatal: cannot restat input file ");
  253.      perror(fnin); exit(1); }
  254.    if ((stin.st_dev != stinold.st_dev) || (stin.st_ino != stinold.st_ino))
  255.     { fprintf(stderr,"filterfile: fatal: will not delete input file %s: \
  256. it has been moved\n",fnin); exit(1); }
  257.    if (stin.st_nlink > 1)
  258.     { fprintf(stderr,"filterfile: fatal: will not delete input file %s: \
  259. it has extra links\n",fnin); exit(1); }
  260.    /* Race! Race! Race! */
  261.    if (unlink(fnin) == -1)
  262.     { fprintf(stderr,"filterfile: fatal: cannot delete input file ");
  263.      perror(fnin); exit(1); }
  264.    (void) close(fdin);
  265.   }
  266.  
  267.  if (flagtimes)
  268.   {
  269.    /* Race! Race! Race! */
  270.    fdout = open(fnout,O_RDONLY);
  271.    if (fdout == -1)
  272.     { fprintf(stderr,"filterfile: fatal: cannot reopen output file ");
  273.      perror(fnout); exit(1); }
  274.    if (fstat(fdout,&stout) == -1)
  275.     { perror("filterfile: fatal: cannot restat output file"); exit(1); }
  276.    if ((stout.st_dev != stoutold.st_dev) || (stout.st_ino != stoutold.st_ino))
  277.     { fprintf(stderr,"filterfile: warning: will not set times of \
  278. output file %s: it has been moved\n",fnout); exit(1); }
  279.    /* Race! Race! Race! */
  280.    if (utimes(fnout,tvp) == -1)
  281.     { fprintf(stderr,"filterfile: warning: cannot set times of output file ");
  282.      perror(fnout); exit(1); }
  283.   }
  284.  
  285.  exit(0);
  286. }
  287.