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.
516 lines
12 KiB
516 lines
12 KiB
/*
|
|
* The main module for SIP-TQt.
|
|
*
|
|
* Copyright (c) 2010 Riverbank Computing Limited <info@riverbankcomputing.com>
|
|
*
|
|
* This file is part of SIP-TQt.
|
|
*
|
|
* This copy of SIP-TQt is licensed for use under the terms of the SIP License
|
|
* Agreement. See the file LICENSE for more details.
|
|
*
|
|
* This copy of SIP-TQt 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-TQt 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-tqt"
|
|
#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-TQt 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);
|
|
}
|