home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Geek Gadgets 1
/
ADE-1.bin
/
ade-dist
/
ncftp-2.3.0-src.tgz
/
tar.out
/
contrib
/
ncftp
/
Macro.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-09-28
|
6KB
|
292 lines
/* Macro.c
*
* Purpose: Let the user create and execute macros.
*/
#include "Sys.h"
#include <ctype.h>
#include "Util.h"
#include "Macro.h"
#include "Cmds.h"
#include "Cmdline.h"
#include "MakeArgv.h"
/* First and last nodes in the macro list. */
MacroNodePtr gFirstMacro = NULL;
MacroNodePtr gLastMacro = NULL;
/* Number of macros in the macro list. */
int gNumGlobalMacros = 0;
/* We need this routine in case the user wants to redefine an existing
* macro.
*/
void DisposeMacro(MacroNodePtr macro)
{
MacroNodePtr prevMac, nextMac;
if (macro == NULL)
return;
/* Dispose of the linked-list of data lines first. */
DisposeLineListContents(¯o->macroData);
/* Repair the macro list. */
prevMac = macro->prev;
nextMac = macro->next;
if (prevMac == NULL)
gFirstMacro = nextMac;
if (nextMac != NULL)
nextMac->prev = prevMac;
if (nextMac == NULL)
gLastMacro = prevMac;
if (prevMac != NULL)
prevMac->next = nextMac;
free(macro->name);
free(macro);
--gNumGlobalMacros;
} /* DisposeMacro */
char *MacroGetLine(char *macline, FILE *fp)
{
char *cp;
string str;
*macline = '\0';
while ((fgets(str, ((int) sizeof(str)) - 1, fp)) != NULL) {
cp = strrchr(str, '#');
if (cp != NULL)
*cp = '\0';
cp = str + strlen(str) - 1;
/* Strip trailing space. */
while (cp >= str && isspace(*cp))
*cp-- = '\0';
/* Strip leading space. */
for (cp = str; isspace(*cp); ) ++cp;
if (*cp != '\0') {
Strncpy(macline, cp, sizeof(string));
return (macline);
}
}
return (NULL);
} /* MacroGetLine */
/* Reads in the macro line by line, until we reach a special keyword
* that designates the end.
*/
MacroNodePtr CollectMacro(char *macroName, char *endKeyword, FILE *fp)
{
string macline;
MacroNodePtr macro;
char *name;
/* If we already have a macro by that name, we'll dispose of this
* macro and replace it.
*/
DisposeMacro(FindMacro(macroName));
if ((name = StrDup(macroName)) == NULL)
return NULL;
macro = (MacroNodePtr) calloc((size_t)1, sizeof(MacroNode));
if (macro == NULL)
return NULL;
macro->name = name;
InitLineList(¯o->macroData);
while (1) {
if ((MacroGetLine(macline, fp)) == NULL)
return NULL; /* incomplete macro. */
/* See if we have found the terminating keyword. */
if (STREQ(endKeyword, macline))
break;
AddLine(¯o->macroData, macline);
}
return (macro);
} /* CollectMacro */
/* Adds a macro to the macro list. */
void AttachMacro(MacroNodePtr macro)
{
if (macro != NULL) {
macro->next = NULL;
if (gFirstMacro == NULL) {
macro->prev = NULL;
gFirstMacro = gLastMacro = macro;
} else {
gLastMacro->next = macro;
macro->prev = gLastMacro;
gLastMacro = macro;
}
++gNumGlobalMacros;
}
} /* AttachMacro */
void ReadMacroFile(void)
{
FILE *fp;
string str;
longstring fName;
char *cp;
MacroNodePtr macp;
size_t len;
(void) OurDirectoryPath(fName, sizeof(fName), kMacroFileName);
fp = fopen(fName, "r");
if (fp == NULL) /* It's okay not to have one. Most folks won't. */
return;
len = strlen(kMacroStartToken);
while (1) {
if ((MacroGetLine(str, fp)) == NULL)
break;
/* See if we have found a starting keyword. */
if (STRNEQ(kMacroStartToken, str, len)) {
cp = str + 6;
if (*cp != '\0') {
macp = CollectMacro(cp, kMacroEndToken, fp);
AttachMacro(macp);
}
}
}
DebugMsg("Read %d macros from %s.\n", gNumGlobalMacros, fName);
(void) fclose(fp);
} /* ReadMacroFile */
/* Runs each line in a macro. */
int ExecuteMacro(MacroNodePtr macro, int argc, char **argv)
{
LinePtr mlp;
int err, i;
char *line2;
if (macro == NULL)
return -1;
line2 = (char *) malloc((size_t) 1024);
if (line2 == NULL) {
Error(kDontPerror,
"Not enough memory to run macro \"%s.\"\n", macro->name);
return -1;
}
DebugMsg("Macro: %s\n", macro->name);
for (i=1; i<argc; i++)
DebugMsg(" %s\n", argv[i]);
err = kNoErr;
for (mlp = macro->macroData.first; mlp != NULL; mlp = mlp->next) {
/* Insert arguments passed to the macro. */
(void) Strncpy(line2, mlp->line, (size_t)1024);
ExpandDollarVariables(line2, (size_t)1024, argc, argv);
DebugMsg("%s: %s\n", macro->name, line2);
if ((err = ExecCommandLine(line2)) != 0)
break;
}
free(line2);
return err;
} /* ExecuteMacro */
int ShowMacro(MacroNodePtr macro)
{
LinePtr mlp;
if (macro == NULL)
return -1;
PrintF("macro %s\n", macro->name);
for (mlp = macro->macroData.first; mlp != NULL; mlp = mlp->next) {
PrintF(" %s\n", mlp->line);
}
PrintF("end\n\n");
return 0;
} /* ShowMacro */
void DumpMacro(char *macName)
{
MacroNodePtr mnp;
if (macName == NULL) {
/* Dump 'em all. */
for (mnp = gFirstMacro; mnp != NULL; mnp = mnp->next)
(void) ShowMacro(mnp);
} else {
mnp = FindMacro(macName);
(void) ShowMacro(mnp);
}
} /* DumpMacro */
/* This routine can be used before the CAName list has been constructed
* (see cmdtab.c). We use this to make sure we don't have any duplicate
* macro names when we try to add a new macro. You can also use this
* if you only want to look for a macro, but don't want to bother with
* the possibility of GetCommandOrMacro() returning a command, or an
* ambiguous name error.
*/
MacroNodePtr FindMacro(char *macroName)
{
MacroNodePtr mnp;
for (mnp = gFirstMacro; mnp != NULL; mnp = mnp->next) {
if (STREQ(mnp->name, macroName))
break;
}
return mnp;
} /* FindMacro */
int RunPrefixedMacro(char *pfx, char *sfx)
{
string macName;
MacroNodePtr mnp;
STRNCPY(macName, ".");
STRNCAT(macName, pfx);
STRNCAT(macName, sfx);
mnp = FindMacro(macName);
return ExecuteMacro(mnp, 0, NULL);
} /* RunPrefixedMacro */
/* eof Macro.c */