[BACK]Return to lsystem.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / less

Annotation of src/usr.bin/less/lsystem.c, Revision 1.5

1.1       etheisen    1: /*
1.5     ! millert     2:  * Copyright (C) 1984-2002  Mark Nudelman
1.1       etheisen    3:  *
1.5     ! millert     4:  * You may distribute under the terms of either the GNU General Public
        !             5:  * License or the Less License, as specified in the README file.
1.1       etheisen    6:  *
1.5     ! millert     7:  * For more information about less, or for information on how to
        !             8:  * contact the author, see the README file.
1.1       etheisen    9:  */
                     10:
                     11:
                     12: /*
                     13:  * Routines to execute other programs.
                     14:  * Necessarily very OS dependent.
                     15:  */
                     16:
1.5     ! millert    17: #include "less.h"
1.1       etheisen   18: #include <signal.h>
                     19: #include "position.h"
                     20:
1.5     ! millert    21: #if MSDOS_COMPILER
1.1       etheisen   22: #include <dos.h>
1.5     ! millert    23: #ifdef _MSC_VER
        !            24: #include <direct.h>
        !            25: #define setdisk(n) _chdrive((n)+1)
        !            26: #else
        !            27: #include <dir.h>
        !            28: #endif
1.1       etheisen   29: #endif
                     30:
                     31: extern int screen_trashed;
                     32: extern IFILE curr_ifile;
                     33:
                     34:
                     35: #if HAVE_SYSTEM
                     36:
                     37: /*
                     38:  * Pass the specified command to a shell to be executed.
                     39:  * Like plain "system()", but handles resetting terminal modes, etc.
                     40:  */
                     41:        public void
