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

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

unix.superglobalmegacorp.com

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