Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
output.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 
18 #ifndef GROONGA_IN_H
19 #include "groonga_in.h"
20 #endif /* GROONGA_IN_H */
21 
22 #include <string.h>
23 #include "str.h"
24 #include "db.h"
25 #include "util.h"
26 #include "output.h"
27 
28 #define LEVELS (&ctx->impl->levels)
29 #define DEPTH (GRN_BULK_VSIZE(LEVELS)>>2)
30 #define CURR_LEVEL (DEPTH ? (GRN_UINT32_VALUE_AT(LEVELS, (DEPTH - 1))) : 0)
31 #define INCR_DEPTH(i) GRN_UINT32_PUT(ctx, LEVELS, i)
32 #define DECR_DEPTH (DEPTH ? grn_bulk_truncate(ctx, LEVELS, GRN_BULK_VSIZE(LEVELS) - sizeof(uint32_t)) : 0)
33 #define INCR_LENGTH (DEPTH ? (GRN_UINT32_VALUE_AT(LEVELS, (DEPTH - 1)) += 2) : 0)
34 
35 static void
36 put_delimiter(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type)
37 {
38  uint32_t level = CURR_LEVEL;
39  switch (output_type) {
40  case GRN_CONTENT_JSON:
41  if (level < 2) { return; }
42  GRN_TEXT_PUTC(ctx, outbuf, ((level & 3) == 3) ? ':' : ',');
43  // if (DEPTH == 1 && ((level & 3) != 3)) { GRN_TEXT_PUTC(ctx, outbuf, '\n'); }
44  break;
45  case GRN_CONTENT_XML:
46  if (!DEPTH) { return; }
47  GRN_TEXT_PUTC(ctx, outbuf, '\n');
48  break;
49  case GRN_CONTENT_TSV:
50  if (level < 2) { return; }
51  if (DEPTH <= 2) {
52  GRN_TEXT_PUTC(ctx, outbuf, ((level & 3) == 3) ? '\t' : '\n');
53  } else {
54  GRN_TEXT_PUTC(ctx, outbuf, '\t');
55  }
56  case GRN_CONTENT_MSGPACK :
57  // do nothing
58  break;
59  case GRN_CONTENT_NONE:
60  break;
61  }
62 }
63 
64 void
66  const char *name, int nelements)
67 {
68  put_delimiter(ctx, outbuf, output_type);
69  switch (output_type) {
70  case GRN_CONTENT_JSON:
71  GRN_TEXT_PUTC(ctx, outbuf, '[');
72  break;
73  case GRN_CONTENT_XML:
74  GRN_TEXT_PUTC(ctx, outbuf, '<');
75  GRN_TEXT_PUTS(ctx, outbuf, name);
76  GRN_TEXT_PUTC(ctx, outbuf, '>');
77  grn_vector_add_element(ctx, &ctx->impl->names, name, strlen(name), 0, GRN_DB_SHORT_TEXT);
78  break;
79  case GRN_CONTENT_TSV:
80  if (DEPTH > 2) { GRN_TEXT_PUTS(ctx, outbuf, "[\t"); }
81  break;
82  case GRN_CONTENT_MSGPACK :
83 #ifdef GRN_WITH_MESSAGE_PACK
84  if (nelements < 0) {
86  "grn_output_array_open nelements (%d) for <%s>",
87  nelements,
88  name);
89  }
90  msgpack_pack_array(&ctx->impl->msgpacker, nelements);
91 #endif
92  break;
93  case GRN_CONTENT_NONE:
94  break;
95  }
96  INCR_DEPTH(0);
97 }
98 
99 void
101 {
102  switch (output_type) {
103  case GRN_CONTENT_JSON:
104  GRN_TEXT_PUTC(ctx, outbuf, ']');
105  break;
106  case GRN_CONTENT_TSV:
107  if (DEPTH > 3) {
108  if (CURR_LEVEL >= 2) { GRN_TEXT_PUTC(ctx, outbuf, '\t'); }
109  GRN_TEXT_PUTC(ctx, outbuf, ']');
110  }
111  break;
112  case GRN_CONTENT_XML:
113  {
114  const char *name;
115  unsigned int name_len = grn_vector_pop_element(ctx, &ctx->impl->names, &name, NULL, NULL);
116  GRN_TEXT_PUTS(ctx, outbuf, "</");
117  GRN_TEXT_PUT(ctx, outbuf, name, name_len);
118  GRN_TEXT_PUTC(ctx, outbuf, '>');
119  }
120  break;
121  case GRN_CONTENT_MSGPACK :
122  // do nothing
123  break;
124  case GRN_CONTENT_NONE:
125  break;
126  }
127  DECR_DEPTH;
128  INCR_LENGTH;
129 }
130 
131 void
133  const char *name, int nelements)
134 {
135  put_delimiter(ctx, outbuf, output_type);
136  switch (output_type) {
137  case GRN_CONTENT_JSON:
138  GRN_TEXT_PUTS(ctx, outbuf, "{");
139  break;
140  case GRN_CONTENT_XML:
141  GRN_TEXT_PUTC(ctx, outbuf, '<');
142  GRN_TEXT_PUTS(ctx, outbuf, name);
143  GRN_TEXT_PUTC(ctx, outbuf, '>');
144  grn_vector_add_element(ctx, &ctx->impl->names, name, strlen(name), 0, GRN_DB_SHORT_TEXT);
145  break;
146  case GRN_CONTENT_TSV:
147  if (DEPTH > 2) { GRN_TEXT_PUTS(ctx, outbuf, "{\t"); }
148  break;
149  case GRN_CONTENT_MSGPACK :
150 #ifdef GRN_WITH_MESSAGE_PACK
151  if (nelements < 0) {
152  GRN_LOG(ctx, GRN_LOG_DEBUG,
153  "grn_output_map_open nelements (%d) for <%s>",
154  nelements,
155  name);
156  }
157  msgpack_pack_map(&ctx->impl->msgpacker, nelements / 2);
158 #endif
159  break;
160  case GRN_CONTENT_NONE:
161  break;
162  }
163  INCR_DEPTH(1);
164 }
165 
166 void
168 {
169  switch (output_type) {
170  case GRN_CONTENT_JSON:
171  GRN_TEXT_PUTS(ctx, outbuf, "}");
172  break;
173  case GRN_CONTENT_TSV:
174  if (DEPTH > 3) {
175  if (CURR_LEVEL >= 2) { GRN_TEXT_PUTC(ctx, outbuf, '\t'); }
176  GRN_TEXT_PUTC(ctx, outbuf, '}');
177  }
178  break;
179  case GRN_CONTENT_XML:
180  {
181  const char *name;
182  unsigned int name_len = grn_vector_pop_element(ctx, &ctx->impl->names, &name, NULL, NULL);
183  GRN_TEXT_PUTS(ctx, outbuf, "</");
184  GRN_TEXT_PUT(ctx, outbuf, name, name_len);
185  GRN_TEXT_PUTC(ctx, outbuf, '>');
186  }
187  break;
188  case GRN_CONTENT_MSGPACK :
189  // do nothing
190  break;
191  case GRN_CONTENT_NONE:
192  break;
193  }
194  DECR_DEPTH;
195  INCR_LENGTH;
196 }
197 
198 void
199 grn_output_int32(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type, int value)
200 {
201  put_delimiter(ctx, outbuf, output_type);
202  switch (output_type) {
203  case GRN_CONTENT_JSON:
204  grn_text_itoa(ctx, outbuf, value);
205  break;
206  case GRN_CONTENT_TSV:
207  grn_text_itoa(ctx, outbuf, value);
208  break;
209  case GRN_CONTENT_XML:
210  GRN_TEXT_PUTS(ctx, outbuf, "<INT>");
211  grn_text_itoa(ctx, outbuf, value);
212  GRN_TEXT_PUTS(ctx, outbuf, "</INT>");
213  break;
214  case GRN_CONTENT_MSGPACK :
215 #ifdef GRN_WITH_MESSAGE_PACK
216  msgpack_pack_int32(&ctx->impl->msgpacker, value);
217 #endif
218  break;
219  case GRN_CONTENT_NONE:
220  break;
221  }
222  INCR_LENGTH;
223 }
224 
225 void
226 grn_output_int64(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type, int64_t value)
227 {
228  put_delimiter(ctx, outbuf, output_type);
229  switch (output_type) {
230  case GRN_CONTENT_JSON:
231  grn_text_lltoa(ctx, outbuf, value);
232  break;
233  case GRN_CONTENT_TSV:
234  grn_text_lltoa(ctx, outbuf, value);
235  break;
236  case GRN_CONTENT_XML:
237  GRN_TEXT_PUTS(ctx, outbuf, "<INT>");
238  grn_text_lltoa(ctx, outbuf, value);
239  GRN_TEXT_PUTS(ctx, outbuf, "</INT>");
240  break;
241  case GRN_CONTENT_MSGPACK :
242 #ifdef GRN_WITH_MESSAGE_PACK
243  msgpack_pack_int64(&ctx->impl->msgpacker, value);
244 #endif
245  break;
246  case GRN_CONTENT_NONE:
247  break;
248  }
249  INCR_LENGTH;
250 }
251 
252 void
253 grn_output_uint64(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type, int64_t value)
254 {
255  put_delimiter(ctx, outbuf, output_type);
256  switch (output_type) {
257  case GRN_CONTENT_JSON:
258  grn_text_ulltoa(ctx, outbuf, value);
259  break;
260  case GRN_CONTENT_TSV:
261  grn_text_ulltoa(ctx, outbuf, value);
262  break;
263  case GRN_CONTENT_XML:
264  GRN_TEXT_PUTS(ctx, outbuf, "<INT>");
265  grn_text_ulltoa(ctx, outbuf, value);
266  GRN_TEXT_PUTS(ctx, outbuf, "</INT>");
267  break;
268  case GRN_CONTENT_MSGPACK :
269 #ifdef GRN_WITH_MESSAGE_PACK
270  msgpack_pack_uint64(&ctx->impl->msgpacker, value);
271 #endif
272  break;
273  case GRN_CONTENT_NONE:
274  break;
275  }
276  INCR_LENGTH;
277 }
278 
279 void
280 grn_output_float(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type, double value)
281 {
282  put_delimiter(ctx, outbuf, output_type);
283  switch (output_type) {
284  case GRN_CONTENT_JSON:
285  grn_text_ftoa(ctx, outbuf, value);
286  break;
287  case GRN_CONTENT_TSV:
288  grn_text_ftoa(ctx, outbuf, value);
289  break;
290  case GRN_CONTENT_XML:
291  GRN_TEXT_PUTS(ctx, outbuf, "<FLOAT>");
292  grn_text_ftoa(ctx, outbuf, value);
293  GRN_TEXT_PUTS(ctx, outbuf, "</FLOAT>");
294  break;
295  case GRN_CONTENT_MSGPACK :
296 #ifdef GRN_WITH_MESSAGE_PACK
297  msgpack_pack_double(&ctx->impl->msgpacker, value);
298 #endif
299  break;
300  case GRN_CONTENT_NONE:
301  break;
302  }
303  INCR_LENGTH;
304 }
305 
306 void
307 grn_output_str(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
308  const char *value, size_t value_len)
309 {
310  put_delimiter(ctx, outbuf, output_type);
311  switch (output_type) {
312  case GRN_CONTENT_JSON:
313  grn_text_esc(ctx, outbuf, value, value_len);
314  break;
315  case GRN_CONTENT_TSV:
316  grn_text_esc(ctx, outbuf, value, value_len);
317  break;
318  case GRN_CONTENT_XML:
319  GRN_TEXT_PUTS(ctx, outbuf, "<TEXT>");
320  grn_text_escape_xml(ctx, outbuf, value, value_len);
321  GRN_TEXT_PUTS(ctx, outbuf, "</TEXT>");
322  break;
323  case GRN_CONTENT_MSGPACK :
324 #ifdef GRN_WITH_MESSAGE_PACK
325  msgpack_pack_raw(&ctx->impl->msgpacker, value_len);
326  msgpack_pack_raw_body(&ctx->impl->msgpacker, value, value_len);
327 #endif
328  break;
329  case GRN_CONTENT_NONE:
330  break;
331  }
332  INCR_LENGTH;
333 }
334 
335 void
336 grn_output_cstr(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
337  const char *value)
338 {
339  grn_output_str(ctx, outbuf, output_type, value, strlen(value));
340 }
341 
342 void
343 grn_output_bool(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type, grn_bool value)
344 {
345  put_delimiter(ctx, outbuf, output_type);
346  switch (output_type) {
347  case GRN_CONTENT_JSON:
348  GRN_TEXT_PUTS(ctx, outbuf, value ? "true" : "false");
349  break;
350  case GRN_CONTENT_TSV:
351  GRN_TEXT_PUTS(ctx, outbuf, value ? "true" : "false");
352  break;
353  case GRN_CONTENT_XML:
354  GRN_TEXT_PUTS(ctx, outbuf, "<BOOL>");
355  GRN_TEXT_PUTS(ctx, outbuf, value ? "true" : "false");
356  GRN_TEXT_PUTS(ctx, outbuf, "</BOOL>");
357  break;
358  case GRN_CONTENT_MSGPACK :
359 #ifdef GRN_WITH_MESSAGE_PACK
360  if (value) {
361  msgpack_pack_true(&ctx->impl->msgpacker);
362  } else {
363  msgpack_pack_false(&ctx->impl->msgpacker);
364  }
365 #endif
366  break;
367  case GRN_CONTENT_NONE:
368  break;
369  }
370  INCR_LENGTH;
371 }
372 
373 static inline void
374 grn_output_null(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type)
375 {
376  put_delimiter(ctx, outbuf, output_type);
377  switch (output_type) {
378  case GRN_CONTENT_JSON:
379  GRN_TEXT_PUTS(ctx, outbuf, "null");
380  break;
381  case GRN_CONTENT_TSV:
382  break;
383  case GRN_CONTENT_XML:
384  GRN_TEXT_PUTS(ctx, outbuf, "<NULL/>");
385  break;
386  case GRN_CONTENT_MSGPACK :
387 #ifdef GRN_WITH_MESSAGE_PACK
388  msgpack_pack_nil(&ctx->impl->msgpacker);
389 #endif
390  break;
391  case GRN_CONTENT_NONE:
392  break;
393  }
394  INCR_LENGTH;
395 }
396 
397 static inline void
398 grn_output_bulk_void(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
399  const char *value, size_t value_len)
400 {
401  if (value_len == sizeof(grn_id) && *(grn_id *)value == GRN_ID_NIL) {
402  grn_output_null(ctx, outbuf, output_type);
403  } else {
404  grn_output_str(ctx, outbuf, output_type, value, value_len);
405  }
406 }
407 
408 void
409 grn_output_time(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type, int64_t value)
410 {
411  double dv = value;
412  dv /= 1000000.0;
413  put_delimiter(ctx, outbuf, output_type);
414  switch (output_type) {
415  case GRN_CONTENT_JSON:
416  grn_text_ftoa(ctx, outbuf, dv);
417  break;
418  case GRN_CONTENT_TSV:
419  grn_text_ftoa(ctx, outbuf, dv);
420  break;
421  case GRN_CONTENT_XML:
422  GRN_TEXT_PUTS(ctx, outbuf, "<DATE>");
423  grn_text_ftoa(ctx, outbuf, dv);
424  GRN_TEXT_PUTS(ctx, outbuf, "</DATE>");
425  break;
426  case GRN_CONTENT_MSGPACK :
427 #ifdef GRN_WITH_MESSAGE_PACK
428  msgpack_pack_double(&ctx->impl->msgpacker, dv);
429 #endif
430  break;
431  case GRN_CONTENT_NONE:
432  break;
433  }
434  INCR_LENGTH;
435 }
436 
437 void
439  grn_geo_point *value)
440 {
441  put_delimiter(ctx, outbuf, output_type);
442  switch (output_type) {
443  case GRN_CONTENT_JSON:
444  if (value) {
445  GRN_TEXT_PUTC(ctx, outbuf, '"');
446  grn_text_itoa(ctx, outbuf, value->latitude);
447  GRN_TEXT_PUTC(ctx, outbuf, 'x');
448  grn_text_itoa(ctx, outbuf, value->longitude);
449  GRN_TEXT_PUTC(ctx, outbuf, '"');
450  } else {
451  GRN_TEXT_PUTS(ctx, outbuf, "null");
452  }
453  break;
454  case GRN_CONTENT_TSV:
455  if (value) {
456  GRN_TEXT_PUTC(ctx, outbuf, '"');
457  grn_text_itoa(ctx, outbuf, value->latitude);
458  GRN_TEXT_PUTC(ctx, outbuf, 'x');
459  grn_text_itoa(ctx, outbuf, value->longitude);
460  GRN_TEXT_PUTC(ctx, outbuf, '"');
461  } else {
462  GRN_TEXT_PUTS(ctx, outbuf, "\"\"");
463  }
464  break;
465  case GRN_CONTENT_XML:
466  GRN_TEXT_PUTS(ctx, outbuf, "<GEO_POINT>");
467  if (value) {
468  grn_text_itoa(ctx, outbuf, value->latitude);
469  GRN_TEXT_PUTC(ctx, outbuf, 'x');
470  grn_text_itoa(ctx, outbuf, value->longitude);
471  }
472  GRN_TEXT_PUTS(ctx, outbuf, "</GEO_POINT>");
473  break;
474  case GRN_CONTENT_MSGPACK :
475 #ifdef GRN_WITH_MESSAGE_PACK
476  if (value) {
477  grn_obj buf;
478  GRN_TEXT_INIT(&buf, 0);
479  grn_text_itoa(ctx, &buf, value->latitude);
480  GRN_TEXT_PUTC(ctx, &buf, 'x');
481  grn_text_itoa(ctx, &buf, value->longitude);
482  msgpack_pack_raw(&ctx->impl->msgpacker, GRN_TEXT_LEN(&buf));
483  msgpack_pack_raw_body(&ctx->impl->msgpacker,
484  GRN_TEXT_VALUE(&buf),
485  GRN_TEXT_LEN(&buf));
486  grn_obj_close(ctx, &buf);
487  } else {
488  msgpack_pack_nil(&ctx->impl->msgpacker);
489  }
490 #endif
491  break;
492  case GRN_CONTENT_NONE:
493  break;
494  }
495  INCR_LENGTH;
496 }
497 
498 static void
499 grn_text_atoj(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
500  grn_obj *obj, grn_id id)
501 {
502  uint32_t vs;
503  grn_obj buf;
504  if (obj->header.type == GRN_ACCESSOR) {
505  grn_accessor *a = (grn_accessor *)obj;
506  GRN_TEXT_INIT(&buf, 0);
507  for (;;) {
508  buf.header.domain = grn_obj_get_range(ctx, obj);
509  GRN_BULK_REWIND(&buf);
510  switch (a->action) {
511  case GRN_ACCESSOR_GET_ID :
512  GRN_UINT32_PUT(ctx, &buf, id);
514  break;
515  case GRN_ACCESSOR_GET_KEY :
516  grn_table_get_key2(ctx, a->obj, id, &buf);
517  buf.header.domain = DB_OBJ(a->obj)->header.domain;
518  break;
520  grn_obj_get_value(ctx, a->obj, id, &buf);
521  buf.header.domain = DB_OBJ(a->obj)->range;
522  break;
524  grn_obj_get_value(ctx, a->obj, id, &buf);
525  {
526  grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
527  GRN_INT32_PUT(ctx, &buf, ri->score);
528  }
529  buf.header.domain = GRN_DB_INT32;
530  break;
532  {
533  grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
534  GRN_INT32_PUT(ctx, &buf, ri->n_subrecs);
535  }
536  buf.header.domain = GRN_DB_INT32;
537  break;
540  if (a->next) {
541  grn_id *idp;
542  grn_obj_get_value(ctx, a->obj, id, &buf);
543  idp = (grn_id *)GRN_BULK_HEAD(&buf);
544  vs = GRN_BULK_VSIZE(&buf) / sizeof(grn_id);
545  grn_output_array_open(ctx, outbuf, output_type, "VECTOR", vs);
546  for (; vs--; idp++) {
547  grn_text_atoj(ctx, outbuf, output_type, (grn_obj *)a->next, *idp);
548  }
549  grn_output_array_close(ctx, outbuf, output_type);
550  } else {
551  grn_text_atoj(ctx, outbuf, output_type, a->obj, id);
552  }
553  goto exit;
554  } else {
555  grn_obj_get_value(ctx, a->obj, id, &buf);
556  }
557  break;
559  /* todo */
560  break;
561  case GRN_ACCESSOR_LOOKUP :
562  /* todo */
563  break;
564  case GRN_ACCESSOR_FUNCALL :
565  /* todo */
566  break;
567  }
568  if (a->next) {
569  a = a->next;
570  if (GRN_BULK_VSIZE(&buf) >= sizeof(grn_id)) {
571  id = *((grn_id *)GRN_BULK_HEAD(&buf));
572  } else {
573  id = GRN_ID_NIL;
574  }
575  } else {
576  break;
577  }
578  }
579  } else {
580  switch (obj->header.type) {
581  case GRN_COLUMN_FIX_SIZE :
582  GRN_VALUE_FIX_SIZE_INIT(&buf, 0, DB_OBJ(obj)->range);
583  break;
584  case GRN_COLUMN_VAR_SIZE :
586  grn_obj *range = grn_ctx_at(ctx, DB_OBJ(obj)->range);
587  if (range->header.flags & GRN_OBJ_KEY_VAR_SIZE) {
588  GRN_VALUE_VAR_SIZE_INIT(&buf, GRN_OBJ_VECTOR, DB_OBJ(obj)->range);
589  } else {
590  GRN_VALUE_FIX_SIZE_INIT(&buf, GRN_OBJ_VECTOR, DB_OBJ(obj)->range);
591  }
592  } else {
593  GRN_VALUE_VAR_SIZE_INIT(&buf, 0, DB_OBJ(obj)->range);
594  }
595  break;
596  case GRN_COLUMN_INDEX :
597  GRN_UINT32_INIT(&buf, 0);
598  break;
599  default:
600  GRN_TEXT_INIT(&buf, 0);
601  break;
602  }
603  grn_obj_get_value(ctx, obj, id, &buf);
604  }
605  grn_output_obj(ctx, outbuf, output_type, &buf, NULL);
606 exit :
607  grn_obj_close(ctx, &buf);
608 }
609 
610 static inline void
611 grn_output_void(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
612  grn_obj *bulk, grn_obj_format *format)
613 {
614  grn_output_null(ctx, outbuf, output_type);
615 }
616 
617 static inline void
618 grn_output_bulk(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
619  grn_obj *bulk, grn_obj_format *format)
620 {
621  grn_obj buf;
622  GRN_TEXT_INIT(&buf, 0);
623  switch (bulk->header.domain) {
624  case GRN_DB_VOID :
625  grn_output_bulk_void(ctx, outbuf, output_type, GRN_BULK_HEAD(bulk), GRN_BULK_VSIZE(bulk));
626  break;
627  case GRN_DB_SHORT_TEXT :
628  case GRN_DB_TEXT :
629  case GRN_DB_LONG_TEXT :
630  grn_output_str(ctx, outbuf, output_type, GRN_BULK_HEAD(bulk), GRN_BULK_VSIZE(bulk));
631  break;
632  case GRN_DB_BOOL :
633  grn_output_bool(ctx, outbuf, output_type,
634  GRN_BULK_VSIZE(bulk) ? GRN_UINT8_VALUE(bulk) : 0);
635  break;
636  case GRN_DB_INT8 :
637  grn_output_int32(ctx, outbuf, output_type,
638  GRN_BULK_VSIZE(bulk) ? GRN_INT8_VALUE(bulk) : 0);
639  break;
640  case GRN_DB_UINT8 :
641  grn_output_int32(ctx, outbuf, output_type,
642  GRN_BULK_VSIZE(bulk) ? GRN_UINT8_VALUE(bulk) : 0);
643  break;
644  case GRN_DB_INT16 :
645  grn_output_int32(ctx, outbuf, output_type,
646  GRN_BULK_VSIZE(bulk) ? GRN_INT16_VALUE(bulk) : 0);
647  break;
648  case GRN_DB_UINT16 :
649  grn_output_int32(ctx, outbuf, output_type,
650  GRN_BULK_VSIZE(bulk) ? GRN_UINT16_VALUE(bulk) : 0);
651  break;
652  case GRN_DB_INT32 :
653  grn_output_int32(ctx, outbuf, output_type,
654  GRN_BULK_VSIZE(bulk) ? GRN_INT32_VALUE(bulk) : 0);
655  break;
656  case GRN_DB_UINT32 :
657  grn_output_int64(ctx, outbuf, output_type,
658  GRN_BULK_VSIZE(bulk) ? GRN_UINT32_VALUE(bulk) : 0);
659  break;
660  case GRN_DB_INT64 :
661  grn_output_int64(ctx, outbuf, output_type,
662  GRN_BULK_VSIZE(bulk) ? GRN_INT64_VALUE(bulk) : 0);
663  break;
664  case GRN_DB_UINT64 :
665  grn_output_uint64(ctx, outbuf, output_type,
666  GRN_BULK_VSIZE(bulk) ? GRN_UINT64_VALUE(bulk) : 0);
667  break;
668  case GRN_DB_FLOAT :
669  grn_output_float(ctx, outbuf, output_type,
670  GRN_BULK_VSIZE(bulk) ? GRN_FLOAT_VALUE(bulk) : 0);
671  break;
672  case GRN_DB_TIME :
673  grn_output_time(ctx, outbuf, output_type,
674  GRN_BULK_VSIZE(bulk) ? GRN_INT64_VALUE(bulk) : 0);
675  break;
678  grn_output_geo_point(ctx, outbuf, output_type,
679  GRN_BULK_VSIZE(bulk) ? (grn_geo_point *)GRN_BULK_HEAD(bulk) : NULL);
680  break;
681  default :
682  if (format) {
683  int j;
684  int ncolumns = GRN_BULK_VSIZE(&format->columns)/sizeof(grn_obj *);
685  grn_id id = GRN_RECORD_VALUE(bulk);
686  grn_obj **columns = (grn_obj **)GRN_BULK_HEAD(&format->columns);
687  if (format->flags & GRN_OBJ_FORMAT_WITH_COLUMN_NAMES) {
688  grn_output_array_open(ctx, outbuf, output_type, "COLUMNS", ncolumns);
689  for (j = 0; j < ncolumns; j++) {
690  grn_id range_id;
691  grn_output_array_open(ctx, outbuf, output_type, "COLUMN", 2);
692  GRN_BULK_REWIND(&buf);
693  grn_column_name_(ctx, columns[j], &buf);
694  grn_output_obj(ctx, outbuf, output_type, &buf, NULL);
695  /* column range */
696  range_id = grn_obj_get_range(ctx, columns[j]);
697  if (range_id == GRN_ID_NIL) {
698  GRN_TEXT_PUTS(ctx, outbuf, "null");
699  } else {
700  int name_len;
701  grn_obj *range_obj;
702  char name_buf[GRN_TABLE_MAX_KEY_SIZE];
703 
704  range_obj = grn_ctx_at(ctx, range_id);
705  name_len = grn_obj_name(ctx, range_obj, name_buf,
707  GRN_BULK_REWIND(&buf);
708  GRN_TEXT_PUT(ctx, &buf, name_buf, name_len);
709  grn_output_obj(ctx, outbuf, output_type, &buf, NULL);
710  }
711  grn_output_array_close(ctx, outbuf, output_type);
712  }
713  grn_output_array_close(ctx, outbuf, output_type);
714  }
715  grn_output_array_open(ctx, outbuf, output_type, "HIT", ncolumns);
716  for (j = 0; j < ncolumns; j++) {
717  grn_text_atoj(ctx, outbuf, output_type, columns[j], id);
718  }
719  grn_output_array_close(ctx, outbuf, output_type);
720  } else {
721  grn_obj *table = grn_ctx_at(ctx, bulk->header.domain);
722  grn_id id = GRN_RECORD_VALUE(bulk);
723  if (table && table->header.type != GRN_TABLE_NO_KEY) {
724  grn_obj *accessor = grn_obj_column(ctx, table, "_key", 4);
725  if (accessor) {
726  if (id == GRN_ID_NIL) {
727  grn_obj_reinit_for(ctx, &buf, accessor);
728  } else {
729  grn_obj_get_value(ctx, accessor, id, &buf);
730  }
731  grn_obj_unlink(ctx, accessor);
732  }
733  grn_output_obj(ctx, outbuf, output_type, &buf, format);
734  } else {
735  grn_output_int64(ctx, outbuf, output_type, id);
736  }
737  }
738  break;
739  }
740  GRN_OBJ_FIN(ctx, &buf);
741 }
742 
743 static inline void
744 grn_output_uvector(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
745  grn_obj *uvector, grn_obj_format *format)
746 {
747  grn_obj buf;
748  GRN_TEXT_INIT(&buf, 0);
749  if (format) {
750  int i, j;
751  grn_id *v = (grn_id *)GRN_BULK_HEAD(uvector), *ve = (grn_id *)GRN_BULK_CURR(uvector);
752  int ncolumns = GRN_BULK_VSIZE(&format->columns) / sizeof(grn_obj *);
753  grn_obj **columns = (grn_obj **)GRN_BULK_HEAD(&format->columns);
754  grn_output_array_open(ctx, outbuf, output_type, "RESULTSET", -1);
755  grn_output_array_open(ctx, outbuf, output_type, "NHITS", 1);
756  grn_text_itoa(ctx, outbuf, ve - v);
757  grn_output_array_close(ctx, outbuf, output_type);
758  if (v < ve) {
759  if (format->flags & GRN_OBJ_FORMAT_WITH_COLUMN_NAMES) {
760  grn_output_array_open(ctx, outbuf, output_type, "COLUMNS", -1);
761  for (j = 0; j < ncolumns; j++) {
762  grn_id range_id;
763  grn_output_array_open(ctx, outbuf, output_type, "COLUMN", -1);
764  GRN_BULK_REWIND(&buf);
765  grn_column_name_(ctx, columns[j], &buf);
766  grn_output_obj(ctx, outbuf, output_type, &buf, NULL);
767  /* column range */
768  range_id = grn_obj_get_range(ctx, columns[j]);
769  if (range_id == GRN_ID_NIL) {
770  GRN_TEXT_PUTS(ctx, outbuf, "null");
771  } else {
772  int name_len;
773  grn_obj *range_obj;
774  char name_buf[GRN_TABLE_MAX_KEY_SIZE];
775 
776  range_obj = grn_ctx_at(ctx, range_id);
777  name_len = grn_obj_name(ctx, range_obj, name_buf,
779  GRN_BULK_REWIND(&buf);
780  GRN_TEXT_PUT(ctx, &buf, name_buf, name_len);
781  grn_output_obj(ctx, outbuf, output_type, &buf, NULL);
782  }
783  grn_output_array_close(ctx, outbuf, output_type);
784  }
785  grn_output_array_close(ctx, outbuf, output_type);
786  }
787  for (i = 0;; i++) {
788  grn_output_array_open(ctx, outbuf, output_type, "HITS", -1);
789  for (j = 0; j < ncolumns; j++) {
790  GRN_BULK_REWIND(&buf);
791  grn_obj_get_value(ctx, columns[j], *v, &buf);
792  grn_output_obj(ctx, outbuf, output_type, &buf, NULL);
793  }
794  grn_output_array_close(ctx, outbuf, output_type);
795  v++;
796  if (v < ve) {
797 
798  } else {
799  break;
800  }
801  }
802  }
803  grn_output_array_close(ctx, outbuf, output_type);
804  } else {
805  grn_obj *range = grn_ctx_at(ctx, uvector->header.domain);
806  if (range && range->header.type == GRN_TYPE) {
807  int value_size = ((struct _grn_type *)range)->obj.range;
808  char *v = (char *)GRN_BULK_HEAD(uvector),
809  *ve = (char *)GRN_BULK_CURR(uvector);
810  grn_output_array_open(ctx, outbuf, output_type, "VECTOR", -1);
811  if (v < ve) {
812  for (;;) {
813  grn_obj value;
814  GRN_OBJ_INIT(&value, GRN_BULK, 0, uvector->header.domain);
815  grn_bulk_write_from(ctx, &value, v, 0, value_size);
816  grn_output_obj(ctx, outbuf, output_type, &value, NULL);
817 
818  v += value_size;
819  if (v < ve) {
820 
821  } else {
822  break;
823  }
824  }
825  }
826  grn_output_array_close(ctx, outbuf, output_type);
827  } else {
828  grn_id *v = (grn_id *)GRN_BULK_HEAD(uvector),
829  *ve = (grn_id *)GRN_BULK_CURR(uvector);
830  grn_output_array_open(ctx, outbuf, output_type, "VECTOR", ve - v);
831  if (v < ve) {
832  grn_obj key;
833  GRN_OBJ_INIT(&key, GRN_BULK, 0, range->header.domain);
834  for (;;) {
835  if (range->header.type != GRN_TABLE_NO_KEY) {
836  grn_table_get_key2(ctx, range, *v, &key);
837  grn_output_obj(ctx, outbuf, output_type, &key, NULL);
838  GRN_BULK_REWIND(&key);
839  } else {
840  grn_obj id;
841  GRN_UINT32_INIT(&id, 0);
842  GRN_UINT32_SET(ctx, &id, *v);
843  grn_output_obj(ctx, outbuf, output_type, &id, NULL);
844  GRN_OBJ_FIN(ctx, &id);
845  }
846  v++;
847  if (v < ve) {
848 
849  } else {
850  break;
851  }
852  }
853  GRN_OBJ_FIN(ctx, &key);
854  }
855  grn_output_array_close(ctx, outbuf, output_type);
856  }
857  }
858  GRN_OBJ_FIN(ctx, &buf);
859 }
860 
861 static inline void
862 grn_output_vector(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
863  grn_obj *vector, grn_obj_format *format)
864 {
865  if (vector->header.domain == GRN_DB_VOID) {
866  ERR(GRN_INVALID_ARGUMENT, "invalid obj->header.domain");
867  }
868  if (format) {
870  "cannot print GRN_VECTOR using grn_obj_format");
871  } else {
872  unsigned int i, n;
873  grn_obj value;
874  GRN_VOID_INIT(&value);
875  n = grn_vector_size(ctx, vector);
876  grn_output_array_open(ctx, outbuf, output_type, "VECTOR", n);
877  for (i = 0; i < n; i++) {
878  const char *_value;
879  unsigned int weight, length;
880  grn_id domain;
881 
882  length = grn_vector_get_element(ctx, vector, i,
883  &_value, &weight, &domain);
884  if (domain != GRN_DB_VOID) {
885  grn_obj_reinit(ctx, &value, domain, 0);
886  } else {
887  grn_obj_reinit(ctx, &value, vector->header.domain, 0);
888  }
889  grn_bulk_write(ctx, &value, _value, length);
890  grn_output_obj(ctx, outbuf, output_type, &value, NULL);
891  }
892  grn_output_array_close(ctx, outbuf, output_type);
893  GRN_OBJ_FIN(ctx, &value);
894  }
895 }
896 
897 static inline void
898 grn_output_pvector(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
899  grn_obj *pvector, grn_obj_format *format)
900 {
901  if (format) {
903  "cannot print GRN_PVECTOR using grn_obj_format");
904  } else {
905  unsigned int i, n;
906  grn_output_array_open(ctx, outbuf, output_type, "VECTOR", -1);
907  n = GRN_BULK_VSIZE(pvector) / sizeof(grn_obj *);
908  for (i = 0; i < n; i++) {
909  grn_obj *value;
910 
911  value = GRN_PTR_VALUE_AT(pvector, i);
912  grn_output_obj(ctx, outbuf, output_type, value, NULL);
913  }
914  grn_output_array_close(ctx, outbuf, output_type);
915  }
916 }
917 
918 static inline void
919 grn_output_table_header(grn_ctx *ctx, grn_obj *outbuf,
920  grn_content_type output_type,
921  grn_obj *table, grn_obj_format *format)
922 {
923  grn_output_array_open(ctx, outbuf, output_type, "NHITS", 1);
924  if (output_type == GRN_CONTENT_XML) {
925  grn_text_itoa(ctx, outbuf, format->nhits);
926  } else {
927  grn_output_int32(ctx, outbuf, output_type, format->nhits);
928  }
929  grn_output_array_close(ctx, outbuf, output_type);
930 }
931 
932 static inline int
933 count_n_elements_in_expression(grn_ctx *ctx, grn_obj *expression)
934 {
935  int n_elements = 0;
936  grn_bool is_first_comma = GRN_TRUE;
937  grn_expr *expr = (grn_expr *)expression;
938  grn_expr_code *code;
939  grn_expr_code *code_end = expr->codes + expr->codes_curr;
940 
941  for (code = expr->codes; code < code_end; code++) {
942  if (code->op == GRN_OP_COMMA) {
943  n_elements++;
944  if (is_first_comma) {
945  n_elements++;
946  is_first_comma = GRN_FALSE;
947  }
948  }
949  }
950 
951  return n_elements;
952 }
953 
954 static inline int
955 count_used_n_codes(grn_ctx *ctx, grn_expr_code *start, grn_expr_code *target)
956 {
957  int n_codes;
958  int i, n_args;
959  grn_bool have_proc_push_code = GRN_FALSE;
960  grn_expr_code *sub_code;
961 
962  if (start == target) {
963  return 0;
964  }
965 
966  n_args = target->nargs;
967  if (target->op == GRN_OP_CALL) {
968  if (!target->value) {
969  have_proc_push_code = GRN_TRUE;
970  }
971  } else {
972  if (target->value) {
973  n_args--;
974  if (n_args == 0) {
975  return 1;
976  }
977  }
978  }
979 
980  n_codes = 1;
981  sub_code = target - 1;
982  for (i = 0; i < n_args; i++) {
983  int sub_n_codes;
984  sub_n_codes = count_used_n_codes(ctx, start, sub_code);
985  n_codes += sub_n_codes;
986  sub_code -= sub_n_codes;
987  if (sub_code < start) {
988  /* TODO: report error */
989  return 0;
990  }
991  }
992 
993  if (have_proc_push_code) {
994  n_codes++;
995  sub_code--;
996  if (sub_code < start) {
997  /* TODO: report error */
998  return 0;
999  }
1000  }
1001 
1002  return n_codes;
1003 }
1004 
1005 static inline void
1006 grn_output_table_column(grn_ctx *ctx, grn_obj *outbuf,
1007  grn_content_type output_type,
1008  grn_obj *column, grn_obj *buf)
1009 {
1010  grn_output_array_open(ctx, outbuf, output_type, "COLUMN", 2);
1011  if (column) {
1012  grn_id range_id;
1013  GRN_BULK_REWIND(buf);
1014  grn_column_name_(ctx, column, buf);
1015  grn_output_obj(ctx, outbuf, output_type, buf, NULL);
1016  range_id = grn_obj_get_range(ctx, column);
1017  if (range_id == GRN_ID_NIL) {
1018  grn_output_cstr(ctx, outbuf, output_type, "null");
1019  } else {
1020  int name_len;
1021  grn_obj *range_obj;
1022  char name_buf[GRN_TABLE_MAX_KEY_SIZE];
1023 
1024  range_obj = grn_ctx_at(ctx, range_id);
1025  name_len = grn_obj_name(ctx, range_obj, name_buf,
1027  GRN_BULK_REWIND(buf);
1028  GRN_TEXT_PUT(ctx, buf, name_buf, name_len);
1029  grn_output_obj(ctx, outbuf, output_type, buf, NULL);
1030  }
1031  } else {
1032  grn_output_cstr(ctx, outbuf, output_type, "");
1033  grn_output_cstr(ctx, outbuf, output_type, "");
1034  }
1035  grn_output_array_close(ctx, outbuf, output_type);
1036 }
1037 
1038 static inline void
1039 grn_output_table_columns_by_expression(grn_ctx *ctx, grn_obj *outbuf,
1040  grn_content_type output_type,
1041  grn_obj *table, grn_obj_format *format,
1042  grn_obj *buf)
1043 {
1044  int n_elements;
1045  int previous_comma_offset = -1;
1046  grn_bool is_first_comma = GRN_TRUE;
1047  grn_bool have_comma = GRN_FALSE;
1048  grn_expr *expr = (grn_expr *)format->expression;
1049  grn_expr_code *code;
1050  grn_expr_code *code_end = expr->codes + expr->codes_curr;
1051 
1052  n_elements = count_n_elements_in_expression(ctx, format->expression);
1053 
1054  grn_output_array_open(ctx, outbuf, output_type, "COLUMNS", n_elements);
1055  for (code = expr->codes; code < code_end; code++) {
1056  int code_start_offset;
1057 
1058  if (code->op != GRN_OP_COMMA) {
1059  continue;
1060  }
1061 
1062  have_comma = GRN_TRUE;
1063  code_start_offset = previous_comma_offset + 1;
1064  if (is_first_comma) {
1065  int code_end_offset;
1066  int n_used_code;
1067 
1068  grn_output_table_column(ctx, outbuf, output_type,
1069  expr->codes[0].value, buf);
1070 
1071  code_end_offset = code - expr->codes - code_start_offset - 1;
1072  n_used_code = count_used_n_codes(ctx,
1073  expr->codes,
1074  expr->codes + code_end_offset);
1075  code_start_offset = code_end_offset - n_used_code + 1;
1076  is_first_comma = GRN_FALSE;
1077  }
1078 
1079  grn_output_table_column(ctx, outbuf, output_type,
1080  expr->codes[code_start_offset].value, buf);
1081  previous_comma_offset = code - expr->codes;
1082  }
1083 
1084  if (!have_comma && expr->codes_curr > 0) {
1085  grn_output_table_column(ctx, outbuf, output_type,
1086  expr->codes[0].value, buf);
1087  }
1088 
1089  grn_output_array_close(ctx, outbuf, output_type);
1090 }
1091 
1092 static inline void
1093 grn_output_table_columns_by_columns(grn_ctx *ctx, grn_obj *outbuf,
1094  grn_content_type output_type,
1095  grn_obj *table, grn_obj_format *format,
1096  grn_obj *buf)
1097 {
1098  int i;
1099  int ncolumns = GRN_BULK_VSIZE(&format->columns)/sizeof(grn_obj *);
1100  grn_obj **columns = (grn_obj **)GRN_BULK_HEAD(&format->columns);
1101 
1102  grn_output_array_open(ctx, outbuf, output_type, "COLUMNS", ncolumns);
1103  for (i = 0; i < ncolumns; i++) {
1104  grn_output_table_column(ctx, outbuf, output_type, columns[i], buf);
1105  }
1106  grn_output_array_close(ctx, outbuf, output_type);
1107 }
1108 
1109 static inline void
1110 grn_output_table_columns(grn_ctx *ctx, grn_obj *outbuf,
1111  grn_content_type output_type,
1112  grn_obj *table, grn_obj_format *format)
1113 {
1114  grn_obj buf;
1115 
1116  GRN_TEXT_INIT(&buf, 0);
1117  if (format->expression) {
1118  grn_output_table_columns_by_expression(ctx, outbuf, output_type,
1119  table, format, &buf);
1120  } else {
1121  grn_output_table_columns_by_columns(ctx, outbuf, output_type,
1122  table, format, &buf);
1123  }
1124  GRN_OBJ_FIN(ctx, &buf);
1125 }
1126 
1127 static inline void
1128 grn_output_table_record_by_expression(grn_ctx *ctx, grn_obj *outbuf,
1129  grn_content_type output_type,
1130  grn_obj *expression)
1131 {
1132  grn_obj *result;
1133  result = grn_expr_exec(ctx, expression, 0);
1134  if (result) {
1135  grn_output_obj(ctx, outbuf, output_type, result, NULL);
1136  } else {
1137  grn_output_cstr(ctx, outbuf, output_type, ctx->errbuf);
1138  }
1139 }
1140 
1141 static inline void
1142 grn_output_table_records_by_expression(grn_ctx *ctx, grn_obj *outbuf,
1143  grn_content_type output_type,
1144  grn_table_cursor *tc,
1145  grn_obj_format *format)
1146 {
1147  int n_elements = 0;
1148  grn_id id;
1149  grn_obj *record;
1150  grn_expr *expr = (grn_expr *)format->expression;
1151  grn_expr_code *code;
1152  grn_expr_code *code_end = expr->codes + expr->codes_curr;
1153 
1154  n_elements = count_n_elements_in_expression(ctx, format->expression);
1155  record = grn_expr_get_var_by_offset(ctx, format->expression, 0);
1156  while ((id = grn_table_cursor_next(ctx, tc)) != GRN_ID_NIL) {
1157  int previous_comma_offset = -1;
1158  grn_bool is_first_comma = GRN_TRUE;
1159  grn_bool have_comma = GRN_FALSE;
1160  GRN_RECORD_SET(ctx, record, id);
1161  grn_output_array_open(ctx, outbuf, output_type, "HIT", n_elements);
1162  for (code = expr->codes; code < code_end; code++) {
1163  if (code->op == GRN_OP_COMMA) {
1164  int code_start_offset = previous_comma_offset + 1;
1165  int code_end_offset;
1166  int original_codes_curr = expr->codes_curr;
1167 
1168  have_comma = GRN_TRUE;
1169  if (is_first_comma) {
1170  int second_code_offset;
1171  int second_code_n_used_code;
1172  second_code_offset = code - expr->codes - 1;
1173  second_code_n_used_code =
1174  count_used_n_codes(ctx,
1175  expr->codes,
1176  expr->codes + second_code_offset);
1177  expr->codes_curr = second_code_offset - second_code_n_used_code + 1;
1178  grn_output_table_record_by_expression(ctx, outbuf, output_type,
1179  format->expression);
1180  code_start_offset = expr->codes_curr;
1181  is_first_comma = GRN_FALSE;
1182  }
1183  code_end_offset = code - expr->codes - code_start_offset;
1184  expr->codes += code_start_offset;
1185  expr->codes_curr = code_end_offset;
1186  grn_output_table_record_by_expression(ctx, outbuf, output_type,
1187  format->expression);
1188  expr->codes -= code_start_offset;
1189  expr->codes_curr = original_codes_curr;
1190  previous_comma_offset = code - expr->codes;
1191  }
1192  }
1193 
1194  if (!have_comma && expr->codes_curr > 0) {
1195  grn_output_table_record_by_expression(ctx, outbuf, output_type,
1196  format->expression);
1197  }
1198 
1199  grn_output_array_close(ctx, outbuf, output_type);
1200  }
1201 }
1202 
1203 static inline void
1204 grn_output_table_records_by_columns(grn_ctx *ctx, grn_obj *outbuf,
1205  grn_content_type output_type,
1206  grn_table_cursor *tc,
1207  grn_obj_format *format)
1208 {
1209  int i;
1210  grn_id id;
1211  int ncolumns = GRN_BULK_VSIZE(&format->columns)/sizeof(grn_obj *);
1212  grn_obj **columns = (grn_obj **)GRN_BULK_HEAD(&format->columns);
1213  while ((id = grn_table_cursor_next(ctx, tc)) != GRN_ID_NIL) {
1214  grn_output_array_open(ctx, outbuf, output_type, "HIT", ncolumns);
1215  for (i = 0; i < ncolumns; i++) {
1216  grn_text_atoj(ctx, outbuf, output_type, columns[i], id);
1217  }
1218  grn_output_array_close(ctx, outbuf, output_type);
1219  }
1220 }
1221 
1222 static inline void
1223 grn_output_table_records(grn_ctx *ctx, grn_obj *outbuf,
1224  grn_content_type output_type,
1225  grn_obj *table, grn_obj_format *format)
1226 {
1227  grn_table_cursor *tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0,
1228  format->offset, format->limit,
1230  if (tc) {
1231  if (format->expression) {
1232  grn_output_table_records_by_expression(ctx, outbuf, output_type,
1233  tc, format);
1234  } else {
1235  grn_output_table_records_by_columns(ctx, outbuf, output_type,
1236  tc, format);
1237  }
1238  grn_table_cursor_close(ctx, tc);
1239  } else {
1240  ERRCLR(ctx);
1241  }
1242 }
1243 
1244 static inline void
1245 grn_output_table(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
1246  grn_obj *table, grn_obj_format *format)
1247 {
1248  grn_obj buf;
1249  GRN_TEXT_INIT(&buf, 0);
1250  if (format) {
1251  int resultset_size = 1;
1252  /* resultset: [NHITS, (COLUMNS), (HITS)] */
1253  if (format->flags & GRN_OBJ_FORMAT_WITH_COLUMN_NAMES) {
1254  resultset_size++;
1255  }
1256  resultset_size += format->limit;
1257  grn_output_array_open(ctx, outbuf, output_type, "RESULTSET", resultset_size);
1258  grn_output_table_header(ctx, outbuf, output_type, table, format);
1259  if (format->flags & GRN_OBJ_FORMAT_WITH_COLUMN_NAMES) {
1260  grn_output_table_columns(ctx, outbuf, output_type, table, format);
1261  }
1262  grn_output_table_records(ctx, outbuf, output_type, table, format);
1263  grn_output_array_close(ctx, outbuf, output_type);
1264  } else {
1265  int i;
1266  grn_obj *column = grn_obj_column(ctx, table, "_key", 4);
1267  grn_table_cursor *tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0,
1268  0, -1, GRN_CURSOR_ASCENDING);
1269  grn_output_array_open(ctx, outbuf, output_type, "HIT", -1);
1270  if (tc) {
1271  grn_id id;
1272  for (i = 0; (id = grn_table_cursor_next(ctx, tc)) != GRN_ID_NIL; i++) {
1273  GRN_BULK_REWIND(&buf);
1274  grn_obj_get_value(ctx, column, id, &buf);
1275  grn_text_esc(ctx, outbuf, GRN_BULK_HEAD(&buf), GRN_BULK_VSIZE(&buf));
1276  }
1277  grn_table_cursor_close(ctx, tc);
1278  }
1279  grn_output_array_close(ctx, outbuf, output_type);
1280  grn_obj_unlink(ctx, column);
1281  }
1282  GRN_OBJ_FIN(ctx, &buf);
1283 }
1284 
1285 void
1286 grn_output_obj(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
1287  grn_obj *obj, grn_obj_format *format)
1288 {
1289  grn_obj buf;
1290  GRN_TEXT_INIT(&buf, 0);
1291  switch (obj->header.type) {
1292  case GRN_VOID :
1293  grn_output_void(ctx, outbuf, output_type, obj, format);
1294  break;
1295  case GRN_BULK :
1296  grn_output_bulk(ctx, outbuf, output_type, obj, format);
1297  break;
1298  case GRN_UVECTOR :
1299  grn_output_uvector(ctx, outbuf, output_type, obj, format);
1300  break;
1301  case GRN_VECTOR :
1302  grn_output_vector(ctx, outbuf, output_type, obj, format);
1303  break;
1304  case GRN_PVECTOR :
1305  grn_output_pvector(ctx, outbuf, output_type, obj, format);
1306  break;
1307  case GRN_TABLE_HASH_KEY :
1308  case GRN_TABLE_PAT_KEY :
1309  case GRN_TABLE_NO_KEY :
1310  grn_output_table(ctx, outbuf, output_type, obj, format);
1311  break;
1312  }
1313  GRN_OBJ_FIN(ctx, &buf);
1314 }
1315 
1316 typedef enum {
1321 } xml_status;
1322 
1323 typedef enum {
1327 } xml_place;
1328 
1329 static char *
1330 transform_xml_next_column(grn_obj *columns, int n)
1331 {
1332  char *column = GRN_TEXT_VALUE(columns);
1333  while (n--) {
1334  while (*column) {
1335  column++;
1336  }
1337  column++;
1338  }
1339  return column;
1340 }
1341 
1342 static void
1343 transform_xml(grn_ctx *ctx, grn_obj *output, grn_obj *transformed)
1344 {
1345  char *s, *e;
1346  xml_status status = XML_START;
1347  xml_place place = XML_PLACE_NONE;
1348  grn_obj buf, name, columns, *expr;
1349  unsigned int len;
1350  int offset = 0, limit = 0, record_n = 0;
1351  int column_n = 0, column_text_n = 0, result_set_n = -1;
1352  int in_vector = 0, first_vector_element = 0;
1353 
1354  s = GRN_TEXT_VALUE(output);
1355  e = GRN_BULK_CURR(output);
1356  GRN_TEXT_INIT(&buf, 0);
1357  GRN_TEXT_INIT(&name, 0);
1358  GRN_TEXT_INIT(&columns, 0);
1359 
1360  expr = ctx->impl->curr_expr;
1361 
1362 #define EQUAL_NAME_P(_name) \
1363  (GRN_TEXT_LEN(&name) == strlen(_name) && \
1364  !memcmp(GRN_TEXT_VALUE(&name), _name, strlen(_name)))
1365 
1366  while (s < e) {
1367  switch (*s) {
1368  case '<' :
1369  s++;
1370  switch (*s) {
1371  case '/' :
1372  status = XML_END_ELEMENT;
1373  s++;
1374  break;
1375  default :
1376  status = XML_START_ELEMENT;
1377  break;
1378  }
1379  GRN_BULK_REWIND(&name);
1380  break;
1381  case '>' :
1382  switch (status) {
1383  case XML_START_ELEMENT :
1384  if (EQUAL_NAME_P("COLUMN")) {
1385  place = XML_PLACE_COLUMN;
1386  column_text_n = 0;
1387  } else if (EQUAL_NAME_P("HIT")) {
1388  place = XML_PLACE_HIT;
1389  column_n = 0;
1390  if (result_set_n == 0) {
1391  GRN_TEXT_PUTS(ctx, transformed, "<HIT NO=\"");
1392  grn_text_itoa(ctx, transformed, record_n++);
1393  GRN_TEXT_PUTS(ctx, transformed, "\">\n");
1394  } else {
1395  GRN_TEXT_PUTS(ctx, transformed, "<NAVIGATIONELEMENT ");
1396  }
1397  } else if (EQUAL_NAME_P("RESULTSET")) {
1398  GRN_BULK_REWIND(&columns);
1399  result_set_n++;
1400  if (result_set_n == 0) {
1401  } else {
1402  GRN_TEXT_PUTS(ctx, transformed, "<NAVIGATIONENTRY>\n");
1403  }
1404  } else if (EQUAL_NAME_P("VECTOR")) {
1405  char *c = transform_xml_next_column(&columns, column_n++);
1406  in_vector = 1;
1407  first_vector_element = 1;
1408  GRN_TEXT_PUTS(ctx, transformed, "<FIELD NAME=\"");
1409  GRN_TEXT_PUTS(ctx, transformed, c);
1410  GRN_TEXT_PUTS(ctx, transformed, "\">");
1411  }
1412  break;
1413  case XML_END_ELEMENT :
1414  if (EQUAL_NAME_P("HIT")) {
1415  place = XML_PLACE_NONE;
1416  if (result_set_n == 0) {
1417  GRN_TEXT_PUTS(ctx, transformed, "</HIT>\n");
1418  } else {
1419  GRN_TEXT_PUTS(ctx, transformed, "/>\n");
1420  }
1421  } else if (EQUAL_NAME_P("RESULTSET")) {
1422  place = XML_PLACE_NONE;
1423  if (result_set_n == 0) {
1424  GRN_TEXT_PUTS(ctx, transformed, "</RESULTSET>\n");
1425  } else {
1426  GRN_TEXT_PUTS(ctx, transformed,
1427  "</NAVIGATIONELEMENTS>\n"
1428  "</NAVIGATIONENTRY>\n");
1429  }
1430  } else if (EQUAL_NAME_P("RESULT")) {
1431  GRN_TEXT_PUTS(ctx, transformed,
1432  "</RESULTPAGE>\n"
1433  "</SEGMENT>\n"
1434  "</SEGMENTS>\n");
1435  } else if (EQUAL_NAME_P("VECTOR")) {
1436  in_vector = 0;
1437  first_vector_element = 0;
1438  GRN_TEXT_PUTS(ctx, transformed, "</FIELD>\n");
1439  } else {
1440  switch (place) {
1441  case XML_PLACE_HIT :
1442  if (result_set_n == 0) {
1443  if (!in_vector) {
1444  char *c = transform_xml_next_column(&columns, column_n++);
1445  GRN_TEXT_PUTS(ctx, transformed, "<FIELD NAME=\"");
1446  GRN_TEXT_PUTS(ctx, transformed, c);
1447  GRN_TEXT_PUTS(ctx, transformed, "\">");
1448  }
1449  if (in_vector && !first_vector_element) {
1450  GRN_TEXT_PUTS(ctx, transformed, ", ");
1451  }
1452  GRN_TEXT_PUT(ctx, transformed,
1453  GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
1454  if (!in_vector) {
1455  GRN_TEXT_PUTS(ctx, transformed, "</FIELD>\n");
1456  }
1457  } else {
1458  char *c = transform_xml_next_column(&columns, column_n++);
1459  GRN_TEXT_PUTS(ctx, transformed, c);
1460  GRN_TEXT_PUTS(ctx, transformed, "=\"");
1461  GRN_TEXT_PUT(ctx, transformed,
1462  GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
1463  GRN_TEXT_PUTS(ctx, transformed, "\" ");
1464  }
1465  first_vector_element = 0;
1466  break;
1467  default :
1468  if (EQUAL_NAME_P("NHITS")) {
1469  if (result_set_n == 0) {
1470  uint32_t nhits;
1471  grn_obj *offset_value, *limit_value;
1472 
1473  nhits = grn_atoui(GRN_TEXT_VALUE(&buf), GRN_BULK_CURR(&buf),
1474  NULL);
1475  offset_value = grn_expr_get_var(ctx, expr,
1476  "offset", strlen("offset"));
1477  limit_value = grn_expr_get_var(ctx, expr,
1478  "limit", strlen("limit"));
1479  if (GRN_TEXT_LEN(offset_value)) {
1480  offset = grn_atoi(GRN_TEXT_VALUE(offset_value),
1481  GRN_BULK_CURR(offset_value),
1482  NULL);
1483  } else {
1484  offset = 0;
1485  }
1486  if (GRN_TEXT_LEN(limit_value)) {
1487  limit = grn_atoi(GRN_TEXT_VALUE(limit_value),
1488  GRN_BULK_CURR(limit_value),
1489  NULL);
1490  } else {
1491 #define DEFAULT_LIMIT 10
1492  limit = DEFAULT_LIMIT;
1493 #undef DEFAULT_LIMIT
1494  }
1495  grn_normalize_offset_and_limit(ctx, nhits, &offset, &limit);
1496  record_n = offset + 1;
1497  GRN_TEXT_PUTS(ctx, transformed,
1498  "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
1499  "<SEGMENTS>\n"
1500  "<SEGMENT>\n"
1501  "<RESULTPAGE>\n"
1502  "<RESULTSET OFFSET=\"");
1503  grn_text_lltoa(ctx, transformed, offset);
1504  GRN_TEXT_PUTS(ctx, transformed, "\" LIMIT=\"");
1505  grn_text_lltoa(ctx, transformed, limit);
1506  GRN_TEXT_PUTS(ctx, transformed, "\" NHITS=\"");
1507  grn_text_lltoa(ctx, transformed, nhits);
1508  GRN_TEXT_PUTS(ctx, transformed, "\">\n");
1509  } else {
1510  GRN_TEXT_PUTS(ctx, transformed,
1511  "<NAVIGATIONELEMENTS COUNT=\"");
1512  GRN_TEXT_PUT(ctx, transformed,
1513  GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
1514  GRN_TEXT_PUTS(ctx, transformed,
1515  "\">\n");
1516  }
1517  } else if (EQUAL_NAME_P("TEXT")) {
1518  switch (place) {
1519  case XML_PLACE_COLUMN :
1520  if (column_text_n == 0) {
1521  GRN_TEXT_PUT(ctx, &columns,
1522  GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
1523  GRN_TEXT_PUTC(ctx, &columns, '\0');
1524  }
1525  column_text_n++;
1526  break;
1527  default :
1528  break;
1529  }
1530  }
1531  }
1532  }
1533  default :
1534  break;
1535  }
1536  s++;
1537  GRN_BULK_REWIND(&buf);
1538  status = XML_TEXT;
1539  break;
1540  default :
1541  len = grn_charlen(ctx, s, e);
1542  switch (status) {
1543  case XML_START_ELEMENT :
1544  case XML_END_ELEMENT :
1545  GRN_TEXT_PUT(ctx, &name, s, len);
1546  break;
1547  default :
1548  GRN_TEXT_PUT(ctx, &buf, s, len);
1549  break;
1550  }
1551  s += len;
1552  break;
1553  }
1554  }
1555 #undef EQUAL_NAME_P
1556 
1557  GRN_OBJ_FIN(ctx, &buf);
1558  GRN_OBJ_FIN(ctx, &name);
1559  GRN_OBJ_FIN(ctx, &columns);
1560 }
1561 
1562 #ifdef GRN_WITH_MESSAGE_PACK
1563 typedef struct {
1564  grn_ctx *ctx;
1565  grn_obj *buffer;
1566 } msgpack_writer_ctx;
1567 
1568 static inline int
1569 msgpack_buffer_writer(void* data, const char* buf, unsigned int len)
1570 {
1571  msgpack_writer_ctx *writer_ctx = (msgpack_writer_ctx *)data;
1572  return grn_bulk_write(writer_ctx->ctx, writer_ctx->buffer, buf, len);
1573 }
1574 #endif
1575 
1576 #define JSON_CALLBACK_PARAM "callback"
1577 
1578 void
1580  grn_rc rc,
1581  grn_obj *head,
1582  grn_obj *body,
1583  grn_obj *foot,
1584  const char *file,
1585  int line)
1586 {
1587  double started, finished, elapsed;
1588  grn_obj *expr = NULL;
1589  grn_obj *jsonp_func = NULL;
1590 
1591  grn_timeval tv_now;
1592  grn_timeval_now(ctx, &tv_now);
1593  started = ctx->impl->tv.tv_sec;
1594  started += ctx->impl->tv.tv_nsec / GRN_TIME_NSEC_PER_SEC_F;
1595  finished = tv_now.tv_sec;
1596  finished += tv_now.tv_nsec / GRN_TIME_NSEC_PER_SEC_F;
1597  elapsed = finished - started;
1598 
1599  switch (ctx->impl->output_type) {
1600  case GRN_CONTENT_JSON:
1601  expr = ctx->impl->curr_expr;
1602  if (expr) {
1603  jsonp_func = grn_expr_get_var(ctx, expr, JSON_CALLBACK_PARAM,
1604  strlen(JSON_CALLBACK_PARAM));
1605  }
1606  if (jsonp_func && GRN_TEXT_LEN(jsonp_func)) {
1607  GRN_TEXT_PUT(ctx, head, GRN_TEXT_VALUE(jsonp_func), GRN_TEXT_LEN(jsonp_func));
1608  GRN_TEXT_PUTC(ctx, head, '(');
1609  }
1610  GRN_TEXT_PUTS(ctx, head, "[[");
1611  grn_text_itoa(ctx, head, rc);
1612  GRN_TEXT_PUTC(ctx, head, ',');
1613  grn_text_ftoa(ctx, head, started);
1614  GRN_TEXT_PUTC(ctx, head, ',');
1615  grn_text_ftoa(ctx, head, elapsed);
1616  if (rc != GRN_SUCCESS) {
1617  GRN_TEXT_PUTC(ctx, head, ',');
1618  grn_text_esc(ctx, head, ctx->errbuf, strlen(ctx->errbuf));
1619  if (ctx->errfunc && ctx->errfile) {
1620  grn_obj *command;
1621  /* TODO: output backtrace */
1622  GRN_TEXT_PUTS(ctx, head, ",[[");
1623  grn_text_esc(ctx, head, ctx->errfunc, strlen(ctx->errfunc));
1624  GRN_TEXT_PUTC(ctx, head, ',');
1625  grn_text_esc(ctx, head, ctx->errfile, strlen(ctx->errfile));
1626  GRN_TEXT_PUTC(ctx, head, ',');
1627  grn_text_itoa(ctx, head, ctx->errline);
1628  GRN_TEXT_PUTS(ctx, head, "]");
1629  if (file && (command = GRN_CTX_USER_DATA(ctx)->ptr)) {
1630  GRN_TEXT_PUTS(ctx, head, ",[");
1631  grn_text_esc(ctx, head, file, strlen(file));
1632  GRN_TEXT_PUTC(ctx, head, ',');
1633  grn_text_itoa(ctx, head, line);
1634  GRN_TEXT_PUTC(ctx, head, ',');
1635  grn_text_esc(ctx, head, GRN_TEXT_VALUE(command), GRN_TEXT_LEN(command));
1636  GRN_TEXT_PUTS(ctx, head, "]");
1637  }
1638  GRN_TEXT_PUTS(ctx, head, "]");
1639  }
1640  }
1641  GRN_TEXT_PUTC(ctx, head, ']');
1642  if (GRN_TEXT_LEN(body)) { GRN_TEXT_PUTC(ctx, head, ','); }
1643  GRN_TEXT_PUTC(ctx, foot, ']');
1644  if (jsonp_func && GRN_TEXT_LEN(jsonp_func)) {
1645  GRN_TEXT_PUTS(ctx, foot, ");");
1646  }
1647  break;
1648  case GRN_CONTENT_TSV:
1649  grn_text_itoa(ctx, head, rc);
1650  GRN_TEXT_PUTC(ctx, head, '\t');
1651  grn_text_ftoa(ctx, head, started);
1652  GRN_TEXT_PUTC(ctx, head, '\t');
1653  grn_text_ftoa(ctx, head, elapsed);
1654  if (rc != GRN_SUCCESS) {
1655  GRN_TEXT_PUTC(ctx, head, '\t');
1656  grn_text_esc(ctx, head, ctx->errbuf, strlen(ctx->errbuf));
1657  if (ctx->errfunc && ctx->errfile) {
1658  /* TODO: output backtrace */
1659  GRN_TEXT_PUTC(ctx, head, '\t');
1660  grn_text_esc(ctx, head, ctx->errfunc, strlen(ctx->errfunc));
1661  GRN_TEXT_PUTC(ctx, head, '\t');
1662  grn_text_esc(ctx, head, ctx->errfile, strlen(ctx->errfile));
1663  GRN_TEXT_PUTC(ctx, head, '\t');
1664  grn_text_itoa(ctx, head, ctx->errline);
1665  }
1666  }
1667  GRN_TEXT_PUTS(ctx, head, "\n");
1668  GRN_TEXT_PUTS(ctx, foot, "\nEND");
1669  break;
1670  case GRN_CONTENT_XML:
1671  {
1672  char buf[GRN_TABLE_MAX_KEY_SIZE];
1673  int is_select = 0;
1674  if (!rc && ctx->impl->curr_expr) {
1675  int len = grn_obj_name(ctx, ctx->impl->curr_expr,
1676  buf, GRN_TABLE_MAX_KEY_SIZE);
1677  buf[len] = '\0';
1678  is_select = strcmp(buf, "select") == 0;
1679  }
1680  if (is_select) {
1681  grn_obj transformed;
1682  GRN_TEXT_INIT(&transformed, 0);
1683  transform_xml(ctx, body, &transformed);
1684  GRN_TEXT_SET(ctx, body,
1685  GRN_TEXT_VALUE(&transformed), GRN_TEXT_LEN(&transformed));
1686  GRN_OBJ_FIN(ctx, &transformed);
1687  } else {
1688  GRN_TEXT_PUTS(ctx, head, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RESULT CODE=\"");
1689  grn_text_itoa(ctx, head, rc);
1690  GRN_TEXT_PUTS(ctx, head, "\" UP=\"");
1691  grn_text_ftoa(ctx, head, started);
1692  GRN_TEXT_PUTS(ctx, head, "\" ELAPSED=\"");
1693  grn_text_ftoa(ctx, head, elapsed);
1694  GRN_TEXT_PUTS(ctx, head, "\">\n");
1695  if (rc != GRN_SUCCESS) {
1696  GRN_TEXT_PUTS(ctx, head, "<ERROR>");
1697  grn_text_escape_xml(ctx, head, ctx->errbuf, strlen(ctx->errbuf));
1698  if (ctx->errfunc && ctx->errfile) {
1699  /* TODO: output backtrace */
1700  GRN_TEXT_PUTS(ctx, head, "<INFO FUNC=\"");
1701  grn_text_escape_xml(ctx, head, ctx->errfunc, strlen(ctx->errfunc));
1702  GRN_TEXT_PUTS(ctx, head, "\" FILE=\"");
1703  grn_text_escape_xml(ctx, head, ctx->errfile, strlen(ctx->errfile));
1704  GRN_TEXT_PUTS(ctx, head, "\" LINE=\"");
1705  grn_text_itoa(ctx, head, ctx->errline);
1706  GRN_TEXT_PUTS(ctx, head, "\"/>");
1707  }
1708  GRN_TEXT_PUTS(ctx, head, "</ERROR>");
1709  }
1710  GRN_TEXT_PUTS(ctx, foot, "\n</RESULT>");
1711  }
1712  }
1713  break;
1714  case GRN_CONTENT_MSGPACK:
1715 #ifdef GRN_WITH_MESSAGE_PACK
1716  {
1717  msgpack_writer_ctx head_writer_ctx;
1718  msgpack_packer header_packer;
1719  int header_size;
1720 
1721  head_writer_ctx.ctx = ctx;
1722  head_writer_ctx.buffer = head;
1723  msgpack_packer_init(&header_packer, &head_writer_ctx, msgpack_buffer_writer);
1724 
1725  /* [HEAD, (BODY)] */
1726  if (GRN_TEXT_LEN(body) > 0) {
1727  msgpack_pack_array(&header_packer, 2);
1728  } else {
1729  msgpack_pack_array(&header_packer, 1);
1730  }
1731 
1732  /* HEAD := [rc, started, elapsed, (error, (ERROR DETAIL))] */
1733  header_size = 3;
1734  if (rc != GRN_SUCCESS) {
1735  header_size++;
1736  if (ctx->errfunc && ctx->errfile) {
1737  header_size++;
1738  }
1739  }
1740  msgpack_pack_array(&header_packer, header_size);
1741  msgpack_pack_int(&header_packer, rc);
1742 
1743  msgpack_pack_double(&header_packer, started);
1744  msgpack_pack_double(&header_packer, elapsed);
1745 
1746  if (rc != GRN_SUCCESS) {
1747  msgpack_pack_raw(&header_packer, strlen(ctx->errbuf));
1748  msgpack_pack_raw_body(&header_packer, ctx->errbuf, strlen(ctx->errbuf));
1749  if (ctx->errfunc && ctx->errfile) {
1750  grn_obj *command = GRN_CTX_USER_DATA(ctx)->ptr;
1751  int error_detail_size;
1752 
1753  /* ERROR DETAIL := [[errfunc, errfile, errline,
1754  (file, line, command)]] */
1755  /* TODO: output backtrace */
1756  msgpack_pack_array(&header_packer, 1);
1757  error_detail_size = 3;
1758  if (command) {
1759  error_detail_size += 3;
1760  }
1761  msgpack_pack_array(&header_packer, error_detail_size);
1762 
1763  msgpack_pack_raw(&header_packer, strlen(ctx->errfunc));
1764  msgpack_pack_raw_body(&header_packer, ctx->errfunc, strlen(ctx->errfunc));
1765 
1766  msgpack_pack_raw(&header_packer, strlen(ctx->errfile));
1767  msgpack_pack_raw_body(&header_packer, ctx->errfile, strlen(ctx->errfile));
1768 
1769  msgpack_pack_int(&header_packer, ctx->errline);
1770 
1771  if (command) {
1772  if (file) {
1773  msgpack_pack_raw(&header_packer, strlen(file));
1774  msgpack_pack_raw_body(&header_packer, file, strlen(file));
1775  } else {
1776  msgpack_pack_raw(&header_packer, 7);
1777  msgpack_pack_raw_body(&header_packer, "(stdin)", 7);
1778  }
1779 
1780  msgpack_pack_int(&header_packer, line);
1781 
1782  msgpack_pack_raw(&header_packer, GRN_TEXT_LEN(command));
1783  msgpack_pack_raw_body(&header_packer, GRN_TEXT_VALUE(command), GRN_TEXT_LEN(command));
1784  }
1785  }
1786  }
1787  }
1788 #endif
1789  break;
1790  case GRN_CONTENT_NONE:
1791  break;
1792  }
1793 }