1: /*************************************************************************
   2:  * This program is copyright (C) 1985, 1986 by Jonathan Payne.  It is    *
   3:  * provided to you without charge for use only on a licensed Unix        *
   4:  * system.  You may copy JOVE provided that this notice is included with *
   5:  * the copy.  You may not sell copies of this program or versions        *
   6:  * modified for use on microcomputer systems, unless the copies are      *
   7:  * included with a Unix system distribution and the source is provided.  *
   8:  *************************************************************************/
   9: 
  10: #include "jove.h"
  11: #include "ctype.h"
  12: #include "termcap.h"
  13: 
  14: #include <varargs.h>
  15: #include <signal.h>
  16: #include <sys/stat.h>
  17: 
  18: /* Kludge windows gets called by the routines that delete lines from the
  19:    buffer.  If the w->w_line or w->w_top are deleted and this procedure
  20:    is not called, the redisplay routine will barf. */
  21: 
  22: ChkWindows(line1, line2)
  23: Line    *line1;
  24: register Line   *line2;
  25: {
  26:     register Window *w = fwind;
  27:     register Line   *lp;
  28: 
  29:     do {
  30:         for (lp = line1->l_next; lp != line2->l_next; lp = lp->l_next) {
  31:             if (lp == w->w_top)
  32:                 w->w_flags |= TOPGONE;
  33:             if (lp == w->w_line)
  34:                 w->w_flags |= CURGONE;
  35:         }
  36:         w = w->w_next;
  37:     } while (w != fwind);
  38: }
  39: 
  40: extern int  RingBell;
  41: 
  42: redisplay()
  43: {
  44:     register Window *w = fwind;
  45:     int lineno,
  46:         done_ID = 0,
  47:         i;
  48:     register struct scrimage    *des_p,
  49:                     *phys_p;
  50: 
  51:     curwind->w_line = curwind->w_bufp->b_dot;
  52:     curwind->w_char = curwind->w_bufp->b_char;
  53: 
  54:     if (InputPending = charp())
  55:         return;
  56: 
  57: #ifdef JOB_CONTROL
  58:     if (UpdFreq)
  59:         sighold(SIGALRM);
  60: #endif
  61:     if (RingBell) {
  62:         dobell(1);
  63:         RingBell = 0;
  64:     }
  65:     if (UpdMesg)
  66:         DrawMesg(YES);
  67: 
  68:     for (lineno = 0, w = fwind; lineno < ILI; w = w->w_next) {
  69:         UpdWindow(w, lineno);
  70:         lineno += w->w_height;
  71:     }
  72: 
  73:     des_p = DesiredScreen;
  74:     phys_p = PhysScreen;
  75:     for (i = 0; i < ILI; i++, des_p++, phys_p++) {
  76:         if (!done_ID && (des_p->s_id != phys_p->s_id)) {
  77:             DoIDline(i);
  78:             done_ID++;
  79:         }
  80:         if ((des_p->s_flags & (DIRTY | L_MOD)) ||
  81:             (des_p->s_id != phys_p->s_id) ||
  82:             (des_p->s_vln != phys_p->s_vln) ||
  83:             (des_p->s_offset != phys_p->s_offset))
  84:             UpdLine(i);
  85:         if (InputPending)
  86:             goto ret;
  87:     }
  88: 
  89:     UpdModLine = 0;
  90: 
  91:     if (Asking) {
  92:         Placur(LI - 1, min(CO - 2, calc_pos(mesgbuf, Asking)));
  93:             /* Nice kludge */
  94:         flusho();
  95:     } else
  96:         GotoDot();
  97: ret:
  98: #ifdef JOB_CONTROL
  99:     if (UpdFreq)
 100:         sigrelse(SIGALRM);
 101: #else
 102:     ;   /* yuck */
 103: #endif
 104: 
 105: }
 106: 
 107: dobell(n)
 108: {
 109:     while (--n >= 0) {
 110:         if (VisBell && VB)
 111:             putstr(VB);
 112:         else
 113:             putpad("20\007", 1);
 114:     }
 115:     flusho();
 116: }
 117: 
 118: /* find_pos() returns the position on the line, that c_char represents
 119:    in line. */
 120: 
 121: find_pos(line, c_char)
 122: Line    *line;
 123: {
 124:     return calc_pos(lcontents(line), c_char);
 125: }
 126: 
 127: calc_pos(lp, c_char)
 128: register char   *lp;
 129: register int    c_char;
 130: {
 131:     register int    pos = 0;
 132:     register int    c;
 133: 
 134:     while ((--c_char >= 0) && ((c = *lp++) & 0177) != 0) {
 135:         if (c == '\t')
 136:             pos += (tabstop - (pos % tabstop));
 137:         else if (isctrl(c))
 138:             pos += 2;
 139:         else
 140:             pos++;
 141:     }
 142:     return pos;
 143: }
 144: 
 145: int UpdModLine = 0,
 146:     UpdMesg = 0,
 147:     CanScroll = 0;
 148: 
 149: DoIDline(start)
 150: {
 151:     register struct scrimage    *des_p = &DesiredScreen[start];
 152:     struct scrimage *phys_p = &PhysScreen[start];
 153:     register int    i,
 154:             j;
 155: 
 156:     /* Some changes have been made.  Try for insert or delete lines.
 157: 	   If either case has happened, Addlines and/or DelLines will do
 158: 	   necessary scrolling, also CONVERTING PhysScreen to account for the
 159: 	   physical changes.  The comparison continues from where the
 160: 	   insertion/deletion takes place; this doesn't happen very often,
 161: 	   usually it happens with more than one window with the same
 162: 	   buffer. */
 163: 
 164:     if (!CanScroll)
 165:         return;     /* We should never have been called! */
 166: 
 167:     for (i = start; i < ILI; i++, des_p++, phys_p++)
 168:         if (des_p->s_id != phys_p->s_id)
 169:             break;
 170: 
 171:     for (; i < ILI; i++) {
 172:         for (j = i + 1; j < ILI; j++) {
 173:             des_p = &DesiredScreen[j];
 174:             phys_p = &PhysScreen[j];
 175:             if (des_p->s_id != 0 && des_p->s_id == phys_p->s_id)
 176:                 break;
 177:             if (des_p->s_id == PhysScreen[i].s_id) {
 178:                 if (des_p->s_id == 0)
 179:                     continue;
 180:                 if (AddLines(i, j - i)) {
 181:                     DoIDline(j);
 182:                     return;
 183:                 }
 184:                 break;
 185:             }
 186:             if ((des_p = &DesiredScreen[i])->s_id == phys_p->s_id) {
 187:                 if (des_p->s_id == 0)
 188:                     continue;
 189:                 if (DelLines(i, j - i)) {
 190:                     DoIDline(i);
 191:                     return;
 192:                 }
 193:                 break;
 194:             }
 195:         }
 196:     }
 197: }
 198: 
 199: /* Make DesiredScreen reflect what the screen should look like when we are done
 200:    with the redisplay.  This deals with horizontal scrolling.  Also makes
 201:    sure the current line of the Window is in the window. */
 202: 
 203: UpdWindow(w, start)
 204: register Window *w;
 205: {
 206:     Line    *lp;
 207:     int i,
 208:         DotIsHere = 0,
 209:         upper,      /* Top of window */
 210:         lower,      /* Bottom of window */
 211:         ntries = 0; /* # of tries at updating window. */
 212:     register struct scrimage    *des_p,
 213:                     *phys_p;
 214:     Buffer  *bp = w->w_bufp;
 215: 
 216: retry:
 217:     if (w->w_flags & CURGONE) {
 218:         w->w_line = bp->b_dot;
 219:         w->w_char = bp->b_char;
 220:     }
 221:     if (w->w_flags & TOPGONE)
 222:         CentWind(w);    /* Reset topline of screen */
 223:     w->w_flags = 0;
 224:     for (i = w->w_height, lp = w->w_top; --i > 0 && lp != 0; lp = lp->l_next)
 225:         if (lp == w->w_line)
 226:             break;
 227:     if (i == 0 || lp == 0) {    /* Current line not in window */
 228:         ntries++;
 229:         if (ntries == 1) {
 230:             CalcWind(w);
 231:             goto retry;
 232:         } else if (ntries == 2) {
 233:             w->w_top = w->w_line = w->w_bufp->b_first;
 234:             f_mess("ERROR in redisplay: I got hopelessly lost!");
 235:             goto retry;
 236:         } else if (ntries == 3) {
 237:             printf("\rOops, still lost, quitting ...\r\n");
 238:             finish(1);
 239:         }
 240:     }
 241: 
 242:     upper = start;
 243:     lower = upper + w->w_height - 1;    /* Don't include modeline */
 244:     des_p = &DesiredScreen[upper];
 245:     phys_p = &PhysScreen[upper];
 246:     for (i = upper, lp = w->w_top; lp != 0 && i < lower; i++, des_p++, phys_p++, lp = lp->l_next) {
 247:         des_p->s_window = w;
 248:         des_p->s_lp = lp;
 249:         des_p->s_id = lp->l_dline & ~DIRTY;
 250:         des_p->s_flags = isdirty(lp) ? L_MOD : 0;
 251:         if (w->w_numlines)
 252:             des_p->s_vln = w->w_topnum + (i - upper);
 253:         else
 254:             des_p->s_vln = 0;
 255: 
 256:         if (lp == w->w_line) {
 257:             int diff = w->w_numlines ? 8 : 0,
 258:                 strt_col = phys_p->s_offset,
 259:                 end_col = strt_col + (CO - 2) - diff;
 260: 
 261:             /* Right now we are displaying from strt_col to
 262: 			   end_col of the buffer line.  These are PRINT
 263: 			   colums, not actual characters. */
 264:             w->w_dotline = i;
 265:             w->w_dotcol = find_pos(lp, w->w_char);
 266:             /* if the new dotcol is out of range, reselect
 267: 			   a horizontal window */
 268:             if (w->w_dotcol < strt_col || w->w_dotcol >= end_col) {
 269:                 if (w->w_dotcol < ((CO - 2) - diff))
 270:                     strt_col = 0;
 271:                 else
 272:                     strt_col = w->w_dotcol - (CO / 2);
 273:             }
 274:             w->w_dotcol += diff;
 275:             des_p->s_offset = strt_col;
 276:             DotIsHere++;
 277:         } else
 278:             des_p->s_offset = 0;
 279:     }
 280:     if (!DotIsHere) {
 281:         f_mess("DotNotHere is impossible!");
 282:         finish(1);
 283:     }
 284: 
 285:     /* Is structure assignment faster than copy each field seperately */
 286:     if (i < lower) {
 287:         static struct scrimage  dirty_plate = { 0, DIRTY, 0, 0, 0, 0 },
 288:                     clean_plate = { 0, 0, 0, 0, 0, 0 };
 289: 
 290:         for (; i < lower; i++, des_p++, phys_p++)
 291:             if (phys_p->s_id != 0)
 292:                 *des_p = dirty_plate;
 293:             else
 294:                 *des_p = clean_plate;
 295:     }
 296: 
 297:     des_p->s_window = w;
 298:     des_p->s_flags = 0;
 299:     if (((des_p->s_id = (int) w->w_bufp) != phys_p->s_id) || UpdModLine)
 300:         des_p->s_flags = MODELINE | DIRTY;
 301: }
 302: 
 303: /* Write whatever is in mesgbuf (maybe we are Asking, or just printed
 304:    a message).  Turns off the UpdateMesg line flag. */
 305: 
 306: DrawMesg(abortable)
 307: {
 308:     if (charp())
 309:         return;
 310:     i_set(ILI, 0);
 311:     if (swrite(mesgbuf, NIL, abortable)) {
 312:         cl_eol();
 313:         UpdMesg = 0;
 314:     }
 315:     flusho();
 316: }
 317: 
 318: /* Goto the current position in the current window.  Presumably redisplay()
 319:    has already been called, and curwind->{w_dotline,w_dotcol} have been set
 320:    correctly. */
 321: 
 322: GotoDot()
 323: {
 324:     if (InputPending)
 325:         return;
 326:     Placur(curwind->w_dotline, curwind->w_dotcol -
 327:                 PhysScreen[curwind->w_dotline].s_offset);
 328:     flusho();
 329: }
 330: 
 331: private
 332: UntilEqual(start)
 333: register int    start;
 334: {
 335:     register struct scrimage    *des_p = &DesiredScreen[start],
 336:                     *phys_p = &PhysScreen[start];
 337: 
 338:     while ((start < ILI) && (des_p->s_id != phys_p->s_id)) {
 339:         des_p++;
 340:         phys_p++;
 341:         start++;
 342:     }
 343: 
 344:     return start;
 345: }
 346: 
 347: /* Calls the routine to do the physical changes, and changes PhysScreen to
 348:    reflect those changes. */
 349: 
 350: AddLines(at, num)
 351: register int    at,
 352:         num;
 353: {
 354:     register  int   i;
 355:     int bottom = UntilEqual(at + num);
 356: 
 357:     if (num == 0 || num >= ((bottom - 1) - at))
 358:         return 0;   /* We did nothing */
 359:     v_ins_line(num, at, bottom - 1);
 360: 
 361:     /* Now change PhysScreen to account for the physical change. */
 362: 
 363:     for (i = bottom - 1; i - num >= at; i--)
 364:         PhysScreen[i] = PhysScreen[i - num];
 365:     for (i = 0; i < num; i++)
 366:         PhysScreen[at + i].s_id = 0;
 367:     return 1;   /* We did something. */
 368: }
 369: 
 370: DelLines(at, num)
 371: register int    at,
 372:         num;
 373: {
 374:     register int    i;
 375:     int bottom = UntilEqual(at + num);
 376: 
 377:     if (num == 0 || num >= ((bottom - 1) - at))
 378:         return 0;
 379:     v_del_line(num, at, bottom - 1);
 380: 
 381:     for (i = at; num + i < bottom; i++)
 382:         PhysScreen[i] = PhysScreen[num + i];
 383:     for (i = bottom - num; i < bottom; i++)
 384:         PhysScreen[i].s_id = 0;
 385:     return 1;
 386: }
 387: 
 388: /* Update line linenum in window w.  Only set PhysScreen to DesiredScreen
 389:    if the swrite or cl_eol works, that is nothing is interupted by
 390:    characters typed. */
 391: 
 392: UpdLine(linenum)
 393: register int    linenum;
 394: {
 395:     register struct scrimage    *des_p = &DesiredScreen[linenum];
 396:     register Window *w = des_p->s_window;
 397: 
 398:     i_set(linenum, 0);
 399:     if (des_p->s_flags & MODELINE)
 400:         ModeLine(w);
 401:     else if (des_p->s_id) {
 402:         des_p->s_lp->l_dline &= ~DIRTY;
 403:         des_p->s_flags &= ~(DIRTY | L_MOD);
 404: #ifdef ID_CHAR
 405:         if (!UseIC && w->w_numlines)
 406: #else
 407:         if (w->w_numlines)
 408: #endif
 409:             (void) swrite(sprint("%6d  ", des_p->s_vln), NIL, YES);
 410: 
 411: #ifdef ID_CHAR
 412:         if (UseIC) {
 413:             char    outbuf[256],
 414:                 *lptr;
 415:             int fromcol = w->w_numlines ? 8 : 0;
 416: 
 417:             if (w->w_numlines)
 418:                 sprintf(outbuf, "%6d  ", des_p->s_vln);
 419:             lptr = lcontents(des_p->s_lp);
 420:             DeTab(des_p->s_offset, lptr, outbuf + fromcol,
 421:                 (sizeof outbuf) - 1 - fromcol,
 422:                 des_p->s_window->w_visspace);
 423:             if (IDchar(outbuf, linenum, 0))
 424:                 PhysScreen[linenum] = *des_p;
 425:             else if (i_set(linenum, 0), swrite(outbuf, NIL, YES))
 426:                 do_cl_eol(linenum);
 427:             else
 428:                 PhysScreen[linenum].s_id = -1;
 429:         } else
 430: #endif ID_CHAR
 431:             if (BufSwrite(linenum))
 432:             do_cl_eol(linenum);
 433:         else
 434:             PhysScreen[linenum].s_id = -1;
 435:     } else if (PhysScreen[linenum].s_id)    /* Not the same ... make sure */
 436:         do_cl_eol(linenum);
 437: }
 438: 
 439: do_cl_eol(linenum)
 440: register int    linenum;
 441: {
 442:     cl_eol();
 443:     PhysScreen[linenum] = DesiredScreen[linenum];
 444: }
 445: 
 446: #ifdef ID_CHAR
 447: 
 448: /* From here to the end of the file is code that tries to utilize the
 449:    insert/delete character feature on some terminals.  It is very confusing
 450:    and not so well written code, AND there is a lot of it.  You may want
 451:    to use the space for something else. */
 452: 
 453: extern struct screenline    *Screen;
 454: int IN_INSmode = 0;
 455: 
 456: int UseIC;
 457: 
 458: int DClen,
 459:     MDClen,
 460:     IClen,
 461:     MIClen,
 462:     IMlen,
 463:     CElen;
 464: 
 465: disp_opt_init()
 466: {
 467:     DClen = DC ? strlen(DC) : 0;
 468:     MDClen = M_DC ? strlen(M_DC) : 9999;
 469:     IClen = IC ? strlen(IC) : 0;
 470:     MIClen = M_IC ? strlen(M_IC) : 9999;
 471:     IMlen = IM ? strlen(IM) : 0;
 472:     CElen = CE ? strlen(CE) : 0;
 473: 
 474:     UseIC = (IC || IM || M_IC);
 475: }
 476: 
 477: INSmode(on)
 478: {
 479:     if (on && !IN_INSmode) {
 480:         putpad(IM, 1);
 481:         IN_INSmode++;
 482:     } else if (!on && IN_INSmode) {
 483:         putpad(EI, 1);
 484:         IN_INSmode = 0;
 485:     }
 486: }
 487: 
 488: private
 489: DeTab(s_offset, buf, outbuf, limit, visspace)
 490: register char   *buf;
 491: char    *outbuf;
 492: {
 493:     register char   *phys_p = outbuf,
 494:             c;
 495:     register int    pos = 0;
 496:     char        *limitp = &outbuf[limit];
 497: 
 498: #define OkayOut(ch) if ((pos++ >= s_offset) && (phys_p < limitp))\
 499:                 *phys_p++ = ch;\
 500:             else
 501: 
 502:     while (c = *buf++) {
 503:         if (c == '\t') {
 504:             int nchars = (tabstop - (pos % tabstop));
 505: 
 506:             if (visspace) {
 507:                 OkayOut('>');
 508:                 --nchars;
 509:             }
 510:             while (--nchars >= 0)
 511:                 OkayOut(' ');
 512: 
 513:         } else if (isctrl(c)) {
 514:             OkayOut('^');
 515:             OkayOut(c == 0177 ? '?' : c + '@');
 516:         } else {
 517:             if (visspace && c == ' ')
 518:                 c = '_';
 519:             OkayOut(c);
 520:         }
 521:         if (pos - s_offset >= CO) {
 522:             phys_p = &outbuf[CO - 1];
 523:             *phys_p++ = '!';
 524:             break;
 525:         }
 526:     }
 527:     *phys_p = 0;
 528: }
 529: 
 530: /* ID character routines full of special cases and other fun stuff like that.
 531:    It actually works though ...
 532: 
 533:   	Returns Non-Zero if you are finished (no differences left). */
 534: 
 535: private
 536: IDchar(new, lineno, col)
 537: register char   *new;
 538: {
 539:     register int    i;
 540:     int j,
 541:         oldlen,
 542:         NumSaved;
 543:     register struct screenline  *sline = &Screen[lineno];
 544: 
 545:     oldlen = sline->s_length - sline->s_line;
 546: 
 547:     for (i = col; i < oldlen && new[i] != 0; i++)
 548:         if (sline->s_line[i] != new[i])
 549:             break;
 550:     if (new[i] == 0 || i == oldlen)
 551:         return (new[i] == 0 && i == oldlen);
 552: 
 553:     for (j = i + 1; j < oldlen && new[j]; j++) {
 554:         if (new[j] == sline->s_line[i]) {
 555:             NumSaved = IDcomp(new + j, sline->s_line + i,
 556:                     strlen(new)) + NumSimilar(new + i,
 557:                         sline->s_line + i, j - i);
 558:             if (OkayInsert(NumSaved, j - i)) {
 559:                 InsChar(lineno, i, j - i, new);
 560:                 return(IDchar(new, lineno, j));
 561:             }
 562:         }
 563:     }
 564: 
 565:     for (j = i + 1; j < oldlen && new[i]; j++) {
 566:         if (new[i] == sline->s_line[j]) {
 567:             NumSaved = IDcomp(new + i, sline->s_line + j,
 568:                     oldlen - j);
 569:             if (OkayDelete(NumSaved, j - i, new[oldlen] == 0)) {
 570:                 DelChar(lineno, i, j - i);
 571:                 return(IDchar(new, lineno, j));
 572:             }
 573:         }
 574:     }
 575:     return 0;
 576: }
 577: 
 578: private
 579: NumSimilar(s, t, n)
 580: register char   *s,
 581:         *t;
 582: {
 583:     register int    num = 0;
 584: 
 585:     while (n--)
 586:         if (*s++ == *t++)
 587:             num++;
 588:     return num;
 589: }
 590: 
 591: private
 592: IDcomp(s, t, len)
 593: register char   *s,
 594:         *t;
 595: {
 596:     register int    i;
 597:     int num = 0,
 598:         nonspace = 0;
 599:     char    c;
 600: 
 601:     for (i = 0; i < len; i++) {
 602:         if ((c = *s++) != *t++)
 603:             break;
 604:         if (c != ' ')
 605:             nonspace++;
 606:         if (nonspace)
 607:             num++;
 608:     }
 609: 
 610:     return num;
 611: }
 612: 
 613: private
 614: OkayDelete(Saved, num, samelength)
 615: {
 616:     /* If the old and the new are the same length, then we don't
 617: 	 * have to clear to end of line.  We take that into consideration.
 618: 	 */
 619:     return ((Saved + (!samelength ? CElen : 0))
 620:         > min(MDClen, DClen * num));
 621: }
 622: 
 623: private
 624: OkayInsert(Saved, num)
 625: {
 626:     register int    n = 0;
 627: 
 628:     if (IC)     /* Per character prefixes */
 629:         n = min(num * IClen, MIClen);
 630: 
 631:     if (IM && !IN_INSmode) {
 632:         /* Good terminal.  Fewer characters in this case */
 633:         n += IMlen;
 634:     }
 635: 
 636:     n += num;   /* The characters themselves */
 637: 
 638:     return Saved > n;
 639: }
 640: 
 641: extern int  CapCol;
 642: extern char *cursend;
 643: extern struct screenline    *Curline;
 644: 
 645: private
 646: DelChar(lineno, col, num)
 647: {
 648:     register char   *from,
 649:             *to;
 650:     register int    i;
 651:     struct screenline *sp = (&Screen[lineno]);
 652: 
 653:     Placur(lineno, col);
 654:     if (M_DC && num > 1) {
 655:         char    minibuf[16];
 656: 
 657:         sprintf(minibuf, M_DC, num);
 658:         putpad(minibuf, num);
 659:     } else {
 660:         for (i = num; --i >= 0; )
 661:             putpad(DC, 1);
 662:     }
 663: 
 664:     to = sp->s_line + col;
 665:     from = to + num;
 666: 
 667:     byte_copy(from, to, sp->s_length - from + 1);
 668:     clrline(sp->s_length - num, sp->s_length);
 669:     sp->s_length -= num;
 670: }
 671: 
 672: private
 673: InsChar(lineno, col, num, new)
 674: char    *new;
 675: {
 676:     register char   *sp1,
 677:             *sp2,   /* To push over the array. */
 678:             *sp3;   /* Last character to push over. */
 679:     int i;
 680: 
 681:     i_set(lineno, 0);
 682:     sp2 = Curline->s_length + num;
 683: 
 684:     if (sp2 >= cursend) {
 685:         i_set(lineno, CO - num - 1);
 686:         cl_eol();
 687:         sp2 = cursend - 1;
 688:     }
 689:     Curline->s_length = sp2;
 690:     sp1 = sp2 - num;
 691:     sp3 = Curline->s_line + col;
 692: 
 693:     while (sp1 >= sp3)
 694:         *sp2-- = *sp1--;
 695: 
 696:     new += col;
 697:     byte_copy(new, sp3, num);
 698:     /* The internal screen is correct, and now we have to do
 699: 	   the physical stuff. */
 700: 
 701:     Placur(lineno, col);
 702:     if (IM) {
 703:         if (!IN_INSmode)
 704:             INSmode(1);
 705:     } else if (M_IC && num > 1) {
 706:         char    minibuf[16];
 707: 
 708:         sprintf(minibuf, M_IC, num);
 709:         putpad(minibuf, num);
 710:     } else if (IC) {
 711:         for (i = 0; i < num; i++)
 712:             putpad(IC, 1);
 713:     }
 714:     for (i = 0; i < num; i++) {
 715:         putchar(new[i]);
 716:         if (IN_INSmode)
 717:             putpad(IP, 1);
 718:     }
 719:     CapCol += num;
 720: }
 721: 
 722: #endif ID_CHAR
 723: 
 724: /* chkmail() returns nonzero if there is new mail since the
 725:    last time we checked. */
 726: 
 727: char    Mailbox[128];   /* initialized in main */
 728: int MailInt = 60;   /* check no more often than 60 seconds */
 729: #ifdef BIFF
 730: int BiffChk = NO;   /* whether or not to turn off biff while in JOVE */
 731: #endif
 732: 
 733: chkmail(force)
 734: {
 735:     time_t  now;
 736:     static time_t   last_chk = 0;
 737:     static int  value = FALSE;
 738:     static off_t    last_size = 0;
 739:     struct stat stbuf;
 740:     int last_val;
 741:     extern time_t   time0;
 742: 
 743:     time(&now);
 744:     if (!force && (now < last_chk + MailInt))
 745:         return value;
 746:     if (stat(Mailbox, &stbuf) < 0)
 747:         return FALSE;
 748:     last_val = value;
 749:     value = ((stbuf.st_mtime > time0) &&
 750:          (stbuf.st_size > 0) &&
 751:          (stbuf.st_size > last_size) &&
 752:          (stbuf.st_mtime + 5 > stbuf.st_atime));
 753:     last_chk = now;
 754:     last_size = stbuf.st_size;
 755:     if (value == TRUE && value != last_val)
 756:         dobell(3);
 757:     return value;
 758: }
 759: 
 760: /* Print the mode line. */
 761: 
 762: private char    *mode_p,
 763:         *mend_p;
 764: int BriteMode = 1;      /* modeline should standout */
 765: 
 766: private
 767: mode_app(str)
 768: register char   *str;
 769: {
 770:     if (mode_p >= mend_p)
 771:         return;
 772:     while ((mode_p < mend_p) && (*mode_p++ = *str++))
 773:         ;
 774:     mode_p--;   /* back over the null */
 775: }
 776: 
 777: char    ModeFmt[120] = "%3c %[%sJOVE (%M)   Buffer: %b  \"%f\" %]%s%m %((%t)%s%)%e";
 778: 
 779: ModeLine(w)
 780: register Window *w;
 781: {
 782:     extern int  i_line;
 783:     int n,
 784:         ign_some = 0;
 785:     char    line[132],
 786:         *fmt = ModeFmt,
 787:         tmp[16],
 788:         fillc,
 789:         c;
 790:     register Buffer *thisbuf = w->w_bufp;
 791:     register Buffer *bp;
 792: 
 793:     mode_p = line;
 794:     mend_p = &line[(sizeof line) - 1];
 795: 
 796:     if (BriteMode != 0 && SO == 0)
 797:         BriteMode = 0;
 798:     fillc = BriteMode ? ' ' : '-';
 799: 
 800:     while (c = *fmt++) {
 801:         if (c == '\\')
 802:             c = *fmt++;
 803:         if (c != '%') {
 804:             if (!ign_some)
 805:                 *mode_p++ = c;
 806:             continue;
 807:         }
 808:         c = *fmt++; /* Character after the percent! */
 809:         if (ign_some && c != ')')
 810:             continue;
 811:         n = 1;
 812:         if (c >= '0' && c <= '9') {
 813:             n = 0;
 814:             while (c >= '0' && c <= '9') {
 815:                 n = n * 10 + (c - '0');
 816:                 c = *fmt++;
 817:             }
 818:         }
 819:         switch (c) {
 820:         case '(':
 821:             if (w->w_next != fwind) /* Not bottom window. */
 822:                 ign_some++;
 823:             break;
 824: 
 825:         case ')':
 826:             ign_some = 0;
 827:             break;
 828: 
 829:         case 'c':
 830:             while (--n >= 0)
 831:                 *mode_p++ = fillc;
 832:             break;
 833: 
 834:         case '[':
 835:         case ']':
 836:             {
 837:                 char    *strs = (c == '[') ? "[[[[[[[[[[" : "]]]]]]]]]]";
 838: 
 839:                 mode_app(strs + 10 - RecDepth);
 840:             break;
 841:             }
 842: 
 843:         case 's':
 844:             if (mode_p[-1] == ' ')
 845:                 continue;
 846:             *mode_p++ = ' ';
 847:             break;
 848: 
 849:         case 'M':
 850:             {
 851:                 static char *mmodes[] = {
 852:                 "Fundamental ",
 853:                 "Text ",
 854:                 "C ",
 855: #ifdef LISP
 856:                 "Lisp ",
 857: #endif
 858:                 0
 859:             };
 860: 
 861:                 mode_app(mmodes[thisbuf->b_major]);
 862: 
 863:             if (BufMinorMode(thisbuf, Fill))
 864:                 mode_app("Fill ");
 865:             if (BufMinorMode(thisbuf, Abbrev))
 866:                 mode_app("Abbrev ");
 867:             if (BufMinorMode(thisbuf, OverWrite))
 868:                 mode_app("OvrWt ");
 869:             if (BufMinorMode(thisbuf, Indent))
 870:                 mode_app("AI ");
 871:             if (KeyMacro.m_flags & DEFINE)
 872:                 mode_app("Def ");
 873:             mode_p--;   /* Back over the extra space. */
 874:             break;
 875:             }
 876: 
 877:         case 'b':
 878:             mode_app(thisbuf->b_name);
 879:             break;
 880: 
 881:         case 'f':
 882:         case 'F':
 883:             if (thisbuf->b_fname == 0)
 884:                 mode_app("[No file]");
 885:             else {
 886:                 if (c == 'f')
 887:                     mode_app(pr_name(thisbuf->b_fname));
 888:                 else
 889:                     mode_app(basename(thisbuf->b_fname));
 890:             }
 891:             break;
 892: 
 893: 
 894:         case 'n':
 895:             for (bp = world, n = 1; bp != 0; bp = bp->b_next, n++)
 896:                 if (bp == thisbuf)
 897:                     break;
 898: 
 899:             sprintf(tmp, "%d", n);
 900:             mode_app(tmp);
 901:             break;
 902: 
 903:         case 'm':
 904:             if (IsModified(w->w_bufp))
 905:                 *mode_p++ = '*';
 906:             else
 907:                 *mode_p++ = ' ';
 908:             break;
 909: 
 910:         case 't':
 911:             {
 912:             char    timestr[12];
 913: 
 914:                 mode_app(get_time((time_t *) 0, timestr, 11, 16));
 915:             break;
 916:             }
 917: 
 918: #ifdef LOAD_AV
 919:         case 'l':
 920:             {
 921:             double  theavg;
 922:                 char    minibuf[10];
 923: 
 924:                 get_la(&theavg);
 925:                 theavg += .005; /* round to nearest .01 */
 926:                 sprintf(minibuf, "%d.%02d",
 927:                    (int) theavg,
 928:                    (int)((theavg - (int) theavg) * 100));
 929:                 mode_app(minibuf);
 930:             }
 931:             break;
 932: #endif
 933: 
 934:         case 'C':   /* check mail here */
 935:             if (chkmail(NO))
 936:                 mode_app("[New mail]");
 937:             break;
 938: 
 939: #ifdef CHDIR
 940:         case 'd':   /* print working directory */
 941:             mode_app(pr_name(pwd()));
 942:             break;
 943: #endif
 944: 
 945:         case 'e':
 946:             {
 947:             /* 2 space pad pluss padding for magic cookies */
 948:             char    *last_p = &line[CO - 2 - (2 * SG)];
 949: 
 950:             while (mode_p < last_p)
 951:                 *mode_p++ = fillc;
 952: 
 953:                 goto outahere;      /* %e means we're done! */
 954:             }
 955:         }
 956:     }
 957: 
 958: outahere:
 959:     *mode_p = 0;
 960: 
 961:     /* Highlight mode line. */
 962:     if (BriteMode) {
 963: #ifdef ID_CHAR
 964:         if (IN_INSmode)
 965:             INSmode(0);
 966: #endif
 967:         putpad(SO, 1);
 968:     }
 969:     if (swrite(line, BriteMode, YES))
 970:         do_cl_eol(i_line);
 971:     if (BriteMode)
 972:         putpad(SE, 1);
 973: }
 974: 
 975: RedrawDisplay()
 976: {
 977:     Line    *newtop = prev_line((curwind->w_line = curline), exp_p ?
 978:                 exp : HALF(curwind));
 979: 
 980:     if (newtop == curwind->w_top)
 981:         v_clear(FLine(curwind), FLine(curwind) + SIZE(curwind));
 982:     else
 983:         SetTop(curwind, newtop);
 984: }
 985: 
 986: v_clear(line1, line2)
 987: register int    line1;
 988: {
 989:     register struct scrimage    *phys_p, *des_p;
 990: 
 991:     phys_p = &PhysScreen[line1];
 992:     des_p = &DesiredScreen[line1];
 993: 
 994:     while (line1 <= line2) {
 995:         i_set(line1++, 0);
 996:         cl_eol();
 997:         phys_p->s_id = des_p->s_id = 0;
 998:         phys_p++, des_p++;
 999:     }
1000: }
1001: 
1002: ClAndRedraw()
1003: {
1004:     cl_scr(1);
1005: }
1006: 
1007: NextPage()
1008: {
1009:     Line    *newline;
1010: 
1011:     if (Asking)
1012:         return;
1013:     if (exp < 0) {
1014:         exp = -exp;
1015:         PrevPage();
1016:         return;
1017:     }
1018:     if (exp_p)
1019:         UpScroll();
1020:     else {
1021:         if (in_window(curwind, curwind->w_bufp->b_last) != -1) {
1022:             rbell();
1023:             return;
1024:         }
1025:         newline = next_line(curwind->w_top, max(1, SIZE(curwind) - 1));
1026:         SetTop(curwind, curwind->w_line = newline);
1027:         if (curwind->w_bufp == curbuf)
1028:             SetLine(newline);
1029:     }
1030: }
1031: 
1032: PrevPage()
1033: {
1034:     Line    *newline;
1035: 
1036:     if (Asking)
1037:         return;
1038:     if (exp < 0) {
1039:         exp = -exp;
1040:         NextPage();
1041:         return;
1042:     }
1043:     if (exp_p)
1044:         DownScroll();
1045:     else {
1046:         newline = prev_line(curwind->w_top, max(1, SIZE(curwind) - 1));
1047:         SetTop(curwind, curwind->w_line = newline);
1048:         if (curwind->w_bufp == curbuf)
1049:             SetLine(newline);
1050:     }
1051: }
1052: 
1053: UpScroll()
1054: {
1055:     SetTop(curwind, next_line(curwind->w_top, exp));
1056:     if ((curwind->w_bufp == curbuf) &&
1057:         (in_window(curwind, curline) == -1))
1058:         SetLine(curwind->w_top);
1059: }
1060: 
1061: DownScroll()
1062: {
1063:     SetTop(curwind, prev_line(curwind->w_top, exp));
1064:     if ((curwind->w_bufp == curbuf) &&
1065:         (in_window(curwind, curline) == -1))
1066:         SetLine(curwind->w_top);
1067: }
1068: 
1069: int VisBell = 0,
1070:     RingBell = 0;   /* So if we have a lot of errors ...
1071: 			   ring the bell only ONCE */
1072: rbell()
1073: {
1074:     RingBell++;
1075: }
1076: 
1077: /* Message prints the null terminated string onto the bottom line of the
1078:    terminal. */
1079: 
1080: message(str)
1081: char    *str;
1082: {
1083:     if (InJoverc)
1084:         return;
1085:     UpdMesg++;
1086:     errormsg = 0;
1087:     if (str != mesgbuf)
1088:         null_ncpy(mesgbuf, str, (sizeof mesgbuf) - 1);
1089: }
1090: 
1091: /* End of Window */
1092: 
1093: Eow()
1094: {
1095:     if (Asking)
1096:         return;
1097:     SetLine(next_line(curwind->w_top, SIZE(curwind) - 1 -
1098:             min(SIZE(curwind) - 1, exp - 1)));
1099:     if (!exp_p)
1100:         Eol();
1101: }
1102: 
1103: /* Beginning of Window */
1104: 
1105: Bow()
1106: {
1107:     if (Asking)
1108:         return;
1109:     SetLine(next_line(curwind->w_top, min(SIZE(curwind) - 1, exp - 1)));
1110: }
1111: 
1112: private int LineNo,
1113:         last_col,
1114:         DoAutoNL;
1115: private Window  *old_wind;  /* save the window we were in BEFORE
1116: 				   before we were called, if UseBuffers
1117: 				   is nonzero */
1118: 
1119: int UseBuffers = FALSE;
1120: int TOabort = 0;
1121: 
1122: /* This initializes the typeout.  If send-typeout-to-buffers is set
1123:    the buffer NAME is created (emptied if it already exists) and output
1124:    goes to the buffer.  Otherwise output is drawn on the screen and
1125:    erased by TOstop() */
1126: 
1127: TOstart(name, auto_newline)
1128: char    *name;
1129: {
1130:     if (UseBuffers) {
1131:         old_wind = curwind;
1132:         pop_wind(name, YES, B_SCRATCH);
1133:     }
1134:     TOabort = LineNo = last_col = 0;
1135:     DoAutoNL = auto_newline;
1136: }
1137: 
1138: /* VARARGS1 */
1139: 
1140: Typeout(fmt, va_alist)
1141: char    *fmt;
1142: va_dcl
1143: {
1144:     if (TOabort)
1145:         return;
1146: 
1147:     if (!UseBuffers && (LineNo == ILI - 1)) {
1148:         register int    c;
1149: 
1150:         LineNo = 0;
1151:         last_col = 0;
1152:         f_mess("--more--");
1153:         if ((c = getchar()) != ' ') {
1154:             TOabort++;
1155:             if (c != CTL(G) && c != RUBOUT)
1156:                 Ungetc(c);
1157:             return;
1158:         }
1159:         f_mess(NullStr);
1160:     }
1161: 
1162:     if (fmt) {
1163:         extern int  i_col;
1164:         char    string[132];
1165:         va_list ap;
1166: 
1167:         va_start(ap);
1168:         format(string, sizeof string, fmt, ap);
1169:         va_end(ap);
1170:         if (UseBuffers)
1171:             ins_str(string, NO);
1172:         else {
1173:             i_set(LineNo, last_col);
1174:             (void) swrite(string, NIL, YES);
1175:             last_col = i_col;
1176:         }
1177:     }
1178:     if (!UseBuffers) {
1179:         PhysScreen[LineNo].s_id = -1;
1180:         if (fmt == 0 || DoAutoNL != 0) {
1181:             cl_eol();
1182:             flusho();
1183:             LineNo++;
1184:             last_col = 0;
1185:         }
1186:     } else if (fmt == 0 || DoAutoNL != 0)
1187:         ins_str("\n", NO);
1188: }
1189: 
1190: TOstop()
1191: {
1192:     int c;
1193: 
1194:     if (UseBuffers) {
1195:         ToFirst();
1196:         SetWind(old_wind);
1197:     } else {
1198:         if (TOabort)
1199:             return;
1200:         if (last_col != 0)
1201:             Typeout((char *) 0);
1202:         Typeout("----------");
1203:         cl_eol();
1204:         flusho();
1205:         c = getchar();
1206:         if (c != ' ')
1207:             Ungetc(c);
1208:     }
1209: }

