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:         sprintf(prompt, ProcFmt);
 559: #ifdef F_COMPLETION
 560:     ans = real_ask("\r\n \t?", f_complete, pretty_name, prompt);
 561:     if (ans == 0)
 562:         complain((char *)0);
 563: #else
 564:     ans = ask(pretty_name, prompt);
 565: #endif
 566:     PathParse(ans, buf);
 567: 
 568:     return buf;
 569: }

Defined functions

EVexpand defined in line 108; used 3 times
bad_extension defined in line 347; used 5 times
f_complete defined in line 460; used 3 times
f_match defined in line 371; used 3 times
fill_in defined in line 402; used 3 times
get_minibuf defined in line 73; used 4 times
isdir defined in line 390; used 3 times
minib_add defined in line 90; used 3 times
real_ask defined in line 145; used 5 times

Defined variables

AbortChar defined in line 58; used 5 times
AskBuffer defined in line 64; used 8 times
Asking defined in line 61; used 10 times
BadExtensions defined in line 344; used 2 times
CurAskPtr defined in line 63; used 12 times
DispBadFs defined in line 340; used 4 times
Minibuf defined in line 62; used 2 times
fc_filebase defined in line 339; used 17 times
private defined in line 145; never used

Defined macros

private defined in line 55; used 14 times
Last modified: 1988-08-11
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4223
Valid CSS Valid XHTML 1.0 Strict