Home | History | Annotate | Line # | Download | only in util
      1 /*	$NetBSD: split_qnameval.c,v 1.2 2020/03/18 19:05:22 christos Exp $	*/
      2 
      3 /*++
      4 /* NAME
      5 /*	split_qnameval 3
      6 /* SUMMARY
      7 /*	name-value splitter
      8 /* SYNOPSIS
      9 /*	#include <stringops.h>
     10 /*
     11 /*	const char *split_qnameval(buf, name, value)
     12 /*	char    *buf;
     13 /*	char    **name;
     14 /*	char    **value;
     15 /* DESCRIPTION
     16 /*	split_qnameval() expects text of the form "key = value"
     17 /*	or "key =", where the key may be quoted with backslash or
     18 /*      double quotes. The buffer argument is broken up into the key
     19 /*      and value substrings.
     20 /*
     21 /*	Arguments:
     22 /* .IP buf
     23 /*	Result from readlline() or equivalent. The buffer is modified.
     24 /* .IP key
     25 /*	Upon successful completion, this is set to the key
     26 /*	substring.
     27 /* .IP value
     28 /*	Upon successful completion, this is set to the value
     29 /*	substring.
     30 /* SEE ALSO
     31 /*	split_nameval(3) name-value splitter
     32 /* BUGS
     33 /* DIAGNOSTICS
     34 /*	The result is a null pointer in case of success, a string
     35 /*	describing the error otherwise: missing '=' after attribute
     36 /*	name; missing attribute name.
     37 /* LICENSE
     38 /* .ad
     39 /* .fi
     40 /*	The Secure Mailer license must be distributed with this software.
     41 /* AUTHOR(S)
     42 /*	Wietse Venema
     43 /*	Google, Inc.
     44 /*	111 8th Avenue
     45 /*	New York, NY 10011, USA
     46 /*--*/
     47 
     48 /* System libraries. */
     49 
     50 #include <sys_defs.h>
     51 #include <ctype.h>
     52 #include <string.h>
     53 
     54 /* Utility library. */
     55 
     56 #include <msg.h>
     57 #include <stringops.h>
     58 
     59 /* split_qnameval - split "key = value", support quoted key */
     60 
     61 const char *split_qnameval(char *buf, char **pkey, char **pvalue)
     62 {
     63     int     in_quotes = 0;
     64     char   *key;
     65     char   *key_end;
     66     char   *value;
     67 
     68     for (key = buf; *key && ISSPACE(*key); key++)
     69 	 /* void */ ;
     70     if (*key == 0)
     71 	return ("no key found; expected format: key = value");
     72 
     73     for (key_end = key; *key_end; key_end++) {
     74 	if (*key_end == '\\') {
     75 	    if (*++key_end == 0)
     76 		break;
     77 	} else if (ISSPACE(*key_end) || *key_end == '=') {
     78 	    if (!in_quotes)
     79 		break;
     80 	} else if (*key_end == '"') {
     81 	    in_quotes = !in_quotes;
     82 	}
     83     }
     84     if (in_quotes) {
     85 	return ("unbalanced '\"\'");
     86     }
     87     value = key_end;
     88     while (ISSPACE(*value))
     89 	value++;
     90     if (*value != '=')
     91 	return ("missing '=' after attribute name");
     92     *key_end = 0;
     93     do {
     94 	value++;
     95     } while (ISSPACE(*value));
     96     trimblanks(value, 0)[0] = 0;
     97     *pkey = key;
     98     *pvalue = value;
     99     return (0);
    100 }
    101 
    102 #ifdef TEST
    103 
    104 #include <stdlib.h>
    105 #include <unistd.h>
    106 #include <string.h>
    107 
    108 #include <mymalloc.h>
    109 
    110 static int compare(int test_number, const char *what,
    111 		           const char *expect, const char *real)
    112 {
    113     if ((expect == 0 && real == 0)
    114 	|| (expect != 0 && real != 0 && strcmp(expect, real) == 0)) {
    115 	return (0);
    116     } else {
    117 	msg_warn("test %d: %s mis-match: expect='%s', real='%s'",
    118 		 test_number, what, expect ? expect : "(null)",
    119 		 real ? real : "(null)");
    120 	return (1);
    121     }
    122 }
    123 
    124 int     main(int argc, char **argv)
    125 {
    126     struct test_info {
    127 	const char *input;
    128 	const char *expect_result;
    129 	const char *expect_key;
    130 	const char *expect_value;
    131     };
    132     static const struct test_info test_info[] = {
    133 	/* Unquoted keys. */
    134 	{"xx = yy", 0, "xx", "yy"},
    135 	{"xx=yy", 0, "xx", "yy"},
    136 	{"xx =", 0, "xx", ""},
    137 	{"xx=", 0, "xx", ""},
    138 	{"xx", "missing '=' after attribute name", 0, 0},
    139 	/* Quoted keys. */
    140 	{"\"xx \" = yy", 0, "\"xx \"", "yy"},
    141 	{"\"xx \"= yy", 0, "\"xx \"", "yy"},
    142 	{"\"xx \" =", 0, "\"xx \"", ""},
    143 	{"\"xx \"=", 0, "\"xx \"", ""},
    144 	{"\"xx \"", "missing '=' after attribute name", 0, 0},
    145 	{"\"xx ", "unbalanced '\"'", 0, 0},
    146 	/* Backslash escapes. */
    147 	{"\"\\\"xx \" = yy", 0, "\"\\\"xx \"", "yy"},
    148 	{0,},
    149     };
    150 
    151     int     errs = 0;
    152     const struct test_info *tp;
    153 
    154     for (tp = test_info; tp->input != 0; tp++) {
    155 	const char *result;
    156 	char   *key = 0;
    157 	char   *value = 0;
    158 	char   *buf = mystrdup(tp->input);
    159 	int     test_number = (int) (tp - test_info);
    160 
    161 	result = split_qnameval(buf, &key, &value);
    162 	errs += compare(test_number, "result", tp->expect_result, result);
    163 	errs += compare(test_number, "key", tp->expect_key, key);
    164 	errs += compare(test_number, "value", tp->expect_value, value);
    165 	myfree(buf);
    166     }
    167     exit(errs);
    168 }
    169 
    170 #endif
    171