blob: 3778066ce0bd9e4989422f3109a5f9177106c01e [file] [log] [blame]
/* -----------------------------------------------------------------------------
* See the LICENSE file for information on copyright, usage and redistribution
* of SWIG, and the README file for authors - http://www.swig.org/release.html.
*
* wrapfunc.c
*
* This file defines a object for creating wrapper functions. Primarily
* this is used for convenience since it allows pieces of a wrapper function
* to be created in a piecemeal manner.
* ----------------------------------------------------------------------------- */
char cvsroot_wrapfunc_c[] = "$Id$";
#include "swig.h"
#include <ctype.h>
static int Compact_mode = 0; /* set to 0 on default */
static int Max_line_size = 128;
/* -----------------------------------------------------------------------------
* NewWrapper()
*
* Create a new wrapper function object.
* ----------------------------------------------------------------------------- */
Wrapper *NewWrapper() {
Wrapper *w;
w = (Wrapper *) malloc(sizeof(Wrapper));
w->localh = NewHash();
w->locals = NewStringEmpty();
w->code = NewStringEmpty();
w->def = NewStringEmpty();
return w;
}
/* -----------------------------------------------------------------------------
* DelWrapper()
*
* Delete a wrapper function object.
* ----------------------------------------------------------------------------- */
void DelWrapper(Wrapper *w) {
Delete(w->localh);
Delete(w->locals);
Delete(w->code);
Delete(w->def);
free(w);
}
/* -----------------------------------------------------------------------------
* Wrapper_compact_print_mode_set()
*
* Set compact_mode.
* ----------------------------------------------------------------------------- */
void Wrapper_compact_print_mode_set(int flag) {
Compact_mode = flag;
}
/* -----------------------------------------------------------------------------
* Wrapper_pretty_print()
*
* Formats a wrapper function and fixes up the indentation.
* ----------------------------------------------------------------------------- */
void Wrapper_pretty_print(String *str, File *f) {
String *ts;
int level = 0;
int c, i;
int empty = 1;
int indent = 2;
int plevel = 0;
int label = 0;
ts = NewStringEmpty();
Seek(str, 0, SEEK_SET);
while ((c = Getc(str)) != EOF) {
if (c == '\"') {
Putc(c, ts);
while ((c = Getc(str)) != EOF) {
if (c == '\\') {
Putc(c, ts);
c = Getc(str);
}
Putc(c, ts);
if (c == '\"')
break;
}
empty = 0;
} else if (c == '\'') {
Putc(c, ts);
while ((c = Getc(str)) != EOF) {
if (c == '\\') {
Putc(c, ts);
c = Getc(str);
}
Putc(c, ts);
if (c == '\'')
break;
}
empty = 0;
} else if (c == ':') {
Putc(c, ts);
if ((c = Getc(str)) == '\n') {
if (!empty && !strchr(Char(ts), '?'))
label = 1;
}
Ungetc(c, str);
} else if (c == '(') {
Putc(c, ts);
plevel += indent;
empty = 0;
} else if (c == ')') {
Putc(c, ts);
plevel -= indent;
empty = 0;
} else if (c == '{') {
Putc(c, ts);
Putc('\n', ts);
for (i = 0; i < level; i++)
Putc(' ', f);
Printf(f, "%s", ts);
Clear(ts);
level += indent;
while ((c = Getc(str)) != EOF) {
if (!isspace(c)) {
Ungetc(c, str);
break;
}
}
empty = 0;
} else if (c == '}') {
if (!empty) {
Putc('\n', ts);
for (i = 0; i < level; i++)
Putc(' ', f);
Printf(f, "%s", ts);
Clear(ts);
}
level -= indent;
Putc(c, ts);
empty = 0;
} else if (c == '\n') {
Putc(c, ts);
empty = 0;
if (!empty) {
int slevel = level;
if (label && (slevel >= indent))
slevel -= indent;
if ((Char(ts))[0] != '#') {
for (i = 0; i < slevel; i++)
Putc(' ', f);
}
Printf(f, "%s", ts);
for (i = 0; i < plevel; i++)
Putc(' ', f);
}
Clear(ts);
label = 0;
empty = 1;
} else if (c == '/') {
empty = 0;
Putc(c, ts);
c = Getc(str);
if (c != EOF) {
Putc(c, ts);
if (c == '/') { /* C++ comment */
while ((c = Getc(str)) != EOF) {
if (c == '\n') {
Ungetc(c, str);
break;
}
Putc(c, ts);
}
} else if (c == '*') { /* C comment */
int endstar = 0;
while ((c = Getc(str)) != EOF) {
if (endstar && c == '/') { /* end of C comment */
Putc(c, ts);
break;
}
endstar = (c == '*');
Putc(c, ts);
if (c == '\n') { /* multi-line C comment. Could be improved slightly. */
for (i = 0; i < level; i++)
Putc(' ', ts);
}
}
}
}
} else {
if (!empty || !isspace(c)) {
Putc(c, ts);
empty = 0;
}
}
}
if (!empty)
Printf(f, "%s", ts);
Delete(ts);
Printf(f, "\n");
}
/* -----------------------------------------------------------------------------
* Wrapper_compact_print()
*
* Formats a wrapper function and fixes up the indentation.
* Print out in compact format, with Compact enabled.
* ----------------------------------------------------------------------------- */
void Wrapper_compact_print(String *str, File *f) {
String *ts, *tf; /*temp string & temp file */
int level = 0;
int c, i;
int empty = 1;
int indent = 2;
ts = NewStringEmpty();
tf = NewStringEmpty();
Seek(str, 0, SEEK_SET);
while ((c = Getc(str)) != EOF) {
if (c == '\"') { /* string 1 */
empty = 0;
Putc(c, ts);
while ((c = Getc(str)) != EOF) {
if (c == '\\') {
Putc(c, ts);
c = Getc(str);
}
Putc(c, ts);
if (c == '\"')
break;
}
} else if (c == '\'') { /* string 2 */
empty = 0;
Putc(c, ts);
while ((c = Getc(str)) != EOF) {
if (c == '\\') {
Putc(c, ts);
c = Getc(str);
}
Putc(c, ts);
if (c == '\'')
break;
}
} else if (c == '{') { /* start of {...} */
empty = 0;
Putc(c, ts);
if (Len(tf) == 0) {
for (i = 0; i < level; i++)
Putc(' ', tf);
} else if ((Len(tf) + Len(ts)) < Max_line_size) {
Putc(' ', tf);
} else {
Putc('\n', tf);
Printf(f, "%s", tf);
Clear(tf);
for (i = 0; i < level; i++)
Putc(' ', tf);
}
Append(tf, ts);
Clear(ts);
level += indent;
while ((c = Getc(str)) != EOF) {
if (!isspace(c)) {
Ungetc(c, str);
break;
}
}
} else if (c == '}') { /* end of {...} */
empty = 0;
if (Len(tf) == 0) {
for (i = 0; i < level; i++)
Putc(' ', tf);
} else if ((Len(tf) + Len(ts)) < Max_line_size) {
Putc(' ', tf);
} else {
Putc('\n', tf);
Printf(f, "%s", tf);
Clear(tf);
for (i = 0; i < level; i++)
Putc(' ', tf);
}
Append(tf, ts);
Putc(c, tf);
Clear(ts);
level -= indent;
} else if (c == '\n') { /* line end */
while ((c = Getc(str)) != EOF) {
if (!isspace(c))
break;
}
if (c == '#') {
Putc('\n', ts);
} else if (c == '}') {
Putc(' ', ts);
} else if ((c != EOF) || (Len(ts) != 0)) {
if (Len(tf) == 0) {
for (i = 0; i < level; i++)
Putc(' ', tf);
} else if ((Len(tf) + Len(ts)) < Max_line_size) {
Putc(' ', tf);
} else {
Putc('\n', tf);
Printf(f, "%s", tf);
Clear(tf);
for (i = 0; i < level; i++)
Putc(' ', tf);
}
Append(tf, ts);
Clear(ts);
}
Ungetc(c, str);
empty = 1;
} else if (c == '/') { /* comment */
empty = 0;
c = Getc(str);
if (c != EOF) {
if (c == '/') { /* C++ comment */
while ((c = Getc(str)) != EOF) {
if (c == '\n') {
Ungetc(c, str);
break;
}
}
} else if (c == '*') { /* C comment */
int endstar = 0;
while ((c = Getc(str)) != EOF) {
if (endstar && c == '/') { /* end of C comment */
break;
}
endstar = (c == '*');
}
} else {
Putc('/', ts);
Putc(c, ts);
}
}
} else if (c == '#') { /* Preprocessor line */
Putc('#', ts);
while ((c = Getc(str)) != EOF) {
Putc(c, ts);
if (c == '\\') { /* Continued line of the same PP */
c = Getc(str);
if (c == '\n')
Putc(c, ts);
else
Ungetc(c, str);
} else if (c == '\n')
break;
}
if (!empty) {
Append(tf, "\n");
}
Append(tf, ts);
Printf(f, "%s", tf);
Clear(tf);
Clear(ts);
for (i = 0; i < level; i++)
Putc(' ', tf);
empty = 1;
} else {
if (!empty || !isspace(c)) {
Putc(c, ts);
empty = 0;
}
}
}
if (!empty) {
Append(tf, ts);
}
if (Len(tf) != 0)
Printf(f, "%s", tf);
Delete(ts);
Delete(tf);
Printf(f, "\n");
}
/* -----------------------------------------------------------------------------
* Wrapper_print()
*
* Print out a wrapper function. Does pretty or compact printing as well.
* ----------------------------------------------------------------------------- */
void Wrapper_print(Wrapper *w, File *f) {
String *str;
str = NewStringEmpty();
Printf(str, "%s\n", w->def);
Printf(str, "%s\n", w->locals);
Printf(str, "%s\n", w->code);
if (Compact_mode == 1)
Wrapper_compact_print(str, f);
else
Wrapper_pretty_print(str, f);
Delete(str);
}
/* -----------------------------------------------------------------------------
* Wrapper_add_local()
*
* Adds a new local variable declaration to a function. Returns -1 if already
* present (which may or may not be okay to the caller).
* ----------------------------------------------------------------------------- */
int Wrapper_add_local(Wrapper *w, const String_or_char *name, const String_or_char *decl) {
/* See if the local has already been declared */
if (Getattr(w->localh, name)) {
return -1;
}
Setattr(w->localh, name, decl);
Printf(w->locals, "%s;\n", decl);
return 0;
}
/* -----------------------------------------------------------------------------
* Wrapper_add_localv()
*
* Same as add_local(), but allows a NULL terminated list of strings to be
* used as a replacement for decl. This saves the caller the trouble of having
* to manually construct the 'decl' string before calling.
* ----------------------------------------------------------------------------- */
int Wrapper_add_localv(Wrapper *w, const String_or_char *name, ...) {
va_list ap;
int ret;
String *decl;
DOH *obj;
decl = NewStringEmpty();
va_start(ap, name);
obj = va_arg(ap, void *);
while (obj) {
Append(decl, obj);
Putc(' ', decl);
obj = va_arg(ap, void *);
}
va_end(ap);
ret = Wrapper_add_local(w, name, decl);
Delete(decl);
return ret;
}
/* -----------------------------------------------------------------------------
* Wrapper_check_local()
*
* Check to see if a local name has already been declared
* ----------------------------------------------------------------------------- */
int Wrapper_check_local(Wrapper *w, const String_or_char *name) {
if (Getattr(w->localh, name)) {
return 1;
}
return 0;
}
/* -----------------------------------------------------------------------------
* Wrapper_new_local()
*
* Adds a new local variable with a guarantee that a unique local name will be
* used. Returns the name that was actually selected.
* ----------------------------------------------------------------------------- */
char *Wrapper_new_local(Wrapper *w, const String_or_char *name, const String_or_char *decl) {
int i;
String *nname = NewString(name);
String *ndecl = NewString(decl);
char *ret;
i = 0;
while (Wrapper_check_local(w, nname)) {
Clear(nname);
Printf(nname, "%s%d", name, i);
i++;
}
Replace(ndecl, name, nname, DOH_REPLACE_ID);
Setattr(w->localh, nname, ndecl);
Printf(w->locals, "%s;\n", ndecl);
ret = Char(nname);
Delete(nname);
Delete(ndecl);
return ret; /* Note: nname should still exists in the w->localh hash */
}
/* -----------------------------------------------------------------------------
* Wrapper_new_localv()
*
* Same as add_local(), but allows a NULL terminated list of strings to be
* used as a replacement for decl. This saves the caller the trouble of having
* to manually construct the 'decl' string before calling.
* ----------------------------------------------------------------------------- */
char *Wrapper_new_localv(Wrapper *w, const String_or_char *name, ...) {
va_list ap;
char *ret;
String *decl;
DOH *obj;
decl = NewStringEmpty();
va_start(ap, name);
obj = va_arg(ap, void *);
while (obj) {
Append(decl, obj);
Putc(' ', decl);
obj = va_arg(ap, void *);
}
va_end(ap);
ret = Wrapper_new_local(w, name, decl);
Delete(decl);
return ret;
}