Coverage Report

Created: 2023-11-19 06:03

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