summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2016-12-15 13:10:02 +0100
committerThomas Haller <thaller@redhat.com>2017-01-02 17:00:51 +0100
commitde9e78cc5024d4bb6b192d4847b5e06079de0bad (patch)
tree6b14cb0dd151597a5a89d790bb06cf8e6f27c719
parenta6a39af8cae30c5634a8b6974500c58e9e20fd54 (diff)
downloadNetworkManager-de9e78cc5024d4bb6b192d4847b5e06079de0bad.tar.gz
ifcfg-rh: refactor handling of lines in shvar.c
Pre-process each line and parse the key and value. Thus, keep the key already prepared. The point is to do the parsing early and keep the data in a more suitable format in shvarLine.
-rw-r--r--src/settings/plugins/ifcfg-rh/shvar.c241
1 files changed, 126 insertions, 115 deletions
diff --git a/src/settings/plugins/ifcfg-rh/shvar.c b/src/settings/plugins/ifcfg-rh/shvar.c
index 9ecbbc4bf7..600e843113 100644
--- a/src/settings/plugins/ifcfg-rh/shvar.c
+++ b/src/settings/plugins/ifcfg-rh/shvar.c
@@ -41,8 +41,9 @@
/*****************************************************************************/
typedef struct {
- gchar *original;
- gchar *value;
+ char *line;
+ const char *key;
+ char *key_with_prefix;
} shvarLine;
struct _shvarFile {
@@ -90,34 +91,27 @@ svParseBoolean (const char *value, gint fallback)
/*****************************************************************************/
static gboolean
-_shell_is_name (const char *key)
+_shell_is_name (const char *key, gssize len)
{
+ gssize i;
+
/* whether @key is a valid identifier (name). */
- if (!key)
+ if (!key || len == 0)
return FALSE;
if ( !g_ascii_isalpha (key[0])
&& key[0] != '_')
return FALSE;
- return NM_STRCHAR_ALL (&key[1], ch,
- g_ascii_isalnum (ch) || ch == '_');
-}
-
-static const char *
-_shell_is_name_assignment (const char *key)
-{
- /* whether @key is a valid identifier (name). */
- if (!key)
- return NULL;
- if ( !g_ascii_isalpha (key[0])
- && key[0] != '_')
- return NULL;
- while (TRUE) {
- const char ch = (++key)[0];
-
- if (ch == '=')
- return &key[1];
- if (!g_ascii_isalnum (ch) && ch != '_')
- return NULL;
+ for (i = 1; TRUE; i++) {
+ if (len < 0) {
+ if (!key[i])
+ return TRUE;
+ } else {
+ if (i >= len)
+ return TRUE;
+ }
+ if ( !g_ascii_isalnum (key[i])
+ && key[i] != '_')
+ return FALSE;
}
}
@@ -632,43 +626,89 @@ svFileSetModified (shvarFile *s)
/*****************************************************************************/
static shvarLine *
-line_new (char *value)
+line_new_parse (const char *value, gsize len)
{
shvarLine *line;
+ gsize k, e;
+
+ nm_assert (value);
line = g_slice_new0 (shvarLine);
- line->original = line->value = value;
+ for (k = 0; k < len; k++) {
+ if (g_ascii_isspace (value[k]))
+ continue;
+
+ if ( g_ascii_isalpha (value[k])
+ || value[k] == '_') {
+ for (e = k + 1; e < len; e++) {
+ if (value[e] == '=') {
+ nm_assert (_shell_is_name (&value[k], e - k));
+ line->line = g_strndup (&value[e + 1], len - e - 1);
+ line->key_with_prefix = g_strndup (value, e);
+ line->key = &line->key_with_prefix[k];
+ return line;
+ }
+ if ( !g_ascii_isalnum (value[e])
+ && value[e] != '_')
+ break;
+ }
+ }
+ break;
+ }
+ line->line = g_strndup (value, len);
return line;
}
-static void
-line_free (shvarLine *line)
+static shvarLine *
+line_new_build (const char *key, const char *value)
{
- g_free (line->value);
- if (line->original != line->value)
- g_free (line->original);
- g_slice_free (shvarLine, line);
+ char *value_escaped = NULL;
+ shvarLine *line;
+
+ value = svEscape (value, &value_escaped);
+
+ line = g_slice_new (shvarLine);
+ line->line = value_escaped ?: g_strdup (value);
+ line->key_with_prefix = g_strdup (key);
+ line->key = line->key_with_prefix;
+ return line;
}
-static const char *
-line_value (const shvarLine *line, const char *key)
+static gboolean
+line_set (shvarLine *line, const char *value)
+{
+ char *value_escaped = NULL;
+ gboolean changed = FALSE;
+
+ nm_assert (line->key);
+
+ if (line->key != line->key_with_prefix) {
+ memmove (line->key_with_prefix, line->key, strlen (line->key) + 1);
+ line->key = line->key_with_prefix;
+ changed = TRUE;
+ }
+
+ value = svEscape (value, &value_escaped);
+
+ if (line->line) {
+ if (nm_streq (value, line->line)) {
+ g_free (value_escaped);
+ return changed;
+ }
+ g_free (line->line);
+ }
+
+ line->line = value_escaped ?: g_strdup (value);
+ return TRUE;
+}
+
+static void
+line_free (shvarLine *line)
{
-#if NM_MORE_ASSERTS > 5
- const char *v;
-
- nm_assert (line);
- nm_assert (line->value);
- nm_assert (key && _shell_is_name (key));
-
- v = line->value;
- while (g_ascii_isspace (v[0]))
- v++;
- nm_assert (g_str_has_prefix (v, key));
- nm_assert (v[strlen (key)] == '=');
- nm_assert (&v[strlen (key)] == strchr (line->value, '='));
-#endif
- return strchr (line->value, '=') + 1;
+ g_free (line->line);
+ g_free (line->key_with_prefix);
+ g_slice_free (shvarLine, line);
}
/*****************************************************************************/
@@ -726,9 +766,9 @@ svOpenFileInternal (const char *name, gboolean create, GError **error)
/* we'd use g_strsplit() here, but we want a list, not an array */
for (p = arena; (q = strchr (p, '\n')) != NULL; p = q + 1)
- s->lineList = g_list_prepend (s->lineList, line_new (g_strndup (p, q - p)));
+ s->lineList = g_list_prepend (s->lineList, line_new_parse (p, q - p));
if (p[0])
- s->lineList = g_list_prepend (s->lineList, line_new (g_strdup (p)));
+ s->lineList = g_list_prepend (s->lineList, line_new_parse (p, strlen (p)));
g_free (arena);
s->lineList = g_list_reverse (s->lineList);
@@ -779,21 +819,13 @@ svCreateFile (const char *name)
static const GList *
shlist_find (const GList *current, const char *key)
{
- gsize len;
-
- nm_assert (_shell_is_name (key));
+ nm_assert (_shell_is_name (key, -1));
if (current) {
- len = strlen (key);
do {
shvarLine *line = current->data;
- const char *original = line->original;
-
- /* skip over leading spaces */
- while (g_ascii_isspace (original[0]))
- original++;
- if (!strncmp (key, original, len) && original[len] == '=')
+ if (line->key && nm_streq (line->key, key))
return current;
current = current->next;
} while (current);
@@ -807,9 +839,10 @@ static const char *
_svGetValue (shvarFile *s, const char *key, char **to_free)
{
const GList *current, *last;
+ const shvarLine *line;
nm_assert (s);
- nm_assert (_shell_is_name (key));
+ nm_assert (_shell_is_name (key, -1));
nm_assert (to_free);
last = NULL;
@@ -818,14 +851,11 @@ _svGetValue (shvarFile *s, const char *key, char **to_free)
last = current;
current = current->next;
}
-
if (last) {
- const shvarLine *line = last->data;
-
- if (line->value)
- return svUnescape (line_value (line, key), to_free);
+ line = last->data;
+ if (line->line)
+ return svUnescape (line->line, to_free);
}
-
*to_free = NULL;
return NULL;
}
@@ -929,7 +959,7 @@ svSetValue (shvarFile *s, const char *key, const char *value)
g_return_if_fail (s != NULL);
g_return_if_fail (key != NULL);
- nm_assert (_shell_is_name (key));
+ nm_assert (_shell_is_name (key, -1));
last = NULL;
current = s->lineList;
@@ -949,35 +979,17 @@ svSetValue (shvarFile *s, const char *key, const char *value)
if (last) {
shvarLine *line = last->data;
- if (line->value) {
- if (line->value != line->original)
- g_free (line->value);
- line->value = NULL;
+ if (nm_clear_g_free (&line->line))
s->modified = TRUE;
- }
}
} else {
- gs_free char *newval_free = NULL;
- shvarLine *line;
- char *new_value;
-
- value = svEscape (value, &newval_free);
-
if (!last) {
- new_value = g_strdup_printf ("%s=%s", key, value);
- s->lineList = g_list_append (s->lineList, line_new (new_value));
+ s->lineList = g_list_append (s->lineList, line_new_build (key, value));
+ s->modified = TRUE;
} else {
- line = last->data;
- if (line->value) {
- if (nm_streq (line_value (line, key), value))
- return;
- if (line->value != line->original)
- g_free (line->value);
- }
- new_value = g_strdup_printf ("%s=%s", key, value);
- line->value = new_value;
+ if (line_set (last->data, value))
+ s->modified = TRUE;
}
- s->modified = TRUE;
}
}
@@ -1059,34 +1071,33 @@ svWriteFile (shvarFile *s, int mode, GError **error)
f = fdopen (tmpfd, "w");
fseek (f, 0, SEEK_SET);
for (current = s->lineList; current; current = current->next) {
- shvarLine *line = current->data;
+ const shvarLine *line = current->data;
const char *str;
- const char *value;
+ char *s_tmp;
+ gboolean valid_value;
+
+ if (!line->key) {
+ str = nm_str_skip_leading_spaces (line->line);
+ if (NM_IN_SET (str[0], '\0', '#'))
+ fprintf (f, "%s\n", line->line);
+ else
+ fprintf (f, "#NM: %s\n", line->line);
+ continue;
+ }
- str = line->value;
- if (!str)
+ if (!line->line)
continue;
- while (g_ascii_isspace (str[0]))
- str++;
- if (NM_IN_SET (str[0], '\0', '#'))
- goto write_regular;
-
- value = _shell_is_name_assignment (str);
- if (value) {
- gs_free char *s_tmp = NULL;
-
- /* we check that the assignment can be properly unescaped. */
- if (svUnescape (value, &s_tmp))
- goto write_regular;
- nm_clear_g_free (&s_tmp);
- s_tmp = g_strndup (str, value - str);
- fprintf (f, "%s\n", s_tmp);
+ /* we check that the assignment can be properly unescaped. */
+ valid_value = !!svUnescape (line->line, &s_tmp);
+ g_free (s_tmp);
+
+ if (valid_value)
+ fprintf (f, "%s=%s\n", line->key_with_prefix, line->line);
+ else {
+ fprintf (f, "%s=\n", line->key);
+ fprintf (f, "#NM: %s=%s\n", line->key_with_prefix, line->line);
}
- fprintf (f, "#NM: %s\n", line->value);
- continue;
-write_regular:
- fprintf (f, "%s\n", line->value);
}
fclose (f);
}