~ubuntu-branches/ubuntu/hoary/postfix/hoary-security

« back to all changes in this revision

Viewing changes to src/util/mac_parse.c

  • Committer: Bazaar Package Importer
  • Author(s): LaMont Jones
  • Date: 2004-10-06 11:50:33 UTC
  • Revision ID: james.westby@ubuntu.com-20041006115033-ooo6yfg6kmoteu04
Tags: upstream-2.1.3
ImportĀ upstreamĀ versionĀ 2.1.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*++
 
2
/* NAME
 
3
/*      mac_parse 3
 
4
/* SUMMARY
 
5
/*      locate macro references in string
 
6
/* SYNOPSIS
 
7
/*      #include <mac_parse.h>
 
8
/*
 
9
/*      int     mac_parse(string, action, context)
 
10
/*      const char *string;
 
11
/*      int     (*action)(int type, VSTRING *buf, char *context);
 
12
/* DESCRIPTION
 
13
/*      This module recognizes macro expressions in null-terminated
 
14
/*      strings.  Macro expressions have the form $name, $(text) or
 
15
/*      ${text}. A macro name consists of alphanumerics and/or
 
16
/*      underscore. Text other than macro expressions is treated
 
17
/*      as literal text.
 
18
/*
 
19
/*      mac_parse() breaks up its string argument into macro references
 
20
/*      and other text, and invokes the \fIaction\fR routine for each item
 
21
/*      found.  With each action routine call, the \fItype\fR argument
 
22
/*      indicates what was found, \fIbuf\fR contains a copy of the text
 
23
/*      found, and \fIcontext\fR is passed on unmodified from the caller.
 
24
/*      The application is at liberty to clobber \fIbuf\fR.
 
25
/* .IP MAC_PARSE_LITERAL
 
26
/*      The text in \fIbuf\fR is literal text.
 
27
/* .IP MAC_PARSE_VARNAME
 
28
/*      The text in \fIbuf\fR is a macro expression.
 
29
/* .PP
 
30
/*      The action routine result value is the bit-wise OR of zero or more
 
31
/*      of the following:
 
32
/* .IP  MAC_PARSE_ERROR
 
33
/*      A parsing error was detected.
 
34
/* .IP  MAC_PARSE_UNDEF
 
35
/*      A macro was expanded but not defined.
 
36
/* .PP
 
37
/*      Use the constant MAC_PARSE_OK when no error was detected.
 
38
/* SEE ALSO
 
39
/*      dict(3) dictionary interface.
 
40
/* DIAGNOSTICS
 
41
/*      Fatal errors: out of memory. malformed macro name.
 
42
/*
 
43
/*      The result value is the bit-wise OR of zero or more of the
 
44
/*      following:
 
45
/* .IP  MAC_PARSE_ERROR
 
46
/*      A parsing error was detected.
 
47
/* .IP  MAC_PARSE_UNDEF
 
48
/*      A macro was expanded but not defined.
 
49
/* LICENSE
 
50
/* .ad
 
51
/* .fi
 
52
/*      The Secure Mailer license must be distributed with this software.
 
53
/* AUTHOR(S)
 
54
/*      Wietse Venema
 
55
/*      IBM T.J. Watson Research
 
56
/*      P.O. Box 704
 
57
/*      Yorktown Heights, NY 10598, USA
 
58
/*--*/
 
59
 
 
60
/* System library. */
 
61
 
 
62
#include <sys_defs.h>
 
63
#include <ctype.h>
 
64
 
 
65
/* Utility library. */
 
66
 
 
67
#include <msg.h>
 
68
#include <mac_parse.h>
 
69
 
 
70
 /*
 
71
  * Helper macro for consistency. Null-terminate the temporary buffer,
 
72
  * execute the action, and reset the temporary buffer for re-use.
 
73
  */
 
74
#define MAC_PARSE_ACTION(status, type, buf, context) \
 
75
        { \
 
76
            VSTRING_TERMINATE(buf); \
 
77
            status |= action(type, buf, context); \
 
78
            VSTRING_RESET(buf); \
 
79
        }
 
80
 
 
81
/* mac_parse - split string into literal text and macro references */
 
82
 
 
83
int     mac_parse(const char *value, MAC_PARSE_FN action, char *context)
 
