]> andersk Git - moira.git/blame - server/qvalidate.pc
Move all host access checking out of qsetup into qaccess where it belongs.
[moira.git] / server / qvalidate.pc
CommitLineData
7ac48069 1/* $Id$
73cf66ba 2 *
7ac48069 3 * Argument validation routines
73cf66ba 4 *
7ac48069 5 * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
6 * For copying and distribution information, please see the file
7 * <mit-copyright.h>.
73cf66ba 8 */
9
73cf66ba 10#include <mit-copyright.h>
73cf66ba 11#include "mr_server.h"
03c05291 12#include "query.h"
7ac48069 13#include "qrtn.h"
14
73cf66ba 15#include <ctype.h>
7ac48069 16#include <stdlib.h>
03c05291 17#include <string.h>
7ac48069 18#include <unistd.h>
19
73cf66ba 20EXEC SQL INCLUDE sqlca;
21EXEC SQL INCLUDE sqlda;
7ac48069 22
23RCSID("$Header$");
73cf66ba 24
03c05291 25extern char *whoami, *table_name[], *sqlbuffer[QMAXARGS];
26extern int dbms_errno, mr_errcode;
73cf66ba 27
28EXEC SQL BEGIN DECLARE SECTION;
29extern char stmt_buf[];
30EXEC SQL END DECLARE SECTION;
31
03c05291 32int validate_chars(char *argv[], struct valobj *vo);
33int validate_id(struct query *, char *argv[], struct valobj *vo);
34int validate_name(char *argv[], struct valobj *vo);
35int validate_rename(char *argv[], struct valobj *vo);
36int validate_type(char *argv[], struct valobj *vo);
37int validate_typedata(struct query *, char *argv[], struct valobj *vo);
38int validate_len(char *argv[], struct valobj *vo);
39int lock_table(struct valobj *vo);
40int readlock_table(struct valobj *vo);
41int convert_wildcards_uppercase(char *arg);
73cf66ba 42
5eaef520 43extern SQLDA *sqlald(int, int, int);
7ac48069 44SQLDA *mr_alloc_sqlda(void);
960b073b 45
03c05291 46EXEC SQL WHENEVER SQLERROR DO dbmserr();
73cf66ba 47
48/* Validation Routines */
49
44d12d58 50int validate_row(struct query *q, char *argv[], struct validate *v)
73cf66ba 51{
5eaef520 52 EXEC SQL BEGIN DECLARE SECTION;
53 char qual[128];
54 int rowcount;
55 EXEC SQL END DECLARE SECTION;
56
57 /* build where clause */
58 build_qual(v->qual, v->argc, argv, qual);
59
60 if (log_flags & LOG_VALID)
61 /* tell the logfile what we're doing */
62 com_err(whoami, 0, "validating row: %s", qual);
63
64 /* look for the record */
65 sprintf(stmt_buf, "SELECT COUNT (*) FROM %s WHERE %s",
66 table_name[q->rtable], qual);
67 dosql(sqlbuffer);
68 if (dbms_errno)
69 return mr_errcode;
70
71 rowcount = atoi(sqlbuffer[0]);
72 if (rowcount == 0)
73 return MR_NO_MATCH;
74 if (rowcount > 1)
75 return MR_NOT_UNIQUE;
76 return MR_EXISTS;
73cf66ba 77}
78
44d12d58 79int validate_fields(struct query *q, char *argv[], struct valobj *vo, int n)
73cf66ba 80{
44d12d58 81 int status;
73cf66ba 82
5eaef520 83 while (--n >= 0)
84 {
85 switch (vo->type)
86 {
73cf66ba 87 case V_NAME:
5eaef520 88 if (log_flags & LOG_VALID)
89 {
90 com_err(whoami, 0, "validating %s in %s: %s",
91 vo->namefield, table_name[vo->table], argv[vo->index]);
92 }
93 status = validate_name(argv, vo);
94 break;
73cf66ba 95
96 case V_ID:
5eaef520 97 if (log_flags & LOG_VALID)
98 {
99 com_err(whoami, 0, "validating %s in %s: %s",
100 vo->idfield, table_name[vo->table], argv[vo->index]);
101 }
102 status = validate_id(q, argv, vo);
103 break;
73cf66ba 104
105 case V_TYPE:
5eaef520 106 if (log_flags & LOG_VALID)
107 {
108 com_err(whoami, 0, "validating %s type: %s",
109 table_name[vo->table], argv[vo->index]);
110 }
111 status = validate_type(argv, vo);
112 break;
73cf66ba 113
114 case V_TYPEDATA:
5eaef520 115 if (log_flags & LOG_VALID)
116 {
117 com_err(whoami, 0, "validating typed data (%s): %s",
118 argv[vo->index - 1], argv[vo->index]);
119 }
120 status = validate_typedata(q, argv, vo);
121 break;
73cf66ba 122
123 case V_RENAME:
5eaef520 124 if (log_flags & LOG_VALID)
125 {
126 com_err(whoami, 0, "validating rename %s in %s",
127 argv[vo->index], table_name[vo->table]);
128 }
129 status = validate_rename(argv, vo);
130 break;
73cf66ba 131
132 case V_CHAR:
5eaef520 133 if (log_flags & LOG_VALID)
134 com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
135 status = validate_chars(argv, vo);
136 break;
03c05291 137
138 case V_LEN:
5eaef520 139 if (log_flags & LOG_VALID)
140 com_err(whoami, 0, "validating length: %s", argv[vo->index]);
141 status = validate_len(argv, vo);
142 break;
73cf66ba 143
144 case V_SORT:
5eaef520 145 status = MR_EXISTS;
146 break;
73cf66ba 147
148 case V_LOCK:
5eaef520 149 status = lock_table(vo);
150 break;
73cf66ba 151
03c05291 152 case V_RLOCK:
5eaef520 153 status = readlock_table(vo);
154 break;
03c05291 155
156 case V_WILD:
5eaef520 157 status = convert_wildcards(argv[vo->index]);
158 break;
73cf66ba 159
160 case V_UPWILD:
5eaef520 161 status = convert_wildcards_uppercase(argv[vo->index]);
162 break;
73cf66ba 163
164 }
165
5eaef520 166 if (status != MR_EXISTS)
167 return status;
168 vo++;
73cf66ba 169 }
170
5eaef520 171 if (dbms_errno)
172 return mr_errcode;
173 return MR_SUCCESS;
73cf66ba 174}
175
176
177/* validate_chars: verify that there are no illegal characters in
178 * the string. Legal characters are printing chars other than
179 * ", *, ?, \, [ and ].
180 */
181static int illegalchars[] = {
5eaef520 182 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
183 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
184 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
185 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
186 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* : - O */
187 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
188 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
189 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
190 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
191 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
192 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
193 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
194 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
195 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
196 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
197 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
73cf66ba 198};
199
44d12d58 200int validate_chars(char *argv[], struct valobj *vo)
73cf66ba 201{
5eaef520 202 char *s = argv[vo->index];
5eaef520 203 EXEC SQL BEGIN DECLARE SECTION;
204 int len;
205 char *tname, *cname;
206 EXEC SQL END DECLARE SECTION;
207
208 /* check for bad characters */
209 while (*s)
210 {
7ac48069 211 if (illegalchars[(int)*s++])
5eaef520 212 return MR_BAD_CHAR;
213 }
03c05291 214
5eaef520 215 /* check for length */
216 tname = table_name[vo->table];
217 cname = vo->namefield;
218 EXEC SQL SELECT data_length INTO :len FROM user_tab_columns
219 WHERE table_name = UPPER(:tname) AND column_name = UPPER(:cname);
03c05291 220
5eaef520 221 if ((strlen(argv[vo->index]) > len) &&
222 strcmp(argv[vo->index], UNIQUE_LOGIN)) /* kludge... sigh */
223 argv[vo->index][len] = '\0'; /* truncate */
03c05291 224
5eaef520 225 return MR_EXISTS;
73cf66ba 226}
227
228
44d12d58 229int validate_id(struct query *q, char *argv[], struct valobj *vo)
73cf66ba 230{
5eaef520 231 EXEC SQL BEGIN DECLARE SECTION;
232 char *name, *namefield, *idfield;
233 int id, rowcount, tbl;
234 EXEC SQL END DECLARE SECTION;
235 int status;
44d12d58 236 char *c;
5eaef520 237
238 name = argv[vo->index];
239 tbl = vo->table;
240 namefield = vo->namefield;
241 idfield = vo->idfield;
242
243 if ((tbl == USERS_TABLE && !strcmp(namefield, "login")) ||
244 tbl == MACHINE_TABLE || tbl == SUBNET_TABLE || tbl == FILESYS_TABLE ||
245 tbl == LIST_TABLE || tbl == CLUSTER_TABLE || tbl == STRINGS_TABLE)
246 {
247 if (tbl == MACHINE_TABLE || tbl == SUBNET_TABLE)
248 {
249 for (c = name; *c; c++)
250 {
251 if (islower(*c))
252 *c = toupper(*c);
253 }
254 }
03c05291 255 status = name_to_id(name, tbl, &id);
5eaef520 256 if (status == 0)
257 {
258 *(int *)argv[vo->index] = id;
259 return MR_EXISTS;
260 }
261 else if (status == MR_NO_MATCH && tbl == STRINGS_TABLE &&
262 (q->type == APPEND || q->type == UPDATE))
263 {
264 id = add_string(name);
265 cache_entry(name, STRINGS_TABLE, id);
266 *(int *)argv[vo->index] = id;
267 return MR_EXISTS;
268 }
269 else if (status == MR_NO_MATCH || status == MR_NOT_UNIQUE)
270 return vo->error;
03c05291 271 else
5eaef520 272 return status;
273 }
274 else
275 {
03c05291 276 /* else, it's `dubu', which uses unix_uid from users */
277 EXEC SQL SELECT COUNT(*) INTO :rowcount FROM users
278 WHERE unix_uid = :name;
5eaef520 279 if (dbms_errno)
280 return mr_errcode;
281 if (rowcount != 1)
282 return vo->error;
03c05291 283 EXEC SQL SELECT users_id INTO :id FROM users
284 WHERE unix_uid = :name;
285 *(int *)argv[vo->index] = id;
5eaef520 286 return MR_EXISTS;
73cf66ba 287 }
73cf66ba 288}
289
44d12d58 290int validate_name(char *argv[], struct valobj *vo)
73cf66ba 291{
5eaef520 292 char *name, *namefield;
44d12d58 293 char *c;
5eaef520 294
295 name = argv[vo->index];
296 namefield = vo->namefield;
297 if (vo->table == SERVERS_TABLE && !strcmp(namefield, "name"))
298 {
299 for (c = name; *c; c++)
300 {
73cf66ba 301 if (islower(*c))
302 *c = toupper(*c);
5eaef520 303 }
73cf66ba 304 }
5eaef520 305 sprintf(stmt_buf, "SELECT DISTINCT COUNT(*) FROM %s WHERE %s.%s = '%s'",
306 table_name[vo->table], table_name[vo->table], namefield, name);
307 dosql(sqlbuffer);
03c05291 308
5eaef520 309 if (dbms_errno)
310 return mr_errcode;
311 return (atoi(sqlbuffer[0]) == 1) ? MR_EXISTS : vo->error;
73cf66ba 312}
313
5eaef520 314int validate_rename(char *argv[], struct valobj *vo)
73cf66ba 315{
5eaef520 316 EXEC SQL BEGIN DECLARE SECTION;
317 char *name, *namefield, *idfield;
318 int id;
319 EXEC SQL END DECLARE SECTION;
320 int status;
44d12d58 321 char *c;
5eaef520 322
323 status = validate_chars(argv, vo);
324 if (status != MR_EXISTS)
325 return status;
326 name = argv[vo->index];
327 /* minor kludge to upcasify machine names */
328 if (vo->table == MACHINE_TABLE)
329 {
330 for (c = name; *c; c++)
331 {
332 if (islower(*c))
333 *c = toupper(*c);
334 }
335 }
336 namefield = vo->namefield;
337 idfield = vo->idfield;
338 id = -1;
339 if (idfield == 0)
340 {
341 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
342 return MR_EXISTS;
343 sprintf(stmt_buf, "SELECT %s FROM %s WHERE %s = '%s'",
344 namefield, table_name[vo->table], namefield, name);
345 dosql(sqlbuffer);
346
347 if (dbms_errno)
348 return mr_errcode;
349 if (sqlca.sqlcode == SQL_NO_MATCH)
350 return MR_EXISTS; /* how's _that_ for intuitive? */
351 else
352 return vo->error;
73cf66ba 353 }
5eaef520 354 status = name_to_id(name, vo->table, &id);
355 if (status == MR_NO_MATCH || id == *(int *)argv[vo->index - 1])
356 return MR_EXISTS;
357 else
358 return vo->error;
73cf66ba 359}
360
361
44d12d58 362int validate_type(char *argv[], struct valobj *vo)
73cf66ba 363{
5eaef520 364 EXEC SQL BEGIN DECLARE SECTION;
365 char *typename;
366 char *val;
367 int cnt;
368 EXEC SQL END DECLARE SECTION;
44d12d58 369 char *c;
5eaef520 370
371 typename = vo->namefield;
372 c = val = argv[vo->index];
373 while (*c)
374 {
7ac48069 375 if (illegalchars[(int)*c++])
5eaef520 376 return MR_BAD_CHAR;
73cf66ba 377 }
378
5eaef520 379 /* uppercase type fields */
380 for (c = val; *c; c++)
381 {
382 if (islower(*c))
383 *c = toupper(*c);
384 }
73cf66ba 385
5eaef520 386 EXEC SQL SELECT COUNT(trans) INTO :cnt FROM alias
387 WHERE name = :typename AND type = 'TYPE' AND trans = :val;
388 if (dbms_errno)
389 return mr_errcode;
390 return cnt ? MR_EXISTS : vo->error;
73cf66ba 391}
392
393/* validate member or type-specific data field */
394
44d12d58 395int validate_typedata(struct query *q, char *argv[], struct valobj *vo)
73cf66ba 396{
5eaef520 397 EXEC SQL BEGIN DECLARE SECTION;
398 char *name;
399 char *field_type;
400 char data_type[129];
401 int id;
402 EXEC SQL END DECLARE SECTION;
403 int status;
44d12d58 404 char *c;
5eaef520 405
406 /* get named object */
407 name = argv[vo->index];
408
409 /* get field type string (known to be at index-1) */
410 field_type = argv[vo->index - 1];
411
412 /* get corresponding data type associated with field type name */
413 EXEC SQL SELECT trans INTO :data_type FROM alias
414 WHERE name = :field_type AND type = 'TYPEDATA';
415 if (dbms_errno)
416 return mr_errcode;
417 if (sqlca.sqlerrd[2] != 1)
418 return MR_TYPE;
419
420 /* now retrieve the record id corresponding to the named object */
421 if (strchr(data_type, ' '))
422 *strchr(data_type, ' ') = '\0';
423 if (!strcmp(data_type, "user"))
424 {
425 /* USER */
426 if (strchr(name, '@'))
427 return MR_USER;
428 status = name_to_id(name, USERS_TABLE, &id);
429 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
430 return MR_USER;
431 if (status)
432 return status;
433 }
434 else if (!strcmp(data_type, "list"))
435 {
436 /* LIST */
437 status = name_to_id(name, LIST_TABLE, &id);
438 if (status && status == MR_NOT_UNIQUE)
439 return MR_LIST;
440 if (status == MR_NO_MATCH)
441 {
442 /* if idfield is non-zero, then if argv[0] matches the string
443 * that we're trying to resolve, we should get the value of
444 * numvalues.[idfield] for the id.
445 */
446 if (vo->idfield && !strcmp(argv[0], argv[vo->index]))
447 {
448 set_next_object_id(q->validate->object_id, q->rtable, 0);
449 name = vo->idfield;
450 EXEC SQL SELECT value INTO :id FROM numvalues
451 WHERE name = :name;
452 if (sqlca.sqlerrd[2] != 1)
453 return MR_LIST;
454 }
455 else
456 return MR_LIST;
457 }
458 else if (status)
459 return status;
460 }
461 else if (!strcmp(data_type, "machine"))
462 {
463 /* MACHINE */
464 for (c = name; *c; c++)
465 {
466 if (islower(*c))
467 *c = toupper(*c);
468 }
469 status = name_to_id(name, MACHINE_TABLE, &id);
470 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
471 return MR_MACHINE;
472 if (status)
473 return status;
474 }
475 else if (!strcmp(data_type, "string"))
476 {
477 /* STRING */
478 status = name_to_id(name, STRINGS_TABLE, &id);
479 if (status && status == MR_NOT_UNIQUE)
480 return MR_STRING;
481 if (status == MR_NO_MATCH)
482 {
483 if (q->type != APPEND && q->type != UPDATE)
484 return MR_STRING;
485 id = add_string(name);
486 cache_entry(name, STRINGS_TABLE, id);
487 }
488 else if (status)
489 return status;
73cf66ba 490 }
5eaef520 491 else if (!strcmp(data_type, "none"))
492 id = 0;
493 else
494 return MR_TYPE;
73cf66ba 495
5eaef520 496 /* now set value in argv */
497 *(int *)argv[vo->index] = id;
73cf66ba 498
5eaef520 499 return MR_EXISTS;
73cf66ba 500}
501
502
03c05291 503/* Make sure the data fits in the field */
44d12d58 504int validate_len(char *argv[], struct valobj *vo)
03c05291 505{
5eaef520 506 EXEC SQL BEGIN DECLARE SECTION;
507 int len;
508 char *tname, *cname;
509 EXEC SQL END DECLARE SECTION;
03c05291 510
5eaef520 511 tname = table_name[vo->table];
512 cname = vo->namefield;
513 EXEC SQL SELECT data_length INTO :len FROM user_tab_columns
514 WHERE table_name = UPPER(:tname) AND column_name = UPPER(:cname);
03c05291 515
5eaef520 516 if ((strlen(argv[vo->index]) > len) &&
517 strcmp(argv[vo->index], UNIQUE_LOGIN)) /* kludge... sigh */
518 argv[vo->index][len] = '\0'; /* truncate */
03c05291 519
5eaef520 520 return MR_EXISTS;
03c05291 521}
522
73cf66ba 523/* Lock the table named by the validation object */
524
5eaef520 525int lock_table(struct valobj *vo)
73cf66ba 526{
03c05291 527#ifdef DO_LOCKING
5eaef520 528 sprintf(stmt_buf, "LOCK TABLE %s IN EXCLUSIVE MODE", table_name[vo->table]);
529 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
530 if (dbms_errno)
531 return mr_errcode;
532 else
03c05291 533#endif
5eaef520 534 return MR_EXISTS;
73cf66ba 535}
536
03c05291 537/*
538 * Get a read lock on the table by accessing the magic lock
539 * record. Certain tables are constructed so that they contain
5eaef520 540 * an id field whose value is zero and a modtime field. We
541 * manipulate the modtime field of the id 0 record to effect
03c05291 542 * locking of the table
73cf66ba 543 */
544
5eaef520 545int readlock_table(struct valobj *vo)
73cf66ba 546{
03c05291 547#ifdef DO_LOCKING
5eaef520 548 sprintf(stmt_buf, "LOCK TABLE %s IN SHARE MODE", table_name[vo->table]);
549 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
03c05291 550
5eaef520 551 if (dbms_errno)
552 return mr_errcode;
553 if (sqlca.sqlcode)
554 return vo->error;
03c05291 555#endif
5eaef520 556 return MR_EXISTS; /* validate_fields expects us to return
557 * this value if everything went okay
558 */
73cf66ba 559}
560
695afd0d 561/* Check the database at startup time. */
03c05291 562
563void sanity_check_database(void)
564{
5eaef520 565 EXEC SQL BEGIN DECLARE SECTION;
566 int oid, id;
567 EXEC SQL END DECLARE SECTION;
695afd0d 568
5eaef520 569 /* Sometimes a crash can leave strings_id in numvalues in an
570 incorrect state. Check for that and fix it. */
695afd0d 571
5eaef520 572 EXEC SQL SELECT value INTO :oid FROM numvalues WHERE name = 'strings_id';
695afd0d 573
5eaef520 574 for (id = oid + 1; sqlca.sqlcode == 0; id++)
575 {
576 EXEC SQL SELECT string_id INTO :id FROM strings
577 WHERE string_id = :id;
578 }
695afd0d 579
5eaef520 580 if (id != oid + 1)
581 EXEC SQL UPDATE numvalues SET value = :id - 1 WHERE name = 'strings_id';
03c05291 582}
583
584
585char *sqlbuffer[QMAXARGS];
73cf66ba 586
587/* Dynamic SQL support routines */
7ac48069 588SQLDA *mr_alloc_sqlda(void)
73cf66ba 589{
5eaef520 590 SQLDA *it;
44d12d58 591 int j;
5eaef520 592
593 it = sqlald(QMAXARGS, ARGLEN, 0);
594 if (!it)
595 {
596 com_err(whoami, MR_NO_MEM, "setting up SQLDA");
597 exit(1);
73cf66ba 598 }
599
5eaef520 600 for (j = 0; j < QMAXARGS; j++)
601 {
602 it->V[j] = sqlbuffer[j] = malloc(ARGLEN);
603 it->T[j] = 97; /* 97 = CHARZ = null-terminated string */
604 it->L[j] = ARGLEN;
73cf66ba 605 }
03c05291 606
5eaef520 607 return it;
73cf66ba 608}
609
610
73cf66ba 611/* Convert normal Unix-style wildcards to SQL voodoo */
5eaef520 612int convert_wildcards(char *arg)
73cf66ba 613{
5eaef520 614 static char buffer[ARGLEN];
44d12d58 615 char *s, *d;
5eaef520 616
617 for (d = buffer, s = arg; *s; s++)
618 {
619 switch (*s)
620 {
621 case '*':
622 *d++ = '%';
623 *d++ = '%';
624 break;
625 case '?':
626 *d++ = '_';
627 break;
628 case '_':
629 *d++ = '*';
630 *d++ = *s;
631 break;
632 case '%':
633 *d++ = '*';
634 *d++ = '%';
635 *d++ = '%';
636 break;
637 default:
638 *d++ = *s;
639 break;
73cf66ba 640 }
641 }
5eaef520 642 *d = '\0';
73cf66ba 643
5eaef520 644 /* Copy back into argv */
645 strcpy(arg, buffer);
73cf66ba 646
5eaef520 647 return MR_EXISTS;
73cf66ba 648}
649
650/* This version includes uppercase conversion, for things like gmac.
651 * This is necessary because "LIKE" doesn't work with "uppercase()".
652 * Including it in a wildcard routine saves making two passes over
653 * the argument string.
654 */
5eaef520 655int convert_wildcards_uppercase(char *arg)
73cf66ba 656{
5eaef520 657 static char buffer[ARGLEN];
44d12d58 658 char *s, *d;
5eaef520 659
660 for (d = buffer, s = arg; *s; s++)
661 {
662 switch (*s)
663 {
664 case '*':
665 *d++ = '%';
666 *d++ = '%';
667 break;
668 case '?':
669 *d++ = '_';
670 break;
671 case '_':
672 *d++ = '*';
673 *d++ = *s;
674 break;
675 case '%':
676 *d++ = '*';
677 *d++ = '%';
678 *d++ = '%';
679 break;
680 default:
681 *d++ = toupper(*s); /* This is the only diff. */
682 break;
73cf66ba 683 }
684 }
5eaef520 685 *d = '\0';
73cf66ba 686
5eaef520 687 /* Copy back into argv */
688 strcpy(arg, buffer);
73cf66ba 689
5eaef520 690 return MR_EXISTS;
73cf66ba 691}
692
693
73cf66ba 694/* Adds a string to the string table. Returns the id number.
5eaef520 695 *
73cf66ba 696 */
5eaef520 697int add_string(char *nm)
73cf66ba 698{
5eaef520 699 EXEC SQL BEGIN DECLARE SECTION;
7ac48069 700 char *name = nm;
5eaef520 701 int id;
702 EXEC SQL END DECLARE SECTION;
703
704 EXEC SQL SELECT value INTO :id FROM numvalues WHERE name = 'strings_id';
705 id++;
706 EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'strings_id';
707
7ac48069 708 EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
5eaef520 709
710 return id;
73cf66ba 711}
This page took 0.173988 seconds and 5 git commands to generate.