DOSBox-X
|
00001 /* 00002 * Copyright (C) 2002-2020 The DOSBox Team 00003 * 00004 * This program is free software; you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation; either version 2 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License along 00015 * with this program; if not, write to the Free Software Foundation, Inc., 00016 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 */ 00018 00019 00020 #include <stdlib.h> 00021 #include <string.h> 00022 00023 #include "shell.h" 00024 #include "support.h" 00025 00026 BatchFile::BatchFile(DOS_Shell * host,char const * const resolved_name,char const * const entered_name, char const * const cmd_line) { 00027 location = 0; 00028 prev=host->bf; 00029 echo=host->echo; 00030 shell=host; 00031 char totalname[DOS_PATHLENGTH+4]; 00032 DOS_Canonicalize(resolved_name,totalname); // Get fullname including drive specificiation 00033 cmd = new CommandLine(entered_name,cmd_line); 00034 filename = totalname; 00035 00036 //Test if file is openable 00037 if (!DOS_OpenFile(totalname,(DOS_NOT_INHERIT|OPEN_READ),&file_handle)) { 00038 //TODO Come up with something better 00039 E_Exit("SHELL:Can't open BatchFile %s",totalname); 00040 } 00041 DOS_CloseFile(file_handle); 00042 } 00043 00044 BatchFile::~BatchFile() { 00045 delete cmd; 00046 shell->bf=prev; 00047 shell->echo=echo; 00048 } 00049 00050 bool BatchFile::ReadLine(char * line) { 00051 //Open the batchfile and seek to stored postion 00052 if (!DOS_OpenFile(filename.c_str(),(DOS_NOT_INHERIT|OPEN_READ),&file_handle)) { 00053 LOG(LOG_MISC,LOG_ERROR)("ReadLine Can't open BatchFile %s",filename.c_str()); 00054 delete this; 00055 return false; 00056 } 00057 DOS_SeekFile(file_handle,&(this->location),DOS_SEEK_SET); 00058 00059 Bit8u c=0;Bit16u n=1; 00060 char temp[CMD_MAXLINE]; 00061 emptyline: 00062 char * cmd_write=temp; 00063 do { 00064 n=1; 00065 DOS_ReadFile(file_handle,&c,&n); 00066 if (n>0) { 00067 /* Why are we filtering this ? 00068 * Exclusion list: tab for batch files 00069 * escape for ansi 00070 * backspace for alien odyssey */ 00071 if (c>31 || c==0x1b || c=='\t' || c==8) { 00072 //Only add it if room for it (and trailing zero) in the buffer, but do the check here instead at the end 00073 //So we continue reading till EOL/EOF 00074 if (((cmd_write - temp) + 1) < (CMD_MAXLINE - 1)) 00075 *cmd_write++ = (char)c; 00076 } else { 00077 if (c != '\n' && c != '\r') 00078 shell->WriteOut(MSG_Get("SHELL_ILLEGAL_CONTROL_CHARACTER"), c, c); 00079 } 00080 } 00081 } while (c!='\n' && n); 00082 *cmd_write=0; 00083 if (!n && cmd_write==temp) { 00084 //Close file and delete bat file 00085 DOS_CloseFile(file_handle); 00086 delete this; 00087 return false; 00088 } 00089 if (!strlen(temp)) goto emptyline; 00090 if (temp[0]==':') goto emptyline; 00091 00092 /* Now parse the line read from the bat file for % stuff */ 00093 cmd_write=line; 00094 char * cmd_read=temp; 00095 while (*cmd_read) { 00096 if (*cmd_read == '%') { 00097 cmd_read++; 00098 if (cmd_read[0] == '%') { 00099 cmd_read++; 00100 if (((cmd_write - line) + 1) < (CMD_MAXLINE - 1)) 00101 *cmd_write++ = '%'; 00102 continue; 00103 } 00104 if (cmd_read[0] == '0') { /* Handle %0 */ 00105 const char *file_name = cmd->GetFileName(); 00106 cmd_read++; 00107 size_t name_len = strlen(file_name); 00108 if (((size_t)(cmd_write - line) + name_len) < (CMD_MAXLINE - 1)) { 00109 strcpy(cmd_write,file_name); 00110 cmd_write += name_len; 00111 } 00112 continue; 00113 } 00114 char next = cmd_read[0]; 00115 if(next > '0' && next <= '9') { 00116 /* Handle %1 %2 .. %9 */ 00117 cmd_read++; //Progress reader 00118 next -= '0'; 00119 if (cmd->GetCount()<(unsigned int)next) continue; 00120 std::string word; 00121 if (!cmd->FindCommand((unsigned int)next,word)) continue; 00122 size_t name_len = strlen(word.c_str()); 00123 if (((size_t)(cmd_write - line) + name_len) < (CMD_MAXLINE - 1)) { 00124 strcpy(cmd_write,word.c_str()); 00125 cmd_write += name_len; 00126 } 00127 continue; 00128 } else { 00129 /* Not a command line number has to be an environment */ 00130 char * first = strchr(cmd_read,'%'); 00131 /* No env afterall. Ignore a single % */ 00132 if (!first) {/* *cmd_write++ = '%';*/continue;} 00133 *first++ = 0; 00134 std::string env; 00135 if (shell->GetEnvStr(cmd_read,env)) { 00136 const char* equals = strchr(env.c_str(),'='); 00137 if (!equals) continue; 00138 equals++; 00139 size_t name_len = strlen(equals); 00140 if (((size_t)(cmd_write - line) + name_len) < (CMD_MAXLINE - 1)) { 00141 strcpy(cmd_write,equals); 00142 cmd_write += name_len; 00143 } 00144 } 00145 cmd_read = first; 00146 } 00147 } else { 00148 if (((cmd_write - line) + 1) < (CMD_MAXLINE - 1)) 00149 *cmd_write++ = *cmd_read++; 00150 } 00151 } 00152 *cmd_write = 0; 00153 //Store current location and close bat file 00154 this->location = 0; 00155 DOS_SeekFile(file_handle,&(this->location),DOS_SEEK_CUR); 00156 DOS_CloseFile(file_handle); 00157 return true; 00158 } 00159 00160 bool BatchFile::Goto(const char * where) { 00161 //Open bat file and search for the where string 00162 if (!DOS_OpenFile(filename.c_str(),128,&file_handle)) { 00163 LOG(LOG_MISC,LOG_ERROR)("SHELL:Goto Can't open BatchFile %s",filename.c_str()); 00164 delete this; 00165 return false; 00166 } 00167 00168 char cmd_buffer[CMD_MAXLINE]; 00169 char * cmd_write; 00170 00171 /* Scan till we have a match or return false */ 00172 Bit8u c;Bit16u n; 00173 again: 00174 cmd_write=cmd_buffer; 00175 do { 00176 n=1; 00177 DOS_ReadFile(file_handle,&c,&n); 00178 if (n>0) { 00179 if (c>31) { 00180 if (((cmd_write - cmd_buffer) + 1) < (CMD_MAXLINE - 1)) 00181 *cmd_write++ = (char)c; 00182 } else { 00183 if (c != '\n' && c != '\r') 00184 shell->WriteOut(MSG_Get("SHELL_ILLEGAL_CONTROL_CHARACTER"), c, c); 00185 } 00186 } 00187 } while (c!='\n' && n); 00188 *cmd_write++ = 0; 00189 char *nospace = trim(cmd_buffer); 00190 if (nospace[0] == ':') { 00191 nospace++; //Skip : 00192 //Strip spaces and = from it. 00193 while(*nospace && (isspace(*reinterpret_cast<unsigned char*>(nospace)) || (*nospace == '='))) 00194 nospace++; 00195 00196 //label is until space/=/eol 00197 const char* beginlabel = nospace; 00198 while(*nospace && !isspace(*reinterpret_cast<unsigned char*>(nospace)) && (*nospace != '=')) 00199 nospace++; 00200 00201 *nospace = 0; 00202 if (strcasecmp(beginlabel,where)==0) { 00203 //Found it! Store location and continue 00204 this->location = 0; 00205 DOS_SeekFile(file_handle,&(this->location),DOS_SEEK_CUR); 00206 DOS_CloseFile(file_handle); 00207 return true; 00208 } 00209 00210 } 00211 if (!n) { 00212 DOS_CloseFile(file_handle); 00213 delete this; 00214 return false; 00215 } 00216 goto again; 00217 return false; 00218 } 00219 00220 void BatchFile::Shift(void) { 00221 cmd->Shift(1); 00222 }