chiark / gitweb /
units: in order to make the default services parseable by GKeyFile, merge repeated...
[elogind.git] / src / util.c
index 78eb728121a3423aeb651c8682fa5a8a52728b18..a01229e659f3906e7191675963b5d0e7c3320534 100644 (file)
@@ -360,7 +360,8 @@ char *split(const char *c, size_t *l, const char *separator, char **state) {
 /* Split a string into words, but consider strings enclosed in '' and
  * "" as words even if they include spaces. */
 char *split_quoted(const char *c, size_t *l, char **state) {
-        char *current;
+        char *current, *e;
+        bool escaped = false;
 
         current = *state ? *state : (char*) c;
 
@@ -371,26 +372,45 @@ char *split_quoted(const char *c, size_t *l, char **state) {
 
         if (*current == '\'') {
                 current ++;
-                *l = strcspn(current, "'");
-                *state = current+*l;
 
-                if (**state == '\'')
-                        (*state)++;
+                for (e = current; *e; e++) {
+                        if (escaped)
+                                escaped = false;
+                        else if (*e == '\\')
+                                escaped = true;
+                        else if (*e == '\'')
+                                break;
+                }
+
+                *l = e-current;
+                *state = *e == 0 ? e : e+1;
         } else if (*current == '\"') {
                 current ++;
-                *l = strcspn(current, "\"");
-                *state = current+*l;
 
-                if (**state == '\"')
-                        (*state)++;
+                for (e = current; *e; e++) {
+                        if (escaped)
+                                escaped = false;
+                        else if (*e == '\\')
+                                escaped = true;
+                        else if (*e == '\"')
+                                break;
+                }
+
+                *l = e-current;
+                *state = *e == 0 ? e : e+1;
         } else {
-                *l = strcspn(current, WHITESPACE);
-                *state = current+*l;
+                for (e = current; *e; e++) {
+                        if (escaped)
+                                escaped = false;
+                        else if (*e == '\\')
+                                escaped = true;
+                        else if (strchr(WHITESPACE, *e))
+                                break;
+                }
+                *l = e-current;
+                *state = e;
         }
 
-        /* FIXME: Cannot deal with strings that have spaces AND ticks
-         * in them */
-
         return (char*) current;
 }
 
@@ -1109,7 +1129,7 @@ char *cescape(const char *s) {
         return r;
 }
 
-char *cunescape(const char *s) {
+char *cunescape_length(const char *s, size_t length) {
         char *r, *t;
         const char *f;
 
@@ -1117,10 +1137,10 @@ char *cunescape(const char *s) {
 
         /* Undoes C style string escaping */
 
-        if (!(r = new(char, strlen(s)+1)))
+        if (!(r = new(char, length+1)))
                 return r;
 
-        for (f = s, t = r; *f; f++) {
+        for (f = s, t = r; f < s + length; f++) {
 
                 if (*f != '\\') {
                         *(t++) = *f;
@@ -1162,6 +1182,11 @@ char *cunescape(const char *s) {
                         *(t++) = '\'';
                         break;
 
+                case 's':
+                        /* This is an extension of the XDG syntax files */
+                        *(t++) = ' ';
+                        break;
+
                 case 'x': {
                         /* hexadecimal encoding */
                         int a, b;
@@ -1222,6 +1247,9 @@ finish:
         return r;
 }
 
+char *cunescape(const char *s) {
+        return cunescape_length(s, strlen(s));
+}
 
 char *xescape(const char *s, const char *bad) {
         char *r, *t;