Annotation of coherent/g/usr/bin/vi/system.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.