Fix typos
[TortoiseGit.git] / src / TortoisePlink / MISC.H
blob41c47eef878b3fbc2d4c9b7648c77b81ff5c2a43
1 /*\r
2  * Header for miscellaneous helper functions, mostly defined in the\r
3  * utils subdirectory.\r
4  */\r
5 \r
6 #ifndef PUTTY_MISC_H\r
7 #define PUTTY_MISC_H\r
8 \r
9 #include "defs.h"\r
10 #include "puttymem.h"\r
11 #include "marshal.h"\r
13 #include <stdio.h>                     /* for FILE * */\r
14 #include <stdarg.h>                    /* for va_list */\r
15 #include <stdlib.h>                    /* for abort */\r
16 #include <time.h>                      /* for struct tm */\r
17 #include <limits.h>                    /* for INT_MAX/MIN */\r
18 #include <assert.h>                    /* for assert (obviously) */\r
20 unsigned long parse_blocksize(const char *bs);\r
21 char ctrlparse(char *s, char **next);\r
23 size_t host_strcspn(const char *s, const char *set);\r
24 char *host_strchr(const char *s, int c);\r
25 char *host_strrchr(const char *s, int c);\r
26 char *host_strduptrim(const char *s);\r
28 char *dupstr(const char *s);\r
29 char *dupcat_fn(const char *s1, ...);\r
30 #define dupcat(...) dupcat_fn(__VA_ARGS__, (const char *)NULL)\r
31 char *dupprintf(const char *fmt, ...) PRINTF_LIKE(1, 2);\r
32 char *dupvprintf(const char *fmt, va_list ap);\r
33 void burnstr(char *string);\r
35 /*\r
36  * The visible part of a strbuf structure. There's a surrounding\r
37  * implementation struct in strbuf.c, which isn't exposed to client\r
38  * code.\r
39  */\r
40 struct strbuf {\r
41     char *s;\r
42     unsigned char *u;\r
43     size_t len;\r
44     BinarySink_IMPLEMENTATION;\r
45 };\r
47 /* strbuf constructors: strbuf_new_nm and strbuf_new differ in that a\r
48  * strbuf constructed using the _nm version will resize itself by\r
49  * alloc/copy/smemclr/free instead of realloc. Use that version for\r
50  * data sensitive enough that it's worth costing performance to\r
51  * avoid copies of it lingering in process memory. */\r
52 strbuf *strbuf_new(void);\r
53 strbuf *strbuf_new_nm(void);\r
55 /* Helpers to allocate a strbuf containing an existing string */\r
56 strbuf *strbuf_dup(ptrlen string);\r
57 strbuf *strbuf_dup_nm(ptrlen string);\r
59 void strbuf_free(strbuf *buf);\r
60 void *strbuf_append(strbuf *buf, size_t len);\r
61 void strbuf_shrink_to(strbuf *buf, size_t new_len);\r
62 void strbuf_shrink_by(strbuf *buf, size_t amount_to_remove);\r
63 char *strbuf_to_str(strbuf *buf); /* does free buf, but you must free result */\r
64 static inline void strbuf_clear(strbuf *buf) { strbuf_shrink_to(buf, 0); }\r
65 bool strbuf_chomp(strbuf *buf, char char_to_remove);\r
67 strbuf *strbuf_new_for_agent_query(void);\r
68 void strbuf_finalise_agent_query(strbuf *buf);\r
70 /* String-to-Unicode converters that auto-allocate the destination and\r
71  * work around the rather deficient interface of mb_to_wc. */\r
72 wchar_t *dup_mb_to_wc_c(int codepage, int flags, const char *string, int len);\r
73 wchar_t *dup_mb_to_wc(int codepage, int flags, const char *string);\r
74 char *dup_wc_to_mb_c(int codepage, int flags, const wchar_t *string, int len,\r
75                      const char *defchr);\r
76 char *dup_wc_to_mb(int codepage, int flags, const wchar_t *string,\r
77                    const char *defchr);\r
79 static inline int toint(unsigned u)\r
80 {\r
81     /*\r
82      * Convert an unsigned to an int, without running into the\r
83      * undefined behaviour which happens by the strict C standard if\r
84      * the value overflows. You'd hope that sensible compilers would\r
85      * do the sensible thing in response to a cast, but actually I\r
86      * don't trust modern compilers not to do silly things like\r
87      * assuming that _obviously_ you wouldn't have caused an overflow\r
88      * and so they can elide an 'if (i < 0)' test immediately after\r
89      * the cast.\r
90      *\r
91      * Sensible compilers ought of course to optimise this entire\r
92      * function into 'just return the input value', and since it's\r
93      * also declared inline, elide it completely in their output.\r
94      */\r
95     if (u <= (unsigned)INT_MAX)\r
96         return (int)u;\r
97     else if (u >= (unsigned)INT_MIN)   /* wrap in cast _to_ unsigned is OK */\r
98         return INT_MIN + (int)(u - (unsigned)INT_MIN);\r
99     else\r
100         return INT_MIN; /* fallback; should never occur on binary machines */\r
103 char *fgetline(FILE *fp);\r
104 bool read_file_into(BinarySink *bs, FILE *fp);\r
105 char *chomp(char *str);\r
106 bool strstartswith(const char *s, const char *t);\r
107 bool strendswith(const char *s, const char *t);\r
109 void base64_encode_atom(const unsigned char *data, int n, char *out);\r
110 int base64_decode_atom(const char *atom, unsigned char *out);\r
111 void base64_decode_bs(BinarySink *bs, ptrlen data);\r
112 void base64_decode_fp(FILE *fp, ptrlen data);\r
113 strbuf *base64_decode_sb(ptrlen data);\r
114 void base64_encode_bs(BinarySink *bs, ptrlen data, int cpl);\r
115 void base64_encode_fp(FILE *fp, ptrlen data, int cpl);\r
116 strbuf *base64_encode_sb(ptrlen data, int cpl);\r
117 bool base64_valid(ptrlen data);\r
119 void percent_encode_bs(BinarySink *bs, ptrlen data, const char *badchars);\r
120 void percent_encode_fp(FILE *fp, ptrlen data, const char *badchars);\r
121 strbuf *percent_encode_sb(ptrlen data, const char *badchars);\r
122 void percent_decode_bs(BinarySink *bs, ptrlen data);\r
123 void percent_decode_fp(FILE *fp, ptrlen data);\r
124 strbuf *percent_decode_sb(ptrlen data);\r
126 struct bufchain_granule;\r
127 struct bufchain_tag {\r
128     struct bufchain_granule *head, *tail;\r
129     size_t buffersize;           /* current amount of buffered data */\r
131     void (*queue_idempotent_callback)(IdempotentCallback *ic);\r
132     IdempotentCallback *ic;\r
133 };\r
135 void bufchain_init(bufchain *ch);\r
136 void bufchain_clear(bufchain *ch);\r
137 size_t bufchain_size(bufchain *ch);\r
138 void bufchain_add(bufchain *ch, const void *data, size_t len);\r
139 ptrlen bufchain_prefix(bufchain *ch);\r
140 void bufchain_consume(bufchain *ch, size_t len);\r
141 void bufchain_fetch(bufchain *ch, void *data, size_t len);\r
142 void bufchain_fetch_consume(bufchain *ch, void *data, size_t len);\r
143 bool bufchain_try_consume(bufchain *ch, size_t len);\r
144 bool bufchain_try_fetch(bufchain *ch, void *data, size_t len);\r
145 bool bufchain_try_fetch_consume(bufchain *ch, void *data, size_t len);\r
146 size_t bufchain_fetch_consume_up_to(bufchain *ch, void *data, size_t len);\r
147 void bufchain_set_callback_inner(\r
148     bufchain *ch, IdempotentCallback *ic,\r
149     void (*queue_idempotent_callback)(IdempotentCallback *ic));\r
150 static inline void bufchain_set_callback(bufchain *ch, IdempotentCallback *ic)\r
152     extern void queue_idempotent_callback(struct IdempotentCallback *ic);\r
153     /* Wrapper that puts in the standard queue_idempotent_callback\r
154      * function. Lives here rather than in bufchain.c so that\r
155      * standalone programs can use the bufchain facility without this\r
156      * optional callback feature and not need to provide a stub of\r
157      * queue_idempotent_callback. */\r
158     bufchain_set_callback_inner(ch, ic, queue_idempotent_callback);\r
161 bool validate_manual_hostkey(char *key);\r
163 struct tm ltime(void);\r
165 /*\r
166  * Special form of strcmp which can cope with NULL inputs. NULL is\r
167  * defined to sort before even the empty string.\r
168  */\r
169 int nullstrcmp(const char *a, const char *b);\r
171 static inline ptrlen make_ptrlen(const void *ptr, size_t len)\r
173     ptrlen pl;\r
174     pl.ptr = ptr;\r
175     pl.len = len;\r
176     return pl;\r
179 static inline const void *ptrlen_end(ptrlen pl)\r
181     return (const char *)pl.ptr + pl.len;\r
184 static inline ptrlen make_ptrlen_startend(const void *startv, const void *endv)\r
186     const char *start = (const char *)startv, *end = (const char *)endv;\r
187     assert(end >= start);\r
188     ptrlen pl;\r
189     pl.ptr = start;\r
190     pl.len = end - start;\r
191     return pl;\r
194 static inline ptrlen ptrlen_from_asciz(const char *str)\r
196     return make_ptrlen(str, strlen(str));\r
199 static inline ptrlen ptrlen_from_strbuf(strbuf *sb)\r
201     return make_ptrlen(sb->u, sb->len);\r
204 bool ptrlen_eq_string(ptrlen pl, const char *str);\r
205 bool ptrlen_eq_ptrlen(ptrlen pl1, ptrlen pl2);\r
206 int ptrlen_strcmp(ptrlen pl1, ptrlen pl2);\r
207 /* ptrlen_startswith and ptrlen_endswith write through their 'tail'\r
208  * argument if and only if it is non-NULL and they return true. Hence\r
209  * you can write ptrlen_startswith(thing, prefix, &thing), writing\r
210  * back to the same ptrlen it read from, to remove a prefix if present\r
211  * and say whether it did so. */\r
212 bool ptrlen_startswith(ptrlen whole, ptrlen prefix, ptrlen *tail);\r
213 bool ptrlen_endswith(ptrlen whole, ptrlen suffix, ptrlen *tail);\r
214 ptrlen ptrlen_get_word(ptrlen *input, const char *separators);\r
215 bool ptrlen_contains(ptrlen input, const char *characters);\r
216 bool ptrlen_contains_only(ptrlen input, const char *characters);\r
217 char *mkstr(ptrlen pl);\r
218 int string_length_for_printf(size_t);\r
219 /* Derive two printf arguments from a ptrlen, suitable for "%.*s" */\r
220 #define PTRLEN_PRINTF(pl) \\r
221     string_length_for_printf((pl).len), (const char *)(pl).ptr\r
222 /* Make a ptrlen out of a compile-time string literal. We try to\r
223  * enforce that it _is_ a string literal by token-pasting "" on to it,\r
224  * which should provoke a compile error if it's any other kind of\r
225  * string. */\r
226 #define PTRLEN_LITERAL(stringlit) \\r
227     TYPECHECK("" stringlit "", make_ptrlen(stringlit, sizeof(stringlit)-1))\r
228 /* Make a ptrlen out of a compile-time string literal in a way that\r
229  * allows you to declare the ptrlen itself as a compile-time initialiser. */\r
230 #define PTRLEN_DECL_LITERAL(stringlit) \\r
231     { TYPECHECK("" stringlit "", stringlit), sizeof(stringlit)-1 }\r
232 /* Make a ptrlen out of a constant byte array. */\r
233 #define PTRLEN_FROM_CONST_BYTES(a) make_ptrlen(a, sizeof(a))\r
235 void wordwrap(BinarySink *bs, ptrlen input, size_t maxwid);\r
237 /* Wipe sensitive data out of memory that's about to be freed. Simpler\r
238  * than memset because we don't need the fill char parameter; also\r
239  * attempts (by fiddly use of volatile) to inhibit the compiler from\r
240  * over-cleverly trying to optimise the memset away because it knows\r
241  * the variable is going out of scope. */\r
242 void smemclr(void *b, size_t len);\r
244 /* Compare two fixed-length chunks of memory for equality, without\r
245  * data-dependent control flow (so an attacker with a very accurate\r
246  * stopwatch can't try to guess where the first mismatching byte was).\r
247  * Returns 0 for mismatch or 1 for equality (unlike memcmp), hinted at\r
248  * by the 'eq' in the name. */\r
249 unsigned smemeq(const void *av, const void *bv, size_t len);\r
251 /* Encode a single UTF-8 character. Assumes that illegal characters\r
252  * (such as things in the surrogate range, or > 0x10FFFF) have already\r
253  * been removed. */\r
254 size_t encode_utf8(void *output, unsigned long ch);\r
256 /* Encode a wide-character string into UTF-8. Tolerates surrogates if\r
257  * sizeof(wchar_t) == 2, assuming that in that case the wide string is\r
258  * encoded in UTF-16. */\r
259 char *encode_wide_string_as_utf8(const wchar_t *wstr);\r
261 /* Decode a single UTF-8 character. Returns U+FFFD for any of the\r
262  * illegal cases. */\r
263 unsigned long decode_utf8(const char **utf8);\r
265 /* Decode a single UTF-8 character to an output buffer of the\r
266  * platform's wchar_t. May write a pair of surrogates if\r
267  * sizeof(wchar_t) == 2, assuming that in that case the wide string is\r
268  * encoded in UTF-16. Otherwise, writes one character. Returns the\r
269  * number written. */\r
270 size_t decode_utf8_to_wchar(const char **utf8, wchar_t *out);\r
272 /* Write a string out in C string-literal format. */\r
273 void write_c_string_literal(FILE *fp, ptrlen str);\r
275 char *buildinfo(const char *newline);\r
277 /*\r
278  * A function you can put at points in the code where execution should\r
279  * never reach in the first place. Better than assert(false), or even\r
280  * assert(false && "some explanatory message"), because some compilers\r
281  * don't interpret assert(false) as a declaration of unreachability,\r
282  * so they may still warn about pointless things like some variable\r
283  * not being initialised on the unreachable code path.\r
284  *\r
285  * I follow the assertion with a call to abort() just in case someone\r
286  * compiles with -DNDEBUG, and I wrap that abort inside my own\r
287  * function labelled NORETURN just in case some unusual kind of system\r
288  * header wasn't foresighted enough to label abort() itself that way.\r
289  */\r
290 static inline NORETURN void unreachable_internal(void) { abort(); }\r
291 #define unreachable(msg) (assert(false && msg), unreachable_internal())\r
293 /*\r
294  * Debugging functions.\r
295  *\r
296  * Output goes to debug.log\r
297  *\r
298  * debug() is like printf().\r
299  *\r
300  * dmemdump() and dmemdumpl() both do memory dumps.  The difference\r
301  * is that dmemdumpl() is more suited for when the memory address is\r
302  * important (say because you'll be recording pointer values later\r
303  * on).  dmemdump() is more concise.\r
304  */\r
306 #ifdef DEBUG\r
307 void debug_printf(const char *fmt, ...) PRINTF_LIKE(1, 2);\r
308 void debug_memdump(const void *buf, int len, bool L);\r
309 #define debug(...) (debug_printf(__VA_ARGS__))\r
310 #define dmemdump(buf,len) (debug_memdump(buf, len, false))\r
311 #define dmemdumpl(buf,len) (debug_memdump(buf, len, true))\r
312 #else\r
313 #define debug(...) ((void)0)\r
314 #define dmemdump(buf,len) ((void)0)\r
315 #define dmemdumpl(buf,len) ((void)0)\r
316 #endif\r
318 #ifndef lenof\r
319 #define lenof(x) ( (sizeof((x))) / (sizeof(*(x))))\r
320 #endif\r
322 #ifndef min\r
323 #define min(x,y) ( (x) < (y) ? (x) : (y) )\r
324 #endif\r
325 #ifndef max\r
326 #define max(x,y) ( (x) > (y) ? (x) : (y) )\r
327 #endif\r
329 static inline uint64_t GET_64BIT_LSB_FIRST(const void *vp)\r
331     const uint8_t *p = (const uint8_t *)vp;\r
332     return (((uint64_t)p[0]      ) | ((uint64_t)p[1] <<  8) |\r
333             ((uint64_t)p[2] << 16) | ((uint64_t)p[3] << 24) |\r
334             ((uint64_t)p[4] << 32) | ((uint64_t)p[5] << 40) |\r
335             ((uint64_t)p[6] << 48) | ((uint64_t)p[7] << 56));\r
338 static inline void PUT_64BIT_LSB_FIRST(void *vp, uint64_t value)\r
340     uint8_t *p = (uint8_t *)vp;\r
341     p[0] = (uint8_t)(value);\r
342     p[1] = (uint8_t)(value >> 8);\r
343     p[2] = (uint8_t)(value >> 16);\r
344     p[3] = (uint8_t)(value >> 24);\r
345     p[4] = (uint8_t)(value >> 32);\r
346     p[5] = (uint8_t)(value >> 40);\r
347     p[6] = (uint8_t)(value >> 48);\r
348     p[7] = (uint8_t)(value >> 56);\r
351 static inline uint32_t GET_32BIT_LSB_FIRST(const void *vp)\r
353     const uint8_t *p = (const uint8_t *)vp;\r
354     return (((uint32_t)p[0]      ) | ((uint32_t)p[1] <<  8) |\r
355             ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24));\r
358 static inline void PUT_32BIT_LSB_FIRST(void *vp, uint32_t value)\r
360     uint8_t *p = (uint8_t *)vp;\r
361     p[0] = (uint8_t)(value);\r
362     p[1] = (uint8_t)(value >> 8);\r
363     p[2] = (uint8_t)(value >> 16);\r
364     p[3] = (uint8_t)(value >> 24);\r
367 static inline uint16_t GET_16BIT_LSB_FIRST(const void *vp)\r
369     const uint8_t *p = (const uint8_t *)vp;\r
370     return (((uint16_t)p[0]      ) | ((uint16_t)p[1] <<  8));\r
373 static inline void PUT_16BIT_LSB_FIRST(void *vp, uint16_t value)\r
375     uint8_t *p = (uint8_t *)vp;\r
376     p[0] = (uint8_t)(value);\r
377     p[1] = (uint8_t)(value >> 8);\r
380 static inline uint64_t GET_64BIT_MSB_FIRST(const void *vp)\r
382     const uint8_t *p = (const uint8_t *)vp;\r
383     return (((uint64_t)p[7]      ) | ((uint64_t)p[6] <<  8) |\r
384             ((uint64_t)p[5] << 16) | ((uint64_t)p[4] << 24) |\r
385             ((uint64_t)p[3] << 32) | ((uint64_t)p[2] << 40) |\r
386             ((uint64_t)p[1] << 48) | ((uint64_t)p[0] << 56));\r
389 static inline void PUT_64BIT_MSB_FIRST(void *vp, uint64_t value)\r
391     uint8_t *p = (uint8_t *)vp;\r
392     p[7] = (uint8_t)(value);\r
393     p[6] = (uint8_t)(value >> 8);\r
394     p[5] = (uint8_t)(value >> 16);\r
395     p[4] = (uint8_t)(value >> 24);\r
396     p[3] = (uint8_t)(value >> 32);\r
397     p[2] = (uint8_t)(value >> 40);\r
398     p[1] = (uint8_t)(value >> 48);\r
399     p[0] = (uint8_t)(value >> 56);\r
402 static inline uint32_t GET_32BIT_MSB_FIRST(const void *vp)\r
404     const uint8_t *p = (const uint8_t *)vp;\r
405     return (((uint32_t)p[3]      ) | ((uint32_t)p[2] <<  8) |\r
406             ((uint32_t)p[1] << 16) | ((uint32_t)p[0] << 24));\r
409 static inline void PUT_32BIT_MSB_FIRST(void *vp, uint32_t value)\r
411     uint8_t *p = (uint8_t *)vp;\r
412     p[3] = (uint8_t)(value);\r
413     p[2] = (uint8_t)(value >> 8);\r
414     p[1] = (uint8_t)(value >> 16);\r
415     p[0] = (uint8_t)(value >> 24);\r
418 static inline uint16_t GET_16BIT_MSB_FIRST(const void *vp)\r
420     const uint8_t *p = (const uint8_t *)vp;\r
421     return (((uint16_t)p[1]      ) | ((uint16_t)p[0] <<  8));\r
424 static inline void PUT_16BIT_MSB_FIRST(void *vp, uint16_t value)\r
426     uint8_t *p = (uint8_t *)vp;\r
427     p[1] = (uint8_t)(value);\r
428     p[0] = (uint8_t)(value >> 8);\r
431 /* For use in X11-related applications, an endianness-variable form of\r
432  * {GET,PUT}_16BIT which expects 'endian' to be either 'B' or 'l' */\r
434 static inline uint16_t GET_16BIT_X11(char endian, const void *p)\r
436     return endian == 'B' ? GET_16BIT_MSB_FIRST(p) : GET_16BIT_LSB_FIRST(p);\r
439 static inline void PUT_16BIT_X11(char endian, void *p, uint16_t value)\r
441     if (endian == 'B')\r
442         PUT_16BIT_MSB_FIRST(p, value);\r
443     else\r
444         PUT_16BIT_LSB_FIRST(p, value);\r
447 /* Replace NULL with the empty string, permitting an idiom in which we\r
448  * get a string (pointer,length) pair that might be NULL,0 and can\r
449  * then safely say things like printf("%.*s", length, NULLTOEMPTY(ptr)) */\r
450 static inline const char *NULLTOEMPTY(const char *s)\r
452     return s ? s : "";\r
455 /* StripCtrlChars, defined in stripctrl.c: an adapter you can put on\r
456  * the front of one BinarySink and which functions as one in turn.\r
457  * Interprets its input as a stream of multibyte characters in the\r
458  * system locale, and removes any that are not either printable\r
459  * characters or newlines. */\r
460 struct StripCtrlChars {\r
461     BinarySink_IMPLEMENTATION;\r
462     /* and this is contained in a larger structure */\r
463 };\r
464 StripCtrlChars *stripctrl_new(\r
465     BinarySink *bs_out, bool permit_cr, wchar_t substitution);\r
466 StripCtrlChars *stripctrl_new_term_fn(\r
467     BinarySink *bs_out, bool permit_cr, wchar_t substitution,\r
468     Terminal *term, unsigned long (*translate)(\r
469         Terminal *, term_utf8_decode *, unsigned char));\r
470 #define stripctrl_new_term(bs, cr, sub, term) \\r
471     stripctrl_new_term_fn(bs, cr, sub, term, term_translate)\r
472 void stripctrl_retarget(StripCtrlChars *sccpub, BinarySink *new_bs_out);\r
473 void stripctrl_reset(StripCtrlChars *sccpub);\r
474 void stripctrl_free(StripCtrlChars *sanpub);\r
475 void stripctrl_enable_line_limiting(StripCtrlChars *sccpub);\r
476 char *stripctrl_string_ptrlen(StripCtrlChars *sccpub, ptrlen str);\r
477 static inline char *stripctrl_string(StripCtrlChars *sccpub, const char *str)\r
479     return stripctrl_string_ptrlen(sccpub, ptrlen_from_asciz(str));\r
482 /*\r
483  * A mechanism for loading a file from disk into a memory buffer where\r
484  * it can be picked apart as a BinarySource.\r
485  */\r
486 struct LoadedFile {\r
487     char *data;\r
488     size_t len, max_size;\r
489     BinarySource_IMPLEMENTATION;\r
490 };\r
491 typedef enum {\r
492     LF_OK,      /* file loaded successfully */\r
493     LF_TOO_BIG, /* file didn't fit in buffer */\r
494     LF_ERROR,   /* error from stdio layer */\r
495 } LoadFileStatus;\r
496 LoadedFile *lf_new(size_t max_size);\r
497 void lf_free(LoadedFile *lf);\r
498 LoadFileStatus lf_load_fp(LoadedFile *lf, FILE *fp);\r
499 LoadFileStatus lf_load(LoadedFile *lf, const Filename *filename);\r
500 static inline ptrlen ptrlen_from_lf(LoadedFile *lf)\r
501 { return make_ptrlen(lf->data, lf->len); }\r
503 /* Set the memory block of 'size' bytes at 'out' to the bitwise XOR of\r
504  * the two blocks of the same size at 'in1' and 'in2'.\r
505  *\r
506  * 'out' may point to exactly the same address as one of the inputs,\r
507  * but if the input and output blocks overlap in any other way, the\r
508  * result of this function is not guaranteed. No memmove-style effort\r
509  * is made to handle difficult overlap cases. */\r
510 void memxor(uint8_t *out, const uint8_t *in1, const uint8_t *in2, size_t size);\r
512 /* Boolean expressions used in OpenSSH certificate configuration */\r
513 bool cert_expr_valid(const char *expression,\r
514                      char **error_msg, ptrlen *error_loc);\r
515 bool cert_expr_match_str(const char *expression,\r
516                          const char *hostname, unsigned port);\r
517 /* Build a certificate expression out of hostname wildcards. Required\r
518  * to handle legacy configuration from early in development, when\r
519  * multiple wildcards were stored separately in config, implicitly\r
520  * ORed together. */\r
521 CertExprBuilder *cert_expr_builder_new(void);\r
522 void cert_expr_builder_free(CertExprBuilder *eb);\r
523 void cert_expr_builder_add(CertExprBuilder *eb, const char *wildcard);\r
524 char *cert_expr_expression(CertExprBuilder *eb);\r
526 #endif\r