1.5     ! millert    42: lsystem(cmd, donemsg)
1.1       etheisen   43:        char *cmd;
1.5     ! millert    44:        char *donemsg;
1.1       etheisen   45: {
1.5     ! millert    46:        register int inp;
        !            47: #if HAVE_SHELL
        !            48:        register char *shell;
        !            49:        register char *p;
1.1       etheisen   50: #endif
                     51:        IFILE save_ifile;
1.5     ! millert    52: #if MSDOS_COMPILER
        !            53:        char cwd[FILENAME_MAX+1];
        !            54: #endif
1.1       etheisen   55:
                     56:        /*
                     57:         * Print the command which is to be executed,
                     58:         * unless the command starts with a "-".
                     59:         */
                     60:        if (cmd[0] == '-')
                     61:                cmd++;
                     62:        else
                     63:        {
                     64:                clear_bot();
                     65:                putstr("!");
                     66:                putstr(cmd);
                     67:                putstr("\n");
                     68:        }
                     69:
1.5     ! millert    70: #if MSDOS_COMPILER
        !            71:        /*
        !            72:         * Working directory is global on MSDOS.
        !            73:         * The child might change the working directory, so we
        !            74:         * must save and restore CWD across calls to "system",
        !            75:         * or else we won't find our file when we return and
        !            76:         * try to "reedit_ifile" it.
        !            77:         */
        !            78:        getcwd(cwd, FILENAME_MAX);
        !            79: #endif
        !            80:
1.1       etheisen   81:        /*
                     82:         * Close the current input file.
                     83:         */
1.5     ! millert    84:        save_ifile = save_curr_ifile();
1.1       etheisen   85:        (void) edit_ifile(NULL_IFILE);
                     86:
                     87:        /*
                     88:         * De-initialize the terminal and take out of raw mode.
                     89:         */
                     90:        deinit();
                     91:        flush();        /* Make sure the deinit chars get out */
                     92:        raw_mode(0);
1.5     ! millert    93: #if MSDOS_COMPILER==WIN32C
        !            94:        close_getchr();
        !            95: #endif
1.1       etheisen   96:
                     97:        /*
                     98:         * Restore signals to their defaults.
                     99:         */
                    100:        init_signals(0);
                    101:
1.5     ! millert   102: #if HAVE_DUP
1.1       etheisen  103:        /*
                    104:         * Force standard input to be the user's terminal
                    105:         * (the normal standard input), even if less's standard input
                    106:         * is coming from a pipe.
                    107:         */
                    108:        inp = dup(0);
                    109:        close(0);
1.5     ! millert   110: #if OS2
        !           111:        /* The __open() system call translates "/dev/tty" to "con". */
        !           112:        if (__open("/dev/tty", OPEN_READ) < 0)
        !           113: #else
        !           114:        if (open("/dev/tty", OPEN_READ) < 0)
        !           115: #endif
1.1       etheisen  116:                dup(inp);
1.5     ! millert   117: #endif
1.1       etheisen  118:
                    119:        /*
                    120:         * Pass the command to the system to be executed.
                    121:         * If we have a SHELL environment variable, use
                    122:         * <$SHELL -c "command"> instead of just <command>.
                    123:         * If the command is empty, just invoke a shell.
                    124:         */
                    125: #if HAVE_SHELL
                    126:        p = NULL;
1.5     ! millert   127:        if ((shell = lgetenv("SHELL")) != NULL && *shell != '\0')
1.1       etheisen  128:        {
                    129:                if (*cmd == '\0')
                    130:                        p = save(shell);
                    131:                else
                    132:                {
1.5     ! millert   133:                        char *esccmd = shell_quote(cmd);
        !           134:                        if (esccmd != NULL)
        !           135:                        {
        !           136:                                size_t len = strlen(shell) + strlen(esccmd) + 5;
        !           137:                                p = (char *) ecalloc(len, sizeof(char));
        !           138:                                snprintf(p, len, "%s %s %s", shell,
        !           139:                                    shell_coption(), esccmd);
        !           140:                                free(esccmd);
        !           141:                        }
1.1       etheisen  142:                }
                    143:        }
                    144:        if (p == NULL)
                    145:        {
                    146:                if (*cmd == '\0')
                    147:                        p = save("sh");
                    148:                else
                    149:                        p = save(cmd);
                    150:        }
                    151:        system(p);
                    152:        free(p);
                    153: #else
1.5     ! millert   154: #if MSDOS_COMPILER==DJGPPC
        !           155:        /*
        !           156:         * Make stdin of the child be in cooked mode.
        !           157:         */
        !           158:        setmode(0, O_TEXT);
        !           159:        /*
        !           160:         * We don't need to catch signals of the child (it
        !           161:         * also makes trouble with some DPMI servers).
        !           162:         */
        !           163:        __djgpp_exception_toggle();
        !           164:        system(cmd);
        !           165:        __djgpp_exception_toggle();
        !           166: #else
        !           167:        system(cmd);
1.1       etheisen  168: #endif
                    169: #endif
                    170:
1.5     ! millert   171: #if HAVE_DUP
1.1       etheisen  172:        /*
                    173:         * Restore standard input, reset signals, raw mode, etc.
                    174:         */
                    175:        close(0);
                    176:        dup(inp);
                    177:        close(inp);
1.5     ! millert   178: #endif
1.1       etheisen  179:
1.5     ! millert   180: #if MSDOS_COMPILER==WIN32C
        !           181:        open_getchr();
        !           182: #endif
1.1       etheisen  183:        init_signals(1);
                    184:        raw_mode(1);
1.5     ! millert   185:        if (donemsg != NULL)
        !           186:        {
        !           187:                putstr(donemsg);
        !           188:                putstr("  (press RETURN)");
        !           189:                get_return();
        !           190:                putchr('\n');
        !           191:                flush();
        !           192:        }
1.1       etheisen  193:        init();
                    194:        screen_trashed = 1;
                    195:
1.5     ! millert   196: #if MSDOS_COMPILER
        !           197:        /*
        !           198:         * Restore the previous directory (possibly
        !           199:         * changed by the child program we just ran).
        !           200:         */
        !           201:        chdir(cwd);
        !           202: #if MSDOS_COMPILER != DJGPPC
        !           203:        /*
        !           204:         * Some versions of chdir() don't change to the drive
        !           205:         * which is part of CWD.  (DJGPP does this in chdir.)
        !           206:         */
        !           207:        if (cwd[1] == ':')
        !           208:        {
        !           209:                if (cwd[0] >= 'a' && cwd[0] <= 'z')
        !           210:                        setdisk(cwd[0] - 'a');
        !           211:                else if (cwd[0] >= 'A' && cwd[0] <= 'Z')
        !           212:                        setdisk(cwd[0] - 'A');
        !           213:        }
        !           214: #endif
        !           215: #endif
        !           216:
1.1       etheisen  217:        /*
                    218:         * Reopen the current input file.
                    219:         */
1.5     ! millert   220:        reedit_ifile(save_ifile);
1.1       etheisen  221:
                    222: #if defined(SIGWINCH) || defined(SIGWIND)
                    223:        /*
                    224:         * Since we were ignoring window change signals while we executed
                    225:         * the system command, we must assume the window changed.
                    226:         * Warning: this leaves a signal pending (in "sigs"),
                    227:         * so psignals() should be called soon after lsystem().
                    228:         */
                    229:        winch(0);
                    230: #endif
                    231: }
                    232:
                    233: #endif
                    234:
                    235: #if PIPEC
                    236:
                    237: /*
                    238:  * Pipe a section of the input file into the given shell command.
                    239:  * The section to be piped is the section "between" the current
                    240:  * position and the position marked by the given letter.
                    241:  *
1.5     ! millert   242:  * If the mark is after the current screen, the section between
        !           243:  * the top line displayed and the mark is piped.
        !           244:  * If the mark is before the current screen, the section between
        !           245:  * the mark and the bottom line displayed is piped.
        !           246:  * If the mark is on the current screen, or if the mark is ".",
        !           247:  * the whole current screen is piped.
1.1       etheisen  248:  */
                    249:        public int
                    250: pipe_mark(c, cmd)
                    251:        int c;
                    252:        char *cmd;
                    253: {
                    254:        POSITION mpos, tpos, bpos;
                    255:
                    256:        /*
                    257:         * mpos = the marked position.
                    258:         * tpos = top of screen.
                    259:         * bpos = bottom of screen.
                    260:         */
                    261:        mpos = markpos(c);
                    262:        if (mpos == NULL_POSITION)
                    263:                return (-1);
                    264:        tpos = position(TOP);
                    265:        if (tpos == NULL_POSITION)
                    266:                tpos = ch_zero();
                    267:        bpos = position(BOTTOM);
                    268:
                    269:        if (c == '.')
                    270:                return (pipe_data(cmd, tpos, bpos));
                    271:        else if (mpos <= tpos)
1.5     ! millert   272:                return (pipe_data(cmd, mpos, bpos));
1.1       etheisen  273:        else if (bpos == NULL_POSITION)
                    274:                return (pipe_data(cmd, tpos, bpos));
                    275:        else
                    276:                return (pipe_data(cmd, tpos, mpos));
                    277: }
                    278:
                    279: /*
                    280:  * Create a pipe to the given shell command.
                    281:  * Feed it the file contents between the positions spos and epos.
                    282:  */
                    283:        public int
                    284: pipe_data(cmd, spos, epos)
                    285:        char *cmd;
                    286:        POSITION spos;
                    287:        POSITION epos;
                    288: {
1.5     ! millert   289:        register FILE *f;
        !           290:        register int c;
1.1       etheisen  291:        extern FILE *popen();
                    292:
                    293:        /*
                    294:         * This is structured much like lsystem().
                    295:         * Since we're running a shell program, we must be careful
                    296:         * to perform the necessary deinitialization before running
                    297:         * the command, and reinitialization after it.
                    298:         */
                    299:        if (ch_seek(spos) != 0)
                    300:        {
                    301:                error("Cannot seek to start position", NULL_PARG);
                    302:                return (-1);
                    303:        }
                    304:
                    305:        if ((f = popen(cmd, "w")) == NULL)
                    306:        {
                    307:                error("Cannot create pipe", NULL_PARG);
                    308:                return (-1);
                    309:        }
                    310:        clear_bot();
                    311:        putstr("!");
                    312:        putstr(cmd);
                    313:        putstr("\n");
                    314:
                    315:        deinit();
                    316:        flush();
                    317:        raw_mode(0);
                    318:        init_signals(0);
1.5     ! millert   319: #if MSDOS_COMPILER==WIN32C
        !           320:        close_getchr();
        !           321: #endif
1.1       etheisen  322: #ifdef SIGPIPE
1.5     ! millert   323:        LSIGNAL(SIGPIPE, SIG_IGN);
1.1       etheisen  324: #endif
                    325:
                    326:        c = EOI;
                    327:        while (epos == NULL_POSITION || spos++ <= epos)
                    328:        {
                    329:                /*
                    330:                 * Read a character from the file and give it to the pipe.
                    331:                 */
                    332:                c = ch_forw_get();
                    333:                if (c == EOI)
                    334:                        break;
                    335:                if (putc(c, f) == EOF)
                    336:                        break;
                    337:        }
                    338:
                    339:        /*
                    340:         * Finish up the last line.
                    341:         */
                    342:        while (c != '\n' && c != EOI )
                    343:        {
                    344:                c = ch_forw_get();
                    345:                if (c == EOI)
                    346:                        break;
                    347:                if (putc(c, f) == EOF)
                    348:                        break;
                    349:        }
                    350:
                    351:        pclose(f);
                    352:
                    353: #ifdef SIGPIPE
1.5     ! millert   354:        LSIGNAL(SIGPIPE, SIG_DFL);
        !           355: #endif
        !           356: #if MSDOS_COMPILER==WIN32C
        !           357:        open_getchr();
1.1       etheisen  358: #endif
                    359:        init_signals(1);
                    360:        raw_mode(1);
                    361:        init();
                    362:        screen_trashed = 1;
                    363: #if defined(SIGWINCH) || defined(SIGWIND)
                    364:        /* {{ Probably don't need this here. }} */
                    365:        winch(0);
                    366: #endif
                    367:        return (0);
                    368: }
                    369:
                    370: #endif
