Browse Source

libpkgconf: refactor out the rfc822 message parser so that the cross-personality code can share it

William Pitcock 1 year ago
parent
commit
1244f8f8e7
6 changed files with 127 additions and 71 deletions
  1. 2
    1
      Makefile.am
  2. 1
    0
      libpkgconf/CMakeLists.txt
  3. 7
    1
      libpkgconf/libpkgconf.h
  4. 95
    0
      libpkgconf/parser.c
  5. 21
    69
      libpkgconf/pkg.c
  6. 1
    0
      meson.build

+ 2
- 1
Makefile.am View File

@@ -137,7 +137,8 @@ libpkgconf_la_SOURCES  =	\
137 137
 		libpkgconf/dependency.c		\
138 138
 		libpkgconf/queue.c		\
139 139
 		libpkgconf/path.c		\
140
-		libpkgconf/personality.c
140
+		libpkgconf/personality.c	\
141
+		libpkgconf/parser.c
141 142
 libpkgconf_la_LDFLAGS = -no-undefined -version-info 3:0:0 -export-symbols-regex '^pkgconf_'
142 143
 
143 144
 dist_man_MANS    = 		\

+ 1
- 0
libpkgconf/CMakeLists.txt View File

@@ -13,6 +13,7 @@ ADD_LIBRARY(libpkgconf SHARED
13 13
     dependency.c
14 14
     fileio.c
15 15
     fragment.c
16
+    parser.c
16 17
     path.c
17 18
     personality.c
18 19
     pkg.c

+ 7
- 1
libpkgconf/libpkgconf.h View File

@@ -248,7 +248,6 @@ PKGCONF_API const pkgconf_cross_personality_t *pkgconf_cross_personality_default
248 248
 #define PKGCONF_PKG_ERRF_PACKAGE_CONFLICT	0x4
249 249
 #define PKGCONF_PKG_ERRF_DEPGRAPH_BREAK		0x8
250 250
 
251
-/* pkg.c */
252 251
 #if defined(__GNUC__) || defined(__INTEL_COMPILER)
253 252
 #define PRINTFLIKE(fmtarg, firstvararg) \
254 253
         __attribute__((__format__ (__printf__, fmtarg, firstvararg)))
@@ -259,6 +258,13 @@ PKGCONF_API const pkgconf_cross_personality_t *pkgconf_cross_personality_default
259 258
 #define DEPRECATED
260 259
 #endif /* defined(__INTEL_COMPILER) || defined(__GNUC__) */
261 260
 
261
+/* parser.c */
262
+typedef void (*pkgconf_parser_operand_func_t)(void *data, const size_t lineno, const char *key, const char *value);
263
+typedef void (*pkgconf_parser_warn_func_t)(void *data, const char *fmt, ...);
264
+
265
+PKGCONF_API void pkgconf_parser_parse(FILE *f, void *data, const pkgconf_parser_operand_func_t *ops, const pkgconf_parser_warn_func_t warnfunc, const char *filename);
266
+
267
+/* pkg.c */
262 268
 PKGCONF_API bool pkgconf_error(const pkgconf_client_t *client, const char *format, ...) PRINTFLIKE(2, 3);
263 269
 PKGCONF_API bool pkgconf_warn(const pkgconf_client_t *client, const char *format, ...) PRINTFLIKE(2, 3);
264 270
 PKGCONF_API bool pkgconf_trace(const pkgconf_client_t *client, const char *filename, size_t lineno, const char *funcname, const char *format, ...) PRINTFLIKE(5, 6);

+ 95
- 0
libpkgconf/parser.c View File

@@ -0,0 +1,95 @@
1
+/*
2
+ * parser.c
3
+ * rfc822 message parser
4
+ *
5
+ * Copyright (c) 2018 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 <libpkgconf/stdinc.h>
17
+#include <libpkgconf/config.h>
18
+#include <libpkgconf/libpkgconf.h>
19
+
20
+/*
21
+ * !doc
22
+ *
23
+ * .. c:function:: pkgconf_pkg_t *pkgconf_pkg_new_from_file(const pkgconf_client_t *client, const char *filename, FILE *f)
24
+ *
25
+ *    Parse a .pc file into a pkgconf_pkg_t object structure.
26
+ *
27
+ *    :param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
28
+ *    :param char* filename: The filename of the package file (including full path).
29
+ *    :param FILE* f: The file object to read from.
30
+ *    :returns: A ``pkgconf_pkg_t`` object which contains the package data.
31
+ *    :rtype: pkgconf_pkg_t *
32
+ */
33
+void
34
+pkgconf_parser_parse(FILE *f, void *data, const pkgconf_parser_operand_func_t *ops, const pkgconf_parser_warn_func_t warnfunc, const char *filename)
35
+{
36
+	char readbuf[PKGCONF_BUFSIZE];
37
+	size_t lineno = 0;
38
+
39
+	while (pkgconf_fgetline(readbuf, PKGCONF_BUFSIZE, f) != NULL)
40
+	{
41
+		char op, *p, *key, *value;
42
+		bool warned_key_whitespace = false, warned_value_whitespace = false;
43
+
44
+		lineno++;
45
+
46
+		p = readbuf;
47
+		while (*p && (isalpha((unsigned int)*p) || isdigit((unsigned int)*p) || *p == '_' || *p == '.'))
48
+			p++;
49
+
50
+		key = readbuf;
51
+		if (!isalpha((unsigned int)*key) && !isdigit((unsigned int)*p))
52
+			continue;
53
+
54
+		while (*p && isspace((unsigned int)*p))
55
+		{
56
+			if (!warned_key_whitespace)
57
+			{
58
+				warnfunc(data, "%s:" SIZE_FMT_SPECIFIER ": warning: whitespace encountered while parsing key section\n",
59
+					filename, lineno);
60
+				warned_key_whitespace = true;
61
+			}
62
+
63
+			/* set to null to avoid trailing spaces in key */
64
+			*p = '\0';
65
+			p++;
66
+		}
67
+
68
+		op = *p;
69
+		*p = '\0';
70
+		p++;
71
+
72
+		while (*p && isspace((unsigned int)*p))
73
+			p++;
74
+
75
+		value = p;
76
+		p = value + (strlen(value) - 1);
77
+		while (*p && isspace((unsigned int) *p) && p > value)
78
+		{
79
+			if (!warned_value_whitespace && op == '=')
80
+			{
81
+				warnfunc(data, "%s:" SIZE_FMT_SPECIFIER ": warning: trailing whitespace encountered while parsing value section\n",
82
+					filename, lineno);
83
+				warned_value_whitespace = true;
84
+			}
85
+
86
+			*p = '\0';
87
+			p--;
88
+		}
89
+
90
+		if (ops[(unsigned char) op])
91
+			ops[(unsigned char) op](data, lineno, key, value);
92
+	}
93
+
94
+	fclose(f);
95
+}

+ 21
- 69
libpkgconf/pkg.c View File

@@ -236,6 +236,26 @@ static const pkgconf_pkg_validity_check_t pkgconf_pkg_validations[] = {
236 236
 	{"Version", offsetof(pkgconf_pkg_t, version)},
237 237
 };
238 238
 
239
+static const pkgconf_parser_operand_func_t pkg_parser_funcs[] = {
240
+	[':'] = (pkgconf_parser_operand_func_t) pkgconf_pkg_parser_keyword_set,
241
+	['='] = (pkgconf_parser_operand_func_t) pkgconf_pkg_parser_value_set
242
+};
243
+
244
+static void pkg_warn_func(pkgconf_pkg_t *pkg, const char *fmt, ...) PRINTFLIKE(2, 3);
245
+
246
+static void
247
+pkg_warn_func(pkgconf_pkg_t *pkg, const char *fmt, ...)
248
+{
249
+	char buf[PKGCONF_ITEM_SIZE];
250
+	va_list va;
251
+
252
+	va_start(va, fmt);
253
+	vsnprintf(buf, sizeof buf, fmt, va);
254
+	va_end(va);
255
+
256
+	pkgconf_warn(pkg->owner, "%s", buf);
257
+}
258
+
239 259
 static bool
240 260
 pkgconf_pkg_validate(const pkgconf_client_t *client, const pkgconf_pkg_t *pkg)
241 261
 {
@@ -273,9 +293,7 @@ pkgconf_pkg_t *
273 293
 pkgconf_pkg_new_from_file(pkgconf_client_t *client, const char *filename, FILE *f)
274 294
 {
275 295
 	pkgconf_pkg_t *pkg;
276
-	char readbuf[PKGCONF_BUFSIZE];
277 296
 	char *idptr;
278
-	size_t lineno = 0;
279 297
 
280 298
 	pkg = calloc(sizeof(pkgconf_pkg_t), 1);
281 299
 	pkg->owner = client;
@@ -298,73 +316,7 @@ pkgconf_pkg_new_from_file(pkgconf_client_t *client, const char *filename, FILE *
298 316
 	if (idptr)
299 317
 		*idptr = '\0';
300 318
 
301
-	while (pkgconf_fgetline(readbuf, PKGCONF_BUFSIZE, f) != NULL)
302
-	{
303
-		char op, *p, *key, *value;
304
-		bool warned_key_whitespace = false, warned_value_whitespace = false;
305
-
306
-		lineno++;
307
-
308
-		PKGCONF_TRACE(client, "%s:" SIZE_FMT_SPECIFIER " > [%s]", filename, lineno, readbuf);
309
-
310
-		p = readbuf;
311
-		while (*p && (isalpha((unsigned int)*p) || isdigit((unsigned int)*p) || *p == '_' || *p == '.'))
312
-			p++;
313
-
314
-		key = readbuf;
315
-		if (!isalpha((unsigned int)*key) && !isdigit((unsigned int)*p))
316
-			continue;
317
-
318
-		while (*p && isspace((unsigned int)*p))
319
-		{
320
-			if (!warned_key_whitespace)
321
-			{
322
-				pkgconf_warn(client, "%s:" SIZE_FMT_SPECIFIER ": warning: whitespace encountered while parsing key section\n",
323
-					pkg->filename, lineno);
324
-				warned_key_whitespace = true;
325
-			}
326
-
327
-			/* set to null to avoid trailing spaces in key */
328
-			*p = '\0';
329
-			p++;
330
-		}
331
-
332
-		op = *p;
333
-		*p = '\0';
334
-		p++;
335
-
336
-		while (*p && isspace((unsigned int)*p))
337
-			p++;
338
-
339
-		value = p;
340
-		p = value + (strlen(value) - 1);
341
-		while (*p && isspace((unsigned int) *p) && p > value)
342
-		{
343
-			if (!warned_value_whitespace && op == '=')
344
-			{
345
-				pkgconf_warn(client, "%s:" SIZE_FMT_SPECIFIER ": warning: trailing whitespace encountered while parsing value section\n",
346
-					pkg->filename, lineno);
347
-				warned_value_whitespace = true;
348
-			}
349
-
350
-			*p = '\0';
351
-			p--;
352
-		}
353
-
354
-		switch (op)
355
-		{
356
-		case ':':
357
-			pkgconf_pkg_parser_keyword_set(pkg, lineno, key, value);
358
-			break;
359
-		case '=':
360
-			pkgconf_pkg_parser_value_set(pkg, lineno, key, value);
361
-			break;
362
-		default:
363
-			break;
364
-		}
365
-	}
366
-
367
-	fclose(f);
319
+	pkgconf_parser_parse(f, pkg, pkg_parser_funcs, (pkgconf_parser_warn_func_t) pkg_warn_func, pkg->filename);
368 320
 
369 321
 	if (!pkgconf_pkg_validate(client, pkg))
370 322
 	{

+ 1
- 0
meson.build View File

@@ -66,6 +66,7 @@ libpkgconf = shared_library('pkgconf',
66 66
   'libpkgconf/dependency.c',
67 67
   'libpkgconf/fileio.c',
68 68
   'libpkgconf/fragment.c',
69
+  'libpkgconf/parser.c',
69 70
   'libpkgconf/path.c',
70 71
   'libpkgconf/personality.c',
71 72
   'libpkgconf/pkg.c',