COM.C
上传用户:xiaogehua
上传日期:2007-01-08
资源大小:1183k
文件大小:54k
源码类别:

操作系统开发

开发平台:

Asm

  1. /*   File              : $Workfile: COM.C$
  2. ;
  3. ;    Description       :
  4. ;
  5. ;    Original Author   : DIGITAL RESEARCH
  6. ;
  7. ;    Last Edited By    : $CALDERA$
  8. ;
  9. ;-----------------------------------------------------------------------;
  10. ;    Copyright Work of Caldera, Inc. All Rights Reserved.
  11. ;      
  12. ;    THIS WORK IS A COPYRIGHT WORK AND CONTAINS CONFIDENTIAL,
  13. ;    PROPRIETARY AND TRADE SECRET INFORMATION OF CALDERA, INC.
  14. ;    ACCESS TO THIS WORK IS RESTRICTED TO (I) CALDERA, INC. EMPLOYEES
  15. ;    WHO HAVE A NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF
  16. ;    THEIR ASSIGNMENTS AND (II) ENTITIES OTHER THAN CALDERA, INC. WHO
  17. ;    HAVE ACCEPTED THE CALDERA OPENDOS SOURCE LICENSE OR OTHER CALDERA LICENSE
  18. ;    AGREEMENTS. EXCEPT UNDER THE EXPRESS TERMS OF THE CALDERA LICENSE
  19. ;    AGREEMENT NO PART OF THIS WORK MAY BE USED, PRACTICED, PERFORMED,
  20. ;    COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, ABRIDGED,
  21. ;    CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST,
  22. ;    TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF
  23. ;    CALDERA, INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT
  24. ;    AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO CRIMINAL AND
  25. ;    CIVIL LIABILITY.
  26. ;-----------------------------------------------------------------------;
  27. ;
  28. ;    *** Current Edit History ***
  29. ;    *** End of Current Edit History ***
  30. ;
  31. ;    $Log$
  32.  *   COM.C 1.2 97/03/21 14:41:21
  33.  *   Added /n option to disable critical error handler
  34.  *   COM.C 1.59 94/12/01 10:05:21
  35.  *   Removed closing handles 5 and 6 in error_code() in order to be able
  36.  *   to continue with a batch file if the user wants to. JBEULICH
  37.  *   Enabled UNC filenames
  38.  *   COM.C 1.58 94/08/10 14:49:22 
  39.  *   After first run through looking for a file to execute, now strips the D:
  40.  *   off the path, if only a drive and not a directory is specified. So, if you
  41.  *   type D:TEST, it will look for TEST on the current directory of drive D:, then
  42.  *   continue to search the path. It will only skip searching the path if a
  43.  *   specific directory is specified.
  44.  *   COM.C 1.57 94/03/29 16:12:11 
  45.  *   docmd_int2f in CSTART.ASM returns 1 if it has been accepted.
  46.  *   In this case, we don't want it, so docmd_offer returns TRUE.
  47.  *   All cases of docmd_offer return if TRUE, so we don't process
  48.  *   the line ourselves.
  49.  *   COM.C 1.56 94/02/08 11:50:17
  50.  *   Fixed a problem where typing COMMAND DIR A: after giving the correct error
  51.  *   message for DIR being an incorrect loadpath, tries to access A: and crashes
  52.  *   under /MULTI.
  53.  *   Break added after error message to fix crashing problem.
  54.  *   Variable lferror added so that after an incorrect loadpath, it does not use
  55.  *   the next bit (ie. A:) as keyboard input.
  56.  *   COM.C 1.54 93/12/09 18:07:04 
  57.  *   Fixed a bug which screwed the upper memory link if you entered c:lh dir
  58.  *   COM.C 1.53 93/12/01 23:14:02 
  59.  *   Fix parsing bug "<infile >outfile command" would fail
  60.  *   COM.C 1.49 93/12/01 11:32:08
  61.  *   Now do a flush cache call before displaying prompt.
  62.  *   COM.C 1.48 93/12/01 00:17:17
  63.  *   docmd_offer() will do an int 2F/AE (2 if external) within batch files
  64.  *   SPR: 811218, shouldn't access drive whatever the prompt
  65.  *   COM.C 1.45 93/11/19 21:08:14
  66.  *   Put code to report "Syntax Error" for "| command" and "command |" back to
  67.  *   it's original state.   
  68.  *   COM.C 1.43 93/11/08 23:59:19
  69.  *   F8 key now only affects autoexec, not 1st batch file
  70.  *   COM.C 1.42 93/11/05 13:03:00
  71.  *   Fix problem with /P /MH (missing break;....)
  72.  *   COM.C 1.41 93/11/05 00:44:07
  73.  *   /MU option only valid with /P option. The problem is if you "exit" with upper
  74.  *   memory unlinked the resident portion isn't freed, and you eat upper memory.
  75.  *   COM.C 1.40 93/10/29 17:05:51
  76.  *   Add PROMPT=$P$G and PATH=d:NWDOS to default env
  77.  *   COM.C 1.39 93/10/22 11:51:30
  78.  *   Changed Beta string from 3 to 4
  79.  *   COM.C 1.36 93/09/15 18:56:39
  80.  *   FOR command now allows any char in brackets. eg for %%v in (+ -) do...
  81.  *   COM.C 1.34 93/08/26 09:39:05
  82.  *   Now use PSP for stack during func 4b exec. There's some debug
  83.  *   code in case things screw up.
  84.  *   COM.C 1.30 93/07/05 08:32:57 
  85.  *   Memory allocation strategy now restored if ctrl-c pressed during a hiload.
  86.  *   COM.C 1.25 93/05/24 11:34:43 
  87.  *   psp now points to itself when /P isn't specified. 
  88.  *   COM.C 1.24 93/05/17 11:22:28
  89.  *   Added support for F5 and F8 being pressed during boot-up.  
  90.  *   COM.C 1.23 93/04/22 14:51:10 
  91.  *   Now close handles 5-19 after an exec.
  92.  *   echoflg is now correctly preserved when batch files are chained. See
  93.  *   echoflg_save2.
  94.  *   COM.C 1.19 93/01/21 14:29:44
  95.  *   Now do INT 21 ah=29 when changing default drive.
  96.  *   COM.C 1.16 92/11/25 09:30:15
  97.  *   Password support enabled/disabled by #if defined(PASSWORD) statements.
  98.  *   HOMEDIR support disabled.
  99.  *   COM.C 1.12 92/09/25 19:48:56
  100.  *   Removed .cmd from search order if DOSPLUS defined.
  101.  *   Fixed bug when ;; appears in path.
  102.  *   COM.C 1.11 92/09/17 11:30:14 
  103.  *   Piping a batch file through MORE no longer stops with Syntax Error
  104.  *   displayed.
  105.  *   COM.C 1.10 92/09/11 10:43:41
  106.  *   COMMAND /P: disables time and date prompt and copyright message.
  107.  *   COMMAND ? no longer hangs.
  108.  *   ENDLOG
  109.  */
  110. #include "defines.h"
  111. #if 0
  112. #if defined(DLS)
  113. #define MSG_VER 111 /* required message file version No. */
  114. #else
  115. #define MSG_VER msg_ver111 /* required message file version No. */
  116. extern char  *MSG_VER;
  117. #endif
  118. #endif
  119. #include <setjmp.h>
  120. #include <string.h>
  121. #if defined(MWC) && defined(strlen)
  122. #undef strcmp /* These are defined as macros in string.h */
  123. #undef strcpy /* which are expaneded in line under */
  124. #undef strlen /* Metaware C. These undefs avoid this. */
  125. #endif
  126. #include <portab.h>
  127. #include <mserror.h>
  128. #if !defined(DOSPLUS)
  129. #include <ccpm.h>
  130. #include <sysdat.h>
  131. #endif
  132. #include "command.h" /* Command Definitions */
  133. #include "support.h" /* Support routines */
  134. #include "dos.h"  /* MSDOS function definitions */
  135. #include "dosif.h" /* DOS interface definitions */
  136. #include "toupper.h"
  137. #include "global.h" /* Global Variables */
  138. /* RG-00- */
  139. #define PATH_LEN     65  /* max path length (null terminated) */
  140. #if !defined(NOSECURITY) && (defined(CDOSTMP) || defined(CDOS))
  141. #include <pd.h>
  142. #include "security.h"
  143. #include "login.h"
  144. #endif
  145. /* RG-00- end */
  146. MLOCAL BYTE valid_sepchar[] = ":.;,=+";
  147. #if defined(DOSPLUS) /* we now define initial  */
  148. MLOCAL BYTE PATH_DIR[]  = "A:\OPENDOS";
  149. MLOCAL BYTE SET_PATH[]  = "PATH=%s";
  150. MLOCAL BYTE SET_PROMPT[]  = "PROMPT=$P$G";
  151. MLOCAL BYTE SET_OS[]   = "OS=OPENDOS"; /* environment in COMMAND */
  152. MLOCAL BYTE SET_VER[]  = "VER=7"; /* not in BIOSINIT        */
  153. #if !defined(FINAL)
  154. MLOCAL BYTE SET_BETA[] = "BETA=Beta 4";
  155. #endif
  156. #endif
  157. GLOBAL jmp_buf break_env;
  158. #if defined(DOSPLUS)
  159. EXTERN UWORD _psp;
  160. EXTERN VOID *batchptr_off;
  161. EXTERN VOID *batchflg_off;
  162. EXTERN VOID *echoflg_off;
  163. EXTERN UWORD FAR *batch_seg_ptr;
  164. #endif
  165. /*RG-03*/
  166. EXTERN BOOLEAN  if_context;         /* BATCH.C */
  167. /*RG-03-end*/
  168. #if defined(DOSPLUS)
  169. EXTERN VOID CDECL show_help(WORD); /* CSTART.ASM */
  170. EXTERN VOID CDECL put_resident_high(WORD); /* CSTART.ASM */
  171. EXTERN BYTE FAR * CDECL get_config_env(VOID); /* CTSART.ASM */
  172. EXTERN UWORD CDECL get_original_envsize(VOID);
  173. EXTERN VOID CDECL copy_crit_msgs(VOID); /* CSUP.ASM */
  174. EXTERN VOID CDECL copy_rld_msgs(VOID); /* CSUP.ASM */
  175. EXTERN WORD CDECL dos_parse_filename(BYTE *);
  176. EXTERN UWORD  CDECL docmd_int2f(BYTE *, BYTE *, UWORD);
  177. #endif
  178. EXTERN void CDECL flush_cache(void);
  179. EXTERN BYTE  *kbdptr;
  180. EXTERN BYTE msg_patheq[]; /* Static Environ String "PATH=" */
  181. EXTERN S_CMD cmd_list[]; /* CMDLIST.C */
  182. #if defined(DOSPLUS)
  183. EXTERN VOID inherit_parent_state();
  184. #endif
  185. EXTERN WORD echoflg_save2;
  186. EXTERN VOID batch_start(BYTE *, BYTE *, BYTE *);
  187. EXTERN VOID batch_end(VOID); /* BATCH.C */
  188. EXTERN VOID batch_endall(VOID); /* BATCH.C */
  189. EXTERN VOID batch_close(VOID); /* BATCH.C */
  190. EXTERN VOID for_end(VOID); /* BATCH.C */
  191. EXTERN BOOLEAN getcmd(BYTE *); /* BATCH.C */
  192. #if !defined(CDOSTMP)
  193. EXTERN VOID int2e_start(); /* BATCH.C */
  194. EXTERN VOID int2e_finish(); /* BATCH.C */
  195. #endif
  196. EXTERN VOID CDECL cmd_cd(BYTE *); /* COMINT.C */     
  197. EXTERN VOID CDECL cmd_ver(); /* COMINT.C */
  198. EXTERN VOID CDECL cmd_set(BYTE *); /* COMINT.C */
  199. GLOBAL VOID docmd(BYTE *, BOOLEAN); /* COM.C */
  200. MLOCAL VOID cmd_loop (BYTE *); /* COM.C */
  201. MLOCAL VOID error_code(UWORD); /* COM.C */
  202. MLOCAL VOID cmd_cleantp(VOID); /* COM.C */
  203. GLOBAL BOOLEAN parse(BYTE *); /* COM.C */
  204. MLOCAL VOID init(BYTE *); /* COM.C */
  205. MLOCAL BOOLEAN doexec(BYTE *, BYTE *, UWORD, BYTE *);
  206. #if !defined(CDOSTMP)
  207. MLOCAL BYTE msg_comspec[] = "COMSPEC=";
  208. /*EXTERN BYTE *reload_file;    CSTART.ASM  */
  209. EXTERN VOID CDECL get_reload_file(VOID); /* CSUP.ASM */
  210. EXTERN VOID CDECL set_reload_file(VOID); /* CSUP.ASM */
  211. EXTERN VOID CDECL get_out_pipe(VOID); /* CSUP.ASM */
  212. EXTERN VOID CDECL install_perm(VOID);    /* CSTART.ASM  */ 
  213. EXTERN VOID CDECL master_env(UWORD);    /* CSTART.ASM  */ 
  214. GLOBAL WORD CDECL findfile(BYTE *, UWORD *);    /* COM.C for MS-DOS  */
  215. MLOCAL WORD checkfile(BYTE *, UWORD *, BYTE *, BYTE *, BYTE *, BYTE *);
  216. EXTERN BYTE cbreak_ok; /* control break handler initialised */
  217. #else
  218. EXTERN WORD CDECL findfile(BYTE *, UWORD *);     /* DOSIF.A86 (P_PATH) */
  219. EXTERN VOID network_init(VOID);     /* NETWORK.C   */
  220. EXTERN PD FAR * CDECL pd; /* Far pointer to Current PD */
  221. MLOCAL BOOLEAN system_init = TRUE;
  222. #endif
  223. EXTERN BYTE FAR * CDECL farptr(BYTE *);
  224. EXTERN BYTE FAR * CDECL cgroupptr(BYTE *);
  225. #if defined(CPM)
  226. EXTERN UWORD CDECL cpm_init(VOID); /* CP/M Init Routine */
  227. #endif
  228. #if !defined(NOSECURITY) && (defined(CDOSTMP) || defined(CDOS))
  229. /* global VC data */
  230. UWORD   vc_base;    /* first vc number for this station */
  231. UWORD   num_of_vcs; /* number of vcs on this station */
  232. #endif
  233. #if !defined(CDOSTMP)
  234. BYTE autoexec_name[13] = "autoexec.bat";
  235. #endif
  236. #if defined(DOSPLUS)
  237. UWORD boot_key_scan_code = 0;
  238. #endif
  239. #if !defined(FINAL)
  240. void save_psp(void);
  241. void check_psp(void);
  242. WORD psp_xsum;
  243. #endif
  244. VOID FAR CDECL _main(cmd)
  245. BYTE *cmd;
  246. {
  247. BYTE    cmd_buf[128];
  248. #if defined(CDOSTMP) /* Insure the NETWORK_INIT   */
  249. network_init(); /* function is called before */
  250. #endif /* any disk activity so that */
  251. /* Diskless DRNET systems can*/
  252. /* be generated.      */
  253. #if !defined(NOSECURITY) && (defined(CDOSTMP) || defined(CDOS))
  254.         /* get the VC data and make global */
  255.         vc_data(&vc_base, &num_of_vcs, &station);
  256. #endif
  257. #if defined(DOSPLUS) && defined(DLS)
  258. copy_crit_msgs();
  259. copy_rld_msgs();
  260. #endif
  261.   init(cmd); /* Initialize COMMAND.???    */
  262. #if defined(CPM)
  263. if(cpm_init()) { /* If this is the CP/M Media */
  264.     eprintf(MSG_SINGLECPM); /* Access program then call  */
  265.     ms_x_exit(1); /* the CPM_INIT function     */
  266. }
  267. #endif
  268. ms_drv_set(drive);  /* try to set default drive  */
  269. FOREVER {
  270.             error_code(setjmp(break_env)); /* Initialize Error Handler */
  271. #if !defined(CDOSTMP)
  272.     cbreak_ok = TRUE; /* we can handle break now */
  273. #endif
  274. #if !defined(NOSECURITY) && (defined(CDOSTMP) || defined(CDOS))
  275. #if defined(CDOSTMP)
  276.     ms_drv_set(drive);   /* try to set default drive  */
  277.             /* Ensure we are the foreground process on the Virtual Console */
  278.             /* before displaying login prompt. */
  279.             if(login_enabled()) {
  280.                 disable_vc_switch(); /* stop user switching to another console */
  281.                 /* if 1st time through on VC 0 then run system autoexec */
  282. if (system_init) {
  283.     login_save_initial_state();
  284.     if (pd->P_CNS==0) {
  285.                     /* log this event */
  286.                     logevent("",LOG_POWERON);
  287. /* process system Autoexec.bat */
  288.         while (*kbdptr || batchflg)
  289.         cmd_loop (cmd_buf);
  290.                 }
  291.     system_init = FALSE;
  292. }
  293.                 if(waiting_on_login() && !background_proc())
  294.                     login_station(); /* login station */
  295.         login_consoles(); /* initialise all VCs */
  296.                 enable_vc_switch();
  297.             }
  298. #endif
  299.             FOREVER {
  300.                 error_code(setjmp(break_env)); /* Initialize Error Handler */
  301.     if (login_enabled()) {
  302.                     if(!logged_in())  /* keep going until logged out */
  303.         break;
  304.     }
  305. #endif
  306.                 cmd_loop (cmd_buf);
  307. #if !defined(NOSECURITY) && (defined(CDOSTMP) || defined(CDOS))
  308.     }
  309.             if(login_enabled()) {
  310. /* kill off any remaining batch processes still running */
  311.                 while (batchflg)
  312.         cmd_exit("");
  313. #if defined(CDOSTMP)
  314. /* the logout event */
  315.                 if(!background_proc())
  316.     logout();
  317. #else
  318. return; /* CDOS.COM just dies when logout happens */
  319. #endif
  320.     }
  321. #endif
  322.         } 
  323. }
  324. /*MLOCAL*/ VOID cmd_loop (cmd)
  325. BYTE *cmd;
  326. {
  327. WORD echoing;     
  328. REG BYTE *cmdline;
  329. BYTE first_ch;
  330.   
  331. cmd_cleanup(); /* Cleanup after the command */
  332. cmdline = cmd;
  333. if (!batchflg) flush_cache();
  334. echoing = getcmd(cmdline); /* do not echo Labels      */
  335. first_ch = *deblank(cmdline);
  336. if((pipe_out && !batchflg && !*deblank(kbdptr)) ||
  337. /* if "|<nul command>" */
  338.    (pipe_in && (first_ch == 0 || first_ch == ':'))) {
  339.     /* or "<null command>|" */
  340.     eprintf(MSG_SYNTAX); /* report syntax error */
  341.     pipe_out = NO; /* forget about pipes */
  342.     pipe_in  = NO;
  343.     if (!batchflg)
  344. *kbdptr = ''; /* discard rest of line */
  345.     crlfflg = YES; /* remember to do a LF */
  346.     return; /* stop now before echo */
  347. }
  348. if(echoing && first_ch != ':') {
  349. /* Echo command line if ECHO */
  350.     puts(cmdline); /* ON and source not keyboard*/
  351.     crlf(); /* and not a label      */
  352. }
  353. crlfflg = NO; /* NO CR/LF req'd           */
  354. cmdline = deblank(cmdline);  /* remove leading spaces    */
  355.  
  356. if(*cmdline && *cmdline != ':') /* Check for a command     */
  357. { /* not a LABEL     */
  358.     if (!strnicmp(cmdline,"IF",2)) docmd(cmdline,YES);
  359.     else {
  360.         if(!parse(cmdline)) { /* If the Parse succeeds then*/
  361.     docmd(cmdline, YES); /* execute the command.      */
  362.                 }
  363.     }
  364. }
  365. }
  366. /*.pa*/
  367. /*
  368.  *
  369.  */
  370. #define COMMAND_P (cflag & 1) /* Permanent Flag */
  371. #define COMMAND_C (cflag & 2) /* One Command Option */
  372. #define COMMAND_T (cflag & 4) /* CDOS TSR option */
  373. MLOCAL VOID init(cmd)
  374. BYTE *cmd;
  375. {
  376. UBYTE console = 1; /* Concurrent Console No. +1 */
  377. SYSDATE date; /* System Date Structure     */
  378. WORD ret; /* General Variable      */
  379. UWORD cflag;
  380. BYTE *s;
  381. #if defined(CDOSTMP)
  382. UWORD vc_base, vc_num, pc_num; /* Virtual Console Data      */
  383. #else
  384. BYTE buf[MAX_ENVLEN], c;
  385. UWORD envsize = 256;
  386. #endif
  387. #if defined(DOSPLUS)
  388. BOOLEAN no_timedate = FALSE;
  389. WORD  prh_function = 0;
  390. UWORD FAR *p_batch_seg;
  391. #endif
  392. BYTE lferror = 0;
  393. strcpy(kbdptr, ""); /* start with no commands */
  394. #if 0
  395. #if defined(DLS)
  396. dls_msg_ver(MSG_VER); /* check message file version*/
  397. #else
  398. s = MSG_VER; /* ensure label is referenced */
  399. #endif
  400. #endif
  401. #if defined(CDOS)
  402. ret = ioctl_ver();
  403. if(ret < 0x1450 || ret > 0x1499) { /* Get the CDOS BDOS Version */
  404.     eprintf(MSG_BADOS); /* and quit if it is not 5.0 */
  405.     ms_x_exit(-1); /* or Above      */
  406. }
  407. #endif
  408. #if defined(DOSPLUS)
  409. batchptr_off = (VOID *) &batch;
  410. batchflg_off = (VOID *) &batchflg;
  411. echoflg_off  = (VOID *) &echoflg;
  412. envsize = get_original_envsize(); /* BAP - sets envsize to */
  413. /* same as original COMMAND */
  414. if ((envsize < 128) || (envsize > 32752)) envsize = 256; /* shouldn't really need this */
  415. parent_psp = MK_FP(_psp, 0x16); /* our parental PSP is here  */
  416. ret = ioctl_ver(); /* Get the BDOS Version No.  */
  417. if(ret < 0x1071) { /* Abort if this is not DOS  */
  418.     eprintf(MSG_BADOS); /* PLUS with a BDOS version  */
  419.     if ((*parent_psp) && (*parent_psp != _psp))
  420. ms_x_exit(-1); /* abort unless root process */
  421.     while(1){};
  422. }
  423. #if 0
  424. #if defined(DLS)
  425. dls_msg_crit(); /* init crit error messages  */
  426. #endif
  427. #endif
  428. #endif
  429. #if defined(CDOSTMP)
  430. console = (UBYTE) bdos(C_GET, 0) + 1; /* CDOS Console No. + 1     */
  431. execed = NO; /* COMMAND.RSP not EXECED    */
  432. err_ret = 0; /* Initial Error Code 0000   */
  433. #else
  434. execed = YES; /* Assume we have been loaded*/
  435. /* from the command line     */
  436. break_flag = ms_set_break(NO); /* Get the Current Break Flag*/
  437. err_ret = ms_x_wait(); /* Get the completion code   */
  438. /* for process's that cause  */
  439. /* COMMAND.COM to be reloaded*/
  440. init_switchar(); /* initialise switchar and   */
  441. /* pathchar      */
  442. #endif
  443. drive = ms_drv_get();   /* get default drive.      */
  444. country.code = ms_s_country(&country); /* Initialise the Country data*/
  445. in_handle = psp_poke(STDIN, 0xFF); /* Get the standard input    */
  446. psp_poke(STDIN, in_handle); /* and save internally      */
  447. out_handle = psp_poke(STDOUT, 0xFF); /* Get the standard Output   */
  448. psp_poke(STDOUT, out_handle); /* and save internally      */
  449. for(ret=5;ret<20;ms_x_close(ret++)); /* close handles 5-20      */
  450. if(initflg) /* is this a warm boot?      */
  451.     return; /* Yes then QUIT      */
  452. initflg = YES; /* there's only one 1st time */
  453. cflag = 0; /* Clear the switch variable */
  454. #if !defined(CDOSTMP)
  455. /*
  456.  *
  457.  * COMMAND.COM
  458.  * The following command line formats must be supported for
  459.  * applications that exec the command processor.
  460.  *
  461.  * COMMAND /CCOPY filex filey FrameWork Install
  462.  * COMMAND /C DIR *.* /P Procomm directory option
  463.  * COMMAND /C=DIR *.*
  464.  *
  465.  * These varients prevent support for multiple options and
  466.  * force the option scanning to be halted at the first command
  467.  *
  468.  * COMMAND /T - TSR support for CDOS
  469.  *
  470.  * We are auto-invoking COMMAND after detecting a TSR, so
  471.  * try and inherit any open batch files.
  472.  *
  473.  */
  474. s = (BYTE *) heap_get(128); /* allocate some heap memory */
  475. FOREVER {
  476.     cmd = deblank(cmd); /* Deblank the command line  */
  477.     if((*cmd == '') || (*cmd == *switchar))
  478. break; /* stop at option or end     */
  479.     cmd = get_filename(s, cmd, NO);
  480.     if(strlen(s)) { /* look for Loadpath/STDIO */
  481. if((ret = ms_x_open(s, OPEN_RW)) >= 0) {
  482.     if(isdev(ret)) {
  483. strcat(kbdptr,"ctty "); /* if its a R/W device put */
  484. strcat(kbdptr, s); /* CTTY <dev> into buffer  */
  485. strcat(kbdptr,"!");
  486.     }
  487.     else /* otherwise its an error  */
  488. eprintf(MSG_LOADPATH); /*  an invalid loadpath    */
  489.     ms_x_close(ret); /* Close the handle */
  490. }
  491. else {
  492.     append_slash(s); /* user specified loadpath   */
  493.     get_reload_file(); /* get reload_file on heap   */
  494.     strcat(s, fptr(heap()));
  495.     if(file_exist(s)) { /* append existing load file */
  496.      ms_x_expand(heap(), s);
  497.      set_reload_file(); /* copy heap to reload_file  */
  498.     }
  499.     else { /* Print an error message if */
  500. eprintf(MSG_LOADPATH); /* an invalid path used.     */
  501. lferror = 1;
  502. break;
  503.     }
  504. }
  505.     }
  506.     else {
  507.         eprintf(MSG_LOADPATH);
  508. break;
  509.     }
  510. }
  511. heap_set(s); /* free up heap memory */
  512. c_option = FALSE;
  513. k_option = FALSE;
  514. FOREVER {
  515.     cmd = deblank(cmd); /* Deblank the command line  */
  516.     if(*cmd != *switchar) /* Stop the option check if  */
  517. break; /* the next character is not */
  518.     cmd++; /* a switch character.      */
  519.     c = toupper(*cmd++);
  520.     switch(c) {
  521. /*RG-05-*/
  522. #if (defined(CDOS)||defined(DOSPLUS)) && !defined(NOHELP)
  523.    case 'H': /* Support /H Help Option      */
  524. case '?': /* Support /? Help Option      */
  525.     cflag |= 2;
  526.                     cmd_ver();
  527.                     crlf();
  528.                     printf(HELP_COM);
  529.     ms_x_exit(0);
  530.     break;
  531. #endif
  532. /*RG-05-end*/
  533. case 'C': /* Support /C Option      */
  534.     echoflg  = ECHO_OFF; /* Don't issue CR LF      */
  535.     c_option = TRUE;
  536. case 'K':
  537.     k_option = TRUE;
  538.     cmd = deblank(cmd);
  539.     if (*cmd == '=') {
  540.      cmd++; /* Skip optional '='         */
  541.         cmd = deblank(cmd);
  542.     }
  543.     
  544.     cflag |= 2;
  545.     break;
  546. case 'N':
  547. n_option = TRUE;
  548. break;
  549. case 'P': /* Support /P Option      */
  550.     cflag |= 1;
  551.     if (*cmd == ':') { /* See if a different fname  */
  552.      cmd++; /* has been specified for    */
  553. ret = 0; /* AUTOEXEC.BAT.             */
  554.      while ((*cmd > 32) && (ret < 12))
  555. autoexec_name[ret++] = *cmd++;
  556.      autoexec_name[ret] = 0;
  557. while (*cmd > 32) cmd++;
  558.     }
  559.     break;
  560. case 'E': /* Environment Option */
  561.     if(*cmd != ':') /* Check for /E:nnn   */
  562.         break;
  563.     cmd++;
  564.     if(getdigit(&ret, &cmd) && ret > 128 && ret < 32752)
  565.         envsize = ret;
  566.     break;
  567. #if defined(CDOS)
  568. case 'T': /* TSR support */
  569.     cflag |= 5;
  570.     inherit_TMP_state(); /* inherit batch files etc */
  571.     break;
  572. #endif
  573. #if defined(DOSPLUS)
  574. case 'T':
  575.     inherit_parent_state();
  576.     break;
  577. #endif
  578. #if defined(DOSPLUS)
  579. case 'M': /* relocate resident portion */
  580.     c = toupper(*cmd++);
  581.     if (c == 'H') prh_function = 1;
  582.     if (c == 'U') prh_function = 2;
  583.     if (c == 'L') prh_function = -1;
  584.     break;
  585. case 'D':
  586.     no_timedate = TRUE;
  587.     break;
  588. #endif
  589. case '': /* Treat the NULL character */
  590.     cmd--; /* specially in case some of*/
  591.     break; /* the following command "/"*/
  592. default: /* Skip invalid options.    */
  593.     break;
  594.     }
  595. }
  596. #if defined(DOSPLUS)
  597. /* We cannot allow COMMAND to go into upper memory unless "/P" has also */
  598. /* been given. If we do the memory won't be freed up on exit */
  599. switch(prh_function) {
  600.    case 0: /* try high, upper, then low */
  601. if(COMMAND_P)
  602. put_resident_high(0);
  603. else
  604. put_resident_high(1);
  605. break;
  606. case 1: /* try high, then low */
  607. put_resident_high(1);
  608. break;
  609. case 2: /* try upper, then low */
  610. if(COMMAND_P)
  611. put_resident_high(2);
  612. break;
  613. default:/* try low */
  614. break;
  615. }
  616. #endif
  617. master_env(envsize); /* Allocate the master       */
  618. /* environment of ENVSIZE    */
  619. /* bytes in length      */
  620. #if 0
  621. /*
  622.  * If no COMSPEC has been defined or it is different from
  623.  * the RELOAD_FILE specification then update COMSPEC.
  624.  */
  625. if(env_scan(msg_comspec, heap()) || stricmp(heap(), reload_file)) {
  626.     sprintf(buf, "%s%s", msg_comspec, reload_file);
  627.     cmd_set(buf);
  628. }
  629. #else
  630. /* BAP changed this */
  631. get_reload_file();
  632. if(env_scan(msg_comspec,heap())) {
  633.     sprintf(buf,"%s%s",msg_comspec,heap());
  634.     cmd_set(buf);
  635. }
  636. #endif
  637. #if defined(DOSPLUS)
  638. save_parent = *parent_psp;
  639. *parent_psp = _psp; /* Always do this */
  640.     if(COMMAND_P) { /* Action the /P flag for   */
  641. execed = NO; /* DOSPLUS.COM     */
  642. PATH_DIR[0] = drive + 'A'; /* if DRDOS directory exists */
  643. ret = ms_x_chmod(PATH_DIR, ATTR_ALL, 0);
  644. if ((ret > 0) && (ret & 0x10)) {/* point the path at it */
  645. sprintf(buf, SET_PATH, PATH_DIR);
  646. cmd_set(buf);
  647. }
  648. cmd_set(SET_PROMPT);
  649. cmd_set(SET_OS);
  650. cmd_set(SET_VER);
  651. #if !defined(FINAL)
  652. cmd_set(SET_BETA);
  653. #endif
  654.         install_perm(); /* Install Backdoor entry    */
  655.     }
  656. /* process the environment created by config.sys */
  657. process_config_env();
  658. #endif
  659. #endif
  660. FOREVER {
  661.     if(execed) { /* If this is a transient  */
  662. if (!lferror)
  663.     strcat(kbdptr, cmd); /* command processor then  */
  664. ret = FALSE; /* get the command line and*/
  665. break; /* ignore AUTOEXEC.BAT.    */
  666.     }
  667.     /* Check for the presence of STARTnnn.BAT in the root   */
  668.     /* of the boot disk if not found check for AUTOEXEC     */
  669.     /* if neither are present then if this is console 0     */
  670.     /* and this is < 1987 ask for the date.      */
  671. #if defined(CDOSTMP) 
  672.             vc_data(&vc_base, &vc_num, &pc_num); /* Get VC Data     */
  673.     vc_num = console - vc_base; /* Relative VC Num  */
  674.     sprintf(heap(), "!start%02d%1d.bat", pc_num, vc_num);
  675.     if((ret = file_exist(heap()+1)) == 0) {
  676.         strcpy(heap(), "!autoexec.bat");
  677. ret = file_exist(heap()+1);
  678.     }
  679.     if(ret != 0) { 
  680. strcat(kbdptr, heap());
  681. sprintf(heap(), " %d %d %d", console, pc_num, vc_num);
  682. strcat(kbdptr, heap());
  683. break;
  684.     }
  685. #else
  686.     strcpy(heap(), "!");
  687.     strcat(heap(), autoexec_name);
  688.     if((ret = file_exist(heap()+1)) != 0) {
  689. if (boot_key_scan_code != 0x3f00 /*F5*/)
  690.     strcat(kbdptr,heap());
  691. break;
  692.     } else {
  693. boot_key_scan_code = 0;
  694.     }
  695. #endif
  696. #if defined(DOSPLUS)
  697.     if (!no_timedate && *autoexec_name!=0)
  698.         strcat(kbdptr, "!date!time");
  699. #else
  700.     ms_getdate(&date);
  701.     if(console == 1 && date.year < 1987)
  702. strcat(kbdptr, "!date!time");
  703. #endif
  704.     break;
  705. }
  706. #if defined(CDOS) && !defined(CPM)
  707.     if(COMMAND_P) /* Action the /P flag for   */
  708. execed = NO; /* CDOS.COM to disable EXIT */
  709. #endif
  710. #if 0
  711. if(COMMAND_C) { /* Append EXIT if COMMAND.COM*/
  712.     strcat(kbdptr, "!exit 0"); /* is just used to execute a */
  713. } /* a command.      */
  714. #endif
  715. #if !defined(CDOSTMP)
  716. #if 0
  717. else { 
  718. #else
  719. if(!COMMAND_C) {
  720. #endif
  721. #if defined(DOSPLUS)
  722.     if (*autoexec_name != 0) {
  723.         cmd_ver(); /* display the signon      */
  724.           printf(MSG_OEMCPYRT);
  725.         crlf();
  726.     }
  727. #else
  728.     if(!COMMAND_T) { /* if it's CDOS TSR support  */
  729. cmd_ver(); /* don't display signon      */
  730. crlf();
  731.     }
  732. #endif
  733. }
  734. #endif
  735. }
  736. /*
  737.  * The following function is called to clean up COMMAND.COM after 
  738.  * an internal or external command has been executed. The major areas
  739.  * to be handled by this function are:-
  740.  *
  741.  * 1) Control-C termination for Batch file termination
  742.  * 2) I/O Redirection
  743.  * 3) Hiloading off
  744.  */
  745. MLOCAL VOID cmd_cleanup()
  746. {
  747. BYTE cmdbuf[128];
  748. #if 0
  749. hiload_set(NO); /* HILOADing off now */
  750. #endif
  751. if(err_ret == BREAK_EXIT || /* Check for Control-C      */
  752.     err_ret == ERROR_EXIT) { /* or Critical Error Exit    */
  753.     if(pipe_out) { /* If a Pipe'ed command is   */
  754. pipe_out = NO; /* is aborted then absorb    */
  755. getcmd(cmdbuf); /* the second command.      */
  756. crlf();
  757.     }
  758.     if(batchflg) {
  759. eprintf(MSG_BATTERM); /* Processing a BATCH file   */
  760. err_flag = TRUE; /* ask if the uses wishes to */
  761. if(yes(NO, YES)) /* to abort this batch job   */
  762.     batch_endall(); /* Close ALL batch files     */
  763. err_flag = FALSE;
  764.     }
  765.     else if(for_flag) /* If processing a FOR      */
  766. for_end(); /* command outside a batch   */
  767. } /* file then abort it.      */
  768. err_ret &= 0x00FF; /* Mask the Termination      */
  769. /* condition this should only*/
  770. /* be tested once.      */
  771. /*
  772.  * After the termination of a Batch file or a Program then
  773.  * the relevant redirection is removed. If the redirection
  774.  * was instigated because of the PIPE facility then the
  775.  * correct clean up code is executed.
  776.  */
  777. while(in_flag & REDIR_ACTIVE) { /* Is Redirection Active     */
  778.     if((in_flag & REDIR_BATCH) && batchflg)
  779. break;
  780.     if((in_flag & REDIR_FOR) && for_flag)
  781. break;
  782.     ms_x_close(STDIN);  /* Close the Redirected File */
  783.     psp_poke(STDIN, in_handle); /* Restore original Handle   */
  784.     
  785.     if(pipe_in) {
  786. pipe_in = NO;
  787. ms_x_unlink(old_pipe);
  788. heap_set(old_pipe);
  789.     }
  790.     in_flag = NULL;
  791. }
  792. while(out_flag & REDIR_ACTIVE) { /* Is Redirection Active     */
  793.     if((out_flag & REDIR_BATCH) && batchflg)
  794. break;
  795.     if((out_flag & REDIR_FOR) && for_flag)
  796. break;
  797.     ms_x_close(STDOUT); /* Close the Redirected File */
  798.     psp_poke(STDOUT, out_handle); /* Restore original Handle   */
  799.     if(pipe_out) {
  800. pipe_in = YES; pipe_out = NO;
  801. old_pipe = heap_get(strlen(out_pipe)+1);
  802. strcpy(old_pipe,out_pipe);
  803.     }
  804.     out_flag = NULL;
  805. }
  806. country.code = ms_s_country(&country); /* re-init the Country data  */
  807. #if 0
  808. #if defined(DLS)
  809. dls_msg_crit(); /* re-init crit error msgs   */
  810. #endif
  811. #endif
  812. }
  813. /*.pa*/
  814. /*
  815.  * ERROR_INIT is the "CRITICAL" error handler which will initialize
  816.  * the error handling code, displays error messages and clean-up the
  817.  * environment after an error has occurred.
  818.  */
  819. /*RG-00*/
  820. /*MLOCAL VOID error_code(error)*/
  821. VOID error_code(error)
  822. /*RG-00-end*/
  823. UWORD error;
  824. {
  825. switch(error) {
  826.     case 0: /* Setting JMPBUF. Enable    */
  827. #if !defined(CDOSTMP) /* break checking in case    */
  828. ms_set_break(YES); /* this is the first time    */
  829. #endif /* through the command proc. */
  830.   return;
  831.     case IA_BREAK:
  832. putc('r'); /* A CR here makes SideKick+ */
  833. /* look good when it      */
  834. /* deinstalls itself      */
  835. /* The following two function calls close the batch file during an INT 23
  836.    thus disallowing to continue with a batch file if the user chooses to
  837.    do so after being prompted. However, there migh have been a reason why
  838.    this has been inserted before which I don't know of. JBM */
  839. /* ms_x_close(5);  ##jc## Close Unused Handles*/
  840. /* ms_x_close(6);  ##jc## Close Unused Handles*/
  841. mem_free(&bufaddr); /* Free External Copy Buffer */
  842. #if defined(CDOSTMP) /* On Concurrent DOS and     */
  843. bdos(DRV_RESET, 0xFFFF); /* DOSPLUS reset the disk    */
  844. crlf(); /* when we get a Control-C.  */
  845. #endif
  846. break;
  847.     case IA_STACK: /* Stack Overflow Error      */
  848.     case IA_HEAP: /* Heap Overflow Error      */
  849. batch_endall();  /* Out of memory error      */
  850. eprintf(MSG_BATNEST); /* probably caused by nesting*/
  851. break; /* batch files TOO deep.     */
  852.     case IA_FILENAME: /* FileName Error      */
  853. eprintf(ERR_FILE); /* display an error message  */
  854. break; /* and terminate the command */
  855.     default:
  856. eprintf(MSG_LONGJMP, error);
  857. break;
  858. }
  859. crlfflg = NO; /* Reset CR/LF Flag     */
  860. }
  861. /*
  862.  * This function is invoked after a CONTROL-BREAK or Critical Error
  863.  * during the execution of an internal function. Any BREAK specific
  864.  * cleanup is executed here. The break handler then restarts normal
  865.  * code execution by executing a LONGJMP.
  866.  */
  867. GLOBAL VOID CDECL int_break()
  868. {
  869. int i;
  870. if (show_file_buf) mem_free(&show_file_buf);
  871. if (global_in_hiload) {
  872.     /* if ctrl-c pressed during a hiload, restore memory */
  873.     /* allocation strategy.  */
  874.     for(i=1;i<10;i++) { /* free up any UMB's we have */
  875. if (hidden_umb[i]) {
  876.     free_region(hidden_umb[i]);
  877.     hidden_umb[i] = 0;
  878. }
  879.     }
  880.     set_upper_memory_link(global_link);
  881.     set_alloc_strategy(global_strat);
  882.     global_in_hiload = 0;
  883. }
  884. err_ret = BREAK_EXIT; /* Update the Global Error Return */
  885. longjmp(break_env, IA_BREAK); /* Either Control-C or Critical   */
  886. /* Error Process Termination.   */
  887. }
  888. /*.pa*/
  889. /*
  890.  * This function parses the command line and extracts all unquoted
  891.  * >>, > and < character sequences and their corresponding filenames.
  892.  * The last redirection specification of the same type is used all
  893.  * previous references will be removed. Redirection will only be 
  894.  * enabled if no redirection of the same type is already active.
  895.  * ie. If redirection is enabled on a batch file all redirection
  896.  * commands of the same type inside the file are ignored.
  897.  */
  898. GLOBAL BOOLEAN parse(s)     /* Parse the command line looking    */
  899. BYTE *s; /* for Redirection commands      */
  900. {
  901. REG BYTE *bps;
  902. BYTE *bpi, *bpo;
  903. BYTE infile[MAX_FILELEN]; /* Input Redirection FileName     */
  904. BYTE outfile[MAX_FILELEN]; /* Output Redirection FileName     */
  905. BYTE cmdbuf[128]; /* Command buffer for Aborted Pipe  */
  906. WORD h;
  907. BOOLEAN quote = NO; /* Check for Quoted Statements      */
  908. BOOLEAN append;  /* Out Redirection Append      */
  909. crlfflg = YES; /* Force a CRLF in case an error     */
  910. /* occurs in the command line parsing*/
  911. for(bpi = NULL, bpo = NULL; *s; s++) {
  912.     if(*s == '"') { /* Maintain the correct    */
  913. quote = !quote;  /* Status of the QUOTE flag*/
  914. continue;
  915.     }
  916.     if(quote) /* If the QUOTE flag is     */
  917. continue; /* then skip the following  */
  918.     if(*s == '>') { /* Found Output redirection  */
  919. bpo = outfile; /* Character extract the Path*/
  920. bps = s+1; append = FALSE; /*  and save locally      */
  921. if(*(bps) == '>') { /* Check for append mode     */
  922.     append = TRUE;
  923.     bps++;
  924. }
  925. bps = get_filename(bpo, deblank(bps), NO);
  926. /* Extract the FileName      */
  927. bps = deblank(bps);
  928. strcpy(s--, bps); /* Then remove data from Line*/
  929. continue; /* S decrement to force new  */
  930.     } /* next character to be read */
  931.     if(*s == '<') { /* Found Input redirection   */
  932. bpi = infile; /* Character extract the Path*/
  933. bps = get_filename(bpi, deblank(s+1), NO);
  934. /* Extract the FileName      */
  935. bps = deblank(bps);
  936. strcpy(s--, bps); /* Then remove data from Line*/
  937.     } /* S decrement to force new  */
  938. } /* next character to be read */
  939. #if defined(DOSPLUS)
  940. /* only redirect if not already redirected */
  941. if ((pipe_in || bpi) && (!(in_flag & REDIR_ACTIVE))) {
  942. #else
  943. if(pipe_in || bpi) { /* Check for any redirection */
  944.     if(in_flag & REDIR_ACTIVE) { /* If Standard Input has been*/
  945. eprintf(MSG_INACTIVE); /* redirected then fail      */
  946. return FAILURE;
  947.     }
  948. #endif
  949.     bpi = pipe_in ? out_pipe : infile; /* BPI points to the filename*/
  950.     h = ms_x_open(bpi, OPEN_READ);
  951.     if(h < 0) {
  952. /* Attempt to Open the file  */
  953. e_check(h); /* || device specified and   */
  954. return FAILURE;  /* print an error message if */
  955.     } /* we fail.      */
  956.     psp_poke(STDIN, psp_poke(h, 0xFF)); /* Force New input file onto */
  957.      /* Standard Input and close  */
  958.     in_flag = REDIR_ACTIVE; /* the returned handle      */
  959. }
  960. #if defined(DOSPLUS)
  961. /* only redirect if not already redirected */
  962. if ((pipe_out || bpo) && (!(out_flag & REDIR_ACTIVE))) {
  963. #else
  964. if(pipe_out || bpo) { /* Check for any redirection */
  965.     if(out_flag & REDIR_ACTIVE) { /* If Standard Output has been*/
  966. eprintf(MSG_OUTACTIVE); /* redirected then fail      */
  967. return FAILURE;
  968.     }
  969. #endif
  970.     if(pipe_out) {
  971. #if defined(CDOSTMP)
  972. out_pipe[0] = *SYSDATB(TEMPDISK)+'A'; /* Initialise the DRIVE */
  973. out_pipe[3] = ''; /* Terminate String */
  974. #else
  975. if (!env_scan("TEMP=",out_pipe)) {
  976.     
  977.     /* if TEMP != "d:" check its a valid directory */
  978.     if ((strlen(out_pipe) > 3) || (out_pipe[1] !=':')) {
  979.      h = ms_x_chmod(out_pipe,ATTR_ALL,0);
  980. if ((h<0) || !(h&0x10)) goto assume_root;
  981.     }
  982.     append_slash(out_pipe);
  983. }
  984. else {
  985. assume_root:
  986.     get_out_pipe(); /* get string from low_seg */
  987.     out_pipe[0] = drive+'A'; /* Initialise the DRIVE */
  988.     out_pipe[3] = ''; /* Terminate String */
  989. }
  990. #endif
  991. bpo = out_pipe;
  992. h = ms_x_unique(out_pipe, ATTR_SYS);
  993.     }
  994.     else { /* Create the output file if */
  995. bpo = outfile; /* not Appending or the OPEN */
  996. /* on the file fails.      */
  997. if(!append || (h = ms_x_open(bpo, OPEN_WRITE)) < 0)
  998.     h = ms_x_creat(bpo, 0);
  999.     }
  1000.     if(e_check(h) < 0) { /* Display any error message */
  1001.      if(pipe_out) { /* Pipe'ed command then     */
  1002.     pipe_out = NO; /* absorb the second command*/
  1003.     getcmd(cmdbuf);  /* return FAILURE on error   */
  1004.     crlfflg = YES;
  1005. }
  1006. return FAILURE;
  1007.     }
  1008.     if(append) /* If in APPEND mode then    */
  1009. ms_x_lseek(h, 0L, 2); /* seek to the end.      */
  1010.     psp_poke(STDOUT, psp_poke(h, 0xFF));/* Force New input file onto */
  1011.      /* Standard Ouput and close  */
  1012.     out_flag = REDIR_ACTIVE; /* the returned handle      */
  1013.     if(pipe_out)
  1014. out_flag |= REDIR_PIPE;
  1015. }
  1016. crlfflg = NO;
  1017. return SUCCESS;
  1018. }
  1019. MLOCAL BOOLEAN docmd_offer(BYTE *cp, BYTE *command, UWORD internal_flag)
  1020. {
  1021. BYTE *lcp;
  1022. int i;
  1023. UWORD int2f_gotit = 0;
  1024. lcp = heap();
  1025. lcp[0] = 0x80; /* copy command line to buffer */
  1026. lcp[1] = strlen(cp); /*   with "readline" format */
  1027. for (i=0;i<lcp[1];i++)
  1028.     lcp[i+2]=cp[i];
  1029. lcp[i+2] = 'r';
  1030. /* offer command line to interested parties */
  1031. if(int2f_gotit = docmd_int2f(lcp,command,internal_flag))
  1032.     return 1; /* if they want it, docmd_offer = TRUE      */
  1033. for(i=command[0];i<8;command[1+(i++)]=' ');
  1034. /* if length is altered, space fill */
  1035. for(i=0;i<lcp[1];i++)
  1036.     cp[i] = lcp[i+2]; /* copy it back in case it was changed */
  1037. cp[i] = 0; /* null terminate it */
  1038. return 0; /* docmd_offer = FALSE, cos the int2f didn't want it */
  1039. }
  1040. GLOBAL VOID docmd(cp, internal)
  1041. REG BYTE  *cp; /* Command Line To be Parsed */
  1042. BOOLEAN   internal; /* Search for INTERNAL Commands */
  1043. {
  1044. REG S_CMD FAR *s_cmd_p;
  1045. WORD   i;
  1046. BYTE FAR  *cpf;
  1047. BYTE    loadfile[MAX_FILELEN];
  1048. BYTE   *cp1, *lcp;
  1049. UWORD   loadtype;
  1050. BYTE   argv0[MAX_FILELEN];
  1051. heap_get(0); /* check for stack overflow */
  1052. lcp = cp; /* in case 1st parse fails.. */
  1053.         crlfflg = YES;
  1054. for(i=0;i<12;loadfile[i++]=' '); /* initialise with blanks */
  1055. ms_f_parse(loadfile, cp, 1); /* parse for internal cmd */
  1056. for(i=7;(i>=0) && (loadfile[i+1] == ' '); i--);
  1057. loadfile[0] = i+1; /* set length of cmd */
  1058. for(;strchr(valid_sepchar,*cp);cp++); /* ignore leading separators */
  1059. for(;is_filechar(cp);cp++); /* skip the command itself */
  1060. /* offer command line to */
  1061. /* interested parties */
  1062. if(docmd_offer(lcp,loadfile,0xFF00+strlen(cp))) /* If they want it */
  1063. return; /* we don't */
  1064. cp = lcp;
  1065. if ((cp[0] != 0) && (cp[1] == ':')) cp+=2;
  1066. for(;strchr(valid_sepchar,*cp);cp++);
  1067. for(;is_filechar(cp);cp++); /* skip the command itself */
  1068. cp1 = cp;
  1069. i = 0;
  1070. while (*cp1 != '') {
  1071.     if (*cp1 == '"')
  1072. i ^= 1;
  1073.     if (is_blank(cp1) == 2 && !i) /* replace each KANJI space */
  1074. *cp1 = *(cp1 + 1) = ' '; /* with one ASCII space */
  1075.     cp1 = skip_char(cp1);
  1076. }
  1077. s_cmd_p = (S_CMD FAR *)farptr((BYTE *)&cmd_list[0]);
  1078. while(internal && s_cmd_p->cmnd) { /* while more builtins */
  1079.     cpf = cgroupptr(s_cmd_p->cmnd);
  1080.     for(i=0;cpf[i];i++) /* make upper case copy */
  1081.      argv0[i]=toupper(cpf[i]);
  1082.     for(;i<8;argv0[i++]=' '); /* space fill it to 8 */
  1083.     if(!strncmp(argv0,loadfile+1,8)) { /* Is this a match ? */
  1084. #if !defined(NOHELP)
  1085. /* Handle  /H or /? in command */
  1086. strcpy(heap(),deblank(cp));
  1087. if(!strnicmp(heap(),"/h",2)||!strnicmp(heap(),"/?",2)) {
  1088.     if (s_cmd_p->help_index != -1)
  1089.      show_help(s_cmd_p->help_index);
  1090.     crlf();
  1091.     return;
  1092. }
  1093. #endif
  1094. /* check for embedded commands in IF that only have meaning in
  1095.                  that context */
  1096. if(s_cmd_p->needparm==PARAM_IFCONTEXT) {
  1097.     if(if_context==FALSE) break;
  1098. }
  1099. cp1 = deblank(cp); /* Remove Blanks from Options*/
  1100. if(s_cmd_p->needparm!=PARAM_NONE /* if a parameter is needed */
  1101.    && !*cp1) { /* but none is supplied      */
  1102.     switch ((UWORD)s_cmd_p->needparm) /* display an error message  */
  1103.     {
  1104.     case PARAM_NEEDFILE: eprintf(MSG_NEEDFILE); break;
  1105.     case PARAM_NEEDPATH: eprintf(MSG_NEEDPATH); break;
  1106.     case PARAM_NEEDDEV:  eprintf(MSG_NEEDDEV);  break;
  1107.     default:  eprintf(MSG_SYNTAX);   break;
  1108.     }
  1109.     eprintf("n");
  1110.     return; /* ignore the command      */
  1111. }
  1112. page_len = get_lines_page();    /* so /P works in 43 and 50 */
  1113. /* line modes */
  1114. (*s_cmd_p->func)(cp1, cp); /* Just Invoke builtin      */
  1115. return;
  1116.     }
  1117.     s_cmd_p ++;  /* compare with next command */
  1118. }
  1119. /* it's not an internal command - could it be help ? */
  1120.         if ((!strnicmp(lcp,"/h",2))||(!strncmp(lcp,"/?",2))) {
  1121.             show_help(0);
  1122.     s_cmd_p = (S_CMD FAR *)farptr((BYTE *)&cmd_list[0]);
  1123.     while(s_cmd_p->cmnd) {
  1124.         cpf = cgroupptr(s_cmd_p->cmnd);
  1125.                 printf("%st",cpf);
  1126.         s_cmd_p++;
  1127.     }
  1128.     crlf();
  1129.     return;
  1130. }
  1131. /* command is not builtin, must be disk based so determine path ... */
  1132. if(docmd_offer(lcp,loadfile,strlen(cp))) /* offer command line to */
  1133. return; /* interested parties */
  1134. /* If they want it, we don't */
  1135. cp = get_filename(loadfile, lcp, NO);
  1136. strcpy(argv0, loadfile); /* the original command name */
  1137. strlwr(loadfile);
  1138. if((loadfile[strlen(loadfile)-1] == '\') ||
  1139.    ((strlen(loadfile) == 2) && (loadfile[1] == ':'))) {
  1140.     if(!dos_parse_filename(loadfile) && d_check(loadfile)) {
  1141. if (ddrive != -1)
  1142. {
  1143.     ms_drv_set(ddrive); /* then check the requested */
  1144.     drive = ddrive; /* drive and make it the    */
  1145.     crlfflg = NO; /* default if OK.     */
  1146. }
  1147.     }
  1148.     else {
  1149. eprintf(ERR15);
  1150. crlf();
  1151.     }
  1152.     return;
  1153. }
  1154. if (strcmp(loadfile,"________") == 0) {
  1155. ms_x_first("________.???",ATTR_HID+ATTR_STD,(DTA *) heap());
  1156. strcpy(loadfile,"C:\________.COM");
  1157. }
  1158. else if((i = findfile(loadfile, &loadtype)) < 0) {
  1159.     if(i == ED_FILE || /* Determine the full */
  1160.        i == ED_ROOM ||  /* path and type of the */
  1161.        i == ED_PATH) { /* command and return if*/
  1162.     eprintf(MSG_BADCMD); /* file or command cannot be located */
  1163.     }
  1164.     else {
  1165. e_check(i);
  1166.     }
  1167.     return;
  1168. }
  1169. if(!env_scan(msg_comspec, heap())) /* If COMSPEC is defined   */
  1170.     set_reload_file(); /* then update RELOAD_FILE */
  1171. doexec(argv0, loadfile, loadtype, cp); /* Load the file */
  1172. allow_pexec = TRUE;
  1173. }
  1174. /*
  1175.  * FindFile searches the file system copying the actions of the 
  1176.  * Concurrent DOS P_PATH function. If this is TMP for Concurrent 
  1177.  * DOS then use the system call otherwise use the C function.
  1178.  *
  1179.  * If no extension is specified then check the file types in
  1180.  * the following order .CMD, .COM, .EXE, .BAT
  1181.  *
  1182.  * If a Path is specified then just check that location otherwise
  1183.  * check the current directory and then all entries in the path.
  1184.  */
  1185. #if !defined(CDOSTMP)
  1186. GLOBAL WORD CDECL findfile(loadpath, loadtype)
  1187. BYTE *loadpath; /* Command Name expanded to full path */
  1188. UWORD *loadtype; /* Command file Type */
  1189. {
  1190. REG BYTE *s;
  1191. BYTE sppath[MAX_PATHLEN]; /* Buffer for the optional  */
  1192. /* load path.     */
  1193. BYTE fname[8+1+3+1+8+1]; /* Buffer for the filename */
  1194. /* optional extension and   */
  1195. /* password     */
  1196. BYTE *path; /* Environment Load path    */
  1197. BYTE *ftype;  /* Optional file type     */
  1198. BYTE *pwd; /* Optional Password     */
  1199. BYTE *envpath; /* current PATH= in env     */
  1200. WORD i, ret;
  1201. #if !STACK
  1202. BYTE pathbuf[MAX_ENVLEN]; /* temporary path buffer    */
  1203. #endif
  1204. strip_path(loadpath, sppath); /* isolate the optional path*/
  1205. ftype = loadpath+strlen(sppath); /* get the Filename Address */
  1206. if(strlen(ftype) < sizeof(fname)) /* If the filename is not   */
  1207.     strcpy(fname, ftype); /* too long then copy to an */
  1208. else /* internal buffer otherwise*/
  1209.     longjmp(break_env, IA_FILENAME); /* break with FILENAME error*/
  1210. if((ftype = strchr(fname, '.')) != 0) { /* then extract the optional*/
  1211.     *ftype++ = ''; /* file type from the name  */
  1212.     pwd = ftype;
  1213. }
  1214. else { /* If no type has been     */
  1215.     ftype = NULLPTR; /* specified then make it   */
  1216.     pwd = fname; /* file type a NULL pointer */
  1217. }
  1218. if ((ret = ms_x_open (fname, 0)) > 0) { /* don't exec a device in   */
  1219.     i = isdev (ret); /* any shape or form     */
  1220.     ms_x_close (ret);
  1221.     if (i)
  1222. return (ED_FILE);
  1223. }
  1224. #if defined(PASSWORD)
  1225. if((pwd = strchr(pwd, *pwdchar)) != 0)  /* Finally extract the      */
  1226.     *pwd++ = ''; /* optional password if none*/
  1227. else /* exists then default to a */
  1228.     pwd = NULLPTR; /* NULL pointer.     */
  1229. #endif
  1230. if(ftype) { /* If a file type has been  */
  1231.     for(i=0; ftypes[i]; i++) /* specified then check that*/
  1232. if(!strcmp(ftype, ftypes[i])) /* is legal and return an   */
  1233.     break; /* error if not.     */
  1234.     if(!ftypes[i]) /* If an illegal filetype   */
  1235. return ED_FILE;  /* has been given then     */
  1236. } /* return FAILURE     */
  1237. *loadtype = i; /* Save the Load File Type  */
  1238. /*
  1239.  * Check if a path is currently defined if YES then get
  1240.  * a copy of the path and save locally on the heap. Protecting
  1241.  * it against being overwritten.
  1242.  */
  1243. if(!env_scan(msg_patheq, heap())) {
  1244.     envpath = heap();
  1245.     while (*envpath) { /* process path in env  */
  1246. if(dbcs_lead(*envpath)) /* so delimiters are the */
  1247.     envpath++; /* pathchar we expect  */
  1248. else
  1249.     if((*envpath == '/') || (*envpath == '\'))
  1250. *envpath = *pathchar;
  1251. envpath++;
  1252.     }
  1253. #if STACK
  1254.     envpath = stack(strlen(heap()) + 1);
  1255. #else
  1256.     envpath = &pathbuf[0];
  1257. #endif
  1258.     strcpy(envpath, heap());
  1259. }
  1260. else
  1261.     envpath = "";
  1262. /*
  1263.  * First attempt to load the file from the default/specified
  1264.  * path and then if no path was specified attempt to load the
  1265.  * file from all the entries in the search path defined in the
  1266.  * environment.
  1267.  */
  1268. if(*sppath)
  1269.     path = sppath;
  1270. else
  1271.     path = "";
  1272. do {
  1273.     i = checkfile(loadpath, loadtype, path, fname, ftype, pwd);
  1274.     switch (i)
  1275.     {
  1276.       case SUCCESS:
  1277. strupr(loadpath);
  1278. return SUCCESS;
  1279.       case ED_FAIL:
  1280.       case ED_DRIVE: /* if bad drive in search  */
  1281. if ((!*sppath) && (*path)) /* path, print msg & carry on*/
  1282. {
  1283.     eprintf(MSG_PATHDRV);
  1284.     i = ED_FILE;
  1285.     break;
  1286. }
  1287.       default:
  1288. break; /* get next search path    */
  1289.     }
  1290.     path = envpath; /* Set PATH to the next     */
  1291.     if((s=strchr(envpath, ';')) != 0) { /* element in the search path*/
  1292. while (*s == ';') { /* Skip over extra semicolons*/
  1293.     *s = 0;
  1294.     s++;
  1295. }
  1296. envpath = s;
  1297.     }
  1298.     else
  1299. envpath = ""; /* path exhausted, -> null */
  1300.     /* If you type FILENAME.EXE, it will search the current drive then */
  1301.     /* the path. If you type C:DIRFILENAME.EXE, it will search */
  1302.     /* C:DIR. Now, if you type C:FILENAME.EXE, it will search the */
  1303.     /* current directory on C:, then path. This is done by resetting */
  1304.     /* sppath after the first run through, if it is just D: */
  1305.     if((strlen(sppath) == 2) && (sppath[1] == ':'))
  1306. sppath[0] = '';
  1307. } while(!*sppath && *path);
  1308. return i;
  1309. }
  1310. /*
  1311.  * CHECKFILE generates the full path of the load file and
  1312.  * attempts to open the file. If the file is located and
  1313.  * can successfully be opened return SUCCESS with the full
  1314.  * path in LOADPATH and the LOADTYPE initialised.
  1315.  *
  1316.  * If no file extension has been specified then use the standard
  1317.  * search order.
  1318.  *
  1319.  * ATTR_SEARCH specifies the attributes used to locate the file
  1320.  * to be loaded.
  1321.  */
  1322. #define ATTR_SEARCH ATTR_STD + ATTR_HID
  1323. MLOCAL WORD checkfile(loadpath, loadtype, path, fname, ftype, pwd)
  1324. BYTE *loadpath;
  1325. UWORD *loadtype;
  1326. BYTE *path, *fname, *ftype, *pwd;
  1327. {
  1328. UWORD type;
  1329. WORD ret;
  1330. DTA search;
  1331. BYTE curpath[MAX_PATHLEN+1];
  1332. if((path = d_check(path)) == NULL) /* Remove the drive specifier*/
  1333.     return ED_DRIVE; /* and return on Error.      */
  1334. /* get path starting from root. n.b. don't use ms_x_expand (func 60h)   */
  1335. /* as it upsets Novell      */
  1336. if (ddrive != -1)
  1337. {
  1338.     sprintf(loadpath, "%c:%c", ddrive + 'A', *pathchar);
  1339.     if((*path == '\') || (*path == '/'))  /* If path is absolute then */
  1340. strcpy(loadpath+2, path);    /* just append to drive     */
  1341.     else {    /* Otherwise append the     */
  1342. ms_x_curdir(ddrive+1, loadpath+3); /* path to the drive and    */
  1343. if(*fptr(loadpath))    /* current subdirectory.    */
  1344.     append_slash(loadpath);
  1345. strcat(loadpath, path);
  1346.     }
  1347. }
  1348. else
  1349.     ms_x_expand(loadpath,path);
  1350. if(*fptr(loadpath))
  1351.     append_slash(loadpath);
  1352. strcat(loadpath, fname); /* Add the FileName      */
  1353. strcat(loadpath, ".");
  1354. path = loadpath + strlen(loadpath); /* Save the Extension Offset */
  1355. #if defined(PCDOS)
  1356. /*
  1357.  * If running under PCDOS the check if any extension has been specified
  1358.  * if not then search first for filename.* and return if no match occurs
  1359.  * This will be quicker than opening each file in turn.
  1360.  */
  1361. if(!ftype) {
  1362.     strcat(path, "*");
  1363.     if((ret = ms_x_first(loadpath, ATTR_SEARCH, &search)) < 0) {
  1364. if( ret == ED_FILE ||     /* Abort if an error occurs     */
  1365.     ret == ED_ROOM ||     /* but ignore File not Found    */
  1366.     ret == ED_PATH)     /* and invalid path errors     */
  1367.     return ED_FILE;
  1368. else
  1369.     return e_check(ret);
  1370.     }
  1371. }
  1372. #endif
  1373. if (ftype == 0)
  1374.     type = COM_FILETYPE; /* Initialize the Type Index */
  1375. else /* correctly depending on the */
  1376.     type = *loadtype; /* initial file type. */
  1377. do {
  1378.     strcpy(path, ftypes[type]); /* Add the first file type  */
  1379. #if defined(PASSWORD)
  1380.     if(pwd) { /* followed by the optional */
  1381. strcat(path, pwdchar); /* password and attempt to  */
  1382. strcat(path, pwd); /* open the file.     */
  1383.     }
  1384. #endif
  1385.     if((ret = ms_x_first(loadpath, ATTR_SEARCH, &search)) < 0) {
  1386. if(ret == ED_PATH) /* Stop scanning this    */
  1387.     return ED_FILE; /* element of the path if  */
  1388. /* it is invalid.    */
  1389. #if 0
  1390. if(ret != ED_FILE && ret != ED_ROOM)
  1391.     return ret;
  1392. #endif
  1393.     }
  1394.     else {
  1395. *loadtype = type; /* Set the correct loadtype */
  1396. return SUCCESS; /* and return SUCCESS     */
  1397.     }
  1398.     if (++type > BAT_FILETYPE)
  1399. #if defined(DOSPLUS) || defined(NETWARE)
  1400. type = COM_FILETYPE;
  1401. #else
  1402. type = CMD_FILETYPE;
  1403. #endif
  1404. } while(!ftype && (type != COM_FILETYPE));
  1405. return ED_FILE;
  1406. }
  1407. #endif
  1408. MLOCAL BOOLEAN doexec(argv0, loadpath, loadtype, tail)
  1409. BYTE *argv0; /* Invoking Command */
  1410. BYTE *loadpath; /* Fully expanded filename */
  1411. UWORD loadtype; /* File Type .BAT, .EXE etc. */
  1412. BYTE *tail; /* Command line options */
  1413. {
  1414. WORD ret;
  1415. WORD i;
  1416. BYTE *s;
  1417. #if !STACK
  1418. BYTE tailbuf[128];
  1419. #endif
  1420. #if 0
  1421. printf("DOEXEC Load File "%s" Command Line "%s"n",
  1422. loadpath, (tail ? tail : ""));
  1423. #endif
  1424. if(loadtype == BAT_FILETYPE) {     /* if Batch file then:-      */
  1425.     
  1426.     if (batchflg == 0) echoflg_save2 = echoflg;
  1427.     
  1428.     ret = echoflg;     /* Save the Current ECHO State   */
  1429.     batch_end();     /* Close any Existing Batch file */
  1430.     echoflg = ret;     /* restore the ECHO status      */
  1431.     batch_start(argv0, loadpath, tail); /* and initialize the new batch  */
  1432.     return YES;      /* use "CALL" to nest batches.   */
  1433. }
  1434. /* if CMD, COM or EXE      */
  1435. if(batchflg) /* close the BATCH file if OPEN cos  */
  1436.     batch_close(); /* some programs update the running  */
  1437. /* batch file.      */
  1438. s = deblank(tail); /* No SPACE before options   */
  1439. if(!*s) /* if this is a blank line   */
  1440.     tail = s;
  1441. #if defined(CDOSTMP)
  1442. ret = exec(loadpath, loadtype, tail, back_flag);
  1443. #else
  1444. ms_set_break(break_flag);
  1445. #if STACK
  1446. s = stack(strlen(tail)+2)+1;
  1447. #else
  1448. s = &tailbuf[1];
  1449. #endif
  1450. tail = strcpy(s, tail) - 1;
  1451. *tail = (UBYTE) strlen(tail+1);
  1452. strcat(tail+1, "r");
  1453. #if !defined(FINAL)
  1454. save_psp();
  1455. #endif
  1456. ret = exec(loadpath, loadtype, tail, back_flag);
  1457. #if !defined(FINAL)
  1458. check_psp();
  1459. #endif
  1460. init_switchar(); /* switch character may have changed */
  1461. break_flag = ms_set_break(YES);
  1462. #endif
  1463. /*
  1464.  * Novell use the MS_DRV_GET function to detect abnormal
  1465.  * program termination. They assume this function is only
  1466.  * called by the command processor when a child has terminated.
  1467.  * They close all Remote Handles when the parent command
  1468.  * processor calls this function.
  1469.  */
  1470. drive = ms_drv_get();   /* get default drive.      */
  1471. for (i=5;i<20;i++) ms_x_close(i); /* Close all handles */
  1472. if(ret < 0) { /* Get the returned Error Code */
  1473. #if defined(CDOS) || defined(CDOSTMP)
  1474.     if(ret == ED_ENVIRON) /* Check for an Environment */
  1475. ret = (-255); /* error this is really  */
  1476. #endif /* a resource unavailable. */
  1477. /* Print a message if the exec */
  1478.     e_check(ret); /* went wrong otherwise get the */
  1479. /* completion status and return */
  1480.     return FAILURE;
  1481. }
  1482. err_ret = ms_x_wait();
  1483. return YES;
  1484. }
  1485. #if !defined(CDOSTMP)
  1486. VOID FAR CDECL int2e_handler (cmd)
  1487. BYTE *cmd;
  1488. {
  1489. BYTE *p;
  1490. jmp_buf save_jmpbuf;
  1491. /* save the normal setjmp environment and reset it to ourselves */
  1492. /* so that the int2e caller does not get aborted on criterr or */
  1493. /* Control break */
  1494.     memmove (&save_jmpbuf, &break_env, sizeof (jmp_buf));
  1495.     if (setjmp (break_env) == 0) {
  1496. if ((p = strchr (cmd, 0xd)) != NULL)
  1497.     *p = ''; 
  1498. int2e_start();
  1499. docmd (deblank (cmd), TRUE);
  1500. /* if int2e is executing a batch file, do not return until all */
  1501. /* batch file commands have been processed. Loop round as in main */
  1502. /* loop */
  1503. while (batchflg > 0)
  1504. {
  1505.     cmd_loop (cmd);
  1506. }
  1507. int2e_finish();
  1508.     }
  1509.     memmove (&break_env, &save_jmpbuf, sizeof (jmp_buf));
  1510. }
  1511. MLOCAL VOID init_switchar()
  1512. {
  1513. *switchar = ms_switchar(); /* get switch character      */
  1514. if (*switchar == '/') /* if not UNIX path char     */
  1515.     *pathchar = '\'; /*   then be compatible      */
  1516. else
  1517.     *pathchar = '/';
  1518. }
  1519. #endif
  1520. #if defined(DOSPLUS)
  1521. GLOBAL VOID process_config_env()
  1522. {
  1523. BYTE FAR *config_env;
  1524. WORD i;
  1525. BYTE buff[128];
  1526. BYTE *s;
  1527. config_env = get_config_env();
  1528. if (config_env) {
  1529. FOREVER {
  1530. i = 0;
  1531. while ((*config_env) && (*config_env!=0x1A) && 
  1532.        (i < 127)) {
  1533. buff[i++] = *config_env++;
  1534. }
  1535. if (i == 0) {
  1536.    while (*config_env != 0x1A) config_env++;
  1537.    config_env++;
  1538.    boot_key_scan_code = * ((UWORD far *) config_env);
  1539.    break;
  1540. }
  1541. buff[i] = 0;
  1542. cmd_set(buff);    
  1543.      while (*config_env) config_env++;
  1544. config_env++;
  1545. }
  1546. #if 0
  1547. s = heap();
  1548. if (!env_scan("HOMEDIR=",s)) {
  1549. if (s[1] == ':') ms_drv_set(toupper(*s)-'A');
  1550. ms_x_chdir(s);
  1551. }
  1552. #endif
  1553. }
  1554. }
  1555. #endif
  1556. #if !defined(FINAL)
  1557. void save_psp()
  1558. {
  1559. BYTE far *fp;
  1560. WORD i;
  1561. fp = MK_FP(_psp,0);
  1562. psp_xsum = 0;
  1563. for  (i=64;i<128;i++) psp_xsum += fp[i];
  1564. }
  1565. void check_psp()
  1566. {
  1567. BYTE far *fp;
  1568. WORD xsum;
  1569. WORD i;
  1570. fp = MK_FP(_psp,0);
  1571. xsum = 0;
  1572. for (i=64;i<128;i++) xsum += fp[i];
  1573. if (xsum != psp_xsum) {
  1574.     printf("BETA DEBUG ERROR: Need more stack!n");
  1575.     printf("Press a key to continue.n");
  1576.     getch();
  1577. }
  1578. }
  1579. #endif