PageRenderTime 57ms CodeModel.GetById 27ms app.highlight 26ms RepoModel.GetById 1ms app.codeStats 0ms

/src/ftk_input_pattern.c

http://ftk.googlecode.com/
C | 558 lines | 445 code | 78 blank | 35 comment | 126 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/*
 27 * History:
 28 * ================================================================
 29 * 2011-07-28 Li XianJing <xianjimli@hotmail.com> created
 30 *
 31 */
 32
 33#include "ftk_log.h"
 34#include "ftk_allocator.h"
 35#include "ftk_input_pattern.h"
 36
 37typedef enum _ValidType
 38{
 39	VT_DIGIT  = 'D',
 40	VT_XDIGIT = 'X',
 41	VT_ALPHA  = 'A',
 42	VT_ID     = 'I'
 43}ValidType;
 44
 45typedef int (*IsValidChar)(unsigned char c);
 46
 47typedef struct _InputPattern
 48{
 49	size_t offset;
 50	size_t size;
 51	size_t min_size;
 52	size_t max_size;
 53	unsigned char default_char;
 54	unsigned char delim_char;
 55	struct _InputPattern* next;
 56	IsValidChar is_valid_char;
 57}InputPattern;
 58
 59struct _FtkInputPattern
 60{
 61	char* text;
 62	int caret;
 63	size_t max_length;
 64
 65	InputPattern* pattern;
 66};
 67
 68static void input_pattern_clear(InputPattern* p)
 69{
 70	p->offset = p->size = p->min_size = p->max_size = 0;
 71	p->default_char = p->delim_char = '\0';
 72	p->next = NULL;
 73	p->is_valid_char = NULL;
 74
 75	return;
 76}
 77
 78static int is_digit(unsigned char c)
 79{
 80	return c >= '0' && c <= '9';
 81}
 82
 83static int is_xdigit(unsigned char c)
 84{
 85	return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
 86}
 87
 88static int is_alpha(unsigned char c)
 89{
 90	return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
 91}
 92
 93static int is_id(unsigned char c)
 94{
 95	return is_alpha(c) || is_digit(c) || c == '_';
 96}
 97
 98static int is_any(unsigned char c)
 99{
100	return 1;
101}
102
103static IsValidChar find_valid_function(unsigned char d)
104{
105	switch(d)
106	{
107		case 'D': return is_digit;
108		case 'X': return is_xdigit;
109		case 'A': return is_alpha;
110		case 'I': return is_id;
111		default: break;
112	}
113
114	return is_any;
115}
116
117static Ret ftk_input_pattern_append(FtkInputPattern* thiz, InputPattern* p)
118{
119	InputPattern* iter = NULL;
120	InputPattern* pattern = NULL;
121	return_val_if_fail(p->is_valid_char != NULL, RET_FAIL);
122
123	if(p->max_size == 0)
124	{
125		p->max_size = p->min_size;
126	}
127
128	pattern = (InputPattern*)FTK_ZALLOC(sizeof(InputPattern));
129	memcpy(pattern, p, sizeof(InputPattern));
130
131	if(thiz->pattern == NULL)
132	{
133		thiz->pattern = pattern;
134	}
135	else
136	{
137		for(iter = thiz->pattern; iter->next != NULL; iter = iter->next);
138		iter->next = pattern;
139	}
140
141	thiz->max_length += p->max_size + 1;
142
143	return RET_OK;
144}
145
146/*D[2]0:D[2]0:D[2]0*/
147/*type[min-max]default_char delim_char*/
148static Ret ftk_input_pattern_parse(FtkInputPattern* thiz, const char* pattern)
149{
150	int state = 0;
151	size_t i = 0;
152	unsigned char c = 0;
153	InputPattern p = {0};
154	enum 
155	{
156		ST_TYPE,
157		ST_MIN,
158		ST_MAX,
159		ST_DEFAULT,
160		ST_DELIM
161	};
162
163	state = ST_TYPE;
164	input_pattern_clear(&p);
165	for(i = 0; pattern[i]; i++)
166	{
167		c = pattern[i];
168
169		switch(state)
170		{
171			case ST_TYPE:
172			{
173				if(c == '[')
174				{
175					state = ST_MIN;
176				}
177				else
178				{
179					p.is_valid_char = find_valid_function(c);
180				}
181				break;
182			}
183			case ST_MIN:
184			{
185				if(c == ']')
186				{
187					state = ST_DEFAULT;
188				}
189				else if(c == '-')
190				{
191					state = ST_MAX;
192				}
193				else
194				{
195					p.min_size = p.min_size * 10 + c - '0';
196				}
197				break;
198			}
199			case ST_MAX:
200			{
201				if(c == ']')
202				{
203					state = ST_DEFAULT;
204				}
205				else
206				{
207					p.max_size = p.max_size * 10 + c - '0';
208				}
209				
210				break;
211			}
212			case ST_DEFAULT:
213			{
214				if(p.is_valid_char(c))
215				{
216					p.default_char = c;
217					state = ST_DELIM;
218					break;
219				}
220				else
221				{
222					/*fall down*/
223				}
224			}
225			case ST_DELIM:
226			{
227				p.delim_char = c;
228				state = ST_TYPE;
229				ftk_input_pattern_append(thiz, &p);
230				input_pattern_clear(&p);
231				break;
232			}
233			default:break;
234		}
235	}
236	
237	ftk_input_pattern_append(thiz, &p);
238
239	return RET_OK;
240}
241
242FtkInputPattern* ftk_input_pattern_create(const char* pattern, const char* init)
243{
244	FtkInputPattern* thiz = NULL;
245
246	return_val_if_fail(pattern != NULL && init != NULL, NULL);
247	
248	thiz = (FtkInputPattern*)FTK_ZALLOC(sizeof(FtkInputPattern));
249
250	if(thiz != NULL)
251	{
252		ftk_input_pattern_parse(thiz, pattern);
253		thiz->max_length += 1;
254		ftk_input_pattern_set_text(thiz, init);
255	}
256
257	return thiz;
258}
259
260static InputPattern* ftk_input_pattern_get_pattern_of_caret(FtkInputPattern* thiz)
261{
262	size_t i = 0;
263	size_t start = 0;
264	size_t end = 0;
265	unsigned char c = 0;
266	InputPattern* iter = thiz->pattern;
267
268	for(i = 0; thiz->text[i] && i < thiz->caret && iter != NULL; i++)
269	{
270		c = thiz->text[i];
271
272		if(c == iter->delim_char)
273		{
274			iter = iter->next;
275			start = i + 1;
276		}
277	}
278
279	if(iter != NULL)
280	{
281		for(; thiz->text[i]; i++)
282		{
283			c = thiz->text[i];
284
285			if(c == iter->delim_char)
286			{
287				break;
288			}	
289		}
290		end = i;
291		iter->offset = start;
292		iter->size = end - start;
293	}
294
295	return iter;
296}
297
298Ret    ftk_input_pattern_input(FtkInputPattern* thiz, FtkKey key)
299{
300	size_t i = 0;
301	Ret ret = RET_OK;
302	InputPattern* pattern = NULL;
303	return_val_if_fail(thiz != NULL, RET_FAIL);
304
305	pattern = ftk_input_pattern_get_pattern_of_caret(thiz);
306	return_val_if_fail(pattern != NULL, RET_FAIL);
307
308	switch(key)
309	{
310		case FTK_KEY_DELETE:
311		{
312			if(pattern->size <= pattern->min_size)
313			{
314				if(thiz->text[thiz->caret] != pattern->delim_char)
315				{
316					thiz->text[thiz->caret] = pattern->default_char;
317				}
318				break;
319			}
320
321			if(thiz->text[thiz->caret] != pattern->delim_char)
322			{
323				if(pattern->size > 1)
324				{
325					for(i = thiz->caret + 1; thiz->text[i]; i++)
326					{
327						thiz->text[i] = thiz->text[i+1];
328					}
329				}
330				else if(pattern->size == 1)
331				{
332					thiz->text[thiz->caret] = pattern->default_char;
333				}
334			}
335			break;
336		}
337		case FTK_KEY_BACKSPACE:
338		{
339			thiz->caret--;
340			if(thiz->caret < pattern->offset) break;
341
342			if(pattern->size <= pattern->min_size)
343			{
344				if(thiz->text[thiz->caret] != pattern->delim_char)
345				{
346					thiz->text[thiz->caret] = pattern->default_char;
347				}
348			}
349			else
350			{
351				if(pattern->size > 1)
352				{
353					for(i = thiz->caret; thiz->text[i]; i++)
354					{
355						thiz->text[i] = thiz->text[i+1];
356					}
357				}
358				else if(pattern->size == 1)
359				{
360					thiz->text[thiz->caret] = pattern->default_char;
361				}
362			}
363			break;
364		}
365		case FTK_KEY_LEFT:
366		{
367			if(thiz->caret > 0)
368			{
369				thiz->caret--;
370			}
371			break;
372		}
373		case FTK_KEY_RIGHT:
374		{
375			if(thiz->caret < strlen(thiz->text))
376			{
377				thiz->caret++;
378			}
379			break;
380		}
381		default:
382		{
383			unsigned char c = (unsigned char)key;
384			if(pattern->is_valid_char(c))
385			{
386				if(pattern->size == pattern->max_size)
387				{
388					/*replace*/
389					if(thiz->text[thiz->caret] != pattern->delim_char)
390					{
391						thiz->text[thiz->caret] = c;
392					}
393				}
394				else
395				{
396					/*insert*/
397					thiz->text[strlen(thiz->text) + 1] = '\0';
398					for(i = strlen(thiz->text); i > thiz->caret; i--)
399					{
400						thiz->text[i] = thiz->text[i-1];
401					}
402					thiz->text[i] = c;
403				}
404				thiz->caret++;
405			}
406			else
407			{
408				ret = RET_CONTINUE;
409			}
410		}
411	}
412
413	if(thiz->caret < 0)
414	{
415		thiz->caret = 0;
416	}
417
418	return ret;
419}
420
421Ret    ftk_input_pattern_set_caret(FtkInputPattern* thiz, size_t caret)
422{
423	return_val_if_fail(thiz != NULL, RET_FAIL);
424
425	if(caret <= strlen(thiz->text))
426	{
427		thiz->caret = caret;
428	}
429
430	return RET_OK;
431}
432
433Ret    ftk_input_pattern_set_text(FtkInputPattern* thiz, const char* text)
434{
435	return_val_if_fail(thiz != NULL && text != NULL, RET_FAIL);
436
437	if(thiz->text == NULL)
438	{
439		thiz->text = (char*)FTK_ZALLOC(thiz->max_length + 1);
440	}
441
442	strncpy(thiz->text, text, thiz->max_length);
443
444	return RET_OK;
445}
446
447size_t ftk_input_pattern_get_caret(FtkInputPattern* thiz)
448{
449	return_val_if_fail(thiz != NULL, 0);
450
451	return thiz->caret;
452}
453
454
455const char* ftk_input_pattern_get_text(FtkInputPattern* thiz)
456{
457	return_val_if_fail(thiz != NULL, NULL);
458
459	return thiz->text;
460}
461
462void ftk_input_pattern_destroy(FtkInputPattern* thiz)
463{
464	InputPattern* save = NULL;
465	InputPattern* iter = NULL;
466
467	if(thiz != NULL)
468	{
469		iter = thiz->pattern;
470
471		while(iter != NULL)
472		{
473			save = iter->next;
474			FTK_FREE(iter);
475			iter = save;
476		}
477
478		FTK_FREE(thiz);
479	}
480
481	return;
482}
483
484#ifdef _TEST
485int main(int argc, char* argv[])
486{
487	InputPattern* p = NULL;
488	ftk_set_allocator(ftk_allocator_default_create());
489	FtkInputPattern* thiz = ftk_input_pattern_create("D[2]0:A[2-4]a:X[0-4]b", "12:abc:4");
490	assert(thiz->pattern->is_valid_char == is_digit);
491	assert(thiz->pattern->min_size == 2);
492	assert(thiz->pattern->max_size == 2);
493	assert(thiz->pattern->default_char == '0');
494	
495	assert(thiz->pattern->next->is_valid_char == is_alpha);
496	assert(thiz->pattern->next->min_size == 2);
497	assert(thiz->pattern->next->max_size == 4);
498	assert(thiz->pattern->next->default_char == 'a');
499	
500	assert(thiz->pattern->next->next->is_valid_char == is_xdigit);
501	assert(thiz->pattern->next->next->min_size == 0);
502	assert(thiz->pattern->next->next->max_size == 4);
503	assert(thiz->pattern->next->next->default_char == 'b');
504
505	ftk_input_pattern_destroy(thiz);
506	
507	thiz = ftk_input_pattern_create("D[2-2]0:A[2-4]a:X[0-4]b", "12:abc:4");
508	assert(thiz->pattern->is_valid_char == is_digit);
509	assert(thiz->pattern->min_size == 2);
510	assert(thiz->pattern->max_size == 2);
511	assert(thiz->pattern->default_char == '0');
512	
513	assert(thiz->pattern->next->is_valid_char == is_alpha);
514	assert(thiz->pattern->next->min_size == 2);
515	assert(thiz->pattern->next->max_size == 4);
516	assert(thiz->pattern->next->default_char == 'a');
517	
518	assert(thiz->pattern->next->next->is_valid_char == is_xdigit);
519	assert(thiz->pattern->next->next->min_size == 0);
520	assert(thiz->pattern->next->next->max_size == 4);
521	assert(thiz->pattern->next->next->default_char == 'b');
522
523	ftk_input_pattern_set_caret(thiz, 0);
524	p = ftk_input_pattern_get_pattern_of_caret(thiz);
525	assert(p->offset == 0);
526	assert(p->size == 2);
527	
528	ftk_input_pattern_set_caret(thiz, 1);
529	p = ftk_input_pattern_get_pattern_of_caret(thiz);
530	assert(p->is_valid_char == is_digit);
531	assert(p->offset == 0);
532	assert(p->size == 2);
533	
534	ftk_input_pattern_set_caret(thiz, 3);
535	p = ftk_input_pattern_get_pattern_of_caret(thiz);
536	assert(p->is_valid_char == is_alpha);
537	assert(p->offset == 3);
538	assert(p->size == 3);
539	
540	ftk_input_pattern_set_caret(thiz, 7);
541	p = ftk_input_pattern_get_pattern_of_caret(thiz);
542	assert(p->is_valid_char == is_xdigit);
543	assert(p->offset == 7);
544	assert(p->size == 1);
545
546	assert(strcmp(thiz->text, "12:abc:4") == 0);
547	ftk_input_pattern_set_caret(thiz, 0);
548	ftk_input_pattern_input(thiz, FTK_KEY_DELETE);
549	assert(strcmp(thiz->text, "1:abc:4") == 0);
550	ftk_input_pattern_input(thiz, FTK_KEY_DELETE);
551	assert(strcmp(thiz->text, "0:abc:4") == 0);
552
553	ftk_input_pattern_destroy(thiz);
554
555
556	return 0;
557}
558#endif