2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $TOG: DataBase.C /main/5 1998/04/17 11:43:17 mgreess $
25 * (c) Copyright 1996 Digital Equipment Corporation.
26 * (c) Copyright 1996 Hewlett-Packard Company.
27 * (c) Copyright 1996 International Business Machines Corp.
28 * (c) Copyright 1996 Sun Microsystems, Inc.
29 * (c) Copyright 1996 Novell, Inc.
30 * (c) Copyright 1996 FUJITSU LIMITED.
31 * (c) Copyright 1996 Hitachi.
34 /* imported interfaces... */
41 #include <sys/types.h>
42 #include "StringList.h"
45 /* exported interfaces... */
49 #define FRIENDLY_ASSERT(e) \
50 if(!(e)) Token::signalError(Token::Internal, Token::Fatal, \
52 "assertion failed: " #e);
54 DB::DB(const char *name)
56 f_name = new char[strlen(name)+1];
61 static int isdir(const char* filename)
66 if(stat(filename, &sb) == 0){
67 if(S_ISDIR(sb.st_mode)){
76 static void makedir(const char *path) /* throw(PosixError) */
78 if(mkdir((char*)path, DATABASE_DIRECTORY_MODE) != 0){
79 throw(PosixError(errno, path));
84 DBTable *DB::table(const char *tname, int scode, int cols,
86 /* throw(PosixError); */
88 DBTable *ret = 0; /* keep compiler happy */
96 ret = new DBTable(this, scode, cols, tname);
100 ret = new DBTable(this, scode, cols, tname);
113 DBTable::DBTable(DB *database, int schema_code, int cols, const char *name)
115 f_database = database;
116 f_schema_code = schema_code;
119 f_name = new char[strlen(name)+1];
120 strcpy(f_name, name);
129 if(f_file && strcmp(f_name, DATABASE_STDIO) != 0) fclose(f_file);
135 DBTable::file(DB::Access access)
138 if(strcmp(f_name, DATABASE_STDIO) == 0){
140 f_file = access == DB::CREATE ? stdout : stdin;
144 const char *p = f_database->path();
145 char *path = new char[strlen(p) + 1 + strlen(f_name) + 1];
146 sprintf(path, "%s/%s", p, f_name);
148 f_file = fopen(path, access == DB::CREATE ? "w" : "r");
151 throw(PosixError(errno, path));
162 //----------------------------------------------------------
163 void DBTable::insert(int typecode, ...)
165 FILE *out = file(DB::CREATE);
168 va_start(ap, typecode);
170 fprintf(out, "%d\n%d\n", f_schema_code, f_cols);
174 while(typecode != 0){
178 const char *str = va_arg(ap, const char*);
179 fprintf(out, "%d\n%ld\t%s\n", STRING_CODE, (long)strlen(str), str);
185 const char *str = va_arg(ap, const char*);
186 size_t len = va_arg(ap, size_t);
187 fprintf(out, "%d\n%ld\t", STRING_CODE, (long)len );
188 fwrite ( str, len, 1, out );
193 case COMPRESSED_STRING_CODE:
195 const char *comp_agent = va_arg(ap, const char* );
196 const char *str = va_arg(ap, const char* );
198 fprintf(out, "%d\n%s\n%ld\t%s\n", COMPRESSED_STRING_CODE,comp_agent,
199 (long)strlen(str), str );
203 case -COMPRESSED_STRING_CODE:
205 const char *comp_agent = va_arg(ap, const char* );
206 const char *str = va_arg(ap, const char* );
208 size_t len = va_arg(ap, size_t );
209 fprintf(out, "%d\n%s\n%ld\t", COMPRESSED_STRING_CODE,
214 fwrite( str, len, 1, out );
222 const char *oid = va_arg(ap, const char*);
223 fprintf(out, "%d\n%s\n", OID_CODE, oid);
229 int x = va_arg(ap, int);
230 fprintf(out, "%d\n%d\n", INTEGER_CODE, x);
234 case SHORT_LIST_CODE:
236 int qty = va_arg(ap, int);
237 int code = va_arg(ap, int);
239 fprintf(out, "%d\n#\n", SHORT_LIST_CODE);
244 int *items = va_arg(ap, int*);
246 for(int i = 0; i < qty; i++){
247 fprintf(out, "%d\n%d\n", code, items[i]);
254 const char **items = va_arg(ap, const char**);
256 for(int i = 0; i < qty; i++){
257 fprintf(out, "%d\n%ld\t%s\n",
258 code, (long)strlen(items[i]), items[i]);
265 const char **items = va_arg(ap, const char**);
267 for(int i = 0; i < qty; i++){
268 fprintf(out, "%d\n%s\n",
275 fprintf(stderr, "Internal error: unknown database type code: %d\n",
287 int qty = va_arg(ap, int);
289 fprintf(out, "%d\n#\n", OID_LIST_CODE);
291 const char **items = va_arg(ap, const char**);
293 for(int i = 0; i < qty; i++){
294 fprintf(out, "%s\n", items[i]);
303 fprintf(stderr, "Internal error: unknown database type code: %d\n",
310 typecode = va_arg(ap, int);
315 fflush(out); /* @# some routines are sloppy and don't
316 * close their tables!
319 assert(cols_found == f_cols);
324 //----------------------------------------------------------
325 void DBTable::insert_untagged(int typecode, ...)
327 FILE *out = file(DB::CREATE);
330 va_start(ap, typecode);
332 fprintf(out, "%d\n", f_schema_code);
341 while(typecode != 0){
345 const char *str = va_arg(ap, const char*);
346 fprintf(out, "%ld\t%s\n", (long)strlen(str), str);
352 const char *str = va_arg(ap, const char*);
353 size_t len = va_arg(ap, size_t);
354 fprintf(out, "%ld\t", (long)len );
355 fwrite ( str, len, 1, out );
362 const char *oid = va_arg(ap, const char*);
363 fprintf(out, "%s\n", oid);
369 int x = va_arg(ap, int);
370 fprintf(out, "%d\n", x);
375 fprintf(stderr, "Internal error: unknown database type code: %d\n",
382 typecode = va_arg(ap, int);
387 fflush(out); /* @# some routines are sloppy and don't
388 * close their tables!
391 assert(cols_found == f_cols);
396 //----------------------------------------------------------
397 void DBTable::start_list()
403 //----------------------------------------------------------
404 void DBTable::end_list()
406 fprintf(file(DB::CREATE), "-\n");
411 //----------------------------------------------------------
412 DBCursor::DBCursor(DBTable &t)
417 f_fields = new StringList();
422 //----------------------------------------------------------
423 DBCursor::~DBCursor()
426 // this is for the last record
428 if ( f_list ) delete f_list;
432 //----------------------------------------------------------
434 void DBCursor::string_field(FILE *fp, char **out, int *lenOut)
439 /* fscanf is wierd, so we do it ourselves... */
440 while(isdigit(io = fgetc(fp))){
441 len = len * 10 + (io - '0');
443 FRIENDLY_ASSERT(io == '\t');
445 char *str = new char[len + 1];
446 io = fread(str, sizeof(str[0]), len+1, fp); /* read \n also */
448 FRIENDLY_ASSERT(io == len+1);
450 str[len] = 0; /* replace \n with 0 (just in case...) */
456 if(lenOut) *lenOut = len;
464 void DBCursor::int_field(FILE *fp, int *out)
469 io = fscanf(fp, "%d\n", &an_int);
471 FRIENDLY_ASSERT(io == 1);
473 if(out) *out = an_int;
477 void DBCursor::short_list(FILE *fp, int *qout, int ltype, void *out)
482 FRIENDLY_ASSERT(c == '#');
485 FRIENDLY_ASSERT(c == '\n');
490 typedef const char** ccpp;
491 ccpp *cpout = (ccpp*)out;
493 assert(f_list == NULL); /* only one SHORT_LIST per record supported */
494 f_list = new StringList;
496 while((c = fgetc(fp)) != '#'){
501 fscanf(fp, "%d\n", &ftype);
502 FRIENDLY_ASSERT(ftype == STRING_CODE);
504 string_field(fp, &item, NULL);
505 f_list->append(item);
508 *cpout = f_list->array();
509 *qout = f_list->qty();
514 abort(); /* only strings supported */
519 FRIENDLY_ASSERT(c == '\n');
523 int DBCursor::next(int typeCode, ...)
526 FILE *fp = f_table->file(DB::READ);
530 if(f_start < 0){ /* on first call to next(), reset the file */
535 io = fscanf(fp, "%d\n", &recordClass); /* get record code */
537 if(io != EOF){ /* got any data? */
539 FRIENDLY_ASSERT(io == 1);
541 // clean up previous fields first if they exist
543 delete f_list; f_list = NULL;
546 va_start(ap, typeCode);
550 io = fscanf(fp, "%d\n", &fieldQty); /* get field count */
551 FRIENDLY_ASSERT(io == 1);
553 /* iterate over fields in the input stream... */
557 io = fscanf(fp, "%d\n", &fieldCode); /* get field type */
558 FRIENDLY_ASSERT(io == 1);
560 assert(typeCode); /* make sure caller didn't give too few args */
568 if (fieldCode == typeCode || (fieldCode + typeCode) == 0) {
569 data = va_arg(ap, char**);
571 if (fieldCode != typeCode) {
572 len = va_arg(ap, int*);
576 string_field(fp, data, len);
581 int_field(fp, fieldCode == typeCode ? va_arg(ap, int*) : 0);
584 case SHORT_LIST_CODE:
586 int *qout = va_arg(ap, int *);
587 int ltype = va_arg(ap, int);
588 void *out = va_arg(ap, void*);
589 short_list(fp, qout, ltype, out);
597 typeCode = va_arg(ap, int);
600 assert(typeCode == 0); /* check for end marker */
605 ret = 0; /* EOF found... no record */
612 void DBCursor::undoNext()
614 FILE *fp = f_table->file(DB::READ);
617 if(fseek(fp, f_start, 0) < 0){
618 throw(PosixError(errno, f_table->name()));
621 abort(); /* @# throw("no next to undo!") */
625 //----------------------------------------------------------------
626 void DBCursor::local_rewind()
631 //----------------------------------------------------------------
634 if ( f_start == -1 ) {
642 //----------------------------------------------------------------
643 void DBCursor::seekToRec( int pos )
645 FILE *fp = f_table->file(DB::READ);
647 if (fseek(fp, pos, 0) < 0 ) {
648 throw(PosixError(errno, f_table->name()));