home *** CD-ROM | disk | FTP | other *** search
- #include <sys/types.h> /* for wait and fork */
- #include <sys/wait.h> /* for wait */
- #include <stdio.h> /* for EOF, fprintf, puts */
- #include <malloc.h> /* for malloc and free */
- #include <strings.h> /* for strlen and strcpy */
- #include "getopt.h" /*XXX: should be <getopt.h> */
- /* XXX: What about system(), exit(), perror()? */
- /* XXX: Shouldn't do repeated malloc-free. Figure out the largest block */
- /* size needed, allocate it once, and use it repeatedly. */
- /* XXX: Maybe option to quote arguments under flagsystem? */
- /* XXX: Or just allow spaces within arguments inside command? */
- /* XXX: The number of separate command parsers in here is ridiculous. */
-
- static char applyusage[] = "Usage: apply [ -ac ] [ -n ] cmd arg ...\n";
- static char applytoomany[] = "apply: warning: extra arguments\n";
- static char applyforkfail[] = "apply: fatal: cannot fork";
- static char applyexecfail[] = "apply: fatal: cannot exec";
- static char applymalloc[] = "apply: fatal: cannot malloc\n";
-
- main(argc,argv)
- int argc;
- char *argv[];
- {
- register char *s;
- register char *t;
- register char **a;
- register int i;
- register int j;
- register char *cmd;
- register int flagsystem = 0;
- register int narg = 1;
- register int nch = 0;
- register int nesc = 0;
- register char escape = '%';
- register int opt;
-
- while ((opt = getopt(argc,argv,"0123456789a:s")) != EOF)
- switch(opt)
- {
- case '?': (void) fprintf(stderr,applyusage);
- (void) exit(1);
- case 'a': escape = *optarg; break; /* can't be null */
- case 's': flagsystem = 2; break;
- #define OSN(i,j) case i: narg = j; break;
- OSN('0',0) OSN('1',1) OSN('2',2) OSN('3',3) OSN('4',4)
- OSN('5',5) OSN('6',6) OSN('7',7) OSN('8',8) OSN('9',9)
- }
- argv += optind, argc -= optind;
-
- if (!*argv)
- {
- (void) fprintf(stderr,applyusage);
- (void) exit(1);
- }
-
- /* Note that we accept %0, and do the same with it as with -0. */
- s = *argv;
- while (*s)
- if (*(s++) != escape)
- nch++;
- else
- {
- if (!*s)
- { flagsystem = (!flagsystem ? 1 : flagsystem); break; }
- switch(*(s++))
- {
- #define TSN(i,j) case i: narg=(nesc++?(narg>j?narg:j):j); break;
- TSN('0',0) TSN('1',1) TSN('2',2) TSN('3',3) TSN('4',4)
- TSN('5',5) TSN('6',6) TSN('7',7) TSN('8',8) TSN('9',9)
- default: nch++; break;
- }
- }
-
- /* Now the number of real characters is nch. */
- /* The number of escape characters is nesc. */
- /* If flagsystem is 1, we should use sh. */
- /* And we should snarf narg args per cmd, plus waste one if !narg. */
-
- if (!nesc)
- {
- t = cmd = malloc((unsigned) (nch + 1));
- s = *argv;
- while (*s)
- if (*s != escape)
- *(t++) = *(s++);
- else
- {
- if (!*++s)
- break;
- switch(*s)
- {
- case 'e': *(t++) = escape; s++; break;
- default: *(t++) = *(s++); break;
- }
- }
- *t = '\0';
- }
- else
- cmd = *argv;
-
- argc--; argv++;
- /* XXX: Should something be done to prevent zombies? */
-
- if (narg && (argc % narg))
- (void) fprintf(stderr,applytoomany);
- while (argc >= narg + !narg)
- {
- if (!nesc)
- {
- if (flagsystem)
- {
- i = nch + narg + !narg;
- for (j = 0;j < narg;j++)
- i += strlen(argv[j]);
- t = s = malloc((unsigned) i);
- if (!t)
- {
- (void) fprintf(stderr,applymalloc);
- (void) exit(1);
- }
- (void) strcpy(t,cmd); t += strlen(cmd); *(t++) = ' ';
- for (j = 0;j < narg;j++)
- {
- (void) strcpy(t,argv[j]); t += strlen(argv[j]); *(t++) = ' ';
- }
- *t = '\0';
- /* slow? whaddya mean, slow? three passes is nothing! */
- if (flagsystem == 2)
- (void) puts(s);
- else
- (void) system(s);
- (void) free(s);
- }
- else
- {
- s = argv[narg];
- argv[narg] = (char *) 0;
- argv[-1] = cmd; /* This always works. Trust me. */
- /* We haven't done anything with stdio, so no need to flush. */
- #ifdef VFORK
- switch(vfork())
- #else
- switch(fork())
- #endif
- {
- case -1: perror(applyforkfail);
- (void) exit(1);
- case 0: (void) execvp(cmd,argv - 1);
- perror(applyexecfail);
- (void) exit(0);
- default: (void) wait((int *) 0);
- }
- argv[narg] = s;
- }
- }
- else /* nesc > 0 */
- {
- i = nch + 1;
- s = cmd;
- while (*s)
- if (*(s++) == escape)
- {
- if (!*s)
- break;
- switch(*s)
- {
- case '0': s++; break;
- #define SSN(k,j) case k: i += strlen(argv[j]); s++; break;
- /* omit 0 */ SSN('1',0); SSN('2',1); SSN('3',2); SSN('4',3);
- SSN('5',4); SSN('6',5); SSN('7',6); SSN('8',7); SSN('9',8);
- default: i += 1; s++; break;
- }
- }
-
- t = malloc((unsigned) i);
- if (!t)
- {
- (void) fprintf(stderr,applymalloc);
- (void) exit(1);
- }
- s = cmd;
- while (*s)
- if (*s != escape)
- *(t++) = *(s++);
- else
- {
- if (!*++s)
- break;
- switch(*s)
- {
- case '0': s++; break;
- #define ISN(i,j) case i:(void)strcpy(t,argv[j]);t+=strlen(argv[j]);s++;break;
- /* omit 0 */ ISN('1',0); ISN('2',1); ISN('3',2); ISN('4',3);
- ISN('5',4); ISN('6',5); ISN('7',6); ISN('8',7); ISN('9',8);
- default: *(t++) = *(s++); break;
- }
- }
- *(t++) = '\0';
- t -= i;
- switch(flagsystem)
- {
- case 0: i = 1;
- for (s = t;*s;s++)
- i += (*s == ' ');
- a = (char **) malloc((unsigned) (sizeof(char *) * i));
- if (!a)
- {
- (void) fprintf(stderr,applymalloc);
- (void) exit(1);
- }
- for (s = a[i = 0] = t;*s;s++)
- if (*s == ' ')
- a[a[i] == s ? i : ++i] = s + 1;
- a[a[i] == s ? i : ++i] = (char *) 0;
- #ifdef VFORK
- switch(vfork())
- #else
- switch(fork())
- #endif
- {
- case -1: perror(applyforkfail);
- (void) exit(1);
- case 0: (void) execvp(*a,a);
- perror(applyexecfail);
- (void) exit(0);
- default: (void) wait((int *) 0);
- }
- (void) free((char *) a);
- break;
- case 1: (void) system(t); break;
- case 2: (void) puts(t); break;
- }
- (void) free(t);
- }
- argv += narg + !narg; argc -= narg + !narg;
- }
-
- (void) exit(0);
- }
-