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.

cmText.c 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008
  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. void cmTextShrinkS( cmChar_t* s, const cmChar_t* t, unsigned tn )
  370. { cmVOC_Shrink(s,strlen(s)+1,t,tn); }
  371. void cmTextShrinkSN(cmChar_t* s, unsigned sn, const cmChar_t* t, unsigned tn )
  372. { cmVOC_Shrink(s,sn,t,tn); }
  373. void cmTextClip( cmChar_t* s, unsigned n )
  374. {
  375. if( n == 0 || s == NULL || strlen(s)==0 )
  376. return;
  377. if( n >= strlen(s) )
  378. {
  379. s[0]=0;
  380. return;
  381. }
  382. s[ strlen(s)-n ] = 0;
  383. }
  384. cmChar_t* cmTextTrimBegin( cmChar_t* s )
  385. {
  386. if( s==NULL || strlen(s) == 0 )
  387. return s;
  388. cmChar_t* s0 = cmTextNextNonWhite(s);
  389. // no non-white char's exist
  390. if( s0 == NULL )
  391. {
  392. s[0] = 0;
  393. return s;
  394. }
  395. if( s0 != s )
  396. cmTextShrinkS(s,s,s0-s);
  397. return s;
  398. }
  399. cmChar_t* cmTextTrimEnd( cmChar_t* s )
  400. {
  401. unsigned sn;
  402. if( s==NULL || (sn = strlen(s))==0)
  403. return s;
  404. cmChar_t* s0 = cmTextLastNonWhiteChar(s);
  405. if(s0-s+1 < sn )
  406. s[s0-s+1] = 0;
  407. return s;
  408. }
  409. cmChar_t* cmTextTrim( cmChar_t* s)
  410. {
  411. cmTextTrimBegin(s);
  412. cmTextTrimEnd(s);
  413. return s;
  414. }
  415. cmChar_t* cmTextExpandS( cmChar_t* s, const cmChar_t* t, unsigned tn )
  416. { return cmVOC_Expand(s,strlen(s)+1,t,tn); }
  417. cmChar_t* cmTextReplaceSN( cmChar_t* s, const cmChar_t* t, unsigned tn, const cmChar_t* u, unsigned un )
  418. {
  419. unsigned n = strlen(s)+1;
  420. return cmVOC_Replace(s,&n,t,tn,u,un);
  421. }
  422. cmChar_t* cmTextReplaceS( cmChar_t* s, const cmChar_t* t, unsigned tn, const cmChar_t* u )
  423. { return cmTextReplaceSN(s,t,tn,u,u==NULL ? 0 : strlen(u)); }
  424. cmChar_t* _cmTextReplace( cmChar_t* s, const cmChar_t* t, const cmChar_t* u, unsigned n )
  425. {
  426. // we will go into an endless loop if 't' is contained in 'u' and n > 1.
  427. //assert( s!= NULL && t!=NULL && u!=NULL && (n==1 || strstr(u,t) == NULL) );
  428. assert( s!= NULL && t!=NULL && u!=NULL );
  429. int tn = strlen(t);
  430. cmChar_t* c = NULL;
  431. unsigned i = 0;
  432. cmChar_t* s0 = s;
  433. while( (c = strstr(s0,t)) != NULL )
  434. {
  435. int offs = c - s;
  436. s = cmTextReplaceS(s,c,tn,u);
  437. assert(s!=NULL);
  438. s0 = s + offs + tn;
  439. ++i;
  440. if( n!=cmInvalidCnt && i>=n)
  441. break;
  442. };
  443. return s;
  444. }
  445. cmChar_t* cmTextReplaceAll( cmChar_t* s, const cmChar_t* t, const cmChar_t* u )
  446. { return _cmTextReplace(s,t,u,cmInvalidCnt); }
  447. cmChar_t* cmTextReplaceFirst( cmChar_t* s, const cmChar_t* t, const cmChar_t* u )
  448. { return _cmTextReplace(s,t,u,1); }
  449. cmChar_t* cmTextInsertSN( cmChar_t* s, const cmChar_t* t, const cmChar_t* u, unsigned un )
  450. {
  451. unsigned n = strlen(s)+1;
  452. return cmVOC_Replace(s,&n,t,0,u,un);
  453. }
  454. cmChar_t* cmTextInsertS( cmChar_t* s, const cmChar_t* t, const cmChar_t* u )
  455. { return cmTextInsertSN(s,t,u,u==NULL?0:strlen(u)); }
  456. cmChar_t* cmTextAppend( cmChar_t* s, unsigned* sn, const cmChar_t* u, unsigned un )
  457. { return cmVOC_Replace(s,sn,s+(*sn),0,u,un); }
  458. cmChar_t* cmTextAppendSN( cmChar_t* s, const cmChar_t* u, unsigned un )
  459. {
  460. unsigned sn = s==NULL ? 0 : strlen(s);
  461. if( un > 0 )
  462. {
  463. s = cmTextAppend(s,&sn,u,un+1);
  464. s[sn-1] = 0;
  465. }
  466. return s;
  467. }
  468. // append u[un] to s[] and append terminating zero.
  469. cmChar_t* cmTextAppendSNZ( cmChar_t* s, const cmChar_t* u, unsigned un )
  470. {
  471. unsigned sn = s==NULL ? 0 : strlen(s)+1;
  472. cmChar_t z = 0;
  473. s = cmTextAppend(s,&sn,u,un);
  474. return cmTextAppend(s,&sn,&z,1);
  475. }
  476. // both s[] and u[] are strz's
  477. cmChar_t* cmTextAppendSS( cmChar_t* s, const cmChar_t* u )
  478. { return cmTextAppendSN(s,u,strlen(u)); }
  479. cmChar_t* cmTextVAppendSS( cmChar_t* s, ... )
  480. {
  481. va_list vl;
  482. va_start(vl,s);
  483. do
  484. {
  485. cmChar_t* s0 = va_arg(vl,cmChar_t*);
  486. if( s0 == NULL )
  487. break;
  488. s = cmTextAppendSS(s,s0);
  489. }while(1);
  490. va_end(vl);
  491. return s;
  492. }
  493. cmChar_t* cmTextAppendChar( cmChar_t* s, cmChar_t c, unsigned n )
  494. {
  495. if( n <= 0 )
  496. return s;
  497. cmChar_t t[ n+1 ];
  498. memset(t,' ',n);
  499. t[n] = 0;
  500. return cmTextAppendSS(s,t);
  501. }
  502. bool cmTextIsEmpty( const cmChar_t* s )
  503. {
  504. if( s!=NULL )
  505. for(; *s; ++s )
  506. if( !isspace(*s) )
  507. return false;
  508. return true;
  509. }
  510. bool cmTextIsNotEmpty( const cmChar_t* s )
  511. { return !cmTextIsEmpty(s); }
  512. unsigned cmTextLength( const cmChar_t* s0 )
  513. {
  514. if( s0 == NULL )
  515. return 0;
  516. return strlen(s0);
  517. }
  518. int cmTextCmp( const cmChar_t* s0, const cmChar_t* s1 )
  519. {
  520. if( s0 == NULL && s1 == NULL )
  521. return 0;
  522. if( s0 == NULL || s1 == NULL )
  523. {
  524. if( s0 == NULL )
  525. return -1;
  526. return 1;
  527. }
  528. return strcmp(s0,s1);
  529. }
  530. int cmTextCmpN( const cmChar_t* s0, const cmChar_t* s1, unsigned n )
  531. {
  532. if( s0 == NULL && s1 == NULL )
  533. return 0;
  534. if( s0 == NULL || s1 == NULL )
  535. {
  536. if( s0 == NULL )
  537. return -1;
  538. return 1;
  539. }
  540. return strncmp(s0,s1,n);
  541. }
  542. void cmTextToLower( const cmChar_t* s0, cmChar_t* s1 )
  543. {
  544. if( s0 == NULL || s1==NULL )
  545. return;
  546. for(; *s0; ++s0,++s1)
  547. *s1 = tolower(*s0);
  548. *s1 = 0;
  549. return;
  550. }
  551. void cmTextToUpper( const cmChar_t* s0, cmChar_t* s1 )
  552. {
  553. if( s0 == NULL || s1==NULL )
  554. return;
  555. for(; *s0; ++s0,++s1)
  556. *s1 = toupper(*s0);
  557. *s1 = 0;
  558. return;
  559. }
  560. cmChar_t* cmTextLine( cmChar_t* s, unsigned line )
  561. {
  562. assert( line>0);
  563. unsigned i;
  564. // count down to the code line containing the tag reference
  565. for(i=0; i<line-1; ++i)
  566. {
  567. s = strchr(s,'\n');
  568. if( s == NULL )
  569. return NULL;
  570. ++s;
  571. }
  572. return s+1;
  573. }
  574. const cmChar_t* cmTextLineC( const cmChar_t* s, unsigned line )
  575. { return cmTextLine((cmChar_t*)s,line); }
  576. cmChar_t* cmTextRemoveConsecutiveSpaces( cmChar_t* s )
  577. {
  578. if( s==NULL || strlen(s) < 2 )
  579. return s;
  580. int i=1;
  581. while( s[i] )
  582. {
  583. if( isspace(s[i-1]) && isspace(s[i]) )
  584. cmTextShrinkS(s, s+i, 1 );
  585. else
  586. ++i;
  587. }
  588. return s;
  589. }
  590. cmChar_t* cmTextColumize( cmChar_t* s, unsigned colCnt )
  591. {
  592. if( s==NULL || strlen(s) < colCnt )
  593. return s;
  594. int i = 0;
  595. int c = 0;
  596. cmChar_t* c0 = NULL;
  597. for(; s[i]; ++i)
  598. {
  599. // remove any existing newlines
  600. if( s[i] == '\n' )
  601. s[i] = ' ';
  602. // track the last space (which is a potential wrap point).
  603. if( isspace(s[i]) )
  604. c0 = s+i;
  605. if( c < colCnt )
  606. ++c;
  607. else
  608. {
  609. // if there is no previous wrap point ...
  610. if( c0 == NULL )
  611. {
  612. // ... then insert one
  613. s = cmTextInsertS(s,s+i,"\n");
  614. }
  615. else
  616. {
  617. // replace the wrap point with a '\n'
  618. *c0 = '\n';
  619. }
  620. c = 0;
  621. c0 = NULL;
  622. }
  623. }
  624. return s;
  625. }
  626. cmChar_t* _cmTextPrefixRows( cmChar_t* s, const cmChar_t* t )
  627. {
  628. if( s==NULL || t==NULL || strlen(t)==0 )
  629. return s;
  630. int i;
  631. for(i=0; s[i]; ++i)
  632. if( i==0 || s[i]=='\n')
  633. {
  634. cmChar_t* u = s + (i==0 ? 0 : i+1);
  635. s = cmTextInsertS(s,u,t);
  636. }
  637. return s;
  638. }
  639. cmChar_t* cmTextIndentRows( cmChar_t* s, unsigned indent )
  640. {
  641. if( s==NULL || indent==0 )
  642. return s;
  643. cmChar_t* t = cmMemAllocZ( cmChar_t, indent+1 );
  644. cmVOC_Fill(t,indent,' ');
  645. t[indent] = 0;
  646. s = _cmTextPrefixRows(s,t);
  647. cmMemFree(t);
  648. return s;
  649. }
  650. cmChar_t* cmTextPrefixRows( cmChar_t* s, const cmChar_t* t )
  651. { return _cmTextPrefixRows(s,t); }
  652. cmChar_t* cmTextTrimRows( cmChar_t* s )
  653. {
  654. bool fl = true;
  655. int i = 0;
  656. while( s[i] )
  657. {
  658. if( s[i] == '\n' )
  659. {
  660. fl = true;
  661. ++i;
  662. }
  663. else
  664. {
  665. if( isspace(s[i]) && fl )
  666. cmTextShrinkS(s, s+i, 1 );
  667. else
  668. {
  669. fl = false;
  670. ++i;
  671. }
  672. }
  673. }
  674. return s;
  675. }
  676. cmChar_t* cmTextEatLeadingSpace( cmChar_t* s )
  677. {
  678. if( s == NULL )
  679. return s;
  680. while( *s )
  681. {
  682. if( !isspace(*s) )
  683. break;
  684. cmTextShrinkS(s,s,1);
  685. }
  686. return s;
  687. }
  688. cmChar_t* cmTextNextRow( cmChar_t* s )
  689. {
  690. if( s == NULL)
  691. return NULL;
  692. for(; *s; ++s)
  693. if( *s == '\n' )
  694. {
  695. ++s;
  696. return *s==0 ? NULL : s;
  697. }
  698. return NULL;
  699. }
  700. const cmChar_t* cmTextNextRowC( const cmChar_t* s )
  701. { return cmTextNextRow((cmChar_t*)s); }
  702. unsigned cmTextMinIndent( const cmChar_t* s )
  703. {
  704. // leadFl=true if at beginning of row
  705. bool leadFl = true;
  706. unsigned min_indent = INT_MAX;
  707. unsigned indent = 0;
  708. for(; *s; ++s)
  709. {
  710. if( leadFl )
  711. {
  712. if( isspace(*s) && *s!='\n' )
  713. indent += 1;
  714. else
  715. {
  716. if( indent < min_indent )
  717. min_indent = indent;
  718. indent = 0;
  719. leadFl = false;
  720. }
  721. }
  722. else
  723. {
  724. if( *s == '\n' )
  725. leadFl = true;
  726. }
  727. }
  728. return min_indent==INT_MAX ? 0 : min_indent;
  729. }
  730. cmChar_t* cmTextOutdent( cmChar_t* s, unsigned outdent )
  731. {
  732. // leadFl=true if at beginning of row
  733. bool leadFl = true;
  734. unsigned indent = 0;
  735. cmChar_t* cs = s;
  736. cmChar_t* s0 = s;
  737. for(; *cs; ++cs)
  738. {
  739. if( leadFl )
  740. {
  741. if( isspace(*cs) && *cs!='\n' )
  742. indent += 1;
  743. else
  744. {
  745. unsigned n = cmMin(outdent,indent);
  746. cmTextShrinkS(s,s0,n);
  747. cs -= n;
  748. indent = 0;
  749. leadFl = false;
  750. }
  751. }
  752. else
  753. {
  754. if( *cs == '\n' )
  755. {
  756. leadFl = true;
  757. s0 = cs + 1;
  758. }
  759. }
  760. }
  761. return s;
  762. }