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: }

Defined functions

bad_extension defined in line 216; used 2 times
do_ask defined in line 195; used 5 times
f_complete defined in line 319; used 1 times
f_match defined in line 242; used 1 times
fill_in defined in line 263; used 1 times
get_minibuf defined in line 32; used 2 times
isdir defined in line 251; used 1 times
minib_add defined in line 44; used 1 times
real_ask defined in line 57; used 3 times

Defined variables

AskBuffer defined in line 23; used 8 times
Asking defined in line 20; used 6 times
BadExtensions defined in line 214; used 3 times
CurAskPtr defined in line 22; used 12 times
Minibuf defined in line 21; used 2 times
fc_filebase defined in line 213; used 8 times
Last modified: 1986-03-28
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1739
Valid CSS Valid XHTML 1.0 Strict