1 /*
2 	#FILENAME#
3 
4 	#DESCRIPTION#
5 
6 	Copyright (C) 2002 #AUTHOR#
7 
8 	Author: #AUTHOR#
9 	Date: #DATE#
10 
11 	This program is free software; you can redistribute it and/or
12 	modify it under the terms of the GNU General Public License
13 	as published by the Free Software Foundation; either version 2
14 	of the License, or (at your option) any later version.
15 
16 	This program is distributed in the hope that it will be useful,
17 	but WITHOUT ANY WARRANTY; without even the implied warranty of
18 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 
20 	See the GNU General Public License for more details.
21 
22 	You should have received a copy of the GNU General Public License
23 	along with this program; if not, write to:
24 
25 		Free Software Foundation, Inc.
26 		59 Temple Place - Suite 330
27 		Boston, MA  02111-1307, USA
28 
29 */
30 
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34 
35 #include <stdlib.h>
36 #include <string.h>
37 #include <stdarg.h>
38 
39 #include "QF/sys.h"
40 #include "QF/dstring.h"
41 #include "QF/cbuf.h"
42 #include "QF/hash.h"
43 #include "QF/gib.h"
44 #include "QF/idparse.h"
45 
46 #include "gib_tree.h"
47 #include "gib_parse.h"
48 #include "gib_vars.h"
49 #include "gib_execute.h"
50 #include "gib_buffer.h"
51 
52 static void
GIB_Buffer_Construct(struct cbuf_s * cbuf)53 GIB_Buffer_Construct (struct cbuf_s *cbuf)
54 {
55 	cbuf->data = calloc (1, sizeof (gib_buffer_data_t));
56 	GIB_DATA (cbuf)->arg_composite = dstring_newstr ();
57 	GIB_DATA (cbuf)->globals = gib_globals;
58 	cbuf->strict = true;
59 }
60 
61 static void
GIB_Buffer_Destruct(struct cbuf_s * cbuf)62 GIB_Buffer_Destruct (struct cbuf_s *cbuf)
63 {
64 	gib_buffer_data_t *g = GIB_DATA (cbuf);
65 	unsigned int i, j;
66 
67 	if (g->dnotify)
68 		g->dnotify (cbuf, g->ddata);
69 
70 	dstring_delete (g->arg_composite);
71 	if (g->locals)
72 		Hash_DelTable (g->locals);
73 	if (g->program)
74 		GIB_Tree_Unref (&g->program);
75 	if (g->script && !(--g->script->refs)) {
76 		free ((void *) g->script->text);
77 		free ((void *) g->script->file);
78 		free (g->script);
79 	}
80 	for (i = 0; i < g->stack.size; i++) {
81 		for (j = 0; j < g->stack.values[i].realsize; j++)
82 			dstring_delete (g->stack.values[i].dstrs[j]);
83 		if (g->stack.values[i].dstrs)
84 			free (g->stack.values[i].dstrs);
85 	}
86 	if (g->stack.values)
87 		free (g->stack.values);
88 	free (cbuf->data);
89 }
90 
91 static void
GIB_Buffer_Reset(struct cbuf_s * cbuf)92 GIB_Buffer_Reset (struct cbuf_s *cbuf)
93 {
94 	gib_buffer_data_t *g = GIB_DATA (cbuf);
95 
96 	// Being reset is nearly the same as being destroyed.
97 	// It just means the buffer is going to be reused.
98 	if (g->dnotify)
99 		g->dnotify (cbuf, g->ddata);
100 
101 	if (g->locals)
102 		Hash_FlushTable (g->locals);
103 	g->globals = gib_globals;
104 	if (g->program)
105 		GIB_Tree_Unref (&g->program);
106 	if (g->script && !(--g->script->refs)) {
107 		free ((void *) g->script->text);
108 		free ((void *) g->script->file);
109 		free (g->script);
110 	}
111 	g->script = 0;
112 	g->program = g->ip = 0;
113 	g->stack.p = 0;
114 	g->waitret = false;
115 	g->dnotify = NULL;
116 	g->reply.obj = NULL;
117 }
118 
119 void
GIB_Buffer_Set_Program(cbuf_t * cbuf,gib_tree_t * program)120 GIB_Buffer_Set_Program (cbuf_t * cbuf, gib_tree_t * program)
121 {
122 	GIB_DATA (cbuf)->program = program;
123 }
124 
125 static unsigned int
GIB_Buffer_Get_Line_Num(const char * program,unsigned int pos)126 GIB_Buffer_Get_Line_Num (const char *program, unsigned int pos)
127 {
128 	unsigned int i, line;
129 
130 	for (i = 0, line = 1; i < pos; i++)
131 		if (program[i] == '\n')
132 			line++;
133 	return line;
134 }
135 
136 static void
GIB_Buffer_Add(cbuf_t * cbuf,const char * str)137 GIB_Buffer_Add (cbuf_t * cbuf, const char *str)
138 {
139 	gib_buffer_data_t *g = GIB_DATA (cbuf);
140 	gib_tree_t **save, *cur;
141 
142 	// AddText should be used only to populate a buffer before
143 	// executing it and shouldn't happen to a running GIB buffer,
144 	// but if it does, try to find somewhere else to put the text.
145 	if (g->ip) {
146 		for (;cbuf; cbuf = cbuf->up)
147 			if (cbuf->interpreter == &id_interp) {
148 				Cbuf_AddText (cbuf, str);
149 				return;
150 			}
151 		Sys_Printf (
152 				"-------------\n"
153 				"|GIB Warning|\n"
154 				"-------------\n"
155 				"Text added to running GIB buffer discarded.\n"
156 				"Text: %s\n",
157 				str
158 		);
159 		return;
160 	} else if (g->program) {
161 		for (cur = g->program; cur->next; cur = cur->next);
162 		save = &cur->next;
163 	} else
164 		save = &g->program;
165 	if (!(*save = GIB_Parse_Lines (str, 0)))
166 		Sys_Printf (
167 			"-----------------\n"
168 			"|GIB Parse Error|\n"
169 			"-----------------\n"
170 			"Parse error while adding text to GIB buffer.\n"
171 			"Line %u: %s\n",
172 			GIB_Buffer_Get_Line_Num (str, GIB_Parse_ErrorPos ()),
173 			GIB_Parse_ErrorMsg ()
174 		);
175 }
176 
177 static void
GIB_Buffer_Insert(cbuf_t * cbuf,const char * str)178 GIB_Buffer_Insert (cbuf_t * cbuf, const char *str)
179 {
180 	gib_buffer_data_t *g = GIB_DATA (cbuf);
181 	gib_tree_t *lines, *cur;
182 
183 	// No GIB builtin should ever insert text into a running
184 	// GIB buffer, so create an idparse buffer to handle the
185 	// legacy console code.
186 	if (g->ip) {
187 		cbuf_t *new = Cbuf_New (&id_interp);
188 		new->up = cbuf;
189 		cbuf->down = new;
190 		cbuf->state = CBUF_STATE_STACK;
191 		Cbuf_InsertText (new, str);
192 		return;
193 	} else if ((lines = GIB_Parse_Lines (str, 0))) {
194 		for (cur = lines; cur; cur = cur->next);
195 		cur->next = g->program;
196 		g->program = lines;
197 	} else
198 		Sys_Printf (
199 			"-----------------\n"
200 			"|GIB Parse Error|\n"
201 			"-----------------\n"
202 			"Parse error while inserting text into GIB buffer.\n"
203 			"Line %u: %s\n",
204 			GIB_Buffer_Get_Line_Num (str, GIB_Parse_ErrorPos ()),
205 			GIB_Parse_ErrorMsg ()
206 		);
207 }
208 
209 void
GIB_Buffer_Push_Sstack(struct cbuf_s * cbuf)210 GIB_Buffer_Push_Sstack (struct cbuf_s *cbuf)
211 {
212 	gib_buffer_data_t *g = GIB_DATA (cbuf);
213 
214 	if (++g->stack.p > g->stack.size) {
215 		g->stack.values = realloc (g->stack.values,
216 								   sizeof (struct gib_dsarray_s) * g->stack.p);
217 		g->stack.values[g->stack.p - 1].dstrs = 0;
218 		g->stack.values[g->stack.p - 1].size =
219 			g->stack.values[g->stack.p - 1].realsize = 0;
220 		g->stack.size = g->stack.p;
221 	}
222 	g->stack.values[g->stack.p - 1].size = 0;
223 }
224 
225 void
GIB_Buffer_Pop_Sstack(struct cbuf_s * cbuf)226 GIB_Buffer_Pop_Sstack (struct cbuf_s *cbuf)
227 {
228 	GIB_DATA (cbuf)->stack.p--;
229 }
230 
231 dstring_t *
GIB_Buffer_Dsarray_Get(struct cbuf_s * cbuf)232 GIB_Buffer_Dsarray_Get (struct cbuf_s *cbuf)
233 {
234 	struct gib_dsarray_s *vals =
235 		GIB_DATA (cbuf)->stack.values + GIB_DATA (cbuf)->stack.p - 1;
236 	if (++vals->size > vals->realsize) {
237 		vals->dstrs = realloc (vals->dstrs, sizeof (dstring_t *) * vals->size);
238 		vals->dstrs[vals->size - 1] = dstring_newstr ();
239 		vals->realsize = vals->size;
240 	} else
241 		dstring_clearstr (vals->dstrs[vals->size - 1]);
242 	return vals->dstrs[vals->size - 1];
243 }
244 
245 
246 static int
GIB_Buffer_Get_Line_Info(cbuf_t * cbuf,char ** line)247 GIB_Buffer_Get_Line_Info (cbuf_t * cbuf, char **line)
248 {
249 	const char *text;
250 	unsigned int ofs, i, start, linenum;
251 
252 	// Do we have a copy of the original program this buffer comes from?
253 	if (GIB_DATA (cbuf)->script) {
254 		text = GIB_DATA (cbuf)->script->text;
255 		for (ofs = GIB_DATA (cbuf)->ip->start, start = 0, i = 0, linenum = 1;
256 			 i <= ofs; i++)
257 			if (text[i] == '\n') {
258 				start = i + 1;
259 				linenum++;
260 			}
261 		while (text[i] != '\n')
262 			i++;
263 		*line = malloc (i - start + 1);
264 		memcpy (*line, text + start, i - start);
265 		(*line)[i - start] = 0;
266 		return linenum;
267 	} else {
268 		*line = strdup (GIB_DATA (cbuf)->ip->str);
269 		return -1;
270 	}
271 }
272 
273 void
GIB_Buffer_Reply_Callback(int argc,const char ** argv,void * data)274 GIB_Buffer_Reply_Callback (int argc, const char **argv, void *data)
275 {
276 	cbuf_t *cbuf = (cbuf_t *) data;
277 	int i;
278 
279 	for (i = 0; i < argc; i++)
280 		dstring_copystr (GIB_Buffer_Dsarray_Get (cbuf), argv[i]);
281 	if (cbuf->state == CBUF_STATE_BLOCKED)
282 		cbuf->state = CBUF_STATE_NORMAL;
283 }
284 
285 void
GIB_Buffer_Error(cbuf_t * cbuf,const char * type,const char * fmt,va_list args)286 GIB_Buffer_Error (cbuf_t * cbuf, const char *type, const char *fmt,
287 				  va_list args)
288 {
289 	char       *line;
290 	int         linenum;
291 	dstring_t  *message = dstring_newstr ();
292 
293 	dvsprintf (message, fmt, args);
294 	va_end (args);
295 	Sys_Printf (
296 			"---------------------\n"
297 			"|GIB Execution Error|\n"
298 			"---------------------\n"
299 			"Type: %s\n",
300 			type
301 		);
302 	if ((linenum = GIB_Buffer_Get_Line_Info (cbuf, &line)) != -1)
303 		Sys_Printf (
304 			"%s:%i: %s\n"
305 			"-->%s\n",
306 			GIB_DATA (cbuf)->script->file, linenum, message->str, line
307 		);
308 	else
309 		Sys_Printf (
310 			"%s\n"
311 			"-->%s\n",
312 			message->str,
313 			line
314 		);
315 	cbuf->state = CBUF_STATE_ERROR;
316 	dstring_delete (message);
317 	free (line);
318 }
319 
320 
321 cbuf_interpreter_t gib_interp = {
322 	GIB_Buffer_Construct,
323 	GIB_Buffer_Destruct,
324 	GIB_Buffer_Reset,
325 	GIB_Buffer_Add,
326 	GIB_Buffer_Insert,
327 	GIB_Execute,
328 	GIB_Execute,
329 };
330 
331 VISIBLE cbuf_interpreter_t *
GIB_Interpreter(void)332 GIB_Interpreter (void)
333 {
334 	return &gib_interp;
335 }
336