1 /*        $NetBSD: mail_parm_split.c,v 1.3 2020/03/18 19:05:16 christos Exp $   */
2 
3 /*++
4 /* NAME
5 /*        mail_parm_split 3
6 /* SUMMARY
7 /*        split parameter list value
8 /* SYNOPSIS
9 /*        #include <mail_parm_split.h>
10 /*
11 /*        ARGV      *mail_parm_split(
12 /*        const char *name,
13 /*        const char *value)
14 /* DESCRIPTION
15 /*        mail_parm_split() splits a parameter list value into its
16 /*        elements, and extracts text from elements that are entirely
17 /*        enclosed in {}. It uses CHARS_COMMA_SP as list element
18 /*        delimiters, and CHARS_BRACE for grouping.
19 /*
20 /*        Arguments:
21 /* .IP name
22 /*        Parameter name. This is used to provide context for
23 /*        error messages.
24 /* .IP value
25 /*        Parameter value.
26 /* DIAGNOSTICS
27 /*        fatal: syntax error while extracting text from {}, such as:
28 /*        missing closing brace, or text after closing brace.
29 /* SEE ALSO
30 /*        argv_splitq(3), string array utilities
31 /*        extpar(3), extract text from parentheses
32 /* LICENSE
33 /* .ad
34 /* .fi
35 /*        The Secure Mailer license must be distributed with this software.
36 /* AUTHOR(S)
37 /*        Wietse Venema
38 /*        IBM T.J. Watson Research
39 /*        P.O. Box 704
40 /*        Yorktown Heights, NY 10598, USA
41 /*
42 /*        Wietse Venema
43 /*        Google, Inc.
44 /*        111 8th Avenue
45 /*        New York, NY 10011, USA
46 /*--*/
47 
48  /*
49   * System library.
50   */
51 #include <sys_defs.h>
52 
53  /*
54   * Utility library.
55   */
56 #include <msg.h>
57 #include <mymalloc.h>
58 #include <stringops.h>
59 
60  /*
61   * Global library.
62   */
63 #include <mail_params.h>
64 #include <mail_parm_split.h>
65 
66 /* mail_parm_split - split list, extract {text}, errors are fatal */
67 
mail_parm_split(const char * name,const char * value)68 ARGV   *mail_parm_split(const char *name, const char *value)
69 {
70     ARGV   *argvp = argv_alloc(1);
71     char   *saved_string = mystrdup(value);
72     char   *bp = saved_string;
73     char   *arg;
74     char   *err;
75 
76     /*
77      * The code that detects the error shall either signal or handle the
78      * error. In this case, mystrtokq() detects no error, extpar() signals
79      * the error to its caller, and this function handles the error.
80      */
81     while ((arg = mystrtokq(&bp, CHARS_COMMA_SP, CHARS_BRACE)) != 0) {
82           if (*arg == CHARS_BRACE[0]
83               && (err = extpar(&arg, CHARS_BRACE, EXTPAR_FLAG_STRIP)) != 0) {
84 #ifndef TEST
85               msg_fatal("%s: %s", name, err);
86 #else
87               msg_warn("%s: %s", name, err);
88               myfree(err);
89 #endif
90           }
91           argv_add(argvp, arg, (char *) 0);
92     }
93     argv_terminate(argvp);
94     myfree(saved_string);
95     return (argvp);
96 }
97 
98 #ifdef TEST
99 
100  /*
101   * This function is security-critical so it better have a unit-test driver.
102   */
103 #include <string.h>
104 #include <vstream.h>
105 #include <vstream.h>
106 #include <vstring_vstream.h>
107 
main(void)108 int     main(void)
109 {
110     VSTRING *vp = vstring_alloc(100);
111     ARGV   *argv;
112     char   *start;
113     char   *str;
114     char  **cpp;
115 
116     while (vstring_fgets_nonl(vp, VSTREAM_IN) && VSTRING_LEN(vp) > 0) {
117           start = vstring_str(vp);
118           vstream_printf("Input:\t>%s<\n", start);
119           vstream_fflush(VSTREAM_OUT);
120           argv = mail_parm_split("stdin", start);
121           for (cpp = argv->argv; (str = *cpp) != 0; cpp++)
122               vstream_printf("Output:\t>%s<\n", str);
123           argv_free(argv);
124           vstream_fflush(VSTREAM_OUT);
125     }
126     vstring_free(vp);
127     return (0);
128 }
129 
130 #endif
131