libcm is a C development framework with an emphasis on audio signal processing applications.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831
  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 "cmFile.h"
  9. #include "cmFileSys.h"
  10. #include "cmMem.h"
  11. #include "cmMallocDebug.h"
  12. #include "cmLinkedHeap.h"
  13. #include "cmText.h"
  14. #include <sys/stat.h>
  15. cmFileH_t cmFileNullHandle = cmSTATIC_NULL_HANDLE;
  16. typedef struct
  17. {
  18. FILE* fp;
  19. cmErr_t err;
  20. cmChar_t* fnStr;
  21. } cmFile_t;
  22. cmFile_t* _cmFileHandleToPtr( cmFileH_t h )
  23. {
  24. cmFile_t* p = (cmFile_t*)h.h;
  25. assert(p != NULL);
  26. return p;
  27. }
  28. cmFileRC_t _cmFileError( cmFile_t* p, cmFileRC_t rc, int errNumb, const cmChar_t* msg )
  29. {
  30. if(errNumb == 0)
  31. rc = cmErrMsg(&p->err,rc,"%s on file '%s'",msg,p->fnStr);
  32. else
  33. rc = cmErrMsg(&p->err,rc,"%s on file '%s'\nSystem Msg:%s",msg,p->fnStr,strerror(errNumb));
  34. return rc;
  35. }
  36. cmFileRC_t cmFileOpen( cmFileH_t* hp, const cmChar_t* fn, enum cmFileOpenFlags_t flags, cmRpt_t* rpt )
  37. {
  38. char mode[] = "/0/0/0";
  39. cmFile_t* p = NULL;
  40. cmErr_t err;
  41. cmFileRC_t rc;
  42. if((rc = cmFileClose(hp)) != kOkFileRC )
  43. return rc;
  44. cmErrSetup(&err,rpt,"File");
  45. hp->h = NULL;
  46. if( cmIsFlag(flags,kReadFileFl) )
  47. mode[0] = 'r';
  48. else
  49. if( cmIsFlag(flags,kWriteFileFl) )
  50. mode[0] = 'w';
  51. else
  52. if( cmIsFlag(flags,kAppendFileFl) )
  53. mode[0] = 'a';
  54. else
  55. cmErrMsg(&err,kInvalidFlagFileRC,"File open flags must contain 'kReadFileFl','kWriteFileFl', or 'kAppendFileFl'.");
  56. if( cmIsFlag(flags,kUpdateFileFl) )
  57. mode[1] = '+';
  58. // handle requests to use stdin,stdout,stderr
  59. FILE* sfp = NULL;
  60. if( cmIsFlag(flags,kStdoutFileFl) )
  61. {
  62. sfp = stdout;
  63. fn = "stdout";
  64. }
  65. else
  66. if( cmIsFlag(flags,kStderrFileFl) )
  67. {
  68. sfp = stderr;
  69. fn = "stderr";
  70. }
  71. else
  72. if( cmIsFlag(flags,kStdinFileFl) )
  73. {
  74. sfp = stdin;
  75. fn = "stdin";
  76. }
  77. if( fn == NULL )
  78. return cmErrMsg(&err,kObjAllocFailFileRC,"File object allocation failed due to empty file name.");
  79. unsigned byteCnt = sizeof(cmFile_t) + strlen(fn) + 1;
  80. if((p = (cmFile_t*)cmMemMallocZ(byteCnt)) == NULL )
  81. return cmErrMsg(&err,kObjAllocFailFileRC,"File object allocation failed for file '%s'.",cmStringNullGuard(fn));
  82. cmErrClone(&p->err,&err);
  83. p->fnStr = (cmChar_t*)(p+1);
  84. strcpy(p->fnStr,fn);
  85. if( sfp != NULL )
  86. p->fp = sfp;
  87. else
  88. {
  89. errno = 0;
  90. if((p->fp = fopen(fn,mode)) == NULL )
  91. {
  92. cmFileRC_t rc = _cmFileError(p,kOpenFailFileRC,errno,"File open failed");
  93. cmMemFree(p);
  94. return rc;
  95. }
  96. }
  97. hp->h = p;
  98. return kOkFileRC;
  99. }
  100. cmFileRC_t cmFileClose( cmFileH_t* hp )
  101. {
  102. if( cmFileIsValid(*hp) == false )
  103. return kOkFileRC;
  104. cmFile_t* p = _cmFileHandleToPtr(*hp);
  105. errno = 0;
  106. if( p->fp != NULL )
  107. if( fclose(p->fp) != 0 )
  108. return _cmFileError(p,kCloseFailFileRC,errno,"File close failed");
  109. cmMemFree(p);
  110. hp->h = NULL;
  111. return kOkFileRC;
  112. }
  113. bool cmFileIsValid( cmFileH_t h )
  114. { return h.h != NULL; }
  115. cmFileRC_t cmFileRead( cmFileH_t h, void* buf, unsigned bufByteCnt )
  116. {
  117. cmFile_t* p = _cmFileHandleToPtr(h);
  118. errno = 0;
  119. if( fread(buf,bufByteCnt,1,p->fp) != 1 )
  120. return _cmFileError(p,kReadFailFileRC,errno,"File read failed");
  121. return kOkFileRC;
  122. }
  123. cmFileRC_t cmFileWrite( cmFileH_t h, const void* buf, unsigned bufByteCnt )
  124. {
  125. cmFile_t* p = _cmFileHandleToPtr(h);
  126. errno = 0;
  127. if( fwrite(buf,bufByteCnt,1,p->fp) != 1 )
  128. return _cmFileError(p,kWriteFailFileRC,errno,"File write failed");
  129. return kOkFileRC;
  130. }
  131. cmFileRC_t cmFileSeek( cmFileH_t h, enum cmFileSeekFlags_t flags, int offsByteCnt )
  132. {
  133. cmFile_t* p = _cmFileHandleToPtr(h);
  134. unsigned fileflags = 0;
  135. if( cmIsFlag(flags,kBeginFileFl) )
  136. fileflags = SEEK_SET;
  137. else
  138. if( cmIsFlag(flags,kCurFileFl) )
  139. fileflags = SEEK_CUR;
  140. else
  141. if( cmIsFlag(flags,kEndFileFl) )
  142. fileflags = SEEK_END;
  143. else
  144. return cmErrMsg(&p->err,kInvalidFlagFileRC,"Invalid file seek flag on '%s'.",p->fnStr);
  145. errno = 0;
  146. if( fseek(p->fp,offsByteCnt,fileflags) != 0 )
  147. return _cmFileError(p,kSeekFailFileRC,errno,"File seek failed");
  148. return kOkFileRC;
  149. }
  150. cmFileRC_t cmFileTell( cmFileH_t h, long* offsPtr )
  151. {
  152. assert( offsPtr != NULL );
  153. *offsPtr = -1;
  154. cmFile_t* p = _cmFileHandleToPtr(h);
  155. errno = 0;
  156. if((*offsPtr = ftell(p->fp)) == -1)
  157. return _cmFileError(p,kTellFailFileRC,errno,"File tell failed");
  158. return kOkFileRC;
  159. }
  160. bool cmFileEof( cmFileH_t h )
  161. { return feof( _cmFileHandleToPtr(h)->fp ) != 0; }
  162. unsigned cmFileByteCount( cmFileH_t h )
  163. {
  164. struct stat sr;
  165. int f;
  166. cmFile_t* p = _cmFileHandleToPtr(h);
  167. const cmChar_t errMsg[] = "File byte count request failed.";
  168. errno = 0;
  169. if((f = fileno(p->fp)) == -1)
  170. {
  171. _cmFileError(p,kHandleInvalidFileRC,errno,errMsg);
  172. return 0;
  173. }
  174. if(fstat(f,&sr) == -1)
  175. {
  176. _cmFileError(p,kStatFailFileRC,errno,errMsg);
  177. return 0;
  178. }
  179. return sr.st_size;
  180. }
  181. cmFileRC_t cmFileByteCountFn( const cmChar_t* fn, cmRpt_t* rpt, unsigned* fileByteCntPtr )
  182. {
  183. assert( fileByteCntPtr != NULL );
  184. cmFileRC_t rc;
  185. cmFileH_t h = cmFileNullHandle;
  186. if((rc = cmFileOpen(&h,fn,kReadFileFl,rpt)) != kOkFileRC )
  187. return rc;
  188. if( fileByteCntPtr != NULL)
  189. *fileByteCntPtr = cmFileByteCount(h);
  190. cmFileClose(&h);
  191. return rc;
  192. }
  193. cmFileRC_t cmFileCompare( const cmChar_t* fn0, const cmChar_t* fn1, cmRpt_t* rpt, bool* isEqualPtr )
  194. {
  195. cmFileRC_t rc = kOkFileRC;
  196. unsigned bufByteCnt = 2048;
  197. cmFileH_t h0 = cmFileNullHandle;
  198. cmFileH_t h1 = cmFileNullHandle;
  199. char b0[ bufByteCnt ];
  200. char b1[ bufByteCnt ];
  201. assert(isEqualPtr != NULL );
  202. *isEqualPtr = true;
  203. if((rc = cmFileOpen(&h0,fn0,kReadFileFl,rpt)) != kOkFileRC )
  204. goto errLabel;
  205. if((rc = cmFileOpen(&h1,fn1,kReadFileFl,rpt)) != kOkFileRC )
  206. goto errLabel;
  207. cmFile_t* p0 = _cmFileHandleToPtr(h0);
  208. cmFile_t* p1 = _cmFileHandleToPtr(h1);
  209. while(1)
  210. {
  211. size_t n0 = fread(b0,1,bufByteCnt,p0->fp);
  212. size_t n1 = fread(b1,1,bufByteCnt,p1->fp);
  213. if( n0 != n1 || memcmp(b0,b1,n0) != 0 )
  214. {
  215. *isEqualPtr = false;
  216. break;
  217. }
  218. if( n0 != bufByteCnt || n1 != bufByteCnt )
  219. break;
  220. }
  221. errLabel:
  222. cmFileClose(&h0);
  223. cmFileClose(&h1);
  224. return rc;
  225. }
  226. const cmChar_t* cmFileName( cmFileH_t h )
  227. {
  228. cmFile_t* p = _cmFileHandleToPtr(h);
  229. return p->fnStr;
  230. }
  231. cmFileRC_t cmFileFnWrite( const cmChar_t* fn, cmRpt_t* rpt, const void* buf, unsigned bufByteCnt )
  232. {
  233. cmFileH_t h = cmFileNullHandle;
  234. cmFileRC_t rc;
  235. if((rc = cmFileOpen(&h,fn,kWriteFileFl,rpt)) != kOkFileRC )
  236. goto errLabel;
  237. rc = cmFileWrite(h,buf,bufByteCnt);
  238. errLabel:
  239. cmFileClose(&h);
  240. return rc;
  241. }
  242. cmChar_t* _cmFileToBuf( cmFileH_t h, unsigned nn, unsigned* bufByteCntPtr )
  243. {
  244. errno = 0;
  245. unsigned n = cmFileByteCount(h);
  246. cmChar_t* buf = NULL;
  247. cmFile_t* p = _cmFileHandleToPtr(h);
  248. // if the file size calculation is ok
  249. if( errno != 0 )
  250. {
  251. _cmFileError(p,kBufAllocFailFileRC,errno,"Invalid file buffer length.");
  252. goto errLabel;
  253. }
  254. // allocate the read target buffer
  255. if((buf = cmMemAlloc(cmChar_t,n+nn)) == NULL)
  256. {
  257. _cmFileError(p,kBufAllocFailFileRC,0,"Read buffer allocation failed.");
  258. goto errLabel;
  259. }
  260. // read the file
  261. if( cmFileRead(h,buf,n) != kOkFileRC )
  262. goto errLabel;
  263. // zero memory after the file data
  264. memset(buf+n,0,nn);
  265. if( bufByteCntPtr != NULL )
  266. *bufByteCntPtr = n;
  267. return buf;
  268. errLabel:
  269. if( bufByteCntPtr != NULL )
  270. *bufByteCntPtr = 0;
  271. cmMemFree(buf);
  272. return NULL;
  273. }
  274. cmChar_t* _cmFileFnToBuf( const cmChar_t* fn, cmRpt_t* rpt, unsigned nn, unsigned* bufByteCntPtr )
  275. {
  276. cmFileH_t h = cmFileNullHandle;
  277. cmChar_t* buf = NULL;
  278. if( cmFileOpen(&h,fn,kReadFileFl | kBinaryFileFl,rpt) != kOkFileRC )
  279. goto errLabel;
  280. buf = _cmFileToBuf(h,nn,bufByteCntPtr);
  281. errLabel:
  282. cmFileClose(&h);
  283. return buf;
  284. }
  285. cmFileRC_t cmFileCopy(
  286. const cmChar_t* srcDir,
  287. const cmChar_t* srcFn,
  288. const cmChar_t* srcExt,
  289. const cmChar_t* dstDir,
  290. const cmChar_t* dstFn,
  291. const cmChar_t* dstExt,
  292. cmErr_t* err)
  293. {
  294. cmFileRC_t rc = kOkFileRC;
  295. unsigned byteCnt = 0;
  296. cmChar_t* buf = NULL;
  297. const cmChar_t* srcPathFn = NULL;
  298. const cmChar_t* dstPathFn = NULL;
  299. // form the source path fn
  300. if((srcPathFn = cmFsMakeFn(srcDir,srcFn,srcExt,NULL)) == NULL )
  301. {
  302. rc = cmErrMsg(err,kFileSysFailFileRC,"The soure file name for dir:%s name:%s ext:%s could not be formed.",cmStringNullGuard(srcDir),cmStringNullGuard(srcFn),cmStringNullGuard(srcExt));
  303. goto errLabel;
  304. }
  305. // form the dest path fn
  306. if((dstPathFn = cmFsMakeFn(dstDir,dstFn,dstExt,NULL)) == NULL )
  307. {
  308. rc = cmErrMsg(err,kFileSysFailFileRC,"The destination file name for dir:%s name:%s ext:%s could not be formed.",cmStringNullGuard(dstDir),cmStringNullGuard(dstFn),cmStringNullGuard(dstExt));
  309. goto errLabel;
  310. }
  311. // verify that the source exists
  312. if( cmFsIsFile(srcPathFn) == false )
  313. {
  314. rc = cmErrMsg(err,kOpenFailFileRC,"The source file '%s' does not exist.",cmStringNullGuard(srcPathFn));
  315. goto errLabel;
  316. }
  317. // read the source file into a buffer
  318. if((buf = cmFileFnToBuf(srcPathFn,err->rpt,&byteCnt)) == NULL )
  319. rc = cmErrMsg(err,kReadFailFileRC,"Attempt to fill a buffer from '%s' failed.",cmStringNullGuard(srcPathFn));
  320. else
  321. {
  322. // write the file to the output file
  323. if( cmFileFnWrite(dstPathFn,err->rpt,buf,byteCnt) != kOkFileRC )
  324. rc = cmErrMsg(err,kWriteFailFileRC,"An attempt to write a buffer to '%s' failed.",cmStringNullGuard(dstPathFn));
  325. }
  326. errLabel:
  327. // free the buffer
  328. cmMemFree(buf);
  329. cmFsFreeFn(srcPathFn);
  330. cmFsFreeFn(dstPathFn);
  331. return rc;
  332. }
  333. cmFileRC_t cmFileBackup( const cmChar_t* dir, const cmChar_t* name, const cmChar_t* ext, cmErr_t* err )
  334. {
  335. cmFileRC_t rc = kOkFileRC;
  336. cmChar_t* newName = NULL;
  337. const cmChar_t* newFn = NULL;
  338. unsigned n = 0;
  339. const cmChar_t* srcFn = NULL;
  340. cmFileSysPathPart_t* pp = NULL;
  341. // form the name of the backup file
  342. if((srcFn = cmFsMakeFn(dir,name,ext,NULL)) == NULL )
  343. {
  344. rc = cmErrMsg(err,kFileSysFailFileRC,"Backup source file name formation failed.");
  345. goto errLabel;
  346. }
  347. // if the src file does not exist then there is nothing to do
  348. if( cmFsIsFile(srcFn) == false )
  349. return rc;
  350. // break the source file name up into dir/fn/ext.
  351. if((pp = cmFsPathParts(srcFn)) == NULL || pp->fnStr==NULL)
  352. {
  353. rc = cmErrMsg(err,kFileSysFailFileRC,"The file name '%s' could not be parsed into its parts.",cmStringNullGuard(srcFn));
  354. goto errLabel;
  355. }
  356. // iterate until a unique file name is found
  357. for(n=0; 1; ++n)
  358. {
  359. cmFsFreeFn(newFn);
  360. // generate a new file name
  361. newName = cmTsPrintfP(newName,"%s_%i",pp->fnStr,n);
  362. // form the new file name into a complete path
  363. if((newFn = cmFsMakeFn(pp->dirStr,newName,pp->extStr,NULL)) == NULL )
  364. {
  365. rc = cmErrMsg(err,kFileSysFailFileRC,"A backup file name could not be formed for the file '%s'.",cmStringNullGuard(newName));
  366. goto errLabel;
  367. }
  368. // if the new file name is not already in use ...
  369. if( cmFsIsFile(newFn) == false )
  370. {
  371. // .. then duplicate the file
  372. if((rc = cmFileCopy(srcFn,NULL,NULL,newFn,NULL,NULL,err)) != kOkFileRC )
  373. rc = cmErrMsg(err,rc,"The file '%s' could not be duplicated as '%s'.",cmStringNullGuard(srcFn),cmStringNullGuard(newFn));
  374. break;
  375. }
  376. }
  377. errLabel:
  378. cmFsFreeFn(srcFn);
  379. cmFsFreeFn(newFn);
  380. cmMemFree(newName);
  381. cmFsFreePathParts(pp);
  382. return rc;
  383. }
  384. cmChar_t* cmFileToBuf( cmFileH_t h, unsigned* bufByteCntPtr )
  385. { return _cmFileToBuf(h,0,bufByteCntPtr); }
  386. cmChar_t* cmFileFnToBuf( const cmChar_t* fn, cmRpt_t* rpt, unsigned* bufByteCntPtr )
  387. { return _cmFileFnToBuf(fn,rpt,0,bufByteCntPtr); }
  388. cmChar_t* cmFileToStr( cmFileH_t h, unsigned* bufByteCntPtr )
  389. { return _cmFileToBuf(h,1,bufByteCntPtr); }
  390. cmChar_t* cmFileFnToStr( const cmChar_t* fn, cmRpt_t* rpt, unsigned* bufByteCntPtr )
  391. { return _cmFileFnToBuf(fn,rpt,1,bufByteCntPtr); }
  392. cmFileRC_t cmFileLineCount( cmFileH_t h, unsigned* lineCntPtr )
  393. {
  394. cmFileRC_t rc = kOkFileRC;
  395. cmFile_t* p = _cmFileHandleToPtr(h);
  396. unsigned lineCnt = 0;
  397. long offs;
  398. int c;
  399. assert( lineCntPtr != NULL );
  400. *lineCntPtr = 0;
  401. if((rc = cmFileTell(h,&offs)) != kOkFileRC )
  402. return rc;
  403. errno = 0;
  404. while(1)
  405. {
  406. c = fgetc(p->fp);
  407. if( c == EOF )
  408. {
  409. if( errno )
  410. rc =_cmFileError(p,kReadFailFileRC,errno,"File read char failed");
  411. else
  412. ++lineCnt; // add one in case the last line isn't terminated with a '\n'.
  413. break;
  414. }
  415. // if an end-of-line was encountered
  416. if( c == '\n' )
  417. ++lineCnt;
  418. }
  419. if((rc = cmFileSeek(h,kBeginFileFl,offs)) != kOkFileRC )
  420. return rc;
  421. *lineCntPtr = lineCnt;
  422. return rc;
  423. }
  424. cmFileRC_t _cmFileGetLine( cmFile_t* p, cmChar_t* buf, unsigned* bufByteCntPtr )
  425. {
  426. // fgets() reads up to n-1 bytes into buf[]
  427. if( fgets(buf,*bufByteCntPtr,p->fp) == NULL )
  428. {
  429. // an read error or EOF condition occurred
  430. *bufByteCntPtr = 0;
  431. if( !feof(p->fp ) )
  432. return _cmFileError(p,kReadFailFileRC,errno,"File read line failed");
  433. return kReadFailFileRC;
  434. }
  435. return kOkFileRC;
  436. }
  437. cmFileRC_t cmFileGetLine( cmFileH_t h, cmChar_t* buf, unsigned* bufByteCntPtr )
  438. {
  439. assert( bufByteCntPtr != NULL );
  440. cmFile_t* p = _cmFileHandleToPtr(h);
  441. unsigned tn = 128;
  442. cmChar_t t[ tn ];
  443. unsigned on = *bufByteCntPtr;
  444. long offs;
  445. cmFileRC_t rc;
  446. // store the current file offset
  447. if((rc = cmFileTell(h,&offs)) != kOkFileRC )
  448. return rc;
  449. // if no buffer was given then use t[]
  450. if( buf == NULL || *bufByteCntPtr == 0 )
  451. {
  452. *bufByteCntPtr = tn;
  453. buf = t;
  454. }
  455. // fill the buffer from the current line
  456. if((rc = _cmFileGetLine(p,buf,bufByteCntPtr)) != kOkFileRC )
  457. return rc;
  458. // get length of the string in the buffer
  459. // (this is one less than the count of bytes written to the buffer)
  460. unsigned n = strlen(buf);
  461. // if the provided buffer was large enough to read the entire string
  462. if( on > n+1 )
  463. {
  464. //*bufByteCntPtr = n+1;
  465. return kOkFileRC;
  466. }
  467. //
  468. // the provided buffer was not large enough
  469. //
  470. // m tracks the length of the string
  471. unsigned m = n;
  472. while( n+1 == *bufByteCntPtr )
  473. {
  474. // fill the buffer from the current line
  475. if((rc = _cmFileGetLine(p,buf,bufByteCntPtr)) != kOkFileRC )
  476. return rc;
  477. n = strlen(buf);
  478. m += n;
  479. }
  480. // restore the original file offset
  481. if((rc = cmFileSeek(h,kBeginFileFl,offs)) != kOkFileRC )
  482. return rc;
  483. // add 1 for /0, 1 for /n and 1 to detect buf-too-short
  484. *bufByteCntPtr = m+3;
  485. return kBufTooSmallFileRC;
  486. }
  487. cmFileRC_t cmFileGetLineAuto( cmFileH_t h, cmChar_t** bufPtrPtr, unsigned* bufByteCntPtr )
  488. {
  489. cmFileRC_t rc = kOkFileRC;
  490. bool fl = true;
  491. cmChar_t* buf = *bufPtrPtr;
  492. *bufPtrPtr = NULL;
  493. while(fl)
  494. {
  495. fl = false;
  496. switch( rc = cmFileGetLine(h,buf,bufByteCntPtr) )
  497. {
  498. case kOkFileRC:
  499. {
  500. *bufPtrPtr = buf;
  501. }
  502. break;
  503. case kBufTooSmallFileRC:
  504. buf = cmMemResizeZ(cmChar_t,buf,*bufByteCntPtr);
  505. fl = true;
  506. break;
  507. default:
  508. cmMemFree(buf);
  509. break;
  510. }
  511. }
  512. return rc;
  513. }
  514. cmFileRC_t cmFileReadChar( cmFileH_t h, char* buf, unsigned cnt )
  515. { return cmFileRead(h,buf,sizeof(buf[0])*cnt); }
  516. cmFileRC_t cmFileReadUChar( cmFileH_t h, unsigned char* buf, unsigned cnt )
  517. { return cmFileRead(h,buf,sizeof(buf[0])*cnt); }
  518. cmFileRC_t cmFileReadShort( cmFileH_t h, short* buf, unsigned cnt )
  519. { return cmFileRead(h,buf,sizeof(buf[0])*cnt); }
  520. cmFileRC_t cmFileReadUShort( cmFileH_t h, unsigned short* buf, unsigned cnt )
  521. { return cmFileRead(h,buf,sizeof(buf[0])*cnt); }
  522. cmFileRC_t cmFileReadLong( cmFileH_t h, long* buf, unsigned cnt )
  523. { return cmFileRead(h,buf,sizeof(buf[0])*cnt); }
  524. cmFileRC_t cmFileReadULong( cmFileH_t h, unsigned long* buf, unsigned cnt )
  525. { return cmFileRead(h,buf,sizeof(buf[0])*cnt); }
  526. cmFileRC_t cmFileReadInt( cmFileH_t h, int* buf, unsigned cnt )
  527. { return cmFileRead(h,buf,sizeof(buf[0])*cnt); }
  528. cmFileRC_t cmFileReadUInt( cmFileH_t h, unsigned int* buf, unsigned cnt )
  529. { return cmFileRead(h,buf,sizeof(buf[0])*cnt); }
  530. cmFileRC_t cmFileReadFloat( cmFileH_t h, float* buf, unsigned cnt )
  531. { return cmFileRead(h,buf,sizeof(buf[0])*cnt); }
  532. cmFileRC_t cmFileReadDouble( cmFileH_t h, double* buf, unsigned cnt )
  533. { return cmFileRead(h,buf,sizeof(buf[0])*cnt); }
  534. cmFileRC_t cmFileReadBool( cmFileH_t h, bool* buf, unsigned cnt )
  535. { return cmFileRead(h,buf,sizeof(buf[0])*cnt); }
  536. cmFileRC_t cmFileWriteChar( cmFileH_t h, const char* buf, unsigned cnt )
  537. { return cmFileWrite(h,buf,sizeof(buf[0])*cnt); }
  538. cmFileRC_t cmFileWriteUChar( cmFileH_t h, const unsigned char* buf, unsigned cnt )
  539. { return cmFileWrite(h,buf,sizeof(buf[0])*cnt); }
  540. cmFileRC_t cmFileWriteShort( cmFileH_t h, const short* buf, unsigned cnt )
  541. { return cmFileWrite(h,buf,sizeof(buf[0])*cnt); }
  542. cmFileRC_t cmFileWriteUShort( cmFileH_t h, const unsigned short* buf, unsigned cnt )
  543. { return cmFileWrite(h,buf,sizeof(buf[0])*cnt); }
  544. cmFileRC_t cmFileWriteLong( cmFileH_t h, const long* buf, unsigned cnt )
  545. { return cmFileWrite(h,buf,sizeof(buf[0])*cnt); }
  546. cmFileRC_t cmFileWriteULong( cmFileH_t h, const unsigned long* buf, unsigned cnt )
  547. { return cmFileWrite(h,buf,sizeof(buf[0])*cnt); }
  548. cmFileRC_t cmFileWriteInt( cmFileH_t h, const int* buf, unsigned cnt )
  549. { return cmFileWrite(h,buf,sizeof(buf[0])*cnt); }
  550. cmFileRC_t cmFileWriteUInt( cmFileH_t h, const unsigned int* buf, unsigned cnt )
  551. { return cmFileWrite(h,buf,sizeof(buf[0])*cnt); }
  552. cmFileRC_t cmFileWriteFloat( cmFileH_t h, const float* buf, unsigned cnt )
  553. { return cmFileWrite(h,buf,sizeof(buf[0])*cnt); }
  554. cmFileRC_t cmFileWriteDouble( cmFileH_t h, const double* buf, unsigned cnt )
  555. { return cmFileWrite(h,buf,sizeof(buf[0])*cnt); }
  556. cmFileRC_t cmFileWriteBool( cmFileH_t h, const bool* buf, unsigned cnt )
  557. { return cmFileWrite(h,buf,sizeof(buf[0])*cnt); }
  558. cmFileRC_t cmFileWriteStr( cmFileH_t h, const cmChar_t* s )
  559. {
  560. cmFileRC_t rc;
  561. unsigned n = cmTextLength(s);
  562. if((rc = cmFileWriteUInt(h,&n,1)) != kOkFileRC )
  563. return rc;
  564. if( n > 0 )
  565. rc = cmFileWriteChar(h,s,n);
  566. return rc;
  567. }
  568. cmFileRC_t cmFileReadStr( cmFileH_t h, cmChar_t** sRef, unsigned maxCharN )
  569. {
  570. unsigned n;
  571. cmFileRC_t rc;
  572. assert(sRef != NULL );
  573. *sRef = NULL;
  574. if( maxCharN == 0 )
  575. maxCharN = 16384;
  576. // read the string length
  577. if((rc = cmFileReadUInt(h,&n,1)) != kOkFileRC )
  578. return rc;
  579. // verify that string isn't too long
  580. if( n > maxCharN )
  581. {
  582. cmFile_t* p = _cmFileHandleToPtr(h);
  583. return cmErrMsg(&p->err,kBufAllocFailFileRC,"The stored string is larger than the maximum allowable size.");
  584. }
  585. // allocate a read buffer
  586. cmChar_t* s = cmMemAllocZ(cmChar_t,n+1);
  587. // fill the buffer from the file
  588. if((rc = cmFileReadChar(h,s,n)) != kOkFileRC )
  589. return rc;
  590. s[n] = 0; // terminate the string
  591. *sRef = s;
  592. return rc;
  593. }
  594. cmFileRC_t cmFilePrint( cmFileH_t h, const cmChar_t* text )
  595. {
  596. cmFile_t* p = _cmFileHandleToPtr(h);
  597. errno = 0;
  598. if( fputs(text,p->fp) < 0 )
  599. return _cmFileError(p,kPrintFailFileRC,errno,"File print failed");
  600. return kOkFileRC;
  601. }
  602. cmFileRC_t cmFileVPrintf( cmFileH_t h, const cmChar_t* fmt, va_list vl )
  603. {
  604. cmFile_t* p = _cmFileHandleToPtr(h);
  605. if( vfprintf(p->fp,fmt,vl) < 0 )
  606. return _cmFileError(p,kPrintFailFileRC,errno,"File print failed");
  607. return kOkFileRC;
  608. }
  609. cmFileRC_t cmFilePrintf( cmFileH_t h, const cmChar_t* fmt, ... )
  610. {
  611. va_list vl;
  612. va_start(vl,fmt);
  613. cmFileRC_t rc = cmFileVPrintf(h,fmt,vl);
  614. va_end(vl);
  615. return rc;
  616. }
  617. cmFileRC_t cmFileLastRC( cmFileH_t h )
  618. {
  619. cmFile_t* p = _cmFileHandleToPtr(h);
  620. return cmErrLastRC(&p->err);
  621. }
  622. cmFileRC_t cmFileSetRC( cmFileH_t h, cmFileRC_t rc )
  623. {
  624. cmFile_t* p = _cmFileHandleToPtr(h);
  625. return cmErrSetRC(&p->err,rc);
  626. }