[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.1.1.2

1.1       etheisen    1: /*
1.1.1.2 ! millert     2:  * Copyright (C) 1984-2002  Mark Nudelman
1.1       etheisen    3:  *
1.1.1.2 ! 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.1.1.2 ! 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:
                     17: #include "less.h"
1.1.1.2 ! millert    18: #include <signal.h>
1.1       etheisen   19: #include "position.h"
                     20:
1.1.1.2 ! millert    21: #if MSDOS_COMPILER
1.1       etheisen   22: #include <dos.h>
1.1.1.2 ! 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.1.1.2 ! millert    42: lsystem(cmd, donemsg)
1.1       etheisen   43:        char *cmd;
1.1.1.2 ! millert    44:        char *donemsg;
1.1       etheisen   45: {
                     46:        register int inp;
1.1.1.2 ! millert    47: #if HAVE_SHELL
1.1       etheisen   48:        register char *shell;
                     49:        register char *p;
1.1.1.2 ! millert    50: #endif
1.1       etheisen   51:        IFILE save_ifile;
1.1.1.2 ! 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.1.1.2 ! 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.1.1.2 ! 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.1.1.2 ! 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.1.1.2 ! 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.1.1.2 ! 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.1.1.2 ! 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.1.1.2 ! 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.1.1.2 ! millert   133:                        char *esccmd = shell_quote(cmd);
        !           134:                        if (esccmd != NULL)
        !           135:                        {
        !           136:                                p = (char *) ecalloc(strlen(shell) +
        !           137:                                        strlen(esccmd) + 5, sizeof(char));
        !           138:                                sprintf(p, "%s %s %s", shell, shell_coption(), esccmd);
        !           139:                                free(esccmd);
        !           140:                        }
1.1       etheisen  141:                }
                    142:        }
                    143:        if (p == NULL)
                    144:        {
                    145:                if (*cmd == '\0')
                    146:                        p = save("sh");
                    147:                else
                    148:                        p = save(cmd);
                    149:        }
                    150:        system(p);
                    151:        free(p);
                    152: #else
1.1.1.2 ! millert   153: #if MSDOS_COMPILER==DJGPPC
        !           154:        /*
        !           155:         * Make stdin of the child be in cooked mode.
        !           156:         */
        !           157:        setmode(0, O_TEXT);
        !           158:        /*
        !           159:         * We don't need to catch signals of the child (it
        !           160:         * also makes trouble with some DPMI servers).
        !           161:         */
        !           162:        __djgpp_exception_toggle();
        !           163:        system(cmd);
        !           164:        __djgpp_exception_toggle();
        !           165: #else
1.1       etheisen  166:        system(cmd);
                    167: #endif
1.1.1.2 ! millert   168: #endif
1.1       etheisen  169:
1.1.1.2 ! millert   170: #if HAVE_DUP
1.1       etheisen  171:        /*
                    172:         * Restore standard input, reset signals, raw mode, etc.
                    173:         */
                    174:        close(0);
                    175:        dup(inp);
                    176:        close(inp);
1.1.1.2 ! millert   177: #endif
1.1       etheisen  178:
1.1.1.2 ! millert   179: #if MSDOS_COMPILER==WIN32C
        !           180:        open_getchr();
        !           181: #endif
1.1       etheisen  182:        init_signals(1);
                    183:        raw_mode(1);
1.1.1.2 ! millert   184:        if (donemsg != NULL)
        !           185:        {
        !           186:                putstr(donemsg);
        !           187:                putstr("  (press RETURN)");
        !           188:                get_return();
        !           189:                putchr('\n');
        !           190:                flush();
        !           191:        }
1.1       etheisen  192:        init();
                    193:        screen_trashed = 1;
                    194:
1.1.1.2 ! millert   195: #if MSDOS_COMPILER
        !           196:        /*
        !           197:         * Restore the previous directory (possibly
        !           198:         * changed by the child program we just ran).
        !           199:         */
        !           200:        chdir(cwd);
        !           201: #if MSDOS_COMPILER != DJGPPC
        !           202:        /*
        !           203:         * Some versions of chdir() don't change to the drive
        !           204:         * which is part of CWD.  (DJGPP does this in chdir.)
        !           205:         */
        !           206:        if (cwd[1] == ':')
        !           207:        {
        !           208:                if (cwd[0] >= 'a' && cwd[0] <= 'z')
        !           209:                        setdisk(cwd[0] - 'a');
        !           210:                else if (cwd[0] >= 'A' && cwd[0] <= 'Z')
        !           211:                        setdisk(cwd[0] - 'A');
        !           212:        }
        !           213: #endif
        !           214: #endif
        !           215:
1.1       etheisen  216:        /*
                    217:         * Reopen the current input file.
                    218:         */
1.1.1.2 ! millert   219:        reedit_ifile(save_ifile);
1.1       etheisen  220:
                    221: #if defined(SIGWINCH) || defined(SIGWIND)
                    222:        /*
                    223:         * Since we were ignoring window change signals while we executed
                    224:         * the system command, we must assume the window changed.
                    225:         * Warning: this leaves a signal pending (in "sigs"),
                    226:         * so psignals() should be called soon after lsystem().
                    227:         */
                    228:        winch(0);
                    229: #endif
                    230: }
                    231:
                    232: #endif
                    233:
                    234: #if PIPEC
                    235:
                    236: /*
                    237:  * Pipe a section of the input file into the given shell command.
                    238:  * The section to be piped is the section "between" the current
                    239:  * position and the position marked by the given letter.
                    240:  *
1.1.1.2 ! millert   241:  * If the mark is after the current screen, the section between
        !           242:  * the top line displayed and the mark is piped.
        !           243:  * If the mark is before the current screen, the section between
        !           244:  * the mark and the bottom line displayed is piped.
        !           245:  * If the mark is on the current screen, or if the mark is ".",
        !           246:  * the whole current screen is piped.
1.1       etheisen  247:  */
                    248:        public int
                    249: pipe_mark(c, cmd)
                    250:        int c;
                    251:        char *cmd;
                    252: {
                    253:        POSITION mpos, tpos, bpos;
                    254:
                    255:        /*
                    256:         * mpos = the marked position.
                    257:         * tpos = top of screen.
                    258:         * bpos = bottom of screen.
                    259:         */
                    260:        mpos = markpos(c);
                    261:        if (mpos == NULL_POSITION)
                    262:                return (-1);
                    263:        tpos = position(TOP);
                    264:        if (tpos == NULL_POSITION)
                    265:                tpos = ch_zero();
                    266:        bpos = position(BOTTOM);
                    267:
                    268:        if (c == '.')
                    269:                return (pipe_data(cmd, tpos, bpos));
                    270:        else if (mpos <= tpos)
1.1.1.2 ! millert   271:                return (pipe_data(cmd, mpos, bpos));
1.1       etheisen  272:        else if (bpos == NULL_POSITION)
                    273:                return (pipe_data(cmd, tpos, bpos));
                    274:        else
                    275:                return (pipe_data(cmd, tpos, mpos));
                    276: }
                    277:
                    278: /*
                    279:  * Create a pipe to the given shell command.
                    280:  * Feed it the file contents between the positions spos and epos.
                    281:  */
                    282:        public int
                    283: pipe_data(cmd, spos, epos)
                    284:        char *cmd;
                    285:        POSITION spos;
                    286:        POSITION epos;
                    287: {
                    288:        register FILE *f;
                    289:        register int c;
                    290:        extern FILE *popen();
                    291:
                    292:        /*
                    293:         * This is structured much like lsystem().
                    294:         * Since we're running a shell program, we must be careful
                    295:         * to perform the necessary deinitialization before running
                    296:         * the command, and reinitialization after it.
                    297:         */
                    298:        if (ch_seek(spos) != 0)
                    299:        {
                    300:                error("Cannot seek to start position", NULL_PARG);
                    301:                return (-1);
                    302:        }
                    303:
                    304:        if ((f = popen(cmd, "w")) == NULL)
                    305:        {
                    306:                error("Cannot create pipe", NULL_PARG);
                    307:                return (-1);
                    308:        }
                    309:        clear_bot();
                    310:        putstr("!");
                    311:        putstr(cmd);
                    312:        putstr("\n");
                    313:
                    314:        deinit();
                    315:        flush();
                    316:        raw_mode(0);
                    317:        init_signals(0);
1.1.1.2 ! millert   318: #if MSDOS_COMPILER==WIN32C
        !           319:        close_getchr();
        !           320: #endif
1.1       etheisen  321: #ifdef SIGPIPE
1.1.1.2 ! millert   322:        LSIGNAL(SIGPIPE, SIG_IGN);
1.1       etheisen  323: #endif
                    324:
                    325:        c = EOI;
                    326:        while (epos == NULL_POSITION || spos++ <= epos)
                    327:        {
                    328:                /*
                    329:                 * Read a character from the file and give it to the pipe.
                    330:                 */
                    331:                c = ch_forw_get();
                    332:                if (c == EOI)
                    333:                        break;
                    334:                if (putc(c, f) == EOF)
                    335:                        break;
                    336:        }
                    337:
                    338:        /*
                    339:         * Finish up the last line.
                    340:         */
                    341:        while (c != '\n' && c != EOI )
                    342:        {
                    343:                c = ch_forw_get();
                    344:                if (c == EOI)
                    345:                        break;
                    346:                if (putc(c, f) == EOF)
                    347:                        break;
                    348:        }
                    349:
                    350:        pclose(f);
                    351:
                    352: #ifdef SIGPIPE
1.1.1.2 ! millert   353:        LSIGNAL(SIGPIPE, SIG_DFL);
        !           354: #endif
        !           355: #if MSDOS_COMPILER==WIN32C
        !           356:        open_getchr();
1.1       etheisen  357: #endif
                    358:        init_signals(1);
                    359:        raw_mode(1);
                    360:        init();
                    361:        screen_trashed = 1;
                    362: #if defined(SIGWINCH) || defined(SIGWIND)
                    363:        /* {{ Probably don't need this here. }} */
                    364:        winch(0);
                    365: #endif
                    366:        return (0);
                    367: }
                    368:
                    369: #endif
