Annotation of 43BSD/contrib/B/src/bed/vtrm.c, revision 1.1.1.1

1.1       root        1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
                      2: static char rcsid[] = "$Header: vtrm.c,v 1.3 85/08/30 10:11:04 timo Exp $";
                      3: 
                      4: /* History:
                      5:  *     21-aug-85 GvR   added support for AL and DL (parametrized al and dl).
                      6:  *     The Epoch tk    created and modified.
                      7:  */
                      8: 
                      9: /*
                     10:  * Virtual TeRMinal package.
                     11:  *
                     12:  * This package uses termcap to determine the terminal capabilities.
                     13:  *
                     14:  * The lines and columns of our virtual terminal are numbered 
                     15:  *     y = {0...lines-1} from top to bottom, and
                     16:  *     x = {0...cols-1} from left to right,
                     17:  * respectively.
                     18:  *
                     19:  * The Visible Procedures in this package are:
                     20:  *
                     21:  * trmstart(&lines, &cols, &flags)
                     22:  *     Obligatory initialization call (sets tty modes etc.),
                     23:  *     Returns the height and width of the screen to the integers
                     24:  *     whose addresses are passed as parameters, and a flag that
                     25:  *     describes some capabilities.
                     26:  *     Function return value: Yes if all went well, No if the terminal
                     27:  *     is not supported.  An error message has already been displayed.
                     28:  *
                     29:  * trmundefined()
                     30:  *     Sets internal representation of screen and attributes to undefined.
                     31:  *     This is necessary for a hard redraw, which would get optimised to
                     32:  *     oblivion,
                     33:  *
                     34:  * trmsense(&y, &x)
                     35:  *     Returns the cursor position through its parameters
                     36:  *     after a possible manual change by the user.
                     37:  *
                     38:  * trmputdata(yfirst, ylast, indent, data)
                     39:  *     Fill lines {yfirst..ylast} with data, after skipping the initial
                     40:  *     'indent' positions. It is assumed that these positions do not contain
                     41:  *     anything dangerous (like standout cookies or null characters).
                     42:  *
                     43:  * trmscrollup(yfirst, ylast, by)
                     44:  *     Shift lines {yfirst..ylast} up by lines (down |by| if by < 0).
                     45:  *
                     46:  * trmsync(y, x)
                     47:  *     Call to output data to the terminal and set cursor position.
                     48:  *
                     49:  * trmbell()
                     50:  *     Send a (possibly visible) bell, immediately (flushing stdout).
                     51:  *
                     52:  * trmend()
                     53:  *     Obligatory termination call (resets tty modes etc.).
                     54:  *
                     55:  * You may call these as one or more cycles of:
                     56:  *     + trmstart
                     57:  *     +    zero or more times any of the other routines
                     58:  *     + trmend
                     59:  * To catch interrupts and the like, you may call trmend even in the middle
                     60:  * of trmstart.
                     61:  */
                     62: 
                     63: 
                     64: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
                     65: /* Includes and data definitions.                                           */
                     66: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
                     67: 
                     68: #include <stdio.h>
                     69: #include <setjmp.h>
                     70: #ifndef TERMIO
                     71: #include <sgtty.h>
                     72: #else
                     73: #include <termio.h>
                     74: #endif TERMIO
                     75: #include <signal.h>
                     76: #include <ctype.h>             /* for isprint() */
                     77: 
                     78: #include "vtrm.h"
                     79: 
                     80: #ifdef lint
                     81: #define VOID (void)
                     82: #else
                     83: #define VOID
                     84: #endif
                     85: 
                     86: #define Forward
                     87: #define Visible
                     88: #define Hidden static
                     89: #define Procedure
                     90: 
                     91: typedef short intlet;
                     92: typedef char *string;
                     93: typedef char bool;
                     94: #define Yes ((bool) 1)
                     95: #define No  ((bool) 0)
                     96: 
                     97: #define Min(a,b) ((a) <= (b) ? (a) : (b))
                     98: 
                     99: /* tty modes */
                    100: #ifndef TERMIO
                    101: /* v7/BSD tty control */
                    102: Hidden struct sgttyb oldtty, newtty;
                    103: /* to enable type ahead for abled persons on systems that provide this: */
                    104: #ifdef TIOCSETN
                    105: #define stty(fd,bp) VOID ioctl(fd, TIOCSETN, bp)
                    106: #endif
                    107: #else
                    108: /* AT&T tty control */
                    109: Hidden struct termio oldtty, newtty;
                    110: #define gtty(fd,bp) ioctl(fd, TCGETA, bp)
                    111: #define stty(fd,bp) VOID ioctl(fd, TCSETAW, bp)
                    112: #endif TERMIO
                    113: Hidden bool know_ttys = No;
                    114: 
                    115: /* visible data for termcap */
                    116: char PC;
                    117: char *BC;
                    118: char *UP;
                    119: short ospeed;
                    120: 
                    121: Forward int outchar();                 /* procedure for termcap's tputs */
                    122: #define Putstr(str)    tputs((str), 1, outchar)
                    123: extern char *tgoto();
                    124: 
                    125: /* termcap terminal capabilities */
                    126: 
                    127: Hidden int lines;
                    128: Hidden int cols;
                    129: 
                    130: Hidden bool has_am;            /* has automatic margins */
                    131: Hidden bool has_da;            /* display may be retained above screen */
                    132: Hidden bool has_db;            /* display may be retained below screen */
                    133: Hidden bool has_in;            /* not save to have null chars on the screen */
                    134: Hidden bool has_mi;            /* move safely in insert (and delete?) mode */
                    135: Hidden bool has_ms;            /* move safely in standout mode */
                    136: Hidden bool has_xs;            /* standout not erased by overwriting */
                    137: 
                    138: Hidden char *al_str;           /* add new blank line */
                    139: Hidden char *par_al_str;       /* parametrized al (AL) */
                    140: Hidden char *cd_str;           /* clear to end of display */
                    141: Hidden char *ce_str;           /* clear to end of line */
                    142: Hidden char *cl_str;           /* cursor home and clear screen */
                    143: Hidden char *cm_str;           /* cursor motion */
                    144: Hidden char *cr_str;           /* carriage return */
                    145: Hidden char *cs_str;           /* change scrolling region */
                    146: Hidden char *dc_str;           /* delete character */
                    147: Hidden char *dl_str;           /* delete line */
                    148: Hidden char *par_dl_str;       /* parametrized dl (DL) */
                    149: Hidden char *do_str;           /* cursor down one line */
                    150: Hidden char *dm_str;           /* enter delete mode */
                    151: Hidden char *ed_str;           /* end delete mode */
                    152: Hidden char *ei_str;           /* end insert mode */
                    153: Hidden char *ho_str;           /* cursor home */
                    154: Hidden char *ic_str;           /* insert character (iff necessary, maybe pad) */
                    155: Hidden char *im_str;           /* enter insert mode */
                    156: Hidden char *le_str;           /* cursor left */
                    157: Hidden char *nd_str;           /* cursor right (non-destructive space) */
                    158: Hidden char *se_str;           /* end standout mode */
                    159: Hidden char *sf_str;           /* scroll text up (from bottom of region) */
                    160: Hidden char *so_str;           /* begin standout mode */
                    161: Hidden char *sr_str;           /* scroll text down (from top of region) */
                    162: Hidden char *te_str;           /* end termcap */
                    163: Hidden char *ti_str;           /* start termcap */
                    164: Hidden char *up_str;           /* cursor up */
                    165: Hidden char *vb_str;           /* visible bell */
                    166: Hidden char *ve_str;           /* make cursor visible again */
                    167: Hidden char *vi_str;           /* make cursor invisible */
                    168: 
                    169: /* sense cursor position, addition to termcap */
                    170: Hidden char *cp_str;           /* format of returned Cursor Position string */
                    171: Hidden char *sp_str;           /* Sense cursor Position from terminal */
                    172: 
                    173: /* terminal status */
                    174: 
                    175: /* calling order of Visible Procs */
                    176: Hidden bool started = No;
                    177: 
                    178: /* to exports the capabilities mentioned in vtrm.h: */
                    179: Hidden int flags = 0;
                    180: 
                    181: /* cost for impossible operations */
                    182: #define Infinity 9999
                    183:        /* Allow for adding Infinity+Infinity within range */
                    184:        /* (Range is assumed at least 2**15 - 1) */
                    185: 
                    186: /* The following for all sorts of undefined things (except for UNKNOWN char) */
                    187: #define Undefined (-1)
                    188: 
                    189: /* current mode of putting char's */
                    190: #define Normal 0
                    191: #define Insert 1
                    192: #define        Delete  2
                    193: Hidden short mode = Normal;
                    194: 
                    195: /* current standout mode */
                    196: #define Off    0
                    197: #define On     0200
                    198: Hidden short so_mode = Off;
                    199: 
                    200: /* masks for char's and intlet's */
                    201: #define NULCHAR        '\000'
                    202: #define CHAR   0177
                    203: #define SOBIT  On
                    204: #define SOCHAR 0377
                    205: /* if (has_xs) record cookies placed on screen in extra bit */
                    206: /* type of cookie is determined by the SO bit */
                    207: #define XSBIT  0400
                    208: #define SOCOOK 0600
                    209: #define COOKBITS SOCOOK
                    210: #define UNKNOWN        1
                    211: #define NOCOOK UNKNOWN
                    212: 
                    213: /* current cursor position */
                    214: Hidden intlet cur_y = Undefined, cur_x = Undefined;
                    215: 
                    216: /* "line[y][x]" holds the char on the terminal, with the SOBIT and XSBIT.
                    217:  * the SOBIT tells whether the character is standing out, the XSBIT whether
                    218:  * there is a cookie on the screen at this position.
                    219:  * In particular a standend-cookie may be recorded AFTER the line
                    220:  * (just in case some trmputdata will write after that position).
                    221:  * "lenline[y]" holds the length of the line.
                    222:  * Unknown chars will be 1, so the optimising compare in putline will fail.
                    223:  * (Partially) empty lines are distinghuished by "lenline[y] < cols".
                    224:  */
                    225: Hidden intlet **line = 0, *lenline = 0;
                    226: 
                    227: /* Clear the screen initially iff only memory cursor addressing available */
                    228: Hidden bool mustclear = No;
                    229: 
                    230: /* Make the cursor invisible when trmsync() tries to move outside the screen */
                    231: Hidden bool no_cursor = No;
                    232: 
                    233: /* Optimise cursor motion */
                    234: Hidden int abs_cost;           /* cost of absolute cursor motion */
                    235: Hidden int cr_cost;            /* cost of carriage return */
                    236: Hidden int do_cost;            /* cost of down */
                    237: Hidden int le_cost;            /* cost of left */
                    238: Hidden int nd_cost;            /* cost of right */
                    239: Hidden int up_cost;            /* cost of up */
                    240: 
                    241: /* Optimise trailing match in put_line, iff the terminal can insert and delete
                    242:  * characters; the cost per n characters will be:
                    243:  *     n * MultiplyFactor + OverHead
                    244:  */
                    245: Hidden int ins_mf, ins_oh, del_mf, del_oh;
                    246: Hidden int ed_cost, ei_cost;           /* used in move() */
                    247: 
                    248: /* The type of scrolling possible determines which routines get used;
                    249:  * these may be:
                    250:  * (1) with addline and deleteline (termcap: al_str & dl_str);
                    251:  * (2) with a settable scrolling region, like VT100 (cs_str, sr_str, sf_str);
                    252:  * (3) no scrolling available. (NOT YET IMPLEMENTED)
                    253:  */
                    254: Hidden Procedure (*scr_up)();
                    255: Hidden Procedure (*scr_down)();
                    256: Forward Procedure scr1up();
                    257: Forward Procedure scr1down();
                    258: Forward Procedure scr2up();
                    259: Forward Procedure scr2down();
                    260: /*Forward Procedure scr3up(); */
                    261: /*Forward Procedure scr3down(); */
                    262: 
                    263: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
                    264: /* Starting, Ending and (fatal) Error.                                      */
                    265: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
                    266: 
                    267: /* 
                    268:  * Initialization call.
                    269:  * Determine terminal capabilities from termcap.
                    270:  * Set up tty modes.
                    271:  * Start up terminal and internal administration.
                    272:  * Return Yes if succeeded, No if trouble (e.g., bad terminal type).
                    273:  */
                    274: Visible int
                    275: trmstart(plines, pcols, pflags)
                    276: int *plines;
                    277: int *pcols;
                    278: int *pflags;
                    279: {
                    280: #ifdef TRACE
                    281: fprintf(stderr, "\ttrmstart(&li, &co, &fl);\n");
                    282: #endif
                    283:        if (started)
                    284:                trmerr("trmstart called twice in succession");
                    285:        if (!gettermcaps())
                    286:                return No;
                    287:        if (!setttymode())
                    288:                return No;
                    289:        start_trm();
                    290: 
                    291:        *plines = lines;
                    292:        *pcols = cols;
                    293:        *pflags = flags;
                    294:        
                    295:        started = Yes;
                    296:        return Yes;
                    297: }
                    298: 
                    299: /*
                    300:  * Termination call.
                    301:  * Reset tty modes, etc.
                    302:  * Beware that it might be called by a catched interrupt even in the middle
                    303:  * of trmstart()!
                    304:  */
                    305: Visible Procedure
                    306: trmend()
                    307: {
                    308: #ifdef TRACE
                    309: fprintf(stderr, "\ttrmend();\n");
                    310: #endif
                    311:        set_mode(Normal);
                    312:        if (so_mode != Off)
                    313:                standend();
                    314:        Putstr(te_str);
                    315:        VOID fflush(stdout);
                    316:        resetttymode();
                    317: 
                    318:        started = No;
                    319: }
                    320: 
                    321: /*
                    322:  * Set all internal statuses to undefined, especially the contents of
                    323:  * the screen, so a hard redraw will not be optimised to heaven.
                    324:  */
                    325: Visible Procedure
                    326: trmundefined()
                    327: {
                    328:        register int y, x;
                    329: #ifdef TRACE
                    330: fprintf(stderr, "\ttrmundefined();\n");
                    331: #endif
                    332: 
                    333:        cur_y = cur_x = Undefined;
                    334:        mode = so_mode = Undefined;
                    335:        
                    336:        for (y = 0; y < lines; y++) {
                    337:                for (x = 0; x <= cols; x++)
                    338:                        line[y][x] = 1; /* impossible char, no so bits */
                    339:                lenline[y] = cols;
                    340:        }
                    341: }
                    342: 
                    343: /* 
                    344:  * Give an error message, and abort.
                    345:  * The abort can be catched by the calling process.
                    346:  */
                    347: Hidden Procedure
                    348: trmerr(mess)
                    349: string mess;
                    350: {
                    351:        trmreset();
                    352:        fprintf(stderr,
                    353:                "*** System error in screen output module:\n*** %s\n", mess);
                    354:        VOID fflush(stderr);
                    355:        abort();
                    356: }
                    357: 
                    358: /*
                    359:  * Give an error message and reset the tty modes (but don't abort).
                    360:  */
                    361: Hidden Procedure trmmess(mess)
                    362: string mess;
                    363: {
                    364:        trmreset();
                    365:        fprintf(stderr, "*** Fatal error: %s\n", mess);
                    366:        VOID fflush(stderr);
                    367: }
                    368: 
                    369: /*
                    370:  * Complain about a missing terminal feature.  Otherwise like trmmess.
                    371:  */
                    372: Hidden Procedure
                    373: trmsorry(mess)
                    374: string mess;
                    375: {
                    376:     trmreset();
                    377:     fprintf(stderr, (
                    378: #ifdef BED
                    379:       "*** Sorry, this terminal isn't powerful enough to run the B editor.\n"
                    380: #else
                    381:       "*** Sorry, this terminal isn't powerful emough.\n"
                    382: #endif
                    383:     ));
                    384:     fprintf(stderr, "*** The problem is: %s.\n", mess);
                    385: #ifdef BED
                    386:     fprintf(stderr,
                    387:       "*** (You might try 'b -e' to use a standard editor instead.)\n");
                    388: #endif
                    389:     VOID fflush(stderr);
                    390: }
                    391: 
                    392: /*
                    393:  * Prepare for giving a (more or less fatal) error message.
                    394:  */
                    395: Hidden Procedure
                    396: trmreset()
                    397: {
                    398:        if (started) {
                    399:                move(lines-1, 0);
                    400:                clear_lines(lines-1, lines-1);
                    401:        }
                    402:        VOID fflush(stdout);
                    403:        resetttymode();
                    404: }
                    405: 
                    406: Hidden Procedure
                    407: check_started(m)
                    408: char *m;
                    409: {
                    410:        char s[80];
                    411:        
                    412:        if (!started) {
                    413:                VOID sprintf(s, "%s called outside trmstart/trmend", m);
                    414:                trmerr(s);
                    415:        }
                    416: }
                    417: 
                    418: int ccc;
                    419: 
                    420: /*ARGSUSED*/
                    421: Hidden Procedure
                    422: countchar(ch)
                    423: char ch;
                    424: {
                    425:        ccc++;
                    426: }
                    427: 
                    428: Hidden int
                    429: strcost(str)
                    430: char *str;
                    431: {
                    432:        if (str == NULL)
                    433:                return Infinity;
                    434:        return str0cost(str);
                    435: }
                    436: 
                    437: Hidden int
                    438: str0cost(str)
                    439: char *str;
                    440: {
                    441:        ccc = 0;
                    442:        tputs(str, 1, countchar);
                    443:        return ccc;
                    444: }
                    445: 
                    446: Hidden int
                    447: gettermcaps()                  /* get terminal capabilities from termcap
                    448:                                 * and related static properties
                    449:                                 */
                    450: {
                    451:        string trmname;
                    452:        char tc_buf[1024];
                    453:        static char strbuf[1024];
                    454:        char *area = strbuf;
                    455:        char *xPC;
                    456:        char *getenv();
                    457:        int tgetent();
                    458:        int tgetnum();
                    459:        int tgetflag();
                    460:        char *tgetstr();
                    461:        int sg;
                    462:        static bool tc_initialized = No;
                    463: #ifdef TIOCGWINSZ
                    464:        struct winsize win;
                    465: #endif
                    466:        
                    467:        if (tc_initialized)
                    468:                return Yes;
                    469:        
                    470:        if ((trmname=getenv("TERM")) == NULL) {
                    471:                trmmess("terminal type not exported in $TERM variable");
                    472:                return No;
                    473:        }
                    474:        if (tgetent(tc_buf, trmname) != 1) {
                    475:                trmmess("unknown terminal type in $TERM envariable");
                    476:                return No;
                    477:        }
                    478:        
                    479:        if (tgetflag("hc")) {
                    480:                trmsorry("can't use a hardcopy terminal");
                    481:                return No;
                    482:        }
                    483: 
                    484:        BC = tgetstr("le", &area);
                    485:        if (BC == NULL)
                    486:                BC = tgetstr("bc", &area);
                    487:        if (BC == NULL)
                    488:                if (tgetflag("bs"))
                    489:                        BC="\b";
                    490:                else {
                    491:                        trmsorry("no LEFT cursor motion");
                    492:                        return No;
                    493:                }
                    494:        UP = tgetstr("up", &area);
                    495:        if (UP == NULL) {
                    496:                trmsorry("no UP cursor motion");
                    497:                return No;
                    498:        }
                    499:        xPC = tgetstr("pc", &area);
                    500:        PC = (xPC != NULL? xPC[0] : NULCHAR);
                    501: 
                    502:        ho_str = tgetstr("ho", &area);
                    503:        do_str = tgetstr("do", &area);
                    504:        nd_str = tgetstr("nd", &area);
                    505:        cm_str = tgetstr("cm", &area);
                    506:        if (cm_str == NULL) {
                    507:                cm_str = tgetstr("CM", &area);
                    508:                if (cm_str == NULL) {
                    509:                        if (ho_str == NULL || do_str == NULL || nd_str == NULL) {
                    510:                                trmsorry("no absolute cursor motion");
                    511:                                return No;
                    512:                        }
                    513:                }
                    514:                else
                    515:                        mustclear = Yes;
                    516:        }
                    517: 
                    518:        al_str = tgetstr("al", &area);
                    519:        dl_str = tgetstr("dl", &area);
                    520:        par_al_str = tgetstr("AL", &area);
                    521:        par_dl_str = tgetstr("DL", &area);
                    522:        if (al_str && dl_str) {
                    523:                scr_up = scr1up;
                    524:                scr_down = scr1down;
                    525:                flags |= CAN_SCROLL;
                    526:        }
                    527:        else {
                    528:                cs_str = tgetstr("cs", &area);
                    529:                sf_str = tgetstr("sf", &area);
                    530:                if (sf_str == NULL)
                    531:                        sf_str = "\n";
                    532:                sr_str = tgetstr("sr", &area);
                    533:                if (cs_str && sr_str) {
                    534:                        scr_up = scr2up;
                    535:                        scr_down = scr2down;
                    536:                        flags |= CAN_SCROLL;
                    537:                }
                    538:                else {
                    539:                        trmsorry("can't scroll");
                    540:                        return No;
                    541:                }
                    542:        }
                    543:                
                    544:        lines = tgetnum("li");
                    545:        cols = tgetnum("co");
                    546: #ifdef TIOCGWINSZ
                    547:        if (ioctl (0, TIOCGWINSZ, &win) == 0) {
                    548:                if (win.ws_col)
                    549:                        cols = win.ws_col;
                    550:                if (win.ws_row)
                    551:                        lines = win.ws_row;
                    552:        }
                    553: #endif
                    554:        if (lines == -1) lines = 24;
                    555:        if (cols == -1) cols = 80;
                    556:        
                    557:        has_am = tgetflag("am");
                    558:        has_db = tgetflag("db");
                    559:        has_in = tgetflag("in");
                    560:        has_mi = tgetflag("mi");
                    561:        has_ms = tgetflag("ms");
                    562:        has_xs = tgetflag("xs");
                    563:        if ((sg=tgetnum("sg")) == 0)
                    564:                has_xs = Yes;
                    565:        else if (sg > 0) {
                    566:                trmsorry("video attributes take up space on the screen");
                    567:                return No;
                    568:        }
                    569:        
                    570:        cd_str = tgetstr("cd", &area);
                    571:        ce_str = tgetstr("ce", &area);
                    572:        if (!ce_str) {
                    573:                trmsorry("can't clear to end of line");
                    574:                return No;
                    575:        }
                    576:        cl_str = tgetstr("cl", &area);
                    577:        cr_str = tgetstr("cr", &area);
                    578:        if (cr_str == NULL) cr_str = "\r";
                    579:        dc_str = tgetstr("dc", &area);
                    580:        dm_str = tgetstr("dm", &area);
                    581:        if (do_str == NULL) do_str = tgetstr("nl", &area);
                    582:        if (do_str == NULL) do_str = "\n";
                    583:        ed_str = tgetstr("ed", &area);
                    584:        ei_str = tgetstr("ei", &area);
                    585:        ic_str = tgetstr("ic", &area);
                    586:        im_str = tgetstr("im", &area);
                    587:        le_str = BC;
                    588:        se_str = tgetstr("se", &area);
                    589:        so_str = tgetstr("so", &area);
                    590:        te_str = tgetstr("te", &area);
                    591:        ti_str = tgetstr("ti", &area);
                    592:        up_str = UP;
                    593:        vb_str = tgetstr("vb", &area);
                    594:        if (vb_str == NULL)     /* then we will do with the audible bell */
                    595:                vb_str = "\007";
                    596:        ve_str = tgetstr("ve", &area);
                    597:        vi_str = tgetstr("vi", &area);
                    598:        
                    599:        /* cursor sensing (non standard) */
                    600:        cp_str = tgetstr("cp", &area);
                    601:        sp_str = tgetstr("sp", &area);
                    602:        if (cp_str != NULL && sp_str != NULL)
                    603:                flags |= CAN_SENSE;
                    604: 
                    605:        if (so_str != NULL && se_str != NULL)
                    606:                flags |= HAS_STANDOUT;
                    607: 
                    608:        /* calculate costs of local and absolute cursor motions */
                    609:        if (cm_str == NULL)
                    610:                abs_cost = Infinity;
                    611:        else
                    612:                abs_cost = strcost(tgoto(cm_str, 0, 0));
                    613:        cr_cost = strcost(cr_str);
                    614:        do_cost = strcost(do_str);
                    615:        le_cost = strcost(le_str);
                    616:        nd_cost = strcost(nd_str);
                    617:        up_cost = strcost(up_str);
                    618: 
                    619:        /* cost of leaving insert or delete mode, used in move() */
                    620:        ei_cost = str0cost(ei_str);
                    621:        ed_cost = str0cost(ed_str);
                    622:        
                    623:        /* calculate insert and delete cost multiply_factor and overhead */
                    624:        if (((im_str && ei_str) || ic_str) && dc_str) {
                    625:                flags |= CAN_OPTIMISE;
                    626:                ins_mf = 1 + str0cost(ic_str);
                    627:                ins_oh = str0cost(im_str) + ei_cost;
                    628:                del_mf = str0cost(dc_str);
                    629:                del_oh = str0cost(dm_str) + ed_cost;
                    630:        }
                    631:                
                    632:        tc_initialized = Yes;
                    633:        return Yes;
                    634: }
                    635: 
                    636: Hidden int
                    637: setttymode()
                    638: {
                    639:        if (!know_ttys) {
                    640:                if (gtty(1, &oldtty) != 0 || gtty(1, &newtty) != 0) {
                    641:                        trmmess("can't get tty modes (output not a terminal)");
                    642:                        return No;
                    643:                }
                    644: #ifndef TERMIO
                    645:                ospeed = oldtty.sg_ospeed;
                    646: #ifdef PWB
                    647:                newtty.sg_flags = (newtty.sg_flags & ~ECHO & ~CRMOD & ~XTABS)
                    648:                                  | RAW;
                    649: #else PWB
                    650:                newtty.sg_flags = (newtty.sg_flags & ~ECHO & ~CRMOD & ~XTABS)
                    651:                                  | CBREAK;
                    652: #endif PWB
                    653: #else TERMIO
                    654:                ospeed= oldtty.c_lflag & CBAUD;
                    655:                newtty.c_iflag &= ~ICRNL; /* No CR->NL mapping on input */
                    656:                newtty.c_oflag &= ~ONLCR; /* NL doesn't output CR */
                    657:                newtty.c_lflag &= ~(ICANON|ECHO); /* No line editing, no echo */
                    658:                newtty.c_cc[VMIN]= 3; /* wait for 3 characters */
                    659:                newtty.c_cc[VTIME]= 1; /* or 0.1 sec. */
                    660: #endif TERMIO
                    661:                know_ttys = Yes;
                    662:        }
                    663:        stty(1, &newtty);
                    664:        return Yes;
                    665: }
                    666: 
                    667: Hidden Procedure
                    668: resetttymode()
                    669: {
                    670:        if (know_ttys)
                    671:                stty(1, &oldtty);
                    672: }
                    673: 
                    674: Hidden char*
                    675: lalloc(size)
                    676: unsigned size;
                    677: {
                    678:        char *l;
                    679:        char *malloc();
                    680:        
                    681:        l = malloc(size);
                    682:        if (l == NULL)
                    683:                trmerr("not enough memory for screen buffer");
                    684:        return l;
                    685: }
                    686: 
                    687: Hidden Procedure
                    688: start_trm()
                    689: {
                    690:        register int y;
                    691:        
                    692:        if (line == 0) {
                    693:                line = (intlet**) lalloc((unsigned) lines * sizeof(intlet*));
                    694:                for (y = 0; y < lines; y++)
                    695:                        line[y] = (intlet*) lalloc((unsigned) ((cols+1)*sizeof(intlet)));
                    696:        }
                    697:        if (lenline == 0)
                    698:                lenline = (intlet*) lalloc((unsigned) lines * sizeof(intlet));
                    699: 
                    700:        
                    701:        trmundefined();
                    702:        
                    703:        Putstr(ti_str);
                    704:        if (cs_str)
                    705:                Putstr(tgoto(cs_str, lines-1, 0));
                    706:        if (mustclear)
                    707:                clear_lines(0, lines-1);
                    708: }
                    709: 
                    710: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
                    711: /* Sensing and moving the cursor.                                           */
                    712: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
                    713: 
                    714: /*
                    715:  * Sense the current (y, x) cursor position, after a possible manual
                    716:  * change by the user with local cursor motions.
                    717:  * If the terminal cannot be asked for the current cursor position,
                    718:  * or if the string returned by the terminal is garbled,
                    719:  * the position is made Undefined.
                    720:  */
                    721: Visible Procedure
                    722: trmsense(py, px)
                    723:        int *py;
                    724:        int *px;
                    725: {
                    726:        bool getpos();
                    727: 
                    728: #ifdef TRACE
                    729: fprintf(stderr, "\ttrmsense(&yy, &xx);\n");
                    730: #endif
                    731:        check_started("trmsense");
                    732: 
                    733:        *py = *px = Undefined;
                    734:        set_mode(Normal);
                    735:        if (so_mode != Off)
                    736:                standend();
                    737:        
                    738:        if (flags&CAN_SENSE && getpos(py, px)) {
                    739:                if (*py < 0 || lines <= *py || *px < 0 || cols <= *px)
                    740:                        *py = *px = Undefined;
                    741:        }
                    742:        cur_y = *py;
                    743:        cur_x = *px;
                    744: }
                    745: 
                    746: Hidden bool
                    747: getpos(py, px)
                    748: int *py, *px;
                    749: {
                    750:        char *format = cp_str;
                    751:        int fc;                 /* current format character */
                    752:        int ic;                 /* current input character */
                    753:        int num;
                    754:        int on_y = 1;
                    755:        bool incr_orig = No;
                    756:        int i, ni;
                    757: 
                    758:        Putstr(sp_str);
                    759:        VOID fflush(stdout);
                    760: 
                    761:        while (fc = *format++) {
                    762:                if (fc != '%') {
                    763:                        if (getchar() != fc)
                    764:                                return No;
                    765:                }
                    766:                else {
                    767:                        switch (fc = *format++) {
                    768:                        case '%':
                    769:                                if (getchar() != '%')
                    770:                                        return No;
                    771:                                continue;
                    772:                        case 'r':
                    773:                                on_y = 1 - on_y;
                    774:                                continue;
                    775:                        case 'i':
                    776:                                incr_orig = Yes;
                    777:                                continue;
                    778:                        case 'd':
                    779:                                ic = getchar();
                    780:                                if (!isdigit(ic))
                    781:                                        return No;
                    782:                                num = ic - '0';
                    783:                                while (isdigit(ic=getchar()))
                    784:                                        num = 10*num + ic - '0';
                    785:                                VOID ungetc(ic, stdin);
                    786:                                break;
                    787:                        case '2':
                    788:                        case '3':
                    789:                                ni = fc - '0';
                    790:                                num = 0;
                    791:                                for (i=0; i<ni; i++) {
                    792:                                        ic = getchar();
                    793:                                        if (isdigit(ic))
                    794:                                                num = 10*num + ic - '0';
                    795:                                        else
                    796:                                                return No;
                    797:                                }
                    798:                                break;
                    799:                        case '+':
                    800:                                num = getchar() - *format++;
                    801:                                break;
                    802:                        case '-':
                    803:                                num = getchar() + *format++;
                    804:                                break;
                    805:                        default:
                    806:                                return No;
                    807:                        }
                    808:                        /* assign num to parameter */
                    809:                        if (incr_orig)
                    810:                                num--;
                    811:                        if (on_y)
                    812:                                *py = num;
                    813:                        else
                    814:                                *px = num;
                    815:                        on_y = 1 - on_y;
                    816:                }
                    817:        }
                    818: 
                    819:        return Yes;
                    820: }
                    821:                
                    822: /* 
                    823:  * To move over characters by rewriting them, we have to check:
                    824:  * (1) that the screen has been initialised on these positions;
                    825:  * (2) we do not screw up characters
                    826:  * when rewriting line[y] from x_from upto x_to
                    827:  */
                    828: Hidden bool
                    829: rewrite_ok(y, xfrom, xto)
                    830: int y, xfrom, xto;
                    831: {
                    832:        register intlet *plnyx, *plnyto;
                    833:        
                    834:        if (xto > lenline[y])
                    835:                return No;
                    836: 
                    837:        plnyto = &line[y][xto];
                    838:        for (plnyx = &line[y][xfrom]; plnyx <= plnyto; plnyx++)
                    839:                if (*plnyx == UNKNOWN
                    840:                    ||
                    841:                    (!has_xs && (*plnyx & SOBIT) != so_mode)
                    842:                   )
                    843:                        return No;
                    844:        return Yes;
                    845: }
                    846:                
                    847: /*
                    848:  * Move to position y,x on the screen
                    849:  */
                    850: /* possible move types for y and x respectively: */
                    851: #define None   0
                    852: #define Down   1
                    853: #define Up     2
                    854: #define Right  1
                    855: #define ReWrite        2
                    856: #define Left   3
                    857: #define CrWrite        4
                    858: 
                    859: Hidden Procedure
                    860: move(y, x)
                    861: int y, x;
                    862: {
                    863:        int dy, dx;
                    864:        int y_cost, x_cost, y_move, x_move;
                    865:        int mode_cost;
                    866:        int xi;
                    867:        
                    868:        if (cur_y == y && cur_x == x)
                    869:                return;
                    870:        
                    871:        if (!has_mi || mode == Undefined)
                    872:                set_mode(Normal);
                    873:        if (!has_xs && ((!has_ms && so_mode != Off) || so_mode == Undefined))
                    874:                standend();
                    875:        
                    876:        if (cur_y == Undefined || cur_x == Undefined)
                    877:                goto absmove;
                    878:        
                    879:        dy = y - cur_y;
                    880:        dx = x - cur_x;
                    881: 
                    882:        if (dy > 0) {
                    883:                y_move = Down;
                    884:                y_cost = dy * do_cost;
                    885:        }
                    886:        else if (dy < 0) {
                    887:                y_move = Up;
                    888:                y_cost = -dy * up_cost;
                    889:        }
                    890:        else {
                    891:                y_move = None;
                    892:                y_cost = 0;
                    893:        }
                    894:        if (y_cost < abs_cost) {
                    895:                switch (mode) {
                    896:                case Normal:
                    897:                        mode_cost = 0;
                    898:                        break;
                    899:                case Insert:
                    900:                        mode_cost = ei_cost;
                    901:                        break;
                    902:                case Delete:
                    903:                        mode_cost = ed_cost;
                    904:                        break;
                    905:                }
                    906:                if (dx > 0) {
                    907:                        x_cost = dx + mode_cost;
                    908:                        if (dx*nd_cost < x_cost || !rewrite_ok(y, cur_x, x)) {
                    909:                                x_cost = dx * nd_cost;
                    910:                                x_move = Right;
                    911:                        }
                    912:                        else
                    913:                                x_move = ReWrite;
                    914:                }
                    915:                else if (dx < 0) {
                    916:                        x_cost = -dx * le_cost;
                    917:                        x_move = Left;
                    918:                }
                    919:                else {
                    920:                        x_cost = 0;
                    921:                        x_move = None;
                    922:                }
                    923:                if (cr_cost + x + mode_cost < x_cost && rewrite_ok(y, 0, x)) {
                    924:                        x_move = CrWrite;
                    925:                        x_cost = cr_cost + x + mode_cost;
                    926:                }
                    927:        }
                    928:        else
                    929:                x_cost = abs_cost;
                    930: 
                    931:        if (y_cost + x_cost < abs_cost) {
                    932:                switch (y_move) {
                    933:                case Down:
                    934:                        while (dy-- > 0) Putstr(do_str);
                    935:                        break;
                    936:                case Up:
                    937:                        while (dy++ < 0) Putstr(up_str);
                    938:                        break;
                    939:                }
                    940:                switch (x_move) {
                    941:                case Right:
                    942:                        while (dx-- > 0) Putstr(nd_str);
                    943:                        break;
                    944:                case Left:
                    945:                        while (dx++ < 0) Putstr(le_str);
                    946:                        break;
                    947:                case CrWrite:
                    948:                        Putstr(cr_str);
                    949:                        cur_x = 0;
                    950:                        /* FALL THROUGH */
                    951:                case ReWrite:
                    952:                        set_mode(Normal);
                    953:                        for (xi = cur_x; xi < x; xi++)
                    954:                                putchar(line[y][xi]);
                    955:                        break;
                    956:                }
                    957:        }
                    958:        else
                    959:        {
                    960:     absmove:
                    961:                if (cm_str == NULL) {
                    962:                        Putstr(ho_str);
                    963:                        for (cur_y = 0; cur_y < y; ++cur_y)
                    964:                                Putstr(do_str);
                    965:                        /* Should try to use tabs here: */
                    966:                        for (cur_x = 0; cur_x < x; ++cur_x)
                    967:                                Putstr(nd_str);
                    968:                }
                    969:                else
                    970:                        Putstr(tgoto(cm_str, x, y));
                    971:        }
                    972:        
                    973:        cur_y = y;
                    974:        cur_x = x;
                    975: }
                    976: 
                    977: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
                    978: /* Putting data on the screen.                                              */
                    979: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
                    980: 
                    981: /*
                    982:  * Fill screen area with given data.
                    983:  * Characters with the SO-bit (0200) set are put in standout mode.
                    984:  */
                    985: Visible Procedure
                    986: trmputdata(yfirst, ylast, indent, data)
                    987: int yfirst;
                    988: int ylast;
                    989: register int indent;
                    990: register string data;
                    991: {
                    992:        register int y;
                    993:        int x, len, lendata, space;
                    994:                
                    995: #ifdef TRACE
                    996: fprintf(stderr, "\ttrmputdata(%d, %d, %d, \"%s\");\n", yfirst, ylast, indent, data);
                    997: #endif
                    998:        check_started("trmputdata");
                    999:        
                   1000:        if (yfirst < 0)
                   1001:                yfirst = 0;
                   1002:        if (ylast >= lines)
                   1003:                ylast = lines-1;
                   1004:        space = cols*(ylast-yfirst+1) - indent;
                   1005:        if (space <= 0)
                   1006:                return;
                   1007:        yfirst += indent/cols;
                   1008:        indent %= cols;
                   1009:        if (data) {
                   1010:                x = indent;
                   1011:                lendata = strlen(data);
                   1012:                if (ylast == lines-1 && lendata >= space)
                   1013:                        lendata = space - 1;
                   1014:                len = Min(lendata, cols-x);
                   1015:                for (y = yfirst; y <= ylast; ) {
                   1016:                        put_line(y, x, data, len);
                   1017:                        y++;
                   1018:                        lendata -= len;
                   1019:                        if (lendata > 0) {
                   1020:                                x = 0;
                   1021:                                data += len;
                   1022:                                len = Min(lendata, cols);
                   1023:                        }
                   1024:                        else
                   1025:                                break;
                   1026:                }
                   1027:        }
                   1028:        if (y <= ylast)
                   1029:                clear_lines(y, ylast);
                   1030: }
                   1031: 
                   1032: /* 
                   1033:  * We will first try to get the picture:
                   1034:  *
                   1035:  *                  op>>>>>>>>>>>op          oq<<<<<<<<<<<<<<<<<<<<<<<<oq
                   1036:  *                  ^            ^           ^                         ^
                   1037:  *           <xskip><-----m1----><----od-----><-----------m2----------->
                   1038:  *   OLD:   "You're in a maze of twisty little pieces of code, all alike"
                   1039:  *   NEW:          "in a maze of little twisting pieces of code, all alike"
                   1040:  *                  <-----m1----><-----nd------><-----------m2----------->
                   1041:  *                  ^            ^             ^                         ^
                   1042:  *                  np>>>>>>>>>>>np            nq<<<<<<<<<<<<<<<<<<<<<<<<nq
                   1043:  * where
                   1044:  *     op, oq, np, nq are pointers to start and end of Old and New data,
                   1045:  * and
                   1046:  *     xskip = length of indent to be skipped,
                   1047:  *     m1 = length of Matching part at start,
                   1048:  *     od = length of Differing mid on screen,
                   1049:  *     nd = length of Differing mid in data to be put,
                   1050:  *     m2 = length of Matching trail.
                   1051:  *
                   1052:  * Then we will try to find a long blank-or-cleared piece in <nd+m2>:
                   1053:  *
                   1054:  *    <---m1---><---d1---><---nb---><---d2---><---m2--->
                   1055:  *              ^         ^         ^        ^         ^
                   1056:  *              np        bp        bq1      nq        nend
                   1057:  * where
                   1058:  *     bp, bq are pointers to start and AFTER end of blank piece,
                   1059:  * and
                   1060:  *     d1 = length of differing part before blank piece,
                   1061:  *     nb = length of blank piece to be skipped,
                   1062:  *     d2 = length of differing part after blank piece.
                   1063:  * Remarks:
                   1064:  *     d1 + nb + d2 == nd,
                   1065:  * and
                   1066:  *     d2 maybe less than 0.
                   1067:  */
                   1068: Hidden int
                   1069: put_line(y, xskip, data, len)
                   1070: int y, xskip;
                   1071: string data;
                   1072: int len;
                   1073: {
                   1074:        register intlet *op, *oq;
                   1075:        register char *np, *nq, *nend;
                   1076:        char *bp, *bq1, *p, *q;
                   1077:        int m1, m2, od, nd, delta, dd, d1, nb, d2;
                   1078:        bool skipping;
                   1079:        int cost, o_cost;       /* normal and optimising cost */
                   1080:        
                   1081:        /* calculate the magic parameters */
                   1082:        op = &line[y][xskip];
                   1083:        oq = &line[y][lenline[y]-1];
                   1084:        np = data;
                   1085:        nq = nend = data + len - 1;
                   1086:        m1 = m2 = 0;
                   1087:        while ((*op&SOCHAR) == (((intlet)*np)&SOCHAR) && op <= oq && np <= nq)
                   1088:                op++, np++, m1++;
                   1089:        if (flags & CAN_OPTIMISE)
                   1090:                while ((*oq&SOCHAR) == (((intlet)*nq)&SOCHAR) && op <= oq && np <= nq)
                   1091:                        oq--, nq--, m2++;
                   1092:        od = oq - op + 1;
                   1093:        nd = nq - np + 1;
                   1094:        /* now we have the first picture above */
                   1095: 
                   1096:        if (od==0 && nd==0)
                   1097:                return;
                   1098:        delta = nd - od;
                   1099: 
                   1100:        /* find the blank piece */
                   1101:        p = q = bp = bq1 = np;
                   1102:        oq += m2;               /* back to current eol */
                   1103:        if (!has_in) {
                   1104:                while (p <= nend) {
                   1105:                        while (q<=nend && *q==' ' && (op>oq || *op==' '))
                   1106:                                q++, op++;
                   1107:                        if (q - p > bq1 - bp)
                   1108:                                bp = p, bq1 = q;
                   1109:                        p = ++q;
                   1110:                        op++;
                   1111:                }
                   1112:        }
                   1113:        d1 = bp - np;
                   1114:        nb = bq1 - bp;
                   1115:        d2 = nq - bq1 + 1;
                   1116:        
                   1117:        /* what is cheapest:
                   1118:         *      normal: put nd+m2;                         (dd = nd+m2)
                   1119:         *      skipping: put d1, skip nb, put d2+m2;      (dd = d2+m2)
                   1120:         *      optimise: put dd, insert or delete delta.  (dd = min(od,nd))
                   1121:         */
                   1122:        cost = nd + m2;         /* normal cost */
                   1123:        if (nb > abs_cost || (d1 == 0 && nb > 0)) {
                   1124:                skipping = Yes;
                   1125:                cost -= nb - (d1>0 ? abs_cost : 0); /* skipping cost */
                   1126:                dd = d2;
                   1127:        }
                   1128:        else {
                   1129:                skipping = No;
                   1130:                dd = nd;
                   1131:        }
                   1132:        
                   1133:        if (m2 != 0) {
                   1134:                /* try optimising */
                   1135:                o_cost = Min(od, nd);
                   1136:                if (delta > 0)
                   1137:                        o_cost += delta * ins_mf + ins_oh;
                   1138:                else if (delta < 0)
                   1139:                        o_cost += -delta * del_mf + del_oh;
                   1140:                if (o_cost >= cost) {
                   1141:                        /* discard m2, no optimise */
                   1142:                        dd += m2;
                   1143:                        m2 = 0;
                   1144:                }
                   1145:                else {
                   1146:                        dd = Min(od, nd);
                   1147:                        skipping = No;
                   1148:                }
                   1149:        }
                   1150: 
                   1151:        /* and now for the real work */
                   1152:        if (!skipping || d1 > 0)
                   1153:                move(y, xskip + m1);
                   1154: 
                   1155:        if (has_xs)
                   1156:                get_so_mode();
                   1157:        
                   1158:        if (skipping) {
                   1159:                if (d1 > 0) {
                   1160:                        set_mode(Normal);
                   1161:                        put_str(np, d1, No);
                   1162:                }
                   1163:                if (has_xs && so_mode != Off)
                   1164:                        standend();
                   1165:                set_blanks(y, xskip+m1+d1, xskip+m1+d1+nb);
                   1166:                if (dd != 0 || delta < 0) {
                   1167:                        move(y, xskip+m1+d1+nb);
                   1168:                        np = bq1;
                   1169:                }
                   1170:        }
                   1171:        
                   1172:        if (dd > 0) {
                   1173:                set_mode(Normal);
                   1174:                put_str(np, dd, No);
                   1175:        }
                   1176:        
                   1177:        if (m2 > 0) {
                   1178:                if (delta > 0) {
                   1179:                        set_mode(Insert);
                   1180:                        ins_str(np+dd, delta);
                   1181:                }
                   1182:                else if (delta < 0) {
                   1183:                        set_mode(Delete);
                   1184:                        del_str(-delta);
                   1185:                }
                   1186:        }
                   1187:        else {
                   1188:                if (delta < 0) {
                   1189:                        clr_to_eol();
                   1190:                        return;
                   1191:                }
                   1192:        }
                   1193:        
                   1194:        lenline[y] = xskip + len;
                   1195:        if (cur_x == cols) {
                   1196:                if (!has_mi)
                   1197:                        set_mode(Normal);
                   1198:                if (!has_ms)
                   1199:                        so_mode = Undefined;
                   1200:                if (has_am)
                   1201:                        cur_y++;
                   1202:                else
                   1203:                        Putstr(cr_str);
                   1204:                cur_x = 0;
                   1205:        }
                   1206:        else if (has_xs) {
                   1207:                if (m2 == 0) {
                   1208:                        if (so_mode == On)
                   1209:                                standend();
                   1210:                }
                   1211:                else {
                   1212:                        if (!(line[cur_y][cur_x] & XSBIT)) {
                   1213:                                if (so_mode != (line[cur_y][cur_x] & SOBIT))
                   1214:                                        (so_mode ? standend() : standout());
                   1215:                        }
                   1216:                }
                   1217:        }
                   1218: }
                   1219: 
                   1220: Hidden Procedure
                   1221: set_mode(m)
                   1222: int m;
                   1223: {
                   1224:        if (m == mode)
                   1225:                return;
                   1226:        switch (mode) {
                   1227:        case Insert:
                   1228:                Putstr(ei_str);
                   1229:                break;
                   1230:        case Delete:
                   1231:                Putstr(ed_str);
                   1232:                break;
                   1233:        case Undefined:
                   1234:                Putstr(ei_str);
                   1235:                Putstr(ed_str);
                   1236:                break;
                   1237:        }
                   1238:        switch (m) {
                   1239:        case Insert:
                   1240:                Putstr(im_str);
                   1241:                break;
                   1242:        case Delete:
                   1243:                Putstr(dm_str);
                   1244:                break;
                   1245:        }
                   1246:        mode = m;
                   1247: }
                   1248: 
                   1249: Hidden Procedure
                   1250: get_so_mode()
                   1251: {
                   1252:        if (cur_x >= lenline[cur_y] || line[cur_y][cur_x] == UNKNOWN)
                   1253:                so_mode = Off;
                   1254:        else
                   1255:                so_mode = line[cur_y][cur_x] & SOBIT;
                   1256: }
                   1257: 
                   1258: Hidden Procedure
                   1259: standout()
                   1260: {
                   1261:        Putstr(so_str);
                   1262:        so_mode = On;
                   1263:        if (has_xs)
                   1264:                line[cur_y][cur_x] |= SOCOOK;
                   1265: }
                   1266: 
                   1267: Hidden Procedure
                   1268: standend()
                   1269: {
                   1270:        Putstr(se_str);
                   1271:        so_mode = Off;
                   1272:        if (has_xs)
                   1273:                line[cur_y][cur_x] = (line[cur_y][cur_x] & ~SOBIT) | XSBIT;
                   1274: }
                   1275: 
                   1276: Hidden Procedure
                   1277: put_str(data, n, inserting)
                   1278: char *data;
                   1279: int n;
                   1280: bool inserting;
                   1281: {
                   1282:        register intlet c, so;
                   1283:        intlet *ln_y_x, *ln_y_end;
                   1284:        
                   1285:        so = so_mode;
                   1286:        if (has_xs) {
                   1287:                ln_y_x = &line[cur_y][cur_x];
                   1288:                ln_y_end = &line[cur_y][lenline[cur_y]];
                   1289:        }
                   1290:        while (n-- > 0) {
                   1291:                if (has_xs && ln_y_x <= ln_y_end && ((*ln_y_x)&XSBIT))
                   1292:                        so = so_mode = (*ln_y_x)&SOBIT;
                   1293:                        /* this also checks for the standend cookie AFTER */
                   1294:                        /* the line because off the equals sign in <= */
                   1295:                c = ((intlet)(*data++))&SOCHAR;
                   1296:                if ((c&SOBIT) != so) {
                   1297:                        so = c&SOBIT;
                   1298:                        so ? standout() : standend();
                   1299:                }
                   1300:                if (inserting)
                   1301:                        Putstr(ic_str);
                   1302:                put_c(c);
                   1303:                if (has_xs)
                   1304:                        ln_y_x++;
                   1305:        }
                   1306: }
                   1307: 
                   1308: Hidden Procedure
                   1309: ins_str(data, n)
                   1310: char *data;
                   1311: int n;
                   1312: {
                   1313:        int x;
                   1314:        
                   1315:        /* x will start AFTER the line, because there might be a cookie */
                   1316:        for (x = lenline[cur_y]; x >= cur_x; x--)
                   1317:                line[cur_y][x+n] = line[cur_y][x];
                   1318:        put_str(data, n, Yes);
                   1319: }
                   1320: 
                   1321: Hidden Procedure
                   1322: del_str(n)
                   1323: int n;
                   1324: {
                   1325:        int x, xto;
                   1326:        
                   1327:        xto = lenline[cur_y] - n; /* again one too far because of cookie */
                   1328:        if (has_xs) {
                   1329:                for (x = cur_x + n; x >= cur_x; x--) {
                   1330:                        if (line[cur_y][x] & XSBIT)
                   1331:                                break;
                   1332:                }
                   1333:                if (x >= cur_x)
                   1334:                        line[cur_y][cur_x+n] =
                   1335:                                (line[cur_y][cur_x+n] & CHAR)
                   1336:                                |
                   1337:                                (line[cur_y][x] & COOKBITS);
                   1338:        }
                   1339:        for (x = cur_x; x <= xto; x++)
                   1340:                line[cur_y][x] = line[cur_y][x+n];
                   1341:        while (n-- > 0)
                   1342:                Putstr(dc_str);
                   1343: }
                   1344: 
                   1345: Hidden Procedure
                   1346: put_c(c)
                   1347: intlet c;
                   1348: {
                   1349:        char ch;
                   1350:        intlet xs_flag;
                   1351:        
                   1352:        ch = c&CHAR;
                   1353:        if (!isprint(ch) && ch != ' ') { /* V7 isprint doesn't include blank */
                   1354:                ch = '?';
                   1355:                c = (c&SOBIT)|'?';
                   1356:        }
                   1357:        putchar(ch);
                   1358:        if (has_xs)
                   1359:                xs_flag = line[cur_y][cur_x]&XSBIT;
                   1360:        else
                   1361:                xs_flag = 0;
                   1362:        line[cur_y][cur_x] = (c&SOCHAR)|xs_flag;
                   1363:        cur_x++;
                   1364: }
                   1365: 
                   1366: Hidden Procedure
                   1367: clear_lines(yfirst, ylast)
                   1368: int yfirst, ylast ;
                   1369: {
                   1370:        register int y;
                   1371:        
                   1372:        if (!has_xs && so_mode != Off)
                   1373:                standend();
                   1374:        if (cl_str && yfirst == 0 && ylast == lines-1) {
                   1375:                Putstr(cl_str);
                   1376:                cur_y = cur_x = 0;
                   1377:                return;
                   1378:        }
                   1379:        for (y = yfirst; y <= ylast; y++) {
                   1380:                if (lenline[y] > 0) {
                   1381:                        move(y, 0);
                   1382:                        if (ylast == lines-1 && cd_str) {
                   1383:                                Putstr(cd_str);
                   1384:                                while (y <= ylast) {
                   1385:                                        if (has_xs) line[y][0] = NOCOOK;
                   1386:                                        lenline[y++] = 0;
                   1387:                                }
                   1388:                                break;
                   1389:                        }
                   1390:                        else {
                   1391:                                clr_to_eol();
                   1392:                        }
                   1393:                }
                   1394:        }
                   1395: }
                   1396: 
                   1397: Hidden Procedure
                   1398: clr_to_eol()
                   1399: {
                   1400:        lenline[cur_y] = cur_x;
                   1401:        if (!has_xs && so_mode != Off)
                   1402:                standend();
                   1403:        Putstr(ce_str);
                   1404:        if (has_xs) {
                   1405:                if (cur_x == 0)
                   1406:                        line[cur_y][0] = NOCOOK;
                   1407:                else if (line[cur_y][cur_x-1]&SOBIT)
                   1408:                        standend();
                   1409:        }
                   1410: }
                   1411: 
                   1412: Hidden Procedure
                   1413: set_blanks
                   1414: (y, xfrom, xto)
                   1415: int y, xfrom, xto;
                   1416: {
                   1417:        register int x;
                   1418:        
                   1419:        for (x = xfrom; x < xto; x++) {
                   1420:                line[y][x] = (line[y][x]&XSBIT) | ' ';
                   1421:        }
                   1422: }
                   1423: 
                   1424: /* 
                   1425:  * outchar() is used by termcap's tputs;
                   1426:  * we can't use putchar because that's probably a macro
                   1427:  */
                   1428: Hidden int
                   1429: outchar(ch)
                   1430: char ch;
                   1431: {
                   1432:        putchar(ch);
                   1433: }
                   1434: 
                   1435: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
                   1436: /* Scrolling (part of) the screen up (or down, dy<0).                       */
                   1437: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
                   1438: 
                   1439: Visible Procedure
                   1440: trmscrollup(yfirst, ylast, by)
                   1441: register int yfirst;
                   1442: register int ylast;
                   1443: register int by;
                   1444: {
                   1445: #ifdef TRACE
                   1446: fprintf(stderr, "\ttrmscrollup(%d, %d, %d);\n", yfirst, ylast, by);
                   1447: #endif
                   1448:        check_started("trmscrollup");
                   1449:        
                   1450:        if (yfirst < 0)
                   1451:                yfirst = 0;
                   1452:        if (ylast >= lines)
                   1453:                ylast = lines-1;
                   1454: 
                   1455:        if (yfirst > ylast)
                   1456:                return;
                   1457: 
                   1458:        if (!has_xs && so_mode != Off)
                   1459:                standend();
                   1460:        
                   1461:        if (by > 0 && yfirst + by > ylast
                   1462:            ||
                   1463:            by < 0 && yfirst - by > ylast)
                   1464:        {
                   1465:                clear_lines(yfirst, ylast);
                   1466:                return;
                   1467:        }
                   1468:        
                   1469:        if (by > 0) {
                   1470:                (*scr_up)(yfirst, ylast, by);
                   1471:                scr_lines(yfirst, ylast, by, 1);
                   1472:        }
                   1473:        else if (by < 0) {
                   1474:                (*scr_down)(yfirst, ylast, -by);
                   1475:                scr_lines(ylast, yfirst, -by, -1);
                   1476:        }
                   1477: }
                   1478: 
                   1479: Hidden Procedure
                   1480: scr_lines(yfrom, yto, n, dy)
                   1481: int yfrom, yto, n, dy;
                   1482: {
                   1483:        register int y;
                   1484:        intlet *saveln;
                   1485:        
                   1486:        while (n-- > 0) {
                   1487:                saveln = line[yfrom];
                   1488:                for (y = yfrom; y != yto; y += dy) {
                   1489:                        line[y] = line[y+dy];
                   1490:                        lenline[y] = lenline[y+dy];
                   1491:                }
                   1492:                line[yto] = saveln;
                   1493:                lenline[yto] = 0;
                   1494:                if (has_xs) line[yto][0] = NOCOOK;
                   1495:        }
                   1496: }
                   1497: 
                   1498: Hidden Procedure
                   1499: scr1up(yfirst, ylast, n)
                   1500:        int yfirst;
                   1501:        int ylast;
                   1502:        int n;
                   1503: {
                   1504:        move(yfirst, 0);
                   1505:        dellines(n);
                   1506:        if (ylast < lines-1) {
                   1507:                move(ylast-n+1, 0);
                   1508:                addlines(n);
                   1509:        }
                   1510: }
                   1511: 
                   1512: Hidden Procedure
                   1513: scr1down(yfirst, ylast, n)
                   1514:        int yfirst;
                   1515:        int ylast;
                   1516:        int n;
                   1517: {
                   1518:        if (ylast == lines-1) {
                   1519:                clear_lines(ylast-n+1, ylast);
                   1520:        }
                   1521:        else {
                   1522:                move(ylast-n+1, 0);
                   1523:                dellines(n);
                   1524:        }
                   1525:        move(yfirst, 0);
                   1526:        addlines(n);
                   1527: }
                   1528: 
                   1529: Hidden Procedure
                   1530: addlines(n)
                   1531: register int n;
                   1532: {
                   1533:        if (par_al_str && n > 1)
                   1534:                        Putstr(tgoto(par_al_str, n, n));
                   1535:        else {
                   1536:                while (n-- > 0)
                   1537:                        Putstr(al_str);
                   1538:        }
                   1539: }
                   1540: 
                   1541: Hidden Procedure
                   1542: dellines(n)
                   1543: register int n;
                   1544: {
                   1545:        if (par_dl_str && n > 1)
                   1546:                Putstr(tgoto(par_dl_str, n, n));
                   1547:        else {
                   1548:                while (n-- > 0)
                   1549:                        Putstr(dl_str);
                   1550:        }
                   1551: }
                   1552: 
                   1553: Hidden Procedure
                   1554: scr2up(yfirst, ylast, n)
                   1555: int yfirst, ylast, n;
                   1556: {
                   1557:        Putstr(tgoto(cs_str, ylast, yfirst));
                   1558:        cur_y = cur_x = Undefined;
                   1559:        move(ylast, 0);
                   1560:        while (n-- > 0) {
                   1561:                Putstr(sf_str);
                   1562:                if (has_db && ylast == lines-1)
                   1563:                        clr_to_eol();
                   1564:        }
                   1565:        Putstr(tgoto(cs_str, lines-1, 0));
                   1566:        cur_y = cur_x = Undefined;
                   1567: }
                   1568: 
                   1569: Hidden Procedure
                   1570: scr2down(yfirst, ylast, n)
                   1571: int yfirst, ylast, n;
                   1572: {
                   1573:        Putstr(tgoto(cs_str, ylast, yfirst));
                   1574:        cur_y = cur_x = Undefined;
                   1575:        move(yfirst, 0);
                   1576:        while (n-- > 0) {
                   1577:                Putstr(sr_str);
                   1578:                if (has_da && yfirst == 0)
                   1579:                        clr_to_eol();
                   1580:        }
                   1581:        Putstr(tgoto(cs_str, lines-1, 0));
                   1582:        cur_y = cur_x = Undefined;
                   1583: }
                   1584: 
                   1585: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
                   1586: /* Synchronization, move cursor to given position (or previous if < 0).     */
                   1587: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
                   1588: 
                   1589: Visible Procedure
                   1590: trmsync(y, x)
                   1591:        int y;
                   1592:        int x;
                   1593: {
                   1594: #ifdef TRACE
                   1595: fprintf(stderr, "\ttrmsync(%d, %d);\n", y, x);
                   1596: #endif
                   1597:        check_started("trmsync");
                   1598:        
                   1599:        if (0 <= y && y < lines && 0 <= x && x < cols) {
                   1600:                move(y, x);
                   1601:                if (no_cursor) {
                   1602:                        Putstr(ve_str);
                   1603:                        no_cursor = No;
                   1604:                }
                   1605:        }
                   1606:        else if (no_cursor == No) {
                   1607:                Putstr(vi_str);
                   1608:                no_cursor = Yes;
                   1609:        }
                   1610:        VOID fflush(stdout);
                   1611: }
                   1612: 
                   1613: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
                   1614: /* Send a bell, visible if possible.                                        */
                   1615: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
                   1616: 
                   1617: Visible Procedure
                   1618: trmbell()
                   1619: {
                   1620: #ifdef TRACE
                   1621: fprintf(stderr, "\ttrmbell();\n");
                   1622: #endif
                   1623:        check_started("trmbell");
                   1624:        
                   1625:        Putstr(vb_str);
                   1626:        VOID fflush(stdout);
                   1627: }
                   1628: 
                   1629: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
                   1630: /* Show the current internal statuses of the screen on stderr.              */
                   1631: /* For debugging only.                                                      */
                   1632: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
                   1633: 
                   1634: #ifdef SHOW
                   1635: Visible Procedure
                   1636: trmshow(s)
                   1637: char *s;
                   1638: {
                   1639:        int y, x;
                   1640:        
                   1641:        fprintf(stderr, "<<< %s >>>\n", s);
                   1642:        for (y = 0; y < lines; y++) {
                   1643:                for (x = 0; x <= lenline[y] /*** && x < cols-1 ***/ ; x++) {
                   1644:                        fputc(line[y][x]&CHAR, stderr);
                   1645:                }
                   1646:                fputc('\n', stderr);
                   1647:                for (x = 0; x <= lenline[y] && x < cols-1; x++) {
                   1648:                        if (line[y][x]&SOBIT)
                   1649:                                fputc('-', stderr);
                   1650:                        else
                   1651:                                fputc(' ', stderr);
                   1652:                }
                   1653:                fputc('\n', stderr);
                   1654:                for (x = 0; x <= lenline[y] && x < cols-1; x++) {
                   1655:                        if (line[y][x]&XSBIT)
                   1656:                                fputc('+', stderr);
                   1657:                        else
                   1658:                                fputc(' ', stderr);
                   1659:                }
                   1660:                fputc('\n', stderr);
                   1661:        }
                   1662:        fprintf(stderr, "CUR_Y = %d, CUR_X = %d.\n", cur_y, cur_x);
                   1663:        VOID fflush(stderr);
                   1664: }
                   1665: #endif

unix.superglobalmegacorp.com

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