X-Git-Url: https://pd.if.org/git/?p=pd_readline;a=blobdiff_plain;f=mg%2Ftags.c;fp=mg%2Ftags.c;h=0000000000000000000000000000000000000000;hp=92d1425e79efee5b563921b6348fe3144961d8dd;hb=4bb27266f935c9aafad6870ffc8847fc65c8120f;hpb=3f771e17236364ded86e96ee64f99344337991f8 diff --git a/mg/tags.c b/mg/tags.c deleted file mode 100644 index 92d1425..0000000 --- a/mg/tags.c +++ /dev/null @@ -1,533 +0,0 @@ -/* $OpenBSD: tags.c,v 1.5 2012/07/02 08:08:31 lum Exp $ */ - -/* - * This file is in the public domain. - * - * Author: Sunil Nimmagadda - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "def.h" - -struct ctag; - -static int addctag(char *); -static int atbow(void); -void closetags(void); -static int ctagcmp(struct ctag *, struct ctag *); -static int loadbuffer(char *); -static int loadtags(const char *); -static int pushtag(char *); -static int searchpat(char *); -static struct ctag *searchtag(char *); -static char *strip(char *, size_t); -static void unloadtags(void); - -#define DEFAULTFN "tags" - -char *tagsfn = NULL; -int loaded = FALSE; - -/* ctags(1) entries are parsed and maintained in a tree. */ -struct ctag { - RB_ENTRY(ctag) entry; - char *tag; - char *fname; - char *pat; -}; -RB_HEAD(tagtree, ctag) tags = RB_INITIALIZER(&tags); -RB_GENERATE(tagtree, ctag, entry, ctagcmp); - -struct tagpos { - SLIST_ENTRY(tagpos) entry; - int doto; - int dotline; - char *bname; -}; -SLIST_HEAD(tagstack, tagpos) shead = SLIST_HEAD_INITIALIZER(shead); - -int -ctagcmp(struct ctag *s, struct ctag *t) -{ - return strcmp(s->tag, t->tag); -} - -/* - * Record the filename that contain tags to be used while loading them - * on first use. If a filename is already recorded, ask user to retain - * already loaded tags (if any) and unload them if user chooses not to. - */ -/* ARGSUSED */ -int -tagsvisit(int f, int n) -{ - char fname[NFILEN], *bufp, *temp; - struct stat sb; - - if (getbufcwd(fname, sizeof(fname)) == FALSE) - fname[0] = '\0'; - - if (strlcat(fname, DEFAULTFN, sizeof(fname)) >= sizeof(fname)) { - ewprintf("Filename too long"); - return (FALSE); - } - - bufp = eread("visit tags table (default %s): ", fname, - NFILEN, EFFILE | EFCR | EFNEW | EFDEF, DEFAULTFN); - - if (stat(bufp, &sb) == -1) { - ewprintf("stat: %s", strerror(errno)); - return (FALSE); - } else if (S_ISREG(sb.st_mode) == 0) { - ewprintf("Not a regular file"); - return (FALSE); - } else if (access(bufp, R_OK) == -1) { - ewprintf("Cannot access file %s", bufp); - return (FALSE); - } - - if (tagsfn == NULL) { - if (bufp == NULL) - return (ABORT); - else if (bufp[0] == '\0') { - if ((tagsfn = strdup(fname)) == NULL) { - ewprintf("Out of memory"); - return (FALSE); - } - } else { - /* bufp points to local variable, so duplicate. */ - if ((tagsfn = strdup(bufp)) == NULL) { - ewprintf("Out of memory"); - return (FALSE); - } - } - } else { - if ((temp = strdup(bufp)) == NULL) { - ewprintf("Out of memory"); - return (FALSE); - } - free(tagsfn); - tagsfn = temp; - if (eyorn("Keep current list of tags table also") == FALSE) { - ewprintf("Starting a new list of tags table"); - unloadtags(); - } - loaded = FALSE; - } - return (TRUE); -} - -/* - * Ask user for a tag while treating word at dot as default. Visit tags - * file if not yet done, load tags and jump to definition of the tag. - */ -int -findtag(int f, int n) -{ - char utok[MAX_TOKEN], dtok[MAX_TOKEN]; - char *tok, *bufp; - int ret; - - if (curtoken(f, n, dtok) == FALSE) - return (FALSE); - - bufp = eread("Find tag (default %s) ", utok, MAX_TOKEN, - EFNUL | EFNEW, dtok); - - if (bufp == NULL) - return (ABORT); - else if (bufp[0] == '\0') - tok = dtok; - else - tok = utok; - - if (tok[0] == '\0') { - ewprintf("There is no default tag"); - return (FALSE); - } - - if (tagsfn == NULL) - if ((ret = tagsvisit(f, n)) != TRUE) - return (ret); - if (!loaded) { - if (loadtags(tagsfn) == FALSE) { - free(tagsfn); - tagsfn = NULL; - return (FALSE); - } - loaded = TRUE; - } - return pushtag(tok); -} - -/* - * Free tags tree. - */ -void -unloadtags(void) -{ - struct ctag *var, *nxt; - - for (var = RB_MIN(tagtree, &tags); var != NULL; var = nxt) { - nxt = RB_NEXT(tagtree, &tags, var); - RB_REMOVE(tagtree, &tags, var); - /* line parsed with fparseln needs to be freed */ - free(var->tag); - free(var); - } -} - -/* - * Lookup tag passed in tree and if found, push current location and - * buffername onto stack, load the file with tag definition into a new - * buffer and position dot at the pattern. - */ -/*ARGSUSED */ -int -pushtag(char *tok) -{ - struct ctag *res; - struct tagpos *s; - char bname[NFILEN]; - int doto, dotline; - - if ((res = searchtag(tok)) == NULL) - return (FALSE); - - doto = curwp->w_doto; - dotline = curwp->w_dotline; - /* record absolute filenames. Fixes issues when mg's cwd is not the - * same as buffer's directory. - */ - if (strlcpy(bname, curbp->b_cwd, sizeof(bname)) >= sizeof(bname)) { - ewprintf("filename too long"); - return (FALSE); - } - if (strlcat(bname, curbp->b_bname, sizeof(bname)) >= sizeof(bname)) { - ewprintf("filename too long"); - return (FALSE); - } - - if (loadbuffer(res->fname) == FALSE) - return (FALSE); - - if (searchpat(res->pat) == TRUE) { - if ((s = malloc(sizeof(struct tagpos))) == NULL) { - ewprintf("Out of memory"); - return (FALSE); - } - if ((s->bname = strdup(bname)) == NULL) { - ewprintf("Out of memory"); - return (FALSE); - } - s->doto = doto; - s->dotline = dotline; - SLIST_INSERT_HEAD(&shead, s, entry); - return (TRUE); - } else { - ewprintf("%s: pattern not found", res->tag); - return (FALSE); - } - /* NOTREACHED */ - return (FALSE); -} - -/* - * If tag stack is not empty pop stack and jump to recorded buffer, dot. - */ -/* ARGSUSED */ -int -poptag(int f, int n) -{ - struct line *dotp; - struct tagpos *s; - - if (SLIST_EMPTY(&shead)) { - ewprintf("No previous location for find-tag invocation"); - return (FALSE); - } - s = SLIST_FIRST(&shead); - SLIST_REMOVE_HEAD(&shead, entry); - if (loadbuffer(s->bname) == FALSE) - return (FALSE); - curwp->w_dotline = s->dotline; - curwp->w_doto = s->doto; - - /* storing of dotp in tagpos wouldn't work out in cases when - * that buffer is killed by user(dangling pointer). Explicitly - * traverse till dotline for correct handling. - */ - dotp = curwp->w_bufp->b_headp; - while (s->dotline--) - dotp = dotp->l_fp; - - curwp->w_dotp = dotp; - free(s->bname); - free(s); - return (TRUE); -} - -/* - * Parse the tags file and construct the tags tree. Remove escape - * characters while parsing the file. - */ -int -loadtags(const char *fn) -{ - char *l; - FILE *fd; - - if ((fd = fopen(fn, "r")) == NULL) { - ewprintf("Unable to open tags file: %s", fn); - return (FALSE); - } - while ((l = fparseln(fd, NULL, NULL, "\\\\\0", - FPARSELN_UNESCCONT | FPARSELN_UNESCREST)) != NULL) { - if (addctag(l) == FALSE) { - fclose(fd); - return (FALSE); - } - } - fclose(fd); - return (TRUE); -} - -/* - * Cleanup and destroy tree and stack. - */ -void -closetags(void) -{ - struct tagpos *s; - - while (!SLIST_EMPTY(&shead)) { - s = SLIST_FIRST(&shead); - SLIST_REMOVE_HEAD(&shead, entry); - free(s->bname); - free(s); - } - unloadtags(); - free(tagsfn); -} - -/* - * Strip away any special characters in pattern. - * The pattern in ctags isn't a true regular expression. Its of the form - * /^xxx$/ or ?^xxx$? and in some cases the "$" would be missing. Strip - * the leading and trailing special characters so the pattern matching - * would be a simple string compare. Escape character is taken care by - * fparseln. - */ -char * -strip(char *s, size_t len) -{ - /* first strip trailing special chars */ - s[len - 1] = '\0'; - if (s[len - 2] == '$') - s[len - 2] = '\0'; - - /* then strip leading special chars */ - s++; - if (*s == '^') - s++; - - return s; -} - -/* - * tags line is of the format "\t\t". Split them - * by replacing '\t' with '\0'. This wouldn't alter the size of malloc'ed - * l, and can be freed during cleanup. - */ -int -addctag(char *l) -{ - struct ctag *t; - - if ((t = malloc(sizeof(struct ctag))) == NULL) { - ewprintf("Out of memory"); - return (FALSE); - } - t->tag = l; - if ((l = strchr(l, '\t')) == NULL) - goto cleanup; - *l++ = '\0'; - t->fname = l; - if ((l = strchr(l, '\t')) == NULL) - goto cleanup; - *l++ = '\0'; - if (*l == '\0') - goto cleanup; - t->pat = strip(l, strlen(l)); - RB_INSERT(tagtree, &tags, t); - return (TRUE); -cleanup: - free(t); - free(l); - return (TRUE); -} - -/* - * Search through each line of buffer for pattern. - */ -int -searchpat(char *pat) -{ - struct line *lp; - int dotline; - size_t plen; - - plen = strlen(pat); - dotline = 1; - lp = lforw(curbp->b_headp); - while (lp != curbp->b_headp) { - if (ltext(lp) != NULL && plen <= llength(lp) && - (strncmp(pat, ltext(lp), plen) == 0)) { - curwp->w_doto = 0; - curwp->w_dotp = lp; - curwp->w_dotline = dotline; - return (TRUE); - } else { - lp = lforw(lp); - dotline++; - } - } - return (FALSE); -} - -/* - * Return TRUE if dot is at beginning of a word or at beginning - * of line, else FALSE. - */ -int -atbow(void) -{ - if (curwp->w_doto == 0) - return (TRUE); - if (ISWORD(curwp->w_dotp->l_text[curwp->w_doto]) && - !ISWORD(curwp->w_dotp->l_text[curwp->w_doto - 1])) - return (TRUE); - return (FALSE); -} - -/* - * Extract the word at dot without changing dot position. - */ -int -curtoken(int f, int n, char *token) -{ - struct line *odotp; - int odoto, tdoto, odotline, size, r; - char c; - - /* Underscore character is to be treated as "inword" while - * processing tokens unlike mg's default word traversal. Save - * and restore it's cinfo value so that tag matching works for - * identifier with underscore. - */ - c = cinfo['_']; - cinfo['_'] = _MG_W; - - odotp = curwp->w_dotp; - odoto = curwp->w_doto; - odotline = curwp->w_dotline; - - /* Move backword unless we are at the beginning of a word or at - * beginning of line. - */ - if (!atbow()) - if ((r = backword(f, n)) == FALSE) - goto cleanup; - - tdoto = curwp->w_doto; - - if ((r = forwword(f, n)) == FALSE) - goto cleanup; - - /* strip away leading whitespace if any like emacs. */ - while (ltext(curwp->w_dotp) && - isspace(curwp->w_dotp->l_text[tdoto])) - tdoto++; - - size = curwp->w_doto - tdoto; - if (size <= 0 || size >= MAX_TOKEN || - ltext(curwp->w_dotp) == NULL) { - r = FALSE; - goto cleanup; - } - strncpy(token, ltext(curwp->w_dotp) + tdoto, size); - token[size] = '\0'; - r = TRUE; - -cleanup: - cinfo['_'] = c; - curwp->w_dotp = odotp; - curwp->w_doto = odoto; - curwp->w_dotline = odotline; - return (r); -} - -/* - * Search tagstree for a given token. - */ -struct ctag * -searchtag(char *tok) -{ - struct ctag t, *res; - - t.tag = tok; - if ((res = RB_FIND(tagtree, &tags, &t)) == NULL) { - ewprintf("No tag containing %s", tok); - return (NULL); - } - return res; -} - -/* - * This is equivalent to filevisit from file.c. - * Look around to see if we can find the file in another buffer; if we - * can't find it, create a new buffer, read in the text, and switch to - * the new buffer. *scratch*, *grep*, *compile* needs to be handled - * differently from other buffers which have "filenames". - */ -int -loadbuffer(char *bname) -{ - struct buffer *bufp; - char *adjf; - - /* check for special buffers which begin with '*' */ - if (bname[0] == '*') { - if ((bufp = bfind(bname, FALSE)) != NULL) { - curbp = bufp; - return (showbuffer(bufp, curwp, WFFULL)); - } else { - return (FALSE); - } - } else { - if ((adjf = adjustname(bname, TRUE)) == NULL) - return (FALSE); - if ((bufp = findbuffer(adjf)) == NULL) - return (FALSE); - } - curbp = bufp; - if (showbuffer(bufp, curwp, WFFULL) != TRUE) - return (FALSE); - if (bufp->b_fname[0] == '\0') { - if (readin(adjf) != TRUE) { - killbuffer(bufp); - return (FALSE); - } - } - return (TRUE); -}