1 /*
2 * ffe - flat file extractor
3 *
4 * Copyright (C) 2006 Timo Savinen
5 * This file is part of ffe.
6 *
7 * ffe is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * ffe is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with ffe; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 *
21 */
22
23 /* $Id: level.c,v 1.8 2010-09-24 11:45:16 timo Exp $ */
24
25 #include "ffe.h"
26 #include <string.h>
27
28 static struct level *levels[MAXLEVEL + 1];
29 static int last_level = 0;
30 static int max_level = 0;
31
32 void
reset_levels(int start,int stop)33 reset_levels(int start, int stop)
34 {
35 while(start <= stop) levels[start++] = NULL;
36 }
37
38 static void
print_level_text(struct level * l,uint8_t * buffer)39 print_level_text(struct level *l,uint8_t *buffer)
40 {
41 register uint8_t *text = buffer;
42
43 if(!buffer) return;
44 start_write();
45 while(*text)
46 {
47 if(*text == '%' && text[1])
48 {
49 text++;
50 switch(*text)
51 {
52 case 'g':
53 if(l) writes(l->group_name);
54 break;
55 case 'm':
56 if(l) writes(l->element_name);
57 break;
58 case '%':
59 writec('%');
60 break;
61 default:
62 writec('%');
63 writec(*text);
64 break;
65 }
66 } else
67 {
68 writec(*text);
69 }
70 text++;
71 }
72 flush_write();
73 }
74
75
76
77 static
print_level(struct level * l,uint8_t * buffer,uint8_t * indent,int indent_level)78 void print_level(struct level *l, uint8_t *buffer, uint8_t *indent, int indent_level)
79 {
80 if(!l) return;
81
82 if(indent) print_indent(indent,indent_level);
83
84 print_level_text(l,buffer);
85 }
86
87 int
get_indent_depth(int level_count)88 get_indent_depth(int level_count)
89 {
90 register int i,depth = 1;
91
92 for(i = 1;i <= level_count;i++) depth += (levels[i] != NULL ? levels[i]->indent_count : 0);
93
94 return depth;
95 }
96
97 /* Print group and element level headers/trailers BEFORE an element is printed
98 */
99 void
print_level_before(struct record * prev_record,struct record * curr_record)100 print_level_before(struct record *prev_record, struct record *curr_record)
101 {
102 int pl = 0,i;
103
104 if(!curr_record->level)
105 {
106 if(prev_record && prev_record->level && prev_record->level->element_name)
107 print_level(prev_record->level,prev_record->o->element_trailer,prev_record->o->indent,get_indent_depth(prev_record->level->level) - 1);
108 return;
109 }
110
111 if(curr_record->level->level > max_level) max_level = curr_record->level->level;
112 last_level = curr_record->level->level;
113
114 if(prev_record && prev_record->level) pl = prev_record->level->level;
115
116 if(last_level == pl) // in the same level
117 {
118 if(prev_record->level->element_name)
119 print_level(prev_record->level,prev_record->o->element_trailer,prev_record->o->indent,get_indent_depth(pl) - 1);
120
121 if((prev_record->level->group_name && curr_record->level->group_name &&
122 strcmp(prev_record->level->group_name,curr_record->level->group_name) != 0) ||
123 (!prev_record->level->group_name || !curr_record->level->group_name))
124 {
125 if(prev_record->level->group_name)
126 print_level(prev_record->level,prev_record->o->group_trailer,prev_record->o->indent,get_indent_depth(pl - 1));
127 if(curr_record->level->group_name)
128 print_level(curr_record->level,curr_record->o->group_header,curr_record->o->indent,get_indent_depth(last_level - 1));
129 }
130 } else if(last_level > pl) // current record is deeper in as previous
131 {
132 if(curr_record->level->group_name)
133 print_level(curr_record->level,curr_record->o->group_header,curr_record->o->indent,get_indent_depth(pl));
134 } else if(last_level < pl) // current record is higher as previous, print trailers for elements between current and previous
135 {
136 i = pl;
137 while(i >= last_level)
138 {
139 if(levels[i] && levels[i]->element_name)
140 print_level(levels[i],curr_record->o->element_trailer,curr_record->o->indent,get_indent_depth(i) - 1);
141 if(i > last_level && levels[i] && levels[i]->group_name)
142 print_level(levels[i],curr_record->o->group_trailer,curr_record->o->indent,get_indent_depth(i - 1));
143 i--;
144 }
145
146 i++;
147
148 if(levels[i] && ((levels[i]->group_name && curr_record->level->group_name && strcmp(levels[i]->group_name,curr_record->level->group_name) != 0) ||
149 (!levels[i]->group_name || !curr_record->level->group_name)))
150 {
151 if(levels[i]->group_name)
152 print_level(levels[i],curr_record->o->group_trailer,curr_record->o->indent,get_indent_depth(i - 1));
153 if(curr_record->level->group_name)
154 print_level(curr_record->level,curr_record->o->group_header,curr_record->o->indent,get_indent_depth(last_level - 1));
155 }
156
157 reset_levels(last_level + 1,max_level);
158 }
159
160 levels[last_level] = curr_record->level;
161
162 if(curr_record->level->element_name)
163 print_level(curr_record->level,curr_record->o->element_header,curr_record->o->indent,get_indent_depth(last_level) - 1);
164 }
165
166 /* print pending trailers after all data has been read
167 */
168 void
print_level_end(struct record * last)169 print_level_end(struct record *last)
170 {
171 int i = last_level;
172
173 while(levels[i] && i >= 1)
174 {
175 if(levels[i]->element_name)
176 print_level(levels[i],last->o->element_trailer,last->o->indent,get_indent_depth(i) - 1);
177 if(levels[i]->group_name)
178 print_level(levels[i],last->o->group_trailer,last->o->indent,get_indent_depth(i - 1));
179 i--;
180 }
181 }
182