/**********
Date: 13th May 1993
Mostly by Mike James these days
Comment: This program parses the input commands for the SFC3 evaluation software
$Log: cmdparse.c,v $
Revision 1.1.1.1 2003/11/04 23:34:56 mjames
Imported into local repositrory
Revision 1.18 2002/09/09 10:26:56 mjames
Removed set generic range and replaced it with a set generic value command
that takes both integers and ranges.
Revision 1.17 2002/01/16 11:22:41 mjames
database.h header file is read in first as it undefined DLL stuff irrelevant
to HPUX
Revision 1.16 2001/12/20 13:49:48 mjames
force ?
Revision 1.15 2001/12/13 22:14:26 mjames
Corrected nested command handlers to allow variable passing without corruption.
Revision 1.14 2001/10/31 22:20:00 mjames
Tidying up problematical comments caused by CVS
'intelligent' comment guessing
Revision 1.13 2001/10/10 20:19:56 mjames
Adjustment of handling of escapes and comments
Revision 1.12 2001/10/10 10:02:59 mjames
Final tweaks to work with end-of line at end-of-file
Revision 1.11 2001/10/10 09:54:30 mjames
Modified command line handler to correctly recognise
comment leaders anywhere on line, not just as first character.
Revision 1.10 2001/07/09 15:08:44 mjames
Check the last character of a line of text to see if it is actually a control code
before deleting it
Revision 1.9 2001/06/19 05:24:57 mjames
Created a trap_fopen to overcome trying to write to read only files.
If this attempted in NT the file can be opened but not written to.
Revision 1.8 2001/06/06 12:10:24 mjames
Move from HPUX
Revision 1.7 2001/05/01 15:21:18 mjames
Added comment leaders on printout of commands executed
Revision 1.6 2001/04/06 22:47:01 mjames
Added doc2, the creator of documentation to Vertical scripts uses PERL
Also correcting generic behaviour and the printing of Verilog.
Revision 1.5 2001/02/06 22:41:14 mjames
Added correct argument passing for 'read file comp_suffix arg0 arg1 arg2 ...
Revision 1.4 2001/01/26 21:50:10 mjames
Managed to get vertical non TCL to compile again
Conversion to argv, argc[] mode of operation continues
Revision 1.3 2001/01/04 21:26:54 mjames
Modifications to add in the TCL style
argument list to all of the functions
.
Revision 1.2 2001/01/02 07:53:52 mjames
Made changes to allow for interface with TCL/Tk
Revision 1.1.1.1 2000/10/19 21:58:35 mjames
Mike put it here
There has been a lot more development, but the comments have been
removed in order to cut down the junk
*********************************************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "expression.h"
#include "generic.h"
#include "database.h"
#include "vertcl_main.h"
#include "cmdparse.h"
#include "cmdlog.h"
#include "cmdutil.h"
#include "cmdexec.h"
/* used for dynamic string allocation/deallocation code
* used here for command keywords May 2 2000 */
#include "lx_support.h"
/*********************************************************************************************************/
#ident "@(#)$Header: c:\\cygwin\\cvsroot/Vert03/cmdlib/cmdparse.c,v 1.1.1.1 2003/11/04 23:34:56 mjames Exp $"
/******************************************* Execute a command ******************************************/
/* define flag for global control of execution mode
* can be Tcl_Cmd or Tcl_GUI : default to be Tcl_Cmd for
* backwards compatibility */
tcl_mode_t tcl_mode = Tcl_Cmd;
#define WORDWIDTH 100 /* max command word ever expected */
#define CMDWIDTH 20 /*Field width for printing CMD word */
int Execute (int argc,char * argv[], struct command Dispatch[])
{
int i,j, FinalResult = UNKNOWNCMD;
if(!argc)
return(NARGS);
if(argv[0][0] == '?')
{
printf("Commands available;\nHelp on:");
for(i=0; i< argc;i++)
for (i=0; Dispatch[i].name; i++)
{
int p;
for(j=0;j<Dispatch[i].NumChar;j++) /* upper case significant chars */
for(;Dispatch[i].name[j];j++) /* and all of the rest, we just print */
if(Dispatch[i].extras) {
p=j;
for(;Dispatch[i].extras[j-p];j++) /* and all of the extras field we just print */
};
for(;j<CMDWIDTH;j++) /* create spacing , relies on auto - wrap */
puts(Dispatch
[i
].
helpstr);
}
FinalResult = OKCMD; /* ? is a valid command at this level */
}
else
{
for (i=0; Dispatch[i].name; i++)
if (strncmp (argv
[0], Dispatch
[i
].
name, Dispatch
[i
].
NumChar)==0)
{
/* Dispatch the next level command */
if (Dispatch[i].function){ /* call function if there */
FinalResult=(*Dispatch[i].function) (Tcl_interp,NULL,argc-1,argv+1);
}
else /* call down the menu */
FinalResult=Execute(argc-1,argv+1,Dispatch[i].Menu);
break;
}
}
return (FinalResult);
}
/******************************************** Strip off words ********************************************/
/* this needs repairing . This code is unsafe.
* Needs to keep a record of how many chars copied !!
* and stop when in danger of a buffer overflow.
*
* Did not work properly if expanded strings are longer than the
* original strings. This now fixed.
*
* Code modified to use some string allocation functions in lx_support.c
*/
/*char wordbuff[1024];
*/
typedef enum { SPACES,CHARS } Phase_t;
int FindWords (char * linebuff, int * pargc, char * argv[],int nArgs, char * Args[],
struct str ** cmd_first,struct str ** cmd_last
)
{
char *WordPtr;
char * BasePtr;
int argc = 0;
int term = ' ',escape,comment,done_word,chars_seen;
char * copy_buff;
Phase_t Phase ;
copy_buff
= malloc(strlen(linebuff
)+1); /* make a safe copy */
/* for (i=0; i<Len; i++) */
/* Cmd->Text[i] = tolower(Cmd->Text[i]); */ /* convert text to lower case */
WordPtr = linebuff; /* set LineStart to beginning of string */
escape = 0;
comment = 0;
/* Now split off the words */
BasePtr = NULL;
while (*WordPtr && argc < WORDSINLINE && comment<2)
{
BasePtr = copy_buff;
Phase = SPACES;
term = ' ';
done_word = 0;
chars_seen = 0;
while(*WordPtr && !done_word && comment <2)
{
switch (Phase)
{
case SPACES:
if(isspace(*WordPtr
)) /* skip leading spaces */
WordPtr++;
else
Phase = CHARS;
break;
case CHARS:
if(!escape && *WordPtr == '\\')
{
escape = 1;
WordPtr ++;
}
else
{
if(term==' ' && !escape && (*WordPtr=='"' || *WordPtr == '\'') )
{ /* sigle or double quotes ? */
term = *WordPtr++;
chars_seen = 1;
}
else
{
/* handle ordinary chars */
if(!escape && term==' ' && WordPtr[0]=='#')
{
comment=2;
done_word = chars_seen; /* comment is appended to valid chars */
WordPtr++;
}
else if (!escape && term == ' ' && WordPtr[0]=='-')
{
comment++;
WordPtr++;
if(comment==2)
done_word = chars_seen; /* comment is appended to valid chars */
}
else if ((*WordPtr=='\r') ||
(*WordPtr=='\n') ||
(!escape && (*WordPtr == term)))
{
if (comment==1)
*BasePtr++ = '-';
comment = 0;
Phase = SPACES;
*BasePtr = '\0';
done_word = 1;
WordPtr++;
}
else
{
if(escape)
*BasePtr++ = '\\';
if (comment==1)
*BasePtr++ = '-';
chars_seen = 1;
comment = 0;
escape = 0;
*BasePtr++ = *WordPtr++;
}
}
}
break;
} /* switch */
} /* while */
*BasePtr = '\0';
/* make_string now performs an expand_string call */
if(chars_seen)
{
argv[argc++] = make_string(copy_buff,cmd_first,cmd_last);
}
}
* pargc = argc;
return (OKCMD);
}
/********************************* executes the command from stdin or a do file **************************/
int ExecuteCommand (FILE * CmdFile,int nArgs, char * Args[])
{
char Buff[PATHLENGTH];
int i, Status;
char * p;
int argc;
char * argv[WORDSINLINE];
struct str * cmd_first, * cmd_last;
cmd_first = NULL;
cmd_last = NULL;
if(!CmdFile
|| feof(CmdFile
))
return(QUITCMD);
p
=fgets(Buff
,PATHLENGTH
-1,CmdFile
); /* read the command from the input stream */
argc=0; /* place the command in the command structure */
if(p==NULL || *Buff=='\0')
return(OKCMD);
/* convert control codes to spaces */
i=0;
while(Buff[i]) {
if (Buff[i]<' ')
Buff[i]=' ';
i++;
}
FindWords (Buff,&argc,argv, nArgs,Args,&cmd_first,&cmd_last); /* split off the words and save in structure */
if (1 || CmdFile != stdin) {
for(i=0;i<argc;i++)
printf("%s ",ISNULLSTR
(argv
[i
])?"\"\"":argv
[i
]); /* log the command word by word if its not given interactively */
}
/* the code below is not as helpful as it seems . Moved recognizer for comments into
Execute as the comments can appear at any point on the command line */
/* if (argc ==0 ||
argv[0][0] == '-' ||
argv[0][0] == '#') */
if(argc==0)
{
/* deallocate any previous structures */
free_strings(&cmd_first,&cmd_last);
return (OKCMD) ; /* comment or a null string */
}
Status = Execute(argc,argv,TopMenu); /* pass the command through the top-level menu */
switch (Status) {
case UNKNOWNCMD :
Log (LOG_ERROR, "# Unknown command\n");
break;
case NARGS :
Log (LOG_ERROR, "# Too few parameters\n");
break;
case FAILED :
Log (LOG_ERROR, "# Problem with command\n");
break;
};
if (Status !=OKCMD) {
Log(LOG_ERROR,"-- ? ");
for (i=0; i < argc; i++) /* display offending command */
Log (LOG_ERROR, " %s", ISNULLSTR(argv[i])?"\"\"":argv[i]);
Log(LOG_ERROR,"\n");
};
/* deallocate any previous structures */
free_strings(&cmd_first,&cmd_last);
return(Status);
}
/********************************* Execute a command string ******************************************/
int ExecuteString (char * commandstring , int nArgs, char * Args[]) {
int argc =0;
char * argv[WORDSINLINE];
int Status = 0;
struct str * cmd_first, * cmd_last;
cmd_first = NULL;
cmd_last = NULL;
FindWords (commandstring,&argc,argv, nArgs,Args,&cmd_first,&cmd_last); /* split off the words and save in structure */
Status = Execute(argc,argv,TopMenu); /* pass the command through the top-level menu */
/* deallocate any previous structures */
free_strings(&cmd_first,&cmd_last);
return(Status);
}
/********************************* A parser for the '*.do files ******************************************/
static int Depth=0;
#define MAXDEPTH 10 /* maximum depth of 'do' files */
#define MAXARGV 10
int ParseFile (FILE * CmdFile,int nArgs,char * Args[])
{
int Status = 0;
char * argp[MAXARGV];
char ** argp_prev;
int nArgs_prev;
int i;
/* diagnosis */
if ( nArgs > MAXARGV )
nArgs = MAXARGV;
if ( nArgs < 0 )
nArgs = 0;
/* belt and braces null check */
if(!CmdFile)
return(FAILED);
for(i=0;i<MAXARGV;i++) {
if (i < nArgs)
argp[i] = strdup(Args[i]);
else
argp[i] = NULL;
/* printf("Arg [%2d]='%s'\n",i,argp[i]); */
}
nArgs_prev = yy_nArgs;
argp_prev = yy_Args;
yy_nArgs = nArgs;
yy_Args = argp;
Depth ++; /* keep a count of recursion depth */
printf("-- Command file nesting level = %d\n",Depth
);
if (Depth > MAXDEPTH)
{
Log (LOG_ERROR, "Recursive call of files is greater than %d\n", MAXDEPTH);
Depth--;
return (FAILED);
}
while(Status == OKCMD ) /* execute the command from do file input stream */
Status = ExecuteCommand(CmdFile, nArgs, argp);
Depth--;
yy_nArgs = nArgs_prev;
yy_Args = argp_prev;
for(i=0;i<MAXARGV;i++)
if (argp[i]) {
argp[i] = NULL;
}
return(Status);
}
/*********************************************************************************************************/