3
* symbol.c - C symbol generation and validation
5
* Copyright © 2009 Scott James Remnant <scott@netsplit.com>.
6
* Copyright © 2009 Canonical Ltd.
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License version 2, as
10
* published by the Free Software Foundation.
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License along
18
* with this program; if not, write to the Free Software Foundation, Inc.,
19
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24
#endif /* HAVE_CONFIG_H */
31
#include <nih/macros.h>
32
#include <nih/alloc.h>
33
#include <nih/string.h>
34
#include <nih/logging.h>
35
#include <nih/error.h>
40
/* Prototypes for static functions */
41
static char *symbol_strcat_interface (char **str, const void *parent,
42
const char *format, ...)
43
__attribute__ ((format (printf, 3, 4), warn_unused_result, malloc));
44
static char *symbol_strcat_title (char **str, const void *parent,
45
const char *format, ...)
46
__attribute__ ((format (printf, 3, 4), warn_unused_result, malloc));
51
* @symbol: Symbol to verify.
53
* Verifies whether @symbol matches the rules for C symbol names. To make
54
* things easier for ourselves, we only support a subset of what C99 can
55
* really support. ie. no universal character names.
57
* Returns: TRUE if valid, FALSE if not.
60
symbol_valid (const char *symbol)
62
nih_assert (symbol != NULL);
64
/* We can get away with just using strlen() here even through symbol
65
* is in UTF-8 because all the valid characters are ASCII.
67
for (size_t i = 0; i < strlen (symbol); i++) {
68
/* Symbols may contain digits, but not at the beginning. */
69
if ((symbol[i] >= '0') && (symbol[i] <= '9')) {
76
/* Valid characters anywhere are [A-Za-z_] */
77
if ( ((symbol[i] < 'A') || (symbol[i] > 'Z'))
78
&& ((symbol[i] < 'a') || (symbol[i] > 'z'))
79
&& (symbol[i] != '_'))
83
/* Symbol must be at least 1 character */
84
if (strlen (symbol) < 1)
93
* @parent: parent object of new string,
94
* @name: name to convert.
96
* Converts the D-Bus style name @name to C style; basically the name
97
* is lower-cased, and underscores inserted between CamelCase words.
99
* If @parent is not NULL, it should be a pointer to another object which
100
* will be used as a parent for the returned string. When all parents
101
* of the returned string are freed, the returned string will also be
104
* Returns: newly allocated string or NULL if allocation fails.
107
symbol_from_name (const void *parent,
114
nih_assert (name != NULL);
116
/* Figure out how long the symbol will need to be by counting
117
* how many places we need to add underscores and adding them
121
for (size_t i = 0; i < strlen (name); i++)
122
if ((i > 0) && (name[i] >= 'A') && (name[i] <= 'Z')
123
&& (name[i-1] != '_')
124
&& ((name[i-1] < 'A') || (name[i-1] > 'Z')))
127
/* Allocate the new string */
128
symbol = nih_alloc (parent, len + 1);
132
/* Copy the characters across, lowercasing as we go and inserting
133
* underscores before any capital unless it follows an underscore.
136
for (size_t i = 0; i < strlen (name); i++) {
137
if ((i > 0) && (name[i] >= 'A') && (name[i] <= 'Z')
138
&& (name[i-1] != '_')
139
&& ((name[i-1] < 'A') || (name[i-1] > 'Z')))
142
*(ptr++) = tolower (name[i]);
152
* symbol_strcat_interface:
153
* @str: pointer to string to modify,
154
* @parent: parent object of new string,
155
* @format: format to append to @str.
157
* Replaces periods in the string expanded from @format with underscores
158
* and concatenates it onto @str. The new string is allocated using
159
* nih_alloc() and @str will be updated to point to the new string; use
160
* the return value simply to check for success.
162
* @parent is ignored; though it is usual to pass a parent of @str for
165
* Returns: newly allocated string or NULL if allocation fails.
168
symbol_strcat_interface (char ** str,
173
nih_local char *name = NULL;
178
nih_assert (str != NULL);
179
nih_assert (*str != NULL);
180
nih_assert (format != NULL);
182
va_start (args, format);
183
name = nih_vsprintf (NULL, format, args);
190
ret = nih_realloc (*str, parent, len + strlen (name) + 1);
196
/* Copy the characters across, replacing the periods between
197
* interface components with underscores.
199
for (char *s = name; *s; s++)
200
(*str)[len++] = (*s == '.' ? '_' : *s);
208
* symbol_strcat_title:
209
* @str: pointer to string to modify,
210
* @parent: parent object of new string,
211
* @format: format to append to @str.
213
* Expands the @format string and modifies it so that each underscore-
214
* separated word has the underscores removed and the initial character
215
* uppercased. The new string is allocated using nih_alloc() and @str
216
* will be updated to point to the new string; use the return value
217
* simply to check for success.
219
* If the string pointed to by @str is NULL, a new string will be
220
* allocated and if @parent is not NULL, it should be a pointer to another
221
* object which will be used as a parent for the returned string. When all
222
* parents of the returned string are freed, the returned string will also
225
* When the string pointed to by @str is not NULL, @parent is ignored;
226
* though it is usual to pass a parent of @str for style reasons.
228
* Returns: newly allocated string or NULL if allocation fails.
231
symbol_strcat_title (char ** str,
237
nih_local char *symbol = NULL;
243
nih_assert (str != NULL);
244
nih_assert (format != NULL);
246
va_start (args, format);
247
symbol = nih_vsprintf (NULL, format, args);
252
str_len = *str ? strlen (*str) : 0;
255
/* Figure out how long the new string will be by counting how many
256
* characters that aren't underscores we'll end up adding.
258
for (char *s = symbol; *s; s++)
262
ret = nih_realloc (*str, parent, len + 1);
270
/* Copy the characters across, uppercasing the first character of
271
* each word and stripping underscores.
273
for (char *s = symbol; *s; s++) {
277
(*str)[len++] = (first ? toupper (*s) : *s);
289
* @parent: parent object of new string,
290
* @prefix: prefix for returned symbol,
291
* @interface_name: name of D-Bus interface,
292
* @name: name of interface member,
293
* @postfix: postfix for returned symbol.
295
* Generates a C symbol for an implementation function, one that is hidden
296
* from the API and thus uniqueness and verboseness is more desirable than
297
* readability. The @prefix is prepended to the @interface_name and
298
* member @name, with the @postfix appended.
300
* If @parent is not NULL, it should be a pointer to another object which
301
* will be used as a parent for the returned string. When all parents
302
* of the returned string are freed, the returned string will also be
305
* Returns: newly allocated string or NULL if allocation fails.
308
symbol_impl (const void *parent,
310
const char *interface_name,
316
nih_assert (prefix != NULL);
317
nih_assert (interface_name != NULL);
318
nih_assert ((postfix != NULL) || (name == NULL));
320
str = nih_sprintf (parent, "%s_", prefix);
324
if (! symbol_strcat_interface (&str, parent, (name ? "%s_" : "%s"),
331
if (! nih_strcat (&str, parent, name)) {
338
if (! nih_strcat_sprintf (&str, parent, "_%s", postfix)) {
349
* @parent: parent object of new string,
350
* @prefix: prefix for returned symbol,
351
* @interface_symbol: symbol for D-Bus interface,
352
* @midfix: midfix for returned symbol,
353
* @symbol: symbol of interface member,
354
* @postfix: postfix for returned symbol.
356
* Generates a C symbol for an external function, one that is either part of
357
* the API or intended to be supplied externally, thus where readability
358
* is more desirable than uniqueness or verboseness. The @prefix is
359
* prepended to the @interface_symbol (if supplied), @midfix (if supplied),
360
* member @symbol, with the @postfix (if supplied) appended.
362
* If @parent is not NULL, it should be a pointer to another object which
363
* will be used as a parent for the returned string. When all parents
364
* of the returned string are freed, the returned string will also be
367
* Returns: newly allocated string or NULL if allocation fails.
370
symbol_extern (const void *parent,
372
const char *interface_symbol,
379
nih_assert (prefix != NULL);
380
nih_assert (symbol != NULL);
382
str = nih_sprintf (parent, "%s_", prefix);
386
if (interface_symbol) {
387
if (! nih_strcat_sprintf (&str, parent, "%s_",
395
if (! nih_strcat_sprintf (&str, parent, "%s_", midfix)) {
401
if (! nih_strcat (&str, parent, symbol)) {
407
if (! nih_strcat_sprintf (&str, parent, "_%s", postfix)) {
418
* @parent: parent object of new string,
419
* @prefix: prefix for returned symbol,
420
* @interface_symbol: symbol for D-Bus interface,
421
* @midfix: midfix for returned symbol,
422
* @symbol: symbol of interface member,
423
* @postfix: postfix for returned symbol.
425
* Generates a C typedef name for a function that is expected to be
426
* supplied, this has the same basic form as an external symbol except that
427
* underscores are removed and the first letter of each part is uppercased.
428
* The @prefix is prepended to the @interface_symbol (if supplied), @midfix
429
* (if supplied), member @symbol, with the @postfix appended.
431
* If @parent is not NULL, it should be a pointer to another object which
432
* will be used as a parent for the returned string. When all parents
433
* of the returned string are freed, the returned string will also be
436
* Returns: newly allocated string or NULL if allocation fails.
439
symbol_typedef (const void *parent,
441
const char *interface_symbol,
448
nih_assert (prefix != NULL);
449
nih_assert (symbol != NULL);
452
if (! symbol_strcat_title (&str, parent, "%s_", prefix))
455
if (interface_symbol) {
456
if (! symbol_strcat_title (&str, parent, "%s_",
464
if (! symbol_strcat_title (&str, parent, "%s_", midfix)) {
470
if (! symbol_strcat_title (&str, parent, "%s", symbol)) {
476
if (! symbol_strcat_title (&str, parent, "_%s", postfix)) {