Defined functions

AddLines defined in line 350; used 1 times
Bow defined in line 1105; used 3 times
ChkWindows defined in line 22; used 1 times
DeTab defined in line 488; used 1 times
DelChar defined in line 645; used 1 times
DelLines defined in line 370; used 1 times
DoIDline defined in line 149; used 3 times
DownScroll defined in line 1061; used 3 times
DrawMesg defined in line 306; used 5 times
Eow defined in line 1093; used 3 times
GotoDot defined in line 322; used 1 times
  • in line 96
IDchar defined in line 535; used 3 times
IDcomp defined in line 591; used 2 times
INSmode defined in line 477; used 6 times
InsChar defined in line 672; used 1 times
ModeLine defined in line 779; used 1 times
NextPage defined in line 1007; used 4 times
NumSimilar defined in line 578; used 1 times
OkayDelete defined in line 613; used 1 times
OkayInsert defined in line 623; used 1 times
PrevPage defined in line 1032; used 3 times
Typeout defined in line 1140; used 46 times
UntilEqual defined in line 331; used 2 times
UpScroll defined in line 1053; used 3 times
UpdLine defined in line 392; used 1 times
  • in line 84
UpdWindow defined in line 203; used 1 times
  • in line 69
chkmail defined in line 733; used 2 times
disp_opt_init defined in line 465; used 1 times
do_cl_eol defined in line 439; used 4 times
dobell defined in line 107; used 2 times
find_pos defined in line 121; used 1 times
mode_app defined in line 766; used 16 times
v_clear defined in line 986; used 1 times

Defined variables

BiffChk defined in line 730; used 1 times
BriteMode defined in line 764; used 7 times
CElen defined in line 463; used 2 times
DClen defined in line 458; used 2 times
DoAutoNL defined in line 1114; used 3 times
IClen defined in line 460; used 2 times
IMlen defined in line 462; used 3 times
IN_INSmode defined in line 454; used 12 times
LineNo defined in line 1112; used 6 times
MDClen defined in line 459; used 2 times
MIClen defined in line 461; used 2 times
MailInt defined in line 728; used 2 times
Mailbox defined in line 727; used 2 times
ModeFmt defined in line 777; used 2 times
TOabort defined in line 1120; used 4 times
UpdModLine defined in line 145; used 8 times
UseBuffers defined in line 1119; used 6 times
UseIC defined in line 456; used 4 times
VisBell defined in line 1069; used 2 times
last_col defined in line 1113; used 6 times
mend_p defined in line 763; used 3 times
mode_p defined in line 762; used 15 times
old_wind defined in line 1115; used 2 times

Defined macros

OkayOut defined in line 498; used 5 times
Last modified: 1986-03-28
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3461
Valid CSS Valid XHTML 1.0 Strict