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.

cmFileSys.c 37KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542
  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 "cmFileSys.h"
  10. #include "cmText.h"
  11. #include <sys/stat.h>
  12. #include <errno.h>
  13. #include <libgen.h> // basename(), dirname()
  14. #include <dirent.h> // opendir()/readdir()
  15. #include <limits.h> // PATH_MAX
  16. #include <sys/types.h> // mkdir
  17. #ifdef OS_OSX
  18. #include "osx/cmFileSysOsx.h"
  19. #endif
  20. #ifdef OS_LINUX
  21. #include "linux/cmFileSysLinux.h"
  22. #endif
  23. cmFileSysH_t cmFileSysNullHandle = {NULL};
  24. typedef struct
  25. {
  26. cmErr_t err;
  27. cmLHeapH_t heapH;
  28. const cmChar_t* appNameStr;
  29. #ifdef OS_OSX
  30. _cmFsOsx_t* p;
  31. cmChar_t* prefDir;
  32. #endif
  33. #ifdef OS_LINUX
  34. _cmFsLinux_t* p;
  35. #endif
  36. } cmFs_t;
  37. cmFsRC_t _cmFileSysError( cmFs_t* p, cmFsRC_t rc, int sysErr, const cmChar_t* fmt, ... )
  38. {
  39. va_list vl;
  40. va_start(vl,fmt);
  41. if( sysErr == 0 )
  42. rc = cmErrVMsg(&p->err,rc,fmt,vl);
  43. else
  44. {
  45. const unsigned bufCharCnt = 511;
  46. cmChar_t buf[bufCharCnt+1];
  47. vsnprintf(buf,bufCharCnt,fmt,vl);
  48. rc = cmErrMsg(&p->err,rc,"%s\nSystem Msg:%s",buf,strerror(sysErr));
  49. }
  50. va_end(vl);
  51. return rc;
  52. }
  53. cmFs_t* _cmFileSysHandleToPtr( cmFileSysH_t h )
  54. {
  55. cmFs_t* p = (cmFs_t*)h.h;
  56. assert( p != NULL);
  57. return p;
  58. }
  59. cmFsRC_t _cmFileSysFinalize( cmFs_t* p )
  60. {
  61. cmFsRC_t rc = kOkFsRC;
  62. if( cmLHeapIsValid(p->heapH) )
  63. cmLHeapDestroy(&p->heapH);
  64. #ifdef OS_OSX
  65. if( p->p != NULL )
  66. if((rc = _cmOsxFileSysFinalize(p->p) ) != kOkFsRC )
  67. {
  68. _cmFileSysError(p,kOsxFailFsRC,0,"The OSX file system finalization failed.");
  69. return rc;
  70. }
  71. #endif
  72. #ifdef OS_LINUX
  73. if( p->p != NULL )
  74. if((rc = _cmLinuxFileSysFinalize(p->p) ) != kOkFsRC )
  75. {
  76. _cmFileSysError(p,kLinuxFailFsRC,0,"The Linux file system finalization failed.");
  77. return rc;
  78. }
  79. #endif
  80. cmMemPtrFree(&p);
  81. return rc;
  82. }
  83. cmFsRC_t cmFileSysInitialize( cmFileSysH_t* hp, cmCtx_t* ctx, const cmChar_t* appNameStr )
  84. {
  85. cmFs_t* p;
  86. cmFsRC_t rc;
  87. cmErr_t err;
  88. if((rc = cmFileSysFinalize(hp)) != kOkFsRC )
  89. return rc;
  90. cmErrSetup(&err,&ctx->rpt,"File System");
  91. if((p = cmMemAllocZ( cmFs_t, 1 )) == NULL )
  92. return cmErrMsg(&err,kMemAllocErrFsRC,"Unable to allocate the file system object.");
  93. cmErrClone(&p->err,&err);
  94. if(cmLHeapIsValid( p->heapH = cmLHeapCreate(1024,ctx)) == false )
  95. {
  96. rc = _cmFileSysError(p,kLHeapAllocErrFsRC,0,"Unable to allocate the linked heap.");
  97. goto errLabel;
  98. }
  99. p->appNameStr = cmLhAllocStr(p->heapH,appNameStr);
  100. hp->h = p;
  101. #ifdef OS_OSX
  102. if( (rc = _cmOsxFileSysInit(&p->p, p->heapH, &p->err)) != kOkFsRC )
  103. {
  104. rc = _cmFileSysError(p,kOsxFailFsRC,0,"OSX file system initialization failed.");
  105. goto errLabel;
  106. }
  107. const cmChar_t* dir = cmFsMakeFn(p->p->prefDir,appNameStr,NULL,NULL);
  108. // BUG?
  109. // we reuse p->p->prefDir here because the one returned by the platform
  110. // specific code is never released ... which isn't quite right either
  111. // See osx/cmFileSysOsx.c.
  112. p->p->prefDir = cmLhAllocStr(p->heapH,dir);
  113. cmFsFreeFn(dir);
  114. #endif
  115. #ifdef OS_LINUX
  116. if( (rc = _cmLinuxFileSysInit(&p->p, p->heapH, &p->err)) != kOkFsRC )
  117. {
  118. rc = _cmFileSysError(p,kLinuxFailFsRC,0,"Linux file system initialization failed.");
  119. goto errLabel;
  120. }
  121. else
  122. {
  123. #endif
  124. #ifdef OS_LINUX
  125. cmChar_t hidAppNameStr[ strlen(appNameStr) + 2 ];
  126. strcpy(hidAppNameStr,".");
  127. strcat(hidAppNameStr,appNameStr);
  128. p->p->prefDir = cmFileSysMakeFn( *hp, p->p->prefDir, hidAppNameStr, NULL, NULL );
  129. // the resource directory must exist before the program can start
  130. p->p->rsrcDir = cmFileSysMakeFn( *hp, p->p->rsrcDir, appNameStr, NULL, NULL );
  131. }
  132. #endif
  133. errLabel:
  134. if( rc != kOkFsRC )
  135. return _cmFileSysFinalize(p);
  136. return kOkFsRC;
  137. }
  138. cmFsRC_t cmFileSysFinalize( cmFileSysH_t* hp )
  139. {
  140. cmFsRC_t rc;
  141. if( hp==NULL || cmFileSysIsValid(*hp) == false )
  142. return kOkFsRC;
  143. cmFs_t* p = _cmFileSysHandleToPtr(*hp);
  144. if((rc = _cmFileSysFinalize(p)) != kOkFsRC )
  145. return rc;
  146. hp->h = NULL;
  147. return rc;
  148. }
  149. const cmChar_t* cmFileSysAppName( cmFileSysH_t h )
  150. {
  151. cmFs_t* p = _cmFileSysHandleToPtr(h);
  152. return p->appNameStr;
  153. }
  154. const cmChar_t* cmFileSysPrefsDir( cmFileSysH_t h )
  155. {
  156. cmFs_t* p = _cmFileSysHandleToPtr(h);
  157. #if defined OS_OSX || defined OS_LINUX
  158. return p->p->prefDir;
  159. #else
  160. return NULL;
  161. #endif
  162. }
  163. const cmChar_t* cmFileSysRsrcDir( cmFileSysH_t h )
  164. {
  165. cmFs_t* p = _cmFileSysHandleToPtr(h);
  166. #if defined OS_OSX || defined OS_LINUX
  167. return p->p->rsrcDir;
  168. #else
  169. return NULL;
  170. #endif
  171. }
  172. const cmChar_t* cmFileSysUserDir( cmFileSysH_t h )
  173. {
  174. cmFs_t* p = _cmFileSysHandleToPtr(h);
  175. #if defined OS_OSX || defined OS_LINUX
  176. return p->p->userDir;
  177. #else
  178. return NULL;
  179. #endif
  180. }
  181. bool cmFileSysIsValid( cmFileSysH_t h )
  182. { return h.h != NULL; }
  183. bool _cmFileSysIsDir( cmFs_t* p, const cmChar_t* dirStr )
  184. {
  185. struct stat s;
  186. errno = 0;
  187. if( stat(dirStr,&s) != 0 )
  188. {
  189. // if the dir does not exist
  190. if( errno == ENOENT )
  191. return false;
  192. _cmFileSysError( p, kStatFailFsRC, errno, "'stat' failed on '%s'",dirStr);
  193. return false;
  194. }
  195. return S_ISDIR(s.st_mode);
  196. }
  197. bool cmFileSysCanWriteToDir( cmFileSysH_t h, const cmChar_t* dirStr )
  198. {
  199. cmFs_t* p = _cmFileSysHandleToPtr(h);
  200. int result;
  201. errno = 0;
  202. if((result = access(dirStr,W_OK)) == 0 )
  203. return true;
  204. if( result == EACCES || result==EROFS )
  205. return false;
  206. _cmFileSysError( p, kAccessFailFsRC, errno, "'access' failed on '%s'.",dirStr);
  207. return false;
  208. }
  209. bool cmFileSysIsDir( cmFileSysH_t h, const cmChar_t* dirStr )
  210. {
  211. cmFs_t* p = _cmFileSysHandleToPtr(h);
  212. return _cmFileSysIsDir(p,dirStr);
  213. }
  214. bool _cmFileSysIsFile( cmFs_t* p, const cmChar_t* fnStr )
  215. {
  216. struct stat s;
  217. errno = 0;
  218. if( stat(fnStr,&s) != 0 )
  219. {
  220. // if the file does not exist
  221. if( errno == ENOENT )
  222. return false;
  223. _cmFileSysError( p, kStatFailFsRC, errno, "'stat' failed on '%s'.",fnStr);
  224. return false;
  225. }
  226. return S_ISREG(s.st_mode);
  227. }
  228. bool cmFileSysIsFile( cmFileSysH_t h, const cmChar_t* fnStr )
  229. {
  230. cmFs_t* p = _cmFileSysHandleToPtr(h);
  231. return _cmFileSysIsFile(p,fnStr);
  232. }
  233. bool _cmFileSysIsLink( cmFs_t* p, const cmChar_t* fnStr )
  234. {
  235. struct stat s;
  236. errno = 0;
  237. if( lstat(fnStr,&s) != 0 )
  238. {
  239. // if the file does not exist
  240. if( errno == ENOENT )
  241. return false;
  242. _cmFileSysError( p, kStatFailFsRC, errno, "'stat' failed on '%s'.",fnStr);
  243. return false;
  244. }
  245. return S_ISLNK(s.st_mode);
  246. }
  247. bool cmFileSysIsLink( cmFileSysH_t h, const cmChar_t* fnStr )
  248. {
  249. cmFs_t* p = _cmFileSysHandleToPtr(h);
  250. return _cmFileSysIsLink(p,fnStr);
  251. }
  252. bool _cmFileSysIsSocket( cmFs_t* p, const cmChar_t* fnStr )
  253. {
  254. struct stat s;
  255. errno = 0;
  256. if( stat(fnStr,&s) != 0 )
  257. {
  258. // if the file does not exist
  259. if( errno == ENOENT )
  260. return false;
  261. _cmFileSysError( p, kStatFailFsRC, errno, "'stat' failed on '%s'.",fnStr);
  262. return false;
  263. }
  264. return S_ISSOCK(s.st_mode);
  265. }
  266. bool _cmFileSysConcat( cmChar_t* rp, unsigned rn, char sepChar, const cmChar_t* suffixStr )
  267. {
  268. unsigned m = strlen(rp);
  269. // m==0 if no sep needs to be inserted or removed
  270. //if( m == 0 )
  271. // return false;
  272. if( m != 0 )
  273. {
  274. // if a sep char needs to be inserted
  275. if( rp[m-1] != sepChar && suffixStr[0] != sepChar )
  276. {
  277. assert((m+1)<rn);
  278. if((m+1)>=rn)
  279. return false;
  280. rp[m] = sepChar;
  281. rp[m+1]= 0;
  282. ++m;
  283. }
  284. else
  285. // if a sep char needs to be removed
  286. if( rp[m-1] == sepChar && suffixStr[0] == sepChar )
  287. {
  288. rp[m-1] = 0;
  289. --m;
  290. }
  291. }
  292. assert( rn>=m && strlen(rp)+strlen(suffixStr) <= rn );
  293. strncat(rp,suffixStr,rn-m);
  294. return true;
  295. }
  296. const cmChar_t* cmFileSysVMakeFn( cmFileSysH_t h, const cmChar_t* dir, const cmChar_t* fn, const cmChar_t* ext, va_list vl )
  297. {
  298. cmFsRC_t rc = kOkFsRC;
  299. cmChar_t* rp = NULL;
  300. const cmChar_t* dp = NULL;
  301. unsigned n = 0;
  302. cmFs_t* p = _cmFileSysHandleToPtr(h);
  303. char pathSep = cmPathSeparatorChar[0];
  304. char extSep = '.';
  305. va_list vl_t;
  306. va_copy(vl_t,vl);
  307. // get prefix directory length
  308. if( dir != NULL )
  309. n += strlen(dir) + 1; // add 1 for ending sep
  310. // get file name length
  311. if( fn != NULL )
  312. n += strlen(fn);
  313. // get extension length
  314. if( ext != NULL )
  315. n += strlen(ext) + 1; // add 1 for period
  316. // get length of all var args dir's
  317. while( (dp = va_arg(vl,const cmChar_t*)) != NULL )
  318. n += strlen(dp) + 1; // add 1 for ending sep
  319. // add 1 for terminating zero and allocate memory
  320. if((rp = cmLHeapAllocZ( p->heapH, n+1 )) == NULL )
  321. {
  322. rc = _cmFileSysError(p,kMemAllocErrFsRC,0,"Unable to allocate file name memory.");
  323. goto errLabel;
  324. }
  325. va_copy(vl,vl_t);
  326. rp[n] = 0;
  327. rp[0] = 0;
  328. // copy out the prefix dir
  329. if( dir != NULL )
  330. strncat(rp,dir,n-strlen(rp));
  331. // copy out each of the var arg's directories
  332. while((dp = va_arg(vl,const cmChar_t*)) != NULL )
  333. if(!_cmFileSysConcat(rp,n,pathSep,dp) )
  334. {
  335. assert(0);
  336. rc = _cmFileSysError(p,kAssertFailFsRC,0,"Assert failed.");
  337. goto errLabel;
  338. }
  339. // copy out the file name
  340. if( fn != NULL )
  341. if(!_cmFileSysConcat(rp,n,pathSep,fn))
  342. {
  343. assert(0);
  344. rc = _cmFileSysError(p,kAssertFailFsRC,0,"Assert failed.");
  345. goto errLabel;
  346. }
  347. // copy out the extension
  348. if( ext != NULL )
  349. if(!_cmFileSysConcat(rp,n,extSep,ext))
  350. {
  351. assert(0);
  352. rc = _cmFileSysError(p,kAssertFailFsRC,0,"Assert failed.");
  353. goto errLabel;
  354. }
  355. assert(strlen(rp)<=n);
  356. errLabel:
  357. if( rc != kOkFsRC && rp != NULL )
  358. cmLHeapFree(p->heapH, rp );
  359. return rp;
  360. }
  361. const cmChar_t* cmFileSysVMakeUserFn( cmFileSysH_t h, const cmChar_t* dirPrefix, const cmChar_t* fn, const cmChar_t* ext, va_list vl )
  362. {
  363. return cmFileSysMakeFn(h,cmFileSysUserDir(h),fn,ext,dirPrefix,NULL);
  364. }
  365. const cmChar_t* cmFileSysMakeFn( cmFileSysH_t h, const cmChar_t* dir, const cmChar_t* fn, const cmChar_t* ext, ... )
  366. {
  367. va_list vl;
  368. va_start(vl,ext);
  369. const cmChar_t* retPtr = cmFileSysVMakeFn(h,dir,fn,ext,vl);
  370. va_end(vl);
  371. return retPtr;
  372. }
  373. const cmChar_t* cmFileSysMakeUserFn( cmFileSysH_t h, const cmChar_t* dir, const cmChar_t* fn, const cmChar_t* ext, ... )
  374. {
  375. va_list vl;
  376. va_start(vl,ext);
  377. const cmChar_t* retPtr = cmFileSysVMakeUserFn(h,dir,fn,ext,vl);
  378. va_end(vl);
  379. return retPtr;
  380. }
  381. const cmChar_t* cmFileSysVMakeDir( cmFileSysH_t h, const cmChar_t* dir, va_list vl )
  382. { return cmFileSysVMakeFn(h,dir,NULL,NULL,vl); }
  383. const cmChar_t* cmFileSysMakeDir( cmFileSysH_t h, const cmChar_t* dir, ... )
  384. {
  385. va_list vl;
  386. va_start(vl,dir);
  387. const cmChar_t* retPtr = cmFileSysVMakeFn(h,dir,NULL,NULL,vl);
  388. va_end(vl);
  389. return retPtr;
  390. }
  391. const cmChar_t* cmFileSysVMakeUserDir( cmFileSysH_t h, const cmChar_t* dir, va_list vl )
  392. { return cmFileSysVMakeUserFn(h,dir,NULL,NULL,vl); }
  393. const cmChar_t* cmFileSysMakeUserDir( cmFileSysH_t h, const cmChar_t* dir, ... )
  394. {
  395. va_list vl;
  396. va_start(vl,dir);
  397. const cmChar_t* retPtr = cmFileSysVMakeUserFn(h,dir,NULL,NULL,vl);
  398. va_end(vl);
  399. return retPtr;
  400. }
  401. const cmChar_t* cmFileSysMakeDirFn( cmFileSysH_t h, const cmChar_t* dir, const cmChar_t* fn )
  402. { return cmFileSysMakeFn( h, dir, fn, NULL, NULL); }
  403. const cmChar_t* cmFileSysMakeUserDirFn(cmFileSysH_t h, const cmChar_t* dir, const cmChar_t* fn )
  404. { return cmFileSysMakeUserFn(h, dir, fn, NULL, NULL ); }
  405. void cmFileSysFreeFn( cmFileSysH_t h, const cmChar_t* fn )
  406. {
  407. cmFs_t* p = _cmFileSysHandleToPtr(h);
  408. if( fn == NULL )
  409. return;
  410. cmLHeapFree(p->heapH, (void*)fn);
  411. }
  412. cmFsRC_t cmFileSysGenFn( cmFileSysH_t h, const cmChar_t* dir, const cmChar_t* prefixStr, const cmChar_t* extStr, const cmChar_t** fnPtr )
  413. {
  414. cmFsRC_t rc = kOkFsRC;
  415. cmFs_t* p = _cmFileSysHandleToPtr(h);
  416. unsigned maxAttemptCnt = 0xffff;
  417. *fnPtr = NULL;
  418. assert(dir != NULL);
  419. if( prefixStr == NULL )
  420. prefixStr = "";
  421. if( extStr == NULL )
  422. extStr = "";
  423. if( !cmFileSysIsDir(h,dir) )
  424. return cmErrMsg(&p->err,kOpenDirFailFsRC,"File name generation failed because the directory '%s' does not exist.",cmStringNullGuard(dir));
  425. unsigned i;
  426. for(i=0; *fnPtr==NULL; ++i)
  427. {
  428. cmChar_t* fn = cmTsPrintfP(NULL,"%s%i",prefixStr,i);
  429. const cmChar_t* path = cmFileSysMakeFn(h,dir,fn,extStr,NULL );
  430. if( !cmFileSysIsFile(h,path) )
  431. *fnPtr = cmMemAllocStr(path);
  432. cmFileSysFreeFn(h,path);
  433. cmMemFree(fn);
  434. if( i == maxAttemptCnt )
  435. return cmErrMsg(&p->err,kGenFileFailFsRC,"File name generation failed because a suitable file name could not be found after %i attempts.",maxAttemptCnt);
  436. };
  437. return rc;
  438. }
  439. cmFsRC_t cmFileSysMkDir( cmFileSysH_t h, const cmChar_t* dir )
  440. {
  441. cmFs_t* p = _cmFileSysHandleToPtr(h);
  442. if( mkdir(dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0 )
  443. return _cmFileSysError( p, kMkDirFailFsRC, errno, "The attempt to create the directory '%s' failed.",dir);
  444. return kOkFsRC;
  445. }
  446. cmFsRC_t cmFileSysMkUserDir( cmFileSysH_t h, const cmChar_t* dir0 )
  447. {
  448. const cmChar_t* dir = cmFileSysMakeUserFn(h,dir0,NULL,NULL,NULL);
  449. if( dir == NULL )
  450. return _cmFileSysError(_cmFileSysHandleToPtr(h),kFormFnFailFsRC,0, "The specified directory string /<user>/%s could not be formed.",cmStringNullGuard(dir0));
  451. cmFsRC_t rc = cmFileSysMkDir(h,dir);
  452. cmFileSysFreeFn(h,dir);
  453. return rc;
  454. }
  455. cmFsRC_t cmFileSysMkDirAll( cmFileSysH_t h, const cmChar_t* dir )
  456. {
  457. cmFsRC_t rc = kOkFsRC;
  458. cmFs_t* p = _cmFileSysHandleToPtr(h);
  459. cmChar_t** a = NULL;
  460. unsigned i;
  461. if((a = cmFileSysDirParts(h,dir)) == NULL )
  462. return _cmFileSysError(p, kInvalidDirFsRC, 0, "The directory '%s' could not be parsed.",cmStringNullGuard(dir));
  463. for(i=0; rc==kOkFsRC && a[i]!=NULL; ++i)
  464. {
  465. cmChar_t* d = cmFileSysFormDir(h,a,i+1);
  466. if( cmFileSysIsDir(h,d)==false )
  467. if((rc = cmFileSysMkDir(h,d)) != kOkFsRC )
  468. break;
  469. cmFileSysFreeDir(h,d);
  470. }
  471. cmFileSysFreeDirParts(h,a);
  472. return rc;
  473. }
  474. cmFsRC_t cmFileSysMkUserDirAll( cmFileSysH_t h, const cmChar_t* dir0 )
  475. {
  476. const cmChar_t* dir = cmFileSysMakeUserFn(h,dir0,NULL,NULL,NULL);
  477. if( dir == NULL )
  478. return _cmFileSysError(_cmFileSysHandleToPtr(h),kFormFnFailFsRC,0,"The specified directory string /<user>/%s could not be formed.",cmStringNullGuard(dir0));
  479. cmFsRC_t rc = cmFileSysMkDirAll(h,dir);
  480. cmFileSysFreeFn(h,dir);
  481. return rc;
  482. }
  483. cmFileSysPathPart_t* cmFileSysPathParts( cmFileSysH_t h, const cmChar_t* pathStr )
  484. {
  485. int n = 0; // char's in pathStr
  486. int dn = 0; // char's in the dir part
  487. int fn = 0; // char's in the name part
  488. int en = 0; // char's in the ext part
  489. cmChar_t* cp = NULL;
  490. cmFileSysPathPart_t* rp = NULL;
  491. cmFs_t* p = _cmFileSysHandleToPtr(h);
  492. if( pathStr==NULL )
  493. return NULL;
  494. // skip leading white space
  495. while( *pathStr )
  496. {
  497. if( isspace(*pathStr ) )
  498. ++pathStr;
  499. else
  500. break;
  501. }
  502. // get the length of pathStr
  503. if((n = strlen(pathStr)) == 0 )
  504. return NULL;
  505. // remove trailing spaces
  506. for(; n>0; --n)
  507. {
  508. if( isspace(pathStr[n-1]) )
  509. --n;
  510. else
  511. break;
  512. }
  513. //
  514. if( n == 0 )
  515. return NULL;
  516. char buf[n+1];
  517. buf[n] = 0;
  518. // Get the last word (which may be a file name) from pathStr.
  519. // (pathStr must be copied into a buf because basename()
  520. // is allowed to change the values in its arg.)
  521. strncpy(buf,pathStr,n);
  522. cp = basename(buf);
  523. if( cp != NULL )
  524. {
  525. cmChar_t* ep;
  526. // does the last word have a period in it
  527. if( (ep = strchr(cp,'.')) != NULL )
  528. {
  529. *ep = 0; // end the file name at the period
  530. ++ep; // set the ext marker
  531. en = strlen(ep); // get the length of the ext
  532. }
  533. fn = strlen(cp); //get the length of the file name
  534. }
  535. // Get the directory part.
  536. // ( pathStr must be copied into a buf because dirname()
  537. // is allowed to change the values in its arg.)
  538. strncpy(buf,pathStr,n);
  539. // if the last char in pathStr[] is '/' then the whole string is a dir.
  540. // (this is not the answer that dirname() and basename() would give).
  541. if( pathStr[n-1] == cmPathSeparatorChar[0] )
  542. {
  543. fn = 0;
  544. en = 0;
  545. dn = n;
  546. cp = buf;
  547. }
  548. else
  549. {
  550. cp = dirname(buf);
  551. }
  552. if( cp != NULL )
  553. dn = strlen(cp);
  554. // get the total size of the returned memory. (add 3 for ecmh possible terminating zero)
  555. n = sizeof(cmFileSysPathPart_t) + dn + fn + en + 3;
  556. // alloc memory
  557. if((rp = (cmFileSysPathPart_t*)cmLHeapAllocZ( p->heapH, n )) == NULL )
  558. {
  559. _cmFileSysError( p, kLHeapAllocErrFsRC, 0, "Unable to allocate the file system path part record for '%s'.",pathStr);
  560. return NULL;
  561. }
  562. // set the return pointers for ecmh of the parts
  563. rp->dirStr = (const cmChar_t* )(rp + 1);
  564. rp->fnStr = rp->dirStr + dn + 1;
  565. rp->extStr = rp->fnStr + fn + 1;
  566. // if there is a directory part
  567. if( dn>0 )
  568. strcpy((cmChar_t*)rp->dirStr,cp);
  569. else
  570. rp->dirStr = NULL;
  571. if( fn || en )
  572. {
  573. // Get the trailing word again.
  574. // pathStr must be copied into a buf because basename() may
  575. // is allowed to change the values in its arg.
  576. strncpy(buf,pathStr,n);
  577. cp = basename(buf);
  578. if( cp != NULL )
  579. {
  580. cmChar_t* ep;
  581. if( (ep = strchr(cp,'.')) != NULL )
  582. {
  583. *ep = 0;
  584. ++ep;
  585. assert( strlen(ep) == en );
  586. strcpy((cmChar_t*)rp->extStr,ep);
  587. }
  588. assert( strlen(cp) == fn );
  589. if(fn)
  590. strcpy((cmChar_t*)rp->fnStr,cp);
  591. }
  592. }
  593. if( fn == 0 )
  594. rp->fnStr = NULL;
  595. if( en == 0 )
  596. rp->extStr = NULL;
  597. return rp;
  598. }
  599. void cmFileSysFreePathParts( cmFileSysH_t h, cmFileSysPathPart_t* pp )
  600. {
  601. if( pp == NULL )
  602. return;
  603. cmFs_t* p = _cmFileSysHandleToPtr(h);
  604. cmLHeapFree(p->heapH, (void*)pp );
  605. }
  606. cmChar_t** cmFileSysDirParts( cmFileSysH_t h, const cmChar_t* dirStr )
  607. {
  608. cmFs_t* p = _cmFileSysHandleToPtr(h);
  609. const cmChar_t* s = dirStr;
  610. const cmChar_t* ep = dirStr + strlen(dirStr);
  611. char pathSep = cmPathSeparatorChar[0];
  612. unsigned n = 2;
  613. unsigned i = 0;
  614. // skip leading white space or pathsep
  615. while( isspace(*s) && s < ep )
  616. ++s;
  617. // if the directory string is empty
  618. if( s >= ep )
  619. return NULL;
  620. // set the beginning of the input dirStr past any leading white space
  621. dirStr = s;
  622. // count the number of dir segments - this might overcount the
  623. // number of segments if there are multiple repeated path seperator
  624. // char's - but this is ok because 'n' is only used to determine
  625. // the size of the returned array - which will simply have some
  626. // NULL entries at the end.
  627. for(; s < ep; ++s )
  628. if( *s == pathSep )
  629. ++n;
  630. // allocate the array
  631. cmChar_t** a = cmLhAllocZ(p->heapH,cmChar_t*,n);
  632. // reset the cur location to the begin of the buf
  633. s = dirStr;
  634. // if the path starts at the root
  635. if( *s == pathSep )
  636. {
  637. a[0] = cmPathSeparatorChar; // cmPathSeparatorChar is a static string in cmGlobal.h
  638. i = 1;
  639. ++s;
  640. }
  641. for(; i<n && s<ep; ++i)
  642. {
  643. const cmChar_t* s1;
  644. if(( s1 = strchr(s,pathSep)) == NULL )
  645. s1 = ep;
  646. if( s1!=s )
  647. {
  648. unsigned sn = (s1 - s)+1;
  649. a[i] = cmLhAlloc(p->heapH,cmChar_t,sn);
  650. strncpy(a[i],s,sn-1);
  651. a[i][sn-1] = 0;
  652. }
  653. s = s1+1;
  654. }
  655. return a;
  656. }
  657. void cmFileSysFreeDirParts( cmFileSysH_t h, cmChar_t** dirStrArray )
  658. {
  659. if( dirStrArray == NULL )
  660. return;
  661. cmFs_t* p = _cmFileSysHandleToPtr(h);
  662. unsigned i;
  663. for(i=0; dirStrArray[i]!=NULL; ++i)
  664. {
  665. // cmPathSeparatorChar is statically alloc'd in cmGlobal.h
  666. if( dirStrArray[i] != cmPathSeparatorChar )
  667. cmLHeapFree(p->heapH,dirStrArray[i]);
  668. }
  669. cmLHeapFree(p->heapH, (void*)dirStrArray );
  670. }
  671. unsigned cmFileSysDirPartsCount(cmFileSysH_t h, cmChar_t** dirStrArray )
  672. {
  673. unsigned i = 0;
  674. if( dirStrArray == NULL )
  675. return 0;
  676. while(dirStrArray[i] != NULL )
  677. ++i;
  678. return i;
  679. }
  680. cmChar_t* cmFileSysFormDir( cmFileSysH_t h, cmChar_t** a, unsigned m )
  681. {
  682. cmFs_t* p = _cmFileSysHandleToPtr(h);
  683. unsigned n;
  684. unsigned i;
  685. // determine the length of the return string
  686. for(i=0,n=0; a[i]!=NULL && i<m; ++i)
  687. n += strlen(a[i]) + strlen(cmPathSeparatorChar);
  688. if( i<m && a[i] == NULL )
  689. {
  690. _cmFileSysError(p,kInvalidDirFsRC,0,"cmFileSysFormDir() cannot form a directory string from %i parts when only %i exist.",m,i);
  691. return NULL;
  692. }
  693. n += 1;
  694. // allocate the return string
  695. cmChar_t* r = cmLhAllocZ(p->heapH,cmChar_t,n);
  696. const cmChar_t* ep = r + n;
  697. // form the return string
  698. for(i=0; a[i]!=NULL && i<m; ++i)
  699. {
  700. strcat(r,a[i]);
  701. if( strcmp(a[i],cmPathSeparatorChar)!=0 && a[i+1]!=NULL )
  702. strcat(r,cmPathSeparatorChar);
  703. assert( r + strlen(r) <= ep );
  704. }
  705. return r;
  706. }
  707. void cmFileSysFreeDir( cmFileSysH_t h, const cmChar_t* dir )
  708. {
  709. if( dir == NULL )
  710. return;
  711. cmFs_t* p = _cmFileSysHandleToPtr(h);
  712. cmLHeapFree(p->heapH,(void*)dir);
  713. }
  714. typedef struct
  715. {
  716. cmFs_t* p;
  717. unsigned filterFlags;
  718. cmFileSysDirEntry_t* rp;
  719. cmChar_t* dataPtr;
  720. cmChar_t* endPtr;
  721. unsigned entryCnt;
  722. unsigned entryIdx;
  723. unsigned dataByteCnt;
  724. unsigned passIdx;
  725. } cmFileSysDeRecd_t;
  726. cmFsRC_t _cmFileSysDirGetEntries( cmFileSysDeRecd_t* drp, const cmChar_t* dirStr )
  727. {
  728. cmFsRC_t rc = kOkFsRC;
  729. DIR* dirp = NULL;
  730. struct dirent* dp = NULL;
  731. char curDirPtr[] = "./";
  732. unsigned dn = 0;
  733. if( dirStr == NULL || strlen(dirStr) == 0 )
  734. dirStr = curDirPtr;
  735. if( _cmFileSysIsDir(drp->p,dirStr) == false )
  736. return rc;
  737. unsigned fnCharCnt= strlen(dirStr) + PATH_MAX;
  738. char fn[ fnCharCnt + 1 ];
  739. // copy the directory into fn[] ...
  740. fn[0] =0;
  741. fn[fnCharCnt] = 0;
  742. strcpy(fn,dirStr);
  743. assert( strlen(fn)+2 < fnCharCnt );
  744. // ... and be sure that it is terminated with a path sep char
  745. if( fn[ strlen(fn)-1 ] != cmPathSeparatorChar[0] )
  746. strcat(fn,cmPathSeparatorChar);
  747. // file names will be appended to the path at this location
  748. unsigned fni = strlen(fn);
  749. // open the directory
  750. if((dirp = opendir(dirStr)) == NULL)
  751. {
  752. rc = _cmFileSysError(drp->p,kOpenDirFailFsRC,errno,"Unable to open the directory:'%s'.",dirStr);
  753. goto errLabel;
  754. }
  755. // get the next directory entry
  756. while((dp = readdir(dirp)) != NULL )
  757. {
  758. // validate d_name
  759. if( (dn = strlen(dp->d_name)) > 0 )
  760. {
  761. unsigned flags = 0;
  762. // handle cases where d_name begins with '.'
  763. if( dp->d_name[0] == '.' )
  764. {
  765. if( strcmp(dp->d_name,".") == 0 )
  766. {
  767. if( cmIsFlag(drp->filterFlags,kCurDirFsFl) == false )
  768. continue;
  769. flags |= kCurDirFsFl;
  770. }
  771. if( strcmp(dp->d_name,"..") == 0 )
  772. {
  773. if( cmIsFlag(drp->filterFlags,kParentDirFsFl) == false )
  774. continue;
  775. flags |= kParentDirFsFl;
  776. }
  777. if( flags == 0 )
  778. {
  779. if( cmIsFlag(drp->filterFlags,kInvisibleFsFl) == false )
  780. continue;
  781. flags |= kInvisibleFsFl;
  782. }
  783. }
  784. fn[fni] = 0;
  785. strncat( fn, dp->d_name, fnCharCnt-fni );
  786. unsigned fnN = strlen(fn);
  787. // if the filename is too long for the buffer
  788. if( fnN > fnCharCnt )
  789. {
  790. rc = _cmFileSysError(drp->p, kFnTooLongFsRC, errno, "The directory entry:'%s' was too long to be processed.",dp->d_name);
  791. goto errLabel;
  792. }
  793. // is a link
  794. if( _cmFileSysIsLink(drp->p,fn) )
  795. {
  796. if( cmIsFlag(drp->filterFlags,kLinkFsFl) == false )
  797. continue;
  798. flags |= kLinkFsFl;
  799. if( cmIsFlag(drp->filterFlags,kRecurseLinksFsFl) )
  800. if((rc = _cmFileSysDirGetEntries(drp,fn)) != kOkFsRC )
  801. goto errLabel;
  802. }
  803. else
  804. {
  805. // is the entry a file
  806. if( _cmFileSysIsFile(drp->p,fn) )
  807. {
  808. if( cmIsFlag(drp->filterFlags,kFileFsFl)==false )
  809. continue;
  810. flags |= kFileFsFl;
  811. }
  812. else
  813. {
  814. // is the entry a dir
  815. if( _cmFileSysIsDir(drp->p,fn) )
  816. {
  817. if( cmIsFlag(drp->filterFlags,kDirFsFl) == false)
  818. continue;
  819. flags |= kDirFsFl;
  820. if( cmIsFlag(drp->filterFlags,kRecurseFsFl) )
  821. if((rc = _cmFileSysDirGetEntries(drp,fn)) != kOkFsRC )
  822. goto errLabel;
  823. }
  824. else
  825. {
  826. continue;
  827. }
  828. }
  829. }
  830. //assert(flags != 0);
  831. if( drp->passIdx == 0 )
  832. {
  833. ++drp->entryCnt;
  834. // add 1 for the name terminating zero
  835. drp->dataByteCnt += sizeof(cmFileSysDirEntry_t) + 1;
  836. if( cmIsFlag(drp->filterFlags,kFullPathFsFl) )
  837. drp->dataByteCnt += fnN;
  838. else
  839. drp->dataByteCnt += dn;
  840. }
  841. else
  842. {
  843. assert( drp->passIdx == 1 );
  844. assert( drp->entryIdx < drp->entryCnt );
  845. unsigned n = 0;
  846. if( cmIsFlag(drp->filterFlags,kFullPathFsFl) )
  847. {
  848. n = fnN+1;
  849. assert( drp->dataPtr + n <= drp->endPtr );
  850. strcpy(drp->dataPtr,fn);
  851. }
  852. else
  853. {
  854. n = dn+1;
  855. assert( drp->dataPtr + n <= drp->endPtr );
  856. strcpy(drp->dataPtr,dp->d_name);
  857. }
  858. drp->rp[ drp->entryIdx ].flags = flags;
  859. drp->rp[ drp->entryIdx ].name = drp->dataPtr;
  860. drp->dataPtr += n;
  861. assert( drp->dataPtr <= drp->endPtr);
  862. ++drp->entryIdx;
  863. }
  864. }
  865. }
  866. errLabel:
  867. if( dirp != NULL )
  868. closedir(dirp);
  869. return rc;
  870. }
  871. cmFileSysDirEntry_t* cmFileSysDirEntries( cmFileSysH_t h, const cmChar_t* dirStr, unsigned filterFlags, unsigned* dirEntryCntPtr )
  872. {
  873. cmFsRC_t rc = kOkFsRC;
  874. cmFileSysDeRecd_t r;
  875. memset(&r,0,sizeof(r));
  876. r.p = _cmFileSysHandleToPtr(h);
  877. r.filterFlags = filterFlags;
  878. assert( dirEntryCntPtr != NULL );
  879. *dirEntryCntPtr = 0;
  880. for(r.passIdx=0; r.passIdx<2; ++r.passIdx)
  881. {
  882. if((rc = _cmFileSysDirGetEntries( &r, dirStr )) != kOkFsRC )
  883. goto errLabel;
  884. if( r.passIdx == 0 && r.dataByteCnt>0 )
  885. {
  886. // allocate memory to hold the return values
  887. if(( r.rp = (cmFileSysDirEntry_t *)cmLHeapAllocZ( r.p->heapH, r.dataByteCnt )) == NULL )
  888. {
  889. rc= _cmFileSysError( r.p, kMemAllocErrFsRC, 0, "Unable to allocate %i bytes of dir entry memory.",r.dataByteCnt);
  890. goto errLabel;
  891. }
  892. r.dataPtr = (cmChar_t*)(r.rp + r.entryCnt);
  893. r.endPtr = ((cmChar_t*)r.rp) + r.dataByteCnt;
  894. }
  895. }
  896. errLabel:
  897. if( rc == kOkFsRC )
  898. {
  899. assert( r.entryIdx == r.entryCnt );
  900. *dirEntryCntPtr = r.entryCnt;
  901. }
  902. else
  903. {
  904. if( r.rp != NULL )
  905. cmLHeapFree(r.p->heapH,r.rp);
  906. r.rp = NULL;
  907. }
  908. return r.rp;
  909. }
  910. void cmFileSysDirFreeEntries( cmFileSysH_t h, cmFileSysDirEntry_t* dp )
  911. {
  912. cmFs_t* p = _cmFileSysHandleToPtr(h);
  913. if( dp != NULL )
  914. cmLHeapFree(p->heapH,dp);
  915. }
  916. cmFsRC_t cmFileSysErrorCode( cmFileSysH_t h )
  917. {
  918. cmFs_t* p = _cmFileSysHandleToPtr(h);
  919. return cmErrLastRC(&p->err);
  920. }
  921. //
  922. //======================================================================================================
  923. // Begin global versions
  924. //
  925. cmFileSysH_t _cmFsH = { NULL };
  926. cmFsRC_t cmFsInitialize( cmCtx_t* ctx, const cmChar_t* appNameStr )
  927. { return cmFileSysInitialize(&_cmFsH,ctx,appNameStr); }
  928. cmFsRC_t cmFsFinalize()
  929. { return cmFileSysFinalize(&_cmFsH); }
  930. const cmChar_t* cmFsAppName()
  931. { return cmFileSysAppName(_cmFsH); }
  932. const cmChar_t* cmFsPrefsDir()
  933. { return cmFileSysPrefsDir(_cmFsH); }
  934. const cmChar_t* cmFsRsrcDir()
  935. { return cmFileSysRsrcDir(_cmFsH); }
  936. const cmChar_t* cmFsUserDir()
  937. { return cmFileSysUserDir(_cmFsH); }
  938. bool cmFsCanWriteToDir( const cmChar_t* dirStr )
  939. { return cmFileSysCanWriteToDir(_cmFsH,dirStr); }
  940. bool cmFsIsDir( const cmChar_t* dirStr )
  941. { return cmFileSysIsDir(_cmFsH,dirStr); }
  942. bool cmFsIsFile( const cmChar_t* fnStr )
  943. { return cmFileSysIsFile(_cmFsH,fnStr); }
  944. bool cmFsIsLink( const cmChar_t* fnStr )
  945. { return cmFileSysIsLink(_cmFsH,fnStr); }
  946. const cmChar_t* cmFsVMakeFn( const cmChar_t* dirPrefix, const cmChar_t* fn, const cmChar_t* ext, va_list vl )
  947. { return cmFileSysVMakeFn(_cmFsH,dirPrefix,fn,ext,vl); }
  948. const cmChar_t* cmFsMakeFn( const cmChar_t* dirPrefix, const cmChar_t* fn, const cmChar_t* ext, ... )
  949. {
  950. va_list vl;
  951. va_start(vl,ext);
  952. const cmChar_t* retPtr = cmFsVMakeFn(dirPrefix,fn,ext,vl);
  953. va_end(vl);
  954. return retPtr;
  955. }
  956. const cmChar_t* cmFsVMakeUserFn( const cmChar_t* dirPrefix, const cmChar_t* fn, const cmChar_t* ext, va_list vl )
  957. { return cmFileSysVMakeUserFn(_cmFsH,dirPrefix,fn,ext,vl); }
  958. const cmChar_t* cmFsMakeUserFn( const cmChar_t* dirPrefix, const cmChar_t* fn, const cmChar_t* ext, ... )
  959. {
  960. va_list vl;
  961. va_start(vl,ext);
  962. const cmChar_t* retPtr = cmFsVMakeUserFn(dirPrefix,fn,ext,vl);
  963. va_end(vl);
  964. return retPtr;
  965. }
  966. const cmChar_t* cmFsMakeDirFn(const cmChar_t* dir, const cmChar_t* fn )
  967. { return cmFileSysMakeDirFn(_cmFsH,dir,fn); }
  968. const cmChar_t* cmFsMakeUserDirFn(const cmChar_t* dir, const cmChar_t* fn )
  969. { return cmFileSysMakeUserDirFn(_cmFsH,dir,fn); }
  970. const cmChar_t* cmFsVMakeDir( const cmChar_t* dir, va_list vl )
  971. { return cmFileSysVMakeDir(_cmFsH,dir,vl); }
  972. const cmChar_t* cmFsMakeDir( const cmChar_t* dir, ... )
  973. {
  974. va_list vl;
  975. va_start(vl,dir);
  976. const cmChar_t* retPtr = cmFsVMakeDir(dir,vl);
  977. va_end(vl);
  978. return retPtr;
  979. }
  980. const cmChar_t* cmFsVMakeUserDir( const cmChar_t* dir, va_list vl )
  981. { return cmFileSysVMakeUserDir(_cmFsH,dir,vl); }
  982. const cmChar_t* cmFsMakeUserDir( const cmChar_t* dir, ... )
  983. {
  984. va_list vl;
  985. va_start(vl,dir);
  986. const cmChar_t* retPtr = cmFsVMakeUserDir(dir,vl);
  987. va_end(vl);
  988. return retPtr;
  989. }
  990. void cmFsFreeFn( const cmChar_t* fn )
  991. { cmFileSysFreeFn(_cmFsH, fn); }
  992. cmFsRC_t cmFsGenFn( const cmChar_t* dir, const cmChar_t* prefixStr, const cmChar_t* extStr, const cmChar_t** fnPtr )
  993. { return cmFileSysGenFn(_cmFsH,dir,prefixStr,extStr,fnPtr); }
  994. cmFsRC_t cmFsMkDir( const cmChar_t* dir )
  995. { return cmFileSysMkDir(_cmFsH,dir); }
  996. cmFsRC_t cmFsMkDirAll( const cmChar_t* dir )
  997. { return cmFileSysMkDirAll(_cmFsH,dir); }
  998. cmFsRC_t cmFsMkUserDir( const cmChar_t* dir )
  999. { return cmFileSysMkUserDir(_cmFsH,dir); }
  1000. cmFsRC_t cmFsMkUserDirAll( const cmChar_t* dir )
  1001. { return cmFileSysMkUserDirAll(_cmFsH,dir); }
  1002. cmFileSysPathPart_t* cmFsPathParts( const cmChar_t* pathNameStr )
  1003. { return cmFileSysPathParts(_cmFsH,pathNameStr); }
  1004. void cmFsFreePathParts( cmFileSysPathPart_t* p )
  1005. { cmFileSysFreePathParts(_cmFsH,p); }
  1006. cmChar_t** cmFsDirParts( const cmChar_t* dirStr )
  1007. { return cmFileSysDirParts(_cmFsH,dirStr); }
  1008. void cmFsFreeDirParts( cmChar_t** dirStrArray )
  1009. { cmFileSysFreeDirParts(_cmFsH,dirStrArray); }
  1010. unsigned cmFsDirPartsCount( cmChar_t** dirStrArray )
  1011. { return cmFileSysDirPartsCount(_cmFsH, dirStrArray); }
  1012. cmChar_t* cmFsFormDir( cmChar_t** dirStrArray, unsigned n )
  1013. { return cmFileSysFormDir(_cmFsH,dirStrArray,n); }
  1014. void cmFsFreeDir( const cmChar_t* dir )
  1015. { cmFileSysFreeDir(_cmFsH,dir); }
  1016. cmFileSysDirEntry_t* cmFsDirEntries( const cmChar_t* dirStr, unsigned includeFlags, unsigned* dirEntryCntPtr )
  1017. { return cmFileSysDirEntries(_cmFsH,dirStr,includeFlags,dirEntryCntPtr); }
  1018. void cmFsDirFreeEntries( cmFileSysDirEntry_t* p )
  1019. { cmFileSysDirFreeEntries(_cmFsH,p); }
  1020. cmFsRC_t cmFsErrorCode()
  1021. { return cmFileSysErrorCode(_cmFsH); }
  1022. // end global version
  1023. //======================================================================================================
  1024. //
  1025. //{ { label:cmFileSysEx }
  1026. //(
  1027. //
  1028. // cmFileSysTest() function gives usage and testing examples
  1029. // for some of the cmFileSys functions. Note that the
  1030. // 'dir0' directory should exist and contain files and
  1031. // a shallow sub-tree in order to exercise the directory
  1032. // tree walking routine.
  1033. //
  1034. //)
  1035. //(
  1036. void _cmFileSysTestFnParser(
  1037. cmFileSysH_t h,
  1038. cmRpt_t* rpt,
  1039. const cmChar_t* fn );
  1040. cmFsRC_t cmFileSysTest( cmCtx_t* ctx )
  1041. {
  1042. // The global heap manager must have been initialized
  1043. // via cmMdInitialize() prior to running this function.
  1044. cmFsRC_t rc = kOkFsRC;
  1045. cmFileSysH_t h = cmFileSysNullHandle;
  1046. const char* dir0 = cmFsMakeUserDir("src/kc",NULL);
  1047. const char* dir1 = cmFsMakeUserDir("blah",NULL,NULL,NULL);
  1048. const char* file0 = cmFsMakeUserFn(NULL,".emacs",NULL,NULL);
  1049. const char* file1 = cmFsMakeUserFn(NULL,"blah","txt",NULL);
  1050. const char not[] = " not ";
  1051. const char e[] = " ";
  1052. bool fl = false;
  1053. const cmChar_t* fn = NULL;
  1054. // Initialize the file system.
  1055. if((rc = cmFileSysInitialize(&h,ctx,"fs_test")) != kOkFsRC )
  1056. return rc;
  1057. //----------------------------------------------------------
  1058. // Print the standard directories
  1059. //
  1060. printf("Prefs Dir:%s\n",cmFsPrefsDir());
  1061. printf("Rsrc Dir: %s\n",cmFsRsrcDir());
  1062. printf("User Dir: %s\n",cmFsUserDir());
  1063. //----------------------------------------------------------
  1064. // Run the file system type checker
  1065. //
  1066. fl = cmFileSysIsDir(h,dir0);
  1067. printf("'%s' is%sa directory.\n",dir0, (fl ? e : not));
  1068. fl = cmFileSysIsDir(h,dir1);
  1069. printf("'%s' is%sa directory.\n",dir1, (fl ? e : not));
  1070. fl = cmFileSysIsFile(h,file0);
  1071. printf("'%s' is%sa file.\n",file0, (fl ? e : not));
  1072. fl = cmFileSysIsFile(h,file1);
  1073. printf("'%s' is%sa file.\n",file1, (fl ? e : not));
  1074. //----------------------------------------------------------
  1075. // Test the file name creation functions
  1076. //
  1077. if((fn = cmFileSysMakeUserFn(h,"src","cmFileSys",
  1078. "c","cm","src",NULL)) != NULL)
  1079. {
  1080. printf("File:'%s'\n",fn);
  1081. }
  1082. cmFileSysFreeFn(h,fn);
  1083. if((fn = cmFileSysMakeUserFn(h,"src","cmFileSys",
  1084. ".c","/cm/","/src/",NULL)) != NULL )
  1085. {
  1086. printf("File:'%s'\n",fn);
  1087. }
  1088. cmFileSysFreeFn(h,fn);
  1089. //----------------------------------------------------------
  1090. // Test the file name parsing functions
  1091. //
  1092. const char* fn0 = cmFileSysMakeUserFn(h,"src/cm/src","cmFileSys","c",NULL);
  1093. const char* fn1 = cmFileSysMakeUserFn(h,"src/cm/src","cmFileSys",NULL,NULL);
  1094. const char* fn2 = cmFileSysMakeUserDir(h,"src/cm/src/cmFileSys/",NULL);
  1095. _cmFileSysTestFnParser(h,&ctx->rpt,fn0);
  1096. _cmFileSysTestFnParser(h,&ctx->rpt,fn1);
  1097. _cmFileSysTestFnParser(h,&ctx->rpt,fn2);
  1098. _cmFileSysTestFnParser(h,&ctx->rpt,"cmFileSys.c");
  1099. _cmFileSysTestFnParser(h,&ctx->rpt,"/");
  1100. _cmFileSysTestFnParser(h,&ctx->rpt," ");
  1101. cmFileSysFreeFn(h,fn0);
  1102. cmFileSysFreeFn(h,fn1);
  1103. cmFileSysFreeFn(h,fn1);
  1104. //----------------------------------------------------------
  1105. // Test the directory tree walking routines.
  1106. //
  1107. cmFileSysDirEntry_t* dep;
  1108. unsigned dirEntCnt;
  1109. unsigned filterFlags = kDirFsFl
  1110. | kFileFsFl
  1111. | kRecurseFsFl
  1112. | kFullPathFsFl;
  1113. const char* src_dir = cmFileSysMakeFn(h,dir0,"doc",NULL,NULL);
  1114. cmRptPrintf(&ctx->rpt,"Dir Entry Test: %s\n",src_dir);
  1115. if((dep = cmFileSysDirEntries(h,src_dir,filterFlags,&dirEntCnt)) != NULL)
  1116. {
  1117. unsigned i;
  1118. for(i=0; i<dirEntCnt; ++i)
  1119. cmRptPrintf(&ctx->rpt,"%s\n",dep[i].name);
  1120. cmFileSysDirFreeEntries(h,dep);
  1121. }
  1122. cmFileSysFreeFn(h,src_dir);
  1123. //----------------------------------------------------------
  1124. // Test the directory parsing/building routines.
  1125. //
  1126. cmRptPrintf(&ctx->rpt,"Dir Parsing routings:\n");
  1127. cmChar_t** a;
  1128. unsigned j;
  1129. for(j=0; j<2; ++j)
  1130. {
  1131. const cmChar_t* dstr = dir0 + j;
  1132. if((a = cmFileSysDirParts(h,dstr)) == NULL)
  1133. cmRptPrint(&ctx->rpt,"cmFileSysDirParts() failed.\n");
  1134. else
  1135. {
  1136. unsigned i;
  1137. cmRptPrintf(&ctx->rpt,"Input:%s\n",dstr);
  1138. for(i=0; a[i]!=NULL; ++i)
  1139. cmRptPrintf(&ctx->rpt,"%i : %s\n",i,a[i]);
  1140. cmChar_t* d;
  1141. if((d = cmFileSysFormDir(h,a,
  1142. cmFileSysDirPartsCount(h,a))) != NULL )
  1143. {
  1144. cmRptPrintf(&ctx->rpt,"Reformed:%s\n",d);
  1145. }
  1146. cmFileSysFreeDirParts(h,a);
  1147. }
  1148. }
  1149. //----------------------------------------------------------
  1150. // Test the extended mkdir routine.
  1151. //
  1152. if( cmFileSysMkUserDirAll(h, "/temp/doc/doc" )!=kOkFsRC )
  1153. {
  1154. cmRptPrint(&ctx->rpt,"cmFileSysMkDirAll() failed.\n");
  1155. }
  1156. // finalize the file system
  1157. if((rc = cmFileSysFinalize(&h)) != kOkFsRC )
  1158. return rc;
  1159. cmRptPrintf(&ctx->rpt,"File Test done\n");
  1160. cmFsFreeFn(dir0);
  1161. cmFsFreeFn(dir1);
  1162. cmFsFreeFn(file0);
  1163. cmFsFreeFn(file1);
  1164. return rc;
  1165. }
  1166. // Parse a file name and print the results.
  1167. // Called by cmFileSysTest().
  1168. void _cmFileSysTestFnParser(
  1169. cmFileSysH_t h,
  1170. cmRpt_t* rpt,
  1171. const cmChar_t* fn )
  1172. {
  1173. cmFileSysPathPart_t* pp;
  1174. cmRptPrintf(rpt,"Fn Parse Test:%s\n",fn);
  1175. if((pp = cmFileSysPathParts(h,fn)) != NULL )
  1176. {
  1177. if(pp->dirStr != NULL)
  1178. cmRptPrintf(rpt,"Dir:%s\n",pp->dirStr);
  1179. if(pp->fnStr != NULL)
  1180. cmRptPrintf(rpt,"Fn:%s\n",pp->fnStr);
  1181. if(pp->extStr != NULL )
  1182. cmRptPrintf(rpt,"Ext:%s\n",pp->extStr);
  1183. cmFileSysFreePathParts(h,pp);
  1184. }
  1185. cmRptPrintf(rpt,"\n");
  1186. }
  1187. //)
  1188. //}