/*
* Added by Doomdark 11-aug-95:
*
* char *substitute_string(char *, vector *, vector *, int, int)
*
* - Substitutes those words from 1st argument that are listed in
* argument 2, with matching word from argument 3. Length of shortest
* string in argument 2 is argument 4, and longest is argument 5.
* arguments 4 and 5 are optional.
* Used by build-in quicktyper in StickLib.
*/
#ifdef SUBST_DEBUG
#include <string.h>
#endif
#include <stdio.h>
#include <ctype.h>
#include "config.h"
#include "array.h"
#include "interpret.h"
/* When compiling from bugs/doomdark/..., use these includes:
#include "../../config.h"
#include "../../array.h"
#include "../../interpret.h"
*/
/* Routine to replace aliases in a string. Currently considers all
* strings that do not contain spaces as words This could easily be
* changed, though.
*/
#define MAX_REC_DEPTH 8
#define STR_BUF_LENGTH 1000
#define MY_ALNUM(x) (isalnum(x) || x == '_')
static char *rec_stack[MAX_REC_DEPTH];
static char strbuf[STR_BUF_LENGTH + 1];
#if 0
#define RETURN_STRING {\
*dest = '\0';\
src = dest = xalloc(dest - strbuf + 1);\
tmp = strbuf;\
while (*tmp) {\
*dest = *tmp;\
tmp++;\
dest++;\
}\
return src;\
}
#else
#define RETURN_STRING {\
if (!replaced)\
return 0;\
*dest = '\0';\
return strbuf;\
}
#endif
/* Arguments:
* src = String to be processed
* aliases = List (LPC array) of aliases (keywords that are to be
* substituted) in alphabetic order. Have to be in alph. order,
* to allow binary search!
* repl_stings = List of substitutes; array of same size as aliases;
* each alias will get substituted by the element in same in
* same position in this array.
* min_len = Length of shortest alias in alias list.
* max_len = Length of longest alias in alias list.
* (These last two are used for efficiency; optional in a sense)
*/
char *
substitute_string(src, aliases, repl_strings, min_len, max_len)
char *src;
struct vector *aliases;
struct vector *repl_strings;
int min_len;
int max_len;
{
int rec_count = 0, replaced = 0;
char *dest = strbuf;
char *end = &strbuf[STR_BUF_LENGTH - 1];
char *a, *b, *tmp;
char x;
int i;
int str_len, low, high, curr, bingo, a_size;
a_size = VEC_SIZE(aliases);
do {
#ifdef SUBST_DEBUG
fprintf(stderr, "Main loop begins; buffer left: '%s'.\n", src);
#endif
while ((x = *src) && !(MY_ALNUM(x))) {
/* Let's skip all non-letters */
*dest = x;
if (++dest >= end)
RETURN_STRING
src++;
}
/* So, we are now at the end of this buffer; be it replaced alias or the
* 'main' buffer... That depends on recursion level.
*/
if (!x) {
#ifdef SUBST_DEBUG
fprintf(stderr, "Current string ends; returning from recoursion..\n");
#endif
if (!rec_count)
RETURN_STRING
src = rec_stack[--rec_count];
continue;
}
tmp = src;
while ((x = *tmp) && MY_ALNUM(x))
tmp++; /* Let's search last char of the word. */
str_len = tmp - src;
if (str_len >= min_len && str_len <= max_len &&
rec_count < MAX_REC_DEPTH) {
#ifdef SUBST_DEBUG
fprintf(stderr, "Alias check loop begins.\n");
#endif
bingo = low = -1;
high = a_size;
while ((curr = (low + high) / 2) > low) {
a = src;
b = aliases -> item[curr].u.string;
i = 1;
while ((x = *b) && !(i = *a - x)) {
a++;
b++;
}
if (!i && a == tmp) {
bingo = curr;
break;
}
if (i < 0) {
if (!curr) break;
high = curr;
} else {
low = curr;
}
}
/* If it was an alias, let's substitute it; let's simulate recursion with
* the recursion stack.
*/
if (bingo >= 0) {
#ifdef SUBST_DEBUG
fprintf(stderr, "Alias found; doing recursion.\n");
#endif
rec_stack[rec_count++] = tmp;
src = repl_strings -> item[bingo].u.string;
replaced++;
continue;
}
}
/* If couldn't substitute it, let's copy it... */
if (str_len > (end - dest + 1)) {
#ifdef SUBST_DEBUG
fprintf(stderr, "Substitution begins.\n");
#endif
/* If we would skip the end of the buffer, let's copy string and return it. */
while (dest < end) {
*dest = *src;
dest++;
src++;
}
RETURN_STRING;
}
do {
*dest = *src;
dest++;
} while (++src < tmp);
} while (1);
}