|
|
1.1 ! root 1: /* system.c -- UNIX version */ ! 2: ! 3: /* Author: ! 4: * Steve Kirkendall ! 5: * 14407 SW Teal Blvd. #C ! 6: * Beaverton, OR 97005 ! 7: * [email protected] ! 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,back) - 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: extern char **environ; ! 26: ! 27: #if ANY_UNIX ! 28: ! 29: /* This is a new version of the system() function. The only difference ! 30: * between this one and the library one is: this one uses the o_shell option. ! 31: */ ! 32: int system(cmd) ! 33: #ifdef __STDC__ ! 34: const ! 35: #endif ! 36: char *cmd; /* a command to run */ ! 37: { ! 38: int pid; /* process ID of child */ ! 39: int died; ! 40: int status; /* exit status of the command */ ! 41: ! 42: ! 43: signal(SIGINT, SIG_IGN); ! 44: pid = fork(); ! 45: switch (pid) ! 46: { ! 47: case -1: /* error */ ! 48: msg("fork() failed"); ! 49: status = -1; ! 50: break; ! 51: ! 52: case 0: /* child */ ! 53: /* for the child, close all files except stdin/out/err */ ! 54: for (status = 3; status < 60 && (close(status), errno != EINVAL); status++) ! 55: { ! 56: } ! 57: ! 58: signal(SIGINT, SIG_DFL); ! 59: if (cmd == o_shell) ! 60: { ! 61: execle(o_shell, o_shell, (char *)0, environ); ! 62: } ! 63: else ! 64: { ! 65: execle(o_shell, o_shell, "-c", cmd, (char *)0, environ); ! 66: } ! 67: msg("execle(\"%s\", ...) failed", o_shell); ! 68: exit(1); /* if we get here, the exec failed */ ! 69: ! 70: default: /* parent */ ! 71: do ! 72: { ! 73: died = wait(&status); ! 74: } while (died >= 0 && died != pid); ! 75: if (died < 0) ! 76: { ! 77: status = -1; ! 78: } ! 79: #if __GNUC__ ! 80: signal(SIGINT, (void (*)()) trapint); ! 81: #else ! 82: signal(SIGINT, trapint); ! 83: #endif ! 84: } ! 85: ! 86: return status; ! 87: } ! 88: ! 89: /* This private function opens a pipe from a filter. It is similar to the ! 90: * system() function above, and to popen(cmd, "r"). ! 91: */ ! 92: int rpipe(cmd, in) ! 93: char *cmd; /* the filter command to use */ ! 94: int in; /* the fd to use for stdin */ ! 95: { ! 96: int r0w1[2];/* the pipe fd's */ ! 97: ! 98: /* make the pipe */ ! 99: if (pipe(r0w1) < 0) ! 100: { ! 101: return -1; /* pipe failed */ ! 102: } ! 103: ! 104: /* The parent process (elvis) ignores signals while the filter runs. ! 105: * The child (the filter program) will reset this, so that it can ! 106: * catch the signal. ! 107: */ ! 108: signal(SIGINT, SIG_IGN); ! 109: ! 110: switch (fork()) ! 111: { ! 112: case -1: /* error */ ! 113: return -1; ! 114: ! 115: case 0: /* child */ ! 116: /* close the "read" end of the pipe */ ! 117: close(r0w1[0]); ! 118: ! 119: /* redirect stdout to go to the "write" end of the pipe */ ! 120: close(1); ! 121: dup(r0w1[1]); ! 122: close(2); ! 123: dup(r0w1[1]); ! 124: close(r0w1[1]); ! 125: ! 126: /* redirect stdin */ ! 127: if (in != 0) ! 128: { ! 129: close(0); ! 130: dup(in); ! 131: close(in); ! 132: } ! 133: ! 134: /* the filter should accept SIGINT signals */ ! 135: signal(SIGINT, SIG_DFL); ! 136: ! 137: /* exec the shell to run the command */ ! 138: execle(o_shell, o_shell, "-c", cmd, (char *)0, environ); ! 139: exit(1); /* if we get here, exec failed */ ! 140: ! 141: default: /* parent */ ! 142: /* close the "write" end of the pipe */ ! 143: close(r0w1[1]); ! 144: ! 145: return r0w1[0]; ! 146: } ! 147: } ! 148: ! 149: #endif /* non-DOS */ ! 150: ! 151: #if OSK ! 152: ! 153: /* This private function opens a pipe from a filter. It is similar to the ! 154: * system() function above, and to popen(cmd, "r"). ! 155: */ ! 156: int rpipe(cmd, in) ! 157: char *cmd; /* the filter command to use */ ! 158: int in; /* the fd to use for stdin */ ! 159: { ! 160: return osk_popen(cmd, "r", in, 0); ! 161: } ! 162: #endif ! 163: ! 164: #if ANY_UNIX || OSK ! 165: ! 166: /* This function closes the pipe opened by rpipe(), and returns 0 for success */ ! 167: int rpclose(fd) ! 168: int fd; ! 169: { ! 170: int status; ! 171: ! 172: close(fd); ! 173: wait(&status); ! 174: #if __GNUC__ ! 175: signal(SIGINT, (void (*)()) trapint); ! 176: #else ! 177: signal(SIGINT, trapint); ! 178: #endif ! 179: return status; ! 180: } ! 181: ! 182: #endif /* non-DOS */ ! 183: ! 184: /* This function expands wildcards in a filename or filenames. It does this ! 185: * by running the "echo" command on the filenames via the shell; it is assumed ! 186: * that the shell will expand the names for you. If for any reason it can't ! 187: * run echo, then it returns the names unmodified. ! 188: */ ! 189: ! 190: #if MSDOS || TOS ! 191: #define PROG "wildcard " ! 192: #define PROGLEN 9 ! 193: #include <string.h> ! 194: #else ! 195: #define PROG "echo " ! 196: #define PROGLEN 5 ! 197: #endif ! 198: ! 199: #if !AMIGA ! 200: char *wildcard(names) ! 201: char *names; ! 202: { ! 203: ! 204: # if VMS ! 205: /* ! 206: We could use expand() [vmswild.c], but what's the point on VMS? ! 207: Anyway, echo is the wrong thing to do, it takes too long to build ! 208: a subprocess on VMS and any "echo" program would have to be supplied ! 209: by elvis. More importantly, many VMS utilities expand names ! 210: themselves (the shell doesn't do any expansion) so the concept is ! 211: non-native. jdc ! 212: */ ! 213: return names; ! 214: # else ! 215: ! 216: int i, j, fd; ! 217: REG char *s, *d; ! 218: ! 219: ! 220: /* build the echo command */ ! 221: if (names != tmpblk.c) ! 222: { ! 223: /* the names aren't in tmpblk.c, so we can do it the easy way */ ! 224: strcpy(tmpblk.c, PROG); ! 225: strcat(tmpblk.c, names); ! 226: } ! 227: else ! 228: { ! 229: /* the names are already in tmpblk.c, so shift them to make ! 230: * room for the word "echo " ! 231: */ ! 232: for (s = names + strlen(names) + 1, d = s + PROGLEN; s > names; ) ! 233: { ! 234: *--d = *--s; ! 235: } ! 236: strncpy(names, PROG, PROGLEN); ! 237: } ! 238: ! 239: /* run the command & read the resulting names */ ! 240: fd = rpipe(tmpblk.c, 0); ! 241: if (fd < 0) return names; ! 242: i = 0; ! 243: do ! 244: { ! 245: j = tread(fd, tmpblk.c + i, BLKSIZE - i); ! 246: i += j; ! 247: } while (j > 0); ! 248: ! 249: /* successful? */ ! 250: if (rpclose(fd) == 0 && j == 0 && i < BLKSIZE && i > 0) ! 251: { ! 252: tmpblk.c[i-1] = '\0'; /* "i-1" so we clip off the newline */ ! 253: return tmpblk.c; ! 254: } ! 255: else ! 256: { ! 257: return names; ! 258: } ! 259: # endif ! 260: } ! 261: #endif ! 262: ! 263: /* This function runs a range of lines through a filter program, and replaces ! 264: * the original text with the filtered version. As a special case, if "to" ! 265: * is MARK_UNSET, then it runs the filter program with stdin coming from ! 266: * /dev/null, and inserts any output lines. ! 267: */ ! 268: int filter(from, to, cmd, back) ! 269: MARK from, to; /* the range of lines to filter */ ! 270: char *cmd; /* the filter command */ ! 271: int back; /* boolean: will we read lines back? */ ! 272: { ! 273: int scratch; /* fd of the scratch file */ ! 274: int fd; /* fd of the pipe from the filter */ ! 275: char scrout[50]; /* name of the scratch out file */ ! 276: MARK new; /* place where new text should go */ ! 277: long sent, rcvd; /* number of lines sent/received */ ! 278: int i, j; ! 279: ! 280: /* write the lines (if specified) to a temp file */ ! 281: if (to) ! 282: { ! 283: /* we have lines */ ! 284: #if MSDOS || TOS ! 285: strcpy(scrout, o_directory); ! 286: if ((i=strlen(scrout)) && !strchr("\\/:", scrout[i-1])) ! 287: scrout[i++]=SLASH; ! 288: strcpy(scrout+i, SCRATCHOUT+3); ! 289: #else ! 290: sprintf(scrout, SCRATCHOUT, o_directory); ! 291: #endif ! 292: mktemp(scrout); ! 293: cmd_write(from, to, CMD_BANG, FALSE, scrout); ! 294: sent = markline(to) - markline(from) + 1L; ! 295: ! 296: /* use those lines as stdin */ ! 297: scratch = open(scrout, O_RDONLY); ! 298: if (scratch < 0) ! 299: { ! 300: unlink(scrout); ! 301: return -1; ! 302: } ! 303: } ! 304: else ! 305: { ! 306: scratch = 0; ! 307: sent = 0L; ! 308: } ! 309: ! 310: /* start the filter program */ ! 311: #if VMS ! 312: /* ! 313: VMS doesn't know a thing about file descriptor 0. The rpipe ! 314: concept is non-portable. Hence we need a file name argument. ! 315: */ ! 316: fd = rpipe(cmd, scratch, scrout); ! 317: #else ! 318: fd = rpipe(cmd, scratch); ! 319: #endif ! 320: if (fd < 0) ! 321: { ! 322: if (to) ! 323: { ! 324: close(scratch); ! 325: unlink(scrout); ! 326: } ! 327: return -1; ! 328: } ! 329: ! 330: if (back) ! 331: { ! 332: ChangeText ! 333: { ! 334: /* adjust MARKs for whole lines, and set "new" */ ! 335: from &= ~(BLKSIZE - 1); ! 336: if (to) ! 337: { ! 338: to &= ~(BLKSIZE - 1); ! 339: to += BLKSIZE; ! 340: new = to; ! 341: } ! 342: else ! 343: { ! 344: new = from + BLKSIZE; ! 345: } ! 346: ! 347: #if VMS ! 348: /* Reading from a VMS mailbox (pipe) is record oriented... */ ! 349: # define tread vms_pread ! 350: #endif ! 351: ! 352: /* repeatedly read in new text and add it */ ! 353: rcvd = 0L; ! 354: while ((i = tread(fd, tmpblk.c, BLKSIZE - 1)) > 0) ! 355: { ! 356: tmpblk.c[i] = '\0'; ! 357: add(new, tmpblk.c); ! 358: #if VMS ! 359: /* What! An advantage to record oriented reads? */ ! 360: new += (i - 1); ! 361: new = (new & ~(BLKSIZE - 1)) + BLKSIZE; ! 362: rcvd++; ! 363: #else ! 364: for (i = 0; tmpblk.c[i]; i++) ! 365: { ! 366: if (tmpblk.c[i] == '\n') ! 367: { ! 368: new = (new & ~(BLKSIZE - 1)) + BLKSIZE; ! 369: rcvd++; ! 370: } ! 371: else ! 372: { ! 373: new++; ! 374: } ! 375: } ! 376: #endif ! 377: } ! 378: } ! 379: ! 380: /* delete old text, if any */ ! 381: if (to) ! 382: { ! 383: cut(from, to); ! 384: delete(from, to); ! 385: } ! 386: } ! 387: else ! 388: { ! 389: /* read the command's output, and copy it to the screen */ ! 390: while ((i = tread(fd, tmpblk.c, BLKSIZE - 1)) > 0) ! 391: { ! 392: for (j = 0; j < i; j++) ! 393: { ! 394: addch(tmpblk.c[j]); ! 395: } ! 396: } ! 397: rcvd = 0; ! 398: } ! 399: ! 400: /* Reporting... */ ! 401: if (sent >= *o_report || rcvd >= *o_report) ! 402: { ! 403: if (sent > 0L && rcvd > 0L) ! 404: { ! 405: msg("%ld lines out, %ld lines back", sent, rcvd); ! 406: } ! 407: else if (sent > 0) ! 408: { ! 409: msg("%ld lines written to filter", sent); ! 410: } ! 411: else ! 412: { ! 413: msg("%ld lines read from filter", rcvd); ! 414: } ! 415: } ! 416: rptlines = 0L; ! 417: ! 418: /* cleanup */ ! 419: rpclose(fd); ! 420: if (to) ! 421: { ! 422: close(scratch); ! 423: unlink(scrout); ! 424: } ! 425: return 0; ! 426: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.