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.

cmLib.c 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  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 "cmFileSys.h"
  12. #include "cmLib.h"
  13. #include "cmText.h"
  14. #ifndef NDEF
  15. #include <dlfcn.h>
  16. typedef void* _libH_t;
  17. bool _cmLibIsNull( _libH_t lh )
  18. { return lh == NULL; };
  19. const cmChar_t* _cmLibSysError()
  20. {
  21. const char* msg = dlerror();
  22. if( msg == NULL )
  23. msg = "<none>";
  24. return msg;
  25. }
  26. _libH_t _cmLibOpen( const char* libFn )
  27. { return dlopen(libFn,RTLD_LAZY); }
  28. bool _cmLibClose( _libH_t* lH )
  29. {
  30. if( *lH != NULL )
  31. {
  32. if( dlclose(*lH) == 0 )
  33. *lH = NULL;
  34. else
  35. return false;
  36. }
  37. return true;
  38. }
  39. void* _cmLibSym( _libH_t h, const char* symLabel )
  40. { return dlsym(h,symLabel); }
  41. #endif
  42. typedef struct cmLibNode_str
  43. {
  44. cmChar_t* fn;
  45. unsigned id;
  46. _libH_t lH;
  47. struct cmLibNode_str* link;
  48. } cmLibNode_t;
  49. typedef struct
  50. {
  51. cmErr_t err;
  52. cmLibNode_t* nodes;
  53. unsigned id;
  54. cmFileSysH_t fsH;
  55. } cmLib_t;
  56. cmLib_t* _cmLibHandleToPtr( cmLibH_t h )
  57. {
  58. cmLib_t* p = (cmLib_t*)h.h;
  59. return p;
  60. }
  61. cmLibH_t cmLibNullHandle = cmSTATIC_NULL_HANDLE;
  62. cmLibRC_t _cmLibNodeFree( cmLib_t* p, cmLibNode_t* np )
  63. {
  64. if( !_cmLibClose( &np->lH ) )
  65. return cmErrMsg(&p->err,kCloseFailLibRC,"Library close failed. System Message: %s", _cmLibSysError());
  66. // free np->fn and set np->fn to NULL - so the node may be reused.
  67. cmMemPtrFree(&np->fn);
  68. np->id = cmInvalidId;
  69. return kOkLibRC;
  70. }
  71. cmLibRC_t _cmLibFinalize( cmLib_t* p )
  72. {
  73. cmLibNode_t* np = p->nodes;
  74. while( np != NULL )
  75. {
  76. cmLibNode_t* pp = np->link;
  77. _cmLibNodeFree(p,np);
  78. cmMemFree(np);
  79. np = pp;
  80. }
  81. if( cmFileSysIsValid(p->fsH) )
  82. cmFileSysFinalize(&p->fsH);
  83. cmMemFree(p);
  84. return kOkLibRC;
  85. }
  86. cmLibRC_t cmLibInitialize( cmCtx_t* ctx, cmLibH_t* hp, const cmChar_t* dirStr )
  87. {
  88. cmLibRC_t rc = kOkLibRC;
  89. cmLib_t* p = cmMemAllocZ(cmLib_t,1);
  90. cmErrSetup(&p->err,&ctx->rpt,"cmLib");
  91. cmFileSysInitialize(&p->fsH,ctx,"cmLibFs");
  92. hp->h = p;
  93. if( cmTextIsNotEmpty(dirStr) )
  94. if((rc = cmLibScan(*hp,dirStr)) != kOkLibRC )
  95. hp->h = NULL;
  96. if( rc != kOkLibRC )
  97. _cmLibFinalize(p);
  98. return rc;
  99. }
  100. cmLibRC_t cmLibFinalize( cmLibH_t* hp )
  101. {
  102. cmLibRC_t rc;
  103. if( hp == NULL || hp->h == NULL )
  104. return kOkLibRC;
  105. cmLib_t* p = _cmLibHandleToPtr(*hp);
  106. if((rc = _cmLibFinalize(p)) == kOkLibRC )
  107. hp->h = NULL;
  108. return rc;
  109. }
  110. bool cmLibIsValid( cmLibH_t h )
  111. { return h.h != NULL; }
  112. unsigned cmLibOpen( cmLibH_t h, const cmChar_t* libFn )
  113. {
  114. cmLib_t* p = _cmLibHandleToPtr(h);
  115. _libH_t lH = _cmLibOpen(libFn);
  116. cmLibNode_t* np = p->nodes;
  117. unsigned idx = 0;
  118. if( _cmLibIsNull(lH) )
  119. {
  120. // There is apparently no way to get an error code which indicates that the
  121. // file load attempt failed because the file was not a shared library -
  122. // which should not generate an error message - therefore
  123. // we must match the end of the the error string returned by dlerror() with
  124. // 'invalid ELF header'.
  125. const char* errMsg = _cmLibSysError();
  126. const char* s = "invalid ELF header";
  127. unsigned sn = strlen(s);
  128. unsigned mn = strlen(errMsg);
  129. if( errMsg!=NULL && mn>sn && strcmp(errMsg+mn-sn,s)==0 )
  130. cmErrSetRC(&p->err,kOpenFailLibRC ); // signal error but no error message
  131. else
  132. cmErrMsg(&p->err,kOpenFailLibRC,"Library load failed. System Message: %s", errMsg );
  133. return cmInvalidId;
  134. }
  135. while( np != NULL )
  136. {
  137. if( np->fn == NULL )
  138. break;
  139. np = np->link;
  140. ++idx;
  141. }
  142. if( np == NULL )
  143. {
  144. np = cmMemAllocZ(cmLibNode_t,1);
  145. np->link = p->nodes;
  146. p->nodes = np;
  147. }
  148. np->fn = cmMemAllocStr(libFn);
  149. np->lH = lH;
  150. np->id = p->id++;
  151. return idx;
  152. }
  153. cmLibNode_t* _cmLibIdToNode( cmLib_t* p, unsigned libId )
  154. {
  155. cmLibNode_t* np = p->nodes;
  156. while( np != NULL )
  157. {
  158. if( np->id == libId )
  159. return np;
  160. np = np->link;
  161. }
  162. return NULL;
  163. }
  164. cmLibRC_t cmLibClose( cmLibH_t h, unsigned libId )
  165. {
  166. cmLib_t* p = _cmLibHandleToPtr(h);
  167. cmLibNode_t* np = _cmLibIdToNode(p,libId);
  168. if( (np == NULL) || _cmLibIsNull(np->lH) )
  169. return cmErrMsg(&p->err,kInvalidIdLibRC,"The library id %i is not valid or the library is closed.",libId);
  170. return kOkLibRC;
  171. }
  172. void* cmLibSym( cmLibH_t h, unsigned libId, const cmChar_t* funcStr )
  173. {
  174. void* f;
  175. cmLib_t* p = _cmLibHandleToPtr(h);
  176. cmLibNode_t* np = _cmLibIdToNode(p,libId);
  177. if( (np == NULL) || _cmLibIsNull(np->lH) )
  178. {
  179. cmErrMsg(&p->err,kInvalidIdLibRC,"The library id %i is not valid or the library is closed.",libId);
  180. return NULL;
  181. }
  182. if((f = _cmLibSym(np->lH,funcStr)) == NULL)
  183. {
  184. cmErrMsg(&p->err,kSymFailLibRC,"The dynamic symbol '%s' was not found. System Message: %s", cmStringNullGuard(funcStr), _cmLibSysError());
  185. return NULL;
  186. }
  187. return f;
  188. }
  189. cmLibRC_t cmLibScan( cmLibH_t h, const cmChar_t* dirStr )
  190. {
  191. cmLib_t* p = _cmLibHandleToPtr(h);
  192. unsigned dirEntryCnt = 0;
  193. cmFileSysDirEntry_t* d = NULL;
  194. cmLibRC_t rc = kOkLibRC;
  195. unsigned i = 0;
  196. if( cmFileSysIsValid(p->fsH) == false )
  197. return cmErrMsg(&p->err,kFileSysFailLibRC,"The file system object was not successfully initialized.");
  198. if((d = cmFileSysDirEntries(p->fsH, dirStr, kFileFsFl | kFullPathFsFl, &dirEntryCnt )) == NULL )
  199. return cmErrMsg(&p->err,kFileSysFailLibRC,"The scan of directory '%s' failed.",cmStringNullGuard(dirStr));
  200. for(i=0; i<dirEntryCnt; ++i)
  201. cmLibOpen(h,d[i].name);
  202. cmFileSysDirFreeEntries(p->fsH,d);
  203. return rc;
  204. }
  205. unsigned cmLibCount( cmLibH_t h )
  206. {
  207. cmLib_t* p = _cmLibHandleToPtr(h);
  208. cmLibNode_t* np = p->nodes;
  209. unsigned n = 0;
  210. while( np != NULL )
  211. {
  212. np = np->link;
  213. ++n;
  214. }
  215. return n;
  216. }
  217. unsigned cmLibIndexToId( cmLibH_t h, unsigned idx )
  218. {
  219. cmLib_t* p = _cmLibHandleToPtr(h);
  220. cmLibNode_t* np = p->nodes;
  221. unsigned i = 0;
  222. while( np != NULL )
  223. {
  224. if( i == idx )
  225. return np->id;
  226. np = np->link;
  227. ++i;
  228. }
  229. if(np == NULL )
  230. {
  231. cmErrMsg(&p->err,kInvalidIdLibRC,"The library index %i is not valid.",idx);
  232. return cmInvalidId;
  233. }
  234. return np->id;
  235. }
  236. const cmChar_t* cmLibName( cmLibH_t h, unsigned libId )
  237. {
  238. cmLib_t* p = _cmLibHandleToPtr(h);
  239. cmLibNode_t* np = _cmLibIdToNode(p,libId);
  240. if( (np == NULL) || _cmLibIsNull(np->lH) )
  241. {
  242. cmErrMsg(&p->err,kInvalidIdLibRC,"The library id %i is not valid or the library is closed.",libId);
  243. return NULL;
  244. }
  245. return np->fn;
  246. }