initial commit
[goodguy/cinelerra.git] / cinelerra-5.1 / db / xsch.C
1 #include <cstdio>
2 #include <cstring>
3 #include <cstdlib>
4 #include <string>
5 #include <list>
6
7 using namespace std;
8
9 #define MAX_LINE_SZ 256
10 #define expect(c) do { if( ch != c ) return -1; ++cp; } while(0)
11
12 class iline {
13 public:
14   FILE *fp;  long pos;
15   char line[MAX_LINE_SZ];
16   int no;
17   iline(FILE *f) : fp(f), pos(0), no(0) { line[0] = 0; }
18   iline(iline &i) {
19     fp = i.fp;  pos = i.pos;
20     strcpy(line,i.line);  no = i.no;
21   }
22 };
23
24 class ichar : public virtual iline {
25 public:
26   int i, n;
27   ichar(FILE *f) : iline(f) { i = n = 0; }
28   ~ichar() {}
29   ichar tws();
30   char &operator *();
31   char &operator [](int n) { return line[i+n]; }
32   char &operator +=(int n) { i+=n; return operator*(); }
33   char &operator -=(int n) { i-=n; return operator*(); }
34   friend ichar &operator ++(ichar &t);
35   friend char operator ++(ichar &t,int);
36 };
37
38 ichar &operator ++(ichar &t) { ++t.i; return t; }
39 char operator ++(ichar &t,int) { return t.line[t.i++]; }
40
41 char &ichar::operator *()
42 {
43   if( i == n ) {
44     int ch;  fseek(fp, pos, SEEK_SET);
45     for( i=n=0; n<MAX_LINE_SZ; ) {
46       if( (ch=fgetc(fp)) < 0 ) ch = 0;
47       if( (line[n++]=ch) == '\n' || !ch ) break;
48     }
49     if( ch == '\n' ) ++no;
50     pos = ftell(fp);
51   }
52   return line[i];
53 }
54
55 class tobj;
56 class iobj;
57 typedef list<string *> eobjs;
58
59 class dobj {
60 public:
61   tobj *top;
62   string *name;
63   enum { ty_none, ty_bit, ty_boolean,
64     ty_tinyint, ty_smallint, ty_mediumint, ty_decimal,
65     ty_integer, ty_bigint, ty_real, ty_double, ty_float,
66     ty_date, ty_time, ty_timestamp, ty_datetime, ty_year,
67     ty_char, ty_varchar, ty_binary, ty_varbinary,
68     ty_blob, ty_tinyblob, ty_mediumblob, ty_longblob,
69     ty_text, ty_tinytext, ty_mediumtext, ty_longtext,
70     ty_enum, ty_set, ty_media } ty;
71   enum {
72     var_types = (1<<ty_varchar) | (1<<ty_varbinary) | (1<<ty_blob) |
73       (1<<ty_tinyblob) | (1<<ty_mediumblob) | (1<<ty_longblob) |
74       (1<<ty_media),
75     text_types = (1<<ty_text) |
76       (1<<ty_tinytext) | (1<<ty_mediumtext) | (1<<ty_longtext),
77     integer_types = (1<<ty_boolean) | (1<<ty_bit) | (1<<ty_binary) |
78       (1<<ty_tinyint) | (1<<ty_smallint) | (1<<ty_decimal) |
79       (1<<ty_mediumint) | (1<<ty_integer) | (1<<ty_bigint),
80     double_types = (1<<ty_real) | (1<<ty_double) | (1<<ty_float),
81   };
82   int is_var() { return (var_types>>ty) & 1; }
83   int is_integer() { return (integer_types>>ty) & 1; }
84   int is_double() { return (double_types>>ty) & 1; }
85   int length, zeroed, is_null, is_autoincr, is_binary, is_unsign, has_def;
86   iobj *idx;
87   eobjs eop;
88   enum def_type { def_none, def_integer, def_double, def_string, def_null, };
89   union { int i; double d; string *s; } def;
90   dobj(tobj *tp) : top(tp) {
91     ty = ty_none;  idx = 0;
92     length = zeroed = is_null = is_autoincr = is_binary = is_unsign = has_def = -1;
93   }
94   ~dobj() {}
95 };
96
97 typedef list<dobj*> dobjs;
98
99 class tobj {
100 public:
101   string *name;
102   dobjs dop;
103   dobj *dobj_of(const char *knm);
104
105   tobj() : name(0) {}
106   ~tobj() {};
107 };
108
109 list<tobj*> tables;
110
111 tobj *tobj_of(const char *tnm)
112 {
113   list<tobj*>::iterator it = tables.begin();
114   list<tobj*>::iterator eit = tables.end();
115   while( it!=eit && *(*it)->name!=tnm ) ++it;
116   return it == eit ? 0 : *it;
117 }
118
119 dobj *tobj::dobj_of(const char *knm)
120 {
121     dobjs::iterator eid = dop.end();
122     dobjs::iterator id = dop.begin();
123     while( id!=eid && *(*id)->name!=knm ) ++id;
124     return id == eid ? 0 : *id;
125 }
126
127 class iobj {
128 public:
129   string *name;
130   tobj *tbl;
131   dobjs keys;
132   short unique, primary;
133   int is_dir;
134   int is_direct();
135   iobj() : name(0), tbl(0), unique(0), primary(0), is_dir(-1) {}
136   ~iobj() {};
137 };
138
139 list<iobj*> indecies;
140
141 class robj {
142 public:
143   string *name;
144   enum { xref_no_action, xref_restrict, xref_cascade, xref_set_null, };
145   int on_delete, on_update;
146   list<string *> keys;
147   robj() : on_delete(xref_no_action), on_update(xref_no_action) {}
148   ~robj() {}
149 };
150
151
152 // trim white space
153 ichar &tws(ichar &c)
154 {
155   ichar b = c;
156   for(;;) {
157     if( isspace(*b) ) { ++b; continue; }
158     if( *b == '/' && b[1] == '*' ) {
159       ++b;  do { ++b; } while( *b != '*' || b[1] != '/' );
160       b += 2;  continue;
161     }
162     else if( *b == '-' && b[1] == '-' ) {
163       ++b;  do { ++b; } while( *b != '\n' );
164       ++b;  continue;
165     }
166     break;
167   }
168   c = b;
169   return c;
170 }
171
172 // scan id
173 string *tid(ichar &c, string *sp=0)
174 {
175   string *rp = 0;
176   ichar b = tws(c);
177   if( *b && (isalpha(*b) || *b == '_') ) {
178     rp = !sp ? new string() : sp;
179     rp->push_back(toupper(b++));
180     while( *b && (isalpha(*b) || isdigit(*b) ||  *b == '_') ) {
181       rp->push_back(tolower(b++));
182     }
183   }
184   if( rp ) c = b;
185   return rp;
186 }
187
188 // scan string '..' or ".."
189 int str_value(ichar &cp, string *&sp)
190 {
191   ichar bp = cp;  sp = 0;
192   int ch = *cp;
193   if( ch != '\'' && ch != '"' ) return -1;
194   int delim = ch;  ++cp;
195   for( sp=new string(); (ch=*cp) && ch != delim; ++cp ) {
196     if( ch == '\\' && !(ch=*++cp) ) break;
197     sp->push_back(ch);
198   }
199   if( ch != delim ) {
200     delete sp;  sp = 0;
201     cp = bp;
202     return -1;
203   }
204   ++cp;
205   return 0;
206 }
207
208 // scan string '..' or "..", or number, or NULL
209 int def_value(ichar &cp, dobj *dp)
210 {
211   ichar bp = cp;
212   if( str_value(cp,dp->def.s) >= 0 ) {
213     dp->has_def = dobj::def_string;
214     return 0;
215   }
216   int ch = *tws(cp);
217   if( isdigit(ch) || ch == '-' || ch == '+' ) {
218     int sign = 0;
219     if( ch == '-' ) sign = -1;
220     if( ch == '+' ) sign = 1;
221     if( sign ) ++cp; else sign = 1;
222     int n = 0;
223     while( (ch-='0') >= 0 && ch <= 9 ) {
224       n = n*10 + ch;  ch = *++cp;
225     }
226     if( ch == '.' ) {
227       double v = n;
228       double frac = 1.;
229       while( (ch-='0') >= 0 && ch <= 9 ) {
230         v = v + ch/(frac*=10);  ch = *++cp;
231       }
232       dp->has_def = dobj::def_double;
233       dp->def.d = v * sign;
234     }
235     else {
236       dp->has_def = dobj::def_integer;
237       dp->def.i = n * sign;
238     }
239     return 0;
240   }
241   string *id = tid(cp);
242   if( id ) {
243     if( *id == "Null" ) {
244       dp->has_def = dobj::def_null;
245       dp->def.s = 0;
246       return 0;
247     }
248     delete id;
249   }
250   cp = bp;
251   return -1;
252 }
253
254 // scan (number)
255 int dimen(ichar &cp, dobj *dp)
256 {
257   int n = 0;
258   int ch = *tws(cp);
259   if( ch == '(' ) {
260     ++cp;  ch = *tws(cp);
261     while( (ch-='0') >= 0 && ch <= 9 ) {
262       n = n*10 + ch;  ch = *++cp;
263     }
264     ch = *tws(cp);  expect(')');
265     dp->length = n;
266   }
267   return 0;
268 }
269
270 // scan Unsigned or Signed, Zerofill
271 int numeric(ichar &cp, dobj *dp)
272 {
273   ichar bp = cp;
274   string *id = tid(cp);
275   if( id && *id == "Unsigned" ) {
276     dp->is_unsign = 1;
277     bp = cp;  id = tid(cp);
278   }
279   else if( id && *id == "Signed" ) {
280     dp->is_unsign = 0;
281     bp = cp;  id = tid(cp);
282   }
283   if( id && *id == "Zerofill" ) {
284     dp->zeroed = 1;
285   }
286   else
287     cp = bp;
288   return 0;
289 }
290
291 // (number) or numeric qualifier
292 int dimen0(ichar &cp, dobj *dp)
293 {
294   return dimen(cp, dp) < 0 || numeric(cp, dp) < 0 ? -1 : 0;
295 }
296
297 // scan data type
298 int dtype(ichar &cp, dobj *dp)
299 {
300   string *id = tid(cp);
301
302   if( id ) {
303     if( *id == "Bit" ) {
304       dp->ty = dobj::ty_bit;
305       if( dimen0(cp, dp) < 0 ) return -1;
306       return 0;
307     }
308
309     if( *id == "Tinyint" ) {
310       dp->ty = dobj::ty_tinyint;
311       if( dimen0(cp, dp) < 0 ) return -1;
312       return 0;
313     }
314
315     if( *id == "Smallint" ) {
316       dp->ty = dobj::ty_smallint;
317       if( dimen0(cp, dp) < 0 ) return -1;
318       return 0;
319     }
320
321     if( *id == "Mediumint" ) {
322       dp->ty = dobj::ty_mediumint;
323       if( dimen0(cp, dp) < 0 ) return -1;
324       return 0;
325     }
326
327     if( *id == "Int" || *id == "Integer" ) {
328       dp->ty = dobj::ty_integer;
329       if( dimen0(cp, dp) < 0 ) return -1;
330       return 0;
331     }
332
333     if( *id == "Bigint" ) {
334       dp->ty = dobj::ty_bigint;
335       if( dimen0(cp, dp) < 0 ) return -1;
336       return 0;
337     }
338
339     if( *id == "Real" ) {
340       dp->ty = dobj::ty_real;
341       if( dimen0(cp, dp) < 0 ) return -1;
342       return 0;
343     }
344
345     if( *id == "Double" ) {
346       dp->ty = dobj::ty_double;
347       if( dimen0(cp, dp) < 0 ) return -1;
348       return 0;
349     }
350
351     if( *id == "Float" ) {
352       dp->ty = dobj::ty_float;
353       if( dimen0(cp, dp) < 0 ) return -1;
354       return 0;
355     }
356
357     if( *id == "Decimal" ) {
358       dp->ty = dobj::ty_decimal;
359       if( dimen0(cp, dp) < 0 ) return -1;
360       return 0;
361     }
362
363     if( *id == "Date" ) {
364       dp->ty = dobj::ty_date;
365       return 0;
366     }
367     else if( *id == "Time" ) {
368       dp->ty = dobj::ty_time;
369       return 0;
370     }
371     else if( *id == "Timestamp" ) {
372       dp->ty = dobj::ty_timestamp;
373       return 0;
374     }
375     else if( *id == "Datetime" ) {
376       dp->ty = dobj::ty_datetime;
377       return 0;
378     }
379     else if( *id == "Year" ) {
380       dp->ty = dobj::ty_year;
381       return 0;
382     }
383
384     if( *id == "Char" ) {
385       dp->ty = dobj::ty_char;
386       if( dimen(cp, dp) < 0 ) return -1;
387       return 0;
388     }
389
390     if( *id == "Varchar" ) {
391       dp->ty = dobj::ty_varchar;
392       if( dimen(cp, dp) < 0 ) return -1;
393       if( (id=tid(cp)) != 0 ) {
394         ichar bp = cp;
395         if( *id == "Binary" ) {
396           dp->is_binary = 1;
397         }
398         else
399           cp = bp;
400       }
401       return 0;
402     }
403
404     if( *id == "Binary" ) {
405       dp->ty = dobj::ty_binary;
406       if( dimen(cp, dp) < 0 ) return -1;
407       return 0;
408     }
409
410     if( *id == "Varbinary" ) {
411       dp->ty = dobj::ty_varbinary;
412       if( dimen(cp, dp) < 0 ) return -1;
413       return 0;
414     }
415
416     if( *id == "Tinyblob" ) {
417       dp->ty = dobj::ty_tinyblob;
418       return 0;
419     }
420
421     if( *id == "Blob" ) {
422       dp->ty = dobj::ty_blob;
423       return 0;
424     }
425
426     if( *id == "Mediumblob" ) {
427       dp->is_unsign = 1;
428       dp->ty = dobj::ty_mediumblob;
429       return 0;
430     }
431
432     if( *id == "Longblob" ) {
433       dp->ty = dobj::ty_longblob;
434       return 0;
435     }
436
437     if( *id == "Tinytext" ) {
438       dp->ty = dobj::ty_tinytext;
439       return 0;
440     }
441
442     if( *id == "Text" ) {
443       dp->ty = dobj::ty_text;
444       return 0;
445     }
446
447     if( *id == "Mediumtext" ) {
448       dp->ty = dobj::ty_mediumtext;
449       return 0;
450     }
451
452     if( *id == "Longtext" ) {
453       dp->ty = dobj::ty_longtext;
454       return 0;
455     }
456
457     if( *id == "Bool" || *id == "Boolean" ) {
458       dp->ty = dobj::ty_boolean;
459       return 0;
460     }
461
462     if( *id == "Enum" ) {
463       dp->ty = dobj::ty_enum;
464       int ch = *tws(cp);  expect('(');
465       if( str_value(tws(cp),id) < 0 ) return -1;
466       dp->eop.push_back(id);
467       while( *tws(cp) == ',' ) {
468         if( str_value(tws(++cp),id) < 0 ) return -1;
469         dp->eop.push_back(id);
470       }
471       ch = *tws(cp);  expect(')');
472       return 0;
473     }
474
475     if( *id == "Media" ) {
476       dp->ty = dobj::ty_media;
477       return 0;
478     }
479   }
480
481   return -1;
482 }
483
484 // scan reference
485 int xrefer(ichar &cp, robj *rp)
486 {
487   string *id = tid(cp);
488   if( !id ) return -1;
489   rp->name = id;
490   int ch = *tws(cp);  expect('(');
491   if( !(id=tid(cp)) ) return -1;
492   rp->keys.push_back(id);
493   while( *tws(cp) == ',' ) {
494     if( !(id=tid(++cp)) ) return -1;
495     rp->keys.push_back(id);
496   }
497   ch = *tws(cp);  expect(')');
498   if( !(id=tid(cp)) ) return -1;
499   if( *id != "On" ) return -1;
500   if( !(id=tid(cp)) ) return -1;
501   int *pp = 0;
502   if( *id == "Delete" ) {
503     pp = &rp->on_delete;
504   }
505   else if( *id == "Update" ) {
506     pp = &rp->on_update;
507   }
508   if( !pp ) return -1;
509   if( !(id=tid(cp)) ) return -1;
510   if( *id == "Restrict" ) {
511     rp->on_delete = robj::xref_restrict;
512     return 0;
513   }
514   if( *id == "Cascade" ) {
515     rp->on_delete = robj::xref_cascade;
516     return 0;
517   }
518   if( *id == "Set" ) {
519     if( !(id=tid(cp)) ) return -1;
520     if( *id != "Null" ) return -1;
521     rp->on_delete = robj::xref_set_null;
522     return 0;
523   }
524   if( *id == "No" ) {
525     if( !(id=tid(cp)) ) return -1;
526     if( *id != "Action" ) return -1;
527     rp->on_delete = robj::xref_no_action;
528     return 0;
529   }
530   return -1;
531 }       
532
533 // scan datatype extension
534 int xtype(ichar &cp, dobj *dp)
535 {
536   string *id = tid(cp);
537   if( id ) {
538     if( *id == "Not" ) {
539       if( *tid(cp) != "Null" ) return -1;
540       dp->is_null = 0;
541       return 0;
542     }
543
544     if( *id == "Null" ) {
545       dp->is_null = 1;
546       return 0;
547     }
548
549     if( *id == "Default" ) {
550       if( def_value(tws(cp),dp) < 0 ) return -1;
551       return 0;
552     }
553
554     if( *id == "Auto_increment" ) {
555       dp->is_autoincr = 1;
556       if( dp->idx ) dp->idx->unique = 1;
557       return 0;
558     }
559
560     if( *id == "Unique" || *id == "Primary" ) {
561       int unique = dp->is_autoincr > 0 ? 1 : 0;
562       int primary = 0;
563       if( *id == "Unique" ) {
564         unique = 1;  id = tid(cp);
565       }
566       if( *id == "Primary" ) primary = 1;
567       ichar bp = cp;
568       if( *tid(cp) != "Key" ) cp = bp;
569       iobj *idx = new iobj();
570       dp->idx = idx;
571       idx->name = new string(*dp->name);
572       idx->name->push_back('_');
573       idx->tbl = dp->top;
574       idx->unique = unique;
575       idx->primary = primary;
576       idx->keys.push_back(dp);
577       indecies.push_back(idx);
578       return 0;
579     }
580
581 #if 0
582     if( *id == "Comment" ) {
583       return 0;
584     }
585
586     if( *id == "Column_format" ) {
587       return 0;
588     }
589
590     if( *id == "Storage" ) {
591       return 0;
592     }
593 #endif
594
595     if( *id == "References" ) {
596       ichar bp = cp;
597       robj *rop = new robj();
598       if ( xrefer(cp, rop) < 0 ) {
599         cp = bp;
600         return -1;
601       }
602       return 0;
603     }
604   }
605   return -1;
606 }
607
608 // scan table member line
609 int member(ichar &cp, dobj *dp)
610 {
611   dp->name = tid(cp);
612   if( dtype(cp,dp) < 0 ) return -1;
613
614   for( int ch=*tws(cp); (ch=*tws(cp)) && isalpha(ch); ) {
615     if( xtype(cp,dp) < 0 ) return -1;
616   }
617
618   return 0;
619 }
620
621 // scan create table line
622 int table(ichar &cp, tobj *top)
623 {
624   string *id = tid(cp);
625   if( !id ) return -1;
626   top->name = id;
627   int ch = *tws(cp);  expect('(');
628   for(;;) {
629     dobj *dp = new dobj(top);
630     if( member(cp,dp) < 0 ) {
631       printf("  err in %s/%s at %d\n",id->c_str(),dp->name->c_str(),cp.no);
632       delete dp;
633       return -1;
634     }
635     top->dop.push_back(dp);
636     if( (ch=*tws(cp)) == ')' ) break;
637     expect(',');
638   }
639   expect(')');
640   while( (id=tid(cp)) ) {
641     ch = *tws(cp);  expect('=');
642     printf("  skipping %s at %d\n",id->c_str(),cp.no);
643     if( isdigit(*tws(cp)) ) while( isdigit(*++cp) );
644     else if( !tid(cp) ) return -1;
645   }
646  ch = *tws(cp);  expect(';');
647   return 0;
648 }
649
650 int iobj::is_direct()
651 {
652   if( is_dir < 0 ) {
653     is_dir = 1;
654     dobjs::iterator ekey = keys.end();
655     dobjs::iterator key = keys.begin();
656     for( int i=0; key!=ekey; ++i ) {
657       dobj *dp = *key++;
658       if( dp->is_integer() ) continue;
659       if( dp->is_double() ) continue;
660       is_dir = 0; break;
661     }
662   }
663   return is_dir;
664 }
665
666 // scan (number)
667 int keylen(ichar &cp, iobj *ip)
668 {
669   int n = 0;
670   int ch = *tws(cp);
671   if( ch == '(' ) {
672     ++cp;  ch = *tws(cp);
673     while( (ch-='0') >= 0 && ch <= 9 ) {
674       n = n*10 + ch;  ch = *++cp;
675     }
676     ch = *tws(cp);  expect(')');
677   }
678   return 0;
679 }
680
681 // scan create index line
682 int index(ichar &cp, iobj *iop)
683 {
684   string *id = tid(cp);
685   if( !id ) return -1;
686   iop->name = id;
687   if( !(id=tid(cp)) ) return -1;
688   if( *id != "On" ) return -1;
689   if( !(id=tid(cp)) ) return -1;
690   tobj *tp = tobj_of(id->c_str());
691   if( !tp ) {
692     printf("index err On:%s at %d\n",id->c_str(),cp.no);
693     return -1;
694   }
695   iop->tbl = tp;
696   int ch = *tws(cp);  expect('(');
697   if( !(id=tid(cp)) ) return -1;
698   dobj *dp = tp->dobj_of(id->c_str());
699   if( !dp ) {
700     printf("index err Key:%s/%s at %d\n",tp->name->c_str(),id->c_str(),cp.no);
701     return -1;
702   }
703   iop->keys.push_back(dp);
704   if( keylen(cp,iop) < 0 ) return -1;
705   while( *tws(cp) == ',' ) {
706     if( !(id=tid(++cp)) ) return -1;
707     dp = tp->dobj_of(id->c_str());
708     if( !dp ) {
709       printf("index err Key:%s/%s at %d\n",tp->name->c_str(),id->c_str(),cp.no);
710       return -1;
711     }
712     iop->keys.push_back(dp);
713     if( keylen(cp,iop) < 0 ) return -1;
714   }
715   ch = *tws(cp);  expect(')');
716   ch = *tws(cp);  expect(';');
717   return 0;
718 }
719
720 // process create line
721 int create(ichar &cp)
722 {
723   int online = -1; (void) online; // avoid unused warn
724   enum { none, unique, fulltext, spatial } modifier = none;
725
726   string *tp = tid(cp);
727   if( *tp == "Table" ) {
728     printf("Create Table at %d\n",cp.no);
729     tobj *top = new tobj();
730     if( table(cp, top) < 0 ) {
731       delete top;
732       return -1;
733     }
734     tables.push_back(top);
735     return 0;
736   }
737   if( *tp == "Online" ) {
738     online = 1;
739     tp = tid(cp);
740   }
741   else if( *tp == "Offine" ) {
742     online = 0;
743     tp = tid(cp);
744   }
745   if( *tp == "Unique" ) {
746     modifier = unique;
747     tp = tid(cp);
748   }
749   else if( *tp == "Fulltext" ) {
750     modifier = fulltext;
751     tp = tid(cp);
752   }
753   else if( *tp == "Spatial" ) {
754     modifier = spatial;
755     tp = tid(cp);
756   }
757   if( *tp == "Index" ) {
758     printf("Create index at %d\n",cp.no);
759     iobj *iop = new iobj();
760     if( index(cp, iop) < 0 ) {
761       delete iop;
762       printf("== FAILED!\n");
763       return -1;
764     }
765     if( modifier == unique ) iop->unique = 1;
766     indecies.push_back(iop);
767     return 0;
768   }
769   fprintf(stderr,"unknown keyword - %s\n", tp->c_str());
770   return -1;
771 }
772
773 void varg_dobj(FILE *sp, dobj *dp, const char *ty, int is_unsign=-1)
774 {
775   const char *tnm = dp->top->name->c_str();
776   const char *nm = dp->name->c_str();
777   fprintf(sp,"const %sObj::t_%s &%s", tnm, nm, nm);
778 }
779
780 void arg_dobj(FILE *sp, dobj *dp, const char *ty, int is_unsign=-1)
781 {
782   if( is_unsign < 0 ) is_unsign = dp->is_unsign;
783   if( is_unsign > 0 ) fprintf(sp, "unsigned ");
784   fprintf(sp,"%s ", ty);
785   if( dp->length > 0 ) fprintf(sp, "*");
786   fprintf(sp,"%s", dp->name->c_str());
787 }
788
789 void arg_dobj(FILE *sp, dobj *dp)
790 {
791   switch( dp->ty ) {
792   case dobj::ty_boolean:
793   case dobj::ty_bit:
794   case dobj::ty_binary:   arg_dobj(sp, dp, "char", 1); break;
795   case dobj::ty_char:
796   case dobj::ty_tinyint:  arg_dobj(sp, dp, "char"); break;
797   case dobj::ty_enum:
798   case dobj::ty_smallint: arg_dobj(sp, dp, "short"); break;
799   case dobj::ty_decimal:
800   case dobj::ty_mediumint:
801   case dobj::ty_integer:  arg_dobj(sp, dp, "int"); break;
802   case dobj::ty_bigint:   arg_dobj(sp, dp, "long"); break;
803   case dobj::ty_real:
804   case dobj::ty_double:   arg_dobj(sp, dp, "double", 0); break;
805   case dobj::ty_float:    arg_dobj(sp, dp, "float", 0); break;
806   case dobj::ty_date:
807   case dobj::ty_time:
808   case dobj::ty_timestamp:
809   case dobj::ty_datetime:
810   case dobj::ty_year:     varg_dobj(sp, dp, "char",0); break;
811   case dobj::ty_varchar:
812     if( dp->is_binary ) { varg_dobj(sp, dp, "char",1); break; }
813   case dobj::ty_tinytext:
814   case dobj::ty_text:
815   case dobj::ty_mediumtext:
816   case dobj::ty_longtext: varg_dobj(sp, dp, "char",0); break;
817   case dobj::ty_varbinary:
818   case dobj::ty_tinyblob:
819   case dobj::ty_blob:
820   case dobj::ty_mediumblob:
821   case dobj::ty_longblob:
822   case dobj::ty_media:    varg_dobj(sp, dp, "char",1); break;
823   default:
824     fprintf(sp,"unimplemented %s,", dp->name->c_str());
825     break;
826   }
827 }
828
829 void put_targs(FILE *sp, tobj *tp, iobj *ip)
830 {
831   dobjs::iterator ekey=ip->keys.end();
832   dobjs::iterator key=ip->keys.begin();
833
834   while( key != ekey ) {
835     dobj *dp = *key++;
836     if( !dp || dp->ty == dobj::ty_none ) {
837       fprintf(stderr," %s member %s error: ty_none\n",
838         tp->name->c_str(),dp->name->c_str());
839       continue;
840     }
841     fprintf(sp,"        ");
842     arg_dobj(sp, dp);
843     if( key == ekey ) break;
844     fprintf(sp,",\n");
845   }
846 }
847
848 const char *typ_dobj(dobj *dp)
849 {
850   const char *cp;
851   switch( dp->ty ) {
852   case dobj::ty_boolean:
853   case dobj::ty_bit:
854   case dobj::ty_binary:    cp = "unsigned char"; break;
855   case dobj::ty_char:
856   case dobj::ty_tinyint:   cp = dp->is_unsign > 0 ? "unsigned char" : "char"; break;
857   case dobj::ty_enum:
858   case dobj::ty_smallint:  cp = dp->is_unsign > 0 ? "unsigned short" : "short"; break;
859   case dobj::ty_decimal:
860   case dobj::ty_mediumint:
861   case dobj::ty_integer:   cp = dp->is_unsign > 0 ? "unsigned int" : "int"; break;
862   case dobj::ty_bigint:    cp = dp->is_unsign > 0 ? "unsigned long" : "long"; break;
863   case dobj::ty_real:
864   case dobj::ty_double:    cp = "double"; break;
865   case dobj::ty_float:     cp = "float"; break;
866   case dobj::ty_date:
867   case dobj::ty_time:
868   case dobj::ty_timestamp:
869   case dobj::ty_datetime:
870   case dobj::ty_year:      cp = "char"; break;
871   case dobj::ty_varchar:
872     if( dp->is_binary ) {  cp = "unsigned char"; break; }
873   case dobj::ty_tinytext:
874   case dobj::ty_text:
875   case dobj::ty_mediumtext:
876   case dobj::ty_longtext:  cp = "char"; break;
877   case dobj::ty_varbinary:
878   case dobj::ty_tinyblob:
879   case dobj::ty_blob:
880   case dobj::ty_mediumblob:
881   case dobj::ty_longblob:
882   case dobj::ty_media:     cp = "unsigned char"; break;
883   default:                 cp = "unimplemented"; break;
884   }
885   return cp;
886 }
887
888 void put_keysz(FILE *sp, tobj *tp, iobj *ip)
889 {
890   dobjs::iterator ekey=ip->keys.end();
891   dobjs::iterator key=ip->keys.begin();
892   const char *tnm = tp->name->c_str();
893
894   while( key != ekey ) {
895     dobj *dp = *key++;
896     const char *nm = dp->name->c_str();
897     fprintf(sp," +sizeof(%sObj::t_%s)", tnm, nm);
898   }
899   if( ip->unique <= 0 ) fprintf(sp,"+sizeof(int)");
900 }
901
902 void put_keys(FILE *sp, tobj *tp, iobj *ip)
903 {
904   dobjs::iterator ekey = ip->keys.end();
905   dobjs::iterator key = ip->keys.begin();
906   const char *tnm = tp->name->c_str();
907
908   while( key != ekey ) {
909     dobj *dp = *key++;
910     const char *nm = dp->name->c_str();
911     fprintf(sp,"    %sObj::t_%s v_%s;\n", tnm, nm, nm);
912   }
913   if( ip->unique <= 0 ) fprintf(sp,"    int v_id;\n");
914 }
915
916 void put_init(FILE *sp, tobj *tp, iobj *ip)
917 {
918   dobjs::iterator ekey = ip->keys.end();
919   dobjs::iterator key = ip->keys.begin();
920
921   while( key != ekey ) {
922     dobj *dp = *key++;
923     const char *nm = dp->name->c_str();
924     fprintf(sp,",\n      v_%s(%s)", nm, nm);
925   }
926 }
927
928 const char *put_cmpr(dobj *dp)
929 {
930   const char *cp;
931   switch( dp->ty ) {
932   case dobj::ty_boolean:
933   case dobj::ty_bit:
934   case dobj::ty_binary:    cp = "uchar"; break;
935   case dobj::ty_char:
936   case dobj::ty_tinyint:   cp = dp->is_unsign > 0 ? "uchar" : "char"; break;
937   case dobj::ty_enum:
938   case dobj::ty_smallint:  cp = dp->is_unsign > 0 ? "ushort" : "short"; break;
939   case dobj::ty_decimal:
940   case dobj::ty_mediumint:
941   case dobj::ty_integer:   cp = dp->is_unsign > 0 ? "uint" : "int"; break;
942   case dobj::ty_bigint:    cp = dp->is_unsign > 0 ? "ulong" : "long"; break;
943   case dobj::ty_real:
944   case dobj::ty_double:    cp = "double"; break;
945   case dobj::ty_float:     cp = "float"; break;
946   case dobj::ty_date:
947   case dobj::ty_time:
948   case dobj::ty_timestamp:
949   case dobj::ty_datetime:
950   case dobj::ty_year:      cp = "char"; break;
951   case dobj::ty_varchar:
952     if( dp->is_binary ) {  cp = "uchar"; break; }
953   case dobj::ty_tinytext:
954   case dobj::ty_text:
955   case dobj::ty_mediumtext:
956   case dobj::ty_longtext:  cp = "char"; break;
957   case dobj::ty_varbinary:
958   case dobj::ty_tinyblob:
959   case dobj::ty_blob:
960   case dobj::ty_mediumblob:
961   case dobj::ty_longblob:  cp = "uchar"; break;
962   case dobj::ty_media:     cp = "media"; break;
963   default:                 cp = "unimplemented"; break;
964   }
965   return cp;
966 }
967
968 void put_rkey(FILE *sp, tobj *tp, iobj *ip)
969 {
970   dobjs::iterator ekey=ip->keys.end();
971   dobjs::iterator key=ip->keys.begin();
972
973   while( key != ekey ) {
974     dobj *dp = *key++;
975     const char *nm = dp->name->c_str();
976     fprintf(sp,"  if( bp ) memcpy(cp, kloc._%s(), kloc.size_%s());\n", nm, nm);
977     fprintf(sp,"  cp += kloc.size_%s();\n", nm);
978   }
979   if( ip->unique <= 0 ) {
980     fprintf(sp,"  if( bp ) memcpy(cp, kloc._id(), kloc._id_size());\n");
981     fprintf(sp,"  cp += kloc._id_size();\n");
982   }
983 }
984
985 void dir_rcmpr(FILE *sp, tobj *tp, iobj *ip)
986 {
987   dobjs::iterator ekey=ip->keys.end();
988   dobjs::iterator key=ip->keys.begin();
989
990   while( key != ekey ) {
991     dobj *dp = *key++;
992     fprintf(sp,"  { %s vv", typ_dobj(dp));
993     if( dp->length > 0 ) fprintf(sp, "[%d]", dp->length);
994     fprintf(sp,"; memcpy(&vv,b,sizeof(vv)); b += sizeof(vv);\n");
995     fprintf(sp,"    int v = cmpr_%s", put_cmpr(dp));
996     const char *nm = dp->name->c_str();
997     fprintf(sp,"( kloc._%s(), kloc->v_%s.size(), &vv", nm, nm);
998     if( dp->length > 0 ) fprintf(sp, "[0]");
999     fprintf(sp,", sizeof(vv));\n");
1000     fprintf(sp,"    if( v != 0 ) return v; }\n");
1001   }
1002   if( ip->unique <= 0 ) {
1003     fprintf(sp,"  int vid; memcpy(&vid,b,sizeof(vid)); b += sizeof(vid);\n");
1004     fprintf(sp,"  int v = cmpr_int(kloc._id(), kloc._id_size(), &vid, sizeof(vid));\n");
1005     fprintf(sp,"  if( v != 0 ) return v;\n");
1006   }
1007 }
1008
1009 void ind_rcmpr(FILE *sp, tobj *tp, iobj *ip)
1010 {
1011   fprintf(sp,"  int b_id; memcpy(&b_id,b,sizeof(b_id));\n");
1012   fprintf(sp,"  if( kloc->id == b_id ) return 0;\n");
1013   fprintf(sp,"  %sLoc vloc(kloc.entity);\n", tp->name->c_str());
1014   fprintf(sp,"  if( vloc.FindId(b_id) )\n");
1015   fprintf(sp,"    kloc.err_(Db::errCorrupt);\n");
1016   dobjs::iterator ekey=ip->keys.end();
1017   dobjs::iterator key=ip->keys.begin();
1018
1019   while( key != ekey ) {
1020     dobj *dp = *key++;
1021     const char *nm = dp->name->c_str();
1022     fprintf(sp,"  { int v = cmpr_%s", put_cmpr(dp));
1023     fprintf(sp,"( kloc._%s(), kloc->v_%s.size(),\n", nm, nm);
1024     fprintf(sp,"                   vloc._%s(), vloc->v_%s.size());\n", nm, nm);
1025     fprintf(sp,"    if( v != 0 ) return v; }\n");
1026   }
1027   if( ip->unique <= 0 ) {
1028     fprintf(sp,"  { int v = cmpr_int(kloc._id(), kloc._id_size(),\n");
1029     fprintf(sp,"               vloc._id(), vloc._id_size());\n");
1030     fprintf(sp,"    if( v != 0 ) return v; }\n");
1031   }
1032 }
1033
1034 void dir_icmpr(FILE *sp, tobj *tp, iobj *ip)
1035 {
1036   dobjs::iterator ekey=ip->keys.end();
1037   dobjs::iterator key=ip->keys.begin();
1038
1039   while( key != ekey ) {
1040     dobj *dp = *key++;
1041     fprintf(sp,"  { %s vv", typ_dobj(dp));
1042     if( dp->length > 0 ) fprintf(sp, "[%d]", dp->length);
1043     fprintf(sp,"; memcpy(&vv,b,sizeof(vv)); b += sizeof(vv);\n");
1044     fprintf(sp,"    int v = cmpr_%s", put_cmpr(dp));
1045     const char *nm = dp->name->c_str();
1046     fprintf(sp,"( kp->v_%s.addr(), kp->v_%s.size(), &vv", nm, nm);
1047     if( dp->length > 0 ) fprintf(sp, "[0]");
1048     fprintf(sp,", sizeof(vv));\n");
1049     fprintf(sp,"    if( v != 0 ) return v; }\n");
1050   }
1051   if( ip->unique <= 0 ) {
1052     fprintf(sp,"  if( kp->v_id >= 0 ) {\n");
1053     fprintf(sp,"    int vid; memcpy(&vid,b,sizeof(vid)); b += sizeof(vid);\n");
1054     fprintf(sp,"    int v = cmpr_int(&kp->v_id, sizeof(kp->v_id), &vid, sizeof(vid));\n");
1055     fprintf(sp,"    if( v != 0 ) return v;\n");
1056     fprintf(sp,"  }\n");
1057   }
1058 }
1059
1060 void ind_icmpr(FILE *sp, tobj *tp, iobj *ip)
1061 {
1062   fprintf(sp,"  int b_id;  memcpy(&b_id,b,sizeof(b_id)); b += sizeof(b_id);\n");
1063   if( ip->unique <= 0 ) fprintf(sp,"  if( kp->v_id == b_id ) return 0;\n");
1064   fprintf(sp,"  %sLoc vloc(kp->loc.entity);\n", tp->name->c_str());
1065   fprintf(sp,"  if( vloc.FindId(b_id) )\n");
1066   fprintf(sp,"    vloc.err_(Db::errCorrupt);\n");
1067
1068   dobjs::iterator ekey=ip->keys.end();
1069   dobjs::iterator key=ip->keys.begin();
1070
1071   while( key != ekey ) {
1072     dobj *dp = *key++;
1073     const char *nm = dp->name->c_str();
1074     fprintf(sp,"  { int v = cmpr_%s", put_cmpr(dp));
1075     fprintf(sp,"( kp->v_%s.addr(), kp->v_%s.size(),\n", nm, nm);
1076     fprintf(sp,"                  vloc._%s(), vloc->v_%s.size());\n", nm, nm);
1077     fprintf(sp,"    if( v != 0 ) return v; }\n");
1078   }
1079   if( ip->unique <= 0 ) {
1080     fprintf(sp,"  if( kp->v_id >= 0 ) {\n");
1081     fprintf(sp,"    int v = cmpr_int(&kp->v_id, sizeof(kp->v_id),\n");
1082     fprintf(sp,"                 vloc._id(), vloc._id_size());\n");
1083     fprintf(sp,"    if( v != 0 ) return v;\n");
1084     fprintf(sp,"  }\n");
1085   }
1086 }
1087
1088 void put_dobj(FILE *sp, dobj *dp, const char *dty, int n)
1089 {
1090   fprintf(sp,"  array_%s(char,%s,%d);\n", dty, dp->name->c_str(), n);
1091 }
1092
1093 void put_dobj(FILE *sp, dobj *dp, const char *dty, const char *ty, int is_unsign=-1)
1094 {
1095   fprintf(sp,"  %s_%s(", dp->length > 0 ? "array" : "basic", dty);
1096   if( is_unsign < 0 ) is_unsign = dp->is_unsign;
1097   if( is_unsign > 0 ) fprintf(sp, "unsigned ");
1098   fprintf(sp,"%s,%s", ty, dp->name->c_str());
1099   if( dp->length > 0 ) fprintf(sp, ",%d", dp->length);
1100   fprintf(sp, ");\n");
1101 }
1102
1103 void put_decl(FILE *sp, dobj *dp, const char *dty)
1104 {
1105   switch( dp->ty ) {
1106   case dobj::ty_boolean:
1107   case dobj::ty_bit:
1108   case dobj::ty_binary:   put_dobj(sp, dp, dty, "char", 1); break;
1109   case dobj::ty_char:
1110   case dobj::ty_tinyint:  put_dobj(sp, dp, dty, "char"); break;
1111   case dobj::ty_enum:
1112   case dobj::ty_smallint: put_dobj(sp, dp, dty, "short"); break;
1113   case dobj::ty_decimal:
1114   case dobj::ty_mediumint:
1115   case dobj::ty_integer:  put_dobj(sp, dp, dty, "int"); break;
1116   case dobj::ty_bigint:   put_dobj(sp, dp, dty, "long"); break;
1117   case dobj::ty_real:
1118   case dobj::ty_double:   put_dobj(sp, dp, dty, "double", 0); break;
1119   case dobj::ty_float:    put_dobj(sp, dp, dty, "float", 0); break;
1120   case dobj::ty_date:     put_dobj(sp, dp, dty, 8); break;
1121   case dobj::ty_time:     put_dobj(sp, dp, dty, 6); break;
1122   case dobj::ty_timestamp:
1123   case dobj::ty_datetime: put_dobj(sp, dp, dty, 14); break;
1124   case dobj::ty_year:     put_dobj(sp, dp, dty, 4); break;
1125   case dobj::ty_text:
1126   case dobj::ty_tinytext:
1127   case dobj::ty_mediumtext:
1128   case dobj::ty_longtext:
1129     fprintf(sp,"  sarray_%s(char,%s);\n", dty, dp->name->c_str());
1130     break;
1131   case dobj::ty_varchar:
1132     if( !dp->is_binary ) {
1133       fprintf(sp,"  varray_%s(char,%s);\n", dty, dp->name->c_str());
1134       break;
1135     }
1136   case dobj::ty_varbinary:
1137   case dobj::ty_blob:
1138   case dobj::ty_tinyblob:
1139   case dobj::ty_mediumblob:
1140   case dobj::ty_longblob:
1141   case dobj::ty_media:
1142     fprintf(sp,"  varray_%s(unsigned char,%s);\n", dty, dp->name->c_str());
1143     dp->is_unsign = 1;
1144     break;
1145   default:
1146     fprintf(sp," %s %s unimplemented;\n", dty, dp->name->c_str());
1147     break;
1148   }
1149 }
1150
1151
1152 int main(int ac, char **av)
1153 {
1154   const char *tdb = ac > 1 ? av[1] : "theDb";
1155   const char *sfn = ac > 2 ? av[2] : "./s";
1156
1157   setbuf(stdout,0);
1158   setbuf(stderr,0);
1159   ichar cp(stdin);
1160
1161   for( string *sp=tid(cp); sp!=0; sp=tid(cp) ) {
1162     if( *sp == "Create" ) create(cp);
1163   }
1164
1165   printf(" %d Tables\n",(int)tables.size());
1166   printf(" %d Indecies\n",(int)indecies.size());
1167
1168   char fn[512];  sprintf(fn,"%s.h",sfn);
1169   FILE *sp = fopen(fn,"w");
1170
1171   // get basename for sfn.h, _SFN_H_
1172   const char *bp = 0;
1173   for( const char *ap=sfn; *ap; ++ap )
1174     if( *ap == '/' ) bp = ap+1;
1175   if( !bp ) bp = sfn;
1176   char ups[512], *up = ups;  *up++ = '_';
1177   for( const char *cp=bp; *cp; ++cp ) *up++ = toupper(*cp);
1178   *up++ = '_';  *up++ = 'H';  *up++ = '_';  *up = 0;
1179
1180   fprintf(sp,"#ifndef %s\n",ups);
1181   fprintf(sp,"#define %s\n",ups);
1182   fprintf(sp,"#include <cstdio>\n");
1183   fprintf(sp,"#include <stdlib.h>\n");
1184   fprintf(sp,"#include <unistd.h>\n");
1185   fprintf(sp,"#include <fcntl.h>\n");
1186   fprintf(sp,"#include <errno.h>\n");
1187   fprintf(sp,"\n");
1188   fprintf(sp,"#include \"tdb.h\"\n");
1189   fprintf(sp,"\n");
1190   fprintf(sp,"\n");
1191
1192   list<tobj*>::iterator sit = tables.begin();
1193   list<tobj*>::iterator eit = tables.end();
1194   list<tobj*>::iterator it;
1195
1196   list<iobj*>::iterator sidx = indecies.begin();
1197   list<iobj*>::iterator eidx = indecies.end();
1198   list<iobj*>::iterator idx;
1199
1200   for( idx=sidx; idx!=eidx; ++idx ) {
1201       iobj *ip = *idx;
1202       ip->is_dir = ip->is_direct();
1203   }
1204
1205   int i=0;
1206   for( it=sit ; it!=eit; ++i, ++it ) {
1207     tobj *tp = *it;
1208     const char *tnm = tp->name->c_str();
1209     printf(" %2d. %s (",i,tnm);
1210     fprintf(sp,"// %s\n",tnm);
1211     fprintf(sp,"DbObj(%s)\n",tnm);
1212
1213     list<dobj*>::iterator sid = tp->dop.begin();
1214     list<dobj*>::iterator eid = tp->dop.end();
1215     list<dobj*>::iterator id;
1216
1217     // output table member declarations
1218     for( id=sid ; id!=eid; ++id ) {
1219       dobj *dp = *id;
1220       printf(" %s",dp->name->c_str());
1221       if( dp->ty == dobj::ty_none ) {
1222         fprintf(stderr," %s member %s error: ty_none\n",
1223           tnm,dp->name->c_str());
1224         continue;
1225       }
1226       put_decl(sp,dp,"def");
1227     }
1228     printf(" )\n");
1229
1230     fprintf(sp,"};\n");
1231     fprintf(sp,"\n");
1232
1233     int j = 0, n = 0;
1234     for( idx=sidx; idx!=eidx; ++idx ) {
1235       iobj *ip = *idx;
1236       if( ip->tbl != tp ) continue;
1237       ++n;
1238       printf("   %2d.%d%c %s on %s(",i,j++,
1239         ip->is_dir>0 ? '=' : '.',
1240         ip->name->c_str(),tp->name->c_str());
1241       dobjs::iterator ekey=ip->keys.end();
1242       dobjs::iterator key=ip->keys.begin();
1243
1244       while( key != ekey ) {
1245         dobj *dp = *key++;
1246         printf(" %s", dp->name->c_str());
1247       }
1248       printf(" )\n");
1249     }
1250     if( n > 0 ) printf("\n");
1251
1252     // output table member accessors
1253     fprintf(sp,"DbLoc(%s)\n",tnm);
1254     for( id=sid ; id!=eid; ++id ) {
1255       dobj *dp = *id;
1256       if( dp->ty == dobj::ty_none ) {
1257         fprintf(stderr," %s member %s error: ty_none\n",
1258           tnm,dp->name->c_str());
1259         continue;
1260       }
1261       put_decl(sp, dp, "ref");
1262     }
1263
1264     for( idx=sidx; idx!=eidx; ++idx ) {
1265       iobj *ip = *idx;
1266       if( ip->tbl != tp ) continue;
1267       const char *knm = ip->name->c_str();
1268       fprintf(sp,"\n");
1269       fprintf(sp,"  class key_%s { public:\n", knm);
1270       fprintf(sp,"    static const int size() { return 0");
1271       put_keysz(sp, *it, ip);
1272       fprintf(sp,"; }\n");
1273       fprintf(sp,"  };\n");
1274       fprintf(sp,"\n");
1275       fprintf(sp,"  class ikey_%s : public Db::iKey { public:\n", knm);
1276       put_keys(sp, *it, ip);
1277       fprintf(sp,"    static int icmpr(char *a, char *b);\n");
1278       // key constructors
1279       fprintf(sp,"    ikey_%s(ObjectLoc &loc,\n", knm);
1280       put_targs(sp, *it, ip);
1281       if( ip->unique <= 0 ) fprintf(sp,", int id=-1");
1282       fprintf(sp,")\n    : iKey(\"%s\",loc,icmpr)", knm);
1283       put_init(sp, *it, ip);
1284       if( ip->unique <= 0 ) fprintf(sp,",\n      v_id(id)");
1285       fprintf(sp," {}\n");
1286       fprintf(sp,"  };\n");
1287       fprintf(sp,"  class rkey_%s : public Db::rKey { public:\n", knm);
1288       fprintf(sp,"    static int rcmpr(char *a, char *b);\n");
1289       fprintf(sp,"    rkey_%s(ObjectLoc &loc) : rKey(\"%s\",loc,rcmpr) {}\n", knm, knm);
1290       fprintf(sp,"    int wr_key(char *cp=0);\n");
1291       fprintf(sp,"  };\n");
1292     }
1293     fprintf(sp,"\n");
1294     fprintf(sp,"  int Allocate();\n");
1295     fprintf(sp,"  int Construct();\n");
1296     fprintf(sp,"  int Destruct();\n");
1297     fprintf(sp,"  void Deallocate();\n");
1298 #ifdef COPY
1299     fprintf(sp,"  int Copy(ObjectLoc &that);\n");
1300 #endif
1301     fprintf(sp,"};\n");
1302   }
1303   fprintf(sp,"\n");
1304
1305   fprintf(sp,"\n");
1306   fprintf(sp,"class %s : public Db {\n",tdb);
1307   fprintf(sp,"  int dfd, dkey, no_atime;\n");
1308   fprintf(sp,"  int db_create();\n");
1309   fprintf(sp,"  int db_open();\n");
1310   fprintf(sp,"  int db_access();\n");
1311   fprintf(sp,"public:\n");
1312   fprintf(sp,"  Objects objects;\n");
1313   for( it=sit ; it!=eit; ++it ) {
1314     tobj *tp = *it;
1315     const char *tnm = tp->name->c_str();
1316     fprintf(sp,"  Entity %s;  %sLoc %c%s;\n", tnm, tnm, tolower(tnm[0]), &tnm[1]);
1317   }
1318   fprintf(sp,"\n");
1319   fprintf(sp,"  int create(const char *dfn);\n");
1320   fprintf(sp,"  int open(const char *dfn, int key=-1);\n");
1321   fprintf(sp,"  int access(const char *dfn, int key=-1, int rw=0);\n");
1322   fprintf(sp,"  void close();\n");
1323   fprintf(sp,"  int attach(int rw=0) { return Db::attach(rw); }\n");
1324   fprintf(sp,"  int detach() { return Db::detach(); }\n");
1325   fprintf(sp,"\n");
1326   fprintf(sp,"  %s();\n",tdb);
1327   fprintf(sp,"  ~%s() { finit(objects); }\n",tdb);
1328   fprintf(sp,"};\n");
1329   fprintf(sp,"\n");
1330   fprintf(sp,"#endif\n");
1331   fclose(sp);
1332
1333   sprintf(fn,"%s.C",sfn);
1334   sp = fopen(fn,"w");
1335   fprintf(sp,"#include \"%s.h\"\n",bp);
1336   fprintf(sp,"\n");
1337
1338   for( it=sit ; it!=eit; ++it ) {
1339     tobj *tp = *it;
1340     const char * tnm = tp->name->c_str();
1341
1342     for( idx=sidx; idx!=eidx; ++idx ) {
1343       iobj *ip = *idx;
1344       if( ip->tbl != tp ) continue;
1345       const char *knm = ip->name->c_str();
1346       fprintf(sp,"\n");
1347       fprintf(sp,"int %sLoc::ikey_%s::\n", tnm, knm);
1348       fprintf(sp,"icmpr(char *a, char *b)\n");
1349       fprintf(sp,"{\n");
1350       fprintf(sp,"  ikey_%s *kp = (ikey_%s *)a;\n", knm, knm);
1351       (ip->is_dir>0 ? dir_icmpr : ind_icmpr)(sp, tp, ip);
1352       fprintf(sp,"  return 0;\n");
1353       fprintf(sp,"}\n");
1354       fprintf(sp,"int %sLoc::rkey_%s::\n", tnm, knm);
1355       fprintf(sp,"rcmpr(char *a, char *b)\n");
1356       fprintf(sp,"{\n");
1357       fprintf(sp,"  rkey_%s *kp = (rkey_%s *)a;\n", knm, knm);
1358       fprintf(sp,"  %sLoc &kloc = (%sLoc&)kp->loc;\n", tnm, tnm);
1359       (ip->is_dir>0 ? dir_rcmpr : ind_rcmpr)(sp, tp, ip);
1360       fprintf(sp,"  return 0;\n");
1361       fprintf(sp,"}\n");
1362       fprintf(sp,"int %sLoc::rkey_%s::\n", tnm, knm);
1363       fprintf(sp,"wr_key(char *bp)\n");
1364       fprintf(sp,"{\n");
1365       fprintf(sp,"  char *cp = bp;\n");
1366       fprintf(sp,"  %sLoc &kloc = (%sLoc&)loc;\n", tnm, tnm);
1367       put_rkey(sp, tp, ip);
1368       fprintf(sp,"  return cp-bp;\n");
1369       fprintf(sp,"}\n");
1370     }
1371     fprintf(sp,"\n");
1372     fprintf(sp,"int %sLoc::Allocate()\n", tnm);
1373     fprintf(sp,"{\n");
1374     fprintf(sp,"  if_err( allocate() );\n");
1375     fprintf(sp,"  if( !addr_wr() ) return err_(Db::errNoMemory);\n");
1376
1377     int n = 0;
1378     list<dobj*>::iterator sid = tp->dop.begin();
1379     list<dobj*>::iterator eid = tp->dop.end();
1380     list<dobj*>::iterator id;
1381
1382     for( id=sid ; !n && id!=eid; ++id ) {
1383       dobj *dp = *id;
1384       switch( dp->ty ) {
1385       case dobj::ty_varchar:
1386       case dobj::ty_tinytext:
1387       case dobj::ty_text:
1388       case dobj::ty_mediumtext:
1389       case dobj::ty_longtext:
1390       case dobj::ty_varbinary:
1391       case dobj::ty_tinyblob:
1392       case dobj::ty_blob:
1393       case dobj::ty_mediumblob:
1394       case dobj::ty_longblob:
1395       case dobj::ty_media:
1396         if( !n++ ) fprintf(sp,"  v_init();\n");
1397         break;
1398       default:
1399         break;
1400       }
1401     }
1402
1403     for( id=sid ; id!=eid; ++id ) {
1404       dobj *dp = *id;
1405       const char *dnm = dp->name->c_str();
1406       if( dp->is_autoincr > 0 && dp->idx ) {
1407         const char *inm = dp->idx->name->c_str();
1408         fprintf(sp,"  { %s", typ_dobj(dp));
1409         fprintf(sp," (%sLoc::*fn)() = &%sLoc::%s;\n", tnm, tnm, dnm);
1410         fprintf(sp,"    %s", typ_dobj(dp));
1411         fprintf(sp," v = last(\"%s\",(%s", inm, typ_dobj(dp));
1412         fprintf(sp," (Db::ObjectLoc::*)())fn);  %s(v+1); }\n", dnm);
1413       }
1414       if( dp->has_def > 0 ) {
1415         switch( dp->has_def ) {
1416         case dobj::def_integer:
1417           fprintf(sp,"  %s(%d);\n", dnm, dp->def.i);
1418           break;
1419         case dobj::def_double:
1420           fprintf(sp,"  %s(%f);\n", dnm, dp->def.d);
1421           break;
1422         case dobj::def_string:
1423           switch( dp->ty ) {
1424           case dobj::ty_enum: {
1425             list<string*>::iterator snm = dp->eop.begin();
1426             list<string*>::iterator enm = dp->eop.end();
1427             list<string*>::iterator nm;
1428             for( n=0,nm=snm; nm!=enm && *(*nm)!=*dp->def.s; ++nm ) ++n;
1429             fprintf(sp,"  %s(%d);\n", dnm, n);
1430             break; }
1431           case dobj::ty_boolean:
1432           case dobj::ty_bit:
1433           case dobj::ty_tinyint:
1434           case dobj::ty_smallint:
1435           case dobj::ty_decimal:
1436           case dobj::ty_mediumint:
1437           case dobj::ty_integer:
1438           case dobj::ty_bigint: {
1439             fprintf(sp,"  %s(%ld);\n", dnm, strtol(dp->def.s->c_str(),0,0));
1440             break; }
1441           case dobj::ty_real:
1442           case dobj::ty_double:
1443           case dobj::ty_float: {
1444             fprintf(sp,"  %s(%f);\n", dnm, strtod(dp->def.s->c_str(),0));
1445             break; }
1446           case dobj::ty_date:
1447           case dobj::ty_time:
1448           case dobj::ty_timestamp:
1449           case dobj::ty_binary:
1450           case dobj::ty_char:
1451           case dobj::ty_datetime:
1452           case dobj::ty_year:
1453           case dobj::ty_varchar:
1454           case dobj::ty_tinytext:
1455           case dobj::ty_text:
1456           case dobj::ty_mediumtext:
1457           case dobj::ty_longtext:
1458           case dobj::ty_varbinary:
1459           case dobj::ty_tinyblob:
1460           case dobj::ty_blob:
1461           case dobj::ty_mediumblob:
1462           case dobj::ty_longblob:
1463           case dobj::ty_media: {
1464             fprintf(sp,"  %s((%s", dnm, typ_dobj(dp));
1465             fprintf(sp," *)\"%s\",%d);\n", dp->def.s->c_str(), (int)dp->def.s->size());
1466             break; }
1467           default:
1468             break;
1469           }
1470           break;
1471         default:
1472           break;
1473         }
1474       }
1475     }
1476     fprintf(sp,"  return 0;\n");
1477     fprintf(sp,"}\n");
1478     fprintf(sp,"\n");
1479     fprintf(sp,"int %sLoc::Construct()\n", tnm);
1480     fprintf(sp,"{\n");
1481     fprintf(sp,"  if_err( insertProhibit() );\n");
1482     fprintf(sp,"  if_err( construct() );\n");
1483     n = 0;
1484     for( idx=sidx; idx!=eidx; ++idx ) {
1485       iobj *ip = *idx;
1486       if( ip->tbl != tp ) continue;
1487       const char *knm = ip->name->c_str();
1488       fprintf(sp,"  { rkey_%s rkey(*this);\n",knm);
1489       fprintf(sp,"    if_err( entity->index(\"%s\")->Insert(rkey,(void*)_id()) ); }\n", knm);
1490     }
1491     fprintf(sp,"  if_err( insertCascade() );\n");
1492     fprintf(sp,"  return 0;\n");
1493     fprintf(sp,"}\n");
1494     fprintf(sp,"\n");
1495     fprintf(sp,"int %sLoc::Destruct()\n", tnm);
1496     fprintf(sp,"{\n");
1497     fprintf(sp,"  if_err( deleteProhibit() );\n");
1498     for( idx=sidx; idx!=eidx; ++idx ) {
1499       iobj *ip = *idx;
1500       if( ip->tbl != tp ) continue;
1501       const char *knm = ip->name->c_str();
1502       fprintf(sp,"  { rkey_%s rkey(*this);\n",knm);
1503       fprintf(sp,"    if_err( entity->index(\"%s\")->Delete(rkey) ); }\n",knm);
1504     }
1505     fprintf(sp,"  if_err( destruct() );\n");
1506     fprintf(sp,"  if_err( deleteCascade() );\n");
1507     fprintf(sp,"  return 0;\n");
1508     fprintf(sp,"}\n");
1509     fprintf(sp,"\n");
1510     fprintf(sp,"void %sLoc::Deallocate()\n", tnm);
1511     fprintf(sp,"{\n");
1512     n = 0;
1513     for( id=sid ; !n && id!=eid; ++id ) {
1514       dobj *dp = *id;
1515       switch( dp->ty ) {
1516       case dobj::ty_varchar:
1517       case dobj::ty_tinytext:
1518       case dobj::ty_text:
1519       case dobj::ty_mediumtext:
1520       case dobj::ty_longtext:
1521       case dobj::ty_varbinary:
1522       case dobj::ty_tinyblob:
1523       case dobj::ty_blob:
1524       case dobj::ty_mediumblob:
1525       case dobj::ty_longblob:
1526       case dobj::ty_media:
1527         if( !n++ ) fprintf(sp,"  v_del();\n");
1528         break;
1529       default:
1530         break;
1531       }
1532     }
1533     fprintf(sp,"  deallocate();\n");
1534     fprintf(sp,"}\n");
1535     fprintf(sp,"\n");
1536   }
1537
1538   fprintf(sp,"\n");
1539   fprintf(sp,"int %s::\n",tdb);
1540   fprintf(sp,"create(const char *dfn)\n");
1541   fprintf(sp,"{\n");
1542   fprintf(sp,"  dfd = ::open(dfn,O_RDWR+O_CREAT+O_TRUNC+no_atime,0666);\n");
1543   fprintf(sp,"  if( dfd < 0 ) { perror(dfn); return -1; }\n");
1544   fprintf(sp,"  int ret = db_create();\n");
1545   fprintf(sp,"  close();\n");
1546   fprintf(sp,"  return ret;\n");
1547   fprintf(sp,"}\n");
1548   fprintf(sp,"\n");
1549   fprintf(sp,"int %s::\n",tdb);
1550   fprintf(sp,"db_create()\n");
1551   fprintf(sp,"{\n");
1552   fprintf(sp,"  if_ret( Db::make(dfd) );\n");
1553   for( it=sit ; it!=eit; ++it ) {
1554     tobj *tp = *it;
1555     const char *tnm = tp->name->c_str();
1556     fprintf(sp,"  if_ret( %s.new_entity(\"%s\", sizeof(%sObj)) );\n", tnm, tnm, tnm);
1557     for( idx=sidx; idx!=eidx; ++idx ) {
1558       iobj *ip = *idx;
1559       if( ip->tbl != tp ) continue;
1560       const char *nm = ip->name->c_str();
1561       if( ip->is_dir > 0 )
1562         fprintf(sp,"  if_ret( %s.add_dir_index(\"%s\", %sLoc::key_%s::size()) );\n",
1563           tnm, nm, tnm, nm);
1564       else
1565         fprintf(sp,"  if_ret( %s.add_ind_index(\"%s\") );\n", tnm, nm);
1566     }
1567     fprintf(sp,"\n");
1568   }
1569   fprintf(sp,"  if_ret( Db::commit(1) );\n");
1570   fprintf(sp,"  return 0;\n");
1571   fprintf(sp,"}\n");
1572   fprintf(sp,"\n");
1573
1574   fprintf(sp,"%s::\n", tdb);
1575   fprintf(sp,"%s()\n", tdb);
1576   fprintf(sp," : dfd(-1), dkey(-1), no_atime(getuid()?0:O_NOATIME), objects(0)");
1577   for( it=sit ; it!=eit; ++it ) {
1578     tobj *tp = *it;
1579     const char *tnm = tp->name->c_str();
1580     fprintf(sp,",\n   %s(this)", tnm);
1581     fprintf(sp,", %c%s(%s)", tolower(tnm[0]), &tnm[1], tnm);
1582   }
1583   fprintf(sp,"\n");
1584   fprintf(sp,"{");
1585   for( it=sit ; it!=eit; ++it ) {
1586     tobj *tp = *it;
1587     const char *tnm = tp->name->c_str();
1588     fprintf(sp,"\n  objects = new ObjectList(objects, %c%s);",
1589       tolower(tnm[0]), &tnm[1]);
1590   }
1591   fprintf(sp,"\n");
1592   for( it=sit ; it!=eit; ++it ) {
1593     tobj *tp = *it;
1594     const char *tnm = tp->name->c_str();
1595     list<dobj*>::iterator sid = tp->dop.begin();
1596     list<dobj*>::iterator eid = tp->dop.end();
1597     list<dobj*>::iterator id;
1598     for( id=sid ; id!=eid; ++id ) {
1599       dobj *dp = *id;
1600       const char *dnm = dp->name->c_str();
1601       switch( dp->ty ) {
1602       case dobj::ty_varchar:
1603       case dobj::ty_tinytext:
1604       case dobj::ty_text:
1605       case dobj::ty_mediumtext:
1606       case dobj::ty_longtext:
1607       case dobj::ty_varbinary:
1608       case dobj::ty_tinyblob:
1609       case dobj::ty_blob:
1610       case dobj::ty_mediumblob:
1611       case dobj::ty_longblob:
1612       case dobj::ty_media: {
1613         fprintf(sp,"  %s.add_vref((vRef)&%sObj::v_%s);\n", tnm, tnm, dnm);
1614         break; }
1615       default:
1616         break;
1617       }
1618     }
1619   }
1620   fprintf(sp,"}\n");
1621   fprintf(sp,"\n");
1622
1623   fprintf(sp,"int %s::\n",tdb);
1624   fprintf(sp,"open(const char *dfn, int key)\n");
1625   fprintf(sp,"{\n");
1626   fprintf(sp,"  dfd = ::open(dfn,O_RDWR+no_atime);\n");
1627   fprintf(sp,"  if( dfd < 0 ) { perror(dfn); return errNotFound; }\n");
1628   fprintf(sp,"  if( (dkey=key) >= 0 ) Db::use_shm(1);\n");
1629   fprintf(sp,"  int ret = Db::open(dfd, dkey);\n");
1630   fprintf(sp,"  if( !ret ) ret = db_open();\n");
1631   fprintf(sp,"  if( ret ) close();\n");
1632   fprintf(sp,"  return ret;\n");
1633   fprintf(sp,"}\n");
1634   fprintf(sp,"\n");
1635
1636   fprintf(sp,"int %s::\n",tdb);
1637   fprintf(sp,"db_open()\n");
1638   fprintf(sp,"{\n");
1639   for( it=sit ; it!=eit; ++it ) {
1640     tobj *tp = *it;
1641     const char *tnm = tp->name->c_str();
1642     fprintf(sp,"  if_ret( %s.get_entity(\"%s\") );\n", tnm, tnm);
1643     for( idx=sidx; idx!=eidx; ++idx ) {
1644       iobj *ip = *idx;
1645       if( ip->tbl != tp ) continue;
1646       const char *nm = ip->name->c_str();
1647       fprintf(sp,"  if_ret( %s.get_index(\"%s\") );\n", tnm, nm);
1648     }
1649     fprintf(sp,"\n");
1650   }
1651   fprintf(sp,"  if_ret( Db::start_transaction() );\n");
1652   fprintf(sp,"  return 0;\n");
1653   fprintf(sp,"}\n");
1654   fprintf(sp,"\n");
1655   fprintf(sp,"void %s::\n",tdb);
1656   fprintf(sp,"close()\n");
1657   fprintf(sp,"{\n");
1658   fprintf(sp,"  Db::close();\n");
1659   fprintf(sp,"  if( dfd >= 0 ) { ::close(dfd); dfd = -1; }\n");
1660   fprintf(sp,"}\n");
1661   fprintf(sp,"\n");
1662   fprintf(sp,"int %s::\n",tdb);
1663   fprintf(sp,"access(const char *dfn, int key, int rw)\n");
1664   fprintf(sp,"{\n");
1665   fprintf(sp,"  if( key < 0 ) return Db::errInvalid;\n");
1666   fprintf(sp,"  dfd = ::open(dfn,O_RDWR+no_atime);\n");
1667   fprintf(sp,"  if( dfd < 0 ) { perror(dfn); return Db::errNotFound; }\n");
1668   fprintf(sp,"  dkey = key;  Db::use_shm(1);\n");
1669   fprintf(sp,"  int ret = Db::attach(dfd, dkey, rw);\n");
1670   fprintf(sp,"  if( !ret ) ret = db_access();\n");
1671   fprintf(sp,"  else if( ret == errNotFound ) {\n");
1672   fprintf(sp,"    ret = Db::open(dfd, dkey);\n");
1673   fprintf(sp,"    if( !ret ) ret = db_open();\n");
1674   fprintf(sp,"    if( !ret ) ret = Db::attach(rw);\n");
1675   fprintf(sp,"  }\n");
1676   fprintf(sp,"  if( ret ) close();\n");
1677   fprintf(sp,"  return ret;\n");
1678   fprintf(sp,"}\n");
1679   fprintf(sp,"\n");
1680   fprintf(sp,"int %s::\n",tdb);
1681   fprintf(sp,"db_access()\n");
1682   fprintf(sp,"{\n");
1683   for( it=sit ; it!=eit; ++it ) {
1684     tobj *tp = *it;
1685     const char *tnm = tp->name->c_str();
1686     fprintf(sp,"  if_ret( %s.get_entity(\"%s\") );\n", tnm, tnm);
1687   }
1688   fprintf(sp,"  return 0;\n");
1689   fprintf(sp,"}\n");
1690   fprintf(sp,"\n");
1691   fprintf(sp,"\n");
1692   printf("ended on line %d - ",cp.no);
1693   for( int i=0, n=cp.i; i<n; ++i ) printf("%c",cp.line[i]);
1694   printf("|");
1695   for( int i=cp.i, n=cp.n; i<n; ++i ) printf("%c",cp.line[i]);
1696   printf("\n");
1697   return 0;
1698 }
1699