Annotation of coherent/g/usr/bin/vi/cmd1.c, revision 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.