entry.c
上传用户:gddssl
上传日期:2007-01-06
资源大小:1003k
文件大小:20k
源码类别:

编辑器/阅读器

开发平台:

DOS

  1. /*****************************************************************************
  2. *   $Id: entry.c,v 6.4 1998/07/22 02:32:58 darren Exp $
  3. *
  4. *   Copyright (c) 1996-1998, Darren Hiebert
  5. *
  6. *   This source code is released for free distribution under the terms of the
  7. *   GNU General Public License.
  8. *
  9. *   This module contains functions for creating tag entries.
  10. *****************************************************************************/
  11. /*============================================================================
  12. =   Include files
  13. ============================================================================*/
  14. #include <stdio.h>
  15. #ifdef HAVE_CONFIG_H
  16. # include <config.h>
  17. #endif
  18. #ifdef DEBUG
  19. # include <assert.h>
  20. #endif
  21. #include "ctags.h"
  22. /*============================================================================
  23.  *= Defines
  24. ============================================================================*/
  25. #define includeExtensionFlags() (Option.tagFileFormat > 1)
  26. /*============================================================================
  27. =   Data definitions
  28. ============================================================================*/
  29. /*  Note that the strings and characters in these arrays must correspond to
  30.  *  the types in the tagType enumeration.
  31.  */
  32. static const char *TagTypeNames[] = {
  33.     "class", "define", "macro", "enum", "enumerator", "prototype", "function",
  34.     "interface", "member", "namespace", "file", "struct", "typedef", "union",
  35.     "variable", "externvar"
  36. };
  37. static const char TagTypeChars[] = "cddgepfimnFstuvx";
  38. /*============================================================================
  39. =   Function prototypes
  40. ============================================================================*/
  41. static size_t writeSourceLine __ARGS((FILE *const fp, const char *const line));
  42. static size_t writeCompactSourceLine __ARGS((FILE *const fp, const char *const line));
  43. static void rememberMaxLengths __ARGS((const size_t nameLength, const size_t lineLength));
  44. static void writeXrefEntry __ARGS((const tagInfo *const tag, const tagType type));
  45. static void truncateTagLine __ARGS((char *const line, const char *const token, const boolean discardNewline));
  46. static int writeEtagsEntry __ARGS((const tagInfo *const tag, const memberInfo *const pMember, const tagScope scope, const tagType type));
  47. static int addExtensionFlags __ARGS((const memberInfo *const pMember, const tagScope scope, const tagType type));
  48. static int writeLineNumberEntry __ARGS((const tagInfo *const tag));
  49. static int writePatternEntry __ARGS((const tagInfo *const tag, const tagType type));
  50. static int writeCtagsEntry __ARGS((const tagInfo *const tag, const memberInfo *const pMember, const tagScope scope, const tagType type, const boolean useLineNumber));
  51. static void writeTagEntry __ARGS((const tagInfo *const tag, const memberInfo *const pMember, const tagScope scope, const tagType type, const boolean useLineNumber));
  52. static boolean includeTag __ARGS((const tagScope scope, const tagType type));
  53. static void writeExtraMemberTagEntry __ARGS((const tagInfo *const tag, const memberInfo *const pMember, const tagScope scope, const tagType type, const boolean useLineNumber, const char *const format));
  54. static void makeExtraMemberTagEntry __ARGS((const tagInfo *const tag, const memberInfo *const pMember, const tagScope scope, const tagType type, const boolean useLineNumber));
  55. static void makeTagEntry __ARGS((const tagInfo *const tag, const memberInfo *const pMember, const tagScope scope, const tagType type, const boolean useLineNumber));
  56. static void writePseudoTag __ARGS((const char *const tagName, const char *const fileName, const char *const pattern));
  57. static void updateSortedFlag __ARGS((const char *const line, FILE *const fp, const long startOfLine));
  58. /*============================================================================
  59. =   Function definitions
  60. ============================================================================*/
  61. extern const char *tagTypeName( type )
  62.     const tagType type;
  63. {
  64.     const char *name;
  65.     if ((int)type < (int)TAG_NUMTYPES)
  66. name = TagTypeNames[(int)type];
  67.     else
  68. name = "?";
  69.     return name;
  70. }
  71. /*  This function copies the current line out some other fp.  It has no
  72.  *  effect on the fileGetc() function.  During copying, any '' characters
  73.  *  are doubled and a leading '^' or trailing '$' is also quoted.  The 'n'
  74.  *  character is not copied.  If the 'n' is preceded by a 'r', then the
  75.  *  'r' isn't copied.
  76.  *
  77.  *  This is meant to be used when generating a tag line.
  78.  */
  79. static size_t writeSourceLine( fp, line )
  80.     FILE *const fp;
  81.     const char *const line;
  82. {
  83.     size_t length = 0;
  84.     const char *p;
  85.     int c;
  86.     /* Write everything up to, but not including, the newline.
  87.      */
  88.     for (p = line, c = *p  ;  c != NEWLINE  &&  c != ''  ;  ++p, c = *p)
  89.     {
  90. const int next = *(p + 1);
  91. /*  If character is '', or a terminal '$', then quote it.
  92.  */
  93. if (c == BACKSLASH  ||  c == (Option.backward ? '?' : '/')  ||
  94.     (c == '$'  &&  next == NEWLINE))
  95. {
  96.     putc(BACKSLASH, fp);
  97.     ++length;
  98. }
  99. /*  Copy the character, unless it is a terminal 'r'.
  100.  */
  101. if (c != CRETURN  ||  next != NEWLINE)
  102. {
  103.     putc(c, fp);
  104.     ++length;
  105. }
  106.     }
  107.     return length;
  108. }
  109. /*  Writes "line", stripping leading and duplicate white space.
  110.  */
  111. static size_t writeCompactSourceLine( fp, line )
  112.     FILE *const fp;
  113.     const char *const line;
  114. {
  115.     boolean lineStarted = FALSE;
  116.     size_t  length = 0;
  117.     const char *p;
  118.     int c;
  119.     /* Write everything up to, but not including, the newline.
  120.      */
  121.     for (p = line, c = *p  ;  c != NEWLINE  &&  c != ''  ;  c = *++p)
  122.     {
  123. if (lineStarted  || ! isspace(c)) /* ignore leading spaces */
  124. {
  125.     lineStarted = TRUE;
  126.     if (isspace(c))
  127.     {
  128. int next;
  129. /*  Consume repeating white space.
  130.  */
  131. while (next = *(p+1) , isspace(next)  &&  next != NEWLINE)
  132.     ++p;
  133. c = ' '; /* force space character for any white space */
  134.     }
  135.     if (c != CRETURN  ||  *(p + 1) != NEWLINE)
  136.     {
  137. putc(c, fp);
  138. ++length;
  139.     }
  140. }
  141.     }
  142.     return length;
  143. }
  144. static void rememberMaxLengths( nameLength, lineLength )
  145.     const size_t nameLength;
  146.     const size_t lineLength;
  147. {
  148.     if (nameLength > TagFile.max.tag)
  149. TagFile.max.tag = nameLength;
  150.     if (lineLength > TagFile.max.line)
  151. TagFile.max.line = lineLength;
  152. }
  153. static void writeXrefEntry( tag, type )
  154.     const tagInfo *const tag;
  155.     const tagType type;
  156. {
  157.     const char *const line = getSourceLine(&TagFile.line, tag->location);
  158.     size_t length = fprintf(TagFile.fp, "%-20s %-10s %4lu  %-14s ",
  159.     tag->name, tagTypeName(type), tag->lineNumber,
  160.     File.name);
  161.     length += writeCompactSourceLine(TagFile.fp, line);
  162.     putc(NEWLINE, TagFile.fp);
  163.     ++length;
  164.     ++TagFile.numTags.added;
  165.     rememberMaxLengths(strlen(tag->name), length);
  166. }
  167. /*  Truncates the text line containing the tag at the character following the
  168.  *  tag, providing a character which designates the end of the tag.
  169.  */
  170. static void truncateTagLine( line, token, discardNewline )
  171.     char *const line;
  172.     const char *const token;
  173.     const boolean discardNewline;
  174. {
  175.     char *p = strstr(line, token);
  176.     if (p != NULL)
  177.     {
  178. p += strlen(token);
  179. if (*p != ''  &&  !(*p == 'n'  &&  discardNewline))
  180.     ++p; /* skip past character terminating character */
  181. *p = '';
  182.     }
  183. }
  184. static int writeEtagsEntry( tag, pMember, scope, type )
  185.     const tagInfo *const tag;
  186.     const memberInfo *const pMember;
  187.     const tagScope scope;
  188.     const tagType type;
  189. {
  190.     char *const line = getSourceLine(&TagFile.line, tag->location);
  191.     int length;
  192.     truncateTagLine(line, tag->name, TRUE);
  193.     if (pMember->type != MEMBER_NONE)
  194. length = fprintf(TagFile.etags.fp, "%s177%s:%s01%lu,%ldn", line,
  195.  pMember->parent, tag->name, tag->lineNumber,
  196.  tag->location);
  197.     else if (scope == SCOPE_STATIC)
  198. length = fprintf(TagFile.etags.fp, "%s177%s:%s01%lu,%ldn", line,
  199.  File.name, tag->name, tag->lineNumber, tag->location);
  200.     else if (type == TAG_CLASS   ||  type == TAG_DEFINE_FUNC  ||
  201.      type == TAG_ENUM    ||  type == TAG_STRUCT       ||
  202.      type == TAG_TYPEDEF ||  type == TAG_UNION)
  203. length = fprintf(TagFile.etags.fp, "%s177%s01%lu,%ldn", line,
  204.  tag->name, tag->lineNumber, tag->location);
  205.     else
  206. length = fprintf(TagFile.etags.fp, "%s177%lu,%ldn", line,
  207.  tag->lineNumber, tag->location);
  208.     TagFile.etags.byteCount += length;
  209.     return length;
  210. }
  211. extern const char *getTypeString( mType )
  212.     const memberType mType;
  213. {
  214.     const char *typeString;
  215.     switch (mType)
  216.     {
  217. case MEMBER_ENUM: typeString = "enum"; break;
  218. case MEMBER_CLASS: typeString = "class"; break;
  219. case MEMBER_INTERFACE: typeString = "interface"; break;
  220. case MEMBER_NAMESPACE: typeString = "namespace"; break;
  221. case MEMBER_STRUCT: typeString = "struct"; break;
  222. case MEMBER_UNION: typeString = "union"; break;
  223. default: typeString = ""; break;
  224.     }
  225.     return typeString;
  226. }
  227. extern const char *getVisibilityString( visibility )
  228.     const visibilityType visibility;
  229. {
  230.     const char *visibilityString;
  231.     switch (visibility)
  232.     {
  233. case VIS_PRIVATE: visibilityString = "private"; break;
  234. case VIS_PROTECTED: visibilityString = "protected"; break;
  235. case VIS_PUBLIC: visibilityString = "public"; break;
  236. default: visibilityString = ""; break;
  237.     }
  238.     return visibilityString;
  239. }
  240. static int addExtensionFlags( pMember, scope, type )
  241.     const memberInfo *const pMember;
  242.     const tagScope scope;
  243.     const tagType type;
  244. {
  245.     const char *const prefix = ";"t";
  246.     const char *const separator = "t";
  247.     int length = 0;
  248. #ifdef LONG_FORM_TYPE
  249.     const char *const format = "%skind:%c";
  250. #else
  251.     const char *const format = "%s%c";
  252. #endif
  253.     /*  Add an extension flag designating that the type of the tag.
  254.      */
  255.     length += fprintf(TagFile.fp, format, prefix, TagTypeChars[(int)type]);
  256.     /*  If this is a static tag, add the appropriate extension flag.
  257.      */
  258.     if (scope == SCOPE_STATIC)
  259. length += fprintf(TagFile.fp, "%sfile:", separator);
  260.     /*  For selected tag types, append an extension flag designating the
  261.      *  parent object in which the tag is defined.
  262.      */
  263.     switch (type)
  264.     {
  265. case TAG_DEFINE_FUNC:
  266. case TAG_DEFINE_OBJ:
  267. default:
  268.     /* always global scope */
  269.     break;
  270. case TAG_ENUMERATOR:
  271. case TAG_FUNCDECL:
  272. case TAG_FUNCTION:
  273. case TAG_MEMBER:
  274. case TAG_TYPEDEF:
  275. case TAG_VARIABLE:
  276. {
  277.     if (pMember->type != MEMBER_NONE)
  278.     {
  279. length += fprintf(TagFile.fp, "%s%s:%s", separator,
  280.   getTypeString(pMember->type),pMember->parent);
  281. if ((File.language == LANG_CPP || File.language == LANG_JAVA) &&
  282.     pMember->visibility != VIS_UNDEFINED)
  283. {
  284.     length += fprintf(TagFile.fp, "%s%s:", separator,
  285.     getVisibilityString(pMember->visibility));
  286. }
  287.     }
  288.     break;
  289. }
  290.     }
  291.     return length;
  292. }
  293. static int writeLineNumberEntry( tag )
  294.     const tagInfo *const tag;
  295. {
  296.     return fprintf(TagFile.fp, "%lu", tag->lineNumber);
  297. }
  298. static int writePatternEntry( tag, type )
  299.     const tagInfo *const tag;
  300.     const tagType type;
  301. {
  302.     char *const line = getSourceLine(&TagFile.line, tag->location);
  303.     const int searchChar = Option.backward ? '?' : '/';
  304.     boolean newlineTerminated;
  305.     int length = 0;
  306.     if (type == TAG_DEFINE_OBJ  ||  type == TAG_DEFINE_FUNC)
  307. truncateTagLine(line, tag->name, FALSE);
  308.     newlineTerminated = (boolean)(line[strlen(line) - 1] == 'n');
  309.     length += fprintf(TagFile.fp, "%c^", searchChar);
  310.     length += writeSourceLine(TagFile.fp, line);
  311.     length += fprintf(TagFile.fp, "%s%c", newlineTerminated ? "$":"",
  312.       searchChar);
  313.     return length;
  314. }
  315. static int writeCtagsEntry( tag, pMember, scope, type, useLineNumber )
  316.     const tagInfo *const tag;
  317.     const memberInfo *const pMember;
  318.     const tagScope scope;
  319.     const tagType type;
  320.     const boolean useLineNumber;
  321. {
  322.     int length = fprintf(TagFile.fp, "%st%st", tag->name, File.name);
  323.     if (useLineNumber || type == TAG_SOURCE_FILE)
  324. length += writeLineNumberEntry(tag);
  325.     else
  326. length += writePatternEntry(tag, type);
  327.     if (includeExtensionFlags())
  328. length += addExtensionFlags(pMember, scope, type);
  329.     length += fprintf(TagFile.fp, "n");
  330.     return length;
  331. }
  332. static void writeTagEntry( tag, pMember, scope, type, useLineNumber )
  333.     const tagInfo *const tag;
  334.     const memberInfo *const pMember;
  335.     const tagScope scope;
  336.     const tagType type;
  337.     const boolean useLineNumber;
  338. {
  339.     size_t length;
  340.     if (Option.etags)
  341. length = writeEtagsEntry(tag, pMember, scope, type);
  342.     else
  343. length = writeCtagsEntry(tag, pMember, scope, type, useLineNumber);
  344.     ++TagFile.numTags.added;
  345.     rememberMaxLengths(strlen(tag->name), length);
  346. }
  347. static boolean includeTag( scope, type )
  348.     const tagScope scope;
  349.     const tagType type;
  350. {
  351.     boolean include;
  352.     if (scope == SCOPE_STATIC  &&  ! Option.include.statics)
  353. include = FALSE;
  354.     else switch (type)
  355.     {
  356. case TAG_CLASS: include = Option.include.classNames; break;
  357. case TAG_DEFINE_OBJ:
  358. case TAG_DEFINE_FUNC: include = Option.include.defines; break;
  359. case TAG_ENUM: include = Option.include.enumNames; break;
  360. case TAG_ENUMERATOR: include = Option.include.enumerators; break;
  361. case TAG_FUNCDECL: include = Option.include.prototypes; break;
  362. case TAG_FUNCTION: include = Option.include.functions; break;
  363. case TAG_INTERFACE: include = Option.include.interfaceNames;break;
  364. case TAG_MEMBER: include = Option.include.members; break;
  365. case TAG_NAMESPACE: include = Option.include.namespaceNames;break;
  366. case TAG_SOURCE_FILE: include = Option.include.sourceFiles; break;
  367. case TAG_STRUCT: include = Option.include.structNames; break;
  368. case TAG_TYPEDEF: include = Option.include.typedefs; break;
  369. case TAG_UNION: include = Option.include.unionNames; break;
  370. case TAG_VARIABLE: include = Option.include.variables; break;
  371. case TAG_EXTERN_VAR: include = Option.include.externVars; break;
  372. default: include = FALSE; break;
  373.     }
  374.     return include;
  375. }
  376. static void writeExtraMemberTagEntry( tag, pMember, scope, type,
  377.       useLineNumber, format )
  378.     const tagInfo *const tag;
  379.     const memberInfo *const pMember;
  380.     const tagScope scope;
  381.     const tagType type;
  382.     const boolean useLineNumber;
  383.     const char *const format;
  384. {
  385.     switch (type)
  386.     {
  387. case TAG_FUNCDECL:
  388. case TAG_FUNCTION:
  389. case TAG_MEMBER:
  390. {
  391.     tagInfo prefixedTag;
  392.     prefixedTag = *tag;
  393.     sprintf(prefixedTag.name, format, pMember->parent, tag->name);
  394.     writeTagEntry(&prefixedTag, pMember, scope, type, useLineNumber);
  395. }
  396. default: break;
  397.     }
  398. }
  399. static void makeExtraMemberTagEntry( tag, pMember, scope, type, useLineNumber )
  400.     const tagInfo *const tag;
  401.     const memberInfo *const pMember;
  402.     const tagScope scope;
  403.     const tagType type;
  404.     const boolean useLineNumber;
  405. {
  406.     if (File.language == LANG_CPP  &&
  407. (pMember->type == MEMBER_CLASS  ||  pMember->type == MEMBER_STRUCT))
  408.     {
  409. writeExtraMemberTagEntry(tag, pMember, scope, type, useLineNumber, "%s::%s");
  410.     }
  411.     else if (File.language == LANG_JAVA  &&  pMember->type == MEMBER_CLASS)
  412.     {
  413. writeExtraMemberTagEntry(tag, pMember, scope, type, useLineNumber, "%s.%s");
  414.     }
  415. }
  416. /*  This function generates a tag for the object in name, whose tag line is
  417.  *  located at a given seek offset.
  418.  */
  419. static void makeTagEntry( tag, pMember, scope, type, useLineNumber )
  420.     const tagInfo *const tag;
  421.     const memberInfo *const pMember;
  422.     const tagScope scope;
  423.     const tagType type;
  424.     const boolean useLineNumber;
  425. {
  426.     if (includeTag(scope, type)  &&  tag->name[0] != '')
  427.     {
  428. if (Option.xref)
  429.     writeXrefEntry(tag, type);
  430. else
  431. {
  432.     writeTagEntry(tag, pMember, scope, type, useLineNumber);
  433.     if (Option.include.classPrefix  &&  pMember->parent[0] != '0')
  434. makeExtraMemberTagEntry(tag, pMember, scope, type, useLineNumber);
  435. }
  436. DebugStatement( debugEntry(scope, type, tag->name, pMember); )
  437.     }
  438. }
  439. extern void makeTag( tag, pMember, scope, type )
  440.     const tagInfo *const tag;
  441.     const memberInfo *const pMember;
  442.     const tagScope scope;
  443.     const tagType type;
  444. {
  445.     makeTagEntry(tag, pMember, scope, type,
  446.  (boolean)(Option.locate == EX_LINENUM));
  447. }
  448. extern void makeDefineTag( tag, scope, parameterized )
  449.     const tagInfo *const tag;
  450.     const tagScope scope;
  451.     const boolean parameterized;
  452. {
  453.     const tagType type = (parameterized ? TAG_DEFINE_FUNC : TAG_DEFINE_OBJ);
  454.     makeTagEntry(tag, &NoClass, scope, type,
  455.  (boolean)(Option.locate != EX_PATTERN));
  456. }
  457. /*----------------------------------------------------------------------------
  458. *- Pseudo tag support
  459. ----------------------------------------------------------------------------*/
  460. static void writePseudoTag( tagName, fileName, pattern )
  461.     const char *const tagName;
  462.     const char *const fileName;
  463.     const char *const pattern;
  464. {
  465.     const size_t length = fprintf(TagFile.fp, "%s%st%st/%s/n",
  466.  PSEUDO_TAG_PREFIX, tagName, fileName, pattern);
  467.     ++TagFile.numTags.added;
  468.     rememberMaxLengths(strlen(tagName), length);
  469. }
  470. extern void addPseudoTags()
  471. {
  472.     if (! Option.xref  &&  ! Option.etags)
  473.     {
  474. char format[11];
  475. const char *formatComment = "unknown format";
  476. sprintf(format, "%u", Option.tagFileFormat);
  477. if (Option.tagFileFormat == 1)
  478.     formatComment = "original ctags format";
  479. else if (Option.tagFileFormat == 2)
  480.     formatComment =
  481.     "extended format; --format=1 will not append ;" to lines";
  482. writePseudoTag("TAG_FILE_FORMAT", format, formatComment);
  483. writePseudoTag("TAG_FILE_SORTED", Option.sorted ? "1":"0",
  484.        "0=unsorted, 1=sorted");
  485. writePseudoTag("TAG_PROGRAM_AUTHOR", AUTHOR_NAME,  AUTHOR_EMAIL);
  486. writePseudoTag("TAG_PROGRAM_NAME", PROGRAM_NAME, "");
  487. writePseudoTag("TAG_PROGRAM_URL", PROGRAM_URL,  "official site");
  488. writePseudoTag("TAG_PROGRAM_VERSION", PROGRAM_VERSION,
  489.        "with C++ and Java support");
  490.     }
  491. }
  492. static void updateSortedFlag( line, fp, startOfLine )
  493.     const char *const line;
  494.     FILE *const fp;
  495.     const long startOfLine;
  496. {
  497.     const char *const tab = strchr(line, 't');
  498.     if (tab != NULL)
  499.     {
  500. const long boolOffset = tab - line + 1; /* where it should be */
  501. if (line[boolOffset] == '0'  ||  line[boolOffset] == '1')
  502. {
  503.     const long nextLine = ftell(fp);
  504.     fseek(fp, startOfLine + boolOffset, SEEK_SET);
  505.     fputc(Option.sorted ? '1' : '0', fp);
  506.     fseek(fp, nextLine, SEEK_SET);
  507. }
  508.     }
  509. }
  510. /*  Look through all line beginning with "!_TAG_FILE", and update those which
  511.  *  require it.
  512.  */
  513. extern unsigned long updatePseudoTags()
  514. {
  515.     enum { maxClassLength = 20 };
  516.     char class[maxClassLength + 1];
  517.     FILE *const fp = TagFile.fp;
  518.     long startOfLine = 0;
  519.     unsigned long linesRead = 0;
  520.     size_t classLength;
  521.     const char *line;
  522.     sprintf(class, "%sTAG_FILE", PSEUDO_TAG_PREFIX);
  523.     classLength = strlen(class);
  524.     DebugStatement( assert(classLength < maxClassLength); )
  525.     rewind(fp);
  526.     line = readLine(&TagFile.line, fp);
  527.     while (line != NULL  &&  line[0] == class[0])
  528.     {
  529. ++linesRead;
  530. if (strncmp(line, class, classLength) == 0)
  531. {
  532.     char tab, classType[16];
  533.     if (sscanf(line + classLength, "%15s%c", classType, &tab) == 2  &&
  534. tab == 't')
  535.     {
  536. if (strcmp(classType, "_SORTED") == 0)
  537.     updateSortedFlag(line, fp, startOfLine);
  538.     }
  539.     startOfLine = ftell(fp);
  540. }
  541. line = readLine(&TagFile.line, fp);
  542.     }
  543.     while (line != NULL) /* skip to end of file */
  544.     {
  545. ++linesRead;
  546. line = readLine(&TagFile.line, fp);
  547.     }
  548.     return linesRead;
  549. }
  550. /* vi:set tabstop=8 shiftwidth=4: */