home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast.iso / eel / tagmod.zip / TAGMOD.E
Text File  |  1990-10-28  |  16KB  |  645 lines

  1. /************************************************************************
  2. * "Epsilon", "EEL" and "Lugaru" are trademarks of Lugaru Software, Ltd. *
  3. *                 *
  4. *  Copyright (C) 1988, 1990 Lugaru Software Ltd.  All rights reserved.  *
  5. *                 *
  6. * Limited permission is hereby granted to reproduce and modify this *
  7. * copyrighted material provided that the resulting code is used only in *
  8. * conjunction with Lugaru products and that this notice is retained in  *
  9. * any such reproduction or modification.        *
  10. ************************************************************************/
  11.  
  12. #include "eel.h"
  13.  
  14. /*
  15. * This file replaces tags.e from Lugaru, it is their source code.
  16. * Don't try a diff, I routinely reindent their code because the 
  17. * way they indent makes me puke.  I can't help it mommy, they
  18. * took my Lisp Machine and forced me to write C.
  19. *
  20. * I have modified this file such that it can tag typedef C structures,
  21. * and function like macros.  Some small changes will make it tag
  22. * all #define things but there are too many in my system for this to be 
  23. * useful so I removed those changes.  Other random changes are the
  24. * ability to tag things which contain regex characters (languages
  25. * like lisp (DEFVAR *FOO* NIL) screw up on the '*'), the ability
  26. * to tag lisp and scheme files (all things that start with def).  Changes
  27. * are marked with KSH.  I also changed the default file name to tags
  28. * since I can't stand the name default.tag.
  29. *
  30. * This file also contains the command M-x tag-project (for c and h files
  31. * hardwired). To use it, you must set up the the project_directories
  32. * variable and the project_directory variable.  The behavior of 
  33. * pluck-tag and goto-tag is changed such that if there is no tag file
  34. * in the current directory, the project tag file is used by default
  35. * (no matter where you are).  This requires your tags to be absolute.
  36. *
  37. * If you downloaded and use the file grep.e, there are some functions
  38. * in here which are also in grep.  You figure out how to structure it.
  39. * Also, I have commented call to push_point below.  Uncomment it
  40. * if you downloaded and use pointstk.e and you want to save your place
  41. * when you meta-dot (C-x . if you insist).
  42. *
  43. * NB: Tagging structures and #defines slows down the tagging process, but
  44. * I use an Everex Step 386/33 at work and 486/25 at home, so I don't 
  45. * really care (or notice).  You might not want to use this on an XT :)
  46. */
  47.  
  48. /*
  49. * Set these variables as follows if your project root is D:\FOO and contains
  50. * subdirectories BAR, BAZ and vendor supplied library source in C:\BLETCH
  51. *
  52. * project_directories = ".;BAR;BAZ;C:\\BLETCH"
  53. *
  54. * project_directory = "D:\\FOO"
  55. */
  56. char project_directories[256] = "";     /* KSH */
  57. char project_directory[FNAMELEN] = "";  /* KSH */
  58.  
  59. char initial_tag_file[FNAMELEN] = "tags"; /* KSH */
  60. char tag_relative = 0;  /* if nonzero, use relative pathname for tags */
  61.  
  62. init_tags()
  63. {
  64.   char buf[FNAMELEN];
  65.  
  66.   if (!exist("-tags")) {
  67.     strcpy(buf, initial_tag_file);
  68.     absolute(buf);
  69.     load_tags(buf);
  70.   }
  71. }
  72.  
  73. load_tags(file)
  74. char *file;
  75. {
  76.   char *oldbuf = bufname;
  77.   int i;
  78.  
  79.   zap("-tags");
  80.   bufname = "-tags";
  81.   i = read_file(file, strip_returns.default);
  82.   case_fold = case_fold.default;        /* KSH */
  83.   bufname = oldbuf;
  84.   if (i && i != 2) {
  85.     delete_buffer("-tags");
  86.     quick_abort();
  87.   }
  88. }
  89.  
  90. do_save_tags()    /* save tags to their file if unsaved */
  91. {
  92.   char *oldbuf = bufname;
  93.  
  94.   if (exist("-tags")) {
  95.     bufname = "-tags";
  96.     if (modified) {   /* saved tags must always be sorted */
  97.       sayput("Sorting tags...");
  98.       sort_another("-tags");
  99.       do_save_file(1, 1, 1);
  100.     }
  101.     bufname = oldbuf;
  102.   }
  103. }
  104.  
  105. re_enquote(targ, source)                /* from lispmode.e */
  106. char *targ;
  107. char *source;
  108. {
  109.     char ch;
  110.     while (ch = *source++)
  111.     {
  112.       if (index ("^*%()\\[]|", ch)) *targ++ = '%';
  113.       *targ++ = ch;
  114.     }
  115.     *targ++ = '\0';
  116. }
  117.  
  118. char tag_mat[80]; /* value returned by tag_match during completion */
  119.  
  120. char *tag_match(s, start) 
  121. char *s;
  122. {
  123.   char quoted[80];
  124.   char *oldbuf = bufname, *res = 0, tmp[80];
  125.   int found;
  126.   int old_fold = case_fold;
  127.   
  128.   case_fold = 0;
  129.   re_enquote (quoted, s);               /* KSH */
  130.   bufname = "-tags";
  131.   if ((start & STARTMATCH) && modified)
  132.     do_save_tags();
  133.   if (start & STARTMATCH) {
  134.     point = 0;
  135.     sprintf(tmp, "\n%s", s);
  136.     if (!parse_string(1, quoted, (char *) 0) && *quoted) /* KSH */
  137.       search(1, tmp);
  138.     to_begin_line();
  139.   }
  140.   if ((!*quoted || parse_string(1, quoted, (char *) 0)) /* KSH */
  141.        && (found = parse_string(1, "^[^;\n]+;", tag_mat))) {
  142.     tag_mat[found - 1] = 0;
  143.     nl_forward();
  144.     res = tag_mat;
  145.   }
  146.   bufname = oldbuf;
  147.   case_fold = old_fold;
  148.   return res;
  149. }
  150.  
  151. get_tag(res, pr)  /* do completion on tags */
  152. char *res, *pr;
  153. {
  154.   comp_read(res, pr, tag_match, 0, "");
  155. }
  156.  
  157. go_tag(s) /* if none, go to next tag */
  158. char *s;
  159. {
  160.   short resp;
  161.  
  162.   if (do_go_tag(s))
  163.     return;
  164.   do {
  165.     sayput("Tag %s has moved, retag file %s [Y]? ", s, filename);
  166.     refresh();
  167.     resp = tolower(getkey());
  168.     check_abort();
  169.   } while (!index("yn \r\n", resp));
  170.   say("");
  171.   if (resp != 'n') {
  172.     do_retag_file(filename);
  173.     if (!do_go_tag(s))
  174.       error("Tag %s is not in file %s", s, filename);
  175.   }
  176. }
  177.  
  178. do_go_tag(s)    /* go to tag s and return nonzero, or 0 if we can't */
  179. char *s;    /* if s is empty, use next tag & fill in s */
  180. {
  181.   char pat[150], *oldbuf = bufname, *file, *p;
  182.   char quoted[150];                     /* KSH */
  183.   int pos;
  184.  
  185.   re_enquote (quoted, s);               /* KSH */
  186.   bufname = "-tags";                    
  187.   if (*quoted) {
  188.     sprintf(pat, "^%s;.*", quoted);
  189.     point = 0;
  190.     if (!re_search(1, pat))
  191.       error("%s is not in the tag list", s);
  192.   } else if (!re_search(1, "^.*;.*"))
  193.     error("no more tags");
  194.   grab(matchstart, point, pat); /* tag, file, line # */
  195.   file = index(pat, ';');
  196.   *file++ = 0;
  197.   if (!*quoted)                         /* KSH */
  198.   {
  199.     strcpy(s, pat);   /* save tag */
  200.     re_enquote (quoted, s);               /* KSH */    
  201.   }
  202.   p = index(file, ';');   /* find start of line # */
  203.   pos = strtoi(p + 1, 10);
  204.   *p = 0;
  205.   bufname = oldbuf;
  206.   absolute(file);
  207.   /* push_point(); */                      /* KSH */
  208.   locate_window("", file);
  209.   find_it(file, strip_returns.default);
  210.   sprintf(pat, "%s[^a-zA-Z0-9_]", quoted);
  211.   point = pos;
  212.   return parse_string(1, pat, (char *) 0);
  213. }
  214.  
  215. command select_tag_file() on cx_tab[ALT(',')]
  216. {       /* switch to a particular tags file */
  217.   char file[80], *def, *old = bufname;
  218.  
  219.   do_save_tags();
  220.   bufname = "-tags";
  221.   def = exist("-tags") ? filename : initial_tag_file;
  222.   bufname = old;
  223.   get_file(file, "Tag file", def);
  224.   load_tags(file);
  225.   say("Tags loaded from %s", file);
  226. }
  227.  
  228. command clear_tags()  /* erase all tags */
  229. {
  230.   init_tags();
  231.   zap("-tags");
  232.   do_save_tags();
  233. }
  234.  
  235. command tag_files() on cx_tab[ALT('.')]
  236. {
  237.   char pat[FNAMELEN], *s;
  238.  
  239.   init_tags();
  240.   get_file(pat, "Add/update tags for files matching", filename);
  241.   iter = 0;
  242.   if (!(s = file_match(pat, 2)))
  243.     error("No matches");
  244.   for (; s; s = file_match(pat, 0)) {
  245.     delete_tags(s);
  246.     tag_a_file(s);
  247.   }
  248.   do_save_tags();
  249.   say("%s tagged.", pat);
  250. }
  251.  
  252. tag_a_file(s)
  253. char *s;
  254. {
  255.   char subr[40], *ext, *orig = bufname, *temp = 0;
  256.   int ok, err = 0, opoint;
  257.  
  258.   if (!look_file(s)) {
  259.     if (!temp)
  260.       temp = temp_buf();
  261.     bufname = temp;
  262.     err = read_file(s, strip_returns.default);
  263.     if (!err)
  264.       call_mode(filename);
  265.   }
  266.   if (!err) {
  267.     ext = get_extension(s);
  268.     sprintf(subr, "tag-suffix-%s", *ext ? (ext + 1) : "none");
  269.     opoint = point;
  270.     point = 0;
  271.     ok = try_calling(subr) || try_calling("tag-suffix-default");
  272.     point = opoint;
  273.   }
  274.   bufname = orig;
  275.   if (temp)
  276.     delete_buffer(temp);
  277.   if (err)    /* couldn't read file */
  278.     quick_abort();  /* already showed error msg */
  279.   else if (!ok)
  280.     error("Don't know how to tag the file %s", s);
  281. }
  282.  
  283. tag_suffix_asm()  /* tag all labels or procs in the file */
  284. {
  285.   char func[70];
  286.   int start, ofold = case_fold;
  287.  
  288.   case_fold = 1;
  289.   while (re_search(1, "^[ \t]*([a-z0-9@$_]+)[ \t]*:")) {
  290.     grab(start = find_group(1, 1), find_group(1, 0), func);
  291.     add_tag(func, filename, start);
  292.   }
  293.   point = 0;
  294.   while (re_search(1, "^[ \t]*([a-z0-9@$_]+)[ \t]+proc[ \t\n;]+")) {
  295.     grab(start = find_group(1, 1), find_group(1, 0), func);
  296.     add_tag(func, filename, start);
  297.   }
  298.   case_fold = ofold;
  299. }
  300.  
  301. tag_suffix_e()    { tag_suffix_c(); }
  302. tag_suffix_h()    { tag_suffix_c(); }
  303.  
  304. tag_suffix_c()    /* tag all c functions in this file */
  305. {
  306.   int end;
  307.  
  308.   while (re_search(1, "({|(/%*)|(#define[ \t]+[a-zA-Z0-9_]+%([^)]*%))|//|[a-zA-Z0-9_]+)")) {
  309.     end = point;    /* find {, comment open, or ident */
  310.     point = matchstart;
  311.     if (curchar() == '{')
  312.       skip_c_braces();
  313.     else if (curchar() == '/') {
  314.       if (character(point + 1) == '*') {
  315.         point += 2;
  316.         search(1, "*/");
  317.       } else
  318.         nl_forward(); /* c++ comment */
  319.     } else if (!good_c_tag())
  320.       point = end;
  321.   }
  322. }
  323.  
  324. skip_c_braces()   /* skip over c function definition */
  325. {
  326.   int level = 0;
  327.   char c, buf[4];
  328.  
  329.   strcpy(buf, "X|\\");
  330.   while (re_search(1, "[{}\"']|/%*|//")) {
  331.     buf[0] = c = character(point - 1);
  332.     if (c == '\"' || c == '\'')
  333.       while (re_search(1, buf)
  334.           && character(point - 1) == '\\')
  335.         point++;
  336.     else if (c == '*')
  337.       point++, search(1, "*/");
  338.     else if (c == '/')    /* c++ comment */
  339.       nl_forward();
  340.     else if (c == '{')
  341.       level++;
  342.     else if (!--level)
  343.       break;
  344.   }
  345. }
  346.  
  347. good_c_tag()  /* return 1 if at a valid c func def & tag it */
  348. {
  349.   char func[150];
  350.   int start = point;
  351.   
  352.   if (curchar() == '#')                 /* KSH */
  353.   {
  354.     if (re_search (1, "[ \t]+"))
  355.     {
  356.       start = point;
  357.       if (!parse_string(1, "[a-zA-Z0-9_]+", func))
  358.       {
  359.         return (0);
  360.       }
  361.       re_search (1, "[^\\][ \t]*\n");
  362.     }
  363.     else 
  364.     {
  365.       to_end_line();
  366.       return (0);
  367.     }
  368.   }
  369.   else if (parse_string (1, "typedef", (char *) 0)) /* KSH */
  370.   {
  371.     point += 7;
  372.     if (re_search (1, "[^a-zA-Z0-9_]+"))
  373.     {
  374.       if (re_search (1, "struct[ \t\n]+[a-zA-Z0-9_]*[ \t\n]*{"))
  375.       {
  376.         int end;
  377.         int found = 0;
  378.  
  379.         point--;
  380.         skip_c_braces();
  381.         while (re_search (1, "((/%*)|//|;)"))
  382.         {
  383.           point = matchstart;
  384.           if (curchar() == '/')
  385.           {
  386.             if (character(point + 1) == '*')
  387.             {
  388.               point += 2;
  389.               search(1, "*/");
  390.             }
  391.             else
  392.             {
  393.               nl_forward(); /* c++ comment */
  394.             }
  395.           }
  396.           else
  397.           {
  398.             break;
  399.           }
  400.         }
  401.         end = point;
  402.         re_search (-1, "[ \t\n]*");
  403.         while (parse_string (-1, "[a-zA-Z0-9_]+", func))
  404.         {
  405.           add_tag(func, filename, point);
  406.           found++;
  407.           re_search (-1, "[ \t\n]*");          
  408.           point--;
  409.           if (curchar() == ',')
  410.           {
  411.             point--;
  412.             re_search (-1, "[ \t]*");                      
  413.           }
  414.           else
  415.           {
  416.             break;
  417.           }
  418.         }
  419.         point = end;
  420.         return (found);
  421.       }
  422.     }
  423.     to_end_line();
  424.     return (0);
  425.   }
  426.   else
  427.   {
  428.     point = start;
  429.     if (!parse_string(1, "[a-zA-Z0-9_]+", func))
  430.     {
  431.       return (0);
  432.     }
  433.     if (!parse_string(1, "[ \t]*%(", (char *) 0))
  434.     {
  435.       return (0);
  436.     }
  437.     if (!move_level(1, "(", ")"))
  438.     {
  439.       return (0);
  440.     }
  441.     re_search(1, "([ \t\n]|(/%*([^*]|%*[^/])*%*/)|//.*)*");
  442.     if (!parse_string(1, "[A-Za-z{]", (char *) 0))
  443.     {
  444.       return (0);
  445.     }
  446.   }
  447.   add_tag(func, filename, start);
  448.   return (1);
  449. }
  450.  
  451. add_tag(func, file, pos)
  452. char *func, *file;
  453. {
  454.   char rel[FNAMELEN], *oldbuf = bufname;
  455.  
  456.   if (tag_relative)   /* use relative version instead */
  457.     relative(file, rel), file = rel;
  458.   say("Adding %s in %s", func, file);
  459.   bufname = "-tags";
  460.   point = 0;
  461.   bprintf("%s;%s;%d\n", func, file, pos);
  462.   bufname = oldbuf;
  463. }
  464.  
  465. do_retag_file(file)
  466. char *file;
  467. {
  468.   delete_tags(file);
  469.   tag_a_file(file);
  470.   do_save_tags();
  471. }
  472.  
  473. delete_tags(file)   /* delete all tags pointing to file */
  474. char *file;
  475. {
  476.   int start;
  477.   char rel[FNAMELEN], pat[FNAMELEN], *oldbuf = bufname;
  478.  
  479.   if (tag_relative)   /* use relative version instead */
  480.     relative(file, rel), file = rel;
  481.   bufname = "-tags";
  482.   point = 0;
  483.   sprintf(pat, ";%s;", file);
  484.   while (search(1, pat)) {
  485.     to_begin_line();
  486.     start = point;
  487.     nl_forward();
  488.     delete(start, point);
  489.   }
  490.   bufname = oldbuf;
  491. }
  492.  
  493. tag_suffix_lsp()                        /* KSH */
  494. {
  495.   int old_case_fold = case_fold;
  496.   int end;
  497.   int start;
  498.   char func[80];
  499.   
  500.   case_fold = 1;
  501.   while (re_search (1, "^%(def"))
  502.   {
  503.     forward_one_sexp ();
  504.     forward_one_sexp ();
  505.     end = point;
  506.     backward_one_sexp ();
  507.     start = point;
  508.     if (character (start) == '\'') start++;
  509.     grab (start, end, func);
  510.     add_tag (func, filename, start);
  511.     point = end;
  512.   }
  513.   case_fold = old_case_fold;
  514. }
  515.  
  516. tag_suffix_scm() { tag_suffix_lsp(); }  /* KSH */
  517.  
  518. /* tag_suffix_kms() { tag_suffix_lsp(); }  /* KSH */
  519.  
  520. pathname_as_directory(spec)             /* KSH */
  521. char *spec;
  522. {
  523.   int i = strlen (spec);
  524.   if (i && spec[i - 1] != '\\')
  525.   {
  526.     spec[i] = '\\';
  527.     spec[i + 1] = 0;
  528.   }
  529. }
  530.  
  531. char *strchr (s, c)                     /* KSH */
  532. char *s;
  533. char c;
  534. {
  535.   while (*s)
  536.   {
  537.     if (*s == c)
  538.       return (s);
  539.     s++;
  540.   }
  541.   return (0);
  542. }
  543.  
  544. init_tags_path()                          /* KSH */
  545. {
  546.   strcpy(initial_tag_file, project_directory);
  547.   pathname_as_directory(initial_tag_file);
  548.   strcat(initial_tag_file, "tags");
  549. }
  550.  
  551. init_tags_default()                     /* KSH */
  552. {
  553.   struct file_info finfo;
  554.  
  555.   if (!check_file(initial_tag_file, &finfo))
  556.   {
  557.     init_tags_path();
  558.   }
  559.   init_tags();
  560. }
  561.  
  562. command tag_project()                   /* KSH */
  563. {
  564.   char str[sizeof(project_directories)];
  565.   char *s = str;
  566.   char *ss = s;
  567.   char files[80];
  568.   char *fs;
  569.   int i;
  570.   char *hfiles = "*.h";
  571.   char *cfiles = "*.c";
  572.   char *ext = cfiles;
  573.  
  574.   if (has_arg)
  575.   {
  576.     ext = hfiles;
  577.   }
  578.   iter = 0;
  579.   delete_buffer ("-tags");
  580.   init_tags_path();
  581.   init_tags();
  582.   while (1)
  583.   {
  584.     strcpy (str, project_directories);
  585.     s = str;
  586.     while (s)
  587.     {
  588.       ss = strchr (s, ';');
  589.       if (ss) *ss++ = 0;
  590.       if (strcmp (s, ".") == 0)
  591.       {
  592.         strcpy (files, project_directory);
  593.       }
  594.       else
  595.       {
  596.         strcpy (files, s);
  597.         absolute (files);
  598.         if (strcmp (files, s) != 0)
  599.         {
  600.           strcpy (files, project_directory);
  601.           pathname_as_directory (files);
  602.           strcat (files, s);
  603.         }
  604.       }
  605.       pathname_as_directory (files);    
  606.       strcat (files, ext);
  607.       s = ss;
  608.       for (fs = file_match (files, 2); fs; fs = file_match (files, 0)) 
  609.       {
  610.         tag_a_file (fs);
  611.       }
  612.     }
  613.     if (ext == cfiles)
  614.       ext = hfiles;
  615.     else
  616.       break;
  617.   }
  618.   do_save_tags ();
  619. }
  620.  
  621. command pluck_tag() on cx_tab[',']
  622. {    /* read a function name at point & go there via tags */
  623.   char tag[80];
  624.  
  625.   init_tags_default ();                 /* KSH */
  626.   iter = 0;
  627.   point--;
  628.   re_search(1, word_pattern);
  629.   re_search(-1, word_pattern);
  630.   grab(point, matchstart, tag);
  631.   go_tag(tag);
  632. }
  633.  
  634. command goto_tag() on cx_tab['.'] /* asks for a tag, then goes there */
  635. {
  636.   char tag[80];
  637.  
  638.   init_tags_default();                  /* KSH */
  639.   iter = 0;
  640.   if (!has_arg)
  641.     get_tag(tag, "Find tag [next tag]: ");
  642.   else
  643.     *tag = 0;
  644.   go_tag(tag);
  645. }