libcm is a C development framework with an emphasis on audio signal processing applications.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325
  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 "cmText.h"
  12. #include "cmFloatTypes.h"
  13. #include "cmVectOps.h"
  14. typedef struct cmTextSys_str
  15. {
  16. cmErr_t err;
  17. cmLHeapH_t lhH;
  18. cmChar_t* buf;
  19. } cmTextSys_t;
  20. cmTextSysH_t cmTextSysNullHandle = cmSTATIC_NULL_HANDLE;
  21. cmTextSysH_t _cmTextSysGlobalH = cmSTATIC_NULL_HANDLE;
  22. cmTextSys_t* _cmTextSysHandleToPtr( cmTextSysH_t h )
  23. {
  24. cmTextSys_t* p = (cmTextSys_t*)h.h;
  25. assert(p != NULL);
  26. return p;
  27. }
  28. cmTxRC_t _cmTextSysFinalize( cmTextSys_t* p )
  29. {
  30. cmTxRC_t rc = kOkTxRC;
  31. if( cmLHeapIsValid(p->lhH) )
  32. cmLHeapDestroy(&p->lhH);
  33. cmMemFree(p->buf);
  34. cmMemFree(p);
  35. return rc;
  36. }
  37. cmTxRC_t cmTextSysInitialize( cmCtx_t* ctx, cmTextSysH_t* hp )
  38. {
  39. cmTxRC_t rc;
  40. if((rc = cmTextSysFinalize(hp)) != kOkTxRC )
  41. return rc;
  42. cmTextSys_t* p = cmMemAllocZ(cmTextSys_t,1);
  43. cmErrSetup(&p->err,&ctx->rpt,"Text System");
  44. if( cmLHeapIsValid( p->lhH = cmLHeapCreate( 8192, ctx )) == false )
  45. {
  46. rc = cmErrMsg(&p->err,kLHeapFailTxRC,"Linked Heap create failed.");
  47. goto errLabel;
  48. }
  49. hp->h = p;
  50. errLabel:
  51. return rc;
  52. }
  53. cmTxRC_t cmTextSysFinalize( cmTextSysH_t* hp )
  54. {
  55. cmTxRC_t rc = kOkTxRC;
  56. if( hp == NULL || cmTextSysIsValid(*hp)==false )
  57. return kOkTxRC;
  58. cmTextSys_t* p = _cmTextSysHandleToPtr(*hp);
  59. if((rc = _cmTextSysFinalize(p)) == kOkTxRC )
  60. {
  61. hp->h = NULL;
  62. }
  63. return rc;
  64. }
  65. bool cmTextSysIsValid( cmTextSysH_t h )
  66. { return h.h != NULL; }
  67. cmChar_t* _cmTextSysVPrintf( cmTextSysH_t h, cmLHeapH_t lhH, bool staticFl, const cmChar_t* fmt, va_list vl )
  68. {
  69. va_list vl1;
  70. va_copy(vl1,vl);
  71. cmTextSys_t* p = cmLHeapIsValid(lhH) ? NULL : _cmTextSysHandleToPtr(h);
  72. unsigned n = vsnprintf(NULL,0,fmt,vl);
  73. cmChar_t* s = NULL;
  74. if( staticFl )
  75. s = p->buf = cmMemResize(cmChar_t,p->buf,n+1);
  76. else
  77. s = cmLhAllocZ(cmLHeapIsValid(lhH) ? lhH : p->lhH,cmChar_t,n+1);
  78. unsigned m = vsnprintf(s,n+1,fmt,vl1);
  79. assert(m==n);
  80. s[n] = 0;
  81. va_end(vl1);
  82. return s;
  83. }
  84. cmChar_t* cmTextSysVPrintfH( cmLHeapH_t lhH, const cmChar_t* fmt, va_list vl )
  85. { return _cmTextSysVPrintf( cmTextSysNullHandle, lhH, false, fmt, vl ); }
  86. cmChar_t* cmTextSysPrintfH( cmLHeapH_t lhH, const cmChar_t* fmt, ... )
  87. {
  88. va_list vl;
  89. va_start( vl, fmt );
  90. cmChar_t* s = cmTextSysVPrintfH(lhH,fmt,vl);
  91. va_end(vl);
  92. return s;
  93. }
  94. cmChar_t* cmTextSysVPrintfS( cmTextSysH_t h, const cmChar_t* fmt, va_list vl )
  95. { return _cmTextSysVPrintf(h,cmLHeapNullHandle,true,fmt,vl); }
  96. cmChar_t* cmTextSysPrintfS( cmTextSysH_t h, const cmChar_t* fmt, ... )
  97. {
  98. va_list vl;
  99. va_start(vl,fmt);
  100. cmChar_t* s = cmTextSysVPrintfS(h,fmt,vl);
  101. va_end(vl);
  102. return s;
  103. }
  104. cmChar_t* cmTextSysVPrintf( cmTextSysH_t h, const cmChar_t* fmt, va_list vl )
  105. { return _cmTextSysVPrintf(h,cmLHeapNullHandle,false,fmt,vl); }
  106. cmChar_t* cmTextSysPrintf( cmTextSysH_t h, const cmChar_t* fmt, ... )
  107. {
  108. va_list vl;
  109. va_start(vl,fmt);
  110. cmChar_t* s = cmTextSysVPrintf(h,fmt,vl);
  111. va_end(vl);
  112. return s;
  113. }
  114. void cmTextSysFreeStr( cmTextSysH_t h, const cmChar_t* s )
  115. {
  116. cmTextSys_t* p = _cmTextSysHandleToPtr(h);
  117. cmLhFree(p->lhH,(cmChar_t*)s);
  118. }
  119. bool cmTextSysIsStored(cmTextSysH_t h, const cmChar_t* s )
  120. {
  121. cmTextSys_t* p = _cmTextSysHandleToPtr(h);
  122. return cmLHeapIsPtrInHeap(p->lhH,s);
  123. }
  124. //
  125. // Global interface
  126. //
  127. cmTxRC_t cmTsInitialize( cmCtx_t* ctx )
  128. { return cmTextSysInitialize(ctx,&_cmTextSysGlobalH); }
  129. cmTxRC_t cmTsFinalize()
  130. { return cmTextSysFinalize(&_cmTextSysGlobalH); }
  131. bool cmTsIsValid()
  132. { return cmTextSysIsValid(_cmTextSysGlobalH); }
  133. cmChar_t* cmTsVPrintfS( const cmChar_t* fmt, va_list vl )
  134. { return cmTextSysVPrintfS(_cmTextSysGlobalH,fmt,vl); }
  135. cmChar_t* cmTsPrintfS( const cmChar_t* fmt, ... )
  136. {
  137. va_list vl;
  138. va_start(vl,fmt);
  139. cmChar_t* s = cmTsVPrintfS(fmt,vl);
  140. va_end(vl);
  141. return s;
  142. }
  143. cmChar_t* cmTsVPrintfH( cmLHeapH_t h, const cmChar_t* fmt, va_list vl )
  144. { return cmTextSysVPrintfH(h,fmt,vl); }
  145. cmChar_t* cmTsPrintfH( cmLHeapH_t h, const cmChar_t* fmt, ... )
  146. {
  147. va_list vl;
  148. va_start(vl,fmt);
  149. cmChar_t* s = cmTsVPrintfH(h,fmt,vl);
  150. va_end(vl);
  151. return s;
  152. }
  153. cmChar_t* cmTsVPrintf( const cmChar_t* fmt, va_list vl )
  154. { return cmTextSysVPrintf(_cmTextSysGlobalH,fmt,vl); }
  155. cmChar_t* cmTsPrintf( const cmChar_t* fmt, ... )
  156. {
  157. va_list vl;
  158. va_start(vl,fmt);
  159. cmChar_t* s = cmTsVPrintf(fmt,vl);
  160. va_end(vl);
  161. return s;
  162. }
  163. void cmTsFreeStr( const cmChar_t* s )
  164. { cmTextSysFreeStr(_cmTextSysGlobalH,s); }
  165. bool cmTsIsStored( const cmChar_t* s )
  166. { return cmTextSysIsStored(_cmTextSysGlobalH,s); }
  167. cmChar_t* cmTsVPrintfP( cmChar_t* s, const cmChar_t* fmt, va_list vl )
  168. {
  169. va_list vl1;
  170. va_copy(vl1,vl);
  171. int n = vsnprintf(NULL,0,fmt,vl);
  172. assert(n != -1);
  173. s = cmMemResize(cmChar_t,s,n+1);
  174. unsigned m = vsnprintf(s,n+1,fmt,vl1);
  175. assert(m==n);
  176. s[n] = 0;
  177. return s;
  178. }
  179. cmChar_t* cmTsPrintfP( cmChar_t* s, const cmChar_t* fmt, ... )
  180. {
  181. va_list vl;
  182. va_start(vl,fmt);
  183. s = cmTsVPrintfP(s,fmt,vl);
  184. va_end(vl);
  185. return s;
  186. }
  187. void _cmTxError( cmErr_t* err, cmTxRC_t rc, const char* fmt, ... )
  188. {
  189. va_list vl;
  190. va_start(vl,fmt);
  191. cmErrVMsg(err,rc,fmt,vl);
  192. va_end(vl);
  193. }
  194. cmTxRC_t _cmTxRptError( cmErr_t* err, const char* msg, const char* inputText )
  195. {
  196. if( err == NULL )
  197. return kOkTxRC;
  198. if( inputText == NULL )
  199. {
  200. _cmTxError(err,kNullTxRC,"Text to %s conversion failed due to NULL input text.");
  201. return kNullTxRC;
  202. }
  203. if( errno != 0 )
  204. {
  205. _cmTxError(err,kCvtErrTxRC,"Text to %s conversion failed on input '%s'.",msg,inputText);
  206. return kCvtErrTxRC;
  207. }
  208. return kOkTxRC;
  209. }
  210. cmTxRC_t cmTextToInt(const char* text, int* vp, cmErr_t* err )
  211. {
  212. assert( vp != NULL );
  213. cmTxRC_t rc = kOkTxRC;
  214. int en = errno;
  215. errno = 0;
  216. *vp = text==NULL ? 0 : strtol(text,NULL,0);
  217. rc = _cmTxRptError(err,"integer",text);
  218. errno = en;
  219. return rc;
  220. }
  221. cmTxRC_t cmTextToUInt( const char* text, unsigned* vp, cmErr_t* err )
  222. {
  223. assert( vp != NULL );
  224. cmTxRC_t rc = kOkTxRC;
  225. int en = errno;
  226. errno = 0;
  227. *vp = text==NULL ? 0 : (unsigned)strtol(text,NULL,0);
  228. rc = _cmTxRptError(err,"unsigned integer",text);
  229. errno = en;
  230. return rc;
  231. }
  232. cmTxRC_t cmTextToFloat( const char* text, float* vp, cmErr_t* err )
  233. {
  234. assert( vp != NULL );
  235. cmTxRC_t rc = kOkTxRC;
  236. int en = errno;
  237. errno = 0;
  238. *vp = text==NULL ? 0 : (float)strtod(text,NULL);
  239. rc = _cmTxRptError(err,"float",text);
  240. errno = en;
  241. return rc;
  242. }
  243. cmTxRC_t cmTextToDouble( const char* text, double* vp, cmErr_t* err )
  244. {
  245. assert( vp != NULL );
  246. cmTxRC_t rc = kOkTxRC;
  247. int en = errno;
  248. errno = 0;
  249. *vp = text==NULL ? 0 : strtod(text,NULL);
  250. rc = _cmTxRptError(err,"double",text);
  251. errno = en;
  252. return rc;
  253. }
  254. cmTxRC_t cmTextToBool( const char* text, bool* vp, cmErr_t* err )
  255. {
  256. assert( vp != NULL );
  257. cmTxRC_t rc = kOkTxRC;
  258. if( strcasecmp(text,"true") == 0 || strcasecmp(text,"0") == 0 )
  259. *vp = true;
  260. else
  261. if( strcasecmp(text,"false") == 0 || strcasecmp(text,"1") == 0 )
  262. *vp = false;
  263. else
  264. rc = _cmTxRptError(err,"bool",text);
  265. return rc;
  266. }
  267. cmChar_t* cmTextNextNonWhiteOrEos( cmChar_t* s )
  268. {
  269. assert( s != NULL );
  270. while( (*s) && isspace(*s) )
  271. ++s;
  272. return s;
  273. }
  274. const cmChar_t* cmTextNextNonWhiteOrEosC( const cmChar_t* s )
  275. { return cmTextNextNonWhiteOrEos((cmChar_t*)s); }
  276. cmChar_t* cmTextNextNonWhite( cmChar_t* s )
  277. { //return (*(s=cmTextNextNonWhiteOrEos(s))) == 0 ? NULL : s;
  278. s=cmTextNextNonWhiteOrEos(s);
  279. if( *s == 0 )
  280. return NULL;
  281. return s;
  282. }
  283. const cmChar_t* cmTextNextNonWhiteC( const cmChar_t* s )
  284. { return cmTextNextNonWhite((cmChar_t*)s); }
  285. cmChar_t* cmTextPrevNonWhiteOrBos( cmChar_t* s0, const cmChar_t* s1 )
  286. {
  287. assert( s0!=NULL && s1!=NULL && s0 <= s1 );
  288. for(; s0 < s1; --s1 )
  289. if( !isspace(*s1) )
  290. break;
  291. return (cmChar_t*)s1;
  292. }
  293. const cmChar_t* cmTextPrevNonWhiteOrBosC( const cmChar_t* s0, const cmChar_t* s1 )
  294. { return cmTextPrevNonWhiteOrBos((cmChar_t*)s0,s1); }
  295. cmChar_t* cmTextPrevNonWhite( cmChar_t* s0, const cmChar_t* s1 )
  296. {
  297. cmChar_t* s2;
  298. if((s2 = cmTextPrevNonWhiteOrBos(s0,s1)) == s0 )
  299. return NULL;
  300. return s2;
  301. }
  302. const cmChar_t* cmTextPrevNonWhiteC( const cmChar_t* s0, const cmChar_t* s1 )
  303. { return cmTextPrevNonWhite((cmChar_t*)s0,s1); }
  304. cmChar_t* cmTextNextWhiteOrEos( cmChar_t* s )
  305. {
  306. assert( s!=NULL);
  307. while(*s && !isspace(*s) )
  308. ++s;
  309. return s;
  310. }
  311. const cmChar_t* cmTextNextWhiteOrEosC( const cmChar_t* s )
  312. { return cmTextNextWhiteOrEos((cmChar_t*)s); }
  313. cmChar_t* cmTextNextWhite( cmChar_t* s )
  314. { return (*(s=cmTextNextWhiteOrEos(s)))!=0 ? s : NULL; }
  315. const cmChar_t* cmTextNextWhiteC( const cmChar_t* s )
  316. { return cmTextNextWhite((cmChar_t*)s); }
  317. cmChar_t* cmTextPrevWhiteOrBos( cmChar_t* s0, const cmChar_t* s1 )
  318. {
  319. assert( s0!=NULL && s1!=NULL && s0 <= s1 );
  320. while( s1>s0 && !isspace(*s1) )
  321. --s1;
  322. return (cmChar_t*)s1;
  323. }
  324. const cmChar_t* cmTextPrevWhiteOrBosC( const cmChar_t* s0, const cmChar_t* s1 )
  325. { return cmTextPrevWhiteOrBos((cmChar_t*)s0,s1); }
  326. cmChar_t* cmTextPrevWhite( cmChar_t* s0, const cmChar_t* s1 )
  327. {
  328. cmChar_t* s2;
  329. if((s2 = cmTextPrevWhiteOrBos(s0,s1)) == s0 )
  330. return NULL;
  331. return s2;
  332. }
  333. const cmChar_t* cmTextPrevWhiteC( const cmChar_t* s0, const cmChar_t* s1 )
  334. { return cmTextPrevWhite((cmChar_t*)s0,s1); }
  335. cmChar_t* cmTextBegOfLine( cmChar_t* s0, const cmChar_t* s1 )
  336. {
  337. assert( s1!=NULL && s0!=NULL && s1 >= s0 );
  338. if( s0 == s1 )
  339. return s0;
  340. --s1;
  341. while( s1>s0 && *s1 != '\n' )
  342. --s1;
  343. if( *s1 == '\n' )
  344. ++s1;
  345. return (cmChar_t*)s1;
  346. }
  347. const cmChar_t* cmTextBegOfLineC( const cmChar_t* s0, const cmChar_t* s1 )
  348. { return cmTextBegOfLine((cmChar_t*)s0,s1); }
  349. cmChar_t* cmTextEndOfLine( cmChar_t* s )
  350. {
  351. assert( s!=NULL);
  352. while( *s!=0 && *s != '\n' )
  353. ++s;
  354. return s;
  355. }
  356. const cmChar_t* cmTextEndOfLineC( const cmChar_t* s )
  357. { return cmTextEndOfLine((cmChar_t*)s); }
  358. cmChar_t* cmTextLastNonWhiteChar( const cmChar_t* s )
  359. {
  360. unsigned n;
  361. if(s==NULL || (n = strlen(s)) == 0 )
  362. return NULL;
  363. cmChar_t* s0 = (cmChar_t*)s + n-1;
  364. for(; s0>=s; --s0)
  365. if( !isspace(*s0) )
  366. return s0;
  367. return NULL;
  368. }
  369. const cmChar_t* cmTextLastNonWhiteCharC( const cmChar_t* s )
  370. { return cmTextLastNonWhiteChar(s); }
  371. cmChar_t* cmTextLastWhiteChar( const cmChar_t* s )
  372. {
  373. unsigned n;
  374. if(s==NULL || (n = strlen(s)) == 0 )
  375. return NULL;
  376. cmChar_t* s0 = (cmChar_t*)s + n-1;
  377. for(; s0>=s; --s0)
  378. if( isspace(*s0) )
  379. return s0;
  380. return NULL;
  381. }
  382. const cmChar_t* cmTextLastWhiteCharC( const cmChar_t* s )
  383. { return cmTextLastWhiteChar(s); }
  384. void cmTextShrinkS( cmChar_t* s, const cmChar_t* t, unsigned tn )
  385. { cmVOC_Shrink(s,strlen(s)+1,t,tn); }
  386. void cmTextShrinkSN(cmChar_t* s, unsigned sn, const cmChar_t* t, unsigned tn )
  387. { cmVOC_Shrink(s,sn,t,tn); }
  388. void cmTextClip( cmChar_t* s, unsigned n )
  389. {
  390. if( n == 0 || s == NULL || strlen(s)==0 )
  391. return;
  392. if( n >= strlen(s) )
  393. {
  394. s[0]=0;
  395. return;
  396. }
  397. s[ strlen(s)-n ] = 0;
  398. }
  399. cmChar_t* cmTextTrimBegin( cmChar_t* s )
  400. {
  401. if( s==NULL || strlen(s) == 0 )
  402. return s;
  403. cmChar_t* s0 = cmTextNextNonWhite(s);
  404. // no non-white char's exist
  405. if( s0 == NULL )
  406. {
  407. s[0] = 0;
  408. return s;
  409. }
  410. if( s0 != s )
  411. cmTextShrinkS(s,s,s0-s);
  412. return s;
  413. }
  414. cmChar_t* cmTextTrimEnd( cmChar_t* s )
  415. {
  416. unsigned sn;
  417. if( s==NULL || (sn = strlen(s))==0)
  418. return s;
  419. cmChar_t* s0 = cmTextLastNonWhiteChar(s);
  420. if(s0-s+1 < sn )
  421. s[s0-s+1] = 0;
  422. return s;
  423. }
  424. cmChar_t* cmTextTrim( cmChar_t* s)
  425. {
  426. cmTextTrimBegin(s);
  427. cmTextTrimEnd(s);
  428. return s;
  429. }
  430. cmChar_t* cmTextExpandS( cmChar_t* s, const cmChar_t* t, unsigned tn )
  431. { return cmVOC_Expand(s,strlen(s)+1,t,tn); }
  432. cmChar_t* cmTextReplaceSN( cmChar_t* s, const cmChar_t* t, unsigned tn, const cmChar_t* u, unsigned un )
  433. {
  434. unsigned n = strlen(s)+1;
  435. return cmVOC_Replace(s,&n,t,tn,u,un);
  436. }
  437. cmChar_t* cmTextReplaceS( cmChar_t* s, const cmChar_t* t, unsigned tn, const cmChar_t* u )
  438. { return cmTextReplaceSN(s,t,tn,u,u==NULL ? 0 : strlen(u)); }
  439. cmChar_t* _cmTextReplace( cmChar_t* s, const cmChar_t* t, const cmChar_t* u, unsigned n )
  440. {
  441. // we will go into an endless loop if 't' is contained in 'u' and n > 1.
  442. //assert( s!= NULL && t!=NULL && u!=NULL && (n==1 || strstr(u,t) == NULL) );
  443. assert( s!= NULL && t!=NULL && u!=NULL );
  444. int tn = strlen(t);
  445. cmChar_t* c = NULL;
  446. unsigned i = 0;
  447. cmChar_t* s0 = s;
  448. while( (c = strstr(s0,t)) != NULL )
  449. {
  450. int offs = c - s;
  451. s = cmTextReplaceS(s,c,tn,u);
  452. assert(s!=NULL);
  453. s0 = s + offs + tn;
  454. ++i;
  455. if( n!=cmInvalidCnt && i>=n)
  456. break;
  457. };
  458. return s;
  459. }
  460. cmChar_t* cmTextReplaceAll( cmChar_t* s, const cmChar_t* t, const cmChar_t* u )
  461. { return _cmTextReplace(s,t,u,cmInvalidCnt); }
  462. cmChar_t* cmTextReplaceFirst( cmChar_t* s, const cmChar_t* t, const cmChar_t* u )
  463. { return _cmTextReplace(s,t,u,1); }
  464. cmChar_t* cmTextInsertSN( cmChar_t* s, const cmChar_t* t, const cmChar_t* u, unsigned un )
  465. {
  466. unsigned n = strlen(s)+1;
  467. return cmVOC_Replace(s,&n,t,0,u,un);
  468. }
  469. cmChar_t* cmTextInsertS( cmChar_t* s, const cmChar_t* t, const cmChar_t* u )
  470. { return cmTextInsertSN(s,t,u,u==NULL?0:strlen(u)); }
  471. cmChar_t* cmTextAppend( cmChar_t* s, unsigned* sn, const cmChar_t* u, unsigned un )
  472. { return cmVOC_Replace(s,sn,s+(*sn),0,u,un); }
  473. cmChar_t* cmTextAppendSN( cmChar_t* s, const cmChar_t* u, unsigned un )
  474. {
  475. unsigned sn = s==NULL ? 0 : strlen(s);
  476. if( un > 0 )
  477. {
  478. s = cmTextAppend(s,&sn,u,un+1);
  479. s[sn-1] = 0;
  480. }
  481. return s;
  482. }
  483. // append u[un] to s[] and append terminating zero.
  484. cmChar_t* cmTextAppendSNZ( cmChar_t* s, const cmChar_t* u, unsigned un )
  485. {
  486. unsigned sn = s==NULL ? 0 : strlen(s)+1;
  487. cmChar_t z = 0;
  488. s = cmTextAppend(s,&sn,u,un);
  489. return cmTextAppend(s,&sn,&z,1);
  490. }
  491. // both s[] and u[] are strz's
  492. cmChar_t* cmTextAppendSS( cmChar_t* s, const cmChar_t* u )
  493. { return cmTextAppendSN(s,u,strlen(u)); }
  494. cmChar_t* cmTextVAppendSS( cmChar_t* s, ... )
  495. {
  496. va_list vl;
  497. va_start(vl,s);
  498. do
  499. {
  500. cmChar_t* s0 = va_arg(vl,cmChar_t*);
  501. if( s0 == NULL )
  502. break;
  503. s = cmTextAppendSS(s,s0);
  504. }while(1);
  505. va_end(vl);
  506. return s;
  507. }
  508. cmChar_t* cmTextAppendChar( cmChar_t* s, cmChar_t c, unsigned n )
  509. {
  510. if( n <= 0 )
  511. return s;
  512. cmChar_t t[ n+1 ];
  513. memset(t,' ',n);
  514. t[n] = 0;
  515. return cmTextAppendSS(s,t);
  516. }
  517. bool cmTextIsEmpty( const cmChar_t* s )
  518. {
  519. if( s!=NULL )
  520. for(; *s; ++s )
  521. if( !isspace(*s) )
  522. return false;
  523. return true;
  524. }
  525. bool cmTextIsNotEmpty( const cmChar_t* s )
  526. { return !cmTextIsEmpty(s); }
  527. unsigned cmTextLength( const cmChar_t* s0 )
  528. {
  529. if( s0 == NULL )
  530. return 0;
  531. return strlen(s0);
  532. }
  533. int cmTextCmp( const cmChar_t* s0, const cmChar_t* s1 )
  534. {
  535. if( s0 == NULL && s1 == NULL )
  536. return 0;
  537. if( s0 == NULL || s1 == NULL )
  538. {
  539. if( s0 == NULL )
  540. return -1;
  541. return 1;
  542. }
  543. return strcmp(s0,s1);
  544. }
  545. int cmTextCmpN( const cmChar_t* s0, const cmChar_t* s1, unsigned n )
  546. {
  547. if( s0 == NULL && s1 == NULL )
  548. return 0;
  549. if( s0 == NULL || s1 == NULL )
  550. {
  551. if( s0 == NULL )
  552. return -1;
  553. return 1;
  554. }
  555. return strncmp(s0,s1,n);
  556. }
  557. void cmTextToLower( const cmChar_t* s0, cmChar_t* s1 )
  558. {
  559. if( s0 == NULL || s1==NULL )
  560. return;
  561. for(; *s0; ++s0,++s1)
  562. *s1 = tolower(*s0);
  563. *s1 = 0;
  564. return;
  565. }
  566. void cmTextToUpper( const cmChar_t* s0, cmChar_t* s1 )
  567. {
  568. if( s0 == NULL || s1==NULL )
  569. return;
  570. for(; *s0; ++s0,++s1)
  571. *s1 = toupper(*s0);
  572. *s1 = 0;
  573. return;
  574. }
  575. cmChar_t* cmTextLine( cmChar_t* s, unsigned line )
  576. {
  577. assert( line>0);
  578. unsigned i;
  579. // count down to the code line containing the tag reference
  580. for(i=0; i<line-1; ++i)
  581. {
  582. s = strchr(s,'\n');
  583. if( s == NULL )
  584. return NULL;
  585. ++s;
  586. }
  587. return s+1;
  588. }
  589. const cmChar_t* cmTextLineC( const cmChar_t* s, unsigned line )
  590. { return cmTextLine((cmChar_t*)s,line); }
  591. unsigned cmTextLineCount( const cmChar_t* s )
  592. {
  593. unsigned n = *s ? 1 : 0;
  594. while( *s )
  595. {
  596. s = cmTextEndOfLineC(s);
  597. switch( *s )
  598. {
  599. case 0:
  600. break;
  601. case '\n':
  602. s += 1;
  603. n += 1;
  604. break;
  605. default:
  606. { assert(0); }
  607. }
  608. }
  609. return n;
  610. }
  611. cmChar_t* cmTextRemoveConsecutiveSpaces( cmChar_t* s )
  612. {
  613. if( s==NULL || strlen(s) < 2 )
  614. return s;
  615. int i=1;
  616. while( s[i] )
  617. {
  618. if( isspace(s[i-1]) && isspace(s[i]) )
  619. cmTextShrinkS(s, s+i, 1 );
  620. else
  621. ++i;
  622. }
  623. return s;
  624. }
  625. cmChar_t* cmTextColumize( cmChar_t* s, unsigned colCnt )
  626. {
  627. if( s==NULL || strlen(s) < colCnt )
  628. return s;
  629. int i = 0;
  630. int c = 0;
  631. cmChar_t* c0 = NULL;
  632. for(; s[i]; ++i)
  633. {
  634. // remove any existing newlines
  635. if( s[i] == '\n' )
  636. s[i] = ' ';
  637. // track the last space (which is a potential wrap point).
  638. if( isspace(s[i]) )
  639. c0 = s+i;
  640. if( c < colCnt )
  641. ++c;
  642. else
  643. {
  644. // if there is no previous wrap point ...
  645. if( c0 == NULL )
  646. {
  647. // ... then insert one
  648. s = cmTextInsertS(s,s+i,"\n");
  649. }
  650. else
  651. {
  652. // replace the wrap point with a '\n'
  653. *c0 = '\n';
  654. }
  655. c = 0;
  656. c0 = NULL;
  657. }
  658. }
  659. return s;
  660. }
  661. cmChar_t* _cmTextPrefixRows( cmChar_t* s, const cmChar_t* t )
  662. {
  663. if( s==NULL || t==NULL || strlen(t)==0 )
  664. return s;
  665. int i;
  666. for(i=0; s[i]; ++i)
  667. if( i==0 || s[i]=='\n')
  668. {
  669. cmChar_t* u = s + (i==0 ? 0 : i+1);
  670. s = cmTextInsertS(s,u,t);
  671. }
  672. return s;
  673. }
  674. cmChar_t* cmTextIndentRows( cmChar_t* s, unsigned indent )
  675. {
  676. if( s==NULL || indent==0 )
  677. return s;
  678. cmChar_t* t = cmMemAllocZ( cmChar_t, indent+1 );
  679. cmVOC_Fill(t,indent,' ');
  680. t[indent] = 0;
  681. s = _cmTextPrefixRows(s,t);
  682. cmMemFree(t);
  683. return s;
  684. }
  685. cmChar_t* cmTextPrefixRows( cmChar_t* s, const cmChar_t* t )
  686. { return _cmTextPrefixRows(s,t); }
  687. cmChar_t* cmTextTrimRows( cmChar_t* s )
  688. {
  689. bool fl = true;
  690. int i = 0;
  691. while( s[i] )
  692. {
  693. if( s[i] == '\n' )
  694. {
  695. fl = true;
  696. ++i;
  697. }
  698. else
  699. {
  700. if( isspace(s[i]) && fl )
  701. cmTextShrinkS(s, s+i, 1 );
  702. else
  703. {
  704. fl = false;
  705. ++i;
  706. }
  707. }
  708. }
  709. return s;
  710. }
  711. cmChar_t* cmTextEatLeadingSpace( cmChar_t* s )
  712. {
  713. if( s == NULL )
  714. return s;
  715. while( *s )
  716. {
  717. if( !isspace(*s) )
  718. break;
  719. cmTextShrinkS(s,s,1);
  720. }
  721. return s;
  722. }
  723. cmChar_t* cmTextNextRow( cmChar_t* s )
  724. {
  725. if( s == NULL)
  726. return NULL;
  727. for(; *s; ++s)
  728. if( *s == '\n' )
  729. {
  730. ++s;
  731. return *s==0 ? NULL : s;
  732. }
  733. return NULL;
  734. }
  735. const cmChar_t* cmTextNextRowC( const cmChar_t* s )
  736. { return cmTextNextRow((cmChar_t*)s); }
  737. unsigned cmTextMinIndent( const cmChar_t* s )
  738. {
  739. // leadFl=true if at beginning of row
  740. bool leadFl = true;
  741. unsigned min_indent = INT_MAX;
  742. unsigned indent = 0;
  743. for(; *s; ++s)
  744. {
  745. if( leadFl )
  746. {
  747. if( isspace(*s) && *s!='\n' )
  748. indent += 1;
  749. else
  750. {
  751. if( indent < min_indent )
  752. min_indent = indent;
  753. indent = 0;
  754. leadFl = false;
  755. }
  756. }
  757. else
  758. {
  759. if( *s == '\n' )
  760. leadFl = true;
  761. }
  762. }
  763. return min_indent==INT_MAX ? 0 : min_indent;
  764. }
  765. cmChar_t* cmTextOutdent( cmChar_t* s, unsigned outdent )
  766. {
  767. // leadFl=true if at beginning of row
  768. bool leadFl = true;
  769. unsigned indent = 0;
  770. cmChar_t* cs = s;
  771. cmChar_t* s0 = s;
  772. for(; *cs; ++cs)
  773. {
  774. if( leadFl )
  775. {
  776. if( isspace(*cs) && *cs!='\n' )
  777. indent += 1;
  778. else
  779. {
  780. unsigned n = cmMin(outdent,indent);
  781. cmTextShrinkS(s,s0,n);
  782. cs -= n;
  783. indent = 0;
  784. leadFl = false;
  785. }
  786. }
  787. else
  788. {
  789. if( *cs == '\n' )
  790. {
  791. leadFl = true;
  792. s0 = cs + 1;
  793. }
  794. }
  795. }
  796. return s;
  797. }
  798. unsigned cmTextDecodeBase64BufferByteCount( const char* xV, unsigned xN )
  799. {
  800. if( xN % 4 != 0 )
  801. return cmInvalidCnt;
  802. unsigned yN = xN / 4 * 3;
  803. if( xV[xN-1] == '=' )
  804. yN -= 1;
  805. if( xV[xN-2] == '=' )
  806. yN -= 2;
  807. return yN;
  808. }
  809. cmTxRC_t cmTextDecodeBase64( const char* xV, unsigned xN, void* yV, unsigned yN )
  810. {
  811. int t[] =
  812. {
  813. 64, // 0
  814. 64, // 1
  815. 64, // 2
  816. 64, // 3
  817. 64, // 4
  818. 64, // 5
  819. 64, // 6
  820. 64, // 7
  821. 64, // 8
  822. 64, // 9
  823. 64, // 10
  824. 64, // 11
  825. 64, // 12
  826. 64, // 13
  827. 64, // 14
  828. 64, // 15
  829. 64, // 16
  830. 64, // 17
  831. 64, // 18
  832. 64, // 19
  833. 64, // 20
  834. 64, // 21
  835. 64, // 22
  836. 64, // 23
  837. 64, // 24
  838. 64, // 25
  839. 64, // 26
  840. 64, // 27
  841. 64, // 28
  842. 64, // 29
  843. 64, // 30
  844. 64, // 31
  845. 64, // 32
  846. 64, // 33
  847. 64, // 34
  848. 64, // 35
  849. 64, // 36
  850. 64, // 37
  851. 64, // 38
  852. 64, // 39
  853. 64, // 40
  854. 64, // 41
  855. 64, // 42
  856. 62, // 43 +
  857. 64, // 44
  858. 64, // 45
  859. 64, // 46
  860. 63, // 47 /
  861. 52, // 48 0
  862. 53, // 49 1
  863. 54, // 50 2
  864. 55, // 51 3
  865. 56, // 52 4
  866. 57, // 53 5
  867. 58, // 54 6
  868. 59, // 55 7
  869. 60, // 56 8
  870. 61, // 57 9
  871. 64, // 58
  872. 64, // 59
  873. 64, // 60
  874. 64, // 61
  875. 64, // 62
  876. 64, // 63
  877. 64, // 64
  878. 0, // 65 A
  879. 1, // 66 B
  880. 2, // 67 C
  881. 3, // 68 D
  882. 4, // 69 E
  883. 5, // 70 F
  884. 6, // 71 G
  885. 7, // 72 H
  886. 8, // 73 I
  887. 9, // 74 J
  888. 10, // 75 K
  889. 11, // 76 L
  890. 12, // 77 M
  891. 13, // 78 N
  892. 14, // 79 O
  893. 15, // 80 P
  894. 16, // 81 Q
  895. 17, // 82 R
  896. 18, // 83 S
  897. 19, // 84 T
  898. 20, // 85 U
  899. 21, // 86 V
  900. 22, // 87 W
  901. 23, // 88 X
  902. 24, // 89 Y
  903. 25, // 90 Z
  904. 64, // 91
  905. 64, // 92
  906. 64, // 93
  907. 64, // 94
  908. 64, // 95
  909. 64, // 96
  910. 26, // 97 a
  911. 27, // 98 b
  912. 28, // 99 c
  913. 29, //100 d
  914. 30, //101 e
  915. 31, //102 f
  916. 32, //103 g
  917. 33, //104 h
  918. 34, //105 i
  919. 35, //106 j
  920. 36, //107 k
  921. 37, //108 l
  922. 38, //109 m
  923. 39, //110 n
  924. 40, //111 o
  925. 41, //112 p
  926. 42, //113 q
  927. 43, //114 r
  928. 44, //115 s
  929. 45, //116 t
  930. 46, //117 u
  931. 47, //118 v
  932. 48, //119 w
  933. 49, //120 x
  934. 50, //121 y
  935. 51, //122 z
  936. 64, //123
  937. 64, //124
  938. 64, //125
  939. 64, //126
  940. 64 //127
  941. };
  942. unsigned i = 0;
  943. unsigned j = 0;
  944. char* zV = (char*)yV;
  945. while( i < xN )
  946. {
  947. unsigned yn = 3;
  948. if( xV[i+3] == '=' )
  949. --yn;
  950. if( xV[i+2] == '=' )
  951. --yn;
  952. unsigned v = 0;
  953. assert( i + 4 <= xN );
  954. v += t[(int)xV[i++]] << 18;
  955. v += t[(int)xV[i++]] << 12;
  956. v += t[(int)xV[i++]] << 6;
  957. v += t[(int)xV[i++]] << 0;
  958. if( j >= yN )
  959. break;
  960. zV[j++] = (v & 0xff0000) >> 16;
  961. if( yn > 1 )
  962. {
  963. if( j >= yN )
  964. break;
  965. zV[j++] = (v & 0x00ff00) >> 8;
  966. }
  967. if( yn > 2 )
  968. {
  969. if( j >= yN )
  970. break;
  971. zV[j++] = (v & 0x0000ff) >> 0;
  972. }
  973. }
  974. return j;
  975. }
  976. unsigned cmTextEncodeBase64BufferByteCount( unsigned binByteCnt )
  977. {
  978. int rem = binByteCnt % 3;
  979. binByteCnt -= rem;
  980. int n = binByteCnt / 3 * 4;
  981. if( rem )
  982. n += 4;
  983. return n;
  984. }
  985. unsigned cmTextEncodeBase64( const void* xV, unsigned xN, char* yV, unsigned yN )
  986. {
  987. const char* t = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  988. const char* zV = (const char*)xV;
  989. unsigned i = 0;
  990. unsigned j = 0;
  991. while( 1 )
  992. {
  993. unsigned k = 3;
  994. unsigned v = ((int)zV[i++]) << 16;
  995. if( i < xN )
  996. v += ((int)zV[i++]) << 8;
  997. else
  998. --k;
  999. if( i < xN )
  1000. v += ((int)zV[i++]);
  1001. else
  1002. --k;
  1003. if( j >= yN )
  1004. break;
  1005. yV[j++] = t[ (v & 0xfc0000) >> 18 ];
  1006. if( j >= yN )
  1007. break;
  1008. yV[j++] = t[ (v & 0x03f000) >> 12 ];
  1009. if( j >= yN )
  1010. break;
  1011. if( k > 1 )
  1012. yV[j++] = t[ (v & 0x000fc0) >> 6 ];
  1013. else
  1014. yV[j++] = '=';
  1015. if( j >= yN )
  1016. break;
  1017. if( k > 2 )
  1018. yV[j++] = t[ (v & 0x00003f) >> 0 ];
  1019. else
  1020. yV[j++] = '=';
  1021. }
  1022. return j;
  1023. }