libcm is a C development framework with an emphasis on audio signal processing applications.
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

cmFileSys.c 36KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531
  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. void cmFileSysFreeFn( cmFileSysH_t h, const cmChar_t* fn )
  402. {
  403. cmFs_t* p = _cmFileSysHandleToPtr(h);
  404. if( fn == NULL )
  405. return;
  406. cmLHeapFree(p->heapH, (void*)fn);
  407. }
  408. cmFsRC_t cmFileSysGenFn( cmFileSysH_t h, const cmChar_t* dir, const cmChar_t* prefixStr, const cmChar_t* extStr, const cmChar_t** fnPtr )
  409. {
  410. cmFsRC_t rc = kOkFsRC;
  411. cmFs_t* p = _cmFileSysHandleToPtr(h);
  412. unsigned maxAttemptCnt = 0xffff;
  413. *fnPtr = NULL;
  414. assert(dir != NULL);
  415. if( prefixStr == NULL )
  416. prefixStr = "";
  417. if( extStr == NULL )
  418. extStr = "";
  419. if( !cmFileSysIsDir(h,dir) )
  420. return cmErrMsg(&p->err,kOpenDirFailFsRC,"File name generation failed because the directory '%s' does not exist.",cmStringNullGuard(dir));
  421. unsigned i;
  422. for(i=0; *fnPtr==NULL; ++i)
  423. {
  424. cmChar_t* fn = cmTsPrintfP(NULL,"%s%i",prefixStr,i);
  425. const cmChar_t* path = cmFileSysMakeFn(h,dir,fn,extStr,NULL );
  426. if( !cmFileSysIsFile(h,path) )
  427. *fnPtr = cmMemAllocStr(path);
  428. cmFileSysFreeFn(h,path);
  429. cmMemFree(fn);
  430. if( i == maxAttemptCnt )
  431. return cmErrMsg(&p->err,kGenFileFailFsRC,"File name generation failed because a suitable file name could not be found after %i attempts.",maxAttemptCnt);
  432. };
  433. return rc;
  434. }
  435. cmFsRC_t cmFileSysMkDir( cmFileSysH_t h, const cmChar_t* dir )
  436. {
  437. cmFs_t* p = _cmFileSysHandleToPtr(h);
  438. if( mkdir(dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0 )
  439. return _cmFileSysError( p, kMkDirFailFsRC, errno, "The attempt to create the directory '%s' failed.",dir);
  440. return kOkFsRC;
  441. }
  442. cmFsRC_t cmFileSysMkUserDir( cmFileSysH_t h, const cmChar_t* dir0 )
  443. {
  444. const cmChar_t* dir = cmFileSysMakeUserFn(h,dir0,NULL,NULL,NULL);
  445. if( dir == NULL )
  446. return _cmFileSysError(_cmFileSysHandleToPtr(h),kFormFnFailFsRC,0, "The specified directory string /<user>/%s could not be formed.",cmStringNullGuard(dir0));
  447. cmFsRC_t rc = cmFileSysMkDir(h,dir);
  448. cmFileSysFreeFn(h,dir);
  449. return rc;
  450. }
  451. cmFsRC_t cmFileSysMkDirAll( cmFileSysH_t h, const cmChar_t* dir )
  452. {
  453. cmFsRC_t rc = kOkFsRC;
  454. cmFs_t* p = _cmFileSysHandleToPtr(h);
  455. cmChar_t** a = NULL;
  456. unsigned i;
  457. if((a = cmFileSysDirParts(h,dir)) == NULL )
  458. return _cmFileSysError(p, kInvalidDirFsRC, 0, "The directory '%s' could not be parsed.",cmStringNullGuard(dir));
  459. for(i=0; rc==kOkFsRC && a[i]!=NULL; ++i)
  460. {
  461. cmChar_t* d = cmFileSysFormDir(h,a,i+1);
  462. if( cmFileSysIsDir(h,d)==false )
  463. if((rc = cmFileSysMkDir(h,d)) != kOkFsRC )
  464. break;
  465. cmFileSysFreeDir(h,d);
  466. }
  467. cmFileSysFreeDirParts(h,a);
  468. return rc;
  469. }
  470. cmFsRC_t cmFileSysMkUserDirAll( cmFileSysH_t h, const cmChar_t* dir0 )
  471. {
  472. const cmChar_t* dir = cmFileSysMakeUserFn(h,dir0,NULL,NULL,NULL);
  473. if( dir == NULL )
  474. return _cmFileSysError(_cmFileSysHandleToPtr(h),kFormFnFailFsRC,0,"The specified directory string /<user>/%s could not be formed.",cmStringNullGuard(dir0));
  475. cmFsRC_t rc = cmFileSysMkDirAll(h,dir);
  476. cmFileSysFreeFn(h,dir);
  477. return rc;
  478. }
  479. cmFileSysPathPart_t* cmFileSysPathParts( cmFileSysH_t h, const cmChar_t* pathStr )
  480. {
  481. int n = 0; // char's in pathStr
  482. int dn = 0; // char's in the dir part
  483. int fn = 0; // char's in the name part
  484. int en = 0; // char's in the ext part
  485. cmChar_t* cp = NULL;
  486. cmFileSysPathPart_t* rp = NULL;
  487. cmFs_t* p = _cmFileSysHandleToPtr(h);
  488. if( pathStr==NULL )
  489. return NULL;
  490. // skip leading white space
  491. while( *pathStr )
  492. {
  493. if( isspace(*pathStr ) )
  494. ++pathStr;
  495. else
  496. break;
  497. }
  498. // get the length of pathStr
  499. if((n = strlen(pathStr)) == 0 )
  500. return NULL;
  501. // remove trailing spaces
  502. for(; n>0; --n)
  503. {
  504. if( isspace(pathStr[n-1]) )
  505. --n;
  506. else
  507. break;
  508. }
  509. //
  510. if( n == 0 )
  511. return NULL;
  512. char buf[n+1];
  513. buf[n] = 0;
  514. // Get the last word (which may be a file name) from pathStr.
  515. // (pathStr must be copied into a buf because basename()
  516. // is allowed to change the values in its arg.)
  517. strncpy(buf,pathStr,n);
  518. cp = basename(buf);
  519. if( cp != NULL )
  520. {
  521. cmChar_t* ep;
  522. // does the last word have a period in it
  523. if( (ep = strchr(cp,'.')) != NULL )
  524. {
  525. *ep = 0; // end the file name at the period
  526. ++ep; // set the ext marker
  527. en = strlen(ep); // get the length of the ext
  528. }
  529. fn = strlen(cp); //get the length of the file name
  530. }
  531. // Get the directory part.
  532. // ( pathStr must be copied into a buf because dirname()
  533. // is allowed to change the values in its arg.)
  534. strncpy(buf,pathStr,n);
  535. // if the last char in pathStr[] is '/' then the whole string is a dir.
  536. // (this is not the answer that dirname() and basename() would give).
  537. if( pathStr[n-1] == cmPathSeparatorChar[0] )
  538. {
  539. fn = 0;
  540. en = 0;
  541. dn = n;
  542. cp = buf;
  543. }
  544. else
  545. {
  546. cp = dirname(buf);
  547. }
  548. if( cp != NULL )
  549. dn = strlen(cp);
  550. // get the total size of the returned memory. (add 3 for ecmh possible terminating zero)
  551. n = sizeof(cmFileSysPathPart_t) + dn + fn + en + 3;
  552. // alloc memory
  553. if((rp = (cmFileSysPathPart_t*)cmLHeapAllocZ( p->heapH, n )) == NULL )
  554. {
  555. _cmFileSysError( p, kLHeapAllocErrFsRC, 0, "Unable to allocate the file system path part record for '%s'.",pathStr);
  556. return NULL;
  557. }
  558. // set the return pointers for ecmh of the parts
  559. rp->dirStr = (const cmChar_t* )(rp + 1);
  560. rp->fnStr = rp->dirStr + dn + 1;
  561. rp->extStr = rp->fnStr + fn + 1;
  562. // if there is a directory part
  563. if( dn>0 )
  564. strcpy((cmChar_t*)rp->dirStr,cp);
  565. else
  566. rp->dirStr = NULL;
  567. if( fn || en )
  568. {
  569. // Get the trailing word again.
  570. // pathStr must be copied into a buf because basename() may
  571. // is allowed to change the values in its arg.
  572. strncpy(buf,pathStr,n);
  573. cp = basename(buf);
  574. if( cp != NULL )
  575. {
  576. cmChar_t* ep;
  577. if( (ep = strchr(cp,'.')) != NULL )
  578. {
  579. *ep = 0;
  580. ++ep;
  581. assert( strlen(ep) == en );
  582. strcpy((cmChar_t*)rp->extStr,ep);
  583. }
  584. assert( strlen(cp) == fn );
  585. if(fn)
  586. strcpy((cmChar_t*)rp->fnStr,cp);
  587. }
  588. }
  589. if( fn == 0 )
  590. rp->fnStr = NULL;
  591. if( en == 0 )
  592. rp->extStr = NULL;
  593. return rp;
  594. }
  595. void cmFileSysFreePathParts( cmFileSysH_t h, cmFileSysPathPart_t* pp )
  596. {
  597. if( pp == NULL )
  598. return;
  599. cmFs_t* p = _cmFileSysHandleToPtr(h);
  600. cmLHeapFree(p->heapH, (void*)pp );
  601. }
  602. cmChar_t** cmFileSysDirParts( cmFileSysH_t h, const cmChar_t* dirStr )
  603. {
  604. cmFs_t* p = _cmFileSysHandleToPtr(h);
  605. const cmChar_t* s = dirStr;
  606. const cmChar_t* ep = dirStr + strlen(dirStr);
  607. char pathSep = cmPathSeparatorChar[0];
  608. unsigned n = 2;
  609. unsigned i = 0;
  610. // skip leading white space or pathsep
  611. while( isspace(*s) && s < ep )
  612. ++s;
  613. // if the directory string is empty
  614. if( s >= ep )
  615. return NULL;
  616. // set the beginning of the input dirStr past any leading white space
  617. dirStr = s;
  618. // count the number of dir segments - this might overcount the
  619. // number of segments if there are multiple repeated path seperator
  620. // char's - but this is ok because 'n' is only used to determine
  621. // the size of the returned array - which will simply have some
  622. // NULL entries at the end.
  623. for(; s < ep; ++s )
  624. if( *s == pathSep )
  625. ++n;
  626. // allocate the array
  627. cmChar_t** a = cmLhAllocZ(p->heapH,cmChar_t*,n);
  628. // reset the cur location to the begin of the buf
  629. s = dirStr;
  630. // if the path starts at the root
  631. if( *s == pathSep )
  632. {
  633. a[0] = cmPathSeparatorChar; // cmPathSeparatorChar is a static string in cmGlobal.h
  634. i = 1;
  635. ++s;
  636. }
  637. for(; i<n && s<ep; ++i)
  638. {
  639. const cmChar_t* s1;
  640. if(( s1 = strchr(s,pathSep)) == NULL )
  641. s1 = ep;
  642. if( s1!=s )
  643. {
  644. unsigned sn = (s1 - s)+1;
  645. a[i] = cmLhAlloc(p->heapH,cmChar_t,sn);
  646. strncpy(a[i],s,sn-1);
  647. a[i][sn-1] = 0;
  648. }
  649. s = s1+1;
  650. }
  651. return a;
  652. }
  653. void cmFileSysFreeDirParts( cmFileSysH_t h, cmChar_t** dirStrArray )
  654. {
  655. if( dirStrArray == NULL )
  656. return;
  657. cmFs_t* p = _cmFileSysHandleToPtr(h);
  658. unsigned i;
  659. for(i=0; dirStrArray[i]!=NULL; ++i)
  660. {
  661. // cmPathSeparatorChar is statically alloc'd in cmGlobal.h
  662. if( dirStrArray[i] != cmPathSeparatorChar )
  663. cmLHeapFree(p->heapH,dirStrArray[i]);
  664. }
  665. cmLHeapFree(p->heapH, (void*)dirStrArray );
  666. }
  667. unsigned cmFileSysDirPartsCount(cmFileSysH_t h, cmChar_t** dirStrArray )
  668. {
  669. unsigned i = 0;
  670. if( dirStrArray == NULL )
  671. return 0;
  672. while(dirStrArray[i] != NULL )
  673. ++i;
  674. return i;
  675. }
  676. cmChar_t* cmFileSysFormDir( cmFileSysH_t h, cmChar_t** a, unsigned m )
  677. {
  678. cmFs_t* p = _cmFileSysHandleToPtr(h);
  679. unsigned n;
  680. unsigned i;
  681. // determine the length of the return string
  682. for(i=0,n=0; a[i]!=NULL && i<m; ++i)
  683. n += strlen(a[i]) + strlen(cmPathSeparatorChar);
  684. if( i<m && a[i] == NULL )
  685. {
  686. _cmFileSysError(p,kInvalidDirFsRC,0,"cmFileSysFormDir() cannot form a directory string from %i parts when only %i exist.",m,i);
  687. return NULL;
  688. }
  689. n += 1;
  690. // allocate the return string
  691. cmChar_t* r = cmLhAllocZ(p->heapH,cmChar_t,n);
  692. const cmChar_t* ep = r + n;
  693. // form the return string
  694. for(i=0; a[i]!=NULL && i<m; ++i)
  695. {
  696. strcat(r,a[i]);
  697. if( strcmp(a[i],cmPathSeparatorChar)!=0 && a[i+1]!=NULL )
  698. strcat(r,cmPathSeparatorChar);
  699. assert( r + strlen(r) <= ep );
  700. }
  701. return r;
  702. }
  703. void cmFileSysFreeDir( cmFileSysH_t h, const cmChar_t* dir )
  704. {
  705. if( dir == NULL )
  706. return;
  707. cmFs_t* p = _cmFileSysHandleToPtr(h);
  708. cmLHeapFree(p->heapH,(void*)dir);
  709. }
  710. typedef struct
  711. {
  712. cmFs_t* p;
  713. unsigned filterFlags;
  714. cmFileSysDirEntry_t* rp;
  715. cmChar_t* dataPtr;
  716. cmChar_t* endPtr;
  717. unsigned entryCnt;
  718. unsigned entryIdx;
  719. unsigned dataByteCnt;
  720. unsigned passIdx;
  721. } cmFileSysDeRecd_t;
  722. cmFsRC_t _cmFileSysDirGetEntries( cmFileSysDeRecd_t* drp, const cmChar_t* dirStr )
  723. {
  724. cmFsRC_t rc = kOkFsRC;
  725. DIR* dirp = NULL;
  726. struct dirent* dp = NULL;
  727. char curDirPtr[] = "./";
  728. unsigned dn = 0;
  729. if( dirStr == NULL || strlen(dirStr) == 0 )
  730. dirStr = curDirPtr;
  731. if( _cmFileSysIsDir(drp->p,dirStr) == false )
  732. return rc;
  733. unsigned fnCharCnt= strlen(dirStr) + PATH_MAX;
  734. char fn[ fnCharCnt + 1 ];
  735. // copy the directory into fn[] ...
  736. fn[0] =0;
  737. fn[fnCharCnt] = 0;
  738. strcpy(fn,dirStr);
  739. assert( strlen(fn)+2 < fnCharCnt );
  740. // ... and be sure that it is terminated with a path sep char
  741. if( fn[ strlen(fn)-1 ] != cmPathSeparatorChar[0] )
  742. strcat(fn,cmPathSeparatorChar);
  743. // file names will be appended to the path at this location
  744. unsigned fni = strlen(fn);
  745. // open the directory
  746. if((dirp = opendir(dirStr)) == NULL)
  747. {
  748. rc = _cmFileSysError(drp->p,kOpenDirFailFsRC,errno,"Unable to open the directory:'%s'.",dirStr);
  749. goto errLabel;
  750. }
  751. // get the next directory entry
  752. while((dp = readdir(dirp)) != NULL )
  753. {
  754. // validate d_name
  755. if( (dn = strlen(dp->d_name)) > 0 )
  756. {
  757. unsigned flags = 0;
  758. // handle cases where d_name begins with '.'
  759. if( dp->d_name[0] == '.' )
  760. {
  761. if( strcmp(dp->d_name,".") == 0 )
  762. {
  763. if( cmIsFlag(drp->filterFlags,kCurDirFsFl) == false )
  764. continue;
  765. flags |= kCurDirFsFl;
  766. }
  767. if( strcmp(dp->d_name,"..") == 0 )
  768. {
  769. if( cmIsFlag(drp->filterFlags,kParentDirFsFl) == false )
  770. continue;
  771. flags |= kParentDirFsFl;
  772. }
  773. if( flags == 0 )
  774. {
  775. if( cmIsFlag(drp->filterFlags,kInvisibleFsFl) == false )
  776. continue;
  777. flags |= kInvisibleFsFl;
  778. }
  779. }
  780. fn[fni] = 0;
  781. strncat( fn, dp->d_name, fnCharCnt-fni );
  782. unsigned fnN = strlen(fn);
  783. // if the filename is too long for the buffer
  784. if( fnN > fnCharCnt )
  785. {
  786. rc = _cmFileSysError(drp->p, kFnTooLongFsRC, errno, "The directory entry:'%s' was too long to be processed.",dp->d_name);
  787. goto errLabel;
  788. }
  789. // is a link
  790. if( _cmFileSysIsLink(drp->p,fn) )
  791. {
  792. if( cmIsFlag(drp->filterFlags,kLinkFsFl) == false )
  793. continue;
  794. flags |= kLinkFsFl;
  795. if( cmIsFlag(drp->filterFlags,kRecurseLinksFsFl) )
  796. if((rc = _cmFileSysDirGetEntries(drp,fn)) != kOkFsRC )
  797. goto errLabel;
  798. }
  799. else
  800. {
  801. // is the entry a file
  802. if( _cmFileSysIsFile(drp->p,fn) )
  803. {
  804. if( cmIsFlag(drp->filterFlags,kFileFsFl)==false )
  805. continue;
  806. flags |= kFileFsFl;
  807. }
  808. else
  809. {
  810. // is the entry a dir
  811. if( _cmFileSysIsDir(drp->p,fn) )
  812. {
  813. if( cmIsFlag(drp->filterFlags,kDirFsFl) == false)
  814. continue;
  815. flags |= kDirFsFl;
  816. if( cmIsFlag(drp->filterFlags,kRecurseFsFl) )
  817. if((rc = _cmFileSysDirGetEntries(drp,fn)) != kOkFsRC )
  818. goto errLabel;
  819. }
  820. else
  821. {
  822. continue;
  823. }
  824. }
  825. }
  826. //assert(flags != 0);
  827. if( drp->passIdx == 0 )
  828. {
  829. ++drp->entryCnt;
  830. // add 1 for the name terminating zero
  831. drp->dataByteCnt += sizeof(cmFileSysDirEntry_t) + 1;
  832. if( cmIsFlag(drp->filterFlags,kFullPathFsFl) )
  833. drp->dataByteCnt += fnN;
  834. else
  835. drp->dataByteCnt += dn;
  836. }
  837. else
  838. {
  839. assert( drp->passIdx == 1 );
  840. assert( drp->entryIdx < drp->entryCnt );
  841. unsigned n = 0;
  842. if( cmIsFlag(drp->filterFlags,kFullPathFsFl) )
  843. {
  844. n = fnN+1;
  845. assert( drp->dataPtr + n <= drp->endPtr );
  846. strcpy(drp->dataPtr,fn);
  847. }
  848. else
  849. {
  850. n = dn+1;
  851. assert( drp->dataPtr + n <= drp->endPtr );
  852. strcpy(drp->dataPtr,dp->d_name);
  853. }
  854. drp->rp[ drp->entryIdx ].flags = flags;
  855. drp->rp[ drp->entryIdx ].name = drp->dataPtr;
  856. drp->dataPtr += n;
  857. assert( drp->dataPtr <= drp->endPtr);
  858. ++drp->entryIdx;
  859. }
  860. }
  861. }
  862. errLabel:
  863. if( dirp != NULL )
  864. closedir(dirp);
  865. return rc;
  866. }
  867. cmFileSysDirEntry_t* cmFileSysDirEntries( cmFileSysH_t h, const cmChar_t* dirStr, unsigned filterFlags, unsigned* dirEntryCntPtr )
  868. {
  869. cmFsRC_t rc = kOkFsRC;
  870. cmFileSysDeRecd_t r;
  871. memset(&r,0,sizeof(r));
  872. r.p = _cmFileSysHandleToPtr(h);
  873. r.filterFlags = filterFlags;
  874. assert( dirEntryCntPtr != NULL );
  875. *dirEntryCntPtr = 0;
  876. for(r.passIdx=0; r.passIdx<2; ++r.passIdx)
  877. {
  878. if((rc = _cmFileSysDirGetEntries( &r, dirStr )) != kOkFsRC )
  879. goto errLabel;
  880. if( r.passIdx == 0 && r.dataByteCnt>0 )
  881. {
  882. // allocate memory to hold the return values
  883. if(( r.rp = (cmFileSysDirEntry_t *)cmLHeapAllocZ( r.p->heapH, r.dataByteCnt )) == NULL )
  884. {
  885. rc= _cmFileSysError( r.p, kMemAllocErrFsRC, 0, "Unable to allocate %i bytes of dir entry memory.",r.dataByteCnt);
  886. goto errLabel;
  887. }
  888. r.dataPtr = (cmChar_t*)(r.rp + r.entryCnt);
  889. r.endPtr = ((cmChar_t*)r.rp) + r.dataByteCnt;
  890. }
  891. }
  892. errLabel:
  893. if( rc == kOkFsRC )
  894. {
  895. assert( r.entryIdx == r.entryCnt );
  896. *dirEntryCntPtr = r.entryCnt;
  897. }
  898. else
  899. {
  900. if( r.rp != NULL )
  901. cmLHeapFree(r.p->heapH,r.rp);
  902. r.rp = NULL;
  903. }
  904. return r.rp;
  905. }
  906. void cmFileSysDirFreeEntries( cmFileSysH_t h, cmFileSysDirEntry_t* dp )
  907. {
  908. cmFs_t* p = _cmFileSysHandleToPtr(h);
  909. if( dp != NULL )
  910. cmLHeapFree(p->heapH,dp);
  911. }
  912. cmFsRC_t cmFileSysErrorCode( cmFileSysH_t h )
  913. {
  914. cmFs_t* p = _cmFileSysHandleToPtr(h);
  915. return cmErrLastRC(&p->err);
  916. }
  917. //
  918. //======================================================================================================
  919. // Begin global versions
  920. //
  921. cmFileSysH_t _cmFsH = { NULL };
  922. cmFsRC_t cmFsInitialize( cmCtx_t* ctx, const cmChar_t* appNameStr )
  923. { return cmFileSysInitialize(&_cmFsH,ctx,appNameStr); }
  924. cmFsRC_t cmFsFinalize()
  925. { return cmFileSysFinalize(&_cmFsH); }
  926. const cmChar_t* cmFsAppName()
  927. { return cmFileSysAppName(_cmFsH); }
  928. const cmChar_t* cmFsPrefsDir()
  929. { return cmFileSysPrefsDir(_cmFsH); }
  930. const cmChar_t* cmFsRsrcDir()
  931. { return cmFileSysRsrcDir(_cmFsH); }
  932. const cmChar_t* cmFsUserDir()
  933. { return cmFileSysUserDir(_cmFsH); }
  934. bool cmFsCanWriteToDir( const cmChar_t* dirStr )
  935. { return cmFileSysCanWriteToDir(_cmFsH,dirStr); }
  936. bool cmFsIsDir( const cmChar_t* dirStr )
  937. { return cmFileSysIsDir(_cmFsH,dirStr); }
  938. bool cmFsIsFile( const cmChar_t* fnStr )
  939. { return cmFileSysIsFile(_cmFsH,fnStr); }
  940. bool cmFsIsLink( const cmChar_t* fnStr )
  941. { return cmFileSysIsLink(_cmFsH,fnStr); }
  942. const cmChar_t* cmFsVMakeFn( const cmChar_t* dirPrefix, const cmChar_t* fn, const cmChar_t* ext, va_list vl )
  943. { return cmFileSysVMakeFn(_cmFsH,dirPrefix,fn,ext,vl); }
  944. const cmChar_t* cmFsMakeFn( const cmChar_t* dirPrefix, const cmChar_t* fn, const cmChar_t* ext, ... )
  945. {
  946. va_list vl;
  947. va_start(vl,ext);
  948. const cmChar_t* retPtr = cmFsVMakeFn(dirPrefix,fn,ext,vl);
  949. va_end(vl);
  950. return retPtr;
  951. }
  952. const cmChar_t* cmFsVMakeUserFn( const cmChar_t* dirPrefix, const cmChar_t* fn, const cmChar_t* ext, va_list vl )
  953. { return cmFileSysVMakeUserFn(_cmFsH,dirPrefix,fn,ext,vl); }
  954. const cmChar_t* cmFsMakeUserFn( const cmChar_t* dirPrefix, const cmChar_t* fn, const cmChar_t* ext, ... )
  955. {
  956. va_list vl;
  957. va_start(vl,ext);
  958. const cmChar_t* retPtr = cmFsVMakeUserFn(dirPrefix,fn,ext,vl);
  959. va_end(vl);
  960. return retPtr;
  961. }
  962. const cmChar_t* cmFsVMakeDir( const cmChar_t* dir, va_list vl )
  963. { return cmFileSysVMakeDir(_cmFsH,dir,vl); }
  964. const cmChar_t* cmFsMakeDir( const cmChar_t* dir, ... )
  965. {
  966. va_list vl;
  967. va_start(vl,dir);
  968. const cmChar_t* retPtr = cmFsVMakeDir(dir,vl);
  969. va_end(vl);
  970. return retPtr;
  971. }
  972. const cmChar_t* cmFsVMakeUserDir( const cmChar_t* dir, va_list vl )
  973. { return cmFileSysVMakeUserDir(_cmFsH,dir,vl); }
  974. const cmChar_t* cmFsMakeUserDir( const cmChar_t* dir, ... )
  975. {
  976. va_list vl;
  977. va_start(vl,dir);
  978. const cmChar_t* retPtr = cmFsVMakeUserDir(dir,vl);
  979. va_end(vl);
  980. return retPtr;
  981. }
  982. void cmFsFreeFn( const cmChar_t* fn )
  983. { cmFileSysFreeFn(_cmFsH, fn); }
  984. cmFsRC_t cmFsGenFn( const cmChar_t* dir, const cmChar_t* prefixStr, const cmChar_t* extStr, const cmChar_t** fnPtr )
  985. { return cmFileSysGenFn(_cmFsH,dir,prefixStr,extStr,fnPtr); }
  986. cmFsRC_t cmFsMkDir( const cmChar_t* dir )
  987. { return cmFileSysMkDir(_cmFsH,dir); }
  988. cmFsRC_t cmFsMkDirAll( const cmChar_t* dir )
  989. { return cmFileSysMkDirAll(_cmFsH,dir); }
  990. cmFsRC_t cmFsMkUserDir( const cmChar_t* dir )
  991. { return cmFileSysMkUserDir(_cmFsH,dir); }
  992. cmFsRC_t cmFsMkUserDirAll( const cmChar_t* dir )
  993. { return cmFileSysMkUserDirAll(_cmFsH,dir); }
  994. cmFileSysPathPart_t* cmFsPathParts( const cmChar_t* pathNameStr )
  995. { return cmFileSysPathParts(_cmFsH,pathNameStr); }
  996. void cmFsFreePathParts( cmFileSysPathPart_t* p )
  997. { cmFileSysFreePathParts(_cmFsH,p); }
  998. cmChar_t** cmFsDirParts( const cmChar_t* dirStr )
  999. { return cmFileSysDirParts(_cmFsH,dirStr); }
  1000. void cmFsFreeDirParts( cmChar_t** dirStrArray )
  1001. { cmFileSysFreeDirParts(_cmFsH,dirStrArray); }
  1002. unsigned cmFsDirPartsCount( cmChar_t** dirStrArray )
  1003. { return cmFileSysDirPartsCount(_cmFsH, dirStrArray); }
  1004. cmChar_t* cmFsFormDir( cmChar_t** dirStrArray, unsigned n )
  1005. { return cmFileSysFormDir(_cmFsH,dirStrArray,n); }
  1006. void cmFsFreeDir( const cmChar_t* dir )
  1007. { cmFileSysFreeDir(_cmFsH,dir); }
  1008. cmFileSysDirEntry_t* cmFsDirEntries( const cmChar_t* dirStr, unsigned includeFlags, unsigned* dirEntryCntPtr )
  1009. { return cmFileSysDirEntries(_cmFsH,dirStr,includeFlags,dirEntryCntPtr); }
  1010. void cmFsDirFreeEntries( cmFileSysDirEntry_t* p )
  1011. { cmFileSysDirFreeEntries(_cmFsH,p); }
  1012. cmFsRC_t cmFsErrorCode()
  1013. { return cmFileSysErrorCode(_cmFsH); }
  1014. // end global version
  1015. //======================================================================================================
  1016. //
  1017. //{ { label:cmFileSysEx }
  1018. //(
  1019. //
  1020. // cmFileSysTest() function gives usage and testing examples
  1021. // for some of the cmFileSys functions. Note that the
  1022. // 'dir0' directory should exist and contain files and
  1023. // a shallow sub-tree in order to exercise the directory
  1024. // tree walking routine.
  1025. //
  1026. //)
  1027. //(
  1028. void _cmFileSysTestFnParser(
  1029. cmFileSysH_t h,
  1030. cmRpt_t* rpt,
  1031. const cmChar_t* fn );
  1032. cmFsRC_t cmFileSysTest( cmCtx_t* ctx )
  1033. {
  1034. // The global heap manager must have been initialized
  1035. // via cmMdInitialize() prior to running this function.
  1036. cmFsRC_t rc = kOkFsRC;
  1037. cmFileSysH_t h = cmFileSysNullHandle;
  1038. const char* dir0 = cmFsMakeUserDir("src/kc",NULL);
  1039. const char* dir1 = cmFsMakeUserDir("blah",NULL,NULL,NULL);
  1040. const char* file0 = cmFsMakeUserFn(NULL,".emacs",NULL,NULL);
  1041. const char* file1 = cmFsMakeUserFn(NULL,"blah","txt",NULL);
  1042. const char not[] = " not ";
  1043. const char e[] = " ";
  1044. bool fl = false;
  1045. const cmChar_t* fn = NULL;
  1046. // Initialize the file system.
  1047. if((rc = cmFileSysInitialize(&h,ctx,"fs_test")) != kOkFsRC )
  1048. return rc;
  1049. //----------------------------------------------------------
  1050. // Print the standard directories
  1051. //
  1052. printf("Prefs Dir:%s\n",cmFsPrefsDir());
  1053. printf("Rsrc Dir: %s\n",cmFsRsrcDir());
  1054. printf("User Dir: %s\n",cmFsUserDir());
  1055. //----------------------------------------------------------
  1056. // Run the file system type checker
  1057. //
  1058. fl = cmFileSysIsDir(h,dir0);
  1059. printf("'%s' is%sa directory.\n",dir0, (fl ? e : not));
  1060. fl = cmFileSysIsDir(h,dir1);
  1061. printf("'%s' is%sa directory.\n",dir1, (fl ? e : not));
  1062. fl = cmFileSysIsFile(h,file0);
  1063. printf("'%s' is%sa file.\n",file0, (fl ? e : not));
  1064. fl = cmFileSysIsFile(h,file1);
  1065. printf("'%s' is%sa file.\n",file1, (fl ? e : not));
  1066. //----------------------------------------------------------
  1067. // Test the file name creation functions
  1068. //
  1069. if((fn = cmFileSysMakeUserFn(h,"src","cmFileSys",
  1070. "c","cm","src",NULL)) != NULL)
  1071. {
  1072. printf("File:'%s'\n",fn);
  1073. }
  1074. cmFileSysFreeFn(h,fn);
  1075. if((fn = cmFileSysMakeUserFn(h,"src","cmFileSys",
  1076. ".c","/cm/","/src/",NULL)) != NULL )
  1077. {
  1078. printf("File:'%s'\n",fn);
  1079. }
  1080. cmFileSysFreeFn(h,fn);
  1081. //----------------------------------------------------------
  1082. // Test the file name parsing functions
  1083. //
  1084. const char* fn0 = cmFileSysMakeUserFn(h,"src/cm/src","cmFileSys","c",NULL);
  1085. const char* fn1 = cmFileSysMakeUserFn(h,"src/cm/src","cmFileSys",NULL,NULL);
  1086. const char* fn2 = cmFileSysMakeUserDir(h,"src/cm/src/cmFileSys/",NULL);
  1087. _cmFileSysTestFnParser(h,&ctx->rpt,fn0);
  1088. _cmFileSysTestFnParser(h,&ctx->rpt,fn1);
  1089. _cmFileSysTestFnParser(h,&ctx->rpt,fn2);
  1090. _cmFileSysTestFnParser(h,&ctx->rpt,"cmFileSys.c");
  1091. _cmFileSysTestFnParser(h,&ctx->rpt,"/");
  1092. _cmFileSysTestFnParser(h,&ctx->rpt," ");
  1093. cmFileSysFreeFn(h,fn0);
  1094. cmFileSysFreeFn(h,fn1);
  1095. cmFileSysFreeFn(h,fn1);
  1096. //----------------------------------------------------------
  1097. // Test the directory tree walking routines.
  1098. //
  1099. cmFileSysDirEntry_t* dep;
  1100. unsigned dirEntCnt;
  1101. unsigned filterFlags = kDirFsFl
  1102. | kFileFsFl
  1103. | kRecurseFsFl
  1104. | kFullPathFsFl;
  1105. const char* src_dir = cmFileSysMakeFn(h,dir0,"doc",NULL,NULL);
  1106. cmRptPrintf(&ctx->rpt,"Dir Entry Test: %s\n",src_dir);
  1107. if((dep = cmFileSysDirEntries(h,src_dir,filterFlags,&dirEntCnt)) != NULL)
  1108. {
  1109. unsigned i;
  1110. for(i=0; i<dirEntCnt; ++i)
  1111. cmRptPrintf(&ctx->rpt,"%s\n",dep[i].name);
  1112. cmFileSysDirFreeEntries(h,dep);
  1113. }
  1114. cmFileSysFreeFn(h,src_dir);
  1115. //----------------------------------------------------------
  1116. // Test the directory parsing/building routines.
  1117. //
  1118. cmRptPrintf(&ctx->rpt,"Dir Parsing routings:\n");
  1119. cmChar_t** a;
  1120. unsigned j;
  1121. for(j=0; j<2; ++j)
  1122. {
  1123. const cmChar_t* dstr = dir0 + j;
  1124. if((a = cmFileSysDirParts(h,dstr)) == NULL)
  1125. cmRptPrint(&ctx->rpt,"cmFileSysDirParts() failed.\n");
  1126. else
  1127. {
  1128. unsigned i;
  1129. cmRptPrintf(&ctx->rpt,"Input:%s\n",dstr);
  1130. for(i=0; a[i]!=NULL; ++i)
  1131. cmRptPrintf(&ctx->rpt,"%i : %s\n",i,a[i]);
  1132. cmChar_t* d;
  1133. if((d = cmFileSysFormDir(h,a,
  1134. cmFileSysDirPartsCount(h,a))) != NULL )
  1135. {
  1136. cmRptPrintf(&ctx->rpt,"Reformed:%s\n",d);
  1137. }
  1138. cmFileSysFreeDirParts(h,a);
  1139. }
  1140. }
  1141. //----------------------------------------------------------
  1142. // Test the extended mkdir routine.
  1143. //
  1144. if( cmFileSysMkUserDirAll(h, "/temp/doc/doc" )!=kOkFsRC )
  1145. {
  1146. cmRptPrint(&ctx->rpt,"cmFileSysMkDirAll() failed.\n");
  1147. }
  1148. // finalize the file system
  1149. if((rc = cmFileSysFinalize(&h)) != kOkFsRC )
  1150. return rc;
  1151. cmRptPrintf(&ctx->rpt,"File Test done\n");
  1152. cmFsFreeFn(dir0);
  1153. cmFsFreeFn(dir1);
  1154. cmFsFreeFn(file0);
  1155. cmFsFreeFn(file1);
  1156. return rc;
  1157. }
  1158. // Parse a file name and print the results.
  1159. // Called by cmFileSysTest().
  1160. void _cmFileSysTestFnParser(
  1161. cmFileSysH_t h,
  1162. cmRpt_t* rpt,
  1163. const cmChar_t* fn )
  1164. {
  1165. cmFileSysPathPart_t* pp;
  1166. cmRptPrintf(rpt,"Fn Parse Test:%s\n",fn);
  1167. if((pp = cmFileSysPathParts(h,fn)) != NULL )
  1168. {
  1169. if(pp->dirStr != NULL)
  1170. cmRptPrintf(rpt,"Dir:%s\n",pp->dirStr);
  1171. if(pp->fnStr != NULL)
  1172. cmRptPrintf(rpt,"Fn:%s\n",pp->fnStr);
  1173. if(pp->extStr != NULL )
  1174. cmRptPrintf(rpt,"Ext:%s\n",pp->extStr);
  1175. cmFileSysFreePathParts(h,pp);
  1176. }
  1177. cmRptPrintf(rpt,"\n");
  1178. }
  1179. //)
  1180. //}