/[webpac]/trunk/openisis/lfmt.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/lfmt.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 239 - (hide annotations)
Mon Mar 8 17:49:13 2004 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 35628 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: lfmt.c,v 1.14 2003/04/08 00:20:52 kripke Exp $
25     implementation of record cooking.
26     */
27    
28     #include <string.h> /* memset et al */
29    
30     #include "ldb.h"
31    
32    
33     #define LFMT_DBG LOG_WARN /* level of debugging */
34    
35     /* ************************************************************
36     private types
37     */
38     typedef struct { /* function definition */
39     const char *name; /* hmmm ... fixed char[] probably faster */
40     const char *sign;
41     int tag;
42     } LfmtToken;
43    
44     typedef enum {
45     LFMT_MP, /* proof */
46     LFMT_MH, /* heading */
47     LFMT_MD /* data */
48     } lfmtMode;
49    
50     typedef struct LfmtIter_ { /* value iterator */
51     const unsigned char *def; /* position in format where iter was opened. */
52     const unsigned char *end; /* position in format where iter was closed. */
53     int pos; /* next field pos */
54     int off; /* offset to start search for next subfield */
55     int occ; /* next occ */
56     /* filter */
57     int tag;
58     char sub;
59     char submode; /* primary loop (counted by occ) is over subfields. */
60     int from; /* primary range. */
61     int to;
62     int sfrom; /* additional subfield range. */
63     int sto;
64     } LfmtIter;
65    
66     #define LFMT_NITER 8
67    
68     typedef struct LfmtRec_ { /* record context -- pushed by the r in REF */
69     struct LfmtRec_ *prev;
70     Rec *r;
71     int frame; /* stack frame associated with this record */
72     const unsigned char *loop; /* position in format where loop was opened. */
73     LfmtIter iter[LFMT_NITER]; /* iterators in loop */
74     int occ; /* loop occ */
75     unsigned char i; /* iterator count */
76     char more; /* more flag */
77     char had; /* had flag */
78     char sub; /* database's subfield separator, typically ^ or $ */
79     } LfmtRec;
80    
81     typedef struct LfmtFmt_ { /* format context -- pushed by @ */
82     struct LfmtFmt_ *prev;
83     const unsigned char *f;
84     const unsigned char *e; /* end -- just for paranoia check */
85     lfmtMode mode;
86     int upcase; /* uppercase flag */
87     } LfmtFmt;
88    
89    
90     typedef struct { /* other type */
91     const LfmtToken *tok; /* recognized token */
92     int data; /* start of params in output */
93     int used; /* used len of output up to our params */
94     char pos; /* position in signature */
95     char want; /* currently expected type */
96     char expl; /* explicit flag */
97     char rec; /* record flag */
98     } LfmtFrame;
99    
100    
101     /*
102     list of special token tags after the format tags 1 .. 999.
103     unlike formatting tokens, which just emit a field with their negative tag,
104     the literal's tag is reset to 0,
105     and all other tokens emit fields with tags based on their parameters.
106    
107     tokens are organized in groups of (up to) 16.
108     the group of an operator determines it's precedence.
109     */
110     #define LFMT_DEFGROUP(i) ((i) << 4) /* * 16 */
111     #define LFMT_GROUP(i) ((i) >> 4)
112    
113     /* token groups */
114     enum {
115     LFMT_LITERAL = 63, /* literals group starting from 63*16 = 1008 */
116     /* syntactical groups starting from 64*16 = 0x400 */
117     LFMT_FUNCTIONS,
118     LFMT_VALUES = 96, /* starting from 96*16 = 0x600 */
119     LFMT_ITERATORS,
120     LFMT_OPITER, /* iterator operators */
121     LFMT_OPSTR, /* string operators */
122     LFMT_OPMUL, /* multiplicative operators */
123     LFMT_OPADD, /* additive operators */
124     LFMT_OPREL, /* relational operators */
125     LFMT_OPBOOL, /* boolean operators */
126     LFMT_OPASSIGN, /* assignment */
127     LFMT_STOPPER = 128, /* starting from 128*16 = 0x800 */
128     LFMT_SYNTAX
129     };
130    
131     enum {
132     /* literals */
133     LFMT_LIT = LFMT_DEFGROUP( LFMT_LITERAL ),
134     LFMT_COND,
135     LFMT_REP,
136     LFMT_COMM,
137     LFMT_BARE, /* field of bareword C&A literal */
138     LFMT_NUMBER, /* standalone numeric literal */
139     /* functions */
140     LFMT_OPEN = LFMT_DEFGROUP( LFMT_FUNCTIONS ),
141     LFMT_AMP,
142     LFMT_AT,
143     LFMT_XREF,
144     LFMT_S,
145     LFMT_Z,
146     LFMT_F,
147     /* */
148     LFMT_MDL,
149     LFMT_MDU,
150     LFMT_MHL,
151     LFMT_MHU,
152     LFMT_MPL,
153     LFMT_MPU,
154     /* values */
155     LFMT_SI = LFMT_DEFGROUP( LFMT_VALUES ),
156     LFMT_EI,
157     /* iterators */
158     LFMT_V = LFMT_DEFGROUP( LFMT_ITERATORS ),
159     LFMT_D,
160     LFMT_N,
161     /* operator groups by decreasing precedence */
162     LFMT_INDEX = LFMT_DEFGROUP( LFMT_OPITER ),
163     LFMT_SUBFIELD,
164     LFMT_STAR = LFMT_DEFGROUP( LFMT_OPSTR ),
165     LFMT_DOT, LFMT_INDENT,
166     LFMT_MUL = LFMT_DEFGROUP( LFMT_OPMUL ),
167     LFMT_DIV,
168     LFMT_PLUS = LFMT_DEFGROUP( LFMT_OPADD ),
169     LFMT_MINUS,
170     LFMT_EQ = LFMT_DEFGROUP( LFMT_OPREL ),
171     LFMT_NE, LFMT_LT, LFMT_LE, LFMT_GT, LFMT_GE, LFMT_CT,
172     LFMT_AND = LFMT_DEFGROUP( LFMT_OPBOOL ),
173     LFMT_OR, LFMT_NOT,
174     LFMT_ASSIGN = LFMT_DEFGROUP( LFMT_OPASSIGN ),
175     /* stoppers */
176     LFMT_COMMA = LFMT_DEFGROUP( LFMT_STOPPER ),
177     LFMT_RANGE,
178     LFMT_CLOSE,
179     /* syntax */
180     LFMT_BLANK = LFMT_DEFGROUP( LFMT_SYNTAX ),
181     LFMT_LOOP,
182     LFMT_WHILE,
183     LFMT_REF,
184     LFMT_IF, LFMT_THEN, LFMT_ELSE, LFMT_FI,
185     LFMT_SELECT, LFMT_CASE, LFMT_ELSECASE, LFMT_ENDSEL,
186     LFMT__LAST
187     };
188    
189     /*
190     while fields emitted by formatting and literal tokens
191     have tags between -1 and -1023 (0xffffffff to 0xfffffc01)
192     with all high bits set, numerics have lowest negative values
193     ranging from 0x80000000 to 0xbfffffff (-2147483648 to -1073741825).
194     That means the highest two bits are 1 and 0.
195     All numeric fields have a val of NULL and use len to hold a number.
196     Besides pure int or fixed-point numbers,
197     there are other numerical types:
198     next two bits may indicate a range or field selector.
199     The lower 3 bytes may give fractional part or range end.
200     */
201     #define LFMT_NMASK 0xf0000000L /* highest bits 1 and 0 mark a number */
202     #define LFMT_NUM 0x80000000L /* basic number */
203     #define LFMT_ITR 0xa0000000L /* with iterator bit */
204     #define LFMT_VAL 0x00ffffffL /* mask for 3 bytes additional info */
205     /* is any numeric */
206     #define LFMT_ISNUM(t) (LFMT_NUM == (LFMT_NMASK & (t)))
207     /* is pure int */
208     #define LFMT_ISINT(t) (LFMT_NUM == (t))
209     /* is iterator */
210     #define LFMT_ISITR(t) (LFMT_ITR == (LFMT_NMASK & (t)))
211    
212     /* ************************************************************
213     private data
214     */
215     static const LfmtToken number = { "", "_1i", LFMT_NUMBER };
216     /* while a numeric *field* has large LFMT_NUM tag,
217     the anonymous number *token* has a literal tag,
218     so we don't take it as high precedence operator.
219     */
220     static const LfmtToken blank = { "_", "_0o_", LFMT_BLANK };
221     static const LfmtToken loop = { "loop", "_0o_", LFMT_LOOP };
222    
223     /*
224     32 = 33 = ! 34 = " 35 = # 36 = $ 37 = % 38 = & 39 = '
225     40 = ( 41 = ) 42 = * 43 = + 44 = , 45 = - 46 = . 47 = /
226     48 = 0 49 = 1 50 = 2 51 = 3 52 = 4 53 = 5 54 = 6 55 = 7
227     56 = 8 57 = 9 58 = : 59 = ; 60 = < 61 = = 62 = > 63 = ?
228     64 = @ 65 = A 66 = B 67 = C 68 = D 69 = E 70 = F 71 = G
229     72 = H 73 = I 74 = J 75 = K 76 = L 77 = M 78 = N 79 = O
230     80 = P 81 = Q 82 = R 83 = S 84 = T 85 = U 86 = V 87 = W
231     88 = X 89 = Y 90 = Z 91 = [ 92 = \ 93 = ] 94 = ^ 95 = _
232     96 = ` 97 = a 98 = b 99 = c 100 = d 101 = e 102 = f 103 = g
233     104 = h 105 = i 106 = j 107 = k 108 = l 109 = m 110 = n 111 = o
234     112 = p 113 = q 114 = r 115 = s 116 = t 117 = u 118 = v 119 = w
235     120 = x 121 = y 122 = z 123 = { 124 = | 125 = } 126 = ~
236     */
237     /* stops dictionary search */
238     static const char sentinel[] = "\x7f";
239     #define ENDDICT { sentinel, NULL, 0 }
240    
241     static const LfmtToken dictSpecial[] = {
242     { "", "_0", 0 }, /* eof */
243     { "!", "_1x", OPENISIS_FMT_ESC },
244     { "\"", "_1x", LFMT_COND },
245     { "#", "_0", OPENISIS_FMT_SHARP },
246     /* { "$", "_0", LFMT_LIT }, */
247     { "%", "_0", OPENISIS_FMT_PERCENT },
248     { "&", "_1as_", LFMT_AMP },
249     { "'", "_1x", LFMT_LIT },
250     { "(", "_0", LFMT_OPEN },
251     { ")", "_0", LFMT_CLOSE },
252     { "*", "n1n", LFMT_MUL },
253     { "+", "n1n", LFMT_PLUS },
254     { ",", "_0", LFMT_COMMA },
255     { "-", "n1n", LFMT_MINUS },
256     { ".", "s1i", LFMT_DOT },
257     { "..","_0", LFMT_RANGE },
258     { "/", "n1n", LFMT_DIV }, /* alias { "/", "_0", OPENISIS_FMT_SLASH }, */
259     { "/*","_1x", LFMT_COMM },
260     /* 0 - 9 */
261     { ":", "s1s", LFMT_CT },
262     { ":=","v1f", LFMT_ASSIGN },
263     /* { ";", "b_", LFMT_LIT }, */
264     { "<", "n1n", LFMT_LT },
265     { "<=","n1n", LFMT_LE },
266     { "<>","n1n", LFMT_NE },
267     { "=", "n1n", LFMT_EQ },
268     { ">", "n1n", LFMT_GT },
269     { ">=","n1n", LFMT_GE },
270     /* { "?", "b_", LFMT_LIT }, */
271     { "@", "_1a", LFMT_AT },
272     /* A - Z */
273     { "[", "v1nn", LFMT_INDEX },
274     /* { "\\", "_0", LFMT_LIT }, */
275     { "]", "_0", LFMT_CLOSE },
276     { "^", "v1c", LFMT_SUBFIELD },
277     /* { "_", "_0", LFMT_LIT }, */
278     /* { "`", "_0", LFMT_LIT }, */
279     /* a - z */
280     { "{", "_0", OPENISIS_FMT_OPEN },
281     { "|", "_1x", LFMT_REP },
282     { "}", "_0", OPENISIS_FMT_CLOSE },
283     { "~", "_1n", LFMT_NOT },
284     ENDDICT };
285     static const LfmtToken dictA[] = { ENDDICT };
286     static const LfmtToken dictB[] = {
287     { "B", "_0", OPENISIS_FMT_B },
288     ENDDICT };
289     static const LfmtToken dictC[] = {
290     { "C", "_1i", OPENISIS_FMT_C },
291     ENDDICT };
292     static const LfmtToken dictD[] = {
293     { "D", "_1i", LFMT_D },
294     ENDDICT };
295     static const LfmtToken dictE[] = {
296     { "E", "_1i", LFMT_EI },
297     { "ELSE", "_1s_", LFMT_ELSE },
298     ENDDICT };
299     static const LfmtToken dictF[] = {
300     /* { "F", "_1nii", LFMT_F }, */
301     { "F", "_1i", OPENISIS_FMT_F },
302     ENDDICT };
303     static const LfmtToken dictG[] = { ENDDICT };
304     static const LfmtToken dictH[] = { ENDDICT };
305     static const LfmtToken dictI[] = {
306     { "I", "_0", OPENISIS_FMT_I },
307     { "IF", "_1n", LFMT_IF },
308     ENDDICT };
309     static const LfmtToken dictJ[] = { ENDDICT };
310     static const LfmtToken dictK[] = { ENDDICT };
311     static const LfmtToken dictL[] = {
312     { "LINK", "_1s_", OPENISIS_FMT_LINK },
313     ENDDICT };
314     static const LfmtToken dictM[] = {
315     { "M", "_1ii", OPENISIS_FMT_M },
316     { "MDL", "_0", LFMT_MDL },
317     { "MDU", "_0", LFMT_MDU },
318     { "MHL", "_0", LFMT_MHL },
319     { "MHU", "_0", LFMT_MHU },
320     { "MPL", "_0", LFMT_MPL },
321     { "MPU", "_0", LFMT_MPU },
322     ENDDICT };
323     static const LfmtToken dictN[] = {
324     { "N", "_1i", LFMT_N },
325     { "NC", "_0i", OPENISIS_FMT_NC },
326     ENDDICT };
327     static const LfmtToken dictO[] = { ENDDICT };
328     static const LfmtToken dictP[] = {
329     { "PICT", "_1s", OPENISIS_FMT_PICT },
330     ENDDICT };
331     static const LfmtToken dictQ[] = {
332     { "QC", "_0", OPENISIS_FMT_QC },
333     ENDDICT };
334     static const LfmtToken dictR[] = {
335     { "REF", "_2rs_", LFMT_REF },
336     ENDDICT };
337     static const LfmtToken dictS[] = {
338     { "S", "_1s_", LFMT_S },
339     ENDDICT };
340     static const LfmtToken dictT[] = {
341     { "TAB", "_0i", OPENISIS_FMT_TAB },
342     ENDDICT };
343     static const LfmtToken dictU[] = {
344     { "UL", "_0", OPENISIS_FMT_UL },
345     ENDDICT };
346     static const LfmtToken dictV[] = {
347     { "V", "_1i", LFMT_V },
348     ENDDICT };
349     static const LfmtToken dictW[] = { ENDDICT };
350     static const LfmtToken dictX[] = {
351     { "X", "_0i", OPENISIS_FMT_X },
352     ENDDICT };
353     static const LfmtToken dictY[] = { ENDDICT };
354     static const LfmtToken dictZ[] = {
355     { "Z", "_1is", LFMT_Z },
356     ENDDICT };
357    
358     static const LfmtToken * const dictAZ[26] = {
359     dictA, dictB, dictC, dictD, dictE, dictF, dictG, dictH, dictI,
360     dictJ, dictK, dictL, dictM, dictN, dictO, dictP, dictQ, dictR,
361     dictS, dictT, dictU, dictV, dictW, dictX, dictY, dictZ
362     };
363    
364    
365     /* character conversion */
366     static const unsigned char upcase[256] = {
367     0,' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
368     ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
369     ' ','!','"','#','$','%','&','\'', '(',')','*','+',',','-','.','/',
370     '0','1','2','3','4','5','6','7', '8','9',':',';','<','=','>','?',
371     '@','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O',
372     'P','Q','R','S','T','U','V','W','X','Y','Z','[','\\',']','^','_',
373     '`','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O',
374     'P','Q','R','S','T','U','V','W','X','Y','Z','{','|','}','~',' ',
375     '?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?',
376     '?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?',
377     '?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?',
378     '?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?',
379     '?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?',
380     '?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?',
381     '?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?',
382     '?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?'
383     };
384    
385     enum {
386     DIG=0x01, /* digit */
387     ALP=0x02, /* ascii alphabetic */
388     IDE=0x04, /* other identifier character */
389     LIT=0x10, /* as signature type, eat literal (a,c,i,x) */
390     ALT=ALP|LIT
391     };
392     /* character type */
393     static const unsigned char ctype[256] = {
394     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
395     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
396     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
397     DIG,DIG,DIG,DIG,DIG,DIG,DIG,DIG,DIG,DIG, 0, 0, 0, 0, 0, 0,
398     /*'@','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O',*/
399     0,ALP,ALP,ALP,ALP,ALP,ALP,ALP,ALP,ALP,ALP,ALP,ALP,ALP,ALP,ALP,
400     /*'P','Q','R','S','T','U','V','W','X','Y','Z','[','\\',']','^','_',*/
401     ALP,ALP,ALP,ALP,ALP,ALP,ALP,ALP,ALP,ALP,ALP, 0, 0, 0, 0,IDE,
402     0,ALT,ALP,ALT,ALP,ALP,ALP,ALP,ALP,ALT,ALP,ALP,ALP,ALP,ALP,ALP,
403     ALP,ALP,ALP,ALP,ALP,ALP,ALP,ALP,ALT,ALP,ALP, 0, 0, 0, 0, 0,
404     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
405     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
406     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
407     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
408     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
409     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
410     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
411     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
412     };
413    
414    
415     /* ************************************************************
416     private functions
417     */
418     /* don't rely on braindead ctype.h, it may use locale */
419     #define ISALPHA(u) ( ALP & ctype[(unsigned char)(u)])
420     #define ISDIGIT(u) ( DIG & ctype[(unsigned char)(u)])
421     #define ISALNUM(u) ((ALP|DIG) & ctype[(unsigned char)(u)])
422     #define ISIDENT(u) ((ALP|DIG|IDE) & ctype[(unsigned char)(u)])
423     #define ISLITER(u) ( LIT & ctype[(unsigned char)(u)])
424    
425     /* ************************************************************
426     package functions
427     */
428     /* ************************************************************
429     public functions
430     */
431    
432     Rec* rFmt ( Rec *buf, const char *fmt, Rec *irec )
433     {
434     /* context */
435     Rec *o = buf;
436     #define ADD( ntag, s, n ) do { \
437     RADD( o, ntag, s, n, o!=buf ); \
438     if ( NULL == o ) goto outofmem; \
439     } while(0)
440     #define CAT( s, n ) do { \
441     RCAT( o, s, n, o!=buf ); \
442     if ( NULL == o ) goto outofmem; \
443     } while(0)
444     /* field add */
445     #define FADD( f ) ADD( f.tag, f.val, f.len )
446     /* string add */
447     #define SADD( ntag, s ) ADD( ntag, s, strlen(s) )
448     #define SCAT( s ) CAT( s, strlen(s) )
449     #define SERR( err ) do { \
450     o = rMsg( o, o!=buf, -LOG_ERROR, \
451     "@%d: %s", fp - f->f, err ); \
452     if ( NULL == o ) goto outofmem; \
453     } while(0)
454     #define SERR1( fmt, a ) do { \
455     o = rMsg( o, o!=buf, -LOG_ERROR, \
456     "@%d: " fmt, fp - f->f, a ); \
457     if ( NULL == o ) goto outofmem; \
458     } while(0)
459     #define SERR2( fmt, a, b ) do { \
460     o = rMsg( o, o!=buf, -LOG_ERROR, \
461     "@%d: " fmt, fp - f->f, a, b ); \
462     if ( NULL == o ) goto outofmem; \
463     } while(0)
464     /* number add */
465     #define NADD( i, d ) do { \
466     ADD( LFMT_NUM | (d), NULL, 0 ); \
467     o->field[o->len - 1].val = NULL; \
468     o->field[o->len - 1].len = i; \
469     } while(0)
470    
471     LfmtFrame stack[128], *s = stack; /* current frame (always == stack+sp) */
472     int sp = -1;
473     /* push new frame for token t */
474     #define PUSHFRAME( t ) do { \
475     if ( ++sp == sizeof(stack)/sizeof(stack[0]) ) goto overflow; \
476     s = stack+sp; \
477     memset( s, 0, sizeof(*s) ); \
478     s->data = o->len; \
479     s->used = o->used; \
480     s->tok = (t); \
481     s->want = (t)->sign[2]; \
482     } while(0)
483    
484     LfmtFmt fmt0, *f = NULL; /* default and current format */
485     const unsigned char *fp = NULL; /* format pointer */
486     #define PUSHFORMAT( pfmt, fstr ) do { \
487     memset( pfmt, 0, sizeof(*(pfmt)) ); \
488     (pfmt)->prev = f; \
489     f = (pfmt); \
490     fp = f->f = (const unsigned char *)fstr; \
491     f->e = fp + strlen(fstr); \
492     } while(0)
493    
494     LfmtRec rec0, *r = NULL; /* default and current record */
495     #define PUSHRECORD( prec, nrec ) do { \
496     memset( prec, 0, sizeof(*(prec)) ); \
497     (prec)->prev = r; \
498     r = (prec); \
499     r->frame = sp; \
500     r->r = nrec; \
501     r->sub = '^'; \
502     } while(0)
503    
504     int tlen = 0; /* token length */
505    
506    
507     PUSHFRAME( &blank );
508     s->rec = 1;
509     PUSHFORMAT( &fmt0, fmt );
510     PUSHRECORD( &rec0, irec );
511    
512     o->dbid = irec->dbid ;
513     o->rowid = irec->rowid;
514    
515    
516     for ( ;; fp += tlen ) {
517     const LfmtToken *tok = NULL;
518     Field lit;
519     unsigned char u;
520     int start = s->data + s->pos; /* start of current param in output */
521     int flds = o->len - start; /* # fields for current param */
522     int vpos = 0; /* pos in dict where we had match of tlen chars */
523     int dpos = 0; /* pos in dict */
524     int expl = 0;
525     unsigned char eatlit = 0;
526     const LfmtToken *dict;
527     enum {
528     CLOSE_OP, /* don't close anything, operator wants field */
529     CLOSE_VAR, /* close variables only */
530     CLOSE_FIELD, /* coerce field only */
531     CLOSE_PARAM, /* compact param only (eat comma) */
532     CLOSE_EXPL, /* close frame explicitly (eat closing token) */
533     CLOSE_IMPL /* close frame implicitly, continue on token */
534     } close;
535     static const char *closename[] = {
536     "", "var", "field", "param", "expl", "impl" };
537    
538     lit.tag = 0;
539     tlen = 0; /* verified length */
540    
541     /*
542     LOG_DBG( LFMT_DBG,
543     "frame %s%c%s id %d pos %d got %d want %c%s",
544     s->tok->name, s->expl ? '(' : ' ', s->tok->sign, s->tok->tag,
545     s->pos, o->len - s->data, s->want, flds ? " (have)" : "" );
546     */
547     /* lookup token */
548    
549     while ( ' ' == (u = upcase[*fp]) ) /* eat whitespace */
550     fp++;
551    
552     if ( ISALPHA(u) ) {
553     dict = dictAZ[u-'A'];
554     if ( sentinel != dict->name )
555     u = upcase[ fp[tlen = 1] ];
556     } else if ( ISDIGIT( *fp ) ) {
557     tok = &number; /* read numeric literal */
558     goto countnumber;
559     } else
560     dict = dictSpecial;
561    
562     /* tok is the last candidate that matched up to IT'S length */
563     for ( ;; dpos++ ) {
564     unsigned char test;
565     LOG_DBG( LOG_TRACE, "trying token '%s'", dict[dpos].name );
566     if ( tlen && vpos != dpos
567     && strncmp( dict[dpos].name, dict[vpos].name, tlen ) )
568     break; /* ran out of verified length */
569     if ( u == dict[dpos].name[tlen] )
570     vpos = dpos;
571     while ( (test = dict[dpos].name[tlen]) && u == test )
572     /* test this entry -- same pos, next char */
573     u = upcase[ fp[++tlen] ];
574     if ( !test ) /* dict entry ends here -- a hit so far */
575     tok = &dict[dpos];
576     /*
577     LOG_DBG( LFMT_DBG, "\thit on token %s(%s) len %d",
578     tok->name, tok->sign, tlen );
579     */
580     if ( u < test || !u ) /* too large - bail out*/
581     break;
582     }
583    
584     if ( NULL != tok ) { /* had some match */
585     if ( tok < &dict[vpos] ) /* had later == longer match */
586     tok = NULL;
587     else if ( dict != dictSpecial ) {
588     /* alpha-token must not be followed by alpha */
589     assert( tlen == (int)strlen(tok->name) );
590     if ( ISALPHA( u ) && ISALPHA( tok->name[tlen-1] ) )
591     tok = NULL;
592     }
593     }
594    
595     if ( NULL == tok /* no hit in alphadict */
596     || (dictSpecial == tok && *fp) /* false eof hit in special dict */
597     ) {
598     SERR2( "unrecognized token '%.*s'", tlen+1, fp );
599     goto broken;
600     }
601    
602     if ( ISLITER( tok->sign[2] ) ) /* eat literals */
603     switch ( tok->sign[2] ) { /* c, a, i, x */
604     case 'c':
605     if ( (lit.len = (eatlit = fp[tlen]) ? 1 : 0 ) ) {
606     lit.tag = -LFMT_BARE;
607     lit.val = (char *)fp + tlen;
608     tlen++;
609     }
610     break;
611     case 'a':
612     if ( (eatlit = ISIDENT( fp[tlen] )) ) {
613     lit.tag = -LFMT_BARE;
614     lit.val = (char *)fp + tlen;
615     lit.len = 0;
616     while ( ISIDENT( fp[tlen] ) ) {
617     lit.len++;
618     tlen++;
619     }
620     }
621     break;
622     case 'i':
623     countnumber:
624     lit.val = NULL;
625     lit.len = 0;
626     if ( (eatlit = ISDIGIT( u = fp[tlen] )) ) {
627     lit.tag = LFMT_NUM;
628     while ( u && 10 > (u -= '0') ) {
629     lit.len = 10*lit.len + u;
630     u = fp[++tlen];
631     }
632     }
633     /* decimal digits on standalone numeric literal */
634     if ( &number == tok
635     && (unsigned char)('.'-'0') == u
636     && '.' != fp[tlen+1] /* avoid eating 1..2 */
637     ) {
638     int dec = 0;
639     int v = 0;
640     while ( (u = fp[++tlen]) && 10 > (u -= '0') )
641     if ( 6 > dec ) {
642     v = 10*v + u;
643     dec++;
644     }
645     while ( 6 < dec++ ) v *= 10;
646     lit.tag = LFMT_NUM | (v & LFMT_VAL);
647     }
648     break;
649     case 'x':
650     switch ( tok->tag ) {
651     case LFMT_COMM:
652     eatlit='*';
653     break;
654     case OPENISIS_FMT_ESC:
655     eatlit=fp[tlen++];
656     break;
657     default:
658     eatlit=tok->name[0];
659     break;
660     }
661     lit.tag = - tok->tag;
662     lit.val = (char *)fp+1;
663     while ( (u = fp[tlen++])
664     && (eatlit != u || (LFMT_COMM==tok->tag && '/' != fp[tlen]))
665     ) ;
666     if ( !u ) {
667     SERR1( "unterminated %s-literal", tok->name );
668     goto broken;
669     }
670     lit.len = tlen - 2;
671     if ( LFMT_COMM == tok->tag ) {
672     tlen++;
673     continue;
674     }
675     }
676    
677     if ( tok->sign[2] ) { /* token wants params */
678     if ( (!eatlit || tok->sign[3]) && (expl = '(' == fp[tlen]) )
679     tlen++; /* eat ( */
680     }
681    
682     /* got token */
683     LOG_DBG( LFMT_DBG,
684     "at %d: '%.*s' %s(%s) id %d (%x) group %d pos %d%c of %s%c%s",
685     fp - f->f, tlen > 10 ? 10 : tlen, fp,
686     tok->name, tok->sign, tok->tag, tok->tag, LFMT_GROUP(tok->tag),
687     s->pos, s->want, s->tok->name, s->expl?'(':' ', s->tok->sign
688     );
689    
690     /* close what needs to be closed */
691     do {
692     int group = LFMT_GROUP( tok->tag );
693     int dflt, wantnum, gotnum;
694    
695     close = CLOSE_FIELD;
696    
697     if ( '_' != tok->sign[0] /* token is operator ... */
698     && (s->expl /* ... within explicit frame or ... */
699     || group < LFMT_GROUP( s->tok->tag )) /* ... of higher prec */
700     ) /* we take it -- even as a variable ? */
701     close = 'v' == tok->sign[0] ? CLOSE_OP : CLOSE_VAR;
702     else switch ( tok->tag ) {
703     case LFMT_COMMA:
704     case LFMT_RANGE:
705     close = CLOSE_PARAM;
706     break;
707     case LFMT_CLOSE:
708     close = CLOSE_EXPL;
709     break;
710     }
711    
712     if ( CLOSE_VAR > close ) /* leave variable to operator */
713     break; /* close loop */
714    
715     if ( flds && LFMT_ISITR( o->field[ o->len-1 ].tag ) ) {
716     /* dereference iterator variable */
717     LfmtIter * iter = r->iter + r->i;
718     if ( ! iter->occ ) {
719     if ( ! iter->from )
720     iter->from = 1; /* field defaults to 1..0 (all) */
721     if ( ! iter->sfrom )
722     iter->sfrom = iter->sto = 1; /* subfield defaults to 1..1 (1st) */
723     }
724    
725     LOG_DBG( LFMT_DBG, "iterator %d/%d V%d[%d..%d]^%c[%d..%d]%s",
726     o->field[ o->len-1 ].len, r->occ,
727     iter->tag, iter->from, iter->to,
728     iter->sub ? iter->sub : ' ', iter->sfrom, iter->sto,
729     iter->submode ? " subfield mode" : ""
730     );
731    
732     o->len--; /* kill the variable. */
733     /* move to next legal position.
734     In standard mode, where we advance one field occurence at a time,
735     this is just the occ >= from.
736     A legal position may still emit no field,
737     if a selected subfield is not available in the current field occ.
738     In subfield mode, we may have to advance 0, 1 or several field
739     occurences to find next occ of subfield.
740     */
741     r->had = 0;
742     do {
743     int socc;
744     if ( 0 > iter->occ ) /* we were already done */
745     break;
746     /* if have legal occurence, ADD it */
747     if ( iter->occ >= iter->from ) for ( socc=1;; socc++ ) {
748     /* not initialization pass. */
749     Field *v = r->r->field + iter->pos;
750     const char *src = v->val;
751     int len = v->len;
752     if ( iter->sub ) { /* find subfield */
753     const char *p = src + iter->off, *e = src+len;
754     while ( p < e && (
755     r->sub != *p++
756     || e == p
757     || (iter->sub != *p++ && iter->sub != '*')
758     ) )
759     ;
760     iter->off = p - src;
761     if ( p >= e )
762     break;
763     if ( iter->sfrom && socc < iter->sfrom )
764     continue;
765     if ( iter->sto && socc > iter->sto )
766     break;
767     src = p;
768     while ( p < e && r->sub != *p )
769     p++;
770     iter->off += len = p - src;
771     }
772     /* make sure there's enough room, +3 for DATA mode */
773     ADD( v->tag, NULL, len+3 );
774     if ( ! f->mode )
775     CAT( src, len );
776     else {
777     const char *e = src + len;
778     char *dst = (char *)o->field[ o->len - 1 ].val;
779     for ( ; src < e; ) {
780     if ( '<' == *src ) {
781     for ( src++; src < e; *dst++ = *src++ )
782     if ( '=' == *src || '>' == *src ) {
783     while ( '>' != *src++ && src < e )
784     ;
785     if ( src < e && '<' == *src ) { /* have >< */
786     *dst++ = ';';
787     *dst++ = ' ';
788     }
789     break;
790     }
791     } else if ( r->sub == *src ) {
792     if ( ++src == e )
793     break;
794     if ( dst == o->field[ o->len - 1 ].val )
795     ; /* no spearator */
796     else if ( 'a' == *src )
797     *dst++ = ';';
798     else if ( 'j' > *src )
799     *dst++ = ',';
800     else
801     *dst++ = '.';
802     src++;
803     } else
804     *dst++ = *src++;
805     }
806     o->used +=
807     o->field[ o->len - 1 ].len =
808     dst - o->field[ o->len - 1 ].val;
809     if ( LFMT_MD == f->mode )
810     CAT( ". ", 3 );
811     } /* f->mode */
812     if ( f->upcase ) {
813     char *p = (char *)o->field[ o->len - 1 ].val;
814     char *e = p + o->field[ o->len - 1 ].len;
815     for ( ; p < e; p++ )
816     *p = upcase[(unsigned char)*p];
817     }
818     r->had = 1;
819     if ( iter->submode || ! iter->sub )
820     break;
821     }
822     if ( iter->submode ) {
823     if ( iter->occ && iter->occ < iter->from ) /* was skipped */
824     iter->off++;
825     for ( ; iter->pos < r->r->len; iter->pos++, iter->off = 0 )
826     if ( iter->tag == r->r->field[ iter->pos ].tag || ! iter->tag ) {
827     Field *v = r->r->field + iter->pos;
828     const char *p = v->val + iter->off, *e = v->val + v->len;
829     while ( p < e && (
830     r->sub != *p++
831     || e == p
832     || (iter->sub != *p++ && iter->sub != '*')
833     ) )
834     ;
835     if ( p < e ) { /* hit */
836     iter->off = (p - v->val) - 2;
837     break;
838     }
839     }
840     } else {
841     if ( iter->occ )
842     iter->pos++;
843     while ( iter->pos < r->r->len
844     && iter->tag
845     && iter->tag != r->r->field[ iter->pos ].tag
846     )
847     iter->pos++;
848     iter->off = 0;
849     }
850     iter->occ++;
851     if ( iter->pos >= r->r->len /* end of record */
852     || (iter->to && iter->to < iter->occ) /* end of selected occ */
853     ) {
854     iter->occ = -1;
855     break;
856     }
857     } while ( iter->occ <= iter->from );
858    
859     if ( 0 < iter->occ ) /* we have a next occurence */
860     r->more = 1;
861     if ( ! r->had && flds && -LFMT_REP == o->field[ o->len - 1 ].tag ) {
862     flds--;
863     o->len--;
864     o->used -= o->field[o->len].len;
865     }
866     r->i++; /* advance to next iterator */
867     } /* dereference iterator variable */
868    
869     if ( CLOSE_FIELD > close ) /* leave field to operator */
870     break; /* close loop */
871    
872     if ( ! flds ) { /* had no field */
873     if ( CLOSE_PARAM > close ) /* nothing to do */
874     break; /* close loop */
875     } else if ( ! s->expl /* frame is implicit ... */
876     && ( LFMT_LOOP != s->tok->tag /* ... and not a loop ... */
877     || CLOSE_EXPL == close /* ... or we saw a hard closer ... */
878     || (r->i && CLOSE_PARAM == close)
879     /* ... or a loop after 1st iterator on param closer */
880     )
881     ) /** upgrade the closing mode to IMPL */
882     close = CLOSE_IMPL;
883    
884     /* close the field, i.e. coerce it */
885     dflt = !flds /* param was not given ... */
886     && (s->pos /* but was started explicitly by a comma like F( 3, ) */
887     || CLOSE_PARAM == close /* or is closed explicitly like F( ,3 ) */
888     );
889     wantnum = 'i' == s->want || 'n' == s->want;
890     gotnum = flds && LFMT_ISNUM( o->field[ o->len-1 ].tag );
891    
892     LOG_DBG( LFMT_DBG,
893     "\tclose %s %d%c pos %d%c of %s%c%s id %x",
894     closename[close],
895     flds, flds ? gotnum ? 'n' : 's' : dflt ? 'd' : '-', s->pos, s->want,
896     s->tok->name, s->expl?'(':' ', s->tok->sign, s->tok->tag );
897    
898     /* close and fix last field */
899     if ( gotnum && !wantnum ) {
900     /* coerce number to string, so it may get concatenated */
901     char b[32];
902     int ll = lprint( b, o->field[ o->len-1 ].len );
903     b[ll++] = ' ';
904     o->len--;
905     ADD( 0, b, ll );
906     gotnum = 0;
907     }
908    
909     if ( CLOSE_PARAM > close )
910     break; /* close loop */
911    
912     /* close and fix param */
913     if ( wantnum ) {
914     if ( dflt ) { /* default 0 */
915     NADD( 0, 0 );
916     flds = 1;
917     } else if ( 1 < flds ) {
918     SERR( "multiple fields for numerical param" );
919     goto broken;
920     } else if ( flds && !gotnum ) {
921     SERR( "expected number" );
922     goto broken;
923     }
924     if ( 'i' == s->want ) /* kill decimal */
925     o->field[s->data].tag &= ~LFMT_VAL;
926     } else {
927     if ( dflt ) {
928     SADD( 0, "" );
929     flds = 1;
930     } else if ( gotnum ) {
931     SERR( "expected string" ); /* shouldn't happen !? */
932     goto broken;
933     } else if ( 1 < flds /* concat strings ... */
934     && ! s->rec /* ... unless in record mode frame (blank,loop,ref) */
935     ) {
936     int i;
937     for ( i = start+1; i < o->len; i++ )
938     if ( o->field[i].val )
939     o->field[ start ].len += o->field[ i ].len;
940     o->len = start + 1;
941     }
942     }
943    
944     /* done fixing param */
945    
946     if ( CLOSE_IMPL > close ) {
947     tok = NULL; /* eat token */
948     if ( CLOSE_EXPL > close ) { /* i.e. CLOSE_PARAM */
949     if ( flds ) { /* increment param pos, set next wanted type */
950     int sl = strlen( s->tok->sign ); /* frame takes sl-2 params */
951     if ( ++(s->pos) < sl-2 ) {
952     if ( '_' != s->tok->sign[ 2 + s->pos ] ) /* repeated param */
953     s->want = s->tok->sign[ 2 + s->pos ]; /* else keep last val */
954     } else if ( '_' != s->tok->sign[sl-1] ) { /* too much */
955     SERR2( "expected at most %d params for '%s'",
956     sl-2, s->tok->name );
957     goto broken;
958     }
959     }
960     break; /* close loop */
961     }
962     }
963    
964     /* done with token -- close and fix frame */
965    
966     #define KILLARGS() do { \
967     o->len = s->data; \
968     o->used = s->used; \
969     } while(0)
970    
971     #define KILLOP() do { \
972     o->len = s->data - 1; \
973     o->used = s->used - (o->field[o->len].val ? o->field[o->len].len : 0); \
974     } while(0)
975    
976     switch ( s->tok->tag ) {
977     case LFMT_PLUS: /* arithmetic */
978     case LFMT_MINUS:
979     case LFMT_MUL:
980     case LFMT_DIV: {
981     lll a = o->field[s->data-1].len;
982     lll b = o->field[s->data].len;
983     /* LOG_DBG( LFMT_DBG, "\tarith on %Ld %Ld", a, b ); */
984     switch ( s->tok->tag ) {
985     case LFMT_PLUS: a += b; break;
986     case LFMT_MINUS: a -= b; break;
987     case LFMT_MUL: a *= b; break;
988     case LFMT_DIV: if ( 0 != b ) a /= b; break;
989     }
990     KILLOP();
991     NADD( (int)a, 0 );
992     } break;
993     case LFMT_F: {
994     char b[32];
995     int ll = lprint( b, o->field[ s->data ].len );
996     KILLARGS();
997     ADD( 0, b, ll );
998     } break;
999     case LFMT_V:
1000     r->iter[ r->i ].tag = o->field[ s->data ].len;
1001     /* set iterator field */
1002     o->field[ s->data ].tag = LFMT_ITR | r->iter[ r->i ].tag;
1003     o->field[ s->data ].len = r->i;
1004     break;
1005     case LFMT_INDEX: {
1006     LfmtIter * iter = r->iter + r->i;
1007     if ( 1 != r->occ ) {
1008     SERR( "OOPS! index not within loop" );
1009     goto internalerr;
1010     }
1011     if ( ! iter->sub || (iter->submode = !iter->from) ) {
1012     /* primary loop */
1013     if ( !(iter->from = (int) o->field[ s->data ].len) )
1014     iter->from = 1;
1015     iter->to = s->pos ? (int) o->field[ s->data+1 ].len : iter->from;
1016     } else {
1017     /* additional subfield loop */
1018     if ( !(iter->sfrom = (int) o->field[ s->data ].len) )
1019     iter->sfrom = 1;
1020     iter->sto = s->pos ? (int) o->field[ s->data+1 ].len : iter->sfrom;
1021     }
1022     iter->end = fp + tlen;
1023     KILLARGS();
1024     } break; /* case LFMT_INDEX: */
1025     case LFMT_SUBFIELD:
1026     if ( 1 != r->occ ) {
1027     SERR( "OOPS! subfield not within loop" );
1028     goto internalerr;
1029     }
1030     r->iter[ r->i ].sub = o->field[ s->data ].val[0];
1031     r->iter[ r->i ].end = fp + tlen;
1032     KILLARGS();
1033     break;
1034     case LFMT_LOOP:
1035     if ( r->more ) {
1036     fp = r->loop; /* start over */
1037     tlen = 0; /* care for += tlen */
1038     tok = NULL;
1039     r->occ++;
1040     r->more = 0;
1041     r->i = 0;
1042     goto doneclosing;
1043     }
1044     r->loop = 0;
1045     break;
1046     }
1047    
1048     /* close frame, unless it's the outmost */
1049     if ( ! sp )
1050     break;
1051    
1052     /* TODO: close loop ? */
1053     s = &stack[ --sp ];
1054    
1055     start = s->data + s->pos; /* start of current param in output */
1056     flds = o->len - start; /* # fields for current param */
1057    
1058     } while ( CLOSE_IMPL == close );
1059     doneclosing:
1060    
1061     if ( NULL == tok )
1062     continue;
1063     if ( ! tok->tag )
1064     goto done;
1065    
1066     /* add new token */
1067     if ( NULL == r->loop ) /* open loop ? */
1068     switch ( LFMT_GROUP(tok->tag) ) {
1069     case LFMT_FUNCTIONS:
1070     if ( LFMT_OPEN != tok->tag )
1071     break;
1072     goto openloop; /* else should do, but gcc doesn't grok it right */
1073     case LFMT_LITERAL:
1074     if ( LFMT_COND != tok->tag && LFMT_REP != tok->tag )
1075     break;
1076     case LFMT_ITERATORS:
1077     openloop:
1078     LOG_DBG( LFMT_DBG, "\topening loop on %s", tok->name );
1079     PUSHFRAME( &loop );
1080     s->rec = stack[sp-1].rec; /* inherit record mode */
1081     r->loop = fp;
1082     r->occ = 1;
1083     r->more = 0;
1084     r->had = 0;
1085     r->i = 0;
1086     if ( (s->expl = (LFMT_OPEN == tok->tag)) ) {
1087     r->loop += tlen;
1088     continue;
1089     }
1090     }
1091    
1092     if ( tok->sign[2] && LFMT_LITERAL != LFMT_GROUP(tok->tag) ) {
1093     /* token opens standard frame */
1094     if ( LFMT_ITERATORS == LFMT_GROUP(tok->tag) ) {
1095     if ( 1 != r->occ ) { /* not first run */
1096     if ( r->iter[r->i].def != fp ) {
1097     SERR1( "internal error at %d. iterator", r->i + 1 );
1098     goto internalerr;
1099     }
1100     NADD( r->i, LFMT_ITR | r->iter[r->i].tag ); /* push iterator */
1101     fp = r->iter[r->i].end; /* skip parsing */
1102     tlen = 0; /* care for += tlen */
1103     continue; /* next token */
1104     }
1105     if ( LFMT_NITER-1 == r->i ) {
1106     SERR1( "maximum number of iterators %d exceeded", LFMT_NITER );
1107     goto overflow;
1108     }
1109     memset( r->iter + r->i, 0, sizeof(r->iter[0]) );
1110     r->iter[r->i].def = fp;
1111     r->iter[r->i].end = fp + tlen;
1112     }
1113     PUSHFRAME( tok );
1114     switch ( tok->tag ) { /* special treatment */
1115     case LFMT_INDEX:
1116     s->expl = 1;
1117     break;
1118     default:
1119     if ( expl )
1120     s->expl = 1;
1121     }
1122     LOG_DBG( LFMT_DBG, "\topen %s%c%s id %x",
1123     s->tok->name, s->expl?'(':' ', s->tok->sign, s->tok->tag );
1124     }
1125    
1126     if ( lit.tag ) { /* a literal */
1127     if ( NULL != lit.val ) { /* string literal */
1128     switch ( lit.tag ) {
1129     case -LFMT_COND:
1130     if ( r->i ? !r->more : r->occ > 1 )
1131     continue;
1132     break;
1133     case -LFMT_REP:
1134     if ( r->i && !r->had )
1135     continue;
1136     break;
1137     }
1138     ADD( lit.tag, lit.val, lit.len );
1139     LOG_DBG( LFMT_DBG, "\tlit %s%.*s id %x",
1140     tok->name, lit.len, lit.val, tok->tag );
1141     } else { /* numeric literal */
1142     NADD( lit.len, lit.tag );
1143     LOG_DBG( LFMT_DBG, "\tlit %d", lit.len );
1144     }
1145     /* new implicit frame immediatly closed by literal ?
1146     problem are implicit loops
1147     if ( o->len == s->data + 1 && ! s->expl ) {
1148     tok = NULL;
1149     goto closeframe;
1150     }
1151     */
1152     } else switch ( tok->tag ) { /* other special tokens */
1153     case LFMT_MDL: f->mode = LFMT_MD; f->upcase = 0; break;
1154     case LFMT_MDU: f->mode = LFMT_MD; f->upcase = 1; break;
1155     case LFMT_MHL: f->mode = LFMT_MH; f->upcase = 0; break;
1156     case LFMT_MHU: f->mode = LFMT_MH; f->upcase = 1; break;
1157     case LFMT_MPL: f->mode = LFMT_MP; f->upcase = 0; break;
1158     case LFMT_MPU: f->mode = LFMT_MP; f->upcase = 1; break;
1159     }
1160    
1161     } /* for token */
1162    
1163     broken:
1164     internalerr:
1165     overflow:
1166     outofmem:
1167     done:
1168     if ( NULL != o ) {
1169     int i = o->len;
1170     while ( i-- )
1171     if ( NULL == o->field[i].val ) {
1172     ;
1173     } else if ( -LFMT_LIT >= o->field[i].tag )
1174     o->field[i].tag = 0;
1175     }
1176     return o;
1177     } /* rFmt */

  ViewVC Help
Powered by ViewVC 1.1.26