home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / v / vim_src.zip / TAG.C < prev    next >
C/C++ Source or Header  |  1993-01-12  |  8KB  |  383 lines

  1. /* vi:ts=4:sw=4
  2.  *
  3.  * VIM - Vi IMitation
  4.  *
  5.  * Code Contributions By:    Bram Moolenaar            mool@oce.nl
  6.  *                            Tim Thompson            twitch!tjt
  7.  *                            Tony Andrews            onecom!wldrdg!tony 
  8.  *                            G. R. (Fred) Walter        watmath!watcgl!grwalter 
  9.  */
  10.  
  11. /*
  12.  * Code to handle tags and the tag stack
  13.  */
  14.  
  15. #include "vim.h"
  16. #include "globals.h"
  17. #include "proto.h"
  18. #include "param.h"
  19. #include "mark.h"
  20.  
  21. #define TAGSTACKSIZE 20
  22.  
  23. /*
  24.  * the taggy struct is used to store the information about a :tag command:
  25.  *    the tag name and the cursor position BEFORE the :tag command
  26.  */
  27. struct taggy
  28. {
  29.     char            *tagname;            /* tag name */
  30.     struct filemark fmark;                /* cursor position */
  31. };
  32.  
  33. /*
  34.  * the tagstack grows from 0 upwards:
  35.  * entry 0: older
  36.  * entry 1: newer
  37.  * entry 2: newest
  38.  */
  39. static struct taggy tagstack[TAGSTACKSIZE];    /* the tag stack */
  40. static int tagstackidx = 0;                /* index just below active entry */
  41. static int tagstacklen = 0;                /* number of tags on the stack */
  42.  
  43. static int findtag __ARGS((char *));
  44. static char *firsttaborspace __ARGS((char *));
  45.  
  46. static char bottommsg[] = "at bottom of tag stack";
  47. static char topmsg[] = "at top of tag stack";
  48.  
  49. /*
  50.  * Jump to tag; handling of tag stack
  51.  *
  52.  * *tag != NUL (:tag): jump to new tag, add to tag stack
  53.  * type == 1 (:pop) || type == 2 (CTRL-T): jump to old position
  54.  * type == 0 (:tag): jump to old tag
  55.  */
  56.     void
  57. dotag(tag, type, count)
  58.     char    *tag;
  59.     int        type;
  60.     int        count;
  61. {
  62.     int             i;
  63.     struct taggy    temptag;
  64.  
  65.     if (*tag != NUL)                        /* new pattern, add to the stack */
  66.     {
  67.         /*
  68.          * if last used entry is not at the top, put it at the top by rotating
  69.          * the stack until it is (the newer entries will be at the bottom)
  70.          */
  71.         while (tagstackidx < tagstacklen)
  72.         {
  73.             temptag = tagstack[tagstacklen - 1];
  74.             for (i = tagstacklen - 1; i > 0; --i)
  75.                 tagstack[i] = tagstack[i - 1];
  76.             tagstack[0] = temptag;
  77.             ++tagstackidx;
  78.         }
  79.                 /* if tagstack is full: remove oldest entry */
  80.         if (++tagstacklen > TAGSTACKSIZE)
  81.         {
  82.             tagstacklen = TAGSTACKSIZE;
  83.             free(tagstack[0].tagname);
  84.             for (i = 1; i < tagstacklen; ++i)
  85.                 tagstack[i - 1] = tagstack[i];
  86.             --tagstackidx;
  87.         }
  88.     /*
  89.      * remember the tag and the position before the jump
  90.      */
  91.         tagstack[tagstackidx].tagname = strsave(tag);
  92.         tagstack[tagstackidx].fmark.lnum = Curpos.lnum;
  93.         tagstack[tagstackidx].fmark.mark.col = Curpos.col;
  94.         tagstack[tagstackidx].fmark.mark.ptr = nr2ptr(Curpos.lnum);
  95.         tagstack[tagstackidx].fmark.fnum = 0;
  96.     }
  97.     else if (tagstacklen == 0)                    /* empty stack */
  98.     {
  99.         emsg("tag stack empty");
  100.         return;
  101.     }
  102.     else if (type)                                /* go to older position */
  103.     {
  104.         if ((tagstackidx -= count) < 0)
  105.         {
  106.             tagstackidx = 0;
  107.             emsg(bottommsg);
  108.         }
  109.         else if (tagstackidx >= tagstacklen)    /* must have been count == 0 */
  110.         {
  111.             emsg(topmsg);
  112.             return;
  113.         }
  114.         if (tagstack[tagstackidx].fmark.mark.ptr == NULL)    /* jump to other file */
  115.         {
  116.             if (getaltfile(tagstack[tagstackidx].fmark.fnum - 1, tagstack[tagstackidx].fmark.lnum, TRUE))
  117.             {
  118.                 emsg(e_notopen);
  119.                 return;
  120.             }
  121.             /* "refresh" this position, so we will not fall off the altfile array */
  122.             tagstack[tagstackidx].fmark.fnum = 0;
  123.             tagstack[tagstackidx].fmark.mark.ptr = nr2ptr(Curpos.lnum);
  124.         }
  125.         else
  126.             Curpos.lnum = ptr2nr(tagstack[tagstackidx].fmark.mark.ptr, (linenr_t)1);
  127.         Curpos.col = tagstack[tagstackidx].fmark.mark.col;
  128.         return;
  129.     }
  130.     else                                    /* go to newer pattern */
  131.     {
  132.         if ((tagstackidx += count - 1) >= tagstacklen)
  133.         {
  134.             tagstackidx = tagstacklen - 1;
  135.             emsg(topmsg);
  136.         }
  137.         else if (tagstackidx < 0)            /* must have been count == 0 */
  138.         {
  139.             emsg(bottommsg);
  140.             tagstackidx = 0;
  141.             return;
  142.         }
  143.     }
  144.     if (findtag(tagstack[tagstackidx].tagname) > 0)
  145.         ++tagstackidx;
  146. }
  147.  
  148. /*
  149.  * invalidate the line pointer for all tags
  150.  * called when abandoning the current file
  151.  */
  152.     void
  153. clrtags()
  154. {
  155.     int            i;
  156.  
  157.     for (i = 0; i < tagstacklen; ++i)
  158.         tagstack[i].fmark.mark.ptr = NULL;
  159. }
  160.  
  161. /*
  162.  * increment the file number for all tags
  163.  * called when adding a file to the file stack
  164.  */
  165.     void
  166. incrtags()
  167. {
  168.     int            i;
  169.  
  170.     for (i = 0; i < tagstacklen; ++i)
  171.     {
  172. #if 0        /* this would take too much time */
  173.         if (tagstack[i].fmark.fnum == 0)    /* current file */
  174.             tagstack[i].fmark.lnum = ptr2nr(tagstack[i].fmark.mark.ptr, 1);
  175. #endif
  176.         ++tagstack[i].fmark.fnum;
  177.     }
  178. }
  179.  
  180. /*
  181.  * decrement the file number for the tags of the current file
  182.  * called when not adding the current file name to the file stack
  183.  */
  184.     void
  185. decrtags()
  186. {
  187.     int            i;
  188.  
  189.     for (i = 0; i < tagstacklen; ++i)
  190.         if (tagstack[i].fmark.fnum == 1)
  191.             tagstack[i].fmark.fnum = 0;
  192. }
  193.  
  194. /*
  195.  * Print the tag stack (use the occasion to update the line numbers)
  196.  */
  197.     void
  198. dotags()
  199. {
  200.     int            i;
  201.     char        *name;
  202.  
  203.     settmode(0);
  204.     outstrn("\n  # TO tag      FROM line in file\n");
  205.     for (i = 0; i < tagstacklen; ++i)
  206.     {
  207.         if (tagstack[i].tagname != NULL)
  208.         {
  209.             name = fm_getname(&(tagstack[i].fmark));
  210.             if (name == NULL)        /* file name not available */
  211.                 continue;
  212.  
  213.             sprintf(IObuff, "%c%2d %-15s %4ld  %s\n",
  214.                 i == tagstackidx ? '>' : ' ',
  215.                 i + 1,
  216.                 tagstack[i].tagname,
  217.                 tagstack[i].fmark.lnum,
  218.                 name);
  219.             outstrn(IObuff);
  220.         }
  221.         flushbuf();
  222.     }
  223.     if (tagstackidx == tagstacklen)        /* idx at top of stack */
  224.         outstrn(">\n");
  225.     settmode(1);
  226.     wait_return(TRUE);
  227. }
  228.  
  229. /*
  230.  * findtag(tag) - goto tag
  231.  *   return 0 for failure, 1 for success
  232.  */
  233.     static int
  234. findtag(tag)
  235.     char           *tag;
  236. {
  237.     FILE       *tp, *fopen();
  238.     char        lbuf[LSIZE];
  239.     char        pbuf[LSIZE];            /* search pattern buffer */
  240.     char       *fname, *str;
  241.     int            cmplen;
  242.     char        *m = NULL;
  243.     register char    *p;
  244.     char        *np;                    /* pointer into file name string */
  245.     char        sbuf[CMDBUFFSIZE + 1];    /* tag file name */
  246.     int            i;
  247.  
  248.     if (tag == NULL)        /* out of memory condition */
  249.         return 0;
  250.  
  251.     if ((cmplen = p_tl) == 0)
  252.         cmplen = 999;
  253.  
  254.     /* get stack of tag file names from tags option */
  255.     for (np = p_tags; *np; )
  256.     {
  257.         for (i = 0; i < CMDBUFFSIZE && *np; ++i)    /* copy next file name into lbuf */
  258.         {
  259.             if (*np == ' ')
  260.             {
  261.                 ++np;
  262.                 break;
  263.             }
  264.             sbuf[i] = *np++;
  265.         }
  266.         sbuf[i] = 0;
  267.         if ((tp = fopen(sbuf, "r")) == NULL)
  268.         {
  269.             m = "Can't open tags file %s";
  270.             goto erret2;
  271.         }
  272.         while (fgets(lbuf, LSIZE, tp) != NULL)
  273.         {
  274.             m = "Format error in tags file %s";    /* default error message */
  275.  
  276.         /* find start of file name, after first TAB or space */
  277.             fname = firsttaborspace(lbuf);
  278.             if (fname == NULL)
  279.                 goto erret;
  280.             *fname++ = '\0';
  281.  
  282.         /* find start of search command, after second TAB or space */
  283.             str = firsttaborspace(fname);
  284.             if (str == NULL)
  285.                 goto erret;
  286.             *str++ = '\0';
  287.  
  288.             if (strncmp(lbuf, tag, (size_t)cmplen) == 0)
  289.             {
  290.                 fclose(tp);
  291.                 /*
  292.                  * Tag found!
  293.                  * Form a string like "+/^function fname".
  294.                  * Scan through the search string. If we see a magic
  295.                  * char, we have to quote it. This lets us use "real"
  296.                  * implementations of ctags.
  297.                  */
  298.                 p = pbuf;
  299.                 *p++ = *str++;            /* copy the '/' or '?' */
  300.                 *p++ = *str++;            /* copy the '^' */
  301.  
  302.                 while (*str)
  303.                 {
  304.                     switch (*str)
  305.                     {
  306.                     case '\\':    if (str[1] == '(')    /* remove '\' before '(' */
  307.                                     ++str;
  308.                                 else
  309.                                     *p++ = *str++;
  310.                                 break;
  311.  
  312.                     case '\n':    *p++ = pbuf[0];    /* copy '/' or '?' */
  313.                                 *p++ = 'n';        /* no setpcmark() for search */
  314.                                 break;
  315.  
  316.                                 /*
  317.                                  * if string ends in search character: skip it
  318.                                  * else escape it with '\'
  319.                                  */
  320.                     case '/':
  321.                     case '?':    if (*str == pbuf[0] && str[1] == '\n')
  322.                                 {
  323.                                     ++str;
  324.                                     continue;
  325.                                 }
  326.                     case '^':
  327.                     case '*':
  328.                     case '.':    *p++ = '\\';
  329.                                 break;
  330.                     }
  331.                     *p++ = *str++;
  332.                 }
  333.                 *p = NUL;
  334.  
  335.                 RedrawingDisabled = TRUE;
  336.                 if ((i = getfile(fname, TRUE)) <= 0)
  337.                 {
  338.                     set_want_col = TRUE;
  339.  
  340.                     RedrawingDisabled = FALSE;
  341.                     dosearch(pbuf[0] == '/' ? FORWARD : BACKWARD, pbuf + 1, FALSE, 1L);
  342.                     if (p_im && i == -1)
  343.                         stuffReadbuff("\033\007i");    /* ESC CTRL-G i */
  344.                     else
  345.                         stuffReadbuff("\007");        /* CTRL-G */
  346.                     return 1;
  347.                 }
  348.                 RedrawingDisabled = FALSE;
  349.                 return 0;
  350.             }
  351.         }
  352.         m = NULL;
  353.  
  354. erret:
  355.         fclose(tp);
  356. erret2:
  357.         if (m)
  358.         {
  359.             smsg(m, sbuf);
  360.             sleep(1);
  361.         }
  362.     }
  363.     if (m == NULL)
  364.         emsg("tag not found");
  365.     return 0;
  366. }
  367.  
  368. /*
  369.  * find first TAB or space
  370.  */
  371.     static char *
  372. firsttaborspace(str)
  373.     char *str;
  374. {
  375.     char *p1, *p2;
  376.  
  377.     p1 = strchr(str, TAB);            /* find first TAB */
  378.     p2 = strchr(str, ' ');            /* find first space */
  379.     if (p1 == NULL || (p2 != NULL && p2 < p1))
  380.         return p2;                    /* space comes first */
  381.     return p1;
  382. }
  383.