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