|
|
1.1 ! root 1: /* system.c -- UNIX version */ ! 2: ! 3: /* Author: ! 4: * Steve Kirkendall ! 5: * 16820 SW Tallac Way ! 6: * Beaverton, OR 97006 ! 7: * [email protected], or ...uunet!tektronix!psueea!jove!kirkenda ! 8: */ ! 9: ! 10: ! 11: /* This file contains a new version of the system() function and related stuff. ! 12: * ! 13: * Entry points are: ! 14: * system(cmd) - run a single shell command ! 15: * wildcard(names) - expand wildcard characters in filanames ! 16: * filter(m,n,cmd) - run text lines through a filter program ! 17: * ! 18: * This is probably the single least portable file in the program. The code ! 19: * shown here should work correctly if it links at all; it will work on UNIX ! 20: * and any O.S./Compiler combination which adheres to UNIX forking conventions. ! 21: */ ! 22: ! 23: #include "config.h" ! 24: #include "vi.h" ! 25: #include <signal.h> ! 26: extern char **environ; ! 27: ! 28: #if ANY_UNIX ! 29: ! 30: /* This is a new version of the system() function. The only difference ! 31: * between this one and the library one is: this one uses the o_shell option. ! 32: */ ! 33: int system(cmd) ! 34: char *cmd; /* a command to run */ ! 35: { ! 36: int status; /* exit status of the command */ ! 37: ! 38: /* warn the user if the file hasn't been saved yet */ ! 39: if (*o_warn && tstflag(file, MODIFIED)) ! 40: { ! 41: if (mode == MODE_VI) ! 42: { ! 43: mode = MODE_COLON; ! 44: } ! 45: msg("Warning: \"%s\" has been modified but not yet saved", origname); ! 46: } ! 47: ! 48: signal(SIGINT, SIG_IGN); ! 49: switch (fork()) ! 50: { ! 51: case -1: /* error */ ! 52: msg("fork() failed"); ! 53: status = -1; ! 54: break; ! 55: ! 56: case 0: /* child */ ! 57: /* for the child, close all files except stdin/out/err */ ! 58: for (status = 3; status < 60 && (close(status), errno != EINVAL); status++) ! 59: { ! 60: } ! 61: ! 62: signal(SIGINT, SIG_DFL); ! 63: if (cmd == o_shell) ! 64: { ! 65: execle(o_shell, o_shell, (char *)0, environ); ! 66: } ! 67: else ! 68: { ! 69: execle(o_shell, o_shell, "-c", cmd, (char *)0, environ); ! 70: } ! 71: msg("execle(\"%s\", ...) failed", o_shell); ! 72: exit(1); /* if we get here, the exec failed */ ! 73: ! 74: default: /* parent */ ! 75: wait(&status); ! 76: signal(SIGINT, trapint); ! 77: } ! 78: ! 79: return status; ! 80: } ! 81: ! 82: /* This private function opens a pipe from a filter. It is similar to the ! 83: * system() function above, and to popen(cmd, "r"). ! 84: */ ! 85: static int rpipe(cmd, in) ! 86: char *cmd; /* the filter command to use */ ! 87: int in; /* the fd to use for stdin */ ! 88: { ! 89: int r0w1[2];/* the pipe fd's */ ! 90: ! 91: /* make the pipe */ ! 92: if (pipe(r0w1) < 0) ! 93: { ! 94: return -1; /* pipe failed */ ! 95: } ! 96: ! 97: /* The parent process (elvis) ignores signals while the filter runs. ! 98: * The child (the filter program) will reset this, so that it can ! 99: * catch the signal. ! 100: */ ! 101: signal(SIGINT, SIG_IGN); ! 102: ! 103: switch (fork()) ! 104: { ! 105: case -1: /* error */ ! 106: return -1; ! 107: ! 108: case 0: /* child */ ! 109: /* close the "read" end of the pipe */ ! 110: close(r0w1[0]); ! 111: ! 112: /* redirect stdout to go to the "write" end of the pipe */ ! 113: close(1); ! 114: dup(r0w1[1]); ! 115: close(2); ! 116: dup(r0w1[1]); ! 117: close(r0w1[1]); ! 118: ! 119: /* redirect stdin */ ! 120: if (in != 0) ! 121: { ! 122: close(0); ! 123: dup(in); ! 124: close(in); ! 125: } ! 126: ! 127: /* the filter should accept SIGINT signals */ ! 128: signal(SIGINT, SIG_DFL); ! 129: ! 130: /* exec the shell to run the command */ ! 131: execle(o_shell, o_shell, "-c", cmd, (char *)0, environ); ! 132: exit(1); /* if we get here, exec failed */ ! 133: ! 134: default: /* parent */ ! 135: /* close the "write" end of the pipe */ ! 136: close(r0w1[1]); ! 137: ! 138: return r0w1[0]; ! 139: } ! 140: } ! 141: ! 142: #endif /* non-DOS */ ! 143: ! 144: #if OSK ! 145: ! 146: /* This private function opens a pipe from a filter. It is similar to the ! 147: * system() function above, and to popen(cmd, "r"). ! 148: */ ! 149: static int rpipe(cmd, in) ! 150: char *cmd; /* the filter command to use */ ! 151: int in; /* the fd to use for stdin */ ! 152: { ! 153: ! 154: char **argblk; ! 155: char *p, *buffer, *command; ! 156: int stdinp, stdoutp; ! 157: unsigned addstack = 0; ! 158: int words, len, loop = 1; ! 159: int fp, pipe_pid; ! 160: extern int os9forkc(); ! 161: extern char *index(); ! 162: ! 163: command = cmd; ! 164: words = 0; ! 165: if ((buffer = (char*) malloc(strlen(cmd))) == (char*) 0) ! 166: return 0; ! 167: ! 168: do { ! 169: if (!(p = index(command, ' '))) { ! 170: loop--; ! 171: len = strlen(command); ! 172: } ! 173: else ! 174: len = p - command; ! 175: words++; ! 176: while (command[len] && command[len] == ' ') ! 177: len++; ! 178: if (!command[len]) ! 179: break; ! 180: command = command + len; ! 181: } ! 182: while (loop); ! 183: if ((argblk = (char **)malloc((words+1) * sizeof(char*))) == (char **)0) ! 184: return 0; ! 185: command = cmd; ! 186: words = 0; ! 187: do { ! 188: if (!(p = index(command, ' '))) { ! 189: loop--; ! 190: len = strlen(command); ! 191: } ! 192: else ! 193: len = p - command; ! 194: strncpy(buffer, command, len); ! 195: argblk[words++] = buffer; ! 196: buffer += len; ! 197: *buffer++ = '\0'; ! 198: while (command[len] && command[len] == ' ') ! 199: len++; ! 200: if (!command[len]) ! 201: break; ! 202: command = command + len; ! 203: } while (loop); ! 204: if (argblk[words - 1][0] == '#') ! 205: addstack = 1024 * atoi(&argblk[--words][1]); ! 206: argblk[words] = 0; ! 207: ! 208: stdoutp = dup(1); ! 209: close(1); /* close stdout */ ! 210: if ((fp = open("/pipe",S_IREAD)) < 0) { ! 211: dup(stdoutp); ! 212: close(stdoutp); ! 213: return 0; ! 214: } ! 215: if (in != 0) { ! 216: stdinp = dup(0); ! 217: close(0); ! 218: dup(in); ! 219: close(in); ! 220: } ! 221: pipe_pid = os9exec(os9forkc,argblk[0],argblk,environ,addstack,0,3); ! 222: if (pipe_pid == -1) { ! 223: fclose(fp); ! 224: dup(stdoutp); ! 225: close(stdoutp); ! 226: if (in != 0) { ! 227: close(0); ! 228: dup(stdinp); ! 229: } ! 230: return 0; ! 231: } ! 232: fp = (short)dup(1); /* save pipe */ ! 233: close(1); /* get rid of the pipe */ ! 234: dup(stdoutp); /* restore old stdout */ ! 235: close(stdoutp); /* close path to stdout copy */ ! 236: if (in != 0) { ! 237: close(0); ! 238: dup(stdinp); ! 239: } ! 240: return fp; ! 241: } ! 242: #endif ! 243: ! 244: #if ANY_UNIX || OSK ! 245: ! 246: /* This function closes the pipe opened by rpipe(), and returns 0 for success */ ! 247: static int rpclose(fd) ! 248: int fd; ! 249: { ! 250: int status; ! 251: ! 252: close(fd); ! 253: wait(&status); ! 254: signal(SIGINT, trapint); ! 255: return status; ! 256: } ! 257: ! 258: #endif /* non-DOS */ ! 259: ! 260: /* This function expands wildcards in a filename or filenames. It does this ! 261: * by running the "echo" command on the filenames via the shell; it is assumed ! 262: * that the shell will expand the names for you. If for any reason it can't ! 263: * run echo, then it returns the names unmodified. ! 264: */ ! 265: ! 266: #if MSDOS || TOS ! 267: #define PROG "wildcard " ! 268: #define PROGLEN 9 ! 269: #include <string.h> ! 270: #else ! 271: #define PROG "echo " ! 272: #define PROGLEN 5 ! 273: #endif ! 274: ! 275: char *wildcard(names) ! 276: char *names; ! 277: { ! 278: int i, j, fd; ! 279: REG char *s, *d; ! 280: ! 281: ! 282: /* build the echo command */ ! 283: if (names != tmpblk.c) ! 284: { ! 285: /* the names aren't in tmpblk.c, so we can do it the easy way */ ! 286: strcpy(tmpblk.c, PROG); ! 287: strcat(tmpblk.c, names); ! 288: } ! 289: else ! 290: { ! 291: /* the names are already in tmpblk.c, so shift them to make ! 292: * room for the word "echo " ! 293: */ ! 294: for (s = names + strlen(names) + 1, d = s + PROGLEN; s > names; ) ! 295: { ! 296: *--d = *--s; ! 297: } ! 298: strncpy(names, PROG, PROGLEN); ! 299: } ! 300: ! 301: /* run the command & read the resulting names */ ! 302: fd = rpipe(tmpblk.c, 0); ! 303: if (fd < 0) return names; ! 304: i = 0; ! 305: do ! 306: { ! 307: j = tread(fd, tmpblk.c + i, BLKSIZE - i); ! 308: i += j; ! 309: } while (j > 0); ! 310: ! 311: /* successful? */ ! 312: if (rpclose(fd) == 0 && j == 0 && i < BLKSIZE && i > 0) ! 313: { ! 314: tmpblk.c[i-1] = '\0'; /* "i-1" so we clip off the newline */ ! 315: return tmpblk.c; ! 316: } ! 317: else ! 318: { ! 319: return names; ! 320: } ! 321: } ! 322: ! 323: /* This function runs a range of lines through a filter program, and replaces ! 324: * the original text with the filtered version. As a special case, if "to" ! 325: * is MARK_UNSET, then it runs the filter program with stdin coming from ! 326: * /dev/null, and inserts any output lines. ! 327: */ ! 328: int filter(from, to, cmd) ! 329: MARK from, to; /* the range of lines to filter */ ! 330: char *cmd; /* the filter command */ ! 331: { ! 332: int scratch; /* fd of the scratch file */ ! 333: int fd; /* fd of the pipe from the filter */ ! 334: char scrout[50]; /* name of the scratch out file */ ! 335: MARK new; /* place where new text should go */ ! 336: int i; ! 337: ! 338: /* write the lines (if specified) to a temp file */ ! 339: if (to) ! 340: { ! 341: /* we have lines */ ! 342: #if MSDOS || TOS ! 343: strcpy(scrout, o_directory); ! 344: if ((i=strlen(scrout)) && strchr("\\/:", scrout[i-1])) ! 345: scrout[i++]=SLASH; ! 346: strcpy(scrout+i, SCRATCHOUT+3); ! 347: #else ! 348: sprintf(scrout, SCRATCHOUT, o_directory); ! 349: #endif ! 350: mktemp(scrout); ! 351: cmd_write(from, to, CMD_BANG, 0, scrout); ! 352: ! 353: /* use those lines as stdin */ ! 354: scratch = open(scrout, O_RDONLY); ! 355: if (scratch < 0) ! 356: { ! 357: unlink(scrout); ! 358: return -1; ! 359: } ! 360: } ! 361: else ! 362: { ! 363: scratch = 0; ! 364: } ! 365: ! 366: /* start the filter program */ ! 367: fd = rpipe(cmd, scratch); ! 368: if (fd < 0) ! 369: { ! 370: if (to) ! 371: { ! 372: close(scratch); ! 373: unlink(scrout); ! 374: } ! 375: return -1; ! 376: } ! 377: ! 378: ChangeText ! 379: { ! 380: /* adjust MARKs for whole lines, and set "new" */ ! 381: from &= ~(BLKSIZE - 1); ! 382: if (to) ! 383: { ! 384: to &= ~(BLKSIZE - 1); ! 385: to += BLKSIZE; ! 386: new = to; ! 387: } ! 388: else ! 389: { ! 390: new = from + BLKSIZE; ! 391: } ! 392: ! 393: /* repeatedly read in new text and add it */ ! 394: while ((i = tread(fd, tmpblk.c, BLKSIZE - 1)) > 0) ! 395: { ! 396: tmpblk.c[i] = '\0'; ! 397: add(new, tmpblk.c); ! 398: for (i = 0; tmpblk.c[i]; i++) ! 399: { ! 400: if (tmpblk.c[i] == '\n') ! 401: { ! 402: new = (new & ~(BLKSIZE - 1)) + BLKSIZE; ! 403: } ! 404: else ! 405: { ! 406: new++; ! 407: } ! 408: } ! 409: } ! 410: } ! 411: ! 412: /* delete old text, if any */ ! 413: if (to) ! 414: { ! 415: delete(from, to); ! 416: } ! 417: ! 418: /* Reporting... */ ! 419: rptlabel = "more"; ! 420: if (rptlines < 0) ! 421: { ! 422: rptlines = -rptlines; ! 423: rptlabel = "less"; ! 424: } ! 425: ! 426: /* cleanup */ ! 427: rpclose(fd); ! 428: if (to) ! 429: { ! 430: close(scratch); ! 431: unlink(scrout); ! 432: } ! 433: return 0; ! 434: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.