libcm is a C development framework with an emphasis on audio signal processing applications.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cmTagFile.c 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. #include "cmPrefix.h"
  2. #include "cmGlobal.h"
  3. #include "cmRpt.h"
  4. #include "cmErr.h"
  5. #include "cmCtx.h"
  6. #include "cmMem.h"
  7. #include "cmMallocDebug.h"
  8. #include "cmLinkedHeap.h"
  9. #include "cmFile.h"
  10. #include "cmTagFile.h"
  11. cmTfH_t cmTfNullHandle = cmSTATIC_NULL_HANDLE;
  12. typedef struct
  13. {
  14. cmErr_t err;
  15. cmFileH_t fH;
  16. cmLHeapH_t lH;
  17. cmTfTag_t* tagArray;
  18. unsigned tagCnt;
  19. unsigned tagAllocCnt;
  20. } cmTf_t;
  21. cmTf_t* _cmTfHandleToPtr( cmTfH_t h )
  22. {
  23. cmTf_t* p = (cmTf_t*)h.h;
  24. assert( p != NULL );
  25. return p;
  26. }
  27. const cmChar_t* _cmTfFlagsToLabel( unsigned flags )
  28. {
  29. switch(flags)
  30. {
  31. case kFuncProtoTfFl: return "p";
  32. case kFuncDefnTfFl: return "d";
  33. case kEnumTfFl: return "e";
  34. case kMacroTfFl: return "m";
  35. case kTypedefTfFl: return "t";
  36. case kFieldTfFl: return "f";
  37. case kExternTfFl: return "x";
  38. case kStructTagTfFl:return "s";
  39. case kUnionTagTfFl: return "u";
  40. default:
  41. { assert(0); }
  42. }
  43. return "<unknown>";
  44. }
  45. void _cmTfPrintTag(cmRpt_t* rpt, const cmTfTag_t* r )
  46. {
  47. cmRptPrintf(rpt,"%s %5i %s\n",_cmTfFlagsToLabel(r->flags),r->line,r->label);
  48. }
  49. cmTfRC_t _cmTfCloseFile( cmTf_t* p )
  50. {
  51. cmTfRC_t rc = kOkTfRC;
  52. if( cmFileIsValid(p->fH) )
  53. cmFileClose(&p->fH);
  54. if( cmLHeapIsValid(p->lH) )
  55. cmLHeapDestroy(&p->lH);
  56. cmMemFree(p);
  57. return rc;
  58. }
  59. cmTfRC_t _cmTfSyntaxErr( cmTf_t* p, const cmChar_t* fn, unsigned line, const cmChar_t* msg )
  60. {
  61. return cmErrMsg(&p->err,kSyntaxErrTfRC,"Syntax error: %s line:%i in file:%s\n",msg,line,cmStringNullGuard(fn));
  62. }
  63. cmTfRC_t _cmTfParseLine( cmTf_t* p, const cmChar_t* fn, unsigned line, cmChar_t* buf, unsigned bufCharCnt )
  64. {
  65. cmTfRC_t rc = kOkTfRC;
  66. const cmChar_t lineLabel[] = "line:";
  67. unsigned lineLabelCharCnt = strlen(lineLabel);
  68. char* s;
  69. cmTfTag_t r;
  70. memset(&r,0,sizeof(r));
  71. // if the line is empty
  72. if( buf==NULL || bufCharCnt == 0 )
  73. return rc;
  74. // eat leading white space
  75. while( *buf && isspace(*buf) )
  76. ++buf;
  77. // if the line is now empty
  78. if( *buf == 0 )
  79. return rc;
  80. // skip the file header lines - which begin with a '!' character
  81. if( *buf == '!' )
  82. return rc;
  83. // locate the end of the first (tag) field
  84. if( (s= strchr(buf,'\t')) == NULL )
  85. return _cmTfSyntaxErr(p,fn,line,"No tag label was found.");
  86. // zero terminate and copy construct the tag field into r.label
  87. *s = 0;
  88. r.label = cmLhAllocStr( p->lH, buf );
  89. buf = s + 1; // buf now points to the file name
  90. if( (s = strchr(buf,'\t')) == NULL )
  91. return _cmTfSyntaxErr(p,fn,line,"No file name field found.");
  92. buf = s + 1; // buf now points to the 'EX" field
  93. if( (s = strchr(buf,'\t')) == NULL )
  94. return _cmTfSyntaxErr(p,fn,line,"No 'EX' field found.");
  95. buf = s + 1; // buf now points to the 'kind' field
  96. //
  97. // Use: 'ctags --list-kinds=c' to list all of the 'kind' character flags.
  98. //
  99. switch( *buf )
  100. {
  101. case 'd': // macro
  102. r.flags |= kMacroTfFl;
  103. break;
  104. case 'e': // enum value
  105. r.flags |= kEnumTfFl;
  106. break;
  107. case 'p': // function prototype
  108. r.flags |= kFuncProtoTfFl;
  109. break;
  110. case 'f': // function defn
  111. r.flags |= kFuncDefnTfFl;
  112. break;
  113. case 't': // typedef
  114. r.flags |= kTypedefTfFl;
  115. break;
  116. case 'm': // member
  117. r.flags |= kFieldTfFl;
  118. break;
  119. case 'x': // externs and forward decl's
  120. r.flags |= kExternTfFl;
  121. break;
  122. case 's': // struct tag
  123. r.flags |= kStructTagTfFl;
  124. break;
  125. case 'u': // union tag
  126. r.flags |= kUnionTagTfFl;
  127. break;
  128. default: // unrecognized type
  129. return rc;
  130. }
  131. if( (s = strchr(buf,'\t')) == NULL )
  132. return _cmTfSyntaxErr(p,fn,line,"No 'kind' field found.");
  133. buf = s + 1; // buf now points to the 'line' field
  134. //
  135. if( strncmp(buf,lineLabel,lineLabelCharCnt) != 0 )
  136. return _cmTfSyntaxErr(p,fn,line,"No 'line' field found.");
  137. buf += lineLabelCharCnt; // buf now points to the number part of the line field
  138. // parse the line number
  139. if( sscanf(buf,"%i",&r.line) != 1 )
  140. return _cmTfSyntaxErr(p,fn,line,"Line number parse failed.");
  141. // store the tag record
  142. p->tagArray[ p->tagCnt ] = r;
  143. ++p->tagCnt;
  144. return rc;
  145. }
  146. cmTfRC_t cmTfOpenFile( cmCtx_t* ctx, cmTfH_t* hp, const cmChar_t* fn )
  147. {
  148. cmTfRC_t rc = kOkTfRC;
  149. cmTf_t* p = cmMemAllocZ(cmTf_t,1);
  150. cmChar_t* bufPtr = NULL;
  151. unsigned lineCnt = 0;
  152. cmErrSetup(&p->err,&ctx->rpt,"Tag File");
  153. // create the internal linked heap
  154. if( cmLHeapIsValid(p->lH = cmLHeapCreate(8192,ctx)) == false )
  155. {
  156. rc = cmErrMsg(&p->err,kLHeapFailTfRC,"The internal link heap create failed.");
  157. goto errLabel;
  158. }
  159. // open the file
  160. if( cmFileOpen( &p->fH, fn, kReadFileFl, &ctx->rpt ) != kOkFileRC )
  161. {
  162. rc = cmErrMsg(&p->err,kFileFailTfRC,"The tag file '%s' could not be opened.",cmStringNullGuard(fn));
  163. goto errLabel;
  164. }
  165. // get a count of the lines in the file
  166. if( cmFileLineCount( p->fH, &p->tagAllocCnt ) != kOkFileRC || p->tagAllocCnt == 0 )
  167. {
  168. rc = cmErrMsg(&p->err,kFileInvalidTfRC,"The tag file '%s' was invalid or empty.",cmStringNullGuard(fn));
  169. goto errLabel;
  170. }
  171. // allocate the tag array
  172. p->tagArray = cmLhAllocZ(p->lH,cmTfTag_t,p->tagAllocCnt);
  173. while( 1 )
  174. {
  175. unsigned bufByteCnt = 0;
  176. cmFileRC_t frc;
  177. // read a line from the file
  178. if((frc = cmFileGetLineAuto(p->fH, &bufPtr, &bufByteCnt )) != kOkFileRC )
  179. {
  180. if( cmFileEof(p->fH)==false )
  181. rc = cmErrMsg(&p->err,kFileFailTfRC,"File read failed on tag line:%i in '%s'\n",lineCnt+1,cmStringNullGuard(fn));
  182. break;
  183. }
  184. // parse a file line
  185. if((rc = _cmTfParseLine(p,fn,lineCnt+1,bufPtr,bufByteCnt)) != kOkTfRC )
  186. break;
  187. ++lineCnt;
  188. }
  189. cmMemFree(bufPtr);
  190. hp->h = p;
  191. errLabel:
  192. if( rc != kOkTfRC )
  193. _cmTfCloseFile(p);
  194. return rc;
  195. }
  196. cmTfRC_t cmTfCloseFile( cmTfH_t* hp )
  197. {
  198. cmTfRC_t rc = kOkTfRC;
  199. if( hp == NULL || cmTfIsValid(*hp) == false )
  200. return kOkTfRC;
  201. cmTf_t* p = _cmTfHandleToPtr(*hp);
  202. if((rc = _cmTfCloseFile(p)) != kOkTfRC )
  203. return rc;
  204. hp->h = NULL;
  205. return rc;
  206. }
  207. bool cmTfIsValid( cmTfH_t h )
  208. { return h.h != NULL; }
  209. unsigned cmTfCount( cmTfH_t h )
  210. {
  211. cmTf_t* p = _cmTfHandleToPtr(h);
  212. return p->tagCnt;
  213. }
  214. const cmTfTag_t* cmTfRecd( cmTfH_t h, unsigned index )
  215. {
  216. cmTf_t* p = _cmTfHandleToPtr(h);
  217. assert( index < p->tagCnt );
  218. return p->tagArray + index;
  219. }
  220. cmTfRC_t cmTfReport( cmTfH_t h, cmRpt_t* rpt )
  221. {
  222. unsigned i;
  223. cmTf_t* p = _cmTfHandleToPtr(h);
  224. for(i=0; i<p->tagCnt; ++i)
  225. {
  226. cmRptPrintf(rpt,"%5i ",i);
  227. _cmTfPrintTag(rpt, p->tagArray + i );
  228. }
  229. return kOkTfRC;
  230. }
  231. cmTfRC_t cmTfTest( cmCtx_t* ctx, const cmChar_t* fn )
  232. {
  233. cmTfRC_t rc = kOkTfRC;
  234. cmTfH_t h = cmTfNullHandle;
  235. if((rc = cmTfOpenFile(ctx,&h,fn)) == kOkTfRC )
  236. {
  237. cmTfReport(h,&ctx->rpt);
  238. rc = cmTfCloseFile(&h);
  239. }
  240. return rc;
  241. }