Category : Batch File Utilities - mostly for DOS
Archive   : RBSETENV.ZIP
Filename : COMSUB.C
* comsub.c - routines to perform command substitution and environment variable
* parsing and expansion
*
* Author: R. Brittain 4/11/90
* This code placed in the public domain
*
*/
#include
#include
#include
#include "comsub.h"
int rebuild_argv(int *argc, char ***argv)
{
/*
* Build a new argv array, by iteratively performing backquote expansion
* and environment variable expansion until no more is possible.
* We always replace argv[] at least once, because the routine terminates it
* with an extra null, which is useful later for exec()ing.
* Returns the number of substitutions performed
*/
int i, count = 0, subst;
count += expand_backquotes(argc, argv);
do {
subst = FALSE;
/* look for any argument beginning with BKQ or ENV */
for (i=0; i < *argc; i++) {
if (*(*argv)[i] == BKQ || *(*argv)[i] == ENV ) {
subst = TRUE;
break;
}
}
if (subst) count += expand_backquotes(argc, argv);
} while (subst);
return(count);
}
int expand_backquotes(int *argc, char ***argv)
{
/*
* Perform command substitution if any argument begins with BKQ (`)
* Perform environment variable expansion if an argument begins with ENV (%)
* Returns the number of substitutions performed
* This routine would be simpler if backquoted commands were always parsed
* as a single command line argument, but doing it here means we don't need
* to modify the startup code.
*/
char **base, *p, *result;
estring command = {NULL, NULL, 0, 80};
int i, j, status = 0;
FILE *fp;
MEMCHECK(base = (char **) malloc(sizeof(char **))) ;
*base = NULL;
for (i=0, j=0; i < *argc; i++) {
if (*(*argv)[i] == BKQ) {
/*
* first character is a BKQ - we have a request for command
* substitution so build command in an estring structure
*/
status++;
MEMCHECK( addstring(&command, (*argv)[i]+1, 0) );
if (*command.b == EXE) {
set_popen_exec();
command.b++;
} else {
set_popen_shell();
}
/*
* if this argument ends with a second BKQ, remove it
* otherwise, scan forward for an argument terminated by BKQ,
* appending to command as we go
*/
if (*(p = endptr(command.b)-1) == BKQ) {
*p = '\0';
} else {
do {
/* increment argument pointer and append to current command */
if ( i++ >= *argc) fatal("Unterminated command substitution",1);
/* we ran out of arguments before finding BKQ */
MEMCHECK(addstring(&command," ",1));
MEMCHECK(addstring(&command,(*argv)[i], 0));
} while (*(endptr((*argv)[i])-1) != BKQ);
/* now stomp on of the trailing backquote */
if (*(p = endptr(command.b)-1) == BKQ) *p = '\0';
}
/* perform variable substitution then run the command via popen */
command.b = expand_env(command.b);
if ((fp = popen(command.b, "r")) == NULL) {
fputs (command.b, stderr);
fatal(": popen failed: \n",1);
}
result = mfgets(fp);
pclose(fp);
/* now parse
p = strtok(result," \t");
while (p != NULL) {
MEMCHECK(base = (char **)realloc(base,(j+2)*sizeof(char **))) ;
MEMCHECK(base[j++] = strdup(p)) ;
base[j] = (char *)NULL;
p = strtok(NULL," \t");
}
} else if (*(*argv)[i] == ENV) {
/* we have a request for environment substitution */
status++;
result = expand_env((*argv)[i]);
/* now parse
p = strtok(result," \t");
while (p != NULL) {
MEMCHECK(base = (char **)realloc(base,(j+2)*sizeof(char **))) ;
MEMCHECK(base[j++] = strdup(p)) ;
base[j] = (char *)NULL;
p = strtok(NULL," \t");
}
} else {
/* grab one more pointer, add to base array, and copy this argument */
MEMCHECK(base = (char **)realloc(base,(j+2)*sizeof(char **))) ;
base[j++] = (*argv)[i];
base[j] = (char *)NULL;
}
}
*argv = base;
*argc = j;
return(status);
}
char *endptr(p)
char *p;
{
while (*p) p++;
return p;
}
char *mfgets (FILE *stream)
{
/*
* Suck in the entire file, replacing newlines by spaces
* and allocating memory as needed
*/
estring contents = {NULL, NULL, 0, 132};
char line[132];
if (feof(stream)) return NULL;
while (fgets(line,sizeof(line),stream) != NULL) {
if (*(endptr(line)-1) == '\n') *(endptr(line)-1) = ' ';
addstring(&contents,line,strlen(line));
}
return(contents.b);
}
char *expand_env(char *s)
{
/*
* Scan string s for '%' (or ENV) and expand environment variables as found
* Return a pointer to the expanded string (which may be the same as the input)
* The input string is left intact
*/
char *r;
estring result = {NULL, NULL, 0, 128};
estring var = {NULL, NULL, 0, 64};
result.p = result.b;
if (strchr(s,ENV) == NULL) {
/*
* nothing to do
*/
return(s);
} else {
/*
* we have some vars to substitute - parse into words by whitespace
* and examine each one
*/
while (*s) {
if (*s == ENV) {
/* some work to do */
if (*(++s) == ENV) {
/* double ENV */
MEMCHECK(addstring(&result, s++, 1));
} else {
/* look for next whitespace or ENV */
var.b = var.p;
while (*s && *s != ENV && !isspace(*s)) {
addstring(&var, s++, 1);
}
/* copy over the variable value, if non null */
if ((r = getenv(strupr(var.b))) != NULL)
MEMCHECK(addstring(&result,r,strlen(r)));
/* examine how the var name was terminated */
if (*s == ENV && isspace(*(s+1))) {
/* redundant trailing ENV - skip over */
s++;
}
}
} else {
/* just copy characters */
MEMCHECK(addstring(&result, s++, 1));
}
}
return(result.b);
}
}
char *addstring(estring *es, char *add, int count)
{
/*
* Add
*
* Returns a pointer to the start of the string (NULL if an expansion failed)
* If the count is zero, then it is taken to be strlen(add) by default
*/
if (count == 0) count = strlen(add);
if (es->p - es->b + count >= es->len) {
if (es->p != NULL) {
/* we are expanding */
*es->p = '\0';
es->b = (char *)realloc(es->b, es->len + max(es->inc, count+1));
if (es->b == (char *)NULL) return (NULL);
es->p = endptr(es->b);
es->len += es->inc;
} else {
/* we are making initial allocation */
es->p = es->b = (char *)calloc(max(es->inc,count+1), 1);
if (es->b == (char *)NULL) return (NULL);
es->len = es->inc;
}
}
strncpy(es->p, add, count);
es->p += count;
*es->p = '\0';
return(es->b);
}
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/