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 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780
  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. return s;
  80. }
  81. cmChar_t* cmTextSysVPrintfH( cmLHeapH_t lhH, const cmChar_t* fmt, va_list vl )
  82. { return _cmTextSysVPrintf( cmTextSysNullHandle, lhH, false, fmt, vl ); }
  83. cmChar_t* cmTextSysPrintfH( cmLHeapH_t lhH, const cmChar_t* fmt, ... )
  84. {
  85. va_list vl;
  86. va_start( vl, fmt );
  87. cmChar_t* s = cmTextSysVPrintfH(lhH,fmt,vl);
  88. va_end(vl);
  89. return s;
  90. }
  91. cmChar_t* cmTextSysVPrintfS( cmTextSysH_t h, const cmChar_t* fmt, va_list vl )
  92. { return _cmTextSysVPrintf(h,cmLHeapNullHandle,true,fmt,vl); }
  93. cmChar_t* cmTextSysPrintfS( cmTextSysH_t h, const cmChar_t* fmt, ... )
  94. {
  95. va_list vl;
  96. va_start(vl,fmt);
  97. cmChar_t* s = cmTextSysVPrintfS(h,fmt,vl);
  98. va_end(vl);
  99. return s;
  100. }
  101. cmChar_t* cmTextSysVPrintf( cmTextSysH_t h, const cmChar_t* fmt, va_list vl )
  102. { return _cmTextSysVPrintf(h,cmLHeapNullHandle,false,fmt,vl); }
  103. cmChar_t* cmTextSysPrintf( cmTextSysH_t h, const cmChar_t* fmt, ... )
  104. {
  105. va_list vl;
  106. va_start(vl,fmt);
  107. cmChar_t* s = cmTextSysVPrintf(h,fmt,vl);
  108. va_end(vl);
  109. return s;
  110. }
  111. void cmTextSysFreeStr( cmTextSysH_t h, const cmChar_t* s )
  112. {
  113. cmTextSys_t* p = _cmTextSysHandleToPtr(h);
  114. cmLhFree(p->lhH,(cmChar_t*)s);
  115. }
  116. //
  117. // Global interface
  118. //
  119. cmTxRC_t cmTsInitialize( cmCtx_t* ctx )
  120. { return cmTextSysInitialize(ctx,&_cmTextSysGlobalH); }
  121. cmTxRC_t cmTsFinalize()
  122. { return cmTextSysFinalize(&_cmTextSysGlobalH); }
  123. bool cmTsIsValid()
  124. { return cmTextSysIsValid(_cmTextSysGlobalH); }
  125. cmChar_t* cmTsVPrintfS( const cmChar_t* fmt, va_list vl )
  126. { return cmTextSysVPrintfS(_cmTextSysGlobalH,fmt,vl); }
  127. cmChar_t* cmTsPrintfS( const cmChar_t* fmt, ... )
  128. {
  129. va_list vl;
  130. va_start(vl,fmt);
  131. cmChar_t* s = cmTsVPrintfS(fmt,vl);
  132. va_end(vl);
  133. return s;
  134. }
  135. cmChar_t* cmTsVPrintfH( cmLHeapH_t h, const cmChar_t* fmt, va_list vl )
  136. { return cmTextSysVPrintfH(h,fmt,vl); }
  137. cmChar_t* cmTsPrintfH( cmLHeapH_t h, const cmChar_t* fmt, ... )
  138. {
  139. va_list vl;
  140. va_start(vl,fmt);
  141. cmChar_t* s = cmTsVPrintfH(h,fmt,vl);
  142. va_end(vl);
  143. return s;
  144. }
  145. cmChar_t* cmTsVPrintf( const cmChar_t* fmt, va_list vl )
  146. { return cmTextSysVPrintf(_cmTextSysGlobalH,fmt,vl); }
  147. cmChar_t* cmTsPrintf( const cmChar_t* fmt, ... )
  148. {
  149. va_list vl;
  150. va_start(vl,fmt);
  151. cmChar_t* s = cmTsVPrintf(fmt,vl);
  152. va_end(vl);
  153. return s;
  154. }
  155. void cmTsFreeStr( const cmChar_t* s )
  156. { cmTextSysFreeStr(_cmTextSysGlobalH,s); }
  157. cmChar_t* cmTsVPrintfP( cmChar_t* s, const cmChar_t* fmt, va_list vl )
  158. {
  159. va_list vl1;
  160. va_copy(vl1,vl);
  161. int n = vsnprintf(NULL,0,fmt,vl);
  162. assert(n != -1);
  163. s = cmMemResize(cmChar_t,s,n+1);
  164. unsigned m = vsnprintf(s,n+1,fmt,vl1);
  165. assert(m==n);
  166. s[n] = 0;
  167. return s;
  168. }
  169. cmChar_t* cmTsPrintfP( cmChar_t* s, const cmChar_t* fmt, ... )
  170. {
  171. va_list vl;
  172. va_start(vl,fmt);
  173. s = cmTsVPrintfP(s,fmt,vl);
  174. va_end(vl);
  175. return s;
  176. }
  177. void _cmTxError( cmErr_t* err, cmTxRC_t rc, const char* fmt, ... )
  178. {
  179. va_list vl;
  180. va_start(vl,fmt);
  181. cmErrVMsg(err,rc,fmt,vl);
  182. va_end(vl);
  183. }
  184. cmTxRC_t _cmTxRptError( cmErr_t* err, const char* msg, const char* inputText )
  185. {
  186. if( err == NULL )
  187. return kOkTxRC;
  188. if( inputText == NULL )
  189. {
  190. _cmTxError(err,kNullTxRC,"Text to %s conversion failed due to NULL input text.");
  191. return kNullTxRC;
  192. }
  193. if( errno != 0 )
  194. {
  195. _cmTxError(err,kCvtErrTxRC,"Text to %s conversion failed on input '%s'.",msg,inputText);
  196. return kCvtErrTxRC;
  197. }
  198. return kOkTxRC;
  199. }
  200. cmTxRC_t cmTextToInt(const char* text, int* vp, cmErr_t* err )
  201. {
  202. assert( vp != NULL );
  203. cmTxRC_t rc = kOkTxRC;
  204. int en = errno;
  205. errno = 0;
  206. *vp = text==NULL ? 0 : strtol(text,NULL,0);
  207. rc = _cmTxRptError(err,"integer",text);
  208. errno = en;
  209. return rc;
  210. }
  211. cmTxRC_t cmTextToUInt( const char* text, unsigned* vp, cmErr_t* err )
  212. {
  213. assert( vp != NULL );
  214. cmTxRC_t rc = kOkTxRC;
  215. int en = errno;
  216. errno = 0;
  217. *vp = text==NULL ? 0 : (unsigned)strtol(text,NULL,0);
  218. rc = _cmTxRptError(err,"unsigned integer",text);
  219. errno = en;
  220. return rc;
  221. }
  222. cmTxRC_t cmTextToFloat( const char* text, float* vp, cmErr_t* err )
  223. {
  224. assert( vp != NULL );
  225. cmTxRC_t rc = kOkTxRC;
  226. int en = errno;
  227. errno = 0;
  228. *vp = text==NULL ? 0 : (float)strtod(text,NULL);
  229. rc = _cmTxRptError(err,"float",text);
  230. errno = en;
  231. return rc;
  232. }
  233. cmTxRC_t cmTextToDouble( const char* text, double* vp, cmErr_t* err )
  234. {
  235. assert( vp != NULL );
  236. cmTxRC_t rc = kOkTxRC;
  237. int en = errno;
  238. errno = 0;
  239. *vp = text==NULL ? 0 : strtod(text,NULL);
  240. rc = _cmTxRptError(err,"double",text);
  241. errno = en;
  242. return rc;
  243. }
  244. cmTxRC_t cmTextToBool( const char* text, bool* vp, cmErr_t* err )
  245. {
  246. assert( vp != NULL );
  247. cmTxRC_t rc = kOkTxRC;
  248. if( strcasecmp(text,"true") == 0 || strcasecmp(text,"0") == 0 )
  249. *vp = true;
  250. else
  251. if( strcasecmp(text,"false") == 0 || strcasecmp(text,"1") == 0 )
  252. *vp = false;
  253. else
  254. rc = _cmTxRptError(err,"bool",text);
  255. return rc;
  256. }
  257. cmChar_t* cmTextNextNonWhiteOrEos( cmChar_t* s )
  258. {
  259. assert( s != NULL );
  260. while( (*s) && isspace(*s) )
  261. ++s;
  262. return s;
  263. }
  264. const cmChar_t* cmTextNextNonWhiteOrEosC( const cmChar_t* s )
  265. { return cmTextNextNonWhiteOrEos((cmChar_t*)s); }
  266. cmChar_t* cmTextNextNonWhite( cmChar_t* s )
  267. { //return (*(s=cmTextNextNonWhiteOrEos(s))) == 0 ? NULL : s;
  268. s=cmTextNextNonWhiteOrEos(s);
  269. if( *s == 0 )
  270. return NULL;
  271. return s;
  272. }
  273. const cmChar_t* cmTextNextNonWhiteC( const cmChar_t* s )
  274. { return cmTextNextNonWhite((cmChar_t*)s); }
  275. cmChar_t* cmTextPrevNonWhiteOrBos( cmChar_t* s0, const cmChar_t* s1 )
  276. {
  277. assert( s0!=NULL && s1!=NULL && s0 <= s1 );
  278. for(; s0 < s1; --s1 )
  279. if( !isspace(*s1) )
  280. break;
  281. return (cmChar_t*)s1;
  282. }
  283. const cmChar_t* cmTextPrevNonWhiteOrBosC( const cmChar_t* s0, const cmChar_t* s1 )
  284. { return cmTextPrevNonWhiteOrBos((cmChar_t*)s0,s1); }
  285. cmChar_t* cmTextPrevNonWhite( cmChar_t* s0, const cmChar_t* s1 )
  286. {
  287. cmChar_t* s2;
  288. if((s2 = cmTextPrevNonWhiteOrBos(s0,s1)) == s0 )
  289. return NULL;
  290. return s2;
  291. }
  292. const cmChar_t* cmTextPrevNonWhiteC( const cmChar_t* s0, const cmChar_t* s1 )
  293. { return cmTextPrevNonWhite((cmChar_t*)s0,s1); }
  294. cmChar_t* cmTextNextWhiteOrEos( cmChar_t* s )
  295. {
  296. assert( s!=NULL);
  297. while(*s && !isspace(*s) )
  298. ++s;
  299. return s;
  300. }
  301. const cmChar_t* cmTextNextWhiteOrEosC( const cmChar_t* s )
  302. { return cmTextNextWhiteOrEos((cmChar_t*)s); }
  303. cmChar_t* cmTextNextWhite( cmChar_t* s )
  304. { return (*(s=cmTextNextWhiteOrEos(s)))!=0 ? s : NULL; }
  305. const cmChar_t* cmTextNextWhiteC( const cmChar_t* s )
  306. { return cmTextNextWhite((cmChar_t*)s); }
  307. cmChar_t* cmTextPrevWhiteOrBos( cmChar_t* s0, const cmChar_t* s1 )
  308. {
  309. assert( s0!=NULL && s1!=NULL && s0 <= s1 );
  310. while( s1>s0 && !isspace(*s1) )
  311. --s1;
  312. return (cmChar_t*)s1;
  313. }
  314. const cmChar_t* cmTextPrevWhiteOrBosC( const cmChar_t* s0, const cmChar_t* s1 )
  315. { return cmTextPrevWhiteOrBos((cmChar_t*)s0,s1); }
  316. cmChar_t* cmTextPrevWhite( cmChar_t* s0, const cmChar_t* s1 )
  317. {
  318. cmChar_t* s2;
  319. if((s2 = cmTextPrevWhiteOrBos(s0,s1)) == s0 )
  320. return NULL;
  321. return s2;
  322. }
  323. const cmChar_t* cmTextPrevWhiteC( const cmChar_t* s0, const cmChar_t* s1 )
  324. { return cmTextPrevWhite((cmChar_t*)s0,s1); }
  325. cmChar_t* cmTextBegOfLine( cmChar_t* s0, const cmChar_t* s1 )
  326. {
  327. assert( s1!=NULL && s0!=NULL && s1 >= s0 );
  328. if( s0 == s1 )
  329. return s0;
  330. --s1;
  331. while( s1>s0 && *s1 != '\n' )
  332. --s1;
  333. if( *s1 == '\n' )
  334. ++s1;
  335. return (cmChar_t*)s1;
  336. }
  337. const cmChar_t* cmTextBegOfLineC( const cmChar_t* s0, const cmChar_t* s1 )
  338. { return cmTextBegOfLine((cmChar_t*)s0,s1); }
  339. cmChar_t* cmTextEndOfLine( cmChar_t* s )
  340. {
  341. assert( s!=NULL);
  342. while( *s!=0 && *s != '\n' )
  343. ++s;
  344. return s;
  345. }
  346. const cmChar_t* cmTextEndOfLineC( const cmChar_t* s )
  347. { return cmTextEndOfLine((cmChar_t*)s); }
  348. cmChar_t* cmTextLastNonWhiteChar( const cmChar_t* s )
  349. {
  350. unsigned n;
  351. if(s==NULL || (n = strlen(s)) == 0 )
  352. return NULL;
  353. cmChar_t* s0 = (cmChar_t*)s + n-1;
  354. for(; s0>=s; --s0)
  355. if( !isspace(*s0) )
  356. return s0;
  357. return NULL;
  358. }
  359. const cmChar_t* cmTextLastNonWhiteCharC( const cmChar_t* s )
  360. { return cmTextLastNonWhiteChar(s); }
  361. void cmTextShrinkS( cmChar_t* s, const cmChar_t* t, unsigned tn )
  362. { cmVOC_Shrink(s,strlen(s)+1,t,tn); }
  363. void cmTextShrinkSN(cmChar_t* s, unsigned sn, const cmChar_t* t, unsigned tn )
  364. { cmVOC_Shrink(s,sn,t,tn); }
  365. void cmTextClip( cmChar_t* s, unsigned n )
  366. {
  367. if( n == 0 || s == NULL || strlen(s)==0 )
  368. return;
  369. if( n >= strlen(s) )
  370. {
  371. s[0]=0;
  372. return;
  373. }
  374. s[ strlen(s)-n ] = 0;
  375. }
  376. cmChar_t* cmTextExpandS( cmChar_t* s, const cmChar_t* t, unsigned tn )
  377. { return cmVOC_Expand(s,strlen(s)+1,t,tn); }
  378. cmChar_t* cmTextReplaceSN( cmChar_t* s, const cmChar_t* t, unsigned tn, const cmChar_t* u, unsigned un )
  379. {
  380. unsigned n = strlen(s)+1;
  381. return cmVOC_Replace(s,&n,t,tn,u,un);
  382. }
  383. cmChar_t* cmTextReplaceS( cmChar_t* s, const cmChar_t* t, unsigned tn, const cmChar_t* u )
  384. { return cmTextReplaceSN(s,t,tn,u,u==NULL ? 0 : strlen(u)); }
  385. cmChar_t* _cmTextReplace( cmChar_t* s, const cmChar_t* t, const cmChar_t* u, unsigned n )
  386. {
  387. // we will go into an endless loop if 't' is contained in 'u' and n > 1.
  388. assert( s!= NULL && t!=NULL && u!=NULL && (n==1 || strstr(u,t) == NULL) );
  389. int tn = strlen(t);
  390. cmChar_t* c = NULL;
  391. unsigned i = 0;
  392. while( (c = strstr(s,t)) != NULL )
  393. {
  394. s = cmTextReplaceS(s,c,tn,u);
  395. assert(s!=NULL);
  396. ++i;
  397. if( n!=cmInvalidCnt && i>=n)
  398. break;
  399. };
  400. return s;
  401. }
  402. cmChar_t* cmTextReplaceAll( cmChar_t* s, const cmChar_t* t, const cmChar_t* u )
  403. { return _cmTextReplace(s,t,u,cmInvalidCnt); }
  404. cmChar_t* cmTextReplaceFirst( cmChar_t* s, const cmChar_t* t, const cmChar_t* u )
  405. { return _cmTextReplace(s,t,u,1); }
  406. cmChar_t* cmTextInsertSN( cmChar_t* s, const cmChar_t* t, const cmChar_t* u, unsigned un )
  407. {
  408. unsigned n = strlen(s)+1;
  409. return cmVOC_Replace(s,&n,t,0,u,un);
  410. }
  411. cmChar_t* cmTextInsertS( cmChar_t* s, const cmChar_t* t, const cmChar_t* u )
  412. { return cmTextInsertSN(s,t,u,u==NULL?0:strlen(u)); }
  413. cmChar_t* cmTextAppend( cmChar_t* s, unsigned* sn, const cmChar_t* u, unsigned un )
  414. { return cmVOC_Replace(s,sn,s+(*sn),0,u,un); }
  415. cmChar_t* cmTextAppendSN( cmChar_t* s, const cmChar_t* u, unsigned un )
  416. {
  417. unsigned sn = s==NULL ? 0 : strlen(s);
  418. if( un > 0 )
  419. {
  420. s = cmTextAppend(s,&sn,u,un+1);
  421. s[sn-1] = 0;
  422. }
  423. return s;
  424. }
  425. // append u[un] to s[] and append terminating zero.
  426. cmChar_t* cmTextAppendSNZ( cmChar_t* s, const cmChar_t* u, unsigned un )
  427. {
  428. unsigned sn = s==NULL ? 0 : strlen(s)+1;
  429. cmChar_t z = 0;
  430. s = cmTextAppend(s,&sn,u,un);
  431. return cmTextAppend(s,&sn,&z,1);
  432. }
  433. // both s[] and u[] are strz's
  434. cmChar_t* cmTextAppendSS( cmChar_t* s, const cmChar_t* u )
  435. { return cmTextAppendSN(s,u,strlen(u)); }
  436. cmChar_t* cmTextAppendChar( cmChar_t* s, cmChar_t c, unsigned n )
  437. {
  438. if( n <= 0 )
  439. return s;
  440. cmChar_t t[ n+1 ];
  441. memset(t,' ',n);
  442. t[n] = 0;
  443. return cmTextAppendSS(s,t);
  444. }
  445. bool cmTextIsEmpty( const cmChar_t* s )
  446. {
  447. if( s!=NULL )
  448. for(; *s; ++s )
  449. if( !isspace(*s) )
  450. return false;
  451. return true;
  452. }
  453. bool cmTextIsNotEmpty( const cmChar_t* s )
  454. { return !cmTextIsEmpty(s); }
  455. cmChar_t* cmTextLine( cmChar_t* s, unsigned line )
  456. {
  457. assert( line>0);
  458. unsigned i;
  459. // count down to the code line containing the tag reference
  460. for(i=0; i<line-1; ++i)
  461. {
  462. s = strchr(s,'\n');
  463. if( s == NULL )
  464. return NULL;
  465. ++s;
  466. }
  467. return s+1;
  468. }
  469. const cmChar_t* cmTextLineC( const cmChar_t* s, unsigned line )
  470. { return cmTextLine((cmChar_t*)s,line); }
  471. cmChar_t* cmTextRemoveConsecutiveSpaces( cmChar_t* s )
  472. {
  473. if( s==NULL || strlen(s) < 2 )
  474. return s;
  475. int i=1;
  476. while( s[i] )
  477. {
  478. if( isspace(s[i-1]) && isspace(s[i]) )
  479. cmTextShrinkS(s, s+i, 1 );
  480. else
  481. ++i;
  482. }
  483. return s;
  484. }
  485. cmChar_t* cmTextColumize( cmChar_t* s, unsigned colCnt )
  486. {
  487. if( s==NULL || strlen(s) < colCnt )
  488. return s;
  489. int i = 0;
  490. int c = 0;
  491. cmChar_t* c0 = NULL;
  492. for(; s[i]; ++i)
  493. {
  494. // remove any existing newlines
  495. if( s[i] == '\n' )
  496. s[i] = ' ';
  497. // track the last space (which is a potential wrap point).
  498. if( isspace(s[i]) )
  499. c0 = s+i;
  500. if( c < colCnt )
  501. ++c;
  502. else
  503. {
  504. // if there is no previous wrap point ...
  505. if( c0 == NULL )
  506. {
  507. // ... then insert one
  508. s = cmTextInsertS(s,s+i,"\n");
  509. }
  510. else
  511. {
  512. // replace the wrap point with a '\n'
  513. *c0 = '\n';
  514. }
  515. c = 0;
  516. c0 = NULL;
  517. }
  518. }
  519. return s;
  520. }
  521. cmChar_t* _cmTextPrefixRows( cmChar_t* s, const cmChar_t* t )
  522. {
  523. if( s==NULL || t==NULL || strlen(t)==0 )
  524. return s;
  525. int i;
  526. for(i=0; s[i]; ++i)
  527. if( i==0 || s[i]=='\n')
  528. {
  529. cmChar_t* u = s + (i==0 ? 0 : i+1);
  530. s = cmTextInsertS(s,u,t);
  531. }
  532. return s;
  533. }
  534. cmChar_t* cmTextIndentRows( cmChar_t* s, unsigned indent )
  535. {
  536. if( s==NULL || indent==0 )
  537. return s;
  538. cmChar_t* t = cmMemAllocZ( cmChar_t, indent+1 );
  539. cmVOC_Fill(t,indent,' ');
  540. t[indent] = 0;
  541. s = _cmTextPrefixRows(s,t);
  542. cmMemFree(t);
  543. return s;
  544. }
  545. cmChar_t* cmTextPrefixRows( cmChar_t* s, const cmChar_t* t )
  546. { return _cmTextPrefixRows(s,t); }
  547. cmChar_t* cmTextTrimRows( cmChar_t* s )
  548. {
  549. bool fl = true;
  550. int i = 0;
  551. while( s[i] )
  552. {
  553. if( s[i] == '\n' )
  554. {
  555. fl = true;
  556. ++i;
  557. }
  558. else
  559. {
  560. if( isspace(s[i]) && fl )
  561. cmTextShrinkS(s, s+i, 1 );
  562. else
  563. {
  564. fl = false;
  565. ++i;
  566. }
  567. }
  568. }
  569. return s;
  570. }
  571. cmChar_t* cmTextEatLeadingSpace( cmChar_t* s )
  572. {
  573. if( s == NULL )
  574. return s;
  575. while( *s )
  576. {
  577. if( !isspace(*s) )
  578. break;
  579. cmTextShrinkS(s,s,1);
  580. }
  581. return s;
  582. }