1 /****************************************************************************
2 * Copyright (C) 2008 by Matteo Franchin *
3 * *
4 * This file is part of Box. *
5 * *
6 * Box is free software: you can redistribute it and/or modify it *
7 * under the terms of the GNU Lesser General Public License as published *
8 * by the Free Software Foundation, either version 3 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * Box 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 *
14 * GNU 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 Box. If not, see <http://www.gnu.org/licenses/>. *
18 ****************************************************************************/
19
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <assert.h>
23
24 #include "types.h"
25 #include "formatter.h"
26
27 #define MAX_STACK_LEVEL 10
28 #define BUFFER_SIZE 128
29
30 typedef enum {
31 STATUS_NORMAL=0,
32 STATUS_STACK_FULL,
33 STATUS_LITERAL,
34 STATUS_WAIT_SUB,
35 STATUS_WAIT_SUP
36 } Status;
37
_Add_Char(BoxGFmtStack * stack,char c)38 static void _Add_Char(BoxGFmtStack *stack, char c) {
39 BoxGFmt *fmt = stack->fmt;
40 int i = fmt->buffer_pos++;
41 if (fmt->buffer_pos > fmt->buffer_size) {
42 if (fmt->buffer == (char *) NULL) {
43 fmt->buffer = (char *) malloc(BUFFER_SIZE);
44 fmt->buffer_size = BUFFER_SIZE;
45 }
46
47 if (fmt->buffer_pos > fmt->buffer_size) {
48 while (fmt->buffer_pos > fmt->buffer_size) fmt->buffer_size *= 2;
49 fmt->buffer = (char *) realloc(fmt->buffer, fmt->buffer_size);
50 }
51
52 assert(fmt->buffer != (char *) NULL);
53 }
54
55 fmt->buffer[i] = c;
56 }
57
BoxGFmt_Get_Buffer(BoxGFmtStack * stack)58 char *BoxGFmt_Get_Buffer(BoxGFmtStack *stack) {
59 BoxGFmt *fmt = stack->fmt;
60 _Add_Char(stack, '\0');
61 --fmt->buffer_pos;
62 return fmt->buffer;
63 }
64
BoxGFmt_Clear_Buffer(BoxGFmtStack * stack)65 void BoxGFmt_Clear_Buffer(BoxGFmtStack *stack) {
66 BoxGFmt *fmt = stack->fmt;
67 fmt->buffer_pos = 0;
68 }
69
_Draw(BoxGFmtStack * stack)70 static int _Draw(BoxGFmtStack *stack) {
71 BoxGFmt *fmt = stack->fmt;
72 if (fmt->buffer_pos < 1) return stack->eye;
73 if (fmt->draw != NULL) fmt->draw(stack);
74 return stack->eye;
75 }
76
_Save(BoxGFmtStack * stack)77 static void _Save(BoxGFmtStack *stack) {
78 BoxGFmt *fmt = stack->fmt;
79 if (fmt->save != NULL) fmt->save(stack);
80 }
81
_Restore(BoxGFmtStack * stack)82 static void _Restore(BoxGFmtStack *stack) {
83 BoxGFmt *fmt = stack->fmt;
84 if (fmt->restore != NULL) fmt->restore(stack);
85 }
86
_Subscript(BoxGFmt * fmt,BoxGFmtStack * stack)87 static void _Subscript(BoxGFmt *fmt, BoxGFmtStack *stack) {
88 if (fmt->subscript != NULL) fmt->subscript(stack);
89 }
90
_Superscript(BoxGFmt * fmt,BoxGFmtStack * stack)91 static void _Superscript(BoxGFmt *fmt, BoxGFmtStack *stack) {
92 if (fmt->superscript != NULL) fmt->superscript(stack);
93 }
94
_Text_Formatter(BoxGFmtStack * stack)95 static int _Text_Formatter(BoxGFmtStack *stack) {
96 BoxGFmt *fmt = stack->fmt;
97 Status status;
98 BoxGFmtStack new_stack;
99
100 status = (stack->level >= MAX_STACK_LEVEL) ?
101 STATUS_STACK_FULL : STATUS_NORMAL;
102
103 for(;;) {
104 char c = stack->text[stack->eye];
105 if (c == '\0') return _Draw(stack);
106
107 switch(status) {
108 case STATUS_STACK_FULL:
109 ++stack->eye;
110 switch(c) {
111 case '}':
112 if (stack->level == MAX_STACK_LEVEL) return stack->eye;
113 --stack->level;
114 break;
115 case '{':
116 ++stack->level;
117 break;
118 }
119 break;
120
121 case STATUS_NORMAL:
122 ++stack->eye;
123 switch(c) {
124 case '_':
125 status = STATUS_WAIT_SUB;
126 break;
127 case '^':
128 status = STATUS_WAIT_SUP;
129 break;
130 case '}':
131 if (stack->level > 0) {
132 fmt->draw(stack);
133 return stack->eye;
134 }
135 _Add_Char(stack, c);
136 break;
137 case '\n':
138 (void) _Draw(stack);
139 fmt->newline(stack);
140 break;
141 default:
142 _Add_Char(stack, c);
143 break;
144 }
145 break;
146
147 case STATUS_LITERAL:
148 status = STATUS_NORMAL;
149 ++stack->eye;
150 _Add_Char(stack, c);
151 break;
152
153 case STATUS_WAIT_SUB:
154 case STATUS_WAIT_SUP:
155 ++stack->eye;
156 switch(c) {
157 case '^':
158 case '_':
159 _Add_Char(stack, c);
160 status = STATUS_NORMAL;
161 break;
162
163 default:
164 (void) _Draw(stack);
165 _Save(stack);
166 new_stack = *stack;
167 ++new_stack.level;
168 if (status == STATUS_WAIT_SUB)
169 _Subscript(fmt, & new_stack);
170 else
171 _Superscript(fmt, & new_stack);
172
173 if (c == '{') {
174 stack->eye = _Text_Formatter(& new_stack);
175
176 } else {
177 /* We emulate the syntax 'char_{s}' for the syntex 'char_s' */
178 new_stack.short_text[0] = c;
179 new_stack.short_text[1] = '}';
180 new_stack.short_text[2] = '\0';
181 new_stack.text = new_stack.short_text;
182 new_stack.eye = 0;
183 (void) _Text_Formatter(& new_stack);
184 }
185
186 _Restore(stack);
187 if (stack->eye == -1) return stack->eye;
188 status = STATUS_NORMAL;
189 break;
190 }
191 break;
192 }
193 }
194 }
195
BoxGFmt_Init(BoxGFmt * fmt)196 void BoxGFmt_Init(BoxGFmt *fmt) {
197 fmt->restore = fmt->save = fmt->draw = fmt->newline =
198 fmt->subscript = fmt->superscript = NULL;
199 fmt->private_data = (void *) NULL;
200 }
201
BoxGFmt_Get(BoxGFmtStack * stack)202 BoxGFmt *BoxGFmt_Get(BoxGFmtStack *stack) {
203 return stack->fmt;
204 }
205
BoxGFmt_Get_Private(BoxGFmt * fmt)206 void *BoxGFmt_Get_Private(BoxGFmt *fmt) {
207 return fmt->private_data;
208 }
209
BoxGFmt_Set_Private(BoxGFmt * fmt,void * private_data)210 void BoxGFmt_Set_Private(BoxGFmt *fmt, void *private_data) {
211 fmt->private_data = private_data;
212 }
213
BoxGFmt_Draw_Text(BoxGFmt * fmt,const char * text)214 void BoxGFmt_Draw_Text(BoxGFmt *fmt, const char *text) {
215 BoxGFmtStack stack;
216 stack.level = 0;
217 stack.eye = 0;
218 stack.text = text;
219
220 fmt->buffer_pos = 0;
221 fmt->buffer_size = 0;
222 fmt->buffer = (char *) NULL;
223 stack.fmt = fmt;
224
225 (void) _Text_Formatter(& stack);
226 if (fmt->buffer != (char *) NULL) free(fmt->buffer);
227 }
228