Exit() is a wrapper for exit() by default, but SetExitHandler() allows specifying a function to call instead. This means that failures within DOH (e.g. Malloc() failing due to lack of memory) will now perform cleanup such as removing output files. This commit also cleans up exit statuses so SWIG should now reliably exit with status 0 if the run was successful and status 1 if there was an error (or a warning and -Werror was in effect). Previously in some situations SWIG would try to exit with the status set to the number of errors encountered, but that's problematic - for example if there were 256 errors this would result in exit status 0 on most platforms. Also some error statuses have special meanings e.g. those defined by <sysexits.h>. Also SWIG/Javascript tried to exit with status -1 in a few places (which typically results in exit status 255).
1538 lines
40 KiB
C
1538 lines
40 KiB
C
/* -----------------------------------------------------------------------------
|
|
* This file is part of SWIG, which is licensed as a whole under version 3
|
|
* (or any later version) of the GNU General Public License. Some additional
|
|
* terms also apply to certain portions of SWIG. The full details of the SWIG
|
|
* license and copyrights can be found in the LICENSE and COPYRIGHT files
|
|
* included with the SWIG source code as distributed by the SWIG developers
|
|
* and at http://www.swig.org/legal.html.
|
|
*
|
|
* misc.c
|
|
*
|
|
* Miscellaneous functions that don't really fit anywhere else.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
#include "swig.h"
|
|
#include <errno.h>
|
|
#include <ctype.h>
|
|
#include <limits.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
|
|
#ifdef _WIN32
|
|
#include <direct.h>
|
|
#ifndef S_ISDIR
|
|
#define S_ISDIR(mode) (((mode) & S_IFDIR) == S_IFDIR)
|
|
#endif
|
|
#endif
|
|
|
|
static char *fake_version = 0;
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_copy_string()
|
|
*
|
|
* Duplicate a NULL-terminate string given as a char *.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
char *Swig_copy_string(const char *s) {
|
|
char *c = 0;
|
|
if (s) {
|
|
c = (char *) Malloc(strlen(s) + 1);
|
|
strcpy(c, s);
|
|
}
|
|
return c;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_set_fakeversion()
|
|
*
|
|
* Version string override
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void Swig_set_fakeversion(const char *version) {
|
|
fake_version = Swig_copy_string(version);
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_package_version()
|
|
*
|
|
* Return the package string containing the version number
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
const char *Swig_package_version(void) {
|
|
return fake_version ? fake_version : PACKAGE_VERSION;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_banner()
|
|
*
|
|
* Emits the SWIG identifying banner for the C/C++ wrapper file.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void Swig_banner(File *f) {
|
|
Printf(f, "/* ----------------------------------------------------------------------------\n\
|
|
* This file was automatically generated by SWIG (http://www.swig.org).\n\
|
|
* Version %s\n\
|
|
*\n\
|
|
* This file is not intended to be easily readable and contains a number of\n\
|
|
* coding conventions designed to improve portability and efficiency. Do not make\n\
|
|
* changes to this file unless you know what you are doing--modify the SWIG\n\
|
|
* interface file instead.\n", Swig_package_version());
|
|
/* String too long for ISO compliance */
|
|
Printf(f, " * ----------------------------------------------------------------------------- */\n");
|
|
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_banner_target_lang()
|
|
*
|
|
* Emits a SWIG identifying banner in the target language
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void Swig_banner_target_lang(File *f, const_String_or_char_ptr commentchar) {
|
|
Printf(f, "%s This file was automatically generated by SWIG (http://www.swig.org).\n", commentchar);
|
|
Printf(f, "%s Version %s\n", commentchar, Swig_package_version());
|
|
Printf(f, "%s\n", commentchar);
|
|
Printf(f, "%s Do not make changes to this file unless you know what you are doing--modify\n", commentchar);
|
|
Printf(f, "%s the SWIG interface file instead.\n", commentchar);
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_strip_c_comments()
|
|
*
|
|
* Return a new string with C comments stripped from the input string. NULL is
|
|
* returned if there aren't any comments.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
String *Swig_strip_c_comments(const String *s) {
|
|
const char *c = Char(s);
|
|
const char *comment_begin = 0;
|
|
const char *comment_end = 0;
|
|
String *stripped = 0;
|
|
|
|
while (*c) {
|
|
if (!comment_begin && *c == '/') {
|
|
++c;
|
|
if (!*c)
|
|
break;
|
|
if (*c == '*')
|
|
comment_begin = c-1;
|
|
} else if (comment_begin && !comment_end && *c == '*') {
|
|
++c;
|
|
if (*c == '/') {
|
|
comment_end = c;
|
|
break;
|
|
}
|
|
}
|
|
++c;
|
|
}
|
|
|
|
if (comment_begin && comment_end) {
|
|
int size = (int)(comment_begin - Char(s));
|
|
String *stripmore = 0;
|
|
stripped = NewStringWithSize(s, size);
|
|
Printv(stripped, comment_end + 1, NIL);
|
|
do {
|
|
stripmore = Swig_strip_c_comments(stripped);
|
|
if (stripmore) {
|
|
Delete(stripped);
|
|
stripped = stripmore;
|
|
}
|
|
} while (stripmore);
|
|
}
|
|
return stripped;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* is_directory()
|
|
* ----------------------------------------------------------------------------- */
|
|
static int is_directory(String *directory) {
|
|
int last = Len(directory) - 1;
|
|
int statres;
|
|
struct stat st;
|
|
char *dir = Char(directory);
|
|
if (dir[last] == SWIG_FILE_DELIMITER[0]) {
|
|
/* remove trailing slash - can cause S_ISDIR to fail on Windows, at least */
|
|
dir[last] = 0;
|
|
statres = stat(dir, &st);
|
|
dir[last] = SWIG_FILE_DELIMITER[0];
|
|
} else {
|
|
statres = stat(dir, &st);
|
|
}
|
|
return (statres == 0 && S_ISDIR(st.st_mode));
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_new_subdirectory()
|
|
*
|
|
* Create the subdirectory only if the basedirectory already exists as a directory.
|
|
* basedirectory can be empty to indicate current directory but not NULL.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
String *Swig_new_subdirectory(String *basedirectory, String *subdirectory) {
|
|
String *error = 0;
|
|
int current_directory = Len(basedirectory) == 0;
|
|
|
|
if (current_directory || is_directory(basedirectory)) {
|
|
Iterator it;
|
|
String *dir = NewString(basedirectory);
|
|
List *subdirs = Split(subdirectory, SWIG_FILE_DELIMITER[0], INT_MAX);
|
|
|
|
for (it = First(subdirs); it.item; it = Next(it)) {
|
|
int result;
|
|
String *subdirectory = it.item;
|
|
Printf(dir, "%s", subdirectory);
|
|
#ifdef _WIN32
|
|
result = _mkdir(Char(dir));
|
|
#else
|
|
result = mkdir(Char(dir), 0777);
|
|
#endif
|
|
if (result != 0 && errno != EEXIST) {
|
|
error = NewStringf("Cannot create directory %s: %s", dir, strerror(errno));
|
|
break;
|
|
}
|
|
if (!is_directory(dir)) {
|
|
error = NewStringf("Cannot create directory %s: it may already exist but not be a directory", dir);
|
|
break;
|
|
}
|
|
Printf(dir, SWIG_FILE_DELIMITER);
|
|
}
|
|
} else {
|
|
error = NewStringf("Cannot create subdirectory %s under the base directory %s. Either the base does not exist as a directory or it is not readable.", subdirectory, basedirectory);
|
|
}
|
|
return error;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_filename_correct()
|
|
*
|
|
* Corrects filename paths by removing duplicate delimiters and on non-unix
|
|
* systems use the correct delimiter across the whole name.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void Swig_filename_correct(String *filename) {
|
|
int network_path = 0;
|
|
if (Len(filename) >= 2) {
|
|
const char *fname = Char(filename);
|
|
if (fname[0] == '\\' && fname[1] == '\\')
|
|
network_path = 1;
|
|
if (fname[0] == '/' && fname[1] == '/')
|
|
network_path = 1;
|
|
}
|
|
#if defined(_WIN32) || defined(MACSWIG)
|
|
/* accept Unix path separator on non-Unix systems */
|
|
Replaceall(filename, "/", SWIG_FILE_DELIMITER);
|
|
#endif
|
|
#if defined(__CYGWIN__)
|
|
/* accept Windows path separator in addition to Unix path separator */
|
|
Replaceall(filename, "\\", SWIG_FILE_DELIMITER);
|
|
#endif
|
|
/* remove all duplicate file name delimiters */
|
|
while (Replaceall(filename, SWIG_FILE_DELIMITER SWIG_FILE_DELIMITER, SWIG_FILE_DELIMITER)) {
|
|
}
|
|
/* Network paths can start with a double slash on Windows - unremove the duplicate slash we just removed */
|
|
if (network_path)
|
|
Insert(filename, 0, SWIG_FILE_DELIMITER);
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_filename_escape()
|
|
*
|
|
* Escapes backslashes in filename - for Windows
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
String *Swig_filename_escape(String *filename) {
|
|
String *adjusted_filename = Copy(filename);
|
|
Swig_filename_correct(adjusted_filename);
|
|
#if defined(_WIN32) /* Note not on Cygwin else filename is displayed with double '/' */
|
|
Replaceall(adjusted_filename, "\\", "\\\\");
|
|
#endif
|
|
return adjusted_filename;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_filename_escape()
|
|
*
|
|
* Escapes spaces in filename - for Makefiles
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
String *Swig_filename_escape_space(String *filename) {
|
|
String *adjusted_filename = Copy(filename);
|
|
Swig_filename_correct(adjusted_filename);
|
|
Replaceall(adjusted_filename, " ", "\\ ");
|
|
return adjusted_filename;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_filename_unescape()
|
|
*
|
|
* Remove double backslash escaping in filename - for Windows
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void Swig_filename_unescape(String *filename) {
|
|
(void)filename;
|
|
#if defined(_WIN32)
|
|
Replaceall(filename, "\\\\", "\\");
|
|
#endif
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_storage_isextern()
|
|
*
|
|
* Determine if the storage class specifier is extern (but not externc)
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
int Swig_storage_isextern(Node *n) {
|
|
const String *storage = Getattr(n, "storage");
|
|
return storage ? Strcmp(storage, "extern") == 0 || Strncmp(storage, "extern ", 7) == 0 : 0;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_storage_isexternc()
|
|
*
|
|
* Determine if the storage class specifier is externc (but not plain extern)
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
int Swig_storage_isexternc(Node *n) {
|
|
const String *storage = Getattr(n, "storage");
|
|
return storage ? Strcmp(storage, "externc") == 0 || Strncmp(storage, "externc ", 8) == 0 : 0;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_storage_isstatic_custom()
|
|
*
|
|
* Determine if the storage class specifier is static
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
int Swig_storage_isstatic_custom(Node *n, const_String_or_char_ptr storage_name) {
|
|
const String *storage = Getattr(n, storage_name);
|
|
return storage ? Strncmp(storage, "static", 6) == 0 : 0;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_storage_isstatic()
|
|
*
|
|
* Determine if the storage class specifier is static
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
int Swig_storage_isstatic(Node *n) {
|
|
return Swig_storage_isstatic_custom(n, "storage");
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_string_escape()
|
|
*
|
|
* Takes a string object and produces a string with escape codes added to it.
|
|
* Octal escaping is used.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
String *Swig_string_escape(String *s) {
|
|
String *ns;
|
|
int c;
|
|
ns = NewStringEmpty();
|
|
|
|
while ((c = Getc(s)) != EOF) {
|
|
if (c == '\n') {
|
|
Printf(ns, "\\n");
|
|
} else if (c == '\r') {
|
|
Printf(ns, "\\r");
|
|
} else if (c == '\t') {
|
|
Printf(ns, "\\t");
|
|
} else if (c == '\\') {
|
|
Printf(ns, "\\\\");
|
|
} else if (c == '\'') {
|
|
Printf(ns, "\\'");
|
|
} else if (c == '\"') {
|
|
Printf(ns, "\\\"");
|
|
} else if (c == ' ') {
|
|
Putc(c, ns);
|
|
} else if (!isgraph(c)) {
|
|
if (c < 0)
|
|
c += UCHAR_MAX + 1;
|
|
Printf(ns, "\\%o", c);
|
|
} else {
|
|
Putc(c, ns);
|
|
}
|
|
}
|
|
return ns;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_string_hexescape()
|
|
*
|
|
* Takes a string object and produces a string with escape codes added to it.
|
|
* Hex escaping is used.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
String *Swig_string_hexescape(String *s) {
|
|
String *ns;
|
|
int c;
|
|
ns = NewStringEmpty();
|
|
|
|
while ((c = Getc(s)) != EOF) {
|
|
if (c == '\n') {
|
|
Printf(ns, "\\n");
|
|
} else if (c == '\r') {
|
|
Printf(ns, "\\r");
|
|
} else if (c == '\t') {
|
|
Printf(ns, "\\t");
|
|
} else if (c == '\\') {
|
|
Printf(ns, "\\\\");
|
|
} else if (c == '\'') {
|
|
Printf(ns, "\\'");
|
|
} else if (c == '\"') {
|
|
Printf(ns, "\\\"");
|
|
} else if (c == ' ') {
|
|
Putc(c, ns);
|
|
} else if (!isgraph(c)) {
|
|
if (c < 0)
|
|
c += UCHAR_MAX + 1;
|
|
Printf(ns, "\\x%X", c);
|
|
} else {
|
|
Putc(c, ns);
|
|
}
|
|
}
|
|
return ns;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_string_upper()
|
|
*
|
|
* Takes a string object and returns a copy that is uppercase
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
String *Swig_string_upper(String *s) {
|
|
String *ns;
|
|
int c;
|
|
ns = NewStringEmpty();
|
|
|
|
Seek(s, 0, SEEK_SET);
|
|
while ((c = Getc(s)) != EOF) {
|
|
Putc(toupper(c), ns);
|
|
}
|
|
return ns;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_string_lower()
|
|
*
|
|
* Takes a string object and returns a copy that is lowercase
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
String *Swig_string_lower(String *s) {
|
|
String *ns;
|
|
int c;
|
|
ns = NewStringEmpty();
|
|
|
|
Seek(s, 0, SEEK_SET);
|
|
while ((c = Getc(s)) != EOF) {
|
|
Putc(tolower(c), ns);
|
|
}
|
|
return ns;
|
|
}
|
|
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_string_title()
|
|
*
|
|
* Takes a string object and returns a copy that is lowercase with first letter
|
|
* capitalized
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
String *Swig_string_title(String *s) {
|
|
String *ns;
|
|
int first = 1;
|
|
int c;
|
|
ns = NewStringEmpty();
|
|
|
|
Seek(s, 0, SEEK_SET);
|
|
while ((c = Getc(s)) != EOF) {
|
|
Putc(first ? toupper(c) : tolower(c), ns);
|
|
first = 0;
|
|
}
|
|
return ns;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_string_ccase()
|
|
*
|
|
* Takes a string object and returns a copy that is lowercase with the first
|
|
* letter capitalized and the one following '_', which are removed.
|
|
*
|
|
* camel_case -> CamelCase
|
|
* camelCase -> CamelCase
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
String *Swig_string_ccase(String *s) {
|
|
String *ns;
|
|
int first = 1;
|
|
int c;
|
|
ns = NewStringEmpty();
|
|
|
|
Seek(s, 0, SEEK_SET);
|
|
while ((c = Getc(s)) != EOF) {
|
|
if (c == '_') {
|
|
first = 1;
|
|
continue;
|
|
}
|
|
Putc(first ? toupper(c) : c, ns);
|
|
first = 0;
|
|
}
|
|
return ns;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_string_lccase()
|
|
*
|
|
* Takes a string object and returns a copy with the character after
|
|
* each '_' capitalised, and the '_' removed. The first character is
|
|
* also forced to lowercase.
|
|
*
|
|
* camel_case -> camelCase
|
|
* CamelCase -> camelCase
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
String *Swig_string_lccase(String *s) {
|
|
String *ns;
|
|
int first = 1;
|
|
int after_underscore = 0;
|
|
int c;
|
|
ns = NewStringEmpty();
|
|
|
|
Seek(s, 0, SEEK_SET);
|
|
while ((c = Getc(s)) != EOF) {
|
|
if (c == '_') {
|
|
after_underscore = 1;
|
|
continue;
|
|
}
|
|
if (first) {
|
|
Putc(tolower(c), ns);
|
|
first = 0;
|
|
} else {
|
|
Putc(after_underscore ? toupper(c) : c, ns);
|
|
}
|
|
after_underscore = 0;
|
|
}
|
|
return ns;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_string_ucase()
|
|
*
|
|
* This is the reverse case of ccase, ie
|
|
*
|
|
* CamelCase -> camel_case
|
|
* get2D -> get_2d
|
|
* asFloat2 -> as_float2
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
String *Swig_string_ucase(String *s) {
|
|
String *ns;
|
|
int c;
|
|
int lastC = 0;
|
|
int nextC = 0;
|
|
int underscore = 0;
|
|
ns = NewStringEmpty();
|
|
|
|
/* We insert a underscore when:
|
|
1. Lower case char followed by upper case char
|
|
getFoo > get_foo; getFOo > get_foo; GETFOO > getfoo
|
|
2. Number preceded by char and not end of string
|
|
get2D > get_2d; get22D > get_22d; GET2D > get_2d
|
|
but:
|
|
asFloat2 > as_float2
|
|
*/
|
|
|
|
Seek(s, 0, SEEK_SET);
|
|
|
|
while ((c = Getc(s)) != EOF) {
|
|
nextC = Getc(s); Ungetc(nextC, s);
|
|
if (isdigit(c) && isalpha(lastC) && nextC != EOF)
|
|
underscore = 1;
|
|
else if (isupper(c) && isalpha(lastC) && !isupper(lastC))
|
|
underscore = 1;
|
|
|
|
lastC = c;
|
|
|
|
if (underscore) {
|
|
Putc('_', ns);
|
|
underscore = 0;
|
|
}
|
|
|
|
Putc(tolower(c), ns);
|
|
}
|
|
return ns;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_string_first_upper()
|
|
*
|
|
* Make the first character in the string uppercase, leave all the
|
|
* rest the same. This is used by the Ruby module to provide backwards
|
|
* compatibility with the old way of naming classes and constants. For
|
|
* more info see the Ruby documentation.
|
|
*
|
|
* firstUpper -> FirstUpper
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
String *Swig_string_first_upper(String *s) {
|
|
String *ns = NewStringEmpty();
|
|
char *cs = Char(s);
|
|
if (cs && cs[0] != 0) {
|
|
Putc(toupper((int)cs[0]), ns);
|
|
Append(ns, cs + 1);
|
|
}
|
|
return ns;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_string_first_lower()
|
|
*
|
|
* Make the first character in the string lowercase, leave all the
|
|
* rest the same. This is used by the Ruby module to provide backwards
|
|
* compatibility with the old way of naming classes and constants. For
|
|
* more info see the Ruby documentation.
|
|
*
|
|
* firstLower -> FirstLower
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
String *Swig_string_first_lower(String *s) {
|
|
String *ns = NewStringEmpty();
|
|
char *cs = Char(s);
|
|
if (cs && cs[0] != 0) {
|
|
Putc(tolower((int)cs[0]), ns);
|
|
Append(ns, cs + 1);
|
|
}
|
|
return ns;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_string_schemify()
|
|
*
|
|
* Replace underscores with dashes, to make identifiers look nice to Schemers.
|
|
*
|
|
* under_scores -> under-scores
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
String *Swig_string_schemify(String *s) {
|
|
String *ns = NewString(s);
|
|
Replaceall(ns, "_", "-");
|
|
return ns;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_string_typecode()
|
|
*
|
|
* Takes a string with possible type-escapes in it and replaces them with
|
|
* real C datatypes.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
String *Swig_string_typecode(String *s) {
|
|
String *ns;
|
|
int c;
|
|
String *tc;
|
|
ns = NewStringEmpty();
|
|
while ((c = Getc(s)) != EOF) {
|
|
if (c == '`') {
|
|
String *str = 0;
|
|
tc = NewStringEmpty();
|
|
while ((c = Getc(s)) != EOF) {
|
|
if (c == '`')
|
|
break;
|
|
Putc(c, tc);
|
|
}
|
|
str = SwigType_str(tc, 0);
|
|
Append(ns, str);
|
|
Delete(str);
|
|
} else {
|
|
Putc(c, ns);
|
|
if (c == '\'') {
|
|
while ((c = Getc(s)) != EOF) {
|
|
Putc(c, ns);
|
|
if (c == '\'')
|
|
break;
|
|
if (c == '\\') {
|
|
c = Getc(s);
|
|
Putc(c, ns);
|
|
}
|
|
}
|
|
} else if (c == '\"') {
|
|
while ((c = Getc(s)) != EOF) {
|
|
Putc(c, ns);
|
|
if (c == '\"')
|
|
break;
|
|
if (c == '\\') {
|
|
c = Getc(s);
|
|
Putc(c, ns);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ns;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_string_mangle()
|
|
*
|
|
* Take a string and mangle it by stripping all non-valid C identifier
|
|
* characters.
|
|
*
|
|
* This routine skips unnecessary blank spaces, therefore mangling
|
|
* 'char *' and 'char*', 'std::pair<int, int >' and
|
|
* 'std::pair<int,int>', produce the same result.
|
|
*
|
|
* However, note that 'long long' and 'long_long' produce different
|
|
* mangled strings.
|
|
*
|
|
* The mangling method still is not 'perfect', for example std::pair and
|
|
* std_pair return the same mangling. This is just a little better
|
|
* than before, but it seems to be enough for most of the purposes.
|
|
*
|
|
* Having a perfect mangling will break some examples and code which
|
|
* assume, for example, that A::get_value will be mangled as
|
|
* A_get_value.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
String *Swig_string_mangle(const String *s) {
|
|
#if 0
|
|
/* old mangling, not suitable for using in macros */
|
|
String *t = Copy(s);
|
|
char *c = Char(t);
|
|
while (*c) {
|
|
if (!isalnum(*c))
|
|
*c = '_';
|
|
c++;
|
|
}
|
|
return t;
|
|
#else
|
|
String *result = NewStringEmpty();
|
|
int space = 0;
|
|
int state = 0;
|
|
char *pc, *cb;
|
|
String *b = Copy(s);
|
|
if (SwigType_istemplate(b)) {
|
|
String *st = Swig_symbol_template_deftype(b, 0);
|
|
String *sq = Swig_symbol_type_qualify(st, 0);
|
|
String *t = SwigType_namestr(sq);
|
|
Delete(st);
|
|
Delete(sq);
|
|
Delete(b);
|
|
b = t;
|
|
}
|
|
pc = cb = Char(b);
|
|
while (*pc) {
|
|
char c = *pc;
|
|
if (isalnum((int) c) || (c == '_')) {
|
|
state = 1;
|
|
if (space && (space == state)) {
|
|
Append(result, "_SS_");
|
|
}
|
|
space = 0;
|
|
Printf(result, "%c", (int) c);
|
|
|
|
} else {
|
|
if (isspace((int) c)) {
|
|
space = state;
|
|
++pc;
|
|
continue;
|
|
} else {
|
|
state = 3;
|
|
space = 0;
|
|
}
|
|
switch (c) {
|
|
case '.':
|
|
if ((cb != pc) && (*(pc - 1) == 'p')) {
|
|
Append(result, "_");
|
|
++pc;
|
|
continue;
|
|
} else {
|
|
c = 'f';
|
|
}
|
|
break;
|
|
case ':':
|
|
if (*(pc + 1) == ':') {
|
|
Append(result, "_");
|
|
++pc;
|
|
++pc;
|
|
continue;
|
|
}
|
|
break;
|
|
case '*':
|
|
c = 'm';
|
|
break;
|
|
case '&':
|
|
c = 'A';
|
|
break;
|
|
case '<':
|
|
c = 'l';
|
|
break;
|
|
case '>':
|
|
c = 'g';
|
|
break;
|
|
case '=':
|
|
c = 'e';
|
|
break;
|
|
case ',':
|
|
c = 'c';
|
|
break;
|
|
case '(':
|
|
c = 'p';
|
|
break;
|
|
case ')':
|
|
c = 'P';
|
|
break;
|
|
case '[':
|
|
c = 'b';
|
|
break;
|
|
case ']':
|
|
c = 'B';
|
|
break;
|
|
case '^':
|
|
c = 'x';
|
|
break;
|
|
case '|':
|
|
c = 'o';
|
|
break;
|
|
case '~':
|
|
c = 'n';
|
|
break;
|
|
case '!':
|
|
c = 'N';
|
|
break;
|
|
case '%':
|
|
c = 'M';
|
|
break;
|
|
case '?':
|
|
c = 'q';
|
|
break;
|
|
case '+':
|
|
c = 'a';
|
|
break;
|
|
case '-':
|
|
c = 's';
|
|
break;
|
|
case '/':
|
|
c = 'd';
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (isalpha((int) c)) {
|
|
Printf(result, "_S%c_", (int) c);
|
|
} else {
|
|
Printf(result, "_S%02X_", (int) c);
|
|
}
|
|
}
|
|
++pc;
|
|
}
|
|
Delete(b);
|
|
return result;
|
|
#endif
|
|
}
|
|
|
|
String *Swig_string_emangle(String *s) {
|
|
return Swig_string_mangle(s);
|
|
}
|
|
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_scopename_split()
|
|
*
|
|
* Take a qualified name like "A::B::C" and splits off the last name.
|
|
* In this case, returns "C" as last and "A::B" as prefix.
|
|
* Always returns non NULL for last, but prefix may be NULL if there is no prefix.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void Swig_scopename_split(const String *s, String **rprefix, String **rlast) {
|
|
char *tmp = Char(s);
|
|
char *c = tmp;
|
|
char *cc = c;
|
|
char *co = 0;
|
|
if (!strstr(c, "::")) {
|
|
*rprefix = 0;
|
|
*rlast = Copy(s);
|
|
}
|
|
|
|
co = strstr(cc, "operator ");
|
|
if (co) {
|
|
if (co == cc) {
|
|
*rprefix = 0;
|
|
*rlast = Copy(s);
|
|
return;
|
|
} else {
|
|
*rprefix = NewStringWithSize(cc, (int)(co - cc - 2));
|
|
*rlast = NewString(co);
|
|
return;
|
|
}
|
|
}
|
|
while (*c) {
|
|
if ((*c == ':') && (*(c + 1) == ':')) {
|
|
cc = c;
|
|
c += 2;
|
|
} else {
|
|
if (*c == '<') {
|
|
int level = 1;
|
|
c++;
|
|
while (*c && level) {
|
|
if (*c == '<')
|
|
level++;
|
|
if (*c == '>')
|
|
level--;
|
|
c++;
|
|
}
|
|
} else {
|
|
c++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (cc != tmp) {
|
|
*rprefix = NewStringWithSize(tmp, (int)(cc - tmp));
|
|
*rlast = NewString(cc + 2);
|
|
return;
|
|
} else {
|
|
*rprefix = 0;
|
|
*rlast = Copy(s);
|
|
}
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_scopename_prefix()
|
|
*
|
|
* Take a qualified name like "A::B::C" and return the scope name.
|
|
* In this case, "A::B". Returns NULL if there is no base.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
String *Swig_scopename_prefix(const String *s) {
|
|
char *tmp = Char(s);
|
|
char *c = tmp;
|
|
char *cc = c;
|
|
char *co = 0;
|
|
if (!strstr(c, "::"))
|
|
return 0;
|
|
co = strstr(cc, "operator ");
|
|
|
|
if (co) {
|
|
if (co == cc) {
|
|
return 0;
|
|
} else {
|
|
String *prefix = NewStringWithSize(cc, (int)(co - cc - 2));
|
|
return prefix;
|
|
}
|
|
}
|
|
while (*c) {
|
|
if ((*c == ':') && (*(c + 1) == ':')) {
|
|
cc = c;
|
|
c += 2;
|
|
} else {
|
|
if (*c == '<') {
|
|
int level = 1;
|
|
c++;
|
|
while (*c && level) {
|
|
if (*c == '<')
|
|
level++;
|
|
if (*c == '>')
|
|
level--;
|
|
c++;
|
|
}
|
|
} else {
|
|
c++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (cc != tmp) {
|
|
return NewStringWithSize(tmp, (int)(cc - tmp));
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_scopename_last()
|
|
*
|
|
* Take a qualified name like "A::B::C" and returns the last. In this
|
|
* case, "C".
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
String *Swig_scopename_last(const String *s) {
|
|
char *tmp = Char(s);
|
|
char *c = tmp;
|
|
char *cc = c;
|
|
char *co = 0;
|
|
if (!strstr(c, "::"))
|
|
return NewString(s);
|
|
|
|
co = strstr(cc, "operator ");
|
|
if (co) {
|
|
return NewString(co);
|
|
}
|
|
|
|
|
|
while (*c) {
|
|
if ((*c == ':') && (*(c + 1) == ':')) {
|
|
c += 2;
|
|
cc = c;
|
|
} else {
|
|
if (*c == '<') {
|
|
int level = 1;
|
|
c++;
|
|
while (*c && level) {
|
|
if (*c == '<')
|
|
level++;
|
|
if (*c == '>')
|
|
level--;
|
|
c++;
|
|
}
|
|
} else {
|
|
c++;
|
|
}
|
|
}
|
|
}
|
|
return NewString(cc);
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_scopename_first()
|
|
*
|
|
* Take a qualified name like "A::B::C" and returns the first scope name.
|
|
* In this case, "A". Returns NULL if there is no base.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
String *Swig_scopename_first(const String *s) {
|
|
char *tmp = Char(s);
|
|
char *c = tmp;
|
|
char *co = 0;
|
|
if (!strstr(c, "::"))
|
|
return 0;
|
|
|
|
co = strstr(c, "operator ");
|
|
if (co) {
|
|
if (co == c) {
|
|
return 0;
|
|
}
|
|
} else {
|
|
co = c + Len(s);
|
|
}
|
|
|
|
while (*c && (c != co)) {
|
|
if ((*c == ':') && (*(c + 1) == ':')) {
|
|
break;
|
|
} else {
|
|
if (*c == '<') {
|
|
int level = 1;
|
|
c++;
|
|
while (*c && level) {
|
|
if (*c == '<')
|
|
level++;
|
|
if (*c == '>')
|
|
level--;
|
|
c++;
|
|
}
|
|
} else {
|
|
c++;
|
|
}
|
|
}
|
|
}
|
|
if (*c && (c != tmp)) {
|
|
return NewStringWithSize(tmp, (int)(c - tmp));
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_scopename_suffix()
|
|
*
|
|
* Take a qualified name like "A::B::C" and returns the suffix.
|
|
* In this case, "B::C". Returns NULL if there is no suffix.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
String *Swig_scopename_suffix(const String *s) {
|
|
char *tmp = Char(s);
|
|
char *c = tmp;
|
|
char *co = 0;
|
|
if (!strstr(c, "::"))
|
|
return 0;
|
|
|
|
co = strstr(c, "operator ");
|
|
if (co) {
|
|
if (co == c)
|
|
return 0;
|
|
}
|
|
while (*c) {
|
|
if ((*c == ':') && (*(c + 1) == ':')) {
|
|
break;
|
|
} else {
|
|
if (*c == '<') {
|
|
int level = 1;
|
|
c++;
|
|
while (*c && level) {
|
|
if (*c == '<')
|
|
level++;
|
|
if (*c == '>')
|
|
level--;
|
|
c++;
|
|
}
|
|
} else {
|
|
c++;
|
|
}
|
|
}
|
|
}
|
|
if (*c && (c != tmp)) {
|
|
return NewString(c + 2);
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_scopename_tolist()
|
|
*
|
|
* Take a qualified scope name like "A::B::C" and convert it to a list.
|
|
* In this case, return a list of 3 elements "A", "B", "C".
|
|
* Returns an empty list if the input is empty.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
List *Swig_scopename_tolist(const String *s) {
|
|
List *scopes = NewList();
|
|
String *name = Len(s) == 0 ? 0 : NewString(s);
|
|
|
|
while (name) {
|
|
String *last = 0;
|
|
String *prefix = 0;
|
|
Swig_scopename_split(name, &prefix, &last);
|
|
Insert(scopes, 0, last);
|
|
Delete(last);
|
|
Delete(name);
|
|
name = prefix;
|
|
}
|
|
Delete(name);
|
|
return scopes;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_scopename_check()
|
|
*
|
|
* Checks to see if a name is qualified with a scope name, examples:
|
|
* foo -> 0
|
|
* ::foo -> 1
|
|
* foo::bar -> 1
|
|
* foo< ::bar > -> 0
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
int Swig_scopename_check(const String *s) {
|
|
char *c = Char(s);
|
|
char *co = strstr(c, "operator ");
|
|
|
|
if (co) {
|
|
if (co == c)
|
|
return 0;
|
|
}
|
|
if (!strstr(c, "::"))
|
|
return 0;
|
|
while (*c) {
|
|
if ((*c == ':') && (*(c + 1) == ':')) {
|
|
return 1;
|
|
} else {
|
|
if (*c == '<') {
|
|
int level = 1;
|
|
c++;
|
|
while (*c && level) {
|
|
if (*c == '<')
|
|
level++;
|
|
if (*c == '>')
|
|
level--;
|
|
c++;
|
|
}
|
|
} else {
|
|
c++;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_string_command()
|
|
*
|
|
* Feature removed in SWIG 4.1.0.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
String *Swig_string_command(String *s) {
|
|
Swig_error("SWIG", Getline(s), "Command encoder no longer supported - use regex encoder instead.\n");
|
|
Exit(EXIT_FAILURE);
|
|
return 0;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_string_strip()
|
|
*
|
|
* Strip given prefix from identifiers
|
|
*
|
|
* Printf(stderr,"%(strip:[wx])s","wxHello") -> Hello
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
String *Swig_string_strip(String *s) {
|
|
String *ns;
|
|
if (!Len(s)) {
|
|
ns = NewString(s);
|
|
} else {
|
|
const char *cs = Char(s);
|
|
const char *ce = Strchr(cs, ']');
|
|
if (*cs != '[' || !ce) {
|
|
ns = NewString(s);
|
|
} else {
|
|
String *fmt = NewStringf("%%.%ds", ce-cs-1);
|
|
String *prefix = NewStringf(fmt, cs+1);
|
|
if (0 == Strncmp(ce+1, prefix, Len(prefix))) {
|
|
ns = NewString(ce+1+Len(prefix));
|
|
} else {
|
|
ns = NewString(ce+1);
|
|
}
|
|
}
|
|
}
|
|
return ns;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_string_rstrip()
|
|
*
|
|
* Strip given suffix from identifiers
|
|
*
|
|
* Printf(stderr,"%(rstrip:[Cls])s","HelloCls") -> Hello
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
String *Swig_string_rstrip(String *s) {
|
|
String *ns;
|
|
int len = Len(s);
|
|
if (!len) {
|
|
ns = NewString(s);
|
|
} else {
|
|
const char *cs = Char(s);
|
|
const char *ce = Strchr(cs, ']');
|
|
if (*cs != '[' || !ce) {
|
|
ns = NewString(s);
|
|
} else {
|
|
String *fmt = NewStringf("%%.%ds", ce-cs-1);
|
|
String *suffix = NewStringf(fmt, cs+1);
|
|
int suffix_len = Len(suffix);
|
|
if (0 == Strncmp(cs+len-suffix_len, suffix, suffix_len)) {
|
|
int copy_len = len-suffix_len-(int)(ce+1-cs);
|
|
ns = NewStringWithSize(ce+1, copy_len);
|
|
} else {
|
|
ns = NewString(ce+1);
|
|
}
|
|
}
|
|
}
|
|
return ns;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_offset_string()
|
|
*
|
|
* Insert number tabs before each new line in s
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void Swig_offset_string(String *s, int number) {
|
|
char *res, *p, *end, *start;
|
|
/* count a number of lines in s */
|
|
int lines = 1;
|
|
int len = Len(s);
|
|
if (len == 0)
|
|
return;
|
|
start = strchr(Char(s), '\n');
|
|
while (start) {
|
|
++lines;
|
|
start = strchr(start + 1, '\n');
|
|
}
|
|
/* do not count pending new line */
|
|
if ((Char(s))[len-1] == '\n')
|
|
--lines;
|
|
/* allocate a temporary storage for a padded string */
|
|
res = (char*)Malloc(len + lines * number * 2 + 1);
|
|
res[len + lines * number * 2] = 0;
|
|
|
|
/* copy lines to res, prepending tabs to each line */
|
|
p = res; /* output pointer */
|
|
start = Char(s); /* start of a current line */
|
|
end = strchr(start, '\n'); /* end of a current line */
|
|
while (end) {
|
|
memset(p, ' ', number*2);
|
|
p += number*2;
|
|
memcpy(p, start, end - start + 1);
|
|
p += end - start + 1;
|
|
start = end + 1;
|
|
end = strchr(start, '\n');
|
|
}
|
|
/* process the last line */
|
|
if (*start) {
|
|
memset(p, ' ', number*2);
|
|
p += number*2;
|
|
strcpy(p, start);
|
|
}
|
|
/* replace 's' contents with 'res' */
|
|
Clear(s);
|
|
Append(s, res);
|
|
Free(res);
|
|
}
|
|
|
|
|
|
#ifdef HAVE_PCRE
|
|
#define PCRE2_CODE_UNIT_WIDTH 8
|
|
#include <pcre2.h>
|
|
|
|
static int split_regex_pattern_subst(String *s, String **pattern, String **subst, const char **input)
|
|
{
|
|
const char *pats, *pate;
|
|
const char *subs, *sube;
|
|
|
|
/* Locate the search pattern */
|
|
const char *p = Char(s);
|
|
if (*p++ != '/') goto err_out;
|
|
pats = p;
|
|
p = strchr(p, '/');
|
|
if (!p) goto err_out;
|
|
pate = p;
|
|
|
|
/* Locate the substitution string */
|
|
subs = ++p;
|
|
p = strchr(p, '/');
|
|
if (!p) goto err_out;
|
|
sube = p;
|
|
|
|
*pattern = NewStringWithSize(pats, (int)(pate - pats));
|
|
*subst = NewStringWithSize(subs, (int)(sube - subs));
|
|
*input = p + 1;
|
|
return 1;
|
|
|
|
err_out:
|
|
Swig_error("SWIG", Getline(s), "Invalid regex substitution: '%s'.\n", s);
|
|
Exit(EXIT_FAILURE);
|
|
return 0;
|
|
}
|
|
|
|
/* This function copies len characters from src to dst, possibly applying case conversions to them: if convertCase is 1, to upper case and if it is -1, to lower
|
|
* case. If convertNextOnly is 1, only a single character is converted (and convertCase is reset), otherwise all of them are. */
|
|
static void copy_with_maybe_case_conversion(String *dst, const char *src, int len, int *convertCase, int convertNextOnly)
|
|
{
|
|
/* Deal with the trivial cases first. */
|
|
if (!len)
|
|
return;
|
|
|
|
if (!*convertCase) {
|
|
Write(dst, src, len);
|
|
return;
|
|
}
|
|
|
|
/* If we must convert only the first character, do it and write the rest at once. */
|
|
if (convertNextOnly) {
|
|
int src_char = *src;
|
|
Putc(*convertCase == 1 ? toupper(src_char) : tolower(src_char), dst);
|
|
*convertCase = 0;
|
|
if (len > 1) {
|
|
Write(dst, src + 1, len - 1);
|
|
}
|
|
} else {
|
|
/* We need to convert all characters. */
|
|
int i;
|
|
for (i = 0; i < len; i++, src++) {
|
|
int src_char = *src;
|
|
Putc(*convertCase == 1 ? toupper(src_char) : tolower(src_char), dst);
|
|
}
|
|
}
|
|
}
|
|
|
|
String *replace_captures(int num_captures, const char *input, String *subst, size_t captures[], String *pattern, String *s)
|
|
{
|
|
int convertCase = 0, convertNextOnly = 0;
|
|
String *result = NewStringEmpty();
|
|
const char *p = Char(subst);
|
|
|
|
while (*p) {
|
|
/* Copy part without substitutions */
|
|
const char *q = strchr(p, '\\');
|
|
if (!q) {
|
|
copy_with_maybe_case_conversion(result, p, (int)strlen(p), &convertCase, convertNextOnly);
|
|
break;
|
|
}
|
|
copy_with_maybe_case_conversion(result, p, (int)(q - p), &convertCase, convertNextOnly);
|
|
p = q + 1;
|
|
|
|
/* Handle substitution */
|
|
if (*p == '\0') {
|
|
Putc('\\', result);
|
|
} else if (isdigit((unsigned char)*p)) {
|
|
int group = *p++ - '0';
|
|
if (group < num_captures) {
|
|
int l = (int)captures[group*2], r = (int)captures[group*2 + 1];
|
|
if (l != -1) {
|
|
copy_with_maybe_case_conversion(result, input + l, r - l, &convertCase, convertNextOnly);
|
|
}
|
|
} else {
|
|
Swig_error("SWIG", Getline(s), "PCRE capture replacement failed while matching \"%s\" using \"%s\" - request for group %d is greater than the number of captures %d.\n",
|
|
Char(pattern), input, group, num_captures-1);
|
|
}
|
|
} else {
|
|
/* Handle Perl-like case conversion escapes. */
|
|
switch (*p) {
|
|
case 'u':
|
|
convertCase = 1;
|
|
convertNextOnly = 1;
|
|
break;
|
|
case 'U':
|
|
convertCase = 1;
|
|
convertNextOnly = 0;
|
|
break;
|
|
case 'l':
|
|
convertCase = -1;
|
|
convertNextOnly = 1;
|
|
break;
|
|
case 'L':
|
|
convertCase = -1;
|
|
convertNextOnly = 0;
|
|
break;
|
|
case 'E':
|
|
convertCase = 0;
|
|
break;
|
|
default:
|
|
Swig_error("SWIG", Getline(s), "Unrecognized escape character '%c' in the replacement string \"%s\".\n",
|
|
*p, Char(subst));
|
|
}
|
|
p++;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_string_regex()
|
|
*
|
|
* Executes a regular expression substitution. For example:
|
|
*
|
|
* Printf(stderr,"gsl%(regex:/GSL_(.*)_/\\1/)s", "GSL_Hello_") -> gslHello
|
|
* ----------------------------------------------------------------------------- */
|
|
String *Swig_string_regex(String *s) {
|
|
const int pcre_options = 0;
|
|
|
|
String *res = 0;
|
|
pcre2_code *compiled_pat = 0;
|
|
const char *input;
|
|
PCRE2_UCHAR pcre_error[256];
|
|
int pcre_errornum;
|
|
size_t pcre_errorpos;
|
|
String *pattern = 0, *subst = 0;
|
|
size_t *captures = 0;
|
|
pcre2_match_data *match_data = 0;
|
|
if (split_regex_pattern_subst(s, &pattern, &subst, &input)) {
|
|
int rc;
|
|
|
|
compiled_pat = pcre2_compile(
|
|
(PCRE2_SPTR8)Char(pattern), PCRE2_ZERO_TERMINATED, pcre_options, &pcre_errornum, &pcre_errorpos, NULL);
|
|
if (!compiled_pat) {
|
|
pcre2_get_error_message (pcre_errornum, pcre_error, sizeof pcre_error);
|
|
Swig_error("SWIG", Getline(s), "PCRE compilation failed: '%s' in '%s':%i.\n",
|
|
pcre_error, Char(pattern), pcre_errorpos);
|
|
Exit(EXIT_FAILURE);
|
|
}
|
|
match_data = pcre2_match_data_create_from_pattern (compiled_pat, NULL);
|
|
rc = pcre2_match(compiled_pat, (PCRE2_SPTR8)input, PCRE2_ZERO_TERMINATED, 0, 0, match_data, NULL);
|
|
captures = pcre2_get_ovector_pointer (match_data);
|
|
if (rc >= 0) {
|
|
res = replace_captures(rc, input, subst, captures, pattern, s);
|
|
} else if (rc != PCRE2_ERROR_NOMATCH) {
|
|
Swig_error("SWIG", Getline(s), "PCRE execution failed: error %d while matching \"%s\" using \"%s\".\n",
|
|
rc, Char(pattern), input);
|
|
Exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
DohDelete(pattern);
|
|
DohDelete(subst);
|
|
pcre2_code_free(compiled_pat);
|
|
pcre2_match_data_free(match_data);
|
|
return res ? res : NewStringEmpty();
|
|
}
|
|
|
|
String *Swig_pcre_version(void) {
|
|
int len = pcre2_config(PCRE2_CONFIG_VERSION, NULL);
|
|
char *buf = Malloc(len);
|
|
String *result;
|
|
pcre2_config(PCRE2_CONFIG_VERSION, buf);
|
|
result = NewStringf("PCRE2 Version: %s", buf);
|
|
Free(buf);
|
|
return result;
|
|
}
|
|
|
|
#else
|
|
|
|
String *Swig_string_regex(String *s) {
|
|
Swig_error("SWIG", Getline(s), "PCRE regex support not enabled in this SWIG build.\n");
|
|
Exit(EXIT_FAILURE);
|
|
return 0;
|
|
}
|
|
|
|
String *Swig_pcre_version(void) {
|
|
return NewStringf("PCRE not used");
|
|
}
|
|
|
|
#endif
|
|
|
|
/* ------------------------------------------------------------
|
|
* Swig_is_generated_overload()
|
|
* Check if the function is an automatically generated
|
|
* overload created because a method has default parameters.
|
|
* ------------------------------------------------------------ */
|
|
int Swig_is_generated_overload(Node *n) {
|
|
Node *base_method = Getattr(n, "sym:overloaded");
|
|
Node *default_args = Getattr(n, "defaultargs");
|
|
return ((base_method != NULL) && (default_args != NULL) && (base_method == default_args));
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_init()
|
|
*
|
|
* Initialize the SWIG core
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void Swig_init() {
|
|
/* Set some useful string encoding methods */
|
|
DohEncoding("escape", Swig_string_escape);
|
|
DohEncoding("hexescape", Swig_string_hexescape);
|
|
DohEncoding("upper", Swig_string_upper);
|
|
DohEncoding("lower", Swig_string_lower);
|
|
DohEncoding("title", Swig_string_title);
|
|
DohEncoding("ctitle", Swig_string_ccase);
|
|
DohEncoding("lctitle", Swig_string_lccase);
|
|
DohEncoding("utitle", Swig_string_ucase);
|
|
DohEncoding("typecode", Swig_string_typecode);
|
|
DohEncoding("mangle", Swig_string_emangle);
|
|
DohEncoding("command", Swig_string_command);
|
|
DohEncoding("schemify", Swig_string_schemify);
|
|
DohEncoding("strip", Swig_string_strip);
|
|
DohEncoding("rstrip", Swig_string_rstrip);
|
|
DohEncoding("regex", Swig_string_regex);
|
|
|
|
/* aliases for the case encoders */
|
|
DohEncoding("uppercase", Swig_string_upper);
|
|
DohEncoding("lowercase", Swig_string_lower);
|
|
DohEncoding("camelcase", Swig_string_ccase);
|
|
DohEncoding("lowercamelcase", Swig_string_lccase);
|
|
DohEncoding("undercase", Swig_string_ucase);
|
|
DohEncoding("firstuppercase", Swig_string_first_upper);
|
|
DohEncoding("firstlowercase", Swig_string_first_lower);
|
|
|
|
/* Initialize typemaps */
|
|
Swig_typemap_init();
|
|
|
|
/* Initialize symbol table */
|
|
Swig_symbol_init();
|
|
|
|
/* Initialize type system */
|
|
SwigType_typesystem_init();
|
|
|
|
/* Initialize template system */
|
|
SwigType_template_init();
|
|
}
|