libcm is a C development framework with an emphasis on audio signal processing applications.
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

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