home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
cenvi23.zip
/
BATCH.CMM
< prev
next >
Wrap
Text File
|
1996-01-02
|
21KB
|
798 lines
/*
* Batch.cmm
*
* Interpret a DOS batch file using CEnvi. This should work on all CEnvi
* versions.
*/
/* ---------------------------------------------------------------------- */
usage()
{
printf("Use the BATCH command to interpret a DOS batch file under any system\n");
printf("that CEnvi supports.\n");
printf("Syntax:\n BATCH [filename] [args]\nwhere:\n");
printf(" filename The .BAT file to be interpreted.\n");
printf(" args Any number of arguments for the batch file.\n");
exit(EXIT_FAILURE);;
}
/* ---------------------------------------------------------------------- */
/*
* Setup sets up all system dependent variables. Later, when #ifdef is working
* this will be replaced using that.
*/
search_path = ""; // make it global
errorlevel = 0;
echo = 1; // echo on
setup()
{
if( defined(_NWNLM_) )
{
search_path = "SYS:/CENVI/";
} else {
if( defined(CMMPATH) ) search_path = CMMPATH;
}
}
/*
* Change the current directory to the given one. Return 0 if successful.
*/
my_chdir(newdir)
{
if( defined(_NWNLM_) ) return chdir(newdir);
if( defined(_DOS_) || defined(_DOS32_) || defined(_WINDOWS_) )
{
lReg.ah = 0x3B;
if !defined(_DOS32_)
lReg.ds = segment(newdir), lReg.dx = offset(newdir);
else
lReg.dx = pointer(newdir);
interrupt(0x21,lReg,out);
return out.ax;
}
if( defined(_NTCON_) || defined(_NTWIN_) || defined(_95CON_) ||
defined(_95WIN_) )
{
return !DynamicLink("KERNEL32","SetCurrentDirectoryA",STDCALL,newdir);
}
if( defined(_OS2_) )
{
#define ORD_DOS32SETCURRENTDIR 255
return DynamicLink("doscalls",ORD_DOS32SETCURRENTDIR,BIT32,CDECL,newdir);
}
}
special_command = "__@%*&^%";
/* ---------------------------------------------------------------------- */
/*
* The count is the number of params, the array is the params. These
* correspond to %X where X is a digit. We also do %variable% for environment
* variables, all uppercase.
*
* To ease processing, we kill the '\n' too.
*/
substitute_line(line,count,array)
{
it = ""; i = 0; j = 0;
while( line[i] )
{
if( line[i]!='%' )
{
if( line[i]!='\n' )
{
it[j++] = line[i];
}
i++;
continue;
}
// Here we have a substitution...
if( isdigit(line[i+1]) )
{
i += 2;
num = line[i-1]-'0';
if( num>=count ) continue; // no such argument
for( k=0;array[num][k];k++ ) it[j++] = array[num][k];
} else {
if( line[++i]=='%' )
{
i++; it[j++] = '%'; continue;
}
env = ""; offset = 0;
for( ;line[i] && !isspace(line[i]) && line[i]!='%';i++ )
env[offset++] = line[i];
if( isspace(line[i]) )
{
printf("Variable is not terminated.\n");
return "";
}
env[offset] = 0; i++;
value = "";
sprintf(to_exec,"if( DataType(%s)==CMM_INT ) sprintf(value,\"%%d\",%s); else if( DataType(%s)==CMM_BYTE ) strcpy(value,%s);\n",env,env,env,env);
Interpret(to_exec,INTERP_TEXT);
while( value[0]!='\0' ) { it[j++] = value[0]; value++; }
}
}
it[j] = '\0';
return it;
}
/*
* Search the appropriate places for the given name. If found, return the
* full filename else return NULL.
*/
find_cmm(name)
{
// First search the exact filename
if( fp = fopen(name,"r") )
{
fclose(fp);
return FullPath(name);
}
// Then search the filename converted to '.cmm'
path = SplitFileName(name);
sprintf(newname,"%s%s.cmm",path.dir,path.name);
if( fp = fopen(newname,"r") )
{
fclose(fp);
return FullPath(newname);
}
// Then search the converted filename using the search path.
strcpy(tmppath,search_path);
while( tmppath[0]!='\0' )
{
while( tmppath[0]==';' ) tmppath++;
start = tmppath;
while( tmppath[0]!='\0' && tmppath[0]!=';' ) tmppath++;
tmppath[0] = '\0'; tmppath++;
sprintf(newname,"%s%c%s.cmm",start,strchr(start,'/')?'/':'\\',path.name);
if( fp = fopen(newname,"r") )
{
fclose(fp);
return FullPath(newname);
}
}
// Else not found
return NULL;
}
/* ---------------------------------------------------------------------- */
next_token(line,index)
{
command = ""; j = 0;
while( isspace(line[index]) ) index++;
while( line[index] && !isspace(line[index]) )
command[j++] = line[index++];
while( isspace(line[index]) ) index++;
command[j] = '\0';
return command;
}
/* ---------------------------------------------------------------------- */
// All these functions return the name of the label we have to GOTO, or ""
// if none.
/*
* We just ignore the line.
*/
REM_handler(the_line,ptr,line_num)
{
return "";
}
/*
* We dump the text to the terminal. The exceptions are if we have 'echo on'
* or 'echo off'.
*/
ECHO_handler(the_line,ptr,line_num)
{
if( !stricmp(the_line+ptr,"ON") )
{
echo = 1;
return "";
}
if( !stricmp(the_line+ptr,"OFF") )
{
echo = 0;
return "";
}
printf("%s\n",the_line+ptr);
return "";
}
/*
* If no parameter, print the current directory. Otherwise, set the current
* directory to what is given.
*/
CD_handler(the_line,ptr,line_num)
{
if( the_line[ptr]=='\0' )
{
printf("%s\n",getcwd(buffer));
return "";
}
if( my_chdir(the_line+ptr) )
printf("The system cannot find the path specified at line %d.\n",line_num);
return "";
}
/*
* Simply clear the screen.
*/
CLS_handler(the_line,ptr,line_num)
{
ScreenClear();
return "";
}
/*
* TYPE a file to the terminal. This is an incredibly simple routine. Use
* MORE for some options.
*/
TYPE_handler(the_line,ptr,line_num)
{
if( fp = fopen(the_line+ptr,"r") )
{
while( 1 )
{
if( (newline = fgets(fp))==NULL ) break;
printf("%s",newline);
}
fclose(fp);
} else {
printf("Unable to open file \"%s\" at line %d.\n",the_line+ptr,line_num);
}
return "";
}
/*
* Since the variable we need to change is a local to one of our callers,
* we pass back a command to it to tell it to do what we want.
*/
SHIFT_handler(the_line,ptr,line_num)
{
return special_command;
}
/*
* Just waits for the user to press any key.
*/
PAUSE_handler(the_line,ptr,line_num)
{
printf("Press any key when ready . . . "); fflush(stdout);
getch();
printf("\n");
return "";
}
/*
* Invoke a new batch file and return to this one when it finishes
*/
CALL_handler(the_line,ptr,line_num)
{
// Set up a new argc/argv array and call main again.
strcpy(newargv[0],"CEnvi");
newargc = 1;
while( the_line[ptr]!='\0' )
{
command = next_token(the_line,ptr);
strcpy(newargv[newargc++],command);
while( isspace(the_line[ptr]) ) ptr++;
}
main(newargc,newargv);
return "";
}
/*
* The _EVIL_ goto command...
*/
GOTO_handler(the_line,ptr,line_num)
{
return the_line+ptr;
}
/*
* No, this does not simulate a person skilled in dealing with evil
* Egyptian gods...
*/
SET_handler(the_line,ptr,line_num)
{
if( defined(_NWNLM_) )
{
printf("Netware has no environment variables at line %d.\n",line_num);
return "";
}
if( the_line[ptr]=='\0' )
{
array = getenv();
for( ii=0;ii<GetArraySpan(array);ii++ )
{
printf("%s=%s\n",array[ii],getenv(array[ii]));
}
return "";
}
// Else we extract the name and see if we have a '=' or not.
command = next_token(the_line,ptr);
if( (where = strchr(command,'='))!=NULL )
{
where[0] = '\0';
strcpy(env_var,command);
strcpy(new_val,where+1);
} else {
strcpy(env_var,command);
new_val = NULL;
if( the_line[ptr]=='=' )
{
while( isspace(the_line[++ptr]) );
strcpy(new_val,the_line+ptr);
}
}
if( new_val==NULL )
{
printval = getenv(env_var);
printf("%s=%s\n",env_var,(printval!=NULL)?printval:"");
} else {
putenv(env_var,new_val);
}
return "";
}
/*
* A simple looping construct.
*/
FOR_handler(the_line,ptr,line_num)
{
command = next_token(the_line,ptr);
if( command[0]!='%' )
{
printf("Illegal loop variable in FOR statement at line %d.\n",line_num);
return "";
}
strcpy(loop_variable,command);
command = next_token(the_line,ptr);
if( stricmp(command,"IN") )
{
printf("Malformed FOR statement, missing IN clause at line %d.\n",line_num);
return "";
}
if( the_line[ptr++]!='(' )
{
printf("Malformed FOR statement, missing open parenthesis at line %d.\n",line_num);
}
// Next we need to collect all the things we index over...
undefine(list); list_index = 0;
done = 0;
while( !done )
{
command = next_token(the_line,ptr);
if( command[strlen(command)-1]==')' )
{
command[strlen(command)-1] = '\0'; done = 1;
}
if( command[0]!='\0' )
{
if( strcspn(command,"*?")==strlen(command) )
{
strcpy(list[list_index++],command);
} else {
files = Directory(command);
for( i=0;files && i<=GetArraySpan(files);i++ )
strcpy(list[list_index++],files[i].name);
}
}
}
command = next_token(the_line,ptr);
if( stricmp(command,"DO") )
{
printf("Malformed FOR statement after arg list at line %d.\n",line_num);
return "";
}
for( i=0;i<list_index;i++ )
{
strcpy(to_do,the_line+ptr);
while( (indx = strstr(to_do,loop_variable))!=NULL )
{
index = indx-to_do;
strcpy(new_do,to_do);
strcpy(new_do+index,list[i]);
strcat(new_do,to_do+index+strlen(loop_variable));
strcpy(to_do,new_do);
}
process_command(to_do,line_num);
}
return "";
}
/*
* And the testing construct.
*/
IF_handler(the_line,ptr,line_num)
{
command = next_token(the_line,ptr);
notted = 0;
if( !stricmp(command,"NOT") )
{
notted = 1;
command = next_token(the_line,ptr);
}
// Here we decide which of the three considitions we have.
if( !stricmp(command,"EXIST") )
{
command = next_token(the_line,ptr);
exist = (fp = fopen(command,"r"))!=NULL;
if( fp ) fclose(fp);
if( notted^exist )
{
return process_command(=the_line+ptr,line_num);
}
return "";
}
if( !stricmp(command,"ERRORLEVEL") )
{
command = next_token(the_line,ptr,line_num);
testlevel = atoi(command);
command = next_token(the_line,ptr);
if( notted^(errorlevel>=testlevel) )
{
return process_command(=the_line+ptr,line_num);
}
return "";
}
if( where = strstr(command,"==") )
{
where[0] = 0; where += 2;
if( notted^!stricmp(command,where) )
{
return process_command(=the_line+ptr,line_num);
}
return "";
}
printf("Unrecognized IF syntax beginning with %s at line %d.\n",command,line_num);
return "";
}
command_names = {
"REM", "ECHO", "CD", "CLS", "TYPE", "SHIFT", "CAUSE", "CALL", "SET",
"GOTO", "FOR", "IF", "PAUSE"
};
/* ---------------------------------------------------------------------- */
process_command(the_line,line_num)
{
ptr = 0; while( isspace(the_line[ptr]) ) ptr++;
// If the line is blank, we skip it
if( the_line[ptr]=='\n' || the_line[ptr]=='\0' ) return "";
// If it is a ':LABEL' line, we skip it.
if( the_line[ptr]==':' ) return "";
// Else it is either an internal command, a .CMM script, or we dump it
// to the system processor.
mark = ptr;
command = next_token(the_line,ptr);
// ----------------------------------------------------------------------
// Here we process all internal commands
// ----------------------------------------------------------------------
for( i=0;i<=GetArraySpan(command_names);i++ )
{
if( !stricmp(command_names[i],command) )
{
sprintf(func_name,"%s_handler",command_names[i]);
return function(func_name,the_line,ptr,line_num);
}
}
// ----------------------------------------------------------------------
// We check to see if it is a drive designation
// ----------------------------------------------------------------------
if( command[1]==':' && strlen(command)==2 )
{
#define ORD_DOS32SETDEFAULTDISK 220
if( defined(_OS2_) )
{
DynamicLink("doscalls",ORD_DOS32SETDEFAULTDISK,BIT32,CDECL,
toupper(command[0])-'A'+1);
}
if( defined(_NTWIN_) || defined(_NTCON_) || defined(_95CON_) ||
defined(_95WIN_) )
{
CD_handler(command,0,line_num);
}
if( defined(_WINDOWS_) || defined(_DOS_) || defined(_DOS32_) )
{
lReg.ah = 0x0E;
lReg.dl = toupper(command[0]) - 'A';
interrupt(0x21,lReg);
}
return "";
}
// -----------------------------------------------------------------------
// Otherwise, it is either a CMM script or we dump it to the command shell
// Here we check to see if we can find a .CMM file to run.
// -----------------------------------------------------------------------
if( (filename = find_cmm(command)) )
{
strcat(filename," ");
strcat(filename,the_line+ptr);
errorlevel = Interpret(filename,
INTERP_FILE |
INTERP_NOINHERIT_LOCAL |
INTERP_NOINHERIT_GLOBAL );
return "";
}
errorlevel = system(the_line+mark);
return "";
}
/* ---------------------------------------------------------------------- */
/*
* Ok, we have a list of internal commands. All other commands are
* either CMM scripts which we interpret, else they are system commands
* which we execute as appropriate for each system.
*
* Lines beginning with a ':' are ignored except when searching for
* GOTO targets.
*/
main(argc,argv)
{
setup();
plus = 1; // the offset into the parameter array for substitution
if( argc<2 || !strcmp(argv[1],"/?") )
{
usage();
}
if( (fp = fopen(argv[1],"r"))==NULL )
{
path = SplitFileName(argv[1]);
sprintf(newname,"%s%s.bat",path.dir,path.name);
fp = fopen(newname,"r");
}
if( fp==NULL )
{
printf("Could not open source file \"%s\" for reading.\n",argv[1]);
return 1;
}
line_count = 0;
while( 1 )
{
if( (newline = fgets(fp))==NULL ) break;
strcpy( lines[line_count++],newline);
}
fclose(fp);
// All right. We have the file in memory as a sequence of lines. Start doing them.
for( i = 0;i<line_count;i++ )
{
strcpy(the_line,lines[i]);
// First we do any parameter substitution in the line
the_line = substitute_line(the_line,argc-plus,argv+plus);
while( isspace(the_line[0]) ) the_line++;
if( the_line[0]=='@' )
{
echo_it = 0; the_line++;
} else {
echo_it = echo;
}
if( echo_it ) printf("\n%s>%s\n",FullPath("."),the_line);
redir_stdout = NULL;
redir_stdin = NULL;
redir_new = NULL;
to_delete = NULL;
mode = "";
in_quotes = 0;
start_from = 0;
while( the_line[0] )
{
next_line = "";
while( (loc = strcspn(the_line+start_from,"\"|<>"))
!=strlen(the_line+start_from) )
{
loc += start_from;
if( the_line[loc]=='\"' )
{
in_quotes = 1 - in_quotes;
start_from = loc+1;
continue;
}
if( in_quotes )
{
start_from = loc+1;
continue;
}
if( the_line[loc]=='<' )
{
if( redir_stdin )
{
fprintf(stderr,"Input already redirected.\n");
exit(EXIT_FAILURE);
}
newloc = loc+1;
while( isspace(the_line[newloc]) ) newloc++;
locstart = newloc;
while( the_line[newloc] && !isspace(the_line[newloc]) )
newloc++;
tmp = the_line[newloc]; the_line[newloc] = 0;
strcpy(redir_stdin,the_line+locstart);
the_line[newloc] = tmp;
strcpy(the_line+loc,the_line+newloc);
continue;
}
if( the_line[loc]=='>' )
{
if( redir_stdout )
{
fprintf(stderr,"Output already redirected.\n");
exit(EXIT_FAILURE);
}
mode = "wt";
newloc = loc+1;
if( the_line[newloc]=='>' )
{
mode = "at";
newloc++;
}
while( isspace(the_line[newloc]) ) newloc++;
locstart = newloc;
while( the_line[newloc] && !isspace(the_line[newloc]) )
newloc++;
tmp = the_line[newloc]; the_line[newloc] = 0;
strcpy(redir_stdout,the_line+locstart);
the_line[newloc] = tmp;
strcpy(the_line+loc,the_line+newloc);
continue;
}
if( the_line[loc]=='|' )
{
if( redir_stdout )
{
fprintf(stderr,"Output is already redirected to a file.\n");
exit(EXIT_FAILURE);
}
mode = "wt";
strcpy(next_line,the_line+loc+1);
the_line[loc] = 0;
strcpy(redir_new,tmpnam());
strcpy(redir_stdout,redir_new);
break;
}
}
if( redir_stdout && !freopen(redir_stdout,mode,stdout) )
{
fprintf(stderr,"Unable to open output redirection file \"%s\".\n",
redir_stdout);
exit(EXIT_FAILURE);
}
if( redir_stdin && !freopen(redir_stdin,"r",stdin) )
{
fprintf(stderr,"Unable to open input redirection file \"%s\".\n",
redir_stdin);
exit(EXIT_FAILURE);
}
label = process_command(the_line,i+1);
if( to_delete ) remove(to_delete);
to_delete = NULL;
if( redir_stdout ) { fclose(stdout); redir_stdout = NULL; }
if( redir_stdin ) { fclose(stdin); }
redir_stdin = redir_new; to_delete = redir_new; redir_new = NULL;
strcpy(the_line,next_line);
}
if( !stricmp(label,special_command) )
{
plus++; continue;
}
if( label[0]!='\0' )
{
yep = 0;
length = strlen(label);
for( j=0;!yep && j<line_count;j++ )
{
if( lines[j][0]==':' && !strncmp(lines[j]+1,label,length) )
{
yep = 1;
i = j - 1;
}
}
if( !yep )
{
printf("Label \"%s\" not found.\n",label);
return 1;
}
}
}
}