1.1.1.2 ! millert   370:
        !           371: #ifdef _OSK
        !           372: /*
        !           373:  *    Popen, and Pclose, for OS-9.
        !           374:  *
        !           375:  *    Based on code copyright (c) 1988 by Wolfgang Ocker, Puchheim,
        !           376:  *                                        Ulli Dessauer, Germering and
        !           377:  *                                        Reimer Mellin, Muenchen
        !           378:  *                                        (W-Germany)
        !           379:  *
        !           380:  *    These functions can be copied and distributed freely for any
        !           381:  *    non-commercial purposes.  It can only be incorporated into
        !           382:  *    commercial software with the written permission of the authors.
        !           383:  *
        !           384:  *    TOP-specific code stripped out and adapted for less by M.Gregorie, 1996
        !           385:  *
        !           386:  *    address:    Wolfgang Ocker
        !           387:  *                Lochhauserstrasse 35a
        !           388:  *                D-8039 Puchheim
        !           389:  *                West Germany
        !           390:  *
        !           391:  *    e-mail:     weo@altger.UUCP, ud@altger.UUCP, ram@altger.UUCP
        !           392:  *                pyramid!tmpmbx!recco!weo
        !           393:  *                pyramid!tmpmbx!nitmar!ud
        !           394:  *                pyramid!tmpmbx!ramsys!ram
        !           395:  *
        !           396:  *                Martin Gregorie
        !           397:  *                10 Sadlers Mead
        !           398:  *                Harlow
        !           399:  *                Essex, CM18 6HG
        !           400:  *                U.K.
        !           401:  *
        !           402:  *                gregorie@logica.com
        !           403:  */
        !           404: #include <strings.h>
        !           405: #include <errno.h>
        !           406: extern char **environ;
        !           407: extern char *getenv();
        !           408: extern int  os9forkc();
        !           409: static int pids[_NFILE] = { 0, 0, 0, 0, 0, 0, 0, 0,
        !           410:                             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: /*
        !           414:  * p o p e n
        !           415:  */
        !           416: FILE *popen(name, mode)
        !           417:        char *name;
        !           418:        char *mode;
        !           419: {
        !           420:     int          fd, fd2, fdsav, pid;
        !           421:     static char  *argv[] = {NULL, NULL, NULL };
        !           422:     static char  cmd[200];
        !           423:     static char  cmd_path[200];
        !           424:     char         *cp;
        !           425:     char         *shell;
        !           426:     FILE         *r;
        !           427:     if ((shell = getenv("SHELL")) == NULL)
        !           428:         return(NULL);
        !           429:     cp = name;
        !           430:     while (*cp == ' ')
        !           431:         cp++;
        !           432:     strcpy(cmd_path, cp);
        !           433:     if (cp = index(cmd_path, ' '))
        !           434:         *cp++ = '\0';
        !           435:     strcpy(cmd, "ex ");
        !           436:     strcat(cmd, cmd_path);
        !           437:     if (cp)
        !           438:     {
        !           439:         strcat(cmd, " ");
        !           440:         strcat(cmd, cp);
        !           441:     }
        !           442:     argv[0] = shell;
        !           443:     argv[1] = cmd;
        !           444:     /*
        !           445:          mode is "r" (stdout) or "w" (stdin)
        !           446:     */
        !           447:     switch(mode[0])
        !           448:     {
        !           449:         case 'w':   fd = 0;
        !           450:                     break;
        !           451:         case 'r':   fd = 1;
        !           452:                     break;
        !           453:         default:    return(NULL);
        !           454:     }
        !           455:     if (fd == 1)
        !           456:         fflush(stdout);
        !           457:     fdsav = dup(fd);
        !           458:     close(fd);
        !           459:
        !           460:     creat("/pipe", S_IWRITE+S_IREAD);
        !           461:     pid = os9exec(os9forkc, argv[0], argv, environ, 0, 0, 3);
        !           462:     fd2 = dup(fd);
        !           463:     close(fd);
        !           464:     dup(fdsav);
        !           465:     close(fdsav);
        !           466:     if (pid > 0)
        !           467:     {
        !           468:         pids[fd2] = pid;
        !           469:         r = fdopen(fd2, mode);
        !           470:     }
        !           471:     else
        !           472:     {
        !           473:         close(fd2);
        !           474:         r = NULL;
        !           475:     }
        !           476:     return(r);
        !           477: }
        !           478:
        !           479: /*
        !           480:  * p c l o s e
        !           481:  */
        !           482: int pclose(fp)
        !           483:        FILE *fp;
        !           484: {
        !           485:     unsigned int    status;
        !           486:     int             pid;
        !           487:     int             fd,
        !           488:                     i;
        !           489:     fd = fileno(fp);
        !           490:     if (pids[fd] == 0)
        !           491:         return(-1);
        !           492:     fflush(fp);
        !           493:     fclose(fp);
        !           494:     while ((pid = wait(&status)) != -1)
        !           495:         if (pid == pids[fd])
        !           496:             break;
        !           497:         else
        !           498:             for (i = 0; i < _NFILE; i++)
        !           499:                 if (pids[i] == pid)
        !           500:                 {
        !           501:                     pids[i] = 0;
        !           502:                     break;
        !           503:                 }
        !           504:     if (pid == -1)
        !           505:         status = -1;
        !           506:     pids[fd] = 0;
        !           507:     return(status);
        !           508: }
        !           509: #endif /* _OSK */