/*- * Copyright (c) 2015, 2016 Taylor R. Campbell * 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 AUTHOR 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 THE AUTHOR OR 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. */ #include #include #include #include #include #include #include "ast.h" #include "attribute.h" #include "eprintf.h" #include "err.h" #include "format.h" #include "progname.h" #include "syntax.h" static void attr_noreturn usage(void) { efprintf(stderr, "Usage: %s", getprogname()); efprintf(stderr, " [-c ] [-d ] [-f ]"); efprintf(stderr, " [-G ]\n"); efprintf(stderr, " [-H ] [-h ]"); efprintf(stderr, " [-s ] \n"); exit(1); } struct options { char *hguard; FILE *hfile; char *hfilename; FILE *cfile; FILE *dumpfile; FILE *protofile; const char *protofilename; struct syntaxopts syntaxopts; struct picopbc_formats formats; int error; }; static struct options options = { .syntaxopts = DEFAULT_SYNTAXOPTS, }; static struct options *O = &options; int main(int argc, char **argv) { int ch; setprogname(argv[0]); if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) err(1, "signal(SIGPIPE, SIG_IGN)"); picopbc_empty_formats(&O->formats); while ((ch = getopt(argc, argv, "c:d:f:G:H:h:s:")) != -1) { switch (ch) { case 'c': if (strcmp(optarg, "-") == 0) O->cfile = stdout; else O->cfile = fopen(optarg, "w"); if (O->cfile == NULL) err(1, "fopen C file"); break; case 'd': if (strcmp(optarg, "-") == 0) O->dumpfile = stdout; else O->dumpfile = fopen(optarg, "w"); if (O->dumpfile == NULL) err(1, "fopen dump file"); break; case 'f': { enum picopbc_format format; if (!picopbc_find_format(optarg, &format)) errx(1, "unknown format: %s", optarg); picopbc_enable_format(&O->formats, format); break; } case 'G': O->hguard = optarg; break; case 'H': O->hfilename = optarg; break; case 'h': if (strcmp(optarg, "-") == 0) { O->hfile = stdout; } else { if (O->hfilename == NULL) O->hfilename = optarg; O->hfile = fopen(optarg, "w"); } if (O->hfile == NULL) err(1, "fopen H file"); break; case 's': if (strcmp(optarg, "c++") == 0) { O->syntaxopts.so_cmtsty = CMTSTY_CPP; } else if (strcasecmp(optarg, "sh") == 0) { O->syntaxopts.so_cmtsty = CMTSTY_SH; } else { warnx("unknown comment style %s", optarg); usage(); } break; case '?': default: usage(); } } argc -= optind; argv += optind; if (argc != 1) usage(); if (O->hfile != NULL && O->hguard == NULL) { if (O->hfilename == NULL) { warnx("specify -G to name header guard"); usage(); } O->hguard = O->hfilename; } if (O->cfile != NULL && O->hfilename == NULL) { warnx("specify -H to name header file"); usage(); } if (strcmp(argv[0], "-") == 0) { O->protofile = stdin; O->protofilename = "(stdin)"; } else { O->protofile = fopen(argv[0], "r"); if (O->protofile == NULL) err(1, "fopen proto file"); O->protofilename = argv[0]; } /* Assume syntax error unless parser successfully completes. */ O->error = 1; /* Run the parser. */ picopbc_parse(O->protofile, O->protofilename, &O->syntaxopts); /* Return the error. */ return O->error; } void picopbc_parsed(int error, struct ast_proto *proto) { struct string hguard, hname; if (O->dumpfile) picopbc_dump(O->dumpfile, proto); if (error) { O->error = error; return; } if (O->hfile) { size_t i, n; assert(O->hguard != NULL); n = strlen(O->hguard); hguard = string_emalloc(n + 2); /* * Guarantee we don't start with an underscore and * uppercase, which is reserved to the C * implementation. */ string_ptr(hguard)[0] = 'H'; string_ptr(hguard)[1] = '_'; for (i = 0; i < n; i++) { char ich = O->hguard[i], och; if (('0' <= ich && ich <= '9') || ('A' <= ich && ich <= 'Z')) och = ich; else if ('a' <= ich && ich <= 'z') och = ich + ('A' - 'a'); else och = '_'; string_ptr(hguard)[i + 2] = och; } } else { hguard = string_null; } if (O->cfile) { /* XXX Let the user specify this. */ const struct string q = STRING_CONST("\""); struct string hfilename; assert(O->hfilename != NULL); hfilename = string(O->hfilename, strlen(O->hfilename)); assert(string_ptr(hfilename) != NULL); hname = string_econcatn(&q, &hfilename, &q, NULL); } else { hname = string_null; } O->error = picopbc_compile(O->hfile, hguard, O->cfile, hname, proto, &O->formats); if (O->cfile) string_free(hname); if (O->hfile) string_free(hguard); }