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

1.1       etheisen    1: /*
1.8     ! shadchin    2:  * Copyright (C) 1984-2011  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.8     ! shadchin   52: #if MSDOS_COMPILER && MSDOS_COMPILER!=WIN32C
1.5       millert    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
1.8     ! shadchin   71: #if MSDOS_COMPILER==WIN32C
        !            72:        if (*cmd == '\0')
        !            73:                cmd = getenv("COMSPEC");
        !            74: #else
1.5       millert    75:        /*
                     76:         * Working directory is global on MSDOS.
                     77:         * The child might change the working directory, so we
                     78:         * must save and restore CWD across calls to "system",
                     79:         * or else we won't find our file when we return and
                     80:         * try to "reedit_ifile" it.
                     81:         */
                     82:        getcwd(cwd, FILENAME_MAX);
                     83: #endif
1.8     ! shadchin   84: #endif
1.5       millert    85:
1.1       etheisen   86:        /*
                     87:         * Close the current input file.
                     88:         */
1.5       millert    89:        save_ifile = save_curr_ifile();
1.1       etheisen   90:        (void) edit_ifile(NULL_IFILE);
                     91:
                     92:        /*
                     93:         * De-initialize the terminal and take out of raw mode.
                     94:         */
                     95:        deinit();
                     96:        flush();        /* Make sure the deinit chars get out */
                     97:        raw_mode(0);
1.5       millert    98: #if MSDOS_COMPILER==WIN32C
                     99:        close_getchr();
                    100: #endif
1.1       etheisen  101:
                    102:        /*
                    103:         * Restore signals to their defaults.
                    104:         */
                    105:        init_signals(0);
                    106:
1.5       millert   107: #if HAVE_DUP
1.1       etheisen  108:        /*
                    109:         * Force standard input to be the user's terminal
                    110:         * (the normal standard input), even if less's standard input
                    111:         * is coming from a pipe.
                    112:         */
                    113:        inp = dup(0);
                    114:        close(0);
1.5       millert   115: #if OS2
                    116:        /* The __open() system call translates "/dev/tty" to "con". */
                    117:        if (__open("/dev/tty", OPEN_READ) < 0)
                    118: #else
                    119:        if (open("/dev/tty", OPEN_READ) < 0)
                    120: #endif
1.1       etheisen  121:                dup(inp);
1.5       millert   122: #endif
1.1       etheisen  123:
                    124:        /*
                    125:         * Pass the command to the system to be executed.
                    126:         * If we have a SHELL environment variable, use
                    127:         * <$SHELL -c "command"> instead of just <command>.
                    128:         * If the command is empty, just invoke a shell.
                    129:         */
                    130: #if HAVE_SHELL
                    131:        p = NULL;
1.5       millert   132:        if ((shell = lgetenv("SHELL")) != NULL && *shell != '\0')
1.1       etheisen  133:        {
                    134:                if (*cmd == '\0')
                    135:                        p = save(shell);
                    136:                else
                    137:                {
1.5       millert   138:                        char *esccmd = shell_quote(cmd);
                    139:                        if (esccmd != NULL)
                    140:                        {
                    141:                                size_t len = strlen(shell) + strlen(esccmd) + 5;
                    142:                                p = (char *) ecalloc(len, sizeof(char));
1.8     ! shadchin  143:                                SNPRINTF3(p, len, "%s %s %s", shell, shell_coption(), esccmd);
1.5       millert   144:                                free(esccmd);
                    145:                        }
1.1       etheisen  146:                }
                    147:        }
                    148:        if (p == NULL)
                    149:        {
                    150:                if (*cmd == '\0')
                    151:                        p = save("sh");
                    152:                else
                    153:                        p = save(cmd);
                    154:        }
                    155:        system(p);
                    156:        free(p);
                    157: #else
