* Copyright (c) 1995-2002, Index Data.
* See the file LICENSE for details.
*
- * $Id: pquery.c,v 1.14 2002-05-01 10:22:52 adam Exp $
+ * $Id: pquery.c,v 1.18 2002-09-24 08:05:42 adam Exp $
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
+#include <ctype.h>
#include <yaz/proto.h>
#include <yaz/oid.h>
static oid_value p_query_dfset = VAL_NONE;
-struct lex_info {
+struct yaz_pqf_parser {
const char *query_buf;
+ const char *query_ptr;
const char *lex_buf;
size_t lex_len;
int query_look;
char *right_sep;
int escape_char;
int term_type;
+ int error;
};
-static Z_RPNStructure *rpn_structure (struct lex_info *li, ODR o, oid_proto,
+static Z_RPNStructure *rpn_structure (struct yaz_pqf_parser *li, ODR o,
+ oid_proto,
int num_attr, int max_attr,
int *attr_list, char **attr_clist,
oid_value *attr_set);
-static enum oid_value query_oid_getvalbyname (struct lex_info *li)
+static enum oid_value query_oid_getvalbyname (struct yaz_pqf_parser *li)
{
enum oid_value value;
char buf[32];
return value;
}
-static int compare_term (struct lex_info *li, const char *src, size_t off)
+static int compare_term (struct yaz_pqf_parser *li, const char *src,
+ size_t off)
{
size_t len=strlen(src);
-
+
if (li->lex_len == len+off && !memcmp (li->lex_buf+off, src, len-off))
return 1;
return 0;
}
-static int query_token (struct lex_info *li)
+static int query_token (struct yaz_pqf_parser *li)
{
int sep_char = ' ';
const char *sep_match;
- const char **qptr = &li->query_buf;
+ const char **qptr = &li->query_ptr;
while (**qptr == ' ')
(*qptr)++;
return 't';
}
-static int lex (struct lex_info *li)
+static int lex (struct yaz_pqf_parser *li)
{
return li->query_look = query_token (li);
}
return out - out_buf;
}
-static int p_query_parse_attr(struct lex_info *li, ODR o,
+static int p_query_parse_attr(struct yaz_pqf_parser *li, ODR o,
int num_attr, int *attr_list,
char **attr_clist, oid_value *attr_set)
{
{
attr_set[num_attr] = query_oid_getvalbyname (li);
if (attr_set[num_attr] == VAL_NONE)
+ {
+ li->error = YAZ_PQF_ERROR_ATTSET;
return 0;
- lex (li);
-
+ }
+ if (!lex (li))
+ {
+ li->error = YAZ_PQF_ERROR_MISSING;
+ return 0;
+ }
if (!(cp = strchr (li->lex_buf, '=')))
+ {
+ li->error = YAZ_PQF_ERROR_BADATTR;
return 0;
+ }
}
else
{
return 1;
}
-static Z_AttributesPlusTerm *rpn_term (struct lex_info *li, ODR o,
+static Z_AttributesPlusTerm *rpn_term (struct yaz_pqf_parser *li, ODR o,
oid_proto proto,
int num_attr, int *attr_list,
char **attr_clist, oid_value *attr_set)
zapt->attributes->attributes = elements;
zapt->term = term;
- term->which = Z_Term_general;
- term->u.general = term_octet;
- term_octet->buf = (unsigned char *)odr_malloc (o, li->lex_len);
+
+ term_octet->buf = (unsigned char *)odr_malloc (o, 1 + li->lex_len);
term_octet->size = term_octet->len =
- escape_string ((char *) (term_octet->buf), li->lex_buf, li->lex_len);
+ escape_string ((char *) (term_octet->buf), li->lex_buf, li->lex_len);
+ term_octet->buf[term_octet->size] = 0; /* null terminate */
+
+ switch (li->term_type)
+ {
+ case Z_Term_general:
+ term->which = Z_Term_general;
+ term->u.general = term_octet;
+ break;
+ case Z_Term_characterString:
+ term->which = Z_Term_characterString;
+ term->u.characterString = (char*) term_octet->buf;
+ /* null terminated above */
+ break;
+ case Z_Term_numeric:
+ term->which = Z_Term_numeric;
+ term->u.numeric = odr_intdup (o, atoi((char*) (term_octet->buf)));
+ break;
+ case Z_Term_null:
+ term->which = Z_Term_null;
+ term->u.null = odr_nullval();
+ break;
+ default:
+ term->which = Z_Term_null;
+ term->u.null = odr_nullval();
+ break;
+ }
return zapt;
}
-static Z_Operand *rpn_simple (struct lex_info *li, ODR o, oid_proto proto,
+static Z_Operand *rpn_simple (struct yaz_pqf_parser *li, ODR o, oid_proto proto,
int num_attr, int *attr_list, char **attr_clist,
oid_value *attr_set)
{
case 's':
lex (li);
if (!li->query_look)
+ {
+ li->error = YAZ_PQF_ERROR_MISSING;
return 0;
+ }
zo->which = Z_Operand_resultSetId;
zo->u.resultSetId = (char *)odr_malloc (o, li->lex_len+1);
memcpy (zo->u.resultSetId, li->lex_buf, li->lex_len);
lex (li);
break;
default:
+ /* we're only called if one of the above types are seens so
+ this shouldn't happen */
+ li->error = YAZ_PQF_ERROR_INTERNAL;
return 0;
}
return zo;
}
-static Z_ProximityOperator *rpn_proximity (struct lex_info *li, ODR o)
+static Z_ProximityOperator *rpn_proximity (struct yaz_pqf_parser *li, ODR o)
{
Z_ProximityOperator *p = (Z_ProximityOperator *)odr_malloc (o, sizeof(*p));
if (!lex (li))
+ {
+ li->error = YAZ_PQF_ERROR_MISSING;
return NULL;
+ }
if (*li->lex_buf == '1')
{
p->exclusion = (int *)odr_malloc (o, sizeof(*p->exclusion));
p->exclusion = NULL;
if (!lex (li))
+ {
+ li->error = YAZ_PQF_ERROR_MISSING;
return NULL;
+ }
p->distance = (int *)odr_malloc (o, sizeof(*p->distance));
*p->distance = atoi (li->lex_buf);
if (!lex (li))
+ {
+ li->error = YAZ_PQF_ERROR_MISSING;
return NULL;
+ }
p->ordered = (int *)odr_malloc (o, sizeof(*p->ordered));
*p->ordered = atoi (li->lex_buf);
if (!lex (li))
+ {
+ li->error = YAZ_PQF_ERROR_MISSING;
return NULL;
+ }
p->relationType = (int *)odr_malloc (o, sizeof(*p->relationType));
*p->relationType = atoi (li->lex_buf);
if (!lex (li))
+ {
+ li->error = YAZ_PQF_ERROR_MISSING;
return NULL;
+ }
if (*li->lex_buf == 'k')
p->which = 0;
else if (*li->lex_buf == 'p')
p->which = atoi (li->lex_buf);
if (!lex (li))
+ {
+ li->error = YAZ_PQF_ERROR_MISSING;
return NULL;
+ }
p->which = Z_ProximityOperator_known;
p->u.known = (int *)odr_malloc (o, sizeof(*p->u.known));
*p->u.known = atoi (li->lex_buf);
return p;
}
-static Z_Complex *rpn_complex (struct lex_info *li, ODR o, oid_proto proto,
+static Z_Complex *rpn_complex (struct yaz_pqf_parser *li, ODR o, oid_proto proto,
int num_attr, int max_attr,
int *attr_list, char **attr_clist,
oid_value *attr_set)
return NULL;
break;
default:
+ /* we're only called if one of the above types are seens so
+ this shouldn't happen */
+ li->error = YAZ_PQF_ERROR_INTERNAL;
return NULL;
}
lex (li);
return zc;
}
-static Z_RPNStructure *rpn_structure (struct lex_info *li, ODR o,
+static void rpn_term_type (struct yaz_pqf_parser *li, ODR o)
+{
+ if (!li->query_look)
+ return ;
+ if (compare_term (li, "general", 0))
+ li->term_type = Z_Term_general;
+ else if (compare_term (li, "numeric", 0))
+ li->term_type = Z_Term_numeric;
+ else if (compare_term (li, "string", 0))
+ li->term_type = Z_Term_characterString;
+ else if (compare_term (li, "oid", 0))
+ li->term_type = Z_Term_oid;
+ else if (compare_term (li, "datetime", 0))
+ li->term_type = Z_Term_dateTime;
+ else if (compare_term (li, "null", 0))
+ li->term_type = Z_Term_null;
+ lex (li);
+}
+
+static Z_RPNStructure *rpn_structure (struct yaz_pqf_parser *li, ODR o,
oid_proto proto,
int num_attr, int max_attr,
int *attr_list,
case 'l':
lex (li);
if (!li->query_look)
- return NULL;
+ {
+ li->error = YAZ_PQF_ERROR_MISSING;
+ return 0;
+ }
if (num_attr >= max_attr)
- return NULL;
+ {
+ li->error = YAZ_PQF_ERROR_TOOMANY;
+ return 0;
+ }
if (!p_query_parse_attr(li, o, num_attr, attr_list,
attr_clist, attr_set))
return 0;
attr_clist, attr_set);
case 'y':
lex (li);
- if (!li->query_look)
- return NULL;
- if (compare_term (li, "general", 0))
- li->term_type = Z_Term_general;
- else if (compare_term (li, "numeric", 0))
- li->term_type = Z_Term_numeric;
- else if (compare_term (li, "string", 0))
- li->term_type = Z_Term_characterString;
- else if (compare_term (li, "oid", 0))
- li->term_type = Z_Term_oid;
- else if (compare_term (li, "datetime", 0))
- li->term_type = Z_Term_dateTime;
- else if (compare_term (li, "null", 0))
- li->term_type = Z_Term_null;
- lex (li);
+ rpn_term_type (li, o);
return
rpn_structure (li, o, proto, num_attr, max_attr, attr_list,
attr_clist, attr_set);
case 0: /* operator/operand expected! */
- return NULL;
+ li->error = YAZ_PQF_ERROR_MISSING;
+ return 0;
}
return sz;
}
-Z_RPNQuery *p_query_rpn_mk (ODR o, struct lex_info *li, oid_proto proto,
+Z_RPNQuery *p_query_rpn_mk (ODR o, struct yaz_pqf_parser *li, oid_proto proto,
const char *qbuf)
{
Z_RPNQuery *zq;
lex (li);
topSet = query_oid_getvalbyname (li);
if (topSet == VAL_NONE)
+ {
+ li->error = YAZ_PQF_ERROR_ATTSET;
return NULL;
+ }
lex (li);
}
zq->attributeSetId = yaz_oidval_to_z3950oid(o, CLASS_ATTSET, topSet);
if (!zq->attributeSetId)
+ {
+ li->error = YAZ_PQF_ERROR_ATTSET;
return 0;
+ }
if (!(zq->RPNStructure = rpn_structure (li, o, proto, 0, 512,
attr_array, attr_clist, attr_set)))
- return NULL;
+ return 0;
+ if (li->query_look)
+ {
+ li->error = YAZ_PQF_ERROR_EXTRA;
+ return 0;
+ }
return zq;
}
Z_RPNQuery *p_query_rpn (ODR o, oid_proto proto,
const char *qbuf)
{
- struct lex_info li;
-
+ struct yaz_pqf_parser li;
+
+ li.error = 0;
li.left_sep = "{\"";
li.right_sep = "}\"";
li.escape_char = '@';
li.term_type = Z_Term_general;
- li.query_buf = qbuf;
+ li.query_buf = li.query_ptr = qbuf;
+ li.lex_buf = 0;
return p_query_rpn_mk (o, &li, proto, qbuf);
}
-Z_AttributesPlusTerm *p_query_scan_mk (struct lex_info *li,
+Z_AttributesPlusTerm *p_query_scan_mk (struct yaz_pqf_parser *li,
ODR o, oid_proto proto,
Odr_oid **attributeSetP,
const char *qbuf)
int num_attr = 0;
int max_attr = 512;
oid_value topSet = VAL_NONE;
+ Z_AttributesPlusTerm *apt;
lex (li);
if (li->query_look == 'r')
*attributeSetP = yaz_oidval_to_z3950oid (o, CLASS_ATTSET, topSet);
- while (li->query_look == 'l')
+ while (1)
{
- lex (li);
- if (!li->query_look)
- return 0;
- if (num_attr >= max_attr)
- return 0;
- if (!p_query_parse_attr(li, o, num_attr, attr_list,
- attr_clist, attr_set))
- return 0;
- num_attr++;
- lex (li);
+ if (li->query_look == 'l')
+ {
+ lex (li);
+ if (!li->query_look)
+ {
+ li->error = YAZ_PQF_ERROR_MISSING;
+ return 0;
+ }
+ if (num_attr >= max_attr)
+ {
+ li->error = YAZ_PQF_ERROR_TOOMANY;
+ return 0;
+ }
+ if (!p_query_parse_attr(li, o, num_attr, attr_list,
+ attr_clist, attr_set))
+ return 0;
+ num_attr++;
+ lex (li);
+ }
+ else if (li->query_look == 'y')
+ {
+ lex (li);
+ rpn_term_type (li, o);
+ }
+ else
+ break;
}
if (!li->query_look)
- return NULL;
- return rpn_term (li, o, proto, num_attr, attr_list, attr_clist, attr_set);
+ {
+ li->error = YAZ_PQF_ERROR_MISSING;
+ return 0;
+ }
+ apt = rpn_term (li, o, proto, num_attr, attr_list, attr_clist, attr_set);
+
+ lex (li);
+
+ if (li->query_look != 0)
+ {
+ li->error = YAZ_PQF_ERROR_EXTRA;
+ return 0;
+ }
+ return apt;
}
Z_AttributesPlusTerm *p_query_scan (ODR o, oid_proto proto,
Odr_oid **attributeSetP,
const char *qbuf)
{
- struct lex_info li;
+ struct yaz_pqf_parser li;
+ li.error = 0;
li.left_sep = "{\"";
li.right_sep = "}\"";
li.escape_char = '@';
li.term_type = Z_Term_general;
- li.query_buf = qbuf;
+ li.query_buf = li.query_ptr = qbuf;
+ li.lex_buf = 0;
return p_query_scan_mk (&li, o, proto, attributeSetP, qbuf);
}
return (p_query_dfset == VAL_NONE) ? -1 : 0;
}
+YAZ_PQF_Parser yaz_pqf_create (void)
+{
+ YAZ_PQF_Parser p = (YAZ_PQF_Parser) xmalloc (sizeof(*p));
+
+ p->error = 0;
+ p->left_sep = "{\"";
+ p->right_sep = "}\"";
+ p->escape_char = '@';
+ p->term_type = Z_Term_general;
+
+ return p;
+}
+
+void yaz_pqf_destroy (YAZ_PQF_Parser p)
+{
+ xfree (p);
+}
+
+Z_RPNQuery *yaz_pqf_parse (YAZ_PQF_Parser p, ODR o, const char *qbuf)
+{
+ if (!p)
+ return 0;
+ p->query_buf = p->query_ptr = qbuf;
+ p->lex_buf = 0;
+ return p_query_rpn_mk (o, p, PROTO_Z3950, qbuf);
+}
+
+Z_AttributesPlusTerm *yaz_pqf_scan (YAZ_PQF_Parser p, ODR o,
+ Odr_oid **attributeSetP,
+ const char *qbuf)
+{
+ if (!p)
+ return 0;
+ p->query_buf = p->query_ptr = qbuf;
+ p->lex_buf = 0;
+ return p_query_scan_mk (p, o, PROTO_Z3950, attributeSetP, qbuf);
+}
+
+int yaz_pqf_error (YAZ_PQF_Parser p, const char **msg, size_t *off)
+{
+ switch (p->error)
+ {
+ case YAZ_PQF_ERROR_NONE:
+ *msg = "no error"; break;
+ case YAZ_PQF_ERROR_EXTRA:
+ *msg = "extra token"; break;
+ case YAZ_PQF_ERROR_MISSING:
+ *msg = "missing token"; break;
+ case YAZ_PQF_ERROR_ATTSET:
+ *msg = "unknown attribute set"; break;
+ case YAZ_PQF_ERROR_TOOMANY:
+ *msg = "too many attributes"; break;
+ case YAZ_PQF_ERROR_BADATTR:
+ *msg = "bad attribute specification"; break;
+ case YAZ_PQF_ERROR_INTERNAL:
+ *msg = "internal error"; break;
+ default:
+ *msg = "unknown error"; break;
+ }
+ *off = p->query_ptr - p->query_buf;
+ return p->error;
+}