add new errorhandling
[mala.git] / std / std_io.c
blob4418c301d026c2055bb705fac97f71de1efa714e
1 /*
2 std_io.c - MaLa standard IO module parsers
4 Copyright (C) 2005, Christian Thaeter <chth@gmx.net>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License version 2 as
8 published by the Free Software Foundation.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, contact me.
20 #include <stdio.h>
21 #include <string.h>
22 #include <ctype.h>
23 #include "mala.h"
24 #include "std_io.h"
25 #include "std.h"
27 static
28 mala_actioninit std_io[] =
31 MALA_PARSER_SIMPLE("--PRINT", mala_print_parser),
32 // MALA_PARSER_BRIEF("--PRINT", "prints to stdout"),
33 // MALA_PARSER_HELP("--PRINT", ("TODO")),
34 // MALA_PARSER_SIGNATURE_USAGE("--", ("")),
35 // MALA_PARSER_RESULT_USAGE("--", ("")),
36 //MALA_PARSER_SIGNATURE_TYPE("--PRINT", ("WORD-OR-BLOCK")),
37 //MALA_PARSER_RESULT_TYPE("--PRINT", ("VOID")),
39 MALA_PARSER_SIMPLE("--NL", mala_newline_parser),
40 //MALA_PARSER_BRIEF("--NL", "prints a newline"),
41 // MALA_PARSER_HELP("--NL", ("TODO")),
42 //MALA_PARSER_RESULT_USAGE("--NL", ("")),
45 MALA_PARSER_MACRO("--PRINTL",("--PRINT", "--LITERAL", "%1", "--NL")),
46 //MALA_PARSER_BRIEF("--PRINTL", "prints a textline to stdout"),
47 // MALA_PARSER_HELP("--PRINTL", ("TODO")),
48 // MALA_PARSER_SIGNATURE_USAGE("--", ("")),
49 // MALA_PARSER_RESULT_USAGE("--", ("")),
50 //MALA_PARSER_SIGNATURE_TYPE("--PRINTL", ("WORD-OR-BLOCK")),
51 //MALA_PARSER_RESULT_TYPE("--PRINTL", ("VOID")),
54 MALA_PARSER_SIMPLE("--PRINTWRAPED",mala_printwraped_parser),
55 //MALA_PARSER_BRIEF("--PRINTWRAPED", "prints formatted text"),
56 //TODO MALA_PARSER_HELP("--PRINTWRAPED", ("Wraps some text to fit nicely on the screen. Tabulators become aligned. The last tabulator delimited field of a line will be printed word-wraped and indented.")),
57 //TODO MALA_PARSER_SIGNATURE_USAGE("--PRINTWRAPED",
58 // ("Columns available on the screen",
59 // "Lines available on the screen",
60 // "Indent of the block in characters",
61 // "Tabwidth to be used",
62 // "Text to be printed")),
63 // //MALA_PARSER_RESULT_USAGE("--PRINTWRAPED", ("TODO")),
64 //TODO MALA_PARSER_SIGNATURE_TYPE("--PRINTWRAPED",
65 // ("COLUMNS",
66 // "LINES",
67 // "INDENT",
68 // "TABWIDTH",
69 // "TEXT")),
71 MALA_ACTIONS_END
74 struct mala_printwraped_context;
76 mala_state
77 mala_newline_parser (MalaProgram prg)
79 MALA_MUTATOR_BEGIN
80 putchar('\n');
81 MALA_MUTATOR_END;
83 mala_program_action_done (prg, 0);
84 return MALA_STATEMENT;
87 mala_state
88 mala_print_parser (MalaProgram prg)
90 mala_state state = mala_program_eval_arg (prg, 1, MALA_LITERAL, NULL);
91 if (state > MALA_START)
92 return state;
94 TODO("use dst in arg_eval");
96 PLANNED("print blocks ?");
98 MALA_MUTATOR_BEGIN
99 printf("%s",mala_string_cstr (mala_stringlist_string (mala_stringlist_next (mala_program_pptr (prg)))));
100 MALA_MUTATOR_END;
102 mala_program_action_done (prg, 1);
103 return MALA_STATEMENT;
107 static void
108 mala_estimate_tabwidth (struct mala_printwraped_context* pwc);
110 static void
111 mala_insert_space (struct mala_printwraped_context* pwc, int stop);
113 static void
114 mala_ltab (struct mala_printwraped_context* pwc);
116 static void
117 mala_rtab (struct mala_printwraped_context* pwc);
119 static void
120 mala_wrap_words (struct mala_printwraped_context* pwc);
122 static void
123 mala_print_wraped (struct mala_printwraped_context* pwc);
125 static void
126 mala_put_word (struct mala_printwraped_context* pwc);
129 struct mala_printwraped_context
131 // constant values
132 int columns;
133 int lines;
134 int indent;
135 int tabwidth;
136 const char * text;
138 // states
139 int pos;
140 const char * out_itr;
141 const char * parse_itr;
142 int tabstops[20];
143 int ltab_itr;
144 int wrap_indent;
145 int wrap_indent_locked;
146 const char * lastspace;
150 void
151 nobug_mala_printwraped_context_dump (const struct mala_printwraped_context* self,
152 const int depth,
153 const char* file,
154 const int line,
155 const char* func)
157 if (self && depth)
159 DUMP_LOG ("columns %d", self->columns);
160 DUMP_LOG ("lines %d", self->lines);
161 DUMP_LOG ("indent %d", self->indent);
162 DUMP_LOG ("tabwidth %d", self->tabwidth);
163 for (int current_tab = 0; current_tab < 19; ++current_tab)
164 DUMP_LOG_IF (self->tabstops[current_tab], "tab %d %d", current_tab, self->tabstops[current_tab]);
169 static void
170 mala_estimate_tabwidth (struct mala_printwraped_context* pwc)
172 int current_tab;
173 int ltab_cnt;
175 again:
176 TRACE (mala_module_std);
177 for (current_tab = 19; current_tab; --current_tab)
178 pwc->tabstops[current_tab] = 0;
180 pwc->tabstops[0] = pwc->indent;
181 current_tab = 0;
182 ltab_cnt = 0;
184 for (pwc->parse_itr = pwc->text, pwc->pos = pwc->indent;
185 *pwc->parse_itr;
186 ++pwc->parse_itr)
188 switch (*pwc->parse_itr)
190 case '\t':
191 if (*(pwc->parse_itr+1) != ' ')
193 // left bound tab
194 if (ltab_cnt < 19)
196 ++ltab_cnt;
198 if (pwc->tabstops[ltab_cnt] < pwc->pos)
200 pwc->tabstops[ltab_cnt] = pwc->indent +
201 (pwc->pos - 1 + pwc->tabwidth) -
202 ((pwc->pos - 1 + pwc->tabwidth) % pwc->tabwidth);
205 pwc->pos = pwc->tabstops[ltab_cnt];
207 if (pwc->pos + pwc->tabwidth >= pwc->columns && pwc->tabwidth > 2)
209 --pwc->tabwidth;
210 TRACE(mala_module_std, "tab decreased to %d",pwc->tabwidth);
211 goto again;
215 break;
216 case '\n':
217 // end of line
218 ltab_cnt = 0;
219 pwc->pos = pwc->indent;
220 break;
221 default:
222 // normal character
223 ++pwc->pos;
224 break;
229 static void
230 mala_insert_space (struct mala_printwraped_context* pwc, int stop)
232 while (pwc->pos < stop)
234 ++pwc->pos;
235 putchar (' ');
239 static void
240 mala_ltab (struct mala_printwraped_context* pwc)
242 TRACE (mala_module_std);
243 while(*pwc->lastspace == ' ')
244 ++pwc->lastspace;
245 ++pwc->lastspace;
247 if (pwc->ltab_itr < 19)
249 ++pwc->ltab_itr;
250 pwc->wrap_indent = pwc->tabstops[pwc->ltab_itr] -
251 (pwc->parse_itr - pwc->lastspace) - 1;
254 pwc->wrap_indent_locked = 0;
255 ++pwc->parse_itr;
256 ++pwc->out_itr;
259 static void
260 mala_rtab (struct mala_printwraped_context* pwc)
262 TRACE (mala_module_std);
263 const char * tmp_itr;
265 if (pwc->pos < pwc->columns)
267 putchar (' ');
268 ++pwc->pos;
271 ++pwc->parse_itr;
272 while (isblank (*pwc->parse_itr))
273 ++pwc->parse_itr;
275 pwc->lastspace = pwc->parse_itr;
277 tmp_itr = pwc->parse_itr;
278 while (*tmp_itr != '\0' && *tmp_itr != '\n')
279 ++tmp_itr;
281 int length = tmp_itr - pwc->parse_itr;
283 pwc->wrap_indent = pwc->columns - length;
284 pwc->wrap_indent_locked = 0;
287 static void
288 mala_put_word (struct mala_printwraped_context* pwc)
290 const char* stop;
291 int length;
292 int left;
293 TRACE (mala_module_std);
297 stop = pwc->out_itr;
298 length = stop - pwc->lastspace;
299 left = pwc->columns - pwc->pos;
301 if (pwc->pos + length > pwc->columns)
303 while(*pwc->lastspace == ' ')
304 ++pwc->lastspace;
306 if (length > pwc->columns - pwc->wrap_indent)
308 stop = pwc->lastspace + pwc->columns - pwc->wrap_indent - 1;
311 if (isalpha (*(pwc->lastspace - 1)))
312 putchar ('-');
314 putchar ('\n');
315 pwc->pos = 0;
318 if (pwc->pos < pwc->wrap_indent)
319 mala_insert_space (pwc, pwc->wrap_indent);
321 if (pwc->wrap_indent >= pwc->columns - 1)
322 pwc->wrap_indent = pwc->columns - 2;
324 while (pwc->lastspace < stop)
326 if (isalpha (*pwc->lastspace))
327 pwc->wrap_indent_locked = 1;
328 else if (!pwc->wrap_indent_locked)
329 ++pwc->wrap_indent;
331 putchar (*pwc->lastspace);
332 ++pwc->pos;
333 ++pwc->lastspace;
336 while (stop < pwc->out_itr);
339 static void
340 mala_wrap_words (struct mala_printwraped_context* pwc)
342 /* prints all text until the next \t \n or \0 linewraped */
343 TRACE (mala_module_std);
344 for (; pwc->out_itr < pwc->parse_itr; ++pwc->out_itr)
346 if (*pwc->out_itr == ' ')
348 mala_put_word (pwc);
351 mala_put_word (pwc);
354 static void
355 mala_print_wraped (struct mala_printwraped_context* pwc)
358 - a line consists of many tab delimited fields with one optional right aligned field at the
359 end introduced with tab-space "\t "
360 - the last normal tab field gets word wraped and aligned the first alphabetic character of this
361 field. Too long words become (simple) hyphenated.
362 - tabs are aligned every 'tabwidth' characters, when the terminal is too small, tabwidth is
363 gradually decremented until the data fits more nicely until tabwidth = 2.
364 - care is taken that even if the output isn't displayable (too less columns) at least something
365 ugly will be presented, never failing.
367 Example:
368 "foo \tbar\n\n\tfoo\t- foo explanation which gets word wraped because this text is long\n\tbaz\t- baz explanation\t [note]"
370 becomes something like:
372 foo bar
374 foo - foo explanation which gets word wraped
375 because this text is long
376 baz - baz explanation [note]
379 TRACE (mala_module_std);
381 for (pwc->lastspace = pwc->out_itr = pwc->parse_itr = pwc->text,
382 pwc->pos = 0;
383 *pwc->parse_itr;
384 ++pwc->parse_itr)
386 switch (*pwc->parse_itr)
388 case '\t':
389 mala_wrap_words (pwc);
390 if (*(pwc->parse_itr+1) != ' ')
391 mala_ltab (pwc);
392 else
393 mala_rtab (pwc);
394 break;
395 case '\n':
396 mala_wrap_words (pwc);
397 putchar ('\n');
398 ++pwc->lastspace;
399 pwc->wrap_indent = pwc->indent;
400 pwc->wrap_indent_locked = 0;
401 pwc->ltab_itr = 0;
402 pwc->pos = 0;
403 break;
407 mala_wrap_words (pwc);
408 putchar ('\n');
412 mala_state
413 mala_printwraped_parser (MalaProgram prg)
415 TRACE (mala_module_std);
417 struct mala_printwraped_context pwc;
419 mala_state state;
421 /* Columns */
422 state = mala_program_eval_arg_fmt (prg, 1, "%d", &pwc.columns, NULL);
423 if (state > MALA_START)
424 return state;
425 if (pwc.columns < 2)
426 pwc.columns = 2;
428 /* Lines _ignored for now_ */
429 PLANNED("paged output");
430 state = mala_program_eval_arg_fmt (prg, 2, "%d", &pwc.lines, NULL);
431 if (state > MALA_START)
432 return state;
433 if (pwc.lines < 2)
434 pwc.lines = 2;
436 /* Indent */
437 state = mala_program_eval_arg_fmt (prg, 3, "%d", &pwc.indent, NULL);
438 if (state > MALA_START)
439 return state;
440 if (pwc.indent >= pwc.columns - 2)
441 /* ugly fallback */
442 pwc.indent = 1;
444 /* Tabwidth */
445 state = mala_program_eval_arg_fmt (prg, 4, "%d", &pwc.tabwidth, NULL);
446 if (state > MALA_START)
447 return state;
448 if (pwc.tabwidth < 2)
449 pwc.tabwidth = 2;
451 // Text
452 MalaStringList textnode;
453 state = mala_program_eval_arg (prg, 5, MALA_LITERAL, &textnode);
454 if (state > MALA_START)
455 return state;
457 pwc.text = mala_stringlist_cstr (textnode);
459 MALA_MUTATOR_BEGIN
461 pwc.ltab_itr = 0;
462 pwc.wrap_indent_locked = 0;
463 pwc.wrap_indent = pwc.indent;
465 mala_estimate_tabwidth (&pwc);
466 mala_print_wraped (&pwc);
468 MALA_MUTATOR_END;
470 mala_program_action_done (prg, 5);
471 return MALA_STATEMENT;
476 mala_module_std_io_init (MalaEngine self)
478 return mala_engine_actions_register (self, std_io);
483 // Local Variables:
484 // mode: C
485 // c-file-style: "gnu"
486 // End:
487 // arch-tag: 3d2a15ac-145d-42d7-98a5-14dc9b7d2003
488 // end_of_file