1.5       millert   158: #if MSDOS_COMPILER==DJGPPC
                    159:        /*
                    160:         * Make stdin of the child be in cooked mode.
                    161:         */
                    162:        setmode(0, O_TEXT);
                    163:        /*
                    164:         * We don't need to catch signals of the child (it
                    165:         * also makes trouble with some DPMI servers).
                    166:         */
                    167:        __djgpp_exception_toggle();
                    168:        system(cmd);
                    169:        __djgpp_exception_toggle();
                    170: #else
                    171:        system(cmd);
1.1       etheisen  172: #endif
                    173: #endif
                    174:
1.5       millert   175: #if HAVE_DUP
1.1       etheisen  176:        /*
                    177:         * Restore standard input, reset signals, raw mode, etc.
                    178:         */
                    179:        close(0);
                    180:        dup(inp);
                    181:        close(inp);
1.5       millert   182: #endif
1.1       etheisen  183:
1.5       millert   184: #if MSDOS_COMPILER==WIN32C
                    185:        open_getchr();
                    186: #endif
1.1       etheisen  187:        init_signals(1);
                    188:        raw_mode(1);
1.5       millert   189:        if (donemsg != NULL)
                    190:        {
                    191:                putstr(donemsg);
                    192:                putstr("  (press RETURN)");
                    193:                get_return();
                    194:                putchr('\n');
                    195:                flush();
                    196:        }
1.1       etheisen  197:        init();
                    198:        screen_trashed = 1;
                    199:
1.8     ! shadchin  200: #if MSDOS_COMPILER && MSDOS_COMPILER!=WIN32C
1.5       millert   201:        /*
                    202:         * Restore the previous directory (possibly
                    203:         * changed by the child program we just ran).
                    204:         */
                    205:        chdir(cwd);
                    206: #if MSDOS_COMPILER != DJGPPC
                    207:        /*
                    208:         * Some versions of chdir() don't change to the drive
                    209:         * which is part of CWD.  (DJGPP does this in chdir.)
                    210:         */
                    211:        if (cwd[1] == ':')
                    212:        {
                    213:                if (cwd[0] >= 'a' && cwd[0] <= 'z')
                    214:                        setdisk(cwd[0] - 'a');
                    215:                else if (cwd[0] >= 'A' && cwd[0] <= 'Z')
                    216:                        setdisk(cwd[0] - 'A');
                    217:        }
                    218: #endif
                    219: #endif
                    220:
1.1       etheisen  221:        /*
                    222:         * Reopen the current input file.
                    223:         */
