1/* -----------------------------------------------------------------------------
2 * See the LICENSE file for information on copyright, usage and redistribution
3 * of SWIG, and the README file for authors - http://www.swig.org/release.html.
4 *
5 * wrapfunc.c
6 *
7 * This file defines a object for creating wrapper functions.  Primarily
8 * this is used for convenience since it allows pieces of a wrapper function
9 * to be created in a piecemeal manner.
10 * ----------------------------------------------------------------------------- */
11
12char cvsroot_wrapfunc_c[] = "$Id: wrapfunc.c 11080 2009-01-24 13:15:51Z bhy $";
13
14#include "swig.h"
15#include <ctype.h>
16
17static int Compact_mode = 0;	/* set to 0 on default */
18static int Max_line_size = 128;
19
20/* -----------------------------------------------------------------------------
21 * NewWrapper()
22 *
23 * Create a new wrapper function object.
24 * ----------------------------------------------------------------------------- */
25
26Wrapper *NewWrapper(void) {
27  Wrapper *w;
28  w = (Wrapper *) malloc(sizeof(Wrapper));
29  w->localh = NewHash();
30  w->locals = NewStringEmpty();
31  w->code = NewStringEmpty();
32  w->def = NewStringEmpty();
33  return w;
34}
35
36/* -----------------------------------------------------------------------------
37 * DelWrapper()
38 *
39 * Delete a wrapper function object.
40 * ----------------------------------------------------------------------------- */
41
42void DelWrapper(Wrapper *w) {
43  Delete(w->localh);
44  Delete(w->locals);
45  Delete(w->code);
46  Delete(w->def);
47  free(w);
48}
49
50/* -----------------------------------------------------------------------------
51 * Wrapper_compact_print_mode_set()
52 *
53 * Set compact_mode.
54 * ----------------------------------------------------------------------------- */
55
56void Wrapper_compact_print_mode_set(int flag) {
57  Compact_mode = flag;
58}
59
60/* -----------------------------------------------------------------------------
61 * Wrapper_pretty_print()
62 *
63 * Formats a wrapper function and fixes up the indentation.
64 * ----------------------------------------------------------------------------- */
65
66void Wrapper_pretty_print(String *str, File *f) {
67  String *ts;
68  int level = 0;
69  int c, i;
70  int empty = 1;
71  int indent = 2;
72  int plevel = 0;
73  int label = 0;
74
75  ts = NewStringEmpty();
76  Seek(str, 0, SEEK_SET);
77  while ((c = Getc(str)) != EOF) {
78    if (c == '\"') {
79      Putc(c, ts);
80      while ((c = Getc(str)) != EOF) {
81	if (c == '\\') {
82	  Putc(c, ts);
83	  c = Getc(str);
84	}
85	Putc(c, ts);
86	if (c == '\"')
87	  break;
88      }
89      empty = 0;
90    } else if (c == '\'') {
91      Putc(c, ts);
92      while ((c = Getc(str)) != EOF) {
93	if (c == '\\') {
94	  Putc(c, ts);
95	  c = Getc(str);
96	}
97	Putc(c, ts);
98	if (c == '\'')
99	  break;
100      }
101      empty = 0;
102    } else if (c == ':') {
103      Putc(c, ts);
104      if ((c = Getc(str)) == '\n') {
105	if (!empty && !strchr(Char(ts), '?'))
106	  label = 1;
107      }
108      Ungetc(c, str);
109    } else if (c == '(') {
110      Putc(c, ts);
111      plevel += indent;
112      empty = 0;
113    } else if (c == ')') {
114      Putc(c, ts);
115      plevel -= indent;
116      empty = 0;
117    } else if (c == '{') {
118      Putc(c, ts);
119      Putc('\n', ts);
120      for (i = 0; i < level; i++)
121	Putc(' ', f);
122      Printf(f, "%s", ts);
123      Clear(ts);
124      level += indent;
125      while ((c = Getc(str)) != EOF) {
126	if (!isspace(c)) {
127	  Ungetc(c, str);
128	  break;
129	}
130      }
131      empty = 0;
132    } else if (c == '}') {
133      if (!empty) {
134	Putc('\n', ts);
135	for (i = 0; i < level; i++)
136	  Putc(' ', f);
137	Printf(f, "%s", ts);
138	Clear(ts);
139      }
140      level -= indent;
141      Putc(c, ts);
142      empty = 0;
143    } else if (c == '\n') {
144      Putc(c, ts);
145      empty = 0;
146      if (!empty) {
147	int slevel = level;
148	if (label && (slevel >= indent))
149	  slevel -= indent;
150	if ((Char(ts))[0] != '#') {
151	  for (i = 0; i < slevel; i++)
152	    Putc(' ', f);
153	}
154	Printf(f, "%s", ts);
155	for (i = 0; i < plevel; i++)
156	  Putc(' ', f);
157      }
158      Clear(ts);
159      label = 0;
160      empty = 1;
161    } else if (c == '/') {
162      empty = 0;
163      Putc(c, ts);
164      c = Getc(str);
165      if (c != EOF) {
166	Putc(c, ts);
167	if (c == '/') {		/* C++ comment */
168	  while ((c = Getc(str)) != EOF) {
169	    if (c == '\n') {
170	      Ungetc(c, str);
171	      break;
172	    }
173	    Putc(c, ts);
174	  }
175	} else if (c == '*') {	/* C comment */
176	  int endstar = 0;
177	  while ((c = Getc(str)) != EOF) {
178	    if (endstar && c == '/') {	/* end of C comment */
179	      Putc(c, ts);
180	      break;
181	    }
182	    endstar = (c == '*');
183	    Putc(c, ts);
184	    if (c == '\n') {	/* multi-line C comment. Could be improved slightly. */
185	      for (i = 0; i < level; i++)
186		Putc(' ', ts);
187	    }
188	  }
189	}
190      }
191    } else {
192      if (!empty || !isspace(c)) {
193	Putc(c, ts);
194	empty = 0;
195      }
196    }
197  }
198  if (!empty)
199    Printf(f, "%s", ts);
200  Delete(ts);
201  Printf(f, "\n");
202}
203
204/* -----------------------------------------------------------------------------
205 * Wrapper_compact_print()
206 *
207 * Formats a wrapper function and fixes up the indentation.
208 * Print out in compact format, with Compact enabled.
209 * ----------------------------------------------------------------------------- */
210
211void Wrapper_compact_print(String *str, File *f) {
212  String *ts, *tf;		/*temp string & temp file */
213  int level = 0;
214  int c, i;
215  int empty = 1;
216  int indent = 2;
217
218  ts = NewStringEmpty();
219  tf = NewStringEmpty();
220  Seek(str, 0, SEEK_SET);
221
222  while ((c = Getc(str)) != EOF) {
223    if (c == '\"') {		/* string 1 */
224      empty = 0;
225      Putc(c, ts);
226      while ((c = Getc(str)) != EOF) {
227	if (c == '\\') {
228	  Putc(c, ts);
229	  c = Getc(str);
230	}
231	Putc(c, ts);
232	if (c == '\"')
233	  break;
234      }
235    } else if (c == '\'') {	/* string 2 */
236      empty = 0;
237      Putc(c, ts);
238      while ((c = Getc(str)) != EOF) {
239	if (c == '\\') {
240	  Putc(c, ts);
241	  c = Getc(str);
242	}
243	Putc(c, ts);
244	if (c == '\'')
245	  break;
246      }
247    } else if (c == '{') {	/* start of {...} */
248      empty = 0;
249      Putc(c, ts);
250      if (Len(tf) == 0) {
251	for (i = 0; i < level; i++)
252	  Putc(' ', tf);
253      } else if ((Len(tf) + Len(ts)) < Max_line_size) {
254	Putc(' ', tf);
255      } else {
256	Putc('\n', tf);
257	Printf(f, "%s", tf);
258	Clear(tf);
259	for (i = 0; i < level; i++)
260	  Putc(' ', tf);
261      }
262      Append(tf, ts);
263      Clear(ts);
264      level += indent;
265      while ((c = Getc(str)) != EOF) {
266	if (!isspace(c)) {
267	  Ungetc(c, str);
268	  break;
269	}
270      }
271    } else if (c == '}') {	/* end of {...} */
272      empty = 0;
273      if (Len(tf) == 0) {
274	for (i = 0; i < level; i++)
275	  Putc(' ', tf);
276      } else if ((Len(tf) + Len(ts)) < Max_line_size) {
277	Putc(' ', tf);
278      } else {
279	Putc('\n', tf);
280	Printf(f, "%s", tf);
281	Clear(tf);
282	for (i = 0; i < level; i++)
283	  Putc(' ', tf);
284      }
285      Append(tf, ts);
286      Putc(c, tf);
287      Clear(ts);
288      level -= indent;
289    } else if (c == '\n') {	/* line end */
290      while ((c = Getc(str)) != EOF) {
291	if (!isspace(c))
292	  break;
293      }
294      if (c == '#') {
295	Putc('\n', ts);
296      } else if (c == '}') {
297	Putc(' ', ts);
298      } else if ((c != EOF) || (Len(ts) != 0)) {
299	if (Len(tf) == 0) {
300	  for (i = 0; i < level; i++)
301	    Putc(' ', tf);
302	} else if ((Len(tf) + Len(ts)) < Max_line_size) {
303	  Putc(' ', tf);
304	} else {
305	  Putc('\n', tf);
306	  Printf(f, "%s", tf);
307	  Clear(tf);
308	  for (i = 0; i < level; i++)
309	    Putc(' ', tf);
310	}
311	Append(tf, ts);
312	Clear(ts);
313      }
314      Ungetc(c, str);
315
316      empty = 1;
317    } else if (c == '/') {	/* comment */
318      empty = 0;
319      c = Getc(str);
320      if (c != EOF) {
321	if (c == '/') {		/* C++ comment */
322	  while ((c = Getc(str)) != EOF) {
323	    if (c == '\n') {
324	      Ungetc(c, str);
325	      break;
326	    }
327	  }
328	} else if (c == '*') {	/* C comment */
329	  int endstar = 0;
330	  while ((c = Getc(str)) != EOF) {
331	    if (endstar && c == '/') {	/* end of C comment */
332	      break;
333	    }
334	    endstar = (c == '*');
335	  }
336	} else {
337	  Putc('/', ts);
338	  Putc(c, ts);
339	}
340      }
341    } else if (c == '#') {	/* Preprocessor line */
342      Putc('#', ts);
343      while ((c = Getc(str)) != EOF) {
344	Putc(c, ts);
345	if (c == '\\') {	/* Continued line of the same PP */
346	  c = Getc(str);
347	  if (c == '\n')
348	    Putc(c, ts);
349	  else
350	    Ungetc(c, str);
351	} else if (c == '\n')
352	  break;
353      }
354      if (!empty) {
355	Append(tf, "\n");
356      }
357      Append(tf, ts);
358      Printf(f, "%s", tf);
359      Clear(tf);
360      Clear(ts);
361      for (i = 0; i < level; i++)
362	Putc(' ', tf);
363      empty = 1;
364    } else {
365      if (!empty || !isspace(c)) {
366	Putc(c, ts);
367	empty = 0;
368      }
369    }
370  }
371  if (!empty) {
372    Append(tf, ts);
373  }
374  if (Len(tf) != 0)
375    Printf(f, "%s", tf);
376  Delete(ts);
377  Delete(tf);
378  Printf(f, "\n");
379}
380
381/* -----------------------------------------------------------------------------
382 * Wrapper_print()
383 *
384 * Print out a wrapper function.  Does pretty or compact printing as well.
385 * ----------------------------------------------------------------------------- */
386
387void Wrapper_print(Wrapper *w, File *f) {
388  String *str;
389
390  str = NewStringEmpty();
391  Printf(str, "%s\n", w->def);
392  Printf(str, "%s\n", w->locals);
393  Printf(str, "%s\n", w->code);
394  if (Compact_mode == 1)
395    Wrapper_compact_print(str, f);
396  else
397    Wrapper_pretty_print(str, f);
398
399  Delete(str);
400}
401
402/* -----------------------------------------------------------------------------
403 * Wrapper_add_local()
404 *
405 * Adds a new local variable declaration to a function. Returns -1 if already
406 * present (which may or may not be okay to the caller).
407 * ----------------------------------------------------------------------------- */
408
409int Wrapper_add_local(Wrapper *w, const_String_or_char_ptr name, const_String_or_char_ptr decl) {
410  /* See if the local has already been declared */
411  if (Getattr(w->localh, name)) {
412    return -1;
413  }
414  Setattr(w->localh, name, decl);
415  Printf(w->locals, "%s;\n", decl);
416  return 0;
417}
418
419/* -----------------------------------------------------------------------------
420 * Wrapper_add_localv()
421 *
422 * Same as add_local(), but allows a NULL terminated list of strings to be
423 * used as a replacement for decl.   This saves the caller the trouble of having
424 * to manually construct the 'decl' string before calling.
425 * ----------------------------------------------------------------------------- */
426
427int Wrapper_add_localv(Wrapper *w, const_String_or_char_ptr name, ...) {
428  va_list ap;
429  int ret;
430  String *decl;
431  DOH *obj;
432  decl = NewStringEmpty();
433  va_start(ap, name);
434
435  obj = va_arg(ap, void *);
436  while (obj) {
437    Append(decl, obj);
438    Putc(' ', decl);
439    obj = va_arg(ap, void *);
440  }
441  va_end(ap);
442
443  ret = Wrapper_add_local(w, name, decl);
444  Delete(decl);
445  return ret;
446}
447
448/* -----------------------------------------------------------------------------
449 * Wrapper_check_local()
450 *
451 * Check to see if a local name has already been declared
452 * ----------------------------------------------------------------------------- */
453
454int Wrapper_check_local(Wrapper *w, const_String_or_char_ptr name) {
455  if (Getattr(w->localh, name)) {
456    return 1;
457  }
458  return 0;
459}
460
461/* -----------------------------------------------------------------------------
462 * Wrapper_new_local()
463 *
464 * Adds a new local variable with a guarantee that a unique local name will be
465 * used.  Returns the name that was actually selected.
466 * ----------------------------------------------------------------------------- */
467
468char *Wrapper_new_local(Wrapper *w, const_String_or_char_ptr name, const_String_or_char_ptr decl) {
469  int i;
470  String *nname = NewString(name);
471  String *ndecl = NewString(decl);
472  char *ret;
473
474  i = 0;
475
476  while (Wrapper_check_local(w, nname)) {
477    Clear(nname);
478    Printf(nname, "%s%d", name, i);
479    i++;
480  }
481  Replace(ndecl, name, nname, DOH_REPLACE_ID);
482  Setattr(w->localh, nname, ndecl);
483  Printf(w->locals, "%s;\n", ndecl);
484  ret = Char(nname);
485  Delete(nname);
486  Delete(ndecl);
487  return ret;			/* Note: nname should still exists in the w->localh hash */
488}
489
490
491/* -----------------------------------------------------------------------------
492 * Wrapper_new_localv()
493 *
494 * Same as add_local(), but allows a NULL terminated list of strings to be
495 * used as a replacement for decl.   This saves the caller the trouble of having
496 * to manually construct the 'decl' string before calling.
497 * ----------------------------------------------------------------------------- */
498
499char *Wrapper_new_localv(Wrapper *w, const_String_or_char_ptr name, ...) {
500  va_list ap;
501  char *ret;
502  String *decl;
503  DOH *obj;
504  decl = NewStringEmpty();
505  va_start(ap, name);
506
507  obj = va_arg(ap, void *);
508  while (obj) {
509    Append(decl, obj);
510    Putc(' ', decl);
511    obj = va_arg(ap, void *);
512  }
513  va_end(ap);
514
515  ret = Wrapper_new_local(w, name, decl);
516  Delete(decl);
517  return ret;
518}
519