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

1.1       root        1: /* cmd1.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 some of the EX commands - mostly ones that deal with
                     12:  * files, options, etc. -- anything except text.
                     13:  */
                     14: 
                     15: #include "config.h"
                     16: #include "ctype.h"
                     17: #include "vi.h"
                     18: #include "regexp.h"
                     19: 
                     20: #ifdef DEBUG
                     21: /* print the selected lines with info on the blocks */
                     22: /*ARGSUSED*/
                     23: void cmd_debug(frommark, tomark, cmd, bang, extra)
                     24:        MARK    frommark;
                     25:        MARK    tomark;
                     26:        CMD     cmd;
                     27:        int     bang;
                     28:        char    *extra;
                     29: {
                     30:        REG char        *scan;
                     31:        REG long        l;
                     32:        REG int         i;
                     33:        int             len;
                     34: 
                     35:        /* scan lnum[] to determine which block its in */
                     36:        l = markline(frommark);
                     37:        for (i = 1; l > lnum[i]; i++)
                     38:        {
                     39:        }
                     40: 
                     41:        do
                     42:        {
                     43:                /* fetch text of the block containing that line */
                     44:                scan = blkget(i)->c;
                     45: 
                     46:                /* calculate its length */
                     47:                if (scan[BLKSIZE - 1])
                     48:                {
                     49:                        len = BLKSIZE;
                     50:                }
                     51:                else
                     52:                {
                     53:                        len = strlen(scan);
                     54:                }
                     55: 
                     56:                /* print block stats */
                     57:                msg("##### hdr[%d]=%d, lnum[%d-1]=%ld, lnum[%d]=%ld (%ld lines)",
                     58:                        i, hdr.n[i], i, lnum[i-1], i, lnum[i], lnum[i] - lnum[i - 1]);
                     59:                msg("##### len=%d, buf=0x%lx, %sdirty",
                     60:                        len, scan, ((int *)scan)[MAXBLKS + 1] ? "" : "not ");
                     61:                if (bang)
                     62:                {
                     63:                        while (--len >= 0)
                     64:                        {
                     65:                                addch(*scan);
                     66:                                scan++;
                     67:                        }
                     68:                }
                     69:                exrefresh();
                     70: 
                     71:                /* next block */
                     72:                i++;
                     73:        } while (i < MAXBLKS && lnum[i] && lnum[i - 1] < markline(tomark));
                     74: }
                     75: 
                     76: 
                     77: /* This function checks a lot of conditions to make sure they aren't screwy */
                     78: /*ARGSUSED*/
                     79: void cmd_validate(frommark, tomark, cmd, bang, extra)
                     80:        MARK    frommark;
                     81:        MARK    tomark;
                     82:        CMD     cmd;
                     83:        int     bang;
                     84:        char    *extra;
                     85: {
                     86:        char    *scan;
                     87:        int     i;
                     88:        int     nlcnt;  /* used to count newlines */
                     89:        int     len;    /* counts non-NUL characters */
                     90: 
                     91:        /* check lnum[0] */
                     92:        if (lnum[0] != 0L)
                     93:        {
                     94:                msg("lnum[0] = %ld", lnum[0]);
                     95:        }
                     96: 
                     97:        /* check each block */
                     98:        for (i = 1; lnum[i] <= nlines; i++)
                     99:        {
                    100:                scan = blkget(i)->c;
                    101:                if (scan[BLKSIZE - 1])
                    102:                {
                    103:                        msg("block %d has no NUL at the end", i);
                    104:                }
                    105:                else
                    106:                {
                    107:                        for (nlcnt = len = 0; *scan; scan++, len++)
                    108:                        {
                    109:                                if (*scan == '\n')
                    110:                                {
                    111:                                        nlcnt++;
                    112:                                }
                    113:                        }
                    114:                        if (scan[-1] != '\n')
                    115:                        {
                    116:                                msg("block %d doesn't end with '\\n' (length %d)", i, len);
                    117:                        }
                    118:                        if (bang || nlcnt != lnum[i] - lnum[i - 1])
                    119:                        {
                    120:                                msg("block %d (line %ld?) has %d lines, but should have %ld",
                    121:                                        i, lnum[i - 1] + 1L, nlcnt, lnum[i] - lnum[i - 1]);
                    122:                        }
                    123:                }
                    124:                exrefresh();
                    125:        }
                    126: 
                    127:        /* check lnum again */
                    128:        if (lnum[i] != INFINITY)
                    129:        {
                    130:                msg("hdr.n[%d] = %d, but lnum[%d] = %ld",
                    131:                        i, hdr.n[i], i, lnum[i]);
                    132:        }
                    133: 
                    134:        msg("# = \"%s\", %% = \"%s\"", prevorig, origname);
                    135:        msg("V_from=%ld.%d, cursor=%ld.%d", markline(V_from), markidx(V_from), markline(cursor), markidx(cursor));
                    136: }
                    137: #endif /* DEBUG */
                    138: 
                    139: 
                    140: /*ARGSUSED*/
                    141: void cmd_mark(frommark, tomark, cmd, bang, extra)
                    142:        MARK    frommark;
                    143:        MARK    tomark;
                    144:        CMD     cmd;
                    145:        int     bang;
                    146:        char    *extra;
                    147: {
                    148:        /* validate the name of the mark */
                    149:        if (*extra == '"')
                    150:        {
                    151:                extra++;
                    152:        }
                    153:        /* valid mark names are lowercase ascii characters */
                    154:        if (!isascii(*extra) || !islower(*extra) || extra[1])
                    155:        {
                    156:                msg("Invalid mark name");
                    157:                return;
                    158:        }
                    159: 
                    160:        mark[*extra - 'a'] = tomark;
                    161: }
                    162: 
                    163: /*ARGSUSED*/
                    164: void cmd_write(frommark, tomark, cmd, bang, extra)
                    165:        MARK    frommark;
                    166:        MARK    tomark;
                    167:        CMD     cmd;
                    168:        int     bang;
                    169:        char    *extra;
                    170: {
                    171:        int             fd;
                    172:        int             append; /* boolean: write in "append" mode? */
                    173:        REG long        l;
                    174:        REG char        *scan;
                    175:        REG int         i;
                    176: 
                    177:        /* if writing to a filter, then let filter() handle it */
                    178:        if (*extra == '!')
                    179:        {
                    180:                filter(frommark, tomark, extra + 1, FALSE);
                    181:                return;
                    182:        }
                    183: 
                    184:        /* if all lines are to be written, use tmpsave() */
                    185:        if (frommark == MARK_FIRST && tomark == MARK_LAST && cmd == CMD_WRITE)
                    186:        {
                    187:                tmpsave(extra, bang);
                    188:                return;
                    189:        }
                    190: 
                    191:        /* see if we're going to do this in append mode or not */
                    192:        append = FALSE;
                    193:        if (extra[0] == '>' && extra[1] == '>')
                    194:        {
                    195:                extra += 2;
                    196:                append = TRUE;
                    197:        }
                    198: 
                    199:        /* either the file must not exist, or we must have a ! or be appending */
                    200:        if (access(extra, 0) == 0 && !bang && !append)
                    201:        {
                    202:                msg("File already exists - Use :w! to overwrite");
                    203:                return;
                    204:        }
                    205: 
                    206:        /* else do it line-by-line, like cmd_print() */
                    207:        if (append)
                    208:        {
                    209: #ifdef O_APPEND
                    210:                fd = open(extra, O_WRONLY|O_APPEND);
                    211: #else
                    212:                fd = open(extra, O_WRONLY);
                    213:                if (fd >= 0)
                    214:                {
                    215:                        lseek(fd, 0L, 2);
                    216:                }
                    217: #endif
                    218:        }
                    219:        else
                    220:        {
                    221:                fd = -1; /* so we know the file isn't open yet */
                    222:        }
                    223: 
                    224:        if (fd < 0)
                    225:        {
                    226:                fd = creat(extra, FILEPERMS);
                    227:                if (fd < 0)
                    228:                {
                    229:                        msg("Can't write to \"%s\"", extra);
                    230:                        return;
                    231:                }
                    232:        }
                    233:        for (l = markline(frommark); l <= markline(tomark); l++)
                    234:        {
                    235:                /* get the next line */
                    236:                scan = fetchline(l);
                    237:                i = strlen(scan);
                    238:                scan[i++] = '\n';
                    239: 
                    240:                /* print the line */
                    241:                if (twrite(fd, scan, i) < i)
                    242:                {
                    243:                        msg("Write failed");
                    244:                        break;
                    245:                }
                    246:        }
                    247:        rptlines = markline(tomark) - markline(frommark) + 1;
                    248:        rptlabel = "written";
                    249:        close(fd);
                    250: }      
                    251: 
                    252: 
                    253: /*ARGSUSED*/
                    254: void cmd_shell(frommark, tomark, cmd, bang, extra)
                    255:        MARK    frommark, tomark;
                    256:        CMD     cmd;
                    257:        int     bang;
                    258:        char    *extra;
                    259: {
                    260:        static char     prevextra[80];
                    261: 
                    262:        /* special case: ":sh" means ":!sh" */
                    263:        if (cmd == CMD_SHELL)
                    264:        {
                    265:                extra = o_shell;
                    266:                frommark = tomark = 0L;
                    267:        }
                    268: 
                    269:        /* if extra is "!", substitute previous command */
                    270:        if (*extra == '!')
                    271:        {
                    272:                if (!*prevextra)
                    273:                {
                    274:                        msg("No previous shell command to substitute for '!'");
                    275:                        return;
                    276:                }
                    277:                extra = prevextra;
                    278:        }
                    279:        else if (cmd == CMD_BANG && strlen(extra) < sizeof(prevextra) - 1)
                    280:        {
                    281:                strcpy(prevextra, extra);
                    282:        }
                    283: 
                    284:        /* warn the user if the file hasn't been saved yet */
                    285:        if (*o_warn && tstflag(file, MODIFIED))
                    286:        {
                    287:                if (mode == MODE_VI)
                    288:                {
                    289:                        mode = MODE_COLON;
                    290:                }
                    291:                msg("Warning: \"%s\" has been modified but not yet saved", origname);
                    292:        }
                    293: 
                    294:        /* if no lines were specified, just run the command */
                    295:        suspend_curses();
                    296:        if (frommark == 0L)
                    297:        {
                    298:                system(extra);
                    299:        }
                    300:        else /* pipe lines from the file through the command */
                    301:        {
                    302:                filter(frommark, tomark, extra, TRUE);
                    303:        }
                    304: 
                    305:        /* resume curses quietly for MODE_EX, but noisily otherwise */
                    306:        resume_curses(mode == MODE_EX);
                    307: }
                    308: 
                    309: 
                    310: /*ARGSUSED*/
                    311: void cmd_global(frommark, tomark, cmd, bang, extra)
                    312:        MARK    frommark, tomark;
                    313:        CMD     cmd;
                    314:        int     bang;
                    315:        char    *extra; /* rest of the command line */
                    316: {
                    317:        char    *cmdptr;        /* the command from the command line */
                    318:        char    cmdln[100];     /* copy of the command from the command line */
                    319:        char    *line;          /* a line from the file */
                    320:        long    l;              /* used as a counter to move through lines */
                    321:        long    lqty;           /* quantity of lines to be scanned */
                    322:        long    nchanged;       /* number of lines changed */
                    323:        regexp  *re;            /* the compiled search expression */
                    324: 
                    325:        /* can't nest global commands */
                    326:        if (doingglobal)
                    327:        {
                    328:                msg("Can't nest global commands.");
                    329:                rptlines = -1L;
                    330:                return;
                    331:        }
                    332: 
                    333:        /* ":g! ..." is the same as ":v ..." */
                    334:        if (bang)
                    335:        {
                    336:                cmd = CMD_VGLOBAL;
                    337:        }
                    338: 
                    339:        /* make sure we got a search pattern */
                    340:        if (*extra != '/' && *extra != '?')
                    341:        {
                    342:                msg("Usage: %c /regular expression/ command", cmd == CMD_GLOBAL ? 'g' : 'v');
                    343:                return;
                    344:        }
                    345: 
                    346:        /* parse & compile the search pattern */
                    347:        cmdptr = parseptrn(extra);
                    348:        if (!extra[1])
                    349:        {
                    350:                msg("Can't use empty regular expression with '%c' command", cmd == CMD_GLOBAL ? 'g' : 'v');
                    351:                return;
                    352:        }
                    353:        re = regcomp(extra + 1);
                    354:        if (!re)
                    355:        {
                    356:                /* regcomp found & described an error */
                    357:                return;
                    358:        }
                    359: 
                    360:        /* for each line in the range */
                    361:        doingglobal = TRUE;
                    362:        ChangeText
                    363:        {
                    364:                /* NOTE: we have to go through the lines in a forward order,
                    365:                 * otherwise "g/re/p" would look funny.  *BUT* for "g/re/d"
                    366:                 * to work, simply adding 1 to the line# on each loop won't
                    367:                 * work.  The solution: count lines relative to the end of
                    368:                 * the file.  Think about it.
                    369:                 */
                    370:                for (l = nlines - markline(frommark),
                    371:                        lqty = markline(tomark) - markline(frommark) + 1L,
                    372:                        nchanged = 0L;
                    373:                     lqty > 0 && nlines - l >= 0 && nchanged >= 0L;
                    374:                     l--, lqty--)
                    375:                {
                    376:                        /* fetch the line */
                    377:                        line = fetchline(nlines - l);
                    378: 
                    379:                        /* if it contains the search pattern... */
                    380:                        if ((!regexec(re, line, 1)) == (cmd != CMD_GLOBAL))
                    381:                        {
                    382:                                /* move the cursor to that line */
                    383:                                cursor = MARK_AT_LINE(nlines - l);
                    384: 
                    385:                                /* do the ex command (without mucking up
                    386:                                 * the original copy of the command line)
                    387:                                 */
                    388:                                strcpy(cmdln, cmdptr);
                    389:                                rptlines = 0L;
                    390:                                doexcmd(cmdln);
                    391:                                nchanged += rptlines;
                    392:                        }
                    393:                }
                    394:        }
                    395:        doingglobal = FALSE;
                    396: 
                    397:        /* free the regexp */
                    398:        _free_(re);
                    399: 
                    400:        /* Reporting...*/
                    401:        rptlines = nchanged;
                    402: }
                    403: 
                    404: 
                    405: /*ARGSUSED*/
                    406: void cmd_file(frommark, tomark, cmd, bang, extra)
                    407:        MARK    frommark, tomark;
                    408:        CMD     cmd;
                    409:        int     bang;
                    410:        char    *extra;
                    411: {
                    412: #ifndef CRUNCH
                    413:        /* if we're given a new filename, use it as this file's name */
                    414:        if (extra && *extra)
                    415:        {
                    416:                strcpy(origname, extra);
                    417:                storename(origname);
                    418:                setflag(file, NOTEDITED);
                    419:        }
                    420: #endif
                    421:        if (cmd == CMD_FILE)
                    422:        {
                    423: #ifndef CRUNCH
                    424:                msg("\"%s\" %s%s%s %ld lines,  line %ld [%ld%%]",
                    425: #else
                    426:                msg("\"%s\" %s%s %ld lines,  line %ld [%ld%%]",
                    427: #endif
                    428:                        *origname ? origname : "[NO FILE]",
                    429:                        tstflag(file, MODIFIED) ? "[MODIFIED]" : "",
                    430: #ifndef CRUNCH
                    431:                        tstflag(file, NOTEDITED) ?"[NOT EDITED]":"",
                    432: #endif
                    433:                        tstflag(file, READONLY) ? "[READONLY]" : "",
                    434:                        nlines,
                    435:                        markline(frommark),
                    436:                        markline(frommark) * 100 / nlines);
                    437:        }
                    438: #ifndef CRUNCH
                    439:        else if (markline(frommark) != markline(tomark))
                    440:        {
                    441:                msg("range \"%ld,%ld\" contains %ld lines",
                    442:                        markline(frommark),
                    443:                        markline(tomark),
                    444:                        markline(tomark) - markline(frommark) + 1L);
                    445:        }
                    446: #endif
                    447:        else
                    448:        {
                    449:                msg("%ld", markline(frommark));
                    450:        }
                    451: }
                    452: 
                    453: 
                    454: /*ARGSUSED*/
                    455: void cmd_edit(frommark, tomark, cmd, bang, extra)
                    456:        MARK    frommark, tomark;
                    457:        CMD     cmd;
                    458:        int     bang;
                    459:        char    *extra;
                    460: {
                    461:        long    line = 1L;      /* might be set to prevline */
                    462: #ifndef CRUNCH
                    463:        char    *init = (char *)0;
                    464: #endif
                    465: 
                    466: 
                    467:        /* if ":vi", then switch to visual mode, and if no file is named
                    468:         * then don't switch files.
                    469:         */
                    470:        if (cmd == CMD_VISUAL)
                    471:        {
                    472:                mode = MODE_VI;
                    473:                msg("");
                    474:                if (!*extra)
                    475:                {
                    476:                        return;
                    477:                }
                    478:        }
                    479: 
                    480:        /* Editing previous file?  Then start at previous line */
                    481:        if (!strcmp(extra, prevorig))
                    482:        {
                    483:                line = prevline;
                    484:        }
                    485: 
                    486: #ifndef CRUNCH
                    487:        /* if we were given an explicit starting line, then start there */
                    488:        if (*extra == '+')
                    489:        {
                    490:                for (init = ++extra; !isspace(*extra); extra++)
                    491:                {
                    492:                }
                    493:                while (isspace(*extra))
                    494:                {
                    495:                        *extra++ = '\0';
                    496:                }
                    497:                if (!*init)
                    498:                {
                    499:                        init = "$";
                    500:                }
                    501:                if (!extra)
                    502:                {
                    503:                        extra = origname;
                    504:                }
                    505:        }
                    506: #endif /* not CRUNCH */
                    507: 
                    508:        /* switch files */
                    509:        if (tmpabort(bang))
                    510:        {
                    511:                tmpstart(extra);
                    512:                if (line <= nlines && line >= 1L)
                    513:                {
                    514:                        cursor = MARK_AT_LINE(line);
                    515:                }
                    516: #ifndef CRUNCH
                    517:                if (init)
                    518:                {
                    519:                        doexcmd(init);
                    520:                }
                    521: #endif
                    522:        }
                    523:        else
                    524:        {
                    525:                msg("Use edit! to abort changes, or w to save changes");
                    526: 
                    527:                /* so we can say ":e!#" next time... */
                    528:                strcpy(prevorig, extra);
                    529:                prevline = 1L;
                    530:        }
                    531: }
                    532: 
                    533: /* This code is also used for rewind -- GB */
                    534: 
                    535: /*ARGSUSED*/
                    536: void cmd_next(frommark, tomark, cmd, bang, extra)
                    537:        MARK    frommark, tomark;
                    538:        CMD     cmd;
                    539:        int     bang;
                    540:        char    *extra;
                    541: {
                    542:        int     i, j;
                    543:        char    *scan;
                    544: 
                    545:        /* if extra stuff given, use ":args" to define a new args list */
                    546:        if (cmd == CMD_NEXT && extra && *extra)
                    547:        {
                    548:                cmd_args(frommark, tomark, cmd, bang, extra);
                    549:        }
                    550: 
                    551:        /* move to the next arg */
                    552:        if (cmd == CMD_NEXT)
                    553:        {
                    554:                i = argno + 1;
                    555:        }
                    556:        else if (cmd == CMD_PREVIOUS)
                    557:        {
                    558:                i = argno - 1;
                    559:        }
                    560:        else /* cmd == CMD_REWIND */
                    561:        {
                    562:                i = 0;
                    563:        }       
                    564:        if (i < 0 || i >= nargs)
                    565:        {
                    566:                msg("No %sfiles to edit", cmd == CMD_REWIND ? "" : "more ");
                    567:                return;
                    568:        }
                    569: 
                    570:        /* find & isolate the name of the file to edit */
                    571:        for (j = i, scan = args; j > 0; j--)
                    572:        {
                    573:                while(*scan++)
                    574:                {
                    575:                }
                    576:        }
                    577: 
                    578:        /* switch to the next file */
                    579:        if (tmpabort(bang))
                    580:        {
                    581:                tmpstart(scan);
                    582:                argno = i;
                    583:        }
                    584:        else
                    585:        {
                    586:                msg("Use :%s! to abort changes, or w to save changes",
                    587:                        cmd == CMD_NEXT ? "next" :
                    588:                        cmd == CMD_PREVIOUS ? "previous" :
                    589:                                        "rewind");
                    590:        }
                    591: }
                    592: 
                    593: /* also called from :wq -- always writes back in this case */
                    594: 
                    595: /*ARGSUSED*/
                    596: void cmd_xit(frommark, tomark, cmd, bang, extra)
                    597:        MARK    frommark, tomark;
                    598:        CMD     cmd;
                    599:        int     bang;
                    600:        char    *extra;
                    601: {
                    602:        static long     whenwarned;     /* when the user was last warned of extra files */
                    603:        int             oldflag;
                    604: 
                    605:        /* if there are more files to edit, then warn user */
                    606:        if (argno >= 0 && argno + 1 < nargs && whenwarned != changes && (!bang || cmd != CMD_QUIT))
                    607:        {
                    608:                msg("More files to edit -- Use \":n\" to go to next file");
                    609:                whenwarned = changes;
                    610:                return;
                    611:        }
                    612: 
                    613:        if (cmd == CMD_QUIT)
                    614:        {
                    615:                oldflag = *o_autowrite;
                    616:                *o_autowrite = FALSE;
                    617:                if (tmpabort(bang))
                    618:                {
                    619:                        mode = MODE_QUIT;
                    620:                }
                    621:                else
                    622:                {
                    623:                        msg("Use q! to abort changes, or wq to save changes");
                    624:                }
                    625:                *o_autowrite = oldflag;
                    626:        }
                    627:        else
                    628:        {
                    629:                /* else try to save this file */
                    630:                oldflag = tstflag(file, MODIFIED);
                    631:                if (cmd == CMD_WQUIT)
                    632:                        setflag(file, MODIFIED);
                    633:                if (tmpend(bang))
                    634:                {
                    635:                        mode = MODE_QUIT;
                    636:                }
                    637:                else
                    638:                {
                    639:                        msg("Could not save file -- use quit! to abort changes, or w filename");
                    640:                }
                    641:                if (!oldflag)
                    642:                        clrflag(file, MODIFIED);
                    643:        }
                    644: }
                    645: 
                    646: 
                    647: /*ARGSUSED*/
                    648: void cmd_args(frommark, tomark, cmd, bang, extra)
                    649:        MARK    frommark, tomark;
                    650:        CMD     cmd;
                    651:        int     bang;
                    652:        char    *extra;
                    653: {
                    654:        char    *scan;
                    655:        int     col;
                    656:        int     arg;
                    657:        int     scrolled = FALSE;
                    658:        int     width;
                    659: 
                    660:        /* if no extra names given, or just current name, then report the args
                    661:         * we have now.
                    662:         */
                    663:        if (!extra || !*extra)
                    664:        {
                    665:                /* empty args list? */
                    666:                if (nargs == 1 && !*args)
                    667:                {
                    668:                        return;
                    669:                }
                    670: 
                    671:                /* list the arguments */
                    672:                for (scan = args, col = arg = 0;
                    673:                     arg < nargs;
                    674:                     scan += width + 1, col += width, arg++)
                    675:                {
                    676:                        width = strlen(scan);
                    677:                        if (col + width >= COLS - 4)
                    678:                        {
                    679:                                addch('\n');
                    680:                                col = 0;
                    681:                                scrolled = TRUE;
                    682:                        }
                    683:                        else if (col > 0)
                    684:                        {
                    685:                                addch(' ');
                    686:                                col++;
                    687:                        }
                    688:                        if (arg == argno)
                    689:                        {
                    690:                                addch('[');
                    691:                                addstr(scan);
                    692:                                addch(']');
                    693:                                col += 2;
                    694:                        }
                    695:                        else
                    696:                        {
                    697:                                addstr(scan);
                    698:                        }
                    699:                }
                    700: 
                    701:                /* write a trailing newline */
                    702:                if ((mode == MODE_EX || mode == MODE_COLON || scrolled) && col)
                    703:                {
                    704:                        addch('\n');
                    705:                }
                    706:                exrefresh();    
                    707:        }
                    708:        else /* new args list given */
                    709:        {
                    710:                for (scan = args, nargs = 1; *extra; )
                    711:                {
                    712:                        if (isspace(*extra))
                    713:                        {
                    714:                                *scan++ = '\0';
                    715:                                while (isspace(*extra))
                    716:                                {
                    717:                                        extra++;
                    718:                                }
                    719:                                if (*extra)
                    720:                                {
                    721:                                        nargs++;
                    722:                                }
                    723:                        }
                    724:                        else
                    725:                        {
                    726:                                *scan++ = *extra++;
                    727:                        }
                    728:                }
                    729:                *scan = '\0';
                    730: 
                    731:                /* reset argno to before the first, so :next will go to first */
                    732:                argno = -1;
                    733: 
                    734:                if (nargs != 1)
                    735:                {
                    736:                         msg("%d files to edit", nargs);
                    737:                }
                    738:        }
                    739: }
                    740: 
                    741: 
                    742: /*ARGSUSED*/
                    743: void cmd_cd(frommark, tomark, cmd, bang, extra)
                    744:        MARK    frommark, tomark;
                    745:        CMD     cmd;
                    746:        int     bang;
                    747:        char    *extra;
                    748: {
                    749:        char    *getenv();
                    750: 
                    751: #ifndef CRUNCH
                    752:        /* if current file is modified, and no '!' was given, then error */
                    753:        if (tstflag(file, MODIFIED) && !bang)
                    754:        {
                    755:                msg("File modified; use \"cd! %s\" to switch anyway", extra);
                    756:        }
                    757: #endif
                    758: 
                    759:        /* default directory name is $HOME */
                    760:        if (!*extra)
                    761:        {
                    762:                extra = getenv("HOME");
                    763:                if (!extra)
                    764:                {
                    765:                        msg("environment variable $HOME not set");
                    766:                        return;
                    767:                }
                    768:        }
                    769: 
                    770:        /* go to the directory */
                    771:        if (chdir(extra) < 0)
                    772:        {
                    773:                perror(extra);
                    774:        }
                    775: }
                    776: 
                    777: 
                    778: /*ARGSUSED*/
                    779: void cmd_map(frommark, tomark, cmd, bang, extra)
                    780:        MARK    frommark, tomark;
                    781:        CMD     cmd;
                    782:        int     bang;
                    783:        char    *extra;
                    784: {
                    785:        char    *mapto;
                    786:        char    *build, *scan;
                    787: #ifndef NO_FKEY
                    788:        static char *fnames[NFKEYS] =
                    789:        {
                    790:                "#10", "#1", "#2", "#3", "#4",
                    791:                "#5", "#6", "#7", "#8", "#9",
                    792: # ifndef NO_SHIFT_FKEY
                    793:                "#10s", "#1s", "#2s", "#3s", "#4s",
                    794:                "#5s", "#6s", "#7s", "#8s", "#9s",
                    795: #  ifndef NO_CTRL_FKEY
                    796:                "#10c", "#1c", "#2c", "#3c", "#4c",
                    797:                "#5c", "#6c", "#7c", "#8c", "#9c",
                    798: #   ifndef NO_ALT_FKEY
                    799:                "#10a", "#1a", "#2a", "#3a", "#4a",
                    800:                "#5a", "#6a", "#7a", "#8a", "#9a",
                    801: #   endif
                    802: #  endif
                    803: # endif
                    804:        };
                    805:        int     key;
                    806: #endif
                    807: 
                    808:        /* "map" with no extra will dump the map table contents */
                    809:        if (!*extra)
                    810:        {
                    811: #ifndef NO_ABBR
                    812:                if (cmd == CMD_ABBR)
                    813:                {
                    814:                        dumpkey(bang ? WHEN_EX|WHEN_VIINP|WHEN_VIREP : WHEN_VIINP|WHEN_VIREP, TRUE);
                    815:                }
                    816:                else
                    817: #endif
                    818:                {
                    819:                        dumpkey(bang ? WHEN_VIINP|WHEN_VIREP : WHEN_VICMD, FALSE);
                    820:                }
                    821:        }
                    822:        else
                    823:        {
                    824:                /* "extra" is key to map, followed by what it maps to */
                    825: 
                    826:                /* handle quoting inside the "raw" string */
                    827:                for (build = mapto = extra;
                    828:                     *mapto && (*mapto != ' ' && *mapto != '\t');
                    829:                     *build++ = *mapto++)
                    830:                {
                    831:                        if (*mapto == ctrl('V') && mapto[1])
                    832:                        {
                    833:                                mapto++;
                    834:                        }
                    835:                }
                    836: 
                    837:                /* skip whitespace, and mark the end of the "raw" string */
                    838:                while ((*mapto == ' ' || *mapto == '\t'))
                    839:                {
                    840:                        *mapto++ = '\0';
                    841:                }
                    842:                *build = '\0';
                    843: 
                    844:                /* strip ^Vs from the "cooked" string */
                    845:                for (scan = build = mapto; *scan; *build++ = *scan++)
                    846:                {
                    847:                        if (*scan == ctrl('V') && scan[1])
                    848:                        {
                    849:                                scan++;
                    850:                        }
                    851:                }
                    852:                *build = '\0';
                    853: 
                    854: #ifndef NO_FKEY
                    855:                /* if the mapped string is '#' and a number, then assume
                    856:                 * the user wanted that function key
                    857:                 */
                    858:                if (extra[0] == '#' && isdigit(extra[1]))
                    859:                {
                    860:                        key = atoi(extra + 1) % 10;
                    861: # ifndef NO_SHIFT_FKEY
                    862:                        build = extra + strlen(extra) - 1;
                    863:                        if (*build == 's')
                    864:                                key += 10;
                    865: #  ifndef NO_CTRL_FKEY
                    866:                        else if (*build == 'c')
                    867:                                key += 20;
                    868: #   ifndef NO_ALT_FKEY
                    869:                        else if (*build == 'a')
                    870:                                key += 30;
                    871: #   endif
                    872: #  endif
                    873: # endif
                    874:                        if (FKEY[key])
                    875:                                mapkey(FKEY[key], mapto, bang ? WHEN_VIINP|WHEN_VIREP : WHEN_VICMD, fnames[key]);
                    876: #if !COHERENT
                    877:                        else
                    878:                                msg("This terminal has no %s key", fnames[key]);
                    879: #endif
                    880:                }
                    881:                else
                    882: #endif
                    883: #ifndef NO_ABBR
                    884:                if (cmd == CMD_ABBR || cmd == CMD_UNABBR)
                    885:                {
                    886:                        mapkey(extra, mapto, bang ? WHEN_EX|WHEN_VIINP|WHEN_VIREP : WHEN_VIINP|WHEN_VIREP, "abbr");
                    887:                }
                    888:                else
                    889: #endif
                    890:                {
                    891:                        mapkey(extra, mapto, bang ? WHEN_VIINP|WHEN_VIREP : WHEN_VICMD, (char *)0);
                    892:                }
                    893:        }
                    894: }
                    895: 
                    896: 
                    897: /*ARGSUSED*/
                    898: void cmd_set(frommark, tomark, cmd, bang, extra)
                    899:        MARK    frommark, tomark;
                    900:        CMD     cmd;
                    901:        int     bang;
                    902:        char    *extra;
                    903: {
                    904:        if (!*extra)
                    905:        {
                    906:                dumpopts(FALSE);/* "FALSE" means "don't dump all" - only set */
                    907:        }
                    908:        else if (!strcmp(extra, "all"))
                    909:        {
                    910:                dumpopts(TRUE); /* "TRUE" means "dump all" - even unset vars */
                    911:        }
                    912:        else
                    913:        {
                    914:                setopts(extra);
                    915: 
                    916:                /* That option may have affected the appearence of text */
                    917:                changes++;
                    918:        }
                    919: }
                    920: 
                    921: /*ARGSUSED*/
                    922: void cmd_tag(frommark, tomark, cmd, bang, extra)
                    923:        MARK    frommark, tomark;
                    924:        CMD     cmd;
                    925:        int     bang;
                    926:        char    *extra;
                    927: {
                    928:        int     fd;     /* file descriptor used to read the file */
                    929:        char    *scan;  /* used to scan through the tmpblk.c */
                    930: #ifdef INTERNAL_TAGS
                    931:        char    *cmp;   /* char of tag name we're comparing, or NULL */
                    932:        char    *end;   /* marks the end of chars in tmpblk.c */
                    933: #else
                    934:        int     i;
                    935: #endif
                    936: #ifndef NO_MAGIC
                    937:        char    wasmagic; /* preserves the original state of o_magic */
                    938: #endif
                    939:        static char prevtag[30];
                    940: 
                    941:        /* if no tag is given, use the previous tag */
                    942:        if (!extra || !*extra)
                    943:        {
                    944:                if (!*prevtag)
                    945:                {
                    946:                        msg("No previous tag");
                    947:                        return;
                    948:                }
                    949:                extra = prevtag;
                    950:        }
                    951:        else
                    952:        {
                    953:                strncpy(prevtag, extra, sizeof prevtag);
                    954:                prevtag[sizeof prevtag - 1] = '\0';
                    955:        }
                    956: 
                    957: #ifndef INTERNAL_TAGS
                    958:        /* use "ref" to look up the tag info for this tag */
                    959:        sprintf(tmpblk.c, "ref -t %s%s %s", (*origname ? "-f" : ""),origname, prevtag);
                    960:        fd = rpipe(tmpblk.c, 0);
                    961:        if (fd < 0)
                    962:        {
                    963:                msg("Can't run \"%s\"", tmpblk.c);
                    964:                return;
                    965:        }
                    966: 
                    967:        /* try to read the tag info */
                    968:        for (scan = tmpblk.c;
                    969:             (i = tread(fd, scan, scan - tmpblk.c + BLKSIZE)) > 0;
                    970:             scan += i)
                    971:        {
                    972:        }
                    973:        *scan = '\0';
                    974: 
                    975:        /* close the pipe.  abort if error */
                    976:        if (rpclose(fd) != 0 || scan < tmpblk.c + 3)
                    977:        {
                    978:                msg("tag \"%s\" not found", extra);
                    979:                return;
                    980:        }
                    981: 
                    982: #else /* use internal code to look up the tag */
                    983:        /* open the tags file */
                    984:        fd = open(TAGS, O_RDONLY);
                    985:        if (fd < 0)
                    986:        {
                    987:                msg("No tags file");
                    988:                return;
                    989:        }
                    990: 
                    991:        /* Hmmm... this would have been a lot easier with <stdio.h> */
                    992: 
                    993:        /* find the line with our tag in it */
                    994:        for(scan = end = tmpblk.c, cmp = extra; ; scan++)
                    995:        {
                    996:                /* read a block, if necessary */
                    997:                if (scan >= end)
                    998:                {
                    999:                        end = tmpblk.c + tread(fd, tmpblk.c, BLKSIZE);
                   1000:                        scan = tmpblk.c;
                   1001:                        if (scan >= end)
                   1002:                        {
                   1003:                                msg("tag \"%s\" not found", extra);
                   1004:                                close(fd);
                   1005:                                return;
                   1006:                        }
                   1007:                }
                   1008: 
                   1009:                /* if we're comparing, compare... */
                   1010:                if (cmp)
                   1011:                {
                   1012:                        /* matched??? wow! */
                   1013:                        if (!*cmp && *scan == '\t')
                   1014:                        {
                   1015:                                break;
                   1016:                        }
                   1017:                        if (*cmp++ != *scan)
                   1018:                        {
                   1019:                                /* failed! skip to newline */
                   1020:                                cmp = (char *)0;
                   1021:                        }
                   1022:                }
                   1023: 
                   1024:                /* if we're skipping to newline, do it fast! */
                   1025:                if (!cmp)
                   1026:                {
                   1027:                        while (scan < end && *scan != '\n')
                   1028:                        {
                   1029:                                scan++;
                   1030:                        }
                   1031:                        if (scan < end)
                   1032:                        {
                   1033:                                cmp = extra;
                   1034:                        }
                   1035:                }
                   1036:        }
                   1037: 
                   1038:        /* found it! get the rest of the line into memory */
                   1039:        for (cmp = tmpblk.c, scan++; scan < end && *scan != '\n'; )
                   1040:        {
                   1041:                *cmp++ = *scan++;
                   1042:        }
                   1043:        if (scan == end)
                   1044:        {
                   1045:                tread(fd, cmp, BLKSIZE - (int)(cmp - tmpblk.c));
                   1046:        }
                   1047:        else
                   1048:                *cmp = *scan;
                   1049: 
                   1050:        /* we can close the tags file now */
                   1051:        close(fd);
                   1052: #endif /* INTERNAL_TAGS */
                   1053: 
                   1054:        /* extract the filename from the line, and edit the file */
                   1055:        for (scan = tmpblk.c; *scan != '\t'; scan++)
                   1056:        {
                   1057:        }
                   1058:        *scan++ = '\0';
                   1059:        if (strcmp(origname, tmpblk.c) != 0)
                   1060:        {
                   1061:                if (!tmpabort(bang))
                   1062:                {
                   1063:                        msg("Use :tag! to abort changes, or :w to save changes");
                   1064:                        return;
                   1065:                }
                   1066:                tmpstart(tmpblk.c);
                   1067:        }
                   1068: 
                   1069:        /* move to the desired line (or to line 1 if that fails) */
                   1070: #ifndef NO_MAGIC
                   1071:        wasmagic = *o_magic;
                   1072:        *o_magic = FALSE;
                   1073: #endif
                   1074:        cursor = MARK_FIRST;
                   1075:        linespec(scan, &cursor);
                   1076:        if (cursor == MARK_UNSET)
                   1077:        {
                   1078:                cursor = MARK_FIRST;
                   1079:                msg("Tag's address is out of date");
                   1080:        }
                   1081: #ifndef NO_MAGIC
                   1082:        *o_magic = wasmagic;
                   1083: #endif
                   1084: }
                   1085: 
                   1086: 
                   1087: 
                   1088: 
                   1089: 
                   1090: /* describe this version of the program */
                   1091: /*ARGSUSED*/
                   1092: void cmd_version(frommark, tomark, cmd, bang, extra)
                   1093:        MARK    frommark;
                   1094:        MARK    tomark;
                   1095:        CMD     cmd;
                   1096:        int     bang;
                   1097:        char    *extra;
                   1098: {
                   1099:        msg("%s", VERSION);
                   1100: #ifdef CREDIT
                   1101:        msg("%s", CREDIT);
                   1102: #endif
                   1103: #ifdef CREDIT2
                   1104:        msg("%s", CREDIT2);
                   1105: #endif
                   1106: #ifdef COMPILED_BY
                   1107:        msg("Compiled by %s", COMPILED_BY);
                   1108: #endif
                   1109: #ifdef COPYING
                   1110:        msg("%s", COPYING);
                   1111: #endif
                   1112: }
                   1113: 
                   1114: 
                   1115: #ifndef NO_MKEXRC
                   1116: /* make a .exrc file which describes the current configuration */
                   1117: /*ARGSUSED*/
                   1118: void cmd_mkexrc(frommark, tomark, cmd, bang, extra)
                   1119:        MARK    frommark;
                   1120:        MARK    tomark;
                   1121:        CMD     cmd;
                   1122:        int     bang;
                   1123:        char    *extra;
                   1124: {
                   1125:        int     fd;
                   1126: 
                   1127:        /* the default name for the .exrc file EXRC */
                   1128:        if (!*extra)
                   1129:        {
                   1130:                extra = EXRC;
                   1131:        }
                   1132: 
                   1133:        /* create the .exrc file */
                   1134:        fd = creat(extra, FILEPERMS);
                   1135:        if (fd < 0)
                   1136:        {
                   1137:                msg("Couldn't create a new \"%s\" file", extra);
                   1138:                return;
                   1139:        }
                   1140: 
                   1141:        /* save stuff */
                   1142:        saveopts(fd);
                   1143:        savemaps(fd, FALSE);
                   1144: #ifndef NO_ABBR
                   1145:        savemaps(fd, TRUE);
                   1146: #endif
                   1147: #ifndef NO_DIGRAPH
                   1148:        savedigs(fd);
                   1149: #endif
                   1150: #ifndef NO_COLOR
                   1151:        savecolor(fd);
                   1152: #endif
                   1153: 
                   1154:        /* close the file */
                   1155:        close(fd);
                   1156:        msg("Configuration saved");
                   1157: }
                   1158: #endif
                   1159: 
                   1160: #ifndef NO_DIGRAPH
                   1161: /*ARGSUSED*/
                   1162: void cmd_digraph(frommark, tomark, cmd, bang, extra)
                   1163:        MARK    frommark;
                   1164:        MARK    tomark;
                   1165:        CMD     cmd;
                   1166:        int     bang;
                   1167:        char    *extra;
                   1168: {
                   1169:        do_digraph(bang, extra);
                   1170: }
                   1171: #endif
                   1172: 
                   1173: 
                   1174: #ifndef NO_ERRLIST 
                   1175: static char    errfile[256];   /* the name of a file containing an error */
                   1176: static long    errline;        /* the line number for an error */
                   1177: static int     errfd = -2;     /* fd of the errlist file */
                   1178: 
                   1179: /* This static function tries to parse an error message.
                   1180:  *
                   1181:  * For most compilers, the first word is taken to be the name of the erroneous
                   1182:  * file, and the first number after that is taken to be the line number where
                   1183:  * the error was detected.  The description of the error follows, possibly
                   1184:  * preceded by an "error ... :" or "warning ... :" label which is skipped.
                   1185:  *
                   1186:  * For Coherent, error messages look like "line#: filename: message".
                   1187:  *
                   1188:  * For non-error lines, or unparsable error lines, this function returns NULL.
                   1189:  * Normally, though, it alters errfile and errline, and returns a pointer to
                   1190:  * the description.
                   1191:  */
                   1192: static char *parse_errmsg(text)
                   1193:        REG char        *text;
                   1194: {
                   1195:        REG char        *cpy;
                   1196:        long            atol();
                   1197: # if COHERENT || TOS /* any Mark Williams compiler */
                   1198:        /* Get the line number.  If no line number, then ignore this line. */
                   1199:        errline = atol(text);
                   1200:        if (errline == 0L)
                   1201:                return (char *)0;
                   1202: 
                   1203:        /* Skip to the start of the filename */
                   1204:        while (*text && *text++ != ':')
                   1205:        {
                   1206:        }
                   1207:        if (!*text++)
                   1208:                return (char *)0;
                   1209: 
                   1210:        /* copy the filename to errfile */
                   1211:        for (cpy = errfile; *text && (*cpy++ = *text++) != ':'; )
                   1212:        {
                   1213:        }
                   1214:        if (!*text++)
                   1215:                return (char *)0;
                   1216:        cpy[-1] = '\0';
                   1217: 
                   1218:        return text;
                   1219: # else /* not a Mark Williams compiler */
                   1220:        char            *errmsg;
                   1221: 
                   1222:        /* the error message is the whole line, by default */
                   1223:        errmsg = text;
                   1224: 
                   1225:        /* skip leading garbage */
                   1226:        while (*text && !isalnum(*text))
                   1227:        {
                   1228:                text++;
                   1229:        }
                   1230: 
                   1231:        /* copy over the filename */
                   1232:        cpy = errfile;
                   1233:        while(isalnum(*text) || *text == '.')
                   1234:        {
                   1235:                *cpy++ = *text++;
                   1236:        }
                   1237:        *cpy = '\0';
                   1238: 
                   1239:        /* ignore the name "Error" and filenames that contain a '/' */
                   1240:        if (*text == '/' || !*errfile || !strcmp(errfile + 1, "rror") || access(errfile, 0) < 0)
                   1241:        {
                   1242:                return (char *)0;
                   1243:        }
                   1244: 
                   1245:        /* skip garbage between filename and line number */
                   1246:        while (*text && !isdigit(*text))
                   1247:        {
                   1248:                text++;
                   1249:        }
                   1250: 
                   1251:        /* if the number is part of a larger word, then ignore this line */
                   1252:        if (*text && isalpha(text[-1]))
                   1253:        {
                   1254:                return (char *)0;
                   1255:        }
                   1256: 
                   1257:        /* get the error line */
                   1258:        errline = 0L;
                   1259:        while (isdigit(*text))
                   1260:        {
                   1261:                errline *= 10;
                   1262:                errline += (*text - '0');
                   1263:                text++;
                   1264:        }
                   1265: 
                   1266:        /* any line which lacks a filename or line number should be ignored */
                   1267:        if (!errfile[0] || !errline)
                   1268:        {
                   1269:                return (char *)0;
                   1270:        }
                   1271: 
                   1272:        /* locate the beginning of the error description */
                   1273:        while (*text && !isspace(*text))
                   1274:        {
                   1275:                text++;
                   1276:        }
                   1277:        while (*text)
                   1278:        {
                   1279: #  ifndef CRUNCH
                   1280:                /* skip "error #:" and "warning #:" clauses */
                   1281:                if (!strncmp(text + 1, "rror ", 5)
                   1282:                 || !strncmp(text + 1, "arning ", 7)
                   1283:                 || !strncmp(text + 1, "atal error", 10))
                   1284:                {
                   1285:                        do
                   1286:                        {
                   1287:                                text++;
                   1288:                        } while (*text && *text != ':');
                   1289:                        continue;
                   1290:                }
                   1291: #  endif
                   1292: 
                   1293:                /* anything other than whitespace or a colon is important */
                   1294:                if (!isspace(*text) && *text != ':')
                   1295:                {
                   1296:                        errmsg = text;
                   1297:                        break;
                   1298:                }
                   1299: 
                   1300:                /* else keep looking... */
                   1301:                text++;
                   1302:        }
                   1303: 
                   1304:        return errmsg;
                   1305: # endif /* not COHERENT */
                   1306: }
                   1307: 
                   1308: /*ARGSUSED*/
                   1309: void cmd_errlist(frommark, tomark, cmd, bang, extra)
                   1310:        MARK    frommark, tomark;
                   1311:        CMD     cmd;
                   1312:        int     bang;
                   1313:        char    *extra;
                   1314: {
                   1315:        static long     endline;/* original number of lines in this file */
                   1316:        static long     offset; /* offset of the next line in the errlist file */
                   1317:        int             i;
                   1318:        char            *errmsg;
                   1319: 
                   1320:        /* if a new errlist file is named, open it */
                   1321:        if (extra && extra[0])
                   1322:        {
                   1323:                /* close the old one */
                   1324:                if (errfd >= 0)
                   1325:                {
                   1326:                        close(errfd);
                   1327:                }
                   1328: 
                   1329:                /* open the new one */
                   1330:                errfd = open(extra, O_RDONLY);
                   1331:                offset = 0L;
                   1332:                endline = nlines;
                   1333:        }
                   1334:        else if (errfd < 0)
                   1335:        {
                   1336:                /* open the default file */
                   1337:                errfd = open(ERRLIST, O_RDONLY);
                   1338:                offset = 0L;
                   1339:                endline = nlines;
                   1340:        }
                   1341: 
                   1342:        /* do we have an errlist file now? */
                   1343:        if (errfd < 0)
                   1344:        {
                   1345:                msg("There is no errlist file");
                   1346:                beep();
                   1347:                return;
                   1348:        }
                   1349: 
                   1350:        /* find the next error message in the file */
                   1351:        do
                   1352:        {
                   1353:                /* read the next line from the errlist */
                   1354:                lseek(errfd, offset, 0);
                   1355:                if (tread(errfd, tmpblk.c, (unsigned)BLKSIZE) <= 0)
                   1356:                {
                   1357:                        msg("No more errors");
                   1358:                        beep();
                   1359:                        close(errfd);
                   1360:                        errfd = -2;
                   1361:                        return;
                   1362:                }
                   1363:                for (i = 0; tmpblk.c[i] != '\n'; i++)
                   1364:                {
                   1365:                }
                   1366:                tmpblk.c[i++] = 0;
                   1367: 
                   1368:                /* look for an error message in the line */
                   1369:                errmsg = parse_errmsg(tmpblk.c);
                   1370:                if (!errmsg)
                   1371:                {
                   1372:                        offset += i;
                   1373:                }
                   1374: 
                   1375:        } while (!errmsg);
                   1376: 
                   1377:        /* switch to the file containing the error, if this isn't it */
                   1378:        if (strcmp(origname, errfile))
                   1379:        {
                   1380:                if (!tmpabort(bang))
                   1381:                {
                   1382:                        msg("Use :er! to abort changes, or :w to save changes");
                   1383:                        beep();
                   1384:                        return;
                   1385:                }
                   1386:                tmpstart(errfile);
                   1387:                endline = nlines;
                   1388:        }
                   1389:        else if (endline == 0L)
                   1390:        {
                   1391:                endline = nlines;
                   1392:        }
                   1393: 
                   1394:        /* go to the line where the error was detected */
                   1395:        cursor = MARK_AT_LINE(errline + (nlines - endline));
                   1396:        if (cursor > MARK_LAST)
                   1397:        {
                   1398:                cursor = MARK_LAST;
                   1399:        }
                   1400:        if (mode == MODE_VI)
                   1401:        {
                   1402:                redraw(cursor, FALSE);
                   1403:        }
                   1404: 
                   1405:        /* display the error message */
                   1406: #ifdef CRUNCH
                   1407:        msg("%.70s", errmsg);
                   1408: #else
                   1409:        if (nlines > endline)
                   1410:        {
                   1411:                msg("line %ld(+%ld): %.60s", errline, nlines - endline, errmsg);
                   1412:        }
                   1413:        else if (nlines < endline)
                   1414:        {
                   1415:                msg("line %ld(-%ld): %.60s", errline, endline - nlines, errmsg);
                   1416:        }
                   1417:        else
                   1418:        {
                   1419:                msg("line %ld: %.65s", errline, errmsg);
                   1420:        }
                   1421: #endif
                   1422: 
                   1423:        /* remember where the NEXT error line will start */
                   1424:        offset += i;
                   1425: }
                   1426: 
                   1427: 
                   1428: /*ARGSUSED*/
                   1429: void cmd_make(frommark, tomark, cmd, bang, extra)
                   1430:        MARK    frommark, tomark;
                   1431:        CMD     cmd;
                   1432:        int     bang;
                   1433:        char    *extra;
                   1434: {
                   1435:        BLK     buf;
                   1436: 
                   1437:        /* if the file hasn't been saved, then complain unless ! */
                   1438:        if (tstflag(file, MODIFIED) && !bang)
                   1439:        {
                   1440:                msg("\"%s\" not saved yet", origname);
                   1441:                return;
                   1442:        }
                   1443: 
                   1444:        /* build the command */
                   1445:        sprintf(buf.c, "%s %s %s%s", (cmd == CMD_CC ? o_cc : o_make), extra, REDIRECT, ERRLIST);
                   1446:        qaddstr(buf.c);
                   1447:        addch('\n');
                   1448: 
                   1449:        /* close the old errlist file, if any */
                   1450:        if (errfd >= 0)
                   1451:        {
                   1452:                close(errfd);
                   1453:                errfd = -3;
                   1454:        }
                   1455: 
                   1456:        /* run the command, with curses temporarily disabled */
                   1457:        suspend_curses();
                   1458:        system(buf.c);
                   1459:        resume_curses(mode == MODE_EX);
                   1460:        if (mode == MODE_COLON)
                   1461:                mode = MODE_VI;
                   1462: 
                   1463:        /* run the "errlist" command */
                   1464:        cmd_errlist(MARK_UNSET, MARK_UNSET, cmd, bang, ERRLIST);
                   1465: }
                   1466: #endif
                   1467: 
                   1468: 
                   1469: 
                   1470: #ifndef NO_COLOR
                   1471: 
                   1472: /* figure out the number of text colors we use with this configuration */
                   1473: # ifndef NO_POPUP
                   1474: #  ifndef NO_VISIBLE
                   1475: #   define NCOLORS 7
                   1476: #  else
                   1477: #   define NCOLORS 6
                   1478: #  endif
                   1479: # else
                   1480: #  ifndef NO_VISIBLE
                   1481: #   define NCOLORS 6
                   1482: #  else
                   1483: #   define NCOLORS 5
                   1484: #  endif
                   1485: # endif
                   1486: 
                   1487: /* the attribute bytes used in each of "when"s */
                   1488: static char bytes[NCOLORS];
                   1489: 
                   1490: static struct
                   1491: {
                   1492:        char    *word;  /* a legal word */
                   1493:        int     type;   /* what type of word this is */
                   1494:        int     val;    /* some other value */
                   1495: }
                   1496:        words[] =
                   1497: {
                   1498:        {"normal",      1,      A_NORMAL},      /* all "when" names must come */
                   1499:        {"standout",    1,      A_STANDOUT},    /* at the top of the list.    */
                   1500:        {"bold",        1,      A_BOLD},        /* The first 3 must be normal,*/
                   1501:        {"underlined",  1,      A_UNDERLINE},   /* standout, and bold; the    */
                   1502:        {"italics",     1,      A_ALTCHARSET},  /* remaining names follow.    */
                   1503: #ifndef NO_POPUP
                   1504:        {"popup",       1,      A_POPUP},
                   1505: #endif
                   1506: #ifndef NO_VISIBLE
                   1507:        {"visible",     1,      A_VISIBLE},
                   1508: #endif
                   1509: 
                   1510:        {"black",       3,      0x00},          /* The color names start right*/
                   1511:        {"blue",        3,      0x01},          /* after the "when" names.    */
                   1512:        {"green",       3,      0x02},
                   1513:        {"cyan",        3,      0x03},
                   1514:        {"red",         3,      0x04},
                   1515:        {"magenta",     3,      0x05},
                   1516:        {"brown",       3,      0x06},
                   1517:        {"white",       3,      0x07},
                   1518:        {"yellow",      3,      0x0E}, /* bright brown */
                   1519:        {"gray",        3,      0x08}, /* bright black?  of course! */
                   1520:        {"grey",        3,      0x08},
                   1521: 
                   1522:        {"bright",      2,      0x08},
                   1523:        {"light",       2,      0x08},
                   1524:        {"blinking",    2,      0x80},
                   1525:        {"on",          0,      0},
                   1526:        {"n",           1,      A_NORMAL},
                   1527:        {"s",           1,      A_STANDOUT},
                   1528:        {"b",           1,      A_BOLD},
                   1529:        {"u",           1,      A_UNDERLINE},
                   1530:        {"i",           1,      A_ALTCHARSET},
                   1531: #ifndef NO_POPUP
                   1532:        {"p",           1,      A_POPUP},
                   1533:        {"menu",        1,      A_POPUP},
                   1534: #endif
                   1535: #ifndef NO_VISIBLE
                   1536:        {"v",           1,      A_VISIBLE},
                   1537: #endif
                   1538:        {(char *)0,     0,      0}
                   1539: };
                   1540: 
                   1541: /*ARGSUSED*/
                   1542: void cmd_color(frommark, tomark, cmd, bang, extra)
                   1543:        MARK    frommark, tomark;
                   1544:        CMD     cmd;
                   1545:        int     bang;
                   1546:        char    *extra;
                   1547: {
                   1548:        int     attrbyte;
                   1549:        int     cmode;
                   1550:        int     nowbg;  /* BOOLEAN: is the next color background? */
                   1551: 
                   1552:        REG char *scan;
                   1553:        REG     i;
                   1554: 
                   1555: 
                   1556: #ifndef CRUNCH
                   1557:        /* if no args are given, then report the current colors */
                   1558:        if (!*extra)
                   1559:        {
                   1560:                /* if no colors are set, then say so */
                   1561:                if (!bytes[0])
                   1562:                {
                   1563:                        msg("no colors have been set");
                   1564:                        return;
                   1565:                }
                   1566: 
                   1567:                /* report all five color combinations */
                   1568:                for (i = 0; i < NCOLORS; i++)
                   1569:                {
                   1570:                        qaddstr("color ");
                   1571:                        qaddstr(words[i].word);
                   1572:                        qaddch(' ');
                   1573:                        if (bytes[i] & 0x80)
                   1574:                                qaddstr("blinking ");
                   1575:                        switch (bytes[i] & 0xf)
                   1576:                        {
                   1577:                          case 0x08:    qaddstr("gray");        break;
                   1578:                          case 0x0e:    qaddstr("yellow");      break;
                   1579:                          case 0x0f:    qaddstr("bright white");break;
                   1580:                          default:
                   1581:                                if (bytes[i] & 0x08)
                   1582:                                        qaddstr("light ");
                   1583:                                qaddstr(words[(bytes[i] & 0x07) + NCOLORS].word);
                   1584:                        }
                   1585:                        qaddstr(" on ");
                   1586:                        qaddstr(words[((bytes[i] >> 4) & 0x07) + NCOLORS].word);
                   1587:                        addch('\n');
                   1588:                        exrefresh();
                   1589:                }
                   1590:                return;
                   1591:        }
                   1592: #endif
                   1593: 
                   1594:        /* The default background color is the same as "normal" chars.
                   1595:         * There is no default foreground color.
                   1596:         */
                   1597:        cmode = A_NORMAL;
                   1598:        attrbyte = bytes[0] & 0x70;
                   1599:        nowbg = FALSE;
                   1600: 
                   1601:        /* parse each word in the "extra" text */
                   1602:        for (scan = extra; *extra; extra = scan)
                   1603:        {
                   1604:                /* locate the end of the word */
                   1605:                while (*scan && *scan != ' ')
                   1606:                {
                   1607:                        scan++;
                   1608:                }
                   1609: 
                   1610:                /* skip whitespace at the end of the word */
                   1611:                while(*scan == ' ')
                   1612:                {
                   1613:                        *scan++ = '\0';
                   1614:                }
                   1615: 
                   1616:                /* lookup the word */
                   1617:                for (i = 0; words[i].word && strcmp(words[i].word, extra); i++)
                   1618:                {
                   1619:                }
                   1620: 
                   1621:                /* if not a word, then complain */
                   1622:                if (!words[i].word)
                   1623:                {
                   1624:                        msg("Invalid color name: %s", extra);
                   1625:                        return;
                   1626:                }
                   1627: 
                   1628:                /* process the word */
                   1629:                switch (words[i].type)
                   1630:                {
                   1631:                  case 1:
                   1632:                        cmode = words[i].val;
                   1633:                        break;
                   1634: 
                   1635:                  case 2:
                   1636:                        attrbyte |= words[i].val;
                   1637:                        break;
                   1638: 
                   1639:                  case 3:
                   1640:                        if (nowbg)
                   1641:                                attrbyte = ((attrbyte & ~0x70) | ((words[i].val & 0x07) << 4));
                   1642:                        else
                   1643:                                attrbyte |= words[i].val;
                   1644:                        nowbg = TRUE;
                   1645:                        break;
                   1646:                }
                   1647:        }
                   1648: 
                   1649:        /* if nowbg isn't set now, then we were never given a foreground color */
                   1650:        if (!nowbg)
                   1651:        {
                   1652:                msg("usage: color [when] [\"bright\"] [\"blinking\"] foreground [background]");
                   1653:                return;
                   1654:        }
                   1655: 
                   1656:        /* the first ":color" command MUST define the "normal" colors */
                   1657:        if (!bytes[0])
                   1658:                cmode = A_NORMAL;
                   1659: 
                   1660:        /* we should now have a cmode and an attribute byte... */
                   1661: 
                   1662:        /* set the color */
                   1663:        setcolor(cmode, attrbyte);
                   1664: 
                   1665:        /* remember what we just did */
                   1666:        bytes[cmode] = attrbyte;
                   1667: 
                   1668:        /* if the other colors haven't been set yet, then set them to defaults */
                   1669:        if (!bytes[1])
                   1670:        {
                   1671:                /* standout is the opposite of normal */
                   1672:                bytes[1] = ((attrbyte << 4) & 0x70 | (attrbyte >> 4) & 0x07);
                   1673:                setcolor(A_STANDOUT, bytes[1]);
                   1674: 
                   1675:                /* if "normal" isn't bright, then bold defaults to normal+bright
                   1676:                 * else bold defaults to bright white.
                   1677:                 */
                   1678:                bytes[2] = attrbyte | ((attrbyte & 0x08) ? 0x0f : 0x08);
                   1679:                setcolor(A_BOLD, bytes[2]);
                   1680: 
                   1681:                /* all others default to the "standout" colors, without blinking */
                   1682:                for (i = 3; i < NCOLORS; i++)
                   1683:                {
                   1684:                        bytes[i] = (bytes[1] & 0x7f);
                   1685:                        setcolor(words[i].val, bytes[i]);
                   1686:                }
                   1687:        }
                   1688: 
                   1689:        /* force a redraw, so we see the new colors */
                   1690:        redraw(MARK_UNSET, FALSE);
                   1691: }
                   1692: 
                   1693: 
                   1694: 
                   1695: void savecolor(fd)
                   1696:        int     fd;     /* file descriptor to write colors to */
                   1697: {
                   1698:        int     i;
                   1699:        char    buf[80];
                   1700: 
                   1701:        /* if no colors are set, then return */
                   1702:        if (!bytes[0])
                   1703:        {
                   1704:                return;
                   1705:        }
                   1706: 
                   1707:        /* save all five color combinations */
                   1708:        for (i = 0; i < NCOLORS; i++)
                   1709:        {
                   1710:                strcpy(buf, "color ");
                   1711:                strcat(buf, words[i].word);
                   1712:                strcat(buf, " ");
                   1713:                if (bytes[i] & 0x80)
                   1714:                        strcat(buf, "blinking ");
                   1715:                switch (bytes[i] & 0xf)
                   1716:                {
                   1717:                  case 0x08:    strcat(buf, "gray");    break;
                   1718:                  case 0x0e:    strcat(buf, "yellow");  break;
                   1719:                  case 0x0f:    strcat(buf, "bright white");break;
                   1720:                  default:
                   1721:                        if (bytes[i] & 0x08)
                   1722:                                strcat(buf, "light ");
                   1723:                        strcat(buf, words[(bytes[i] & 0x07) + NCOLORS].word);
                   1724:                }
                   1725:                strcat(buf, " on ");
                   1726:                strcat(buf, words[((bytes[i] >> 4) & 0x07) + NCOLORS].word);
                   1727:                strcat(buf, "\n");
                   1728:                twrite(fd, buf, (unsigned)strlen(buf));
                   1729:        }
                   1730: }
                   1731: #endif
                   1732: 
                   1733: #ifdef SIGTSTP
                   1734: /* temporarily suspend elvis */
                   1735: /*ARGSUSED*/
                   1736: void cmd_suspend(frommark, tomark, cmd, bang, extra)
                   1737:        MARK    frommark;
                   1738:        MARK    tomark;
                   1739:        CMD     cmd;
                   1740:        int     bang;
                   1741:        char    *extra;
                   1742: {
                   1743:        void    (*func)();      /* stores the previous setting of SIGTSTP */
                   1744: 
                   1745: #if ANY_UNIX
                   1746:        /* the Bourne shell can't handle ^Z */
                   1747:        if (!strcmp(o_shell, "/bin/sh"))
                   1748:        {
                   1749:                msg("The /bin/sh shell doesn't support ^Z");
                   1750:                return;
                   1751:        }
                   1752: #endif
                   1753: 
                   1754:        move(LINES - 1, 0);
                   1755:        if (tstflag(file, MODIFIED))
                   1756:        {
                   1757:                addstr("Warning: \"");
                   1758:                addstr(origname);
                   1759:                addstr("\" modified but not yet saved");
                   1760:                clrtoeol();
                   1761:        }
                   1762:        refresh();
                   1763:        suspend_curses();
                   1764:        func = signal(SIGTSTP, SIG_DFL);
                   1765:        kill (0, SIGTSTP);
                   1766: 
                   1767:        /* the process stops and resumes here */
                   1768: 
                   1769:        signal(SIGTSTP, func);
                   1770:        resume_curses(TRUE);
                   1771:        if (mode == MODE_VI || mode == MODE_COLON)
                   1772:                redraw(MARK_UNSET, FALSE);
                   1773:        else
                   1774:                refresh ();
                   1775: }
                   1776: #endif

unix.superglobalmegacorp.com

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