/src/ftk_input_pattern.c

http://ftk.googlecode.com/ · C · 558 lines · 445 code · 78 blank · 35 comment · 130 complexity · 903de5f7816a3fb386e3619d1a19a6ab MD5 · raw file

  1. /*
  2. * File: ftk_input_pattern.c
  3. * Author: Li XianJing <xianjimli@hotmail.com>
  4. * Brief: input pattern to format some special input, such as date,
  5. * time and ip address.
  6. *
  7. * Copyright (c) 2009 - 2011 Li XianJing <xianjimli@hotmail.com>
  8. *
  9. * Licensed under the Academic Free License version 2.1
  10. *
  11. * This program is free software; you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License as published by
  13. * the Free Software Foundation; either version 2 of the License, or
  14. * (at your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License
  22. * along with this program; if not, write to the Free Software
  23. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  24. */
  25. /*
  26. * History:
  27. * ================================================================
  28. * 2011-07-28 Li XianJing <xianjimli@hotmail.com> created
  29. *
  30. */
  31. #include "ftk_log.h"
  32. #include "ftk_allocator.h"
  33. #include "ftk_input_pattern.h"
  34. typedef enum _ValidType
  35. {
  36. VT_DIGIT = 'D',
  37. VT_XDIGIT = 'X',
  38. VT_ALPHA = 'A',
  39. VT_ID = 'I'
  40. }ValidType;
  41. typedef int (*IsValidChar)(unsigned char c);
  42. typedef struct _InputPattern
  43. {
  44. size_t offset;
  45. size_t size;
  46. size_t min_size;
  47. size_t max_size;
  48. unsigned char default_char;
  49. unsigned char delim_char;
  50. struct _InputPattern* next;
  51. IsValidChar is_valid_char;
  52. }InputPattern;
  53. struct _FtkInputPattern
  54. {
  55. char* text;
  56. int caret;
  57. size_t max_length;
  58. InputPattern* pattern;
  59. };
  60. static void input_pattern_clear(InputPattern* p)
  61. {
  62. p->offset = p->size = p->min_size = p->max_size = 0;
  63. p->default_char = p->delim_char = '\0';
  64. p->next = NULL;
  65. p->is_valid_char = NULL;
  66. return;
  67. }
  68. static int is_digit(unsigned char c)
  69. {
  70. return c >= '0' && c <= '9';
  71. }
  72. static int is_xdigit(unsigned char c)
  73. {
  74. return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
  75. }
  76. static int is_alpha(unsigned char c)
  77. {
  78. return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
  79. }
  80. static int is_id(unsigned char c)
  81. {
  82. return is_alpha(c) || is_digit(c) || c == '_';
  83. }
  84. static int is_any(unsigned char c)
  85. {
  86. return 1;
  87. }
  88. static IsValidChar find_valid_function(unsigned char d)
  89. {
  90. switch(d)
  91. {
  92. case 'D': return is_digit;
  93. case 'X': return is_xdigit;
  94. case 'A': return is_alpha;
  95. case 'I': return is_id;
  96. default: break;
  97. }
  98. return is_any;
  99. }
  100. static Ret ftk_input_pattern_append(FtkInputPattern* thiz, InputPattern* p)
  101. {
  102. InputPattern* iter = NULL;
  103. InputPattern* pattern = NULL;
  104. return_val_if_fail(p->is_valid_char != NULL, RET_FAIL);
  105. if(p->max_size == 0)
  106. {
  107. p->max_size = p->min_size;
  108. }
  109. pattern = (InputPattern*)FTK_ZALLOC(sizeof(InputPattern));
  110. memcpy(pattern, p, sizeof(InputPattern));
  111. if(thiz->pattern == NULL)
  112. {
  113. thiz->pattern = pattern;
  114. }
  115. else
  116. {
  117. for(iter = thiz->pattern; iter->next != NULL; iter = iter->next);
  118. iter->next = pattern;
  119. }
  120. thiz->max_length += p->max_size + 1;
  121. return RET_OK;
  122. }
  123. /*D[2]0:D[2]0:D[2]0*/
  124. /*type[min-max]default_char delim_char*/
  125. static Ret ftk_input_pattern_parse(FtkInputPattern* thiz, const char* pattern)
  126. {
  127. int state = 0;
  128. size_t i = 0;
  129. unsigned char c = 0;
  130. InputPattern p = {0};
  131. enum
  132. {
  133. ST_TYPE,
  134. ST_MIN,
  135. ST_MAX,
  136. ST_DEFAULT,
  137. ST_DELIM
  138. };
  139. state = ST_TYPE;
  140. input_pattern_clear(&p);
  141. for(i = 0; pattern[i]; i++)
  142. {
  143. c = pattern[i];
  144. switch(state)
  145. {
  146. case ST_TYPE:
  147. {
  148. if(c == '[')
  149. {
  150. state = ST_MIN;
  151. }
  152. else
  153. {
  154. p.is_valid_char = find_valid_function(c);
  155. }
  156. break;
  157. }
  158. case ST_MIN:
  159. {
  160. if(c == ']')
  161. {
  162. state = ST_DEFAULT;
  163. }
  164. else if(c == '-')
  165. {
  166. state = ST_MAX;
  167. }
  168. else
  169. {
  170. p.min_size = p.min_size * 10 + c - '0';
  171. }
  172. break;
  173. }
  174. case ST_MAX:
  175. {
  176. if(c == ']')
  177. {
  178. state = ST_DEFAULT;
  179. }
  180. else
  181. {
  182. p.max_size = p.max_size * 10 + c - '0';
  183. }
  184. break;
  185. }
  186. case ST_DEFAULT:
  187. {
  188. if(p.is_valid_char(c))
  189. {
  190. p.default_char = c;
  191. state = ST_DELIM;
  192. break;
  193. }
  194. else
  195. {
  196. /*fall down*/
  197. }
  198. }
  199. case ST_DELIM:
  200. {
  201. p.delim_char = c;
  202. state = ST_TYPE;
  203. ftk_input_pattern_append(thiz, &p);
  204. input_pattern_clear(&p);
  205. break;
  206. }
  207. default:break;
  208. }
  209. }
  210. ftk_input_pattern_append(thiz, &p);
  211. return RET_OK;
  212. }
  213. FtkInputPattern* ftk_input_pattern_create(const char* pattern, const char* init)
  214. {
  215. FtkInputPattern* thiz = NULL;
  216. return_val_if_fail(pattern != NULL && init != NULL, NULL);
  217. thiz = (FtkInputPattern*)FTK_ZALLOC(sizeof(FtkInputPattern));
  218. if(thiz != NULL)
  219. {
  220. ftk_input_pattern_parse(thiz, pattern);
  221. thiz->max_length += 1;
  222. ftk_input_pattern_set_text(thiz, init);
  223. }
  224. return thiz;
  225. }
  226. static InputPattern* ftk_input_pattern_get_pattern_of_caret(FtkInputPattern* thiz)
  227. {
  228. size_t i = 0;
  229. size_t start = 0;
  230. size_t end = 0;
  231. unsigned char c = 0;
  232. InputPattern* iter = thiz->pattern;
  233. for(i = 0; thiz->text[i] && i < thiz->caret && iter != NULL; i++)
  234. {
  235. c = thiz->text[i];
  236. if(c == iter->delim_char)
  237. {
  238. iter = iter->next;
  239. start = i + 1;
  240. }
  241. }
  242. if(iter != NULL)
  243. {
  244. for(; thiz->text[i]; i++)
  245. {
  246. c = thiz->text[i];
  247. if(c == iter->delim_char)
  248. {
  249. break;
  250. }
  251. }
  252. end = i;
  253. iter->offset = start;
  254. iter->size = end - start;
  255. }
  256. return iter;
  257. }
  258. Ret ftk_input_pattern_input(FtkInputPattern* thiz, FtkKey key)
  259. {
  260. size_t i = 0;
  261. Ret ret = RET_OK;
  262. InputPattern* pattern = NULL;
  263. return_val_if_fail(thiz != NULL, RET_FAIL);
  264. pattern = ftk_input_pattern_get_pattern_of_caret(thiz);
  265. return_val_if_fail(pattern != NULL, RET_FAIL);
  266. switch(key)
  267. {
  268. case FTK_KEY_DELETE:
  269. {
  270. if(pattern->size <= pattern->min_size)
  271. {
  272. if(thiz->text[thiz->caret] != pattern->delim_char)
  273. {
  274. thiz->text[thiz->caret] = pattern->default_char;
  275. }
  276. break;
  277. }
  278. if(thiz->text[thiz->caret] != pattern->delim_char)
  279. {
  280. if(pattern->size > 1)
  281. {
  282. for(i = thiz->caret + 1; thiz->text[i]; i++)
  283. {
  284. thiz->text[i] = thiz->text[i+1];
  285. }
  286. }
  287. else if(pattern->size == 1)
  288. {
  289. thiz->text[thiz->caret] = pattern->default_char;
  290. }
  291. }
  292. break;
  293. }
  294. case FTK_KEY_BACKSPACE:
  295. {
  296. thiz->caret--;
  297. if(thiz->caret < pattern->offset) break;
  298. if(pattern->size <= pattern->min_size)
  299. {
  300. if(thiz->text[thiz->caret] != pattern->delim_char)
  301. {
  302. thiz->text[thiz->caret] = pattern->default_char;
  303. }
  304. }
  305. else
  306. {
  307. if(pattern->size > 1)
  308. {
  309. for(i = thiz->caret; thiz->text[i]; i++)
  310. {
  311. thiz->text[i] = thiz->text[i+1];
  312. }
  313. }
  314. else if(pattern->size == 1)
  315. {
  316. thiz->text[thiz->caret] = pattern->default_char;
  317. }
  318. }
  319. break;
  320. }
  321. case FTK_KEY_LEFT:
  322. {
  323. if(thiz->caret > 0)
  324. {
  325. thiz->caret--;
  326. }
  327. break;
  328. }
  329. case FTK_KEY_RIGHT:
  330. {
  331. if(thiz->caret < strlen(thiz->text))
  332. {
  333. thiz->caret++;
  334. }
  335. break;
  336. }
  337. default:
  338. {
  339. unsigned char c = (unsigned char)key;
  340. if(pattern->is_valid_char(c))
  341. {
  342. if(pattern->size == pattern->max_size)
  343. {
  344. /*replace*/
  345. if(thiz->text[thiz->caret] != pattern->delim_char)
  346. {
  347. thiz->text[thiz->caret] = c;
  348. }
  349. }
  350. else
  351. {
  352. /*insert*/
  353. thiz->text[strlen(thiz->text) + 1] = '\0';
  354. for(i = strlen(thiz->text); i > thiz->caret; i--)
  355. {
  356. thiz->text[i] = thiz->text[i-1];
  357. }
  358. thiz->text[i] = c;
  359. }
  360. thiz->caret++;
  361. }
  362. else
  363. {
  364. ret = RET_CONTINUE;
  365. }
  366. }
  367. }
  368. if(thiz->caret < 0)
  369. {
  370. thiz->caret = 0;
  371. }
  372. return ret;
  373. }
  374. Ret ftk_input_pattern_set_caret(FtkInputPattern* thiz, size_t caret)
  375. {
  376. return_val_if_fail(thiz != NULL, RET_FAIL);
  377. if(caret <= strlen(thiz->text))
  378. {
  379. thiz->caret = caret;
  380. }
  381. return RET_OK;
  382. }
  383. Ret ftk_input_pattern_set_text(FtkInputPattern* thiz, const char* text)
  384. {
  385. return_val_if_fail(thiz != NULL && text != NULL, RET_FAIL);
  386. if(thiz->text == NULL)
  387. {
  388. thiz->text = (char*)FTK_ZALLOC(thiz->max_length + 1);
  389. }
  390. strncpy(thiz->text, text, thiz->max_length);
  391. return RET_OK;
  392. }
  393. size_t ftk_input_pattern_get_caret(FtkInputPattern* thiz)
  394. {
  395. return_val_if_fail(thiz != NULL, 0);
  396. return thiz->caret;
  397. }
  398. const char* ftk_input_pattern_get_text(FtkInputPattern* thiz)
  399. {
  400. return_val_if_fail(thiz != NULL, NULL);
  401. return thiz->text;
  402. }
  403. void ftk_input_pattern_destroy(FtkInputPattern* thiz)
  404. {
  405. InputPattern* save = NULL;
  406. InputPattern* iter = NULL;
  407. if(thiz != NULL)
  408. {
  409. iter = thiz->pattern;
  410. while(iter != NULL)
  411. {
  412. save = iter->next;
  413. FTK_FREE(iter);
  414. iter = save;
  415. }
  416. FTK_FREE(thiz);
  417. }
  418. return;
  419. }
  420. #ifdef _TEST
  421. int main(int argc, char* argv[])
  422. {
  423. InputPattern* p = NULL;
  424. ftk_set_allocator(ftk_allocator_default_create());
  425. FtkInputPattern* thiz = ftk_input_pattern_create("D[2]0:A[2-4]a:X[0-4]b", "12:abc:4");
  426. assert(thiz->pattern->is_valid_char == is_digit);
  427. assert(thiz->pattern->min_size == 2);
  428. assert(thiz->pattern->max_size == 2);
  429. assert(thiz->pattern->default_char == '0');
  430. assert(thiz->pattern->next->is_valid_char == is_alpha);
  431. assert(thiz->pattern->next->min_size == 2);
  432. assert(thiz->pattern->next->max_size == 4);
  433. assert(thiz->pattern->next->default_char == 'a');
  434. assert(thiz->pattern->next->next->is_valid_char == is_xdigit);
  435. assert(thiz->pattern->next->next->min_size == 0);
  436. assert(thiz->pattern->next->next->max_size == 4);
  437. assert(thiz->pattern->next->next->default_char == 'b');
  438. ftk_input_pattern_destroy(thiz);
  439. thiz = ftk_input_pattern_create("D[2-2]0:A[2-4]a:X[0-4]b", "12:abc:4");
  440. assert(thiz->pattern->is_valid_char == is_digit);
  441. assert(thiz->pattern->min_size == 2);
  442. assert(thiz->pattern->max_size == 2);
  443. assert(thiz->pattern->default_char == '0');
  444. assert(thiz->pattern->next->is_valid_char == is_alpha);
  445. assert(thiz->pattern->next->min_size == 2);
  446. assert(thiz->pattern->next->max_size == 4);
  447. assert(thiz->pattern->next->default_char == 'a');
  448. assert(thiz->pattern->next->next->is_valid_char == is_xdigit);
  449. assert(thiz->pattern->next->next->min_size == 0);
  450. assert(thiz->pattern->next->next->max_size == 4);
  451. assert(thiz->pattern->next->next->default_char == 'b');
  452. ftk_input_pattern_set_caret(thiz, 0);
  453. p = ftk_input_pattern_get_pattern_of_caret(thiz);
  454. assert(p->offset == 0);
  455. assert(p->size == 2);
  456. ftk_input_pattern_set_caret(thiz, 1);
  457. p = ftk_input_pattern_get_pattern_of_caret(thiz);
  458. assert(p->is_valid_char == is_digit);
  459. assert(p->offset == 0);
  460. assert(p->size == 2);
  461. ftk_input_pattern_set_caret(thiz, 3);
  462. p = ftk_input_pattern_get_pattern_of_caret(thiz);
  463. assert(p->is_valid_char == is_alpha);
  464. assert(p->offset == 3);
  465. assert(p->size == 3);
  466. ftk_input_pattern_set_caret(thiz, 7);
  467. p = ftk_input_pattern_get_pattern_of_caret(thiz);
  468. assert(p->is_valid_char == is_xdigit);
  469. assert(p->offset == 7);
  470. assert(p->size == 1);
  471. assert(strcmp(thiz->text, "12:abc:4") == 0);
  472. ftk_input_pattern_set_caret(thiz, 0);
  473. ftk_input_pattern_input(thiz, FTK_KEY_DELETE);
  474. assert(strcmp(thiz->text, "1:abc:4") == 0);
  475. ftk_input_pattern_input(thiz, FTK_KEY_DELETE);
  476. assert(strcmp(thiz->text, "0:abc:4") == 0);
  477. ftk_input_pattern_destroy(thiz);
  478. return 0;
  479. }
  480. #endif