9 #define MAX_LINE_SZ 256
10 #define expect(c) do { if( ch != c ) return -1; ++cp; } while(0)
15 char line[MAX_LINE_SZ];
17 iline(FILE *f) : fp(f), pos(0), no(0) {}
19 fp = i.fp; pos = i.pos;
20 strcpy(line,i.line); no = i.no;
24 class ichar : public virtual iline {
27 ichar(FILE *f) : iline(f) { i = n = 0; }
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);
38 ichar &operator ++(ichar &t) { ++t.i; return t; }
39 char operator ++(ichar &t,int) { return t.line[t.i++]; }
41 char &ichar::operator *()
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;
49 if( ch == '\n' ) ++no;
57 typedef list<string *> eobjs;
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;
72 var_types = (1<<ty_varchar) | (1<<ty_varbinary) | (1<<ty_blob) |
73 (1<<ty_tinyblob) | (1<<ty_mediumblob) | (1<<ty_longblob) |
75 text_types = (1<<ty_text) |
76 (1<<ty_tinytext) | (1<<ty_mediumtext) | (1<<ty_longtext),
78 int is_var() { return (var_types>>ty) & 1; }
79 int is_text() { return (text_types>>ty) & 1; }
80 int length, zeroed, is_null, is_autoincr, is_binary, is_unsign, has_def;
83 enum def_type { def_none, def_integer, def_double, def_string, def_null, };
84 union { int i; double d; string *s; } def;
85 dobj(tobj *tp) : top(tp) {
86 ty = ty_none; idx = 0;
87 length = zeroed = is_null = is_autoincr = is_binary = is_unsign = has_def = -1;
92 typedef list<dobj*> dobjs;
99 tobj() : name(0), dop(0) {}
110 kobj(string *s) : name(s) {}
114 typedef list<kobj> kobjs;
125 iobj() : name(0), tbl(0), unique(0), primary(0), length(-1) {}
129 list<iobj*> indecies;
135 enum { xref_no_action, xref_restrict, xref_cascade, xref_set_null, };
136 int on_delete, on_update;
138 robj() : on_delete(xref_no_action), on_update(xref_no_action) {}
148 if( isspace(*b) ) { ++b; continue; }
149 if( *b == '/' && b[1] == '*' ) {
150 ++b; do { ++b; } while( *b != '*' || b[1] != '/' );
153 else if( *b == '-' && b[1] == '-' ) {
154 ++b; do { ++b; } while( *b != '\n' );
164 string *tid(ichar &c, string *sp=0)
168 if( *b && (isalpha(*b) || *b == '_') ) {
169 rp = !sp ? new string() : sp;
170 rp->push_back(toupper(b++));
171 while( *b && (isalpha(*b) || isdigit(*b) || *b == '_') ) {
172 rp->push_back(tolower(b++));
179 // scan string '..' or ".."
180 int str_value(ichar &cp, string *&sp)
182 ichar bp = cp; sp = 0;
184 if( ch != '\'' && ch != '"' ) return -1;
185 int delim = ch; ++cp;
186 for( sp=new string(); (ch=*cp) && ch != delim; ++cp ) {
187 if( ch == '\\' && !(ch=*++cp) ) break;
199 // scan string '..' or "..", or number, or NULL
200 int def_value(ichar &cp, dobj *dp)
203 if( str_value(cp,dp->def.s) >= 0 ) {
204 dp->has_def = dobj::def_string;
208 if( isdigit(ch) || ch == '-' || ch == '+' ) {
210 if( ch == '-' ) sign = -1;
211 if( ch == '+' ) sign = 1;
212 if( sign ) ++cp; else sign = 1;
214 while( (ch-='0') >= 0 && ch <= 9 ) {
215 n = n*10 + ch; ch = *++cp;
220 while( (ch-='0') >= 0 && ch <= 9 ) {
221 v = v + ch/(frac*=10); ch = *++cp;
223 dp->has_def = dobj::def_double;
224 dp->def.d = v * sign;
227 dp->has_def = dobj::def_integer;
228 dp->def.i = n * sign;
232 string *id = tid(cp);
234 if( *id == "Null" ) {
235 dp->has_def = dobj::def_null;
246 int dimen(ichar &cp, dobj *dp)
252 while( (ch-='0') >= 0 && ch <= 9 ) {
253 n = n*10 + ch; ch = *++cp;
255 ch = *tws(cp); expect(')');
261 // scan Unsigned or Signed, Zerofill
262 int numeric(ichar &cp, dobj *dp)
265 string *id = tid(cp);
266 if( id && *id == "Unsigned" ) {
268 bp = cp; id = tid(cp);
270 else if( id && *id == "Signed" ) {
272 bp = cp; id = tid(cp);
274 if( id && *id == "Zerofill" ) {
282 // (number) or numeric qualifier
283 int dimen0(ichar &cp, dobj *dp)
285 return dimen(cp, dp) < 0 || numeric(cp, dp) < 0 ? -1 : 0;
289 int dtype(ichar &cp, dobj *dp)
291 string *id = tid(cp);
295 dp->ty = dobj::ty_bit;
296 if( dimen0(cp, dp) < 0 ) return -1;
300 if( *id == "Tinyint" ) {
301 dp->ty = dobj::ty_tinyint;
302 if( dimen0(cp, dp) < 0 ) return -1;
306 if( *id == "Smallint" ) {
307 dp->ty = dobj::ty_smallint;
308 if( dimen0(cp, dp) < 0 ) return -1;
312 if( *id == "Mediumint" ) {
313 dp->ty = dobj::ty_mediumint;
314 if( dimen0(cp, dp) < 0 ) return -1;
318 if( *id == "Int" || *id == "Integer" ) {
319 dp->ty = dobj::ty_integer;
320 if( dimen0(cp, dp) < 0 ) return -1;
324 if( *id == "Bigint" ) {
325 dp->ty = dobj::ty_bigint;
326 if( dimen0(cp, dp) < 0 ) return -1;
330 if( *id == "Real" ) {
331 dp->ty = dobj::ty_real;
332 if( dimen0(cp, dp) < 0 ) return -1;
336 if( *id == "Double" ) {
337 dp->ty = dobj::ty_double;
338 if( dimen0(cp, dp) < 0 ) return -1;
342 if( *id == "Float" ) {
343 dp->ty = dobj::ty_float;
344 if( dimen0(cp, dp) < 0 ) return -1;
348 if( *id == "Decimal" ) {
349 dp->ty = dobj::ty_decimal;
350 if( dimen0(cp, dp) < 0 ) return -1;
354 if( *id == "Date" ) {
355 dp->ty = dobj::ty_date;
358 else if( *id == "Time" ) {
359 dp->ty = dobj::ty_time;
362 else if( *id == "Timestamp" ) {
363 dp->ty = dobj::ty_timestamp;
366 else if( *id == "Datetime" ) {
367 dp->ty = dobj::ty_datetime;
370 else if( *id == "Year" ) {
371 dp->ty = dobj::ty_year;
375 if( *id == "Char" ) {
376 dp->ty = dobj::ty_char;
377 if( dimen(cp, dp) < 0 ) return -1;
381 if( *id == "Varchar" ) {
382 dp->ty = dobj::ty_varchar;
383 if( dimen(cp, dp) < 0 ) return -1;
384 if( (id=tid(cp)) != 0 ) {
386 if( *id == "Binary" ) {
395 if( *id == "Binary" ) {
396 dp->ty = dobj::ty_binary;
397 if( dimen(cp, dp) < 0 ) return -1;
401 if( *id == "Varbinary" ) {
402 dp->ty = dobj::ty_varbinary;
403 if( dimen(cp, dp) < 0 ) return -1;
407 if( *id == "Tinyblob" ) {
408 dp->ty = dobj::ty_tinyblob;
412 if( *id == "Blob" ) {
413 dp->ty = dobj::ty_blob;
417 if( *id == "Mediumblob" ) {
419 dp->ty = dobj::ty_mediumblob;
423 if( *id == "Longblob" ) {
424 dp->ty = dobj::ty_longblob;
428 if( *id == "Tinytext" ) {
429 dp->ty = dobj::ty_tinytext;
433 if( *id == "Text" ) {
434 dp->ty = dobj::ty_text;
438 if( *id == "Mediumtext" ) {
439 dp->ty = dobj::ty_mediumtext;
443 if( *id == "Longtext" ) {
444 dp->ty = dobj::ty_longtext;
448 if( *id == "Bool" || *id == "Boolean" ) {
449 dp->ty = dobj::ty_boolean;
453 if( *id == "Enum" ) {
454 dp->ty = dobj::ty_enum;
455 int ch = *tws(cp); expect('(');
456 if( str_value(tws(cp),id) < 0 ) return -1;
457 dp->eop.push_back(id);
458 while( *tws(cp) == ',' ) {
459 if( str_value(tws(++cp),id) < 0 ) return -1;
460 dp->eop.push_back(id);
462 ch = *tws(cp); expect(')');
466 if( *id == "Media" ) {
467 dp->ty = dobj::ty_media;
476 int xrefer(ichar &cp, robj *rp)
478 string *id = tid(cp);
481 int ch = *tws(cp); expect('(');
482 if( !(id=tid(cp)) ) return -1;
483 rp->keys.push_back(id);
484 while( *tws(cp) == ',' ) {
485 if( !(id=tid(++cp)) ) return -1;
486 rp->keys.push_back(id);
488 ch = *tws(cp); expect(')');
489 if( !(id=tid(cp)) ) return -1;
490 if( *id != "On" ) return -1;
491 if( !(id=tid(cp)) ) return -1;
493 if( *id == "Delete" ) {
496 else if( *id == "Update" ) {
500 if( !(id=tid(cp)) ) return -1;
501 if( *id == "Restrict" ) {
502 rp->on_delete = robj::xref_restrict;
505 if( *id == "Cascade" ) {
506 rp->on_delete = robj::xref_cascade;
510 if( !(id=tid(cp)) ) return -1;
511 if( *id != "Null" ) return -1;
512 rp->on_delete = robj::xref_set_null;
516 if( !(id=tid(cp)) ) return -1;
517 if( *id != "Action" ) return -1;
518 rp->on_delete = robj::xref_no_action;
524 // scan datatype extension
525 int xtype(ichar &cp, dobj *dp)
527 string *id = tid(cp);
530 if( *tid(cp) != "Null" ) return -1;
535 if( *id == "Null" ) {
540 if( *id == "Default" ) {
541 if( def_value(tws(cp),dp) < 0 ) return -1;
545 if( *id == "Auto_increment" ) {
547 if( dp->idx ) dp->idx->unique = 1;
551 if( *id == "Unique" || *id == "Primary" ) {
552 int unique = dp->is_autoincr > 0 ? 1 : 0;
554 if( *id == "Unique" ) {
555 unique = 1; id = tid(cp);
557 if( *id == "Primary" ) primary = 1;
559 if( *tid(cp) != "Key" ) cp = bp;
560 iobj *idx = new iobj();
562 idx->name = new string(*dp->name);
563 idx->name->push_back('_');
564 idx->tbl = new string(*dp->top->name);
565 idx->unique = unique;
566 idx->primary = primary;
567 idx->keys.push_back(dp->name);
568 indecies.push_back(idx);
573 if( *id == "Comment" ) {
577 if( *id == "Column_format" ) {
581 if( *id == "Storage" ) {
586 if( *id == "References" ) {
588 robj *rop = new robj();
589 if ( xrefer(cp, rop) < 0 ) {
599 // scan table member line
600 int member(ichar &cp, dobj *dp)
603 if( dtype(cp,dp) < 0 ) return -1;
605 for( int ch=*tws(cp); (ch=*tws(cp)) && isalpha(ch); ) {
606 if( xtype(cp,dp) < 0 ) return -1;
612 // scan create table line
613 int table(ichar &cp, tobj *top)
615 string *id = tid(cp);
618 int ch = *tws(cp); expect('(');
620 dobj *dp = new dobj(top);
621 if( member(cp,dp) < 0 ) return -1;
622 top->dop.push_back(dp);
623 if( (ch=*tws(cp)) == ')' ) break;
627 while( (id=tid(cp)) ) {
628 ch = *tws(cp); expect('=');
629 printf(" skipping %s at %d\n",id->c_str(),cp.no);
630 if( isdigit(*tws(cp)) ) while( isdigit(*++cp) );
631 else if( !tid(cp) ) return -1;
633 ch = *tws(cp); expect(';');
638 int keylen(ichar &cp, iobj *ip)
644 while( (ch-='0') >= 0 && ch <= 9 ) {
645 n = n*10 + ch; ch = *++cp;
647 ch = *tws(cp); expect(')');
653 // scan create index line
654 int index(ichar &cp, iobj *iop)
656 string *id = tid(cp);
659 if( !(id=tid(cp)) ) return -1;
660 if( *id != "On" ) return -1;
661 if( !(id=tid(cp)) ) return -1;
663 int ch = *tws(cp); expect('(');
664 if( !(id=tid(cp)) ) return -1;
665 iop->keys.push_back(id);
666 if( keylen(cp,iop) < 0 ) return -1;
667 while( *tws(cp) == ',' ) {
668 if( !(id=tid(++cp)) ) return -1;
669 iop->keys.push_back(id);
670 if( keylen(cp,iop) < 0 ) return -1;
672 ch = *tws(cp); expect(')');
673 ch = *tws(cp); expect(';');
677 // process create line
678 int create(ichar &cp)
680 int online = -1; (void) online; // avoid unused warn
681 enum { none, unique, fulltext, spatial } modifier = none;
683 string *tp = tid(cp);
684 if( *tp == "Table" ) {
685 printf("Create Table at %d\n",cp.no);
686 tobj *top = new tobj();
687 if( table(cp, top) < 0 ) {
691 tables.push_back(top);
694 if( *tp == "Online" ) {
698 else if( *tp == "Offine" ) {
702 if( *tp == "Unique" ) {
706 else if( *tp == "Fulltext" ) {
710 else if( *tp == "Spatial" ) {
714 if( *tp == "Index" ) {
715 printf("Create index at %d\n",cp.no);
716 iobj *iop = new iobj();
717 if( index(cp, iop) < 0 ) {
721 if( modifier == unique ) iop->unique = 1;
722 indecies.push_back(iop);
725 fprintf(stderr,"unknown keyword - %s\n", tp->c_str());
730 void put_args(FILE *sp, tobj *tp, iobj *ip)
732 list<string*>::iterator ekey=ip->keys.end();
733 list<string*>::iterator key=ip->keys.begin();
734 if( key == ekey ) return;
737 const char *knm = (*key)->c_str();
739 list<dobj*>::iterator eid = tp->dop.end();
740 list<dobj*>::iterator id = tp->dop.begin();
741 while( id!=eid && *(*id)->name!=knm ) ++id;
743 fprintf(stderr," error: cant find index key %s in %s\n",knm,tp->name->c_str());
748 const char *nm = dp->name->c_str();
749 fprintf(sp,"%s::t_%s &%s",tp->name->c_str(),nm,nm);
750 if( ++key == ekey ) break;
757 void varg_dobj(FILE *sp, dobj *dp, const char *ty, int is_unsign=-1)
759 if( is_unsign < 0 ) is_unsign = dp->is_unsign;
760 if( is_unsign > 0 ) fprintf(sp, "unsigned ");
761 fprintf(sp,"%s *%s", ty, dp->name->c_str());
764 void varg_dobj(FILE *sp, dobj *dp, const char *ty, int is_unsign=-1)
766 const char *tnm = dp->top->name->c_str();
767 const char *nm = dp->name->c_str();
768 fprintf(sp,"const %sObj::t_%s &%s", tnm, nm, nm);
772 void arg_dobj(FILE *sp, dobj *dp, const char *ty, int is_unsign=-1)
774 if( is_unsign < 0 ) is_unsign = dp->is_unsign;
775 if( is_unsign > 0 ) fprintf(sp, "unsigned ");
776 fprintf(sp,"%s ", ty);
777 if( dp->length > 0 ) fprintf(sp, "*");
778 fprintf(sp,"%s", dp->name->c_str());
781 void arg_dobj(FILE *sp, dobj *dp)
784 case dobj::ty_boolean:
786 case dobj::ty_binary: arg_dobj(sp, dp, "char", 1); break;
788 case dobj::ty_tinyint: arg_dobj(sp, dp, "char"); break;
790 case dobj::ty_smallint: arg_dobj(sp, dp, "short"); break;
791 case dobj::ty_decimal:
792 case dobj::ty_mediumint:
793 case dobj::ty_integer: arg_dobj(sp, dp, "int"); break;
794 case dobj::ty_bigint: arg_dobj(sp, dp, "long"); break;
796 case dobj::ty_double: arg_dobj(sp, dp, "double", 0); break;
797 case dobj::ty_float: arg_dobj(sp, dp, "float", 0); break;
800 case dobj::ty_timestamp:
801 case dobj::ty_datetime:
802 case dobj::ty_year: varg_dobj(sp, dp, "char",0); break;
803 case dobj::ty_varchar:
804 if( dp->is_binary ) { varg_dobj(sp, dp, "char",1); break; }
805 case dobj::ty_tinytext:
807 case dobj::ty_mediumtext:
808 case dobj::ty_longtext: varg_dobj(sp, dp, "char",0); break;
809 case dobj::ty_varbinary:
810 case dobj::ty_tinyblob:
812 case dobj::ty_mediumblob:
813 case dobj::ty_longblob:
814 case dobj::ty_media: varg_dobj(sp, dp, "char",1); break;
816 fprintf(sp,"unimplemented %s,", dp->name->c_str());
821 void put_targs(FILE *sp, tobj *tp, iobj *ip)
823 list<string*>::iterator ekey=ip->keys.end();
824 list<string*>::iterator key=ip->keys.begin();
826 for( ; key != ekey; ) {
827 const char *knm = (*key)->c_str(); ++key;
828 list<dobj*>::iterator eid = tp->dop.end();
829 list<dobj*>::iterator id = tp->dop.begin();
830 while( id!=eid && *(*id)->name!=knm ) ++id;
832 fprintf(stderr," error: cant find index key %s in %s\n",knm,tp->name->c_str());
836 if( dp->ty == dobj::ty_none ) {
837 fprintf(stderr," %s member %s error: ty_none\n",
838 tp->name->c_str(),dp->name->c_str());
843 if( key == ekey ) continue;
848 void typ_dobj(FILE *sp, dobj *dp)
852 case dobj::ty_boolean:
854 case dobj::ty_binary: cp = "unsigned char"; break;
856 case dobj::ty_tinyint: cp = dp->is_unsign > 0 ? "unsigned char" : "char"; break;
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;
864 case dobj::ty_double: cp = "double"; break;
865 case dobj::ty_float: cp = "float"; break;
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:
875 case dobj::ty_mediumtext:
876 case dobj::ty_longtext: cp = "char"; break;
877 case dobj::ty_varbinary:
878 case dobj::ty_tinyblob:
880 case dobj::ty_mediumblob:
881 case dobj::ty_longblob:
882 case dobj::ty_media: cp = "unsigned char"; break;
883 default: cp = "unimplemented"; break;
888 void put_keys(FILE *sp, tobj *tp, iobj *ip)
890 list<string*>::iterator ekey=ip->keys.end();
891 list<string*>::iterator key=ip->keys.begin();
892 const char *tnm = tp->name->c_str();
894 for( ; key != ekey; ++key ) {
895 const char *knm = (*key)->c_str();
897 list<dobj*>::iterator eid = tp->dop.end();
898 list<dobj*>::iterator id = tp->dop.begin();
899 while( id!=eid && *(*id)->name!=knm ) ++id;
901 fprintf(stderr," error: cant find index key %s in %s\n", knm, tnm);
906 const char *nm = dp->name->c_str();
907 fprintf(sp," %sObj::t_%s v_%s;\n", tnm, nm, nm);
909 if( ip->unique <= 0 ) fprintf(sp," int v_id;\n");
912 void put_init(FILE *sp, tobj *tp, iobj *ip)
914 list<string*>::iterator ekey=ip->keys.end();
915 list<string*>::iterator key;
917 for( key=ip->keys.begin(); key!=ekey; ++key ) {
918 const char *knm = (*key)->c_str();
920 list<dobj*>::iterator eid = tp->dop.end();
921 list<dobj*>::iterator id = tp->dop.begin();
922 while( id!=eid && *(*id)->name!=knm ) ++id;
924 fprintf(stderr," error: cant find index key %s in %s\n",knm,tp->name->c_str());
929 const char *nm = dp->name->c_str();
930 fprintf(sp,",\n v_%s(%s)", nm, nm);
934 void put_cmpr(FILE *sp, dobj *dp)
938 case dobj::ty_boolean:
940 case dobj::ty_binary: cp = "uchar"; break;
942 case dobj::ty_tinyint: cp = dp->is_unsign > 0 ? "uchar" : "char"; break;
944 case dobj::ty_smallint: cp = dp->is_unsign > 0 ? "ushort" : "short"; break;
945 case dobj::ty_decimal:
946 case dobj::ty_mediumint:
947 case dobj::ty_integer: cp = dp->is_unsign > 0 ? "uint" : "int"; break;
948 case dobj::ty_bigint: cp = dp->is_unsign > 0 ? "ulong" : "long"; break;
950 case dobj::ty_double: cp = "double"; break;
951 case dobj::ty_float: cp = "float"; break;
954 case dobj::ty_timestamp:
955 case dobj::ty_datetime:
956 case dobj::ty_year: cp = "char"; break;
957 case dobj::ty_varchar:
958 if( dp->is_binary ) { cp = "uchar"; break; }
959 case dobj::ty_tinytext:
961 case dobj::ty_mediumtext:
962 case dobj::ty_longtext: cp = "char"; break;
963 case dobj::ty_varbinary:
964 case dobj::ty_tinyblob:
966 case dobj::ty_mediumblob:
967 case dobj::ty_longblob: cp = "uchar"; break;
968 case dobj::ty_media: cp = "media"; break;
969 default: cp = "unimplemented"; break;
974 void put_rcmpr(FILE *sp, tobj *tp, iobj *ip)
976 list<string*>::iterator ekey=ip->keys.end();
977 list<string*>::iterator skey=ip->keys.begin();
978 list<string*>::iterator key;
980 for( key=skey; key!=ekey; ++key ) {
981 const char *knm = (*key)->c_str();
983 list<dobj*>::iterator eid = tp->dop.end();
984 list<dobj*>::iterator id = tp->dop.begin();
985 while( id!=eid && *(*id)->name!=knm ) ++id;
987 fprintf(stderr," error: cant find index key %s in %s\n",knm,tp->name->c_str());
992 const char *nm = dp->name->c_str();
993 fprintf(sp," v = cmpr_"); put_cmpr(sp,dp);
994 fprintf(sp,"( kloc._%s(), kloc->v_%s.size(),\n", nm, nm);
995 fprintf(sp," vloc._%s(), vloc->v_%s.size());\n", nm, nm);
996 fprintf(sp," if( v != 0 ) return v;\n");
998 if( ip->unique <= 0 ) {
999 fprintf(sp," v = cmpr_int(kloc._id(), kloc._id_size(),\n");
1000 fprintf(sp," vloc._id(), vloc._id_size());\n");
1001 fprintf(sp," if( v != 0 ) return v;\n");
1005 void put_icmpr(FILE *sp, tobj *tp, iobj *ip)
1007 list<string*>::iterator ekey=ip->keys.end();
1008 list<string*>::iterator skey=ip->keys.begin();
1009 list<string*>::iterator key;
1011 for( key=skey; key!=ekey; ++key ) {
1012 const char *knm = (*key)->c_str();
1014 list<dobj*>::iterator eid = tp->dop.end();
1015 list<dobj*>::iterator id = tp->dop.begin();
1016 while( id!=eid && *(*id)->name!=knm ) ++id;
1018 fprintf(stderr," error: cant find index key %s in %s\n",knm,tp->name->c_str());
1023 const char *nm = dp->name->c_str();
1024 fprintf(sp," v = cmpr_"); put_cmpr(sp,dp);
1025 fprintf(sp,"( kp->v_%s.addr(), kp->v_%s.size(),\n", nm, nm);
1026 fprintf(sp," vloc._%s(), vloc->v_%s.size());\n", nm, nm);
1027 fprintf(sp," if( v != 0 ) return v;\n");
1029 if( ip->unique <= 0 ) {
1030 fprintf(sp," if( kp->v_id >= 0 ) {\n");
1031 fprintf(sp," v = cmpr_int(&kp->v_id, sizeof(kp->v_id),\n");
1032 fprintf(sp," vloc._id(), vloc._id_size());\n");
1033 fprintf(sp," if( v != 0 ) return v;\n");
1038 void put_dobj(FILE *sp, dobj *dp, const char *dty, int n)
1040 fprintf(sp," array_%s(char,%s,%d);\n", dty, dp->name->c_str(), n);
1043 void put_dobj(FILE *sp, dobj *dp, const char *dty, const char *ty, int is_unsign=-1)
1045 fprintf(sp," %s_%s(", dp->length > 0 ? "array" : "basic", dty);
1046 if( is_unsign < 0 ) is_unsign = dp->is_unsign;
1047 if( is_unsign > 0 ) fprintf(sp, "unsigned ");
1048 fprintf(sp,"%s,%s", ty, dp->name->c_str());
1049 if( dp->length > 0 ) fprintf(sp, ",%d", dp->length);
1050 fprintf(sp, ");\n");
1053 void put_decl(FILE *sp, dobj *dp, const char *dty)
1056 case dobj::ty_boolean:
1058 case dobj::ty_binary: put_dobj(sp, dp, dty, "char", 1); break;
1060 case dobj::ty_tinyint: put_dobj(sp, dp, dty, "char"); break;
1062 case dobj::ty_smallint: put_dobj(sp, dp, dty, "short"); break;
1063 case dobj::ty_decimal:
1064 case dobj::ty_mediumint:
1065 case dobj::ty_integer: put_dobj(sp, dp, dty, "int"); break;
1066 case dobj::ty_bigint: put_dobj(sp, dp, dty, "long"); break;
1068 case dobj::ty_double: put_dobj(sp, dp, dty, "double", 0); break;
1069 case dobj::ty_float: put_dobj(sp, dp, dty, "float", 0); break;
1070 case dobj::ty_date: put_dobj(sp, dp, dty, 8); break;
1071 case dobj::ty_time: put_dobj(sp, dp, dty, 6); break;
1072 case dobj::ty_timestamp:
1073 case dobj::ty_datetime: put_dobj(sp, dp, dty, 14); break;
1074 case dobj::ty_year: put_dobj(sp, dp, dty, 4); break;
1076 case dobj::ty_tinytext:
1077 case dobj::ty_mediumtext:
1078 case dobj::ty_longtext:
1079 fprintf(sp," sarray_%s(char,%s);\n", dty, dp->name->c_str());
1081 case dobj::ty_varchar:
1082 if( !dp->is_binary ) {
1083 fprintf(sp," varray_%s(char,%s);\n", dty, dp->name->c_str());
1086 case dobj::ty_varbinary:
1088 case dobj::ty_tinyblob:
1089 case dobj::ty_mediumblob:
1090 case dobj::ty_longblob:
1091 case dobj::ty_media:
1092 fprintf(sp," varray_%s(unsigned char,%s);\n", dty, dp->name->c_str());
1096 fprintf(sp," %s %s unimplemented;\n", dty, dp->name->c_str());
1102 int main(int ac, char **av)
1104 const char *tdb = ac > 1 ? av[1] : "theDb";
1105 const char *sfn = ac > 2 ? av[2] : "./s";
1111 for( string *sp=tid(cp); sp!=0; sp=tid(cp) ) {
1112 if( *sp == "Create" ) create(cp);
1115 printf(" %d Tables\n",(int)tables.size());
1116 printf(" %d Indecies\n",(int)indecies.size());
1118 char fn[512]; sprintf(fn,"%s.h",sfn);
1119 FILE *sp = fopen(fn,"w");
1121 // get basename for sfn.h, _SFN_H_
1123 for( const char *ap=sfn; *ap; ++ap )
1124 if( *ap == '/' ) bp = ap+1;
1126 char ups[512], *up = ups; *up++ = '_';
1127 for( const char *cp=bp; *cp; ++cp ) *up++ = toupper(*cp);
1128 *up++ = '_'; *up++ = 'H'; *up++ = '_'; *up = 0;
1130 fprintf(sp,"#ifndef %s\n",ups);
1131 fprintf(sp,"#define %s\n",ups);
1132 fprintf(sp,"#include <cstdio>\n");
1133 fprintf(sp,"#include <stdlib.h>\n");
1134 fprintf(sp,"#include <unistd.h>\n");
1135 fprintf(sp,"#include <fcntl.h>\n");
1136 fprintf(sp,"#include <errno.h>\n");
1138 fprintf(sp,"#include \"tdb.h\"\n");
1142 list<tobj*>::iterator sit = tables.begin();
1143 list<tobj*>::iterator eit = tables.end();
1144 list<tobj*>::iterator it;
1147 for( it=sit ; it!=eit; ++i, ++it ) {
1149 const char *tnm = tp->name->c_str();
1150 printf(" %2d. %s (",i,tnm);
1151 fprintf(sp,"// %s\n",tnm);
1152 fprintf(sp,"DbObj(%s)\n",tnm);
1154 list<dobj*>::iterator sid = tp->dop.begin();
1155 list<dobj*>::iterator eid = tp->dop.end();
1156 list<dobj*>::iterator id;
1158 // output table member declarations
1159 for( id=sid ; id!=eid; ++id ) {
1161 printf(" %s",dp->name->c_str());
1162 if( dp->ty == dobj::ty_none ) {
1163 fprintf(stderr," %s member %s error: ty_none\n",
1164 tnm,dp->name->c_str());
1167 put_decl(sp,dp,"def");
1174 list<iobj*>::iterator sidx=indecies.begin();
1175 list<iobj*>::iterator eidx=indecies.end();
1176 list<iobj*>::iterator idx;
1179 for( idx=sidx; idx!=eidx; ++idx ) {
1180 if( *(*idx)->tbl != *(*it)->name ) continue;
1182 printf(" %2d.%d. %s on %s(",i,j++,
1183 (*idx)->name->c_str(),(*idx)->tbl->c_str());
1184 list<string*>::iterator skey=(*idx)->keys.begin();
1185 list<string*>::iterator ekey=(*idx)->keys.end();
1186 list<string*>::iterator key;
1187 for( key=skey; key!=ekey; ++key )
1188 printf(" %s", (*key)->c_str());
1191 if( n > 0 ) printf("\n");
1193 // output table member accessors
1194 fprintf(sp,"DbLoc(%s)\n",tnm);
1195 for( id=sid ; id!=eid; ++id ) {
1197 if( dp->ty == dobj::ty_none ) {
1198 fprintf(stderr," %s member %s error: ty_none\n",
1199 tnm,dp->name->c_str());
1202 put_decl(sp, dp, "ref");
1205 for( idx=sidx; idx!=eidx; ++idx ) {
1206 if( *(*idx)->tbl != *(*it)->name ) continue;
1207 const char *knm = (*idx)->name->c_str();
1209 fprintf(sp," class ikey_%s : public Db::iKey { public:\n", knm);
1210 put_keys(sp, *it, *idx);
1211 fprintf(sp," static int cmpr(char *a, char *b);\n");
1213 fprintf(sp," ikey_%s(ObjectLoc &loc,\n", knm);
1214 put_targs(sp, *it, *idx);
1215 if( (*idx)->unique <= 0 ) fprintf(sp,", int id=-1");
1216 fprintf(sp,")\n : iKey(\"%s\",loc,cmpr)", knm);
1217 put_init(sp, *it, *idx);
1218 if( (*idx)->unique <= 0 ) fprintf(sp,",\n v_id(id)");
1219 fprintf(sp," {}\n");
1220 fprintf(sp," };\n");
1221 fprintf(sp," class rkey_%s : public Db::rKey { public:\n", knm);
1222 fprintf(sp," static int cmpr(char *a, char *b);\n");
1223 fprintf(sp," rkey_%s(ObjectLoc &loc) : rKey(\"%s\",loc,cmpr)", knm, knm);
1224 fprintf(sp," {}\n");
1225 fprintf(sp," };\n");
1228 fprintf(sp," int Allocate();\n");
1229 fprintf(sp," int Construct();\n");
1230 fprintf(sp," int Destruct();\n");
1231 fprintf(sp," void Deallocate();\n");
1233 fprintf(sp," int Copy(ObjectLoc &that);\n");
1240 fprintf(sp,"class %s : public Db {\n",tdb);
1241 fprintf(sp," int dfd, dkey, no_atime;\n");
1242 fprintf(sp," int db_create();\n");
1243 fprintf(sp," int db_open();\n");
1244 fprintf(sp," int db_access();\n");
1245 fprintf(sp,"public:\n");
1246 fprintf(sp," Objects objects;\n");
1247 for( it=sit ; it!=eit; ++it ) {
1249 const char *tnm = tp->name->c_str();
1250 fprintf(sp," Entity %s; %sLoc %c%s;\n", tnm, tnm, tolower(tnm[0]), &tnm[1]);
1253 fprintf(sp," int create(const char *dfn);\n");
1254 fprintf(sp," int open(const char *dfn, int key=-1);\n");
1255 fprintf(sp," int access(const char *dfn, int key=-1, int rw=0);\n");
1256 fprintf(sp," void close();\n");
1257 fprintf(sp," int attach(int rw=0) { return Db::attach(rw); }\n");
1258 fprintf(sp," int detach() { return Db::detach(); }\n");
1260 fprintf(sp," %s();\n",tdb);
1261 fprintf(sp," ~%s() { finit(objects); }\n",tdb);
1264 fprintf(sp,"#endif\n");
1267 sprintf(fn,"%s.C",sfn);
1269 fprintf(sp,"#include \"%s.h\"\n",bp);
1272 for( it=sit ; it!=eit; ++it ) {
1274 const char * tnm = tp->name->c_str();
1275 list<iobj*>::iterator sidx=indecies.begin();
1276 list<iobj*>::iterator eidx=indecies.end();
1277 list<iobj*>::iterator idx;
1279 for( idx=sidx; idx!=eidx; ++idx ) {
1280 if( *(*idx)->tbl != *(*it)->name ) continue;
1281 const char *knm = (*idx)->name->c_str();
1283 fprintf(sp,"int %sLoc::ikey_%s::\n", tnm, knm);
1284 fprintf(sp,"cmpr(char *a, char *b)\n");
1286 fprintf(sp," ikey_%s *kp = (ikey_%s *)a;\n", knm, knm);
1287 fprintf(sp," int v = *(int*)b;\n");
1288 if( (*idx)->unique <= 0 ) fprintf(sp," if( kp->v_id == v ) return 0;\n");
1289 fprintf(sp," %sLoc vloc(kp->loc.entity);\n", tnm);
1290 fprintf(sp," if( vloc.FindId(v) )\n");
1291 fprintf(sp," vloc.err_(Db::errCorrupt);\n");
1292 put_icmpr(sp, tp, *idx);
1293 fprintf(sp," return 0;\n");
1296 fprintf(sp,"int %sLoc::rkey_%s::\n", tnm, knm);
1297 fprintf(sp,"cmpr(char *a, char *b)\n");
1299 fprintf(sp," rkey_%s *kp = (rkey_%s *)a;\n", knm, knm);
1300 fprintf(sp," %sLoc &kloc = (%sLoc&)kp->loc;\n", tnm, tnm);
1301 fprintf(sp," int v = kloc->id, b_id = *(int*)b;\n");
1302 fprintf(sp," if( v == b_id ) return 0;\n");
1303 fprintf(sp," %sLoc vloc(kloc.entity);\n", tnm);
1304 fprintf(sp," if( vloc.FindId(b_id) )\n");
1305 fprintf(sp," kloc.err_(Db::errCorrupt);\n");
1306 put_rcmpr(sp, tp, *idx);
1307 fprintf(sp," return 0;\n");
1311 fprintf(sp,"int %sLoc::Allocate()\n", tnm);
1313 fprintf(sp," if_err( allocate() );\n");
1314 fprintf(sp," if( !addr_wr() ) return err_(Db::errNoMemory);\n");
1317 list<dobj*>::iterator sid = tp->dop.begin();
1318 list<dobj*>::iterator eid = tp->dop.end();
1319 list<dobj*>::iterator id;
1321 for( id=sid ; !n && id!=eid; ++id ) {
1324 case dobj::ty_varchar:
1325 case dobj::ty_tinytext:
1327 case dobj::ty_mediumtext:
1328 case dobj::ty_longtext:
1329 case dobj::ty_varbinary:
1330 case dobj::ty_tinyblob:
1332 case dobj::ty_mediumblob:
1333 case dobj::ty_longblob:
1334 case dobj::ty_media:
1335 if( !n++ ) fprintf(sp," v_init();\n");
1342 for( id=sid ; id!=eid; ++id ) {
1344 const char *dnm = dp->name->c_str();
1345 if( dp->is_autoincr > 0 && dp->idx ) {
1346 const char *inm = dp->idx->name->c_str();
1347 fprintf(sp," { "); typ_dobj(sp, dp);
1348 fprintf(sp," (%sLoc::*fn)() = &%sLoc::%s;\n", tnm, tnm, dnm);
1349 fprintf(sp," "); typ_dobj(sp, dp);
1350 fprintf(sp," v = last(\"%s\",(", inm); typ_dobj(sp, dp);
1351 fprintf(sp," (Db::ObjectLoc::*)())fn); %s(v+1); }\n", dnm);
1353 if( dp->has_def > 0 ) {
1354 switch( dp->has_def ) {
1355 case dobj::def_integer:
1356 fprintf(sp," %s(%d);\n", dnm, dp->def.i);
1358 case dobj::def_double:
1359 fprintf(sp," %s(%f);\n", dnm, dp->def.d);
1361 case dobj::def_string:
1363 case dobj::ty_enum: {
1364 list<string*>::iterator snm = dp->eop.begin();
1365 list<string*>::iterator enm = dp->eop.end();
1366 list<string*>::iterator nm;
1367 for( n=0,nm=snm; nm!=enm && *(*nm)!=*dp->def.s; ++nm ) ++n;
1368 fprintf(sp," %s(%d);\n", dnm, n);
1370 case dobj::ty_boolean:
1372 case dobj::ty_tinyint:
1373 case dobj::ty_smallint:
1374 case dobj::ty_decimal:
1375 case dobj::ty_mediumint:
1376 case dobj::ty_integer:
1377 case dobj::ty_bigint: {
1378 fprintf(sp," %s(%ld);\n", dnm, strtol(dp->def.s->c_str(),0,0));
1381 case dobj::ty_double:
1382 case dobj::ty_float: {
1383 fprintf(sp," %s(%f);\n", dnm, strtod(dp->def.s->c_str(),0));
1387 case dobj::ty_timestamp:
1388 case dobj::ty_binary:
1390 case dobj::ty_datetime:
1392 case dobj::ty_varchar:
1393 case dobj::ty_tinytext:
1395 case dobj::ty_mediumtext:
1396 case dobj::ty_longtext:
1397 case dobj::ty_varbinary:
1398 case dobj::ty_tinyblob:
1400 case dobj::ty_mediumblob:
1401 case dobj::ty_longblob:
1402 case dobj::ty_media: {
1403 fprintf(sp," %s((", dnm); typ_dobj(sp,dp);
1404 fprintf(sp," *)\"%s\",%d);\n", dp->def.s->c_str(), (int)dp->def.s->size());
1415 fprintf(sp," return 0;\n");
1418 fprintf(sp,"int %sLoc::Construct()\n", tnm);
1420 fprintf(sp," if_err( insertProhibit() );\n");
1421 fprintf(sp," if_err( construct() );\n");
1423 for( idx=sidx; idx!=eidx; ++idx ) {
1424 if( *(*idx)->tbl != *(*it)->name ) continue;
1425 if( !n++ ) fprintf(sp," int id = this->id();\n");
1426 const char *knm = (*idx)->name->c_str();
1427 fprintf(sp," { rkey_%s rkey(*this);\n",knm);
1428 fprintf(sp," if_err( entity->index(\"%s\")->Insert(rkey,&id) ); }\n",knm);
1430 fprintf(sp," if_err( insertCascade() );\n");
1431 fprintf(sp," return 0;\n");
1434 fprintf(sp,"int %sLoc::Destruct()\n", tnm);
1436 fprintf(sp," if_err( deleteProhibit() );\n");
1437 for( idx=sidx; idx!=eidx; ++idx ) {
1438 if( *(*idx)->tbl != *(*it)->name ) continue;
1439 const char *knm = (*idx)->name->c_str();
1440 fprintf(sp," { rkey_%s rkey(*this);\n",knm);
1441 fprintf(sp," if_err( entity->index(\"%s\")->Delete(rkey) ); }\n",knm);
1443 fprintf(sp," if_err( destruct() );\n");
1444 fprintf(sp," if_err( deleteCascade() );\n");
1445 fprintf(sp," return 0;\n");
1448 fprintf(sp,"void %sLoc::Deallocate()\n", tnm);
1451 for( id=sid ; !n && id!=eid; ++id ) {
1454 case dobj::ty_varchar:
1455 case dobj::ty_tinytext:
1457 case dobj::ty_mediumtext:
1458 case dobj::ty_longtext:
1459 case dobj::ty_varbinary:
1460 case dobj::ty_tinyblob:
1462 case dobj::ty_mediumblob:
1463 case dobj::ty_longblob:
1464 case dobj::ty_media:
1465 if( !n++ ) fprintf(sp," v_del();\n");
1471 fprintf(sp," deallocate();\n");
1477 fprintf(sp,"int %s::\n",tdb);
1478 fprintf(sp,"create(const char *dfn)\n");
1480 fprintf(sp," dfd = ::open(dfn,O_RDWR+O_CREAT+O_TRUNC+no_atime,0666);\n");
1481 fprintf(sp," if( dfd < 0 ) { perror(dfn); return -1; }\n");
1482 fprintf(sp," int ret = db_create();\n");
1483 fprintf(sp," close();\n");
1484 fprintf(sp," return ret;\n");
1487 fprintf(sp,"int %s::\n",tdb);
1488 fprintf(sp,"db_create()\n");
1490 fprintf(sp," if_ret( Db::make(dfd) );\n");
1491 for( it=sit ; it!=eit; ++it ) {
1493 const char *tnm = tp->name->c_str();
1494 fprintf(sp," if_ret( %s.new_entity(\"%s\", sizeof(%sObj)) );\n", tnm, tnm, tnm);
1495 list<iobj*>::iterator sidx=indecies.begin();
1496 list<iobj*>::iterator eidx=indecies.end();
1497 list<iobj*>::iterator idx;
1498 for( idx=sidx; idx!=eidx; ++idx ) {
1499 if( *(*idx)->tbl != *(*it)->name ) continue;
1500 const char *nm = (*idx)->name->c_str();
1501 fprintf(sp," if_ret( %s.add_kindex(\"%s\") );\n", tnm, nm);
1505 fprintf(sp," if_ret( Db::commit(1) );\n");
1506 fprintf(sp," return 0;\n");
1510 fprintf(sp,"%s::\n", tdb);
1511 fprintf(sp,"%s()\n", tdb);
1512 fprintf(sp," : dfd(-1), dkey(-1), no_atime(getuid()?0:O_NOATIME), objects(0)");
1513 for( it=sit ; it!=eit; ++it ) {
1515 const char *tnm = tp->name->c_str();
1516 fprintf(sp,",\n %s(this)", tnm);
1517 fprintf(sp,", %c%s(%s)", tolower(tnm[0]), &tnm[1], tnm);
1521 for( it=sit ; it!=eit; ++it ) {
1523 const char *tnm = tp->name->c_str();
1524 fprintf(sp,"\n objects = new ObjectList(objects, %c%s);",
1525 tolower(tnm[0]), &tnm[1]);
1528 for( it=sit ; it!=eit; ++it ) {
1530 const char *tnm = tp->name->c_str();
1531 list<dobj*>::iterator sid = tp->dop.begin();
1532 list<dobj*>::iterator eid = tp->dop.end();
1533 list<dobj*>::iterator id;
1534 for( id=sid ; id!=eid; ++id ) {
1536 const char *dnm = dp->name->c_str();
1538 case dobj::ty_varchar:
1539 case dobj::ty_tinytext:
1541 case dobj::ty_mediumtext:
1542 case dobj::ty_longtext:
1543 case dobj::ty_varbinary:
1544 case dobj::ty_tinyblob:
1546 case dobj::ty_mediumblob:
1547 case dobj::ty_longblob:
1548 case dobj::ty_media: {
1549 fprintf(sp," %s.add_vref((vRef)&%sObj::v_%s);\n", tnm, tnm, dnm);
1559 fprintf(sp,"int %s::\n",tdb);
1560 fprintf(sp,"open(const char *dfn, int key)\n");
1562 fprintf(sp," dfd = ::open(dfn,O_RDWR+no_atime);\n");
1563 fprintf(sp," if( dfd < 0 ) { perror(dfn); return errNotFound; }\n");
1564 fprintf(sp," if( (dkey=key) >= 0 ) Db::use_shm(1);\n");
1565 fprintf(sp," int ret = Db::open(dfd, dkey);\n");
1566 fprintf(sp," if( !ret ) ret = db_open();\n");
1567 fprintf(sp," if( ret ) close();\n");
1568 fprintf(sp," return ret;\n");
1572 fprintf(sp,"int %s::\n",tdb);
1573 fprintf(sp,"db_open()\n");
1575 for( it=sit ; it!=eit; ++it ) {
1577 const char *tnm = tp->name->c_str();
1578 fprintf(sp," if_ret( %s.get_entity(\"%s\") );\n", tnm, tnm);
1579 list<iobj*>::iterator sidx=indecies.begin();
1580 list<iobj*>::iterator eidx=indecies.end();
1581 list<iobj*>::iterator idx;
1582 for( idx=sidx; idx!=eidx; ++idx ) {
1583 if( *(*idx)->tbl != *(*it)->name ) continue;
1584 const char *nm = (*idx)->name->c_str();
1585 fprintf(sp," if_ret( %s.key_index(\"%s\") );\n", tnm, nm);
1589 fprintf(sp," if_ret( Db::start_transaction() );\n");
1590 fprintf(sp," return 0;\n");
1593 fprintf(sp,"void %s::\n",tdb);
1594 fprintf(sp,"close()\n");
1596 fprintf(sp," Db::close();\n");
1597 fprintf(sp," if( dfd >= 0 ) { ::close(dfd); dfd = -1; }\n");
1600 fprintf(sp,"int %s::\n",tdb);
1601 fprintf(sp,"access(const char *dfn, int key, int rw)\n");
1603 fprintf(sp," if( key < 0 ) return Db::errInvalid;\n");
1604 fprintf(sp," dfd = ::open(dfn,O_RDWR+no_atime);\n");
1605 fprintf(sp," if( dfd < 0 ) { perror(dfn); return Db::errNotFound; }\n");
1606 fprintf(sp," dkey = key; Db::use_shm(1);\n");
1607 fprintf(sp," int ret = Db::attach(dfd, dkey, rw);\n");
1608 fprintf(sp," if( !ret ) ret = db_access();\n");
1609 fprintf(sp," else if( ret == errNotFound ) {\n");
1610 fprintf(sp," ret = Db::open(dfd, dkey);\n");
1611 fprintf(sp," if( !ret ) ret = db_open();\n");
1612 fprintf(sp," if( !ret ) ret = Db::attach(rw);\n");
1614 fprintf(sp," if( ret ) close();\n");
1615 fprintf(sp," return ret;\n");
1618 fprintf(sp,"int %s::\n",tdb);
1619 fprintf(sp,"db_access()\n");
1621 for( it=sit ; it!=eit; ++it ) {
1623 const char *tnm = tp->name->c_str();
1624 fprintf(sp," if_ret( %s.get_entity(\"%s\") );\n", tnm, tnm);
1626 fprintf(sp," return 0;\n");
1630 printf("ended on line %d - ",cp.no);
1631 for( int i=0, n=cp.i; i<n; ++i ) printf("%c",cp.line[i]);
1633 for( int i=cp.i, n=cp.n; i<n; ++i ) printf("%c",cp.line[i]);