Annotation of 43BSDTahoe/new/jove/c.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: /* Contains commands for C mode.  Paren matching routines are in here. */
                      9: 
                     10: #include "jove.h"
                     11: #include "re.h"
                     12: #include "ctype.h"
                     13: 
                     14: #ifdef MAC
                     15: #      undef private
                     16: #      define private
                     17: #endif
                     18: 
                     19: #ifdef LINT_ARGS
                     20: private int
                     21:        backslashed(char *, int);
                     22: private void   
                     23:        do_expr(int, int),
                     24:        FindMatch(int),
                     25:        parse_cmt_fmt(char *),
                     26:        strip_c(char *, char *);
                     27: #else
                     28: private int
                     29:        backslashed();
                     30: private void   
                     31:        do_expr(),
                     32:        FindMatch(),
                     33:        parse_cmt_fmt(),
                     34:        strip_c();
                     35: #endif /* LINT_ARGS */
                     36: 
                     37: #ifdef MAC
                     38: #      undef private
                     39: #      define private static
                     40: #endif
                     41: 
                     42: 
                     43: private int
                     44: backslashed(lp, cpos)
                     45: register char  *lp;
                     46: register int   cpos;
                     47: {
                     48:        register int    cnt = 0;
                     49: 
                     50:        while (cpos > 0 && lp[--cpos] == '\\')
                     51:                cnt += 1;
                     52:        return (cnt % 2);
                     53: }
                     54: 
                     55: private char   *p_types = "(){}[]";
                     56: private int    mp_kind;
                     57: #define MP_OKAY                0
                     58: #define MP_MISMATCH    1
                     59: #define MP_UNBALANCED  2
                     60: 
                     61: void
                     62: mp_error()
                     63: {
                     64:        switch (mp_kind) {
                     65:        case MP_MISMATCH:
                     66:                message("[Mismatched parentheses]");
                     67:                break;
                     68: 
                     69:        case MP_UNBALANCED:
                     70:                message("[Unbalanced parenthesis]");
                     71:                break;
                     72: 
                     73:        case MP_OKAY:
                     74:        default:
                     75:                return;
                     76:        }
                     77:        rbell();
                     78: }
                     79: 
                     80: /* Search from the current position for the paren that matches p_type.
                     81:    Search in the direction dir.  If can_mismatch is YES then it is okay
                     82:    to have mismatched parens.  If stop_early is YES then when an open
                     83:    paren is found at the beginning of a line, it is assumed that there
                     84:    is no point in backing up further.  This is so when you hit tab or
                     85:    LineFeed outside, in-between procedure/function definitions, it won't
                     86:    sit there searching all the way to the beginning of the file for a
                     87:    match that doesn't exist.  {forward,backward}-s-expression are the
                     88:    only ones that insist on getting the "true" story. */
                     89: 
                     90: Bufpos *
                     91: m_paren(p_type, dir, can_mismatch, can_stop)
                     92: char   p_type;
                     93: register int   dir;
                     94: {
                     95:        static Bufpos   ret;
                     96:        Bufpos  savedot,
                     97:                *sp;
                     98:        char    re_buf[100],
                     99:                *re_alts[NALTS];
                    100:        int     count = 0;
                    101:        register char   *lp,
                    102:                        c;
                    103:        char    p_match,
                    104:                re_str[128],
                    105:                *cp,
                    106:                quote_c = 0;
                    107:        register int    c_char;
                    108:        int     in_comment = -1,
                    109:                stopped = NO;
                    110: 
                    111:        sprintf(re_str, "[(){}[\\]%s]", (MajorMode(CMODE)) ? "/\"'" : "\"");
                    112:        REcompile(re_str, 1, re_buf, re_alts);
                    113:        if (cp = index(p_types, p_type))
                    114:                p_match = cp[dir];
                    115:        else
                    116:                complain("[Cannot match %c's]", p_type);
                    117:        DOTsave(&savedot);
                    118: 
                    119:        /* To make things a little faster I avoid copying lines into
                    120:           linebuf by setting curline and curchar by hand.  Warning:
                    121:           this is slightly to very risky.  When I did this there were
                    122:           lots of problems with procedures that expect the contents of
                    123:           curline to be in linebuf. */
                    124:        while (count >= 0) {
                    125:                sp = docompiled(dir, re_buf, re_alts);
                    126:                if (sp == 0)
                    127:                        break;
                    128:                lp = lbptr(sp->p_line);
                    129: 
                    130:                if (sp->p_line != curline)
                    131:                        /* let's assume that strings do NOT go over line
                    132:                           bounderies (for now don't check for wrapping
                    133:                           strings) */
                    134:                        quote_c = 0;
                    135:                curline = sp->p_line;
                    136:                curchar = sp->p_char;   /* here's where I cheat */
                    137:                c_char = curchar;
                    138:                if (dir == FORWARD)
                    139:                        c_char -= 1;
                    140:                if (backslashed(lp, c_char))
                    141:                        continue;
                    142:                c = lp[c_char];
                    143:                /* check if this is a comment (if we're not inside quotes) */
                    144:                if (quote_c == 0 && c == '/') {
                    145:                        int     new_ic;
                    146: 
                    147:                        if ((c_char != 0) && lp[c_char - 1] == '*') {
                    148:                                new_ic = (dir == FORWARD) ? NO : YES;
                    149:                                if (new_ic == NO && in_comment == -1) {
                    150:                                        count = 0;
                    151:                                        quote_c = 0;
                    152:                                }
                    153:                        } else if (lp[c_char + 1] == '*') {
                    154:                                new_ic = (dir == FORWARD) ? YES : NO;
                    155:                                if (new_ic == NO && in_comment == -1) {
                    156:                                        count = 0;
                    157:                                        quote_c = 0;
                    158:                                }
                    159:                        }
                    160:                        in_comment = new_ic;
                    161:                }
                    162:                if (in_comment == YES)
                    163:                        continue;
                    164:                if (c == '"' || c == '\'') {
                    165:                        if (quote_c == c)
                    166:                                quote_c = 0;
                    167:                        else if (quote_c == 0)
                    168:                                quote_c = c;
                    169:                }
                    170:                if (quote_c != 0)
                    171:                        continue;
                    172:                if (isopenp(c)) {
                    173:                        count += dir;
                    174:                        if (c_char == 0 && can_stop == YES && count >= 0) {
                    175:                                stopped = YES;
                    176:                                break;
                    177:                        }
                    178:                } else if (isclosep(c))
                    179:                        count -= dir;
                    180:        }
                    181: 
                    182:        ret.p_line = curline;
                    183:        ret.p_char = curchar;
                    184: 
                    185:        curline = savedot.p_line;
                    186:        curchar = savedot.p_char;       /* here's where I undo it */
                    187: 
                    188:        if (count >= 0)
                    189:                mp_kind = MP_UNBALANCED;
                    190:        else if (c != p_match)
                    191:                mp_kind = MP_MISMATCH;
                    192:        else
                    193:                mp_kind = MP_OKAY;
                    194: 
                    195:        /* If we stopped (which means we were allowed to stop) and there
                    196:           was an error, we clear the error so no error message is printed.
                    197:           An error should be printed ONLY when we are sure about the fact,
                    198:           namely we didn't stop prematurely HOPING that it was the right
                    199:           answer. */
                    200:        if (stopped && mp_kind != MP_OKAY) {
                    201:                mp_kind = MP_OKAY;
                    202:                return 0;
                    203:        }
                    204:        if (mp_kind == MP_OKAY || (mp_kind == MP_MISMATCH && can_mismatch == YES))
                    205:                return &ret;
                    206:        return 0;
                    207: }
                    208: 
                    209: private void
                    210: do_expr(dir, skip_words)
                    211: register int   dir;
                    212: {
                    213:        register char   c,
                    214:                        syntax = (dir == FORWARD) ? _Op : _Cl;
                    215: 
                    216:        if (dir == BACKWARD)
                    217:                b_char(1);
                    218:        c = linebuf[curchar];
                    219:        for (;;) {
                    220:                if (!skip_words && ismword(c)) {
                    221:                    WITH_TABLE(curbuf->b_major)
                    222:                    if (dir == FORWARD)
                    223:                        f_word(1);
                    224:                    else
                    225:                        b_word(1);      
                    226:                    END_TABLE();
                    227:                    break;
                    228:                } else if (has_syntax(c, syntax)) {
                    229:                        FindMatch(dir);
                    230:                        break;
                    231:                }
                    232:                f_char(dir);
                    233:                if (eobp() || bobp())
                    234:                        return;
                    235:                c = linebuf[curchar];
                    236:        }
                    237: }
                    238: 
                    239: void
                    240: FSexpr()
                    241: {
                    242:        register int    num = arg_value();
                    243: 
                    244:        if (num < 0) {
                    245:                set_arg_value(-num);
                    246:                BSexpr();
                    247:        }
                    248:        while (--num >= 0)
                    249:                do_expr(FORWARD, NO);
                    250: }
                    251: 
                    252: void
                    253: FList()
                    254: {
                    255:        register int    num = arg_value();
                    256: 
                    257:        if (num < 0) {
                    258:                set_arg_value(-num);
                    259:                BList();
                    260:        }
                    261:        while (--num >= 0)
                    262:                do_expr(FORWARD, YES);
                    263: }
                    264: 
                    265: void
                    266: BSexpr()
                    267: {
                    268:        register int    num = arg_value();
                    269: 
                    270:        if (num < 0) {
                    271:                negate_arg_value();
                    272:                FSexpr();
                    273:        }
                    274:        while (--num >= 0)
                    275:                do_expr(BACKWARD, NO);
                    276: }
                    277: 
                    278: void
                    279: BList()
                    280: {
                    281:        register int    num = arg_value();
                    282: 
                    283:        if (num < 0) {
                    284:                negate_arg_value();
                    285:                FList();
                    286:        }
                    287:        while (--num >= 0)
                    288:                do_expr(BACKWARD, YES);
                    289: }
                    290: 
                    291: void
                    292: BUpList()
                    293: {
                    294:        Bufpos  *mp;
                    295:        char    c = (MajorMode(CMODE) ? '}' : ')');
                    296: 
                    297:        mp = m_paren(c, BACKWARD, NO, YES);
                    298:        if (mp == 0)
                    299:                mp_error();
                    300:        else
                    301:                SetDot(mp);
                    302: }
                    303: 
                    304: void
                    305: FDownList()
                    306: {
                    307:        Bufpos  *sp;
                    308:        char    *sstr = (MajorMode(CMODE) ? "[{([\\])}]" : "[()]"),
                    309:                *lp;
                    310: 
                    311:        sp = dosearch(sstr, FORWARD, YES);
                    312:        if (sp != 0)
                    313:                lp = lcontents(sp->p_line);
                    314:        if (sp == 0 || has_syntax(lp[sp->p_char - 1], _Cl))
                    315:                complain("[No contained expression]");
                    316:        SetDot(sp);
                    317: }
                    318: 
                    319: /* Move to the matching brace or paren depending on the current position
                    320:    in the buffer. */
                    321: 
                    322: private void
                    323: FindMatch(dir)
                    324: {
                    325:        register Bufpos *bp;
                    326:        register char   c = linebuf[curchar];
                    327: 
                    328:        if ((index(p_types, c) == 0) ||
                    329:            (backslashed(linebuf, curchar)))
                    330:                complain((char *) 0);
                    331:        if (dir == FORWARD)
                    332:                f_char(1);
                    333:        bp = m_paren(c, dir, YES, NO);
                    334:        if (dir == FORWARD)
                    335:                b_char(1);
                    336:        if (bp != 0)
                    337:                SetDot(bp);
                    338:        mp_error();     /* if there is an error the user wants to
                    339:                           know about it */
                    340: }
                    341: 
                    342: Bufpos *
                    343: c_indent(incrmt)
                    344: {
                    345:        Bufpos  *bp;
                    346:        int     indent = 0;
                    347: 
                    348:        if (bp = m_paren('}', BACKWARD, NO, YES)) {
                    349:                Bufpos  save;
                    350: 
                    351:                DOTsave(&save);
                    352:                SetDot(bp);
                    353:                ToIndent();
                    354:                indent = calc_pos(linebuf, curchar);
                    355:                SetDot(&save);
                    356:        }
                    357:        if (incrmt) {
                    358:                if (indent == 0)
                    359:                        incrmt = tabstop;
                    360:                else
                    361:                        incrmt = (tabstop - (indent%tabstop));
                    362:        }
                    363:        n_indent(indent + incrmt);
                    364:        return bp;
                    365: }
                    366: 
                    367: #ifdef CMT_FMT
                    368: 
                    369: char   CmtFmt[80] = "/*%n%! * %c%!%n */";
                    370: 
                    371: void
                    372: Comment()
                    373: {
                    374:        FillComment(CmtFmt);
                    375: }
                    376: 
                    377: /* Strip leading and trailing white space.  Skip over any imbedded '\r's. */
                    378: 
                    379: private void
                    380: strip_c(from, to)
                    381: char   *from,
                    382:        *to;
                    383: {
                    384:        register char   *fr_p = from,
                    385:                        *to_p = to,
                    386:                        c;
                    387: 
                    388:        while (c = *fr_p) {
                    389:                if (c == ' ' || c == '\t' || c == '\r')
                    390:                        fr_p += 1;
                    391:                else
                    392:                        break;
                    393:        }
                    394:        while (c = *fr_p) {
                    395:                if (c != '\r')
                    396:                        *to_p++ = c;
                    397:                fr_p += 1;
                    398:        }
                    399:        while (--to_p >= to)
                    400:                if (*to_p != ' ' && *to_p != '\t')
                    401:                        break;
                    402:        *++to_p = '\0';
                    403: }
                    404: 
                    405: private char   open_c[20],     /* the open comment format string */
                    406:                open_pat[20],   /* the search pattern for open comment */
                    407:                l_header[20],   /* the prefix for each comment line */
                    408:                l_trailer[20],  /* the suffix ... */
                    409:                close_c[20],
                    410:                close_pat[20];
                    411: 
                    412: private char   *comment_body[] = {
                    413:        open_c,
                    414:        l_header,
                    415:        l_trailer,
                    416:        close_c
                    417: };
                    418:                                        
                    419: private int    nlflags;
                    420: 
                    421: /* Fill in the data structures above from the format string.  Don't return
                    422:    if there's trouble. */
                    423: 
                    424: private void
                    425: parse_cmt_fmt(str)
                    426: char   *str;
                    427: {
                    428:        register char   *fmtp = str;
                    429:        register char   **c_body = comment_body,
                    430:                        *body_p = *c_body;
                    431:        int     c,
                    432:                newlines = 1;
                    433: 
                    434:        /* pick apart the comment string */
                    435:        while (c = *fmtp++) {
                    436:                if (c != '%') {
                    437:                        *body_p++ = c;
                    438:                        continue;
                    439:                }
                    440:                switch(c = *fmtp++) {
                    441:                case 'n':
                    442:                        if (newlines == 2 || newlines == 3)
                    443:                                complain("%n not allowed in line header or trailer: %s",
                    444:                                  fmtp - 2);
                    445:                        nlflags += newlines;
                    446:                        *body_p++ = '\r';
                    447:                        break;
                    448:                case 't':
                    449:                        *body_p++ = '\t';
                    450:                        break;
                    451:                case '%':
                    452:                        *body_p++ = '%';
                    453:                        break;
                    454:                case '!':
                    455:                case 'c':
                    456:                        newlines += 1;
                    457:                        *body_p++ = '\0';
                    458:                        body_p = *++c_body;
                    459:                        break;
                    460:                default:
                    461:                        complain("[Unknown comment escape: %%%c]", c);
                    462:                        /* VARARGS */
                    463:                        break;
                    464:                }
                    465:        }
                    466:        *body_p = '\0';
                    467:        /* make search patterns */
                    468:        strip_c(open_c, open_pat);
                    469:        strip_c(close_c, close_pat);
                    470: }
                    471: 
                    472: #define NL_IN_OPEN_C  ((nlflags % 4) == 1)
                    473: #define NL_IN_CLOSE_C (nlflags >= 4)
                    474: 
                    475: void
                    476: FillComment(format)
                    477: char   *format;
                    478: {
                    479:        int     saveRMargin,
                    480:                indent_pos,
                    481:                close_at_dot = NO,
                    482:                slen,
                    483:                header_len,
                    484:                trailer_len;
                    485:        register char   *cp;
                    486:        static char     inside_err[] = "[Must be between %s and %s to re-format]";
                    487:        Bufpos  open_c_pt,
                    488:                close_c_pt,
                    489:                tmp_bp,
                    490:                *match_o,
                    491:                *match_c;
                    492:        Mark    *entry_mark,
                    493:                *open_c_mark,
                    494:                *savedot;
                    495: 
                    496:        parse_cmt_fmt(format);
                    497:        /* figure out if we're "inside" a comment */
                    498:        if ((match_o = dosearch(open_pat, BACKWARD, 0)) == 0)
                    499:                /* VARARGS */
                    500:                complain("No opening %s to match to.", open_pat);
                    501:        open_c_pt = *match_o;
                    502:        if ((match_c = dosearch(close_pat, BACKWARD, NO)) != 0 &&
                    503:            inorder(open_c_pt.p_line, open_c_pt.p_char,
                    504:                    match_c->p_line, match_c->p_char))
                    505:                complain(inside_err, open_pat, close_pat);
                    506:        if ((match_o = dosearch(open_pat, FORWARD, NO)) != 0) {
                    507:                tmp_bp = *match_o;
                    508:                match_o = &tmp_bp;
                    509:        } 
                    510:        if ((match_c = dosearch(close_pat, FORWARD, 0)) != (Bufpos *) 0)
                    511:                close_c_pt = *match_c;
                    512: 
                    513:        /* Here's where we figure out whether to format from dot or from
                    514:           the close comment.  Note that we've already searched backwards to
                    515:           find the open comment symbol for the comment we are formatting.
                    516:           The open symbol mentioned below refers to the possible existence
                    517:           of the next comment.  There are 5 cases:
                    518:                1) no open or close symbol              ==> dot
                    519:                2) open, but no close symbol            ==> dot
                    520:                3) close, but no open                   ==> close
                    521:                4) open, close are inorder              ==> dot
                    522:                5) open, close are not inorder          ==> close */
                    523: 
                    524: 
                    525:        if (match_o == (Bufpos *) 0) {
                    526:                if (match_c == (Bufpos *) 0)
                    527:                        close_at_dot = YES;
                    528:        } else if (match_c == (Bufpos *) 0)
                    529:                close_at_dot = YES;
                    530:        else if (inorder(match_o->p_line, match_o->p_char,
                    531:                 match_c->p_line, match_c->p_char))
                    532:                close_at_dot = YES;
                    533:        if (close_at_dot) {
                    534:                close_c_pt.p_line = curline;
                    535:                close_c_pt.p_char = curchar;
                    536:        } else {
                    537:                SetDot(match_c);
                    538:        }
                    539:        SetDot(&open_c_pt);
                    540:        open_c_mark = MakeMark(curline, curchar, M_FLOATER);
                    541:        indent_pos = calc_pos(linebuf, curchar);
                    542:        /* search for a close comment; delete it if it exits */
                    543:        SetDot(&close_c_pt);
                    544:        if (close_at_dot == 0) {
                    545:                slen = strlen(close_pat);
                    546:                while (slen--)
                    547:                        del_char(BACKWARD, 1);
                    548:        }
                    549:        entry_mark = MakeMark(curline, curchar, M_FLOATER);
                    550:        ToMark(open_c_mark);
                    551:        /* always separate the comment body from anything preceeding it */
                    552:        LineInsert(1);
                    553:        DelWtSpace();
                    554:        Bol();
                    555:        for (cp = open_c; *cp; cp++) {
                    556:                if (*cp == '\r') {
                    557:                        if (!eolp())
                    558:                                LineInsert(1);
                    559:                        else
                    560:                                line_move(FORWARD, 1, NO);
                    561:                } else if (*cp == ' ' || *cp == '\t') {
                    562:                        if (linebuf[curchar] != *cp)
                    563:                                insert_c(*cp, 1);
                    564:                } else
                    565:                        /* Since we matched the open comment string on this
                    566:                           line, we don't need to worry about crossing line
                    567:                           boundaries. */
                    568:                        curchar += 1;
                    569:        }
                    570:        savedot = MakeMark(curline, curchar, M_FLOATER);
                    571: 
                    572:        /* We need to strip the line header pattern of leading white space
                    573:           since we need to match the line after all of its leading
                    574:           whitespace is gone. */
                    575:        for (cp = l_header; *cp && (isspace(*cp)); cp++)
                    576:                ;
                    577:        header_len = strlen(cp);
                    578:        trailer_len = strlen(l_trailer);
                    579: 
                    580:        /* Strip each comment line of the open and close comment strings
                    581:           before reformatting it. */
                    582: 
                    583:        do {
                    584:                Bol();
                    585:                DelWtSpace();
                    586:                if (header_len && !strncmp(linebuf, cp, header_len))
                    587:                        del_char(FORWARD, header_len);
                    588:                if (trailer_len) {
                    589:                        Eol();
                    590:                        if ((curchar > trailer_len) &&
                    591:                            (!strncmp(&linebuf[curchar - trailer_len],
                    592:                                      l_trailer, trailer_len)))
                    593:                                del_char(BACKWARD, trailer_len);
                    594:                }
                    595:                if (curline->l_next != 0)
                    596:                        line_move(FORWARD, 1, NO);
                    597:                else
                    598:                        break;
                    599:        } while (curline != entry_mark->m_line->l_next);
                    600: 
                    601:        do_set_mark(savedot->m_line, savedot->m_char);
                    602:        ToMark(entry_mark);
                    603:        saveRMargin = RMargin;
                    604:        RMargin = saveRMargin - strlen(l_header) -
                    605:                  strlen(l_trailer) - indent_pos + 2;
                    606:        do_rfill(NO);
                    607:        RMargin = saveRMargin;
                    608:        /* get back to the start of the comment */
                    609:        PopMark(); 
                    610:        do {
                    611:                if (curline == open_c_mark->m_line->l_next) {
                    612:                        ;
                    613:                } else {
                    614:                        n_indent(indent_pos);
                    615:                        ins_str(l_header, NO);
                    616:                }
                    617:                Eol();
                    618:                if (!NL_IN_CLOSE_C && (curline == entry_mark->m_line))
                    619:                        ;
                    620:                else
                    621:                        ins_str(l_trailer, NO);
                    622:                if (curline->l_next != 0)
                    623:                        line_move(FORWARD, 1, NO);
                    624:                else 
                    625:                        break;
                    626:        } while (curline != entry_mark->m_line->l_next);
                    627:        /* handle the close comment symbol */
                    628:        if (curline == entry_mark->m_line->l_next) {
                    629:                line_move(BACKWARD, 1, NO);
                    630:                Eol();
                    631:        }
                    632:        DelWtSpace();
                    633:        /* if the addition of the close symbol would cause the line to be
                    634:           too long, put the close symbol on the next line. */
                    635:        if (!(NL_IN_CLOSE_C) &&
                    636:          strlen(close_c) + calc_pos(linebuf, curchar) > RMargin) {
                    637:                LineInsert(1);
                    638:                n_indent(indent_pos);
                    639:        }
                    640:        for (cp = close_c; *cp; cp++) {
                    641:                if (*cp == '\r') {
                    642:                        LineInsert(1);
                    643:                        n_indent(indent_pos);
                    644:                } else
                    645:                        insert_c(*cp, 1);
                    646:        }
                    647:        ToMark(open_c_mark);
                    648:        Eol();
                    649:        del_char(FORWARD, 1);
                    650: }
                    651: 
                    652: #endif /* CMT_FMT */
                    653: 

unix.superglobalmegacorp.com

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