Annotation of coherent/g/usr/bin/vi/ex.c, revision 1.1.1.1

1.1       root        1: /* ex.c */
                      2: 
                      3: /* Author:
                      4:  *     Steve Kirkendall
                      5:  *     14407 SW Teal Blvd. #C
                      6:  *     Beaverton, OR 97005
                      7:  *     [email protected]
                      8:  */
                      9: 
                     10: 
                     11: /* This file contains the code for reading ex commands. */
                     12: 
                     13: #include "config.h"
                     14: #include "ctype.h"
                     15: #include "vi.h"
                     16: 
                     17: /* This data type is used to describe the possible argument combinations */
                     18: typedef short ARGT;
                     19: #define FROM   1               /* allow a linespec */
                     20: #define        TO      2               /* allow a second linespec */
                     21: #define BANG   4               /* allow a ! after the command name */
                     22: #define EXTRA  8               /* allow extra args after command name */
                     23: #define XFILE  16              /* expand wildcards in extra part */
                     24: #define NOSPC  32              /* no spaces allowed in the extra part */
                     25: #define        DFLALL  64              /* default file range is 1,$ */
                     26: #define DFLNONE        128             /* no default file range */
                     27: #define NODFL  256             /* do not default to the current file name */
                     28: #define EXRCOK 512             /* can be in a .exrc file */
                     29: #define NL     1024            /* if mode!=MODE_EX, then write a newline first */
                     30: #define PLUS   2048            /* allow a line number, as in ":e +32 foo" */
                     31: #define ZERO   4096            /* allow 0 to be given as a line number */
                     32: #define NOBAR  8192            /* treat following '|' chars as normal */
                     33: #define FILES  (XFILE + EXTRA) /* multiple extra files allowed */
                     34: #define WORD1  (EXTRA + NOSPC) /* one extra word allowed */
                     35: #define FILE1  (FILES + NOSPC) /* 1 file allowed, defaults to current file */
                     36: #define NAMEDF (FILE1 + NODFL) /* 1 file allowed, defaults to "" */
                     37: #define NAMEDFS        (FILES + NODFL) /* multiple files allowed, default is "" */
                     38: #define RANGE  (FROM + TO)     /* range of linespecs allowed */
                     39: #define NONE   0               /* no args allowed at all */
                     40: 
                     41: /* This array maps ex command names to command codes. The order in which
                     42:  * command names are listed below is significant -- ambiguous abbreviations
                     43:  * are always resolved to be the first possible match.  (e.g. "r" is taken
                     44:  * to mean "read", not "rewind", because "read" comes before "rewind")
                     45:  */
                     46: static struct
                     47: {
                     48:        char    *name;  /* name of the command */
                     49:        CMD     code;   /* enum code of the command */
                     50:        void    (*fn)();/* function which executes the command */
                     51:        ARGT    argt;   /* command line arguments permitted/needed/used */
                     52: }
                     53:        cmdnames[] =
                     54: {   /* cmd name        cmd code        function        arguments */
                     55:        {"append",      CMD_APPEND,     cmd_append,     FROM+ZERO+BANG  },
                     56: #ifdef DEBUG
                     57:        {"bug",         CMD_DEBUG,      cmd_debug,      RANGE+BANG+EXTRA+NL},
                     58: #endif
                     59:        {"change",      CMD_CHANGE,     cmd_append,     RANGE+BANG      },
                     60:        {"delete",      CMD_DELETE,     cmd_delete,     RANGE+WORD1     },
                     61:        {"edit",        CMD_EDIT,       cmd_edit,       BANG+FILE1+PLUS },
                     62:        {"file",        CMD_FILE,       cmd_file,       NAMEDF          },
                     63:        {"global",      CMD_GLOBAL,     cmd_global,     RANGE+BANG+EXTRA+DFLALL+NOBAR},
                     64:        {"insert",      CMD_INSERT,     cmd_append,     FROM+BANG       },
                     65:        {"join",        CMD_INSERT,     cmd_join,       RANGE+BANG      },
                     66:        {"k",           CMD_MARK,       cmd_mark,       FROM+WORD1      },
                     67:        {"list",        CMD_LIST,       cmd_print,      RANGE+NL        },
                     68:        {"move",        CMD_MOVE,       cmd_move,       RANGE+EXTRA     },
                     69:        {"next",        CMD_NEXT,       cmd_next,       BANG+NAMEDFS    },
                     70:        {"Next",        CMD_PREVIOUS,   cmd_next,       BANG            },
                     71:        {"print",       CMD_PRINT,      cmd_print,      RANGE+NL        },
                     72:        {"quit",        CMD_QUIT,       cmd_xit,        BANG            },
                     73:        {"read",        CMD_READ,       cmd_read,       FROM+ZERO+NAMEDF},
                     74:        {"substitute",  CMD_SUBSTITUTE, cmd_substitute, RANGE+EXTRA     },
                     75:        {"to",          CMD_COPY,       cmd_move,       RANGE+EXTRA     },
                     76:        {"undo",        CMD_UNDO,       cmd_undo,       NONE            },
                     77:        {"vglobal",     CMD_VGLOBAL,    cmd_global,     RANGE+EXTRA+DFLALL+NOBAR},
                     78:        {"write",       CMD_WRITE,      cmd_write,      RANGE+BANG+FILE1+DFLALL},
                     79:        {"xit",         CMD_XIT,        cmd_xit,        BANG+NL         },
                     80:        {"yank",        CMD_YANK,       cmd_delete,     RANGE+WORD1     },
                     81: 
                     82:        {"!",           CMD_BANG,       cmd_shell,      EXRCOK+RANGE+NAMEDFS+DFLNONE+NL+NOBAR},
                     83:        {"#",           CMD_NUMBER,     cmd_print,      RANGE+NL        },
                     84:        {"<",           CMD_SHIFTL,     cmd_shift,      RANGE           },
                     85:        {">",           CMD_SHIFTR,     cmd_shift,      RANGE           },
                     86:        {"=",           CMD_EQUAL,      cmd_file,       RANGE           },
                     87:        {"&",           CMD_SUBAGAIN,   cmd_substitute, RANGE           },
                     88: #ifndef NO_AT
                     89:        {"@",           CMD_AT,         cmd_at,         EXTRA           },
                     90: #endif
                     91: 
                     92: #ifndef NO_ABBR
                     93:        {"abbreviate",  CMD_ABBR,       cmd_map,        EXRCOK+BANG+EXTRA},
                     94: #endif
                     95:        {"args",        CMD_ARGS,       cmd_args,       EXRCOK+NAMEDFS  },
                     96: #ifndef NO_ERRLIST
                     97:        {"cc",          CMD_CC,         cmd_make,       BANG+FILES      },
                     98: #endif
                     99:        {"cd",          CMD_CD,         cmd_cd,         EXRCOK+BANG+NAMEDF},
                    100:        {"copy",        CMD_COPY,       cmd_move,       RANGE+EXTRA     },
                    101: #ifndef NO_DIGRAPH
                    102:        {"digraph",     CMD_DIGRAPH,    cmd_digraph,    EXRCOK+BANG+EXTRA},
                    103: #endif
                    104: #ifndef NO_ERRLIST
                    105:        {"errlist",     CMD_ERRLIST,    cmd_errlist,    BANG+NAMEDF     },
                    106: #endif
                    107:        {"ex",          CMD_EDIT,       cmd_edit,       BANG+FILE1      },
                    108:        {"mark",        CMD_MARK,       cmd_mark,       FROM+WORD1      },
                    109: #ifndef NO_MKEXRC
                    110:        {"mkexrc",      CMD_MKEXRC,     cmd_mkexrc,     NAMEDF          },
                    111: #endif
                    112:        {"number",      CMD_NUMBER,     cmd_print,      RANGE+NL        },
                    113:        {"put",         CMD_PUT,        cmd_put,        FROM+ZERO+WORD1 },
                    114:        {"set",         CMD_SET,        cmd_set,        EXRCOK+EXTRA    },
                    115:        {"shell",       CMD_SHELL,      cmd_shell,      NL              },
                    116:        {"source",      CMD_SOURCE,     cmd_source,     EXRCOK+NAMEDF   },
                    117: #ifdef SIGTSTP
                    118:        {"stop",        CMD_STOP,       cmd_suspend,    NONE            },
                    119: #endif
                    120:        {"tag",         CMD_TAG,        cmd_tag,        BANG+WORD1      },
                    121:        {"version",     CMD_VERSION,    cmd_version,    EXRCOK+NONE     },
                    122:        {"visual",      CMD_VISUAL,     cmd_edit,       BANG+NAMEDF     },
                    123:        {"wq",          CMD_WQUIT,      cmd_xit,        NL              },
                    124: 
                    125: #ifdef DEBUG
                    126:        {"debug",       CMD_DEBUG,      cmd_debug,      RANGE+BANG+EXTRA+NL},
                    127:        {"validate",    CMD_VALIDATE,   cmd_validate,   BANG+NL         },
                    128: #endif
                    129:        {"chdir",       CMD_CD,         cmd_cd,         EXRCOK+BANG+NAMEDF},
                    130: #ifndef NO_COLOR
                    131:        {"color",       CMD_COLOR,      cmd_color,      EXRCOK+EXTRA    },
                    132: #endif
                    133: #ifndef NO_ERRLIST
                    134:        {"make",        CMD_MAKE,       cmd_make,       BANG+NAMEDFS    },
                    135: #endif
                    136:        {"map",         CMD_MAP,        cmd_map,        EXRCOK+BANG+EXTRA},
                    137:        {"previous",    CMD_PREVIOUS,   cmd_next,       BANG            },
                    138:        {"rewind",      CMD_REWIND,     cmd_next,       BANG            },
                    139: #ifdef SIGTSTP
                    140:        {"suspend",     CMD_SUSPEND,    cmd_suspend,    NONE            },
                    141: #endif
                    142:        {"unmap",       CMD_UNMAP,      cmd_map,        EXRCOK+BANG+EXTRA},
                    143: #ifndef NO_ABBR
                    144:        {"unabbreviate",CMD_UNABBR,     cmd_map,        EXRCOK+WORD1    },
                    145: #endif
                    146: 
                    147:        {(char *)0}
                    148: };
                    149: 
                    150: 
                    151: /* This function parses a search pattern - given a pointer to a / or ?,
                    152:  * it replaces the ending / or ? with a \0, and returns a pointer to the
                    153:  * stuff that came after the pattern.
                    154:  */
                    155: char   *parseptrn(ptrn)
                    156:        REG char        *ptrn;
                    157: {
                    158:        REG char        *scan;
                    159: 
                    160:        for (scan = ptrn + 1;
                    161:             *scan && *scan != *ptrn;
                    162:             scan++)
                    163:        {
                    164:                /* allow backslashed versions of / and ? in the pattern */
                    165:                if (*scan == '\\' && scan[1] != '\0')
                    166:                {
                    167:                        scan++;
                    168:                }
                    169:        }
                    170:        if (*scan)
                    171:        {
                    172:                *scan++ = '\0';
                    173:        }
                    174: 
                    175:        return scan;
                    176: }
                    177: 
                    178: 
                    179: /* This function parses a line specifier for ex commands */
                    180: char *linespec(s, markptr)
                    181:        REG char        *s;             /* start of the line specifier */
                    182:        MARK            *markptr;       /* where to store the mark's value */
                    183: {
                    184:        long            num;
                    185:        REG char        *t;
                    186: 
                    187:        /* parse each ;-delimited clause of this linespec */
                    188:        do
                    189:        {
                    190:                /* skip an initial ';', if any */
                    191:                if (*s == ';')
                    192:                {
                    193:                        s++;
                    194:                }
                    195: 
                    196:                /* skip leading spaces */
                    197:                while (isspace(*s))
                    198:                {
                    199:                        s++;
                    200:                }
                    201: 
                    202:                /* dot means current position */
                    203:                if (*s == '.')
                    204:                {
                    205:                        s++;
                    206:                        *markptr = cursor;
                    207:                }
                    208:                /* '$' means the last line */
                    209:                else if (*s == '$')
                    210:                {
                    211:                        s++;
                    212:                        *markptr = MARK_LAST;
                    213:                }
                    214:                /* digit means an absolute line number */
                    215:                else if (isdigit(*s))
                    216:                {
                    217:                        for (num = 0; isdigit(*s); s++)
                    218:                        {
                    219:                                num = num * 10 + *s - '0';
                    220:                        }
                    221:                        *markptr = MARK_AT_LINE(num);
                    222:                }
                    223:                /* appostrophe means go to a set mark */
                    224:                else if (*s == '\'')
                    225:                {
                    226:                        s++;
                    227:                        *markptr = m_tomark(cursor, 1L, (int)*s);
                    228:                        s++;
                    229:                }
                    230:                /* slash means do a search */
                    231:                else if (*s == '/' || *s == '?')
                    232:                {
                    233:                        /* put a '\0' at the end of the search pattern */
                    234:                        t = parseptrn(s);
                    235: 
                    236:                        /* search for the pattern */
                    237:                        *markptr &= ~(BLKSIZE - 1);
                    238:                        if (*s == '/')
                    239:                        {
                    240:                                pfetch(markline(*markptr));
                    241:                                if (plen > 0)
                    242:                                        *markptr += plen - 1;
                    243:                                *markptr = m_fsrch(*markptr, s);
                    244:                        }
                    245:                        else
                    246:                        {
                    247:                                *markptr = m_bsrch(*markptr, s);
                    248:                        }
                    249: 
                    250:                        /* adjust command string pointer */
                    251:                        s = t;
                    252:                }
                    253: 
                    254:                /* if linespec was faulty, quit now */
                    255:                if (!*markptr)
                    256:                {
                    257:                        return s;
                    258:                }
                    259: 
                    260:                /* maybe add an offset */
                    261:                t = s;
                    262:                if (*t == '-' || *t == '+')
                    263:                {
                    264:                        s++;
                    265:                        for (num = 0; isdigit(*s); s++)
                    266:                        {
                    267:                                num = num * 10 + *s - '0';
                    268:                        }
                    269:                        if (num == 0)
                    270:                        {
                    271:                                num = 1;
                    272:                        }
                    273:                        *markptr = m_updnto(*markptr, num, *t);
                    274:                }
                    275:        } while (*s == ';' || *s == '+' || *s == '-');
                    276: 
                    277:        /* protect against invalid line numbers */
                    278:        num = markline(*markptr);
                    279:        if (num < 1L || num > nlines)
                    280:        {
                    281:                msg("Invalid line number -- must be from 1 to %ld", nlines);
                    282:                *markptr = MARK_UNSET;
                    283:        }
                    284: 
                    285:        return s;
                    286: }
                    287: 
                    288: 
                    289: 
                    290: /* This function reads an ex command and executes it. */
                    291: void ex()
                    292: {
                    293:        char            cmdbuf[150];
                    294:        REG int         cmdlen;
                    295:        static long     oldline;
                    296: 
                    297:        significant = FALSE;
                    298:        oldline = markline(cursor);
                    299: 
                    300:        while (mode == MODE_EX)
                    301:        {
                    302:                /* read a line */
                    303: #ifdef CRUNCH
                    304:                cmdlen = vgets(':', cmdbuf, sizeof(cmdbuf));
                    305: #else
                    306:                cmdlen = vgets(*o_prompt ? ':' : '\0', cmdbuf, sizeof(cmdbuf));
                    307: #endif
                    308:                if (cmdlen < 0)
                    309:                {
                    310:                        return;
                    311:                }
                    312: 
                    313:                /* if empty line, assume ".+1" */
                    314:                if (cmdlen == 0)
                    315:                {
                    316:                        strcpy(cmdbuf, ".+1");
                    317:                        qaddch('\r');
                    318:                        clrtoeol();
                    319:                }
                    320:                else
                    321:                {
                    322:                        addch('\n');
                    323:                }
                    324:                refresh();
                    325: 
                    326:                /* parse & execute the command */
                    327:                doexcmd(cmdbuf);
                    328: 
                    329:                /* handle autoprint */
                    330:                if (significant || markline(cursor) != oldline)
                    331:                {
                    332:                        significant = FALSE;
                    333:                        oldline = markline(cursor);
                    334:                        if (*o_autoprint && mode == MODE_EX)
                    335:                        {
                    336:                                cmd_print(cursor, cursor, CMD_PRINT, FALSE, "");
                    337:                        }
                    338:                }
                    339:        }
                    340: }
                    341: 
                    342: void doexcmd(cmdbuf)
                    343:        char            *cmdbuf;        /* string containing an ex command */
                    344: {
                    345:        REG char        *scan;          /* used to scan thru cmdbuf */
                    346:        MARK            frommark;       /* first linespec */
                    347:        MARK            tomark;         /* second linespec */
                    348:        REG int         cmdlen;         /* length of the command name given */
                    349:        CMD             cmd;            /* what command is this? */
                    350:        ARGT            argt;           /* argument types for this command */
                    351:        short           forceit;        /* bang version of a command? */
                    352:        REG int         cmdidx;         /* index of command */
                    353:        REG char        *build;         /* used while copying filenames */
                    354:        int             iswild;         /* boolean: filenames use wildcards? */
                    355:        int             isdfl;          /* using default line ranges? */
                    356:        int             didsub;         /* did we substitute file names for % or # */
                    357: 
                    358:        /* ex commands can't be undone via the shift-U command */
                    359:        U_line = 0L;
                    360: 
                    361:        /* permit extra colons at the start of the line */
                    362:        for (; *cmdbuf == ':'; cmdbuf++)
                    363:        {
                    364:        }
                    365: 
                    366:        /* ignore command lines that start with a double-quote */
                    367:        if (*cmdbuf == '"')
                    368:        {
                    369:                return;
                    370:        }
                    371:        scan = cmdbuf;
                    372: 
                    373:        /* parse the line specifier */
                    374:        if (nlines < 1)
                    375:        {
                    376:                /* no file, so don't allow addresses */
                    377:        }
                    378:        else if (*scan == '%')
                    379:        {
                    380:                /* '%' means all lines */
                    381:                frommark = MARK_FIRST;
                    382:                tomark = MARK_LAST;
                    383:                scan++;
                    384:        }
                    385:        else if (*scan == '0')
                    386:        {
                    387:                scan++;
                    388:                frommark = tomark = (*scan ? MARK_UNSET : MARK_FIRST);
                    389:        }
                    390:        else
                    391:        {
                    392:                frommark = cursor;
                    393:                scan = linespec(scan, &frommark);
                    394:                tomark = frommark;
                    395:                if (frommark && *scan == ',')
                    396:                {
                    397:                        scan++;
                    398:                        scan = linespec(scan, &tomark);
                    399:                }
                    400:                if (!tomark)
                    401:                {
                    402:                        /* faulty line spec -- fault already described */
                    403:                        return;
                    404:                }
                    405:                if (frommark > tomark)
                    406:                {
                    407:                        msg("first address exceeds the second");
                    408:                        return;
                    409:                }
                    410:        }
                    411:        isdfl = (scan == cmdbuf);
                    412: 
                    413:        /* skip whitespace */
                    414:        while (isspace(*scan))
                    415:        {
                    416:                scan++;
                    417:        }
                    418: 
                    419:        /* if no command, then just move the cursor to the mark */
                    420:        if (!*scan)
                    421:        {
                    422:                if (tomark != MARK_UNSET)
                    423:                        cursor = tomark;
                    424:                return;
                    425:        }
                    426: 
                    427:        /* figure out how long the command name is */
                    428:        if (!isalpha(*scan))
                    429:        {
                    430:                cmdlen = 1;
                    431:        }
                    432:        else
                    433:        {
                    434:                for (cmdlen = 1;
                    435:                     isalpha(scan[cmdlen]);
                    436:                     cmdlen++)
                    437:                {
                    438:                }
                    439:        }
                    440: 
                    441:        /* lookup the command code */
                    442:        for (cmdidx = 0;
                    443:             cmdnames[cmdidx].name && strncmp(scan, cmdnames[cmdidx].name, cmdlen);
                    444:             cmdidx++)
                    445:        {
                    446:        }
                    447:        argt = cmdnames[cmdidx].argt;
                    448:        cmd = cmdnames[cmdidx].code;
                    449:        if (cmd == CMD_NULL)
                    450:        {
                    451:                msg("Unknown command \"%.*s\"", cmdlen, scan);
                    452:                return;
                    453:        }
                    454: 
                    455:        /* !!! if the command doesn't have NOBAR set, then replace | with \0 */
                    456: 
                    457:        /* if the command ended with a bang, set the forceit flag */
                    458:        scan += cmdlen;
                    459:        if ((argt & BANG) && *scan == '!')
                    460:        {
                    461:                scan++;
                    462:                forceit = 1;
                    463:        }
                    464:        else
                    465:        {
                    466:                forceit = 0;
                    467:        }
                    468: 
                    469:        /* skip any more whitespace, to leave scan pointing to arguments */
                    470:        while (isspace(*scan))
                    471:        {
                    472:                scan++;
                    473:        }
                    474: 
                    475:        /* a couple of special cases for filenames */
                    476:        if (argt & XFILE)
                    477:        {
                    478:                /* if names were given, process them */
                    479:                if (*scan)
                    480:                {
                    481:                        for (build = tmpblk.c, iswild = didsub = FALSE; *scan; scan++)
                    482:                        {
                    483:                                switch (*scan)
                    484:                                {
                    485:                                  case '\\':
                    486:                                        if (scan[1] == '\\' || scan[1] == '%' || scan[1] == '#')
                    487:                                        {
                    488:                                                *build++ = *++scan;
                    489:                                        }
                    490:                                        else
                    491:                                        {
                    492:                                                *build++ = '\\';
                    493:                                        }
                    494:                                        break;
                    495: 
                    496:                                  case '%':
                    497:                                        if (!*origname)
                    498:                                        {
                    499:                                                msg("No filename to substitute for %%");
                    500:                                                return;
                    501:                                        }
                    502:                                        strcpy(build, origname);
                    503:                                        while (*build)
                    504:                                        {
                    505:                                                build++;
                    506:                                        }
                    507:                                        didsub = TRUE;
                    508:                                        break;
                    509: 
                    510:                                  case '#':
                    511:                                        if (!*prevorig)
                    512:                                        {
                    513:                                                msg("No filename to substitute for #");
                    514:                                                return;
                    515:                                        }
                    516:                                        strcpy(build, prevorig);
                    517:                                        while (*build)
                    518:                                        {
                    519:                                                build++;
                    520:                                        }
                    521:                                        didsub = TRUE;
                    522:                                        break;
                    523: 
                    524:                                  case '*':
                    525:                                  case '?':
                    526: #if !(MSDOS || TOS)
                    527:                                  case '[':
                    528:                                  case '`':
                    529:                                  case '{': /* } */
                    530:                                  case '$':
                    531:                                  case '~':
                    532: #endif
                    533:                                        *build++ = *scan;
                    534:                                        iswild = TRUE;
                    535:                                        break;
                    536: 
                    537:                                  default:
                    538:                                        *build++ = *scan;
                    539:                                }
                    540:                        }
                    541:                        *build = '\0';
                    542: 
                    543:                        if (cmd == CMD_BANG
                    544:                         || cmd == CMD_READ && tmpblk.c[0] == '!'
                    545:                         || cmd == CMD_WRITE && tmpblk.c[0] == '!')
                    546:                        {
                    547:                                if (didsub)
                    548:                                {
                    549:                                        if (mode != MODE_EX)
                    550:                                        {
                    551:                                                addch('\n');
                    552:                                        }
                    553:                                        addstr(tmpblk.c);
                    554:                                        addch('\n');
                    555:                                        exrefresh();
                    556:                                }
                    557:                        }
                    558:                        else
                    559:                        {
                    560:                                if (iswild && tmpblk.c[0] != '>')
                    561:                                {
                    562:                                        scan = wildcard(tmpblk.c);
                    563:                                }
                    564:                        }
                    565:                }
                    566:                else /* no names given, maybe assume origname */
                    567:                {
                    568:                        if (!(argt & NODFL))
                    569:                        {
                    570:                                strcpy(tmpblk.c, origname);
                    571:                        }
                    572:                        else
                    573:                        {
                    574:                                *tmpblk.c = '\0';
                    575:                        }
                    576:                }
                    577: 
                    578:                scan = tmpblk.c;
                    579:        }
                    580: 
                    581:        /* bad arguments? */
                    582:        if (!(argt & EXRCOK) && nlines < 1L)
                    583:        {
                    584:                msg("Can't use the \"%s\" command in a %s file", cmdnames[cmdidx].name, EXRC);
                    585:                return;
                    586:        }
                    587:        if (!(argt & (ZERO | EXRCOK)) && frommark == MARK_UNSET)
                    588:        {
                    589:                msg("Can't use address 0 with \"%s\" command.", cmdnames[cmdidx].name);
                    590:                return;
                    591:        }
                    592:        if (!(argt & FROM) && frommark != cursor && nlines >= 1L)
                    593:        {
                    594:                msg("Can't use address with \"%s\" command.", cmdnames[cmdidx].name);
                    595:                return;
                    596:        }
                    597:        if (!(argt & TO) && tomark != frommark && nlines >= 1L)
                    598:        {
                    599:                msg("Can't use a range with \"%s\" command.", cmdnames[cmdidx].name);
                    600:                return;
                    601:        }
                    602:        if (!(argt & EXTRA) && *scan)
                    603:        {
                    604:                msg("Extra characters after \"%s\" command.", cmdnames[cmdidx].name);
                    605:                return;
                    606:        }
                    607:        if ((argt & NOSPC) && !(cmd == CMD_READ && (forceit || *scan == '!')))
                    608:        {
                    609:                build = scan;
                    610: #ifndef CRUNCH
                    611:                if ((argt & PLUS) && *build == '+')
                    612:                {
                    613:                        while (*build && !isspace(*build))
                    614:                        {
                    615:                                build++;
                    616:                        }
                    617:                        while (*build && isspace(*build))
                    618:                        {
                    619:                                build++;
                    620:                        }
                    621:                }
                    622: #endif /* not CRUNCH */
                    623:                for (; *build; build++)
                    624:                {
                    625:                        if (isspace(*build))
                    626:                        {
                    627:                                msg("Too many %s to \"%s\" command.",
                    628:                                        (argt & XFILE) ? "filenames" : "arguments",
                    629:                                        cmdnames[cmdidx].name);
                    630:                                return;
                    631:                        }
                    632:                }
                    633:        }
                    634: 
                    635:        /* some commands have special default ranges */
                    636:        if (isdfl && (argt & DFLALL))
                    637:        {
                    638:                frommark = MARK_FIRST;
                    639:                tomark = MARK_LAST;
                    640:        }
                    641:        else if (isdfl && (argt & DFLNONE))
                    642:        {
                    643:                frommark = tomark = 0L;
                    644:        }
                    645: 
                    646:        /* write a newline if called from visual mode */
                    647:        if ((argt & NL) && mode != MODE_EX && !exwrote)
                    648:        {
                    649:                addch('\n');
                    650:                exrefresh();
                    651:        }
                    652: 
                    653:        /* act on the command */
                    654:        (*cmdnames[cmdidx].fn)(frommark, tomark, cmd, forceit, scan);
                    655: }
                    656: 
                    657: 
                    658: /* This function executes EX commands from a file.  It returns 1 normally, or
                    659:  * 0 if the file could not be opened for reading.
                    660:  */
                    661: int doexrc(filename)
                    662:        char    *filename;      /* name of a ".exrc" file */
                    663: {
                    664:        int     fd;             /* file descriptor */
                    665:        int     len;            /* length of the ".exrc" file */
                    666: 
                    667: #ifdef CRUNCH
                    668:        /* small address space - we need to conserve space */
                    669: 
                    670:        /* !!! kludge: we use U_text as the buffer.  This has the side-effect
                    671:         * of interfering with the shift-U visual command.  Disable shift-U.
                    672:         */
                    673:        U_line = 0L;
                    674: #else
                    675: # if TINYSTACK
                    676:        /* small stack - we need to conserve space */
                    677: 
                    678:        /* !!! kludge: we use U_text as the buffer.  This has the side-effect
                    679:         * of interfering with the shift-U visual command.  Disable shift-U.
                    680:         */
                    681:        U_line = 0L;
                    682: # else
                    683:        /* This is how we would *like* to do it -- with a large buffer on the
                    684:         * stack, so we can handle large .exrc files and also recursion.
                    685:         */
                    686:        char    U_text[4096];
                    687: # endif
                    688: #endif
                    689: 
                    690:        /* open the file, read it, and close */
                    691:        fd = open(filename, O_RDONLY);
                    692:        if (fd < 0)
                    693:        {
                    694:                return 0;
                    695:        }
                    696:        len = tread(fd, U_text, sizeof U_text);
                    697:        close(fd);
                    698: 
                    699:        /* execute the string */
                    700:        exstring(U_text, len, ctrl('V'));
                    701: 
                    702:        return 1;
                    703: }
                    704: 
                    705: /* This function executes EX commands from a string.  The commands may be
                    706:  * separated by newlines or by | characters.  It also handles quoting.
                    707:  * Each individual command is limited to 132 bytes, but the total string
                    708:  * may be longer.
                    709:  */
                    710: void exstring(buf, len, qchar)
                    711:        char    *buf;   /* the commands to execute */
                    712:        int     len;    /* the length of the string */
                    713:        int     qchar;  /* the quote character -- ^V for file, or \ for kbd */
                    714: {
                    715:        char    single[133];    /* a single command */
                    716:        char    *src, *dest;
                    717:        int     i;
                    718: 
                    719:        /* find & do each command */
                    720:        for (src = buf; src < &buf[len]; src++)
                    721:        {
                    722:                /* Copy a single command into single[].  Convert any quoted |
                    723:                 * into a normal |, and stop at a newline or unquoted |.
                    724:                 */
                    725:                for (dest = single, i = 0;
                    726:                     i < 132 && src < &buf[len] && *src != '\n' && *src != '|';
                    727:                     src++, i++)
                    728:                {
                    729:                        if (src[0] == qchar && src[1] == '|')
                    730:                        {
                    731:                                src++;
                    732:                        }
                    733:                        *dest++ = *src;
                    734:                }
                    735:                *dest = '\0';
                    736: 
                    737:                /* do it */
                    738:                doexcmd(single);
                    739:        }
                    740: }

unix.superglobalmegacorp.com

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