home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / VILE327.ZIP / VILE327.TAR / vile3.27 / tags.c < prev    next >
C/C++ Source or Header  |  1992-12-14  |  12KB  |  544 lines

  1. /* Look up vi-style tags in the file "tags".
  2.  *    Invoked either by ":ta routine-name" or by "^]" while sitting
  3.  *    on a string.  In the latter case, the tag is the word under
  4.  *    the cursor.
  5.  *    written for vile by Paul Fox, (c)1990
  6.  *
  7.  * $Log: tags.c,v $
  8.  * Revision 1.25  1992/11/19  22:24:25  foxharp
  9.  * recheck tagsprefix on every fetch of file
  10.  *
  11.  * Revision 1.24  1992/11/19  08:49:25  foxharp
  12.  * allow more dynamic killing/creating of the tags buffer, so if you get
  13.  * the wrong tags file by mistake, you can ":kill tags" and retry
  14.  *
  15.  * Revision 1.23  1992/08/05  21:51:10  foxharp
  16.  * use "slash" instead of '/'
  17.  *
  18.  * Revision 1.22  1992/07/30  07:29:19  foxharp
  19.  * further fix off-by-one on tags that use line numbers
  20.  *
  21.  * Revision 1.21  1992/07/15  09:00:35  foxharp
  22.  * fixed off-by-one in tags-buffer line scan, so single digit line
  23.  * numbers now work, e.g. "file.c    src/file.c    1".
  24.  * also, always set up "tagprefix", in case we switch to tagsrelative
  25.  * mode later on
  26.  *
  27.  * Revision 1.20  1992/07/13  20:09:27  foxharp
  28.  * path-relative tags are now controlled by a boolean mode "set tagsrelative"
  29.  *
  30.  * Revision 1.19  1992/07/13  19:45:51  foxharp
  31.  * added "tags relative to where we found the tags file" code
  32.  *
  33.  * Revision 1.18  1992/05/16  12:00:31  pgf
  34.  * prototypes/ansi/void-int stuff/microsoftC
  35.  *
  36.  * Revision 1.17  1992/03/19  23:26:23  pgf
  37.  * removed extra string lib externs
  38.  *
  39.  * Revision 1.16  1992/01/05  00:06:13  pgf
  40.  * split mlwrite into mlwrite/mlprompt/mlforce to make errors visible more
  41.  * often.  also normalized message appearance somewhat.
  42.  *
  43.  * Revision 1.15  1991/11/08  13:07:09  pgf
  44.  * ifdefed out lazy filename matching
  45.  *
  46.  * Revision 1.14  1991/11/07  02:00:32  pgf
  47.  * lint cleanup
  48.  *
  49.  * Revision 1.13  1991/11/01  14:38:00  pgf
  50.  * saber cleanup
  51.  *
  52.  * Revision 1.12  1991/10/27  01:53:15  pgf
  53.  * use global taglen value for command line tags -- there's no current
  54.  * buffer yet
  55.  *
  56.  * Revision 1.11  1991/10/22  03:09:32  pgf
  57.  * tags given on the command line now set the response for further tag commands
  58.  *
  59.  * Revision 1.10  1991/10/20  23:06:43  pgf
  60.  * cleaned up taglen stuff
  61.  *
  62.  * Revision 1.9  1991/10/15  11:58:58  pgf
  63.  * added taglength support
  64.  *
  65.  * Revision 1.8  1991/10/08  01:30:00  pgf
  66.  * added new bp arg to lfree and lalloc
  67.  *
  68.  * Revision 1.7  1991/10/08  01:26:33  pgf
  69.  * untagpop now sets "lastdot" correctly
  70.  *
  71.  * Revision 1.6  1991/09/19  13:44:13  pgf
  72.  * tags file is looked up via VAL_TAGS setting (the global one -- local tags
  73.  * paths and files don't make sense.  yet? )
  74.  *
  75.  * Revision 1.5  1991/08/07  12:35:07  pgf
  76.  * added RCS log messages
  77.  *
  78.  * revision 1.4
  79.  * date: 1991/06/25 19:53:33;
  80.  * massive data structure restructure
  81.  * 
  82.  * revision 1.3
  83.  * date: 1991/06/07 13:23:30;
  84.  * don't move "last dot" mark if dot doesn't change
  85.  * 
  86.  * revision 1.2
  87.  * date: 1991/04/08 15:47:17;
  88.  * fixed readin() arg count
  89.  * 
  90.  * revision 1.1
  91.  * date: 1990/09/21 10:26:07;
  92.  * initial vile RCS revision
  93.  */
  94. #include    "estruct.h"
  95. #include        "edef.h"
  96.  
  97. #if TAGS
  98.  
  99.  
  100. #ifndef NULL
  101. #define NULL 0
  102. #endif
  103.  
  104. static char tagname[NFILEN];
  105. static char tagprefix[NFILEN];
  106.  
  107. void pushuntag();
  108.  
  109.  
  110. /* ARGSUSED */
  111. int
  112. gototag(f,n)
  113. int f,n;
  114. {
  115.     register int s = TRUE;
  116.     int taglen;
  117.  
  118.     if (clexec || isnamedcmd) {
  119.             if ((s=mlreply("Tag name: ", tagname, NFILEN)) != TRUE)
  120.                     return (s);
  121.         taglen = b_val(curbp,VAL_TAGLEN);
  122.     } else {
  123.         screen_string(tagname,NFILEN,_ident);
  124.         taglen = 0;
  125.     }
  126.     if (s == TRUE)
  127.         s = tags(tagname,taglen);
  128.     return s;
  129. }
  130.  
  131. int
  132. cmdlinetag(t)
  133. char *t;
  134. {
  135.     strcpy(tagname,t);
  136.     return tags(tagname, global_b_val(VAL_TAGLEN));
  137. }
  138.  
  139.  
  140. int
  141. tags(tag,taglen)
  142. char *tag;
  143. int taglen;
  144. {
  145.     register LINE *lp, *clp;
  146.     register int i, s;
  147.     char *tfp, *lplim;
  148.     char tname[NFILEN];
  149.     char tfname[NFILEN];
  150.     char tagpat[NPAT];
  151.     int lineno;
  152.     int changedfile;
  153.     MARK odot;
  154.     LINE *cheap_scan();
  155.     BUFFER *tagbp;
  156.  
  157.     strcpy(tname,tag);
  158.  
  159.     if ((tagbp = gettagsfile()) == NULL )
  160.         return FALSE;
  161.  
  162.     lp = cheap_scan(tagbp, tname, taglen ? taglen : strlen(tname));
  163.     if (lp == NULL) {
  164.         TTbeep();
  165.         mlforce("[No such tag: \"%s\"]",tname);
  166.         return FALSE;
  167.     }
  168.     
  169.     lplim = &lp->l_text[lp->l_used];
  170.     tfp = lp->l_text;
  171.     while (tfp < lplim)
  172.         if (*tfp++ == '\t')
  173.             break;
  174.  
  175.     i = 0;
  176.     if (b_val(curbp,MDTAGSRELTIV) && *tfp != '/') {
  177.         strcpy(tfname, tagprefix);
  178.         i += strlen(tagprefix);
  179.     }
  180.     while (i < NFILEN && tfp < lplim && *tfp != '\t') {
  181.         tfname[i++] = *tfp++;
  182.     }
  183.     tfname[i] = 0;
  184.  
  185.     if (tfp >= lplim) {
  186.         mlforce("[Bad line in tags file.]");
  187.         return FALSE;
  188.     }
  189.  
  190.     if (curbp && curwp) {
  191.         lineno = 1;
  192.             for(clp = lforw(curbp->b_line.l); 
  193.                 clp != curwp->w_dot.l; clp = lforw(clp))
  194.             lineno++;
  195.         pushuntag(curbp->b_fname, lineno);
  196.     }
  197.  
  198.     if (curbp == NULL || strcmp(tfname,curbp->b_fname)) {
  199.         s = getfile(tfname,TRUE);
  200.         if (s != TRUE) {
  201.             tossuntag();
  202.             return s;
  203.         }
  204.         changedfile = TRUE;
  205.     } else {
  206.         if (tname[strlen(tname)-1] == '\t')
  207.             tname[strlen(tname)-1] = '\0'; /* get rid of tab we added */
  208.         mlwrite("Tag \"%s\" in current buffer", tname);
  209.         changedfile = FALSE;
  210.     }
  211.  
  212.     /* it's an absolute move -- remember where we are */
  213.     odot = DOT;
  214.  
  215.     i = 0;
  216.     tfp++;  /* skip the tab */
  217.     if (tfp >= lplim) {
  218.         mlforce("[Bad line in tags file.]");
  219.         return FALSE;
  220.     }
  221.     if (isdigit(*tfp)) { /* then it's a line number */
  222.         lineno = 0;
  223.         while (isdigit(*tfp) && (tfp < lplim)) {
  224.             lineno = 10*lineno + *tfp - '0';
  225.             tfp++;
  226.         }
  227.         s = gotoline(TRUE,lineno);
  228.         if (s != TRUE && !changedfile)
  229.             tossuntag();
  230.     } else {
  231.         tfp += 2; /* skip the "/^" */
  232.         lplim -= 2; /* skip the "$/" */
  233.         while (i < NPAT && tfp < lplim) {
  234.             if (*tfp == '\\' && tfp < lplim - 1)
  235.                 tfp++;  /* the backslash escapes the next char */
  236.             tagpat[i++] = *tfp++;
  237.         }
  238.         tagpat[i] = 0;
  239.         lp = cheap_scan(curbp,tagpat,i);
  240.         if (lp == NULL) {
  241.             mlforce("[Tag not present]");
  242.             TTbeep();
  243.             if (!changedfile)
  244.                 tossuntag();
  245.             return FALSE;
  246.         }
  247.         curwp->w_dot.l = lp;
  248.         curwp->w_flag |= WFMOVE;
  249.         firstnonwhite(FALSE,1);
  250.         s = TRUE;
  251.     }
  252.     /* if we moved, update the "last dot" mark */
  253.     if (s == TRUE && !sameline(DOT, odot)) {
  254.         curwp->w_lastdot = odot;
  255.     }
  256.     return s;
  257.     
  258. }
  259.  
  260. #define TAGBUF "tags"
  261. BUFFER *
  262. gettagsfile()
  263. {
  264.     int s;
  265.     char *tagsfile;
  266.     BUFFER *tagbp;
  267.  
  268.     /* is there a TAGBUF buffer around? */
  269.         if ((tagbp=bfind(TAGBUF, NO_CREAT, 0)) == NULL) {
  270.         char *tagf = global_b_val_ptr(VAL_TAGS);
  271.         /* look up the tags file */
  272.         tagsfile = flook(tagf, FL_HERE);
  273.  
  274.         /* if it isn't around, don't sweat it */
  275.         if (tagsfile == NULL)
  276.         {
  277.                 mlforce("[No tags file available.]");
  278.             return NULL;
  279.         }
  280.  
  281.         /* find the pointer to that buffer */
  282.         if ((tagbp=bfind(tagf, OK_CREAT, BFINVS)) == NULL) {
  283.             mlforce("[Can't create tags buffer]");
  284.             return NULL;
  285.         }
  286.  
  287.         if ((s = readin(tagsfile, FALSE, tagbp, FALSE)) != TRUE) {
  288.             return NULL;
  289.         }
  290.         /* be sure it's named TAGBUF */
  291.         strcpy(tagbp->b_bname, TAGBUF);
  292.         tagbp->b_flag |= BFINVS;
  293.             
  294.         }
  295.     if (strrchr(tagbp->b_fname,'/')) {
  296.         strcpy(tagprefix, tagbp->b_fname);
  297.         *(strrchr(tagprefix,'/')+1) = '\0';
  298.     } else {
  299.         tagprefix[0] = '\0';
  300.     }
  301.     return tagbp;
  302. }
  303.  
  304. LINE *
  305. cheap_scan(bp,name,len)
  306. BUFFER *bp;
  307. char *name;
  308. int len;
  309. {
  310.     LINE *lp;
  311.     lp = lforw(bp->b_line.l);
  312.     while (lp != bp->b_line.l) {
  313.         if (llength(lp) >= len) {
  314.             if (llength(lp) >= len &&
  315.                  !strncmp(lp->l_text, name, len))
  316.                 return lp;
  317.         }
  318.         lp = lforw(lp);
  319.     }
  320.     return NULL;
  321. }
  322.  
  323. int
  324. untagpop(f,n)
  325. int f,n;
  326. {
  327.     int lineno;
  328.     char fname[NFILEN];
  329.     MARK odot;
  330.  
  331.     if (!f) n = 1;
  332.     while (n && popuntag(fname,&lineno))
  333.         n--;
  334.     if (lineno && fname[0]) {
  335.         int s;
  336.         s = getfile(fname,FALSE);
  337.         if (s != TRUE)
  338.             return s;
  339.  
  340.         /* it's an absolute move -- remember where we are */
  341.         odot = DOT;
  342.         s = gotoline(TRUE,lineno);
  343.         /* if we moved, update the "last dot" mark */
  344.         if (s == TRUE && !sameline(DOT, odot)) {
  345.             curwp->w_lastdot = odot;
  346.         }
  347.         return s;
  348.     }
  349.     TTbeep();
  350.     mlforce("[No stacked un-tags]");
  351.     return FALSE;
  352. }
  353.  
  354.  
  355. struct untag {
  356.     char *u_fname;
  357.     int u_lineno;
  358.     struct untag *u_stklink;
  359. };
  360.  
  361. struct untag *untaghead = NULL;
  362.  
  363. void
  364. pushuntag(fname,lineno)
  365. char *fname;
  366. int lineno;
  367. {
  368.     struct untag *utp;
  369.     utp = (struct untag *)malloc(sizeof(struct untag));
  370.     if (!utp)
  371.         return;
  372.  
  373.     utp->u_fname = (char *)malloc(strlen(fname)+1);
  374.     if (!utp->u_fname) {
  375.         free((char *)utp);
  376.         return;
  377.     }
  378.  
  379.     strcpy(utp->u_fname, fname);
  380.     utp->u_lineno = lineno;
  381.     utp->u_stklink = untaghead;
  382.     untaghead = utp;
  383. }
  384.  
  385. int
  386. popuntag(fname,linenop)
  387. char *fname;
  388. int *linenop;
  389. {
  390.     register struct untag *utp;
  391.  
  392.     if (untaghead) {
  393.         utp = untaghead;
  394.         untaghead = utp->u_stklink;
  395.         strcpy(fname, utp->u_fname);
  396.         *linenop = utp->u_lineno;
  397.         free(utp->u_fname);
  398.         free((char *)utp);
  399.         return TRUE;
  400.     }
  401.     fname[0] = '\0';
  402.     *linenop = 0;
  403.     return FALSE;
  404.  
  405. }
  406.  
  407. /* discard without returning anything */
  408. void
  409. tossuntag()
  410. {
  411.     register struct untag *utp;
  412.  
  413.     if (untaghead) {
  414.         utp = untaghead;
  415.         untaghead = utp->u_stklink;
  416.         free((char *)utp);
  417.     }
  418. }
  419.  
  420. #ifdef LAZINESS
  421. BUFFER *filesbp;
  422.  
  423.  
  424. /* create a filelist from the contents of
  425.  *    the tags file.  for "dir1/dir2/file" include both that and
  426.  *    "dir1/dir2/"
  427.  */
  428. int
  429. makeflist()
  430. {
  431.     register LINE *tlp;
  432.     register char *fnp;
  433.     register int i;
  434.     char fname[NFILEN];
  435.     BUFFER *tagbp;
  436.  
  437.     if (!(othmode & OTH_LAZY))
  438.         return TRUE;
  439.  
  440.     if ((tagbp = gettagsfile()) == NULL)
  441.             return FALSE;
  442.  
  443.     if (filesbp != NULL)
  444.         return TRUE;
  445.  
  446.     /* create the file list buffer   */
  447.     filesbp = bfind("[files]", OK_CREAT, BFINVS);
  448.     if (filesbp == NULL)
  449.         return FALSE;
  450.     filesbp->b_active = TRUE;
  451.  
  452.     /* loop through the tags file */
  453.     tlp = lforw(tagbp->b_line.l);
  454.     while (tlp != tagbp->b_line.l) {
  455.         /* skip the tagname */
  456.         i = 0;
  457.         while (i < llength(tlp) && lgetc(tlp,i) != '\t')
  458.             i++;
  459.         /* we're going to store the pathnames reversed, so that
  460.             the sorting puts all directories together (they'll
  461.             all start with their trailing slash) and all 
  462.             files with matching basenames will be grouped
  463.             together as well.
  464.         */
  465.         /* pull out the filename, in reverse */
  466.         fnp = &fname[NFILEN-1];
  467.         *fnp-- = '\0';
  468.         while (i < llength(tlp)  && fnp >= fname && 
  469.                     (*fnp = lgetc(tlp,i++)) != '\t') {
  470.             fnp--;
  471.         }
  472.         fnp++; /* forward past the tab */
  473.  
  474.         /* insert into the file list */
  475.         if (sortsearch(fnp, &fname[NFILEN-1]-fnp, filesbp,
  476.                             TRUE, NULL) == NULL)
  477.             return FALSE;
  478.  
  479.         /* first (really last) slash */
  480.         if ((fnp = strchr(fnp, slash)) != NULL) {
  481.             /* insert the directory name into the file list again */
  482.             if (sortsearch(fnp, &fname[NFILEN-1]-fnp, filesbp,
  483.                             TRUE, NULL) == NULL)
  484.                 return FALSE;
  485.         }
  486.         tlp = lforw(tlp);
  487.     }
  488.     return TRUE;
  489. }
  490.  
  491. /* look for or insert a text string into the given buffer.  start looking
  492.     at the given line if non-null. */
  493. int
  494. sortsearch(text, len,  bp, insert, lpp)
  495. char *text;
  496. int len;
  497. BUFFER *bp;
  498. int insert;
  499. LINE **lpp;
  500. {
  501.     LINE *nlp, *lp;
  502.     register int r, cmplen;
  503.  
  504.     if (lpp == NULL) {
  505.         lp = lforw(bp->b_line.l);
  506.     } else {
  507.         lp = *lpp;
  508.         if (lp == NULL)
  509.             lp = lforw(bp->b_line.l);
  510.         else
  511.             lp = lforw(lp);
  512.     }
  513.  
  514.     while (1) {
  515.         cmplen = (len < llength(lp) && !insert) ? len : llength(lp);
  516.         if ((r = strncmp(text, lp->l_text, cmplen)) > 0 ||
  517.              lp == bp->b_line.l) { /* stick line into buffer */
  518.                  if (!insert)
  519.                 return FALSE;
  520.                 if ((nlp=lalloc(len,bp)) == NULL)
  521.                         return FALSE;
  522.             memcpy(nlp->l_text, text, len);
  523.                 lp->l_bp->l_fp = nlp;
  524.                 nlp->l_bp = lp->l_bp;
  525.                 lp->l_bp = nlp;
  526.                 nlp->l_fp = lp;
  527.             if (lpp)
  528.                 *lpp = nlp;
  529.             return TRUE;
  530.         } else if (r == 0) { /* it's already here, don't insert twice */
  531.             if (lpp)
  532.                 *lpp = lp;
  533.             return TRUE;
  534.         }
  535.         lp = lforw(lp);
  536.     }
  537. }
  538. #endif
  539.  
  540.  
  541. #else
  542. void taghello() { }
  543. #endif
  544.