# # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2004 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright (c) 2018, Joyent, Inc. PROG= cscope-fast OBJS= main.o dir.o crossref.o scanner.o lookup.o command.o display.o \ find.o edit.o exec.o help.o history.o input.o menu.o alloc.o \ cgrep.o compath.o invlib.o logdir.o \ mouse.o mygetenv.o mygetwd.o mypopen.o \ vpaccess.o vpfopen.o vpinit.o vpopen.o vpstat.o SRCS= $(OBJS:%.o=%.c) CLEANFILES += $(OBJS) scanner.c TMPDIR= /tmp include ../Makefile.tools # these three are because we cannot seem to redefine the size of YYLMAX, # and thus yytext, in the code because yytext is defined before our code # is seen. YYLMAX is supposed to be STMTMAX+PATLEN+1. PATLEN= 250 STMTMAX= 10000 YYLMAX= 10251 CFLAGS += -DPATLEN=$(PATLEN) -DSTMTMAX=$(STMTMAX) -DYYLMAX=$(YYLMAX) CERRWARN += -Wno-parentheses CERRWARN += -Wno-implicit-function-declaration CERRWARN += -Wno-unused CERRWARN += $(CNOWARN_UNINIT) # not linted SMATCH=off CFLAGS += $(CCVERBOSE) LDLIBS += -lcurses -ll NATIVE_LIBS += libcurses.so libl.so .KEEP_STATE: .PARALLEL: $(OBJS) all: $(PROG) # because of goto's in the scanner scanner.o : CCVERBOSE= $(PROG): $(OBJS) $(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(POST_PROCESS) install: all .WAIT $(ROOTONBLDMACHPROG) clean: $(RM) $(CLEANFILES) lint: lint_SRCS include ../Makefile.targ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 1999 by Sun Microsystems, Inc. * All rights reserved. */ /* memory allocation functions */ #include #include #include extern char *argv0; /* command name (must be set in main function) */ char *stralloc(char *s); void *mymalloc(size_t size); void *mycalloc(size_t nelem, size_t size); void *myrealloc(void *p, size_t size); static void *alloctest(void *p); /* allocate a string */ char * stralloc(char *s) { return (strcpy(mymalloc(strlen(s) + 1), s)); } /* version of malloc that only returns if successful */ void * mymalloc(size_t size) { return (alloctest(malloc(size))); } /* version of calloc that only returns if successful */ void * mycalloc(size_t nelem, size_t size) { return (alloctest(calloc(nelem, size))); } /* version of realloc that only returns if successful */ void * myrealloc(void *p, size_t size) { return (alloctest(realloc(p, size))); } /* check for memory allocation failure */ static void * alloctest(void *p) { if (p == NULL) { (void) fprintf(stderr, "\n%s: out of storage\n", argv0); exit(1); } return (p); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1990 AT&T */ /* All Rights Reserved */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * cscope - interactive C symbol or text cross-reference * * text searching functions */ #include #include #include #include #include #include #include #include "library.h" typedef enum { NO = 0, YES = 1 } BOOL; typedef struct re_bm { int delta0[256]; int *delta2; uchar_t *cmap; uchar_t *bmpat; int patlen; } re_bm; typedef struct Link { uchar_t lit; struct Node *node; struct Link *next; } Link; typedef struct Node { short out; short d; short shift1; short shift2; long id; struct Node **tab; Link *alts; struct Node *fail; } Node; typedef struct re_cw { int maxdepth, mindepth; long nodeid; int step[256]; uchar_t *cmap; struct Node *root; } re_cw; typedef enum { /* lit expression types */ Literal, Dot, Charclass, EOP, /* non-lit expression types */ Cat, Alternate, Star, Plus, Quest, /* not really expression types, just helping */ Lpar, Rpar, Backslash } Exprtype; typedef int ID; typedef struct Expr { Exprtype type; /* Type of expression (in grammar) */ ID id; /* unique ID of lit expression */ int lit; /* Literal character or tag */ int flen; /* Number of following lit expressions */ ID *follow; /* Array of IDs of following lit expressions */ struct Expr *l; /* pointer to Left child (or ccl count) */ struct Expr *r; /* pointer to Right child (or ccl mask) */ struct Expr *parent; /* pointer to Parent */ } Expr; typedef struct State { struct State *tab[256]; int cnt; /* number of matched chars on full match, -1 otherwise */ int npos; /* number of IDs in position set for this state. */ int pos; /* index into posbase for beginning of IDs */ } State; typedef struct FID { ID id; /* Lit Expression id */ int fcount; /* Number of Lit exp matches before this one. */ } FID; typedef struct Positionset { int count; /* Number of lit exps in position set */ ID last; /* ID of last lit exp in position set */ FID *base; /* array of MAXID FIDS */ /* 0 means not in position set */ /* -1 means first in position set */ /* n (>0) is ID of prev member of position set. */ } Positionset; typedef struct re_re { FID *posbase; /* Array of IDs from all states */ int nposalloc; /* Allocated size of posbase */ int posnext; /* Index into free space in posbase */ int posreset; /* Index into end of IDs for initial state in posbase */ int maxid; /* Number of (also maximum ID of) lit expressions */ Expr *root; /* Pointer to root (EOP) expression */ Expr **ptr; /* Pointer to array of ptrs to lit expressions. */ uchar_t *cmap; /* Character mapping array */ Positionset firstpos; Positionset tmp; int nstates; /* Number of current states defined */ int statelim; /* Limit on number of states before flushing */ State *states; /* Array of states */ State istate; /* Initial state */ } re_re; typedef struct { uchar_t *cmap; re_re *re_ptr; re_bm *bm_ptr; re_cw *cw_ptr; BOOL fullmatch; BOOL (*procfn)(); BOOL (*succfn)(); uchar_t *loc1; uchar_t *loc2; uchar_t *expression; } PATTERN; typedef enum { BEGIN, /* File is not yet in buffer at all */ MORE, /* File is partly in buffer */ NO_MORE /* File has been completely read into buffer */ } FILE_STAT; typedef struct { uchar_t *prntbuf; /* current line of input from data file */ uchar_t *newline; /* end of line (real or sentinel \n) */ long ln; /* line number */ } LINE; #define NL '\n' #define CCL_SIZ 32 #define CCL_SET(a, c) ((a)[(c) >> 3] |= bittab[(c) & 07]) #define CCL_CLR(a, c) ((a)[(c) >> 3] &= ~bittab[(c) & 07]) #define CCL_CHK(a, c) ((a)[(c) >> 3] & bittab[(c) & 07]) #define ESIZE (BUFSIZ) #define MAXBUFSIZE (64*BUFSIZ) #define MAXMALLOCS 1024 #define MAXLIT 256 /* is plenty big enough */ #define LARGE MAXBUFSIZE+ESIZE+2 #define CLEAR(r, rps) (void) memset((char *)(rps)->base, 0, \ (int)((r)->maxid * sizeof (FID))), \ (rps)->count = 0, (rps)->last = -1 #define SET(rps, n, cnt) { \ if ((rps)->base[n].id == 0) {\ (rps)->count++;\ (rps)->base[n].fcount = (cnt);\ (rps)->base[n].id = (rps)->last;\ (rps)->last = (n);\ } else if ((cnt) > (rps)->base[n].fcount) {\ (rps)->base[n].fcount = (cnt);\ }} #define START { _p = tmp; } #define ADDL(c) { if (_p >= &tmp[MAXLIT]) _p--; *_p++ = c; } #define FINISH { ADDL(0) if ((_p-tmp) > bestlen) \ (void) memmove(best, tmp, bestlen = _p-tmp); } #define NEW(N) (froot?(t = froot, froot = froot->next, t->next = NULL, \ t->node = N, t): newlink(0, N)) #define ADD(N) if (qtail) qtail = qtail->next = NEW(N); \ else qtail = qhead = NEW(N) #define DEL() { Link *_l = qhead; if ((qhead = qhead->next) == NULL) \ { qtail = NULL; } _l->next = froot; froot = _l; } static uchar_t *buffer; static uchar_t *bufend; static FILE *output; static char *format; static char *file; static int file_desc; static FILE_STAT file_stat; static PATTERN match_pattern; static uchar_t char_map[2][256]; static int iflag; static Exprtype toktype; static int toklit, parno, maxid; static uchar_t tmp[MAXLIT], best[MAXLIT]; static uchar_t *_p; static int bestlen; static Node *next_node; static Link *froot, *next_link; static jmp_buf env; static int nmalloc; static uchar_t *mallocs[MAXMALLOCS]; static uchar_t bittab[] = { 1, 2, 4, 8, 16, 32, 64, 128 }; #ifdef DEBUG #define TRACE(n) (n < debug) #define EPRINTSIZE 50000 static void spr(int c, int *p, uchar_t *buf); void epr(Expr *e, uchar_t *res); static int debug = 12; #endif static void init_file(LINE *cur_ptr); static void get_line(LINE *cur_ptr, uchar_t *s); static void get_ncount(LINE *cur_ptr, uchar_t *s); static int execute(void); static State *startstate(re_re *r); static State *stateof(re_re *r, Positionset *ps); static State *nextstate(re_re *r, State *s, int a); static State *addstate(re_re *r, Positionset *ps, int cnt); static BOOL match(Expr *e, int a); static BOOL first_lit(Positionset *fpos, Expr *e); static void eptr(re_re *r, Expr *e); static void efollow(re_re *r, Positionset *fpos, Expr *e); static void follow(Positionset *fpos, Expr *e); static void followstate(re_re *r, State *s, int a, Positionset *fpos); static Expr *eall(re_re *r, PATTERN *pat); static Expr *d0(re_re *r, PATTERN *pat); static Expr *d1(re_re *r, PATTERN *pat); static Expr *d2(re_re *r, PATTERN *pat); static Expr *d3(re_re *r, PATTERN *pat); static Expr *newexpr(Exprtype t, int lit, Expr *left, Expr *right); static void lex(re_re *r, PATTERN *pat); static int re_lit(PATTERN *pat, uchar_t **b, uchar_t **e); static void traverse(PATTERN *pat, Expr *e); static int ccl(PATTERN *pat, uchar_t *tab); static BOOL altlist(), word(); static BOOL altlist(Expr *e, uchar_t *buf, re_cw *pat); static Node *newnode(re_cw *c, int d); static Link *newlink(uchar_t lit, Node *n); static void fail(Node *root); static void zeroroot(Node *root, Node *n); static void shift(re_cw *c); static void shifttab(Node *n); static void shiftprop(re_cw *c, Node *n); static void delta_2(re_bm *b); static int getstate(re_re *r, Positionset *ps); static void savestate(re_re *r); static void stateinit(re_re *r); static re_bm *re_bmcomp(uchar_t *pb, uchar_t *pe, uchar_t *cmap); static re_cw *re_cwinit(uchar_t *cmap); static re_cw *re_recw(re_re *r, uchar_t *map); static re_re *egprep(PATTERN *pat); static void re_cwadd(re_cw *c, uchar_t *s, uchar_t *e); static void re_cwcomp(re_cw *c); static void eginit(re_re *r); static BOOL re_bmexec(PATTERN *pat, uchar_t *s, uchar_t *e, uchar_t **mb, uchar_t **me); static BOOL re_cwexec(PATTERN *pat, uchar_t *rs, uchar_t *re, uchar_t **mb, uchar_t **me); static BOOL re_reexec(PATTERN *pat, uchar_t *b, uchar_t *e, uchar_t **mb, uchar_t **me); static uchar_t *egmalloc(size_t n); static void fgetfile(LINE *cur_ptr); static void dogre(PATTERN *pat); static BOOL pattern_match(PATTERN *pat, LINE *lptr); static BOOL fixloc(uchar_t **mb, uchar_t **me); static BOOL grepmatch(PATTERN *pat, uchar_t **mb, uchar_t **me); static void err(char *s); static char *message; void egrepcaseless(int i) { iflag = i; /* simulate "egrep -i" */ } char * egrepinit(char *expression) { static int firsttime = 1; int i; if (firsttime) { firsttime = 0; for (i = 0; i < 256; i++) { char_map[0][i] = (uchar_t)i; char_map[1][i] = tolower(i); } } for (i = 0; i < nmalloc; i ++) free(mallocs[i]); nmalloc = 0; message = NULL; match_pattern.expression = (uchar_t *)expression; match_pattern.cmap = char_map[iflag]; if (setjmp(env) == 0) { dogre(&match_pattern); #ifdef DEBUG { PATTERN *p = match_pattern; if (p->procfn == re_bmexec) if (!p->fullmatch) if (p->succfn == re_reexec) printf("PARTIAL BOYER_MOORE\n"); else printf("PARTIAL B_M with GREP\n"); else printf("FULL BOYER_MOORE\n"); else if (p->procfn == re_cwexec) printf("C_W\n"); else printf("GENERAL\n"); } #endif } return (message); } static void dogre(PATTERN *pat) { uchar_t *lb, *le; #ifdef DEBUG printf("PATTERN %s\n", pat->expression); #endif pat->re_ptr = egprep(pat); bestlen = re_lit(pat, &lb, &le); if (bestlen && pat->fullmatch) { /* Full Boyer Moore */ #ifdef DEBUG printf("BESTLEN %d\n", bestlen); { uchar_t *p; for (p = lb; p < le; p++) printf("%c", *p); printf("\n"); } #endif pat->bm_ptr = re_bmcomp(lb, le, pat->cmap); pat->procfn = re_bmexec; return; } if (bestlen > 1) { /* Partial Boyer Moore */ pat->bm_ptr = re_bmcomp(lb, le, pat->cmap); pat->procfn = re_bmexec; pat->fullmatch = NO; } else { pat->fullmatch = YES; if ((pat->cw_ptr = re_recw(pat->re_ptr, pat->cmap)) != NULL) { pat->procfn = re_cwexec; /* CW */ return; } } /* general egrep regular expression */ pat->succfn = re_reexec; if (pat->fullmatch) { pat->procfn = pat->succfn; pat->succfn = NULL; } } static BOOL fixloc(uchar_t **mb, uchar_t **me) { /* Handle match to null string */ while (*me <= *mb) (*me)++; if (*(*me - 1) != NL) while (**me != NL) (*me)++; /* Handle match to new-line only */ if (*mb == *me - 1 && **mb == NL) { (*me)++; } /* Handle match including beginning or ending new-line */ if (**mb == NL) (*mb)++; if (*(*me - 1) == NL) (*me)--; return (YES); } static BOOL grepmatch(PATTERN *pat, uchar_t **mb, uchar_t **me) { uchar_t *s, *f; if (pat->fullmatch) return (fixloc(mb, me)); for (f = *me - 1; *f != NL; f++) { } f++; for (s = *mb; *s != NL; s--) { } if ((*pat->succfn)(pat, s, f, mb, me)) { return (YES); } else { *mb = f; return (NO); } } static void eginit(re_re *r) { unsigned int n; r->ptr = (Expr **)egmalloc(r->maxid * sizeof (Expr *)); eptr(r, r->root); n = r->maxid * sizeof (FID); r->firstpos.base = (FID *)egmalloc(n); r->tmp.base = (FID *)egmalloc(n); CLEAR(r, &r->firstpos); if (!first_lit(&r->firstpos, r->root->l)) { /* * This expression matches the null string!!!! * Add EOP to beginning position set. */ SET(&r->firstpos, r->root->id, 0) /* (void) printf("first of root->l == 0, b=%s\n", b); */ } stateinit(r); (void) addstate(r, &r->firstpos, 0); savestate(r); } static void eptr(re_re *r, Expr *e) { if ((e->id < 0) || (e->id >= r->maxid)) { err("internal error"); } r->ptr[e->id] = e; if (e->type != Charclass) { if (e->l) eptr(r, e->l); if (e->r) eptr(r, e->r); } } static BOOL re_reexec(PATTERN *pat, uchar_t *b, uchar_t *e, uchar_t **mb, uchar_t **me) { re_re *r = pat->re_ptr; State *s, *t; #ifdef DEBUG if (TRACE(10)) { uchar_t buf[EPRINTSIZE]; epr(r->root, buf); (void) printf("expr='%s'\n", buf); } #endif s = startstate(r); for (;;) { uchar_t c; if (s->cnt >= 0) { #ifdef DEBUG if (TRACE(6)) (void) printf("match at input '%s'\n", b); #endif *mb = b - s->cnt; *me = b; if (fixloc(mb, me)) return (YES); } if (b >= e) break; c = pat->cmap[*b]; #ifdef DEBUG if (TRACE(4)) (void) printf("state %d: char '%c'\n", s-r->states, *b); #endif if ((t = s->tab[c]) != NULL) s = t; else s = nextstate(r, s, (int)c); b++; } #ifdef DEBUG if (TRACE(3)) { uchar_t buf[EPRINTSIZE]; epr(r->root, buf); (void) printf("pat = %s\n", buf); } #endif return (NO); } static BOOL match(Expr *e, int a) { switch (e->type) { case Dot: return ((BOOL)(a != NL)); case Literal: return ((BOOL)(a == e->lit)); case Charclass: return ((BOOL)(CCL_CHK((uchar_t *)e->r, a))); default: return (NO); } } /* * generates the followset for a node in fpos */ static void follow(Positionset *fpos, Expr *e) { Expr *p; if (e->type == EOP) return; else p = e->parent; switch (p->type) { case EOP: SET(fpos, p->id, 0) break; case Plus: case Star: (void) first_lit(fpos, e); follow(fpos, p); break; case Quest: case Alternate: follow(fpos, p); break; case Cat: if (e == p->r || !first_lit(fpos, p->r)) follow(fpos, p); break; default: break; } } /* * first_lit returns NO if e is nullable and in the process, * ets up fpos. */ static BOOL first_lit(Positionset *fpos, Expr *e) { BOOL k; switch (e->type) { case Literal: case Dot: case Charclass: SET(fpos, e->id, 0) return (YES); case EOP: case Star: case Quest: (void) first_lit(fpos, e->l); return (NO); case Plus: return (first_lit(fpos, e->l)); case Cat: return ((BOOL)(first_lit(fpos, e->l) || first_lit(fpos, e->r))); case Alternate: k = first_lit(fpos, e->r); return ((BOOL)(first_lit(fpos, e->l) && k)); default: err("internal error"); } return (NO); } static void efollow(re_re *r, Positionset *fpos, Expr *e) { ID i, *p; CLEAR(r, fpos); follow(fpos, e); e->flen = fpos->count; e->follow = (ID *)egmalloc(e->flen * sizeof (ID)); p = e->follow; #ifdef DEBUG printf("ID = %d LIT %c FLEN = %d\n", e->id, e->lit, e->flen); #endif for (i = fpos->last; i > 0; i = fpos->base[i].id) { *p++ = i; #ifdef DEBUG printf("FOLLOW ID = %d LIT %c\n", r->ptr[i]->id, r->ptr[i]->lit); #endif } if (p != e->follow + e->flen) { err("internal error"); } } static State * addstate(re_re *r, Positionset *ps, int cnt) { ID j; FID *p, *q; State *s; if (cnt) { s = r->states + getstate(r, ps); (void) memset((char *)s->tab, 0, sizeof (s->tab)); s->cnt = r->istate.cnt; } else { s = &r->istate; s->cnt = -1; } s->pos = r->posnext; r->posnext += ps->count; s->npos = ps->count; p = r->posbase + s->pos; for (j = ps->last; j > 0; p++, j = q->id) { q = &ps->base[j]; p->id = j; p->fcount = q->fcount; if (p->id == r->root->id && s->cnt < p->fcount) s->cnt = p->fcount; } #ifdef DEBUG if (TRACE(3)) { uchar_t buf[2000]; spr(s->npos, s->pos+r->posbase, buf); (void) printf("new state[%d] %s%s\n", s-r->states, buf, s->cnt?" cnt":""); } #endif return (s); } static State * nextstate(re_re *r, State *s, int a) { State *news; CLEAR(r, &r->tmp); followstate(r, s, a, &r->tmp); if (s != &r->istate) followstate(r, &r->istate, a, &r->tmp); #ifdef DEBUG if (TRACE(5)) { uchar_t buf[2000]; ppr(&r->tmp, buf); (void) printf("nextstate(%d, '%c'): found %s\n", s-r->states, a, buf); } #endif if (r->tmp.count == 0) news = &r->istate; else if ((news = stateof(r, &r->tmp)) == NULL) news = addstate(r, &r->tmp, 1); s->tab[a] = news; #ifdef DEBUG if (TRACE(5)) { (void) printf("nextstate(%d, '%c'): returning %ld\n", s-r->states, a, news); } #endif return (news); } static void followstate(re_re *r, State *s, int a, Positionset *fpos) { int j; ID *q, *eq; Expr *e; for (j = s->pos; j < (s->pos + s->npos); j++) { e = r->ptr[r->posbase[j].id]; if (e->type == EOP) continue; if (match(e, a)) { if (e->follow == NULL) efollow(r, &r->firstpos, e); for (q = e->follow, eq = q + e->flen; q < eq; q++) { SET(fpos, *q, r->posbase[j].fcount + 1) #ifdef DEBUG printf("CHAR %c FC %c COUNT %d\n", a, r->ptr[*q]->lit, r->posbase[j].fcount+1); #endif } } } } static uchar_t * egmalloc(size_t n) { uchar_t *x; x = (uchar_t *)mymalloc(n); mallocs[nmalloc++] = x; if (nmalloc >= MAXMALLOCS) nmalloc = MAXMALLOCS - 1; return (x); } #ifdef DEBUG void ppr(Positionse *ps, char *p) { ID n; if (ps->count < 1) { (void) sprintf(p, "{}"); return; } *p++ = '{'; for (n = ps->last; n > 0; n = ps->base[n].id) { (void) sprintf(p, "%d,", n); p = strchr(p, 0); } p[-1] = '}'; } void epr(Expr *e, uchar_t *res) { uchar_t r1[EPRINTSIZE], r2[EPRINTSIZE]; int i; if (e == NULL) { (void) sprintf(res, "!0!"); return; } switch (e->type) { case Dot: case Literal: spr(e->flen, e->follow, r1); (void) sprintf(res, "%c%s", e->lit, r1); break; case Charclass: *res++ = '['; for (i = 0; i < 256; i++) if (CCL_CHK((uchar_t *)e->r, i)) { *res++ = i; } *res++ = ']'; *res = '\0'; break; case Cat: epr(e->l, r1); epr(e->r, r2); (void) sprintf(res, "%s%s", r1, r2); break; case Alternate: epr(e->l, r1); epr(e->r, r2); (void) sprintf(res, "(%s|%s)", r1, r2); break; case Star: epr(e->l, r1); (void) sprintf(res, "(%s)*", r1); break; case Plus: epr(e->l, r1); (void) sprintf(res, "(%s)+", r1); break; case Quest: epr(e->l, r1); (void) sprintf(res, "(%s)?", r1); break; case EOP: epr(e->l, r1); (void) sprintf(res, "%s", r1); break; default: (void) sprintf(res, "", e->type); err(res); break; } } static void spr(int c, int *p, uchar_t *buf) { if (c > 0) { *buf++ = '{'; *buf = '\0'; while (--c > 0) { (void) sprintf(buf, "%d,", *p++); buf = strchr(buf, 0); } (void) sprintf(buf, "%d}", *p); } else (void) sprintf(buf, "{}"); } #endif static void stateinit(re_re *r) { /* CONSTANTCONDITION */ r->statelim = (sizeof (int) < 4 ? 32 : 128); r->states = (State *)egmalloc(r->statelim * sizeof (State)); /* CONSTANTCONDITION */ r->nposalloc = (sizeof (int) < 4 ? 2048 : 8192); r->posbase = (FID *)egmalloc(r->nposalloc * sizeof (FID)); r->nstates = r->posnext = 0; } static void clrstates(re_re *r) { r->nstates = 0; /* reclaim space for states and positions */ r->posnext = r->posreset; (void) memset((char *)r->istate.tab, 0, sizeof (r->istate.tab)); } static void savestate(re_re *r) { r->posreset = r->posnext; /* save for reset */ } static State * startstate(re_re *r) { return (&r->istate); } static int getstate(re_re *r, Positionset *ps) { if (r->nstates >= r->statelim || r->posnext + ps->count >= r->nposalloc) { clrstates(r); #ifdef DEBUG printf("%d STATES FLUSHED\n", r->statelim); #endif } return (r->nstates++); } static State * stateof(re_re *r, Positionset *ps) { State *s; int i; FID *p, *e; for (i = 0, s = r->states; i < r->nstates; i++, s++) { if (s->npos == ps->count) { for (p = s->pos+r->posbase, e = p+s->npos; p < e; p++) if (ps->base[p->id].id == 0 || ps->base[p->id].fcount != p->fcount) goto next; return (s); } next:; } return (NULL); } static re_re * egprep(PATTERN *pat) { re_re *r; r = (re_re *)egmalloc(sizeof (re_re)); (void) memset((char *)r, 0, sizeof (re_re)); pat->loc1 = pat->expression; pat->loc2 = pat->expression + strlen((char *)pat->expression); parno = 0; maxid = 1; r->cmap = pat->cmap; lex(r, pat); r->root = newexpr(EOP, '#', eall(r, pat), (Expr *)NULL); r->maxid = maxid; eginit(r); return (r); } static Expr * newexpr(Exprtype t, int lit, Expr *left, Expr *right) { Expr *e = (Expr *)egmalloc(sizeof (Expr)); e->type = t; e->parent = NULL; e->lit = lit; if (e->lit) e->id = maxid++; else e->id = 0; if ((e->l = left) != NULL) { left->parent = e; } if ((e->r = right) != NULL) { right->parent = e; } e->follow = NULL; e->flen = 0; return (e); } static void lex(re_re *r, PATTERN *pat) { if (pat->loc1 == pat->loc2) { toktype = EOP; toklit = -1; } else switch (toklit = *pat->loc1++) { case '.': toktype = Dot; break; case '*': toktype = Star; break; case '+': toktype = Plus; break; case '?': toktype = Quest; break; case '[': toktype = Charclass; break; case '|': toktype = Alternate; break; case '(': toktype = Lpar; break; case ')': toktype = Rpar; break; case '\\': toktype = Backslash; if (pat->loc1 == pat->loc2) { err("syntax error - missing character " "after \\"); } else { toklit = r->cmap[*pat->loc1++]; } break; case '^': case '$': toktype = Literal; toklit = NL; break; default: toktype = Literal; toklit = r->cmap[toklit]; break; } } static int ccl(PATTERN *pat, uchar_t *tab) { int i; int range = 0; int lastc = -1; int count = 0; BOOL comp = NO; (void) memset((char *)tab, 0, CCL_SIZ * sizeof (uchar_t)); if (*pat->loc1 == '^') { pat->loc1++; comp = YES; } if (*pat->loc1 == ']') { uchar_t c = pat->cmap[*pat->loc1]; CCL_SET(tab, c); lastc = *pat->loc1++; } /* scan for chars */ for (; (pat->loc1 < pat->loc2) && (*pat->loc1 != ']'); pat->loc1++) { if (*pat->loc1 == '-') { if (lastc < 0) CCL_SET(tab, pat->cmap['-']); else range = 1; continue; } if (range) { for (i = *pat->loc1; i >= lastc; i--) { CCL_SET(tab, pat->cmap[i]); } } else { uchar_t c = pat->cmap[*pat->loc1]; CCL_SET(tab, c); } range = 0; lastc = *pat->loc1; } if (range) CCL_SET(tab, pat->cmap['-']); if (pat->loc1 < pat->loc2) pat->loc1++; else err("syntax error - missing ]"); if (comp) { CCL_SET(tab, pat->cmap[NL]); for (i = 0; i < CCL_SIZ; i++) tab[i] ^= 0xff; } for (i = 0; i < 256; i++) { if (pat->cmap[i] != i) CCL_CLR(tab, i); if (CCL_CHK(tab, i)) { lastc = i; count++; } } if (count == 1) *tab = (char)lastc; return (count); } /* * egrep patterns: * * Alternation: d0: d1 { '|' d1 }* * Concatenation: d1: d2 { d2 }* * Repetition: d2: d3 { '*' | '?' | '+' } * Literal: d3: lit | '.' | '[]' | '(' d0 ')' */ static Expr * d3(re_re *r, PATTERN *pat) { Expr *e; uchar_t *tab; int count; switch (toktype) { case Backslash: case Literal: e = newexpr(Literal, toklit, (Expr *)NULL, (Expr *)NULL); lex(r, pat); break; case Dot: e = newexpr(Dot, '.', (Expr *)NULL, (Expr *)NULL); lex(r, pat); break; case Charclass: tab = egmalloc(CCL_SIZ * sizeof (uchar_t)); count = ccl(pat, tab); if (count == 1) { toklit = *tab; e = newexpr(Literal, toklit, (Expr *)NULL, (Expr *)NULL); } else { e = newexpr(Charclass, '[', (Expr *)NULL, (Expr *)NULL); e->l = (Expr *)count; /* number of chars */ e->r = (Expr *)tab; /* bitmap of chars */ } lex(r, pat); break; case Lpar: lex(r, pat); count = ++parno; e = d0(r, pat); if (toktype == Rpar) lex(r, pat); else err("syntax error - missing )"); return (e); default: err("syntax error"); e = NULL; } return (e); } static Expr * d2(re_re *r, PATTERN *pat) { Expr *e; Exprtype t; e = d3(r, pat); while ((toktype == Star) || (toktype == Plus) || (toktype == Quest)) { t = toktype; lex(r, pat); e = newexpr(t, 0, e, (Expr *)NULL); } return (e); } static Expr * d1(re_re *r, PATTERN *pat) { Expr *e, *f; e = d2(r, pat); while ((toktype == Literal) || (toktype == Dot) || (toktype == Lpar) || (toktype == Backslash) || (toktype == Charclass)) { f = d2(r, pat); e = newexpr(Cat, 0, e, f); } return (e); } static Expr * d0(re_re *r, PATTERN *pat) { Expr *e, *f; e = d1(r, pat); while (toktype == Alternate) { lex(r, pat); if (toktype == EOP) continue; f = d1(r, pat); e = newexpr(Alternate, 0, e, f); } return (e); } static Expr * eall(re_re *r, PATTERN *pat) { Expr *e; while (toktype == Alternate) /* bogus but user-friendly */ lex(r, pat); e = d0(r, pat); while (toktype == Alternate) /* bogus but user-friendly */ lex(r, pat); if (toktype != EOP) err("syntax error"); return (e); } static void err(char *s) { message = s; longjmp(env, 1); } static int re_lit(PATTERN *pat, uchar_t **b, uchar_t **e) { bestlen = 0; pat->fullmatch = YES; START traverse(pat, pat->re_ptr->root->l); FINISH if (bestlen < 2) return (0); *b = egmalloc(bestlen * sizeof (uchar_t)); (void) memmove(*b, best, bestlen); *e = *b + bestlen - 1; return (bestlen - 1); } static void traverse(PATTERN *pat, Expr *e) { switch (e->type) { case Literal: ADDL(e->lit) break; case Cat: traverse(pat, e->l); traverse(pat, e->r); break; case Plus: traverse(pat, e->l); FINISH /* can't go on past a + */ pat->fullmatch = NO; START /* but we can start with one! */ traverse(pat, e->l); break; default: FINISH pat->fullmatch = NO; START break; } } static re_bm * re_bmcomp(uchar_t *pb, uchar_t *pe, uchar_t *cmap) { int j; int delta[256]; re_bm *b; b = (re_bm *)egmalloc(sizeof (*b)); b->patlen = pe - pb; b->cmap = cmap; b->bmpat = pb; delta_2(b); for (j = 0; j < 256; j++) delta[j] = b->patlen; for (pe--; pb < pe; pb++) delta[b->cmap[*pb]] = pe - pb; delta[b->cmap[*pb]] = LARGE; for (j = 0; j < 256; j++) b->delta0[j] = delta[b->cmap[j]]; return (b); } static void delta_2(re_bm *b) { int m = b->patlen; int i, k, j; b->delta2 = (int *)egmalloc(m * sizeof (int)); for (j = 0; j < m; j++) { k = 1; again: while (k <= j && b->bmpat[j-k] == b->bmpat[j]) k++; for (i = j + 1; i < m; i++) { if (k <= i && b->bmpat[i-k] != b->bmpat[i]) { k++; goto again; } } b->delta2[j] = k + m - j - 1; } } static BOOL re_bmexec(PATTERN *pat, uchar_t *s, uchar_t *e, uchar_t **mb, uchar_t **me) { re_bm *b = pat->bm_ptr; uchar_t *sp; int k; s += b->patlen - 1; while ((unsigned long)s < (unsigned long)e) { while ((unsigned long)(s += b->delta0[*s]) < (unsigned long)e) ; if ((unsigned long)s < (unsigned long)(e + b->patlen)) return (NO); /* no match */ s -= LARGE; for (k = b->patlen-2, sp = s-1; k >= 0; k--) { if (b->cmap[*sp--] != b->bmpat[k]) break; } if (k < 0) { *mb = ++sp; *me = s+1; if (grepmatch(pat, mb, me)) return (YES); s = *mb; } else if (k < 0) { s++; } else { int j; j = b->delta2[k]; k = b->delta0[*++sp]; if ((j > k) || (k == (int)LARGE)) k = j; s = sp + k; } } return (NO); } static re_cw * re_recw(re_re *r, uchar_t *map) { Expr *e, *root = r->root; re_cw *pat; uchar_t *buf; if (root->type != EOP) return (NULL); e = root->l; pat = re_cwinit(map); buf = (uchar_t *)egmalloc(20000 * sizeof (uchar_t)); if (!altlist(e, buf, pat)) { return (NULL); } re_cwcomp(pat); return (pat); } static BOOL altlist(Expr *e, uchar_t *buf, re_cw *pat) { if (e->type == Alternate) return ((BOOL)(altlist(e->l, buf, pat) && altlist(e->r, buf, pat))); return (word(e, buf, pat)); } static BOOL word(Expr *e, uchar_t *buf, re_cw *pat) { static uchar_t *p; if (buf) p = buf; if (e->type == Cat) { if (!word(e->l, (uchar_t *)NULL, pat)) return (NO); if (!word(e->r, (uchar_t *)NULL, pat)) return (NO); } else if (e->type == Literal) *p++ = e->lit; else return (NO); if (buf) re_cwadd(pat, buf, p); return (YES); } static re_cw * re_cwinit(uchar_t *cmap) { re_cw *c; froot = NULL; next_node = NULL; next_link = NULL; c = (re_cw *)egmalloc(sizeof (*c)); c->nodeid = 0; c->maxdepth = 0; c->mindepth = 10000; c->root = newnode(c, 0); c->cmap = cmap; return (c); } static void re_cwadd(re_cw *c, uchar_t *s, uchar_t *e) { Node *p, *state; Link *l; int depth; state = c->root; while (s <= --e) { for (l = state->alts; l; l = l->next) if (l->lit == *e) break; if (l == NULL) break; else state = l->node; } if (s <= e) { depth = state->d+1; l = newlink(*e--, p = newnode(c, depth++)); l->next = state->alts; state->alts = l; state = p; while (s <= e) { state->alts = newlink(*e--, p = newnode(c, depth++)); state = p; } if (c->mindepth >= depth) c->mindepth = depth-1; } state->out = 1; } #ifdef DEBUG static pr(Node *n) { Link *l; printf("%d[%d,%d]: ", n->id, n->shift1, n->shift2); for (l = n->alts; l; l = l->next) { printf("edge from \"%d\" to \"%d\" label {\"%c\"};", n->id, l->node->id, l->lit); if (l->node->out) { printf(" draw \"%d\" as Doublecircle;", l->node->id); } if (l->node->fail) { printf(" edge from \"%d\" to \"%d\" dashed;", l->node->id, l->node->fail->id); } printf("\n"); pr(l->node); } } #endif static void fail(Node *root) { Link *qhead = NULL, *qtail = NULL; Link *l, *ll; Link *t; Node *state, *r, *s; int a; for (l = root->alts; l; l = l->next) { ADD(l->node); l->node->fail = root; } while (qhead) { r = qhead->node; DEL(); for (l = r->alts; l; l = l->next) { s = l->node; a = l->lit; ADD(s); state = r->fail; while (state) { for (ll = state->alts; ll; ll = ll->next) if (ll->lit == a) break; if (ll || (state == root)) { if (ll) state = ll->node; /* * do it here as only other exit is * state 0 */ if (state->out) { s->out = 1; } break; } else state = state->fail; } s->fail = state; } } zeroroot(root, root); } static void zeroroot(Node *root, Node *n) { Link *l; if (n->fail == root) n->fail = NULL; for (l = n->alts; l; l = l->next) zeroroot(root, l->node); } static void shift(re_cw *c) { Link *qhead = NULL, *qtail = NULL; Link *l; Link *t; Node *state, *r, *s; int k; for (k = 0; k < 256; k++) c->step[k] = c->mindepth+1; c->root->shift1 = 1; c->root->shift2 = c->mindepth; for (l = c->root->alts; l; l = l->next) { l->node->shift2 = c->root->shift2; ADD(l->node); l->node->fail = NULL; } while (qhead) { r = qhead->node; DEL(); r->shift1 = c->mindepth; r->shift2 = c->mindepth; if ((state = r->fail) != NULL) { do { k = r->d - state->d; if (k < state->shift1) { state->shift1 = k; } if (r->out && (k < state->shift2)) { state->shift2 = k; } } while ((state = state->fail) != NULL); } for (l = r->alts; l; l = l->next) { s = l->node; ADD(s); } } shiftprop(c, c->root); shifttab(c->root); c->step[0] = 1; } static void shifttab(Node *n) { Link *l; Node **nn; n->tab = nn = (Node **)egmalloc(256 * sizeof (Node *)); (void) memset((char *)n->tab, 0, 256 * sizeof (Node *)); for (l = n->alts; l; l = l->next) nn[l->lit] = l->node; } static void shiftprop(re_cw *c, Node *n) { Link *l; Node *nn; for (l = n->alts; l; l = l->next) { if (c->step[l->lit] > l->node->d) c->step[l->lit] = l->node->d; nn = l->node; if (n->shift2 < nn->shift2) nn->shift2 = n->shift2; shiftprop(c, nn); } } static void re_cwcomp(re_cw *c) { fail(c->root); shift(c); } static BOOL re_cwexec(PATTERN *pat, uchar_t *rs, uchar_t *re, uchar_t **mb, uchar_t **me) { Node *state; Link *l; uchar_t *sp; uchar_t *s; uchar_t *e; Node *ostate; int k; re_cw *c = pat->cw_ptr; uchar_t fake[1]; uchar_t mappedsp; fake[0] = 0; state = c->root; s = rs+c->mindepth-1; e = re; while (s < e) { /* scan */ for (sp = s; (ostate = state) != NULL; ) { mappedsp = c->cmap[*sp]; if (state->tab) { if ((state = state->tab[mappedsp]) == NULL) goto nomatch; } else { for (l = state->alts; ; l = l->next) { if (l == NULL) goto nomatch; if (l->lit == mappedsp) { state = l->node; break; } } } if (state->out) { *mb = sp; *me = s+1; if (fixloc(mb, me)) return (YES); } if (--sp < rs) { sp = fake; break; } } nomatch: k = c->step[c->cmap[*sp]] - ostate->d - 1; if (k < ostate->shift1) k = ostate->shift1; if (k > ostate->shift2) k = ostate->shift2; s += k; state = c->root; } return (NO); } static Node * newnode(re_cw *c, int d) { static Node *lim = NULL; static int incr = 256; if (!next_node) lim = NULL; if (next_node == lim) { next_node = (Node *)egmalloc(incr * sizeof (Node)); lim = next_node + incr; } next_node->d = d; if (d > c->maxdepth) c->maxdepth = d; next_node->id = c->nodeid++; next_node->alts = NULL; next_node->tab = NULL; next_node->out = 0; return (next_node++); } static Link * newlink(uchar_t lit, Node *n) { static Link *lim = NULL; static int incr = 256; if (!next_link) lim = NULL; if (next_link == lim) { next_link = (Link *)egmalloc(incr * sizeof (Link)); lim = next_link + incr; } next_link->lit = lit; next_link->node = n; next_link->next = NULL; return (next_link++); } int egrep(char *f, FILE *o, char *fo) { uchar_t buff[MAXBUFSIZE + ESIZE]; buffer = buff; *buffer++ = NL; /* New line precedes buffer to prevent runover */ file = f; output = o; format = fo; return (execute()); } static int execute(void) { LINE current; BOOL matched; BOOL all_searched; /* file being matched until end */ if ((file_desc = open(file, O_RDONLY)) < 0) { return (-1); } init_file(¤t); /* while there is more get more text from the data stream */ for (;;) { all_searched = NO; /* * Find next new-line in buffer. * Begin after previous new line character */ current.prntbuf = current.newline + 1; current.ln++; /* increment line number */ if (current.prntbuf < bufend) { /* There is more text in buffer */ /* * Take our next * "line" as the entire remaining buffer. * However, if there is more of the file yet * to be read in, exclude any incomplete * line at end. */ if (file_stat == NO_MORE) { all_searched = YES; current.newline = bufend - 1; if (*current.newline != NL) { current.newline = bufend; } } else { /* * Find end of the last * complete line in the buffer. */ current.newline = bufend; while (*--current.newline != NL) { } if (current.newline < current.prntbuf) { /* end not found */ current.newline = bufend; } } } else { /* There is no more text in the buffer. */ current.newline = bufend; } if (current.newline >= bufend) { /* * There is no more text in the buffer, * or no new line was found. */ switch (file_stat) { case MORE: /* file partly unread */ case BEGIN: fgetfile(¤t); current.ln--; continue; /* with while loop */ case NO_MORE: break; } /* Nothing more to read in for this file. */ if (current.newline <= current.prntbuf) { /* Nothing in the buffer, either */ /* We are done with the file. */ current.ln--; break; /* out of while loop */ } /* There is no NL at the end of the file */ } matched = pattern_match(&match_pattern, ¤t); if (matched) { int nc; get_ncount(¤t, match_pattern.loc1); get_line(¤t, match_pattern.loc2); nc = current.newline + 1 - current.prntbuf; (void) fprintf(output, format, file, current.ln); (void) fwrite((char *)current.prntbuf, 1, nc, output); } else { if (all_searched) break; /* out of while loop */ get_ncount(¤t, current.newline + 1); } } (void) close(file_desc); return (0); } static void init_file(LINE *cur_ptr) { file_stat = BEGIN; cur_ptr->ln = 0; bufend = buffer; cur_ptr->newline = buffer - 1; } static BOOL pattern_match(PATTERN *pat, LINE *lptr) { if ((*pat->procfn)(pat, lptr->prntbuf - 1, lptr->newline + 1, &pat->loc1, &pat->loc2)) { return (YES); } else { pat->loc1 = lptr->prntbuf; pat->loc2 = lptr->newline - 1; return (NO); } } /* end of function pattern_match() */ static void fgetfile(LINE *cur_ptr) { /* * This function reads as much of the current file into the buffer * as will fit. */ int bytes; /* bytes read in current buffer */ int bufsize = MAXBUFSIZE; /* free space in data buffer */ int save_current; uchar_t *begin = cur_ptr->prntbuf; /* * Bytes of current incomplete line, if any, save_current in buffer. * These must be saved. */ save_current = (int)(bufend - begin); if (file_stat == MORE) { /* * A portion of the file fills the buffer. We must clear * out the dead wood to make room for more of the file. */ int k = 0; k = begin - buffer; if (!k) { /* * We have one humungous current line, * which fills the whole buffer. * Toss it. */ begin = bufend; k = begin - buffer; save_current = 0; } begin = buffer; bufend = begin + save_current; bufsize = MAXBUFSIZE - save_current; if (save_current > 0) { /* * Must save portion of current line. * Copy to beginning of buffer. */ (void) memmove(buffer, buffer + k, save_current); } } /* Now read in the file. */ do { bytes = read(file_desc, (char *)bufend, (unsigned int)bufsize); if (bytes < 0) { /* can't read any more of file */ bytes = 0; } bufend += bytes; bufsize -= bytes; } while (bytes > 0 && bufsize > 0); if (begin >= bufend) { /* No new lines or incomplete line in buffer */ file_stat = NO_MORE; } else if (bufsize) { /* Still space in the buffer, so we have read entire file */ file_stat = NO_MORE; } else { /* We filled entire buffer, so there may be more yet to read */ file_stat = MORE; } /* Note: bufend is 1 past last good char */ *bufend = NL; /* Sentinel new-line character */ /* Set newline to character preceding the current line */ cur_ptr->newline = begin - 1; } static void get_line(LINE *cur_ptr, uchar_t *s) { while (*s++ != NL) { } cur_ptr->newline = --s; cur_ptr->ln++; } static void get_ncount(LINE *cur_ptr, uchar_t *s) { uchar_t *p = cur_ptr->prntbuf; while (*--s != NL) { } cur_ptr->newline = s++; while ((s > p) && (p = (uchar_t *)memchr((char *)p, NL, s - p)) != NULL) { cur_ptr->ln++; ++p; } cur_ptr->ln--; cur_ptr->prntbuf = s; } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * cscope - interactive C symbol or text cross-reference * * command functions */ #include /* KEY_.* */ #include /* O_RDONLY */ #include #include #include "global.h" #include "library.h" BOOL caseless; /* ignore letter case when searching */ BOOL *change; /* change this line */ BOOL changing; /* changing text */ char newpat[PATLEN + 1]; /* new pattern */ char pattern[PATLEN + 1]; /* symbol or text pattern */ static char appendprompt[] = "Append to file: "; static char pipeprompt[] = "Pipe to shell command: "; static char readprompt[] = "Read from file: "; static char selectionprompt[] = "Selection: "; static char toprompt[] = "To: "; static void scrollbar(MOUSEEVENT *p); /* execute the command */ BOOL command(int commandc) { char filename[PATHLEN + 1]; /* file path name */ MOUSEEVENT *p; /* mouse data */ int c, i; FILE *file; HISTORY *curritem, *item; /* command history */ char *s; switch (commandc) { case ctrl('C'): /* toggle caseless mode */ if (caseless == NO) { caseless = YES; putmsg2("Caseless mode is now ON"); } else { caseless = NO; putmsg2("Caseless mode is now OFF"); } egrepcaseless(caseless); /* turn on/off -i flag */ return (NO); case ctrl('R'): /* rebuild the cross reference */ if (isuptodate == YES) { putmsg("The -d option prevents rebuilding the " "symbol database"); return (NO); } exitcurses(); freefilelist(); /* remake the source file list */ makefilelist(); rebuild(); if (errorsfound == YES) { errorsfound = NO; askforreturn(); } entercurses(); putmsg(""); /* clear any previous message */ totallines = 0; topline = nextline = 1; break; case ctrl('X'): /* mouse selection */ if ((p = getmouseevent()) == NULL) { return (NO); /* unknown control sequence */ } /* if the button number is a scrollbar tag */ if (p->button == '0') { scrollbar(p); break; } /* ignore a sweep */ if (p->x2 >= 0) { return (NO); } /* if this is a line selection */ if (p->y1 < FLDLINE) { /* find the selected line */ /* note: the selection is forced into range */ for (i = disprefs - 1; i > 0; --i) { if (p->y1 >= displine[i]) { break; } } /* display it in the file with the editor */ editref(i); } else { /* this is an input field selection */ field = mouseselection(p, FLDLINE, FIELDS); setfield(); resetcmd(); return (NO); } break; case '\t': /* go to next input field */ case '\n': case '\r': case ctrl('N'): case KEY_DOWN: case KEY_ENTER: case KEY_RIGHT: field = (field + 1) % FIELDS; setfield(); resetcmd(); return (NO); case ctrl('P'): /* go to previous input field */ case KEY_UP: case KEY_LEFT: field = (field + (FIELDS - 1)) % FIELDS; setfield(); resetcmd(); return (NO); case KEY_HOME: /* go to first input field */ field = 0; setfield(); resetcmd(); return (NO); case KEY_LL: /* go to last input field */ field = FIELDS - 1; setfield(); resetcmd(); return (NO); case ' ': /* display next page */ case '+': case ctrl('V'): case KEY_NPAGE: /* don't redisplay if there are no lines */ if (totallines == 0) { return (NO); } /* * note: seekline() is not used to move to the next * page because display() leaves the file pointer at * the next page to optimize paging forward */ break; case '-': /* display previous page */ case KEY_PPAGE: /* don't redisplay if there are no lines */ if (totallines == 0) { return (NO); } i = topline; /* save the current top line */ nextline = topline; /* go back to this page */ /* if on first page but not at beginning, go to beginning */ if (nextline > 1 && nextline <= mdisprefs) { nextline = 1; } else { /* go back the maximum displayable lines */ nextline -= mdisprefs; /* if this was the first page, go to the last page */ if (nextline < 1) { nextline = totallines - mdisprefs + 1; if (nextline < 1) { nextline = 1; } /* old top is past last line */ i = totallines + 1; } } /* * move down til the bottom line is just before the * previous top line */ c = nextline; for (;;) { seekline(nextline); display(); if (i - bottomline <= 0) { break; } nextline = ++c; } return (NO); /* display already up to date */ case '>': /* write or append the lines to a file */ if (totallines == 0) { putmsg("There are no lines to write to a file"); } else { /* get the file name */ (void) move(PRLINE, 0); (void) addstr("Write to file: "); s = "w"; if ((c = mygetch()) == '>') { (void) move(PRLINE, 0); (void) addstr(appendprompt); c = '\0'; s = "a"; } if (c != '\r' && c != '\n' && c != KEY_ENTER && c != KEY_BREAK && getaline(newpat, COLS - sizeof (appendprompt), c, NO) > 0) { shellpath(filename, sizeof (filename), newpat); if ((file = fopen(filename, s)) == NULL) { cannotopen(filename); } else { seekline(1); while ((c = getc(refsfound)) != EOF) { (void) putc(c, file); } seekline(topline); (void) fclose(file); } } clearprompt(); } return (NO); /* return to the previous field */ case '<': /* read lines from a file */ (void) move(PRLINE, 0); (void) addstr(readprompt); if (getaline(newpat, COLS - sizeof (readprompt), '\0', NO) > 0) { clearprompt(); shellpath(filename, sizeof (filename), newpat); if (readrefs(filename) == NO) { putmsg2("Ignoring an empty file"); return (NO); } return (YES); } clearprompt(); return (NO); case '^': /* pipe the lines through a shell command */ case '|': /* pipe the lines to a shell command */ if (totallines == 0) { putmsg("There are no lines to pipe to a shell command"); return (NO); } /* get the shell command */ (void) move(PRLINE, 0); (void) addstr(pipeprompt); if (getaline(newpat, COLS - sizeof (pipeprompt), '\0', NO) == 0) { clearprompt(); return (NO); } /* if the ^ command, redirect output to a temp file */ if (commandc == '^') { (void) strcat(strcat(newpat, " >"), temp2); } exitcurses(); if ((file = mypopen(newpat, "w")) == NULL) { (void) fprintf(stderr, "cscope: cannot open pipe to shell command: %s\n", newpat); } else { seekline(1); while ((c = getc(refsfound)) != EOF) { (void) putc(c, file); } seekline(topline); (void) mypclose(file); } if (commandc == '^') { if (readrefs(temp2) == NO) { putmsg("Ignoring empty output of ^ command"); } } askforreturn(); entercurses(); break; case ctrl('L'): /* redraw screen */ case KEY_CLEAR: (void) clearok(curscr, TRUE); (void) wrefresh(curscr); drawscrollbar(topline, bottomline, totallines); return (NO); case '!': /* shell escape */ (void) execute(shell, shell, (char *)NULL); seekline(topline); break; case '?': /* help */ (void) clear(); help(); (void) clear(); seekline(topline); break; case ctrl('E'): /* edit all lines */ editall(); break; case ctrl('A'): /* repeat last pattern */ case ctrl('Y'): /* (old command) */ if (*pattern != '\0') { (void) addstr(pattern); goto repeat; } break; case ctrl('B'): /* cmd history back */ case ctrl('F'): /* cmd history fwd */ curritem = currentcmd(); item = (commandc == ctrl('F')) ? nextcmd() : prevcmd(); clearmsg2(); if (curritem == item) { /* inform user that we're at history end */ putmsg2( "End of input field and search pattern history"); } if (item) { field = item->field; setfield(); atfield(); (void) addstr(item->text); (void) strcpy(pattern, item->text); switch (c = mygetch()) { case '\r': case '\n': case KEY_ENTER: goto repeat; default: ungetch(c); atfield(); (void) clrtoeol(); /* clear current field */ break; } } return (NO); case '\\': /* next character is not a command */ (void) addch('\\'); /* display the quote character */ /* get a character from the terminal */ if ((commandc = mygetch()) == EOF) { return (NO); /* quit */ } (void) addstr("\b \b"); /* erase the quote character */ goto ispat; case '.': atfield(); /* move back to the input field */ /* FALLTHROUGH */ default: /* edit a selected line */ if (isdigit(commandc) && commandc != '0' && !mouse) { if (returnrequired == NO) { editref(commandc - '1'); } else { (void) move(PRLINE, 0); (void) addstr(selectionprompt); if (getaline(newpat, COLS - sizeof (selectionprompt), commandc, NO) > 0 && (i = atoi(newpat)) > 0) { editref(i - 1); } clearprompt(); } } else if (isprint(commandc)) { /* this is the start of a pattern */ ispat: if (getaline(newpat, COLS - fldcolumn - 1, commandc, caseless) > 0) { (void) strcpy(pattern, newpat); resetcmd(); /* reset history */ repeat: addcmd(field, pattern); /* add to history */ if (field == CHANGE) { /* prompt for the new text */ (void) move(PRLINE, 0); (void) addstr(toprompt); (void) getaline(newpat, COLS - sizeof (toprompt), '\0', NO); } /* search for the pattern */ if (search() == YES) { switch (field) { case DEFINITION: case FILENAME: if (totallines > 1) { break; } topline = 1; editref(0); break; case CHANGE: return (changestring()); } } else if (field == FILENAME && access(newpat, READ) == 0) { /* try to edit the file anyway */ edit(newpat, "1"); } } else { /* no pattern--the input was erased */ return (NO); } } else { /* control character */ return (NO); } } return (YES); } /* clear the prompt line */ void clearprompt(void) { (void) move(PRLINE, 0); (void) clrtoeol(); } /* read references from a file */ BOOL readrefs(char *filename) { FILE *file; int c; if ((file = fopen(filename, "r")) == NULL) { cannotopen(filename); return (NO); } if ((c = getc(file)) == EOF) { /* if file is empty */ return (NO); } totallines = 0; nextline = 1; if (writerefsfound() == YES) { (void) putc(c, refsfound); while ((c = getc(file)) != EOF) { (void) putc(c, refsfound); } (void) fclose(file); (void) freopen(temp1, "r", refsfound); countrefs(); } return (YES); } /* change one text string to another */ BOOL changestring(void) { char buf[PATLEN + 1]; /* input buffer */ char newfile[PATHLEN + 1]; /* new file name */ char oldfile[PATHLEN + 1]; /* old file name */ char linenum[NUMLEN + 1]; /* file line number */ char msg[MSGLEN + 1]; /* message */ FILE *script; /* shell script file */ BOOL anymarked = NO; /* any line marked */ MOUSEEVENT *p; /* mouse data */ int c, i; char *s; /* open the temporary file */ if ((script = fopen(temp2, "w")) == NULL) { cannotopen(temp2); return (NO); } /* create the line change indicators */ change = (BOOL *)mycalloc((unsigned)totallines, sizeof (BOOL)); changing = YES; initmenu(); /* until the quit command is entered */ for (;;) { /* display the current page of lines */ display(); same: /* get a character from the terminal */ (void) move(PRLINE, 0); (void) addstr( "Select lines to change (press the ? key for help): "); if ((c = mygetch()) == EOF || c == ctrl('D') || c == ctrl('Z')) { break; /* change lines */ } /* see if the input character is a command */ switch (c) { case ' ': /* display next page */ case '+': case ctrl('V'): case KEY_NPAGE: case '-': /* display previous page */ case KEY_PPAGE: case '!': /* shell escape */ case '?': /* help */ (void) command(c); break; case ctrl('L'): /* redraw screen */ case KEY_CLEAR: (void) command(c); goto same; case ESC: /* kept for backwards compatibility */ /* FALLTHROUGH */ case '\r': /* don't change lines */ case '\n': case KEY_ENTER: case KEY_BREAK: case ctrl('G'): clearprompt(); goto nochange; case '*': /* mark/unmark all displayed lines */ for (i = 0; topline + i < nextline; ++i) { mark(i); } goto same; case 'a': /* mark/unmark all lines */ for (i = 0; i < totallines; ++i) { if (change[i] == NO) { change[i] = YES; } else { change[i] = NO; } } /* show that all have been marked */ seekline(totallines); break; case ctrl('X'): /* mouse selection */ if ((p = getmouseevent()) == NULL) { goto same; /* unknown control sequence */ } /* if the button number is a scrollbar tag */ if (p->button == '0') { scrollbar(p); break; } /* find the selected line */ /* note: the selection is forced into range */ for (i = disprefs - 1; i > 0; --i) { if (p->y1 >= displine[i]) { break; } } mark(i); goto same; default: /* if a line was selected */ if (isdigit(c) && c != '0' && !mouse) { if (returnrequired == NO) { mark(c - '1'); } else { clearprompt(); (void) move(PRLINE, 0); (void) addstr(selectionprompt); if (getaline(buf, COLS - sizeof (selectionprompt), c, NO) > 0 && (i = atoi(buf)) > 0) { mark(i - 1); } } } goto same; } } /* for each line containing the old text */ (void) fprintf(script, "ed - <<\\!\nH\n"); *oldfile = '\0'; seekline(1); for (i = 0; fscanf(refsfound, "%s%*s%s%*[^\n]", newfile, linenum) == 2; ++i) { /* see if the line is to be changed */ if (change[i] == YES) { anymarked = YES; /* if this is a new file */ if (strcmp(newfile, oldfile) != 0) { /* make sure it can be changed */ if (access(newfile, WRITE) != 0) { (void) sprintf(msg, "Cannot write to file %s", newfile); putmsg(msg); anymarked = NO; break; } /* if there was an old file */ if (*oldfile != '\0') { (void) fprintf(script, "w\n"); /* save it */ } /* edit the new file */ (void) strcpy(oldfile, newfile); (void) fprintf(script, "e %s\n", oldfile); } /* output substitute command */ (void) fprintf(script, "%ss/", linenum); /* change */ for (s = pattern; *s != '\0'; ++s) { /* old text */ if (*s == '/') { (void) putc('\\', script); } (void) putc(*s, script); } (void) putc('/', script); /* to */ for (s = newpat; *s != '\0'; ++s) { /* new text */ if (strchr("/\\&", *s) != NULL) { (void) putc('\\', script); } (void) putc(*s, script); } (void) fprintf(script, "/gp\n"); /* and print */ } } (void) fprintf(script, "w\nq\n!\n"); /* write and quit */ (void) fclose(script); clearprompt(); /* if any line was marked */ if (anymarked == YES) { /* edit the files */ (void) refresh(); (void) fprintf(stderr, "Changed lines:\n\r"); (void) execute(shell, shell, temp2, (char *)NULL); askforreturn(); } nochange: changing = NO; initmenu(); free(change); seekline(topline); return (YES); /* clear any marks on exit without change */ } /* mark/unmark this displayed line to be changed */ void mark(int i) { int j; j = i + topline - 1; if (j < totallines) { (void) move(displine[i], selectlen); if (change[j] == NO) { change[j] = YES; (void) addch('>'); } else { change[j] = NO; (void) addch(' '); } } } /* scrollbar actions */ static void scrollbar(MOUSEEVENT *p) { /* reposition list if it makes sense */ if (totallines == 0) { return; } switch (p->percent) { case 101: /* scroll down one page */ if (nextline + mdisprefs > totallines) { nextline = totallines - mdisprefs + 1; } break; case 102: /* scroll up one page */ nextline = topline - mdisprefs; if (nextline < 1) { nextline = 1; } break; case 103: /* scroll down one line */ nextline = topline + 1; break; case 104: /* scroll up one line */ if (topline > 1) { nextline = topline - 1; } break; default: nextline = p->percent * totallines / 100; } seekline(nextline); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 1999 by Sun Microsystems, Inc. * All rights reserved. */ /* * compath(pathname) * * This compresses pathnames. All strings of multiple slashes are * changed to a single slash. All occurrences of "./" are removed. * Whenever possible, strings of "/.." are removed together with * the directory names that they follow. * * WARNING: since pathname is altered by this function, it should * be located in a temporary buffer. This avoids the problem * of accidently changing strings obtained from makefiles * and stored in global structures. */ #include char * compath(char *pathname) { char *nextchar; char *lastchar; char *sofar; char *pnend; int pnlen; /* * do not change the path if it has no "/" */ if (strchr(pathname, '/') == 0) return (pathname); /* * find all strings consisting of more than one '/' */ for (lastchar = pathname + 1; *lastchar != '\0'; lastchar++) if ((*lastchar == '/') && (*(lastchar - 1) == '/')) { /* * find the character after the last slash */ nextchar = lastchar; while (*++lastchar == '/') { } /* * eliminate the extra slashes by copying * everything after the slashes over the slashes */ sofar = nextchar; while ((*nextchar++ = *lastchar++) != '\0') ; lastchar = sofar; } /* * find all strings of "./" */ for (lastchar = pathname + 1; *lastchar != '\0'; lastchar++) if ((*lastchar == '/') && (*(lastchar - 1) == '.') && ((lastchar - 1 == pathname) || (*(lastchar - 2) == '/'))) { /* * copy everything after the "./" over the "./" */ nextchar = lastchar - 1; sofar = nextchar; while ((*nextchar++ = *++lastchar) != '\0') ; lastchar = sofar; } /* * find each occurrence of "/.." */ for (lastchar = pathname + 1; *lastchar != '\0'; lastchar++) if ((lastchar != pathname) && (*lastchar == '/') && (*(lastchar + 1) == '.') && (*(lastchar + 2) == '.') && ((*(lastchar + 3) == '/') || (*(lastchar + 3) == '\0'))) { /* * find the directory name preceding the "/.." */ nextchar = lastchar - 1; while ((nextchar != pathname) && (*(nextchar - 1) != '/')) --nextchar; /* * make sure the preceding directory's name * is not "." or ".." */ if ((*nextchar == '.') && (*(nextchar + 1) == '/') || ((*(nextchar + 1) == '.') && (*(nextchar + 2) == '/'))) { /* EMPTY */; } else { /* * prepare to eliminate either * "dir_name/../" or "dir_name/.." */ if (*(lastchar + 3) == '/') lastchar += 4; else lastchar += 3; /* * copy everything after the "/.." to * before the preceding directory name */ sofar = nextchar - 1; while ((*nextchar++ = *lastchar++) != '\0'); lastchar = sofar; /* * if the character before what was taken * out is '/', set up to check if the * slash is part of "/.." */ if ((sofar + 1 != pathname) && (*sofar == '/')) --lastchar; } } /* * if the string is more than a character long and ends * in '/', eliminate the '/'. */ pnlen = strlen(pathname); pnend = strchr(pathname, '\0') - 1; if ((pnlen > 1) && (*pnend == '/')) { *pnend-- = '\0'; pnlen--; } /* * if the string has more than two characters and ends in * "/.", remove the "/.". */ if ((pnlen > 2) && (*(pnend - 1) == '/') && (*pnend == '.')) *--pnend = '\0'; /* * if all characters were deleted, return "."; * otherwise return pathname */ if (*pathname == '\0') (void) strcpy(pathname, "."); return (pathname); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * cscope - interactive C symbol cross-reference * * preprocessor macro and constant definitions */ /* * Copyright (c) 1999 by Sun Microsystems, Inc. * All rights reserved. */ #include #define ctrl(x) (x & 037) /* control character macro */ /* database output macros that update its offset */ #define dbputc(c) (++dboffset, (void) putc(c, newrefs)) #define dbfputs(s) (dboffset += fputs(s, newrefs)) #define dbfprintf(s, f, a) (dboffset += fprintf(s, f, a)) /* fast string equality tests (avoids most strcmp() calls) */ #define strequal(s1, s2) (*(s1) == *(s2) && strcmp(s1, s2) == 0) #define strnotequal(s1, s2) (*(s1) != *(s2) || strcmp(s1, s2) != 0) /* set the mark character for searching the cross-reference file */ #define setmark(c) (blockmark = c, block[blocklen] = blockmark) /* get the next character in the cross-reference */ /* note that blockp is assumed not to be null */ #define getrefchar() (*(++blockp + 1) != '\0' ? *blockp : \ (readblock() != NULL ? *blockp : '\0')) /* skip the next character in the cross-reference */ /* * note that blockp is assumed not to be null and that * this macro will always be in a statement by itself */ #define skiprefchar() if (*(++blockp + 1) == '\0') (void) readblock() #define ESC '\033' /* escape character */ #define MSGLEN PATLEN + 80 /* displayed message length */ #define READ 4 /* access(2) parameter */ #define WRITE 2 /* access(2) parameter */ /* these also appear in the fscanf format string in countrefs() */ #define NUMLEN 6 /* line number length */ #define PATHLEN PATH_MAX /* file pathname length */ /* default file names */ #define INVNAME "cscope.in.out" /* inverted index to the database */ #define INVPOST "cscope.po.out" /* inverted index postings */ #define NAMEFILE "cscope.files" /* source file names and options */ #define REFFILE "cscope.out" /* symbol database */ /* * cross-reference database mark characters (when new ones are added, * update the cscope.out format description in cscope.1) */ #define ASSIGNMENT '=' #define CLASSDEF 'c' #define DEFINE '#' #define DEFINEEND ')' #define ENUMDEF 'e' #define ESUEND ';' #define FCNCALL '`' #define FCNDEF '$' #define FCNEND '}' #define GLOBALDEF 'g' #define INCLUDE '~' #define LOCALDEF 'l' #define MEMBERDEF 'm' #define NEWFILE '@' #define PARAMETER 'p' #define STRUCTDEF 's' #define TYPEDEF 't' #define UNIONDEF 'u' /* other scanner token types */ #define LEXEOF 0 #define IDENT 1 #define NEWLINE 2 /* screen lines */ #define FLDLINE (LINES - FIELDS - 1) /* first input field line */ #define MSGLINE 0 /* message line */ #define PRLINE (LINES - 1) /* input prompt line */ #define REFLINE 3 /* first displayed reference line */ /* input fields (value matches field order on screen) */ #define SYMBOL 0 #define DEFINITION 1 #define CALLEDBY 2 #define CALLING 3 #define ASSIGN 4 #define CHANGE 5 #define STRING 6 #define FILENAME 7 #define INCLUDES 8 #define FIELDS 9 /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * cscope - interactive C symbol cross-reference * * build cross-reference file */ #include "global.h" /* convert long to a string */ #define ltobase(value) n = value; \ s = buf + (sizeof (buf) - 1); \ *s = '\0'; \ digits = 1; \ while (n >= BASE) { \ ++digits; \ i = n; \ n /= BASE; \ *--s = i - n * BASE + '!'; \ } \ *--s = n + '!'; #define SYMBOLINC 20 /* symbol list size increment */ #define FREAD "r" /* fopen for reading */ long dboffset; /* new database offset */ BOOL errorsfound; /* prompt before clearing messages */ long fileindex; /* source file name index */ long lineoffset; /* source line database offset */ long npostings; /* number of postings */ int nsrcoffset; /* number of file name database offsets */ long *srcoffset; /* source file name database offsets */ int symbols; /* number of symbols */ static char *filename; /* file name for warning messages */ static long fcnoffset; /* function name database offset */ static long macrooffset; /* macro name database offset */ static int msymbols = SYMBOLINC; /* maximum number of symbols */ static struct symbol { /* symbol data */ int type; /* type */ int first; /* index of first character in text */ int last; /* index of last+1 character in text */ int length; /* symbol length */ } *symbol; static void putcrossref(void); void crossref(char *srcfile) { int i; int length; /* symbol length */ int token; /* current token */ /* open the source file */ if ((yyin = vpfopen(srcfile, FREAD)) == NULL) { cannotopen(srcfile); errorsfound = YES; return; } filename = srcfile; /* save the file name for warning messages */ putfilename(srcfile); /* output the file name */ dbputc('\n'); dbputc('\n'); /* read the source file */ initscanner(srcfile); fcnoffset = macrooffset = 0; symbols = 0; if (symbol == NULL) { symbol = mymalloc(msymbols * sizeof (struct symbol)); } for (;;) { /* get the next token */ switch (token = yylex()) { default: /* if requested, truncate C symbols */ length = last - first; if (truncatesyms && length > 8 && token != INCLUDE && token != NEWFILE) { length = 8; last = first + 8; } /* see if the token has a symbol */ if (length == 0) { savesymbol(token); break; } /* see if the symbol is already in the list */ for (i = 0; i < symbols; ++i) { if (length == symbol[i].length && strncmp(yytext + first, yytext + symbol[i].first, length) == 0 && (token == IDENT || token == symbol[i].type)) { first = yyleng; break; } } if (i == symbols) { /* if not already in list */ savesymbol(token); } break; case NEWLINE: /* end of line containing symbols */ --yyleng; /* remove the newline */ putcrossref(); /* output the symbols and source line */ lineno = yylineno; /* save the symbol line number */ break; case LEXEOF: /* end of file; last line may not have \n */ /* * if there were symbols, output them and the * source line */ if (symbols > 0) { putcrossref(); } (void) fclose(yyin); /* close the source file */ /* output the leading tab expected by the next call */ dbputc('\t'); return; } } } /* save the symbol in the list */ void savesymbol(int token) { /* make sure there is room for the symbol */ if (symbols == msymbols) { msymbols += SYMBOLINC; symbol = (struct symbol *)myrealloc(symbol, msymbols * sizeof (struct symbol)); } /* save the symbol */ symbol[symbols].type = token; symbol[symbols].first = first; symbol[symbols].last = last; symbol[symbols].length = last - first; ++symbols; first = yyleng; } /* output the file name */ void putfilename(char *srcfile) { /* check for file system out of space */ /* note: dbputc is not used to avoid lint complaint */ if (putc(NEWFILE, newrefs) == EOF) { cannotwrite(newreffile); /* NOTREACHED */ } ++dboffset; if (invertedindex) { srcoffset[nsrcoffset++] = dboffset; } dbfputs(srcfile); fcnoffset = macrooffset = 0; } /* output the symbols and source line */ static void putcrossref(void) { int i, j; unsigned c; BOOL blank = NO; /* output blank */ BOOL newline = NO; /* output newline */ int symput = 0; /* symbols output */ int type; /* output the source line */ lineoffset = dboffset; dbfprintf(newrefs, "%d ", lineno); for (i = 0; i < yyleng; ++i) { /* change a tab to a blank and compress blanks */ if ((c = yytext[i]) == ' ' || c == '\t') { blank = YES; } /* look for the start of a symbol */ else if (symput < symbols && i == symbol[symput].first) { /* check for compressed blanks */ if (blank) { blank = NO; if (newline) { dbputc('\n'); } dbputc(' '); } dbputc('\n'); /* symbols start on a new line */ /* output any symbol type */ if ((type = symbol[symput].type) != IDENT) { dbputc('\t'); dbputc(type); } else { type = ' '; } /* output the symbol */ j = symbol[symput].last; c = yytext[j]; yytext[j] = '\0'; if (invertedindex) { putposting(yytext + i, type); } putstring(yytext + i); newline = YES; yytext[j] = (char)c; i = j - 1; ++symput; } else { if (newline) { newline = NO; dbputc('\n'); } /* check for compressed blanks */ if (blank) { if (dicode2[c]) { c = (0200 - 2) + dicode1[' '] + dicode2[c]; } else { dbputc(' '); } } else if (dicode1[c] && (j = dicode2[(unsigned)yytext[i + 1]]) != 0 && symput < symbols && i + 1 != symbol[symput].first) { /* compress digraphs */ c = (0200 - 2) + dicode1[c] + j; ++i; } /* * if the last line of the file is a '}' without a * newline, the lex EOF code overwrites it with a 0 */ if (c) { dbputc((int)c); } else { dbputc(' '); } blank = NO; /* skip compressed characters */ if (c < ' ') { ++i; /* skip blanks before a preprocesor keyword */ /* * note: don't use isspace() because \f and \v * are used for keywords */ while ((j = yytext[i]) == ' ' || j == '\t') { ++i; } /* skip the rest of the keyword */ while (isalpha(yytext[i])) { ++i; } /* skip space after certain keywords */ if (keyword[c].delim != '\0') { while ((j = yytext[i]) == ' ' || j == '\t') { ++i; } } /* skip a '(' after certain keywords */ if (keyword[c].delim == '(' && yytext[i] == '(') { ++i; } --i; /* compensate for ++i in for() */ } } } /* ignore trailing blanks */ dbputc('\n'); dbputc('\n'); /* output any #define end marker */ /* * note: must not be part of #define so putsource() doesn't discard it * so findcalledbysub() can find it and return */ if (symput < symbols && symbol[symput].type == DEFINEEND) { dbputc('\t'); dbputc(DEFINEEND); dbputc('\n'); dbputc('\n'); /* mark beginning of next source line */ macrooffset = 0; } symbols = 0; } /* output the inverted index posting */ void putposting(char *term, int type) { long i, n; char *s; int digits; /* digits output */ long offset; /* function/macro database offset */ char buf[11]; /* number buffer */ /* get the function or macro name offset */ offset = fcnoffset; if (macrooffset != 0) { offset = macrooffset; } /* then update them to avoid negative relative name offset */ switch (type) { case DEFINE: macrooffset = dboffset; break; case DEFINEEND: macrooffset = 0; return; /* null term */ case FCNDEF: fcnoffset = dboffset; break; case FCNEND: fcnoffset = 0; return; /* null term */ } /* ignore a null term caused by a enum/struct/union without a tag */ if (*term == '\0') { return; } /* skip any #include secondary type char (< or ") */ if (type == INCLUDE) { ++term; } /* * output the posting, which should be as small as possible to reduce * the temp file size and sort time */ (void) fputs(term, postings); (void) putc(' ', postings); /* * the line offset is padded so postings for the same term will sort * in ascending line offset order to order the references as they * appear withing a source file */ ltobase(lineoffset); for (i = PRECISION - digits; i > 0; --i) { (void) putc('!', postings); } do { (void) putc(*s, postings); } while (*++s != '\0'); /* postings are also sorted by type */ (void) putc(type, postings); /* function or macro name offset */ if (offset > 0) { (void) putc(' ', postings); ltobase(offset); do { (void) putc(*s, postings); } while (*++s != '\0'); } if (putc('\n', postings) == EOF) { cannotwrite(temp1); /* NOTREACHED */ } ++npostings; } /* put the string into the new database */ void putstring(char *s) { unsigned c; int i; /* compress digraphs */ for (i = 0; (c = s[i]) != '\0'; ++i) { if (dicode1[c] && dicode2[(unsigned)s[i + 1]]) { c = (0200 - 2) + dicode1[c] + dicode2[(unsigned)s[i + 1]]; ++i; } dbputc((int)c); } } /* print a warning message with the file name and line number */ void warning(text) char *text; { extern int yylineno; (void) fprintf(stderr, "cscope: \"%s\", line %d: warning: %s\n", filename, yylineno, text); errorsfound = YES; } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * cscope - interactive C symbol cross-reference * * directory searching functions */ #include /* needed by stat.h */ #include /* stat */ #include "global.h" #include "dirent.h" #include "vp.h" /* vpdirs and vpndirs */ #define DIRSEPS " ,:" /* directory list separators */ #define DIRINC 10 /* directory list size increment */ #define HASHMOD 2003 /* must be a prime number */ #define SRCINC HASHMOD /* source file list size increment */ /* largest known database had 22049 files */ char **incdirs; /* #include directories */ char **srcdirs; /* source directories */ char **srcfiles; /* source files */ int nincdirs; /* number of #include directories */ int mincdirs = DIRINC; /* maximum number of #include directories */ int nsrcdirs; /* number of source directories */ int msrcdirs = DIRINC; /* maximum number of source directories */ int nsrcfiles; /* number of source files */ int msrcfiles = SRCINC; /* maximum number of source files */ static struct listitem { /* source file table entry */ char *file; struct listitem *next; } *srcfiletable[HASHMOD]; static void getsrcfiles(char *vpdir, char *dir); static BOOL issrcfile(char *file); /* add a source directory to the list for each view path source directory */ void sourcedir(char *dirlist) { struct stat statstruct; char *dir; /* don't change environment variable text */ dirlist = stralloc(dirlist); /* parse the directory list */ dir = strtok(dirlist, DIRSEPS); while (dir != NULL) { /* * make sure it is a directory (must exist in current * view path node) */ if (stat(compath(dir), &statstruct) == 0 && S_ISDIR(statstruct.st_mode)) { if (srcdirs == NULL) { srcdirs = mymalloc(msrcdirs * sizeof (char *)); } else if (nsrcdirs == msrcdirs) { msrcdirs += DIRINC; srcdirs = myrealloc(srcdirs, msrcdirs * sizeof (char *)); } srcdirs[nsrcdirs++] = stralloc(dir); } dir = strtok((char *)NULL, DIRSEPS); } } /* add a #include directory to the list for each view path source directory */ void includedir(char *dirlist) { struct stat statstruct; char *dir; /* don't change environment variable text */ dirlist = stralloc(dirlist); /* parse the directory list */ dir = strtok(dirlist, DIRSEPS); while (dir != NULL) { /* * make sure it is a directory (must exist in current * view path node) */ if (stat(compath(dir), &statstruct) == 0 && S_ISDIR(statstruct.st_mode)) { if (incdirs == NULL) { incdirs = mymalloc(mincdirs * sizeof (char *)); } else if (nincdirs == mincdirs) { mincdirs += DIRINC; incdirs = myrealloc(incdirs, mincdirs * sizeof (char *)); } incdirs[nincdirs++] = stralloc(dir); } dir = strtok((char *)NULL, DIRSEPS); } } /* make the source file list */ void makefilelist(void) { static BOOL firstbuild = YES; /* first time through */ FILE *names; /* name file pointer */ char dir[PATHLEN + 1]; char path[PATHLEN + 1]; struct stat statstruct; char *file; char *s; int i, j; /* if there are source file arguments */ if (fileargc > 0) { /* put them in a list that can be expanded */ for (i = 0; i < fileargc; ++i) { file = fileargv[i]; if (infilelist(file) == NO) { if (vpaccess(file, READ) == 0) { addsrcfile(file); } else { (void) fprintf(stderr, "cscope: cannot find file %s\n", file); errorsfound = YES; } } } return; } /* see if a file name file exists */ if (namefile == NULL && vpaccess(NAMEFILE, READ) == 0) { namefile = NAMEFILE; } /* if there is a file of source file names */ if (namefile != NULL) { if ((names = vpfopen(namefile, "r")) == NULL) { cannotopen(namefile); myexit(1); } /* get the names in the file */ while (fscanf(names, "%s", path) == 1) { if (*path == '-') { /* if an option */ i = path[1]; switch (i) { case 'q': /* quick search */ invertedindex = YES; break; case 'T': /* truncate symbols to 8 characters */ truncatesyms = YES; break; case 'I': /* #include file directory */ case 'p': /* file path components to */ /* display */ s = path + 2; /* for "-Ipath" */ if (*s == '\0') { /* if "-I path" */ (void) fscanf(names, "%s", path); s = path; } switch (i) { case 'I': /* #include file directory */ if (firstbuild == YES) { /* expand $ and ~ */ shellpath(dir, sizeof (dir), s); includedir(dir); } break; case 'p': /* file path components */ /* to display */ if (*s < '0' || *s > '9') { (void) fprintf(stderr, "cscope: -p option " "in file %s: " "missing or " "invalid numeric " "value\n", namefile); } dispcomponents = atoi(s); break; } break; default: (void) fprintf(stderr, "cscope: only -I, -p, and -T " "options can be in file %s\n", namefile); } } else if (vpaccess(path, READ) == 0) { addsrcfile(path); } else { (void) fprintf(stderr, "cscope: cannot find file %s\n", path); errorsfound = YES; } } (void) fclose(names); firstbuild = NO; return; } /* make a list of all the source files in the directories */ for (i = 0; i < nsrcdirs; ++i) { s = srcdirs[i]; getsrcfiles(s, s); if (*s != '/') { /* if it isn't a full path name */ /* compute its path from any higher view path nodes */ for (j = 1; j < vpndirs; ++j) { (void) sprintf(dir, "%s/%s", vpdirs[j], s); /* make sure it is a directory */ if (stat(compath(dir), &statstruct) == 0 && S_ISDIR(statstruct.st_mode)) { getsrcfiles(dir, s); } } } } } /* get the source file names in this directory */ static void getsrcfiles(char *vpdir, char *dir) { DIR *dirfile; /* directory file descriptor */ struct dirent *entry; /* directory entry pointer */ char path[PATHLEN + 1]; /* attempt to open the directory */ if ((dirfile = opendir(vpdir)) != NULL) { /* read each entry in the directory */ while ((entry = readdir(dirfile)) != NULL) { /* if it is a source file not already found */ (void) sprintf(path, "%s/%s", dir, entry->d_name); if (entry->d_ino != 0 && issrcfile(path) && infilelist(path) == NO) { addsrcfile(path); /* add it to the list */ } } closedir(dirfile); } } /* see if this is a source file */ static BOOL issrcfile(char *file) { struct stat statstruct; char *s; /* if there is a file suffix */ if ((s = strrchr(file, '.')) != NULL && *++s != '\0') { /* if an SCCS or versioned file */ if (file[1] == '.' && file + 2 != s) { /* 1 character prefix */ switch (*file) { case 's': case 'S': return (NO); } } if (s[1] == '\0') { /* 1 character suffix */ switch (*s) { case 'c': case 'h': case 'l': case 'y': case 'C': case 'G': case 'H': case 'L': return (YES); } } else if (s[2] == '\0') { /* 2 character suffix */ if (*s == 'b' && s[1] == 'p' || /* breakpoint listing */ *s == 'q' && (s[1] == 'c' || s[1] == 'h') || /* Ingres */ *s == 'p' && s[1] == 'r' || /* SDL */ *s == 's' && s[1] == 'd') { /* SDL */ /* * some directories have 2 character * suffixes so make sure it is a file */ if (vpstat(file, &statstruct) == 0 && S_ISREG(statstruct.st_mode)) { return (YES); } } } } return (NO); } /* add an include file to the source file list */ void incfile(char *file, int type) { char path[PATHLEN + 1]; int i; /* see if the file is already in the source file list */ if (infilelist(file) == YES) { return; } /* look in current directory if it was #include "file" */ if (type == '"' && vpaccess(file, READ) == 0) { addsrcfile(file); } else { /* search for the file in the #include directory list */ for (i = 0; i < nincdirs; ++i) { /* don't include the file from two directories */ (void) sprintf(path, "%s/%s", incdirs[i], file); if (infilelist(path) == YES) { break; } /* make sure it exists and is readable */ if (vpaccess(compath(path), READ) == 0) { addsrcfile(path); break; } } } } /* see if the file is already in the list */ BOOL infilelist(char *file) { struct listitem *p; for (p = srcfiletable[hash(compath(file)) % HASHMOD]; p != NULL; p = p->next) { if (strequal(file, p->file)) { return (YES); } } return (NO); } /* add a source file to the list */ void addsrcfile(char *path) { struct listitem *p; int i; /* make sure there is room for the file */ if (nsrcfiles == msrcfiles) { msrcfiles += SRCINC; srcfiles = myrealloc(srcfiles, msrcfiles * sizeof (char *)); } /* add the file to the list */ p = (struct listitem *)mymalloc(sizeof (struct listitem)); p->file = stralloc(compath(path)); i = hash(p->file) % HASHMOD; p->next = srcfiletable[i]; srcfiletable[i] = p; srcfiles[nsrcfiles++] = p->file; } /* free the memory allocated for the source file list */ void freefilelist(void) { struct listitem *p, *nextp; int i; while (nsrcfiles > 0) { free(srcfiles[--nsrcfiles]); } for (i = 0; i < HASHMOD; ++i) { for (p = srcfiletable[i]; p != NULL; p = nextp) { nextp = p->next; free(p); } srcfiletable[i] = NULL; } } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright 2015 Gary Mills */ /* * cscope - interactive C symbol cross-reference * * display functions */ #include "global.h" #include "version.h" /* FILEVERSION and FIXVERSION */ #include /* COLS and LINES */ #include /* jmp_buf */ #include #include /* see if the function column should be displayed */ #define displayfcn() (field <= ASSIGN) #define MINCOLS 68 /* minimum columns for 3 digit Lines message numbers */ int *displine; /* screen line of displayed reference */ int disprefs; /* displayed references */ int field; /* input field */ unsigned fldcolumn; /* input field column */ int mdisprefs; /* maximum displayed references */ int selectlen; /* selection number field length */ int nextline; /* next line to be shown */ int topline = 1; /* top line of page */ int bottomline; /* bottom line of page */ int totallines; /* total reference lines */ FILE *refsfound; /* references found file */ FILE *nonglobalrefs; /* non-global references file */ static int fldline; /* input field line */ static int subsystemlen; /* OGS subsystem name display */ /* field length */ static int booklen; /* OGS book name display field length */ static int filelen; /* file name display field length */ static int fcnlen; /* function name display field length */ static jmp_buf env; /* setjmp/longjmp buffer */ static int lastdispline; /* last displayed reference line */ static char lastmsg[MSGLEN + 1]; /* last message displayed */ static int numlen; /* line number display field length */ static char depthstring[] = "Depth: "; static char helpstring[] = "Press the ? key for help"; typedef char *(*FP)(); /* pointer to function returning a character pointer */ static struct { char *text1; char *text2; FP findfcn; enum { EGREP, REGCMP } patterntype; } fields[FIELDS + 1] = { /* last search is not part of the cscope display */ { "Find this", "C symbol", (FP) findsymbol, REGCMP}, { "Find this", "definition", (FP) finddef, REGCMP}, { "Find", "functions called by this function", (FP) findcalledby, REGCMP}, { "Find", "functions calling this function", (FP) findcalling, REGCMP}, { "Find", "assignments to", (FP) findassignments, REGCMP}, { "Change this", "grep pattern", findgreppat, EGREP}, { "Find this", "egrep pattern", findegreppat, EGREP}, { "Find this", "file", (FP) findfile, REGCMP}, { "Find", "files #including this file", (FP) findinclude, REGCMP}, { "Find all", "function/class definitions", (FP) findallfcns, REGCMP}, }; /* initialize display parameters */ void dispinit(void) { /* calculate the maximum displayed reference lines */ lastdispline = FLDLINE - 2; mdisprefs = lastdispline - REFLINE + 1; if (mdisprefs <= 0) { (void) printw("cscope: window must be at least %d lines high", FIELDS + 6); myexit(1); } if (COLS < MINCOLS) { (void) printw("cscope: window must be at least %d columns wide", MINCOLS); myexit(1); } if (!mouse) { if (returnrequired == NO && mdisprefs > 9) { mdisprefs = 9; /* single digit selection number */ } /* calculate the maximum selection number width */ (void) sprintf(newpat, "%d", mdisprefs); selectlen = strlen(newpat); } /* allocate the displayed line array */ displine = (int *)mymalloc(mdisprefs * sizeof (int)); } /* display a page of the references */ void display(void) { char *subsystem; /* OGS subsystem name */ char *book; /* OGS book name */ char file[PATHLEN + 1]; /* file name */ char function[PATLEN + 1]; /* function name */ char linenum[NUMLEN + 1]; /* line number */ int screenline; /* screen line number */ int width; /* source line display width */ int i; char *s; (void) erase(); /* if there are no references */ if (totallines == 0) { if (*lastmsg != '\0') { (void) addstr(lastmsg); /* redisplay any message */ } else { (void) printw("Cscope version %d%s", FILEVERSION, FIXVERSION); (void) move(0, COLS - (int)sizeof (helpstring)); (void) addstr(helpstring); } } else { /* display the pattern */ if (changing == YES) { (void) printw("Change \"%s\" to \"%s\"", pattern, newpat); } else { (void) printw("%c%s: %s", toupper(fields[field].text2[0]), fields[field].text2 + 1, pattern); } /* display the cscope invocation nesting depth */ if (cscopedepth > 1) { (void) move(0, COLS - (int)sizeof (depthstring) - 2); (void) addstr(depthstring); (void) printw("%d", cscopedepth); } /* display the column headings */ (void) move(2, selectlen + 1); if (ogs == YES && field != FILENAME) { (void) printw("%-*s ", subsystemlen, "Subsystem"); (void) printw("%-*s ", booklen, "Book"); } if (dispcomponents > 0) { (void) printw("%-*s ", filelen, "File"); } if (displayfcn()) { (void) printw("%-*s ", fcnlen, "Function"); } if (field != FILENAME) { (void) addstr("Line"); } (void) addch('\n'); /* if at end of file go back to beginning */ if (nextline > totallines) { seekline(1); } /* calculate the source text column */ width = COLS - selectlen - numlen - 2; if (ogs == YES) { width -= subsystemlen + booklen + 2; } if (dispcomponents > 0) { width -= filelen + 1; } if (displayfcn()) { width -= fcnlen + 1; } /* * until the max references have been displayed or * there is no more room */ topline = nextline; for (disprefs = 0, screenline = REFLINE; disprefs < mdisprefs && screenline <= lastdispline; ++disprefs, ++screenline) { /* read the reference line */ if (fscanf(refsfound, "%s%s%s %[^\n]", file, function, linenum, yytext) < 4) { break; } ++nextline; displine[disprefs] = screenline; /* if no mouse, display the selection number */ if (!mouse) { (void) printw("%*d", selectlen, disprefs + 1); } /* display any change mark */ if (changing == YES && change[topline + disprefs - 1] == YES) { (void) addch('>'); } else { (void) addch(' '); } /* display the file name */ if (field == FILENAME) { (void) printw("%-.*s\n", COLS - 3, file); continue; } /* if OGS, display the subsystem and book names */ if (ogs == YES) { ogsnames(file, &subsystem, &book); (void) printw("%-*.*s ", subsystemlen, subsystemlen, subsystem); (void) printw("%-*.*s ", booklen, booklen, book); } /* display the requested path components */ if (dispcomponents > 0) { (void) printw("%-*.*s ", filelen, filelen, pathcomponents(file, dispcomponents)); } /* display the function name */ if (displayfcn()) { (void) printw("%-*.*s ", fcnlen, fcnlen, function); } /* display the line number */ (void) printw("%*s ", numlen, linenum); /* there may be tabs in egrep output */ while ((s = strchr(yytext, '\t')) != NULL) { *s = ' '; } /* display the source line */ s = yytext; for (;;) { /* see if the source line will fit */ if ((i = strlen(s)) > width) { /* find the nearest blank */ for (i = width; s[i] != ' ' && i > 0; --i) { } if (i == 0) { i = width; /* no blank */ } } /* print up to this point */ (void) printw("%.*s", i, s); s += i; /* if line didn't wrap around */ if (i < width) { /* go to next line */ (void) addch('\n'); } /* skip blanks */ while (*s == ' ') { ++s; } /* see if there is more text */ if (*s == '\0') { break; } /* if the source line is too long */ if (++screenline > lastdispline) { /* * if this is the first displayed line, * display what will fit on the screen */ if (topline == nextline - 1) { goto endrefs; } /* erase the reference */ while (--screenline >= displine[disprefs]) { (void) move(screenline, 0); (void) clrtoeol(); } ++screenline; /* * go back to the beginning of this * reference */ --nextline; seekline(nextline); goto endrefs; } /* indent the continued source line */ (void) move(screenline, COLS - width); } } endrefs: /* check for more references */ bottomline = nextline; if (bottomline - topline < totallines) { (void) move(FLDLINE - 1, 0); (void) standout(); (void) printw("%*s", selectlen + 1, ""); if (bottomline - 1 == topline) { (void) printw("Line %d", topline); } else { (void) printw("Lines %d-%d", topline, bottomline - 1); } (void) printw(" of %d, press the space bar to " "display next lines", totallines); (void) standend(); } } /* display the input fields */ (void) move(FLDLINE, 0); for (i = 0; i < FIELDS; ++i) { (void) printw("%s %s:\n", fields[i].text1, fields[i].text2); } drawscrollbar(topline, nextline, totallines); } /* set the cursor position for the field */ void setfield(void) { fldline = FLDLINE + field; fldcolumn = strlen(fields[field].text1) + strlen(fields[field].text2) + 3; } /* move to the current input field */ void atfield(void) { (void) move(fldline, (int)fldcolumn); } /* search for the symbol or text pattern */ /*ARGSUSED*/ SIGTYPE jumpback(int sig) { longjmp(env, 1); } BOOL search(void) { char *volatile egreperror = NULL; /* egrep error message */ FINDINIT volatile rc = NOERROR; /* findinit return code */ SIGTYPE (*volatile savesig)() = SIG_DFL; /* old value of signal */ FP f; /* searching function */ char *s; int c; /* note: the pattern may have been a cscope argument */ if (caseless == YES) { for (s = pattern; *s != '\0'; ++s) { *s = tolower(*s); } } /* open the references found file for writing */ if (writerefsfound() == NO) { return (NO); } /* find the pattern - stop on an interrupt */ if (linemode == NO) { putmsg("Searching"); } initprogress(); if (setjmp(env) == 0) { savesig = signal(SIGINT, jumpback); f = fields[field].findfcn; if (fields[field].patterntype == EGREP) { egreperror = (*f)(pattern); } else { if ((nonglobalrefs = fopen(temp2, "w")) == NULL) { cannotopen(temp2); return (NO); } if ((rc = findinit()) == NOERROR) { (void) dbseek(0L); /* goto the first block */ (*f)(); findcleanup(); /* append the non-global references */ (void) freopen(temp2, "r", nonglobalrefs); while ((c = getc(nonglobalrefs)) != EOF) { (void) putc(c, refsfound); } } (void) fclose(nonglobalrefs); } } (void) signal(SIGINT, savesig); /* reopen the references found file for reading */ (void) freopen(temp1, "r", refsfound); nextline = 1; totallines = 0; /* see if it is empty */ if ((c = getc(refsfound)) == EOF) { if (egreperror != NULL) { (void) sprintf(lastmsg, "Egrep %s in this pattern: %s", egreperror, pattern); } else if (rc == NOTSYMBOL) { (void) sprintf(lastmsg, "This is not a C symbol: %s", pattern); } else if (rc == REGCMPERROR) { (void) sprintf(lastmsg, "Error in this regcmp(3C) regular expression: %s", pattern); } else { (void) sprintf(lastmsg, "Could not find the %s: %s", fields[field].text2, pattern); } return (NO); } /* put back the character read */ (void) ungetc(c, refsfound); countrefs(); return (YES); } /* open the references found file for writing */ BOOL writerefsfound(void) { if (refsfound == NULL) { if ((refsfound = fopen(temp1, "w")) == NULL) { cannotopen(temp1); return (NO); } } else if (freopen(temp1, "w", refsfound) == NULL) { putmsg("Cannot reopen temporary file"); return (NO); } return (YES); } /* count the references found */ void countrefs(void) { char *subsystem; /* OGS subsystem name */ char *book; /* OGS book name */ char file[PATHLEN + 1]; /* file name */ char function[PATLEN + 1]; /* function name */ char linenum[NUMLEN + 1]; /* line number */ int i; /* * count the references found and find the length of the file, * function, and line number display fields */ subsystemlen = 9; /* strlen("Subsystem") */ booklen = 4; /* strlen("Book") */ filelen = 4; /* strlen("File") */ fcnlen = 8; /* strlen("Function") */ numlen = 0; while ((i = fscanf(refsfound, "%250s%250s%6s %5000[^\n]", file, function, linenum, yytext)) != EOF) { if (i != 4 || !isgraph(*file) || !isgraph(*function) || !isdigit(*linenum)) { putmsg("File does not have expected format"); totallines = 0; return; } if ((i = strlen(pathcomponents(file, dispcomponents))) > filelen) { filelen = i; } if (ogs == YES) { ogsnames(file, &subsystem, &book); if ((i = strlen(subsystem)) > subsystemlen) { subsystemlen = i; } if ((i = strlen(book)) > booklen) { booklen = i; } } if ((i = strlen(function)) > fcnlen) { fcnlen = i; } if ((i = strlen(linenum)) > numlen) { numlen = i; } ++totallines; } rewind(refsfound); /* restrict the width of displayed columns */ i = (COLS - 5) / 3; if (ogs == YES) { i = (COLS - 7) / 5; } if (filelen > i && i > 4) { filelen = i; } if (subsystemlen > i && i > 9) { subsystemlen = i; } if (booklen > i && i > 4) { booklen = i; } if (fcnlen > i && i > 8) { fcnlen = i; } } /* print error message on system call failure */ void myperror(char *text) { char msg[MSGLEN + 1]; /* message */ (void) sprintf(msg, "%s: %s", text, strerror(errno)); putmsg(msg); } /* putmsg clears the message line and prints the message */ void putmsg(char *msg) { if (incurses == NO) { *msg = tolower(*msg); (void) fprintf(stderr, "cscope: %s\n", msg); } else { (void) move(MSGLINE, 0); (void) clrtoeol(); (void) addstr(msg); (void) refresh(); } (void) strncpy(lastmsg, msg, sizeof (lastmsg) - 1); } /* clearmsg2 clears the second message line */ void clearmsg2(void) { if (incurses == YES) { (void) move(MSGLINE + 1, 0); (void) clrtoeol(); } } /* putmsg2 clears the second message line and prints the message */ void putmsg2(char *msg) { if (incurses == NO) { putmsg(msg); } else { clearmsg2(); (void) addstr(msg); (void) refresh(); } } /* position the references found file at the specified line */ void seekline(int line) { int c; /* verify that there is a references found file */ if (refsfound == NULL) { return; } /* go to the beginning of the file */ rewind(refsfound); /* find the requested line */ nextline = 1; while (nextline < line && (c = getc(refsfound)) != EOF) { if (c == '\n') { nextline++; } } } /* get the OGS subsystem and book names */ void ogsnames(char *file, char **subsystem, char **book) { static char buf[PATHLEN + 1]; char *s, *slash; *subsystem = *book = ""; (void) strcpy(buf, file); s = buf; if (*s == '/') { ++s; } while ((slash = strchr(s, '/')) != NULL) { *slash = '\0'; if ((int)strlen(s) >= 3 && strncmp(slash - 3, ".ss", 3) == 0) { *subsystem = s; s = slash + 1; if ((slash = strchr(s, '/')) != NULL) { *book = s; *slash = '\0'; } break; } s = slash + 1; } } /* get the requested path components */ char * pathcomponents(char *path, int components) { int i; char *s; s = path + strlen(path) - 1; for (i = 0; i < components; ++i) { while (s > path && *--s != '/') { ; } } if (s > path && *s == '/') { ++s; } return (s); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 1999 by Sun Microsystems, Inc. * All rights reserved. */ /* * cscope - interactive C symbol cross-reference * * file editing functions */ #include /* KEY_BREAK and refresh */ #include #include #include "global.h" /* edit this displayed reference */ void editref(int i) { char file[PATHLEN + 1]; /* file name */ char linenum[NUMLEN + 1]; /* line number */ /* verify that there is a references found file */ if (refsfound == NULL) { return; } /* get the selected line */ seekline(i + topline); /* get the file name and line number */ if (fscanf(refsfound, "%s%*s%s", file, linenum) == 2) { edit(file, linenum); /* edit it */ } seekline(topline); /* restore the line pointer */ } /* edit all references */ void editall(void) { char file[PATHLEN + 1]; /* file name */ char linenum[NUMLEN + 1]; /* line number */ int c; /* verify that there is a references found file */ if (refsfound == NULL) { return; } /* get the first line */ seekline(1); /* get each file name and line number */ while (fscanf(refsfound, "%s%*s%s%*[^\n]", file, linenum) == 2) { edit(file, linenum); /* edit it */ if (editallprompt == YES) { putmsg("Type ^D to stop editing all lines, " "or any other character to continue: "); if ((c = mygetch()) == EOF || c == ctrl('D') || c == ctrl('Z') || c == KEY_BREAK) { /* needed for interrupt on first time */ (void) refresh(); break; } } } seekline(topline); } /* call the editor */ void edit(char *file, char *linenum) { char msg[MSGLEN + 1]; /* message */ char plusnum[NUMLEN + 2]; /* line number option */ char *s; (void) sprintf(msg, "%s +%s %s", editor, linenum, file); putmsg(msg); (void) sprintf(plusnum, "+%s", linenum); /* if this is the more or page commands */ if (strcmp(s = basename(editor), "more") == 0 || strcmp(s, "page") == 0) { /* * get it to pause after displaying a file smaller * than the screen length */ (void) execute(editor, editor, plusnum, file, "/dev/null", (char *)NULL); } else { (void) execute(editor, editor, plusnum, file, (char *)NULL); } } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * cscope - interactive C symbol cross-reference * * process execution functions */ #include "global.h" #include #include #include #include #include #include #include #define getdtablesize() _NFILE #define MAXARGS 100 /* maximum number of arguments to executed command */ pid_t childpid; /* child's process ID */ static SIGTYPE (*oldsigquit)(); /* old value of quit signal */ static SIGTYPE (*oldsigtstp)(); /* old value of terminal stop signal */ static pid_t myfork(void); static int join(pid_t p); /* * execute forks and executes a program or shell script, waits for it to * finish, and returns its exit code. */ /*VARARGS0*/ int execute(char *path, ...) { va_list ap; char *args[MAXARGS + 1]; int exitcode; int i; char msg[MSGLEN + 1]; pid_t p; /* fork and exec the program or shell script */ exitcurses(); if ((p = myfork()) == 0) { /* close all files except stdin, stdout, and stderr */ for (i = 3; i < getdtablesize() && close(i) == 0; ++i) { ; } /* execute the program or shell script */ va_start(ap, path); for (i = 0; i < MAXARGS && (args[i] = va_arg(ap, char *)) != NULL; ++i) { } va_end(ap); args[i] = NULL; /* in case MAXARGS reached */ args[0] = basename(args[0]); (void) execvp(path, args); /* returns only on failure */ (void) sprintf(msg, "\ncscope: cannot execute %s", path); (void) perror(msg); /* display the reason */ askforreturn(); /* wait until the user sees the message */ exit(1); /* exit the child */ } else { exitcode = join(p); /* parent */ } if (noacttimeout) { (void) fprintf(stderr, "cscope: no activity time out--exiting\n"); myexit(SIGALRM); } entercurses(); return (exitcode); } /* myfork acts like fork but also handles signals */ static pid_t myfork(void) { pid_t p; /* process number */ oldsigtstp = signal(SIGTSTP, SIG_DFL); /* the parent ignores the interrupt and quit signals */ if ((p = fork()) > 0) { childpid = p; oldsigquit = signal(SIGQUIT, SIG_IGN); } /* so they can be used to stop the child */ else if (p == 0) { (void) signal(SIGINT, SIG_DFL); (void) signal(SIGQUIT, SIG_DFL); (void) signal(SIGHUP, SIG_DFL); /* restore hangup default */ } /* check for fork failure */ if (p == -1) { myperror("Cannot fork"); } return (p); } /* join is the compliment of fork */ static int join(pid_t p) { int status; pid_t w; /* wait for the correct child to exit */ do { w = wait(&status); } while (p != -1 && w != p); childpid = 0; /* restore signal handling */ (void) signal(SIGQUIT, oldsigquit); (void) signal(SIGTSTP, oldsigtstp); /* return the child's exit code */ return (status >> 8); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * cscope - interactive C symbol or text cross-reference * * searching functions */ #include #include #include #include "global.h" #include "vp.h" /* * most of these functions have been optimized so their innermost loops have * only one test for the desired character by putting the char and * an end-of-block marker (\0) at the end of the disk block buffer. * When the inner loop exits on the char, an outer loop will see if * the char is followed by a \0. If so, it will read the next block * and restart the inner loop. */ char block[BUFSIZ + 2]; /* leave room for end-of-block mark */ int blocklen; /* length of disk block read */ char blockmark; /* mark character to be searched for */ long blocknumber; /* block number */ char *blockp; /* pointer to current char in block */ char lastfilepath[PATHLEN + 1]; /* last file that full path was */ /* computed for */ static char cpattern[PATLEN + 1]; /* compressed pattern */ static long lastfcnoffset; /* last function name offset */ static long postingsfound; /* retrieved number of postings */ static char *regexp; /* regular expression */ static POSTING *postingp; /* retrieved posting set pointer */ static long searchcount; /* count of files searched */ static long starttime; /* start time for progress messages */ static POSTING *getposting(void); static void putsource(FILE *output); static void putref(char *file, char *function); static void findcalledbysub(char *file); static void findterm(void); static void fileprogress(void); static void putpostingref(POSTING *p); static void putline(FILE *output); static char *strtolower(char *s); static char *filepath(char *file); /* find the symbol in the cross-reference */ void findsymbol(void) { char file[PATHLEN + 1]; /* source file name */ char function[PATLEN + 1]; /* function name */ char macro[PATLEN + 1]; /* macro name */ char symbol[PATLEN + 1]; /* symbol name */ char *cp; char c; char *s; if (invertedindex == YES) { long lastline = 0; POSTING *p; findterm(); while ((p = getposting()) != NULL) { if (p->type != INCLUDE && p->lineoffset != lastline) { putpostingref(p); lastline = p->lineoffset; } } return; } (void) scanpast('\t'); /* find the end of the header */ skiprefchar(); /* skip the file marker */ getstring(file); /* save the file name */ *function = '\0'; /* a macro can be inside a function, but not vice versa */ *macro = '\0'; /* find the next symbol */ /* note: this code was expanded in-line for speed */ /* while (scanpast('\n') != NULL) { */ /* other macros were replaced by code using cp instead of blockp */ cp = blockp; for (;;) { setmark('\n'); do { /* innermost loop optimized to only one test */ while (*cp != '\n') { ++cp; } } while (*(cp + 1) == '\0' && (cp = readblock()) != NULL); /* skip the found character */ if (cp != NULL && *(++cp + 1) == '\0') { cp = readblock(); } if (cp == NULL) { break; } /* look for a source file or function name */ if (*cp == '\t') { blockp = cp; switch (getrefchar()) { case NEWFILE: /* file name */ /* save the name */ skiprefchar(); getstring(file); /* check for the end of the symbols */ if (*file == '\0') { return; } fileprogress(); /* FALLTHROUGH */ case FCNEND: /* function end */ *function = '\0'; goto notmatched; /* don't match name */ case FCNDEF: /* function name */ s = function; break; case DEFINE: /* could be a macro */ if (fileversion >= 10) { s = macro; } else { s = symbol; } break; case DEFINEEND: *macro = '\0'; goto notmatched; /* don't match name */ case INCLUDE: /* #include file */ goto notmatched; /* don't match name */ default: /* other symbol */ s = symbol; } /* save the name */ skiprefchar(); getstring(s); /* see if this is a regular expression pattern */ if (regexp != NULL) { if (caseless == YES) { s = strtolower(s); } if (*s != '\0' && regex(regexp, s) != NULL) { goto matched; } } /* match the symbol to the text pattern */ else if (strequal(pattern, s)) { goto matched; } goto notmatched; } /* if this is a regular expression pattern */ if (regexp != NULL) { c = *cp; if (c & 0200) { /* digraph char? */ c = dichar1[(c & 0177) / 8]; } /* if this is a symbol */ if (isalpha(c) || c == '_') { blockp = cp; getstring(symbol); s = symbol; if (caseless == YES) { s = strtolower(s); } /* match the symbol to the regular expression */ if (regex(regexp, s) != NULL) { goto matched; } goto notmatched; } } /* match the character to the text pattern */ else if (*cp == cpattern[0]) { blockp = cp; /* match the rest of the symbol to the text pattern */ if (matchrest()) { s = NULL; matched: /* * output the file, calling function or macro, * and source line */ if (*macro != '\0' && s != macro) { putref(file, macro); } else if (s != function) { putref(file, function); } else { putref(file, ""); } if (blockp == NULL) { return; } } notmatched: cp = blockp; } } blockp = cp; } /* find the function definition or #define */ void finddef(void) { char file[PATHLEN + 1]; /* source file name */ char function[PATLEN + 1]; /* function name */ char macro[PATLEN + 1]; /* macro name */ char symbol[PATLEN + 1]; /* symbol name */ char *s; if (invertedindex == YES) { POSTING *p; findterm(); while ((p = getposting()) != NULL) { switch (p->type) { case DEFINE: /* could be a macro */ case FCNDEF: case CLASSDEF: case ENUMDEF: case MEMBERDEF: case STRUCTDEF: case TYPEDEF: case UNIONDEF: case GLOBALDEF: /* other global definition */ case LOCALDEF: /* other local definition */ case PARAMETER: putpostingref(p); } } return; } /* find the next file name or definition */ *function = '\0'; /* a macro can be inside a function, but not vice versa */ *macro = '\0'; while (scanpast('\t') != NULL) { switch (*blockp) { case NEWFILE: skiprefchar(); /* save file name */ getstring(file); if (*file == '\0') { /* if end of symbols */ return; } fileprogress(); /* FALLTHROUGH */ case FCNEND: /* function end */ *function = '\0'; break; case FCNDEF: /* function name */ s = function; goto def; case DEFINE: /* could be a macro */ if (fileversion >= 10) { s = macro; } else { s = symbol; } goto def; case DEFINEEND: *macro = '\0'; break; case CLASSDEF: case ENUMDEF: case MEMBERDEF: case STRUCTDEF: case TYPEDEF: case UNIONDEF: case GLOBALDEF: /* other global definition */ case LOCALDEF: /* other local definition */ case PARAMETER: s = symbol; def: /* save the name */ skiprefchar(); getstring(s); /* see if this is a regular expression pattern */ if (regexp != NULL) { if (caseless == YES) { s = strtolower(s); } if (*s != '\0' && regex(regexp, s) != NULL) { goto matched; } } else if (strequal(pattern, s)) { /* match the symbol to the text pattern */ matched: /* * output the file, calling function or macro, * and source line */ if (*macro != '\0' && s != macro) { putref(file, macro); } else if (s != function) { putref(file, function); } else { putref(file, ""); } } } } } /* find all function definitions (used by samuel only) */ void findallfcns(void) { char file[PATHLEN + 1]; /* source file name */ char function[PATLEN + 1]; /* function name */ /* find the next file name or definition */ while (scanpast('\t') != NULL) { switch (*blockp) { case NEWFILE: skiprefchar(); /* save file name */ getstring(file); if (*file == '\0') { /* if end of symbols */ return; } fileprogress(); break; case FCNDEF: case CLASSDEF: skiprefchar(); /* save function name */ getstring(function); /* output the file, function and source line */ putref(file, function); break; } } } /* find the functions called by this function */ void findcalledby(void) { char file[PATHLEN + 1]; /* source file name */ if (invertedindex == YES) { POSTING *p; findterm(); while ((p = getposting()) != NULL) { switch (p->type) { case DEFINE: /* could be a macro */ case FCNDEF: if (dbseek(p->lineoffset) != -1 && scanpast('\t') != NULL) { /* skip def */ findcalledbysub(srcfiles[p->fileindex]); } } } return; } /* find the function definition(s) */ while (scanpast('\t') != NULL) { switch (*blockp) { case NEWFILE: skiprefchar(); /* save file name */ getstring(file); if (*file == '\0') { /* if end of symbols */ return; } fileprogress(); break; case DEFINE: /* could be a macro */ if (fileversion < 10) { break; } /* FALLTHROUGH */ case FCNDEF: skiprefchar(); /* match name to pattern */ if (match()) { findcalledbysub(file); } break; } } } static void findcalledbysub(char *file) { /* find the next function call or the end of this function */ while (scanpast('\t') != NULL) { switch (*blockp) { case DEFINE: /* #define inside a function */ if (fileversion >= 10) { /* skip it */ while (scanpast('\t') != NULL && *blockp != DEFINEEND) ; } break; case FCNCALL: /* function call */ /* output the file name */ (void) fprintf(refsfound, "%s ", filepath(file)); /* output the function name */ skiprefchar(); putline(refsfound); (void) putc(' ', refsfound); /* output the source line */ putsource(refsfound); break; case DEFINEEND: /* #define end */ case FCNEND: /* function end */ case FCNDEF: /* function end (pre 9.5) */ case NEWFILE: /* file end */ return; } } } /* find the functions calling this function */ void findcalling(void) { char file[PATHLEN + 1]; /* source file name */ char function[PATLEN + 1]; /* function name */ char macro[PATLEN + 1]; /* macro name */ if (invertedindex == YES) { POSTING *p; findterm(); while ((p = getposting()) != NULL) { if (p->type == FCNCALL) { putpostingref(p); } } return; } /* find the next file name or function definition */ /* a macro can be inside a function, but not vice versa */ *macro = '\0'; while (scanpast('\t') != NULL) { switch (*blockp) { case NEWFILE: /* save file name */ skiprefchar(); getstring(file); if (*file == '\0') { /* if end of symbols */ return; } fileprogress(); /* FALLTHROUGH */ case FCNEND: /* function end */ *function = '\0'; break; case DEFINE: /* could be a macro */ if (fileversion >= 10) { skiprefchar(); getstring(macro); } break; case DEFINEEND: *macro = '\0'; break; case FCNDEF: /* save calling function name */ skiprefchar(); getstring(function); break; case FCNCALL: /* match function called to pattern */ skiprefchar(); if (match()) { /* output the file, calling function or */ /* macro, and source */ if (*macro != '\0') { putref(file, macro); } else { putref(file, function); } } } } } /* find direct assignment to, and increment and decrement of, this variable */ void findassignments(void) { char file[PATHLEN + 1]; /* source file name */ char function[PATLEN + 1]; /* function name */ char macro[PATLEN + 1]; /* macro name */ if (fileversion < 13) { putmsg("Database built with cscope version < 13 does not " "have assignment information"); (void) sleep(3); return; } #if CTRACE ctroff(); #endif if (invertedindex == YES) { POSTING *p; findterm(); while ((p = getposting()) != NULL) { switch (p->type) { case ASSIGNMENT: case GLOBALDEF: /* can have initializer */ case LOCALDEF: /* can have initializer */ case PARAMETER: /* initial value */ putpostingref(p); } } return; } /* find the next file name or function definition */ /* a macro can be inside a function, but not vice versa */ *macro = '\0'; while (scanpast('\t') != NULL) { switch (*blockp) { case NEWFILE: /* save file name */ skiprefchar(); getstring(file); if (*file == '\0') { /* if end of symbols */ return; } fileprogress(); /* FALLTHROUGH */ case FCNEND: /* function end */ *function = '\0'; break; case DEFINE: /* could be a macro */ if (fileversion >= 10) { skiprefchar(); getstring(macro); } break; case DEFINEEND: *macro = '\0'; break; case FCNDEF: /* save calling function name */ skiprefchar(); getstring(function); break; case ASSIGNMENT: /* match assignment to pattern */ case GLOBALDEF: /* can have initializer */ case LOCALDEF: /* can have initializer */ case PARAMETER: /* initial value */ skiprefchar(); if (match()) { /* output the file, calling function or */ /* macro, and source */ if (*macro != '\0') { putref(file, macro); } else { putref(file, function); } } } } } /* find the grep pattern in the source files */ char * findgreppat(void) { char egreppat[2 * PATLEN]; char *cp, *pp; /* translate egrep special characters in the regular expression */ cp = egreppat; for (pp = pattern; *pp != '\0'; ++pp) { if (strchr("+?|()", *pp) != NULL) { *cp++ = '\\'; } *cp++ = *pp; } *cp = '\0'; /* search the source files */ return (findegreppat(egreppat)); } /* find this regular expression in the source files */ char * findegreppat(char *egreppat) { int i; char *egreperror; char msg[MSGLEN + 1]; /* compile the pattern */ if ((egreperror = egrepinit(egreppat)) == NULL) { /* search the files */ for (i = 0; i < nsrcfiles; ++i) { char *file = filepath(srcfiles[i]); fileprogress(); if (egrep(file, refsfound, "%s %ld ") < 0) { (void) sprintf(msg, "Cannot open file %s", file); putmsg2(msg); } } } return (egreperror); } /* find matching file names */ void findfile(void) { int i; char *s; for (i = 0; i < nsrcfiles; ++i) { s = srcfiles[i]; if (caseless == YES) { s = strtolower(s); } if (regex(regexp, s) != NULL) { (void) fprintf(refsfound, "%s 1 \n", filepath(srcfiles[i])); } } } /* find files #including this file */ void findinclude(void) { char file[PATHLEN + 1]; /* source file name */ if (invertedindex == YES) { POSTING *p; findterm(); while ((p = getposting()) != NULL) { if (p->type == INCLUDE) { putpostingref(p); } } return; } /* find the next file name or function definition */ while (scanpast('\t') != NULL) { switch (*blockp) { case NEWFILE: /* save file name */ skiprefchar(); getstring(file); if (*file == '\0') { /* if end of symbols */ return; } fileprogress(); break; case INCLUDE: /* match function called to pattern */ skiprefchar(); /* skip global or local #include marker */ skiprefchar(); if (match()) { /* output the file and source line */ putref(file, ""); } } } } /* initialize */ FINDINIT findinit(void) { char buf[PATLEN + 3]; BOOL isregexp = NO; int i; char *s; unsigned c; /* remove trailing white space */ for (s = pattern + strlen(pattern) - 1; isspace(*s); --s) { *s = '\0'; } /* allow a partial match for a file name */ if (field == FILENAME || field == INCLUDES) { /* allow types.h to match #include */ if (invertedindex == YES && field == INCLUDES && strncmp(pattern, ".*", 2) != 0) { (void) sprintf(pattern, ".*%s", strcpy(buf, pattern)); } if ((regexp = regcmp(pattern, (char *)NULL)) == NULL) { return (REGCMPERROR); } return (NOERROR); } /* see if the pattern is a regular expression */ if (strpbrk(pattern, "^.[{*+$") != NULL) { isregexp = YES; } else { /* check for a valid C symbol */ s = pattern; if (!isalpha(*s) && *s != '_') { return (NOTSYMBOL); } while (*++s != '\0') { if (!isalnum(*s) && *s != '_') { return (NOTSYMBOL); } } /* * look for use of the -T option (truncate symbol to 8 * characters) on a database not built with -T */ if (truncatesyms == YES && isuptodate == YES && dbtruncated == NO && s - pattern >= 8) { (void) strcpy(pattern + 8, ".*"); isregexp = YES; } } /* if this is a regular expression or letter case is to be ignored */ /* or there is an inverted index */ if (isregexp == YES || caseless == YES || invertedindex == YES) { /* remove a leading ^ */ s = pattern; if (*s == '^') { (void) strcpy(newpat, s + 1); (void) strcpy(s, newpat); } /* remove a trailing $ */ i = strlen(s) - 1; if (s[i] == '$') { s[i] = '\0'; } /* if requested, try to truncate a C symbol pattern */ if (truncatesyms == YES && strpbrk(s, "[{*+") == NULL) { s[8] = '\0'; } /* must be an exact match */ /* * note: regcmp doesn't recognize ^*keypad$ as an syntax error * unless it is given as a single arg */ (void) sprintf(buf, "^%s$", s); if ((regexp = regcmp(buf, (char *)NULL)) == NULL) { return (REGCMPERROR); } } else { /* if requested, truncate a C symbol pattern */ if (truncatesyms == YES && field <= CALLING) { pattern[8] = '\0'; } /* compress the string pattern for matching */ s = cpattern; for (i = 0; (c = pattern[i]) != '\0'; ++i) { if (dicode1[c] && dicode2[(unsigned)pattern[i + 1]]) { c = (0200 - 2) + dicode1[c] + dicode2[(unsigned)pattern[i + 1]]; ++i; } *s++ = (char)c; } *s = '\0'; } return (NOERROR); } void findcleanup(void) { /* discard any regular expression */ if (regexp != NULL) { free(regexp); regexp = NULL; } } /* find this term, which can be a regular expression */ static void findterm(void) { char *s; int len; char prefix[PATLEN + 1]; char term[PATLEN + 1]; npostings = 0; /* will be non-zero after database built */ lastfcnoffset = 0; /* clear the last function name found */ boolclear(); /* clear the posting set */ /* get the string prefix (if any) of the regular expression */ (void) strcpy(prefix, pattern); if ((s = strpbrk(prefix, ".[{*+")) != NULL) { *s = '\0'; } /* if letter case is to be ignored */ if (caseless == YES) { /* * convert the prefix to upper case because it is lexically * less than lower case */ s = prefix; while (*s != '\0') { *s = toupper(*s); ++s; } } /* find the term lexically >= the prefix */ (void) invfind(&invcontrol, prefix); if (caseless == YES) { /* restore lower case */ (void) strcpy(prefix, strtolower(prefix)); } /* * a null prefix matches the null term in the inverted index, * so move to the first real term */ if (*prefix == '\0') { (void) invforward(&invcontrol); } len = strlen(prefix); do { (void) invterm(&invcontrol, term); /* get the term */ s = term; if (caseless == YES) { s = strtolower(s); /* make it lower case */ } /* if it matches */ if (regex(regexp, s) != NULL) { /* add it's postings to the set */ if ((postingp = boolfile(&invcontrol, &npostings, OR)) == NULL) { break; } } else if (len > 0) { /* if there is a prefix */ /* * if ignoring letter case and the term is out of the * range of possible matches */ if (caseless == YES) { if (strncmp(term, prefix, len) > 0) { break; /* stop searching */ } } /* if using letter case and the prefix doesn't match */ else if (strncmp(term, prefix, len) != 0) { break; /* stop searching */ } } /* display progress about every three seconds */ if (++searchcount % 50 == 0) { progress("%ld of %ld symbols matched", searchcount, totalterms); } } while (invforward(&invcontrol)); /* while didn't wrap around */ /* initialize the progress message for retrieving the references */ initprogress(); postingsfound = npostings; } /* display the file search progress about every three seconds */ static void fileprogress(void) { if (++searchcount % 10 == 0) { progress("%ld of %ld files searched", searchcount, (long)nsrcfiles); } } /* initialize the progress message */ void initprogress(void) { searchcount = 0; starttime = time((long *)NULL); } /* display the progress every three seconds */ void progress(char *format, long n1, long n2) { char msg[MSGLEN + 1]; long now; /* print after 2 seconds so the average is nearer 3 seconds */ if (linemode == NO && (now = time((long *)NULL)) - starttime >= 2) { starttime = now; (void) sprintf(msg, format, n1, n2); putmsg(msg); } } /* match the pattern to the string */ BOOL match(void) { char string[PATLEN + 1]; char *s; /* see if this is a regular expression pattern */ if (regexp != NULL) { getstring(string); if (*string == '\0') { return (NO); } s = string; if (caseless == YES) { s = strtolower(s); } return (regex(regexp, s) ? YES : NO); } /* it is a string pattern */ return ((BOOL)(*blockp == cpattern[0] && matchrest())); } /* match the rest of the pattern to the name */ BOOL matchrest(void) { int i = 1; skiprefchar(); do { while (*blockp == cpattern[i]) { ++blockp; ++i; } } while (*(blockp + 1) == '\0' && readblock() != NULL); if (*blockp == '\n' && cpattern[i] == '\0') { return (YES); } return (NO); } /* get the next posting for this term */ static POSTING * getposting(void) { if (npostings-- <= 0) { return (NULL); } /* display progress about every three seconds */ if (++searchcount % 100 == 0) { progress("%ld of %ld possible references retrieved", searchcount, postingsfound); } return (postingp++); } /* put the posting reference into the file */ static void putpostingref(POSTING *p) { static char function[PATLEN + 1]; /* function name */ if (p->fcnoffset == 0) { *function = '\0'; } else if (p->fcnoffset != lastfcnoffset) { if (dbseek(p->fcnoffset) != -1) { getstring(function); lastfcnoffset = p->fcnoffset; } } if (dbseek(p->lineoffset) != -1) { putref(srcfiles[p->fileindex], function); } } /* put the reference into the file */ static void putref(char *file, char *function) { FILE *output; /* put global references first */ if (*function == '\0') { function = ""; output = refsfound; } else { output = nonglobalrefs; } if (fprintf(output, "%s %s ", filepath(file), function) == EOF) { cannotwrite(temp1); /* NOTREACHED */ } putsource(output); } /* put the source line into the file */ static void putsource(FILE *output) { char *cp, nextc = '\0'; if (fileversion <= 5) { (void) scanpast(' '); putline(output); (void) putc('\n', output); return; } /* scan back to the beginning of the source line */ cp = blockp; while (*cp != '\n' || nextc != '\n') { nextc = *cp; if (--cp < block) { /* read the previous block */ (void) dbseek((blocknumber - 1) * BUFSIZ); cp = &block[BUFSIZ - 1]; } } /* there must be a double newline followed by a line number */ blockp = cp; setmark(' '); /* so getrefchar doesn't skip the last block char */ if (*blockp != '\n' || getrefchar() != '\n' || !isdigit(getrefchar()) && fileversion >= 12) { putmsg("Internal error: cannot get source line from database"); myexit(1); } /* until a double newline is found */ do { /* skip a symbol type */ if (*blockp == '\t') { skiprefchar(); skiprefchar(); } /* output a piece of the source line */ putline(output); } while (blockp != NULL && getrefchar() != '\n'); (void) putc('\n', output); } /* put the rest of the cross-reference line into the file */ static void putline(FILE *output) { char *cp; unsigned c; setmark('\n'); cp = blockp; do { while ((c = *cp) != '\n') { /* check for a compressed digraph */ if (c & 0200) { c &= 0177; (void) putc(dichar1[c / 8], output); (void) putc(dichar2[c & 7], output); } else if (c < ' ') { /* a compressed keyword */ (void) fputs(keyword[c].text, output); if (keyword[c].delim != '\0') { (void) putc(' ', output); } if (keyword[c].delim == '(') { (void) putc('(', output); } } else { (void) putc((int)c, output); } ++cp; } } while (*(cp + 1) == '\0' && (cp = readblock()) != NULL); blockp = cp; } /* put the rest of the cross-reference line into the string */ void getstring(char *s) { char *cp; unsigned c; setmark('\n'); cp = blockp; do { while ((c = *cp) != '\n') { if (c & 0200) { c &= 0177; *s++ = dichar1[c / 8]; *s++ = dichar2[c & 7]; } else { *s++ = (char)c; } ++cp; } } while (*(cp + 1) == '\0' && (cp = readblock()) != NULL); blockp = cp; *s = '\0'; } /* scan past the next occurence of this character in the cross-reference */ char * scanpast(int c) { char *cp; setmark(c); cp = blockp; do { /* innermost loop optimized to only one test */ while (*cp != c) { ++cp; } } while (*(cp + 1) == '\0' && (cp = readblock()) != NULL); blockp = cp; if (cp != NULL) { skiprefchar(); /* skip the found character */ } return (blockp); } /* read a block of the cross-reference */ char * readblock(void) { /* read the next block */ blocklen = read(symrefs, block, BUFSIZ); blockp = block; /* add the search character and end-of-block mark */ block[blocklen] = blockmark; block[blocklen + 1] = '\0'; /* return NULL on end-of-file */ if (blocklen == 0) { blockp = NULL; } else { ++blocknumber; } return (blockp); } /* seek to the database offset */ long dbseek(long offset) { long n; int rc = 0; if ((n = offset / BUFSIZ) != blocknumber) { if ((rc = lseek(symrefs, n * BUFSIZ, 0)) == -1) { myperror("Lseek failed"); (void) sleep(3); return (rc); } (void) readblock(); blocknumber = n; } blockp = block + offset % BUFSIZ; return (rc); } /* convert the string to lower case */ static char * strtolower(char *s) { static char buf[PATLEN + 1]; char *lp = buf; while (*s != '\0') { /* * note: s in not incremented in this line because the BSD * compatibility tolower macro evaluates its argument twice */ *lp++ = tolower(*s); ++s; } *lp = '\0'; return (buf); } /* if needed, convert a relative path to a full path */ static char * filepath(char *file) { static char path[PATHLEN + 1]; int i; if (*file != '/') { /* if same file as last time, return the same path */ if (strequal(file, lastfilepath)) { return (path); } (void) strcpy(lastfilepath, file); /* if requested, prepend a path to a relative file path */ if (prependpath != NULL) { (void) sprintf(path, "%s/%s", prependpath, file); return (path); } /* * if the database was built with a view path, return a * full path so "cscope -d -f" does not have to be called * from the build directory with the same view path */ if (dbvpndirs > 1) { for (i = 0; i < dbvpndirs; i++) { (void) sprintf(path, "%s/%s", dbvpdirs[i], file); if (access(path, READ) != -1) { return (path); } } } (void) strcpy(path, file); /* for lastfilepath check */ } return (file); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * cscope - interactive C symbol cross-reference * * global type, data, and function definitions */ #include /* isalpha, isdigit, etc. */ #include /* SIGINT and SIGQUIT */ #include /* standard I/O package */ #include #include "constants.h" /* misc. constants */ #include "invlib.h" /* inverted index library */ #include "library.h" /* library function return values */ #include "mouse.h" /* mouse interface */ #define SIGTYPE void typedef enum { /* boolean data type */ NO, YES } BOOL; typedef enum { /* findinit return code */ NOERROR, NOTSYMBOL, REGCMPERROR } FINDINIT; typedef struct history { /* command history */ int field; char *text; struct history *previous; struct history *next; } HISTORY; typedef enum { /* keyword type */ DECL, /* type declaration */ FLOW, /* control flow (do, if, for, while, switch, etc.) */ MISC /* misc.: sizeof or table placeholder for compression */ } KEYWORD; /* digraph data for text compression */ extern char dichar1[]; /* 16 most frequent first chars */ extern char dichar2[]; /* 8 most frequent second chars */ /* using the above as first chars */ extern char dicode1[]; /* digraph first character code */ extern char dicode2[]; /* digraph second character code */ /* main.c global data */ extern char *editor, *home, *shell; /* environment variables */ extern BOOL compress; /* compress the characters in the crossref */ extern int cscopedepth; /* cscope invocation nesting depth */ extern char currentdir[]; /* current directory */ extern BOOL dbtruncated; /* database symbols are truncated to 8 chars */ extern char **dbvpdirs; /* directories (including current) in */ /* database view path */ extern int dbvpndirs; /* number of directories in database */ /* view path */ extern int dispcomponents; /* file path components to display */ extern BOOL editallprompt; /* prompt between editing files */ extern int fileargc; /* file argument count */ extern char **fileargv; /* file argument values */ extern int fileversion; /* cross-reference file version */ extern BOOL incurses; /* in curses */ extern INVCONTROL invcontrol; /* inverted file control structure */ extern BOOL invertedindex; /* the database has an inverted index */ extern BOOL isuptodate; /* consider the crossref up-to-date */ extern BOOL linemode; /* use line oriented user interface */ extern char *namefile; /* file of file names */ extern char *newreffile; /* new cross-reference file name */ extern FILE *newrefs; /* new cross-reference */ extern BOOL noacttimeout; /* no activity timeout occurred */ extern BOOL ogs; /* display OGS book and subsystem names */ extern FILE *postings; /* new inverted index postings */ extern char *prependpath; /* prepend path to file names */ extern BOOL returnrequired; /* RETURN required after selection number */ extern int symrefs; /* cross-reference file */ extern char temp1[]; /* temporary file name */ extern char temp2[]; /* temporary file name */ extern long totalterms; /* total inverted index terms */ extern BOOL truncatesyms; /* truncate symbols to 8 characters */ /* command.c global data */ extern BOOL caseless; /* ignore letter case when searching */ extern BOOL *change; /* change this line */ extern BOOL changing; /* changing text */ extern char newpat[]; /* new pattern */ extern char pattern[]; /* symbol or text pattern */ /* crossref.c global data */ extern long dboffset; /* new database offset */ extern BOOL errorsfound; /* prompt before clearing error messages */ extern long fileindex; /* source file name index */ extern long lineoffset; /* source line database offset */ extern long npostings; /* number of postings */ extern int symbols; /* number of symbols */ /* dir.c global data */ extern char **incdirs; /* #include directories */ extern char **srcdirs; /* source directories */ extern char **srcfiles; /* source files */ extern int nincdirs; /* number of #include directories */ extern int nsrcdirs; /* number of source directories */ extern int nsrcfiles; /* number of source files */ extern int msrcfiles; /* maximum number of source files */ /* display.c global data */ extern int *displine; /* screen line of displayed reference */ extern int disprefs; /* displayed references */ extern int field; /* input field */ extern unsigned fldcolumn; /* input field column */ extern int mdisprefs; /* maximum displayed references */ extern int selectlen; /* selection number field length */ extern int nextline; /* next line to be shown */ extern int topline; /* top line of page */ extern int bottomline; /* bottom line of page */ extern int totallines; /* total reference lines */ extern FILE *refsfound; /* references found file */ extern FILE *nonglobalrefs; /* non-global references file */ /* exec.c global data */ extern pid_t childpid; /* child's process ID */ /* find.c global data */ extern char block[]; /* cross-reference file block */ extern int blocklen; /* length of disk block read */ extern char blockmark; /* mark character to be searched for */ extern long blocknumber; /* block number */ extern char *blockp; /* pointer to current character in block */ extern char lastfilepath[]; /* last file that full path was computed for */ /* lookup.c global data */ extern struct keystruct { char *text; char delim; KEYWORD type; struct keystruct *next; } keyword[]; /* scanner.l global data */ extern int first; /* buffer index for first char of symbol */ extern int last; /* buffer index for last char of symbol */ extern int lineno; /* symbol line number */ extern FILE *yyin; /* input file descriptor */ extern int yyleng; /* input line length */ extern int yylineno; /* input line number */ #if hpux extern unsigned char yytext[]; /* input line text */ #else extern char yytext[]; /* input line text */ #endif /* vpinit.c global data */ extern char *argv0; /* command name */ /* cscope functions called from more than one function or between files */ /* cgrep.c */ void egrepcaseless(int i); char *egrepinit(char *expression); int egrep(char *f, FILE *o, char *fo); /* command.c */ BOOL command(int commandc); void clearprompt(void); BOOL readrefs(char *filename); BOOL changestring(void); void mark(int i); /* crossref.c */ void crossref(char *srcfile); void savesymbol(int token); void putfilename(char *srcfile); void putposting(char *term, int type); void putstring(char *s); void warning(char *text); /* dir.c */ void sourcedir(char *dirlist); void includedir(char *dirlist); void makefilelist(void); void incfile(char *file, int type); BOOL infilelist(char *file); void addsrcfile(char *path); void freefilelist(void); /* display.c */ void dispinit(void); void display(void); void setfield(void); void atfield(void); void jumpback(int sig); BOOL search(void); BOOL writerefsfound(void); void countrefs(void); void myperror(char *text); void putmsg(char *msg); void clearmsg2(void); void putmsg2(char *msg); void seekline(int line); void ogsnames(char *file, char **subsystem, char **book); char *pathcomponents(char *path, int components); void strtoupper(char *s); /* edit.c */ void editref(int i); void editall(void); void edit(char *file, char *linenum); /* find.c */ void findsymbol(void); void finddef(void); void findallfcns(void); void findcalledby(void); void findcalling(void); void findassignments(void); char *findgreppat(void); char *findegreppat(char *egreppat); void findfile(void); void findinclude(void); FINDINIT findinit(void); void findcleanup(void); void initprogress(void); void progress(char *format, long n1, long n2); BOOL match(void); BOOL matchrest(void); void getstring(char *s); char *scanpast(int c); char *readblock(void); long dbseek(long offset); /* help.c */ void help(void); /* history.c */ void addcmd(int f, char *s); void resetcmd(void); HISTORY *currentcmd(void); HISTORY *prevcmd(void); HISTORY *nextcmd(void); /* input.c */ void catchint(int sig); int ungetch(int c); int mygetch(void); int getaline(char s[], size_t size, int firstchar, BOOL iscaseless); void askforchar(void); void askforreturn(void); void shellpath(char *out, int limit, char *in); /* lookup.c */ void initsymtab(void); struct keystruct *lookup(char *ident); int hash(char *s); /* main.c */ void rebuild(void); void entercurses(void); void exitcurses(void); void myexit(int sig) __NORETURN; void cannotopen(char *file); void cannotwrite(char *file); /* menu.c */ void initmenu(void); extern void initscanner(char *srcfile); extern int yylex(void); extern int execute(char *, ...); /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 1999 by Sun Microsystems, Inc. * All rights reserved. */ /* * cscope - interactive C symbol cross-reference * * display help */ #include "global.h" #include /* LINES */ #define MAXHELP 50 /* maximum number of help strings */ void help(void) { char **ep, *s, **tp, *text[MAXHELP]; int line; tp = text; if (changing == NO) { if (mouse) { *tp++ = "Point with the mouse and click button 1 to " "move to the desired input field,\n"; *tp++ = "type the pattern to search for, and then " "press the RETURN key. For the first 5\n"; *tp++ = "and last 2 input fields, the pattern can be " "a regcmp(3C) regular expression.\n"; *tp++ = "If the search is successful, you can edit " "the file containing a displayed line\n"; *tp++ = "by pointing with the mouse and clicking " "button 1.\n"; *tp++ = "\nYou can either use the button 2 menu or " "these command characters:\n\n"; } else { *tp++ = "Press the TAB key repeatedly to move to the " "desired input field, type the\n"; *tp++ = "pattern to search for, and then press the " "RETURN key. For the first 4 and\n"; *tp++ = "last 2 input fields, the pattern can be a " "regcmp(3C) regular expression.\n"; *tp++ = "If the search is successful, you can use " "these command characters:\n\n"; *tp++ = "1-9\tEdit the file containing the displayed " "line.\n"; } *tp++ = "space\tDisplay next lines.\n"; *tp++ = "+\tDisplay next lines.\n"; *tp++ = "-\tDisplay previous lines.\n"; *tp++ = "^E\tEdit all lines.\n"; *tp++ = ">\tWrite all lines to a file.\n"; *tp++ = ">>\tAppend all lines to a file.\n"; *tp++ = "<\tRead lines from a file.\n"; *tp++ = "^\tFilter all lines through a shell command.\n"; *tp++ = "|\tPipe all lines to a shell command.\n"; *tp++ = "\nAt any time you can use these command " "characters:\n\n"; if (!mouse) { *tp++ = "^P\tMove to the previous input field.\n"; } *tp++ = "^A\tSearch again with the last pattern typed.\n"; *tp++ = "^B\tRecall previous input field and search pattern.\n"; *tp++ = "^F\tRecall next input field and search pattern.\n"; *tp++ = "^C\tToggle ignore/use letter case when searching.\n"; *tp++ = "^R\tRebuild the symbol database.\n"; *tp++ = "!\tStart an interactive shell (type ^D to return " "to cscope).\n"; *tp++ = "^L\tRedraw the screen.\n"; *tp++ = "?\tDisplay this list of commands.\n"; *tp++ = "^D\tExit cscope.\n"; *tp++ = "\nNote: If the first character of the pattern you " "want to search for matches\n"; *tp++ = "a command, type a \\ character first.\n"; } else { if (mouse) { *tp++ = "Point with the mouse and click button 1 " "to mark or unmark the line to be\n"; *tp++ = "changed. You can also use the button 2 " "menu or these command characters:\n\n"; } else { *tp++ = "When changing text, you can use these " "command characters:\n\n"; *tp++ = "1-9\tMark or unmark the line to be changed.\n"; } *tp++ = "*\tMark or unmark all displayed lines to be " "changed.\n"; *tp++ = "space\tDisplay next lines.\n"; *tp++ = "+\tDisplay next lines.\n"; *tp++ = "-\tDisplay previous lines.\n"; *tp++ = "a\tMark or unmark all lines to be changed.\n"; *tp++ = "^D\tChange the marked lines and exit.\n"; *tp++ = "RETURN\tExit without changing the marked lines.\n"; *tp++ = "!\tStart an interactive shell (type ^D to return " "to cscope).\n"; *tp++ = "^L\tRedraw the screen.\n"; *tp++ = "?\tDisplay this list of commands.\n"; } /* print help, a screen at a time */ ep = tp; line = 0; for (tp = text; tp < ep; ) { if (line < LINES - 1) { for (s = *tp; *s != '\0'; ++s) { if (*s == '\n') { ++line; } } (void) addstr(*tp++); } else { (void) addstr("\n"); askforchar(); (void) clear(); line = 0; } } if (line) { (void) addstr("\n"); askforchar(); } } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 1999 by Sun Microsystems, Inc. * All rights reserved. */ /* * cscope - interactive C symbol or text cross-reference * * command history */ #include #include "global.h" HISTORY *head, *tail, *current; /* add a cmd to the history list */ void addcmd(int f, char *s) { HISTORY *h; h = (HISTORY *)mymalloc(sizeof (HISTORY)); if (tail) { tail->next = h; h->next = 0; h->previous = tail; tail = h; } else { head = tail = h; h->next = h->previous = 0; } h->field = f; h->text = stralloc(s); current = 0; } /* return previous history item */ HISTORY * prevcmd(void) { if (current) { if (current->previous) /* stay on first item */ return (current = current->previous); else return (current); } else if (tail) return (current = tail); else return (NULL); } /* return next history item */ HISTORY * nextcmd(void) { if (current) { if (current->next) /* stay on first item */ return (current = current->next); else return (current); } else return (NULL); } /* reset current to tail */ void resetcmd(void) { current = 0; } HISTORY * currentcmd(void) { return (current); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2015 Gary Mills * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * cscope - interactive C symbol cross-reference * * terminal input functions */ #include "global.h" #include /* KEY_BACKSPACE, KEY_BREAK, and KEY_ENTER */ #include /* jmp_buf */ static jmp_buf env; /* setjmp/longjmp buffer */ static int prevchar; /* previous, ungotten character */ /* catch the interrupt signal */ /*ARGSUSED*/ SIGTYPE catchint(int sig) { (void) signal(SIGINT, catchint); longjmp(env, 1); } /* unget a character */ int ungetch(int c) { prevchar = c; return (0); } /* get a character from the terminal */ int mygetch(void) { SIGTYPE (*volatile savesig)() = SIG_DFL; /* old value of signal */ int c; /* change an interrupt signal to a break key character */ if (setjmp(env) == 0) { savesig = signal(SIGINT, catchint); (void) refresh(); /* update the display */ reinitmouse(); /* curses can change the menu number */ if (prevchar) { c = prevchar; prevchar = 0; } else { c = getch(); /* get a character from the terminal */ } } else { /* longjmp to here from signal handler */ c = KEY_BREAK; } (void) signal(SIGINT, savesig); return (c); } /* get a line from the terminal in non-canonical mode */ int getaline(char s[], size_t size, int firstchar, BOOL iscaseless) { int c, i = 0; int j; /* if a character already has been typed */ if (firstchar != '\0') { if (iscaseless == YES) { firstchar = tolower(firstchar); } (void) addch((unsigned)firstchar); /* display it */ s[i++] = firstchar; /* save it */ } /* until the end of the line is reached */ while ((c = mygetch()) != '\r' && c != '\n' && c != KEY_ENTER && c != '\003' && c != KEY_BREAK) { if (c == erasechar() || c == '\b' || /* erase */ c == KEY_BACKSPACE) { if (i > 0) { (void) addstr("\b \b"); --i; } } else if (c == killchar()) { /* kill */ for (j = 0; j < i; ++j) { (void) addch('\b'); } for (j = 0; j < i; ++j) { (void) addch(' '); } for (j = 0; j < i; ++j) { (void) addch('\b'); } i = 0; } else if (isprint(c) || c == '\t') { /* printable */ if (iscaseless == YES) { c = tolower(c); } /* if it will fit on the line */ if (i < size) { (void) addch((unsigned)c); /* display it */ s[i++] = c; /* save it */ } } else if (c == ctrl('X')) { /* mouse */ (void) getmouseevent(); /* ignore it */ } else if (c == EOF) { /* end-of-file */ break; } /* return on an empty line to allow a command to be entered */ if (firstchar != '\0' && i == 0) { break; } } s[i] = '\0'; return (i); } /* ask user to enter a character after reading the message */ void askforchar(void) { (void) addstr("Type any character to continue: "); (void) mygetch(); } /* ask user to press the RETURN key after reading the message */ void askforreturn(void) { if (linemode == NO) { (void) fprintf(stderr, "Press the RETURN key to continue: "); (void) getchar(); } } /* expand the ~ and $ shell meta characters in a path */ void shellpath(char *out, int limit, char *in) { char *lastchar; char *s, *v; /* skip leading white space */ while (isspace(*in)) { ++in; } lastchar = out + limit - 1; /* * a tilde (~) by itself represents $HOME; followed by a name it * represents the $LOGDIR of that login name */ if (*in == '~') { *out++ = *in++; /* copy the ~ because it may not be expanded */ /* get the login name */ s = out; while (s < lastchar && *in != '/' && *in != '\0' && !isspace(*in)) { *s++ = *in++; } *s = '\0'; /* if the login name is null, then use $HOME */ if (*out == '\0') { v = getenv("HOME"); } else { /* get the home directory of the login name */ v = logdir(out); } /* copy the directory name */ if (v != NULL) { (void) strcpy(out - 1, v); out += strlen(v) - 1; } else { /* login not found so ~ must be part of the file name */ out += strlen(out); } } /* get the rest of the path */ while (out < lastchar && *in != '\0' && !isspace(*in)) { /* look for an environment variable */ if (*in == '$') { /* copy the $ because it may not be expanded */ *out++ = *in++; /* get the variable name */ s = out; while (s < lastchar && *in != '/' && *in != '\0' && !isspace(*in)) { *s++ = *in++; } *s = '\0'; /* get its value */ if ((v = getenv(out)) != NULL) { (void) strcpy(out - 1, v); out += strlen(v) - 1; } else { /* * var not found, so $ must be part of * the file name */ out += strlen(out); } } else { /* ordinary character */ *out++ = *in++; } } *out = '\0'; } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #if SHARE #include #include #define ERR -1 #endif #include "invlib.h" #include "library.h" #define DEBUG 0 /* debugging code and realloc messages */ #define BLOCKSIZE 2 * BUFSIZ /* logical block size */ #define LINEMAX 1000 /* sorted posting line max size */ #define POSTINC 10000 /* posting buffer size increment */ #define SEP ' ' /* sorted posting field separator */ #define SETINC 100 /* posting set size increment */ #define STATS 0 /* print statistics */ #define SUPERINC 10000 /* super index size increment */ #define TERMMAX 512 /* term max size */ #define VERSION 1 /* inverted index format version */ #define ZIPFSIZE 200 /* zipf curve size */ #define FREAD "r" /* fopen for reading */ #define FREADP "r+" /* fopen for update */ #define FWRITE "w" /* fopen truncate or create for writing */ #define FWRITEP "w+" /* fopen truncate or create for update */ extern char *argv0; /* command name (must be set in main function) */ int invbreak; #if STATS int showzipf; /* show postings per term distribution */ #endif static POSTING *item, *enditem, *item1 = NULL, *item2 = NULL; static unsigned setsize1, setsize2; static long numitems, totterm, zerolong; static char *indexfile, *postingfile; static FILE *outfile, *fpost; static unsigned supersize = SUPERINC, supintsize; static int numpost, numlogblk, amtused, nextpost, lastinblk, numinvitems; static POSTING *POST, *postptr; static unsigned long *SUPINT, *supint, nextsupfing; static char *SUPFING, *supfing; static char thisterm[TERMMAX]; static union { long invblk[BLOCKSIZE / sizeof (long)]; char chrblk[BLOCKSIZE]; } logicalblk; #if DEBUG || STATS static long totpost; #endif #if STATS static int zipf[ZIPFSIZE + 1]; #endif static void invcannotalloc(size_t n); static void invcannotopen(char *file); static void invcannotwrite(char *file); static int invnewterm(void); static int boolready(void); long invmake(char *invname, char *invpost, FILE *infile) { unsigned char *s; long num; int i; long fileindex; unsigned postsize = POSTINC * sizeof (POSTING); unsigned long *intptr; char line[LINEMAX]; long tlong; PARAM param; POSTING posting; #if STATS int j; unsigned maxtermlen = 0; #endif /* output file */ if ((outfile = vpfopen(invname, FWRITEP)) == NULL) { invcannotopen(invname); return (0); } indexfile = invname; (void) fseek(outfile, (long)BUFSIZ, 0); /* posting file */ if ((fpost = vpfopen(invpost, FWRITE)) == NULL) { invcannotopen(invpost); return (0); } postingfile = invpost; nextpost = 0; /* get space for the postings list */ if ((POST = (POSTING *)malloc(postsize)) == NULL) { invcannotalloc(postsize); return (0); } postptr = POST; /* get space for the superfinger (superindex) */ if ((SUPFING = malloc(supersize)) == NULL) { invcannotalloc(supersize); return (0); } supfing = SUPFING; supintsize = supersize / 40; /* also for the superfinger index */ if ((SUPINT = malloc(supintsize * sizeof (long))) == NULL) { invcannotalloc(supintsize * sizeof (long)); return (0); } supint = SUPINT; supint++; /* leave first term open for a count */ /* initialize using an empty term */ (void) strcpy(thisterm, ""); *supint++ = 0; *supfing++ = ' '; *supfing++ = '\0'; nextsupfing = 2; #if DEBUG || STATS totpost = 0L; #endif totterm = 0L; numpost = 1; /* * set up as though a block had come and gone, i.e., set up for * new block */ amtused = 16; /* leave no space - init 3 words + one for luck */ numinvitems = 0; numlogblk = 0; lastinblk = BLOCKSIZE; /* now loop as long as more to read (till eof) */ while (fgets(line, LINEMAX, infile) != NULL) { #if DEBUG || STATS ++totpost; #endif s = (unsigned char *) strchr(line, SEP); if (s == NULL) /* where did this line come from ??? */ continue; /* workaround: just skip it */ *s = '\0'; #if STATS if ((i = strlen(line)) > maxtermlen) { maxtermlen = i; } #endif #if DEBUG (void) printf("%ld: %s ", totpost, line); (void) fflush(stdout); #endif if (strcmp(thisterm, line) == 0) { if (postptr + 10 > POST + postsize / sizeof (POSTING)) { i = postptr - POST; postsize += POSTINC * sizeof (POSTING); if ((POST = realloc(POST, postsize)) == NULL) { invcannotalloc(postsize); return (0); } postptr = i + POST; #if DEBUG (void) printf("reallocated post space to %u, " "totpost=%ld\n", postsize, totpost); #endif } numpost++; } else { /* have a new term */ if (!invnewterm()) { return (0); } (void) strcpy(thisterm, line); numpost = 1; postptr = POST; fileindex = 0; } /* get the new posting */ num = *++s - '!'; i = 1; do { num = BASE * num + *++s - '!'; } while (++i < PRECISION); posting.lineoffset = num; while (++fileindex < nsrcoffset && num > srcoffset[fileindex]) { ; } posting.fileindex = --fileindex; posting.type = *++s; num = *++s - '!'; if (*s != '\n') { num = *++s - '!'; while (*++s != '\n') { num = BASE * num + *s - '!'; } posting.fcnoffset = num; } else { posting.fcnoffset = 0; } *postptr++ = posting; #if DEBUG (void) printf("%ld %ld %ld %ld\n", posting.fileindex, posting.fcnoffset, posting.lineoffset, posting.type); (void) fflush(stdout); #endif } if (!invnewterm()) { return (0); } /* now clean up final block */ logicalblk.invblk[0] = numinvitems; /* loops pointer around to start */ logicalblk.invblk[1] = 0; logicalblk.invblk[2] = numlogblk - 1; if (fwrite((char *)&logicalblk, BLOCKSIZE, 1, outfile) == 0) { goto cannotwrite; } numlogblk++; /* write out block to save space. what in it doesn't matter */ if (fwrite((char *)&logicalblk, BLOCKSIZE, 1, outfile) == 0) { goto cannotwrite; } /* finish up the super finger */ *SUPINT = numlogblk; /* add to the offsets the size of the offset pointers */ intptr = (SUPINT + 1); i = (char *)supint - (char *)SUPINT; while (intptr < supint) *intptr++ += i; /* write out the offsets (1 for the N at start) and the super finger */ if (fwrite((char *)SUPINT, sizeof (*SUPINT), numlogblk + 1, outfile) == 0 || fwrite(SUPFING, 1, supfing - SUPFING, outfile) == 0) { goto cannotwrite; } /* save the size for reference later */ nextsupfing = sizeof (long) + sizeof (long) * numlogblk + (supfing - SUPFING); /* * make sure the file ends at a logical block boundary. This is * necessary for invinsert to correctly create extended blocks */ i = nextsupfing % BLOCKSIZE; /* write out junk to fill log blk */ if (fwrite(SUPFING, BLOCKSIZE - i, 1, outfile) == 0 || fflush(outfile) == EOF) { /* rewind doesn't check for write failure */ goto cannotwrite; } /* write the control area */ rewind(outfile); param.version = VERSION; param.filestat = 0; param.sizeblk = BLOCKSIZE; param.startbyte = (numlogblk + 1) * BLOCKSIZE + BUFSIZ; param.supsize = nextsupfing; param.cntlsize = BUFSIZ; param.share = 0; if (fwrite((char *)¶m, sizeof (param), 1, outfile) == 0) { goto cannotwrite; } for (i = 0; i < 10; i++) /* for future use */ if (fwrite((char *)&zerolong, sizeof (zerolong), 1, outfile) == 0) { goto cannotwrite; } /* make first block loop backwards to last block */ if (fflush(outfile) == EOF) { /* fseek doesn't check for write failure */ goto cannotwrite; } /* get to second word first block */ (void) fseek(outfile, (long)BUFSIZ + 8, 0); tlong = numlogblk - 1; if (fwrite((char *)&tlong, sizeof (tlong), 1, outfile) == 0 || fclose(outfile) == EOF) { cannotwrite: invcannotwrite(invname); return (0); } if (fclose(fpost) == EOF) { invcannotwrite(postingfile); return (0); } --totterm; /* don't count null term */ #if STATS (void) printf("logical blocks = %d, postings = %ld, terms = %ld, " "max term length = %d\n", numlogblk, totpost, totterm, maxtermlen); if (showzipf) { (void) printf( "\n************* ZIPF curve ****************\n"); for (j = ZIPFSIZE; j > 1; j--) if (zipf[j]) break; for (i = 1; i < j; ++i) { (void) printf("%3d -%6d ", i, zipf[i]); if (i % 6 == 0) (void) putchar('\n'); } (void) printf(">%d-%6d\n", ZIPFSIZE, zipf[0]); } #endif /* free all malloc'd memory */ free(POST); free(SUPFING); free(SUPINT); return (totterm); } /* add a term to the data base */ static int invnewterm(void) { int backupflag, i, j, maxback, holditems, gooditems, howfar; int len, numwilluse, wdlen; char *tptr, *tptr2, *tptr3; union { unsigned long packword[2]; ENTRY e; } iteminfo; totterm++; #if STATS /* keep zipfian info on the distribution */ if (numpost <= ZIPFSIZE) zipf[numpost]++; else zipf[0]++; #endif len = strlen(thisterm); wdlen = (len + (sizeof (long) - 1)) / sizeof (long); numwilluse = (wdlen + 3) * sizeof (long); /* new block if at least 1 item in block */ if (numinvitems && numwilluse + amtused > BLOCKSIZE) { /* set up new block */ if (supfing + 500 > SUPFING + supersize) { i = supfing - SUPFING; supersize += 20000; if ((SUPFING = realloc(SUPFING, supersize)) == NULL) { invcannotalloc(supersize); return (0); } supfing = i + SUPFING; #if DEBUG (void) printf("reallocated superfinger space to %d, " "totpost=%ld\n", supersize, totpost); #endif } /* check that room for the offset as well */ if ((numlogblk + 10) > supintsize) { i = supint - SUPINT; supintsize += SUPERINC; if ((SUPINT = realloc((char *)SUPINT, supintsize * sizeof (long))) == NULL) { invcannotalloc(supintsize * sizeof (long)); return (0); } supint = i + SUPINT; #if DEBUG (void) printf("reallocated superfinger offset to %d, " "totpost = %ld\n", supintsize * sizeof (long), totpost); #endif } /* See if backup is efficatious */ backupflag = 0; maxback = strlen(thisterm) / 10; holditems = numinvitems; if (maxback > numinvitems) maxback = numinvitems - 2; howfar = 0; while (--maxback > 0) { howfar++; iteminfo.packword[0] = logicalblk.invblk[--holditems * 2 + (sizeof (long) - 1)]; if ((i = iteminfo.e.size / 10) < maxback) { maxback = i; backupflag = howfar; gooditems = holditems; tptr2 = logicalblk.chrblk + iteminfo.e.offset; } } /* see if backup will occur */ if (backupflag) { numinvitems = gooditems; } logicalblk.invblk[0] = numinvitems; /* set forward pointer pointing to next */ logicalblk.invblk[1] = numlogblk + 1; /* set back pointer to last block */ logicalblk.invblk[2] = numlogblk - 1; if (fwrite((char *)logicalblk.chrblk, 1, BLOCKSIZE, outfile) == 0) { invcannotwrite(indexfile); return (0); } amtused = 16; numlogblk++; /* check if had to back up, if so do it */ if (backupflag) { /* find out where the end of the new block is */ iteminfo.packword[0] = logicalblk.invblk[numinvitems * 2 + 1]; tptr3 = logicalblk.chrblk + iteminfo.e.offset; /* move the index for this block */ for (i = 3; i <= (backupflag * 2 + 2); i++) { logicalblk.invblk[i] = logicalblk.invblk[numinvitems * 2+i]; } /* move the word into the super index */ iteminfo.packword[0] = logicalblk.invblk[3]; iteminfo.packword[1] = logicalblk.invblk[4]; tptr2 = logicalblk.chrblk + iteminfo.e.offset; (void) strncpy(supfing, tptr2, (int)iteminfo.e.size); *(supfing + iteminfo.e.size) = '\0'; #if DEBUG (void) printf("backup %d at term=%s to term=%s\n", backupflag, thisterm, supfing); #endif *supint++ = nextsupfing; nextsupfing += strlen(supfing) + 1; supfing += strlen(supfing) + 1; /* now fix up the logical block */ tptr = logicalblk.chrblk + lastinblk; lastinblk = BLOCKSIZE; tptr2 = logicalblk.chrblk + lastinblk; j = tptr3 - tptr; while (tptr3 > tptr) *--tptr2 = *--tptr3; lastinblk -= j; amtused += (8 * backupflag + j); for (i = 3; i < (backupflag * 2 + 2); i += 2) { iteminfo.packword[0] = logicalblk.invblk[i]; iteminfo.e.offset += (tptr2 - tptr3); logicalblk.invblk[i] = iteminfo.packword[0]; } numinvitems = backupflag; } else { /* no backup needed */ numinvitems = 0; lastinblk = BLOCKSIZE; /* add new term to superindex */ (void) strcpy(supfing, thisterm); supfing += strlen(thisterm) + 1; *supint++ = nextsupfing; nextsupfing += strlen(thisterm) + 1; } } lastinblk -= (numwilluse - 8); iteminfo.e.offset = lastinblk; iteminfo.e.size = (char)len; iteminfo.e.space = 0; iteminfo.e.post = numpost; (void) strncpy(logicalblk.chrblk + lastinblk, thisterm, len); amtused += numwilluse; logicalblk.invblk[(lastinblk/sizeof (long))+wdlen] = nextpost; if ((i = postptr - POST) > 0) { if (fwrite((char *)POST, sizeof (POSTING), i, fpost) == 0) { invcannotwrite(postingfile); return (0); } nextpost += i * sizeof (POSTING); } logicalblk.invblk[3+2*numinvitems++] = iteminfo.packword[0]; logicalblk.invblk[2+2*numinvitems] = iteminfo.packword[1]; return (1); } static void swap_ints(void *p, size_t sz) { uint32_t *s; uint32_t *e = (uint32_t *)p + (sz / sizeof (uint32_t)); for (s = p; s < e; s++) *s = BSWAP_32(*s); } static void write_param(INVCONTROL *invcntl) { if (invcntl->swap) swap_ints(&invcntl->param, sizeof (invcntl->param)); rewind(invcntl->invfile); (void) fwrite((char *)&invcntl->param, sizeof (invcntl->param), 1, invcntl->invfile); if (invcntl->swap) swap_ints(&invcntl->param, sizeof (invcntl->param)); } static void read_superfinger(INVCONTROL *invcntl) { size_t count; (void) fseek(invcntl->invfile, invcntl->param.startbyte, SEEK_SET); (void) fread(invcntl->iindex, (int)invcntl->param.supsize, 1, invcntl->invfile); if (invcntl->swap) { /* * The superfinger consists of a count, followed by * count offsets, followed by a string table (which * the offsets reference). * * We need to swap the count and the offsets. */ count = 1 + BSWAP_32(*(uint32_t *)invcntl->iindex); swap_ints(invcntl->iindex, count * sizeof (unsigned long)); } } static void read_logblock(INVCONTROL *invcntl, int block) { /* note always fetch it if the file is busy */ if ((block != invcntl->numblk) || (invcntl->param.filestat >= INVBUSY)) { (void) fseek(invcntl->invfile, (block * invcntl->param.sizeblk) + invcntl->param.cntlsize, SEEK_SET); invcntl->numblk = block; (void) fread(invcntl->logblk, (int)invcntl->param.sizeblk, 1, invcntl->invfile); if (invcntl->swap) { size_t count; ENTRY *ecur, *eend; uint32_t *postptr; /* * A logblock consists of a count, a next block id, * and a previous block id, followed by count * ENTRYs, followed by alternating strings and * offsets. */ swap_ints(invcntl->logblk, 3 * sizeof (unsigned long)); count = *(uint32_t *)invcntl->logblk; ecur = (ENTRY *)((uint32_t *)invcntl->logblk + 3); eend = ecur + count; for (; ecur < eend; ecur++) { ecur->offset = BSWAP_16(ecur->offset); ecur->post = BSWAP_32(ecur->post); /* * After the string is the posting offset. */ postptr = (uint32_t *)(invcntl->logblk + ecur->offset + P2ROUNDUP(ecur->size, sizeof (long))); *postptr = BSWAP_32(*postptr); } } } } void read_next_posting(INVCONTROL *invcntl, POSTING *posting) { (void) fread((char *)posting, sizeof (*posting), 1, invcntl->postfile); if (invcntl->swap) { posting->lineoffset = BSWAP_32(posting->lineoffset); posting->fcnoffset = BSWAP_32(posting->fcnoffset); /* * fileindex is a 24-bit field, so shift it before swapping */ posting->fileindex = BSWAP_32(posting->fileindex << 8); } } int invopen(INVCONTROL *invcntl, char *invname, char *invpost, int stat) { int read_index; if ((invcntl->invfile = vpfopen(invname, ((stat == 0) ? FREAD : FREADP))) == NULL) { invcannotopen(invname); return (-1); } if (fread((char *)&invcntl->param, sizeof (invcntl->param), 1, invcntl->invfile) == 0) { (void) fprintf(stderr, "%s: empty inverted file\n", argv0); goto closeinv; } if (invcntl->param.version != VERSION && BSWAP_32(invcntl->param.version) != VERSION) { (void) fprintf(stderr, "%s: cannot read old index format; use -U option to " "force database to rebuild\n", argv0); goto closeinv; } invcntl->swap = (invcntl->param.version != VERSION); if (invcntl->swap) swap_ints(&invcntl->param, sizeof (invcntl->param)); if (stat == 0 && invcntl->param.filestat == INVALONE) { (void) fprintf(stderr, "%s: inverted file is locked\n", argv0); goto closeinv; } if ((invcntl->postfile = vpfopen(invpost, ((stat == 0) ? FREAD : FREADP))) == NULL) { invcannotopen(invpost); goto closeinv; } /* allocate core for a logical block */ if ((invcntl->logblk = malloc(invcntl->param.sizeblk)) == NULL) { invcannotalloc((unsigned)invcntl->param.sizeblk); goto closeboth; } /* allocate for and read in superfinger */ read_index = 1; invcntl->iindex = NULL; #if SHARE if (invcntl->param.share == 1) { key_t ftok(), shm_key; struct shmid_ds shm_buf; char *shmat(); int shm_id; /* see if the shared segment exists */ shm_key = ftok(invname, 2); shm_id = shmget(shm_key, 0, 0); /* * Failure simply means (hopefully) that segment doesn't * exist */ if (shm_id == -1) { /* * Have to give general write permission due to AMdahl * not having protected segments */ shm_id = shmget(shm_key, invcntl->param.supsize + sizeof (long), IPC_CREAT | 0666); if (shm_id == -1) perror("Could not create shared " "memory segment"); } else read_index = 0; if (shm_id != -1) { invcntl->iindex = shmat(shm_id, 0, ((read_index) ? 0 : SHM_RDONLY)); if (invcntl->iindex == (char *)ERR) { (void) fprintf(stderr, "%s: shared memory link failed\n", argv0); invcntl->iindex = NULL; read_index = 1; } } } #endif if (invcntl->iindex == NULL) invcntl->iindex = malloc(invcntl->param.supsize + 16); if (invcntl->iindex == NULL) { invcannotalloc((unsigned)invcntl->param.supsize); free(invcntl->logblk); goto closeboth; } if (read_index) { read_superfinger(invcntl); } invcntl->numblk = -1; if (boolready() == -1) { closeboth: (void) fclose(invcntl->postfile); closeinv: (void) fclose(invcntl->invfile); return (-1); } /* write back out the control block if anything changed */ invcntl->param.filestat = stat; if (stat > invcntl->param.filestat) write_param(invcntl); return (1); } /* invclose must be called to wrap things up and deallocate core */ void invclose(INVCONTROL *invcntl) { /* write out the control block in case anything changed */ if (invcntl->param.filestat > 0) { invcntl->param.filestat = 0; write_param(invcntl); } (void) fclose(invcntl->invfile); (void) fclose(invcntl->postfile); #if SHARE if (invcntl->param.share > 0) { shmdt(invcntl->iindex); invcntl->iindex = NULL; } #endif if (invcntl->iindex != NULL) free(invcntl->iindex); free(invcntl->logblk); } /* invstep steps the inverted file forward one item */ void invstep(INVCONTROL *invcntl) { if (invcntl->keypnt < (*(int *)invcntl->logblk - 1)) { invcntl->keypnt++; return; } /* move forward a block else wrap */ read_logblock(invcntl, *(int *)(invcntl->logblk + sizeof (long))); invcntl->keypnt = 0; } /* invforward moves forward one term in the inverted file */ int invforward(INVCONTROL *invcntl) { invstep(invcntl); /* skip things with 0 postings */ while (((ENTRY *)(invcntl->logblk + 12) + invcntl->keypnt)->post == 0) { invstep(invcntl); } /* Check for having wrapped - reached start of inverted file! */ if ((invcntl->numblk == 0) && (invcntl->keypnt == 0)) return (0); return (1); } /* invterm gets the present term from the present logical block */ int invterm(INVCONTROL *invcntl, char *term) { ENTRY * entryptr; entryptr = (ENTRY *)(invcntl->logblk + 12) + invcntl->keypnt; (void) strncpy(term, entryptr->offset + invcntl->logblk, (int)entryptr->size); *(term + entryptr->size) = '\0'; return (entryptr->post); } /* invfind searches for an individual item in the inverted file */ long invfind(INVCONTROL *invcntl, char *searchterm) { int imid, ilow, ihigh; long num; int i; unsigned long *intptr, *intptr2; ENTRY *entryptr; /* make sure it is initialized via invready */ if (invcntl->invfile == 0) return (-1L); /* now search for the appropriate finger block */ intptr = (unsigned long *)invcntl->iindex; ilow = 0; ihigh = *intptr++ - 1; while (ilow <= ihigh) { imid = (ilow + ihigh) / 2; intptr2 = intptr + imid; i = strcmp(searchterm, (invcntl->iindex + *intptr2)); if (i < 0) ihigh = imid - 1; else if (i > 0) ilow = ++imid; else { ilow = imid + 1; break; } } /* be careful about case where searchterm is after last in this block */ imid = (ilow) ? ilow - 1 : 0; /* fetch the appropriate logical block if not in core */ read_logblock(invcntl, imid); srch_ext: /* now find the term in this block. tricky this */ intptr = (unsigned long *)invcntl->logblk; ilow = 0; ihigh = *intptr - 1; intptr += 3; num = 0; while (ilow <= ihigh) { imid = (ilow + ihigh) / 2; entryptr = (ENTRY *)intptr + imid; i = strncmp(searchterm, (invcntl->logblk + entryptr->offset), (int)entryptr->size); if (i == 0) i = strlen(searchterm) - entryptr->size; if (i < 0) ihigh = imid - 1; else if (i > 0) ilow = ++imid; else { num = entryptr->post; break; } } /* be careful about case where searchterm is after last in this block */ if (imid >= *(long *)invcntl->logblk) { invcntl->keypnt = *(long *)invcntl->logblk; invstep(invcntl); /* note if this happens the term could be in extended block */ if (invcntl->param.startbyte < invcntl->numblk * invcntl->param.sizeblk) goto srch_ext; } else invcntl->keypnt = imid; return (num); } #if DEBUG /* invdump dumps the block the term parameter is in */ void invdump(INVCONTROL *invcntl, char *term) { long i, j, n, *longptr; ENTRY * entryptr; char temp[512], *ptr; /* dump superindex if term is "-" */ if (*term == '-') { j = atoi(term + 1); longptr = (long *)invcntl->iindex; n = *longptr++; (void) printf("Superindex dump, num blocks=%ld\n", n); longptr += j; while ((longptr <= ((long *)invcntl->iindex) + n) && invbreak == 0) { (void) printf("%2ld %6ld %s\n", j++, *longptr, invcntl->iindex + *longptr); longptr++; } return; } else if (*term == '#') { j = atoi(term + 1); /* fetch the appropriate logical block */ read_logblock(invcntl, j); } else i = abs((int)invfind(invcntl, term)); longptr = (long *)invcntl->logblk; n = *longptr++; (void) printf("Entry term to invdump=%s, postings=%ld, " "forward ptr=%ld, back ptr=%ld\n", term, i, *(longptr), *(longptr + 1)); entryptr = (ENTRY *)(invcntl->logblk + 12); (void) printf("%ld terms in this block, block=%ld\n", n, invcntl->numblk); (void) printf("\tterm\t\t\tposts\tsize\toffset\tspace\t1st word\n"); for (j = 0; j < n && invbreak == 0; j++) { ptr = invcntl->logblk + entryptr->offset; (void) strncpy(temp, ptr, (int)entryptr->size); temp[entryptr->size] = '\0'; ptr += (sizeof (long) * (long)((entryptr->size + (sizeof (long) - 1)) / sizeof (long))); (void) printf("%2ld %-24s\t%5ld\t%3d\t%d\t%d\t%ld\n", j, temp, entryptr->post, entryptr->size, entryptr->offset, entryptr->space, *(long *)ptr); entryptr++; } } #endif static int boolready(void) { numitems = 0; if (item1 != NULL) free(item1); setsize1 = SETINC; if ((item1 = (POSTING *)malloc(SETINC * sizeof (POSTING))) == NULL) { invcannotalloc(SETINC); return (-1); } if (item2 != NULL) free(item2); setsize2 = SETINC; if ((item2 = (POSTING *)malloc(SETINC * sizeof (POSTING))) == NULL) { invcannotalloc(SETINC); return (-1); } item = item1; enditem = item; return (0); } void boolclear(void) { numitems = 0; item = item1; enditem = item; } POSTING * boolfile(INVCONTROL *invcntl, long *num, int bool) { ENTRY *entryptr; FILE *file; char *ptr; unsigned long *ptr2; POSTING *newitem; POSTING posting; unsigned u; POSTING *newsetp, *set1p; long newsetc, set1c, set2c; entryptr = (ENTRY *) (invcntl->logblk + 12) + invcntl->keypnt; ptr = invcntl->logblk + entryptr->offset; ptr2 = ((unsigned long *)ptr) + (entryptr->size + (sizeof (long) - 1)) / sizeof (long); *num = entryptr->post; switch (bool) { case OR: case NOT: if (*num == 0) { *num = numitems; return (item); } } /* make room for the new set */ u = 0; switch (bool) { case AND: case NOT: newsetp = set1p = item; break; case OR: u = enditem - item; /* FALLTHROUGH */ case REVERSENOT: u += *num; if (item == item2) { if (u > setsize1) { u += SETINC; if ((item1 = (POSTING *) realloc(item1, u * sizeof (POSTING))) == NULL) { goto cannotalloc; } setsize1 = u; } newitem = item1; } else { if (u > setsize2) { u += SETINC; if ((item2 = (POSTING *)realloc(item2, u * sizeof (POSTING))) == NULL) { cannotalloc: invcannotalloc(u * sizeof (POSTING)); (void) boolready(); *num = -1; return (NULL); } setsize2 = u; } newitem = item2; } set1p = item; newsetp = newitem; } file = invcntl->postfile; (void) fseek(file, (long)*ptr2, SEEK_SET); read_next_posting(invcntl, &posting); newsetc = 0; switch (bool) { case OR: /* while something in both sets */ set1p = item; newsetp = newitem; for (set1c = 0, set2c = 0; set1c < numitems && set2c < *num; newsetc++) { if (set1p->lineoffset < posting.lineoffset) { *newsetp++ = *set1p++; set1c++; } else if (set1p->lineoffset > posting.lineoffset) { *newsetp++ = posting; read_next_posting(invcntl, &posting); set2c++; } else if (set1p->type < posting.type) { *newsetp++ = *set1p++; set1c++; } else if (set1p->type > posting.type) { *newsetp++ = posting; read_next_posting(invcntl, &posting); set2c++; } else { /* identical postings */ *newsetp++ = *set1p++; set1c++; read_next_posting(invcntl, &posting); set2c++; } } /* find out what ran out and move the rest in */ if (set1c < numitems) { newsetc += numitems - set1c; while (set1c++ < numitems) { *newsetp++ = *set1p++; } } else { while (set2c++ < *num) { *newsetp++ = posting; newsetc++; read_next_posting(invcntl, &posting); } } item = newitem; break; /* end of OR */ #if 0 case AND: set1c = 0; set2c = 0; while (set1c < numitems && set2c < *num) { if (set1p->lineoffset < posting.lineoffset) { set1p++; set1c++; } else if (set1p->lineoffset > posting.lineoffset) { read_next_posting(invcntl, &posting); set2c++; } else if (set1p->type < posting.type) { *set1p++; set1c++; } else if (set1p->type > posting.type) { read_next_posting(invcntl, &posting); set2c++; } else { /* identical postings */ *newsetp++ = *set1p++; newsetc++; set1c++; read_next_posting(invcntl, &posting); set2c++; } } break; /* end of AND */ case NOT: set1c = 0; set2c = 0; while (set1c < numitems && set2c < *num) { if (set1p->lineoffset < posting.lineoffset) { *newsetp++ = *set1p++; newsetc++; set1c++; } else if (set1p->lineoffset > posting.lineoffset) { read_next_posting(invcntl, &posting); set2c++; } else if (set1p->type < posting.type) { *newsetp++ = *set1p++; newsetc++; set1c++; } else if (set1p->type > posting.type) { read_next_posting(invcntl, &posting); set2c++; } else { /* identical postings */ set1c++; set1p++; read_next_posting(invcntl, &posting); set2c++; } } newsetc += numitems - set1c; while (set1c++ < numitems) { *newsetp++ = *set1p++; } break; /* end of NOT */ case REVERSENOT: /* core NOT incoming set */ set1c = 0; set2c = 0; while (set1c < numitems && set2c < *num) { if (set1p->lineoffset < posting.lineoffset) { set1p++; set1c++; } else if (set1p->lineoffset > posting.lineoffset) { *newsetp++ = posting; read_next_posting(invcntl, &posting); set2c++; } else if (set1p->type < posting.type) { set1p++; set1c++; } else if (set1p->type > posting.type) { *newsetp++ = posting; read_next_posting(invcntl, &posting); set2c++; } else { /* identical postings */ set1c++; set1p++; read_next_posting(invcntl, &posting); set2c++; } } while (set2c++ < *num) { *newsetp++ = posting; newsetc++; read_next_posting(invcntl, &posting); } item = newitem; break; /* end of REVERSENOT */ #endif } numitems = newsetc; *num = newsetc; enditem = (POSTING *)newsetp; return ((POSTING *)item); } #if 0 POSTING * boolsave(int clear) { int i; POSTING *ptr; POSTING *oldstuff, *newstuff; if (numitems == 0) { if (clear) boolclear(); return (NULL); } /* * if clear then give them what we have and use (void) * boolready to realloc */ if (clear) { ptr = item; /* free up the space we didn't give them */ if (item == item1) item1 = NULL; else item2 = NULL; (void) boolready(); return (ptr); } i = (enditem - item) * sizeof (POSTING) + 100; if ((ptr = (POSTING *)malloc(i))r == NULL) { invcannotalloc(i); return (ptr); } /* move present set into place */ oldstuff = item; newstuff = ptr; while (oldstuff < enditem) *newstuff++ = *oldstuff++; return (ptr); } #endif static void invcannotalloc(size_t n) { (void) fprintf(stderr, "%s: cannot allocate %u bytes\n", argv0, n); } static void invcannotopen(char *file) { (void) fprintf(stderr, "%s: cannot open file %s\n", argv0, file); } static void invcannotwrite(char *file) { (void) perror(argv0); /* must be first to preserve errno */ (void) fprintf(stderr, "%s: write to file %s failed\n", argv0, file); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * Copyright 1999, 2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* inverted index definitions */ /* postings temporary file long number coding into characters */ #define BASE 95 /* 127 - ' ' */ #define PRECISION 5 /* maximum digits after converting a long */ /* inverted index access parameters */ #define INVAVAIL 0 #define INVBUSY 1 #define INVALONE 2 /* boolean set operations */ #define OR 3 #define AND 4 #define NOT 5 #define REVERSENOT 6 /* note that the entire first block is for parameters */ typedef struct { long version; /* inverted index format version */ long filestat; /* file status word */ long sizeblk; /* size of logical block in bytes */ long startbyte; /* first byte of superfinger */ long supsize; /* size of superfinger in bytes */ long cntlsize; /* size of max cntl space (should be a */ /* multiple of BUFSIZ) */ long share; /* flag whether to use shared memory */ } PARAM; typedef struct { FILE *invfile; /* the inverted file ptr */ FILE *postfile; /* posting file ptr */ PARAM param; /* control parameters for the file */ char *iindex; /* ptr to space for superindex */ char *logblk; /* ptr to space for a logical block */ long numblk; /* number of block presently at *logblk */ long keypnt; /* number item in present block found */ int swap; /* file endian mistmatch? */ } INVCONTROL; typedef struct { short offset; /* offset in this logical block */ unsigned char size; /* size of term */ unsigned char space; /* number of longs of growth space */ long post; /* number of postings for this entry */ } ENTRY; typedef struct { long lineoffset; /* source line database offset */ long fcnoffset; /* function name database offset */ long fileindex : 24; /* source file name index */ long type : 8; /* reference type (mark character) */ } POSTING; extern long *srcoffset; /* source file name database offsets */ extern int nsrcoffset; /* number of file name database offsets */ extern void boolclear(void); extern POSTING *boolfile(INVCONTROL *invcntl, long *num, int bool); extern void invclose(INVCONTROL *invcntl); extern long invfind(INVCONTROL *invcntl, char *searchterm); extern int invforward(INVCONTROL *invcntl); extern int invopen(INVCONTROL *invcntl, char *invname, char *invpost, int stat); extern int invterm(INVCONTROL *invcntl, char *term); extern long invmake(char *invname, char *invpost, FILE *infile); /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* library function return value declarations */ /* * Copyright (c) 1999 by Sun Microsystems, Inc. * All rights reserved. */ /* private library */ char *compath(char *pathname); char *getwd(char *dir); char *logdir(char *name); char *mygetenv(char *variable, char *deflt); char *mygetwd(char *dir); /* alloc.c */ char *stralloc(char *s); void *mymalloc(size_t size); void *mycalloc(size_t nelem, size_t size); void *myrealloc(void *p, size_t size); /* mypopen.c */ FILE *mypopen(char *cmd, char *mode); int mypclose(FILE *ptr); /* vp*.c */ FILE *vpfopen(char *filename, char *type); void vpinit(char *currentdir); int vpopen(char *path, int oflag); struct stat; int vpstat(char *path, struct stat *statp); /* standard C library */ #include #include /* string functions */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 1999 by Sun Microsystems, Inc. * All rights reserved. */ /* * logdir() * * This routine does not use the getpwent(3) library routine * because the latter uses the stdio package. The allocation of * storage in this package destroys the integrity of the shell's * storage allocation. */ #include /* O_RDONLY */ #include #include #include #define BUFSIZ 160 static char line[BUFSIZ+1]; static char * passwdfield(char *p) { while (*p && *p != ':') ++p; if (*p) *p++ = 0; return (p); } char * logdir(char *name) { char *p; int i, j; int pwf; /* attempt to open the password file */ if ((pwf = open("/etc/passwd", O_RDONLY)) == -1) return (0); /* find the matching password entry */ do { /* get the next line in the password file */ i = read(pwf, line, BUFSIZ); for (j = 0; j < i; j++) if (line[j] == '\n') break; /* return a null pointer if the whole file has been read */ if (j >= i) return (0); line[++j] = 0; /* terminate the line */ /* point at the next line */ (void) lseek(pwf, (long)(j - i), 1); p = passwdfield(line); /* get the logname */ } while (*name != *line || /* fast pretest */ strcmp(name, line) != 0); (void) close(pwf); /* skip the intervening fields */ p = passwdfield(p); p = passwdfield(p); p = passwdfield(p); p = passwdfield(p); /* return the login directory */ (void) passwdfield(p); return (p); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 1999 by Sun Microsystems, Inc. * All rights reserved. */ /* * cscope - interactive C symbol cross-reference * * keyword look-up routine for the C symbol scanner */ #include "global.h" /* keyword text for fast testing of keywords in the scanner */ char externtext[] = "extern"; char typedeftext[] = "typedef"; /* * This keyword table is also used for keyword text compression. Keywords * with an index less than the numeric value of a space are replaced with the * control character corresponding to the index, so they cannot be moved * without changing the database file version and adding compatibility code * for old databases. */ struct keystruct keyword[] = { { "#define", ' ', MISC, NULL }, /* must be table entry 0 */ /* for old databases */ { "#include", ' ', MISC, NULL }, /* must be table entry 1 */ { "break", '\0', FLOW, NULL }, /* rarely in cross-reference */ { "case", ' ', FLOW, NULL }, { "char", ' ', DECL, NULL }, { "continue", '\0', FLOW, NULL }, /* rarely in cross-reference */ { "default", '\0', FLOW, NULL }, /* rarely in cross-reference */ { "#define", ' ', MISC, NULL }, /* must be table entry 7 */ { "double", ' ', DECL, NULL }, { "\t", '\0', MISC, NULL }, /* must be table entry 9 */ { "\n", '\0', MISC, NULL }, /* must be table entry 10 */ { "else", ' ', FLOW, NULL }, { "enum", ' ', DECL, NULL }, { externtext, ' ', DECL, NULL }, { "float", ' ', DECL, NULL }, { "for", '(', FLOW, NULL }, { "goto", ' ', FLOW, NULL }, { "if", '(', FLOW, NULL }, { "int", ' ', DECL, NULL }, { "long", ' ', DECL, NULL }, { "register", ' ', DECL, NULL }, { "return", '\0', FLOW, NULL }, { "short", ' ', DECL, NULL }, { "sizeof", '\0', MISC, NULL }, { "static", ' ', DECL, NULL }, { "struct", ' ', DECL, NULL }, { "switch", '(', FLOW, NULL }, { typedeftext, ' ', DECL, NULL }, { "union", ' ', DECL, NULL }, { "unsigned", ' ', DECL, NULL }, { "void", ' ', DECL, NULL }, { "while", '(', FLOW, NULL }, /* these keywords are not compressed */ { "auto", ' ', DECL, NULL }, { "do", ' ', FLOW, NULL }, { "fortran", ' ', DECL, NULL }, { "const", ' ', DECL, NULL }, { "signed", ' ', DECL, NULL }, { "volatile", ' ', DECL, NULL }, }; #define KEYWORDS (sizeof (keyword) / sizeof (struct keystruct)) #define HASHMOD (KEYWORDS * 2 + 1) static struct keystruct *hashtab[HASHMOD]; /* pointer table */ /* put the keywords into the symbol table */ void initsymtab(void) { int i, j; struct keystruct *p; for (i = 1; i < KEYWORDS; ++i) { p = &keyword[i]; j = hash(p->text) % HASHMOD; p->next = hashtab[j]; hashtab[j] = p; } } /* see if this identifier is a keyword */ struct keystruct * lookup(char *ident) { struct keystruct *p; int c; /* look up the identifier in the keyword table */ for (p = hashtab[hash(ident) % HASHMOD]; p != NULL; p = p->next) { if (strequal(ident, p->text)) { if (compress == YES && (c = p - keyword) < ' ') { ident[0] = c; /* compress the keyword */ } return (p); } } /* this is an identifier */ return (NULL); } /* form hash value for string */ int hash(char *s) { unsigned i; for (i = 0; *s != '\0'; ) i += *s++; /* += is faster than <<= for cscope */ return (i); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * cscope - interactive C symbol cross-reference * * main functions */ #include /* stdscr and TRUE */ #include /* O_RDONLY */ #include /* needed by stat.h */ #include /* O_RDONLY */ #include /* O_RDONLY */ #include /* stat */ #include /* O_RDONLY */ #include "global.h" #include "version.h" /* FILEVERSION and FIXVERSION */ #include "vp.h" /* vpdirs and vpndirs */ #define OPTSEPS " \t" /* CSCOPEOPTION separators */ #define MINHOURS 4 /* minimum no activity timeout hours */ /* defaults for unset environment variables */ #define EDITOR "vi" #define SHELL "sh" #define TMPDIR "/tmp" /* * note: these digraph character frequencies were calculated from possible * printable digraphs in the cross-reference for the C compiler */ char dichar1[] = " teisaprnl(of)=c"; /* 16 most frequent first chars */ char dichar2[] = " tnerpla"; /* 8 most frequent second chars */ /* using the above as first chars */ char dicode1[256]; /* digraph first character code */ char dicode2[256]; /* digraph second character code */ char *editor, *home, *shell; /* environment variables */ BOOL compress = YES; /* compress the characters in the crossref */ int cscopedepth; /* cscope invocation nesting depth */ char currentdir[PATHLEN + 1]; /* current directory */ BOOL dbtruncated; /* database symbols are truncated to 8 chars */ char **dbvpdirs; /* directories (including current) in */ /* database view path */ int dbvpndirs; /* # of directories in database view path */ int dispcomponents = 1; /* file path components to display */ BOOL editallprompt = YES; /* prompt between editing files */ int fileargc; /* file argument count */ char **fileargv; /* file argument values */ int fileversion; /* cross-reference file version */ BOOL incurses; /* in curses */ INVCONTROL invcontrol; /* inverted file control structure */ BOOL invertedindex; /* the database has an inverted index */ BOOL isuptodate; /* consider the crossref up-to-date */ BOOL linemode; /* use line oriented user interface */ char *namefile; /* file of file names */ char *newinvname; /* new inverted index file name */ char *newinvpost; /* new inverted index postings file name */ char *newreffile; /* new cross-reference file name */ FILE *newrefs; /* new cross-reference */ BOOL noacttimeout; /* no activity timeout occurred */ BOOL ogs; /* display OGS book and subsystem names */ FILE *postings; /* new inverted index postings */ char *prependpath; /* prepend path to file names */ BOOL returnrequired; /* RETURN required after selection number */ int symrefs = -1; /* cross-reference file */ char temp1[PATHLEN + 1]; /* temporary file name */ char temp2[PATHLEN + 1]; /* temporary file name */ long totalterms; /* total inverted index terms */ BOOL truncatesyms; /* truncate symbols to 8 characters */ static BOOL buildonly; /* only build the database */ static BOOL fileschanged; /* assume some files changed */ static char *invname = INVNAME; /* inverted index to the database */ static char *invpost = INVPOST; /* inverted index postings */ static unsigned noacttime; /* no activity timeout in seconds */ static BOOL onesearch; /* one search only in line mode */ static char *reffile = REFFILE; /* cross-reference file path name */ static char *reflines; /* symbol reference lines file */ static char *tmpdir; /* temporary directory */ static long traileroffset; /* file trailer offset */ static BOOL unconditional; /* unconditionally build database */ static void options(int argc, char **argv); static void printusage(void); static void removeindex(void); static void cannotindex(void); static void initcompress(void); static void opendatabase(void); static void closedatabase(void); static void build(void); static int compare(const void *s1, const void *s2); static char *getoldfile(void); static void putheader(char *dir); static void putlist(char **names, int count); static BOOL samelist(FILE *oldrefs, char **names, int count); static void skiplist(FILE *oldrefs); static void copydata(void); static void copyinverted(void); static void putinclude(char *s); static void movefile(char *new, char *old); static void timedout(int sig); int main(int argc, char **argv) { int envc; /* environment argument count */ char **envv; /* environment argument list */ FILE *names; /* name file pointer */ int oldnum; /* number in old cross-ref */ char path[PATHLEN + 1]; /* file path */ FILE *oldrefs; /* old cross-reference file */ char *s; int c, i; pid_t pid; /* save the command name for messages */ argv0 = basename(argv[0]); /* get the current directory for build() and line-oriented P command */ if (mygetwd(currentdir) == NULL) { (void) fprintf(stderr, "cscope: warning: cannot get current directory name\n"); (void) strcpy(currentdir, ""); } /* initialize any view path; (saves time since currendir is known) */ vpinit(currentdir); dbvpndirs = vpndirs; /* number of directories in database view path */ /* directories (including current) in database view path */ dbvpdirs = vpdirs; /* the first source directory is the current directory */ sourcedir("."); /* read the environment */ editor = mygetenv("EDITOR", EDITOR); editor = mygetenv("VIEWER", editor); /* use viewer if set */ home = getenv("HOME"); shell = mygetenv("SHELL", SHELL); tmpdir = mygetenv("TMPDIR", TMPDIR); /* increment nesting depth */ cscopedepth = atoi(mygetenv("CSCOPEDEPTH", "0")); (void) sprintf(path, "CSCOPEDEPTH=%d", ++cscopedepth); (void) putenv(stralloc(path)); if ((s = getenv("CSCOPEOPTIONS")) != NULL) { /* parse the environment option string */ envc = 1; envv = mymalloc(sizeof (char *)); s = strtok(stralloc(s), OPTSEPS); while (s != NULL) { envv = myrealloc(envv, ++envc * sizeof (char *)); envv[envc - 1] = stralloc(s); s = strtok((char *)NULL, OPTSEPS); } /* set the environment options */ options(envc, envv); } /* set the command line options */ options(argc, argv); /* create the temporary file names */ pid = getpid(); (void) sprintf(temp1, "%s/cscope%d.1", tmpdir, (int)pid); (void) sprintf(temp2, "%s/cscope%d.2", tmpdir, (int)pid); /* if running in the foreground */ if (signal(SIGINT, SIG_IGN) != SIG_IGN) { /* cleanup on the interrupt and quit signals */ (void) signal(SIGINT, myexit); (void) signal(SIGQUIT, myexit); } /* cleanup on the hangup signal */ (void) signal(SIGHUP, myexit); /* if the database path is relative and it can't be created */ if (reffile[0] != '/' && access(".", WRITE) != 0) { /* if the database may not be up-to-date or can't be read */ (void) sprintf(path, "%s/%s", home, reffile); if (isuptodate == NO || access(reffile, READ) != 0) { /* put it in the home directory */ reffile = stralloc(path); (void) sprintf(path, "%s/%s", home, invname); invname = stralloc(path); (void) sprintf(path, "%s/%s", home, invpost); invpost = stralloc(path); (void) fprintf(stderr, "cscope: symbol database will be %s\n", reffile); } } /* if the cross-reference is to be considered up-to-date */ if (isuptodate == YES) { if ((oldrefs = vpfopen(reffile, "r")) == NULL) { cannotopen(reffile); exit(1); } /* * get the crossref file version but skip the current * directory */ if (fscanf(oldrefs, "cscope %d %*s", &fileversion) != 1) { (void) fprintf(stderr, "cscope: cannot read file version from file %s\n", reffile); exit(1); } if (fileversion >= 8) { /* override these command line options */ compress = YES; invertedindex = NO; /* see if there are options in the database */ for (;;) { /* no -q leaves multiple blanks */ while ((c = getc(oldrefs)) == ' ') { ; } if (c != '-') { (void) ungetc(c, oldrefs); break; } switch (c = getc(oldrefs)) { case 'c': /* ASCII characters only */ compress = NO; break; case 'q': /* quick search */ invertedindex = YES; (void) fscanf(oldrefs, "%ld", &totalterms); break; case 'T': /* truncate symbols to 8 characters */ dbtruncated = YES; truncatesyms = YES; break; } } initcompress(); /* seek to the trailer */ if (fscanf(oldrefs, "%ld", &traileroffset) != 1) { (void) fprintf(stderr, "cscope: cannot read trailer offset from " "file %s\n", reffile); exit(1); } if (fseek(oldrefs, traileroffset, 0) != 0) { (void) fprintf(stderr, "cscope: cannot seek to trailer in " "file %s\n", reffile); exit(1); } } /* * read the view path for use in converting relative paths to * full paths * * note: don't overwrite vp[n]dirs because this can cause * the wrong database index files to be found in the viewpath */ if (fileversion >= 13) { if (fscanf(oldrefs, "%d", &dbvpndirs) != 1) { (void) fprintf(stderr, "cscope: cannot read view path size from " "file %s\n", reffile); exit(1); } if (dbvpndirs > 0) { dbvpdirs = mymalloc( dbvpndirs * sizeof (char *)); for (i = 0; i < dbvpndirs; ++i) { if (fscanf(oldrefs, "%s", path) != 1) { (void) fprintf(stderr, "cscope: cannot read view " "path from file %s\n", reffile); exit(1); } dbvpdirs[i] = stralloc(path); } } } /* skip the source and include directory lists */ skiplist(oldrefs); skiplist(oldrefs); /* get the number of source files */ if (fscanf(oldrefs, "%d", &nsrcfiles) != 1) { (void) fprintf(stderr, "cscope: cannot read source file size from " "file %s\n", reffile); exit(1); } /* get the source file list */ srcfiles = mymalloc(nsrcfiles * sizeof (char *)); if (fileversion >= 9) { /* allocate the string space */ if (fscanf(oldrefs, "%d", &oldnum) != 1) { (void) fprintf(stderr, "cscope: cannot read string space size " "from file %s\n", reffile); exit(1); } s = mymalloc(oldnum); (void) getc(oldrefs); /* skip the newline */ /* read the strings */ if (fread(s, oldnum, 1, oldrefs) != 1) { (void) fprintf(stderr, "cscope: cannot read source file names " "from file %s\n", reffile); exit(1); } /* change newlines to nulls */ for (i = 0; i < nsrcfiles; ++i) { srcfiles[i] = s; for (++s; *s != '\n'; ++s) { ; } *s = '\0'; ++s; } /* if there is a file of source file names */ if (namefile != NULL && (names = vpfopen(namefile, "r")) != NULL || (names = vpfopen(NAMEFILE, "r")) != NULL) { /* read any -p option from it */ while (fscanf(names, "%s", path) == 1 && *path == '-') { i = path[1]; s = path + 2; /* for "-Ipath" */ if (*s == '\0') { /* if "-I path" */ (void) fscanf(names, "%s", path); s = path; } switch (i) { case 'p': /* file path components */ /* to display */ if (*s < '0' || *s > '9') { (void) fprintf(stderr, "cscope: -p option " "in file %s: " "missing or " "invalid numeric " "value\n", namefile); } dispcomponents = atoi(s); } } (void) fclose(names); } } else { for (i = 0; i < nsrcfiles; ++i) { if (fscanf(oldrefs, "%s", path) != 1) { (void) fprintf(stderr, "cscope: cannot read source file " "name from file %s\n", reffile); exit(1); } srcfiles[i] = stralloc(path); } } (void) fclose(oldrefs); } else { /* get source directories from the environment */ if ((s = getenv("SOURCEDIRS")) != NULL) { sourcedir(s); } /* make the source file list */ srcfiles = mymalloc(msrcfiles * sizeof (char *)); makefilelist(); if (nsrcfiles == 0) { (void) fprintf(stderr, "cscope: no source files found\n"); printusage(); exit(1); } /* get include directories from the environment */ if ((s = getenv("INCLUDEDIRS")) != NULL) { includedir(s); } /* add /usr/include to the #include directory list */ includedir("/usr/include"); /* initialize the C keyword table */ initsymtab(); /* create the file name(s) used for a new cross-reference */ (void) strcpy(path, reffile); s = basename(path); *s = '\0'; (void) strcat(path, "n"); ++s; (void) strcpy(s, basename(reffile)); newreffile = stralloc(path); (void) strcpy(s, basename(invname)); newinvname = stralloc(path); (void) strcpy(s, basename(invpost)); newinvpost = stralloc(path); /* build the cross-reference */ initcompress(); build(); if (buildonly == YES) { exit(0); } } opendatabase(); /* * removing a database will not release the disk space if a cscope * process has the file open, so a project may want unattended cscope * processes to exit overnight, including their subshells and editors */ if (noacttime) { (void) signal(SIGALRM, timedout); (void) alarm(noacttime); } /* * if using the line oriented user interface so cscope can be a * subprocess to emacs or samuel */ if (linemode == YES) { if (*pattern != '\0') { /* do any optional search */ if (search() == YES) { while ((c = getc(refsfound)) != EOF) { (void) putchar(c); } } } if (onesearch == YES) { myexit(0); } for (;;) { char buf[PATLEN + 2]; if (noacttime) { (void) alarm(noacttime); } (void) printf(">> "); (void) fflush(stdout); if (fgets(buf, sizeof (buf), stdin) == NULL) { myexit(0); } /* remove any trailing newline character */ if (*(s = buf + strlen(buf) - 1) == '\n') { *s = '\0'; } switch (*buf) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': /* samuel only */ field = *buf - '0'; (void) strcpy(pattern, buf + 1); (void) search(); (void) printf("cscope: %d lines\n", totallines); while ((c = getc(refsfound)) != EOF) { (void) putchar(c); } break; case 'c': /* toggle caseless mode */ case ctrl('C'): if (caseless == NO) { caseless = YES; } else { caseless = NO; } egrepcaseless(caseless); break; case 'r': /* rebuild database cscope style */ case ctrl('R'): freefilelist(); makefilelist(); /* FALLTHROUGH */ case 'R': /* rebuild database samuel style */ rebuild(); (void) putchar('\n'); break; case 'C': /* clear file names */ freefilelist(); (void) putchar('\n'); break; case 'F': /* add a file name */ (void) strcpy(path, buf + 1); if (infilelist(path) == NO && vpaccess(path, READ) == 0) { addsrcfile(path); } (void) putchar('\n'); break; case 'P': /* print the path to the files */ if (prependpath != NULL) { (void) puts(prependpath); } else { (void) puts(currentdir); } break; case 'q': /* quit */ case ctrl('D'): case ctrl('Z'): myexit(0); default: (void) fprintf(stderr, "cscope: unknown command '%s'\n", buf); break; } } /* NOTREACHED */ } /* pause before clearing the screen if there have been error messages */ if (errorsfound == YES) { errorsfound = NO; askforreturn(); } (void) signal(SIGINT, SIG_IGN); /* ignore interrupts */ (void) signal(SIGPIPE, SIG_IGN); /* | command can cause pipe signal */ /* initialize the curses display package */ (void) initscr(); /* initialize the screen */ setfield(); /* set the initial cursor position */ entercurses(); (void) keypad(stdscr, TRUE); /* enable the keypad */ dispinit(); /* initialize display parameters */ putmsg(""); /* clear any build progress message */ display(); /* display the version number and input fields */ /* do any optional search */ if (*pattern != '\0') { atfield(); /* move to the input field */ (void) command(ctrl('A')); /* search */ display(); /* update the display */ } else if (reflines != NULL) { /* read any symbol reference lines file */ (void) readrefs(reflines); display(); /* update the display */ } for (;;) { if (noacttime) { (void) alarm(noacttime); } atfield(); /* move to the input field */ /* exit if the quit command is entered */ if ((c = mygetch()) == EOF || c == ctrl('D') || c == ctrl('Z')) { break; } /* execute the commmand, updating the display if necessary */ if (command(c) == YES) { display(); } } /* cleanup and exit */ myexit(0); /* NOTREACHED */ return (0); } static void options(int argc, char **argv) { char path[PATHLEN + 1]; /* file path */ int c; char *s; while (--argc > 0 && (*++argv)[0] == '-') { for (s = argv[0] + 1; *s != '\0'; s++) { /* look for an input field number */ if (isdigit(*s)) { field = *s - '0'; if (*++s == '\0' && --argc > 0) { s = *++argv; } if (strlen(s) > PATLEN) { (void) fprintf(stderr, "cscope: pattern too long, cannot " "be > %d characters\n", PATLEN); exit(1); } (void) strcpy(pattern, s); goto nextarg; } switch (*s) { case '-': /* end of options */ --argc; ++argv; goto lastarg; case 'V': /* print the version number */ (void) fprintf(stderr, "%s: version %d%s\n", argv0, FILEVERSION, FIXVERSION); exit(0); /*NOTREACHED*/ case 'b': /* only build the cross-reference */ buildonly = YES; break; case 'c': /* ASCII characters only in crossref */ compress = NO; break; case 'C': /* turn on caseless mode for symbol searches */ caseless = YES; /* simulate egrep -i flag */ egrepcaseless(caseless); break; case 'd': /* consider crossref up-to-date */ isuptodate = YES; break; case 'e': /* suppress ^E prompt between files */ editallprompt = NO; break; case 'L': onesearch = YES; /* FALLTHROUGH */ case 'l': linemode = YES; break; case 'o': /* display OGS book and subsystem names */ ogs = YES; break; case 'q': /* quick search */ invertedindex = YES; break; case 'r': /* display as many lines as possible */ returnrequired = YES; break; case 'T': /* truncate symbols to 8 characters */ truncatesyms = YES; break; case 'u': /* unconditionally build the cross-reference */ unconditional = YES; break; case 'U': /* assume some files have changed */ fileschanged = YES; break; case 'f': /* alternate cross-reference file */ case 'F': /* symbol reference lines file */ case 'i': /* file containing file names */ case 'I': /* #include file directory */ case 'p': /* file path components to display */ case 'P': /* prepend path to file names */ case 's': /* additional source file directory */ case 'S': case 't': /* no activity timeout in hours */ c = *s; if (*++s == '\0' && --argc > 0) { s = *++argv; } if (*s == '\0') { (void) fprintf(stderr, "%s: -%c option: missing or empty " "value\n", argv0, c); goto usage; } switch (c) { case 'f': /* alternate cross-reference file */ reffile = s; (void) strcpy(path, s); /* System V has a 14 character limit */ s = basename(path); if ((int)strlen(s) > 11) { s[11] = '\0'; } s = path + strlen(path); (void) strcpy(s, ".in"); invname = stralloc(path); (void) strcpy(s, ".po"); invpost = stralloc(path); break; case 'F': /* symbol reference lines file */ reflines = s; break; case 'i': /* file containing file names */ namefile = s; break; case 'I': /* #include file directory */ includedir(s); break; case 'p': /* file path components to display */ if (*s < '0' || *s > '9') { (void) fprintf(stderr, "%s: -p option: missing " "or invalid numeric " "value\n", argv0); goto usage; } dispcomponents = atoi(s); break; case 'P': /* prepend path to file names */ prependpath = s; break; case 's': case 'S': /* additional source directory */ sourcedir(s); break; case 't': /* no activity timeout in hours */ if (*s < '1' || *s > '9') { (void) fprintf(stderr, "%s: -t option: missing or " "invalid numeric value\n", argv0); goto usage; } c = atoi(s); if (c < MINHOURS) { (void) fprintf(stderr, "cscope: minimum timeout " "is %d hours\n", MINHOURS); (void) sleep(3); c = MINHOURS; } noacttime = c * 3600; break; } goto nextarg; default: (void) fprintf(stderr, "%s: unknown option: -%c\n", argv0, *s); usage: printusage(); exit(1); } } nextarg: continue; } lastarg: /* save the file arguments */ fileargc = argc; fileargv = argv; } static void printusage(void) { (void) fprintf(stderr, "Usage: cscope [-bcdelLoqrtTuUV] [-f file] [-F file] [-i file] " "[-I dir] [-s dir]\n"); (void) fprintf(stderr, " [-p number] [-P path] [-[0-8] pattern] " "[source files]\n"); (void) fprintf(stderr, "-b Build the database only.\n"); (void) fprintf(stderr, "-c Use only ASCII characters in the database file, " "that is,\n"); (void) fprintf(stderr, " do not compress the data.\n"); (void) fprintf(stderr, "-d Do not update the database.\n"); (void) fprintf(stderr, "-f \"file\" Use \"file\" as the database file name " "instead of\n"); (void) fprintf(stderr, " the default (cscope.out).\n"); (void) fprintf(stderr, "-F \"file\" Read symbol reference lines from file, just\n"); /* BEGIN CSTYLED */ (void) fprintf(stderr, " like the \"<\" command.\n"); /* END CSTYLED */ (void) fprintf(stderr, "-i \"file\" Read any -I, -p, -q, and -T options and the\n"); (void) fprintf(stderr, " list of source files from \"file\" instead of the \n"); (void) fprintf(stderr, " default (cscope.files).\n"); (void) fprintf(stderr, "-I \"dir\" Look in \"dir\" for #include files.\n"); (void) fprintf(stderr, "-q Build an inverted index for quick symbol seaching.\n"); (void) fprintf(stderr, "-s \"dir\" Look in \"dir\" for additional source files.\n"); } static void removeindex(void) { (void) fprintf(stderr, "cscope: removed files %s and %s\n", invname, invpost); (void) unlink(invname); (void) unlink(invpost); } static void cannotindex(void) { (void) fprintf(stderr, "cscope: cannot create inverted index; ignoring -q option\n"); invertedindex = NO; errorsfound = YES; (void) fprintf(stderr, "cscope: removed files %s and %s\n", newinvname, newinvpost); (void) unlink(newinvname); (void) unlink(newinvpost); removeindex(); /* remove any existing index to prevent confusion */ } void cannotopen(char *file) { char msg[MSGLEN + 1]; (void) sprintf(msg, "Cannot open file %s", file); putmsg(msg); } void cannotwrite(char *file) { char msg[MSGLEN + 1]; (void) sprintf(msg, "Removed file %s because write failed", file); myperror(msg); /* display the reason */ (void) unlink(file); myexit(1); /* calls exit(2), which closes files */ } /* set up the digraph character tables for text compression */ static void initcompress(void) { int i; if (compress == YES) { for (i = 0; i < 16; ++i) { dicode1[(unsigned)(dichar1[i])] = i * 8 + 1; } for (i = 0; i < 8; ++i) { dicode2[(unsigned)(dichar2[i])] = i + 1; } } } /* open the database */ static void opendatabase(void) { if ((symrefs = vpopen(reffile, O_RDONLY)) == -1) { cannotopen(reffile); myexit(1); } blocknumber = -1; /* force next seek to read the first block */ /* open any inverted index */ if (invertedindex == YES && invopen(&invcontrol, invname, invpost, INVAVAIL) == -1) { askforreturn(); /* so user sees message */ invertedindex = NO; } } /* close the database */ static void closedatabase(void) { (void) close(symrefs); if (invertedindex == YES) { invclose(&invcontrol); nsrcoffset = 0; npostings = 0; } } /* rebuild the database */ void rebuild(void) { closedatabase(); build(); opendatabase(); /* revert to the initial display */ if (refsfound != NULL) { (void) fclose(refsfound); refsfound = NULL; } *lastfilepath = '\0'; /* last file may have new path */ } /* build the cross-reference */ static void build(void) { int i; FILE *oldrefs; /* old cross-reference file */ time_t reftime; /* old crossref modification time */ char *file; /* current file */ char *oldfile; /* file in old cross-reference */ char newdir[PATHLEN + 1]; /* directory in new cross-reference */ char olddir[PATHLEN + 1]; /* directory in old cross-reference */ char oldname[PATHLEN + 1]; /* name in old cross-reference */ int oldnum; /* number in old cross-ref */ struct stat statstruct; /* file status */ int firstfile; /* first source file in pass */ int lastfile; /* last source file in pass */ int built = 0; /* built crossref for these files */ int copied = 0; /* copied crossref for these files */ BOOL interactive = YES; /* output progress messages */ /* * normalize the current directory relative to the home directory so * the cross-reference is not rebuilt when the user's login is moved */ (void) strcpy(newdir, currentdir); if (strcmp(currentdir, home) == 0) { (void) strcpy(newdir, "$HOME"); } else if (strncmp(currentdir, home, strlen(home)) == 0) { (void) sprintf(newdir, "$HOME%s", currentdir + strlen(home)); } /* sort the source file names (needed for rebuilding) */ qsort((char *)srcfiles, (unsigned)nsrcfiles, sizeof (char *), compare); /* * if there is an old cross-reference and its current directory * matches or this is an unconditional build */ if ((oldrefs = vpfopen(reffile, "r")) != NULL && unconditional == NO && fscanf(oldrefs, "cscope %d %s", &fileversion, olddir) == 2 && (strcmp(olddir, currentdir) == 0 || /* remain compatible */ strcmp(olddir, newdir) == 0)) { /* get the cross-reference file's modification time */ (void) fstat(fileno(oldrefs), &statstruct); reftime = statstruct.st_mtime; if (fileversion >= 8) { BOOL oldcompress = YES; BOOL oldinvertedindex = NO; BOOL oldtruncatesyms = NO; int c; /* see if there are options in the database */ for (;;) { while ((c = getc(oldrefs)) == ' ') { } if (c != '-') { (void) ungetc(c, oldrefs); break; } switch (c = getc(oldrefs)) { case 'c': /* ASCII characters only */ oldcompress = NO; break; case 'q': /* quick search */ oldinvertedindex = YES; (void) fscanf(oldrefs, "%ld", &totalterms); break; case 'T': /* truncate symbols to 8 characters */ oldtruncatesyms = YES; break; } } /* check the old and new option settings */ if (oldcompress != compress || oldtruncatesyms != truncatesyms) { (void) fprintf(stderr, "cscope: -c or -T option mismatch between " "command line and old symbol database\n"); goto force; } if (oldinvertedindex != invertedindex) { (void) fprintf(stderr, "cscope: -q option mismatch between " "command line and old symbol database\n"); if (invertedindex == NO) { removeindex(); } goto outofdate; } /* seek to the trailer */ if (fscanf(oldrefs, "%ld", &traileroffset) != 1 || fseek(oldrefs, traileroffset, 0) == -1) { (void) fprintf(stderr, "cscope: incorrect symbol database file " "format\n"); goto force; } } /* if assuming that some files have changed */ if (fileschanged == YES) { goto outofdate; } /* see if the view path is the same */ if (fileversion >= 13 && samelist(oldrefs, vpdirs, vpndirs) == NO) { goto outofdate; } /* see if the directory lists are the same */ if (samelist(oldrefs, srcdirs, nsrcdirs) == NO || samelist(oldrefs, incdirs, nincdirs) == NO || fscanf(oldrefs, "%d", &oldnum) != 1 || fileversion >= 9 && fscanf(oldrefs, "%*s") != 0) { /* skip the string space size */ goto outofdate; } /* * see if the list of source files is the same and * none have been changed up to the included files */ for (i = 0; i < nsrcfiles; ++i) { if (fscanf(oldrefs, "%s", oldname) != 1 || strnotequal(oldname, srcfiles[i]) || vpstat(srcfiles[i], &statstruct) != 0 || statstruct.st_mtime > reftime) { goto outofdate; } } /* the old cross-reference is up-to-date */ /* so get the list of included files */ while (i++ < oldnum && fscanf(oldrefs, "%s", oldname) == 1) { addsrcfile(oldname); } (void) fclose(oldrefs); return; outofdate: /* if the database format has changed, rebuild it all */ if (fileversion != FILEVERSION) { (void) fprintf(stderr, "cscope: converting to new symbol database file " "format\n"); goto force; } /* reopen the old cross-reference file for fast scanning */ if ((symrefs = vpopen(reffile, O_RDONLY)) == -1) { cannotopen(reffile); myexit(1); } /* get the first file name in the old cross-reference */ blocknumber = -1; (void) readblock(); /* read the first cross-ref block */ (void) scanpast('\t'); /* skip the header */ oldfile = getoldfile(); } else { /* force cross-referencing of all the source files */ force: reftime = 0; oldfile = NULL; } /* open the new cross-reference file */ if ((newrefs = fopen(newreffile, "w")) == NULL) { cannotopen(newreffile); myexit(1); } if (invertedindex == YES && (postings = fopen(temp1, "w")) == NULL) { cannotopen(temp1); cannotindex(); } (void) fprintf(stderr, "cscope: building symbol database\n"); putheader(newdir); fileversion = FILEVERSION; if (buildonly == YES && !isatty(0)) { interactive = NO; } else { initprogress(); } /* output the leading tab expected by crossref() */ dbputc('\t'); /* * make passes through the source file list until the last level of * included files is processed */ firstfile = 0; lastfile = nsrcfiles; if (invertedindex == YES) { srcoffset = mymalloc((nsrcfiles + 1) * sizeof (long)); } for (;;) { /* get the next source file name */ for (fileindex = firstfile; fileindex < lastfile; ++fileindex) { /* display the progress about every three seconds */ if (interactive == YES && fileindex % 10 == 0) { if (copied == 0) { progress("%ld files built", (long)built, 0L); } else { progress("%ld files built, %ld " "files copied", (long)built, (long)copied); } } /* if the old file has been deleted get the next one */ file = srcfiles[fileindex]; while (oldfile != NULL && strcmp(file, oldfile) > 0) { oldfile = getoldfile(); } /* * if there isn't an old database or this is * a new file */ if (oldfile == NULL || strcmp(file, oldfile) < 0) { crossref(file); ++built; } else if (vpstat(file, &statstruct) == 0 && statstruct.st_mtime > reftime) { /* if this file was modified */ crossref(file); ++built; /* * skip its old crossref so modifying the last * source file does not cause all included files * to be built. Unfortunately a new file that * is alphabetically last will cause all * included files to be built, but this is * less likely */ oldfile = getoldfile(); } else { /* copy its cross-reference */ putfilename(file); if (invertedindex == YES) { copyinverted(); } else { copydata(); } ++copied; oldfile = getoldfile(); } } /* see if any included files were found */ if (lastfile == nsrcfiles) { break; } firstfile = lastfile; lastfile = nsrcfiles; if (invertedindex == YES) { srcoffset = myrealloc(srcoffset, (nsrcfiles + 1) * sizeof (long)); } /* sort the included file names */ qsort((char *)&srcfiles[firstfile], (unsigned)(lastfile - firstfile), sizeof (char *), compare); } /* add a null file name to the trailing tab */ putfilename(""); dbputc('\n'); /* get the file trailer offset */ traileroffset = dboffset; /* * output the view path and source and include directory and * file lists */ putlist(vpdirs, vpndirs); putlist(srcdirs, nsrcdirs); putlist(incdirs, nincdirs); putlist(srcfiles, nsrcfiles); if (fflush(newrefs) == EOF) { /* rewind doesn't check for write failure */ cannotwrite(newreffile); /* NOTREACHED */ } /* create the inverted index if requested */ if (invertedindex == YES) { char sortcommand[PATHLEN + 1]; if (fflush(postings) == EOF) { cannotwrite(temp1); /* NOTREACHED */ } (void) fstat(fileno(postings), &statstruct); (void) fprintf(stderr, "cscope: building symbol index: temporary file size is " "%ld bytes\n", statstruct.st_size); (void) fclose(postings); /* * sort -T is broken until it is fixed we don't have too much choice */ /* * (void) sprintf(sortcommand, "sort -y -T %s %s", tmpdir, temp1); */ (void) sprintf(sortcommand, "LC_ALL=C sort %s", temp1); if ((postings = popen(sortcommand, "r")) == NULL) { (void) fprintf(stderr, "cscope: cannot open pipe to sort command\n"); cannotindex(); } else { if ((totalterms = invmake(newinvname, newinvpost, postings)) > 0) { movefile(newinvname, invname); movefile(newinvpost, invpost); } else { cannotindex(); } (void) pclose(postings); } (void) unlink(temp1); (void) free(srcoffset); (void) fprintf(stderr, "cscope: index has %ld references to %ld symbols\n", npostings, totalterms); } /* rewrite the header with the trailer offset and final option list */ rewind(newrefs); putheader(newdir); (void) fclose(newrefs); /* close the old database file */ if (symrefs >= 0) { (void) close(symrefs); } if (oldrefs != NULL) { (void) fclose(oldrefs); } /* replace it with the new database file */ movefile(newreffile, reffile); } /* string comparison function for qsort */ static int compare(const void *s1, const void *s2) { return (strcmp((char *)s1, (char *)s2)); } /* get the next file name in the old cross-reference */ static char * getoldfile(void) { static char file[PATHLEN + 1]; /* file name in old crossref */ if (blockp != NULL) { do { if (*blockp == NEWFILE) { skiprefchar(); getstring(file); if (file[0] != '\0') { /* if not end-of-crossref */ return (file); } return (NULL); } } while (scanpast('\t') != NULL); } return (NULL); } /* * output the cscope version, current directory, database format options, and * the database trailer offset */ static void putheader(char *dir) { dboffset = fprintf(newrefs, "cscope %d %s", FILEVERSION, dir); if (compress == NO) { dboffset += fprintf(newrefs, " -c"); } if (invertedindex == YES) { dboffset += fprintf(newrefs, " -q %.10ld", totalterms); } else { /* * leave space so if the header is overwritten without -q * because writing the inverted index failed, the header is * the same length */ dboffset += fprintf(newrefs, " "); } if (truncatesyms == YES) { dboffset += fprintf(newrefs, " -T"); } dbfprintf(newrefs, " %.10ld\n", traileroffset); } /* put the name list into the cross-reference file */ static void putlist(char **names, int count) { int i, size = 0; (void) fprintf(newrefs, "%d\n", count); if (names == srcfiles) { /* calculate the string space needed */ for (i = 0; i < count; ++i) { size += strlen(names[i]) + 1; } (void) fprintf(newrefs, "%d\n", size); } for (i = 0; i < count; ++i) { if (fputs(names[i], newrefs) == EOF || putc('\n', newrefs) == EOF) { cannotwrite(newreffile); /* NOTREACHED */ } } } /* see if the name list is the same in the cross-reference file */ static BOOL samelist(FILE *oldrefs, char **names, int count) { char oldname[PATHLEN + 1]; /* name in old cross-reference */ int oldcount; int i; /* see if the number of names is the same */ if (fscanf(oldrefs, "%d", &oldcount) != 1 || oldcount != count) { return (NO); } /* see if the name list is the same */ for (i = 0; i < count; ++i) { if (fscanf(oldrefs, "%s", oldname) != 1 || strnotequal(oldname, names[i])) { return (NO); } } return (YES); } /* skip the list in the cross-reference file */ static void skiplist(FILE *oldrefs) { int i; if (fscanf(oldrefs, "%d", &i) != 1) { (void) fprintf(stderr, "cscope: cannot read list size from file %s\n", reffile); exit(1); } while (--i >= 0) { if (fscanf(oldrefs, "%*s") != 0) { (void) fprintf(stderr, "cscope: cannot read list name from file %s\n", reffile); exit(1); } } } /* copy this file's symbol data */ static void copydata(void) { char symbol[PATLEN + 1]; char *cp; setmark('\t'); cp = blockp; for (;;) { /* copy up to the next \t */ do { /* innermost loop optimized to only one test */ while (*cp != '\t') { dbputc(*cp++); } } while (*++cp == '\0' && (cp = readblock()) != NULL); dbputc('\t'); /* copy the tab */ /* get the next character */ if (*(cp + 1) == '\0') { cp = readblock(); } /* exit if at the end of this file's data */ if (cp == NULL || *cp == NEWFILE) { break; } /* look for an #included file */ if (*cp == INCLUDE) { blockp = cp; putinclude(symbol); putstring(symbol); setmark('\t'); cp = blockp; } } blockp = cp; } /* copy this file's symbol data and output the inverted index postings */ static void copyinverted(void) { char *cp; int c; int type; /* reference type (mark character) */ char symbol[PATLEN + 1]; /* note: this code was expanded in-line for speed */ /* while (scanpast('\n') != NULL) { */ /* other macros were replaced by code using cp instead of blockp */ cp = blockp; for (;;) { setmark('\n'); do { /* innermost loop optimized to only one test */ while (*cp != '\n') { dbputc(*cp++); } } while (*++cp == '\0' && (cp = readblock()) != NULL); dbputc('\n'); /* copy the newline */ /* get the next character */ if (*(cp + 1) == '\0') { cp = readblock(); } /* exit if at the end of this file's data */ if (cp == NULL) { break; } switch (*cp) { case '\n': lineoffset = dboffset + 1; continue; case '\t': dbputc('\t'); blockp = cp; type = getrefchar(); switch (type) { case NEWFILE: /* file name */ return; case INCLUDE: /* #included file */ putinclude(symbol); goto output; } dbputc(type); skiprefchar(); getstring(symbol); goto output; } c = *cp; if (c & 0200) { /* digraph char? */ c = dichar1[(c & 0177) / 8]; } /* if this is a symbol */ if (isalpha(c) || c == '_') { blockp = cp; getstring(symbol); type = ' '; output: putposting(symbol, type); putstring(symbol); if (blockp == NULL) { return; } cp = blockp; } } blockp = cp; } /* process the #included file in the old database */ static void putinclude(char *s) { dbputc(INCLUDE); skiprefchar(); getstring(s); incfile(s + 1, *s); } /* replace the old file with the new file */ static void movefile(char *new, char *old) { (void) unlink(old); if (link(new, old) == -1) { (void) perror("cscope"); (void) fprintf(stderr, "cscope: cannot link file %s to file %s\n", new, old); myexit(1); } if (unlink(new) == -1) { (void) perror("cscope"); (void) fprintf(stderr, "cscope: cannot unlink file %s\n", new); errorsfound = YES; } } /* enter curses mode */ void entercurses(void) { incurses = YES; (void) nonl(); /* don't translate an output \n to \n\r */ (void) cbreak(); /* single character input */ (void) noecho(); /* don't echo input characters */ (void) clear(); /* clear the screen */ initmouse(); /* initialize any mouse interface */ drawscrollbar(topline, nextline, totallines); atfield(); } /* exit curses mode */ void exitcurses(void) { /* clear the bottom line */ (void) move(LINES - 1, 0); (void) clrtoeol(); (void) refresh(); /* exit curses and restore the terminal modes */ (void) endwin(); incurses = NO; /* restore the mouse */ cleanupmouse(); (void) fflush(stdout); } /* no activity timeout occurred */ static void timedout(int sig) { /* if there is a child process, don't exit until it does */ if (childpid) { closedatabase(); noacttimeout = YES; return; } exitcurses(); (void) fprintf(stderr, "cscope: no activity for %d hours--exiting\n", noacttime / 3600); myexit(sig); } /* cleanup and exit */ void myexit(int sig) { /* deleted layer causes multiple signals */ (void) signal(SIGHUP, SIG_IGN); /* remove any temporary files */ if (temp1[0] != '\0') { (void) unlink(temp1); (void) unlink(temp2); } /* restore the terminal to its original mode */ if (incurses == YES) { exitcurses(); } /* dump core for debugging on the quit signal */ if (sig == SIGQUIT) { (void) abort(); } exit(sig); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 1999 by Sun Microsystems, Inc. * All rights reserved. */ /* * cscope - interactive C symbol cross-reference * * mouse menu functions */ #include "global.h" /* changing */ static MOUSEMENU mainmenu[] = { "Send", "##\033s##\r", "Repeat", "\01", "Rebuild", "\022", "Help", "?", "Exit", "\04", 0, 0 }; static MOUSEMENU changemenu[] = { "Mark Screen", "*", "Mark All", "a", "Change", "\04", "Continue", "\b", /* key that will be ignored at Select prompt */ "Help", "?", "Exit", "\r", 0, 0 }; /* initialize the mouse menu */ void initmenu(void) { if (changing == YES) { downloadmenu(changemenu); } else { downloadmenu(mainmenu); } } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* common mouse interface functions */ #include /* NULL */ #include /* NULL */ #include /* NULL */ #include /* isdigit */ #include "global.h" #define ctrl(x) (x & 037) MOUSETYPE mouse; static MOUSEMENU *loadedmenu; static BOOL changemenu = YES; /* see if there is a mouse interface */ void initmouse(void) { char *s, *term; if ((term = getenv("TERM")) == NULL) { return; } if (strcmp(term, "emacsterm") == 0 || strcmp(term, "viterm") == 0) { mouse = EMACSTERM; } else if ((s = getenv("MOUSE")) != NULL && strcmp(s, "myx") == 0) { /* * the MOUSE enviroment variable is for 5620 terminal * programs that have mouse support but the TERM environment * variable is the same as a terminal without a mouse, such * as myx */ mouse = MYX; } if ((s = getenv("MOUSEMENU")) != NULL && strcmp(s, "none") == 0) { changemenu = NO; } initmenu(); } /* reinitialize the mouse in case curses changed the attributes */ void reinitmouse(void) { if (mouse == EMACSTERM) { /* * enable the mouse click and sweep coordinate control * sequence */ (void) printf("\033{2"); if (changemenu) { (void) printf("\033#2"); /* switch to menu 2 */ } (void) fflush(stdout); } } /* restore any original mouse attributes not handled by terminfo */ void cleanupmouse(void) { int i; if (mouse == MYX && loadedmenu != NULL) { /* remove the mouse menu */ (void) printf("\033[6;0X\033[9;0X"); for (i = 0; loadedmenu[i].text != NULL; ++i) { (void) printf("\033[0;0x"); } loadedmenu = NULL; } } /* download a mouse menu */ void downloadmenu(MOUSEMENU *menu) { int i; int len; switch (mouse) { case EMACSTERM: reinitmouse(); (void) printf("\033V1"); /* display the scroll bar */ if (changemenu) { (void) printf("\033M0@%s@%s@", menu[0].text, menu[0].value); for (i = 1; menu[i].text != NULL; ++i) { (void) printf("\033M@%s@%s@", menu[i].text, menu[i].value); } } (void) fflush(stdout); break; case MYX: if (changemenu) { cleanupmouse(); (void) printf("\033[6;1X\033[9;1X"); for (i = 0; menu[i].text != NULL; ++i) { len = strlen(menu[i].text); (void) printf("\033[%d;%dx%s%s", len, len + strlen(menu[i].value), menu[i].text, menu[i].value); } (void) fflush(stdout); loadedmenu = menu; } break; case NONE: case PC7300: break; } } /* draw the scroll bar */ void drawscrollbar(int top, int bot, int total) { int p1, p2; if (mouse == EMACSTERM) { if (bot > top && total > 0) { p1 = 16 + (top - 1) * 100 / total; p2 = 16 + (bot - 1) * 100 / total; if (p2 > 116) { p2 = 116; } if (p1 < 16) { p1 = 16; } /* * don't send ^S or ^Q to avoid hanging a layer using * cu(1) */ if (p1 == ctrl('Q') || p1 == ctrl('S')) { ++p1; } if (p2 == ctrl('Q') || p2 == ctrl('S')) { ++p2; } } else { p1 = p2 = 16; } (void) printf("\033W%c%c", p1, p2); } } /* translate a mouse click or sweep to a selection */ int mouseselection(MOUSEEVENT *p, int offset, int maxselection) { int i; i = p->y1 - offset; if (i < 0) { i = 0; } else if (i >= maxselection) { i = maxselection - 1; } return (i); } /* get the mouse event */ MOUSEEVENT * getmouseevent(void) { static MOUSEEVENT m; if (mouse == EMACSTERM) { switch (mygetch()) { case ctrl('_'): /* click */ if ((m.button = mygetch()) == '0') { /* if scroll bar */ m.percent = getpercent(); } else { m.x1 = getcoordinate(); m.y1 = getcoordinate(); m.x2 = m.y2 = -1; } break; case ctrl(']'): /* sweep */ m.button = mygetch(); m.x1 = getcoordinate(); m.y1 = getcoordinate(); m.x2 = getcoordinate(); m.y2 = getcoordinate(); break; default: return (NULL); } return (&m); } return (NULL); } /* get a row or column coordinate from a mouse button click or sweep */ int getcoordinate(void) { int c, next; c = mygetch(); next = 0; if (c == ctrl('A')) { next = 95; c = mygetch(); } if (c < ' ') { return (0); } return (next + c - ' '); } /* get a percentage */ int getpercent(void) { int c; c = mygetch(); if (c < 16) { return (0); } if (c > 120) { return (100); } return (c - 16); } /* update the window label area */ int labelarea(char *s) { static BOOL labelon; switch (mouse) { case EMACSTERM: if (labelon == NO) { labelon = YES; (void) printf("\033L1"); /* force it on */ } (void) printf("\033L!%s!", s); return (1); case MYX: (void) printf("\033[?%dv%s", strlen(s), s); return (1); case NONE: case PC7300: default: return (0); /* no label area */ } } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 1999 by Sun Microsystems, Inc. * All rights reserved. */ typedef struct { int button; int percent; int x1; int y1; int x2; int y2; } MOUSEEVENT; typedef struct { char *text; char *value; } MOUSEMENU; typedef enum { NONE, /* must be first value */ EMACSTERM, MYX, PC7300 } MOUSETYPE; extern MOUSETYPE mouse; extern int mouseselection(MOUSEEVENT *p, int offset, int maxselection); extern void cleanupmouse(void); extern void drawscrollbar(int top, int bot, int total); extern int getcoordinate(void); extern MOUSEEVENT *getmouseevent(void); extern int getpercent(void); extern void initmouse(void); extern int labelarea(char *s); extern void reinitmouse(void); extern void downloadmenu(MOUSEMENU *menu); /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 1999 by Sun Microsystems, Inc. * All rights reserved. */ /* return the non-null environment value or the default argument */ #include #include char * mygetenv(char *variable, char *deflt) { char *value; value = getenv(variable); if (value == (char *)NULL || *value == '\0') { return (deflt); } return (value); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 1999 by Sun Microsystems, Inc. * All rights reserved. */ #include /* needed by stat.h */ #include /* stat */ #include /* NULL */ #include /* string functions */ #include /* * if the ksh PWD environment variable matches the current * working directory, don't call getwd() */ char * mygetwd(char *dir) { char *pwd; /* PWD environment variable value */ struct stat d_sb; /* current directory status */ struct stat tmp_sb; /* temporary stat buffer */ char *getwd(); /* get the current directory's status */ if (stat(".", &d_sb) < 0) { return (NULL); } /* use $PWD if it matches this directory */ if ((pwd = getenv("PWD")) != NULL && *pwd != '\0' && stat(pwd, &tmp_sb) == 0 && d_sb.st_ino == tmp_sb.st_ino && d_sb.st_dev == tmp_sb.st_dev) { (void) strcpy(dir, pwd); return (pwd); } return (getwd(dir)); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 1999 by Sun Microsystems, Inc. * All rights reserved. */ #include #include #include #include #include #include #include #include "global.h" /* pid_t, SIGTYPE, shell, and basename() */ #define tst(a, b) (*mode == 'r'? (b) : (a)) #define RDR 0 #define WTR 1 static pid_t popen_pid[20]; static SIGTYPE (*tstat)(); FILE * mypopen(char *cmd, char *mode) { int p[2]; pid_t *poptr; int myside, yourside; pid_t pid; if (pipe(p) < 0) return (NULL); myside = tst(p[WTR], p[RDR]); yourside = tst(p[RDR], p[WTR]); if ((pid = fork()) > 0) { tstat = signal(SIGTSTP, SIG_DFL); } else if (pid == 0) { /* myside and yourside reverse roles in child */ int stdio; /* close all pipes from other popen's */ for (poptr = popen_pid; poptr < popen_pid+20; poptr++) { if (*poptr) (void) close(poptr - popen_pid); } stdio = tst(0, 1); (void) close(myside); (void) close(stdio); (void) fcntl(yourside, F_DUPFD, stdio); (void) close(yourside); (void) execlp(shell, basename(shell), "-c", cmd, 0); _exit(1); } if (pid == -1) return (NULL); popen_pid[myside] = pid; (void) close(yourside); return (fdopen(myside, mode)); } int mypclose(FILE *ptr) { int f; pid_t r; int status; SIGTYPE (*hstat)(), (*istat)(), (*qstat)(); f = fileno(ptr); (void) fclose(ptr); istat = signal(SIGINT, SIG_IGN); qstat = signal(SIGQUIT, SIG_IGN); hstat = signal(SIGHUP, SIG_IGN); while ((r = wait(&status)) != popen_pid[f] && r != -1) { } if (r == -1) status = -1; (void) signal(SIGINT, istat); (void) signal(SIGQUIT, qstat); (void) signal(SIGHUP, hstat); (void) signal(SIGTSTP, tstat); /* mark this pipe closed */ popen_pid[f] = 0; return (status); } %{ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * cscope - interactive C symbol cross-reference * * * C symbol scanner */ #ident "@(#)scanner.l 1.2 93/06/07 SMI" #include "global.h" /* the line counting has been moved from character reading for speed */ /* comments are discarded */ #undef input #define input() \ ((yytchar = (yytchar = yysptr > yysbuf ? \ *--yysptr : getc(yyin)) == '/' ? comment() : yytchar) == \ EOF ? 0 : toascii(yytchar)) #define noncommentinput() \ ((yytchar = yysptr > yysbuf ? *--yysptr : getc(yyin)) == \ EOF ? 0 : yytchar) #undef unput #define unput(c) (*yysptr++ = (c)) /* not a preprocessor line (allow Ingres(TM) "## char var;" lines) */ #define notpp() (ppdefine == NO && (*yytext != '#' || yytext[1] == '#')) #define IFLEVELINC 5 /* #if nesting level size increment */ /* keyword text for fast testing of keywords in the scanner */ extern char externtext[]; extern char typedeftext[]; int first; /* buffer index for first char of symbol */ int last; /* buffer index for last char of symbol */ int lineno; /* symbol line number */ static BOOL arraydimension; /* inside array dimension declaration */ static BOOL bplisting; /* breakpoint listing */ static int braces; /* unmatched left brace count */ static int cesudeftoken; /* class/enum/struct/union definition */ static BOOL classdef; /* c++ class definition */ static BOOL elseelif; /* #else or #elif found */ static BOOL esudef; /* enum/struct/union definition */ static int esubraces; /* outermost enum/struct/union */ /* brace count */ static BOOL externdec; /* extern declaration */ static BOOL fcndef; /* function definition */ static BOOL globalscope; /* file global scope */ /* (outside functions) */ static int iflevel; /* #if nesting level */ static BOOL initializer; /* data initializer */ static int initializerbraces; /* data initializer outer brace count */ static BOOL lex; /* lex file */ static BOOL localdef; /* function/block local definition */ static int miflevel = IFLEVELINC; /* maximum #if nesting level */ static int *maxifbraces; /* maximum brace count within #if */ static int *preifbraces; /* brace count before #if */ static int parens; /* unmatched left parenthesis count */ static BOOL ppdefine; /* preprocessor define statement */ static BOOL psuedoelif; /* psuedo-#elif */ static BOOL oldtype; /* next identifier is an old type */ static BOOL rules; /* lex/yacc rules */ static BOOL sdl; /* SDL file */ static BOOL structfield; /* structure field declaration */ static BOOL template; /* function template */ static int templateparens; /* function template outer parentheses count */ static BOOL typedefdef; /* typedef name definition */ static BOOL typedefname; /* typedef name use */ static int token; /* token found */ static BOOL asy; /* assembly file */ void multicharconstant(char terminator); int do_assembly(int token); %} identifier [a-zA-Z_][a-zA-Z_0-9]* number \.?[0-9][.0-9a-fA-FlLuUxX]* %start SDL %a 6000 %o 11000 %p 3000 %% %\{ { /* lex/yacc C declarations/definitions */ globalscope = YES; goto more; /* NOTREACHED */ } %\} { globalscope = NO; goto more; /* NOTREACHED */ } ^%% { /* lex/yacc rules delimiter */ braces = 0; if (rules == NO) { rules = YES; /* simulate a yylex() or yyparse() definition */ (void) strcat(yytext, " /* "); first = strlen(yytext); if (lex == YES) { (void) strcat(yytext, "yylex"); } else { /* * yacc: yyparse implicitly calls yylex */ char *s = " yylex()"; char *cp = s + strlen(s); while (--cp >= s) { unput(*cp); } (void) strcat(yytext, "yyparse"); } last = strlen(yytext); (void) strcat(yytext, " */"); yyleng = strlen(yytext); yymore(); return (FCNDEF); } else { rules = NO; globalscope = YES; last = first; yymore(); return (FCNEND); } /* NOTREACHED */ } (PROCEDURE|STATE)[ \t]+({identifier}|\*) { /* SDL procedure or state */ braces = 1; fcndef = YES; /* treat as function definition */ token = FCNDEF; globalscope = NO; goto findident; /* NOTREACHED */ } (CALL|NEXTSTATE)[ \t]+({identifier}|\*) { /* SDL call or nextstate */ token = FCNCALL; goto findident; /* treat as function call */ /* NOTREACHED */ } END(PROCEDURE|STATE)[ \t]+({identifier}|\*) { /* end of an SDL procedure or state */ goto endstate; /* treat as the end of a function */ /* NOTREACHED */ } \{ { /* count unmatched left braces for fcn def detection */ ++braces; /* * mark an untagged enum/struct/union so its beginning * can be found */ if (cesudeftoken) { last = first; savesymbol(cesudeftoken); cesudeftoken = '\0'; } goto more; /* NOTREACHED */ } \#[ \t]*endif/.*[\n\r][ \t\n\r]*#[ \t]*if { /* * attempt to correct erroneous brace count caused by: * * #if ... * ... { * #endif * #if ... * ... { * #endif */ /* the current #if must not have an #else or #elif */ if (elseelif == YES) { goto endif; } psuedoelif = YES; goto more; /* NOTREACHED */ } \#[ \t]*ifn?(def)? { /* #if, #ifdef or #ifndef */ elseelif = NO; if (psuedoelif == YES) { psuedoelif = NO; goto elif; } /* * make sure there is room for the current brace count */ if (iflevel == miflevel) { miflevel += IFLEVELINC; maxifbraces = myrealloc(maxifbraces, miflevel * sizeof (int)); preifbraces = myrealloc(preifbraces, miflevel * sizeof (int)); } /* push the current brace count */ preifbraces[iflevel] = braces; maxifbraces[iflevel++] = 0; goto more; /* NOTREACHED */ } \#[ \t]*el(se|if) { /* #elif or #else */ elseelif = YES; elif: if (iflevel > 0) { /* save the maximum brace count for this #if */ if (braces > maxifbraces[iflevel]) { maxifbraces[iflevel - 1] = braces; } /* restore the brace count to before the #if */ braces = preifbraces[iflevel - 1]; } goto more; /* NOTREACHED */ } \#[ \t]*endif { /* #endif */ endif: if (iflevel > 0) { /* get the maximum brace count for this #if */ if (braces < maxifbraces[--iflevel]) { braces = maxifbraces[iflevel]; } } goto more; /* NOTREACHED */ } \} { /* could be the last enum member initializer */ if (braces == initializerbraces) { initializerbraces = -1; initializer = NO; } if (--braces <= 0) { endstate: braces = 0; classdef = NO; } /* * if the end of an outermost enum/struct/union * definition */ if (esudef == YES && braces == esubraces) { esudef = NO; esubraces = -1; last = first; yymore(); return (ESUEND); } /* if the end of a function */ if ((braces == 0 || braces == 1 && classdef == YES) && fcndef == YES) { fcndef = NO; globalscope = YES; last = first; yymore(); return (FCNEND); } goto more; /* NOTREACHED */ } \( { /* * count unmatched left parentheses for function * templates */ ++parens; goto more; /* NOTREACHED */ } \) { if (--parens <= 0) { parens = 0; } /* if the end of a function template */ if (parens == templateparens) { templateparens = -1; template = NO; } goto more; /* NOTREACHED */ } = { /* if a global definition initializer */ if ((globalscope == YES || localdef == YES) && notpp()) { initializerbraces = braces; initializer = YES; } goto more; /* NOTREACHED */ } : { /* if a structure field */ /* note: a pr header has a colon in the date */ if (esudef == YES && notpp()) { structfield = YES; } goto more; /* NOTREACHED */ } \, { if (braces == initializerbraces) { initializerbraces = -1; initializer = NO; } structfield = NO; goto more; /* NOTREACHED */ } "##" | /* start of Ingres(TM) code line */ ; { /* if not in an enum/struct/union declaration */ if (esudef == NO) { externdec = NO; typedefdef = NO; localdef = NO; } structfield = NO; initializer = NO; oldtype = NO; goto more; /* NOTREACHED */ } \#[ \t]*define[ \t]+{identifier} { /* preprocessor macro or constant definition */ ppdefine = YES; token = DEFINE; if (compress == YES) { /* compress the keyword */ yytext[0] = '\7'; } findident: first = yyleng - 1; while (isalnum(yytext[first]) || yytext[first] == '_') { --first; } ++first; goto iflongline; /* NOTREACHED */ } class[ \t]+{identifier}[ \t\n\ra-zA-Z0-9_():]*\{ { /* class definition */ classdef = YES; cesudeftoken = 'c'; REJECT; /* NOTREACHED */ } (enum|struct|union)/([ \t\n\r]+{identifier})?[ \t\n\r]*\{ { /* enum/struct/union definition */ esudef = YES; if (esubraces < 0) { /* if outermost enum/struct/union */ esubraces = braces; } cesudeftoken = *(yytext + first); goto iflongline; /* NOTREACHED */ } {identifier}/[ \t]*\(([ \t\n\ra-zA-Z0-9_*&[\]=,.]*|\([ \ta-zA-Z0-9_*[\],]*\))*\)[ \t\n\r()]*[:a-zA-Z_#{] { /* * warning: "if (...)" must not overflow yytext, so * the content of function argument definitions is * restricted, in particular parentheses are * not allowed */ if (asy) { /* * In assembly files, if it looks like * a definition, pass it down as one and we'll * take care of it later. */ token = FCNDEF; goto iflongline; } /* if a function definition */ /* * note: "#define a (b) {" and "#if defined(a)\n#" * are not */ if (braces == 0 && notpp() && rules == NO || braces == 1 && classdef == YES) { fcndef = YES; token = FCNDEF; globalscope = NO; goto iflongline; } goto iffcncall; /* NOTREACHED */ } {identifier}/[ \t]*\( { if (asy) { /* * Macro calls can get here if they have * arguments which contain %'s (i.e., * registers). */ token = FCNDEF; goto iflongline; } /* if a function call */ iffcncall: if ((fcndef == YES || ppdefine == YES || rules == YES) && externdec == NO && (localdef == NO || initializer == YES)) { token = FCNCALL; goto iflongline; } if (template == NO && typedefdef == NO) { templateparens = parens; template = YES; } token = IDENT; goto iflongline; /* NOTREACHED */ } (\+\+|--)[ \t]*{identifier} { /* prefix increment or decrement */ token = ASSIGNMENT; goto findident; /* NOTREACHED */ } {identifier}/[ \t]*(\+\+|--) { /* postfix increment or decrement */ token = ASSIGNMENT; goto iflongline; /* NOTREACHED */ } \*[ \t]*{identifier}/[ \t]*[^a-zA-Z0-9_(+-][^+-] { /* indirect assignment or dcl */ while (!isalnum(yytext[first]) && yytext[first] != '_') { ++first; } goto ident; /* NOTREACHED */ } {identifier}/[ \t\n\r]*(=[^=]|[-+*/%&^|]=|<<=|>>=) { /* assignment */ if ((fcndef == YES || ppdefine == YES || rules == YES) && localdef == NO) { token = ASSIGNMENT; goto iflongline; } goto ident; /* NOTREACHED */ } {identifier}/[* \t\n\r]+[a-zA-Z0-9_] { /* possible typedef name use */ if (notpp() && esudef == NO && fcndef == YES && typedefdef == NO && parens == 0) { char c, *s = yytext + first - 1; while (--s >= yytext && (c = *s) != ';' && c != '{') { if (!isspace(c) && !isalpha(c)) { goto nottypedefname; } } typedefname = YES; } nottypedefname: /* skip the global/parameter/local tests */ token = IDENT; goto iflongline; /* NOTREACHED */ } {identifier} { struct keystruct *p; char *s; ident: token = IDENT; if (notpp() && externdec == NO && arraydimension == NO && initializer == NO) { /* if an enum/struct/union member definition */ if (esudef == YES) { if (structfield == NO) { token = MEMBERDEF; } } else if (typedefdef == YES && oldtype == NO) { /* if a typedef name */ token = TYPEDEF; } else if (globalscope == YES && template == NO && oldtype == NO) { /* if a global definition */ token = GLOBALDEF; } else if (fcndef == YES && braces == 0) { /* if a function parameter definition */ token = PARAMETER; } else if (localdef == YES) { /* if a local definition */ token = LOCALDEF; } } iflongline: /* if a long line */ if (yyleng > STMTMAX) { int c; /* skip to the end of the line */ warning("line too long"); while ((c = input()) != LEXEOF) { if (c == '\n') { unput(c); break; } } } /* truncate a long symbol */ if (yyleng - first > PATLEN) { warning("symbol too long"); yyleng = first + PATLEN; yytext[yyleng] = '\0'; } yymore(); if (asy) { int t; last = yyleng; t = do_assembly(token); if (t >= 0) { token = t; return (token); } goto end; } /* if a keyword */ if ((p = lookup(yytext + first)) != NULL) { first = yyleng; s = p->text; /* if an extern declaration */ if (s == externtext) { externdec = YES; } else if (s == typedeftext) { /* if a typedef name definition */ typedefdef = YES; oldtype = YES; } else if (p->type == DECL && fcndef == YES && typedefdef == NO && parens == 0) { /* if a local definition */ localdef = YES; } else if (templateparens == parens && template == YES) { /* * keyword doesn't start a function * template */ templateparens = -1; template = NO; } else { /* * next identifier after typedef was * a keyword */ oldtype = NO; } typedefname = NO; } else { /* identifier */ last = yyleng; /* * if an enum/struct/union keyword preceded * this ident. */ if (esudef == YES && cesudeftoken) { token = cesudeftoken; cesudeftoken = '\0'; } else { oldtype = NO; } /* if a local definition using a typedef name */ if (typedefname == YES) { localdef = YES; } typedefname = NO; return (token); } end: ; } \[ { /* array dimension (don't worry about subscripts) */ arraydimension = YES; goto more; /* NOTREACHED */ } \] { arraydimension = NO; goto more; /* NOTREACHED */ } \\\n { /* preprocessor statement is continued on next line */ goto eol; /* NOTREACHED */ } \n { /* end of the line */ if (ppdefine == YES) { /* end of a #define */ ppdefine = NO; (void) yyless(yyleng - 1); /* rescan \n */ last = first; yymore(); return (DEFINEEND); } /* * skip the first 8 columns of a breakpoint listing * line and skip the file path in the page header */ if (bplisting == YES) { int c, i; switch (input()) { /* tab and EOF just fall through */ case ' ': /* breakpoint number line */ case '[': for (i = 1; i < 8 && input() != LEXEOF; ++i) { /*EMPTY*/ } break; case '.': /* header line */ case '/': /* skip to the end of the line */ while ((c = input()) != LEXEOF) { if (c == '\n') { unput(c); break; } } break; case '\n': /* empty line */ unput('\n'); break; } } eol: ++yylineno; first = 0; last = 0; if (symbols > 0) { return (NEWLINE); } lineno = yylineno; } \' { /* character constant */ if (sdl == NO) { multicharconstant('\''); } goto more; /* NOTREACHED */ } \" { /* string constant */ multicharconstant('"'); goto more; /* NOTREACHED */ } ^[ \t\f\b]+ { /* don't save leading white space */ } \#[# \t]*include[ \t]*["<][^"> \t\n\r]+ { /* #include or Ingres ##include */ char *s; s = strpbrk(yytext, "\"<"); incfile(s + 1, *s); first = s - yytext; last = yyleng; if (compress == YES) { /* compress the keyword */ yytext[0] = '\1'; } /* * avoid multicharconstant call triggered by trailing * ", which puts a trailing comment in the database */ if (*s == '"') { int c; while ((c = input()) != LEXEOF) { if (c == '"') { yytext[yyleng] = '"'; yytext[++yyleng] = '\0'; break; } /* the trailing '"' may be missing */ if (c == '\n') { unput('\n'); break; } } } yymore(); return (INCLUDE); /* NOTREACHED */ } \#[ \t]*pragma[ \t]+weak[ \t]+{identifier} { ppdefine = YES; token = DEFINE; goto findident; /*NOTREACHED*/ } \#[ \t]*{identifier} | /* preprocessor keyword */ {number} | /* number */ . { /* punctuation and operators */ more: first = yyleng; yymore(); } %% void initscanner(char *srcfile) { char *s; if (maxifbraces == NULL) { maxifbraces = mymalloc(miflevel * sizeof (int)); preifbraces = mymalloc(miflevel * sizeof (int)); } first = 0; /* buffer index for first char of symbol */ last = 0; /* buffer index for last char of symbol */ lineno = 1; /* symbol line number */ yylineno = 1; /* input line number */ arraydimension = NO; /* inside array dimension declaration */ bplisting = NO; /* breakpoint listing */ braces = 0; /* unmatched left brace count */ cesudeftoken = '\0'; /* class/enum/struct/union definition */ classdef = NO; /* c++ class definition */ elseelif = NO; /* #else or #elif found */ esudef = NO; /* enum/struct/union definition */ esubraces = -1; /* outermost enum/struct/union brace count */ externdec = NO; /* extern declaration */ fcndef = NO; /* function definition */ globalscope = YES; /* file global scope (outside functions) */ iflevel = 0; /* #if nesting level */ initializer = NO; /* data initializer */ initializerbraces = -1; /* data initializer outer brace count */ lex = NO; /* lex file */ localdef = NO; /* function/block local definition */ parens = 0; /* unmatched left parenthesis count */ ppdefine = NO; /* preprocessor define statement */ psuedoelif = NO; /* psuedo-#elif */ oldtype = NO; /* next identifier is an old type */ rules = NO; /* lex/yacc rules */ sdl = NO; /* SDL file */ structfield = NO; /* structure field declaration */ template = NO; /* function template */ templateparens = -1; /* function template outer parentheses count */ typedefdef = NO; /* typedef name definition */ typedefname = NO; /* typedef name use */ asy = NO; /* assembly file */ BEGIN 0; /* if this is not a C file */ if ((s = strrchr(srcfile, '.')) != NULL) { switch (*++s) { /* this switch saves time on C files */ case 'b': if (strcmp(s, "bp") == 0) { /* breakpoint listing */ bplisting = YES; } break; case 'l': if (strcmp(s, "l") == 0) { /* lex */ lex = YES; globalscope = NO; } break; case 'p': case 's': if (strcmp(s, "pr") == 0 || strcmp(s, "sd") == 0) { /* SDL */ sdl = YES; BEGIN SDL; } else if (strcmp(s, "s") == 0) { asy = YES; } break; case 'y': if (strcmp(s, "y") == 0) { /* yacc */ globalscope = NO; } break; } } } int comment(void) { int c, lastc; do { if ((c = getc(yyin)) == '*') { /* C comment */ lastc = '\0'; while ((c = getc(yyin)) != EOF && (c != '/' || lastc != '*')) { /* fewer '/'s */ if (c == '\n') { ++yylineno; } lastc = c; } /* return a blank for Reiser cpp token concatenation */ if ((c = getc(yyin)) == '_' || isalnum(c)) { (void) ungetc(c, yyin); c = ' '; break; } } else if (c == '/') { /* C++ comment */ while ((c = getc(yyin)) != EOF && c != '\n') { /*EMPTY*/ } break; } else { /* not a comment */ (void) ungetc(c, yyin); c = '/'; break; } /* there may be an immediately following comment */ } while (c == '/'); return (c); } void multicharconstant(char terminator) { char c; /* scan until the terminator is found */ while ((c = yytext[yyleng++] = noncommentinput()) != terminator) { switch (c) { case '\\': /* escape character */ if ((yytext[yyleng++] = noncommentinput()) == '\n') { ++yylineno; } break; case '\t': /* tab character */ /* if not a lex program, continue */ if (lex == NO) { break; } /* FALLTHROUGH */ case '\n': /* illegal character */ /* * assume the terminator is missing, so put * this character back */ unput(c); yytext[--yyleng] = '\0'; /* FALLTHROUGH */ case LEXEOF: /* end of file */ return; default: /* change a control character to a blank */ if (!isprint(c)) { yytext[yyleng - 1] = ' '; } } /* if this token will overflow the line buffer */ /* note: '\\' may cause yyleng to be > STMTMAX */ if (yyleng >= STMTMAX) { /* truncate the token */ while ((c = noncommentinput()) != LEXEOF) { if (c == terminator) { unput(c); break; } else if (c == '\n') { ++yylineno; } } } } yytext[yyleng] = '\0'; } /* * Returns true if the beginning of str matches ident, and the next character * is not alphanumeric and not an underscore. */ int identcmp(const char *str, const char *ident) { int n = strlen(ident); return (strncmp(str, ident, n) == 0 && !isalnum(str[n]) && str[n] != '_'); } /* * Here we want to * - Make *ENTRY*() macro invocations into function definitions * - Make SET_SIZE() macro calls into function ends * - Make "call sym" instructions into function calls * - Eliminate C function definitions (since they are for lint, and we want * only one definition for each function) */ int do_assembly(int token) { /* Handle C keywords? */ switch (token) { case FCNDEF: /* * We have a symbol that looks like a C function definition or * call. (Note: That can include assembly instructions with * the right parentheses.) We want to convert assembly macro * invocations to function calls, and ignore everything else. * Since we technically can't tell the difference, we'll use * an all-caps heuristic. * * ... except for SET_SIZE macros, since they will precede * FUNCEND tokens, which will break code in find.c which * assumes that FUNCEND tokens occur at the beginning of * lines. */ if (isupper(yytext[first]) && strcmp(yytext, "SET_SIZE") != 0) return (FCNCALL); /* Don't return a token. */ return (-1); case GLOBALDEF: case IDENT: /* Macro arguments come down as global variable definitions. */ if (identcmp(yytext, "ENTRY") || identcmp(yytext, "ENTRY2") || identcmp(yytext, "ENTRY_NP") || identcmp(yytext, "ENTRY_NP2") || identcmp(yytext, "RTENTRY") || identcmp(yytext, "ALTENTRY")) { /* * Identifiers on lines beginning with *ENTRY* macros * are actually function definitions. */ return (FCNDEF); } if (identcmp(yytext, "SET_SIZE")) { /* * Identifiers on lines beginning with SET_SIZE are * actually function ends. */ return (FCNEND); } if (first != 0 && identcmp(yytext, "call")) { /* * Make this a function call. We exclude first == 0, * because that happens when we're looking at "call" * itself. (Then we'd get function calls to "call" * everywhere.) */ return (FCNCALL); } /* FALLTHROUGH */ default: /* Default to normal behavior. */ return (token); } } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * cscope - interactive C symbol cross-reference * * Changing the cross-reference file part of the program version * forces rebuilding of the cross-reference. */ /* * Copyright (c) 1999 by Sun Microsystems, Inc. * All rights reserved. */ #define FILEVERSION 13 /* symbol database file format version */ #define FIXVERSION ".4" /* feature and bug fix version */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * VPATH assumptions: * VPATH is the environment variable containing the view path * where each path name is followed by ':', '\n', or '\0'. * Embedded blanks are considered part of the path. */ /* * Copyright (c) 1999 by Sun Microsystems, Inc. * All rights reserved. */ #include #define MAXPATH PATH_MAX /* max length for entire name */ extern char **vpdirs; /* directories (including current) in */ /* view path */ extern int vpndirs; /* number of directories in view path */ extern void vpinit(char *); extern int vpaccess(char *path, mode_t amode); /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 1999 by Sun Microsystems, Inc. * All rights reserved. */ /* vpaccess - view path version of the access system call */ #include #include #include #include "vp.h" int vpaccess(char *path, mode_t amode) { char buf[MAXPATH + 1]; int returncode; int i; if ((returncode = access(path, amode)) == -1 && path[0] != '/') { vpinit((char *)0); for (i = 1; i < vpndirs; i++) { (void) sprintf(buf, "%s/%s", vpdirs[i], path); if ((returncode = access(buf, amode)) != -1) { break; } } } return (returncode); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 1999 by Sun Microsystems, Inc. * All rights reserved. */ /* vpfopen - view path version of the fopen library function */ #include #include #include #include #include "vp.h" FILE * vpfopen(char *filename, char *type) { char buf[MAXPATH + 1]; FILE *returncode; int i; if ((returncode = fopen(filename, type)) == NULL && filename[0] != '/' && strcmp(type, "r") == 0) { vpinit((char *)0); for (i = 1; i < vpndirs; i++) { (void) sprintf(buf, "%s/%s", vpdirs[i], filename); if ((returncode = fopen(buf, type)) != NULL) { break; } } } return (returncode); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 1999 by Sun Microsystems, Inc. * All rights reserved. */ /* vpinit - initialize vpdirs or update vpdirs based on currentdir */ #include #include /* string functions */ #include #include /* stderr */ #include "vp.h" #include "library.h" char **vpdirs; /* directories (including current) in view path */ int vpndirs; /* number of directories in view path */ char *argv0 = "libvp"; /* command name default for messages */ void vpinit(char *currentdir) { char *suffix; /* path from view path node */ char *vpath; /* VPATH environment variable value */ char buf[MAXPATH + 1]; int i; char *s; /* if an existing directory list is to be updated, free it */ if (currentdir != NULL && vpndirs > 0) { for (i = 0; i < vpndirs; ++i) { free(vpdirs[i]); } free(vpdirs); vpndirs = 0; } /* return if the directory list has been computed */ /* or there isn't a view path environment variable */ if (vpndirs > 0 || (vpath = getenv("VPATH")) == NULL || *vpath == '\0') { return; } /* if not given, get the current directory name */ if (currentdir == NULL && (currentdir = mygetwd(buf)) == NULL) { (void) fprintf(stderr, "%s: cannot get current directory name\n", argv0); return; } /* see if this directory is in the first view path node */ for (i = 0; vpath[i] == currentdir[i] && vpath[i] != '\0'; ++i) { ; } if (i == 0 || (vpath[i] != ':' && vpath[i] != '\0') || (currentdir[i] != '/' && currentdir[i] != '\0')) { return; } suffix = ¤tdir[i]; /* count the nodes in the view path */ vpndirs = 1; for (s = vpath; *s != '\0'; ++s) { if (*s == ':' && *(s + 1) != ':' && *(s + 1) != '\0') { ++vpndirs; } } /* create the source directory list */ vpdirs = (char **)mymalloc(vpndirs * sizeof (char *)); /* don't change VPATH in the environment */ vpath = stralloc(vpath); /* split the view path into nodes */ for (i = 0, s = vpath; i < vpndirs && *s != '\0'; ++i) { while (*s == ':') { /* ignore null nodes */ ++s; } vpdirs[i] = s; while (*s != '\0' && *++s != ':') { if (*s == '\n') { *s = '\0'; } } if (*s != '\0') { *s++ = '\0'; } } /* convert the view path nodes to directories */ for (i = 0; i < vpndirs; ++i) { s = mymalloc((strlen(vpdirs[i]) + strlen(suffix) + 1)); (void) strcpy(s, vpdirs[i]); (void) strcat(s, suffix); vpdirs[i] = s; } free(vpath); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 1999 by Sun Microsystems, Inc. * All rights reserved. */ /* vpopen - view path version of the open system call */ #include #include #include #include #include "vp.h" #define READ 0 int vpopen(char *path, int oflag) { char buf[MAXPATH + 1]; int returncode; int i; if ((returncode = open(path, oflag, 0666)) == -1 && *path != '/' && oflag == READ) { vpinit((char *)0); for (i = 1; i < vpndirs; i++) { (void) sprintf(buf, "%s/%s", vpdirs[i], path); if ((returncode = open(buf, oflag, 0666)) != -1) { break; } } } return (returncode); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 1999 by Sun Microsystems, Inc. * All rights reserved. */ /* vpstat - view path version of the stat system call */ #include #include #include #include "vp.h" int vpstat(char *path, struct stat *statp) { char buf[MAXPATH + 1]; int returncode; int i; if ((returncode = stat(path, statp)) == -1 && path[0] != '/') { vpinit((char *)0); for (i = 1; i < vpndirs; i++) { (void) sprintf(buf, "%s/%s", vpdirs[i], path); if ((returncode = stat(buf, statp)) != -1) { break; } } } return (returncode); }