Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
str.c
Go to the documentation of this file.
1 /* -*- c-basic-offset: 2 -*- */
2 /* Copyright(C) 2009-2013 Brazil
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Lesser General Public
6  License version 2.1 as published by the Free Software Foundation.
7 
8  This library is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11  Lesser General Public License for more details.
12 
13  You should have received a copy of the GNU Lesser General Public
14  License along with this library; if not, write to the Free Software
15  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17 #include "groonga_in.h"
18 #include <limits.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include "db.h"
22 #include "str.h"
23 
24 #ifndef _ISOC99_SOURCE
25 #define _ISOC99_SOURCE
26 #endif /* _ISOC99_SOURCE */
27 #include <math.h>
28 
29 inline static int
30 grn_str_charlen_utf8(grn_ctx *ctx, const unsigned char *str, const unsigned char *end)
31 {
32  /* MEMO: This function allows non-null-terminated string as str. */
33  /* But requires the end of string. */
34  if (end <= str || !*str) {
35  return 0;
36  }
37  if (*str & 0x80) {
38  int i;
39  int len;
40  GRN_BIT_SCAN_REV(~(*str << 24), len);
41  len = 31 - len;
42  if ((unsigned int)(len - 2) >= 3) { /* (len == 1 || len >= 5) */
44  "grn_str_charlen_utf8(): first byte is invalid");
45  return 0;
46  }
47  if (str + len > end) {
49  "grn_str_charlen_utf8(): incomplete character");
50  return 0;
51  }
52  for (i = 1; i < len; ++i) {
53  if ((str[i] & 0xc0) != 0x80) {
55  "grn_str_charlen_utf8(): <%d>th byte is invalid",
56  i + 1);
57  return 0;
58  }
59  }
60  return len;
61  } else {
62  return 1;
63  }
64 }
65 
66 unsigned int
67 grn_str_charlen(grn_ctx *ctx, const char *str, grn_encoding encoding)
68 {
69  /* MEMO: This function requires null-terminated string as str.*/
70  unsigned char *p = (unsigned char *) str;
71  if (!*p) { return 0; }
72  switch (encoding) {
73  case GRN_ENC_EUC_JP :
74  if (*p & 0x80) {
75  if (*(p + 1)) {
76  return 2;
77  } else {
78  /* This is invalid character */
79  GRN_LOG(ctx, GRN_LOG_WARNING, "invalid euc-jp string end on grn_str_charlen");
80  return 0;
81  }
82  }
83  return 1;
84  break;
85  case GRN_ENC_UTF8 :
86  if (*p & 0x80) {
87  int b, w;
88  size_t size;
89  for (b = 0x40, w = 0; b && (*p & b); b >>= 1, w++);
90  if (!w) {
91  GRN_LOG(ctx, GRN_LOG_WARNING, "invalid utf8 string(1) on grn_str_charlen");
92  return 0;
93  }
94  for (size = 1; w--; size++) {
95  if (!*++p || (*p & 0xc0) != 0x80) {
96  GRN_LOG(ctx, GRN_LOG_WARNING, "invalid utf8 string(2) on grn_str_charlen");
97  return 0;
98  }
99  }
100  return size;
101  } else {
102  return 1;
103  }
104  break;
105  case GRN_ENC_SJIS :
106  if (*p & 0x80) {
107  /* we regard 0xa0 as JIS X 0201 KANA. adjusted to other tools. */
108  if (0xa0 <= *p && *p <= 0xdf) {
109  /* hankaku-kana */
110  return 1;
111  } else if (!(*(p + 1))) {
112  /* This is invalid character */
113  GRN_LOG(ctx, GRN_LOG_WARNING, "invalid sjis string end on grn_str_charlen");
114  return 0;
115  } else {
116  return 2;
117  }
118  } else {
119  return 1;
120  }
121  break;
122  default :
123  return 1;
124  break;
125  }
126  return 0;
127 }
128 
129 int
130 grn_charlen_(grn_ctx *ctx, const char *str, const char *end, grn_encoding encoding)
131 {
132  /* MEMO: This function allows non-null-terminated string as str. */
133  /* But requires the end of string. */
134  unsigned char *p = (unsigned char *) str;
135  if (p >= (unsigned char *)end) { return 0; }
136  switch (encoding) {
137  case GRN_ENC_EUC_JP :
138  if (*p & 0x80) {
139  if ((p + 1) < (unsigned char *)end) {
140  return 2;
141  } else {
142  /* This is invalid character */
143  GRN_LOG(ctx, GRN_LOG_WARNING, "invalid euc-jp string end on grn_charlen");
144  return 0;
145  }
146  }
147  return 1;
148  break;
149  case GRN_ENC_UTF8 :
150  return grn_str_charlen_utf8(ctx, p, (unsigned char *)end);
151  break;
152  case GRN_ENC_SJIS :
153  if (*p & 0x80) {
154  /* we regard 0xa0 as JIS X 0201 KANA. adjusted to other tools. */
155  if (0xa0 <= *p && *p <= 0xdf) {
156  /* hankaku-kana */
157  return 1;
158  } else if (++p >= (unsigned char *)end) {
159  /* This is invalid character */
160  GRN_LOG(ctx, GRN_LOG_WARNING, "invalid sjis string end on grn_charlen");
161  return 0;
162  } else {
163  return 2;
164  }
165  } else {
166  return 1;
167  }
168  break;
169  default :
170  return 1;
171  break;
172  }
173  return 0;
174 }
175 
176 int
177 grn_charlen(grn_ctx *ctx, const char *str, const char *end)
178 {
179  return grn_charlen_(ctx, str, end, ctx->encoding);
180 }
181 
182 static unsigned char symbol[] = {
183  ',', '.', 0, ':', ';', '?', '!', 0, 0, 0, '`', 0, '^', '~', '_', 0, 0, 0,
184  0, 0, 0, 0, 0, 0, 0, '-', '-', '/', '\\', 0, 0, '|', 0, 0, 0, '\'', 0,
185  '"', '(', ')', 0, 0, '[', ']', '{', '}', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
186  '+', '-', 0, 0, 0, '=', 0, '<', '>', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
187  '$', 0, 0, '%', '#', '&', '*', '@', 0, 0, 0, 0, 0, 0, 0, 0
188 };
189 
190 inline static grn_rc
191 normalize_euc(grn_ctx *ctx, grn_str *nstr)
192 {
193  static uint16_t hankana[] = {
194  0xa1a1, 0xa1a3, 0xa1d6, 0xa1d7, 0xa1a2, 0xa1a6, 0xa5f2, 0xa5a1, 0xa5a3,
195  0xa5a5, 0xa5a7, 0xa5a9, 0xa5e3, 0xa5e5, 0xa5e7, 0xa5c3, 0xa1bc, 0xa5a2,
196  0xa5a4, 0xa5a6, 0xa5a8, 0xa5aa, 0xa5ab, 0xa5ad, 0xa5af, 0xa5b1, 0xa5b3,
197  0xa5b5, 0xa5b7, 0xa5b9, 0xa5bb, 0xa5bd, 0xa5bf, 0xa5c1, 0xa5c4, 0xa5c6,
198  0xa5c8, 0xa5ca, 0xa5cb, 0xa5cc, 0xa5cd, 0xa5ce, 0xa5cf, 0xa5d2, 0xa5d5,
199  0xa5d8, 0xa5db, 0xa5de, 0xa5df, 0xa5e0, 0xa5e1, 0xa5e2, 0xa5e4, 0xa5e6,
200  0xa5e8, 0xa5e9, 0xa5ea, 0xa5eb, 0xa5ec, 0xa5ed, 0xa5ef, 0xa5f3, 0xa1ab,
201  0xa1eb
202  };
203  static unsigned char dakuten[] = {
204  0xf4, 0, 0, 0, 0, 0xac, 0, 0xae, 0, 0xb0, 0, 0xb2, 0, 0xb4, 0, 0xb6, 0,
205  0xb8, 0, 0xba, 0, 0xbc, 0, 0xbe, 0, 0xc0, 0, 0xc2, 0, 0, 0xc5, 0, 0xc7,
206  0, 0xc9, 0, 0, 0, 0, 0, 0, 0xd0, 0, 0, 0xd3, 0, 0, 0xd6, 0, 0, 0xd9, 0,
207  0, 0xdc
208  };
209  static unsigned char handaku[] = {
210  0xd1, 0, 0, 0xd4, 0, 0, 0xd7, 0, 0, 0xda, 0, 0, 0xdd
211  };
212  int16_t *ch;
213  const unsigned char *s, *s_, *e;
214  unsigned char *d, *d0, *d_, b;
215  uint_least8_t *cp, *ctypes, ctype;
216  size_t size = nstr->orig_blen, length = 0;
217  int removeblankp = nstr->flags & GRN_STR_REMOVEBLANK;
218  if (!(nstr->norm = GRN_MALLOC(size * 2 + 1))) {
220  }
221  d0 = (unsigned char *) nstr->norm;
222  if (nstr->flags & GRN_STR_WITH_CHECKS) {
223  if (!(nstr->checks = GRN_MALLOC(size * 2 * sizeof(int16_t) + 1))) {
224  GRN_FREE(nstr->norm);
225  nstr->norm = NULL;
227  }
228  }
229  ch = nstr->checks;
230  if (nstr->flags & GRN_STR_WITH_CTYPES) {
231  if (!(nstr->ctypes = GRN_MALLOC(size + 1))) {
232  GRN_FREE(nstr->checks);
233  GRN_FREE(nstr->norm);
234  nstr->checks = NULL;
235  nstr->norm = NULL;
237  }
238  }
239  cp = ctypes = nstr->ctypes;
240  e = (unsigned char *)nstr->orig + size;
241  for (s = s_ = (unsigned char *) nstr->orig, d = d_ = d0; s < e; s++) {
242  if ((*s & 0x80)) {
243  if (((s + 1) < e) && (*(s + 1) & 0x80)) {
244  unsigned char c1 = *s++, c2 = *s, c3 = 0;
245  switch (c1 >> 4) {
246  case 0x08 :
247  if (c1 == 0x8e && 0xa0 <= c2 && c2 <= 0xdf) {
248  uint16_t c = hankana[c2 - 0xa0];
249  switch (c) {
250  case 0xa1ab :
251  if (d > d0 + 1 && d[-2] == 0xa5
252  && 0xa6 <= d[-1] && d[-1] <= 0xdb && (b = dakuten[d[-1] - 0xa6])) {
253  *(d - 1) = b;
254  if (ch) { ch[-1] += 2; s_ += 2; }
255  continue;
256  } else {
257  *d++ = c >> 8; *d = c & 0xff;
258  }
259  break;
260  case 0xa1eb :
261  if (d > d0 + 1 && d[-2] == 0xa5
262  && 0xcf <= d[-1] && d[-1] <= 0xdb && (b = handaku[d[-1] - 0xcf])) {
263  *(d - 1) = b;
264  if (ch) { ch[-1] += 2; s_ += 2; }
265  continue;
266  } else {
267  *d++ = c >> 8; *d = c & 0xff;
268  }
269  break;
270  default :
271  *d++ = c >> 8; *d = c & 0xff;
272  break;
273  }
274  ctype = GRN_CHAR_KATAKANA;
275  } else {
276  *d++ = c1; *d = c2;
277  ctype = GRN_CHAR_OTHERS;
278  }
279  break;
280  case 0x09 :
281  *d++ = c1; *d = c2;
282  ctype = GRN_CHAR_OTHERS;
283  break;
284  case 0x0a :
285  switch (c1 & 0x0f) {
286  case 1 :
287  switch (c2) {
288  case 0xbc :
289  *d++ = c1; *d = c2;
290  ctype = GRN_CHAR_KATAKANA;
291  break;
292  case 0xb9 :
293  *d++ = c1; *d = c2;
294  ctype = GRN_CHAR_KANJI;
295  break;
296  case 0xa1 :
297  if (removeblankp) {
298  if (cp > ctypes) { *(cp - 1) |= GRN_STR_BLANK; }
299  continue;
300  } else {
301  *d = ' ';
303  }
304  break;
305  default :
306  if (c2 >= 0xa4 && (c3 = symbol[c2 - 0xa4])) {
307  *d = c3;
308  ctype = GRN_CHAR_SYMBOL;
309  } else {
310  *d++ = c1; *d = c2;
311  ctype = GRN_CHAR_OTHERS;
312  }
313  break;
314  }
315  break;
316  case 2 :
317  *d++ = c1; *d = c2;
318  ctype = GRN_CHAR_SYMBOL;
319  break;
320  case 3 :
321  c3 = c2 - 0x80;
322  if ('a' <= c3 && c3 <= 'z') {
323  ctype = GRN_CHAR_ALPHA;
324  *d = c3;
325  } else if ('A' <= c3 && c3 <= 'Z') {
326  ctype = GRN_CHAR_ALPHA;
327  *d = c3 + 0x20;
328  } else if ('0' <= c3 && c3 <= '9') {
329  ctype = GRN_CHAR_DIGIT;
330  *d = c3;
331  } else {
332  ctype = GRN_CHAR_OTHERS;
333  *d++ = c1; *d = c2;
334  }
335  break;
336  case 4 :
337  *d++ = c1; *d = c2;
338  ctype = GRN_CHAR_HIRAGANA;
339  break;
340  case 5 :
341  *d++ = c1; *d = c2;
342  ctype = GRN_CHAR_KATAKANA;
343  break;
344  case 6 :
345  case 7 :
346  case 8 :
347  *d++ = c1; *d = c2;
348  ctype = GRN_CHAR_SYMBOL;
349  break;
350  default :
351  *d++ = c1; *d = c2;
352  ctype = GRN_CHAR_OTHERS;
353  break;
354  }
355  break;
356  default :
357  *d++ = c1; *d = c2;
358  ctype = GRN_CHAR_KANJI;
359  break;
360  }
361  } else {
362  /* skip invalid character */
363  continue;
364  }
365  } else {
366  unsigned char c = *s;
367  switch (c >> 4) {
368  case 0 :
369  case 1 :
370  /* skip unprintable ascii */
371  if (cp > ctypes) { *(cp - 1) |= GRN_STR_BLANK; }
372  continue;
373  case 2 :
374  if (c == 0x20) {
375  if (removeblankp) {
376  if (cp > ctypes) { *(cp - 1) |= GRN_STR_BLANK; }
377  continue;
378  } else {
379  *d = ' ';
381  }
382  } else {
383  *d = c;
384  ctype = GRN_CHAR_SYMBOL;
385  }
386  break;
387  case 3 :
388  *d = c;
389  ctype = (c <= 0x39) ? GRN_CHAR_DIGIT : GRN_CHAR_SYMBOL;
390  break;
391  case 4 :
392  *d = ('A' <= c) ? c + 0x20 : c;
393  ctype = (c == 0x40) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
394  break;
395  case 5 :
396  *d = (c <= 'Z') ? c + 0x20 : c;
397  ctype = (c <= 0x5a) ? GRN_CHAR_ALPHA : GRN_CHAR_SYMBOL;
398  break;
399  case 6 :
400  *d = c;
401  ctype = (c == 0x60) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
402  break;
403  case 7 :
404  *d = c;
405  ctype = (c <= 0x7a) ? GRN_CHAR_ALPHA : (c == 0x7f ? GRN_CHAR_OTHERS : GRN_CHAR_SYMBOL);
406  break;
407  default :
408  *d = c;
409  ctype = GRN_CHAR_OTHERS;
410  break;
411  }
412  }
413  d++;
414  length++;
415  if (cp) { *cp++ = ctype; }
416  if (ch) {
417  *ch++ = (int16_t)(s + 1 - s_);
418  s_ = s + 1;
419  while (++d_ < d) { *ch++ = 0; }
420  }
421  }
422  if (cp) { *cp = GRN_CHAR_NULL; }
423  *d = '\0';
424  nstr->length = length;
425  nstr->norm_blen = (size_t)(d - (unsigned char *)nstr->norm);
426  return GRN_SUCCESS;
427 }
428 
429 #ifdef GRN_WITH_NFKC
430 const char *grn_nfkc_map1(const unsigned char *str);
431 const char *grn_nfkc_map2(const unsigned char *prefix, const unsigned char *suffix);
432 
433 inline static grn_rc
434 normalize_utf8(grn_ctx *ctx, grn_str *nstr)
435 {
436  int16_t *ch;
437  const unsigned char *s, *s_, *s__ = NULL, *p, *p2, *pe, *e;
438  unsigned char *d, *d_, *de;
439  uint_least8_t *cp;
440  size_t length = 0, ls, lp, size = nstr->orig_blen, ds = size * 3;
441  int removeblankp = nstr->flags & GRN_STR_REMOVEBLANK;
442  if (!(nstr->norm = GRN_MALLOC(ds + 1))) {
444  }
445  if (nstr->flags & GRN_STR_WITH_CHECKS) {
446  if (!(nstr->checks = GRN_MALLOC(ds * sizeof(int16_t) + 1))) {
447  GRN_FREE(nstr->norm); nstr->norm = NULL;
449  }
450  }
451  ch = nstr->checks;
452  if (nstr->flags & GRN_STR_WITH_CTYPES) {
453  if (!(nstr->ctypes = GRN_MALLOC(ds + 1))) {
454  if (nstr->checks) { GRN_FREE(nstr->checks); nstr->checks = NULL; }
455  GRN_FREE(nstr->norm); nstr->norm = NULL;
457  }
458  }
459  cp = nstr->ctypes;
460  d = (unsigned char *)nstr->norm;
461  de = d + ds;
462  d_ = NULL;
463  e = (unsigned char *)nstr->orig + size;
464  for (s = s_ = (unsigned char *)nstr->orig; ; s += ls) {
465  if (!(ls = grn_str_charlen_utf8(ctx, s, e))) {
466  break;
467  }
468  if ((p = (unsigned char *)grn_nfkc_map1(s))) {
469  pe = p + strlen((char *)p);
470  } else {
471  p = s;
472  pe = p + ls;
473  }
474  if (d_ && (p2 = (unsigned char *)grn_nfkc_map2(d_, p))) {
475  p = p2;
476  pe = p + strlen((char *)p);
477  if (cp) { cp--; }
478  if (ch) {
479  ch -= (d - d_);
480  s_ = s__;
481  }
482  d = d_;
483  length--;
484  }
485  for (; ; p += lp) {
486  if (!(lp = grn_str_charlen_utf8(ctx, p, pe))) {
487  break;
488  }
489  if ((*p == ' ' && removeblankp) || *p < 0x20 /* skip unprintable ascii */ ) {
490  if (cp > nstr->ctypes) { *(cp - 1) |= GRN_STR_BLANK; }
491  } else {
492  if (de <= d + lp) {
493  unsigned char *norm;
494  ds += (ds >> 1) + lp;
495  if (!(norm = GRN_REALLOC(nstr->norm, ds + 1))) {
496  if (nstr->ctypes) { GRN_FREE(nstr->ctypes); nstr->ctypes = NULL; }
497  if (nstr->checks) { GRN_FREE(nstr->checks); nstr->checks = NULL; }
498  GRN_FREE(nstr->norm); nstr->norm = NULL;
500  }
501  de = norm + ds;
502  d = norm + (d - (unsigned char *)nstr->norm);
503  nstr->norm = (char *)norm;
504  if (ch) {
505  int16_t *checks;
506  if (!(checks = GRN_REALLOC(nstr->checks, ds * sizeof(int16_t)+ 1))) {
507  if (nstr->ctypes) { GRN_FREE(nstr->ctypes); nstr->ctypes = NULL; }
508  GRN_FREE(nstr->checks); nstr->checks = NULL;
509  GRN_FREE(nstr->norm); nstr->norm = NULL;
511  }
512  ch = checks + (ch - nstr->checks);
513  nstr->checks = checks;
514  }
515  if (cp) {
516  uint_least8_t *ctypes;
517  if (!(ctypes = GRN_REALLOC(nstr->ctypes, ds + 1))) {
518  GRN_FREE(nstr->ctypes); nstr->ctypes = NULL;
519  if (nstr->checks) { GRN_FREE(nstr->checks); nstr->checks = NULL; }
520  GRN_FREE(nstr->norm); nstr->norm = NULL;
522  }
523  cp = ctypes + (cp - nstr->ctypes);
524  nstr->ctypes = ctypes;
525  }
526  }
527  memcpy(d, p, lp);
528  d_ = d;
529  d += lp;
530  length++;
531  if (cp) { *cp++ = grn_nfkc_char_type(p); }
532  if (ch) {
533  size_t i;
534  if (s_ == s + ls) {
535  *ch++ = -1;
536  } else {
537  *ch++ = (int16_t)(s + ls - s_);
538  s__ = s_;
539  s_ = s + ls;
540  }
541  for (i = lp; i > 1; i--) { *ch++ = 0; }
542  }
543  }
544  }
545  }
546  if (cp) { *cp = GRN_CHAR_NULL; }
547  *d = '\0';
548  nstr->length = length;
549  nstr->norm_blen = (size_t)(d - (unsigned char *)nstr->norm);
550  return GRN_SUCCESS;
551 }
552 #endif /* GRN_WITH_NFKC */
553 
554 inline static grn_rc
555 normalize_sjis(grn_ctx *ctx, grn_str *nstr)
556 {
557  static uint16_t hankana[] = {
558  0x8140, 0x8142, 0x8175, 0x8176, 0x8141, 0x8145, 0x8392, 0x8340, 0x8342,
559  0x8344, 0x8346, 0x8348, 0x8383, 0x8385, 0x8387, 0x8362, 0x815b, 0x8341,
560  0x8343, 0x8345, 0x8347, 0x8349, 0x834a, 0x834c, 0x834e, 0x8350, 0x8352,
561  0x8354, 0x8356, 0x8358, 0x835a, 0x835c, 0x835e, 0x8360, 0x8363, 0x8365,
562  0x8367, 0x8369, 0x836a, 0x836b, 0x836c, 0x836d, 0x836e, 0x8371, 0x8374,
563  0x8377, 0x837a, 0x837d, 0x837e, 0x8380, 0x8381, 0x8382, 0x8384, 0x8386,
564  0x8388, 0x8389, 0x838a, 0x838b, 0x838c, 0x838d, 0x838f, 0x8393, 0x814a,
565  0x814b
566  };
567  static unsigned char dakuten[] = {
568  0x94, 0, 0, 0, 0, 0x4b, 0, 0x4d, 0, 0x4f, 0, 0x51, 0, 0x53, 0, 0x55, 0,
569  0x57, 0, 0x59, 0, 0x5b, 0, 0x5d, 0, 0x5f, 0, 0x61, 0, 0, 0x64, 0, 0x66,
570  0, 0x68, 0, 0, 0, 0, 0, 0, 0x6f, 0, 0, 0x72, 0, 0, 0x75, 0, 0, 0x78, 0,
571  0, 0x7b
572  };
573  static unsigned char handaku[] = {
574  0x70, 0, 0, 0x73, 0, 0, 0x76, 0, 0, 0x79, 0, 0, 0x7c
575  };
576  int16_t *ch;
577  const unsigned char *s, *s_;
578  unsigned char *d, *d0, *d_, b, *e;
579  uint_least8_t *cp, *ctypes, ctype;
580  size_t size = nstr->orig_blen, length = 0;
581  int removeblankp = nstr->flags & GRN_STR_REMOVEBLANK;
582  if (!(nstr->norm = GRN_MALLOC(size * 2 + 1))) {
584  }
585  d0 = (unsigned char *) nstr->norm;
586  if (nstr->flags & GRN_STR_WITH_CHECKS) {
587  if (!(nstr->checks = GRN_MALLOC(size * 2 * sizeof(int16_t) + 1))) {
588  GRN_FREE(nstr->norm);
589  nstr->norm = NULL;
591  }
592  }
593  ch = nstr->checks;
594  if (nstr->flags & GRN_STR_WITH_CTYPES) {
595  if (!(nstr->ctypes = GRN_MALLOC(size + 1))) {
596  GRN_FREE(nstr->checks);
597  GRN_FREE(nstr->norm);
598  nstr->checks = NULL;
599  nstr->norm = NULL;
601  }
602  }
603  cp = ctypes = nstr->ctypes;
604  e = (unsigned char *)nstr->orig + size;
605  for (s = s_ = (unsigned char *) nstr->orig, d = d_ = d0; s < e; s++) {
606  if ((*s & 0x80)) {
607  if (0xa0 <= *s && *s <= 0xdf) {
608  uint16_t c = hankana[*s - 0xa0];
609  switch (c) {
610  case 0x814a :
611  if (d > d0 + 1 && d[-2] == 0x83
612  && 0x45 <= d[-1] && d[-1] <= 0x7a && (b = dakuten[d[-1] - 0x45])) {
613  *(d - 1) = b;
614  if (ch) { ch[-1]++; s_++; }
615  continue;
616  } else {
617  *d++ = c >> 8; *d = c & 0xff;
618  }
619  break;
620  case 0x814b :
621  if (d > d0 + 1 && d[-2] == 0x83
622  && 0x6e <= d[-1] && d[-1] <= 0x7a && (b = handaku[d[-1] - 0x6e])) {
623  *(d - 1) = b;
624  if (ch) { ch[-1]++; s_++; }
625  continue;
626  } else {
627  *d++ = c >> 8; *d = c & 0xff;
628  }
629  break;
630  default :
631  *d++ = c >> 8; *d = c & 0xff;
632  break;
633  }
634  ctype = GRN_CHAR_KATAKANA;
635  } else {
636  if ((s + 1) < e && 0x40 <= *(s + 1) && *(s + 1) <= 0xfc) {
637  unsigned char c1 = *s++, c2 = *s, c3 = 0;
638  if (0x81 <= c1 && c1 <= 0x87) {
639  switch (c1 & 0x0f) {
640  case 1 :
641  switch (c2) {
642  case 0x5b :
643  *d++ = c1; *d = c2;
644  ctype = GRN_CHAR_KATAKANA;
645  break;
646  case 0x58 :
647  *d++ = c1; *d = c2;
648  ctype = GRN_CHAR_KANJI;
649  break;
650  case 0x40 :
651  if (removeblankp) {
652  if (cp > ctypes) { *(cp - 1) |= GRN_STR_BLANK; }
653  continue;
654  } else {
655  *d = ' ';
657  }
658  break;
659  default :
660  if (0x43 <= c2 && c2 <= 0x7e && (c3 = symbol[c2 - 0x43])) {
661  *d = c3;
662  ctype = GRN_CHAR_SYMBOL;
663  } else if (0x7f <= c2 && c2 <= 0x97 && (c3 = symbol[c2 - 0x44])) {
664  *d = c3;
665  ctype = GRN_CHAR_SYMBOL;
666  } else {
667  *d++ = c1; *d = c2;
668  ctype = GRN_CHAR_OTHERS;
669  }
670  break;
671  }
672  break;
673  case 2 :
674  c3 = c2 - 0x1f;
675  if (0x4f <= c2 && c2 <= 0x58) {
676  ctype = GRN_CHAR_DIGIT;
677  *d = c2 - 0x1f;
678  } else if (0x60 <= c2 && c2 <= 0x79) {
679  ctype = GRN_CHAR_ALPHA;
680  *d = c2 + 0x01;
681  } else if (0x81 <= c2 && c2 <= 0x9a) {
682  ctype = GRN_CHAR_ALPHA;
683  *d = c2 - 0x20;
684  } else if (0x9f <= c2 && c2 <= 0xf1) {
685  *d++ = c1; *d = c2;
686  ctype = GRN_CHAR_HIRAGANA;
687  } else {
688  *d++ = c1; *d = c2;
689  ctype = GRN_CHAR_OTHERS;
690  }
691  break;
692  case 3 :
693  if (0x40 <= c2 && c2 <= 0x96) {
694  *d++ = c1; *d = c2;
695  ctype = GRN_CHAR_KATAKANA;
696  } else {
697  *d++ = c1; *d = c2;
698  ctype = GRN_CHAR_SYMBOL;
699  }
700  break;
701  case 4 :
702  case 7 :
703  *d++ = c1; *d = c2;
704  ctype = GRN_CHAR_SYMBOL;
705  break;
706  default :
707  *d++ = c1; *d = c2;
708  ctype = GRN_CHAR_OTHERS;
709  break;
710  }
711  } else {
712  *d++ = c1; *d = c2;
713  ctype = GRN_CHAR_KANJI;
714  }
715  } else {
716  /* skip invalid character */
717  continue;
718  }
719  }
720  } else {
721  unsigned char c = *s;
722  switch (c >> 4) {
723  case 0 :
724  case 1 :
725  /* skip unprintable ascii */
726  if (cp > ctypes) { *(cp - 1) |= GRN_STR_BLANK; }
727  continue;
728  case 2 :
729  if (c == 0x20) {
730  if (removeblankp) {
731  if (cp > ctypes) { *(cp - 1) |= GRN_STR_BLANK; }
732  continue;
733  } else {
734  *d = ' ';
736  }
737  } else {
738  *d = c;
739  ctype = GRN_CHAR_SYMBOL;
740  }
741  break;
742  case 3 :
743  *d = c;
744  ctype = (c <= 0x39) ? GRN_CHAR_DIGIT : GRN_CHAR_SYMBOL;
745  break;
746  case 4 :
747  *d = ('A' <= c) ? c + 0x20 : c;
748  ctype = (c == 0x40) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
749  break;
750  case 5 :
751  *d = (c <= 'Z') ? c + 0x20 : c;
752  ctype = (c <= 0x5a) ? GRN_CHAR_ALPHA : GRN_CHAR_SYMBOL;
753  break;
754  case 6 :
755  *d = c;
756  ctype = (c == 0x60) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
757  break;
758  case 7 :
759  *d = c;
760  ctype = (c <= 0x7a) ? GRN_CHAR_ALPHA : (c == 0x7f ? GRN_CHAR_OTHERS : GRN_CHAR_SYMBOL);
761  break;
762  default :
763  *d = c;
764  ctype = GRN_CHAR_OTHERS;
765  break;
766  }
767  }
768  d++;
769  length++;
770  if (cp) { *cp++ = ctype; }
771  if (ch) {
772  *ch++ = (int16_t)(s + 1 - s_);
773  s_ = s + 1;
774  while (++d_ < d) { *ch++ = 0; }
775  }
776  }
777  if (cp) { *cp = GRN_CHAR_NULL; }
778  *d = '\0';
779  nstr->length = length;
780  nstr->norm_blen = (size_t)(d - (unsigned char *)nstr->norm);
781  return GRN_SUCCESS;
782 }
783 
784 inline static grn_rc
785 normalize_none(grn_ctx *ctx, grn_str *nstr)
786 {
787  int16_t *ch;
788  const unsigned char *s, *s_, *e;
789  unsigned char *d, *d0, *d_;
790  uint_least8_t *cp, *ctypes, ctype;
791  size_t size = nstr->orig_blen, length = 0;
792  int removeblankp = nstr->flags & GRN_STR_REMOVEBLANK;
793  if (!(nstr->norm = GRN_MALLOC(size + 1))) {
795  }
796  d0 = (unsigned char *) nstr->norm;
797  if (nstr->flags & GRN_STR_WITH_CHECKS) {
798  if (!(nstr->checks = GRN_MALLOC(size * sizeof(int16_t) + 1))) {
799  GRN_FREE(nstr->norm);
800  nstr->norm = NULL;
802  }
803  }
804  ch = nstr->checks;
805  if (nstr->flags & GRN_STR_WITH_CTYPES) {
806  if (!(nstr->ctypes = GRN_MALLOC(size + 1))) {
807  GRN_FREE(nstr->checks);
808  GRN_FREE(nstr->norm);
809  nstr->checks = NULL;
810  nstr->norm = NULL;
812  }
813  }
814  cp = ctypes = nstr->ctypes;
815  e = (unsigned char *)nstr->orig + size;
816  for (s = s_ = (unsigned char *) nstr->orig, d = d_ = d0; s < e; s++) {
817  unsigned char c = *s;
818  switch (c >> 4) {
819  case 0 :
820  case 1 :
821  /* skip unprintable ascii */
822  if (cp > ctypes) { *(cp - 1) |= GRN_STR_BLANK; }
823  continue;
824  case 2 :
825  if (c == 0x20) {
826  if (removeblankp) {
827  if (cp > ctypes) { *(cp - 1) |= GRN_STR_BLANK; }
828  continue;
829  } else {
830  *d = ' ';
832  }
833  } else {
834  *d = c;
835  ctype = GRN_CHAR_SYMBOL;
836  }
837  break;
838  case 3 :
839  *d = c;
840  ctype = (c <= 0x39) ? GRN_CHAR_DIGIT : GRN_CHAR_SYMBOL;
841  break;
842  case 4 :
843  *d = ('A' <= c) ? c + 0x20 : c;
844  ctype = (c == 0x40) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
845  break;
846  case 5 :
847  *d = (c <= 'Z') ? c + 0x20 : c;
848  ctype = (c <= 0x5a) ? GRN_CHAR_ALPHA : GRN_CHAR_SYMBOL;
849  break;
850  case 6 :
851  *d = c;
852  ctype = (c == 0x60) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
853  break;
854  case 7 :
855  *d = c;
856  ctype = (c <= 0x7a) ? GRN_CHAR_ALPHA : (c == 0x7f ? GRN_CHAR_OTHERS : GRN_CHAR_SYMBOL);
857  break;
858  default :
859  *d = c;
860  ctype = GRN_CHAR_OTHERS;
861  break;
862  }
863  d++;
864  length++;
865  if (cp) { *cp++ = ctype; }
866  if (ch) {
867  *ch++ = (int16_t)(s + 1 - s_);
868  s_ = s + 1;
869  while (++d_ < d) { *ch++ = 0; }
870  }
871  }
872  if (cp) { *cp = GRN_CHAR_NULL; }
873  *d = '\0';
874  nstr->length = length;
875  nstr->norm_blen = (size_t)(d - (unsigned char *)nstr->norm);
876  return GRN_SUCCESS;
877 }
878 
879 /* use cp1252 as latin1 */
880 inline static grn_rc
881 normalize_latin1(grn_ctx *ctx, grn_str *nstr)
882 {
883  int16_t *ch;
884  const unsigned char *s, *s_, *e;
885  unsigned char *d, *d0, *d_;
886  uint_least8_t *cp, *ctypes, ctype;
887  size_t size = nstr->orig_blen, length = 0;
888  int removeblankp = nstr->flags & GRN_STR_REMOVEBLANK;
889  if (!(nstr->norm = GRN_MALLOC(size + 1))) {
891  }
892  d0 = (unsigned char *) nstr->norm;
893  if (nstr->flags & GRN_STR_WITH_CHECKS) {
894  if (!(nstr->checks = GRN_MALLOC(size * sizeof(int16_t) + 1))) {
895  GRN_FREE(nstr->norm);
896  nstr->norm = NULL;
898  }
899  }
900  ch = nstr->checks;
901  if (nstr->flags & GRN_STR_WITH_CTYPES) {
902  if (!(nstr->ctypes = GRN_MALLOC(size + 1))) {
903  GRN_FREE(nstr->checks);
904  GRN_FREE(nstr->norm);
905  nstr->checks = NULL;
906  nstr->norm = NULL;
908  }
909  }
910  cp = ctypes = nstr->ctypes;
911  e = (unsigned char *)nstr->orig + size;
912  for (s = s_ = (unsigned char *) nstr->orig, d = d_ = d0; s < e; s++) {
913  unsigned char c = *s;
914  switch (c >> 4) {
915  case 0 :
916  case 1 :
917  /* skip unprintable ascii */
918  if (cp > ctypes) { *(cp - 1) |= GRN_STR_BLANK; }
919  continue;
920  case 2 :
921  if (c == 0x20) {
922  if (removeblankp) {
923  if (cp > ctypes) { *(cp - 1) |= GRN_STR_BLANK; }
924  continue;
925  } else {
926  *d = ' ';
928  }
929  } else {
930  *d = c;
931  ctype = GRN_CHAR_SYMBOL;
932  }
933  break;
934  case 3 :
935  *d = c;
936  ctype = (c <= 0x39) ? GRN_CHAR_DIGIT : GRN_CHAR_SYMBOL;
937  break;
938  case 4 :
939  *d = ('A' <= c) ? c + 0x20 : c;
940  ctype = (c == 0x40) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
941  break;
942  case 5 :
943  *d = (c <= 'Z') ? c + 0x20 : c;
944  ctype = (c <= 0x5a) ? GRN_CHAR_ALPHA : GRN_CHAR_SYMBOL;
945  break;
946  case 6 :
947  *d = c;
948  ctype = (c == 0x60) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
949  break;
950  case 7 :
951  *d = c;
952  ctype = (c <= 0x7a) ? GRN_CHAR_ALPHA : (c == 0x7f ? GRN_CHAR_OTHERS : GRN_CHAR_SYMBOL);
953  break;
954  case 8 :
955  if (c == 0x8a || c == 0x8c || c == 0x8e) {
956  *d = c + 0x10;
957  ctype = GRN_CHAR_ALPHA;
958  } else {
959  *d = c;
960  ctype = GRN_CHAR_SYMBOL;
961  }
962  break;
963  case 9 :
964  if (c == 0x9a || c == 0x9c || c == 0x9e || c == 0x9f) {
965  *d = (c == 0x9f) ? c + 0x60 : c;
966  ctype = GRN_CHAR_ALPHA;
967  } else {
968  *d = c;
969  ctype = GRN_CHAR_SYMBOL;
970  }
971  break;
972  case 0x0c :
973  *d = c + 0x20;
974  ctype = GRN_CHAR_ALPHA;
975  break;
976  case 0x0d :
977  *d = (c == 0xd7 || c == 0xdf) ? c : c + 0x20;
978  ctype = (c == 0xd7) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
979  break;
980  case 0x0e :
981  *d = c;
982  ctype = GRN_CHAR_ALPHA;
983  break;
984  case 0x0f :
985  *d = c;
986  ctype = (c == 0xf7) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
987  break;
988  default :
989  *d = c;
990  ctype = GRN_CHAR_OTHERS;
991  break;
992  }
993  d++;
994  length++;
995  if (cp) { *cp++ = ctype; }
996  if (ch) {
997  *ch++ = (int16_t)(s + 1 - s_);
998  s_ = s + 1;
999  while (++d_ < d) { *ch++ = 0; }
1000  }
1001  }
1002  if (cp) { *cp = GRN_CHAR_NULL; }
1003  *d = '\0';
1004  nstr->length = length;
1005  nstr->norm_blen = (size_t)(d - (unsigned char *)nstr->norm);
1006  return GRN_SUCCESS;
1007 }
1008 
1009 inline static grn_rc
1010 normalize_koi8r(grn_ctx *ctx, grn_str *nstr)
1011 {
1012  int16_t *ch;
1013  const unsigned char *s, *s_, *e;
1014  unsigned char *d, *d0, *d_;
1015  uint_least8_t *cp, *ctypes, ctype;
1016  size_t size = strlen(nstr->orig), length = 0;
1017  int removeblankp = nstr->flags & GRN_STR_REMOVEBLANK;
1018  if (!(nstr->norm = GRN_MALLOC(size + 1))) {
1019  return GRN_NO_MEMORY_AVAILABLE;
1020  }
1021  d0 = (unsigned char *) nstr->norm;
1022  if (nstr->flags & GRN_STR_WITH_CHECKS) {
1023  if (!(nstr->checks = GRN_MALLOC(size * sizeof(int16_t) + 1))) {
1024  GRN_FREE(nstr->norm);
1025  nstr->norm = NULL;
1026  return GRN_NO_MEMORY_AVAILABLE;
1027  }
1028  }
1029  ch = nstr->checks;
1030  if (nstr->flags & GRN_STR_WITH_CTYPES) {
1031  if (!(nstr->ctypes = GRN_MALLOC(size + 1))) {
1032  GRN_FREE(nstr->checks);
1033  GRN_FREE(nstr->norm);
1034  nstr->checks = NULL;
1035  nstr->norm = NULL;
1036  return GRN_NO_MEMORY_AVAILABLE;
1037  }
1038  }
1039  cp = ctypes = nstr->ctypes;
1040  e = (unsigned char *)nstr->orig + size;
1041  for (s = s_ = (unsigned char *) nstr->orig, d = d_ = d0; s < e; s++) {
1042  unsigned char c = *s;
1043  switch (c >> 4) {
1044  case 0 :
1045  case 1 :
1046  /* skip unprintable ascii */
1047  if (cp > ctypes) { *(cp - 1) |= GRN_STR_BLANK; }
1048  continue;
1049  case 2 :
1050  if (c == 0x20) {
1051  if (removeblankp) {
1052  if (cp > ctypes) { *(cp - 1) |= GRN_STR_BLANK; }
1053  continue;
1054  } else {
1055  *d = ' ';
1057  }
1058  } else {
1059  *d = c;
1060  ctype = GRN_CHAR_SYMBOL;
1061  }
1062  break;
1063  case 3 :
1064  *d = c;
1065  ctype = (c <= 0x39) ? GRN_CHAR_DIGIT : GRN_CHAR_SYMBOL;
1066  break;
1067  case 4 :
1068  *d = ('A' <= c) ? c + 0x20 : c;
1069  ctype = (c == 0x40) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
1070  break;
1071  case 5 :
1072  *d = (c <= 'Z') ? c + 0x20 : c;
1073  ctype = (c <= 0x5a) ? GRN_CHAR_ALPHA : GRN_CHAR_SYMBOL;
1074  break;
1075  case 6 :
1076  *d = c;
1077  ctype = (c == 0x60) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
1078  break;
1079  case 7 :
1080  *d = c;
1081  ctype = (c <= 0x7a) ? GRN_CHAR_ALPHA : (c == 0x7f ? GRN_CHAR_OTHERS : GRN_CHAR_SYMBOL);
1082  break;
1083  case 0x0a :
1084  *d = c;
1085  ctype = (c == 0xa3) ? GRN_CHAR_ALPHA : GRN_CHAR_OTHERS;
1086  break;
1087  case 0x0b :
1088  if (c == 0xb3) {
1089  *d = c - 0x10;
1090  ctype = GRN_CHAR_ALPHA;
1091  } else {
1092  *d = c;
1093  ctype = GRN_CHAR_OTHERS;
1094  }
1095  break;
1096  case 0x0c :
1097  case 0x0d :
1098  *d = c;
1099  ctype = GRN_CHAR_ALPHA;
1100  break;
1101  case 0x0e :
1102  case 0x0f :
1103  *d = c - 0x20;
1104  ctype = GRN_CHAR_ALPHA;
1105  break;
1106  default :
1107  *d = c;
1108  ctype = GRN_CHAR_OTHERS;
1109  break;
1110  }
1111  d++;
1112  length++;
1113  if (cp) { *cp++ = ctype; }
1114  if (ch) {
1115  *ch++ = (int16_t)(s + 1 - s_);
1116  s_ = s + 1;
1117  while (++d_ < d) { *ch++ = 0; }
1118  }
1119  }
1120  if (cp) { *cp = GRN_CHAR_NULL; }
1121  *d = '\0';
1122  nstr->length = length;
1123  nstr->norm_blen = (size_t)(d - (unsigned char *)nstr->norm);
1124  return GRN_SUCCESS;
1125 }
1126 
1127 static grn_str *
1128 grn_fakenstr_open(grn_ctx *ctx, const char *str, size_t str_len, grn_encoding encoding, int flags)
1129 {
1130  /* TODO: support GRN_STR_REMOVEBLANK flag and ctypes */
1131  grn_str *nstr;
1132  if (!(nstr = GRN_MALLOC(sizeof(grn_str)))) {
1133  GRN_LOG(ctx, GRN_LOG_ALERT, "memory allocation on grn_fakenstr_open failed !");
1134  return NULL;
1135  }
1136  if (!(nstr->norm = GRN_MALLOC(str_len + 1))) {
1137  GRN_LOG(ctx, GRN_LOG_ALERT, "memory allocation for keyword on grn_snip_add_cond failed !");
1138  GRN_FREE(nstr);
1139  return NULL;
1140  }
1141  nstr->orig = str;
1142  nstr->orig_blen = str_len;
1143  memcpy(nstr->norm, str, str_len);
1144  nstr->norm[str_len] = '\0';
1145  nstr->norm_blen = str_len;
1146  nstr->ctypes = NULL;
1147  nstr->flags = flags;
1148 
1149  if (flags & GRN_STR_WITH_CHECKS) {
1150  int16_t f = 0;
1151  unsigned char c;
1152  size_t i;
1153  if (!(nstr->checks = (int16_t *) GRN_MALLOC(sizeof(int16_t) * str_len))) {
1154  GRN_FREE(nstr->norm);
1155  GRN_FREE(nstr);
1156  return NULL;
1157  }
1158  switch (encoding) {
1159  case GRN_ENC_EUC_JP:
1160  for (i = 0; i < str_len; i++) {
1161  if (!f) {
1162  c = (unsigned char) str[i];
1163  f = ((c >= 0xa1U && c <= 0xfeU) || c == 0x8eU ? 2 : (c == 0x8fU ? 3 : 1)
1164  );
1165  nstr->checks[i] = f;
1166  } else {
1167  nstr->checks[i] = 0;
1168  }
1169  f--;
1170  }
1171  break;
1172  case GRN_ENC_SJIS:
1173  for (i = 0; i < str_len; i++) {
1174  if (!f) {
1175  c = (unsigned char) str[i];
1176  f = (c >= 0x81U && ((c <= 0x9fU) || (c >= 0xe0U && c <= 0xfcU)) ? 2 : 1);
1177  nstr->checks[i] = f;
1178  } else {
1179  nstr->checks[i] = 0;
1180  }
1181  f--;
1182  }
1183  break;
1184  case GRN_ENC_UTF8:
1185  for (i = 0; i < str_len; i++) {
1186  if (!f) {
1187  c = (unsigned char) str[i];
1188  f = (c & 0x80U ? (c & 0x20U ? (c & 0x10U ? 4 : 3)
1189  : 2)
1190  : 1);
1191  nstr->checks[i] = f;
1192  } else {
1193  nstr->checks[i] = 0;
1194  }
1195  f--;
1196  }
1197  break;
1198  default:
1199  for (i = 0; i < str_len; i++) {
1200  nstr->checks[i] = 1;
1201  }
1202  break;
1203  }
1204  } else {
1205  nstr->checks = NULL;
1206  }
1207  return nstr;
1208 }
1209 
1210 grn_str *
1211 grn_str_open_(grn_ctx *ctx, const char *str, unsigned int str_len, int flags, grn_encoding encoding)
1212 {
1213  grn_rc rc;
1214  grn_str *nstr;
1215  if (!str || !str_len) { return NULL; }
1216 
1217  if (!(flags & GRN_STR_NORMALIZE)) {
1218  return grn_fakenstr_open(ctx, str, str_len, encoding, flags);
1219  }
1220 
1221  if (!(nstr = GRN_MALLOC(sizeof(grn_str)))) {
1222  GRN_LOG(ctx, GRN_LOG_ALERT, "memory allocation on grn_str_open failed !");
1223  return NULL;
1224  }
1225  nstr->orig = str;
1226  nstr->orig_blen = str_len;
1227  nstr->norm = NULL;
1228  nstr->norm_blen = 0;
1229  nstr->checks = NULL;
1230  nstr->ctypes = NULL;
1231  nstr->encoding = encoding;
1232  nstr->flags = flags;
1233  switch (encoding) {
1234  case GRN_ENC_EUC_JP :
1235  rc = normalize_euc(ctx, nstr);
1236  break;
1237  case GRN_ENC_UTF8 :
1238 #ifdef GRN_WITH_NFKC
1239  rc = normalize_utf8(ctx, nstr);
1240 #else /* GRN_WITH_NFKC */
1241  rc = normalize_none(ctx, nstr);
1242 #endif /* GRN_WITH_NFKC */
1243  break;
1244  case GRN_ENC_SJIS :
1245  rc = normalize_sjis(ctx, nstr);
1246  break;
1247  case GRN_ENC_LATIN1 :
1248  rc = normalize_latin1(ctx, nstr);
1249  break;
1250  case GRN_ENC_KOI8R :
1251  rc = normalize_koi8r(ctx, nstr);
1252  break;
1253  default :
1254  rc = normalize_none(ctx, nstr);
1255  break;
1256  }
1257  if (rc) {
1258  grn_str_close(ctx, nstr);
1259  return NULL;
1260  }
1261  return nstr;
1262 }
1263 
1264 grn_str *
1265 grn_str_open(grn_ctx *ctx, const char *str, unsigned int str_len, int flags)
1266 {
1267  return grn_str_open_(ctx, str, str_len, flags, ctx->encoding);
1268 }
1269 
1270 grn_rc
1272 {
1273  if (nstr) {
1274  if (nstr->norm) { GRN_FREE(nstr->norm); }
1275  if (nstr->ctypes) { GRN_FREE(nstr->ctypes); }
1276  if (nstr->checks) { GRN_FREE(nstr->checks); }
1277  GRN_FREE(nstr);
1278  return GRN_SUCCESS;
1279  } else {
1280  return GRN_INVALID_ARGUMENT;
1281  }
1282 }
1283 
1284 static const char *grn_enc_string[] = {
1285  "default",
1286  "none",
1287  "euc_jp",
1288  "utf8",
1289  "sjis",
1290  "latin1",
1291  "koi8r"
1292 };
1293 
1294 const char *
1296 {
1297  if (enc < (sizeof(grn_enc_string) / sizeof(char *))) {
1298  return grn_enc_string[enc];
1299  } else {
1300  return "unknown";
1301  }
1302 }
1303 
1305 grn_encoding_parse(const char *str)
1306 {
1308  int i = sizeof(grn_enc_string) / sizeof(grn_enc_string[0]);
1309  while (i--) {
1310  if (!strcmp(str, grn_enc_string[i])) {
1311  e = (grn_encoding)i;
1312  }
1313  }
1314  return e;
1315 }
1316 
1317 size_t
1318 grn_str_len(grn_ctx *ctx, const char *str, grn_encoding encoding, const char **last)
1319 {
1320  size_t len, tlen;
1321  const char *p = NULL;
1322  for (len = 0; ; len++) {
1323  p = str;
1324  if (!(tlen = grn_str_charlen(ctx, str, encoding))) {
1325  break;
1326  }
1327  str += tlen;
1328  }
1329  if (last) { *last = p; }
1330  return len;
1331 }
1332 
1333 int
1334 grn_isspace(const char *str, grn_encoding encoding)
1335 {
1336  const unsigned char *s = (const unsigned char *) str;
1337  if (!s) { return 0; }
1338  switch (s[0]) {
1339  case ' ' :
1340  case '\f' :
1341  case '\n' :
1342  case '\r' :
1343  case '\t' :
1344  case '\v' :
1345  return 1;
1346  case 0x81 :
1347  if (encoding == GRN_ENC_SJIS && s[1] == 0x40) { return 2; }
1348  break;
1349  case 0xA1 :
1350  if (encoding == GRN_ENC_EUC_JP && s[1] == 0xA1) { return 2; }
1351  break;
1352  case 0xE3 :
1353  if (encoding == GRN_ENC_UTF8 && s[1] == 0x80 && s[2] == 0x80) { return 3; }
1354  break;
1355  default :
1356  break;
1357  }
1358  return 0;
1359 }
1360 
1361 int8_t
1362 grn_atoi8(const char *nptr, const char *end, const char **rest)
1363 {
1364  const char *p = nptr;
1365  int8_t v = 0, t, n = 0, o = 0;
1366  if (p < end && *p == '-') {
1367  p++;
1368  n = 1;
1369  o = 1;
1370  }
1371  while (p < end && *p >= '0' && *p <= '9') {
1372  t = v * 10 - (*p - '0');
1373  if (t > v || (!n && t == INT8_MIN)) { v = 0; break; }
1374  v = t;
1375  o = 0;
1376  p++;
1377  }
1378  if (rest) { *rest = o ? nptr : p; }
1379  return n ? v : -v;
1380 }
1381 
1382 uint8_t
1383 grn_atoui8(const char *nptr, const char *end, const char **rest)
1384 {
1385  uint8_t v = 0, t;
1386  while (nptr < end && *nptr >= '0' && *nptr <= '9') {
1387  t = v * 10 + (*nptr - '0');
1388  if (t < v) { v = 0; break; }
1389  v = t;
1390  nptr++;
1391  }
1392  if (rest) { *rest = nptr; }
1393  return v;
1394 }
1395 
1396 int16_t
1397 grn_atoi16(const char *nptr, const char *end, const char **rest)
1398 {
1399  const char *p = nptr;
1400  int16_t v = 0, t, n = 0, o = 0;
1401  if (p < end && *p == '-') {
1402  p++;
1403  n = 1;
1404  o = 1;
1405  }
1406  while (p < end && *p >= '0' && *p <= '9') {
1407  t = v * 10 - (*p - '0');
1408  if (t > v || (!n && t == INT16_MIN)) { v = 0; break; }
1409  v = t;
1410  o = 0;
1411  p++;
1412  }
1413  if (rest) { *rest = o ? nptr : p; }
1414  return n ? v : -v;
1415 }
1416 
1417 uint16_t
1418 grn_atoui16(const char *nptr, const char *end, const char **rest)
1419 {
1420  uint16_t v = 0, t;
1421  while (nptr < end && *nptr >= '0' && *nptr <= '9') {
1422  t = v * 10 + (*nptr - '0');
1423  if (t < v) { v = 0; break; }
1424  v = t;
1425  nptr++;
1426  }
1427  if (rest) { *rest = nptr; }
1428  return v;
1429 }
1430 
1431 int
1432 grn_atoi(const char *nptr, const char *end, const char **rest)
1433 {
1434  const char *p = nptr;
1435  int v = 0, t, n = 0, o = 0;
1436  if (p < end && *p == '-') {
1437  p++;
1438  n = 1;
1439  o = 1;
1440  }
1441  while (p < end && *p >= '0' && *p <= '9') {
1442  t = v * 10 - (*p - '0');
1443  if (t > v || (!n && t == INT32_MIN)) { v = 0; break; }
1444  v = t;
1445  o = 0;
1446  p++;
1447  }
1448  if (rest) { *rest = o ? nptr : p; }
1449  return n ? v : -v;
1450 }
1451 
1452 unsigned int
1453 grn_atoui(const char *nptr, const char *end, const char **rest)
1454 {
1455  unsigned int v = 0, t;
1456  while (nptr < end && *nptr >= '0' && *nptr <= '9') {
1457  t = v * 10 + (*nptr - '0');
1458  if (t < v) { v = 0; break; }
1459  v = t;
1460  nptr++;
1461  }
1462  if (rest) { *rest = nptr; }
1463  return v;
1464 }
1465 
1466 int64_t
1467 grn_atoll(const char *nptr, const char *end, const char **rest)
1468 {
1469  /* FIXME: INT_MIN is not supported */
1470  const char *p = nptr;
1471  int n = 0, o = 0;
1472  int64_t v = 0, t;
1473  if (p < end && *p == '-') {
1474  p++;
1475  n = 1;
1476  o = 1;
1477  }
1478  while (p < end && *p >= '0' && *p <= '9') {
1479  t = v * 10 + (*p - '0');
1480  if (t < v) { v = 0; break; }
1481  v = t;
1482  o = 0;
1483  p++;
1484  }
1485  if (rest) { *rest = o ? nptr : p; }
1486  return n ? -v : v;
1487 }
1488 
1489 unsigned int
1490 grn_htoui(const char *nptr, const char *end, const char **rest)
1491 {
1492  unsigned int v = 0, t;
1493  while (nptr < end) {
1494  switch (*nptr) {
1495  case '0' :
1496  case '1' :
1497  case '2' :
1498  case '3' :
1499  case '4' :
1500  case '5' :
1501  case '6' :
1502  case '7' :
1503  case '8' :
1504  case '9' :
1505  t = v * 16 + (*nptr++ - '0');
1506  break;
1507  case 'a' :
1508  case 'b' :
1509  case 'c' :
1510  case 'd' :
1511  case 'e' :
1512  case 'f' :
1513  t = v * 16 + (*nptr++ - 'a') + 10;
1514  break;
1515  case 'A' :
1516  case 'B' :
1517  case 'C' :
1518  case 'D' :
1519  case 'E' :
1520  case 'F' :
1521  t = v * 16 + (*nptr++ - 'A') + 10;
1522  break;
1523  default :
1524  v = 0; goto exit;
1525  }
1526  if (t < v) { v = 0; goto exit; }
1527  v = t;
1528  }
1529 exit :
1530  if (rest) { *rest = nptr; }
1531  return v;
1532 }
1533 
1534 void
1535 grn_itoh(unsigned int i, char *p, unsigned int len)
1536 {
1537  static const char *hex = "0123456789ABCDEF";
1538  p += len - 1;
1539  while (len--) {
1540  *p-- = hex[i & 0xf];
1541  i >>= 4;
1542  }
1543 }
1544 
1545 grn_rc
1546 grn_itoa(int i, char *p, char *end, char **rest)
1547 {
1548  char *q;
1549  if (p >= end) { return GRN_INVALID_ARGUMENT; }
1550  q = p;
1551  if (i < 0) {
1552  *p++ = '-';
1553  q = p;
1554  if (i == INT_MIN) {
1555  if (p >= end) { return GRN_INVALID_ARGUMENT; }
1556  *p++ = (-(i % 10)) + '0';
1557  i /= 10;
1558  }
1559  i = -i;
1560  }
1561  do {
1562  if (p >= end) { return GRN_INVALID_ARGUMENT; }
1563  *p++ = i % 10 + '0';
1564  } while ((i /= 10) > 0);
1565  if (rest) { *rest = p; }
1566  for (p--; q < p; q++, p--) {
1567  char t = *q;
1568  *q = *p;
1569  *p = t;
1570  }
1571  return GRN_SUCCESS;
1572 }
1573 
1574 grn_rc
1575 grn_itoa_padded(int i, char *p, char *end, char ch)
1576 {
1577  char *q;
1578  if (p >= end) { return GRN_INVALID_ARGUMENT; }
1579  if (i < 0) {
1580  *p++ = '-';
1581  if (i == INT_MIN) {
1582  if (p >= end) { return GRN_INVALID_ARGUMENT; }
1583  *p++ = (-(i % 10)) + '0';
1584  i /= 10;
1585  }
1586  i = -i;
1587  }
1588  q = end - 1;
1589  do {
1590  if (q < p) { return GRN_INVALID_ARGUMENT; }
1591  *q-- = i % 10 + '0';
1592  } while ((i /= 10) > 0);
1593  while (q >= p) {
1594  *q-- = ch;
1595  }
1596  return GRN_SUCCESS;
1597 }
1598 
1599 grn_rc
1600 grn_lltoa(int64_t i, char *p, char *end, char **rest)
1601 {
1602  char *q;
1603  if (p >= end) { return GRN_INVALID_ARGUMENT; }
1604  q = p;
1605  if (i < 0) {
1606  *p++ = '-';
1607  q = p;
1608  if (i == INT64_MIN) {
1609  *p++ = (-(i % 10)) + '0';
1610  i /= 10;
1611  }
1612  i = -i;
1613  }
1614  do {
1615  if (p >= end) { return GRN_INVALID_ARGUMENT; }
1616  *p++ = i % 10 + '0';
1617  } while ((i /= 10) > 0);
1618  if (rest) { *rest = p; }
1619  for (p--; q < p; q++, p--) {
1620  char t = *q;
1621  *q = *p;
1622  *p = t;
1623  }
1624  return GRN_SUCCESS;
1625 }
1626 
1627 grn_rc
1628 grn_ulltoa(uint64_t i, char *p, char *end, char **rest)
1629 {
1630  char *q;
1631  if (p >= end) { return GRN_INVALID_ARGUMENT; }
1632  q = p;
1633  do {
1634  if (p >= end) { return GRN_INVALID_ARGUMENT; }
1635  *p++ = i % 10 + '0';
1636  } while ((i /= 10) > 0);
1637  if (rest) { *rest = p; }
1638  for (p--; q < p; q++, p--) {
1639  char t = *q;
1640  *q = *p;
1641  *p = t;
1642  }
1643  return GRN_SUCCESS;
1644 }
1645 
1646 #define I2B(i) \
1647  ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(i) & 0x3f])
1648 
1649 #define B2I(b) \
1650  (((b) < '+' || 'z' < (b)) ? 0xff : "\x3e\xff\xff\xff\x3f\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\xff\xff\xff\xff\xff\xff\xff\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\xff\xff\xff\xff\xff\xff\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33"[(b) - '+'])
1651 
1652 #define MASK 0x34d34d34
1653 
1654 char *
1655 grn_itob(grn_id id, char *p)
1656 {
1657  id ^= MASK;
1658  *p++ = I2B(id >> 24);
1659  *p++ = I2B(id >> 18);
1660  *p++ = I2B(id >> 12);
1661  *p++ = I2B(id >> 6);
1662  *p++ = I2B(id);
1663  return p;
1664 }
1665 
1666 grn_id
1667 grn_btoi(char *b)
1668 {
1669  uint8_t i;
1670  grn_id id = 0;
1671  int len = 5;
1672  while (len--) {
1673  char c = *b++;
1674  if ((i = B2I(c)) == 0xff) { return 0; }
1675  id = (id << 6) + i;
1676  }
1677  return id ^ MASK;
1678 }
1679 
1680 #define I2B32H(i) ("0123456789ABCDEFGHIJKLMNOPQRSTUV"[(i) & 0x1f])
1681 
1682 char *
1683 grn_lltob32h(int64_t i, char *p)
1684 {
1685  uint64_t u = (uint64_t)i + 0x8000000000000000ULL;
1686  *p++ = I2B32H(u >> 60);
1687  *p++ = I2B32H(u >> 55);
1688  *p++ = I2B32H(u >> 50);
1689  *p++ = I2B32H(u >> 45);
1690  *p++ = I2B32H(u >> 40);
1691  *p++ = I2B32H(u >> 35);
1692  *p++ = I2B32H(u >> 30);
1693  *p++ = I2B32H(u >> 25);
1694  *p++ = I2B32H(u >> 20);
1695  *p++ = I2B32H(u >> 15);
1696  *p++ = I2B32H(u >> 10);
1697  *p++ = I2B32H(u >> 5);
1698  *p++ = I2B32H(u);
1699  return p;
1700 }
1701 
1702 char *
1703 grn_ulltob32h(uint64_t i, char *p)
1704 {
1705  char lb = (i >> 59) & 0x10;
1706  i += 0x8000000000000000ULL;
1707  *p++ = lb + I2B32H(i >> 60);
1708  *p++ = I2B32H(i >> 55);
1709  *p++ = I2B32H(i >> 50);
1710  *p++ = I2B32H(i >> 45);
1711  *p++ = I2B32H(i >> 40);
1712  *p++ = I2B32H(i >> 35);
1713  *p++ = I2B32H(i >> 30);
1714  *p++ = I2B32H(i >> 25);
1715  *p++ = I2B32H(i >> 20);
1716  *p++ = I2B32H(i >> 15);
1717  *p++ = I2B32H(i >> 10);
1718  *p++ = I2B32H(i >> 5);
1719  *p++ = I2B32H(i);
1720  return p;
1721 }
1722 
1723 grn_rc
1724 grn_aton(grn_ctx *ctx, const char *p, const char *end, const char **rest,
1725  grn_obj *res)
1726 {
1727  if (*p == '+') {
1728  p++;
1729  }
1730 
1731  switch (*p) {
1732  case '-' :
1733  case '0' : case '1' : case '2' : case '3' : case '4' :
1734  case '5' : case '6' : case '7' : case '8' : case '9' :
1735  {
1736  int64_t int64;
1737  char rest_char;
1738  int64 = grn_atoll(p, end, rest);
1739  rest_char = **rest;
1740  if (end == *rest) {
1741  if ((int64_t)INT32_MIN <= int64 && int64 <= (int64_t)INT32_MAX) {
1742  grn_obj_reinit(ctx, res, GRN_DB_INT32, 0);
1743  GRN_INT32_SET(ctx, res, int64);
1744  } else if ((int64_t)INT32_MAX < int64 && int64 <= (int64_t)UINT32_MAX) {
1745  grn_obj_reinit(ctx, res, GRN_DB_UINT32, 0);
1746  GRN_UINT32_SET(ctx, res, int64);
1747  } else {
1748  grn_obj_reinit(ctx, res, GRN_DB_INT64, 0);
1749  GRN_INT64_SET(ctx, res, int64);
1750  }
1751  } else if (rest_char == '.' || rest_char == 'e' || rest_char == 'E' ||
1752  (rest_char >= '0' && rest_char <= '9')) {
1753  char *rest_float;
1754  double d;
1755  errno = 0;
1756  d = strtod(p, &rest_float);
1757  if (!errno && rest_float == end) {
1758  grn_obj_reinit(ctx, res, GRN_DB_FLOAT, 0);
1759  GRN_FLOAT_SET(ctx, res, d);
1760  *rest = rest_float;
1761  } else {
1762  return GRN_INVALID_ARGUMENT;
1763  }
1764  }
1765  }
1766  break;
1767  default :
1768  return GRN_INVALID_ARGUMENT;
1769  break;
1770  }
1771 
1772  return GRN_SUCCESS;
1773 }
1774 
1775 int
1776 grn_str_tok(const char *str, size_t str_len, char delim, const char **tokbuf, int buf_size, const char **rest)
1777 {
1778  const char **tok = tokbuf, **tok_end = tokbuf + buf_size;
1779  if (buf_size > 0) {
1780  const char *str_end = str + str_len;
1781  for (;;str++) {
1782  if (str == str_end) {
1783  *tok++ = str;
1784  break;
1785  }
1786  if (delim == *str) {
1787  // *str = '\0';
1788  *tok++ = str;
1789  if (tok == tok_end) { break; }
1790  }
1791  }
1792  }
1793  if (rest) { *rest = str; }
1794  return tok - tokbuf;
1795 }
1796 
1797 inline static int
1798 op_getopt_flag(int *flags, const grn_str_getopt_opt *o,
1799  int argc, char * const argv[], int i, const char *optvalue)
1800 {
1801  switch (o->op) {
1802  case GETOPT_OP_NONE:
1803  break;
1804  case GETOPT_OP_ON:
1805  *flags |= o->flag;
1806  break;
1807  case GETOPT_OP_OFF:
1808  *flags &= ~o->flag;
1809  break;
1810  case GETOPT_OP_UPDATE:
1811  *flags = o->flag;
1812  break;
1813  default:
1814  return i;
1815  }
1816  if (o->arg) {
1817  if (optvalue) {
1818  *o->arg = (char *)optvalue;
1819  } else if (++i < argc) {
1820  *o->arg = argv[i];
1821  } else {
1822  return -1;
1823  }
1824  }
1825  return i;
1826 }
1827 
1828 int
1829 grn_str_getopt(int argc, char * const argv[], const grn_str_getopt_opt *opts,
1830  int *flags)
1831 {
1832  int i;
1833  for (i = 1; i < argc; i++) {
1834  const char * v = argv[i];
1835  if (*v == '-') {
1836  const grn_str_getopt_opt *o;
1837  int found;
1838  if (*++v == '-') {
1839  const char *eq;
1840  size_t len;
1841  found = 0;
1842  v++;
1843  for (eq = v; *eq != '\0' && *eq != '='; eq++) {}
1844  len = eq - v;
1845  for (o = opts; o->opt != '\0' || o->longopt != NULL; o++) {
1846  if (o->longopt && strlen(o->longopt) == len &&
1847  !memcmp(v, o->longopt, len)) {
1848  i = op_getopt_flag(flags, o, argc, argv, i,
1849  (*eq == '\0' ? NULL : eq + 1));
1850  if (i < 0) {
1851  fprintf(stderr, "%s: option '--%s' needs argument.\n", argv[0], o->longopt);
1852  return -1;
1853  }
1854  found = 1;
1855  break;
1856  }
1857  }
1858  if (!found) { goto exit; }
1859  } else {
1860  const char *p;
1861  for (p = v; *p; p++) {
1862  found = 0;
1863  for (o = opts; o->opt != '\0' || o->longopt != NULL; o++) {
1864  if (o->opt && *p == o->opt) {
1865  i = op_getopt_flag(flags, o, argc, argv, i, NULL);
1866  if (i < 0) {
1867  fprintf(stderr, "%s: option '-%c' needs argument.\n", argv[0], *p);
1868  return -1;
1869  }
1870  found = 1;
1871  break;
1872  }
1873  }
1874  if (!found) { goto exit; }
1875  }
1876  }
1877  } else {
1878  break;
1879  }
1880  }
1881  return i;
1882 exit:
1883  fprintf(stderr, "%s: cannot recognize option '%s'.\n", argv[0], argv[i]);
1884  return -1;
1885 }
1886 
1887 #define UNIT_SIZE (1 << 12)
1888 #define UNIT_MASK (UNIT_SIZE - 1)
1889 
1891 
1892 grn_rc
1893 grn_bulk_resize(grn_ctx *ctx, grn_obj *buf, unsigned int newsize)
1894 {
1895  char *head;
1896  unsigned int rounded_newsize;
1897  newsize += grn_bulk_margin_size + 1;
1898  if (GRN_BULK_OUTP(buf)) {
1899  rounded_newsize = (newsize + (UNIT_MASK)) & ~UNIT_MASK;
1900  if (rounded_newsize < newsize) { return GRN_NOT_ENOUGH_SPACE; }
1901  newsize = rounded_newsize;
1902  head = buf->u.b.head - (buf->u.b.head ? grn_bulk_margin_size : 0);
1903  if (!(head = GRN_REALLOC(head, newsize))) { return GRN_NO_MEMORY_AVAILABLE; }
1904  buf->u.b.curr = head + grn_bulk_margin_size + GRN_BULK_VSIZE(buf);
1905  buf->u.b.head = head + grn_bulk_margin_size;
1906  buf->u.b.tail = head + newsize;
1907  } else {
1908  if (newsize > GRN_BULK_BUFSIZE) {
1909  rounded_newsize = (newsize + (UNIT_MASK)) & ~UNIT_MASK;
1910  if (rounded_newsize < newsize) { return GRN_NOT_ENOUGH_SPACE; }
1911  newsize = rounded_newsize;
1912  if (!(head = GRN_MALLOC(newsize))) { return GRN_NO_MEMORY_AVAILABLE; }
1913  memcpy(head, GRN_BULK_HEAD(buf), GRN_BULK_VSIZE(buf));
1914  buf->u.b.curr = head + grn_bulk_margin_size + GRN_BULK_VSIZE(buf);
1915  buf->u.b.head = head + grn_bulk_margin_size;
1916  buf->u.b.tail = head + newsize;
1918  }
1919  }
1920  return GRN_SUCCESS;
1921 }
1922 
1923 grn_rc
1924 grn_bulk_reinit(grn_ctx *ctx, grn_obj *buf, unsigned int size)
1925 {
1926  GRN_BULK_REWIND(buf);
1927  return grn_bulk_resize(ctx, buf, size);
1928 }
1929 
1930 grn_rc
1931 grn_bulk_write(grn_ctx *ctx, grn_obj *buf, const char *str, unsigned int len)
1932 {
1933  grn_rc rc = GRN_SUCCESS;
1934  char *curr;
1935  if (GRN_BULK_REST(buf) < len) {
1936  if ((rc = grn_bulk_resize(ctx, buf, GRN_BULK_VSIZE(buf) + len))) { return rc; }
1937  }
1938  curr = GRN_BULK_CURR(buf);
1939  memcpy(curr, str, len);
1940  GRN_BULK_INCR_LEN(buf, len);
1941  return rc;
1942 }
1943 
1944 grn_rc
1946  const char *str, unsigned int from, unsigned int len)
1947 {
1948  grn_rc rc = grn_bulk_truncate(ctx, bulk, from);
1949  if (!rc) { rc = grn_bulk_write(ctx, bulk, str, len); }
1950  return rc;
1951 }
1952 
1953 grn_rc
1954 grn_bulk_reserve(grn_ctx *ctx, grn_obj *buf, unsigned int len)
1955 {
1956  grn_rc rc = GRN_SUCCESS;
1957  if (GRN_BULK_REST(buf) < len) {
1958  if ((rc = grn_bulk_resize(ctx, buf, GRN_BULK_VSIZE(buf) + len))) { return rc; }
1959  }
1960  return rc;
1961 }
1962 
1963 grn_rc
1964 grn_bulk_space(grn_ctx *ctx, grn_obj *buf, unsigned int len)
1965 {
1966  grn_rc rc = grn_bulk_reserve(ctx, buf, len);
1967  if (!rc) {
1968  GRN_BULK_INCR_LEN(buf, len);
1969  }
1970  return rc;
1971 }
1972 
1973 static grn_rc
1974 grn_bulk_space_clear(grn_ctx *ctx, grn_obj *buf, unsigned int len)
1975 {
1976  grn_rc rc = grn_bulk_reserve(ctx, buf, len);
1977  if (!rc) {
1978  memset(GRN_BULK_CURR(buf), 0, len);
1979  GRN_BULK_INCR_LEN(buf, len);
1980  }
1981  return rc;
1982 }
1983 
1984 grn_rc
1985 grn_bulk_truncate(grn_ctx *ctx, grn_obj *bulk, unsigned int len)
1986 {
1987  if (GRN_BULK_OUTP(bulk)) {
1988  if ((bulk->u.b.tail - bulk->u.b.head) < len) {
1989  return grn_bulk_space_clear(ctx, bulk, len);
1990  } else {
1991  bulk->u.b.curr = bulk->u.b.head + len;
1992  }
1993  } else {
1994  if (GRN_BULK_BUFSIZE < len) {
1995  return grn_bulk_space_clear(ctx, bulk, len);
1996  } else {
1997  bulk->header.flags = len;
1998  }
1999  }
2000  return GRN_SUCCESS;
2001 }
2002 
2003 grn_rc
2004 grn_text_itoa(grn_ctx *ctx, grn_obj *buf, int i)
2005 {
2006  grn_rc rc = GRN_SUCCESS;
2007  for (;;) {
2008  char *curr = GRN_BULK_CURR(buf);
2009  char *tail = GRN_BULK_TAIL(buf);
2010  if (grn_itoa(i, curr, tail, &curr)) {
2011  if ((rc = grn_bulk_resize(ctx, buf, GRN_BULK_WSIZE(buf) + UNIT_SIZE))) { return rc; }
2012  } else {
2013  GRN_BULK_SET_CURR(buf, curr);
2014  break;
2015  }
2016  }
2017  return rc;
2018 }
2019 
2020 grn_rc
2021 grn_text_itoa_padded(grn_ctx *ctx, grn_obj *buf, int i, char ch, unsigned int len)
2022 {
2023  grn_rc rc = GRN_SUCCESS;
2024  char *curr;
2025  if ((rc = grn_bulk_reserve(ctx, buf, len))) { return rc; }
2026  curr = GRN_BULK_CURR(buf);
2027  if (!grn_itoa_padded(i, curr, curr + len, ch)) {
2028  GRN_BULK_SET_CURR(buf, curr + len);
2029  }
2030  return rc;
2031 }
2032 
2033 grn_rc
2034 grn_text_lltoa(grn_ctx *ctx, grn_obj *buf, long long int i)
2035 {
2036  grn_rc rc = GRN_SUCCESS;
2037  for (;;) {
2038  char *curr = GRN_BULK_CURR(buf);
2039  char *tail = GRN_BULK_TAIL(buf);
2040  if (grn_lltoa(i, curr, tail, &curr)) {
2041  if ((rc = grn_bulk_resize(ctx, buf, GRN_BULK_WSIZE(buf) + UNIT_SIZE))) { return rc; }
2042  } else {
2043  GRN_BULK_SET_CURR(buf, curr);
2044  break;
2045  }
2046  }
2047  return rc;
2048 }
2049 
2050 grn_rc
2051 grn_text_ulltoa(grn_ctx *ctx, grn_obj *buf, unsigned long long int i)
2052 {
2053  grn_rc rc = GRN_SUCCESS;
2054  for (;;) {
2055  char *curr = GRN_BULK_CURR(buf);
2056  char *tail = GRN_BULK_TAIL(buf);
2057  if (grn_ulltoa(i, curr, tail, &curr)) {
2058  if ((rc = grn_bulk_resize(ctx, buf, GRN_BULK_WSIZE(buf) + UNIT_SIZE))) { return rc; }
2059  } else {
2060  GRN_BULK_SET_CURR(buf, curr);
2061  break;
2062  }
2063  }
2064  return rc;
2065 }
2066 
2067 inline static void
2068 ftoa_(grn_ctx *ctx, grn_obj *buf, double d)
2069 {
2070  char *curr;
2071  size_t len;
2072 #define DIGIT_NUMBER 15
2073  grn_bulk_reserve(ctx, buf, DIGIT_NUMBER + 1);
2074  curr = GRN_BULK_CURR(buf);
2075  len = sprintf(curr, "%#.*g", DIGIT_NUMBER, d);
2076 #undef DIGIT_NUMBER
2077  if (curr[len - 1] == '.') {
2078  GRN_BULK_INCR_LEN(buf, len);
2079  GRN_TEXT_PUTC(ctx, buf, '0');
2080  } else {
2081  char *p, *q;
2082  curr[len] = '\0';
2083  if ((p = strchr(curr, 'e'))) {
2084  for (q = p; *(q - 2) != '.' && *(q - 1) == '0'; q--) { len--; }
2085  memmove(q, p, curr + len - q);
2086  } else {
2087  for (q = curr + len; *(q - 2) != '.' && *(q - 1) == '0'; q--) { len--; }
2088  }
2089  GRN_BULK_INCR_LEN(buf, len);
2090  }
2091 }
2092 
2093 grn_rc
2094 grn_text_ftoa(grn_ctx *ctx, grn_obj *buf, double d)
2095 {
2096  grn_rc rc = GRN_SUCCESS;
2097  if (GRN_BULK_REST(buf) < 32) {
2098  if ((rc = grn_bulk_resize(ctx, buf, GRN_BULK_VSIZE(buf) + 32))) { return rc; }
2099  }
2100 #ifdef HAVE_FPCLASSIFY
2101  switch (fpclassify(d)) {
2102  case FP_NAN :
2103  GRN_TEXT_PUTS(ctx, buf, "#<nan>");
2104  break;
2105  case FP_INFINITE :
2106  GRN_TEXT_PUTS(ctx, buf, d > 0 ? "#i1/0" : "#i-1/0");
2107  break;
2108  default :
2109  ftoa_(ctx, buf, d);
2110  break;
2111  }
2112 #else /* HAVE_FPCLASSIFY */
2113  if (d == d) {
2114  if (d != 0 && ((d / 2.0) == d)) {
2115  GRN_TEXT_PUTS(ctx, buf, d > 0 ? "#i1/0" : "#i-1/0");
2116  } else {
2117  ftoa_(ctx, buf, d);
2118  }
2119  } else {
2120  GRN_TEXT_PUTS(ctx, buf, "#<nan>");
2121  }
2122 #endif /* HAVE_FPCLASSIFY */
2123  return rc;
2124 }
2125 
2126 grn_rc
2127 grn_text_itoh(grn_ctx *ctx, grn_obj *buf, int i, unsigned int len)
2128 {
2129  grn_rc rc = GRN_SUCCESS;
2130  if (GRN_BULK_REST(buf) < len) {
2131  if ((rc = grn_bulk_resize(ctx, buf, GRN_BULK_VSIZE(buf) + len))) { return rc; }
2132  }
2133  grn_itoh(i, GRN_BULK_CURR(buf), len);
2134  GRN_BULK_INCR_LEN(buf, len);
2135  return rc;
2136 }
2137 
2138 grn_rc
2140 {
2141  size_t len = 5;
2142  grn_rc rc = GRN_SUCCESS;
2143  if (GRN_BULK_REST(buf) < len) {
2144  if ((rc = grn_bulk_resize(ctx, buf, GRN_BULK_VSIZE(buf) + len))) { return rc; }
2145  }
2146  grn_itob(id, GRN_BULK_CURR(buf));
2147  GRN_BULK_INCR_LEN(buf, len);
2148  return rc;
2149 }
2150 
2151 grn_rc
2152 grn_text_lltob32h(grn_ctx *ctx, grn_obj *buf, long long int i)
2153 {
2154  size_t len = 13;
2155  grn_rc rc = GRN_SUCCESS;
2156  if (GRN_BULK_REST(buf) < len) {
2157  if ((rc = grn_bulk_resize(ctx, buf, GRN_BULK_VSIZE(buf) + len))) { return rc; }
2158  }
2159  grn_lltob32h(i, GRN_BULK_CURR(buf));
2160  GRN_BULK_INCR_LEN(buf, len);
2161  return rc;
2162 }
2163 
2164 grn_rc
2165 grn_text_esc(grn_ctx *ctx, grn_obj *buf, const char *s, unsigned int len)
2166 {
2167  const char *e;
2168  unsigned int l;
2169  grn_rc rc = GRN_SUCCESS;
2170 
2171  GRN_TEXT_PUTC(ctx, buf, '"');
2172  for (e = s + len; s < e; s += l) {
2173  if (!(l = grn_charlen(ctx, s, e))) { break; }
2174  if (l == 1) {
2175  switch (*s) {
2176  case '"' :
2177  grn_bulk_write(ctx, buf, "\\\"", 2);
2178  break;
2179  case '\\' :
2180  grn_bulk_write(ctx, buf, "\\\\", 2);
2181  break;
2182  case '\b' :
2183  grn_bulk_write(ctx, buf, "\\b", 2);
2184  break;
2185  case '\f' :
2186  grn_bulk_write(ctx, buf, "\\f", 2);
2187  break;
2188  case '\n' :
2189  grn_bulk_write(ctx, buf, "\\n", 2);
2190  break;
2191  case '\r' :
2192  grn_bulk_write(ctx, buf, "\\r", 2);
2193  break;
2194  case '\t' :
2195  grn_bulk_write(ctx, buf, "\\t", 2);
2196  break;
2197  case '\x00': case '\x01': case '\x02': case '\x03': case '\x04': case '\x05':
2198  case '\x06': case '\x07': case '\x0b': case '\x0e': case '\x0f': case '\x10':
2199  case '\x11': case '\x12': case '\x13': case '\x14': case '\x15': case '\x16':
2200  case '\x17': case '\x18': case '\x19': case '\x1a': case '\x1b': case '\x1c':
2201  case '\x1d': case '\x1e': case '\x1f': case '\x7f':
2202  if (!(rc = grn_bulk_write(ctx, buf, "\\u", 2))) {
2203  if ((rc = grn_text_itoh(ctx, buf, *s, 4))) {
2204  GRN_BULK_INCR_LEN(buf, -2);
2205  return rc;
2206  }
2207  } else {
2208  return rc;
2209  }
2210  break;
2211  default :
2212  GRN_TEXT_PUTC(ctx, buf, *s);
2213  }
2214  } else if (l == 3) {
2215  if (*s == '\xe2' && *(s + 1) == '\x80') {
2216  switch (*(s + 2)) {
2217  case '\xa8': /* \u2028 */
2218  grn_bulk_write(ctx, buf, "\\u2028", 6);
2219  break;
2220  case '\xa9': /* \u2029 */
2221  grn_bulk_write(ctx, buf, "\\u2029", 6);
2222  break;
2223  default:
2224  grn_bulk_write(ctx, buf, s, l);
2225  }
2226  } else {
2227  grn_bulk_write(ctx, buf, s, l);
2228  }
2229  } else {
2230  grn_bulk_write(ctx, buf, s, l);
2231  }
2232  }
2233  GRN_TEXT_PUTC(ctx, buf, '"');
2234  return rc;
2235 }
2236 
2237 grn_rc
2238 grn_text_escape_xml(grn_ctx *ctx, grn_obj *buf, const char *s, unsigned int len)
2239 {
2240  const char *e;
2241  unsigned int l;
2242  grn_rc rc = GRN_SUCCESS;
2243 
2244  for (e = s + len; s < e; s += l) {
2245  if (!(l = grn_charlen(ctx, s, e))) { break; }
2246  if (l == 1) {
2247  switch (*s) {
2248  case '"' :
2249  grn_bulk_write(ctx, buf, "&quot;", 6);
2250  break;
2251  case '<' :
2252  grn_bulk_write(ctx, buf, "&lt;", 4);
2253  break;
2254  case '>' :
2255  grn_bulk_write(ctx, buf, "&gt;", 4);
2256  break;
2257  case '&' :
2258  grn_bulk_write(ctx, buf, "&amp;", 5);
2259  break;
2260  default :
2261  GRN_TEXT_PUTC(ctx, buf, *s);
2262  }
2263  } else {
2264  grn_bulk_write(ctx, buf, s, l);
2265  }
2266  }
2267  return rc;
2268 }
2269 
2270 #define TOK_ESC (0x80)
2271 
2272 const char *
2273 grn_text_unesc_tok(grn_ctx *ctx, grn_obj *buf, const char *s, const char *e, char *tok_type)
2274 {
2275  const char *p;
2276  unsigned int len;
2277  uint8_t stat = GRN_TOK_VOID;
2278  for (p = s; p < e; p += len) {
2279  if (!(len = grn_charlen(ctx, p, e))) {
2280  p = e;
2281  stat &= ~TOK_ESC;
2282  goto exit;
2283  }
2284  switch (stat) {
2285  case GRN_TOK_VOID :
2286  if (*p == ' ') { continue; }
2287  switch (*p) {
2288  case '"' :
2289  stat = GRN_TOK_STRING;
2290  break;
2291  case '\'' :
2292  stat = GRN_TOK_QUOTE;
2293  break;
2294  case ')' :
2295  case '(' :
2296  GRN_TEXT_PUT(ctx, buf, p, len);
2297  p += len;
2298  stat = GRN_TOK_SYMBOL;
2299  goto exit;
2300  case '\\' :
2301  stat = GRN_TOK_SYMBOL|TOK_ESC;
2302  break;
2303  default :
2304  stat = GRN_TOK_SYMBOL;
2305  GRN_TEXT_PUT(ctx, buf, p, len);
2306  break;
2307  }
2308  break;
2309  case GRN_TOK_SYMBOL :
2310  if (*p == ' ') { goto exit; }
2311  switch (*p) {
2312  case '\'' :
2313  case '"' :
2314  case ')' :
2315  case '(' :
2316  goto exit;
2317  case '\\' :
2318  stat |= TOK_ESC;
2319  break;
2320  default :
2321  GRN_TEXT_PUT(ctx, buf, p, len);
2322  break;
2323  }
2324  break;
2325  case GRN_TOK_STRING :
2326  switch (*p) {
2327  case '"' :
2328  p += len;
2329  goto exit;
2330  case '\\' :
2331  stat |= TOK_ESC;
2332  break;
2333  default :
2334  GRN_TEXT_PUT(ctx, buf, p, len);
2335  break;
2336  }
2337  break;
2338  case GRN_TOK_QUOTE :
2339  switch (*p) {
2340  case '\'' :
2341  p += len;
2342  goto exit;
2343  case '\\' :
2344  stat |= TOK_ESC;
2345  break;
2346  default :
2347  GRN_TEXT_PUT(ctx, buf, p, len);
2348  break;
2349  }
2350  break;
2351  case GRN_TOK_SYMBOL|TOK_ESC :
2352  case GRN_TOK_STRING|TOK_ESC :
2353  case GRN_TOK_QUOTE|TOK_ESC :
2354  switch (*p) {
2355  case 'b' :
2356  GRN_TEXT_PUTC(ctx, buf, '\b');
2357  break;
2358  case 'f' :
2359  GRN_TEXT_PUTC(ctx, buf, '\f');
2360  break;
2361  case 'n' :
2362  GRN_TEXT_PUTC(ctx, buf, '\n');
2363  break;
2364  case 'r' :
2365  GRN_TEXT_PUTC(ctx, buf, '\r');
2366  break;
2367  case 't' :
2368  GRN_TEXT_PUTC(ctx, buf, '\t');
2369  break;
2370  default :
2371  GRN_TEXT_PUT(ctx, buf, p, len);
2372  break;
2373  }
2374  stat &= ~TOK_ESC;
2375  break;
2376  }
2377  }
2378 exit :
2379  *tok_type = stat;
2380  return p;
2381 }
2382 
2383 grn_rc
2384 grn_text_benc(grn_ctx *ctx, grn_obj *buf, unsigned int v)
2385 {
2386  grn_rc rc = GRN_SUCCESS;
2387  uint8_t *p;
2388  if (GRN_BULK_REST(buf) < 5) {
2389  if ((rc = grn_bulk_resize(ctx, buf, GRN_BULK_VSIZE(buf) + 5))) { return rc; }
2390  }
2391  p = (uint8_t *)GRN_BULK_CURR(buf);
2392  GRN_B_ENC(v, p);
2393  GRN_BULK_SET_CURR(buf, (char *)p);
2394  return rc;
2395 }
2396 
2397 /* 0x00 - 0x7f */
2398 static const int_least8_t urlenc_tbl[] = {
2399  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2400  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2401  1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1,
2402  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
2403  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2404  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2405  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2406  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
2407 };
2408 
2409 grn_rc
2410 grn_text_urlenc(grn_ctx *ctx, grn_obj *buf, const char *s, unsigned int len)
2411 {
2412  const char *e, c = '%';
2413  for (e = s + len; s < e; s++) {
2414  if (*s < 0 || urlenc_tbl[(int)*s]) {
2415  if (!grn_bulk_write(ctx, buf, &c, 1)) {
2416  if (grn_text_itoh(ctx, buf, *s, 2)) {
2417  GRN_BULK_INCR_LEN(buf, -1);
2418  }
2419  }
2420  } else {
2421  GRN_TEXT_PUTC(ctx, buf, *s);
2422  }
2423  }
2424  return GRN_SUCCESS;
2425 }
2426 
2427 static const char *weekdays[7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
2428 static const char *months[12] = {
2429  "Jan", "Feb", "Mar", "Apr", "May", "Jun",
2430  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
2431 
2432 grn_rc
2434 {
2435  time_t tsec;
2436  struct tm *t;
2437 #ifdef HAVE_GMTIME_R
2438  struct tm tm;
2439  tsec = (time_t)sec;
2440  t = gmtime_r(&tsec, &tm);
2441 #else /* HAVE_GMTIME_R */
2442  tsec = (time_t)sec;
2443  t = gmtime(&tsec);
2444 #endif /* HAVE_GMTIME_R */
2445  if (t) {
2446  GRN_TEXT_SET(ctx, bulk, weekdays[t->tm_wday], 3);
2447  GRN_TEXT_PUTS(ctx, bulk, ", ");
2448  grn_text_itoa_padded(ctx, bulk, t->tm_mday, '0', 2);
2449  GRN_TEXT_PUTS(ctx, bulk, " ");
2450  GRN_TEXT_PUT(ctx, bulk, months[t->tm_mon], 3);
2451  GRN_TEXT_PUTS(ctx, bulk, " ");
2452  grn_text_itoa(ctx, bulk, t->tm_year + 1900);
2453  GRN_TEXT_PUTS(ctx, bulk, " ");
2454  grn_text_itoa_padded(ctx, bulk, t->tm_hour, '0', 2);
2455  GRN_TEXT_PUTS(ctx, bulk, ":");
2456  grn_text_itoa_padded(ctx, bulk, t->tm_min, '0', 2);
2457  GRN_TEXT_PUTS(ctx, bulk, ":");
2458  grn_text_itoa_padded(ctx, bulk, t->tm_sec, '0', 2);
2459  GRN_TEXT_PUTS(ctx, bulk, " GMT");
2460  } else {
2461  GRN_TEXT_SETS(ctx, bulk, "Mon, 16 Mar 1980 20:40:00 GMT");
2462  }
2463  return GRN_SUCCESS;
2464 }
2465 
2466 
2467 grn_rc
2469 {
2470  if (!(buf->header.impl_flags & GRN_OBJ_REFER)) {
2471  if (GRN_BULK_OUTP(buf) && buf->u.b.head) {
2472  GRN_REALLOC(buf->u.b.head - grn_bulk_margin_size, 0);
2473  }
2474  }
2475  buf->header.flags = 0;
2477  buf->u.b.head = NULL;
2478  buf->u.b.curr = NULL;
2479  buf->u.b.tail = NULL;
2480  return GRN_SUCCESS;
2481 }
2482 
2483 grn_rc
2484 grn_substring(grn_ctx *ctx, char **str, char **str_end, int start, int end, grn_encoding encoding)
2485 {
2486  int i;
2487  size_t l;
2488  char *s = *str, *e = *str_end;
2489  for (i = 0; s < e; i++, s += l) {
2490  if (i == start) { *str = s; }
2491  if (!(l = grn_charlen(ctx, s, e))) {
2492  return GRN_INVALID_ARGUMENT;
2493  }
2494  if (i == end) {
2495  *str_end = s;
2496  break;
2497  }
2498  }
2499  return GRN_SUCCESS;
2500 }
2501 
2502 static void
2503 grn_text_atoj(grn_ctx *ctx, grn_obj *bulk, grn_obj *obj, grn_id id)
2504 {
2505  uint32_t vs;
2506  grn_obj buf;
2507  if (obj->header.type == GRN_ACCESSOR) {
2508  grn_accessor *a = (grn_accessor *)obj;
2509  GRN_TEXT_INIT(&buf, 0);
2510  for (;;) {
2511  GRN_BULK_REWIND(&buf);
2512  switch (a->action) {
2513  case GRN_ACCESSOR_GET_ID :
2514  GRN_UINT32_PUT(ctx, &buf, id);
2515  buf.header.domain = GRN_DB_UINT32;
2516  break;
2517  case GRN_ACCESSOR_GET_KEY :
2518  grn_table_get_key2(ctx, a->obj, id, &buf);
2519  buf.header.domain = DB_OBJ(a->obj)->header.domain;
2520  break;
2521  case GRN_ACCESSOR_GET_VALUE :
2522  grn_obj_get_value(ctx, a->obj, id, &buf);
2523  buf.header.domain = GRN_DB_INT32; /* fix me */
2524  break;
2525  case GRN_ACCESSOR_GET_SCORE :
2526  grn_obj_get_value(ctx, a->obj, id, &buf);
2527  {
2528  grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
2529  GRN_INT32_PUT(ctx, &buf, ri->score);
2530  }
2531  buf.header.domain = GRN_DB_INT32;
2532  break;
2534  {
2535  grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
2536  GRN_INT32_PUT(ctx, &buf, ri->n_subrecs);
2537  }
2538  buf.header.domain = GRN_DB_INT32;
2539  break;
2542  if (a->next) {
2543  grn_id *idp;
2544  grn_obj_get_value(ctx, a->obj, id, &buf);
2545  idp = (grn_id *)GRN_BULK_HEAD(&buf);
2546  GRN_TEXT_PUTC(ctx, bulk, '[');
2547  for (vs = GRN_BULK_VSIZE(&buf) / sizeof(grn_id); vs--; idp++) {
2548  grn_text_atoj(ctx, bulk, (grn_obj *)a->next, *idp);
2549  if (vs) { GRN_TEXT_PUTC(ctx, bulk, ','); }
2550  }
2551  GRN_TEXT_PUTC(ctx, bulk, ']');
2552  } else {
2553  grn_text_atoj(ctx, bulk, a->obj, id);
2554  }
2555  goto exit;
2556  } else {
2557  grn_obj_get_value(ctx, a->obj, id, &buf);
2558  }
2559  break;
2561  /* todo */
2562  break;
2563  case GRN_ACCESSOR_LOOKUP :
2564  /* todo */
2565  break;
2566  case GRN_ACCESSOR_FUNCALL :
2567  /* todo */
2568  break;
2569  }
2570  if (a->next) {
2571  a = a->next;
2572  id = *((grn_id *)GRN_BULK_HEAD(&buf));
2573  } else {
2574  break;
2575  }
2576  }
2577  } else {
2578  switch (obj->header.type) {
2579  case GRN_COLUMN_FIX_SIZE :
2580  GRN_VALUE_FIX_SIZE_INIT(&buf, 0, DB_OBJ(obj)->range);
2581  break;
2582  case GRN_COLUMN_VAR_SIZE :
2584  grn_obj *range = grn_ctx_at(ctx, DB_OBJ(obj)->range);
2585  if (range->header.flags & GRN_OBJ_KEY_VAR_SIZE) {
2586  GRN_VALUE_VAR_SIZE_INIT(&buf, GRN_OBJ_VECTOR, DB_OBJ(obj)->range);
2587  } else {
2588  GRN_VALUE_FIX_SIZE_INIT(&buf, GRN_OBJ_VECTOR, DB_OBJ(obj)->range);
2589  }
2590  } else {
2591  GRN_VALUE_VAR_SIZE_INIT(&buf, 0, DB_OBJ(obj)->range);
2592  }
2593  break;
2594  case GRN_COLUMN_INDEX :
2595  GRN_UINT32_INIT(&buf, 0);
2596  break;
2597  default:
2598  GRN_TEXT_INIT(&buf, 0);
2599  break;
2600  }
2601  grn_obj_get_value(ctx, obj, id, &buf);
2602  }
2603  grn_text_otoj(ctx, bulk, &buf, NULL);
2604 exit :
2605  grn_obj_close(ctx, &buf);
2606 }
2607 
2608 grn_rc
2610 {
2611  grn_obj buf;
2612  GRN_TEXT_INIT(&buf, 0);
2613  switch (obj->header.type) {
2614  case GRN_BULK :
2615  switch (obj->header.domain) {
2616  case GRN_DB_VOID :
2617  case GRN_DB_SHORT_TEXT :
2618  case GRN_DB_TEXT :
2619  case GRN_DB_LONG_TEXT :
2620  grn_text_esc(ctx, bulk, GRN_BULK_HEAD(obj), GRN_BULK_VSIZE(obj));
2621  break;
2622  case GRN_DB_BOOL :
2623  if (*((unsigned char *)GRN_BULK_HEAD(obj))) {
2624  GRN_TEXT_PUTS(ctx, bulk, "true");
2625  } else {
2626  GRN_TEXT_PUTS(ctx, bulk, "false");
2627  }
2628  break;
2629  case GRN_DB_INT8 :
2630  grn_text_itoa(ctx, bulk, GRN_BULK_VSIZE(obj) ? GRN_INT8_VALUE(obj) : 0);
2631  break;
2632  case GRN_DB_UINT8 :
2633  grn_text_lltoa(ctx, bulk, GRN_BULK_VSIZE(obj) ? GRN_UINT8_VALUE(obj) : 0);
2634  break;
2635  case GRN_DB_INT16 :
2636  grn_text_itoa(ctx, bulk, GRN_BULK_VSIZE(obj) ? GRN_INT16_VALUE(obj) : 0);
2637  break;
2638  case GRN_DB_UINT16 :
2639  grn_text_lltoa(ctx, bulk, GRN_BULK_VSIZE(obj) ? GRN_UINT16_VALUE(obj) : 0);
2640  break;
2641  case GRN_DB_INT32 :
2642  grn_text_itoa(ctx, bulk, GRN_BULK_VSIZE(obj) ? GRN_INT32_VALUE(obj) : 0);
2643  break;
2644  case GRN_DB_UINT32 :
2645  grn_text_lltoa(ctx, bulk, GRN_BULK_VSIZE(obj) ? GRN_UINT32_VALUE(obj) : 0);
2646  break;
2647  case GRN_DB_INT64 :
2648  grn_text_lltoa(ctx, bulk, GRN_BULK_VSIZE(obj) ? GRN_INT64_VALUE(obj) : 0);
2649  break;
2650  case GRN_DB_UINT64 :
2651  grn_text_ulltoa(ctx, bulk, GRN_BULK_VSIZE(obj) ? GRN_UINT64_VALUE(obj) : 0);
2652  break;
2653  case GRN_DB_FLOAT :
2654  grn_text_ftoa(ctx, bulk, GRN_BULK_VSIZE(obj) ? GRN_FLOAT_VALUE(obj) : 0);
2655  break;
2656  case GRN_DB_TIME :
2657  {
2658  double dv = *((int64_t *)GRN_BULK_HEAD(obj));
2659  dv /= 1000000.0;
2660  grn_text_ftoa(ctx, bulk, dv);
2661  }
2662  break;
2663  case GRN_DB_TOKYO_GEO_POINT :
2664  case GRN_DB_WGS84_GEO_POINT :
2665  if (GRN_BULK_VSIZE(obj) == sizeof(grn_geo_point)) {
2667  GRN_TEXT_PUTC(ctx, bulk, '"');
2668  grn_text_itoa(ctx, bulk, gp->latitude);
2669  GRN_TEXT_PUTC(ctx, bulk, 'x');
2670  grn_text_itoa(ctx, bulk, gp->longitude);
2671  GRN_TEXT_PUTC(ctx, bulk, '"');
2672  } else {
2673  GRN_TEXT_PUTS(ctx, bulk, "\"\"");
2674  }
2675  break;
2676  default :
2677  if (format) {
2678  int j;
2679  int ncolumns = GRN_BULK_VSIZE(&format->columns)/sizeof(grn_obj *);
2680  grn_id id = GRN_RECORD_VALUE(obj);
2681  grn_obj **columns = (grn_obj **)GRN_BULK_HEAD(&format->columns);
2682  if (format->flags & GRN_OBJ_FORMAT_WITH_COLUMN_NAMES) {
2683  GRN_TEXT_PUTS(ctx, bulk, "[");
2684  for (j = 0; j < ncolumns; j++) {
2685  grn_id range_id;
2686  if (j) { GRN_TEXT_PUTC(ctx, bulk, ','); }
2687  GRN_TEXT_PUTS(ctx, bulk, "[");
2688  GRN_BULK_REWIND(&buf);
2689  grn_column_name_(ctx, columns[j], &buf);
2690  grn_text_otoj(ctx, bulk, &buf, NULL);
2691  GRN_TEXT_PUTC(ctx, bulk, ',');
2692  /* column range */
2693  range_id = grn_obj_get_range(ctx, columns[j]);
2694  if (range_id == GRN_ID_NIL) {
2695  GRN_TEXT_PUTS(ctx, bulk, "null");
2696  } else {
2697  int name_len;
2698  grn_obj *range_obj;
2699  char name_buf[GRN_TABLE_MAX_KEY_SIZE];
2700 
2701  range_obj = grn_ctx_at(ctx, range_id);
2702  name_len = grn_obj_name(ctx, range_obj, name_buf,
2704  GRN_BULK_REWIND(&buf);
2705  GRN_TEXT_PUT(ctx, &buf, name_buf, name_len);
2706  grn_text_otoj(ctx, bulk, &buf, NULL);
2707  }
2708  GRN_TEXT_PUTS(ctx, bulk, "]");
2709  }
2710  GRN_TEXT_PUTS(ctx, bulk, "],");
2711  }
2712  GRN_TEXT_PUTC(ctx, bulk, '[');
2713  for (j = 0; j < ncolumns; j++) {
2714  if (j) { GRN_TEXT_PUTC(ctx, bulk, ','); }
2715  grn_text_atoj(ctx, bulk, columns[j], id);
2716  }
2717  GRN_TEXT_PUTC(ctx, bulk, ']');
2718  } else {
2719  grn_obj *table = grn_ctx_at(ctx, obj->header.domain);
2720  grn_id id = GRN_RECORD_VALUE(obj);
2721  if (table && table->header.type != GRN_TABLE_NO_KEY) {
2722  /* todo : temporal patch. grn_table_at() is kinda costful... */
2723  if (grn_table_at(ctx, table, id)) {
2724  grn_obj *accessor = grn_obj_column(ctx, table, "_key", 4);
2725  if (accessor) {
2726  grn_obj_get_value(ctx, accessor, id, &buf);
2727  grn_obj_unlink(ctx, accessor);
2728  }
2729  }
2730  grn_text_otoj(ctx, bulk, &buf, format);
2731  } else {
2732  grn_text_lltoa(ctx, bulk, id);
2733  }
2734  }
2735  }
2736  break;
2737  case GRN_UVECTOR :
2738  if (format) {
2739  int i, j;
2740  grn_id *v = (grn_id *)GRN_BULK_HEAD(obj), *ve = (grn_id *)GRN_BULK_CURR(obj);
2741  int ncolumns = GRN_BULK_VSIZE(&format->columns) / sizeof(grn_obj *);
2742  grn_obj **columns = (grn_obj **)GRN_BULK_HEAD(&format->columns);
2743  GRN_TEXT_PUTS(ctx, bulk, "[[");
2744  grn_text_itoa(ctx, bulk, ve - v);
2745  GRN_TEXT_PUTC(ctx, bulk, ']');
2746  if (v < ve) {
2747  if (format->flags & GRN_OBJ_FORMAT_WITH_COLUMN_NAMES) {
2748  GRN_TEXT_PUTS(ctx, bulk, ",[");
2749  for (j = 0; j < ncolumns; j++) {
2750  grn_id range_id;
2751  if (j) { GRN_TEXT_PUTC(ctx, bulk, ','); }
2752  GRN_TEXT_PUTS(ctx, bulk, "[");
2753  GRN_BULK_REWIND(&buf);
2754  grn_column_name_(ctx, columns[j], &buf);
2755  grn_text_otoj(ctx, bulk, &buf, NULL);
2756  GRN_TEXT_PUTC(ctx, bulk, ',');
2757  /* column range */
2758  range_id = grn_obj_get_range(ctx, columns[j]);
2759  if (range_id == GRN_ID_NIL) {
2760  GRN_TEXT_PUTS(ctx, bulk, "null");
2761  } else {
2762  int name_len;
2763  grn_obj *range_obj;
2764  char name_buf[GRN_TABLE_MAX_KEY_SIZE];
2765 
2766  range_obj = grn_ctx_at(ctx, range_id);
2767  name_len = grn_obj_name(ctx, range_obj, name_buf,
2769  GRN_BULK_REWIND(&buf);
2770  GRN_TEXT_PUT(ctx, &buf, name_buf, name_len);
2771  grn_text_otoj(ctx, bulk, &buf, NULL);
2772  }
2773  GRN_TEXT_PUTS(ctx, bulk, "]");
2774  }
2775  GRN_TEXT_PUTC(ctx, bulk, ']');
2776  }
2777  for (i = 0;; i++) {
2778  GRN_TEXT_PUTS(ctx, bulk, ",[");
2779  for (j = 0; j < ncolumns; j++) {
2780  if (j) { GRN_TEXT_PUTC(ctx, bulk, ','); }
2781  GRN_BULK_REWIND(&buf);
2782  grn_obj_get_value(ctx, columns[j], *v, &buf);
2783  grn_text_otoj(ctx, bulk, &buf, NULL);
2784  }
2785  GRN_TEXT_PUTC(ctx, bulk, ']');
2786  v++;
2787  if (v < ve) {
2788  GRN_TEXT_PUTC(ctx, bulk, ',');
2789  } else {
2790  break;
2791  }
2792  }
2793  }
2794  GRN_TEXT_PUTC(ctx, bulk, ']');
2795  } else {
2796  grn_obj *range = grn_ctx_at(ctx, obj->header.domain);
2797  if (range && range->header.type == GRN_TYPE) {
2798  grn_id value_size = ((struct _grn_type *)range)->obj.range;
2799  char *v = (char *)GRN_BULK_HEAD(obj),
2800  *ve = (char *)GRN_BULK_CURR(obj);
2801  GRN_TEXT_PUTC(ctx, bulk, '[');
2802  if (v < ve) {
2803  for (;;) {
2804  grn_obj value;
2805  GRN_OBJ_INIT(&value, GRN_BULK, 0, obj->header.domain);
2806  grn_bulk_write_from(ctx, &value, v, 0, value_size);
2807  grn_text_otoj(ctx, bulk, &value, NULL);
2808 
2809  v += value_size;
2810  if (v < ve) {
2811  GRN_TEXT_PUTC(ctx, bulk, ',');
2812  } else {
2813  break;
2814  }
2815  }
2816  }
2817  GRN_TEXT_PUTC(ctx, bulk, ']');
2818  } else {
2819  grn_id *v = (grn_id *)GRN_BULK_HEAD(obj),
2820  *ve = (grn_id *)GRN_BULK_CURR(obj);
2821  GRN_TEXT_PUTC(ctx, bulk, '[');
2822  if (v < ve) {
2823  for (;;) {
2824  if (range->header.type != GRN_TABLE_NO_KEY) {
2825  grn_obj key;
2826  GRN_OBJ_INIT(&key, GRN_BULK, 0, range->header.domain);
2827  grn_table_get_key2(ctx, range, *v, &key);
2828  grn_text_otoj(ctx, bulk, &key, NULL);
2829  GRN_OBJ_FIN(ctx, &key);
2830  } else {
2831  grn_text_lltoa(ctx, bulk, *v);
2832  }
2833  v++;
2834  if (v < ve) {
2835  GRN_TEXT_PUTC(ctx, bulk, ',');
2836  } else {
2837  break;
2838  }
2839  }
2840  }
2841  GRN_TEXT_PUTC(ctx, bulk, ']');
2842  }
2843  }
2844  break;
2845  case GRN_VECTOR :
2846  if (obj->header.domain == GRN_DB_VOID) {
2847  ERR(GRN_INVALID_ARGUMENT, "invalid obj->header.domain");
2848  }
2849  if (format) {
2851  "cannot print GRN_VECTOR using grn_obj_format");
2852  } else {
2853  unsigned int i, n;
2854  grn_obj value;
2855  GRN_VOID_INIT(&value);
2856  n = grn_vector_size(ctx, obj);
2857  GRN_TEXT_PUTC(ctx, bulk, '[');
2858  for (i = 0; i < n; i++) {
2859  const char *_value;
2860  unsigned int weight, length;
2861  grn_id domain;
2862  if (i) { GRN_TEXT_PUTC(ctx, bulk, ','); }
2863 
2864  length = grn_vector_get_element(ctx, obj, i,
2865  &_value, &weight, &domain);
2866  if (domain != GRN_DB_VOID) {
2867  grn_obj_reinit(ctx, &value, domain, 0);
2868  } else {
2869  grn_obj_reinit(ctx, &value, obj->header.domain, 0);
2870  }
2871  grn_bulk_write(ctx, &value, _value, length);
2872  grn_text_otoj(ctx, bulk, &value, NULL);
2873  }
2874  GRN_TEXT_PUTC(ctx, bulk, ']');
2875  }
2876  break;
2877  case GRN_PVECTOR :
2878  if (format) {
2880  "cannot print GRN_PVECTOR using grn_obj_format");
2881  } else {
2882  unsigned int i, n;
2883  GRN_TEXT_PUTC(ctx, bulk, '[');
2884  n = GRN_BULK_VSIZE(obj) / sizeof(grn_obj *);
2885  for (i = 0; i < n; i++) {
2886  grn_obj *value;
2887 
2888  if (i) { GRN_TEXT_PUTC(ctx, bulk, ','); }
2889  value = GRN_PTR_VALUE_AT(obj, i);
2890  grn_text_otoj(ctx, bulk, value, NULL);
2891  }
2892  GRN_TEXT_PUTC(ctx, bulk, ']');
2893  }
2894  break;
2895  case GRN_TABLE_HASH_KEY :
2896  case GRN_TABLE_PAT_KEY :
2897  case GRN_TABLE_NO_KEY :
2898  if (format) {
2899  int i, j;
2900  int ncolumns = GRN_BULK_VSIZE(&format->columns)/sizeof(grn_obj *);
2901  grn_obj **columns = (grn_obj **)GRN_BULK_HEAD(&format->columns);
2902  grn_table_cursor *tc = grn_table_cursor_open(ctx, obj, NULL, 0, NULL, 0,
2903  format->offset, format->limit,
2905  if (!tc) { ERRCLR(ctx); }
2906  GRN_TEXT_PUTS(ctx, bulk, "[[");
2907  grn_text_itoa(ctx, bulk, format->nhits);
2908  GRN_TEXT_PUTC(ctx, bulk, ']');
2909  if (format->flags & GRN_OBJ_FORMAT_WITH_COLUMN_NAMES) {
2910  GRN_TEXT_PUTS(ctx, bulk, ",[");
2911  for (j = 0; j < ncolumns; j++) {
2912  grn_id range_id;
2913  if (j) { GRN_TEXT_PUTC(ctx, bulk, ','); }
2914  GRN_TEXT_PUTS(ctx, bulk, "[");
2915  GRN_BULK_REWIND(&buf);
2916  grn_column_name_(ctx, columns[j], &buf);
2917  grn_text_otoj(ctx, bulk, &buf, NULL);
2918  GRN_TEXT_PUTC(ctx, bulk, ',');
2919  /* column range */
2920  range_id = grn_obj_get_range(ctx, columns[j]);
2921  if (range_id == GRN_ID_NIL) {
2922  GRN_TEXT_PUTS(ctx, bulk, "null");
2923  } else {
2924  int name_len;
2925  grn_obj *range_obj;
2926  char name_buf[GRN_TABLE_MAX_KEY_SIZE];
2927 
2928  range_obj = grn_ctx_at(ctx, range_id);
2929  name_len = grn_obj_name(ctx, range_obj, name_buf,
2931  GRN_BULK_REWIND(&buf);
2932  GRN_TEXT_PUT(ctx, &buf, name_buf, name_len);
2933  grn_text_otoj(ctx, bulk, &buf, NULL);
2934  }
2935  GRN_TEXT_PUTS(ctx, bulk, "]");
2936  }
2937  GRN_TEXT_PUTC(ctx, bulk, ']');
2938  }
2939  if (tc) {
2940  grn_id id;
2941  for (i = 0; (id = grn_table_cursor_next(ctx, tc)) != GRN_ID_NIL; i++) {
2942  GRN_TEXT_PUTS(ctx, bulk, ",[");
2943  for (j = 0; j < ncolumns; j++) {
2944  if (j) { GRN_TEXT_PUTC(ctx, bulk, ','); }
2945  grn_text_atoj(ctx, bulk, columns[j], id);
2946  }
2947  GRN_TEXT_PUTC(ctx, bulk, ']');
2948  }
2949  grn_table_cursor_close(ctx, tc);
2950  }
2951  GRN_TEXT_PUTC(ctx, bulk, ']');
2952  } else {
2953  int i;
2954  grn_id id;
2955  grn_obj *column = grn_obj_column(ctx, obj, "_key", 4);
2956  grn_table_cursor *tc = grn_table_cursor_open(ctx, obj, NULL, 0, NULL, 0,
2957  0, -1, GRN_CURSOR_ASCENDING);
2958  GRN_TEXT_PUTC(ctx, bulk, '[');
2959  if (tc) {
2960  for (i = 0; (id = grn_table_cursor_next(ctx, tc)) != GRN_ID_NIL; i++) {
2961  if (i) { GRN_TEXT_PUTC(ctx, bulk, ','); }
2962  GRN_BULK_REWIND(&buf);
2963  grn_obj_get_value(ctx, column, id, &buf);
2964  grn_text_esc(ctx, bulk, GRN_BULK_HEAD(&buf), GRN_BULK_VSIZE(&buf));
2965  }
2966  grn_table_cursor_close(ctx, tc);
2967  }
2968  GRN_TEXT_PUTC(ctx, bulk, ']');
2969  grn_obj_unlink(ctx, column);
2970  }
2971  break;
2972  }
2973  grn_obj_close(ctx, &buf);
2974  return GRN_SUCCESS;
2975 }
2976 
2977 const char *
2978 grn_text_urldec(grn_ctx *ctx, grn_obj *buf, const char *p, const char *e, char d)
2979 {
2980  while (p < e) {
2981  if (*p == d) {
2982  p++; break;
2983  } else if (*p == '%' && p + 3 <= e) {
2984  const char *r;
2985  unsigned int c = grn_htoui(p + 1, p + 3, &r);
2986  if (p + 3 == r) {
2987  GRN_TEXT_PUTC(ctx, buf, c);
2988  p += 3;
2989  } else {
2990  GRN_LOG(ctx, GRN_LOG_NOTICE, "invalid %% sequence (%c%c)", p[1], p[2]);
2991  GRN_TEXT_PUTC(ctx, buf, '%');
2992  p += 1;
2993  }
2994  } else {
2995  GRN_TEXT_PUTC(ctx, buf, *p);
2996  p++;
2997  }
2998  }
2999  return p;
3000 }
3001 
3002 const char *
3003 grn_text_cgidec(grn_ctx *ctx, grn_obj *buf, const char *p, const char *e,
3004  const char *delimiters)
3005 {
3006  while (p < e) {
3007  grn_bool found_delimiter = GRN_FALSE;
3008  const char *delimiter;
3009  for (delimiter = delimiters; *delimiter; delimiter++) {
3010  if (*p == *delimiter) {
3011  found_delimiter = GRN_TRUE;
3012  break;
3013  }
3014  }
3015  if (found_delimiter) {
3016  p++;
3017  break;
3018  }
3019 
3020  if (*p == '+') {
3021  GRN_TEXT_PUTC(ctx, buf, ' ');
3022  p++;
3023  } else if (*p == '%' && p + 3 <= e) {
3024  const char *r;
3025  unsigned int c = grn_htoui(p + 1, p + 3, &r);
3026  if (p + 3 == r) {
3027  GRN_TEXT_PUTC(ctx, buf, c);
3028  p += 3;
3029  } else {
3030  GRN_LOG(ctx, GRN_LOG_NOTICE, "invalid %% sequence (%c%c)", p[1], p[2]);
3031  GRN_TEXT_PUTC(ctx, buf, '%');
3032  p += 1;
3033  }
3034  } else {
3035  GRN_TEXT_PUTC(ctx, buf, *p);
3036  p++;
3037  }
3038  }
3039  return p;
3040 }
3041 
3042 void
3043 grn_str_url_path_normalize(grn_ctx *ctx, const char *path, size_t path_len,
3044  char *buf, size_t buf_len)
3045 {
3046  char *b = buf, *be = buf + buf_len - 1;
3047  const char *p = path, *pe = path + path_len, *pc;
3048 
3049  if (buf_len < 2) { return; }
3050 
3051  while (p < pe) {
3052  for (pc = p; pc < pe && *pc != '/'; pc++) {}
3053  if (*p == '.') {
3054  if (pc == p + 2 && *(p + 1) == '.') {
3055  /* '..' */
3056  if (b - buf >= 2) {
3057  for (b -= 2; *b != '/' && b >= buf; b--) {}
3058  }
3059  if (*b == '/') {
3060  b++;
3061  ERR(GRN_INVALID_ARGUMENT, "parent path doesn't exist.");
3062  }
3063  p = pc + 1;
3064  continue;
3065  } else if (pc == p + 1) {
3066  /* '.' */
3067  p = pc + 1;
3068  continue;
3069  }
3070  }
3071  if (be - b >= pc - p) {
3072  memcpy(b, p, (pc - p));
3073  b += pc - p;
3074  p = pc;
3075  if (p < pe && *pc == '/' && be > b) {
3076  *b++ = '/';
3077  p++;
3078  }
3079  }
3080  }
3081  *b = '\0';
3082 }
3083 
3084 grn_rc
3085 grn_text_fgets(grn_ctx *ctx, grn_obj *buf, FILE *fp)
3086 {
3087  size_t len;
3088  grn_rc rc = GRN_END_OF_DATA;
3089  for (;;) {
3090  grn_bulk_reserve(ctx, buf, BUFSIZ);
3091  if (!fgets(GRN_BULK_CURR(buf), BUFSIZ, fp)) { break; }
3092  if (!(len = strlen(GRN_BULK_CURR(buf)))) { break; }
3093  GRN_BULK_INCR_LEN(buf, len);
3094  rc = GRN_SUCCESS;
3095  if (GRN_BULK_CURR(buf)[-1] == '\n') { break; }
3096  }
3097  return rc;
3098 }
3099 
3100 grn_bool
3102 {
3103  const char *v = GRN_BULK_HEAD(obj);
3104  unsigned int s = GRN_BULK_VSIZE(obj);
3105  for (; s; s--, v++) {
3106  if (*v) { return GRN_FALSE; }
3107  }
3108  return GRN_TRUE;
3109 }
3110