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.

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