1.5     ! millert   371:
        !           372: #ifdef _OSK
        !           373: /*
        !           374:  *    Popen, and Pclose, for OS-9.
        !           375:  *
        !           376:  *    Based on code copyright (c) 1988 by Wolfgang Ocker, Puchheim,
        !           377:  *                                        Ulli Dessauer, Germering and
        !           378:  *                                        Reimer Mellin, Muenchen
        !           379:  *                                        (W-Germany)
        !           380:  *
        !           381:  *    These functions can be copied and distributed freely for any
        !           382:  *    non-commercial purposes.  It can only be incorporated into
        !           383:  *    commercial software with the written permission of the authors.
        !           384:  *
        !           385:  *    TOP-specific code stripped out and adapted for less by M.Gregorie, 1996
        !           386:  *
        !           387:  *    address:    Wolfgang Ocker
        !           388:  *                Lochhauserstrasse 35a
        !           389:  *                D-8039 Puchheim
        !           390:  *                West Germany
        !           391:  *
        !           392:  *    e-mail:     weo@altger.UUCP, ud@altger.UUCP, ram@altger.UUCP
        !           393:  *                pyramid!tmpmbx!recco!weo
        !           394:  *                pyramid!tmpmbx!nitmar!ud
        !           395:  *                pyramid!tmpmbx!ramsys!ram
        !           396:  *
        !           397:  *                Martin Gregorie
        !           398:  *                10 Sadlers Mead
        !           399:  *                Harlow
        !           400:  *                Essex, CM18 6HG
        !           401:  *                U.K.
        !           402:  *
        !           403:  *                gregorie@logica.com
        !           404:  */
        !           405: #include <strings.h>
        !           406: #include <errno.h>
        !           407: extern char **environ;
        !           408: extern char *getenv();
        !           409: extern int  os9forkc();
        !           410: static int pids[_NFILE] = { 0, 0, 0, 0, 0, 0, 0, 0,
        !           411:                             0, 0, 0, 0, 0, 0, 0, 0,
        !           412:                             0, 0, 0, 0, 0, 0, 0, 0,
        !           413:                             0, 0, 0, 0, 0, 0, 0, 0 };
        !           414: /*
        !           415:  * p o p e n
        !           416:  */
        !           417: FILE *popen(name, mode)
        !           418:        char *name;
        !           419:        char *mode;
        !           420: {
        !           421:     int          fd, fd2, fdsav, pid;
        !           422:     static char  *argv[] = {NULL, NULL, NULL };
        !           423:     static char  cmd[200];
        !           424:     static char  cmd_path[200];
        !           425:     char         *cp;
        !           426:     char         *shell;
        !           427:     FILE         *r;
        !           428:     if ((shell = getenv("SHELL")) == NULL)
        !           429:         return(NULL);
        !           430:     cp = name;
        !           431:     while (*cp == ' ')
        !           432:         cp++;
        !           433:     strlcpy(cmd_path, cp, sizeof(cmd_path));
        !           434:     if (cp = index(cmd_path, ' '))
        !           435:         *cp++ = '\0';
        !           436:     strlcpy(cmd, "ex ", sizeof(cmd));
        !           437:     strlcat(cmd, cmd_path, sizeof(cmd));
        !           438:     if (cp)
        !           439:     {
        !           440:         strlcat(cmd, " ", sizeof(cmd));
        !           441:         strlcat(cmd, cp, sizeof(cmd));
        !           442:     }
        !           443:     argv[0] = shell;
        !           444:     argv[1] = cmd;
        !           445:     /*
        !           446:          mode is "r" (stdout) or "w" (stdin)
        !           447:     */
        !           448:     switch(mode[0])
        !           449:     {
        !           450:         case 'w':   fd = 0;
        !           451:                     break;
        !           452:         case 'r':   fd = 1;
        !           453:                     break;
        !           454:         default:    return(NULL);
        !           455:     }
        !           456:     if (fd == 1)
        !           457:         fflush(stdout);
        !           458:     fdsav = dup(fd);
        !           459:     close(fd);
        !           460:
        !           461:     creat("/pipe", S_IWRITE+S_IREAD);
        !           462:     pid = os9exec(os9forkc, argv[0], argv, environ, 0, 0, 3);
        !           463:     fd2 = dup(fd);
        !           464:     close(fd);
        !           465:     dup(fdsav);
        !           466:     close(fdsav);
        !           467:     if (pid > 0)
        !           468:     {
        !           469:         pids[fd2] = pid;
        !           470:         r = fdopen(fd2, mode);
        !           471:     }
        !           472:     else
        !           473:     {
        !           474:         close(fd2);
        !           475:         r = NULL;
        !           476:     }
        !           477:     return(r);
        !           478: }
        !           479:
        !           480: /*
        !           481:  * p c l o s e
        !           482:  */
        !           483: int pclose(fp)
        !           484:        FILE *fp;
        !           485: {
        !           486:     unsigned int    status;
        !           487:     int             pid;
        !           488:     int             fd,
        !           489:                     i;
        !           490:     fd = fileno(fp);
        !           491:     if (pids[fd] == 0)
        !           492:         return(-1);
        !           493:     fflush(fp);
        !           494:     fclose(fp);
        !           495:     while ((pid = wait(&status)) != -1)
        !           496:         if (pid == pids[fd])
        !           497:             break;
        !           498:         else
        !           499:             for (i = 0; i < _NFILE; i++)
        !           500:                 if (pids[i] == pid)
        !           501:                 {
        !           502:                     pids[i] = 0;
        !           503:                     break;
        !           504:                 }
        !           505:     if (pid == -1)
        !           506:         status = -1;
        !           507:     pids[fd] = 0;
        !           508:     return(status);
        !           509: }
        !           510: #endif /* _OSK */