Happy new year
[yaz-moved-to-github.git] / src / tokenizer.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2009 Index Data
3  * See the file LICENSE for details.
4  */
5
6 /**
7  * \file tokenizer.c
8  * \brief Simple tokenizer system.
9  */
10
11 #include <assert.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <ctype.h>
15 #include <yaz/log.h>
16 #include <yaz/wrbuf.h>
17 #include <yaz/tokenizer.h>
18
19 struct yaz_tok_parse {
20     int unget_byte;
21     WRBUF wr_string;
22     int look;
23     
24     yaz_tok_cfg_t cfg;
25     yaz_tok_get_byte_t get_byte_func;
26     void *get_byte_data;
27 };
28
29 struct yaz_tok_cfg {
30     int ref_count;
31     char *comment;
32     char *white_space;
33     char *single_tokens;
34     char *quote_tokens_begin;
35     char *quote_tokens_end;
36 };
37
38 void yaz_tok_cfg_single_tokens(yaz_tok_cfg_t t, const char *simple)
39 {
40     xfree(t->single_tokens);
41     t->single_tokens = xstrdup(simple);
42 }
43
44 yaz_tok_cfg_t yaz_tok_cfg_create(void)
45 {
46     yaz_tok_cfg_t t = (yaz_tok_cfg_t) xmalloc(sizeof(*t));
47     t->white_space = xstrdup(" \t\r\n");
48     t->single_tokens = xstrdup("");
49     t->quote_tokens_begin = xstrdup("\"");
50     t->quote_tokens_end = xstrdup("\"");
51     t->comment = xstrdup("#");
52     t->ref_count = 1;
53     return t;
54 }
55
56 void yaz_tok_cfg_destroy(yaz_tok_cfg_t t)
57 {
58     t->ref_count--;
59     if (t->ref_count == 0)
60     {
61         xfree(t->white_space);
62         xfree(t->single_tokens);
63         xfree(t->quote_tokens_begin);
64         xfree(t->quote_tokens_end);
65         xfree(t->comment);
66         xfree(t);
67     }
68 }
69
70 static int read_buf(void **vp)
71 {
72     const char *cp = *(const char **) vp;
73     int ch = *cp;
74     if (ch)
75     {
76         cp++;
77         *(const char **)vp = cp;
78     }
79     return ch;
80 }
81
82 yaz_tok_parse_t yaz_tok_parse_buf(yaz_tok_cfg_t t, const char *buf)
83 {
84     return yaz_tok_parse_create(t, read_buf, (void *) buf);
85 }
86
87 static int get_byte(yaz_tok_parse_t tp)
88 {
89     int ch = tp->unget_byte;
90     assert(tp->get_byte_func);
91     if (ch)
92         tp->unget_byte = 0;
93     else
94         ch = tp->get_byte_func(&tp->get_byte_data);
95     return ch;
96 }
97
98 static void unget_byte(yaz_tok_parse_t tp, int ch)
99 {
100     tp->unget_byte = ch;
101 }
102
103 yaz_tok_parse_t yaz_tok_parse_create(yaz_tok_cfg_t t,
104                                      yaz_tok_get_byte_t h,
105                                      void *vp)
106 {
107     yaz_tok_parse_t tp = (yaz_tok_parse_t) xmalloc(sizeof(*tp));
108
109     tp->cfg = t;
110     tp->cfg->ref_count++;
111     tp->get_byte_func = h;
112     tp->get_byte_data = vp;
113
114     tp->look = YAZ_TOK_ERROR;
115     tp->unget_byte = 0;
116
117     tp->wr_string = wrbuf_alloc();
118     return tp;
119 }
120                                            
121
122 void yaz_tok_parse_destroy(yaz_tok_parse_t tp)
123 {
124     yaz_tok_cfg_destroy(tp->cfg);
125     wrbuf_destroy(tp->wr_string);
126     xfree(tp);
127 }
128
129 int yaz_tok_move(yaz_tok_parse_t tp)
130 {
131     yaz_tok_cfg_t t = tp->cfg;
132     const char *cp;
133     int ch = get_byte(tp);
134
135     /* skip white space */
136     while (ch && strchr(t->white_space, ch))
137         ch = get_byte(tp);
138     if (!ch) 
139         ch = YAZ_TOK_EOF;
140     else if (strchr(t->comment, ch))
141         ch = YAZ_TOK_EOF;
142     else if ((cp = strchr(t->single_tokens, ch)))
143         ch = *cp;  /* single token match */
144     else if ((cp = strchr(t->quote_tokens_begin, ch)))
145     {   /* quoted string */
146         int end_ch = t->quote_tokens_end[cp - t->quote_tokens_begin];
147         ch = get_byte(tp);
148         wrbuf_rewind(tp->wr_string);
149         while (ch && ch != end_ch)
150             wrbuf_putc(tp->wr_string, ch);
151         if (!ch)
152             ch = YAZ_TOK_ERROR;
153         else
154             ch = YAZ_TOK_QSTRING;
155     }
156     else
157     {  /* unquoted string */
158         wrbuf_rewind(tp->wr_string);
159         while (ch && !strchr(t->white_space, ch)
160                && !strchr(t->single_tokens, ch)
161                && !strchr(t->comment, ch))
162         {
163             wrbuf_putc(tp->wr_string, ch);
164             ch = get_byte(tp);
165         }
166         unget_byte(tp, ch);
167         ch = YAZ_TOK_STRING;
168     }
169     tp->look = ch;
170     return ch;
171 }
172
173 const char *yaz_tok_parse_string(yaz_tok_parse_t tp)
174 {
175     return wrbuf_cstr(tp->wr_string);
176 }
177
178 /*
179  * Local variables:
180  * c-basic-offset: 4
181  * indent-tabs-mode: nil
182  * End:
183  * vim: shiftwidth=4 tabstop=8 expandtab
184  */
185