1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2005,2008 Oracle. All rights reserved. 5 * 6 * $Id: query.c,v 1.17 2008/01/08 20:58:23 bostic Exp $ 7 */ 8 9#include "csv.h" 10#include "csv_local.h" 11#include "csv_extern.h" 12 13static int query_by_field(char *); 14static int query_fieldlist(char *); 15static int query_help(char *); 16static int query_usage(void); 17 18typedef struct _cmdtab { 19 char *cmd; /* Command name */ 20 int (*f)(char *); /* Underlying function. */ 21 char *help; /* Help message. */ 22} CMDTAB; 23 24static CMDTAB cmdtab[] = { 25 { "?", 26 query_help, 27 "?\t\tDisplay help screen" }, 28 { "exit", 29 NULL, 30 "exit\t\tExit program" }, 31 { "fields", 32 query_fieldlist, 33 "fields\t\tDisplay list of field names" }, 34 { "help", 35 query_help, 36 "help\t\tDisplay help screen" }, 37 { "quit", 38 NULL, 39 "quit\t\tExit program" }, 40 { NULL, 41 query_by_field, 42 "field[op]value\tDisplay fields by value (=, !=, <, <=, >, >=, ~, !~)" }, 43 { NULL, NULL, NULL } 44}; 45 46/* 47 * query_interactive -- 48 * Allow the user to interactively query the database. 49 */ 50int 51query_interactive() 52{ 53 int done; 54 char *p, input[256]; 55 56 for (;;) { 57 printf("Query: "); 58 (void)fflush(stdout); 59 if (fgets(input, sizeof(input), stdin) == NULL) { 60 printf("\n"); 61 if (ferror(stdin)) { 62 dbenv->err(dbenv, errno, 63 "error occurred reading from stdin"); 64 return (1); 65 } 66 break; 67 } 68 if ((p = strchr(input, '\n')) == NULL) { 69 dbenv->errx(dbenv, "input buffer too small"); 70 return (1); 71 } 72 *p = '\0'; 73 if (query(input, &done) != 0) 74 return (1); 75 if (done != 0) 76 break; 77 } 78 return (0); 79} 80 81/* 82 * query -- 83 * Process a query. 84 */ 85int 86query(char *cmd, int *donep) 87{ 88 CMDTAB *p; 89 90 if (donep != NULL) 91 *donep = 0; 92 93 for (p = cmdtab; p->cmd != NULL; ++p) 94 if (p->cmd != NULL && 95 strncasecmp(cmd, p->cmd, strlen(p->cmd)) == 0) 96 break; 97 98 if (p->cmd == NULL) 99 return (query_by_field(cmd)); 100 101 if (p->f == NULL) { 102 if (donep != NULL) 103 *donep = 1; 104 return (0); 105 } 106 107 return (p->f(cmd)); 108} 109 110/* 111 * query_by_field -- 112 * Query the primary database by field. 113 */ 114static int 115query_by_field(char *input) 116{ 117 OPERATOR operator; 118 size_t len; 119 char *field, *op, *value; 120 121 /* 122 * We expect to see "field [op] value" -- figure it out. 123 * 124 * Skip leading whitespace. 125 */ 126 while (isspace(*input)) 127 ++input; 128 129 /* 130 * Find an operator, and it better not start the string. 131 */ 132 if ((len = strcspn(field = input, "<>!=~")) == 0) 133 return (query_usage()); 134 op = field + len; 135 136 /* Figure out the operator, and find the start of the value. */ 137 switch (op[0]) { 138 case '~': 139 operator = WC; 140 value = op + 1; 141 break; 142 case '!': 143 if (op[1] == '=') { 144 operator = NEQ; 145 value = op + 2; 146 break; 147 } 148 if (op[1] == '~') { 149 operator = NWC; 150 value = op + 2; 151 break; 152 } 153 return (query_usage()); 154 case '<': 155 if (op[1] == '=') { 156 operator = LTEQ; 157 value = op + 2; 158 } else { 159 operator = LT; 160 value = op + 1; 161 } 162 break; 163 case '=': 164 operator = EQ; 165 if (op[1] == '=') 166 value = op + 2; 167 else 168 value = op + 1; 169 break; 170 case '>': 171 if (op[1] == '=') { 172 operator = GTEQ; 173 value = op + 2; 174 } else { 175 operator = GT; 176 value = op + 1; 177 } 178 break; 179 default: 180 return (query_usage()); 181 } 182 183 /* Terminate the field name, and there better be a field name. */ 184 while (--op > input && isspace(*op)) 185 ; 186 if (op == input) 187 return (query_usage()); 188 op[1] = '\0'; 189 190 /* Make sure there is a value field. */ 191 while (isspace(*value)) 192 ++value; 193 if (*value == '\0') 194 return (query_usage()); 195 196 return (DbRecord_search_field_name(field, value, operator)); 197} 198 199/* 200 * query_fieldlist -- 201 * Display list of field names. 202 */ 203static int 204query_fieldlist(char *input) 205{ 206 DbField *f; 207 208 input = input; /* Quiet compiler. */ 209 210 for (f = fieldlist; f->name != NULL; ++f) 211 printf("field %3d: %s\n", f->fieldno, f->name); 212 return (0); 213} 214 215/* 216 * query_help -- 217 * Query command list. 218 */ 219static int 220query_help(char *input) 221{ 222 CMDTAB *p; 223 224 input = input; /* Quiet compiler. */ 225 226 printf("Query commands:\n"); 227 for (p = cmdtab; p->help != NULL; ++p) 228 printf("\t%s\n", p->help); 229 return (0); 230} 231 232/* 233 * query_usage -- 234 * Query usage message. 235 */ 236static int 237query_usage(void) 238{ 239 fprintf(stderr, "%s: query syntax error\n", progname); 240 return (query_help(NULL)); 241} 242