From 0b09c111ed4f41d47b704374dd3a820efd7e5c7d Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Thu, 7 Dec 2017 20:07:30 -0600 Subject: [PATCH] main: implement a MSVC renderer (only some fragments supported) (closes #161) --- CMakeLists.txt | 2 +- Makefile.am | 2 +- main.c | 7 ++ meson.build | 1 + renderer-msvc.c | 174 ++++++++++++++++++++++++++++++++++++++++++++++++ renderer-msvc.h | 23 +++++++ 6 files changed, 207 insertions(+), 2 deletions(-) create mode 100644 renderer-msvc.c create mode 100644 renderer-msvc.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a9d5206..bd3ff86 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,7 +98,7 @@ ADD_SUBDIRECTORY(libpkgconf) #-------- Build and install executable -------- INCLUDE_DIRECTORIES(${libpkgconf_BINARY_DIR}) -ADD_EXECUTABLE(pkgconf main.c getopt_long.c) +ADD_EXECUTABLE(pkgconf main.c getopt_long.c renderer-msvc.c) TARGET_LINK_LIBRARIES(pkgconf libpkgconf) INSTALL(TARGETS pkgconf DESTINATION bin) diff --git a/Makefile.am b/Makefile.am index eeca2ce..a675e6e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -137,7 +137,7 @@ dist_man_MANS = \ man/pkg.m4.7 pkgconf_LDADD = libpkgconf.la -pkgconf_SOURCES = main.c getopt_long.c +pkgconf_SOURCES = main.c getopt_long.c renderer-msvc.c pkgconf_CPPFLAGS = -Ilibpkgconf noinst_HEADERS = getopt_long.h diff --git a/main.c b/main.c index 0494740..5ad7d1c 100644 --- a/main.c +++ b/main.c @@ -18,6 +18,7 @@ #include #include "libpkgconf/config.h" #include "getopt_long.h" +#include "renderer-msvc.h" #ifdef _WIN32 #include /* for _setmode() */ #include @@ -63,6 +64,7 @@ #define PKG_DEBUG (((uint64_t) 1) << 38) #define PKG_SHORT_ERRORS (((uint64_t) 1) << 39) #define PKG_EXISTS (((uint64_t) 1) << 40) +#define PKG_MSVC_SYNTAX (((uint64_t) 1) << 41) static pkgconf_client_t pkg_client; static const pkgconf_fragment_render_ops_t *want_render_ops = NULL; @@ -683,6 +685,7 @@ usage(void) printf(" --keep-system-libs keep -L%s entries in libs output\n", SYSTEM_LIBDIR); printf(" --path show the exact filenames for any matching .pc files\n"); printf(" --modversion print the specified module's version to stdout\n"); + printf(" --msvc-syntax print translatable fragments in MSVC syntax\n"); printf("\nreport bugs to <%s>.\n", PACKAGE_BUGREPORT); } @@ -779,6 +782,7 @@ main(int argc, char *argv[]) { "dont-define-prefix", no_argument, &want_flags, PKG_DONT_DEFINE_PREFIX }, { "dont-relocate-paths", no_argument, &want_flags, PKG_DONT_RELOCATE_PATHS }, { "env", required_argument, NULL, 48 }, + { "msvc-syntax", no_argument, &want_flags, PKG_MSVC_SYNTAX }, { NULL, 0, NULL, 0 } }; @@ -839,6 +843,9 @@ main(int argc, char *argv[]) } } + if ((want_flags & PKG_MSVC_SYNTAX) == PKG_MSVC_SYNTAX) + want_render_ops = msvc_renderer_get(); + if ((env_traverse_depth = getenv("PKG_CONFIG_MAXIMUM_TRAVERSE_DEPTH")) != NULL) maximum_traverse_depth = atoi(env_traverse_depth); diff --git a/meson.build b/meson.build index 33fe237..3261a38 100644 --- a/meson.build +++ b/meson.build @@ -79,6 +79,7 @@ libpkgconf = shared_library('pkgconf', pkgconf_exe = executable('pkgconf', 'main.c', 'getopt_long.c', + 'renderer-msvc.c', link_with : libpkgconf, install : true) diff --git a/renderer-msvc.c b/renderer-msvc.c new file mode 100644 index 0000000..87307a8 --- /dev/null +++ b/renderer-msvc.c @@ -0,0 +1,174 @@ +/* + * renderer-msvc.c + * MSVC library syntax renderer + * + * Copyright (c) 2017 pkgconf authors (see AUTHORS). + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * This software is provided 'as is' and without any warranty, express or + * implied. In no event shall the authors be liable for any damages arising + * from the use of this software. + */ + +#include +#include + +#include +#include "renderer-msvc.h" + +static inline char * +fragment_escape(const char *src) +{ + ssize_t outlen = strlen(src) + 10; + char *out = calloc(outlen, 1); + char *dst = out; + + while (*src) + { + if (((*src < ' ') || + (*src > ' ' && *src < '$') || + (*src > '$' && *src < '(') || + (*src > ')' && *src < '+') || + (*src > ':' && *src < '=') || + (*src > '=' && *src < '@') || + (*src > 'Z' && *src < '^') || + (*src == '`') || + (*src > 'z' && *src < '~') || + (*src > '~')) && *src != '\\') + *dst++ = '\\'; + + *dst++ = *src++; + + if ((ptrdiff_t)(dst - out) + 2 > outlen) + { + outlen *= 2; + out = realloc(out, outlen); + } + } + + *dst = 0; + return out; +} + +static inline size_t +fragment_len(const pkgconf_fragment_t *frag, bool escape) +{ + size_t len = 1; + + if (!escape) + len += strlen(frag->data); + else + { + char *tmp = fragment_escape(frag->data); + len += strlen(tmp); + free(tmp); + } + + return len; +} + +static inline bool +allowed_fragment(const pkgconf_fragment_t *frag) +{ + return !(!frag->type || frag->data == NULL || strchr("Ll", frag->type) == NULL); +} + +static size_t +msvc_renderer_render_len(const pkgconf_list_t *list, bool escape) +{ + size_t out = 1; /* trailing nul */ + pkgconf_node_t *node; + + PKGCONF_FOREACH_LIST_ENTRY(list->head, node) + { + const pkgconf_fragment_t *frag = node->data; + + if (!allowed_fragment(frag)) + continue; + + switch (frag->type) + { + case 'L': + out += 9; /* "/libpath:" */ + break; + case 'l': + out += 4; /* ".lib" */ + break; + default: + break; + } + + out += fragment_len(frag, escape); + } + + return out; +} + +static void +msvc_renderer_render_buf(const pkgconf_list_t *list, char *buf, size_t buflen, bool escape) +{ + pkgconf_node_t *node; + char *bptr = buf; + + memset(buf, 0, buflen); + + PKGCONF_FOREACH_LIST_ENTRY(list->head, node) + { + const pkgconf_fragment_t *frag = node->data; + size_t buf_remaining = buflen - (bptr - buf); + + if (!allowed_fragment(frag)) + continue; + + if (fragment_len(frag, escape) > buf_remaining) + break; + + if (frag->type == 'L') + { + size_t cnt = pkgconf_strlcpy(bptr, "/libpath:", buf_remaining); + bptr += cnt; + buf_remaining -= cnt; + } + + if (!escape) + { + size_t cnt = pkgconf_strlcpy(bptr, frag->data, buf_remaining); + bptr += cnt; + buf_remaining -= cnt; + } + else + { + char *tmp = fragment_escape(frag->data); + size_t cnt = pkgconf_strlcpy(bptr, tmp, buf_remaining); + free(tmp); + + bptr += cnt; + buf_remaining -= cnt; + } + + if (frag->type == 'l') + { + size_t cnt = pkgconf_strlcpy(bptr, ".lib", buf_remaining); + bptr += cnt; + buf_remaining -= cnt; + } + + *bptr++ = ' '; + } + + *bptr = '\0'; +} + +static const pkgconf_fragment_render_ops_t msvc_renderer_ops = { + .render_len = msvc_renderer_render_len, + .render_buf = msvc_renderer_render_buf +}; + +const pkgconf_fragment_render_ops_t * +msvc_renderer_get(void) +{ + return &msvc_renderer_ops; +} diff --git a/renderer-msvc.h b/renderer-msvc.h new file mode 100644 index 0000000..2a095fd --- /dev/null +++ b/renderer-msvc.h @@ -0,0 +1,23 @@ +/* + * renderer-msvc.h + * MSVC library syntax renderer header + * + * Copyright (c) 2017 pkgconf authors (see AUTHORS). + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * This software is provided 'as is' and without any warranty, express or + * implied. In no event shall the authors be liable for any damages arising + * from the use of this software. + */ + +#ifndef RENDERER_MSVC_H +#define RENDERER_MSVC_H + +#include + +const pkgconf_fragment_render_ops_t *msvc_renderer_get(void); + +#endif