adding zephyr-im master branch
This commit is contained in:
169
zwgc/substitute.c
Normal file
169
zwgc/substitute.c
Normal file
@ -0,0 +1,169 @@
|
||||
/* This file is part of the Project Athena Zephyr Notification System.
|
||||
* It is one of the source files comprising zwgc, the Zephyr WindowGram
|
||||
* client.
|
||||
*
|
||||
* Created by: Marc Horowitz <marc@athena.mit.edu>
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
|
||||
* For copying and distribution information, see the file
|
||||
* "mit-copyright.h".
|
||||
*/
|
||||
|
||||
#if (!defined(lint) && !defined(SABER))
|
||||
static const char rcsid_substitute_c[] = "$Id$";
|
||||
#endif
|
||||
|
||||
#include <zephyr/mit-copyright.h>
|
||||
|
||||
#include <sysdep.h>
|
||||
#include "new_memory.h"
|
||||
#include "lexer.h"
|
||||
#include "substitute.h"
|
||||
|
||||
/*
|
||||
* Internal Routine:
|
||||
*
|
||||
* string eat_dollar_sign_stuff(string (*lookup)(string); string *text_ptr)
|
||||
* Modifies: *text_ptr
|
||||
* Effects: This routine deals with handling the stuff after a '$'
|
||||
* for substitute. If *text_ptr starts with a valid
|
||||
* variable reference (minus the leading '$'), we look up
|
||||
* the variable using lookup and return its value.
|
||||
* *text_ptr is also advanced past the variable reference.
|
||||
* If a '$' starts *text_ptr, *text_ptr is advanced past it &
|
||||
* "$" returned. (This handles "$$" -> "$") Otherwise,
|
||||
* "$" is returned and *text_ptr is not advanced.
|
||||
* The returned string must not be freed.
|
||||
*/
|
||||
|
||||
static string
|
||||
eat_dollar_sign_stuff(string (*lookup)(string),
|
||||
string *text_ptr) /* Input/Output parameter */
|
||||
{
|
||||
char c;
|
||||
char closing_brace = 0;
|
||||
char *p = *text_ptr;
|
||||
char *variable_name_start;
|
||||
int variable_name_length;
|
||||
|
||||
/*
|
||||
* Handle "$$" -> "$" translation:
|
||||
*/
|
||||
c = *p;
|
||||
if (c=='$') {
|
||||
*text_ptr = p+1;
|
||||
return("$");
|
||||
}
|
||||
|
||||
/*
|
||||
* If opening brace present (i.e., '(' or '{'), skip it and save away
|
||||
* what closing brace we must see at the end of the variable reference:
|
||||
*/
|
||||
if (c=='{') {
|
||||
closing_brace = '}';
|
||||
c = *++p;
|
||||
} else if (c=='(') {
|
||||
closing_brace = ')';
|
||||
c = *++p;
|
||||
}
|
||||
|
||||
/*
|
||||
* Eat {identifier_char}* keeping track of what we ate:
|
||||
*/
|
||||
variable_name_start = p;
|
||||
variable_name_length = 0;
|
||||
while (c = *p, is_identifier_char(c)) {
|
||||
p++;
|
||||
variable_name_length++;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there was an opening brace, there had better be a comparable
|
||||
* closing brace. If so, skip it. If not, we have an invalid variable
|
||||
* reference so return '$' without advancing *text_ptr.
|
||||
*/
|
||||
if (closing_brace) {
|
||||
if (c==closing_brace)
|
||||
c = *++p;
|
||||
else
|
||||
return("$");
|
||||
}
|
||||
|
||||
/*
|
||||
* Zero length variable names are not valid:
|
||||
*/
|
||||
if (!variable_name_length)
|
||||
return("$");
|
||||
|
||||
/*
|
||||
* We have a valid variable reference. Advance past it then lookup
|
||||
* its value and return it:
|
||||
*/
|
||||
*text_ptr = p;
|
||||
if (variable_name_length > MAX_IDENTIFIER_LENGTH)
|
||||
variable_name_length = MAX_IDENTIFIER_LENGTH;
|
||||
variable_name_start = string_CreateFromData(variable_name_start,
|
||||
variable_name_length);
|
||||
p = lookup(variable_name_start);
|
||||
free(variable_name_start);
|
||||
return(p);
|
||||
}
|
||||
|
||||
/*
|
||||
* string substitute(string (*lookup)(string); string text)
|
||||
* Effects: returns the result of expanding all variable
|
||||
* references in text using lookup. Example:
|
||||
* "test $foo.$bar baz" would be translated to
|
||||
* "text <foo>.<bar> baz" where "<foo>" is the value of
|
||||
* lookup("foo") and "<bar>" is the value of lookup("bar").
|
||||
* Variables are case sensitive and have the form
|
||||
* {identifier_char}+ where identifier_char is defined
|
||||
* in lexer.h by is_identifier_char. $(foo) and
|
||||
* ${foo} are alternate forms for $foo. In particular,
|
||||
* ${foo}bar is a reference to foo followed by "bar" while
|
||||
* $foobar is a reference to foobar. Incomplete variable
|
||||
* references like $(foo bar are displayed as if they
|
||||
* were not variable references. To allow quoting, "$$"
|
||||
* is translated to "$". Only the first
|
||||
* MAX_IDENTIFIER_LENGTH characters of an identifier are
|
||||
* significant. The strings returned by lookup are not
|
||||
* modified in any way or freed.
|
||||
*/
|
||||
|
||||
string
|
||||
substitute(string (*lookup)(string),
|
||||
string text)
|
||||
{
|
||||
string result_so_far = string_Copy("");
|
||||
char *p, *temp;
|
||||
|
||||
for (;;) {
|
||||
/*
|
||||
* Move [^$]* from start of text to end of result_so_far:
|
||||
*/
|
||||
for (p=text; *p && (*p)!='$'; p++) ;
|
||||
if (text != p) {
|
||||
temp = string_CreateFromData(text, p-text);
|
||||
text = p;
|
||||
result_so_far = string_Concat2(result_so_far, temp);
|
||||
free(temp);
|
||||
}
|
||||
|
||||
/*
|
||||
* If text now empty, exit -- the result is in result_so_far:
|
||||
*/
|
||||
if (!*text)
|
||||
return(result_so_far);
|
||||
|
||||
/*
|
||||
* Otherwise, text begins with a '$'. Eat it then call
|
||||
* eat_dollar_sign_stuff to process stuff after it.
|
||||
* Append result to result_so_far, update text, & continue.
|
||||
*/
|
||||
text++;
|
||||
p = eat_dollar_sign_stuff(lookup, &text);
|
||||
result_so_far = string_Concat2(result_so_far, p);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user