1 /******************************************************************************
2 * This file is Copyright 1992 by Philip G. Richards.  All Rights Reserved.
3 * See the file README that came with this distribution for permissions on
4 * code usage, copying, and distribution.  It comes with absolutely no warranty.
5 ******************************************************************************/
6 
7 #include "client.h"
8 #include "main.h"
9 #include "macro.h"
10 #include <stdlib.h>
11 
12 typedef struct MACRO {
13 	char	*name;
14 	int	length;
15 	char	**text;
16 	char	*help;
17 } MACRO;
18 
19 static int maxmacro = 0, nummacro = 0;
20 static MACRO *macrotable = (MACRO*)0;
21 
22 static int *macrostack = (int*)0;
23 static int stacktop    = 0;
24 static int stacklimit  = 0;
25 static int *cntstack   = (int*)0;
26 
27 static void
clean_macro(MACRO * macro)28 clean_macro(MACRO *macro)
29 {
30     if (macro == (MACRO*)0)
31 	return;
32 
33     macro->name   = (char*)0;
34     macro->length = 0;
35     macro->text   = (char**)0;
36     macro->help   = (char*)0;
37 }
38 
39 static void
destroy_macro(MACRO * macro)40 destroy_macro(MACRO *macro)
41 {
42     int i;
43 
44     if (macro == (MACRO*)0)
45 	return;
46 
47     for (i = 0; i < macro->length; i++)
48         (void)free((char*)(macro->text[i]));
49 
50     (void)free((char*)(macro->name));
51     (void)free((char*)(macro->help));
52 
53     nummacro--;
54 
55     clean_macro(macro);
56 }
57 
58 static MACRO *
lookup_macro(char * name)59 lookup_macro(char *name)
60 {
61     int i;
62 
63     if (macrotable == (MACRO*)0)
64 	return (MACRO*)0;
65 
66     for (i = 0; i < nummacro; i++)
67         if (macrotable[i].name && strcmp(macrotable[i].name, name) == 0)
68 	    break;
69 
70     return (i < nummacro)? (&macrotable[i]): (MACRO*)0;
71 }
72 
73 int
remove_macro(char * name)74 remove_macro(char *name)
75 {
76     MACRO *macro;
77 
78     macro = lookup_macro(name);
79 
80     if (macro)
81 	destroy_macro(macro);
82     else
83 	ffprintf(STDERR, "?no macro `%s'\n", name);
84 
85     return (macro == 0);
86 }
87 
88 int
list_macro(char * name)89 list_macro(char *name)
90 {
91     MACRO *macro;
92 
93     macro = lookup_macro(name);
94 
95     if (macro)
96     {
97 	int i;
98 
99 	ffprintf(STDOUT, "--- Macro `%s':  %d lines\n",
100 		 macro->name, macro->length);
101 
102 	if (macro->help)
103 	    ffprintf(STDOUT, "    Help text: `%s'\n", macro->help);
104 	else
105 	    ffprintf(STDOUT, "	  No help text defined\n");
106 
107 	for (i = 0; i < macro->length; i++)
108 	    if (macro->text[i])
109 	        ffprintf(STDOUT, "\t%s\n", macro->text[i]);
110 	    else
111 	        ffprintf(STDOUT, "\n");
112 
113 	ffprintf(STDERR, ".\n");
114     }
115     else
116 	ffprintf(STDERR, "?no macro `%s'\n", name);
117 
118     return (macro == 0);
119 }
120 
121 /***************************************************************************
122 * it is assumed that name will be free'd by the caller (if necessary)
123 * but that macrotext is being handed over fully to this function;
124 * i.e., do what you like with name back in the calling environment,
125 * but under no circumstances free macrotext!
126 ***************************************************************************/
127 int
install_macro(char * name,int macrolen,char ** macrotext,char * macrohelp)128 install_macro(char *name, int macrolen, char **macrotext, char *macrohelp)
129 {
130     MACRO *oldmacro;
131     MACRO *newmacro = (MACRO*)0;
132 
133     if (name == (char*)0 || *name == '\0')
134     {
135 	ffprintf(STDERR, "?attempt to install null named macro failed\n");
136 	return 1;
137     }
138 
139     oldmacro = lookup_macro(name);
140 
141     if (oldmacro != (MACRO*)0)
142     {	/* free the old macro; the new macro can take its place */
143 	ffprintf(STDINFO, "?overwriting old macro definition for `%s'\n",
144 		      name);
145 	destroy_macro(oldmacro);
146 	newmacro = oldmacro;
147     }
148     else if (nummacro < maxmacro)
149     {	/* there is a free space in the table */
150 	int i;
151 	for (i = 0; i < maxmacro; i++)
152 	    if (!macrotable[i].name)
153 		break;
154 
155 	/* if this fails then we have *big* problems, oh well, check anyway */
156 	if (i < maxmacro)
157 	    newmacro = &macrotable[i];
158 	else
159 	{
160 	    ffprintf(STDERR,"??internal error: nummacro(%d) < maxmacro(%d) and no gap found\n", nummacro, maxmacro);
161 	    return 1;
162 	}
163     }
164     else
165     {	/* no free space in table; extend by a bit */
166 	maxmacro += 4;
167 
168 	if (macrotable)
169 	    macrotable = (MACRO*)realloc((char*)macrotable,
170 					  sizeof(MACRO) * maxmacro);
171 	else
172 	    macrotable = (MACRO*)malloc(sizeof(MACRO) * maxmacro);
173 
174 	if (macrotable == (MACRO*)0)
175 	{
176 	    ffprintf(STDERR, "??run out of memory in install_macro()\n");
177 	    abort();
178 	}
179 	else
180 	{
181 	    int i;
182 	    for (i = nummacro + 1; i < maxmacro; i++)
183 		clean_macro(&macrotable[i]);
184 	}
185 
186 	newmacro = &macrotable[nummacro];
187     }
188 
189     nummacro++;
190 
191     newmacro->name   = strdup(name);
192     newmacro->length = macrolen;
193     newmacro->text   = macrotext;
194     newmacro->help   = macrohelp? strdup(macrohelp): 0;
195 
196     return 0;
197 }
198 
199 int
deinstall_macro(char * name)200 deinstall_macro(char *name)
201 {
202     MACRO *macro;
203 
204     macro = lookup_macro(name);
205 
206     if (macro == (MACRO*)0)
207     {
208 	ffprintf(STDERR, "?can not delete macro `%s': doesn't exist\n", name);
209 	return 1;
210     }
211 
212     destroy_macro(macro);
213 
214     return 0;
215 }
216 
217 int
initialise_macro(int argc,char ** argv)218 initialise_macro(int argc, char **argv)
219 {
220     MACRO *macro;
221     int i;
222 
223     macro = lookup_macro(argv[0]);
224     if (macro == (MACRO*)0)
225 	return 1;
226 
227     if (dbug_flag > 0)
228     {
229 	int i;
230 	ffprintf(STDDBG, "\nmacro initialise called with valid macro name:\n");
231 	for (i = 0; i <= argc; i++)
232 	    ffprintf(STDDBG, "    $%-2d = \"%s\"\n", i, argv[i]);
233 
234 	ffprintf(STDDBG, "\ndefinition:\n");
235 	for (i = 0; i < macro->length; i++)
236 	    ffprintf(STDDBG, "%02d: %s\n", i, macro->text[i]);
237 
238 	ffprintf(STDDBG, "\n");
239     }
240 
241     /* we don't allow recursion (yet) so check this isn't trying to */
242     for (i = 0; i < stacktop; i++)
243 	if (macro == &macrotable[macrostack[i]])
244 	{
245 	    ffprintf(STDERR,
246 		"?attempted recursion in macro `%s' -- ignoring call to `%s'\n",
247 		macrotable[macrostack[stacktop-1]].name, macro->name);
248 	    (void)fflush(STDERR);
249 	    return 0;
250 	}
251 
252     /* push this macro onto the macro execution stack */
253     if (stacktop >= stacklimit)
254     {
255 	stacklimit += 8;
256 
257 	if (macrostack)
258 	    macrostack = (int*)realloc((char*)macrostack,
259 					  stacklimit * sizeof(int));
260 	else
261 	    macrostack = (int*)malloc(stacklimit * sizeof(int));
262 
263 	if (cntstack)
264 	    cntstack = (int*)realloc((char*)cntstack,
265 					  stacklimit * sizeof(int));
266 	else
267 	    cntstack = (int*)malloc(stacklimit * sizeof(int));
268     }
269 
270     macrostack[stacktop] = (int)(macro - macrotable);
271     cntstack[stacktop++] = 0;
272 
273     return 0;
274 }
275 
276 char *
get_macroline(void)277 get_macroline(void)
278 {
279     if (stacktop > 0)
280     {
281 	int st = stacktop - 1;
282 	if (cntstack[st] < macrotable[macrostack[st]].length)
283 	    return (macrotable[macrostack[st]].text[cntstack[st]++]);
284 	else
285 	    stacktop--;
286     }
287 
288     return (char*)0;
289 }
290 
291 #define NCO 6
292 void
fsp_macro_long_help_all(void)293 fsp_macro_long_help_all(void)
294 {
295     int i;
296     int notext = 0;
297 
298     if (macrotable == (MACRO*)0 || nummacro == 0)
299     {
300 	ffprintf(STDOUT,"No macros defined\n");
301 	return;
302     }
303 
304     ffprintf(STDOUT,"Macros are:\n");
305 
306     for (i = 0; i < maxmacro; i++)
307 	if (macrotable[i].name)
308 	{
309 	    if (macrotable[i].help)
310 		ffprintf(STDOUT,"      %-10s    %s\n",
311 			 macrotable[i].name, macrotable[i].help);
312 	    else
313 		notext++;
314 	}
315 
316     if (notext)
317     {
318 	int j;
319 
320 	ffprintf(STDOUT,"\nUndocumented macros are:\n");
321 
322 	for (i = 0, j = 0; i < maxmacro; i++)
323 	    if (macrotable[i].name)
324 		if (!macrotable[i].help)
325 		{
326 		    ffprintf(STDOUT,"  %-10s%s",
327 			     macrotable[i].name, j == NCO-1? "\n" : "");
328 		    j = (j+1) % NCO;
329 		}
330 
331 	if (j)
332 	    ffprintf(STDOUT,"\n");
333     }
334 }
335 
336 int
fsp_macro_long_help(char * name)337 fsp_macro_long_help(char *name)
338 {
339     MACRO *macro;
340 
341     macro = lookup_macro(name);
342 
343     if (macro)
344     {
345 	if (macro->help)
346 	    ffprintf(STDOUT,"%-10s    %s\n", macro->name, macro->help);
347 	else
348 	    ffprintf(STDOUT, "no help available for macro `%s'\n", name);
349     }
350     else
351 	return 1;
352 
353     return 0;
354 }
355 
356 void
fsp_macro_short_help(void)357 fsp_macro_short_help(void)
358 {
359     int i, j;
360 
361     if (macrotable == (MACRO*)0 || nummacro == 0)
362     {
363 	ffprintf(STDOUT,"No macros defined\n");
364 	return;
365     }
366 
367     ffprintf(STDOUT,"Macros are:\n");
368 
369     for (i = 0, j = 0; i < maxmacro; i++)
370 	if (macrotable[i].name)
371 	{
372 	    ffprintf(STDOUT,"  %-10s%s",
373 		     macrotable[i].name, j == NCO-1? "\n" : "");
374 	    j = (j+1) % NCO;
375 	}
376 
377     if (j)
378 	ffprintf(STDOUT,"\n");
379 }
380