1.5       millert   224:        reedit_ifile(save_ifile);
1.1       etheisen  225:
                    226: #if defined(SIGWINCH) || defined(SIGWIND)
                    227:        /*
                    228:         * Since we were ignoring window change signals while we executed
                    229:         * the system command, we must assume the window changed.
                    230:         * Warning: this leaves a signal pending (in "sigs"),
                    231:         * so psignals() should be called soon after lsystem().
                    232:         */
                    233:        winch(0);
                    234: #endif
                    235: }
                    236:
                    237: #endif
                    238:
                    239: #if PIPEC
                    240:
                    241: /*
                    242:  * Pipe a section of the input file into the given shell command.
                    243:  * The section to be piped is the section "between" the current
                    244:  * position and the position marked by the given letter.
                    245:  *
1.5       millert   246:  * If the mark is after the current screen, the section between
                    247:  * the top line displayed and the mark is piped.
                    248:  * If the mark is before the current screen, the section between
                    249:  * the mark and the bottom line displayed is piped.
                    250:  * If the mark is on the current screen, or if the mark is ".",
                    251:  * the whole current screen is piped.
1.1       etheisen  252:  */
                    253:        public int
                    254: pipe_mark(c, cmd)
                    255:        int c;
                    256:        char *cmd;
                    257: {
                    258:        POSITION mpos, tpos, bpos;
                    259:
                    260:        /*
                    261:         * mpos = the marked position.
                    262:         * tpos = top of screen.
                    263:         * bpos = bottom of screen.
                    264:         */
                    265:        mpos = markpos(c);
                    266:        if (mpos == NULL_POSITION)
                    267:                return (-1);
                    268:        tpos = position(TOP);
                    269:        if (tpos == NULL_POSITION)
                    270:                tpos = ch_zero();
                    271:        bpos = position(BOTTOM);
                    272:
                    273:        if (c == '.')
                    274:                return (pipe_data(cmd, tpos, bpos));
                    275:        else if (mpos <= tpos)
1.5       millert   276:                return (pipe_data(cmd, mpos, bpos));
1.1       etheisen  277:        else if (bpos == NULL_POSITION)
                    278:                return (pipe_data(cmd, tpos, bpos));
                    279:        else
                    280:                return (pipe_data(cmd, tpos, mpos));
                    281: }
                    282:
                    283: /*
                    284:  * Create a pipe to the given shell command.
                    285:  * Feed it the file contents between the positions spos and epos.
                    286:  */
                    287:        public int
                    288: pipe_data(cmd, spos, epos)
                    289:        char *cmd;
                    290:        POSITION spos;
                    291:        POSITION epos;
                    292: {
1.5       millert   293:        register FILE *f;
                    294:        register int c;
1.1       etheisen  295:        extern FILE *popen();
                    296:
                    297:        /*
                    298:         * This is structured much like lsystem().
                    299:         * Since we're running a shell program, we must be careful
                    300:         * to perform the necessary deinitialization before running
                    301:         * the command, and reinitialization after it.
                    302:         */
                    303:        if (ch_seek(spos) != 0)
                    304:        {
                    305:                error("Cannot seek to start position", NULL_PARG);
                    306:                return (-1);
                    307:        }
                    308:
                    309:        if ((f = popen(cmd, "w")) == NULL)
                    310:        {
                    311:                error("Cannot create pipe", NULL_PARG);
                    312:                return (-1);
                    313:        }
                    314:        clear_bot();
                    315:        putstr("!");
                    316:        putstr(cmd);
                    317:        putstr("\n");
                    318:
                    319:        deinit();
                    320:        flush();
                    321:        raw_mode(0);
                    322:        init_signals(0);
1.5       millert   323: #if MSDOS_COMPILER==WIN32C
                    324:        close_getchr();
                    325: #endif
1.1       etheisen  326: #ifdef SIGPIPE
1.5       millert   327:        LSIGNAL(SIGPIPE, SIG_IGN);
1.1       etheisen  328: #endif
                    329:
                    330:        c = EOI;
                    331:        while (epos == NULL_POSITION || spos++ <= epos)
                    332:        {
                    333:                /*
                    334:                 * Read a character from the file and give it to the pipe.
                    335:                 */
                    336:                c = ch_forw_get();
                    337:                if (c == EOI)
                    338:                        break;
                    339:                if (putc(c, f) == EOF)
                    340:                        break;
                    341:        }
                    342:
                    343:        /*
                    344:         * Finish up the last line.
                    345:         */
                    346:        while (c != '\n' && c != EOI )
                    347:        {
                    348:                c = ch_forw_get();
                    349:                if (c == EOI)
                    350:                        break;
                    351:                if (putc(c, f) == EOF)
                    352:                        break;
                    353:        }
                    354:
                    355:        pclose(f);
                    356:
                    357: #ifdef SIGPIPE
1.5       millert   358:        LSIGNAL(SIGPIPE, SIG_DFL);
                    359: #endif
                    360: #if MSDOS_COMPILER==WIN32C
                    361:        open_getchr();
1.1       etheisen  362: #endif
                    363:        init_signals(1);
                    364:        raw_mode(1);
                    365:        init();
                    366:        screen_trashed = 1;
                    367: #if defined(SIGWINCH) || defined(SIGWIND)
                    368:        /* {{ Probably don't need this here. }} */
                    369:        winch(0);
                    370: #endif
                    371:        return (0);
                    372: }
                    373:
                    374: #endif