/*====================================================================* - Copyright (C) 2001 Leptonica. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *====================================================================*/ /* * xtractprotos.c * * This program accepts a list of C files on the command line * and outputs the C prototypes to stdout. It uses cpp to * handle the preprocessor macros, and then parses the cpp output. * In leptonica, it is used to make allheaders.h (and optionally * leptprotos.h, which contains just the function prototypes.) * In leptonica, only the file allheaders.h is included with * source files. * * An optional 'prestring' can be prepended to each declaration. * And the function prototypes can either be sent to stdout, written * to a named file, or placed in-line within allheaders.h. * * The signature is: * * xtractprotos [-prestring=] [-protos=] [list of C files] * * Without -protos, the prototypes are written to stdout. * With -protos, allheaders.h is rewritten: * * if you use -protos=inline, the prototypes are placed within * allheaders.h. * * if you use -protos=leptprotos.h, the prototypes written to * the file leptprotos.h, and alltypes.h has * #include "leptprotos.h" * * For constructing allheaders.h, two text files are provided: * allheaders_top.txt * allheaders_bot.txt * The former contains the leptonica version number, so it must * be updated when a new version is made. * * For simple C prototype extraction, xtractprotos has essentially * the same functionality as Adam Bryant's cextract, but the latter * has not been officially supported for over 15 years, has been * patched numerous times, and doesn't work with sys/sysmacros.h * for 64 bit architecture. * * This is used to extract all prototypes in liblept. * The function that does all the work is parseForProtos(), * which takes as input the output from cpp. * * xtractprotos can run in leptonica to do an 'ab initio' generation * of allheaders.h; that is, it can make allheaders.h without * leptprotos.h and with an allheaders.h file of 0 length. * Of course, the usual situation is to run it with a valid allheaders.h, * which includes all the function prototypes. To avoid including * all the prototypes in the input for each file, cpp runs here * with -DNO_PROTOS, so the prototypes are not included -- this is * much faster. * * The xtractprotos version number, defined below, is incremented * whenever a new version is made. * * Note: this uses cpp to preprocess the input. (The name of the cpp * tempfile is constructed below. It has a "." in the tail, which * Cygwin needs to prevent it from appending ".exe" to the filename.) */ #ifdef HAVE_CONFIG_H #include #endif /* HAVE_CONFIG_H */ #include #include "allheaders.h" #define L_BUFSIZE 512 /* hardcoded below in sscanf() */ static const char *version = "1.5"; int main(int argc, char **argv) { char *filein, *str, *tempfile, *prestring, *outprotos, *protostr; char buf[L_BUFSIZE]; l_int32 i, maxindex, in_line, nflags, protos_added, firstfile, len, ret; size_t nbytes; L_BYTEA *ba, *ba2; SARRAY *sa; static char mainName[] = "xtractprotos"; if (argc == 1) { lept_stderr( "xtractprotos [-prestring=] [-protos=] " "[list of C files]\n" "where the prestring is prepended to each prototype, and \n" "protos can be either 'inline' or the name of an output " "prototype file\n"); return 1; } setLeptDebugOK(1); /* ---------------------------------------------------------------- */ /* Parse input flags and find prestring and outprotos, if requested */ /* ---------------------------------------------------------------- */ prestring = outprotos = NULL; in_line = FALSE; nflags = 0; maxindex = L_MIN(3, argc); for (i = 1; i < maxindex; i++) { if (argv[i][0] == '-') { if (!strncmp(argv[i], "-prestring", 10)) { nflags++; ret = sscanf(argv[i] + 1, "prestring=%490s", buf); if (ret != 1) { lept_stderr("parse failure for prestring\n"); return 1; } if ((len = strlen(buf)) > L_BUFSIZE - 3) { L_WARNING("prestring too large; omitting!\n", mainName); } else { buf[len] = ' '; buf[len + 1] = '\0'; prestring = stringNew(buf); } } else if (!strncmp(argv[i], "-protos", 7)) { nflags++; ret = sscanf(argv[i] + 1, "protos=%490s", buf); if (ret != 1) { lept_stderr("parse failure for protos\n"); return 1; } outprotos = stringNew(buf); if (!strncmp(outprotos, "inline", 7)) in_line = TRUE; } } } if (argc - nflags < 2) { lept_stderr("no files specified!\n"); return 1; } /* ---------------------------------------------------------------- */ /* Generate the prototype string */ /* ---------------------------------------------------------------- */ ba = l_byteaCreate(500); /* First the extern C head */ sa = sarrayCreate(0); sarrayAddString(sa, "/*", L_COPY); snprintf(buf, L_BUFSIZE, " * These prototypes were autogen'd by xtractprotos, v. %s", version); sarrayAddString(sa, buf, L_COPY); sarrayAddString(sa, " */", L_COPY); sarrayAddString(sa, "#ifdef __cplusplus", L_COPY); sarrayAddString(sa, "extern \"C\" {", L_COPY); sarrayAddString(sa, "#endif /* __cplusplus */\n", L_COPY); str = sarrayToString(sa, 1); l_byteaAppendString(ba, str); lept_free(str); sarrayDestroy(&sa); /* Then the prototypes */ firstfile = 1 + nflags; protos_added = FALSE; if ((tempfile = l_makeTempFilename()) == NULL) { lept_stderr("failure to make a writeable temp file\n"); return 1; } for (i = firstfile; i < argc; i++) { filein = argv[i]; len = strlen(filein); if (filein[len - 1] == 'h') /* skip .h files */ continue; snprintf(buf, L_BUFSIZE, "cpp -ansi -DNO_PROTOS %s %s", filein, tempfile); ret = system(buf); /* cpp */ if (ret) { lept_stderr("cpp failure for %s; continuing\n", filein); continue; } if ((str = parseForProtos(tempfile, prestring)) == NULL) { lept_stderr("parse failure for %s; continuing\n", filein); continue; } if (strlen(str) > 1) { /* strlen(str) == 1 is a file without protos */ l_byteaAppendString(ba, str); protos_added = TRUE; } lept_free(str); } lept_rmfile(tempfile); lept_free(tempfile); /* Lastly the extern C tail */ sa = sarrayCreate(0); sarrayAddString(sa, "\n#ifdef __cplusplus", L_COPY); sarrayAddString(sa, "}", L_COPY); sarrayAddString(sa, "#endif /* __cplusplus */", L_COPY); str = sarrayToString(sa, 1); l_byteaAppendString(ba, str); lept_free(str); sarrayDestroy(&sa); protostr = (char *)l_byteaCopyData(ba, &nbytes); l_byteaDestroy(&ba); /* ---------------------------------------------------------------- */ /* Generate the output */ /* ---------------------------------------------------------------- */ if (!outprotos) { /* just write to stdout */ lept_stderr("%s\n", protostr); lept_free(protostr); return 0; } /* If no protos were found, do nothing further */ if (!protos_added) { lept_stderr("No protos found\n"); lept_free(protostr); return 1; } /* Make the output files */ ba = l_byteaInitFromFile("allheaders_top.txt"); if (!in_line) { snprintf(buf, sizeof(buf), "#include \"%s\"\n", outprotos); l_byteaAppendString(ba, buf); l_binaryWrite(outprotos, "w", protostr, nbytes); } else { l_byteaAppendString(ba, protostr); } ba2 = l_byteaInitFromFile("allheaders_bot.txt"); l_byteaJoin(ba, &ba2); l_byteaWrite("allheaders.h", ba, 0, 0); l_byteaDestroy(&ba); lept_free(protostr); return 0; }