|
|
1.1 ! root 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 "termcap.h" ! 12: #include "ctype.h" ! 13: #include <signal.h> ! 14: #include <varargs.h> ! 15: ! 16: #ifdef F_COMPLETION ! 17: # include <sys/stat.h> ! 18: #endif ! 19: ! 20: int Asking = 0; ! 21: char Minibuf[LBSIZE]; ! 22: private Line *CurAskPtr = 0; /* points at some line in mini-buffer */ ! 23: private Buffer *AskBuffer = 0; /* Askbuffer points to actual structure */ ! 24: ! 25: /* The way the mini-buffer works is this: The first line of the mini-buffer ! 26: is where the user does his stuff. The rest of the buffer contains ! 27: strings that the user often wants to use, for instance, file names, or ! 28: common search strings, etc. If he types C-N or C-P while in ask(), we ! 29: bump the point up or down a line and extract the contents (we make sure ! 30: is somewhere in the mini-buffer). */ ! 31: ! 32: static Buffer * ! 33: get_minibuf() ! 34: { ! 35: if (AskBuffer) ! 36: return AskBuffer; ! 37: AskBuffer = do_select((Window *) 0, "Minibuf"); ! 38: AskBuffer->b_type = B_SCRATCH; ! 39: return AskBuffer; ! 40: } ! 41: ! 42: /* Add a string to the mini-buffer. */ ! 43: ! 44: minib_add(str, movedown) ! 45: char *str; ! 46: { ! 47: register Buffer *saveb = curbuf; ! 48: ! 49: SetBuf(get_minibuf()); ! 50: LineInsert(); ! 51: ins_str(str, NO); ! 52: if (movedown) ! 53: CurAskPtr = curline; ! 54: SetBuf(saveb); ! 55: } ! 56: ! 57: static char * ! 58: real_ask(delim, d_proc, def, prompt) ! 59: char *delim, ! 60: *def, ! 61: *prompt; ! 62: int (*d_proc)(); ! 63: { ! 64: static int InAsk = 0; ! 65: jmp_buf savejmp; ! 66: int c, ! 67: prompt_len; ! 68: Buffer *saveb = curbuf; ! 69: int abort = 0, ! 70: no_typed = 0; ! 71: data_obj *push_cmd = LastCmd; ! 72: int o_exp = exp, ! 73: o_exp_p = exp_p; ! 74: ! 75: if (InAsk) ! 76: complain((char *) 0); ! 77: push_env(savejmp); ! 78: InAsk++; ! 79: SetBuf(get_minibuf()); ! 80: if (!inlist(AskBuffer->b_first, CurAskPtr)) ! 81: CurAskPtr = curline; ! 82: prompt_len = strlen(prompt); ! 83: ToFirst(); /* Beginning of buffer. */ ! 84: linebuf[0] = '\0'; ! 85: modify(); ! 86: makedirty(curline); ! 87: ! 88: if (setjmp(mainjmp)) ! 89: if (InJoverc) { /* this is a kludge */ ! 90: abort++; ! 91: goto cleanup; ! 92: } ! 93: ! 94: for (;;) { ! 95: exp = 1; ! 96: exp_p = 0; ! 97: last_cmd = this_cmd; ! 98: init_strokes(); ! 99: cont: s_mess("%s%s", prompt, linebuf); ! 100: Asking = curchar + prompt_len; ! 101: c = getch(); ! 102: if ((c == EOF) || index(delim, c)) { ! 103: if (d_proc == 0 || (*d_proc)(c) == 0) ! 104: goto cleanup; ! 105: } else switch (c) { ! 106: case CTL(G): ! 107: message("[Aborted]"); ! 108: abort++; ! 109: goto cleanup; ! 110: ! 111: case CTL(N): ! 112: case CTL(P): ! 113: if (CurAskPtr != 0) { ! 114: int n = (c == CTL(P) ? -exp : exp); ! 115: ! 116: CurAskPtr = next_line(CurAskPtr, n); ! 117: if (CurAskPtr == curbuf->b_first && CurAskPtr->l_next != 0) ! 118: CurAskPtr = CurAskPtr->l_next; ! 119: (void) ltobuf(CurAskPtr, linebuf); ! 120: modify(); ! 121: makedirty(curline); ! 122: Eol(); ! 123: this_cmd = 0; ! 124: } ! 125: break; ! 126: ! 127: case CTL(R): ! 128: if (def) ! 129: ins_str(def, NO); ! 130: else ! 131: rbell(); ! 132: break; ! 133: ! 134: default: ! 135: dispatch(c); ! 136: break; ! 137: } ! 138: if (curbuf != AskBuffer) ! 139: SetBuf(AskBuffer); ! 140: if (curline != curbuf->b_first) { ! 141: CurAskPtr = curline; ! 142: curline = curbuf->b_first; /* with whatever is in linebuf */ ! 143: } ! 144: if (this_cmd == ARG_CMD) ! 145: goto cont; ! 146: } ! 147: cleanup: ! 148: pop_env(savejmp); ! 149: ! 150: LastCmd = push_cmd; ! 151: exp_p = o_exp_p; ! 152: exp = o_exp; ! 153: no_typed = (linebuf[0] == '\0'); ! 154: strcpy(Minibuf, linebuf); ! 155: SetBuf(saveb); ! 156: InAsk = Asking = Interactive = 0; ! 157: if (!abort) { ! 158: if (!charp()) { ! 159: Placur(ILI, 0); ! 160: flusho(); ! 161: } ! 162: if (no_typed) ! 163: return 0; ! 164: } else ! 165: complain(mesgbuf); ! 166: return Minibuf; ! 167: } ! 168: ! 169: /* VARARGS2 */ ! 170: ! 171: char * ! 172: ask(def, fmt, va_alist) ! 173: char *def, ! 174: *fmt; ! 175: va_dcl ! 176: { ! 177: char prompt[128]; ! 178: char *ans; ! 179: va_list ap; ! 180: ! 181: va_start(ap); ! 182: format(prompt, sizeof prompt, fmt, ap); ! 183: va_end(ap); ! 184: ans = real_ask("\r\n", (int (*)()) 0, def, prompt); ! 185: if (ans == 0) { /* Typed nothing. */ ! 186: if (def == 0) ! 187: complain("[No default]"); ! 188: return def; ! 189: } ! 190: return ans; ! 191: } ! 192: ! 193: /* VARARGS2 */ ! 194: ! 195: char * ! 196: do_ask(delim, d_proc, def, fmt, va_alist) ! 197: char *delim, ! 198: *def, ! 199: *fmt; ! 200: int (*d_proc)(); ! 201: va_dcl ! 202: { ! 203: char prompt[128]; ! 204: va_list ap; ! 205: ! 206: va_start(ap); ! 207: format(prompt, sizeof prompt, fmt, ap); ! 208: va_end(ap); ! 209: return real_ask(delim, d_proc, def, prompt); ! 210: } ! 211: ! 212: #ifdef F_COMPLETION ! 213: static char *fc_filebase; ! 214: char BadExtensions[128] = ".o"; ! 215: ! 216: static ! 217: bad_extension(name, bads) ! 218: char *name, ! 219: *bads; ! 220: { ! 221: char *ip; ! 222: int namelen = strlen(name), ! 223: ext_len, ! 224: stop = 0; ! 225: ! 226: do { ! 227: if (ip = index(bads, ' ')) ! 228: *ip = 0; ! 229: else { ! 230: ip = bads + strlen(bads); ! 231: stop++; ! 232: } ! 233: if ((ext_len = ip - bads) == 0) ! 234: continue; ! 235: if ((ext_len < namelen) && ! 236: (strcmp(&name[namelen - ext_len], bads) == 0)) ! 237: return YES; ! 238: } while ((bads = ip + 1), !stop); ! 239: return NO; ! 240: } ! 241: ! 242: f_match(file) ! 243: char *file; ! 244: { ! 245: int len = strlen(fc_filebase); ! 246: ! 247: return ((len == 0) || ! 248: (strncmp(file, fc_filebase, strlen(fc_filebase)) == 0)); ! 249: } ! 250: ! 251: static ! 252: isdir(name) ! 253: char *name; ! 254: { ! 255: struct stat stbuf; ! 256: char filebuf[FILESIZE]; ! 257: ! 258: PathParse(name, filebuf); ! 259: return ((stat(filebuf, &stbuf) != -1) && ! 260: (stbuf.st_mode & S_IFDIR) == S_IFDIR); ! 261: } ! 262: ! 263: static ! 264: fill_in(dir_vec, n) ! 265: register char **dir_vec; ! 266: { ! 267: int minmatch = 0, ! 268: numfound = 0, ! 269: lastmatch = -1, ! 270: i, ! 271: the_same = TRUE, /* After filling in, are we the same ! 272: as when we were called? */ ! 273: is_ntdir; /* Is Newly Typed Directory name */ ! 274: char bads[128]; ! 275: ! 276: for (i = 0; i < n; i++) { ! 277: strcpy(bads, BadExtensions); ! 278: /* bad_extension() is destructive */ ! 279: if (bad_extension(dir_vec[i], bads)) ! 280: continue; ! 281: if (numfound) ! 282: minmatch = min(minmatch, ! 283: numcomp(dir_vec[lastmatch], dir_vec[i])); ! 284: else ! 285: minmatch = strlen(dir_vec[i]); ! 286: lastmatch = i; ! 287: numfound++; ! 288: } ! 289: /* Ugh. Beware--this is hard to get right in a reasonable ! 290: manner. Please excuse this code--it's past my bedtime. */ ! 291: if (numfound == 0) { ! 292: rbell(); ! 293: return; ! 294: } ! 295: Eol(); ! 296: if (minmatch > strlen(fc_filebase)) { ! 297: the_same = FALSE; ! 298: null_ncpy(fc_filebase, dir_vec[lastmatch], minmatch); ! 299: Eol(); ! 300: makedirty(curline); ! 301: } ! 302: is_ntdir = ((numfound == 1) && ! 303: (curchar > 0) && ! 304: (linebuf[curchar - 1] != '/') && ! 305: (isdir(linebuf))); ! 306: if (the_same && !is_ntdir) { ! 307: add_mess(n == 1 ? " [Unique]" : " [Ambiguous]"); ! 308: (void) SitFor(7); ! 309: } ! 310: if (is_ntdir) ! 311: Insert('/'); ! 312: } ! 313: ! 314: extern int alphacomp(); ! 315: ! 316: /* called from do_ask() when one of "\r\n ?" is typed. Does the right ! 317: thing, depending on which. */ ! 318: ! 319: static ! 320: f_complete(c) ! 321: { ! 322: char dir[FILESIZE], ! 323: **dir_vec; ! 324: int nentries, ! 325: i; ! 326: ! 327: if (c == CR || c == LF) ! 328: return 0; /* tells ask to return now */ ! 329: if ((fc_filebase = rindex(linebuf, '/')) != 0) { ! 330: char tmp[FILESIZE]; ! 331: ! 332: null_ncpy(tmp, linebuf, (++fc_filebase - linebuf)); ! 333: if (tmp[0] == '\0') ! 334: strcpy(tmp, "/"); ! 335: PathParse(tmp, dir); ! 336: } else { ! 337: fc_filebase = linebuf; ! 338: strcpy(dir, "."); ! 339: } ! 340: if ((nentries = scandir(dir, &dir_vec, f_match, alphacomp)) == -1) { ! 341: add_mess(" [Unknown directory: %s]", dir); ! 342: (void) SitFor(7); ! 343: return 1; ! 344: } ! 345: if (nentries == 0) { ! 346: add_mess(" [No match]"); ! 347: (void) SitFor(7); ! 348: } else if (c == ' ') ! 349: fill_in(dir_vec, nentries); ! 350: else { ! 351: /* we're a '?' */ ! 352: int maxlen = 0, ! 353: ncols, ! 354: col, ! 355: lines, ! 356: linespercol; ! 357: ! 358: TOstart("Completion", FALSE); /* false means newline only on request */ ! 359: Typeout("(! means file will not be chosen unless typed explicitly)"); ! 360: Typeout((char *) 0); ! 361: Typeout("Possible completions (in %s):", dir); ! 362: Typeout((char *) 0); ! 363: ! 364: for (i = 0; i < nentries; i++) ! 365: maxlen = max(strlen(dir_vec[i]), maxlen); ! 366: maxlen += 4; /* pad each column with at least 4 spaces */ ! 367: ncols = (CO - 2) / maxlen; ! 368: linespercol = 1 + (nentries / ncols); ! 369: ! 370: for (lines = 0; lines < linespercol; lines++) { ! 371: for (col = 0; col < ncols; col++) { ! 372: int isbad, ! 373: which; ! 374: char bads[128]; ! 375: ! 376: which = (col * linespercol) + lines; ! 377: if (which >= nentries) ! 378: break; ! 379: strcpy(bads, BadExtensions); ! 380: isbad = bad_extension(dir_vec[which], bads); ! 381: Typeout("%s%-*s", isbad ? "!" : NullStr, ! 382: maxlen - isbad, dir_vec[which]); ! 383: } ! 384: Typeout((char *) 0); ! 385: } ! 386: TOstop(); ! 387: } ! 388: freedir(&dir_vec, nentries); ! 389: return 1; ! 390: } ! 391: ! 392: #endif ! 393: ! 394: char * ! 395: ask_file(def, buf) ! 396: char *def, ! 397: *buf; ! 398: { ! 399: char *ans, ! 400: prompt[128], ! 401: *pretty_name = pr_name(def); ! 402: ! 403: if (def != 0 && *def != '\0') ! 404: sprintf(prompt, ": %f (default %s) ", pretty_name); ! 405: else ! 406: sprintf(prompt, ProcFmt); ! 407: #ifdef F_COMPLETION ! 408: ans = real_ask("\r\n ?", f_complete, pretty_name, prompt); ! 409: if (ans == 0 && (ans = pretty_name) == 0) ! 410: complain("[No default file name]"); ! 411: #else ! 412: ans = ask(pretty_name, prompt); ! 413: #endif ! 414: PathParse(ans, buf); ! 415: ! 416: return buf; ! 417: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.