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.

cmText.c 24KB

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. }