84
{
 
85
    char   *myname = "mac_parse";
 
86
    VSTRING *buf = vstring_alloc(1);    /* result buffer */
 
87
    const char *vp;                     /* value pointer */
 
88
    const char *pp;                     /* open_paren pointer */
 
89
    const char *ep;                     /* string end pointer */
 
90
    static char open_paren[] = "({";
 
91
    static char close_paren[] = ")}";
 
92
    int     level;
 
93
    int     status = 0;
 
94
 
 
95
#define SKIP(start, var, cond) \
 
96
        for (var = start; *var && (cond); var++);
 
97
 
 
98
    if (msg_verbose > 1)
 
99
        msg_info("%s: %s", myname, value);
 
100
 
 
101
    for (vp = value; *vp;) {
 
102
        if (*vp != '$') {                       /* ordinary character */
 
103
            VSTRING_ADDCH(buf, *vp);
 
104
            vp += 1;
 
105
        } else if (vp[1] == '$') {              /* $$ becomes $ */
 
106
            VSTRING_ADDCH(buf, *vp);
 
107
            vp += 2;
 
108
        } else {                                /* found bare $ */
 
109
            if (VSTRING_LEN(buf) > 0)
 
110
                MAC_PARSE_ACTION(status, MAC_PARSE_LITERAL, buf, context);
 
111
            vp += 1;
 
112
            pp = open_paren;
 
113
            if (*vp == *pp || *vp == *++pp) {   /* ${x} or $(x) */
 
114
                level = 1;
 
115
                vp += 1;
 
116
                for (ep = vp; level > 0; ep++) {
 
117
                    if (*ep == 0) {
 
118
                        msg_warn("truncated macro reference: \"%s\"", value);
 
119
                        status |= MAC_PARSE_ERROR;
 
120
                        break;
 
121
                    }
 
122
                    if (*ep == *pp)
 
123
                        level++;
 
124
                    if (*ep == close_paren[pp - open_paren])
 
125
                        level--;
 
126
                }
 
127
                if (status & MAC_PARSE_ERROR)
 
128
                    break;
 
129
                vstring_strncat(buf, vp, level > 0 ? ep - vp : ep - vp - 1);
 
130
                vp = ep;
 
131
            } else {                            /* plain $x */
 
132
                SKIP(vp, ep, ISALNUM(*ep) || *ep == '_');
 
133
                vstring_strncat(buf, vp, ep - vp);
 
134
                vp = ep;
 
135
            }
 
136
            if (VSTRING_LEN(buf) == 0) {
 
137
                status |= MAC_PARSE_ERROR;
 
138
                msg_warn("empty macro name: \"%s\"", value);
 
139
                break;
 
140
            }
 
141
            MAC_PARSE_ACTION(status, MAC_PARSE_VARNAME, buf, context);
 
142
        }
 
143
    }
 
144
    if (VSTRING_LEN(buf) > 0 && (status & MAC_PARSE_ERROR) == 0)
 
145
        MAC_PARSE_ACTION(status, MAC_PARSE_LITERAL, buf, context);
 
146
 
 
147
    /*
 
148
     * Cleanup.
 
149
     */
 
150
    vstring_free(buf);
 
151
 
 
152
    return (status);
 
153
}
 
154
 
 
155
#ifdef TEST
 
156
 
 
157
 /*
 
158
  * Proof-of-concept test program. Read strings from stdin, print parsed
 
159
  * result to stdout.
 
160
  */
 
161
#include <vstring_vstream.h>
 
162
 
 
163
/* mac_parse_print - print parse tree */
 
164
 
 
165
static void mac_parse_print(int type, VSTRING *buf, char *unused_context)
 
166
{
 
167
    char   *type_name;
 
168
 
 
169
    switch (type) {
 
170
    case MAC_PARSE_VARNAME:
 
171
        type_name = "MAC_PARSE_VARNAME";
 
172
        break;
 
173
    case MAC_PARSE_LITERAL:
 
174
        type_name = "MAC_PARSE_LITERAL";
 
175
        break;
 
176
    default:
 
177
        msg_panic("unknown token type %d", type);
 
178
    }
 
179
    vstream_printf("%s \"%s\"\n", type_name, vstring_str(buf));
 
180
}
 
181
 
 
182
int     main(int unused_argc, char **unused_argv)
 
183
{
 
184
    VSTRING *buf = vstring_alloc(1);
 
185
 
 
186
    while (vstring_fgets_nonl(buf, VSTREAM_IN)) {
 
187
        mac_parse(vstring_str(buf), mac_parse_print, (char *) 0);
 
188
        vstream_fflush(VSTREAM_OUT);
 
189
    }
 
190
    vstring_free(buf);
 
191
}
 
192
 
 
193
#endif