|
|
1.1 ! root 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: #include "jove.h" ! 9: #include "termcap.h" ! 10: #include "ctype.h" ! 11: #include <signal.h> ! 12: ! 13: #ifdef MAC ! 14: # include "mac.h" ! 15: #else ! 16: # include <varargs.h> ! 17: # ifdef F_COMPLETION ! 18: # include <sys/stat.h> ! 19: # endif ! 20: #endif /* MAC */ ! 21: ! 22: #ifdef MAC ! 23: # undef private ! 24: # define private ! 25: #endif ! 26: ! 27: #ifdef LINT_ARGS ! 28: private Buffer * get_minibuf(void); ! 29: private char * real_ask(char *, int (*)(), char *, char *); ! 30: ! 31: private int ! 32: f_complete(int), ! 33: bad_extension(char *), ! 34: crush_bads(char **, int), ! 35: isdir(char *); ! 36: private void ! 37: fill_in(char **, int), ! 38: EVexpand(void); ! 39: #else ! 40: private Buffer * get_minibuf(); ! 41: private char * real_ask(); ! 42: ! 43: private int ! 44: f_complete(), ! 45: bad_extension(), ! 46: crush_bads(), ! 47: isdir(); ! 48: private void ! 49: fill_in(), ! 50: EVexpand(); ! 51: #endif /* LINT_ARGS */ ! 52: ! 53: #ifdef MAC ! 54: # undef private ! 55: # define private static ! 56: #endif ! 57: ! 58: int AbortChar = CTL('G'), ! 59: DoEVexpand = NO; /* should we expand evironment variables? */ ! 60: ! 61: int Asking = NO; ! 62: char Minibuf[LBSIZE]; ! 63: private Line *CurAskPtr = 0; /* points at some line in mini-buffer */ ! 64: private Buffer *AskBuffer = 0; /* Askbuffer points to actual structure */ ! 65: ! 66: /* The way the mini-buffer works is this: The first line of the mini-buffer ! 67: is where the user does his stuff. The rest of the buffer contains ! 68: strings that the user often wants to use, for instance, file names, or ! 69: common search strings, etc. If he types C-N or C-P while in ask(), we ! 70: bump the point up or down a line and extract the contents (we make sure ! 71: is somewhere in the mini-buffer). */ ! 72: ! 73: static Buffer * ! 74: get_minibuf() ! 75: { ! 76: if (AskBuffer) { /* make sure ut still exists */ ! 77: register Buffer *b; ! 78: ! 79: for (b = world; b != 0; b = b->b_next) ! 80: if (b == AskBuffer) ! 81: return b; ! 82: } ! 83: AskBuffer = do_select((Window *) 0, "*minibuf*"); ! 84: AskBuffer->b_type = B_SCRATCH; ! 85: return AskBuffer; ! 86: } ! 87: ! 88: /* Add a string to the mini-buffer. */ ! 89: ! 90: void ! 91: minib_add(str, movedown) ! 92: char *str; ! 93: { ! 94: register Buffer *saveb = curbuf; ! 95: ! 96: SetBuf(get_minibuf()); ! 97: LineInsert(1); ! 98: ins_str(str, NO); ! 99: if (movedown) ! 100: CurAskPtr = curline; ! 101: SetBuf(saveb); ! 102: } ! 103: ! 104: /* look for any substrings of the form $foo in linebuf, and expand ! 105: them according to their value in the environment (if possible) - ! 106: this munges all over curchar and linebuf without giving it a second ! 107: thought (I must be getting lazy in my old age) */ ! 108: private void ! 109: EVexpand() ! 110: { ! 111: register int c; ! 112: register char *lp = linebuf, ! 113: *ep; ! 114: char varname[128], ! 115: *vp, ! 116: *lp_start; ! 117: Mark *m = MakeMark(curline, curchar, M_FLOATER); ! 118: ! 119: while (c = *lp++) { ! 120: if (c != '$') ! 121: continue; ! 122: lp_start = lp - 1; /* the $ */ ! 123: vp = varname; ! 124: while (c = *lp++) { ! 125: if (!isword(c)) ! 126: break; ! 127: *vp++ = c; ! 128: } ! 129: *vp = '\0'; ! 130: /* if we find an env. variable with the right ! 131: name, we insert it in linebuf, and then delete ! 132: the variable name that we're replacing - and ! 133: then we continue in case there are others ... */ ! 134: if (ep = getenv(varname)) { ! 135: curchar = lp_start - linebuf; ! 136: ins_str(ep, NO); ! 137: del_char(FORWARD, strlen(varname) + 1); ! 138: lp = linebuf + curchar; ! 139: } ! 140: } ! 141: ToMark(m); ! 142: DelMark(m); ! 143: } ! 144: ! 145: private char * ! 146: real_ask(delim, d_proc, def, prompt) ! 147: char *delim, ! 148: *def, ! 149: *prompt; ! 150: int (*d_proc)(); ! 151: { ! 152: static int InAsk = 0; ! 153: jmp_buf savejmp; ! 154: int c, ! 155: prompt_len; ! 156: Buffer *saveb = curbuf; ! 157: int abort = 0, ! 158: no_typed = 0; ! 159: data_obj *push_cmd = LastCmd; ! 160: int o_a_v = arg_value(), ! 161: o_i_an_a = is_an_arg(); ! 162: #ifdef MAC ! 163: menus_off(); ! 164: #endif ! 165: ! 166: if (InAsk) ! 167: complain((char *) 0); ! 168: push_env(savejmp); ! 169: InAsk += 1; ! 170: SetBuf(get_minibuf()); ! 171: if (!inlist(AskBuffer->b_first, CurAskPtr)) ! 172: CurAskPtr = curline; ! 173: prompt_len = strlen(prompt); ! 174: ToFirst(); /* Beginning of buffer. */ ! 175: linebuf[0] = '\0'; ! 176: modify(); ! 177: makedirty(curline); ! 178: ! 179: if (setjmp(mainjmp)) ! 180: if (InJoverc) { /* this is a kludge */ ! 181: abort = YES; ! 182: goto cleanup; ! 183: } ! 184: ! 185: for (;;) { ! 186: clr_arg_value(); ! 187: last_cmd = this_cmd; ! 188: init_strokes(); ! 189: cont: s_mess("%s%s", prompt, linebuf); ! 190: Asking = curchar + prompt_len; ! 191: c = getch(); ! 192: if ((c == EOF) || index(delim, c)) { ! 193: if (DoEVexpand) ! 194: EVexpand(); ! 195: if (d_proc == (int(*)())0 || (*d_proc)(c) == 0) ! 196: goto cleanup; ! 197: } else if (c == AbortChar) { ! 198: message("[Aborted]"); ! 199: abort = YES; ! 200: goto cleanup; ! 201: } else switch (c) { ! 202: case CTL('N'): ! 203: case CTL('P'): ! 204: if (CurAskPtr != 0) { ! 205: int n = (c == CTL('P') ? -arg_value() : arg_value()); ! 206: CurAskPtr = next_line(CurAskPtr, n); ! 207: if (CurAskPtr == curbuf->b_first && CurAskPtr->l_next != 0) ! 208: CurAskPtr = CurAskPtr->l_next; ! 209: (void) ltobuf(CurAskPtr, linebuf); ! 210: modify(); ! 211: makedirty(curline); ! 212: Eol(); ! 213: this_cmd = 0; ! 214: } ! 215: break; ! 216: ! 217: case CTL('R'): ! 218: if (def) ! 219: ins_str(def, NO); ! 220: else ! 221: rbell(); ! 222: break; ! 223: ! 224: default: ! 225: dispatch(c); ! 226: break; ! 227: } ! 228: if (curbuf != AskBuffer) ! 229: SetBuf(AskBuffer); ! 230: if (curline != curbuf->b_first) { ! 231: CurAskPtr = curline; ! 232: curline = curbuf->b_first; /* with whatever is in linebuf */ ! 233: } ! 234: if (this_cmd == ARG_CMD) ! 235: goto cont; ! 236: } ! 237: cleanup: ! 238: pop_env(savejmp); ! 239: ! 240: LastCmd = push_cmd; ! 241: set_arg_value(o_a_v); ! 242: set_is_an_arg(o_i_an_a); ! 243: no_typed = (linebuf[0] == '\0'); ! 244: strcpy(Minibuf, linebuf); ! 245: SetBuf(saveb); ! 246: InAsk = Asking = Interactive = NO; ! 247: if (!abort) { ! 248: if (!charp()) { ! 249: Placur(ILI, 0); ! 250: flusho(); ! 251: } ! 252: if (no_typed) ! 253: return 0; ! 254: } else ! 255: complain(mesgbuf); ! 256: return Minibuf; ! 257: } ! 258: ! 259: /* VARARGS2 */ ! 260: ! 261: char * ! 262: ask(def, fmt, va_alist) ! 263: char *def, ! 264: *fmt; ! 265: va_dcl ! 266: { ! 267: char prompt[128]; ! 268: char *ans; ! 269: va_list ap; ! 270: ! 271: va_start(ap); ! 272: format(prompt, sizeof prompt, fmt, ap); ! 273: va_end(ap); ! 274: ans = real_ask("\r\n", (int (*)()) 0, def, prompt); ! 275: if (ans == 0) { /* Typed nothing. */ ! 276: if (def == 0) ! 277: complain("[No default]"); ! 278: return def; ! 279: } ! 280: return ans; ! 281: } ! 282: ! 283: /* VARARGS1 */ ! 284: ! 285: char * ! 286: do_ask(delim, d_proc, def, fmt, va_alist) ! 287: char *delim, ! 288: *def, ! 289: *fmt; ! 290: int (*d_proc)(); ! 291: va_dcl ! 292: { ! 293: char prompt[128]; ! 294: va_list ap; ! 295: ! 296: va_start(ap); ! 297: format(prompt, sizeof prompt, fmt, ap); ! 298: va_end(ap); ! 299: return real_ask(delim, d_proc, def, prompt); ! 300: } ! 301: ! 302: /* VARARGS1 */ ! 303: ! 304: int ! 305: yes_or_no_p(fmt, va_alist) ! 306: char *fmt; ! 307: va_dcl ! 308: { ! 309: char prompt[128]; ! 310: int c; ! 311: va_list ap; ! 312: ! 313: va_start(ap); ! 314: format(prompt, sizeof prompt, fmt, ap); ! 315: va_end(ap); ! 316: for (;;) { ! 317: message(prompt); ! 318: Asking = strlen(prompt); /* so redisplay works */ ! 319: c = getch(); ! 320: Asking = NO; ! 321: if (c == AbortChar) ! 322: complain("[Aborted]"); ! 323: switch (CharUpcase(c)) { ! 324: case 'Y': ! 325: return YES; ! 326: ! 327: case 'N': ! 328: return NO; ! 329: ! 330: default: ! 331: add_mess("[Type Y or N]"); ! 332: SitFor(10); ! 333: } ! 334: } ! 335: /* NOTREACHED */ ! 336: } ! 337: ! 338: #ifdef F_COMPLETION ! 339: static char *fc_filebase; ! 340: int DispBadFs = YES; /* display bad file names? */ ! 341: #ifndef MSDOS ! 342: char BadExtensions[128] = ".o"; ! 343: #else /* MSDOS */ ! 344: char BadExtensions[128] = ".obj .exe .com .bak .arc .lib .zoo"; ! 345: #endif /* MSDOS */ ! 346: ! 347: static ! 348: bad_extension(name) ! 349: char *name; ! 350: { ! 351: char *ip, ! 352: *bads = BadExtensions; ! 353: int namelen = strlen(name), ! 354: ext_len, ! 355: stop = 0; ! 356: ! 357: do { ! 358: if ((ip = index(bads, ' ')) == 0) { ! 359: ip = bads + strlen(bads); ! 360: stop = YES; ! 361: } ! 362: if ((ext_len = ip - bads) == 0) ! 363: continue; ! 364: if ((ext_len < namelen) && ! 365: (strncmp(&name[namelen - ext_len], bads, ext_len) == 0)) ! 366: return YES; ! 367: } while ((bads = ip + 1), !stop); ! 368: return NO; ! 369: } ! 370: ! 371: int ! 372: f_match(file) ! 373: char *file; ! 374: { ! 375: int len = strlen(fc_filebase); ! 376: ! 377: if (DispBadFs == NO) ! 378: if (bad_extension(file)) ! 379: return NO; ! 380: ! 381: return ((len == 0) || ! 382: #ifdef MSDOS ! 383: (casencmp(file, fc_filebase, strlen(fc_filebase)) == 0) ! 384: #else ! 385: (strncmp(file, fc_filebase, strlen(fc_filebase)) == 0) ! 386: #endif ! 387: ); ! 388: } ! 389: ! 390: static ! 391: isdir(name) ! 392: char *name; ! 393: { ! 394: struct stat stbuf; ! 395: char filebuf[FILESIZE]; ! 396: ! 397: PathParse(name, filebuf); ! 398: return ((stat(filebuf, &stbuf) != -1) && ! 399: (stbuf.st_mode & S_IFDIR) == S_IFDIR); ! 400: } ! 401: ! 402: private void ! 403: fill_in(dir_vec, n) ! 404: register char **dir_vec; ! 405: { ! 406: int minmatch = 0, ! 407: numfound = 0, ! 408: lastmatch = -1, ! 409: i, ! 410: the_same = TRUE, /* After filling in, are we the same ! 411: as when we were called? */ ! 412: is_ntdir; /* Is Newly Typed Directory name */ ! 413: char bads[128]; ! 414: ! 415: for (i = 0; i < n; i++) { ! 416: /* if it's no, then we have already filtered them out ! 417: in f_match() so there's no point in doing it again */ ! 418: if (DispBadFs == YES) { ! 419: if (bad_extension(dir_vec[i])) ! 420: continue; ! 421: } ! 422: if (numfound) ! 423: minmatch = min(minmatch, ! 424: numcomp(dir_vec[lastmatch], dir_vec[i])); ! 425: else ! 426: minmatch = strlen(dir_vec[i]); ! 427: lastmatch = i; ! 428: numfound += 1; ! 429: } ! 430: /* Ugh. Beware--this is hard to get right in a reasonable ! 431: manner. Please excuse this code--it's past my bedtime. */ ! 432: if (numfound == 0) { ! 433: rbell(); ! 434: return; ! 435: } ! 436: Eol(); ! 437: if (minmatch > strlen(fc_filebase)) { ! 438: the_same = FALSE; ! 439: null_ncpy(fc_filebase, dir_vec[lastmatch], minmatch); ! 440: Eol(); ! 441: makedirty(curline); ! 442: } ! 443: is_ntdir = ((numfound == 1) && ! 444: (curchar > 0) && ! 445: (linebuf[curchar - 1] != '/') && ! 446: (isdir(linebuf))); ! 447: if (the_same && !is_ntdir) { ! 448: add_mess((n == 1) ? " [Unique]" : " [Ambiguous]"); ! 449: SitFor(7); ! 450: } ! 451: if (is_ntdir) ! 452: insert_c('/', 1); ! 453: } ! 454: ! 455: extern int alphacomp(); ! 456: ! 457: /* called from do_ask() when one of "\r\n ?" is typed. Does the right ! 458: thing, depending on which. */ ! 459: ! 460: static ! 461: f_complete(c) ! 462: { ! 463: char dir[FILESIZE], ! 464: **dir_vec; ! 465: int nentries, ! 466: i; ! 467: ! 468: if (c == CR || c == LF) ! 469: return 0; /* tells ask to return now */ ! 470: #ifndef MSDOS /* kg */ ! 471: if ((fc_filebase = rindex(linebuf, '/')) != 0) { ! 472: #else /* MSDOS */ ! 473: fc_filebase = rindex(linebuf, '/'); ! 474: if (fc_filebase == (char *)0) ! 475: fc_filebase = rindex(linebuf, '\\'); ! 476: if (fc_filebase == (char *)0) ! 477: fc_filebase = rindex(linebuf, ':'); ! 478: if (fc_filebase != (char *)0) { ! 479: #endif /* MSDOS */ ! 480: char tmp[FILESIZE]; ! 481: ! 482: fc_filebase += 1; ! 483: null_ncpy(tmp, linebuf, (fc_filebase - linebuf)); ! 484: if (tmp[0] == '\0') ! 485: strcpy(tmp, "/"); ! 486: PathParse(tmp, dir); ! 487: } else { ! 488: fc_filebase = linebuf; ! 489: strcpy(dir, "."); ! 490: } ! 491: if ((nentries = scandir(dir, &dir_vec, f_match, alphacomp)) == -1) { ! 492: add_mess(" [Unknown directory: %s]", dir); ! 493: SitFor(7); ! 494: return 1; ! 495: } ! 496: if (nentries == 0) { ! 497: add_mess(" [No match]"); ! 498: SitFor(7); ! 499: } else if (c == ' ' || c == '\t') ! 500: fill_in(dir_vec, nentries); ! 501: else { ! 502: /* we're a '?' */ ! 503: int maxlen = 0, ! 504: ncols, ! 505: col, ! 506: lines, ! 507: linespercol; ! 508: ! 509: TOstart("Completion", FALSE); /* false means newline only on request */ ! 510: Typeout("(! means file will not be chosen unless typed explicitly)"); ! 511: Typeout((char *) 0); ! 512: Typeout("Possible completions (in %s):", dir); ! 513: Typeout((char *) 0); ! 514: ! 515: for (i = 0; i < nentries; i++) ! 516: maxlen = max(strlen(dir_vec[i]), maxlen); ! 517: maxlen += 4; /* pad each column with at least 4 spaces */ ! 518: ncols = (CO - 2) / maxlen; ! 519: linespercol = 1 + (nentries / ncols); ! 520: ! 521: for (lines = 0; lines < linespercol; lines++) { ! 522: for (col = 0; col < ncols; col++) { ! 523: int isbad, ! 524: which; ! 525: ! 526: which = (col * linespercol) + lines; ! 527: if (which >= nentries) ! 528: break; ! 529: if (DispBadFs == YES) ! 530: isbad = bad_extension(dir_vec[which]); ! 531: else ! 532: isbad = NO; ! 533: Typeout("%s%-*s", isbad ? "!" : NullStr, ! 534: maxlen - isbad, dir_vec[which]); ! 535: } ! 536: Typeout((char *) 0); ! 537: } ! 538: TOstop(); ! 539: } ! 540: freedir(&dir_vec, nentries); ! 541: return 1; ! 542: } ! 543: ! 544: #endif ! 545: ! 546: char * ! 547: ask_file(prmt, def, buf) ! 548: char *prmt, ! 549: *def, ! 550: *buf; ! 551: { ! 552: char *ans, ! 553: prompt[128], ! 554: *pretty_name = pr_name(def, YES); ! 555: if (prmt) ! 556: sprintf(prompt, prmt); ! 557: else { ! 558: if (def != 0 && *def != '\0') ! 559: sprintf(prompt, ": %f (default %s) ", pretty_name); ! 560: else ! 561: sprintf(prompt, ProcFmt); ! 562: } ! 563: #ifdef F_COMPLETION ! 564: ans = real_ask("\r\n \t?", f_complete, pretty_name, prompt); ! 565: if (ans == 0 && (ans = pretty_name) == 0) ! 566: complain("[No default file name]"); ! 567: #else ! 568: ans = ask(pretty_name, prompt); ! 569: #endif ! 570: PathParse(ans, buf); ! 571: ! 572: return buf; ! 573: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.