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