1 /*
2 * renderer-msvc.c
3 * MSVC library syntax renderer
4 *
5 * Copyright (c) 2017 pkgconf authors (see AUTHORS).
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * This software is provided 'as is' and without any warranty, express or
12 * implied. In no event shall the authors be liable for any damages arising
13 * from the use of this software.
14 */
15
16 #include <string.h>
17 #include <stdlib.h>
18
19 #include <libpkgconf/libpkgconf.h>
20 #include "renderer-msvc.h"
21
22 static inline bool
fragment_should_quote(const pkgconf_fragment_t * frag)23 fragment_should_quote(const pkgconf_fragment_t *frag)
24 {
25 const char *src;
26
27 if (frag->data == NULL)
28 return false;
29
30 for (src = frag->data; *src; src++)
31 {
32 if (((*src < ' ') ||
33 (*src >= (' ' + (frag->children.head != NULL ? 1 : 0)) && *src < '$') ||
34 (*src > '$' && *src < '(') ||
35 (*src > ')' && *src < '+') ||
36 (*src > ':' && *src < '=') ||
37 (*src > '=' && *src < '@') ||
38 (*src > 'Z' && *src < '^') ||
39 (*src == '`') ||
40 (*src > 'z' && *src < '~') ||
41 (*src > '~')))
42 return true;
43 }
44
45 return false;
46 }
47
48 static inline size_t
fragment_len(const pkgconf_fragment_t * frag)49 fragment_len(const pkgconf_fragment_t *frag)
50 {
51 size_t len = 1;
52
53 if (frag->type)
54 len += 2;
55
56 if (frag->data != NULL)
57 {
58 len += strlen(frag->data);
59
60 if (fragment_should_quote(frag))
61 len += 2;
62 }
63
64 return len;
65 }
66
67 static inline bool
allowed_fragment(const pkgconf_fragment_t * frag)68 allowed_fragment(const pkgconf_fragment_t *frag)
69 {
70 return !(!frag->type || frag->data == NULL || strchr("DILl", frag->type) == NULL);
71 }
72
73 static size_t
msvc_renderer_render_len(const pkgconf_list_t * list,bool escape)74 msvc_renderer_render_len(const pkgconf_list_t *list, bool escape)
75 {
76 (void) escape;
77
78 size_t out = 1; /* trailing nul */
79 pkgconf_node_t *node;
80
81 PKGCONF_FOREACH_LIST_ENTRY(list->head, node)
82 {
83 const pkgconf_fragment_t *frag = node->data;
84
85 if (!allowed_fragment(frag))
86 continue;
87
88 switch (frag->type)
89 {
90 case 'L':
91 out += 9; /* "/libpath:" */
92 break;
93 case 'l':
94 out += 4; /* ".lib" */
95 break;
96 default:
97 break;
98 }
99
100 out += fragment_len(frag);
101 }
102
103 return out;
104 }
105
106 static void
msvc_renderer_render_buf(const pkgconf_list_t * list,char * buf,size_t buflen,bool escape)107 msvc_renderer_render_buf(const pkgconf_list_t *list, char *buf, size_t buflen, bool escape)
108 {
109 pkgconf_node_t *node;
110 char *bptr = buf;
111
112 memset(buf, 0, buflen);
113
114 PKGCONF_FOREACH_LIST_ENTRY(list->head, node)
115 {
116 const pkgconf_fragment_t *frag = node->data;
117 size_t buf_remaining = buflen - (bptr - buf);
118 size_t cnt;
119
120 if (!allowed_fragment(frag))
121 continue;
122
123 if (fragment_len(frag) > buf_remaining)
124 break;
125
126 switch(frag->type) {
127 case 'D':
128 case 'I':
129 *bptr++ = '/';
130 *bptr++ = frag->type;
131 break;
132 case 'L':
133 cnt = pkgconf_strlcpy(bptr, "/libpath:", buf_remaining);
134 bptr += cnt;
135 buf_remaining -= cnt;
136 break;
137 }
138
139 escape = fragment_should_quote(frag);
140
141 if (escape)
142 *bptr++ = '"';
143
144 cnt = pkgconf_strlcpy(bptr, frag->data, buf_remaining);
145 bptr += cnt;
146 buf_remaining -= cnt;
147
148 if (frag->type == 'l')
149 {
150 cnt = pkgconf_strlcpy(bptr, ".lib", buf_remaining);
151 bptr += cnt;
152 }
153
154 if (escape)
155 *bptr++ = '"';
156
157 *bptr++ = ' ';
158 }
159
160 *bptr = '\0';
161 }
162
163 static const pkgconf_fragment_render_ops_t msvc_renderer_ops = {
164 .render_len = msvc_renderer_render_len,
165 .render_buf = msvc_renderer_render_buf
166 };
167
168 const pkgconf_fragment_render_ops_t *
msvc_renderer_get(void)169 msvc_renderer_get(void)
170 {
171 return &msvc_renderer_ops;
172 }
173