Annotation of 43BSDTahoe/new/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 <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:                if (def != 0 && *def != '\0')
                    559:                        sprintf(prompt, ": %f (default %s) ", pretty_name);
                    560:                else
                    561:                        sprintf(prompt, ProcFmt);
                    562:        }
                    563: #ifdef F_COMPLETION
                    564:        ans = real_ask("\r\n \t?", f_complete, pretty_name, prompt);
                    565:        if (ans == 0 && (ans = pretty_name) == 0)
                    566:                complain("[No default file name]");
                    567: #else
                    568:        ans = ask(pretty_name, prompt);
                    569: #endif
                    570:        PathParse(ans, buf);
                    571: 
                    572:        return buf;
                    573: }

unix.superglobalmegacorp.com

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