str.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. #include <ctype.h>
  2. #include <string.h>
  3. #include "eruta.h"
  4. #include "str.h"
  5. #include "bad.h"
  6. #include "mem.h"
  7. /* str contains utf-8 enables strings. It's currently nothing
  8. but a thin layer over Allegro's string library since
  9. that's pretty nice and UTF-8 enabled, unlike bstring (and
  10. it uses bsytrig internallly, so, no sense in having 2 string libraries :)
  11. The idea of the thin wrapper is
  12. a) To limit typing, strings are used everywhere so I want short names for the functions
  13. b) To enable me to replace the string functions in case I want to reuse
  14. them in something that doesn't use Allegro.
  15. */
  16. /** Strdup is not ANSI standard so have to make my own version. */
  17. char * cstr_dup(char * str) {
  18. size_t len = strlen(str);
  19. char * result = malloc(len + 1);
  20. if (!result) return NULL;
  21. strncpy(result, str, len);
  22. result[len] = '\0';
  23. return result;
  24. }
  25. /** Converts an US string to a number as per atoi. */
  26. int ustr_atoi(USTR * str) {
  27. return atoi(ustr_c(str));
  28. }
  29. /* Appends N characters from the C string str.
  30. The C string is first converted to a USTR, and the ntne characters are counted.
  31. XXX: todo how to do this efficiently without losing any unicode data?
  32. */
  33. /** Converts a ustr to s double by using strtod. Return 0 and sets OK to
  34. NULL if conversion failed for some reason. If OK is NULL, it is ignored. */
  35. double ustr_tod(USTR * ustr, int * ok) {
  36. char * aid = NULL;
  37. const char * cstr;
  38. double res;
  39. if(!ustr) goto error;
  40. errno = 0;
  41. cstr = ustr_c(ustr);
  42. res = strtod(cstr, &aid);
  43. if (aid == cstr) goto error;
  44. if (errno == ERANGE) goto error;
  45. // all was fine here, return ok
  46. if(ok) *ok = TRUE;
  47. return res;
  48. error: // if ze get here there was a conversion error
  49. if(ok) *ok = FALSE;
  50. return 0;
  51. }
  52. /** Converts a ustr to s double by using strtol. Return 0 and sets OK to
  53. NULL if conversion failed for some reason. If OK is NULL, it is ignored. */
  54. long ustr_tol(USTR * ustr, int * ok, int base) {
  55. char * aid = NULL;
  56. const char * cstr;
  57. long res;
  58. if(!ustr) goto error;
  59. errno = 0;
  60. cstr = ustr_c(ustr);
  61. res = strtol(cstr, &aid, base);
  62. if (aid == cstr) goto error;
  63. if (errno == ERANGE) goto error;
  64. // all was fine here, return ok
  65. if(ok) *ok = TRUE;
  66. return res;
  67. error: // if ze get here there was a conversion error
  68. if(ok) *ok = FALSE;
  69. return 0;
  70. }
  71. /** Converts an ustr to a double without doing any error checking. */
  72. double ustr_atod(USTR * ustr) {
  73. return ustr_tod(ustr, NULL);
  74. }
  75. /** Converts an ustr to a long without doing any error checking.
  76. Uses the decimal base.
  77. */
  78. double ustr_atol(USTR * ustr) {
  79. return ustr_tol(ustr, NULL, 10);
  80. }
  81. /** Makes a new ustr from the double. Must be freed with ustr_free */
  82. USTR * ustr_newdouble(double d) {
  83. return ustr_newf("%lf", d);
  84. }
  85. /** Makes a new ustr from a long. Must be freed with ustr_free */
  86. USTR * ustr_newlong(long l) {
  87. return ustr_newf("%ld", l);
  88. }
  89. /** Helper for calling any of the isXXX functions
  90. based on the first character expression string
  91. a call isalnum on ch and return the result.
  92. A call isalpha on ch and return the result.
  93. b call isblank on ch and return the result.
  94. c call iscntrl on ch and return the result.
  95. d call isdigit on ch and return the result.
  96. g call isgraph on ch and return the result.
  97. l call islower on ch and return the result.
  98. p call isprint on ch and return the result.
  99. P call ispunct on ch and return the result.
  100. u call isspace on ch and return the result.
  101. x call isxdigit on ch and return the result.
  102. any other first character: return FALSE.
  103. */
  104. int cstr_charis(const char * expression, int ch) {
  105. char first;
  106. if (!expression) return FALSE;
  107. first = expression[0];
  108. switch(first) {
  109. case 'a': return isalnum(ch);
  110. case 'A': return isalpha(ch);
  111. case 'b': return isblank(ch);
  112. case 'c': return iscntrl(ch);
  113. case 'd': return isdigit(ch);
  114. case 'g': return isgraph(ch);
  115. case 'l': return islower(ch);
  116. case 'p': return isprint(ch);
  117. case 'P': return ispunct(ch);
  118. case 's': return isspace(ch);
  119. case 'u': return isupper(ch);
  120. case 'x': return isxdigit(ch);
  121. default: return FALSE;
  122. }
  123. // cannot reach this place
  124. }
  125. /** Ultra-simple matching of a single character ch
  126. versus a string expression of allowed characters or instructions.
  127. The expression is interpreted as follows:
  128. $a call isalnum on ch and return the result.
  129. $A call isalpha on ch and return the result.
  130. $b call isblank on ch and return the result.
  131. $c call iscntrl on ch and return the result.
  132. $d call isdigit on ch and return the result.
  133. $g call isgraph on ch and return the result.
  134. $l call islower on ch and return the result.
  135. $p call isprint on ch and return the result.
  136. $P call ispunct on ch and return the result.
  137. $s call isspace on ch and return the result.
  138. $u call isupper on ch and return the result.
  139. $x call isxdigit on ch and return the result.
  140. @ must be followed by a list of characters, strchr is called on that list.
  141. ^ must be followed by a list of characters, strchr is called on that list,
  142. and it's logical opposite is returned.
  143. . matches any character and always returns true.
  144. empty string or NULL: matches nothing and always returns false.
  145. A ! prefix to any of these means to apply the
  146. C ! operator to the rest of the expression's result.
  147. If expression starts with any other character, FALSE is returned as well.
  148. */
  149. int cstr_simplematch(const char * expression, int ch) {
  150. char first;
  151. if (!expression) return FALSE;
  152. first = expression[0];
  153. switch(first) {
  154. case '\0': return FALSE;
  155. case '!' : return !cstr_simplematch(expression+1, ch);
  156. case '@' : return (strchr(expression+1, ch) != NULL);
  157. case '^' : return (strchr(expression+1, ch) == NULL);
  158. case '.' : return TRUE;
  159. case '$' : return cstr_charis(expression+1, ch);
  160. default: return FALSE;
  161. }
  162. // can't reach here
  163. }
  164. USTR * ustrlistnode_ustr(USTRListNode * self) {
  165. if(!self) return NULL;
  166. return self->ustr;
  167. }
  168. USTRListNode * ustrlistnode_alloc(void) {
  169. return STRUCT_ALLOC(USTRListNode);
  170. }
  171. USTRListNode * ustrlistnode_init(USTRListNode * self, const USTR * ustr) {
  172. if(!self) return NULL;
  173. self->ustr = ustr_dup(ustr);
  174. badlistnode_initempty(&self->list);
  175. return self;
  176. }
  177. USTRListNode * ustrlistnode_initcstr(USTRListNode * self, const char * cstr) {
  178. if(!self) return NULL;
  179. self->ustr = ustr_new(cstr);
  180. badlistnode_initempty(&self->list);
  181. return self;
  182. }
  183. USTRListNode * ustrlistnode_new(const USTR * ustr) {
  184. return ustrlistnode_init(ustrlistnode_alloc(), ustr);
  185. }
  186. USTRListNode * ustrlistnode_newcstr(const char * cstr) {
  187. return ustrlistnode_initcstr(ustrlistnode_alloc(), cstr);
  188. }
  189. USTRListNode * ustrlistnode_done(USTRListNode * self) {
  190. if(!self) return NULL;
  191. ustr_free(self->ustr);
  192. badlistnode_initempty(&self->list);
  193. return self;
  194. }
  195. USTRListNode * badlistnode_ustrlistnode(BadListNode * elem) {
  196. if(!elem) return NULL;
  197. return bad_container(elem, USTRListNode, list);
  198. }
  199. USTRListNode * ustrlistnode_next(USTRListNode * self) {
  200. BadListNode * bnode;
  201. if (!self) return NULL;
  202. bnode = badlistnode_next(&self->list);
  203. return badlistnode_ustrlistnode(bnode);
  204. }
  205. USTRListNode * ustrlistnode_prev(USTRListNode * self) {
  206. BadListNode * bnode;
  207. if (!self) return NULL;
  208. bnode = badlistnode_prev(&self->list);
  209. return badlistnode_ustrlistnode(bnode);
  210. }
  211. USTRListNode * ustrlistnode_free(USTRListNode * self) {
  212. if(!self) return NULL;
  213. ustrlistnode_done(self);
  214. return mem_free(self);
  215. }
  216. USTRListNode * ustrlist_head(USTRList * self) {
  217. if(!self) return NULL;
  218. return badlistnode_ustrlistnode(self->head);
  219. }
  220. USTRListNode * ustrlist_tail(USTRList * self) {
  221. if(!self) return NULL;
  222. return badlistnode_ustrlistnode(self->tail);
  223. }
  224. USTRList * ustrlist_alloc(void) {
  225. USTRList * self;
  226. self = STRUCT_ALLOC(USTRList);
  227. return self;
  228. }
  229. USTRList * ustrlist_init(USTRList * self) {
  230. if (!self) return self;
  231. badlist_init(self);
  232. return self;
  233. }
  234. USTRList * ustrlist_new() {
  235. return ustrlist_init(ustrlist_alloc());
  236. }
  237. USTRList * ustrlist_done(USTRList * self) {
  238. BadListNode * elem;
  239. USTRListNode * node;
  240. if(!self) return NULL;
  241. elem = badlist_head(self);
  242. while(elem) {
  243. node = badlistnode_ustrlistnode(elem);
  244. elem = badlistnode_next(elem);
  245. // here, elem is already pointing to next so node is safe to free
  246. ustrlistnode_free(node);
  247. }
  248. ustrlist_init(self);
  249. return self;
  250. }
  251. USTRList * ustrlist_free(USTRList * self) {
  252. if(!ustrlist_done(self)) return NULL;
  253. mem_free(self);
  254. return NULL;
  255. }
  256. USTRList * ustrlist_addnode(USTRList * self, USTRListNode * node) {
  257. if(!self) return NULL;
  258. badlist_add(self, &node->list);
  259. return self;
  260. }
  261. USTRList * ustrlist_shiftnode(USTRList * self, USTRListNode * node) {
  262. if(!self) return NULL;
  263. badlist_shift(self, &node->list);
  264. return self;
  265. }
  266. /* Removes the node from the list and frees it too. */
  267. USTRList * ustrlist_removenode(USTRList * self, USTRListNode * node) {
  268. if(!self) return NULL;
  269. badlist_remove(self, &node->list);
  270. ustrlistnode_free(node);
  271. return self;
  272. }
  273. USTRListNode * ustrlist_addustr(USTRList * self, const USTR * ustr) {
  274. USTRListNode * node = ustrlistnode_new(ustr);
  275. if(!node) return NULL;
  276. ustrlist_addnode(self, node);
  277. return node;
  278. }
  279. USTRListNode * ustrlist_addcstr(USTRList * self, const char * cstr) {
  280. USTRListNode * node = ustrlistnode_newcstr(cstr);
  281. if(!node) return NULL;
  282. ustrlist_addnode(self, node);
  283. return node;
  284. }
  285. USTRListNode * ustrlist_shiftustr(USTRList * self, const USTR * ustr) {
  286. USTRListNode * node = ustrlistnode_new(ustr);
  287. if(!node) return NULL;
  288. ustrlist_shiftnode(self, node);
  289. return node;
  290. }
  291. USTRListNode * ustrlist_shiftcstr(USTRList * self, const char * cstr) {
  292. USTRListNode * node = ustrlistnode_newcstr(cstr);
  293. if(!node) return NULL;
  294. ustrlist_shiftnode(self, node);
  295. return node;
  296. }
  297. int ustrlist_size(USTRList * self) {
  298. return badlist_size(self);
  299. }
  300. USTRList * ustrlist_droplast(USTRList * self) {
  301. USTRListNode * node;
  302. node = ustrlist_tail(self);
  303. ustrlist_removenode(self, node);
  304. return self;
  305. }
  306. /* Joins the list to a newly allocated string. The result must be freed after
  307. use with (al_)ustr_free(). */
  308. USTR * ustrlist_join(USTRList * self) {
  309. USTRListNode * node;
  310. USTR * result;
  311. result = ustr_new("");
  312. for(node = ustrlist_head(self); node; node = ustrlistnode_next(node)) {
  313. ustr_append(result, ustrlistnode_ustr(node));
  314. }
  315. return result;
  316. }
  317. /* Joins the list to a newly allocated string, using sep as the separator.
  318. The result must be freed after use with (al_)ustr_free(). */
  319. USTR * ustrlist_joinwithcstr(USTRList * self, const char * sep) {
  320. int first = true;
  321. USTRListNode * node;
  322. USTR * result;
  323. result = ustr_new("");
  324. for(node = ustrlist_head(self); node; node = ustrlistnode_next(node)) {
  325. if(first) {
  326. first = false;
  327. } else {
  328. ustr_appendcstr(result, sep);
  329. }
  330. ustr_append(result, ustrlistnode_ustr(node));
  331. }
  332. return result;
  333. }
  334. /* Joins the list to a newly allocated string, using ch as the separator.
  335. The result must be freed after use with (al_)ustr_free(). */
  336. USTR * ustrlist_joinwithch(USTRList * self, const char ch) {
  337. int first = true;
  338. USTRListNode * node;
  339. USTR * result;
  340. result = ustr_new("");
  341. for(node = ustrlist_head(self); node; node = ustrlistnode_next(node)) {
  342. if(first) {
  343. first = false;
  344. } else {
  345. ustr_appendch(result, ch);
  346. }
  347. ustr_append(result, ustrlistnode_ustr(node));
  348. }
  349. return result;
  350. }
  351. /* Joins the list to a newly allocated string, using sep as the separator.
  352. The result must be freed after use with (al_)ustr_free(). */
  353. USTR * ustrlist_joinwithustr(USTRList * self, USTR * sep) {
  354. int first = true;
  355. USTRListNode * node;
  356. USTR * result;
  357. result = ustr_new("");
  358. for(node = ustrlist_head(self); node; node = ustrlistnode_next(node)) {
  359. if(first) {
  360. first = false;
  361. } else {
  362. ustr_append(result, sep);
  363. }
  364. ustr_append(result, ustrlistnode_ustr(node));
  365. }
  366. return result;
  367. }
  368. /* Returns the list the node reached after skipping skip nodes from head.
  369. * Returns NULL if there is no such node or on other failures.
  370. */
  371. USTRListNode * ustrlist_skipnode(USTRList * self, int skip) {
  372. USTRListNode * now ;
  373. // skip skip lines
  374. for (now = ustrlist_head(self); now && (skip > 0); skip --) {
  375. now = ustrlistnode_next(now); // move to next line.
  376. }
  377. return now;
  378. }
  379. typedef int USTRGetWidth(USTR const * ustr, void * data);
  380. /** Splits the incoming c string into a list of ustrings, each which have a width
  381. less than width. The callback get_width is called to determine
  382. the size of the string as it is puzzled together. The string will be split on
  383. spaces. Tabs are non-braking but will be replaced by spaces. Newlines will force a new line.
  384. */
  385. USTRList * ustrlist_splitcstr(const char * cstr, double width,
  386. USTRGetWidth * get_width, void * data) {
  387. return NULL; /* Look for widget textinfo in stead. */
  388. }