mark@infopiz.uucp (02/19/90)
+-+-+-+ Beginning of part 2 +-+-+-+ X char `009`009*out = NULL;`009/* Output File Name`009 */ X char `009`009*outmode = "w";`009/* Mode to Open Output File */ X int`009`009`009cmargc = 0; `009/* Piped Command Arg Count */ X char`009`009**cmargv = NULL;/* Piped Command Arg Vector */ X X /* X * First handle the case where the last thing on the line ends with X * a '&'. This indicates the desire for the command to be run in a X * subprocess, so we satisfy that desire. X */ X ap = argv[argc-1]; X if (0 == strcmp("&", ap)) X`009exit(background_process(--argc, argv)); X if ('&' == ap[strlen(ap)-1]) X`009`123 X`009ap[strlen(ap)-1] = '\0'; X`009exit(background_process(argc, argv)); X`009`125 X /* X * Now we handle the general redirection cases that involve '>', '>>', X * '<', and pipes '`124'. X */ X for (j = 0; j < argc; ++j) X`009`123 X`009if (0 == strcmp("<", argv[j])) X`009 `123 X`009 if (j+1 >= argc) X`009`009`123 X`009`009errno = EINVAL; X`009`009perror("No input file"); X`009`009exit(EXIT_ERR); X`009`009`125 X`009 in = argv[++j]; X`009 continue; X`009 `125 X`009if ('<' == *(ap = argv[j])) X`009 `123 X`009 in = 1 + ap; X`009 continue; X`009 `125 X`009if (0 == strcmp(">", ap)) X`009 `123 X`009 if (j+1 >= argc) X`009`009`123 X`009`009errno = EINVAL; X`009`009perror("No output file"); X`009`009exit(EXIT_ERR); X`009`009`125 X`009 out = argv[++j]; X`009 continue; X`009 `125 X`009if ('>' == *ap) X`009 `123 X`009 if ('>' == ap[1]) X`009`009`123 X`009`009outmode = "a"; X`009`009if ('\0' == ap[2]) X`009`009 out = argv[++j]; X`009`009else X`009`009 out = 2 + ap; X`009`009`125 X`009 else X`009`009out = 1 + ap; X`009 continue; X`009 `125 X`009if (0 == strcmp("`124", argv[j])) X`009 `123 X`009 if (j+1 >= argc) X`009`009`123 X`009`009errno = EPIPE; X`009`009perror("No command to Pipe to"); X`009`009exit(EXIT_ERR); X`009`009`125 X`009 cmargc = argc-(j+1); X`009 cmargv = &argv[j+1]; X`009 argc = j; X`009 continue; X`009 `125 X`009if ('`124' == *(ap = argv[j])) X`009 `123 X`009 ++argv[j]; X`009 cmargc = argc-j; X`009 cmargv = &argv[j]; X`009 argc = j; X`009 continue; X`009 `125 X`009expand_wild_cards(ap, &list_head, &list_tail, &item_count); X`009`125 X /* X * Allocate and fill in the new argument vector, Some Unix's terminate X * the list with an extra null pointer. X */ X argv = *av = calloc(item_count+1, sizeof(char *)); X for (j = 0; j < item_count; ++j, list_head = list_head->next) X`009argv[j] = list_head->value; X *ac = item_count; X if (cmargv != NULL) X`009`123 X`009char subcmd[1024]; X`009static char *pipe_and_fork(); X X`009if (out != NULL) X`009 `123 X`009 errno = EINVAL; X`009 perror("Invalid '`124' and '>' specified"); X`009 exit(EXIT_ERR); X`009 `125 X`009strcpy(subcmd, cmargv[0]); X`009for (j = 1; j < cmargc; ++j) X`009 `123 X`009 strcat(subcmd, " \""); X`009 strcat(subcmd, cmargv[j]); X`009 strcat(subcmd, "\""); X`009 `125 X`009out = pipe_and_fork(subcmd); X`009`125 X if ((in != NULL) && (NULL == freopen(in, "r", stdin, "mbc=32", "mbf=2"))) X`009`123 X`009perror(in); `009 `009/* Can't find file`009`009*/ X`009exit(EXIT_ERR);`009`009/* Is a fatal error`009`009*/ X`009`125 V if ((out != NULL) && (NULL == freopen(out, outmode, stdout, "mbc=32", "mbf= X2"))) X`009`123`009 X`009perror(ap);`009`009/* Error, can't write or append`009*/ X`009exit(EXIT_ERR);`009`009/* Is a fatal error`009`009*/ X`009`125 X#ifdef DEBUG X fprintf(stderr, "Arglist:\n"); X for (j = 0; j < *ac; ++j) X`009fprintf(stderr, "argv[%d] = '%s'\n", j, argv[j]); X#endif X`125 X Xstatic add_item(head, tail, value, count) Xstruct list_item **head; Xstruct list_item **tail; Xchar *value; Xint *count; X`123 X if (*head == 0) X`009`123 X`009if (NULL == (*head = calloc(1, sizeof(**head)))) X`009 `123 X`009 errno = ENOMEM; X`009 perror(""); X`009 exit(EXIT_ERR); X`009 `125 X`009*tail = *head; X`009`125 X else X`009if (NULL == ((*tail)->next = calloc(1, sizeof(**head)))) X`009 `123 X`009 errno = ENOMEM; X`009 perror(""); X`009 exit(EXIT_ERR); X`009 `125 X`009else X`009 *tail = (*tail)->next; X (*tail)->value = value; X ++(*count); X`125 X Xstatic expand_wild_cards(item, head, tail, count) Xchar *item; Xstruct ltem_list **head; Xstruct ltem_list **tail; Xint *count; X`123 Xint expcount = 0; Xint context = 0; Xint status; Xint status_value; Xint had_version; X$DESCRIPTOR(filespec, item); X$DESCRIPTOR(defaultspec, "SYS$DISK:[]*.*;"); X$DESCRIPTOR(resultspec, ""); X X if (strcspn(item, "*%") == strlen(item)) X`009`123 X`009add_item(head, tail, item, count); X`009return; X`009`125 X resultspec.dsc$b_dtype = DSC$K_DTYPE_T; X resultspec.dsc$b_class = DSC$K_CLASS_D; X resultspec.dsc$a_pointer = NULL; X filespec.dsc$w_length = strlen(item); X /* X * Only return version specs, if the caller specified a version X */ X had_version = strchr(item, ';'); X while (1 == (1&lib$find_file(&filespec, &resultspec, &context, X `009`009`009`009 &defaultspec, 0, &status_value, &0))) X`009`123 X`009char *string; X`009char *c; X X`009if (NULL == (string = calloc(1, resultspec.dsc$w_length+1))) X`009 `123 X`009 errno = ENOMEM; X`009 perror(""); X`009 exit(EXIT_ERR); X`009 `125 X`009strncpy(string, resultspec.dsc$a_pointer, resultspec.dsc$w_length); X`009string[resultspec.dsc$w_length] = '\0'; X`009if (NULL == had_version) X`009 *((char *)strrchr(string, ';')) = '\0'; X`009/* X`009 * Be consistent with what the C RTL has already done to the rest of X`009 * the argv items and lowercase all of these names. X`009 */ X`009for (c = string; *c; ++c) X`009 if (isupper(*c)) X`009`009*c = tolower(*c); X`009add_item(head, tail, string, count); X`009++expcount; X`009`125 X if (expcount == 0) X`009add_item(head, tail, item, count); X lib$sfree1_dd(&resultspec); X lib$find_file_end(&context); X`125 X Xstatic int child_st[2];`009/* Event Flag set when child process completes`009*/ X Xstatic short child_chan;/* I/O Channel for Pipe Mailbox`009`009`009*/ X Xstatic exit_handler(status) Xint *status; X`123 Xshort iosb[4]; X X if (0 == child_st[0]) X`009`123 X#ifdef DEBUG X`009fprintf(stderr, "Waiting for Child Process to Finnish . . .\n"); X#endif X`009sys$qiow(0, child_chan, IO$_WRITEOF, iosb, 0, 0, 0, 0, 0, 0, 0, 0); X`009sys$dassgn(child_chan); X`009fclose(stdout); X`009sys$synch(0, child_st); X`009`125 X`125 X X#include syidef`009`009/* System Information Definitions`009*/ X Xstatic sig_child(chan) Xint chan; X`123 X#ifdef DEBUG X fprintf(stderr, "Child Completion AST\n"); X#endif X if (child_st[0] == 0) X`009child_st[0] = 1; X`125 X Xstatic struct exit_control_block X `123 X struct exit_control_block *flink; X int`009(*exit_routine)(); X int arg_count; X int *status_address; X int exit_status; X `125 exit_block = X `123 X 0, X exit_handler, X 1, X &exit_block.exit_status, X 0 X `125; X Xstatic char *pipe_and_fork(cmd) Xchar *cmd; X`123 X $DESCRIPTOR(cmddsc, cmd); X static char mbxname[64]; X $DESCRIPTOR(mbxdsc, mbxname); X short iosb[4]; X int status; X int pid; X struct X`009`123 X`009short dna_buflen; X`009short dna_itmcod; X`009char *dna_buffer; X`009short *dna_retlen; X`009int listend; X`009`125 itmlst = X`009`123 X`009sizeof(mbxname), X`009DVI$_DEVNAM, X`009mbxname, X`009&mbxdsc.dsc$w_length, X`0090 X`009`125; X int mbxsize; X struct X`009`123 X`009short mbf_buflen; X`009short mbf_itmcod; X`009int *mbf_maxbuf; X`009short *mbf_retlen; X`009int listend; X`009`125 syiitmlst = X`009`123 X`009sizeof(mbxsize), X`009SYI$_MAXBUF, X`009&mbxsize, X`0090, X`0090 X`009`125; X X cmddsc.dsc$w_length = strlen(cmd); X /* X * Get the SYSGEN parameter MAXBUF, and the smaller of it and 2048 as X * the size of the 'pipe' mailbox. X */ V if (1 == (1&(vaxc$errno = sys$getsyiw(0, 0, 0, &syiitmlst, iosb, 0, 0, 0))) X) X`009vaxc$errno = iosb[0]; X if (0 == (1&vaxc$errno)) X`009`123 X `009errno = EVMSERR; X`009perror("Can't get SYSGEN parameter value for MAXBUF"); X`009exit(EXIT_ERR); X`009`125 X if (mbxsize > 2048) X`009mbxsize = 2048; V if (0 == (1&(vaxc$errno = sys$crembx(0, &child_chan, mbxsize, mbxsize, 0, 0 X, 0)))) X`009`123 X`009errno = EVMSERR; X`009perror("Can't create pipe mailbox"); X`009exit(EXIT_ERR); X`009`125 X if (1 == (1&(vaxc$errno = sys$getdviw(0, child_chan, 0, &itmlst, iosb, X `009`009`009`009`009 0, 0, 0)))) X`009vaxc$errno = iosb[0]; X if (0 == (1&vaxc$errno)) X`009`123 X `009errno = EVMSERR; X`009perror("Can't get pipe mailbox device name"); X`009exit(EXIT_ERR); X`009`125 X mbxname[mbxdsc.dsc$w_length] = '\0'; X#ifdef DEBUG X fprintf(stderr, "Pipe Mailbox Name = '%s'\n", mbxname); X#endif X if (0 == (1&(vaxc$errno = lib$spawn(&cmddsc, &mbxdsc, 0, &1, X `009`009`009`009`0090, &pid, child_st, &0, sig_child, X `009`009`009`009`009&child_chan)))) X`009`123 X`009errno = EVMSERR; X`009perror("Can't spawn subprocess"); X`009exit(EXIT_ERR); X`009`125 X#ifdef DEBUG X fprintf(stderr, "Subprocess's Pid = %08X\n", pid); X#endif X sys$dclexh(&exit_block); X return(mbxname); X`125 X Xbackground_process(argc, argv) Xint argc; Xchar **argv; X`123 Xchar command[2048] = "$"; X$DESCRIPTOR(value, command); X$DESCRIPTOR(cmd, "BACKGROUND$COMMAND"); X$DESCRIPTOR(null, "NLA0:"); Xint pid; X X strcat(command, argv[0]); X while (--argc) X`009`123 X`009strcat(command, " \""); X`009strcat(command, *(++argv)); X`009strcat(command, "\""); X`009`125 X value.dsc$w_length = strlen(command); X if (0 == (1&(vaxc$errno = lib$set_symbol(&cmd, &value)))) X`009`123 X`009errno = EVMSERR; X`009perror("Can't create symbol for subprocess command"); X`009exit(EXIT_ERR); X`009`125 X if (0 == (1&(vaxc$errno = lib$spawn(&cmd, &null, 0, &17, 0, &pid)))) X`009`123 X`009errno = EVMSERR; X`009perror("Can't spawn subprocess"); X`009exit(EXIT_ERR); X`009`125 X#ifdef DEBUG X fprintf(stderr, "%s\n", command); X#endif X fprintf(stderr, "%08X\n", pid); X return(EXIT_OK); X`125 X`012 X/* got this off net.sources */ X X#ifdef`009VMS X#define`009index`009strchr X#endif`009/*VMS*/ X X/* X * get option letter from argument vector X */ Xint`009opterr = 1,`009`009/* useless, never set or used */ X`009optind = 1,`009`009/* index into parent argv vector */ X`009optopt;`009`009`009/* character checked for validity */ Xchar`009*optarg;`009`009/* argument associated with option */ X X#define BADCH`009(int)'?' X#define EMSG`009"" X#define tell(s)`009fputs(*nargv,stderr);fputs(s,stderr); \ X`009`009fputc(optopt,stderr);fputc('\n',stderr);return(BADCH); X Xgetopt(nargc,nargv,ostr) Xint`009nargc; Xchar`009**nargv, X`009*ostr; X`123 X`009static char`009*place = EMSG;`009/* option letter processing */ X`009register char`009*oli;`009`009/* option letter list index */ X`009char`009*index(); X X`009if(!*place) `123`009`009`009/* update scanning pointer */ V`009`009if(optind >= nargc `124`124 *(place = nargv[optind]) != '-' `124`124 !* X++place) return(EOF); X`009`009if (*place == '-') `123`009/* found "--" */ X`009`009`009++optind; X`009`009`009return(EOF); X`009`009`125 X`009`125`009`009`009`009/* option letter okay? */ V`009if ((optopt = (int)*place++) == (int)':' `124`124 !(oli = index(ostr,optopt X))) `123 X`009`009if(!*place) ++optind; X`009`009tell(": illegal option -- "); X`009`125 X`009if (*++oli != ':') `123`009`009/* don't need argument */ X`009`009optarg = NULL; X`009`009if (!*place) ++optind; X`009`125 X`009else `123`009`009`009`009/* need an argument */ X`009`009if (*place) optarg = place;`009/* no white space */ X`009`009else if (nargc <= ++optind) `123`009/* no arg */ X`009`009`009place = EMSG; X`009`009`009tell(": option requires an argument -- "); X`009`009`125 X`009 `009else optarg = nargv[optind];`009/* white space */ X`009`009place = EMSG; X`009`009++optind; X`009`125 X`009return(optopt);`009`009`009/* dump back option letter */ X`125 $ GOSUB UNPACK_FILE $ EXIT -+-+-+-+-+ End of part 2 +-+-+-+-+-