fix buffer printer overflowing buffer
[cparser] / printer.c
1 /*
2  * This file is part of cparser.
3  * Copyright (C) 2007-2009 Matthias Braun <matze@braunis.de>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
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.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18  * 02111-1307, USA.
19  */
20 #include "config.h"
21
22 #include "printer.h"
23
24 #include <stdio.h>
25 #include <stdarg.h>
26
27 static FILE* out;
28
29 static void print_string_file(const char *str)
30 {
31         fputs(str, out);
32 }
33
34 static void print_vformat_file(const char *format, va_list ap)
35 {
36         vfprintf(out, format, ap);
37 }
38
39 static void print_char_file(wchar_rep_t c)
40 {
41         const unsigned tc = (unsigned) c;
42         if (tc < 0x80) {
43                 fputc(tc, out);
44         } else if (tc < 0x800) {
45                 fputc(0xC0 | (tc >> 6),   out);
46                 fputc(0x80 | (tc & 0x3F), out);
47         } else if (tc < 0x10000) {
48                 fputc(0xE0 | ( tc >> 12),         out);
49                 fputc(0x80 | ((tc >>  6) & 0x3F), out);
50                 fputc(0x80 | ( tc        & 0x3F), out);
51         } else {
52                 fputc(0xF0 | ( tc >> 18),         out);
53                 fputc(0x80 | ((tc >> 12) & 0x3F), out);
54                 fputc(0x80 | ((tc >>  6) & 0x3F), out);
55                 fputc(0x80 | ( tc        & 0x3F), out);
56         }
57 }
58
59 void print_to_file(FILE *new_out)
60 {
61         out = new_out;
62         print_string  = print_string_file;
63         print_vformat = print_vformat_file;
64         print_char    = print_char_file;
65 }
66
67
68
69 static struct obstack *obst;
70
71 static void print_string_obstack(const char *str)
72 {
73         size_t len = strlen(str);
74         obstack_grow(obst, str, len);
75 }
76
77 static void print_vformat_obstack(const char *format, va_list ap)
78 {
79         obstack_vprintf(obst, format, ap);
80 }
81
82 static void print_char_obstack(wchar_rep_t c)
83 {
84         const unsigned tc = (unsigned) c;
85         if (tc < 0x80) {
86                 obstack_1grow(obst, tc);
87         } else if (tc < 0x800) {
88                 obstack_1grow(obst, 0xC0 | (tc >> 6));
89                 obstack_1grow(obst, 0x80 | (tc & 0x3F));
90         } else if (tc < 0x10000) {
91                 obstack_1grow(obst, 0xE0 | ( tc >> 12));
92                 obstack_1grow(obst, 0x80 | ((tc >>  6) & 0x3F));
93                 obstack_1grow(obst, 0x80 | ( tc        & 0x3F));
94         } else {
95                 obstack_1grow(obst, 0xF0 | ( tc >> 18));
96                 obstack_1grow(obst, 0x80 | ((tc >> 12) & 0x3F));
97                 obstack_1grow(obst, 0x80 | ((tc >>  6) & 0x3F));
98                 obstack_1grow(obst, 0x80 | ( tc        & 0x3F));
99         }
100 }
101
102 void print_to_obstack(struct obstack *new_obst)
103 {
104         obst = new_obst;
105         print_string  = print_string_obstack;
106         print_vformat = print_vformat_obstack;
107         print_char    = print_char_obstack;
108 }
109
110
111
112 static char *buffer_pos;
113 static char *buffer_end;
114
115 static inline void buffer_add_char(int c)
116 {
117         if (buffer_pos == buffer_end)
118                 return;
119         *buffer_pos++ = c;
120 }
121
122 static void print_string_buffer(const char *str)
123 {
124         for (const char *c = str; *c != '\0'; ++c) {
125                 buffer_add_char(*c);
126         }
127 }
128
129 static void print_vformat_buffer(const char *format, va_list ap)
130 {
131         size_t size    = buffer_end - buffer_pos;
132         size_t written = (size_t) vsnprintf(buffer_pos, size, format, ap);
133         buffer_pos    += written < size ? written : size;
134 }
135
136 static void print_char_buffer(wchar_rep_t c)
137 {
138         const unsigned tc = (unsigned) c;
139         if (tc < 0x80) {
140                 buffer_add_char(tc);
141         } else if (tc < 0x800) {
142                 buffer_add_char(0xC0 | (tc >> 6));
143                 buffer_add_char(0x80 | (tc & 0x3F));
144         } else if (tc < 0x10000) {
145                 buffer_add_char(0xE0 | ( tc >> 12));
146                 buffer_add_char(0x80 | ((tc >>  6) & 0x3F));
147                 buffer_add_char(0x80 | ( tc        & 0x3F));
148         } else {
149                 buffer_add_char(0xF0 | ( tc >> 18));
150                 buffer_add_char(0x80 | ((tc >> 12) & 0x3F));
151                 buffer_add_char(0x80 | ((tc >>  6) & 0x3F));
152                 buffer_add_char(0x80 | ( tc        & 0x3F));
153         }
154 }
155
156 void print_to_buffer(char *buffer, size_t buffer_size)
157 {
158         buffer_pos = buffer;
159         buffer_end = buffer + buffer_size - 2;
160
161         print_string  = print_string_buffer;
162         print_vformat = print_vformat_buffer;
163         print_char    = print_char_buffer;
164 }
165
166 void finish_print_to_buffer(void)
167 {
168         *buffer_pos = '\0';
169         buffer_pos = NULL;
170         buffer_end = NULL;
171 }
172
173
174 void (*print_string)(const char *str) = print_string_file;
175 void (*print_vformat)(const char *format, va_list ap) = print_vformat_file;
176 void (*print_char)(wchar_rep_t c) = print_char_file;
177
178 void printer_push(void)
179 {
180         /* TODO */
181 }
182
183 void printer_pop(void)
184 {
185         /* TODO */
186 }