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

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