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