]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/zwgc/substitute.c
r4264@bucket (orig r254): kcr | 2008-01-20 22:11:44 -0500
[1ts-debian.git] / zephyr / zwgc / substitute.c
1 /* This file is part of the Project Athena Zephyr Notification System.
2  * It is one of the source files comprising zwgc, the Zephyr WindowGram
3  * client.
4  *
5  *      Created by:     Marc Horowitz <marc@athena.mit.edu>
6  *
7  *      $Id$
8  *
9  *      Copyright (c) 1989 by the Massachusetts Institute of Technology.
10  *      For copying and distribution information, see the file
11  *      "mit-copyright.h".
12  */
13
14 #if (!defined(lint) && !defined(SABER))
15 static char rcsid_substitute_c[] = "$Id$";
16 #endif
17
18 #include <zephyr/mit-copyright.h>
19
20 #include <sysdep.h>
21 #include "new_memory.h"
22 #include "lexer.h"
23 #include "substitute.h"
24
25 /*
26  *  Internal Routine:
27  *
28  *    string eat_dollar_sign_stuff(string (*lookup)(string); string *text_ptr)
29  *        Modifies: *text_ptr
30  *        Effects: This routine deals with handling the stuff after a '$'
31  *                 for substitute.  If *text_ptr starts with a valid
32  *                 variable reference (minus the leading '$'), we look up
33  *                 the variable using lookup and return its value.
34  *                 *text_ptr is also advanced past the variable reference.
35  *                 If a '$' starts *text_ptr, *text_ptr is advanced past it &
36  *                 "$" returned.  (This handles "$$" -> "$")  Otherwise,
37  *                 "$" is returned and *text_ptr is not advanced.
38  *                 The returned string must not be freed.
39  */
40
41 static string
42 eat_dollar_sign_stuff(string (*lookup)(string),
43                       string *text_ptr)                 /* Input/Output parameter */
44 {
45     char c;
46     char closing_brace = 0;
47     char *p = *text_ptr;
48     char *variable_name_start;
49     int variable_name_length;
50
51     /*
52      * Handle "$$" -> "$" translation:
53      */
54     c = *p;
55     if (c=='$') {
56         *text_ptr = p+1;
57         return("$");
58     }
59
60     /*
61      * If opening brace present (i.e., '(' or '{'), skip it and save away
62      * what closing brace we must see at the end of the variable reference:
63      */
64     if (c=='{') {
65         closing_brace = '}';
66         c = *++p;
67     } else if (c=='(') {
68         closing_brace = ')';
69         c = *++p;
70     }
71
72     /*
73      * Eat {identifier_char}* keeping track of what we ate:
74      */
75     variable_name_start = p;
76     variable_name_length = 0;
77     while (c = *p, is_identifier_char(c)) {
78         p++;
79         variable_name_length++;
80     }
81
82     /*
83      * If there was an opening brace, there had better be a comparable
84      * closing brace.  If so, skip it.  If not, we have an invalid variable
85      * reference so return '$' without advancing *text_ptr.
86      */
87     if (closing_brace) {
88         if (c==closing_brace)
89           c = *++p;
90         else
91           return("$");
92     }
93
94     /*
95      * Zero length variable names are not valid:
96      */
97     if (!variable_name_length)
98       return("$");
99
100     /*
101      * We have a valid variable reference.  Advance past it then lookup
102      * its value and return it:
103      */
104     *text_ptr = p;
105     if (variable_name_length > MAX_IDENTIFIER_LENGTH)
106       variable_name_length = MAX_IDENTIFIER_LENGTH;
107     variable_name_start = string_CreateFromData(variable_name_start,
108                                                 variable_name_length);
109     p = lookup(variable_name_start);
110     free(variable_name_start);
111     return(p);
112 }
113
114 /*
115  *    string substitute(string (*lookup)(string); string text)
116  *        Effects: returns the result of expanding all variable
117  *                 references in text using lookup.  Example:
118  *                 "test $foo.$bar baz" would be translated to
119  *                 "text <foo>.<bar> baz" where "<foo>" is the value of
120  *                 lookup("foo") and "<bar>" is the value of lookup("bar").
121  *                 Variables are case sensitive and have the form
122  *                 {identifier_char}+ where identifier_char is defined
123  *                 in lexer.h by is_identifier_char.  $(foo) and
124  *                 ${foo} are alternate forms for $foo.  In particular,
125  *                 ${foo}bar is a reference to foo followed by "bar" while
126  *                 $foobar is a reference to foobar.  Incomplete variable
127  *                 references like $(foo bar are displayed as if they
128  *                 were not variable references.  To allow quoting, "$$"
129  *                 is translated to "$".  Only the first
130  *                 MAX_IDENTIFIER_LENGTH characters of an identifier are
131  *                 significant.  The strings returned by lookup are not
132  *                 modified in any way or freed.
133  */
134
135 string
136 substitute(string (*lookup)(string),
137            string text)
138 {
139     string result_so_far = string_Copy("");
140     char *p, *temp;
141
142     for (;;) {
143         /*
144          * Move [^$]* from start of text to end of result_so_far:
145          */
146         for (p=text; *p && (*p)!='$'; p++) ;
147         if (text != p) {
148             temp = string_CreateFromData(text, p-text);
149             text = p;
150             result_so_far = string_Concat2(result_so_far, temp);
151             free(temp);
152         }
153
154         /*
155          * If text now empty, exit -- the result is in result_so_far:
156          */
157         if (!*text)
158           return(result_so_far);
159
160         /*
161          * Otherwise, text begins with a '$'.  Eat it then call
162          * eat_dollar_sign_stuff to process stuff after it.
163          * Append result to result_so_far, update text, & continue.
164          */
165         text++;
166         p = eat_dollar_sign_stuff(lookup, &text);
167         result_so_far = string_Concat2(result_so_far, p);
168     }
169 }