1 /*
2 * Copyright (C) 2002-2015 The DOSBox Team
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 *
18 * Wengier: LFN and AUTO MOUNT support
19 */
20
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include <algorithm> //std::copy
25 #include <iterator> //std::front_inserter
26 #include "shell.h"
27 #include "control.h"
28 #include "regs.h"
29 #include "callback.h"
30 #include "support.h"
31
ShowPrompt(void)32 void DOS_Shell::ShowPrompt(void) {
33 Bit8u drive=DOS_GetDefaultDrive()+'A';
34 char dir[DOS_PATHLENGTH];
35 dir[0] = 0; //DOS_GetCurrentDir doesn't always return something. (if drive is messed up)
36 DOS_GetCurrentDir(0,dir,uselfn);
37 WriteOut("%c:\\%s>",drive,dir);
38 }
39
outc(Bit8u c)40 static void outc(Bit8u c) {
41 Bit16u n=1;
42 DOS_WriteFile(STDOUT,&c,&n);
43 }
44
InputCommand(char * line)45 void DOS_Shell::InputCommand(char * line) {
46 Bitu size=CMD_MAXLINE-2; //lastcharacter+0
47 Bit8u c;Bit16u n=1;
48 Bitu str_len=0;Bitu str_index=0;
49 Bit16u len=0;
50 bool current_hist=false; // current command stored in history?
51
52 line[0] = '\0';
53
54 std::list<std::string>::iterator it_history = l_history.begin(), it_completion = l_completion.begin();
55
56 while (size) {
57 dos.echo=false;
58 while(!DOS_ReadFile(input_handle,&c,&n)) {
59 Bit16u dummy;
60 DOS_CloseFile(input_handle);
61 DOS_OpenFile("con",2,&dummy);
62 LOG(LOG_MISC,LOG_ERROR)("Reopening the input handle. This is a bug!");
63 }
64 if (!n) {
65 size=0; //Kill the while loop
66 continue;
67 }
68 switch (c) {
69 case 0x00: /* Extended Keys */
70 {
71 DOS_ReadFile(input_handle,&c,&n);
72 switch (c) {
73
74 case 0x3d: /* F3 */
75 if (!l_history.size()) break;
76 it_history = l_history.begin();
77 if (it_history != l_history.end() && it_history->length() > str_len) {
78 const char *reader = &(it_history->c_str())[str_len];
79 while ((c = *reader++)) {
80 line[str_index ++] = c;
81 DOS_WriteFile(STDOUT,&c,&n);
82 }
83 str_len = str_index = (Bitu)it_history->length();
84 size = CMD_MAXLINE - str_index - 2;
85 line[str_len] = 0;
86 }
87 break;
88
89 case 0x4B: /* LEFT */
90 if (str_index) {
91 outc(8);
92 str_index --;
93 }
94 break;
95
96 case 0x4D: /* RIGHT */
97 if (str_index < str_len) {
98 outc(line[str_index++]);
99 }
100 break;
101
102 case 0x47: /* HOME */
103 while (str_index) {
104 outc(8);
105 str_index--;
106 }
107 break;
108
109 case 0x4F: /* END */
110 while (str_index < str_len) {
111 outc(line[str_index++]);
112 }
113 break;
114
115 case 0x48: /* UP */
116 if (l_history.empty() || it_history == l_history.end()) break;
117
118 // store current command in history if we are at beginning
119 if (it_history == l_history.begin() && !current_hist) {
120 current_hist=true;
121 l_history.push_front(line);
122 }
123
124 for (;str_index>0; str_index--) {
125 // removes all characters
126 outc(8); outc(' '); outc(8);
127 }
128 strcpy(line, it_history->c_str());
129 len = (Bit16u)it_history->length();
130 str_len = str_index = len;
131 size = CMD_MAXLINE - str_index - 2;
132 DOS_WriteFile(STDOUT, (Bit8u *)line, &len);
133 it_history ++;
134 break;
135
136 case 0x50: /* DOWN */
137 if (l_history.empty() || it_history == l_history.begin()) break;
138
139 // not very nice but works ..
140 it_history --;
141 if (it_history == l_history.begin()) {
142 // no previous commands in history
143 it_history ++;
144
145 // remove current command from history
146 if (current_hist) {
147 current_hist=false;
148 l_history.pop_front();
149 }
150 break;
151 } else it_history --;
152
153 for (;str_index>0; str_index--) {
154 // removes all characters
155 outc(8); outc(' '); outc(8);
156 }
157 strcpy(line, it_history->c_str());
158 len = (Bit16u)it_history->length();
159 str_len = str_index = len;
160 size = CMD_MAXLINE - str_index - 2;
161 DOS_WriteFile(STDOUT, (Bit8u *)line, &len);
162 it_history ++;
163
164 break;
165 case 0x53:/* DELETE */
166 {
167 if(str_index>=str_len) break;
168 Bit16u a=str_len-str_index-1;
169 Bit8u* text=reinterpret_cast<Bit8u*>(&line[str_index+1]);
170 DOS_WriteFile(STDOUT,text,&a);//write buffer to screen
171 outc(' ');outc(8);
172 for(Bitu i=str_index;i<str_len-1;i++) {
173 line[i]=line[i+1];
174 outc(8);
175 }
176 line[--str_len]=0;
177 size++;
178 }
179 break;
180 case 15: /* Shift-Tab */
181 if (l_completion.size()) {
182 if (it_completion == l_completion.begin()) it_completion = l_completion.end ();
183 it_completion--;
184
185 if (it_completion->length()) {
186 for (;str_index > completion_index; str_index--) {
187 // removes all characters
188 outc(8); outc(' '); outc(8);
189 }
190
191 strcpy(&line[completion_index], it_completion->c_str());
192 len = (Bit16u)it_completion->length();
193 str_len = str_index = completion_index + len;
194 size = CMD_MAXLINE - str_index - 2;
195 DOS_WriteFile(STDOUT, (Bit8u *)it_completion->c_str(), &len);
196 }
197 }
198 default:
199 break;
200 }
201 };
202 break;
203 case 0x08: /* BackSpace */
204 if (str_index) {
205 outc(8);
206 Bit32u str_remain=str_len - str_index;
207 size++;
208 if (str_remain) {
209 memmove(&line[str_index-1],&line[str_index],str_remain);
210 line[--str_len]=0;
211 str_index --;
212 /* Go back to redraw */
213 for (Bit16u i=str_index; i < str_len; i++)
214 outc(line[i]);
215 } else {
216 line[--str_index] = '\0';
217 str_len--;
218 }
219 outc(' '); outc(8);
220 // moves the cursor left
221 while (str_remain--) outc(8);
222 }
223 if (l_completion.size()) l_completion.clear();
224 break;
225 case 0x0a: /* New Line not handled */
226 /* Don't care */
227 break;
228 case 0x0d: /* Return */
229 outc('\n');
230 size=0; //Kill the while loop
231 break;
232 case'\t':
233 {
234 if (l_completion.size()) {
235 it_completion ++;
236 if (it_completion == l_completion.end()) it_completion = l_completion.begin();
237 } else {
238 // build new completion list
239 // Lines starting with CD will only get directories in the list
240 bool dir_only = (strncasecmp(line,"CD ",3)==0);
241 int q=0;
242
243 // get completion mask
244 char *p_completion_start = strrchr(line, ' ');
245 while (p_completion_start) {
246 q=0;
247 char *i;
248 for (i=line;i<p_completion_start;i++)
249 if (*i=='\"') q++;
250 if (q/2*2==q) break;
251 *i=0;
252 p_completion_start = strrchr(line, ' ');
253 *i=' ';
254 }
255
256 if (p_completion_start) {
257 p_completion_start ++;
258 completion_index = (Bit16u)(str_len - strlen(p_completion_start));
259 } else {
260 p_completion_start = line;
261 completion_index = 0;
262 }
263
264 char *path;
265 if ((path = strrchr(line+completion_index,':'))) completion_index = (Bit16u)(path-line+1);
266 if ((path = strrchr(line+completion_index,'\\'))) completion_index = (Bit16u)(path-line+1);
267 if ((path = strrchr(line+completion_index,'/'))) completion_index = (Bit16u)(path-line+1);
268
269 // build the completion list
270 char mask[DOS_PATHLENGTH+2],smask[DOS_PATHLENGTH];
271 if (p_completion_start) {
272 strcpy(mask, p_completion_start);
273 char* dot_pos=strrchr(mask,'.');
274 char* bs_pos=strrchr(mask,'\\');
275 char* fs_pos=strrchr(mask,'/');
276 char* cl_pos=strrchr(mask,':');
277 // not perfect when line already contains wildcards, but works
278 if ((dot_pos-bs_pos>0) && (dot_pos-fs_pos>0) && (dot_pos-cl_pos>0))
279 strcat(mask, "*");
280 else strcat(mask, "*.*");
281 } else {
282 strcpy(mask, "*.*");
283 }
284
285 RealPt save_dta=dos.dta();
286 dos.dta(dos.tables.tempdta);
287
288 bool res = false;
289 if (DOS_GetSFNPath(mask,smask,false)) {
290 sprintf(mask,"\"%s\"",smask);
291 res = DOS_FindFirst(mask, 0xffff & ~DOS_ATTR_VOLUME);
292 }
293 if (!res) {
294 dos.dta(save_dta);
295 break; // TODO: beep
296 }
297
298 DOS_DTA dta(dos.dta());
299 char name[DOS_NAMELENGTH_ASCII], lname[LFN_NAMELENGTH], qlname[LFN_NAMELENGTH+2];
300 Bit32u sz;Bit16u date;Bit16u time;Bit8u att;
301
302 std::list<std::string> executable;
303 q=0;
304 while (*p_completion_start)
305 if (*p_completion_start++=='\"')
306 q++;
307 while (res) {
308 dta.GetResult(name,lname,sz,date,time,att);
309 if (strchr(uselfn?lname:name,' ')!=NULL||q/2*2!=q)
310 sprintf(qlname,"\"%s\"",uselfn?lname:name);
311 else
312 strcpy(qlname,uselfn?lname:name);
313 // add result to completion list
314
315 char *ext; // file extension
316 if (strcmp(name, ".") && strcmp(name, "..")) {
317 if (dir_only) { //Handle the dir only case different (line starts with cd)
318 if(att & DOS_ATTR_DIRECTORY) l_completion.push_back(qlname);
319 } else {
320 ext = strrchr(name, '.');
321 if (ext && (strcmp(ext, ".BAT") == 0 || strcmp(ext, ".COM") == 0 || strcmp(ext, ".EXE") == 0))
322 // we add executables to the a seperate list and place that list infront of the normal files
323 executable.push_front(qlname);
324 else
325 l_completion.push_back(qlname);
326 }
327 }
328 res=DOS_FindNext();
329 }
330 /* Add executable list to front of completion list. */
331 std::copy(executable.begin(),executable.end(),std::front_inserter(l_completion));
332 it_completion = l_completion.begin();
333 dos.dta(save_dta);
334 }
335
336 if (l_completion.size() && it_completion->length()) {
337 for (;str_index > completion_index; str_index--) {
338 // removes all characters
339 outc(8); outc(' '); outc(8);
340 }
341
342 strcpy(&line[completion_index], it_completion->c_str());
343 len = (Bit16u)it_completion->length();
344 str_len = str_index = completion_index + len;
345 size = CMD_MAXLINE - str_index - 2;
346 DOS_WriteFile(STDOUT, (Bit8u *)it_completion->c_str(), &len);
347 }
348 }
349 break;
350 case 0x1b: /* ESC */
351 //write a backslash and return to the next line
352 outc('\\');
353 outc('\n');
354 *line = 0; // reset the line.
355 if (l_completion.size()) l_completion.clear(); //reset the completion list.
356 this->InputCommand(line); //Get the NEW line.
357 size = 0; // stop the next loop
358 str_len = 0; // prevent multiple adds of the same line
359 break;
360 default:
361 if (l_completion.size()) l_completion.clear();
362 if(str_index < str_len && true) { //mem_readb(BIOS_KEYBOARD_FLAGS1)&0x80) dev_con.h ?
363 outc(' ');//move cursor one to the right.
364 Bit16u a = str_len - str_index;
365 Bit8u* text=reinterpret_cast<Bit8u*>(&line[str_index]);
366 DOS_WriteFile(STDOUT,text,&a);//write buffer to screen
367 outc(8);//undo the cursor the right.
368 for(Bitu i=str_len;i>str_index;i--) {
369 line[i]=line[i-1]; //move internal buffer
370 outc(8); //move cursor back (from write buffer to screen)
371 }
372 line[++str_len]=0;//new end (as the internal buffer moved one place to the right
373 size--;
374 };
375
376 line[str_index]=c;
377 str_index ++;
378 if (str_index > str_len){
379 line[str_index] = '\0';
380 str_len++;
381 size--;
382 }
383 DOS_WriteFile(STDOUT,&c,&n);
384 break;
385 }
386 }
387
388 if (!str_len) return;
389 str_len++;
390
391 // remove current command from history if it's there
392 if (current_hist) {
393 current_hist=false;
394 l_history.pop_front();
395 }
396
397 // add command line to history
398 l_history.push_front(line); it_history = l_history.begin();
399 if (l_completion.size()) l_completion.clear();
400 }
401
402 std::string full_arguments = "";
Execute(char * name,char * args)403 bool DOS_Shell::Execute(char * name,char * args) {
404 /* return true => don't check for hardware changes in do_command
405 * return false => check for hardware changes in do_command */
406 char fullname[DOS_PATHLENGTH+4]; //stores results from Which
407 char* p_fullname;
408 char line[CMD_MAXLINE];
409 if(strlen(args)!= 0){
410 if(*args != ' '){ //put a space in front
411 line[0]=' ';line[1]=0;
412 strncat(line,args,CMD_MAXLINE-2);
413 line[CMD_MAXLINE-1]=0;
414 }
415 else
416 {
417 safe_strncpy(line,args,CMD_MAXLINE);
418 }
419 }else{
420 line[0]=0;
421 };
422
423 /* check for a drive change */
424 if (((strcmp(name + 1, ":") == 0) || (strcmp(name + 1, ":\\") == 0)) && isalpha(*name))
425 {
426 if (strrchr(name,'\\')) { WriteOut(MSG_Get("SHELL_EXECUTE_ILLEGAL_COMMAND"),name); return true; }
427 if (!DOS_SetDrive(toupper(name[0])-'A')) {
428 #ifdef WIN32
429 Section_prop * sec=0; sec=static_cast<Section_prop *>(control->GetSection("dos"));
430 if(!sec->Get_bool("automount")) { WriteOut(MSG_Get("SHELL_EXECUTE_DRIVE_NOT_FOUND"),toupper(name[0])); return true; }
431 // automount: attempt direct letter to drive map.
432 first_1:
433 int drvtype=GetDriveType(name);
434 if(drvtype==1 && strlen(name)==2 && name[1]==':') {
435 char names[4];
436 strcpy(names,name);
437 strcat(names,"\\");
438 drvtype=GetDriveType(names);
439 }
440 if(drvtype==2) {
441 WriteOut(MSG_Get("SHELL_EXECUTE_AUTOMOUNT"));
442 WriteOut("\n");
443 WriteOut(MSG_Get("SHELL_EXECUTE_DRIVE_ACCESS_REMOVABLE"),toupper(name[0]));
444 } else if(drvtype==4) {
445 WriteOut(MSG_Get("SHELL_EXECUTE_AUTOMOUNT"));
446 WriteOut("\n");
447 WriteOut(MSG_Get("SHELL_EXECUTE_DRIVE_ACCESS_NETWORK"),toupper(name[0]));
448 } else if(drvtype==5) {
449 WriteOut(MSG_Get("SHELL_EXECUTE_AUTOMOUNT"));
450 WriteOut("\n");
451 WriteOut(MSG_Get("SHELL_EXECUTE_DRIVE_ACCESS_OPTICAL"),toupper(name[0]));
452 } else if(drvtype==3||drvtype==6) {
453 WriteOut(MSG_Get("SHELL_EXECUTE_AUTOMOUNT"));
454 if(drvtype==3 && strcasecmp(name,"c:")==0)
455 WriteOut(MSG_Get("SHELL_EXECUTE_DRIVE_ACCESS_WARNING_WIN"));
456 WriteOut("\n");
457 WriteOut(MSG_Get("SHELL_EXECUTE_DRIVE_ACCESS_LOCAL"),toupper(name[0]));
458 } else {
459 WriteOut(MSG_Get("SHELL_EXECUTE_DRIVE_NOT_FOUND"),toupper(name[0]));
460 return true;
461 }
462
463 first_2:
464 Bit8u c;Bit16u n=1;
465 DOS_ReadFile (STDIN,&c,&n);
466 do switch (c) {
467 case 'n': case 'N':
468 {
469 DOS_WriteFile (STDOUT,&c, &n);
470 DOS_ReadFile (STDIN,&c,&n);
471 do switch (c) {
472 case 0xD: WriteOut("\n\n"); WriteOut(MSG_Get("SHELL_EXECUTE_DRIVE_NOT_FOUND"),toupper(name[0])); return true;
473 case 0x08: WriteOut("\b \b"); goto first_2;
474 } while (DOS_ReadFile (STDIN,&c,&n));
475 }
476 case 'y': case 'Y':
477 {
478 DOS_WriteFile (STDOUT,&c, &n);
479 DOS_ReadFile (STDIN,&c,&n);
480 do switch (c) {
481 case 0xD: WriteOut("\n"); goto continue_1;
482 case 0x08: WriteOut("\b \b"); goto first_2;
483 } while (DOS_ReadFile (STDIN,&c,&n));
484 }
485 case 0xD: WriteOut("\n"); goto first_1;
486 case '\t': case 0x08: goto first_2;
487 default:
488 {
489 DOS_WriteFile (STDOUT,&c, &n);
490 DOS_ReadFile (STDIN,&c,&n);
491 do switch (c) {
492 case 0xD: WriteOut("\n");goto first_1;
493 case 0x08: WriteOut("\b \b"); goto first_2;
494 } while (DOS_ReadFile (STDIN,&c,&n));
495 goto first_2;
496 }
497 } while (DOS_ReadFile (STDIN,&c,&n));
498
499 continue_1:
500
501 char mountstring[DOS_PATHLENGTH+CROSS_LEN+20];
502 sprintf(mountstring,"MOUNT %s ",name);
503
504 if(GetDriveType(name)==5) strcat(mountstring,"-t cdrom ");
505 else if(GetDriveType(name)==2) strcat(mountstring,"-t floppy ");
506 strcat(mountstring,name);
507 strcat(mountstring,"\\");
508 // if(GetDriveType(name)==5) strcat(mountstring," -ioctl");
509
510 this->ParseLine(mountstring);
511 if (!DOS_SetDrive(toupper(name[0])-'A'))
512 #endif
513 WriteOut(MSG_Get("SHELL_EXECUTE_DRIVE_NOT_FOUND"),toupper(name[0]));
514 }
515 return true;
516 }
517 /* Check for a full name */
518 p_fullname = Which(name);
519 if (!p_fullname) return false;
520 strcpy(fullname,p_fullname);
521 const char* extension = strrchr(fullname,'.');
522
523 /*always disallow files without extension from being executed. */
524 /*only internal commands can be run this way and they never get in this handler */
525 if(extension == 0)
526 {
527 //Check if the result will fit in the parameters. Else abort
528 if(strlen(fullname) >( DOS_PATHLENGTH - 1) ) return false;
529 char temp_name[DOS_PATHLENGTH+4],* temp_fullname;
530 //try to add .com, .exe and .bat extensions to filename
531
532 strcpy(temp_name,fullname);
533 strcat(temp_name,".COM");
534 temp_fullname=Which(temp_name);
535 if (temp_fullname) { extension=".com";strcpy(fullname,temp_fullname); }
536
537 else
538 {
539 strcpy(temp_name,fullname);
540 strcat(temp_name,".EXE");
541 temp_fullname=Which(temp_name);
542 if (temp_fullname) { extension=".exe";strcpy(fullname,temp_fullname);}
543
544 else
545 {
546 strcpy(temp_name,fullname);
547 strcat(temp_name,".BAT");
548 temp_fullname=Which(temp_name);
549 if (temp_fullname) { extension=".bat";strcpy(fullname,temp_fullname);}
550
551 else
552 {
553 return false;
554 }
555
556 }
557 }
558 }
559
560 if (strcasecmp(extension, ".bat") == 0)
561 { /* Run the .bat file */
562 /* delete old batch file if call is not active*/
563 bool temp_echo=echo; /*keep the current echostate (as delete bf might change it )*/
564 if(bf && !call) delete bf;
565 bf=new BatchFile(this,fullname,name,line);
566 echo=temp_echo; //restore it.
567 }
568 else
569 { /* only .bat .exe .com extensions maybe be executed by the shell */
570 if(strcasecmp(extension, ".com") !=0)
571 {
572 if(strcasecmp(extension, ".exe") !=0) return false;
573 }
574 /* Run the .exe or .com file from the shell */
575 /* Allocate some stack space for tables in physical memory */
576 reg_sp-=0x200;
577 //Add Parameter block
578 DOS_ParamBlock block(SegPhys(ss)+reg_sp);
579 block.Clear();
580 //Add a filename
581 RealPt file_name=RealMakeSeg(ss,reg_sp+0x20);
582 MEM_BlockWrite(Real2Phys(file_name),fullname,(Bitu)(strlen(fullname)+1));
583
584 /* HACK: Store full commandline for mount and imgmount */
585 full_arguments.assign(line);
586
587 /* Fill the command line */
588 CommandTail cmdtail;
589 cmdtail.count = 0;
590 memset(&cmdtail.buffer,0,CTBUF); //Else some part of the string is unitialized (valgrind)
591 if (strlen(line)>=CTBUF) line[CTBUF-1]=0;
592 cmdtail.count=(Bit8u)strlen(line);
593 memcpy(cmdtail.buffer,line,strlen(line));
594 cmdtail.buffer[strlen(line)]=0xd;
595 /* Copy command line in stack block too */
596 MEM_BlockWrite(SegPhys(ss)+reg_sp+0x100,&cmdtail,CTBUF+1);
597
598
599 /* Split input line up into parameters, using a few special rules, most notable the one for /AAA => A\0AA
600 * Qbix: It is extremly messy, but this was the only way I could get things like /:aa and :/aa to work correctly */
601
602 //Prepare string first
603 char parseline[258] = { 0 };
604 for(char *pl = line,*q = parseline; *pl ;pl++,q++) {
605 if (*pl == '=' || *pl == ';' || *pl ==',' || *pl == '\t' || *pl == ' ') *q = 0; else *q = *pl; //Replace command seperators with 0.
606 } //No end of string \0 needed as parseline is larger than line
607
608 for(char* p = parseline; (p-parseline) < 250 ;p++) { //Stay relaxed within boundaries as we have plenty of room
609 if (*p == '/') { //Transform /Hello into H\0ello
610 *p = 0;
611 p++;
612 while ( *p == 0 && (p-parseline) < 250) p++; //Skip empty fields
613 if ((p-parseline) < 250) { //Found something. Lets get the first letter and break it up
614 p++;
615 memmove(static_cast<void*>(p + 1),static_cast<void*>(p),(250-(p-parseline)));
616 if ((p-parseline) < 250) *p = 0;
617 }
618 }
619 }
620 parseline[255] = parseline[256] = parseline[257] = 0; //Just to be safe.
621
622 /* Parse FCB (first two parameters) and put them into the current DOS_PSP */
623 Bit8u add;
624 Bit16u skip = 0;
625 //find first argument, we end up at parseline[256] if there is only one argument (similar for the second), which exists and is 0.
626 while(skip < 256 && parseline[skip] == 0) skip++;
627 FCB_Parsename(dos.psp(),0x5C,0x01,parseline + skip,&add);
628 skip += add;
629
630 //Move to next argument if it exists
631 while(parseline[skip] != 0) skip++; //This is safe as there is always a 0 in parseline at the end.
632 while(skip < 256 && parseline[skip] == 0) skip++; //Which is higher than 256
633 FCB_Parsename(dos.psp(),0x6C,0x01,parseline + skip,&add);
634
635 block.exec.fcb1=RealMake(dos.psp(),0x5C);
636 block.exec.fcb2=RealMake(dos.psp(),0x6C);
637 /* Set the command line in the block and save it */
638 block.exec.cmdtail=RealMakeSeg(ss,reg_sp+0x100);
639 block.SaveData();
640 #if 0
641 /* Save CS:IP to some point where i can return them from */
642 Bit32u oldeip=reg_eip;
643 Bit16u oldcs=SegValue(cs);
644 RealPt newcsip=CALLBACK_RealPointer(call_shellstop);
645 SegSet16(cs,RealSeg(newcsip));
646 reg_ip=RealOff(newcsip);
647 #endif
648 /* Start up a dos execute interrupt */
649 reg_ax=0x4b00;
650 //Filename pointer
651 SegSet16(ds,SegValue(ss));
652 reg_dx=RealOff(file_name);
653 //Paramblock
654 SegSet16(es,SegValue(ss));
655 reg_bx=reg_sp;
656 SETFLAGBIT(IF,false);
657 CALLBACK_RunRealInt(0x21);
658 /* Restore CS:IP and the stack */
659 reg_sp+=0x200;
660 #if 0
661 reg_eip=oldeip;
662 SegSet16(cs,oldcs);
663 #endif
664 }
665 return true; //Executable started
666 }
667
668
669
670
671 static const char * bat_ext=".BAT";
672 static const char * com_ext=".COM";
673 static const char * exe_ext=".EXE";
674 static char which_ret[DOS_PATHLENGTH+4];
675
Which(char * name)676 char * DOS_Shell::Which(char * name) {
677 size_t name_len = strlen(name);
678 if(name_len >= DOS_PATHLENGTH) return 0;
679
680 /* Parse through the Path to find the correct entry */
681 /* Check if name is already ok but just misses an extension */
682
683 if (DOS_FileExists(name)) return name;
684 upcase(name);
685 if (DOS_FileExists(name)) return name;
686 /* try to find .com .exe .bat */
687 strcpy(which_ret,name);
688 strcat(which_ret,com_ext);
689 if (DOS_FileExists(which_ret)) return which_ret;
690 strcpy(which_ret,name);
691 strcat(which_ret,exe_ext);
692 if (DOS_FileExists(which_ret)) return which_ret;
693 strcpy(which_ret,name);
694 strcat(which_ret,bat_ext);
695 if (DOS_FileExists(which_ret)) return which_ret;
696
697
698 /* No Path in filename look through path environment string */
699 char path[DOS_PATHLENGTH];std::string temp;
700 if (!GetEnvStr("PATH",temp)) return 0;
701 const char * pathenv=temp.c_str();
702 if (!pathenv) return 0;
703 pathenv = strchr(pathenv,'=');
704 if (!pathenv) return 0;
705 pathenv++;
706 Bitu i_path = 0;
707 while (*pathenv) {
708 /* remove ; and ;; at the beginning. (and from the second entry etc) */
709 while(*pathenv == ';')
710 pathenv++;
711
712 /* get next entry */
713 i_path = 0; /* reset writer */
714 while(*pathenv && (*pathenv !=';') && (i_path < DOS_PATHLENGTH) )
715 path[i_path++] = *pathenv++;
716
717 if(i_path == DOS_PATHLENGTH) {
718 /* If max size. move till next ; and terminate path */
719 while(*pathenv && (*pathenv != ';'))
720 pathenv++;
721 path[DOS_PATHLENGTH - 1] = 0;
722 } else path[i_path] = 0;
723
724
725 /* check entry */
726 if(size_t len = strlen(path)){
727 if(len >= (DOS_PATHLENGTH - 2)) continue;
728
729 if(path[len - 1] != '\\') {
730 strcat(path,"\\");
731 len++;
732 }
733
734 //If name too long =>next
735 if((name_len + len + 1) >= DOS_PATHLENGTH) continue;
736 strcat(path,name);
737
738 strcpy(which_ret,path);
739 if (DOS_FileExists(which_ret)) return which_ret;
740 strcpy(which_ret,path);
741 strcat(which_ret,com_ext);
742 if (DOS_FileExists(which_ret)) return which_ret;
743 strcpy(which_ret,path);
744 strcat(which_ret,exe_ext);
745 if (DOS_FileExists(which_ret)) return which_ret;
746 strcpy(which_ret,path);
747 strcat(which_ret,bat_ext);
748 if (DOS_FileExists(which_ret)) return which_ret;
749 }
750 }
751 return 0;
752 }
753