/[webpac]/trunk2/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

Contents of /trunk2/openisis/lrec.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 337 - (show annotations)
Thu Jun 10 19:22:40 2004 UTC (15 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 22538 byte(s)
new trunk for webpac v2

1 /*
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