home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume38 / cie / part01 next >
Text File  |  1993-06-21  |  74KB  |  2,447 lines

  1. Newsgroups: comp.sources.misc
  2. From: kennedy@art.intellection.com (Brian M Kennedy)
  3. Subject: v38i015:  cie - C++ In Emacs v1.0, Part01/02
  4. Message-ID: <csm-v38i015=cie.182302@sparky.IMD.Sterling.COM>
  5. X-Md4-Signature: d975b3451263f1d25fd0907d3c799274
  6. Sender: kent@sparky.imd.sterling.com (Kent Landfield)
  7. Reply-To: Brian M Kennedy <kennedy@intellection.com>
  8. Organization: Sterling Software
  9. Date: Sun, 20 Jun 1993 23:23:27 GMT
  10. Approved: kent@sparky.imd.sterling.com
  11.  
  12. Submitted-by: kennedy@art.intellection.com (Brian M Kennedy)
  13. Posting-number: Volume 38, Issue 15
  14. Archive-name: cie/part01
  15. Environment: Emacs, C++
  16.  
  17. Excerpts from the README:
  18.  
  19. This package is a collection of some of the tools/enhancements we use for C++
  20. development work within GNU Emacs.  Briefly, it consists of an enhanced etags
  21. for C++, a related class hierarchy generator, a mode and M-x commands for
  22. browsing the hierarchy and getting lists of class members, a command goto-file
  23. that takes you to the proper line in a file, functions to make both tag names
  24. and file names mouseable, and a class manual generator that uses the hierarchy
  25. and tag information, coupled with the comments in the code, to build a class
  26. manual in texinfo format.
  27.  
  28. I've been stalling on releasing this, hoping to find time to implement some of
  29. the outstanding features and do some significant cleanup.  I have decided that
  30. I will never get to it (and I feel more and more guilty every time I see one
  31. of the many requests for these features on the newsgroups), so I am just going
  32. to release it basically as is.  My apologies.
  33.  
  34. This has run with GNU Emacs 18.51, 18.55, 18.57 and 18.58.  I have not yet 
  35. switched to Emacs 19, so neither has this code.  If you want to use it with 
  36. Emacs 19, I encourage you to volunteer to "port" it for the rest of us ;-)
  37.  
  38. The etags++ and hier++ C++ programs have been compiled with Sun C++, 
  39. Centerline C++, Lucid C++, and Comeau C++ on Sun OS, Ultrix, and AIX 
  40. platforms.
  41.  
  42. =====
  43.  
  44. Here are excerpts from the important files:
  45.  
  46. ======================
  47. ;;; tags.el
  48.  
  49. ;; INTELLECTION MODS:
  50. ;; 
  51. ;; 1) Prefers the tags named explicitly after C-A's at the end of each line.
  52. ;;    This is true both for find-tag and for the completion-alist.
  53. ;; 2) Support for C++ scoping -- class::name is considered a tag and both
  54. ;;    class::name and name are matches (class::name preferred though).
  55. ;; 3) Support for completion of scoped names as well as unscoped names.
  56. ;;    That is, the alist contains both the fully-scoped name, and each
  57. ;;    subname (c1::c2::mem => c1::c2::mem, c2::mem, and mem in the alist).
  58. ;; 4) Added mechanism to save out the completion alist into TAGS.alist
  59. ;;    which is checked for when loading TAGS to prevent the need to rebuild
  60. ;;    the alist (which can take a while with large systems).  As an added
  61. ;;    advantage, this mechanism removes duplicates from the alist before
  62. ;;    saving it out (making it faster and much smaller).
  63.  
  64. ======================
  65. ;;; hier-mode.el
  66. ;;; Hierarchy mode (for hierarchies output by hier++)
  67.  
  68. "Major mode for viewing class hierarchy files output by hier++.
  69. The file is formatted like this:
  70.  
  71. * class_a 
  72.   * child_b  :class_a
  73.   * child_c  :class_a :class_f
  74.     * grandchild_d  :child_c
  75.     * grandchild_e  :child_c
  76. * class_f
  77.   * child_c  :class_a :class_f
  78.     * grandchild_d  :child_c
  79.     * grandchild_e  :child_c
  80.   * child_g  :class_f
  81.  
  82. Classes child_b and child_c are derived from class_a; classes child_c and
  83. child_g are derived from class_f; classes grandchild_d and grandchild_e are
  84. both derived from child_c.  Note that each class (and all of its children) 
  85. will appear in the file once under each parent.
  86.  
  87. Defined keys:
  88. M-p moves to the previous sibling
  89. M-n moves to the next sibling
  90. M-u moves up to the parent
  91. M-h finds the first occurrence of the hierarchy element for a class 
  92.     (similar to M-. in behavior)
  93. M-g finds the next occurrence (like M-,) in the case of multiple-inheritance.
  94. M-m brings up a new window with a listing of all the members (both direct and 
  95.     inherited) of that hierarchy entry.  It does this via tags, so you must 
  96.     have tags set up in Emacs.  It will also only work properly if the tags 
  97.     file was generated by etags++ (companion to hier++)."
  98.  
  99. ======================
  100. ;;; class-manual.el
  101. ;;; Class Manual Generation
  102. ;;;   Code to use hier-mode (for hierarchies output by hier++) and etags++
  103. ;;;   functionality to build a class manual using the header comments in 
  104. ;;;   the code itself.  The formatting is in standard texinfo.
  105. ;;;   This is a hack that has been helpful for us, given our coding 
  106. ;;;   guidelines.  It will likely need modification to produce good
  107. ;;;   output for you.  (Header comments are those placed between the 
  108. ;;;   signature and the body of functions or classes.  If you don't follow
  109. ;;;   this convention, then this code will need modification.)
  110.  
  111. ======================
  112. // etags++/etags++.c
  113. //
  114. // This program reads in C++ code and generates a tags file for GNU Emacs.
  115. // This program is more sophisticated than the standard etags program for C++
  116. // programs.  It finds all classes, structs, unions, enums, enumerators, #defines,
  117. // typedefs, functions (both global and member), and data (both global and member).
  118. // Furthermore, it handles C++ scoping correctly, outputting fully-scoped tags
  119. // at the end of each line.  Thus, we have modified our Emacs tags.el to search
  120. // the fully-scoped names at the ends of the lines before the patterns.  It also
  121. // handles template syntax.
  122.  
  123. ======================
  124. // etags++/hier++.c
  125. //
  126. // This program reads in C++ code and generates a "hier" file that displays the
  127. // class hierarchy.  You can then use the GNU Emacs hier-mode for traversing the
  128. // hierarchy and extracting information from your TAGS (if generated by etags++).
  129.  
  130.  
  131. =============================================================================
  132. == c++_in_emacs.shar ========================================================
  133. =============================================================================
  134. #! /bin/sh
  135. # This is a shell archive.  Remove anything before this line, then feed it
  136. # into a shell via "sh file" or similar.  To overwrite existing files,
  137. # type "sh file -c".
  138. # Contents:  cie cie/etags++ cie/etags++/c++file.c
  139. #   cie/etags++/etags++.c cie/hier-mode.el cie/minibuffer-yank.el
  140. #   cie/tags.el
  141. # Wrapped by kent@sparky on Sun Jun 20 18:21:17 1993
  142. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  143. echo If this archive is complete, you will see the following message:
  144. echo '          "shar: End of archive 1 (of 2)."'
  145. if test ! -d 'cie' ; then
  146.     echo shar: Creating directory \"'cie'\"
  147.     mkdir 'cie'
  148. fi
  149. if test ! -d 'cie/etags++' ; then
  150.     echo shar: Creating directory \"'cie/etags++'\"
  151.     mkdir 'cie/etags++'
  152. fi
  153. if test -f 'cie/etags++/c++file.c' -a "${1}" != "-c" ; then 
  154.   echo shar: Will not clobber existing file \"'cie/etags++/c++file.c'\"
  155. else
  156.   echo shar: Extracting \"'cie/etags++/c++file.c'\" \(10994 characters\)
  157.   sed "s/^X//" >'cie/etags++/c++file.c' <<'END_OF_FILE'
  158. X////////////////////////////////////////////////////////////////////////////////
  159. X// c++file.c
  160. X//
  161. X// This .c file, written in C++, is intended to be included in etags++.c and hier++.c.
  162. X// It is a quick-and-dirty "fuzzy" parser for C++ files that identifies enough tokens for
  163. X// etags++ and hier++ to do a good job.  See those files for information on the resultant
  164. X// functionality.  This file simply provides the common parsing code.
  165. X//
  166. X// Author:  Brian M. Kennedy
  167. X// (C) Copyright 1993, Intellection Inc.
  168. X// Permission is granted to use, copy, or modify this code as long as this author and
  169. X// copyright notice is maintained in all copies.
  170. X//
  171. X// Note:
  172. X//   This is quick, hack code that was not written to be modifiable or maintainable -- beware!!
  173. X//   I would not allow code such as this into our product!  But it is okay for a quick tool hack.
  174. X//   If you are a user, I hope you enjoy it.  If you are modifier, my apologies ;-(
  175. X
  176. X#include <stdlib.h>
  177. X#include <iostream.h>
  178. X#include <fstream.h>
  179. X#include <ctype.h>
  180. X#include <string.h>
  181. X
  182. X
  183. Xtypedef char Boolean;
  184. X#define FALSE 0
  185. X#define TRUE  1
  186. X
  187. X
  188. X// Exit Status
  189. X#define GOOD 0
  190. X#define BAD  1
  191. X
  192. X
  193. X////////////////////////////////////////////////////////////////////////////////
  194. X
  195. Xinline Boolean
  196. Xisident (char c)
  197. X{ return c == '_' || isalnum(c); }
  198. X
  199. X
  200. Xunsigned
  201. Xsize (unsigned num)
  202. X{ unsigned ret = 0;
  203. X  while (num)
  204. X  { ++ret;
  205. X    num /= 10;
  206. X  }
  207. X  return ret;
  208. X}
  209. X
  210. X
  211. X////////////////////////////////////////////////////////////////////////////////
  212. X
  213. Xstruct File
  214. X{
  215. X  int   size;
  216. X  char* chars;
  217. X
  218. X  File (int max_size);
  219. X  File (int max_size, char* initial_string);
  220. X
  221. X  void read (const char* filename);
  222. X};
  223. X
  224. X
  225. XFile::
  226. XFile (int max_size)
  227. X:size(max_size+1), chars(new char [size+2])
  228. X{
  229. X  chars[0] = 0;
  230. X  chars[size+1] = 0;
  231. X}
  232. X
  233. X
  234. XFile::
  235. XFile (int max_size, char* initial_string)
  236. X:size(max_size), chars(new char [size+2])
  237. X{
  238. X  chars[0] = 0;
  239. X  strcpy(chars+1, initial_string);
  240. X  chars[size+1] = 0;
  241. X}
  242. X
  243. X
  244. Xvoid File::
  245. Xread (const char* filename)
  246. X{ ifstream is (filename);
  247. X  is.get(chars+1, size, 0);    // note: chars is indexed-based at 1, not 0
  248. X}
  249. X
  250. X
  251. X////////////////////////////////////////////////////////////////////////////////
  252. X
  253. Xstruct File_Pos
  254. X{
  255. X  const File* file;
  256. X  unsigned    char_no;
  257. X  unsigned    line_no;
  258. X
  259. X  File_Pos (const File& file_arg) :file(&file_arg), char_no(1), line_no(1) {}
  260. X  File_Pos (const File_Pos& p)    :file(p.file), char_no(p.char_no), line_no(p.line_no) {}
  261. X
  262. X  const char* chars () const           { return file->chars + char_no; }
  263. X  char        chars (unsigned n) const { return chars()[n]; }
  264. X
  265. X  File_Pos& inc   ();
  266. X  File_Pos& inc   (unsigned n);
  267. X
  268. X  inline  Boolean match (const char* string, unsigned size);
  269. X  Boolean match (const char* string) { return match(string, strlen(string)); }
  270. X  Boolean match (Boolean (*fn)(char c));
  271. X
  272. X  void find_match (const char* string, unsigned size);
  273. X  void find_match (const char* string) { find_match(string, strlen(string)); }
  274. X  void find_match (Boolean (*fn)(char c));
  275. X  void find_match (char match, char escape);
  276. X
  277. X  void find_prev_newline ();
  278. X};
  279. X
  280. X
  281. Xinline File_Pos& File_Pos::
  282. Xinc ()
  283. X{ char c = chars(0);
  284. X  if (c)
  285. X  { ++char_no;
  286. X    if (c == '\n')
  287. X      ++line_no;
  288. X  }
  289. X  return *this;
  290. X}
  291. X
  292. X
  293. XFile_Pos& File_Pos::
  294. Xinc (unsigned n)
  295. X{ for(unsigned i = 0; i < n; ++i)
  296. X    inc();
  297. X  return *this;
  298. X}
  299. X
  300. X
  301. Xinline Boolean File_Pos::
  302. Xmatch (const char* string, unsigned size)
  303. X{ if (strncmp(string, chars(), size))
  304. X    return FALSE;
  305. X  else
  306. X  { inc(size);
  307. X    return TRUE;
  308. X  }
  309. X}
  310. X
  311. X
  312. XBoolean File_Pos::
  313. Xmatch (Boolean (*fn)(char c))
  314. X{ Boolean ret = fn(chars(0));
  315. X  while (fn(chars(0)))
  316. X    inc();
  317. X  return ret;
  318. X}
  319. X
  320. X
  321. Xvoid File_Pos::
  322. Xfind_match (const char* string, unsigned size)
  323. X{
  324. X  while (!match(string,size) && chars(0))
  325. X    inc();
  326. X}
  327. X
  328. Xvoid File_Pos::
  329. Xfind_match (Boolean (*fn)(char c))
  330. X{
  331. X  while (!match(fn) && chars(0))
  332. X    inc();
  333. X}
  334. X
  335. X
  336. Xvoid File_Pos::
  337. Xfind_match (char match, char escape)
  338. X{
  339. X  while (chars(0) && chars(0) != match)
  340. X  { if (chars(0) == escape)
  341. X      inc();
  342. X    inc();
  343. X  }
  344. X  inc();
  345. X}
  346. X
  347. X
  348. Xvoid File_Pos::
  349. Xfind_prev_newline ()
  350. X{
  351. X  while (chars(0) && chars(0) != '\n')
  352. X    --char_no;
  353. X  ++char_no;
  354. X}
  355. X
  356. X
  357. X////////////////////////////////////////////////////////////////////////////////
  358. X
  359. Xenum C_Token
  360. X{ CHARACTER, ESCAPED,
  361. X  TOKEN, COMMENT, DIRECTIVE, 
  362. X  CODE_TOKEN, CLASS_KW, STRUCT_KW, UNION_KW, ENUM_KW, TYPEDEF_KW,
  363. X  TEMPLATE_KW, TEMPLATE_ARGS,  
  364. X  IDENTIFIER, STRING_CONSTANT, CHAR_CONSTANT, DEFINE, 
  365. X  OPEN_PARE, CLOSE_PARE, OPEN_BRACE, CLOSE_BRACE, COLONS, COMMA, SEMI_COLON, EQUAL,
  366. X  NOTE, EXPORT, DECLARE_MACRO, 
  367. X  DEFINE_MACRO, DEFINE_GET, DEFINE_SET, DEFINE_GETSET, DEFINE_INC, DEFINE_DEC,
  368. X  END_OF_FILE
  369. X};
  370. X
  371. X
  372. Xstruct C_File_Pos
  373. X:public File_Pos
  374. X{
  375. X  C_Token  token;
  376. X  unsigned length;
  377. X
  378. X  C_File_Pos (const File& file_arg);
  379. X
  380. X  void identify_token  ();
  381. X  void next_char       ();
  382. X  void next_token      ();
  383. X  void next_code       ();
  384. X  void next_identifier ();
  385. X
  386. X  void close_brace   ();
  387. X  void close_pare    ();
  388. X  void close_func    ();
  389. X  void close_define  ();
  390. X
  391. X};
  392. X
  393. X
  394. XC_File_Pos::
  395. XC_File_Pos (const File& file_arg)
  396. X:File_Pos(file_arg), token(CHARACTER), length(1)
  397. X{ identify_token(); }
  398. X
  399. X
  400. X#define TOKEN_IDENTIFIER           \
  401. X{ pos.match(isident);              \
  402. X  token  = IDENTIFIER;             \
  403. X  length = pos.char_no - char_no;  \
  404. X}
  405. X
  406. X
  407. Xvoid C_File_Pos::
  408. Xidentify_token ()
  409. X{
  410. X  File_Pos pos (*this);
  411. X  switch(chars(0))
  412. X  {
  413. X  case '\0':
  414. X    token = END_OF_FILE;
  415. X    length = 1;
  416. X    break;
  417. X  case 'c':
  418. X    if (pos.match("class", 5) && !isident(pos.chars(0)))
  419. X    { token = CLASS_KW;
  420. X      length = pos.char_no - char_no;
  421. X    }
  422. X    else
  423. X      TOKEN_IDENTIFIER;
  424. X    break;
  425. X  case 's':
  426. X    if (pos.match("struct", 6) && !isident(pos.chars(0)))
  427. X    { token = STRUCT_KW;
  428. X      length = pos.char_no - char_no;
  429. X    }
  430. X    else
  431. X      TOKEN_IDENTIFIER;
  432. X    break;
  433. X  case 'u':
  434. X    if (pos.match("union", 5) && !isident(pos.chars(0)))
  435. X    { token = UNION_KW;
  436. X      length = pos.char_no - char_no;
  437. X    }
  438. X    else
  439. X      TOKEN_IDENTIFIER;
  440. X    break;
  441. X  case 'e':
  442. X    if (pos.match("enum", 4) && !isident(pos.chars(0)))
  443. X    { token = ENUM_KW;
  444. X      length = pos.char_no - char_no;
  445. X    }
  446. X    else
  447. X      TOKEN_IDENTIFIER;
  448. X    break;
  449. X  case 't':
  450. X    if (pos.match("typedef", 7))
  451. X    { if (!isident(pos.chars(0)))
  452. X      { token = TYPEDEF_KW;
  453. X    length = pos.char_no - char_no;
  454. X      }
  455. X      else
  456. X    TOKEN_IDENTIFIER;
  457. X    }
  458. X    else if (pos.match("template", 8) && !isident(pos.chars(0)))
  459. X    { token = TEMPLATE_KW;
  460. X      length = pos.char_no - char_no;
  461. X    }
  462. X    else
  463. X      TOKEN_IDENTIFIER;
  464. X    break;
  465. X  case '#':
  466. X    do
  467. X    { pos.inc();
  468. X    } while (pos.chars(0) != '\n' && isspace(pos.chars(0)));
  469. X    if (pos.match("define", 6) && !isident(pos.chars(0)))
  470. X    { token = DEFINE;
  471. X      length = pos.char_no - char_no;
  472. X    }
  473. X    else
  474. X    { pos.find_match('\n', '\\');
  475. X      token  = DIRECTIVE;
  476. X      length = pos.char_no - char_no;
  477. X    }
  478. X    break;
  479. X  case '(':
  480. X    token = OPEN_PARE;
  481. X    length = 1;
  482. X    break;
  483. X  case ')':
  484. X    token = CLOSE_PARE;
  485. X    length = 1;
  486. X    break;
  487. X  case '{':
  488. X    token = OPEN_BRACE;
  489. X    length = 1;
  490. X    break;
  491. X  case '}':
  492. X    token = CLOSE_BRACE;
  493. X    length = 1;
  494. X    break;
  495. X  case '<': {
  496. X    unsigned last_more = pos.char_no;
  497. X    pos.inc();
  498. X    while (!strchr("{}\"\';\n", pos.chars(0)))
  499. X    { if (pos.chars(0) == '>')
  500. X    last_more = pos.char_no;
  501. X      pos.inc();
  502. X    }
  503. X    if (last_more != char_no)
  504. X    { token = TEMPLATE_ARGS;
  505. X      length = last_more - char_no + 1;
  506. X    }
  507. X    else
  508. X    { token = CHARACTER;
  509. X      length = 1;
  510. X    }
  511. X    break;
  512. X  }
  513. X  case ':':
  514. X    if (pos.match("::", 2))
  515. X    { token = COLONS;
  516. X      length = 2;
  517. X    }
  518. X    else
  519. X    { token = CHARACTER;
  520. X      length = 1;
  521. X    }
  522. X    break;
  523. X  case ',':
  524. X    token = COMMA;
  525. X    length = 1;
  526. X    break;
  527. X  case ';':
  528. X    token = SEMI_COLON;
  529. X    length = 1;
  530. X    break;
  531. X  case '=':
  532. X    token = EQUAL;
  533. X    length = 1;
  534. X    break;
  535. X  case '/':
  536. X    if (pos.match("//", 2))
  537. X    { pos.find_match("\n", 1);
  538. X      token = COMMENT;
  539. X      length = pos.char_no - char_no;
  540. X    }
  541. X    else if (pos.match("/*", 2))  // */
  542. X    { pos.find_match("*/", 2);
  543. X      token = COMMENT;
  544. X      length = pos.char_no - char_no;
  545. X    }
  546. X    else
  547. X    { token = CHARACTER;
  548. X      length = 1;
  549. X    }
  550. X    break;
  551. X  case '\"':
  552. X    pos.inc();
  553. X    pos.find_match('\"', '\\');
  554. X    token = STRING_CONSTANT;
  555. X    length = pos.char_no - char_no;
  556. X    break;
  557. X  case '\'':
  558. X    pos.inc();
  559. X    pos.find_match('\'', '\\');
  560. X    token = CHAR_CONSTANT;
  561. X    length = pos.char_no - char_no;
  562. X    break;
  563. X  case '\\':
  564. X    token = ESCAPED;
  565. X    length = 2;
  566. X    break;
  567. X  case 'R':
  568. X    if (pos.match("RWExport") && !isident(pos.chars(0)))
  569. X    { token = COMMENT;
  570. X      length = pos.char_no - char_no;
  571. X    }
  572. X    else
  573. X      TOKEN_IDENTIFIER;    
  574. X    break;
  575. X  case 'D':
  576. X    if (pos.match("DEFINE_"))
  577. X    { switch(pos.chars(0))
  578. X      {
  579. X      case 'G':
  580. X    token = (chars(3) == 'S') ? DEFINE_GETSET : DEFINE_GET;
  581. X    break;
  582. X      case 'S':
  583. X    token = DEFINE_SET;
  584. X    break;
  585. X      case 'I':
  586. X    token = DEFINE_INC;
  587. X    break;
  588. X      case 'D':
  589. X    token = DEFINE_DEC;
  590. X    break;
  591. X      default:
  592. X    token = DEFINE_MACRO;
  593. X      }
  594. X      pos.match(isident);
  595. X      length = pos.char_no - char_no;
  596. X    }
  597. X    else if (pos.match("DECLARE_"))
  598. X    { pos.match(isident);
  599. X      token = DECLARE_MACRO;
  600. X      length = pos.char_no - char_no;
  601. X    }
  602. X    else
  603. X      TOKEN_IDENTIFIER;
  604. X    break;
  605. X  case 'N':
  606. X    if (pos.match("NOTE") && !isident(pos.chars(0)))
  607. X    { token = NOTE;
  608. X      length = pos.char_no - char_no;
  609. X    }
  610. X    else
  611. X      TOKEN_IDENTIFIER;
  612. X    break;
  613. X  case 'E':
  614. X    if (   pos.match("EXPORT_ACCESSOR") 
  615. X       || pos.match("EXPORT_PARM")
  616. X       || (pos.match("EXPORT") && !isident(pos.chars(0))))
  617. X    { token = EXPORT;
  618. X      length = pos.char_no - char_no;
  619. X    }
  620. X    else
  621. X      TOKEN_IDENTIFIER;
  622. X    break;
  623. X  default:
  624. X    if (!isalpha(chars(0)))
  625. X    { token = CHARACTER;
  626. X      length = 1;
  627. X    }
  628. X    else
  629. X      TOKEN_IDENTIFIER;
  630. X  }
  631. X}
  632. X
  633. X
  634. Xinline void C_File_Pos::
  635. Xnext_char ()
  636. X{ inc(length);
  637. X  identify_token();
  638. X}
  639. X
  640. X
  641. Xvoid C_File_Pos::
  642. Xnext_token ()
  643. X{ do
  644. X  { next_char();
  645. X  } while (token <= TOKEN);
  646. X}
  647. X
  648. X
  649. Xvoid C_File_Pos::
  650. Xnext_code ()
  651. X{ do
  652. X  { next_char();
  653. X  } while (token <= CODE_TOKEN);
  654. X}
  655. X
  656. X
  657. Xvoid C_File_Pos::
  658. Xnext_identifier ()
  659. X{ do
  660. X  { next_char();
  661. X  } while (token != IDENTIFIER && token != END_OF_FILE);
  662. X}
  663. X
  664. X
  665. Xvoid C_File_Pos::
  666. Xclose_brace ()
  667. X{ int level = 1;
  668. X  while (level)
  669. X  { next_code();
  670. X    if (token == OPEN_BRACE)
  671. X      ++level;
  672. X    else if (token == CLOSE_BRACE)
  673. X      --level;
  674. X    else if (token == END_OF_FILE)
  675. X      level = 0;
  676. X  }
  677. X}
  678. X
  679. X
  680. Xvoid C_File_Pos::
  681. Xclose_pare ()
  682. X{ int level = 1;
  683. X  while (level)
  684. X  { next_code();
  685. X    if (token == OPEN_PARE)
  686. X      ++level;
  687. X    else if (token == CLOSE_PARE)
  688. X      --level;
  689. X    else if (token == END_OF_FILE)
  690. X      level = 0;
  691. X  }
  692. X}
  693. X
  694. X
  695. Xvoid C_File_Pos::
  696. Xclose_func ()
  697. X{ while (token != SEMI_COLON && token != OPEN_BRACE && token != END_OF_FILE)
  698. X    next_code();
  699. X  if (token == OPEN_BRACE)
  700. X    close_brace();
  701. X}
  702. X
  703. X
  704. Xvoid C_File_Pos::
  705. Xclose_define ()
  706. X{ while (chars(0) && chars(0) != '\n')
  707. X  { if (chars(0) == '\\')
  708. X      inc();
  709. X    inc();
  710. X  }
  711. X  if (chars(0))
  712. X    token = CHARACTER;
  713. X  else
  714. X    token = END_OF_FILE;
  715. X  length = 1;
  716. X}
  717. END_OF_FILE
  718.   if test 10994 -ne `wc -c <'cie/etags++/c++file.c'`; then
  719.     echo shar: \"'cie/etags++/c++file.c'\" unpacked with wrong size!
  720.   fi
  721.   # end of 'cie/etags++/c++file.c'
  722. fi
  723. if test -f 'cie/etags++/etags++.c' -a "${1}" != "-c" ; then 
  724.   echo shar: Will not clobber existing file \"'cie/etags++/etags++.c'\"
  725. else
  726.   echo shar: Extracting \"'cie/etags++/etags++.c'\" \(13241 characters\)
  727.   sed "s/^X//" >'cie/etags++/etags++.c' <<'END_OF_FILE'
  728. X////////////////////////////////////////////////////////////////////////////////
  729. X// etags++.c
  730. X//
  731. X// This program reads in C++ code and generates a tags file for GNU Emacs.
  732. X// This program is more sophisticated than the standard etags program for C++
  733. X// programs.  It finds all classes, structs, unions, enums, enumerators, #defines,
  734. X// typedefs, functions (both global and member), and data (both global and member).
  735. X// Furthermore, it handles C++ scoping correctly, outputting fully-scoped tags
  736. X// at the end of each line.  Thus, we have modified our Emacs tags.el to search
  737. X// the fully-scoped names at the ends of the lines before the patterns.  It also
  738. X// handles template syntax.
  739. X//
  740. X// In addition, we have added support for a few important macro conventions that
  741. X// we use.  DECLARE_*(name,..) macros define the tag <name> in the current scope;
  742. X// DEFINE_*(class,name,...) macros define the tag <class>::<name>.  We use NOTE(name)
  743. X// macros to name comments, so that you can refer to them by See::name in other
  744. X// comments.  In Emacs, M-. on See::name will take you to the named comment.
  745. X//
  746. X// Note that this uses "fuzzy", quick-and-dirty parsing to find the tokens.  Thus, it
  747. X// can miss some things.  Also note that this is not an etags replacement -- it only
  748. X// supports C/C++ code.  The etags program will still be needed for TeX, Fortran, etc.
  749. X//
  750. X// Author:  Brian M. Kennedy
  751. X// (C) Copyright 1993, Intellection Inc.
  752. X// Permission is granted to use, copy, or modify this code as long as this author and
  753. X// copyright notice is maintained in all copies.
  754. X//
  755. X// Note:
  756. X//   This is quick, hack code that was not written to be modifiable or maintainable -- beware!!
  757. X//   I would not allow code such as this into our product!  But it is okay for a quick tool hack.
  758. X//   If you are a user, I hope you enjoy it.  If you are modifier, my apologies ;-(
  759. X
  760. X#include "c++file.c"
  761. X
  762. X
  763. X////////////////////////////////////////////////////////////////////////////////
  764. X
  765. Xstruct Tag;
  766. X
  767. Xstruct Scope
  768. X{
  769. X  C_File_Pos name;
  770. X  Scope*     next;
  771. X
  772. X  Scope (const Scope& copy);
  773. X  Scope (const C_File_Pos& name_arg, Scope* next_arg);
  774. X  ~Scope () { delete next; }
  775. X
  776. X  Scope* pop ();
  777. X
  778. X  unsigned etags_size () const;
  779. X  void     etags_put  (ostream& os) const;
  780. X};
  781. X
  782. Xinline Scope* copy (const Scope* s);
  783. X
  784. X
  785. XScope::
  786. XScope (const Scope& s)
  787. X:name(s.name), next(copy(s.next))
  788. X{}
  789. X
  790. X
  791. XScope::
  792. XScope (const C_File_Pos& name_arg, Scope* next_arg)
  793. X:name(name_arg), next(copy(next_arg))
  794. X{}
  795. X
  796. X
  797. Xinline Scope* Scope::
  798. Xpop ()
  799. X{ Scope* ret = next;
  800. X  next = 0;
  801. X  delete this;
  802. X  return ret;
  803. X}
  804. X
  805. X
  806. Xunsigned Scope::
  807. Xetags_size () const
  808. X{ if(this)
  809. X    return name.length + 2 + next->etags_size();
  810. X  else
  811. X    return 0;
  812. X}
  813. X
  814. X
  815. Xvoid Scope::
  816. Xetags_put  (ostream& os) const
  817. X{ if(this)
  818. X  { next->etags_put(os);
  819. X    os.write(name.chars(), name.length);
  820. X    os << "::";
  821. X  }
  822. X}
  823. X
  824. X
  825. Xinline Scope*
  826. Xcopy (const Scope* s)
  827. X{ return s ? new Scope (*s) : 0; }
  828. X
  829. X
  830. X////////////////////////////////////////////////////////////////////////////////
  831. X// Prefixes
  832. X
  833. Xchar* prefix_string = " See EXPORTED set_ inc_ dec_";
  834. X
  835. XFile  prefix_file (strlen(prefix_string), prefix_string);
  836. X
  837. XC_File_Pos prefix_pos (prefix_file);
  838. XC_File_Pos see_pos    ((prefix_pos.next_identifier(), prefix_pos));
  839. XC_File_Pos exported_pos ((prefix_pos.next_identifier(), prefix_pos));
  840. XC_File_Pos set_pos    ((prefix_pos.next_identifier(), prefix_pos));
  841. XC_File_Pos inc_pos    ((prefix_pos.next_identifier(), prefix_pos));
  842. XC_File_Pos dec_pos    ((prefix_pos.next_identifier(), prefix_pos));
  843. X
  844. XScope  see_scope_obj (see_pos, 0);
  845. XScope* see_scope = &see_scope_obj;
  846. X
  847. XScope  exported_scope_obj (exported_pos, 0);
  848. XScope* exported_scope = &exported_scope_obj;
  849. X
  850. X
  851. X////////////////////////////////////////////////////////////////////////////////
  852. X
  853. Xstruct Tag
  854. X{
  855. X  Tag*       next;
  856. X  C_File_Pos name;
  857. X  File_Pos   pattern;
  858. X  Scope*     scope;
  859. X
  860. X  Tag (const Tag& t);
  861. X  Tag (const C_File_Pos& name_arg, const Scope* scope_arg);
  862. X
  863. X  ~Tag () { delete scope; }
  864. X
  865. X  unsigned etags_size () const;
  866. X  void     etags_put  (ostream& os) const;
  867. X};
  868. X
  869. XTag::
  870. XTag (const Tag& t)
  871. X:next(0), name(t.name), pattern(t.pattern), scope(copy(t.scope))
  872. X{}
  873. X
  874. XTag::
  875. XTag (const C_File_Pos& name_arg, const Scope* scope_arg)
  876. X:next(0), name(name_arg), pattern(name_arg), scope(copy(scope_arg))
  877. X{ pattern.find_prev_newline();
  878. X}
  879. X
  880. X
  881. Xunsigned Tag::
  882. Xetags_size () const
  883. X{ return ((name.length + pattern.char_no - name.char_no)
  884. X      + 1 + size(name.line_no) + 1 + size(name.char_no) + 2
  885. X      + scope->etags_size() + name.length + 1);
  886. X}
  887. X
  888. X
  889. Xvoid Tag::
  890. Xetags_put (ostream& os) const
  891. X{ os.write(pattern.chars(), name.length + name.char_no - pattern.char_no);
  892. X  os << '\177' << name.line_no << ',' << name.char_no << ",\1";  
  893. X  scope->etags_put(os);
  894. X  os.write(name.chars(), name.length);
  895. X  os << '\n';
  896. X}
  897. X
  898. X
  899. X////////////////////////////////////////////////////////////////////////////////
  900. X
  901. Xstruct Tag_List
  902. X{
  903. X  Tag* first;
  904. X  Tag* last;
  905. X
  906. X  Tag_List () :first(0), last(0) {}
  907. X  ~Tag_List ();
  908. X
  909. X  void inc (Tag* tag);
  910. X
  911. X  unsigned etags_size () const;
  912. X  void     etags_put  (ostream& os) const;
  913. X};
  914. X
  915. X
  916. XTag_List::
  917. X~Tag_List ()
  918. X{ Tag* tag = first;
  919. X  while(tag)
  920. X  { first = tag->next;
  921. X    delete tag;
  922. X    tag = first;
  923. X  }
  924. X  last = 0;
  925. X}
  926. X
  927. X
  928. Xinline void Tag_List::
  929. Xinc (Tag* tag)
  930. X{ if(last)
  931. X  { last->next = tag;
  932. X    last = tag;
  933. X  }
  934. X  else
  935. X  { first = last = tag;
  936. X  }
  937. X}
  938. X
  939. X
  940. Xunsigned Tag_List::
  941. Xetags_size () const
  942. X{ unsigned sum = 0;
  943. X  for(Tag* tag = first; tag; tag = tag->next)
  944. X    sum += tag->etags_size();
  945. X  return sum;
  946. X}
  947. X
  948. X
  949. Xvoid Tag_List::
  950. Xetags_put  (ostream& os) const
  951. X{ for(Tag* tag = first; tag; tag = tag->next)
  952. X    tag->etags_put(os);
  953. X}
  954. X
  955. X
  956. Xostream&
  957. Xoperator << (ostream& os, Tag_List* tags)
  958. X{ tags->etags_put(os);
  959. X  return os;
  960. X}
  961. X
  962. X
  963. X////////////////////////////////////////////////////////////////////////////////
  964. X
  965. XTag_List*
  966. Xget_tags (const File& file)
  967. X{
  968. X  Tag_List*  tags = new Tag_List ();
  969. X  Scope*     scope = 0;
  970. X  Scope*     qualified = 0;
  971. X  C_File_Pos pos (file);
  972. X  C_File_Pos prev_id (pos);
  973. X  while(pos.token != END_OF_FILE)
  974. X  {
  975. X    switch(pos.token)
  976. X    {
  977. X    case CLASS_KW:
  978. X    case STRUCT_KW:
  979. X    case UNION_KW:
  980. X      pos.next_code();
  981. X      if(pos.token == IDENTIFIER)
  982. X      { C_File_Pos tag_name (pos);
  983. X    do
  984. X    { pos.next_code();
  985. X    } while(pos.token != SEMI_COLON && pos.token != OPEN_BRACE && pos.token != END_OF_FILE);
  986. X    if(pos.token == OPEN_BRACE)
  987. X    { tags->inc(new Tag(tag_name, scope));
  988. X      scope = new Scope(tag_name, scope);
  989. X    }
  990. X      }
  991. X      else
  992. X      { while(pos.token != SEMI_COLON && pos.token != OPEN_BRACE && pos.token != END_OF_FILE)
  993. X      pos.next_code();
  994. X    if(pos.token == OPEN_BRACE)
  995. X      pos.close_brace();
  996. X      }
  997. X      break;
  998. X    case ENUM_KW:
  999. X      pos.next_code();
  1000. X      if(pos.token == IDENTIFIER)
  1001. X      { C_File_Pos tag_name (pos);
  1002. X    do
  1003. X    { pos.next_code();
  1004. X    } while(pos.token != SEMI_COLON && pos.token != OPEN_BRACE && pos.token != END_OF_FILE);
  1005. X    if(pos.token == OPEN_BRACE)
  1006. X      tags->inc(new Tag (tag_name, scope));
  1007. X      }
  1008. X      if(pos.token == OPEN_BRACE)
  1009. X      { while(pos.token != CLOSE_BRACE && pos.token != END_OF_FILE)
  1010. X    { pos.next_code();
  1011. X      if(pos.token == IDENTIFIER)
  1012. X        tags->inc(new Tag (pos, scope));
  1013. X      do
  1014. X      { pos.next_code();
  1015. X      } while(pos.token != COMMA && pos.token != CLOSE_BRACE && pos.token != END_OF_FILE);
  1016. X    }
  1017. X      }
  1018. X      while(pos.token != SEMI_COLON && pos.token != END_OF_FILE)
  1019. X    pos.next_code();
  1020. X      break;
  1021. X    case TYPEDEF_KW:        // only catches last typedef (e.g 'c' in typedef int a, b, c;)
  1022. X    { C_File_Pos next (pos);
  1023. X      next.next_code();
  1024. X      do
  1025. X      { pos = next;
  1026. X    next.next_code();
  1027. X      } while(next.token != SEMI_COLON && next.token != OPEN_PARE && next.token != END_OF_FILE);
  1028. X      
  1029. X      if(next.token == OPEN_PARE && next.chars(1) == '*')
  1030. X      { // Function Typedef
  1031. X    next.next_code();
  1032. X    if(next.token == IDENTIFIER)
  1033. X      tags->inc(new Tag (next, scope));
  1034. X      }
  1035. X
  1036. X      while(next.token != SEMI_COLON && next.token != END_OF_FILE)
  1037. X      { pos = next;
  1038. X    next.next_code();
  1039. X      }
  1040. X
  1041. X      if(pos.token == IDENTIFIER)
  1042. X    tags->inc(new Tag (pos, scope));
  1043. X      pos = next;
  1044. X    }
  1045. X      break;
  1046. X    case DEFINE:
  1047. X      pos.next_code();
  1048. X      if(pos.token == IDENTIFIER || pos.token == DECLARE_MACRO || pos.token == DEFINE_MACRO)
  1049. X    tags->inc(new Tag (pos, scope));
  1050. X      pos.close_define();
  1051. X      break;
  1052. X    case CLOSE_BRACE:
  1053. X      if(scope) scope = scope->pop();
  1054. X      break;
  1055. X    case OPEN_BRACE:
  1056. X      pos.close_brace();
  1057. X      break;
  1058. X    case OPEN_PARE:
  1059. X      if(prev_id.token == IDENTIFIER)
  1060. X      { tags->inc(new Tag(prev_id, qualified));
  1061. X    prev_id = pos;
  1062. X      }
  1063. X      pos.close_pare();
  1064. X      pos.close_func();
  1065. X      break;
  1066. X    case COLONS:
  1067. X      if(prev_id.token == IDENTIFIER)
  1068. X      { qualified = new Scope(prev_id, qualified);
  1069. X    prev_id = pos;
  1070. X      }
  1071. X      break;
  1072. X    case IDENTIFIER:
  1073. X      if(prev_id.token != COLONS)
  1074. X      { delete qualified;
  1075. X    qualified = copy(scope);
  1076. X      }
  1077. X      prev_id = pos;
  1078. X      break;
  1079. X    case SEMI_COLON:
  1080. X      if(prev_id.token == IDENTIFIER)
  1081. X      { tags->inc(new Tag(prev_id, qualified));
  1082. X    prev_id = pos;
  1083. X      }
  1084. X      break;
  1085. X    case EQUAL:
  1086. X      if(prev_id.token == IDENTIFIER)
  1087. X      { tags->inc(new Tag(prev_id, qualified));
  1088. X    prev_id = pos;
  1089. X      }
  1090. X      pos.close_func();
  1091. X      break;
  1092. X    case NOTE:
  1093. X      pos.next_code();
  1094. X      if(pos.token == OPEN_PARE)
  1095. X      { pos.next_code();
  1096. X    if(pos.token == IDENTIFIER)
  1097. X      tags->inc(new Tag(pos, see_scope));
  1098. X    if(pos.token != CLOSE_PARE)
  1099. X      pos.close_pare();
  1100. X      }
  1101. X      while(pos.token != SEMI_COLON && pos.token != END_OF_FILE)
  1102. X    pos.next_code();
  1103. X      break;
  1104. X    case EXPORT:
  1105. X      pos.next_code();
  1106. X      if(pos.token == OPEN_PARE)
  1107. X      { do
  1108. X    { pos.next_code();
  1109. X    } while (pos.token != COMMA && pos.token != END_OF_FILE);
  1110. X    pos.next_code();
  1111. X    if(pos.token == IDENTIFIER)
  1112. X      tags->inc(new Tag(pos, exported_scope));
  1113. X    if(pos.token != CLOSE_PARE)
  1114. X      pos.close_pare();
  1115. X      }
  1116. X      while(pos.token != SEMI_COLON && pos.token != END_OF_FILE)
  1117. X    pos.next_code();
  1118. X      break;
  1119. X    case DECLARE_MACRO:
  1120. X      pos.next_code();
  1121. X      if(pos.token == OPEN_PARE)
  1122. X      { pos.next_code();
  1123. X    if(pos.token == IDENTIFIER)
  1124. X      tags->inc(new Tag(pos, scope));
  1125. X    if(pos.token != CLOSE_PARE)
  1126. X      pos.close_pare();
  1127. X      }
  1128. X      while(pos.token != SEMI_COLON && pos.token != END_OF_FILE)
  1129. X    pos.next_code();
  1130. X      break;
  1131. X    case DEFINE_MACRO:
  1132. X      pos.next_code();
  1133. X      if(pos.token == OPEN_PARE)
  1134. X      { pos.next_code();
  1135. X    if(pos.token == IDENTIFIER)
  1136. X    { qualified = new Scope (pos, 0);
  1137. X      while(pos.token != COMMA && pos.token != CLOSE_PARE && pos.token != END_OF_FILE)
  1138. X        pos.next_code();
  1139. X      if(pos.token == COMMA)
  1140. X      { pos.next_code();
  1141. X        if(pos.token == IDENTIFIER)
  1142. X          tags->inc(new Tag(pos, qualified));
  1143. X      }
  1144. X      qualified = qualified->pop();
  1145. X    }
  1146. X    if(pos.token != CLOSE_PARE)
  1147. X      pos.close_pare();
  1148. X      }
  1149. X      break;
  1150. X    case DEFINE_GET:
  1151. X    case DEFINE_GETSET:
  1152. X      pos.next_code();
  1153. X      if(pos.token == OPEN_PARE)
  1154. X      { while(pos.token != COMMA && pos.token != CLOSE_PARE && pos.token != END_OF_FILE)
  1155. X      pos.next_code();
  1156. X    if(pos.token == COMMA)
  1157. X    { pos.next_code();
  1158. X      if(pos.token == IDENTIFIER)
  1159. X          tags->inc(new Tag(pos, scope));
  1160. X    }
  1161. X    if(pos.token != CLOSE_PARE)
  1162. X      pos.close_pare();
  1163. X      }
  1164. X      break;
  1165. X    case DEFINE_SET:
  1166. X    case DEFINE_INC:
  1167. X    case DEFINE_DEC:
  1168. X      pos.next_code();
  1169. X      if(pos.token == OPEN_PARE)
  1170. X        pos.close_pare();
  1171. X      break;
  1172. X    default:
  1173. X      ;
  1174. X    }
  1175. X    pos.next_code();
  1176. X  }
  1177. X  return tags;
  1178. X}
  1179. X
  1180. X
  1181. X////////////////////////////////////////////////////////////////////////////////
  1182. X
  1183. Xvoid
  1184. Xusage_error (const char* progname)
  1185. X{ cerr << "Usage " << progname << " [-a] [-f outfile] [-k max_infile_kbytes] infile ..."
  1186. X    << endl;
  1187. X  exit(BAD);
  1188. X}
  1189. X
  1190. X
  1191. Xmain (int argc, char** argv)
  1192. X{
  1193. X  unsigned argi = 0;
  1194. X  char* progname = argv[argi];
  1195. X  
  1196. X  // Default flags
  1197. X  Boolean     append  = FALSE;
  1198. X  const char* outfile = 0;
  1199. X  int         size    = 1024;
  1200. X  
  1201. X  // Process flags
  1202. X  for(argi = 1; argi < argc && argv[argi][0] == '-'; ++argi)
  1203. X  {
  1204. X    Boolean done = FALSE;
  1205. X    for(unsigned chari = 1; !done && argv[argi][chari]; ++chari)
  1206. X    {
  1207. X      switch(argv[argi][chari])
  1208. X      {
  1209. X      case '?':
  1210. X      case 'h':
  1211. X    usage_error(progname);
  1212. X      case 'a':
  1213. X    append = TRUE;
  1214. X    break;
  1215. X      case 'f':
  1216. X    if(outfile)
  1217. X    { cerr << "The -f option may only be given once." << endl;
  1218. X      usage_error(progname);
  1219. X    }
  1220. X    if(argv[argi][chari+1])
  1221. X    { done = TRUE;
  1222. X      outfile = &argv[argi][chari+1];
  1223. X    }
  1224. X    else if(argi < argc)
  1225. X    { done = TRUE;
  1226. X      outfile = argv[++argi];
  1227. X    }
  1228. X    else
  1229. X    { cerr << "The -f option must be given an argument (the outfile name)" << endl;
  1230. X      usage_error(progname);
  1231. X    }
  1232. X    break;
  1233. X      case 'k':
  1234. X    if(argv[argi][chari+1])
  1235. X    { done = TRUE;
  1236. X      size = atoi(&argv[argi][chari+1]);
  1237. X    }
  1238. X    else if(argi < argc)
  1239. X    { done = TRUE;
  1240. X      size = atoi(argv[++argi]);
  1241. X    }
  1242. X    else
  1243. X    { cerr << "The -k option must be given an argument (the max_file_size in kbytes)" << endl;
  1244. X      usage_error(progname);
  1245. X    }
  1246. X    break;
  1247. X      default:
  1248. X    ;
  1249. X      }
  1250. X    }
  1251. X  }
  1252. X  
  1253. X  // Arg value checks
  1254. X  if(size < 64)
  1255. X    size = 64;
  1256. X  if(!outfile)
  1257. X    outfile = "TAGS";
  1258. X
  1259. X  // Create output TAGS file
  1260. X  ofstream out (outfile, (append ? ios::app : ios::out));
  1261. X
  1262. X  // Create File for input
  1263. X  File infile (size*1024);
  1264. X
  1265. X  // Process files
  1266. X  for(; argi < argc; ++argi)
  1267. X  {
  1268. X    infile.read(argv[argi]);
  1269. X    Tag_List* tags = get_tags(infile);
  1270. X    out << "\f\n" << argv[argi] << ',' << tags->etags_size() << '\n' << tags;
  1271. X    delete tags;
  1272. X  }
  1273. X
  1274. X  out << flush;
  1275. X
  1276. X  exit(GOOD);
  1277. X}
  1278. END_OF_FILE
  1279.   if test 13241 -ne `wc -c <'cie/etags++/etags++.c'`; then
  1280.     echo shar: \"'cie/etags++/etags++.c'\" unpacked with wrong size!
  1281.   fi
  1282.   # end of 'cie/etags++/etags++.c'
  1283. fi
  1284. if test -f 'cie/hier-mode.el' -a "${1}" != "-c" ; then 
  1285.   echo shar: Will not clobber existing file \"'cie/hier-mode.el'\"
  1286. else
  1287.   echo shar: Extracting \"'cie/hier-mode.el'\" \(11240 characters\)
  1288.   sed "s/^X//" >'cie/hier-mode.el' <<'END_OF_FILE'
  1289. X;;; hier-mode.el
  1290. X;;; Hierarchy mode (for hierarchies output by hier++)
  1291. X
  1292. X;;; See the docstring for defun hier-mode for a description.
  1293. X
  1294. X;;; Copyright (C) 1993, Intellection Inc.
  1295. X;;;
  1296. X;;; Author: Brian M Kennedy (kennedy@intellection.com)
  1297. X;;;
  1298. X;;; This program is free software; you can redistribute it and/or modify
  1299. X;;; it under the terms of the GNU General Public License as published by
  1300. X;;; the Free Software Foundation; either version 1, or (at your option)
  1301. X;;; any later version.
  1302. X;;;
  1303. X;;; This program is distributed in the hope that it will be useful,
  1304. X;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  1305. X;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  1306. X;;; GNU General Public License for more details.
  1307. X;;;
  1308. X;;; A copy of the GNU General Public License can be obtained from the
  1309. X;;; Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  1310. X
  1311. X;;; 92/08     Brian M Kennedy  Added direct access commands; added sort to member list
  1312. X;;; 92/06     Brian M Kennedy  Original 
  1313. X;;; (using other GNU Emacs modes as a template)
  1314. X
  1315. X;;; Ideally, this mode should be rewritten based on outline.el, by simply setting
  1316. X;;; a few of outline.el's variables.  That would provide additional functionality
  1317. X;;; such as hide/show.  But to do it right, you should modify the other functions
  1318. X;;; in this file to auto-show things being searched for (otherwise, hiding would
  1319. X;;; be more a hindrance than a help).
  1320. X
  1321. X(provide 'hier-mode)
  1322. X
  1323. X(autoload 'visit-tags-table-buffer "tags")
  1324. X(autoload 'prompt-for-tag          "tags")
  1325. X
  1326. X
  1327. X(defvar hier-mode-syntax-table nil
  1328. X  "Syntax table used while in hier mode.")
  1329. X(if hier-mode-syntax-table
  1330. X    ()
  1331. X  (setq hier-mode-syntax-table (make-syntax-table))
  1332. X  )
  1333. X
  1334. X(defvar hier-mode-abbrev-table nil
  1335. X  "Abbrev table used while in bib mode.")
  1336. X(define-abbrev-table 'hier-mode-abbrev-table ())
  1337. X
  1338. X(defvar hier-mode-map nil "")
  1339. X(if hier-mode-map
  1340. X    ()
  1341. X  (setq hier-mode-map (make-sparse-keymap))
  1342. X  (define-key hier-mode-map "\M-h" 'hier-find)
  1343. X  (define-key hier-mode-map "\M-g" 'hier-find-again)
  1344. X  (define-key hier-mode-map "\M-m" 'hier-show-members)
  1345. X  (define-key hier-mode-map "\M-p" 'hier-previous-element)
  1346. X  (define-key hier-mode-map "\M-n" 'hier-next-element)
  1347. X  (define-key hier-mode-map "\M-u" 'hier-upto-parent)
  1348. X  )
  1349. X
  1350. X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1351. X
  1352. X(defun hier-mode ()
  1353. X  "Major mode for viewing class hierarchy files output by hier++.
  1354. XThe file is formatted like this:
  1355. X
  1356. X* class_a 
  1357. X  * child_b  :class_a
  1358. X  * child_c  :class_a :class_f
  1359. X    * grandchild_d  :child_c
  1360. X    * grandchild_e  :child_c
  1361. X* class_f
  1362. X  * child_c  :class_a :class_f
  1363. X    * grandchild_d  :child_c
  1364. X    * grandchild_e  :child_c
  1365. X  * child_g  :class_f
  1366. X
  1367. XClasses child_b and child_c are derived from class_a; classes child_c and
  1368. Xchild_g are derived from class_f; classes grandchild_d and grandchild_e are
  1369. Xboth derived from child_c.  Note that each class (and all of its children) 
  1370. Xwill appear in the file once under each parent.
  1371. X
  1372. XDefined keys:
  1373. XM-p moves to the previous sibling
  1374. XM-n moves to the next sibling
  1375. XM-u moves up to the parent
  1376. XM-h finds the first occurrence of the hierarchy element for a class 
  1377. X    (similar to M-. in behavior)
  1378. XM-g finds the next occurrence (like M-,) in the case of multiple-inheritance.
  1379. XM-m brings up a new window with a listing of all the members (both direct and 
  1380. X    inherited) of that hierarchy entry.  It does this via tags, so you must 
  1381. X    have tags set up in Emacs.  It will also only work properly if the tags 
  1382. X    file was generated by etags++ (companion to hier++)."
  1383. X  (interactive)
  1384. X  (kill-all-local-variables)
  1385. X  (use-local-map hier-mode-map)
  1386. X  (setq mode-name "Hierarchy")
  1387. X  (setq major-mode 'hier-mode)
  1388. X  (setq local-abbrev-table hier-mode-abbrev-table)
  1389. X  (set-syntax-table hier-mode-syntax-table)
  1390. X  ;(run-hooks 'hier-mode-hook)
  1391. X  )
  1392. X
  1393. X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1394. X;; Find hierarchy elements
  1395. X
  1396. X;; Return a default name to search for, based on the text at point.
  1397. X(defun hier-find-default ()
  1398. X  (save-excursion
  1399. X    (while (looking-at "\\sw\\|\\s_")
  1400. X      (forward-char 1))
  1401. X    (if (re-search-backward "\\sw\\|\\s_" nil t)
  1402. X    (progn (forward-char 1)
  1403. X           (buffer-substring (point)
  1404. X                 (progn (forward-sexp -1)
  1405. X                    (while (looking-at "\\s'")
  1406. X                      (forward-char 1))
  1407. X                    (point))))
  1408. X      nil)))
  1409. X
  1410. X(defun hier-find-element (string)
  1411. X  (let* ((default (hier-find-default))
  1412. X     (spec (read-string
  1413. X        (if default
  1414. X            (format "%s(default %s) " string default)
  1415. X          string))))
  1416. X    (list (if (equal spec "")
  1417. X          default
  1418. X        spec))))
  1419. X
  1420. X(defvar hier-last-find-element nil
  1421. X  "The last element searched for by hier-find.")
  1422. X
  1423. X(defun hier-find (element)
  1424. X  (interactive (hier-find-element "Find element: "))
  1425. X  (setq hier-last-find-element (concat "* " element " "))
  1426. X  (goto-char (point-min))
  1427. X  (hier-find-again)
  1428. X  )
  1429. X
  1430. X(defun hier-find-again ()
  1431. X  (interactive)
  1432. X  (if hier-last-find-element
  1433. X      (search-forward hier-last-find-element)))
  1434. X
  1435. X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1436. X;; Cursor movement through hierarchy
  1437. X
  1438. X(defun hier-previous-element (ignore)
  1439. X  "Goto previous hierarchy element at this level or higher."
  1440. X  (interactive "p")
  1441. X  (back-to-indentation)
  1442. X  (let ((indent (current-indentation)))
  1443. X    (previous-line 1)
  1444. X    (while (< indent (current-indentation))
  1445. X      (previous-line 1) ))
  1446. X  (back-to-indentation) )
  1447. X
  1448. X(defun hier-next-element (ignore)
  1449. X  "Goto next hierarchy element at this level or higher."
  1450. X  (interactive "p")
  1451. X  (back-to-indentation)
  1452. X  (let ((indent (current-indentation)))
  1453. X    (next-line 1)
  1454. X    (while (< indent (current-indentation))
  1455. X      (next-line 1) ))
  1456. X  (back-to-indentation) )
  1457. X
  1458. X(defun hier-upto-parent (arg)
  1459. X  "Goto the parent hierarchy element."
  1460. X  (interactive "p")
  1461. X  (let ((indent (current-indentation)))
  1462. X    (if (> indent 0)
  1463. X    (while (<= indent (current-indentation))
  1464. X      (forward-line -1) )))
  1465. X  (back-to-indentation) )
  1466. X
  1467. X
  1468. X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1469. X;; Find Class Members
  1470. X
  1471. X(defun hier-regexp-list (&optional re-list)
  1472. X  (end-of-line)
  1473. X  (let ((eol (point)))
  1474. X    (back-to-indentation)
  1475. X    (forward-char 2)
  1476. X    (let ((re (concat "\C-a" 
  1477. X              (buffer-substring (point) (progn (while (looking-at "\\sw\\|\\s_")
  1478. X                             (forward-char 1))
  1479. X                               (point) ))
  1480. X              "::")))
  1481. X      (setq re-list (cons re re-list))
  1482. X      (forward-word 1)
  1483. X      (while (<= (point) eol)
  1484. X    (forward-word -1)
  1485. X    (let ((start (point))
  1486. X          (end   (progn (while (looking-at "\\sw\\|\\s_")
  1487. X                  (forward-char 1))
  1488. X                (point) )) )
  1489. X      (save-excursion
  1490. X        (hier-find (buffer-substring start end))
  1491. X        (setq re-list (hier-regexp-list re-list)) ))
  1492. X    (forward-word 1) )
  1493. X      re-list)))
  1494. X
  1495. X
  1496. X(defvar hier-members-column 30
  1497. X  "Column to line up member names in *Members List* buffer.")
  1498. X
  1499. X(defun hier-members-apropos (name re-list &optional data-members-only-p)
  1500. X  "Display list of all tags in tag table that regexp matches."
  1501. X  (save-excursion
  1502. X    (with-output-to-temp-buffer "*Members List*"
  1503. X      (if data-members-only-p
  1504. X      (princ "== Data Members of Class ")
  1505. X    (princ "== All Members of Class "))
  1506. X      (prin1 name)
  1507. X      (princ " ==")
  1508. X      (terpri)
  1509. X      (visit-tags-table-buffer)
  1510. X      (while re-list
  1511. X    (goto-char 1)
  1512. X    (while (re-search-forward (car re-list) nil t)
  1513. X      (skip-chars-backward "^\C-a")
  1514. X      (princ (buffer-substring (point)
  1515. X                   (progn (end-of-line)
  1516. X                      (point))))
  1517. X      (terpri)
  1518. X      (forward-line 1) )
  1519. X    (setq re-list (cdr re-list)) ))
  1520. X    (set-buffer "*Members List*")
  1521. X    ;; Remove Non-Data Members?
  1522. X    (if data-members-only-p
  1523. X    ;; remove lines not ending in "_" or "=" (title line)
  1524. X    (progn (goto-char (point-max))
  1525. X           (while (not (bobp))
  1526. X         (forward-char -2)
  1527. X         (if (not (looking-at "[_=]"))
  1528. X             (progn (forward-char 2)
  1529. X                (delete-region (point) (progn (forward-line -1) (point))))
  1530. X           (forward-line -1)))))
  1531. X    ;; Sort Buffer
  1532. X    (goto-line 2)
  1533. X    (sort-regexp-fields nil "^.*$" "::[^:\n]*$" (point) (point-max))
  1534. X    ;; Remove Duplicate Entries
  1535. X    (goto-line 2)
  1536. X    (while (not (save-excursion (forward-line 1) (eobp)))
  1537. X      (if (string-equal (buffer-substring (point) (progn (forward-line 1) (point)))
  1538. X            (buffer-substring (point) (progn (forward-line 1) (point))))
  1539. X      (delete-region (point) (progn (forward-line -1) (point))) )
  1540. X      (forward-line -1) )
  1541. X    ;; Line Up Colons
  1542. X    (goto-char (point-min))
  1543. X    (while (search-forward "::" nil t)
  1544. X      (let ((indent (- hier-members-column (current-column))))
  1545. X    (if (> indent 0)
  1546. X        (progn (beginning-of-line)
  1547. X           (indent-to-column indent) )))
  1548. X      (forward-line 1) )
  1549. X    ))
  1550. X
  1551. X
  1552. X(defun hier-show-members (&optional data-members-only-p)
  1553. X  "Show the members, both direct and inherited, of this hierarchy element."
  1554. X  (interactive)
  1555. X  (save-excursion
  1556. X    (back-to-indentation)
  1557. X    (forward-char 2)
  1558. X    (let ((name (buffer-substring (point) (progn (while (looking-at "\\sw\\|\\s_")
  1559. X                           (forward-char 1))
  1560. X                         (point) ))) )
  1561. X      (hier-members-apropos name (hier-regexp-list) data-members-only-p) )))
  1562. X
  1563. X
  1564. X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1565. X;; Auxiliary Functions
  1566. X
  1567. X(defun hier-base-list ()
  1568. X  "Returns a list of the names of all the direct base classes on the current line."
  1569. X  (save-excursion
  1570. X    (end-of-line)
  1571. X    (let ((base-list nil)
  1572. X      (eol (point)))
  1573. X      (back-to-indentation)
  1574. X      (forward-char 2)
  1575. X      (while (looking-at "\\sw\\|\\s_")
  1576. X    (forward-char 1))
  1577. X      (forward-word 1)
  1578. X      (while (<= (point) eol)
  1579. X    (forward-word -1)
  1580. X    (setq base-list (cons (buffer-substring (point)
  1581. X                        (progn (while (looking-at "\\sw\\|\\s_")
  1582. X                             (forward-char 1))
  1583. X                               (point) ))
  1584. X                  base-list))
  1585. X    (forward-word 1) )
  1586. X      base-list) ) )
  1587. X
  1588. X
  1589. X(defun hier-derived-list ()
  1590. X  "Returns a list of the names of all the directly derived classes
  1591. X   from the one on the current line."
  1592. X  (save-excursion
  1593. X    (let ((derived-list nil)
  1594. X      (indent (current-indentation)))
  1595. X      (next-line 1)
  1596. X      (back-to-indentation)
  1597. X      (while (< indent (current-indentation))
  1598. X    (forward-char 2)
  1599. X    (setq derived-list (cons (buffer-substring (point)
  1600. X                           (progn (while (looking-at "\\sw\\|\\s_")
  1601. X                                (forward-char 1))
  1602. X                              (point) ))
  1603. X                 derived-list))
  1604. X    (hier-next-element 1) )
  1605. X      derived-list) ) )
  1606. X
  1607. X
  1608. X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1609. X;; External Functions
  1610. X
  1611. X(defvar hier-file-name nil
  1612. X  "The filename in which to find the class hierarchy generated by hier++.")
  1613. X
  1614. X(defun prompt-for-hier-file-name ()
  1615. X  "Get hier-file-name from user."
  1616. X  (setq hier-file-name
  1617. X    (read-file-name "File containing class hierarchy [typically CLASS.hier]: ")))
  1618. X
  1619. X(defun class-hierarchy (class-name)
  1620. X  "Display the hierarchy for the given class.  M-g for next occurrence."
  1621. X  (interactive (list (prompt-for-tag "Display hierarchy for class: ")))
  1622. X  (if (not hier-file-name)
  1623. X      (prompt-for-hier-file-name))
  1624. X  (find-file-other-window hier-file-name)
  1625. X  (hier-find class-name))
  1626. X
  1627. X(defun class-members (class-name)
  1628. X  "Display all members for the given class."
  1629. X  (interactive (list (prompt-for-tag "Display all members for class: ")))
  1630. X  (save-excursion
  1631. X    (set-buffer (find-file-noselect hier-file-name))
  1632. X    (hier-find class-name)
  1633. X    (hier-show-members) ))
  1634. X
  1635. X(defun class-data-members (class-name)
  1636. X  "Display the data members for the given class."
  1637. X  (interactive (list (prompt-for-tag "Display data members for class: ")))
  1638. X  (save-excursion
  1639. X    (set-buffer (find-file-noselect hier-file-name))
  1640. X    (hier-find class-name)
  1641. X    (hier-show-members t) ))
  1642. END_OF_FILE
  1643.   if test 11240 -ne `wc -c <'cie/hier-mode.el'`; then
  1644.     echo shar: \"'cie/hier-mode.el'\" unpacked with wrong size!
  1645.   fi
  1646.   # end of 'cie/hier-mode.el'
  1647. fi
  1648. if test -f 'cie/minibuffer-yank.el' -a "${1}" != "-c" ; then 
  1649.   echo shar: Will not clobber existing file \"'cie/minibuffer-yank.el'\"
  1650. else
  1651.   echo shar: Extracting \"'cie/minibuffer-yank.el'\" \(1845 characters\)
  1652.   sed "s/^X//" >'cie/minibuffer-yank.el' <<'END_OF_FILE'
  1653. X;;; minibuffer-yank.el
  1654. X
  1655. X;;; Use this to yank the default or typical response into the minibuffer.
  1656. X;;; In CIE, this is used to yank the default tag into the buffer.  So, for
  1657. X;;; example, you could type the "Class_Name::" and then C-c C-y to pull in
  1658. X;;; the default which contained the unscoped tag.  Or you could yank in the
  1659. X;;; tag and edit it.  And so on.  It can also be used for many other things.
  1660. X;;; By default it yanks in the current buffer file name (very convenient).
  1661. X
  1662. X;;; Copyright (C) 1993, Intellection Inc.
  1663. X;;;
  1664. X;;; Author: Walt Buehring
  1665. X;;;
  1666. X;;; This program is free software; you can redistribute it and/or modify
  1667. X;;; it under the terms of the GNU General Public License as published by
  1668. X;;; the Free Software Foundation; either version 1, or (at your option)
  1669. X;;; any later version.
  1670. X;;;
  1671. X;;; This program is distributed in the hope that it will be useful,
  1672. X;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  1673. X;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  1674. X;;; GNU General Public License for more details.
  1675. X;;;
  1676. X;;; A copy of the GNU General Public License can be obtained from the
  1677. X;;; Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  1678. X
  1679. X
  1680. X;;; Minibuffer Yank
  1681. X
  1682. X(defvar minibuffer-yank-string nil
  1683. X  "Bound by commands to specify string yanked by \"minibuffer-yank\" instead
  1684. Xof the buffer file name.")
  1685. X
  1686. X(defun minibuffer-yank ()
  1687. X  "Insert the value of 'minibuffer-yank-string' if non-nil, else the
  1688. Xfilename of the buffer which invoked the minibuffer command."
  1689. X  (interactive)
  1690. X  ;; Use the previous buffer on the buffer list and ensure it has a 
  1691. X  ;; filename associated with it.
  1692. X  (if minibuffer-yank-string
  1693. X      (insert minibuffer-yank-string)
  1694. X    (and (cdr (buffer-list))
  1695. X     (let ((f (buffer-file-name (car (cdr (buffer-list))))))
  1696. X       (and f
  1697. X        (insert (file-name-nondirectory f)))))))
  1698. END_OF_FILE
  1699.   if test 1845 -ne `wc -c <'cie/minibuffer-yank.el'`; then
  1700.     echo shar: \"'cie/minibuffer-yank.el'\" unpacked with wrong size!
  1701.   fi
  1702.   # end of 'cie/minibuffer-yank.el'
  1703. fi
  1704. if test -f 'cie/tags.el' -a "${1}" != "-c" ; then 
  1705.   echo shar: Will not clobber existing file \"'cie/tags.el'\"
  1706. else
  1707.   echo shar: Extracting \"'cie/tags.el'\" \(24786 characters\)
  1708.   sed "s/^X//" >'cie/tags.el' <<'END_OF_FILE'
  1709. X;; Tags facility for Emacs.
  1710. X;; Copyright (C) 1985, 1986, 1988 Free Software Foundation, Inc.
  1711. X
  1712. X;; This file WAS part of some old GNU Emacs.
  1713. X
  1714. X;; GNU Emacs is distributed in the hope that it will be useful,
  1715. X;; but WITHOUT ANY WARRANTY.  No author or distributor
  1716. X;; accepts responsibility to anyone for the consequences of using it
  1717. X;; or for whether it serves any particular purpose or works at all,
  1718. X;; unless he says so in writing.  Refer to the GNU Emacs General Public
  1719. X;; License for full details.
  1720. X
  1721. X;; Everyone is granted permission to copy, modify and redistribute
  1722. X;; GNU Emacs, but only under the conditions described in the
  1723. X;; GNU Emacs General Public License.   A copy of this license is
  1724. X;; supposed to have been given to you along with GNU Emacs so you
  1725. X;; can know your rights and responsibilities.  It should be in a
  1726. X;; file named COPYING.  Among other things, the copyright notice
  1727. X;; and this notice must be preserved on all copies.
  1728. X
  1729. X;; $Id: tags.el,v 1.5 1993/05/13 17:22:55 kennedy Exp $
  1730. X;;
  1731. X;; NOTE:
  1732. X;; 1.    Quick fix inserted for C users.  The problem is that in the tags line
  1733. X;;
  1734. X;;        typedef char *string^?...
  1735. X;;
  1736. X;;    `string' won't be an exact match, because the `*' is a word character
  1737. X;;    in the TAGS buffer (although not in a C source file).  The quick fix is
  1738. X;;    in tag-exact-match-p; look for "HACK 7/19/89".
  1739. X;; 2.   Fixed tags-completion-alist problem 1/23/90.
  1740. X
  1741. X;; INTELLECTION MODS:
  1742. X;; 
  1743. X;; 1) Prefers the tags named explicitly after C-A's at the end of each line.
  1744. X;;    This is true both for find-tag and for the completion-alist.
  1745. X;; 2) Support for C++ scoping -- class::name is considered a tag and both
  1746. X;;    class::name and name are matches (class::name preferred though).
  1747. X;; 3) Support for completion of scoped names as well as unscoped names.
  1748. X;;    That is, the alist contains both the fully-scoped name, and each
  1749. X;;    subname (c1::c2::mem => c1::c2::mem, c2::mem, and mem in the alist).
  1750. X;; 4) Added mechanism to save out the completion alist into TAGS.alist
  1751. X;;    which is checked for when loading TAGS to prevent the need to rebuild
  1752. X;;    the alist (which can take a while with large systems).  As an added
  1753. X;;    advantage, this mechanism removes duplicates from the alist before
  1754. X;;    saving it out (making it faster and much smaller).
  1755. X
  1756. X
  1757. X(provide 'tags)
  1758. X
  1759. X(defvar tags-prompt-with-initial-input nil
  1760. X  "*When non-nil, supply default tag as initial input when prompting")
  1761. X
  1762. X;; Tag table state.
  1763. X
  1764. X(defun initialize-new-tag-table ()
  1765. X  "Call when the tag table changes."
  1766. X  (setq tag-table-files nil
  1767. X    find-tag-state nil
  1768. X    tag-order nil
  1769. X    tag-lines-already-matched nil)
  1770. X  (make-local-variable 'tags-completion-alist) )
  1771. X
  1772. X(defun save-tags-state ()
  1773. X  "Returns an object that can later be passed to `restore-tags-state'."
  1774. X  (vector tag-order
  1775. X      tag-lines-already-matched
  1776. X      tag-table-files
  1777. X      find-tag-state
  1778. X      next-file-list))
  1779. X
  1780. X(defun restore-tags-state (state)
  1781. X  "Restore from an object created by `save-tags-state'."
  1782. X  (setq tag-order (aref state 0)
  1783. X    tag-lines-already-matched (aref state 1)
  1784. X    tag-table-files (aref state 2)
  1785. X    find-tag-state (aref state 3)
  1786. X    next-file-list (aref state 4)))
  1787. X
  1788. X(defvar tag-order nil
  1789. X  "List of functions to use in partitioning the set of tag matches.")
  1790. X
  1791. X(defvar tag-lines-already-matched nil
  1792. X  "List of lines within the tag table that are already matched.")
  1793. X
  1794. X(defvar tag-table-files nil
  1795. X  "List of file names covered by current tags table.
  1796. Xnil means it has not been computed yet; do (tag-table-files) to compute it.")
  1797. X
  1798. X(defvar tags-completion-alist nil
  1799. X  "Alist of tag names defined in current tags table.")
  1800. X
  1801. X(defvar find-tag-state nil
  1802. X  "Some of the state of the last find-tag, find-tag-other-window, or
  1803. Xfind-tag-regexp.  This is a vector whose 0th element is the last tagname
  1804. Xor regexp used.")
  1805. X
  1806. X(defvar tags-table-file-list nil
  1807. X  "Alist of tags table file names for \\[select-tags-table].
  1808. XEach element is a list containing one element, a file name.
  1809. XAny tags table file you visit is automatically added to this list.
  1810. XYou can also add names yourself.")
  1811. X
  1812. X(defvar next-file-list nil
  1813. X  "List of files for \\[next-file] to process.")
  1814. X
  1815. X
  1816. X
  1817. X(defun visit-tags-table (file)
  1818. X  "Tell tags commands to use tags table file FILE.
  1819. XFILE should be the name of a file created with the `etags' program.
  1820. XA directory name is ok too; it means file TAGS in that directory."
  1821. X  (interactive (list (read-file-name "Visit tags table: (default TAGS) "
  1822. X                     default-directory
  1823. X                     (expand-file-name "TAGS" default-directory)
  1824. X                     t)))
  1825. X  (setq file (expand-file-name file default-directory))
  1826. X  (if (file-directory-p file)
  1827. X      (setq file (expand-file-name "TAGS" file)))
  1828. X  ;; Add an element to TAGS-TABLE-FILE-LIST.
  1829. X  (or (assoc file tags-table-file-list)
  1830. X      (setq tags-table-file-list
  1831. X        (cons (list file) tags-table-file-list)))
  1832. X  (setq tags-file-name file)
  1833. X  (save-excursion
  1834. X    (visit-tags-table-buffer)))
  1835. X
  1836. X
  1837. X(defun visit-tags-table-buffer ()
  1838. X  "Select the buffer containing the current tags table.
  1839. XThis is a file whose name is in the variable tags-file-name."
  1840. X  (or tags-file-name
  1841. X      (call-interactively 'visit-tags-table))
  1842. X  (let ((new-file nil))
  1843. X    (set-buffer (or (get-file-buffer tags-file-name)
  1844. X            (progn
  1845. X              (initialize-new-tag-table)
  1846. X              (setq new-file t)
  1847. X              (find-file-noselect tags-file-name))))
  1848. X    (or (not new-file)
  1849. X    (progn
  1850. X      (initialize-new-tag-table)
  1851. X      ;; reclaim memory from old alist before creating new.
  1852. X      (setq tags-completion-alist nil)
  1853. X      (garbage-collect)
  1854. X      (setq tags-completion-alist (tags-completion-alist)))))
  1855. X  (or (verify-visited-file-modtime (get-file-buffer tags-file-name))
  1856. X      (cond ((yes-or-no-p "Tags file has changed, read new contents? ")
  1857. X         (revert-buffer t t)
  1858. X         (initialize-new-tag-table)
  1859. X         ;; reclaim memory from old alist before creating new.
  1860. X         (setq tags-completion-alist nil)
  1861. X         (garbage-collect)
  1862. X         (setq tags-completion-alist (tags-completion-alist)))))
  1863. X  (or (eq (char-after 1) ?\^L)
  1864. X      (error "File %s not a valid tag table" tags-file-name)))
  1865. X
  1866. X
  1867. X(defun file-of-tag ()
  1868. X  "Return the file name of the file whose tags point is within.
  1869. XAssumes the tag table is the current buffer.
  1870. XFile name returned is relative to tag table file's directory."
  1871. X  (save-excursion
  1872. X    (search-backward "\f\n")
  1873. X    (forward-char 2)
  1874. X    (buffer-substring (point)
  1875. X              (progn (skip-chars-forward "^,") (point)))))
  1876. X
  1877. X(defun tag-table-files ()
  1878. X  "Return a list of files in the current tag table.
  1879. XFile names returned are absolute."
  1880. X  (or tag-table-files
  1881. X      (save-excursion
  1882. X    (visit-tags-table-buffer)
  1883. X    (let (files)
  1884. X      (goto-char (point-min))
  1885. X      (while (search-forward "\f\n" nil t)
  1886. X        (setq files (cons (expand-file-name
  1887. X                (buffer-substring
  1888. X                  (point)
  1889. X                  (progn (skip-chars-forward "^,\n") (point)))
  1890. X                (file-name-directory tags-file-name))
  1891. X                  files)))
  1892. X      (setq tag-table-files (nreverse files))))))
  1893. X
  1894. X(defun tags-completion-alist ()
  1895. X  "Return an alist of tags in the current buffer, which is a tag table."
  1896. X  ; BMK: read alist if a .alist file exists and is newer
  1897. X  (let ((alist nil)
  1898. X    (alist-file (concat buffer-file-name ".alist")))
  1899. X    (if (and (file-readable-p alist-file)
  1900. X         (file-newer-than-file-p alist-file buffer-file-name))
  1901. X    (load-file alist-file)
  1902. X      (let ((gc-cons-threshold 1000000)
  1903. X        (next nil))
  1904. X    (message "Making tags completion alist...")
  1905. X    (save-excursion
  1906. X      (goto-char (point-min))
  1907. X      (while (search-forward "\177" nil t)
  1908. X        (if (save-excursion
  1909. X          (skip-chars-forward "^\001\n")
  1910. X          (setq next (1+ (point)))
  1911. X          (= (following-char) ?\001))
  1912. X        ;; If there are ^A's, get tags after them.
  1913. X        ;; BMK: for each, get each subscoped tag down to id
  1914. X        (progn
  1915. X          (goto-char next)    ;; after the first ^A
  1916. X          (while (= (preceding-char) ?\001)
  1917. X            (while (not (looking-at "[\001\n]"))
  1918. X              (skip-chars-forward ":")
  1919. X              (setq alist 
  1920. X                (cons (cons (buffer-substring (point)
  1921. X                              (save-excursion 
  1922. X                                (skip-chars-forward "^\001\n")
  1923. X                                (point)))
  1924. X                    nil)
  1925. X                  alist))
  1926. X              (skip-chars-forward "^:\001\n"))
  1927. X            (forward-char 1)))
  1928. X          ;; If no ^A's, get tags from before the ^?.
  1929. X          (skip-chars-backward "^-A-Za-z0-9_$:~\n")
  1930. X          (or (bolp)
  1931. X          (setq alist
  1932. X            (cons (cons (buffer-substring
  1933. X                     (point)
  1934. X                     (progn
  1935. X                       (skip-chars-backward "-A-Za-z0-9_$:~")
  1936. X                       (point)))
  1937. X                    nil)
  1938. X                  alist)))
  1939. X          (goto-char next)        ; next line
  1940. X          )))
  1941. X    (message "Making tags completion alist...done")))
  1942. X    alist) )
  1943. X
  1944. X(defun tags-alist-less-p (a b)
  1945. X  (string< (car a) (car b)))
  1946. X
  1947. X(defun save-tags-completion-alist ()
  1948. X  "Save out a .alist file for this tags table."
  1949. X  (interactive)
  1950. X  (save-excursion
  1951. X    (visit-tags-table-buffer)
  1952. X    ;; sort list then eliminate duplicates
  1953. X    (message "Removing duplicates from tags completion alist...")
  1954. X    (setq tags-completion-alist
  1955. X      (sort tags-completion-alist 'tags-alist-less-p))
  1956. X    (let ((l tags-completion-alist))
  1957. X      (while (and l (cdr l))
  1958. X    ;; compare current element to next
  1959. X    (if (not (string= (car (car l)) (car (car (cdr l)))))
  1960. X        ;; no match, proceed to next element
  1961. X        (setq l (cdr l))    
  1962. X      ;; match, drop next element.
  1963. X      (setcdr l (cdr (cdr l))))))
  1964. X    (garbage-collect)
  1965. X    ;; generate lisp form that will recreate the completion alist
  1966. X    (let* ((alist-file (concat buffer-file-name ".alist"))
  1967. X       (alist-buffer (get-buffer-create "*TAGS-alist*")) )
  1968. X      (prin1 (list 'setq 'alist (list 'quote tags-completion-alist))
  1969. X         alist-buffer)
  1970. X      (terpri alist-buffer)
  1971. X      (set-buffer alist-buffer)
  1972. X      (write-file alist-file)
  1973. X      (kill-buffer alist-buffer) ) )
  1974. X  )
  1975. X
  1976. X
  1977. X;; BMK: give completing-read an initial input
  1978. X(defun prompt-for-tag (prompt)
  1979. X  "Prompt for a tag to find.  Default is determined by find-tag-default."
  1980. X  (let* ((default (find-tag-default))
  1981. X     (alist (save-excursion (visit-tags-table-buffer)
  1982. X                tags-completion-alist))
  1983. X     (read-prompt (if (or (not default) tags-prompt-with-initial-input)
  1984. X              prompt
  1985. X            (format "%s(default %s) " prompt default)))
  1986. X     (initial-input (if tags-prompt-with-initial-input default nil))
  1987. X     (minibuffer-yank-string default)
  1988. X     spec)
  1989. X    (setq spec (completing-read read-prompt
  1990. X                ;; completing-read craps out if given a nil table
  1991. X                (or alist '(("")))
  1992. X                nil
  1993. X                nil
  1994. X                initial-input))
  1995. X    (if (equal spec "")
  1996. X    (if (or tags-prompt-with-initial-input (null default))
  1997. X        (error "No tag specified.")
  1998. X      default)
  1999. X      spec)))
  2000. X
  2001. X
  2002. X;; Return a default tag to search for, based on the text at point, or nil.
  2003. X;; BMK: Grab fully-scoped C++ tags as the default.  
  2004. X;;      This is highly preferable.  The old function is below.
  2005. X(defun find-tag-default ()
  2006. X  (save-excursion
  2007. X    ; Find end of default tag
  2008. X    (if (looking-at "\\sw\\|\\s_")
  2009. X    (while (looking-at "\\sw\\|\\s_")
  2010. X      (forward-char 1))
  2011. X      (progn (while (and (not (bobp)) (not (looking-at "\\sw\\|\\s_")))
  2012. X           (forward-char -1))
  2013. X         (if (and (not (eobp)) (looking-at "\\sw\\|\\s_"))
  2014. X         (forward-char 1) )))
  2015. X    (if (bobp) ; no tag found
  2016. X    nil
  2017. X      (let ((end-point (point)))
  2018. X    (forward-char -1)
  2019. X    (while (and (not (bobp)) (looking-at "\\sw\\|\\s_\\|:"))
  2020. X      (forward-char -1))
  2021. X    (while (not (looking-at "\\sw\\|\\s_"))
  2022. X        (forward-char 1))
  2023. X    (if (looking-at "[A-Z]\\|[a-z]\\|:\\s_")
  2024. X        (buffer-substring (point) end-point)
  2025. X      nil)))))
  2026. X
  2027. X;;(defun find-tag-default ()
  2028. X;;  (save-excursion
  2029. X;;    (while (looking-at "\\sw\\|\\s_")
  2030. X;;      (forward-char 1))
  2031. X;;    (if (re-search-backward "\\sw\\|\\s_" nil t)
  2032. X;;    (progn (forward-char 1)
  2033. X;;           (buffer-substring (point)
  2034. X;;                 (progn (forward-sexp -1)
  2035. X;;                    (while (looking-at "\\s'")
  2036. X;;                      (forward-char 1))
  2037. X;;                    (point))))
  2038. X;;      nil)))
  2039. X
  2040. X
  2041. X(defun find-tag (tagname &optional next-p other-window regexp-p)
  2042. X  "Find tag (in current tag table) whose name contains TAGNAME;
  2043. Xmore exact matches are found first.
  2044. XSelect the buffer containing the tag's definition and move point there.
  2045. XThe default for TAGNAME is the expression in the buffer after or around point.
  2046. X
  2047. XIf second arg NEXT-P is non-nil (interactively, with prefix arg), search
  2048. Xfor another tag that matches the last tagname or regexp used.
  2049. X
  2050. XIf third arg OTHER-WINDOW is non-nil, select the buffer in another window.
  2051. X
  2052. XIf fourth arg REGEXP-P is non-nil, treat TAGNAME as a regexp.
  2053. X
  2054. XSee documentation of variable `tags-file-name'."
  2055. X  (interactive (if current-prefix-arg
  2056. X           '(nil t)
  2057. X           (list (prompt-for-tag "Find tag: "))))
  2058. X  (cond
  2059. X   (next-p (find-tag-in-order nil nil nil nil nil other-window))
  2060. X   (regexp-p (find-tag-in-order tagname
  2061. X                're-search-forward
  2062. X                '(tag-re-match-p)
  2063. X                t
  2064. X                "matching"
  2065. X                other-window))
  2066. X   (t
  2067. X    (find-tag-in-order
  2068. X     tagname
  2069. X     'search-forward
  2070. X     '(tag-exact-match-rhs-p 
  2071. X       tag-member-match-rhs-p 
  2072. X       tag-exact-match-p 
  2073. X       tag-word-match-p 
  2074. X       tag-any-match-p)
  2075. X     nil
  2076. X     "containing"
  2077. X     other-window))))
  2078. X
  2079. X(defun find-tag-other-window (tagname &optional next-p)
  2080. X  "Find tag (in current tag table) whose name contains TAGNAME;
  2081. Xmore exact matches are found first.
  2082. XSelect the buffer containing the tag's definition
  2083. Xin another window, and move point there.
  2084. XThe default for TAGNAME is the expression in the buffer around or before point.
  2085. X
  2086. XIf second arg NEXT-P is non-nil (interactively, with prefix arg), search
  2087. Xfor another tag that matches the last tagname used.
  2088. X
  2089. XSee documentation of variable `tags-file-name'."
  2090. X  (interactive (if current-prefix-arg
  2091. X           '(nil t)
  2092. X           (list (prompt-for-tag "Find tag other window: "))))
  2093. X  (find-tag tagname next-p t))
  2094. X
  2095. X(defun find-tag-regexp (regexp &optional next-p other-window)
  2096. X  "Find tag (in current tag table) whose name matches REGEXP.
  2097. XSelect the buffer containing the tag's definition and move point there.
  2098. X
  2099. XIf second arg NEXT-P is non-nil (interactively, with prefix arg), search
  2100. Xfor another tag that matches the last tagname used.
  2101. X
  2102. XIf third arg OTHER-WINDOW is non-nil, select the buffer in another window.
  2103. X
  2104. XSee documentation of variable `tags-file-name'."
  2105. X  (interactive (if current-prefix-arg
  2106. X           '(nil t)
  2107. X         (list (read-string "Find tag regexp: "))))
  2108. X  (find-tag regexp next-p other-window t))
  2109. X
  2110. X(defun find-tag-in-order
  2111. X  (pattern search-forward-func order next-line-after-failure-p matching other-window)
  2112. X  "Internal tag finding function.  PATTERN is a string to pass to
  2113. Xsecond arg SEARCH-FORWARD-FUNC, and to any member of the function list
  2114. XORDER (third arg).  If ORDER is nil, use saved state to continue a
  2115. Xprevious search.
  2116. X
  2117. XFourth arg MATCHING is a string, an English '-ing' word, to be used in
  2118. Xan error message.
  2119. X
  2120. XFifth arg NEXT-LINE-AFTER-FAILURE-P is non-nil if after a failed match,
  2121. Xpoint should be moved to the next line.
  2122. X
  2123. XIf sixth arg OTHER-WINDOW is non-nil, select the buffer in another window.
  2124. X
  2125. XAlgorithm is as follows.  For each qualifier-func in ORDER, go to
  2126. Xbeginning of tags file, and perform inner loop: for each naive match for
  2127. XPATTERN found using SEARCH-FORWARD-FUNC, qualify the naive match using
  2128. Xqualifier-func.  If it qualifies, go to the specified line in the
  2129. Xspecified source file and return.  Qualified matches are remembered to
  2130. Xavoid repetition.  State is saved so that the loop can be continued."
  2131. X  (let (file linebeg startpos)
  2132. X    (save-excursion
  2133. X      (visit-tags-table-buffer)
  2134. X      (if order
  2135. X      (progn
  2136. X        ;; Save state.
  2137. X        (setq find-tag-state (vector pattern search-forward-func matching)
  2138. X          tag-order order
  2139. X          tag-lines-already-matched nil)
  2140. X        ;; Start at beginning of tags file.
  2141. X        (goto-char (point-min)))
  2142. X    (progn
  2143. X      ;; Restore state.
  2144. X      (setq pattern (aref find-tag-state 0)
  2145. X        search-forward-func (aref find-tag-state 1)
  2146. X        matching (aref find-tag-state 2))))
  2147. X
  2148. X      ;; Get a qualified match.
  2149. X      (catch 'qualified-match-found
  2150. X    (while (car tag-order)
  2151. X      (while (funcall search-forward-func pattern nil t)
  2152. X        ;; Naive match found.
  2153. X        (if (and
  2154. X         ;; Qualify the match.
  2155. X         (funcall (car tag-order) pattern)
  2156. X         ;; Make sure it is not a previous qualified match.
  2157. X         ;; Use of `memq' depends on numbers being eq.
  2158. X         (not (memq (save-excursion (beginning-of-line) (point))
  2159. X                tag-lines-already-matched)))
  2160. X        (throw 'qualified-match-found nil))
  2161. X        (if next-line-after-failure-p (forward-line 1)))
  2162. X      (setq tag-order (cdr tag-order))
  2163. X      (goto-char (point-min)))
  2164. X    (error "No %stags %s %s" (if order "" "more ") matching pattern))
  2165. X
  2166. X      ;; Found a tag; extract location info.
  2167. X      (beginning-of-line)
  2168. X      (setq tag-lines-already-matched (cons (point) tag-lines-already-matched))
  2169. X      (search-forward "\177")
  2170. X      (setq file (expand-file-name (file-of-tag)
  2171. X                   (file-name-directory tags-file-name)))
  2172. X      (setq linebeg
  2173. X        (buffer-substring (1- (point))
  2174. X                  (save-excursion (beginning-of-line) (point))))
  2175. X      (search-forward ",")
  2176. X      (setq startpos (string-to-int (buffer-substring
  2177. X                      (point)
  2178. X                      (progn (skip-chars-forward "0-9")
  2179. X                         (point)))))
  2180. X      ;; Leave point on next line of tags file.
  2181. X      (forward-line 1))
  2182. X
  2183. X    ;; Find the right line in the specified file.
  2184. X    (if other-window
  2185. X    (find-file-other-window file)
  2186. X      (find-file file))
  2187. X    (widen)
  2188. X    (push-mark)
  2189. X
  2190. X    (let ((offset 16)    ;; this constant is 1/2 the initial search window
  2191. X      found
  2192. X      (pat (concat "^" (regexp-quote linebeg))))
  2193. X      (or startpos (setq startpos (point-min)))
  2194. X      (while (and (not found)
  2195. X          (progn
  2196. X           (goto-char (- startpos offset))
  2197. X           (not (bobp))))
  2198. X    (setq found
  2199. X          (re-search-forward pat (+ startpos offset (length pat)) t))
  2200. X    (setq offset (* 4 offset)))    ;; expand search window
  2201. X      (or found
  2202. X      (re-search-forward pat nil t)
  2203. X      (error "\"%s\" not found in %s; time to rerun etags" pat file)))
  2204. X    (beginning-of-line))
  2205. X  (setq tags-loop-form '(find-tag-in-order nil nil nil nil nil nil))
  2206. X  ;; Return t in case used as the tags-loop-form.
  2207. X  t)
  2208. X
  2209. X;;; Match qualifier functions for tagnames.
  2210. X
  2211. X(defun tag-exact-match-rhs-p (tag)
  2212. X  "Did we find an exact, case sensitive match for TAG following a Control-A?
  2213. XAssume point is in a tags file, immediately after an occurence of TAG."
  2214. X  (let ((tag-length (length tag)))
  2215. X    (and (looking-at "[\001\n]")
  2216. X     (save-excursion
  2217. X       (backward-char tag-length)
  2218. X       (and (= (preceding-char) ?\001)
  2219. X        (let ((case-fold-search nil))
  2220. X          (looking-at tag)))))))
  2221. X
  2222. X(defun tag-member-match-rhs-p (tag)
  2223. X  "Did we find an exact, case sensitive match for TAG following a colon following a Control-A?
  2224. XAssume point is in a tags file, immediately after an occurence of TAG."
  2225. X  (let ((tag-length (length tag)))
  2226. X    (and (looking-at "[\001\n]")
  2227. X     (save-excursion
  2228. X       (backward-char tag-length)
  2229. X       (and (or (= (preceding-char) ?\001) (= (preceding-char) ?:))
  2230. X        (let ((case-fold-search nil))
  2231. X          (looking-at tag)))))))
  2232. X
  2233. X
  2234. X(defun tag-exact-match-p (tag)
  2235. X  "Did we find an exact match for TAG?  Assume point is in a tags file,
  2236. Ximmediately after an occurence of TAG."
  2237. X  (let ((tag-length (length tag)))
  2238. X    (or (and (looking-at "[ \t();,]?\177")
  2239. X         (save-excursion (backward-char tag-length)
  2240. X                 (or (bolp)
  2241. X                 (let ((c (preceding-char)))
  2242. X                   (or (= c ? ) (= c ?\t)
  2243. X                       (= c ?*)    ;; HACK 7/19/89
  2244. X                       )))))
  2245. X    (and (looking-at "[\001\n]")
  2246. X         (save-excursion (backward-char tag-length)
  2247. X                 (= (preceding-char) ?\001))))))
  2248. X
  2249. X(defun tag-word-match-p (tag)
  2250. X  "Did we find a word match for TAG?  Assume point is in a tags file,
  2251. Ximmediately after an occurence of TAG."
  2252. X  (let ((tag-length (length tag)))
  2253. X    (or (and (looking-at "\\b.*\177")
  2254. X         (save-excursion (backward-char tag-length)
  2255. X                 (looking-at "\\b")))
  2256. X    (and (looking-at "\\b.*[\001\n]")
  2257. X         (save-excursion (backward-char tag-length)
  2258. X                 (and
  2259. X                  (looking-at "\\b")
  2260. X                  (progn
  2261. X                (skip-chars-backward "^\001\n")
  2262. X                (= (preceding-char) ?\001))))))))
  2263. X
  2264. X(defun tag-any-match-p (tag)
  2265. X  "Did we find any match for TAG?  Assume point is in a tags file,
  2266. Ximmediately after an occurence of TAG."
  2267. X  (or (looking-at ".*\177")
  2268. X      (save-excursion
  2269. X    (backward-char (length tag))
  2270. X    (skip-chars-backward "^\001\n")
  2271. X    (= (preceding-char) ?\001))))
  2272. X
  2273. X;;; Match qualifier function for regexps.
  2274. X
  2275. X(defun tag-re-match-p (re)
  2276. X  "Is point (in a tags file) on a line with a match for RE?"
  2277. X  (save-excursion
  2278. X    (beginning-of-line)
  2279. X    (catch 'done
  2280. X      (let* ((bol (point))
  2281. X         (eol (save-excursion (end-of-line) (point)))
  2282. X         (del (save-excursion (if (search-forward "\177" eol t)
  2283. X                      (point)
  2284. X                    (throw 'done nil)))))
  2285. X     (if (search-forward "\001" eol t)
  2286. X         ;; There are ^A's: try to match in each tag after a ^A
  2287. X         (let ((bot (point))
  2288. X           eot)
  2289. X           (while (< bot eol)
  2290. X         (save-excursion
  2291. X           (setq eot (if (search-forward "\001" eol t)
  2292. X                    (1- (point))
  2293. X                  eol))
  2294. X           (if (re-search-forward re eot t)
  2295. X               (throw 'done t))
  2296. X           (setq bot (1+ eot))
  2297. X           (goto-char bot))))
  2298. X       ;; No ^A: try to match the line before the ^?
  2299. X       (goto-char bol)
  2300. X       (re-search-forward re (1- del) t))))))
  2301. X
  2302. X(defun next-file (&optional initialize)
  2303. X  "Select next file among files in current tag table.
  2304. XNon-nil argument (prefix arg, if interactive)
  2305. Xinitializes to the beginning of the list of files in the tag table."
  2306. X  (interactive "P")
  2307. X  (if initialize
  2308. X      (setq next-file-list (tag-table-files)))
  2309. X  (or next-file-list
  2310. X      (error "All files processed."))
  2311. X  (find-file (car next-file-list))
  2312. X  (setq next-file-list (cdr next-file-list)))
  2313. X
  2314. X(defvar tags-loop-form nil
  2315. X  "Form for tags-loop-continue to eval to process one file.
  2316. XIf it returns nil, it is through with one file; move on to next.")
  2317. X
  2318. X(defun tags-loop-continue (&optional first-time)
  2319. X  "Continue last \\[find-tag], \\[tags-search], or
  2320. X\\[tags-query-replace] command.  Used noninteractively with non-nil
  2321. Xargument to begin such a command.  See variable `tags-loop-form'."
  2322. X  (interactive)
  2323. X  (if first-time
  2324. X      (progn (next-file t)
  2325. X         (goto-char (point-min))))
  2326. X  (while (not (eval tags-loop-form))
  2327. X    (next-file)
  2328. X    (message "Scanning file %s..." buffer-file-name)
  2329. X    (goto-char (point-min))))
  2330. X
  2331. X(defun tags-search (regexp)
  2332. X  "Search through all files listed in tag table for match for REGEXP.
  2333. XStops when a match is found.
  2334. XTo continue searching for next match, use command \\[tags-loop-continue].
  2335. X
  2336. XSee documentation of variable tags-file-name."
  2337. X  (interactive "sTags search (regexp): ")
  2338. X  (if (and (equal regexp "")
  2339. X       (eq (car tags-loop-form) 're-search-forward))
  2340. X      (tags-loop-continue nil)
  2341. X    (setq tags-loop-form
  2342. X      (list 're-search-forward regexp nil t))
  2343. X    (tags-loop-continue t)))
  2344. X
  2345. X(defun tags-query-replace (from to)
  2346. X  "Query-replace-regexp FROM with TO through all files listed in tag table.
  2347. XIf you exit (C-G or ESC), you can resume the query-replace
  2348. Xwith the command \\[tags-loop-continue].
  2349. X
  2350. XSee documentation of variable tags-file-name."
  2351. X  (interactive "sTags query replace (regexp): \nsTags query replace %s by: ")
  2352. X  (setq tags-loop-form
  2353. X    (list 'and (list 'save-excursion
  2354. X             (list 're-search-forward from nil t))
  2355. X          (list 'not (list 'perform-replace from to t t nil))))
  2356. X  (tags-loop-continue t))
  2357. X
  2358. X(defun list-tags (string)
  2359. X  "Display list of tags in file FILE.
  2360. XFILE should not contain a directory spec
  2361. Xunless it has one in the tag table."
  2362. X  (interactive "sList tags (in file): ")
  2363. X  (with-output-to-temp-buffer "*Tags List*"
  2364. X    (princ "Tags in file ")
  2365. X    (princ string)
  2366. X    (terpri)
  2367. X    (save-excursion
  2368. X     (visit-tags-table-buffer)
  2369. X     (goto-char 1)
  2370. X     (search-forward (concat "\f\n" string ","))
  2371. X     (forward-line 1)
  2372. X     (while (not (looking-at "\f"))
  2373. X       (princ (buffer-substring (point)
  2374. X                (progn (skip-chars-forward "^\177")
  2375. X                       (point))))
  2376. X       (terpri)
  2377. X       (forward-line 1)))))
  2378. X
  2379. X(defun tags-apropos (string)
  2380. X  "Display list of all tags in tag table REGEXP matches."
  2381. X  (interactive "sTag apropos (regexp): ")
  2382. X  (with-output-to-temp-buffer "*Tags List*"
  2383. X    (princ "Tags matching regexp ")
  2384. X    (prin1 string)
  2385. X    (terpri)
  2386. X    (save-excursion
  2387. X     (visit-tags-table-buffer)
  2388. X     (goto-char 1)
  2389. X     (while (re-search-forward string nil t)
  2390. X       (beginning-of-line)
  2391. X       (princ (buffer-substring (point)
  2392. X                (progn (skip-chars-forward "^\177")
  2393. X                       (point))))
  2394. X       (terpri)
  2395. X       (forward-line 1)))))
  2396. X
  2397. X(defun select-tags-table ()
  2398. X  "Select a tags table file from a menu of those you have already used.
  2399. XThe list of tags tables to select from is stored in `tags-table-file-list';
  2400. Xsee the doc of that variable if you want to add names to the list."
  2401. X  (interactive)
  2402. X  (switch-to-buffer "*Tags Table List*")
  2403. X  (erase-buffer)
  2404. X  (let ((list tags-table-file-list))
  2405. X    (while list
  2406. X      (insert (car (car list)) "\n")
  2407. X      (setq list (cdr list))))
  2408. X  (goto-char 1)
  2409. X  (insert "Type `t' to select a tag table:\n\n")
  2410. X  (set-buffer-modified-p nil)
  2411. X  (let ((map (make-sparse-keymap)))
  2412. X    (define-key map "t" 'select-tags-table-select)
  2413. X    (use-local-map map)))
  2414. X  
  2415. X(defun select-tags-table-select ()
  2416. X  "Select the tag table named on this line."
  2417. X  (interactive)
  2418. X  (let ((name (buffer-substring (point)
  2419. X                (save-excursion (end-of-line) (point)))))
  2420. X    (visit-tags-table name)
  2421. X    (message "Tag table now %s" name)))
  2422. X
  2423. X
  2424. END_OF_FILE
  2425.   if test 24786 -ne `wc -c <'cie/tags.el'`; then
  2426.     echo shar: \"'cie/tags.el'\" unpacked with wrong size!
  2427.   fi
  2428.   # end of 'cie/tags.el'
  2429. fi
  2430. echo shar: End of archive 1 \(of 2\).
  2431. cp /dev/null ark1isdone
  2432. MISSING=""
  2433. for I in 1 2 ; do
  2434.     if test ! -f ark${I}isdone ; then
  2435.     MISSING="${MISSING} ${I}"
  2436.     fi
  2437. done
  2438. if test "${MISSING}" = "" ; then
  2439.     echo You have unpacked both archives.
  2440.     rm -f ark[1-9]isdone
  2441. else
  2442.     echo You still must unpack the following archives:
  2443.     echo "        " ${MISSING}
  2444. fi
  2445. exit 0
  2446. exit 0 # Just in case...
  2447.