diff options
| author | Rafael G. Martins <rafael@rafaelmartins.eng.br> | 2016-04-27 03:22:31 +0200 | 
|---|---|---|
| committer | Rafael G. Martins <rafael@rafaelmartins.eng.br> | 2016-04-27 03:22:31 +0200 | 
| commit | 6f975248895d0300c6fd8783b1138bdd4be00bcc (patch) | |
| tree | 79a3f2d17000b6429685ba39bd47412bca1bcf21 /src/blogc.c | |
| parent | 9699bf0ce6b34c0d05c509925f3367f2200caad5 (diff) | |
| download | blogc-6f975248895d0300c6fd8783b1138bdd4be00bcc.tar.gz blogc-6f975248895d0300c6fd8783b1138bdd4be00bcc.tar.bz2 blogc-6f975248895d0300c6fd8783b1138bdd4be00bcc.zip | |
blogc-git-receiver: import external tool to blogc repository
still in the effort to reduce maintenance work, I'm importing
blogc-git-receiver tool to the main blogc repository.
the tool is build by default, if needed headers are found. that means
that it will probably only be built for posix-compliant operating
systems.
Diffstat (limited to 'src/blogc.c')
| -rw-r--r-- | src/blogc.c | 285 | 
1 files changed, 285 insertions, 0 deletions
| diff --git a/src/blogc.c b/src/blogc.c new file mode 100644 index 0000000..2338c9e --- /dev/null +++ b/src/blogc.c @@ -0,0 +1,285 @@ +/* + * blogc: A blog compiler. + * Copyright (C) 2015-2016 Rafael G. Martins <rafael@rafaelmartins.eng.br> + * + * This program can be distributed under the terms of the BSD License. + * See the file LICENSE. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif /* HAVE_CONFIG_H */ + +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif /* HAVE_SYS_STAT_H */ + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif /* HAVE_SYS_TYPES_H */ + +#include <errno.h> +#include <locale.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> + +#include "source-parser.h" +#include "template-parser.h" +#include "loader.h" +#include "renderer.h" +#include "error.h" +#include "utils.h" + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "Unknown" +#endif + + +static void +blogc_print_help(void) +{ +    printf( +        "usage:\n" +        "    blogc [-h] [-v] [-l] [-D KEY=VALUE ...] [-p KEY] [-t TEMPLATE]\n" +        "          [-o OUTPUT] [SOURCE ...] - A blog compiler.\n" +        "\n" +        "positional arguments:\n" +        "    SOURCE        source file(s)\n" +        "\n" +        "optional arguments:\n" +        "    -h            show this help message and exit\n" +        "    -v            show version and exit\n" +        "    -l            build listing page, from multiple source files\n" +        "    -D KEY=VALUE  set global configuration parameter\n" +        "    -p KEY        show the value of a global configuration parameter\n" +        "                  after source parsing and exit\n" +        "    -t TEMPLATE   template file\n" +        "    -o OUTPUT     output file\n"); +} + + +static void +blogc_print_usage(void) +{ +    printf( +        "usage: blogc [-h] [-v] [-l] [-D KEY=VALUE ...] [-p KEY] [-t TEMPLATE]\n" +        "             [-o OUTPUT] [SOURCE ...]\n"); +} + + +static void +blogc_mkdir_recursive(const char *filename) +{ +    char *fname = sb_strdup(filename); +    for (char *tmp = fname; *tmp != '\0'; tmp++) { +        if (*tmp != '/' && *tmp != '\\') +            continue; +#if defined(HAVE_SYS_STAT_H) && defined(HAVE_SYS_TYPES_H) +        char bkp = *tmp; +        *tmp = '\0'; +        if ((strlen(fname) > 0) && +#if defined(WIN32) || defined(_WIN32) +            (-1 == mkdir(fname)) && +#else +            (-1 == mkdir(fname, 0777)) && +#endif +            (errno != EEXIST)) +        { +            fprintf(stderr, "blogc: error: failed to create output " +                "directory (%s): %s\n", fname, strerror(errno)); +            free(fname); +            exit(2); +        } +        *tmp = bkp; +#else +        // FIXME: show this warning only if actually trying to create a directory. +        fprintf(stderr, "blogc: warning: can't create output directories " +            "for your platform. please create the directories yourself.\n"); +        break; +#endif +    } +    free(fname); +} + + +int +main(int argc, char **argv) +{ +    setlocale(LC_ALL, ""); + +    int rv = 0; + +    bool listing = false; +    char *template = NULL; +    char *output = NULL; +    char *print = NULL; +    char *tmp = NULL; +    char **pieces = NULL; + +    sb_slist_t *sources = NULL; +    sb_trie_t *config = sb_trie_new(free); +    sb_trie_insert(config, "BLOGC_VERSION", sb_strdup(PACKAGE_VERSION)); + +    for (unsigned int i = 1; i < argc; i++) { +        tmp = NULL; +        if (argv[i][0] == '-') { +            switch (argv[i][1]) { +                case 'h': +                    blogc_print_help(); +                    goto cleanup; +                case 'v': +                    printf("%s\n", PACKAGE_STRING); +                    goto cleanup; +                case 'l': +                    listing = true; +                    break; +                case 't': +                    if (argv[i][2] != '\0') +                        template = sb_strdup(argv[i] + 2); +                    else if (i + 1 < argc) +                        template = sb_strdup(argv[++i]); +                    break; +                case 'o': +                    if (argv[i][2] != '\0') +                        output = sb_strdup(argv[i] + 2); +                    else if (i + 1 < argc) +                        output = sb_strdup(argv[++i]); +                    break; +                case 'p': +                    if (argv[i][2] != '\0') +                        print = sb_strdup(argv[i] + 2); +                    else if (i + 1 < argc) +                        print = sb_strdup(argv[++i]); +                    break; +                case 'D': +                    if (argv[i][2] != '\0') +                        tmp = argv[i] + 2; +                    else if (i + 1 < argc) +                        tmp = argv[++i]; +                    if (tmp != NULL) { +                        pieces = sb_str_split(tmp, '=', 2); +                        if (sb_strv_length(pieces) != 2) { +                            fprintf(stderr, "blogc: error: invalid value for " +                                "-D (must have an '='): %s\n", tmp); +                            sb_strv_free(pieces); +                            rv = 2; +                            goto cleanup; +                        } +                        for (unsigned int j = 0; pieces[0][j] != '\0'; j++) { +                            if (!((pieces[0][j] >= 'A' && pieces[0][j] <= 'Z') || +                                pieces[0][j] == '_')) +                            { +                                fprintf(stderr, "blogc: error: invalid value " +                                    "for -D (configuration key must be uppercase " +                                    "with '_'): %s\n", pieces[0]); +                                sb_strv_free(pieces); +                                rv = 2; +                                goto cleanup; +                            } +                        } +                        sb_trie_insert(config, pieces[0], sb_strdup(pieces[1])); +                        sb_strv_free(pieces); +                        pieces = NULL; +                    } +                    break; +                default: +                    blogc_print_usage(); +                    fprintf(stderr, "blogc: error: invalid argument: -%c\n", +                        argv[i][1]); +                    rv = 2; +                    goto cleanup; +            } +        } +        else +            sources = sb_slist_append(sources, sb_strdup(argv[i])); +    } + +    if (!listing && sb_slist_length(sources) == 0) { +        blogc_print_usage(); +        fprintf(stderr, "blogc: error: one source file is required\n"); +        rv = 2; +        goto cleanup; +    } + +    if (!listing && sb_slist_length(sources) > 1) { +        blogc_print_usage(); +        fprintf(stderr, "blogc: error: only one source file should be provided, " +            "if running without '-l'\n"); +        rv = 2; +        goto cleanup; +    } + +    blogc_error_t *err = NULL; + +    sb_slist_t *s = blogc_source_parse_from_files(config, sources, &err); +    if (err != NULL) { +        blogc_error_print(err); +        rv = 2; +        goto cleanup2; +    } + +    sb_slist_t* l = blogc_template_parse_from_file(template, &err); +    if (err != NULL) { +        blogc_error_print(err); +        rv = 2; +        goto cleanup3; +    } + +    if (print != NULL) { +        const char *val = sb_trie_lookup(config, print); +        if (val == NULL) { +            fprintf(stderr, "blogc: error: configuration variable not found: %s\n", +                print); +            rv = 2; +        } +        else { +            printf("%s\n", val); +        } +        goto cleanup3; +    } + +    if (template == NULL) { +        blogc_print_usage(); +        fprintf(stderr, "blogc: error: argument -t is required when rendering content\n"); +        rv = 2; +        goto cleanup3; +    } + +    char *out = blogc_render(l, s, config, listing); + +    bool write_to_stdout = (output == NULL || (0 == strcmp(output, "-"))); + +    FILE *fp = stdout; +    if (!write_to_stdout) { +        blogc_mkdir_recursive(output); +        fp = fopen(output, "w"); +        if (fp == NULL) { +            fprintf(stderr, "blogc: error: failed to open output file (%s): %s\n", +                output, strerror(errno)); +            rv = 2; +            goto cleanup4; +        } +    } + +    if (out != NULL) +        fprintf(fp, "%s", out); + +    if (!write_to_stdout) +        fclose(fp); + +cleanup4: +    free(out); +cleanup3: +    blogc_template_free_stmts(l); +cleanup2: +    sb_slist_free_full(s, (sb_free_func_t) sb_trie_free); +    blogc_error_free(err); +cleanup: +    sb_trie_free(config); +    free(template); +    free(output); +    free(print); +    sb_slist_free_full(sources, free); +    return rv; +} | 
