/[webpac]/trunk/openisis/lrec.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /trunk/openisis/lrec.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 239 - (hide annotations)
Mon Mar 8 17:49:13 2004 UTC (17 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 22538 byte(s)
including openisis 0.9.0 into webpac tree

1 dpavlin 237 /*
2     openisis - an open implementation of the CDS/ISIS database
3     Version 0.8.x (patchlevel see file Version)
4     Copyright (C) 2001-2003 by Erik Grziwotz, erik@openisis.org
5    
6     This library is free software; you can redistribute it and/or
7     modify it under the terms of the GNU Lesser General Public
8     License as published by the Free Software Foundation; either
9     version 2.1 of the License, or (at your option) any later version.
10    
11     This library is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14     Lesser General Public License for more details.
15    
16     You should have received a copy of the GNU Lesser General Public
17     License along with this library; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19    
20     see README for more information
21     EOH */
22    
23     /*
24     $Id: lrec.c,v 1.53 2003/05/29 18:03:35 kripke Exp $
25     implementation of record cooking.
26     */
27    
28     #include <stddef.h>
29     #include <stdarg.h>
30     #include <stdio.h> /* vsnprintf */
31     #include <stdlib.h> /* free */
32     #include <string.h> /* memset et al */
33    
34     #ifdef WIN32
35     # define vsnprintf _vsnprintf
36     #endif /* WIN32 */
37    
38     #include "ldb.h"
39     #include "lio.h"
40     #include "lcs.h"
41    
42    
43     /* ************************************************************
44     private types
45     */
46    
47     typedef struct {
48     int len; /* length of tagf */
49     int tagf[2]; /* tag and modification flags */
50     } LrecMF;
51    
52     #define MF_SET 0x01
53     #define MF_DEL 0x02
54    
55     /* ************************************************************
56     private data
57     */
58     /* ************************************************************
59     private functions
60     */
61    
62     static LrecMF* mfCtor (Rec *rec) {
63     int len = (int)(2 * rec->len);
64     int *M;
65     Field *F;
66     LrecMF *lmf = (LrecMF*) mAlloc ((1 + len) * sizeof (int));
67     if (0 == lmf) {
68     return 0;
69     }
70     memset (lmf->tagf, 0, len * sizeof (int));
71     lmf->len = len;
72     for (M = lmf->tagf, F = rec->field; len > M - lmf->tagf; ++F, M += 2) {
73     *M = (int) F->tag;
74     }
75     return lmf;
76     }
77    
78     static int rCompact (Rec *rec) {
79     int rt = 0;
80     if (0 != rec) {
81     char *V = (char*)rec + rec->base;
82     Field *F = rec->field;
83     Field *L = F + rec->len;
84     int used = rec->base;
85     while (F < L) {
86     if (V != F->val) {
87     rt = !0;
88     break;
89     }
90     V += F->len;
91     used += F->len;
92     ++F;
93     }
94     if (rt) {
95     char *buf = (char*) mAlloc (rec->used - (V - (char*)rec));
96     char *B = buf;
97     int nb = 0;
98     if (0 == buf) {
99     return 0;
100     }
101     while (F < L) {
102     memcpy (B, F->val, F->len);
103     F->val = V;
104     B += F->len;
105     V += F->len;
106     nb += F->len;
107     ++F;
108     }
109     memcpy ((char*)rec + used, buf, nb);
110     rec->used = used + nb;
111     mFree (buf);
112     }
113     }
114     return rt;
115     }
116    
117     /** @return
118     -2 - malloc failed,
119     -1 - tag not present,
120     0 - compactification not neccessary,
121     1 - rec data buffer has gaps
122     */
123     static int rReplace (
124     Rec **rec, LrecMF *lmf,
125     int tag, int occr, int lmode, const char *val, int disc
126     ) {
127     Rec *nr;
128     Field *F;
129     int *M;
130     int vlen;
131     int fnd = -1;
132     int ocnt = -1;
133     for (M = lmf->tagf; lmf->len > M - lmf->tagf; M += 2) {
134     if (tag == M[0]) {
135     if (0 <= occr) {
136     if (++ocnt == occr) {
137     M[1] = lmode;
138     fnd = (M - lmf->tagf) / 2;
139     break;
140     }
141     }
142     else {
143     if (0 == (MF_SET & M[1])) {
144     M[1] = lmode;
145     fnd = (M - lmf->tagf) / 2;
146     if (lmode) {
147     for (M += 2; lmf->len > M - lmf->tagf; M += 2) {
148     if (tag == M[0]) {
149     M[1] = MF_DEL;
150     }
151     }
152     }
153     break;
154     }
155     }
156     }
157     }
158     if (0 > fnd) {
159     return -1;
160     }
161     if (MF_SET != lmode) {
162     return 1;
163     }
164     F = (*rec)->field + fnd;
165     vlen = strlen (val);
166     if (F->len == vlen) {
167     memcpy ((char*)F->val, val, vlen);
168     return 0;
169     }
170     if (F->len > vlen) {
171     memcpy ((char*)F->val, val, vlen);
172     F->len = vlen;
173     return 1;
174     }
175     if ((*rec)->bytes < (*rec)->used + vlen) {
176     nr = rDup (*rec, vlen, disc);
177     if (0 == nr) {
178     return -2;
179     }
180     F = (*rec = nr)->field + fnd;
181     }
182     F->val = (char*)(*rec) + (*rec)->used;
183     F->len = vlen;
184     memcpy ((char*)F->val, val, vlen);
185     (*rec)->used += vlen;
186     return 1;
187     }
188    
189     static int rDel (Rec *rec, LrecMF *lmf) {
190     Field *F;
191     int *M;
192     int idx;
193     int dcnt = 0;
194     int done = 0;
195     for (M = lmf->tagf; lmf->len > M - lmf->tagf; M += 2) {
196     if (0 != (MF_DEL & M[1])) {
197     idx = (M - lmf->tagf) / 2 - dcnt;
198     if (idx < rec->len - 1) {
199     F = rec->field + idx;
200     memmove (F, F + 1, (rec->len - idx - 1) * sizeof (Field));
201     }
202     --(rec->len);
203     ++dcnt;
204     done = !0;
205     }
206     }
207     return done;
208     }
209    
210     /* ************************************************************
211     package functions
212     */
213    
214     /* ************************************************************
215     public functions
216     */
217    
218    
219     Field *rGet ( Rec *r, int tag, int *pos )
220     {
221     if (r) {
222     int p = pos ? *pos : 0;
223     for ( ; p < r->len; p++ )
224     if ( tag == r->field[p].tag ) {
225     if ( pos )
226     *pos = p+1;
227     return &r->field[p];
228     }
229     if ( pos )
230     *pos = r->len;
231     }
232     return 0;
233     } /* rGet */
234    
235     Field *rOccurence ( Rec *r, int tag, int occ ) {
236     Field *F;
237     int pos = 0;
238     do {
239     F = rGet (r, tag, &pos);
240     } while (F && 0 <= --occ);
241     return F;
242     }
243    
244     char *rString (Rec *rec, int tag, int *pos, char *buf, int len) {
245     Field *F = rGet (rec, tag, pos);
246     if (!F) {
247     return 0;
248     }
249     if (len > 1 + F->len) {
250     len = 1 + (int) F->len;
251     }
252     if (0 >= --len) {
253     *buf = 0;
254     return buf;
255     }
256     strncpy (buf, F->val, len) [len] = 0;
257     return buf;
258     }
259    
260    
261     char *rString2 (Rec *rec, Rec *dflt, int tag, char *buf, int len) {
262     char *rt = rString (rec, tag, 0, buf, len);
263     if (rt) {
264     return rt;
265     }
266     return rString (dflt, tag, 0, buf, len);
267     }
268    
269    
270     int rInt ( Rec *r, int tag, int def, int *pos )
271     {
272     if (r) {
273     int p = pos ? *pos : 0;
274     int rt;
275     for ( ; p < r->len; p++ )
276     if ( tag == r->field[p].tag ) {
277     if ( pos )
278     *pos = p+1;
279     rt = a2i( r->field[p].val, r->field[p].len );
280     if (rt) {
281     return rt;
282     }
283     if (0 < luti_true (r->field[p].val, r->field[p].len)) {
284     return 1;
285     }
286     return 0;
287     }
288     if ( pos )
289     *pos = r->len;
290     }
291     return def;
292     } /* rInt */
293    
294    
295     int rInt2 (Rec *rec, Rec *dflt, int tag, int def) {
296     int rt1 = rInt (rec, tag, def, 0);
297     if (def == rt1) {
298     return rInt (dflt, tag, def, 0);
299     }
300     return rt1;
301     }
302    
303    
304     int rEnum (Fdt *fdt, Rec *rec, int tag, int def, int *pos) {
305     char buf[OPENISIS_FD_NAMELEN];
306     Field *F;
307     Fd *D;
308     int len, ev;
309     if (! fdt || ! rec) {
310     return def;
311     }
312     D = fById (fdt, tag, 0);
313     if (! D) {
314     return def;
315     }
316     F = rGet (rec, tag, pos);
317     if (! F) {
318     return def;
319     }
320     len = (int) F->len;
321     if (OPENISIS_FD_NAMELEN <= len) {
322     len = OPENISIS_FD_NAMELEN - 1;
323     }
324     strncpy (buf, F->val, len) [len] = 0;
325     ev = fEnum (fdt, tag, buf);
326     if (NOENUM == ev) {
327     return def;
328     }
329     return ev;
330     }
331    
332    
333     Rec* rDup ( Rec *r, int room, int discard )
334     {
335     Rec *nr = 0;
336     int nfields, nbytes, hadfields, hadcontent;
337     if ( ! r ) {
338     nfields = 80; /* for a 1K base */
339     nbytes = 8*1024;
340     if ( nbytes < BASESZ(80) + room*3/2 )
341     nbytes = BASESZ(80) + room*3/2;
342     hadfields = 0;
343     hadcontent = 0;
344     } else {
345     rCompact (r);
346     hadfields = r->len;
347     hadcontent = r->used - r->base;
348     if ( 0 > room ) { /* shrink to fit */
349     nfields = r->len;
350     nbytes = BASESZ(nfields) + hadcontent;
351     } else {
352     nfields = 54 > r->len ? 80 : (r->len * 3 / 2); /* add 50% */
353     if ( nfields < r->fields )
354     nfields = r->fields;
355     nbytes = 6*1024 > r->bytes ? 8*1024 : (r->bytes *3 / 2);
356     if ( nbytes < r->used + room )
357     nbytes = r->used + room*3/2;
358     nbytes += (nfields - r->fields)*sizeof(Field);
359     }
360     }
361     LOG_DBG( LOG_DEBUG,
362     "extending rec size %d (cont %d) to %d bytes, %d -> %d fields",
363     !r ? -1 : r->bytes, hadcontent, nbytes, hadfields, nfields );
364     assert( nbytes >= BASESZ( nfields ) + hadcontent + room );
365     if ( ! (nr = mAlloc( nbytes )) )
366     return 0;
367     memset( nr, 0, nbytes ); /* paranoia */
368     nr->bytes = nbytes;
369     nr->fields = nfields;
370     nr->base = BASESZ( nfields );
371     nr->used = nr->base + hadcontent;
372     nr->len = hadfields;
373     if ( ! r ) {
374     nr->dbid = -1; /* no valid dbid if new rec */
375     }
376     else {
377     char *obuf = ((char*)r) + r->base;
378     char *nbuf = ((char*)nr) + nr->base;
379     nr->dbid = r->dbid;
380     /* for ! r, the following are 0 by memset */
381     nr->rowid = r->rowid;
382     nr->state = r->state;
383     if ( hadcontent )
384     memcpy( nbuf, obuf, hadcontent );
385     if ( hadfields ) {
386     int i;
387     int displace = nbuf - obuf; /* ptrdiff_t */
388     Field *f = nr->field;
389     memcpy( nr->field, r->field, hadfields*sizeof(Field) );
390     for ( i=hadfields; i--; )
391     if ( f[i].val )
392     f[i].val += displace;
393     #ifndef NDEBUG
394     {
395     char *end = ((char*)nr) + nr->used;
396     for ( i=hadfields; i--; )
397     if ( f[i].val
398     && (f[i].val < nbuf || f[i].val + f[i].len > end)
399     ) {
400     int wasok = r->field[i].val >= obuf
401     && r->field[i].val + r->field[i].len <= obuf + hadcontent;
402     sMsg( LOG_ERROR, "OOPS! nuked field %d which previously was %s",
403     i, wasok ? "ok" : "already broken" );
404     return 0; /* no cleanup, we're nearly dead anyway */
405     }
406     }
407     #endif
408     }
409     if ( discard )
410     free( r );
411     }
412     assert( RECOK(nr) );
413     return nr;
414     } /* rDup */
415    
416    
417     Rec* rMsg ( Rec *r, int discard, int tag, const char *fmt, ... )
418     {
419     char buf[1024];
420     int l;
421     va_list ap;
422     va_start( ap, fmt );
423     l = vsnprintf( buf, sizeof(buf), fmt, ap );
424     if ( 0 > l ) /* older versions return -1 */
425     l = sizeof(buf);
426     va_end( ap );
427     RADD( r, tag, buf, l, discard );
428     return r;
429     } /* rMsg */
430    
431     /*
432     #define openIsisPrintf( r, d, t, f, a... ) \
433     openIsisRMsg( OPENISIS_SES0(), r, d, t, f, ## a )
434     requires gcc ...
435     */
436     Rec* openIsisPrintf ( Rec *r, int discard, int tag, const char *fmt, ... )
437     {
438     char buf[1024];
439     int l;
440     va_list ap;
441     va_start( ap, fmt );
442     l = vsnprintf( buf, sizeof(buf), fmt, ap );
443     if ( 0 > l ) /* older versions return -1 */
444     l = sizeof(buf);
445     va_end( ap );
446     RADD( r, tag, buf, l, discard );
447     return r;
448     } /* openIsisPrintf */
449    
450    
451     Rec *rAddI (Rec *rec, int tag, int val, int discard) {
452     char buf[32];
453     int len = i2a (buf, (int)val);
454     RADD (rec, tag, buf, len, discard);
455     return rec;
456     }
457    
458    
459     Rec* rSet ( Rec *oldr, int mode, ... )
460     {
461     const char **argv = 0;
462     LrecMF *lmf = 0;
463     Fdt *fdt = 0;
464     Rec *newr = oldr;
465     int argc = 0xffff & mode;
466     int dis = RDIS & mode;
467     int op = ROP & mode;
468     int lmode = MF_SET;
469     int compact = 0;
470    
471     va_list ap;
472     va_start( ap, mode );
473    
474     if (RFDT & mode) {
475     fdt = va_arg( ap, Fdt* );
476     }
477     if (RARGV & mode) {
478     argv = va_arg( ap, const char** );
479     }
480     if (! fdt) {
481     fdt = luti_fdt_from_rec (oldr);
482     }
483     if (op) {
484     switch (op) {
485     case RDEL:
486     lmode = MF_DEL;
487     break;
488     case RCHG:
489     break;
490     case RDFLT:
491     lmode = 0;
492     break;
493     default:
494     sMsg (ERR_IDIOT, "rSet: illegal mode %x", op);
495     return newr;
496     }
497     if (oldr) {
498     if (0 == (lmf = mfCtor (oldr))) {
499     goto done;
500     }
501     }
502     else if (RDEL == op) {
503     goto done;
504     }
505     }
506    
507     for ( ;; ) {
508     char ib[16];
509     Rec *tmpr;
510     const char *v = 0;
511     int id = -1;
512     int occr = -1;
513     Fd *fd = 0;
514     int rpl;
515     if ( argv ) {
516     if ( 1 > argc )
517     break;
518     v = luti_parse_path (*argv, fdt, &fd, &id, &occr);
519     if (!v || *v) {
520     fd = 0;
521     id = -1;
522     }
523     v = 0;
524     ++argv;
525     --argc;
526     }
527     else {
528     id = va_arg( ap, int );
529     if ( ! id )
530     break;
531     fd = fdt ? fById( fdt, id, 0 ) : 0;
532     if (RDEL != op) {
533     v = va_arg( ap, char* );
534     }
535     }
536     if ( fd ) {
537     if (RDEL != op) {
538     int e;
539     if (argv) {
540     if ( 1 > argc ) {
541     if (FTB != fd->type) {
542     break;
543     }
544     }
545     else {
546     v = *argv++;
547     --argc;
548     }
549     }
550     switch ( fd->type ) {
551     case FTE:
552     e = fEnum( fdt, fd->id, v );
553     if ( NOENUM == e ) {
554     if ( RIGN & mode )
555     continue;
556     sMsg( LOG_ERROR,
557     "bad enum value '%s' for id %d", v, fd->id );
558     goto error;
559     }
560     i2a( ib, e );
561     v = ib;
562     break;
563     case FTB:
564     e = v ? luti_true (v, -1) : 1;
565     if (0 > e) {
566     /* non-given values default to true */
567     ++argc;
568     --argv;
569     v = "1";
570     }
571     else {
572     v = e ? "1" : "0";
573     }
574     break;
575     }
576     } /* RDEL != op */
577     } /* fd */
578     else {
579     if (argv) {
580     if (RDEL != op) {
581     if ( 1 > argc ) {
582     break;
583     }
584     v = *argv++;
585     --argc;
586     }
587     }
588     if (fdt /*|| 0 >= id*/) {
589     if ( RIGN & mode )
590     continue;
591     if ( argv )
592     sMsg( LOG_ERROR, "unknown field name '%s'",
593     argv[RDEL == op ? -1 : -2] );
594     else
595     sMsg( LOG_ERROR, "unknown field id %d", id );
596     break;
597     }
598     }
599     if (!v) {
600     v = "";
601     }
602     if (op) {
603     rpl = lmf ? rReplace (
604     &newr, lmf, id, occr, lmode, v, dis || newr != oldr) :
605     -1;
606     if (RDFLT == op) {
607     if (-1 != rpl) {
608     continue;
609     }
610     }
611     else {
612     if (-2 == rpl) {
613     goto done;
614     }
615     if (-1 != rpl) {
616     if (1 == rpl) {
617     compact = !0;
618     }
619     continue;
620     }
621     if (RDEL == op) {
622     continue;
623     }
624     }
625     /* fall thru */
626     }
627     tmpr = newr;
628     RADDS( newr, id, v, dis || newr != oldr );
629     if (0 == newr) {
630     goto done;
631     }
632     if (newr != tmpr) {
633     compact = 0;
634     }
635     sMsg( LOG_VERBOSE,
636     "added v '%s' id %d as %dth", v, id, newr->len );
637     }
638    
639     error:
640     if (lmf) {
641     if (rDel (newr, lmf)) {
642     compact = !0;
643     }
644     }
645    
646     if (compact && 0 == (RNOC & mode)) {
647     rCompact (newr);
648     }
649    
650     done:
651     if (lmf) {
652     mFree (lmf);
653     }
654     va_end( ap );
655     return newr;
656     } /* rSet */
657    
658    
659     Rec *dFmt ( Rec *buf, const char *fmt, int db, int rowid )
660     {
661     Rec *r = dRead( db, rowid );
662     Rec *q;
663     if ( ! r )
664     return 0;
665     q = rFmt( buf, fmt, r );
666     free( r );
667     return q;
668     } /* dFmt */
669    
670    
671     Rec *dScan ( int db, int rowid, int tag, const char *txt )
672     {
673     int max = dMaxId( db );
674     int tlen = strlen( txt );
675     const char f = *txt;
676    
677     for ( ; rowid <= max; rowid++ ) {
678     int i, found = 0;
679     Rec *r = dRead( db, rowid );
680     if ( ! r )
681     continue;
682    
683     for ( i=0; i < r->len; i++ ) {
684     const char *c, *e;
685     if ( found
686     || (tag > 0 && tag != r->field[i].tag)
687     || tlen > r->field[i].len
688     )
689     continue;
690     c = r->field[i].val;
691     e = c + r->field[i].len - tlen;
692     for ( ; c<=e; c++ )
693     if ( f == *c && !memcmp( c, txt, tlen ) ) {
694     found = !0;
695     break;
696     }
697     }
698     if ( found )
699     return r;
700     }
701     return 0;
702     } /* dScan */
703    
704    
705    
706    
707    
708     Rec *rSplitf ( Rec *r, const Field* field )
709     {
710     int i;
711     int nfields = 0; /* number of subfields */
712     int size; /* byte length of field list */
713     const char *p, *e;
714    
715     if ( ! field || 2 > field->len )
716     return 0;
717     if ( '^' != field->val[0] ) /* initial anonymous subfield */
718     nfields = 1;
719     /* go counting hats ... */
720     for ( e = (p=field->val) + field->len - 1; p<e; )
721     if ( '^' == *p++ && '^' != *p ) /* ignore first of ^^ */
722     nfields++;
723     if ( '^' == *p )
724     sMsg( LOG_ERROR, "found trailing '^' in field '%.*s'",
725     (int)field->len, field->val );
726    
727     if ( r ) {
728     if ( 1 > r->len )
729     return 0;
730     size = sizeof(Rec) + (r->len - 1) * sizeof(Field);
731     if ( nfields > r->len )
732     nfields = r->len;
733     } else {
734     /* first field already counted in sizeof(Rec) */
735     size = sizeof(Rec) + (nfields - 1) * sizeof(Field);
736     r = (Rec *)mAlloc( size );
737     if ( ! r )
738     return 0;
739     }
740     memset( r, 0, size );
741     r->rowid = 0;
742     r->len = nfields;
743    
744     e = (p = field->val) + field->len;
745     if ( '^' == *p ) /* else initial anonymous subfield */
746     p++;
747     for ( i=0; i<nfields; i++ ) {
748     /* p is on hat or end ... skip all consecutive hats */
749     while ( p<e && '^' == *p )
750     p++;
751     if ( p >= e ) {
752     sMsg( LOG_ERROR,
753     "confused cats hound counting hats at %d in '%.*s'",
754     i, field->len, field->val );
755     r->len = i;
756     break;
757     }
758     /* p is after a hat */
759     r->field[ i ].tag = p==field->val ? 0 : (unsigned char)*p++;
760     r->field[ i ].val = p;
761     /* advance in buf */
762     while ( p<e && '^' != *p )
763     p++;
764     r->field[ i ].len = p - r->field[ i ].val;
765     /* log_msg( LOG_ERROR, "subf %d of %d tag %c off %d",
766     i, nfields, r->field[ i ].tag, r->field[ i ].val - field->val ); */
767     }
768    
769     return r;
770     } /* rSplitf */
771    
772    
773    
774    
775     enum { /* stream reading state */
776     RS_REC, /* not in any record */
777     RS_TAG, /* in tag: done is at beginning of line */
778     RS_SEP, /* in sep: done is at beginning of sep */
779     RS_VAL, /* done is somewhere in the value ... */
780     RS_EOL /* not really a state, but a flag */
781     };
782    
783    
784     /**
785     read a record from a stream.
786     This may either
787     <ol>
788     <li> read a record and return 1
789     </li>
790     <li> not get enough bytes on a non-blocking stream and return 0
791     </li>
792     <li> have some error and return negative
793     </li>
794     </ol>
795     */
796     int sGetr ( OpenIsisRecStream *s )
797     {
798     Ios *lio = s->in;
799     int state = 3 & s->flg;
800     int emptyline = 0;
801     int ret = 0;
802     if ( ! s->rec
803     && ! (s->rec = s->buf) /* have buffer ? */
804     && ! (s->rec = rDup( 0, 0, 0 ))
805     /* allocate and prepare an 8k standard record */
806     ) {
807     ret = sMsg( LOG_ERROR, "could not get record" );
808     goto fatal;
809     }
810     if ( RS_REC == state ) { /* initialize */
811     s->rec->rowid = 0;
812     s->rec->len = 0; /* nuke all fields */
813     s->rec->used = s->rec->base; /* nuke value buffer */
814     /* let base/fields untouched, it hopefully has a reasonable value */
815     state = RS_TAG;
816     }
817     if ( ! s->rec->len )
818     state = RS_TAG;
819     for (;;) {
820     unsigned char *b, *p, *e; /* begin, pointer, end */
821     if ( lio->b.done >= lio->b.fill ) {
822     reload:
823     if ( ! LIO_FILL( lio ) )
824     goto done; /* EAGAIN -- see ya later */
825     /* so we have bytes or EOF */
826     if ( lio->b.done >= lio->b.fill ) {
827     if ( LIO_IN & lio->file ) {
828     sMsg( LOG_ERROR, "confused in instream: no bytes and no EOF" );
829     lio_close( &lio->file, LIO_IN );
830     }
831     break;
832     }
833     }
834     /* so we have bytes */
835     p = b = lio->b.c + lio->b.done;
836     e = lio->b.c + lio->b.fill;
837     /* try to eat one line */
838     switch ( state ) {
839     case RS_TAG: {
840     int tag = -1;
841     int recognized = 0;
842     if ( LCS_ISFR(lcs_latin1_ct[*p]) ) { /* line starts with line/record sep */
843     if ( '\n' == *p && (RS_EOL & s->flg) ) { /* TODO */
844     s->flg &= ~RS_EOL;
845     continue;
846     }
847     emptyline = !0;
848     break;
849     }
850     for (;;p++) {
851     if ( p < e ) {
852     if ( LCS_ISWORD(lcs_latin1_ct[*p]) )
853     continue; /* tight loop */
854     break;
855     }
856     if ( 4096 > p - b )
857     goto reload;
858     sMsg( ERR_TRASH, "tag too long" );
859     goto fatal;
860     }
861     /* identify tag between s and p */
862     if ( p == b )
863     recognized = !0;/* empty tag */
864     else if ( '0' <= *b && *b <= '9' ) {
865     unsigned char *d = b; /* digit ? */
866     tag = 0;
867     while ( d < p && '0' <= *d && *d <= '9' )
868     tag = 10*tag + *d++ - '0';
869     if ( !(recognized = d == p) ) /* all digits */
870     tag = -1;
871     }
872     if ( ! recognized && s->dict ) { /* dict lookup */
873     int i=s->dict->len, l = p-b;
874     Field *f = s->dict->field;
875     for ( ; i--; f++ )
876     if ( l == f->len && memcmp( b, f->val, l ) ) {
877     tag = f->tag;
878     break;
879     }
880     }
881     /* create new field unless it's a continuation line */
882     if ( p == b && s->rec->len )
883     ;
884     else if ( recognized )
885     RADD( s->rec, tag, 0, 0, s->rec != s->buf );
886     else
887     RADD( s->rec, tag, b, p-b, s->rec != s->buf );
888     if ( ! s->rec )
889     goto outamem;
890     /* did that */
891     lio->b.done = (b = p) - lio->b.c;
892     if ( LCS_ISFR(lcs_latin1_ct[*p]) )
893     break;
894     state = RS_SEP;
895     } case RS_SEP:
896     /* p = b is at beginning of separator */
897     while ( p < e && ' ' == *p ) /* skip leading blanks */
898     p++;
899     if ( p < e && LCS_ISCST(lcs_latin1_ct[*p]) && '\t' != *p++ )
900     while ( p < e && ' ' == *p ) /* skip trailing blanks */
901     p++;
902     if ( e == p ) {
903     if ( 4096 > p - b )
904     goto reload;
905     sMsg( ERR_TRASH, "sep too long" );
906     goto fatal;
907     }
908     assert( s->rec->len );
909     if ( s->rec->field[s->rec->len - 1].len )
910     RCAT( s->rec, b, p-b, s->rec != s->buf );
911     if ( ! s->rec )
912     goto outamem;
913     lio->b.done = (b = p) - lio->b.c;
914     if ( LCS_ISFR(lcs_latin1_ct[*p]) )
915     break;
916     state = RS_VAL;
917     case RS_VAL: default: /* ??? */
918     while ( p < e && !LCS_ISFR(lcs_latin1_ct[*p]) )
919     p++;
920     assert( s->rec->len );
921     if ( p > b )
922     RCAT( s->rec, b, p-b, s->rec != s->buf );
923     if ( ! s->rec )
924     goto outamem;
925     lio->b.done = (b = p) - lio->b.c;
926     if ( p == e )
927     goto reload;
928     /* else we found line or record separator */
929     } /* switch state */
930     if ( '\r' == *p ) { /* do that ole' ugly CR/NL quatsch */
931     if ( e-p < 2 && 0 < LIO_FILL(lio) ) /* extend end */
932     e = lio->b.c + lio->b.fill;
933     if ( e-p < 2 )
934     s->flg |= RS_EOL; /* possibly check later */
935     else if ( '\n' == p[1] )
936     p++;
937     }
938     lio->b.done = 1 + p - lio->b.c; /* consider p eaten */
939     if ( LCS_R == lcs_latin1_ct[*p]
940     || (emptyline && (OPENISIS_STOPONEMPTY & s->flg))
941     )
942     break;
943     state = RS_TAG;
944     }
945     /* got record */
946     state = RS_REC;
947     if ( s->rec && s->rec->len ) {
948     if ( (OPENISIS_AUTOCLONE & s->flg) && s->rec == s->buf )
949     s->rec = rDup( s->buf, 0, 0 );
950     ret = 1;
951     }
952     goto done;
953     outamem:
954     fatal:
955     if ( LIO_SISOPEN( s->in ) )
956     LIO_CLOSE( s->in );
957     done:
958     s->flg = state | (~3 & s->flg); /* save state */
959     /* sMsg( LOG_ERROR, "fill %d done %d", lio->b.fill, lio->b.done ); */
960     return ret;
961     } /* openIsisReadStream */
962    
963    
964     int rSer ( char *buf, OpenIsisRec *rec )
965     {
966     Field *f = rec->field;
967     int i = rec->len;
968     char *p = buf, *e;
969    
970     for ( ; i--; f++ ) {
971     p += i2a( p, f->tag );
972     *p++ = 9; /* TAB */
973     memcpy( p, f->val, f->len );
974     for ( e = p + f->len; p<e; )
975     if ( 10 == *p++ )
976     p[-1] = 11;
977     *p++ = 10;
978     }
979     *p++ = 10;
980     return p - buf;
981     } /* rSer */
982    
983    
984     /** binary serialize, turns newline into newline tab
985     buf must have len >= 2*rec->used
986     */
987     int rSerB ( char *buf, OpenIsisRec *rec )
988     {
989     Field *f = rec->field;
990     int i = rec->len;
991     char *p = buf;
992     const char *s, *e;
993    
994     for ( ; i--; f++ ) {
995     p += i2a( p, f->tag );
996     *p++ = 9; /* TAB */
997     for ( e = (s = f->val) + f->len; s<e; )
998     if ( 10 == (*p++ = *s++) )
999     *p++ = 9;
1000     *p++ = 10;
1001     }
1002     *p++ = 10;
1003     return p - buf;
1004     } /* rSerB */
1005    
1006    
1007     char* rSerA (Rec *rec, char *buf, int *len) {
1008     if (!len) {
1009     return 0;
1010     }
1011     if (!rec) {
1012     *len = 0;
1013     return buf;
1014     }
1015     if (*len <= rec->used) {
1016     buf = (char*) mAlloc (1 + rec->used);
1017     if (!buf) {
1018     sMsg (ERR_NOMEM, "rSerA: cannot malloc %d", (1 + rec->used));
1019     return 0;
1020     }
1021     }
1022     *len = rSer (buf, rec);
1023     return buf;
1024     }
1025    
1026    
1027     int rDeser ( OpenIsisRec **rp, const char *buf, int len, int flg )
1028     {
1029     Rec *rec = *rp;
1030     Field *f;
1031     const char *p = buf, *e = buf+len;
1032     char *q;
1033     int dis = RDIS & flg;
1034     int tag;
1035     /* non-transparent mode - no continuation lines */
1036     for ( ; e > p; p++ ) {
1037     if ( 10 == *p ) { /* blank line */
1038     if ( OPENISIS_STOPONEMPTY & flg )
1039     break;
1040     continue;
1041     }
1042     p += a2il( p, e-p, &tag );
1043     if ( e > p && 9 == *p ) /* TAB */
1044     p++;
1045     RADD( rec, tag, 0, e-p, dis || rec!=*rp );
1046     if ( !rec )
1047     break;
1048     f = rec->field + rec->len-1;
1049     for ( q=(char*)f->val; e>p && 10 != *p; )
1050     if ( 11 == (*q++ = *p++) )
1051     q[-1] = 10;
1052     rec->used += f->len = q - f->val;
1053     }
1054     *rp = rec;
1055     return p-buf;
1056     } /* rDeser */

  ViewVC Help
Powered by ViewVC 1.1.26