You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
515 lines
12 KiB
515 lines
12 KiB
/* |
|
* The main module for SIP. |
|
* |
|
* Copyright (c) 2010 Riverbank Computing Limited <info@riverbankcomputing.com> |
|
* |
|
* This file is part of SIP. |
|
* |
|
* This copy of SIP is licensed for use under the terms of the SIP License |
|
* Agreement. See the file LICENSE for more details. |
|
* |
|
* This copy of SIP may also used under the terms of the GNU General Public |
|
* License v2 or v3 as published by the Free Software Foundation which can be |
|
* found in the files LICENSE-GPL2 and LICENSE-GPL3 included in this package. |
|
* |
|
* SIP is supplied WITHOUT ANY WARRANTY; without even the implied warranty of |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|
*/ |
|
|
|
|
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <stdarg.h> |
|
#include <string.h> |
|
#include <ctype.h> |
|
|
|
#include "sip.h" |
|
|
|
|
|
#ifndef PACKAGE |
|
#define PACKAGE "sip" |
|
#endif |
|
|
|
#define VERSION "4.10.5" |
|
|
|
|
|
/* Global variables - see sip.h for their meaning. */ |
|
char *sipVersion; |
|
stringList *includeDirList; |
|
|
|
static char *sipPackage = PACKAGE; |
|
static int warnings = FALSE; |
|
|
|
|
|
static void help(void); |
|
static void version(void); |
|
static void usage(void); |
|
static char parseopt(int,char **,char *,char **,int *,char **); |
|
static int parseInt(char *,char); |
|
|
|
|
|
int main(int argc, char **argv) |
|
{ |
|
char *filename, *docFile, *codeDir, *srcSuffix, *flagFile, *consModule; |
|
char arg, *optarg, *buildFile, *apiFile, *xmlFile; |
|
int optnr, exceptions, tracing, releaseGIL, parts, kwdArgs, protHack, docs; |
|
FILE *file; |
|
sipSpec spec; |
|
stringList *versions, *xfeatures; |
|
|
|
/* Initialise. */ |
|
sipVersion = VERSION; |
|
includeDirList = NULL; |
|
versions = NULL; |
|
xfeatures = NULL; |
|
buildFile = NULL; |
|
codeDir = NULL; |
|
docFile = NULL; |
|
srcSuffix = NULL; |
|
flagFile = NULL; |
|
apiFile = NULL; |
|
xmlFile = NULL; |
|
consModule = NULL; |
|
exceptions = FALSE; |
|
tracing = FALSE; |
|
releaseGIL = FALSE; |
|
parts = 0; |
|
kwdArgs = FALSE; |
|
protHack = FALSE; |
|
docs = FALSE; |
|
|
|
/* Parse the command line. */ |
|
optnr = 1; |
|
|
|
while ((arg = parseopt(argc, argv, "hVa:b:ec:d:gI:j:km:op:Prs:t:wx:z:", &flagFile, &optnr, &optarg)) != '\0') |
|
switch (arg) |
|
{ |
|
case 'o': |
|
/* Generate docstrings. */ |
|
docs = TRUE; |
|
break; |
|
|
|
case 'p': |
|
/* The name of the consolidated module. */ |
|
consModule = optarg; |
|
break; |
|
|
|
case 'P': |
|
/* Enable the protected/public hack. */ |
|
protHack = TRUE; |
|
break; |
|
|
|
case 'a': |
|
/* Where to generate the API file. */ |
|
apiFile = optarg; |
|
break; |
|
|
|
case 'm': |
|
/* Where to generate the XML file. */ |
|
xmlFile = optarg; |
|
break; |
|
|
|
case 'b': |
|
/* Generate a build file. */ |
|
buildFile = optarg; |
|
break; |
|
|
|
case 'e': |
|
/* Enable exceptions. */ |
|
exceptions = TRUE; |
|
break; |
|
|
|
case 'g': |
|
/* Always release the GIL. */ |
|
releaseGIL = TRUE; |
|
break; |
|
|
|
case 'j': |
|
/* Generate the code in this number of parts. */ |
|
parts = parseInt(optarg,'j'); |
|
break; |
|
|
|
case 'z': |
|
/* Read a file for the next flags. */ |
|
if (flagFile != NULL) |
|
fatal("The -z flag cannot be specified in an argument file\n"); |
|
|
|
flagFile = optarg; |
|
break; |
|
|
|
case 'c': |
|
/* Where to generate the code. */ |
|
codeDir = optarg; |
|
break; |
|
|
|
case 'd': |
|
/* Where to generate the documentation. */ |
|
docFile = optarg; |
|
break; |
|
|
|
case 't': |
|
/* Which platform or version to generate code for. */ |
|
appendString(&versions,optarg); |
|
break; |
|
|
|
case 'x': |
|
/* Which features are disabled. */ |
|
appendString(&xfeatures,optarg); |
|
break; |
|
|
|
case 'I': |
|
/* Where to get included files from. */ |
|
appendString(&includeDirList,optarg); |
|
break; |
|
|
|
case 'r': |
|
/* Enable tracing. */ |
|
tracing = TRUE; |
|
break; |
|
|
|
case 's': |
|
/* The suffix to use for source files. */ |
|
srcSuffix = optarg; |
|
break; |
|
|
|
case 'w': |
|
/* Enable warning messages. */ |
|
warnings = TRUE; |
|
break; |
|
|
|
case 'k': |
|
/* Allow keyword arguments in functions and methods. */ |
|
kwdArgs = TRUE; |
|
break; |
|
|
|
case 'h': |
|
/* Help message. */ |
|
help(); |
|
break; |
|
|
|
case 'V': |
|
/* Display the version number. */ |
|
version(); |
|
break; |
|
|
|
default: |
|
usage(); |
|
} |
|
|
|
if (optnr < argc) |
|
{ |
|
file = NULL; |
|
filename = argv[optnr++]; |
|
|
|
if (optnr < argc) |
|
usage(); |
|
} |
|
else |
|
{ |
|
file = stdin; |
|
filename = "stdin"; |
|
} |
|
|
|
/* Parse the input file. */ |
|
parse(&spec, file, filename, versions, xfeatures, kwdArgs, protHack); |
|
|
|
/* Verify and transform the parse tree. */ |
|
transform(&spec); |
|
|
|
/* Generate code. */ |
|
generateCode(&spec, codeDir, buildFile, docFile, srcSuffix, exceptions, |
|
tracing, releaseGIL, parts, xfeatures, consModule, docs); |
|
|
|
/* Generate the API file. */ |
|
if (apiFile != NULL) |
|
generateAPI(&spec, spec.module, apiFile); |
|
|
|
/* Generate the XML export. */ |
|
if (xmlFile != NULL) |
|
generateXML(&spec, spec.module, xmlFile); |
|
|
|
/* All done. */ |
|
return 0; |
|
} |
|
|
|
|
|
/* |
|
* Parse the next command line argument - similar to UNIX getopts(). Allow a |
|
* flag to specify that a file contains further arguments. |
|
*/ |
|
static char parseopt(int argc, char **argv, char *opts, char **flags, |
|
int *optnrp, char **optargp) |
|
{ |
|
char arg, *op, *fname; |
|
int optnr; |
|
static FILE *fp = NULL; |
|
|
|
/* Deal with any file first. */ |
|
|
|
fname = *flags; |
|
|
|
if (fname != NULL && fp == NULL && (fp = fopen(fname,"r")) == NULL) |
|
fatal("Unable to open %s\n",fname); |
|
|
|
if (fp != NULL) |
|
{ |
|
char buf[200], *cp, *fname; |
|
int ch; |
|
|
|
fname = *flags; |
|
cp = buf; |
|
|
|
while ((ch = fgetc(fp)) != EOF) |
|
{ |
|
/* Skip leading whitespace. */ |
|
|
|
if (cp == buf && isspace(ch)) |
|
continue; |
|
|
|
if (ch == '\n') |
|
break; |
|
|
|
if (cp == &buf[sizeof (buf) - 1]) |
|
fatal("A flag in %s is too long\n",fname); |
|
|
|
*cp++ = (char)ch; |
|
} |
|
|
|
*cp = '\0'; |
|
|
|
if (ch == EOF) |
|
{ |
|
fclose(fp); |
|
fp = NULL; |
|
*flags = NULL; |
|
} |
|
|
|
/* |
|
* Get the option character and any optional argument from the |
|
* line. |
|
*/ |
|
|
|
if (buf[0] != '\0') |
|
{ |
|
if (buf[0] != '-' || buf[1] == '\0') |
|
fatal("An non-flag was given in %s\n",fname); |
|
|
|
arg = buf[1]; |
|
|
|
/* Find any optional argument. */ |
|
|
|
for (cp = &buf[2]; *cp != '\0'; ++cp) |
|
if (!isspace(*cp)) |
|
break; |
|
|
|
if (*cp == '\0') |
|
cp = NULL; |
|
else |
|
cp = sipStrdup(cp); |
|
|
|
*optargp = cp; |
|
|
|
if ((op = strchr(opts,arg)) == NULL) |
|
fatal("An invalid flag was given in %s\n",fname); |
|
|
|
if (op[1] == ':' && cp == NULL) |
|
fatal("Missing flag argument in %s\n",fname); |
|
|
|
if (op[1] != ':' && cp != NULL) |
|
fatal("Unexpected flag argument in %s\n",fname); |
|
|
|
return arg; |
|
} |
|
} |
|
|
|
/* Check there is an argument and it is a switch. */ |
|
|
|
optnr = *optnrp; |
|
|
|
if (optnr >= argc || argv[optnr] == NULL || argv[optnr][0] != '-') |
|
return '\0'; |
|
|
|
/* Check it is a valid switch. */ |
|
|
|
arg = argv[optnr][1]; |
|
|
|
if (arg == '\0' || (op = strchr(opts,arg)) == NULL) |
|
usage(); |
|
|
|
/* Check for the switch parameter, if any. */ |
|
|
|
if (op[1] == ':') |
|
{ |
|
if (argv[optnr][2] != '\0') |
|
{ |
|
*optargp = &argv[optnr][2]; |
|
++optnr; |
|
} |
|
else if (optnr + 1 >= argc || argv[optnr + 1] == NULL) |
|
usage(); |
|
else |
|
{ |
|
*optargp = argv[optnr + 1]; |
|
optnr += 2; |
|
} |
|
} |
|
else if (argv[optnr][2] != '\0') |
|
usage(); |
|
else |
|
{ |
|
*optargp = NULL; |
|
++optnr; |
|
} |
|
|
|
*optnrp = optnr; |
|
|
|
return arg; |
|
} |
|
|
|
|
|
/* |
|
* Parse an integer option. |
|
*/ |
|
static int parseInt(char *arg, char opt) |
|
{ |
|
char *endptr; |
|
int val; |
|
|
|
val = strtol(arg, &endptr, 10); |
|
|
|
if (*arg == '\0' || *endptr != '\0') |
|
fatal("Invalid integer argument for -%c flag\n", opt); |
|
|
|
return val; |
|
} |
|
|
|
|
|
/* |
|
* Append a string to a list of them. |
|
*/ |
|
void appendString(stringList **headp, const char *s) |
|
{ |
|
stringList *sl; |
|
|
|
/* Create the new entry. */ |
|
|
|
sl = sipMalloc(sizeof (stringList)); |
|
|
|
sl -> s = s; |
|
sl -> next = NULL; |
|
|
|
/* Append it to the list. */ |
|
|
|
while (*headp != NULL) |
|
headp = &(*headp) -> next; |
|
|
|
*headp = sl; |
|
} |
|
|
|
|
|
/* |
|
* Display a warning message. |
|
*/ |
|
void warning(char *fmt,...) |
|
{ |
|
static int start = TRUE; |
|
|
|
va_list ap; |
|
|
|
if (!warnings) |
|
return; |
|
|
|
if (start) |
|
{ |
|
fprintf(stderr,"%s: Warning: ",sipPackage); |
|
start = FALSE; |
|
} |
|
|
|
va_start(ap,fmt); |
|
vfprintf(stderr,fmt,ap); |
|
va_end(ap); |
|
|
|
if (strchr(fmt,'\n') != NULL) |
|
start = TRUE; |
|
} |
|
|
|
|
|
/* |
|
* Display all or part of a one line error message describing a fatal error. |
|
* If the message is complete (it has a newline) then the program exits. |
|
*/ |
|
void fatal(char *fmt,...) |
|
{ |
|
static int start = TRUE; |
|
|
|
va_list ap; |
|
|
|
if (start) |
|
{ |
|
fprintf(stderr,"%s: ",sipPackage); |
|
start = FALSE; |
|
} |
|
|
|
va_start(ap,fmt); |
|
vfprintf(stderr,fmt,ap); |
|
va_end(ap); |
|
|
|
if (strchr(fmt,'\n') != NULL) |
|
exit(1); |
|
} |
|
|
|
|
|
/* |
|
* Display the SIP version number on stdout and exit with zero exit status. |
|
*/ |
|
static void version(void) |
|
{ |
|
printf("%s\n",sipVersion); |
|
exit(0); |
|
} |
|
|
|
|
|
/* |
|
* Display the help message on stdout and exit with zero exit status. |
|
*/ |
|
static void help(void) |
|
{ |
|
printf( |
|
"Usage:\n" |
|
" %s [-h] [-V] [-a file] [-b file] [-c dir] [-d file] [-e] [-g] [-I dir] [-j #] [-k] [-m file] [-o] [-p module] [-P] [-r] [-s suffix] [-t tag] [-w] [-x feature] [-z file] [file]\n" |
|
"where:\n" |
|
" -h display this help message\n" |
|
" -V display the %s version number\n" |
|
" -a file the name of the TQScintilla API file [default not generated]\n" |
|
" -b file the name of the build file [default none generated]\n" |
|
" -c dir the name of the code directory [default not generated]\n" |
|
" -d file the name of the documentation file [default not generated]\n" |
|
" -e enable support for exceptions [default disabled]\n" |
|
" -g always release and reacquire the GIL [default only when specified]\n" |
|
" -I dir look in this directory when including files\n" |
|
" -j # split the generated code into # files [default 1 per class]\n" |
|
" -k support keyword arguments in functions and methods\n" |
|
" -m file the name of the XML export file [default not generated]\n" |
|
" -o enable the automatic generation of docstrings [default disabled]\n" |
|
" -p module the name of the consolidated module that this is a component of\n" |
|
" -P enable the protected/public hack\n" |
|
" -r generate code with tracing enabled [default disabled]\n" |
|
" -s suffix the suffix to use for C or C++ source files [default \".c\" or \".cpp\"]\n" |
|
" -t tag the version/platform to generate code for\n" |
|
" -w enable warning messages\n" |
|
" -x feature this feature is disabled\n" |
|
" -z file the name of a file containing more command line flags\n" |
|
" file the name of the specification file [default stdin]\n" |
|
, sipPackage, sipPackage); |
|
|
|
exit(0); |
|
} |
|
|
|
|
|
/* |
|
* Display the usage message. |
|
*/ |
|
static void usage(void) |
|
{ |
|
fatal("Usage: %s [-h] [-V] [-a file] [-b file] [-c dir] [-d file] [-e] [-g] [-I dir] [-j #] [-k] [-m file] [-o] [-p module] [-P] [-r] [-s suffix] [-t tag] [-w] [-x feature] [-z file] [file]\n", sipPackage); |
|
}
|
|
|