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.9KB

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