Annotation of 43BSDReno/contrib/jove/ask.c, revision 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.