home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 1 / 1927 / apply.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-12-28  |  6.1 KB  |  240 lines

  1. #include <sys/types.h> /* for wait and fork */
  2. #include <sys/wait.h> /* for wait */
  3. #include <stdio.h> /* for EOF, fprintf, puts */
  4. #include <malloc.h> /* for malloc and free */
  5. #include <strings.h> /* for strlen and strcpy */
  6. #include "getopt.h" /*XXX: should be <getopt.h> */
  7. /* XXX: What about system(), exit(), perror()? */
  8. /* XXX: Shouldn't do repeated malloc-free. Figure out the largest block */
  9. /*      size needed, allocate it once, and use it repeatedly. */
  10. /* XXX: Maybe option to quote arguments under flagsystem? */
  11. /* XXX: Or just allow spaces within arguments inside command? */
  12. /* XXX: The number of separate command parsers in here is ridiculous. */
  13.  
  14. static char applyusage[] = "Usage: apply [ -ac ] [ -n ] cmd arg ...\n";
  15. static char applytoomany[] = "apply: warning: extra arguments\n";
  16. static char applyforkfail[] = "apply: fatal: cannot fork";
  17. static char applyexecfail[] = "apply: fatal: cannot exec";
  18. static char applymalloc[] = "apply: fatal: cannot malloc\n";
  19.  
  20. main(argc,argv)
  21. int argc;
  22. char *argv[];
  23. {
  24.  register char *s;
  25.  register char *t;
  26.  register char **a;
  27.  register int i;
  28.  register int j;
  29.  register char *cmd;
  30.  register int flagsystem = 0;
  31.  register int narg = 1;
  32.  register int nch = 0;
  33.  register int nesc = 0;
  34.  register char escape = '%';
  35.  register int opt;
  36.  
  37.  while ((opt = getopt(argc,argv,"0123456789a:s")) != EOF)
  38.    switch(opt)
  39.     {
  40.      case '?': (void) fprintf(stderr,applyusage);
  41.            (void) exit(1);
  42.      case 'a': escape = *optarg; break; /* can't be null */
  43.      case 's': flagsystem = 2; break;
  44. #define OSN(i,j) case i: narg = j; break;
  45.      OSN('0',0) OSN('1',1) OSN('2',2) OSN('3',3) OSN('4',4)
  46.      OSN('5',5) OSN('6',6) OSN('7',7) OSN('8',8) OSN('9',9)
  47.     }
  48.  argv += optind, argc -= optind;
  49.  
  50.  if (!*argv)
  51.   {
  52.    (void) fprintf(stderr,applyusage);
  53.    (void) exit(1);
  54.   }
  55.  
  56.  /* Note that we accept %0, and do the same with it as with -0. */
  57.  s = *argv;
  58.  while (*s)
  59.    if (*(s++) != escape)
  60.      nch++;
  61.    else
  62.     {
  63.      if (!*s)
  64.       { flagsystem = (!flagsystem ? 1 : flagsystem); break; }
  65.      switch(*(s++))
  66.       {
  67. #define TSN(i,j) case i: narg=(nesc++?(narg>j?narg:j):j); break;
  68.        TSN('0',0) TSN('1',1) TSN('2',2) TSN('3',3) TSN('4',4)
  69.        TSN('5',5) TSN('6',6) TSN('7',7) TSN('8',8) TSN('9',9)
  70.        default: nch++; break;
  71.       }
  72.     }
  73.  
  74.  /* Now the number of real characters is nch. */
  75.  /* The number of escape characters is nesc. */
  76.  /* If flagsystem is 1, we should use sh. */
  77.  /* And we should snarf narg args per cmd, plus waste one if !narg. */
  78.  
  79.  if (!nesc)
  80.   {
  81.    t = cmd = malloc((unsigned) (nch + 1));
  82.    s = *argv;
  83.    while (*s)
  84.      if (*s != escape)
  85.        *(t++) = *(s++);
  86.      else
  87.       {
  88.        if (!*++s)
  89.          break;
  90.        switch(*s)
  91.         {
  92.          case 'e': *(t++) = escape; s++; break;
  93.      default: *(t++) = *(s++); break;
  94.         }
  95.       }
  96.    *t = '\0';
  97.   }
  98.  else
  99.    cmd = *argv;
  100.    
  101.  argc--; argv++;
  102.  /* XXX: Should something be done to prevent zombies? */
  103.  
  104.  if (narg && (argc % narg))
  105.    (void) fprintf(stderr,applytoomany);
  106.  while (argc >= narg + !narg)
  107.   {
  108.    if (!nesc)
  109.     {
  110.      if (flagsystem)
  111.       {
  112.        i = nch + narg + !narg;
  113.        for (j = 0;j < narg;j++)
  114.      i += strlen(argv[j]);
  115.        t = s = malloc((unsigned) i);
  116.        if (!t)
  117.     {
  118.      (void) fprintf(stderr,applymalloc);
  119.      (void) exit(1);
  120.     }
  121.        (void) strcpy(t,cmd); t += strlen(cmd); *(t++) = ' ';
  122.        for (j = 0;j < narg;j++)
  123.     {
  124.          (void) strcpy(t,argv[j]); t += strlen(argv[j]); *(t++) = ' ';
  125.     }
  126.        *t = '\0';
  127.        /* slow? whaddya mean, slow? three passes is nothing! */
  128.        if (flagsystem == 2)
  129.          (void) puts(s);
  130.        else
  131.          (void) system(s);
  132.        (void) free(s);
  133.       }
  134.      else
  135.       {
  136.        s = argv[narg];
  137.        argv[narg] = (char *) 0;
  138.        argv[-1] = cmd; /* This always works. Trust me. */
  139.        /* We haven't done anything with stdio, so no need to flush. */
  140. #ifdef VFORK
  141.        switch(vfork())
  142. #else
  143.        switch(fork())
  144. #endif
  145.         {
  146.          case -1: perror(applyforkfail);
  147.           (void) exit(1);
  148.          case 0: (void) execvp(cmd,argv - 1);
  149.              perror(applyexecfail);
  150.              (void) exit(0);
  151.          default: (void) wait((int *) 0);
  152.         }
  153.        argv[narg] = s;
  154.       }
  155.     }
  156.    else /* nesc > 0 */
  157.     {
  158.      i = nch + 1;
  159.      s = cmd;
  160.      while (*s)
  161.        if (*(s++) == escape)
  162.     {
  163.          if (!*s)
  164.            break;
  165.      switch(*s)
  166.       {
  167.        case '0': s++; break;
  168. #define SSN(k,j) case k: i += strlen(argv[j]); s++; break;
  169.        /* omit 0 */ SSN('1',0); SSN('2',1); SSN('3',2); SSN('4',3);
  170.        SSN('5',4);  SSN('6',5); SSN('7',6); SSN('8',7); SSN('9',8);
  171.        default: i += 1; s++; break;
  172.       }
  173.     }
  174.  
  175.      t = malloc((unsigned) i);
  176.      if (!t)
  177.       {
  178.        (void) fprintf(stderr,applymalloc);
  179.        (void) exit(1);
  180.       }
  181.      s = cmd;
  182.      while (*s)
  183.        if (*s != escape)
  184.      *(t++) = *(s++);
  185.        else
  186.         {
  187.          if (!*++s)
  188.            break;
  189.      switch(*s)
  190.       {
  191.        case '0': s++; break;
  192. #define ISN(i,j) case i:(void)strcpy(t,argv[j]);t+=strlen(argv[j]);s++;break;
  193.        /* omit 0 */ ISN('1',0); ISN('2',1); ISN('3',2); ISN('4',3);
  194.        ISN('5',4);  ISN('6',5); ISN('7',6); ISN('8',7); ISN('9',8);
  195.        default: *(t++) = *(s++); break;
  196.       }
  197.         }
  198.      *(t++) = '\0';
  199.      t -= i;
  200.      switch(flagsystem)
  201.       {
  202.        case 0: i = 1;
  203.            for (s = t;*s;s++)
  204.          i += (*s == ' ');
  205.            a = (char **) malloc((unsigned) (sizeof(char *) * i));
  206.                if (!a)
  207.             {
  208.              (void) fprintf(stderr,applymalloc);
  209.              (void) exit(1);
  210.             }
  211.            for (s = a[i = 0] = t;*s;s++)
  212.          if (*s == ' ')
  213.            a[a[i] == s ? i : ++i] = s + 1;
  214.            a[a[i] == s ? i : ++i] = (char *) 0;
  215. #ifdef VFORK
  216.                switch(vfork())
  217. #else
  218.                switch(fork())
  219. #endif
  220.                 {
  221.                  case -1: perror(applyforkfail);
  222.                   (void) exit(1);
  223.                  case 0: (void) execvp(*a,a);
  224.                      perror(applyexecfail);
  225.                      (void) exit(0);
  226.                  default: (void) wait((int *) 0);
  227.                 }
  228.            (void) free((char *) a);
  229.            break;
  230.        case 1: (void) system(t); break;
  231.        case 2: (void) puts(t); break;
  232.       }
  233.      (void) free(t);
  234.     }
  235.    argv += narg + !narg; argc -= narg + !narg;
  236.   }
  237.  
  238.  (void) exit(0);
  239. }
  240.