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

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