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

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

unix.superglobalmegacorp.com

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