Annotation of coherent/d/usr/bin/elvis/system.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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