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