Merge branch 'master' into sru_2_0
[yaz-moved-to-github.git] / src / cclptree.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2013 Index Data
3  * See the file LICENSE for details.
4  */
5 /**
6  * \file cclptree.c
7  * \brief Implements CCL parse tree printing
8  *
9  * This source file implements functions to parse and print
10  * a CCL node tree (as a result of parsing).
11  */
12 #if HAVE_CONFIG_H
13 #include <config.h>
14 #endif
15
16 #include <stdio.h>
17 #include <string.h>
18
19 #include <yaz/querytowrbuf.h>
20 #include <yaz/yaz-iconv.h>
21 #include <yaz/ccl.h>
22
23 static void ccl_pquery_indent(WRBUF w, struct ccl_rpn_node *p, int indent);
24
25 static void ccl_pquery_complex(WRBUF w, struct ccl_rpn_node *p, int indent)
26 {
27     int sep_char = indent == -1 ? ' ' : '\n';
28     int next_indent = indent == -1 ? indent : indent+1;
29     switch (p->kind)
30     {
31     case CCL_RPN_AND:
32         wrbuf_puts(w, "@and");
33         break;
34     case CCL_RPN_OR:
35         wrbuf_puts(w, "@or");
36         break;
37     case CCL_RPN_NOT:
38         wrbuf_puts(w, "@not");
39         break;
40     case CCL_RPN_PROX:
41         if (p->u.p[2] && p->u.p[2]->kind == CCL_RPN_TERM)
42         {
43             const char *cp = p->u.p[2]->u.t.term;
44             /* exlusion distance ordered relation which-code unit-code */
45             if (*cp == '!')
46             {
47                 /* word order specified */
48                 if (yaz_isdigit(cp[1]))
49                     wrbuf_printf(w, "@prox 0 %s 1 2 k 2", cp+1);
50                 else
51                     wrbuf_printf(w, "@prox 0 1 1 2 k 2");
52             }
53             else if (*cp == '%')
54             {
55                 /* word order not specified */
56                 if (yaz_isdigit(cp[1]))
57                     wrbuf_printf(w, "@prox 0 %s 0 2 k 2", cp+1);
58                 else
59                     wrbuf_printf(w, "@prox 0 1 0 2 k 2");
60             }
61         }
62         else
63             wrbuf_puts(w, "@prox 0 2 0 1 k 2");
64         break;
65     default:
66         wrbuf_puts(w, "@ bad op (unknown)");
67     }
68     wrbuf_putc(w, sep_char);
69     ccl_pquery_indent(w, p->u.p[0], next_indent);
70     ccl_pquery_indent(w, p->u.p[1], next_indent);
71 }
72
73 static void ccl_prterm(WRBUF w, const char *term)
74 {
75     yaz_encode_pqf_term(w, term, strlen(term));
76 }
77
78 static void ccl_pquery_indent(WRBUF w, struct ccl_rpn_node *p, int indent)
79 {
80     struct ccl_rpn_attr *att;
81
82     if (!p)
83         return;
84     if (indent != -1)
85     {
86         int i;
87         for (i = 0; i < indent; i++)
88             wrbuf_putc(w, ' ');
89     }
90     switch (p->kind)
91     {
92     case CCL_RPN_AND:
93     case CCL_RPN_OR:
94     case CCL_RPN_NOT:
95     case CCL_RPN_PROX:
96         ccl_pquery_complex(w, p, indent);
97         break;
98     case CCL_RPN_SET:
99         wrbuf_puts(w, "@set ");
100         ccl_prterm(w, p->u.setname);
101         if (indent != -1)
102             wrbuf_putc(w, '\n');
103         break;
104     case CCL_RPN_TERM:
105         for (att = p->u.t.attr_list; att; att = att->next)
106         {
107             char tmpattr[128];
108             wrbuf_puts(w, "@attr ");
109             if (att->set)
110             {
111                 wrbuf_puts(w, att->set);
112                 wrbuf_puts(w, " ");
113             }
114             switch(att->kind)
115             {
116             case CCL_RPN_ATTR_NUMERIC:
117                 sprintf(tmpattr, "%d=%d ", att->type, att->value.numeric);
118                 wrbuf_puts(w, tmpattr);
119                 break;
120             case CCL_RPN_ATTR_STRING:
121                 sprintf(tmpattr, "%d=", att->type);
122                 wrbuf_puts(w, tmpattr);
123                 wrbuf_puts(w, att->value.str);
124                 wrbuf_puts(w, " ");
125                 break;
126             }
127         }
128         ccl_prterm(w, p->u.t.term);
129         if (indent != -1)
130             wrbuf_putc(w, '\n');
131         break;
132     }
133 }
134
135 void ccl_pquery(WRBUF w, struct ccl_rpn_node *p)
136 {
137     ccl_pquery_indent(w, p, -1);
138 }
139
140 void ccl_pr_tree(struct ccl_rpn_node *rpn, FILE *fd_out)
141 {
142     WRBUF w = wrbuf_alloc();
143
144     ccl_pquery_indent(w, rpn, 0);
145
146     fputs(wrbuf_cstr(w), fd_out);
147     wrbuf_destroy(w);
148 }
149
150 /*
151  * Local variables:
152  * c-basic-offset: 4
153  * c-file-style: "Stroustrup"
154  * indent-tabs-mode: nil
155  * End:
156  * vim: shiftwidth=4 tabstop=8 expandtab
157  */
158