Annotation of 43BSD/contrib/jove/ask.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.