1: /*************************************************************************** 2: * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne. JOVE * 3: * is provided to you without charge, and with no warranty. You may give * 4: * away copies of JOVE, including sources, provided that this notice is * 5: * included in all the files. * 6: ***************************************************************************/ 7: 8: /* 9: * Modified 1/16/95. The loadaverage method has changed. You will need 10: * 'getloadavg()' now. Heck, if 'mere' pdp-11s have it anyone can ;-). 11: */ 12: 13: #include "jove.h" 14: #include "ctype.h" 15: #include "termcap.h" 16: #include <signal.h> 17: 18: #ifdef MAC 19: # include "mac.h" 20: #else 21: # include <varargs.h> 22: #endif 23: 24: #ifdef MSDOS 25: #include <time.h> 26: #endif 27: 28: struct cmd * 29: FindCmd(proc) 30: register void (*proc)(); 31: { 32: register struct cmd *cp; 33: 34: for (cp = commands; cp->Name; cp++) 35: if (cp->c_proc == proc) 36: return cp; 37: return 0; 38: } 39: 40: int Interactive; /* True when we invoke with the command handler? */ 41: data_obj *LastCmd; 42: char *ProcFmt = ": %f "; 43: 44: void 45: ExecCmd(cp) 46: register data_obj *cp; 47: { 48: LastCmd = cp; 49: if (cp->Type & MAJOR_MODE) 50: SetMajor((cp->Type >> 8)); 51: else if (cp->Type & MINOR_MODE) 52: TogMinor((cp->Type >> 8)); 53: else switch (cp->Type&TYPEMASK) { 54: case MACRO: 55: do_macro((struct macro *) cp); 56: break; 57: 58: case FUNCTION: 59: { 60: register struct cmd *cmd = (struct cmd *) cp; 61: 62: if (cmd->c_proc) 63: (*cmd->c_proc)(); 64: } 65: } 66: } 67: 68: Line * 69: lastline(lp) 70: register Line *lp; 71: { 72: register Line *next; 73: 74: while (next = lp->l_next) 75: lp = next; 76: return lp; 77: } 78: 79: private int *slowp = 0; 80: 81: char key_strokes[100]; 82: private char *key_p = key_strokes; 83: 84: void 85: init_strokes() 86: { 87: key_strokes[0] = 0; 88: key_p = key_strokes; 89: } 90: 91: void 92: add_stroke(c) 93: { 94: if (key_p + 5 > &key_strokes[(sizeof key_strokes) - 1]) 95: key_p = key_strokes; 96: sprintf(key_p, "%p ", c); 97: key_p += strlen(key_p); 98: } 99: 100: void 101: slowpoke() 102: { 103: if (slowp) 104: *slowp = YES; 105: f_mess(key_strokes); 106: } 107: 108: #ifdef UNIX 109: # ifdef BSD4_2 110: # define N_SEC 1 /* will be precisely 1 second on 4.2 */ 111: # else 112: # define N_SEC 2 /* but from 1 to 2 seconds otherwise */ 113: # endif 114: #else /* MSDOS or MAC */ 115: # define N_SEC 1 116: int in_macro(); 117: #endif /* UNIX */ 118: 119: int 120: waitchar(slow) 121: int *slow; 122: { 123: #ifdef UNIX 124: unsigned int old_time; 125: int c; 126: int (*oldproc)(); 127: #else /* MSDOS or MAC */ 128: long sw, time(); 129: #endif /* UNIX */ 130: 131: slowp = slow; 132: if (slow) 133: *slow = NO; 134: #ifdef UNIX 135: oldproc = signal(SIGALRM, slowpoke); 136: 137: if ((old_time = alarm((unsigned) N_SEC)) == 0) 138: old_time = UpdFreq; 139: c = getch(); 140: (void) alarm(old_time); 141: (void) signal(SIGALRM, oldproc); 142: 143: return c; 144: #else /* MSDOS or MAC */ 145: #ifdef MAC 146: Keyonly = 1; 147: if(charp() || in_macro()) return getch(); /* to avoid flicker */ 148: #endif 149: time(&sw); 150: sw += N_SEC; 151: while(time(NULL) <= sw) 152: if (charp() || in_macro()) 153: return getch(); 154: #ifdef MAC 155: menus_off(); 156: #endif 157: slowpoke(); 158: return getch(); 159: #endif /* UNIX */ 160: } 161: 162: /* dir > 0 means forward; else means backward. */ 163: 164: char * 165: StrIndex(dir, buf, charpos, what) 166: char *buf, 167: what; 168: { 169: char *cp = &buf[charpos], 170: c; 171: 172: if (dir > 0) { 173: while (c = *cp++) 174: if (c == what) 175: return (cp - 1); 176: } else { 177: while (cp >= buf && (c = *cp--)) 178: if (c == what) 179: return (cp + 1); 180: } 181: return 0; 182: } 183: 184: int 185: blnkp(buf) 186: register char *buf; 187: { 188: register char c; 189: 190: while ((c = *buf++) && (c == ' ' || c == '\t')) 191: ; 192: return c == 0; /* It's zero if we got to the end of the Line */ 193: } 194: 195: Line * 196: next_line(line, num) 197: register Line *line; 198: register int num; 199: { 200: if (num < 0) 201: return prev_line(line, -num); 202: if (line) 203: while (--num >= 0 && line->l_next != 0) 204: line = line->l_next; 205: return line; 206: } 207: 208: Line * 209: prev_line(line, num) 210: register Line *line; 211: register int num; 212: { 213: if (num < 0) 214: return next_line(line, -num); 215: if (line) 216: while (--num >= 0 && line->l_prev != 0) 217: line = line->l_prev; 218: return line; 219: } 220: 221: void 222: DotTo(line, col) 223: Line *line; 224: { 225: Bufpos bp; 226: 227: bp.p_line = line; 228: bp.p_char = col; 229: SetDot(&bp); 230: } 231: 232: /* If bp->p_line is != current line, then save current line. Then set dot 233: to bp->p_line, and if they weren't equal get that line into linebuf. */ 234: 235: void 236: SetDot(bp) 237: register Bufpos *bp; 238: { 239: register int notequal; 240: 241: if (bp == 0) 242: return; 243: 244: notequal = bp->p_line != curline; 245: if (notequal) 246: lsave(); 247: if (bp->p_line) 248: curline = bp->p_line; 249: if (notequal) 250: getDOT(); 251: curchar = bp->p_char; 252: if (curchar > length(curline)) 253: curchar = length(curline); 254: } 255: 256: void 257: ToLast() 258: { 259: SetLine(curbuf->b_last); 260: Eol(); 261: } 262: 263: int MarkThresh = 22; /* average screen size ... */ 264: static int line_diff; 265: 266: int 267: LineDist(nextp, endp) 268: register Line *nextp, 269: *endp; 270: { 271: (void) inorder(nextp, 0, endp, 0); 272: return line_diff; 273: } 274: 275: int 276: inorder(nextp, char1, endp, char2) 277: register Line *nextp, 278: *endp; 279: { 280: int count = 0; 281: register Line *prevp = nextp; 282: 283: line_diff = 0; 284: if (nextp == endp) 285: return char1 < char2; 286: 287: while (nextp || prevp) { 288: if (nextp == endp || prevp == endp) 289: break; 290: if (nextp) 291: nextp = nextp->l_next; 292: if (prevp) 293: prevp = prevp->l_prev; 294: count += 1; 295: } 296: if (nextp == 0 && prevp == 0) 297: return -1; 298: line_diff = count; 299: 300: return nextp == endp; 301: } 302: 303: void 304: PushPntp(line) 305: register Line *line; 306: { 307: if (LineDist(curline, line) >= MarkThresh) 308: set_mark(); 309: } 310: 311: void 312: ToFirst() 313: { 314: SetLine(curbuf->b_first); 315: } 316: 317: int 318: length(line) 319: Line *line; 320: { 321: return strlen(lcontents(line)); 322: }; 323: 324: void 325: to_word(dir) 326: register int dir; 327: { 328: register char c; 329: 330: if (dir == FORWARD) { 331: while ((c = linebuf[curchar]) != 0 && !isword(c)) 332: curchar += 1; 333: if (eolp()) { 334: if (curline->l_next == 0) 335: return; 336: SetLine(curline->l_next); 337: to_word(dir); 338: return; 339: } 340: } else { 341: while (!bolp() && (c = linebuf[curchar - 1], !isword(c))) 342: curchar -= 1; 343: if (bolp()) { 344: if (curline->l_prev == 0) 345: return; 346: SetLine(curline->l_prev); 347: Eol(); 348: to_word(dir); 349: } 350: } 351: } 352: 353: /* Are there any modified buffers? Allp means include B_PROCESS 354: buffers in the check. */ 355: 356: int 357: ModBufs(allp) 358: { 359: register Buffer *b; 360: 361: for (b = world; b != 0; b = b->b_next) { 362: if (b->b_type == B_SCRATCH) 363: continue; 364: if ((b->b_type == B_FILE || allp) && IsModified(b)) 365: return 1; 366: } 367: return 0; 368: } 369: 370: char * 371: filename(b) 372: register Buffer *b; 373: { 374: return b->b_fname ? pr_name(b->b_fname, YES) : "[No file]"; 375: } 376: 377: char * 378: itoa(num) 379: register int num; 380: { 381: static char line[15]; 382: 383: sprintf(line, "%d", num); 384: return line; 385: } 386: 387: int 388: min(a, b) 389: register int a, 390: b; 391: { 392: return (a < b) ? a : b; 393: } 394: 395: int 396: max(a, b) 397: register int a, 398: b; 399: { 400: return (a > b) ? a : b; 401: } 402: 403: void 404: tiewind(w, bp) 405: register Window *w; 406: register Buffer *bp; 407: { 408: int not_tied = (w->w_bufp != bp); 409: 410: UpdModLine = YES; /* kludge ... but speeds things up considerably */ 411: w->w_line = bp->b_dot; 412: w->w_char = bp->b_char; 413: w->w_bufp = bp; 414: if (not_tied) 415: CalcWind(w); /* ah, this has been missing since the 416: beginning of time! */ 417: } 418: 419: extern int Jr_Len; 420: 421: char * 422: lcontents(line) 423: register Line *line; 424: { 425: if (line == curline) 426: return linebuf; 427: else 428: return lbptr(line); 429: } 430: 431: char * 432: ltobuf(line, buf) 433: Line *line; 434: char *buf; 435: { 436: if (line == curline) { 437: if (buf != linebuf) 438: strcpy(buf, linebuf); 439: Jr_Len = strlen(linebuf); 440: } else 441: getline(line->l_dline, buf); 442: return buf; 443: } 444: 445: void 446: DOTsave(buf) 447: Bufpos *buf; 448: { 449: buf->p_line = curline; 450: buf->p_char = curchar; 451: } 452: 453: /* Return none-zero if we had to rearrange the order. */ 454: 455: int 456: fixorder(line1, char1, line2, char2) 457: register Line **line1, 458: **line2; 459: register int *char1, 460: *char2; 461: { 462: Line *tline; 463: int tchar; 464: 465: if (inorder(*line1, *char1, *line2, *char2)) 466: return 0; 467: 468: tline = *line1; 469: tchar = *char1; 470: *line1 = *line2; 471: *char1 = *char2; 472: *line2 = tline; 473: *char2 = tchar; 474: 475: return 1; 476: } 477: 478: int 479: inlist(first, what) 480: register Line *first, 481: *what; 482: { 483: while (first) { 484: if (first == what) 485: return 1; 486: first = first->l_next; 487: } 488: return 0; 489: } 490: 491: /* Make `buf' (un)modified and tell the redisplay code to update the modeline 492: if it will need to be changed. */ 493: 494: int ModCount = 0; 495: 496: void 497: modify() 498: { 499: extern int DOLsave; 500: 501: if (!curbuf->b_modified) { 502: UpdModLine = YES; 503: curbuf->b_modified = YES; 504: } 505: DOLsave = YES; 506: if (!Asking) 507: ModCount += 1; 508: } 509: 510: void 511: unmodify() 512: { 513: if (curbuf->b_modified) { 514: UpdModLine = YES; 515: curbuf->b_modified = NO; 516: } 517: } 518: 519: int 520: numcomp(s1, s2) 521: register char *s1, 522: *s2; 523: { 524: register int count = 0; 525: 526: while (*s1 != 0 && *s1++ == *s2++) 527: count += 1; 528: return count; 529: } 530: 531: char * 532: copystr(str) 533: char *str; 534: { 535: char *val; 536: 537: if (str == 0) 538: return 0; 539: val = emalloc(strlen(str) + 1); 540: 541: strcpy(val, str); 542: return val; 543: } 544: 545: #ifndef byte_copy 546: void 547: byte_copy(from, to, count) 548: register char *from, 549: *to; 550: register int count; 551: { 552: while (--count >= 0) 553: *to++ = *from++; 554: } 555: #endif 556: 557: void 558: len_error(flag) 559: { 560: char *mesg = "[line too long]"; 561: 562: if (flag == COMPLAIN) 563: complain(mesg); 564: else 565: error(mesg); 566: } 567: 568: /* Insert num number of c's at offset atchar in a linebuf of LBSIZE */ 569: 570: void 571: ins_c(c, buf, atchar, num, max) 572: char c, *buf; 573: { 574: register char *pp, *pp1; 575: register int len; 576: int numchars; /* number of characters to copy forward */ 577: 578: if (num <= 0) 579: return; 580: len = atchar + strlen(&buf[atchar]); 581: if (len + num >= max) 582: len_error(COMPLAIN); 583: pp = &buf[len + 1]; /* + 1 so we can --pp (not pp--) */ 584: pp1 = &buf[len + num + 1]; 585: numchars = len - atchar; 586: while (numchars-- >= 0) 587: *--pp1 = *--pp; 588: pp = &buf[atchar]; 589: while (--num >= 0) 590: *pp++ = c; 591: } 592: 593: int 594: TwoBlank() 595: { 596: register Line *next = curline->l_next; 597: 598: return ((next != 0) && 599: (*(lcontents(next)) == '\0') && 600: (next->l_next != 0) && 601: (*(lcontents(next->l_next)) == '\0')); 602: } 603: 604: void 605: linecopy(onto, atchar, from) 606: register char *onto, 607: *from; 608: { 609: register char *endp = &onto[LBSIZE - 2]; 610: 611: onto += atchar; 612: 613: while (*onto = *from++) 614: if (onto++ >= endp) 615: len_error(ERROR); 616: } 617: 618: char * 619: IOerr(err, file) 620: char *err, *file; 621: { 622: return sprint("Couldn't %s \"%s\".", err, file); 623: } 624: 625: #ifdef UNIX 626: void 627: pclose(p) 628: int *p; 629: { 630: (void) close(p[0]); 631: (void) close(p[1]); 632: } 633: 634: void 635: dopipe(p) 636: int p[]; 637: { 638: if (pipe(p) == -1) 639: complain("[Pipe failed]"); 640: } 641: 642: #endif /* UNIX */ 643: /* NOSTRICT */ 644: 645: char * 646: emalloc(size) 647: { 648: register char *ptr; 649: 650: if (ptr = malloc((unsigned) size)) 651: return ptr; 652: /* Try garbage collecting lines */ 653: GCchunks(); 654: if (ptr = malloc((unsigned) size)) 655: return ptr; 656: /* Uh ... Oh screw it! */ 657: error("[Out of memory] "); 658: /* NOTREACHED */ 659: } 660: 661: /* Return the basename of file F. */ 662: 663: char * 664: basename(f) 665: register char *f; 666: { 667: register char *cp; 668: 669: if (cp = rindex(f, '/')) 670: return cp + 1; 671: else 672: #ifdef MSDOS 673: if (cp = rindex(f, '\\')) 674: return cp + 1; 675: else 676: if (cp = rindex(f, ':')) 677: return cp + 1; 678: #endif /* MSDOS */ 679: return f; 680: } 681: 682: void 683: push_env(savejmp) 684: jmp_buf savejmp; 685: { 686: byte_copy((char *) mainjmp, (char *) savejmp, sizeof (jmp_buf)); 687: } 688: 689: void 690: pop_env(savejmp) 691: jmp_buf savejmp; 692: { 693: byte_copy((char *) savejmp, (char *) mainjmp, sizeof (jmp_buf)); 694: } 695: 696: void 697: get_la(dp) 698: double *dp; 699: { 700: 701: getloadavg(dp, 1); 702: } 703: 704: /* get the time buf, designated by *timep, from FROM to TO. */ 705: char * 706: get_time(timep, buf, from, to) 707: char *buf; 708: time_t *timep; 709: { 710: time_t now; 711: char *cp; 712: extern char *ctime(); 713: 714: if (timep != 0) 715: now = *timep; 716: else 717: (void) time(&now); 718: cp = ctime(&now) + from; 719: #ifndef MSDOS 720: if (to == -1) 721: #else /* MSDOS */ 722: if ((to == -1) && (cp[strlen(cp)-1] == '\n')) 723: #endif /* MSDOS */ 724: cp[strlen(cp) - 1] = '\0'; /* Get rid of \n */ 725: else 726: cp[to - from] = '\0'; 727: if (buf) { 728: strcpy(buf, cp); 729: return buf; 730: } else 731: return cp; 732: } 733: 734: #if !(defined(MSDOS) || defined(MAC)) 735: 736: int 737: strcmp(s1, s2) 738: register char *s1, 739: *s2; 740: { 741: if (!s1 || !s2) 742: return 1; /* which is not zero ... */ 743: while (*s1 == *s2++) 744: if (*s1++ == '\0') 745: return 0; 746: return (*s1 - *--s2); 747: } 748: 749: #endif 750: 751: int 752: casecmp(s1, s2) 753: register char *s1, 754: *s2; 755: { 756: if (!s1 || !s2) 757: return 1; /* which is not zero ... */ 758: while (CharUpcase(*s1) == CharUpcase(*s2++)) 759: if (*s1++ == '\0') 760: return 0; 761: return (*s1 - *--s2); 762: } 763: 764: int 765: casencmp(s1, s2, n) 766: register char *s1, 767: *s2; 768: register int n; 769: { 770: if (!s1 || !s2) 771: return 1; /* which is not zero ... */ 772: while (--n >= 0 && (CharUpcase(*s1) == CharUpcase(*s2++))) 773: if (*s1++ == '\0') 774: return 0; 775: return ((n < 0) ? 0 : *s1 - *--s2); 776: } 777: 778: void 779: null_ncpy(to, from, n) 780: char *to, 781: *from; 782: { 783: (void) strncpy(to, from, n); 784: to[n] = '\0'; 785: } 786: 787: /* Tries to pause for delay/10 seconds OR until a character is typed 788: at the keyboard. This works well on BSD4_2 and not so well on the 789: rest. Returns 1 if it returned because of keyboard input, or 0 790: otherwise. */ 791: 792: #ifdef MAC 793: void 794: SitFor(delay) 795: unsigned int delay; 796: { 797: long start, 798: end; 799: 800: #define Ticks (long *) 0x16A /* 1/60 sec */ 801: Keyonly = 1; 802: redisplay(); 803: start = *Ticks; 804: 805: end = start + delay * 6; 806: do 807: if (InputPending = charp()) 808: break; 809: while (*Ticks < end); 810: } 811: #else /* not MAC */ 812: 813: void 814: SitFor(delay) 815: unsigned int delay; 816: { 817: #ifndef MSDOS 818: #if defined(BSD4_2) && !defined(pdp11) 819: #include <sys/time.h> 820: 821: struct timeval timer; 822: long readfds = 1; 823: 824: timer.tv_sec = (delay / 10); 825: timer.tv_usec = (delay % 10) * 100000; 826: 827: if (charp()) 828: return; 829: /* gross that I had to snarf this from getch() */ 830: if (!UpdMesg && !Asking) { /* Don't erase if we are asking */ 831: if (mesgbuf[0] && !errormsg) 832: message(NullStr); 833: } 834: redisplay(); 835: select(1, &readfds, (long *)0, (long *)0, &timer); 836: #else 837: static int cps[] = { 838: 0, 839: 5, 840: 7, 841: 11, 842: 13, 843: 15, 844: 20, 845: 30, 846: 60, 847: 120, 848: 180, 849: 240, 850: 480, 851: 960, 852: 1920, 853: 1920, 854: }; 855: register int nchars, 856: check_cnt; 857: 858: if (charp()) 859: return; 860: nchars = (delay * cps[ospeed]) / 10; 861: check_cnt = BufSize; 862: redisplay(); 863: while ((--nchars > 0) && !InputPending) { 864: putchar(0); 865: if (--check_cnt == 0) { 866: check_cnt = BufSize; 867: InputPending = charp(); 868: } 869: } 870: #endif 871: #else /* MSDOS */ 872: #include <bios.h> 873: #include <dos.h> 874: 875: long start, 876: end; 877: #ifndef IBMPC 878: struct dostime_t tc; 879: #endif 880: 881: redisplay(); 882: #ifdef IBMPC 883: _bios_timeofday(_TIME_GETCLOCK, &start); 884: #else 885: _dos_gettime(&tc); 886: start = (long)(tc.hour*60L*60L*10L)+(long)(tc.minute*60L*10L)+ 887: (long)(tc.second*10)+(long)(tc.hsecond/10); 888: #endif 889: end = (start + delay); 890: do { 891: if (InputPending = charp()) 892: break; 893: #ifdef IBMPC 894: if (_bios_timeofday(_TIME_GETCLOCK, &start)) 895: break; /* after midnight */ 896: #else 897: start = (long)(tc.hour*60L*60L*10L)+(long)(tc.minute*60L*10L)+ 898: (long)(tc.second*10)+(long)(tc.hsecond/10); 899: #endif 900: } 901: while (start < end); 902: #endif /* MSDOS */ 903: } 904: #endif /* MAC */ 905: 906: int 907: sindex(pattern, string) 908: register char *pattern, 909: *string; 910: { 911: register int len = strlen(pattern); 912: 913: while (*string != '\0') { 914: if (*pattern == *string && strncmp(pattern, string, len) == 0) 915: return TRUE; 916: string += 1; 917: } 918: return FALSE; 919: } 920: 921: void 922: make_argv(argv, ap) 923: register char *argv[]; 924: va_list ap; 925: { 926: register char *cp; 927: register int i = 0; 928: 929: argv[i++] = va_arg(ap, char *); 930: argv[i++] = basename(argv[0]); 931: while (cp = va_arg(ap, char *)) 932: argv[i++] = cp; 933: argv[i] = 0; 934: } 935: 936: int 937: pnt_line() 938: { 939: register Line *lp = curbuf->b_first; 940: register int i; 941: 942: for (i = 0; lp != 0; i++, lp = lp->l_next) 943: if (lp == curline) 944: break; 945: return i + 1; 946: }