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

操作系统开发

开发平台:

Asm

  1. /*
  2. ;    File              : $Workfile: BATCH.C$
  3. ;
  4. ;    Description       :
  5. ;
  6. ;    Original Author   : DIGITAL RESEARCH
  7. ;
  8. ;    Last Edited By    : $CALDERA$
  9. ;
  10. ;-----------------------------------------------------------------------;
  11. ;    Copyright Work of Caldera, Inc. All Rights Reserved.
  12. ;      
  13. ;    THIS WORK IS A COPYRIGHT WORK AND CONTAINS CONFIDENTIAL,
  14. ;    PROPRIETARY AND TRADE SECRET INFORMATION OF CALDERA, INC.
  15. ;    ACCESS TO THIS WORK IS RESTRICTED TO (I) CALDERA, INC. EMPLOYEES
  16. ;    WHO HAVE A NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF
  17. ;    THEIR ASSIGNMENTS AND (II) ENTITIES OTHER THAN CALDERA, INC. WHO
  18. ;    HAVE ACCEPTED THE CALDERA OPENDOS SOURCE LICENSE OR OTHER CALDERA LICENSE
  19. ;    AGREEMENTS. EXCEPT UNDER THE EXPRESS TERMS OF THE CALDERA LICENSE
  20. ;    AGREEMENT NO PART OF THIS WORK MAY BE USED, PRACTICED, PERFORMED,
  21. ;    COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, ABRIDGED,
  22. ;    CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST,
  23. ;    TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF
  24. ;    CALDERA, INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT
  25. ;    AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO CRIMINAL AND
  26. ;    CIVIL LIABILITY.
  27. ;-----------------------------------------------------------------------;
  28. ;
  29. ;    *** Current Edit History ***
  30. ;    *** End of Current Edit History ***
  31. ;
  32. ;    $Log$
  33. ;    ENDLOG
  34. */
  35. /*
  36.  * 27 Oct 87 Improve GOTO command to ignore trailing white space, only
  37.  * match on the first 8 characters and only allow valid
  38.  * filename characters.
  39.  * 28 Oct 87 Correct duplicate prompt display when a batch file label
  40.  * is read and the echo flag is ON.
  41.  *  9 Nov 87 Change Batch file termination so that Output Redirection is
  42.  * correctly handled.
  43.  * 13 Jan 88 If prompt display is aborted because of a critical error
  44.  * the following prompt will be forced to "$n$g".
  45.  * 25 Jan 88 Support redirection on the FOR command correctly
  46.  * 24 Feb 88 Generate batch file parameter %0 correctly as WS200 install
  47.  * requires that the drive specifier be present. Garry Silvey
  48.  *  5 May 88 Batch paramater %0 is now a copied from the invoking command
  49.  * line.
  50.  * 18 May 88 Support the ESC_CHAR in the command line.
  51.  * 20 May 88 Disable MULTI_CHAR support in DOSPLUS when the user enters the
  52.  * first command.
  53.  * 26 May 88 Added STACK switch and support $q in prompt.
  54.  * 27 May 88 Added string undefs.
  55.  *  6 Jun 88 Call resident portion to do readline (SideKick+ problem)
  56.  * 23 Jun 88 Support CR only delimited batch files and if errorlevel ==
  57.  * syntax used in installation files.
  58.  *  6 Jul 88 Support the FOR ... CALL syntax correctly. (IMS)
  59.  * 17 Aug 88 Jump to labels followed by comments (Ashton Tate By-Line)
  60.  * 21 Sep 88 Use KEYIN_FLG to allow the default ECHO state to be ON.
  61.  * 16 Nov 88 Disable BACK_CHAR in Concurrent DOS.
  62.  * 21 Dec 88 Allow leading whitespace before labels
  63.  *  5 Jan 89 Support Quoted strings in Batch files.
  64.  * 18 Apr 89 Support Quoted strings in IF command
  65.  * 19 Apr 89 Quotes in IF command: "x == "x" parses, "x=x" == "x.. doesn't
  66.  * 24 Apr 89 Increase MAX_LINE to 128 for pctools ver 5
  67.  * 19 May 89 Take out support for quoted strings in IF command
  68.  * 05 Jun 89 Do not echo command or display the prompt during FOR command.
  69.  * Restore support for batch files with long lines.
  70.  * 02 Nov 89 batch_line bodge which substitutes 0xFF for 0x00 changed - we
  71.  * now substitute 'rn', then throw away rest of the line.
  72.  * 01 Dec 89 batch_line - trailing % at end of line is discarded
  73.  * 15 Dec 89 "if errorlevel -1" allowed
  74.  * 30 Jan 90 Added int2e_start and int2e_finish to save and restore
  75.  * important batch file variables to allow novell menu program
  76.  * to use int 2e to invoke batch files.
  77.  * 30 Jan 90 Forced batch data structures to appear on segment boundaries;
  78.  * Added dummy memory descriptor before batch structure;
  79.  * Put segment address of batch structure in batch_seg_ptr;
  80.  * All so novell can find and patch the drive letter of
  81.  * autoexec.bat during a remote boot.
  82.  *  6-Mar-90 Watcom C v 7.0
  83.  *  7-Mar-90 allow ESC_CHAR through unless followed by MULTI/BACK_CHAR
  84.  * 14-Mar-90 Reduce batch_buf to 32 bytes like wot dos is
  85.  * 20-Mar-90 Batch structures allocated by mem_alloc (ie. MS_M_ALLOC)
  86.  * rather than on heap. Batch file nesting no longer heap limited.
  87.  * 27-Mar-90 Allow "=", "==", "===" etc in "if errorlevel==n"
  88.  * 10-Apr-90 Make errorlevel 999 same as errorlevel 231 (mod 256)
  89.  *  8-May-90 Don't echo getcmd unless batch file (eg. "dir|more" shouldn't
  90.  * echo "C:>more")
  91.  * 23-May-90 batch_read no longer repeatedly deblanks line (which leads
  92.  * to the buffer happily wandering up memory).
  93.  * 30-May-90 "if ab de==ef" form doesn't generate syntax error
  94.  * 13-Jun-90 batch_line rejects unmatched "|" as syntax error
  95.  * 20-Sep-90 is_filechar() and is_pathchar() now take pointer instead of byte
  96.  * Changed batch_char() to return pointer instead of byte,
  97.  * renamed to batch_ptr().
  98.  * Amended make_label(), batch_start() and cmd_for() to check for
  99.  * DBCS lead bytes.
  100.  * 24-Sep-90 Add $m and $u option to PROMPT to display status of mail
  101.              and user name respectively
  102.  * 27-Sep-90 Add IF USERID <userid> COMMAND
  103.                        IF LOGINNAME <loginname> COMMAND
  104.                        IF GROUPNAME <groupname> COMMAND 
  105.                        IF ASK ["string"] <char> COMMAND
  106.                        .. AND .. OR .. to IF processing
  107.                        INPUT ["string"] <environment-variable>
  108.                        INPUTC ["string"] <environment-variable>
  109.  * 10-Oct-90 inherit batch files from TMP when TSR auto-loads CDOS.COM
  110.   (a bodge for Stellar)
  111.  * 25-Oct-90 inherit echoflg from TMP when TSR auto-loads CDOS.COM
  112.  * 31-Oct-90 change IF ASK command to IF KEY command
  113. DRDOS BUXTON
  114. ------------
  115.  * 25-Apr-91 '!' is now ignored during COMMAND /C processing.
  116.  * 28-May-91 leading white space is now ignored before labels.
  117.  * 09-Jun-91 Added GOSUB, RETURN and SWITCH commands.  
  118.  * 24-Jul-91 if batch_seg_ptr is poked to zero all batch processing is
  119.    terminated.
  120.  * 26-Jul-91 batch files are now read into a far buffer. This avoids
  121.    reading directly to seg FFFF if we happen to be there and so
  122.  solves some NOVELL problems.
  123.  * 18-Jun-92 Support ? in batch files as in config.sys.
  124.  * 23-Jun-92 $u in prompt causes LOGINNAME in environment to be displayed.
  125.  * 07-Jul-92 IF EXIST now finds hidden files. 
  126. */
  127. #include "defines.h"
  128. #include <string.h>
  129. #if defined(MWC) && defined(strlen)
  130. #undef strcmp /* These are defined as macros in string.h */
  131. #undef strcpy /* which are expanded in line under */
  132. #undef strlen /* Metaware C. These undefs avoid this. */
  133. #endif
  134. #include <portab.h>
  135. #if !defined(DOSPLUS)
  136. #include <ccpm.h>
  137. #endif
  138. #include "command.h"
  139. #include "toupper.h"
  140. #include "support.h"
  141. #include "dosif.h"
  142. #include "global.h"
  143. #include "dos.h"
  144. #include <setjmp.h>
  145. /*RG-01*/
  146. #if defined(CDOSTMP) || defined(CDOS)
  147. #include    <pd.h>
  148. #define PATH_LEN     65  /* max path length (null terminated) */
  149. EXTERN PD FAR * CDECL pd; /* Far pointer to Current PD */
  150. EXTERN VOID CDECL cmd_set(BYTE *);             /* COMINT.C */
  151. #if !defined (NOSECURITY) 
  152. #include    "security.h"
  153. #include    "login.h"
  154. #endif
  155. #endif
  156. /*RG-01-end*/
  157. EXTERN VOID CDECL cmd_pause();
  158. EXTERN BOOLEAN parse(BYTE *);
  159. EXTERN UWORD boot_key_scan_code; /* in COM.C */
  160. /*RG-03*/
  161. BOOLEAN if_context=FALSE;
  162. BOOLEAN ifcond=FALSE;
  163. /*RG-03-end*/
  164. EXTERN jmp_buf break_env;
  165. #define MAX_LINE 128 /* Maximum No of Chars in input line */
  166. #if defined(CPM)
  167. EXTERN UWORD user; /* USER Number variable for CPM.EXE */
  168. #endif
  169. EXTERN BYTE msg_prmeq[]; /* Static Environ String "PROMPT=" */
  170. #if 0
  171. #define FCONTROL struct fcc
  172. MLOCAL FCONTROL {
  173. BOOLEAN  sflg; /* FOR File Search Flag  */
  174. DTA  search; /* FOR Search structure  */
  175. BYTE  *files; /* FOR File list */
  176. BYTE  *cmd; /* FOR Command Line */
  177. BYTE  forvar; /* FOR variable char */
  178. };
  179. #endif 
  180. MLOCAL FCONTROL *forptr;
  181. #if 0
  182. #define BCONTROL struct bcc
  183. GLOBAL BCONTROL {
  184. BCONTROL FAR *bcontrol; /* Previous Batch Control Structure  */
  185. BOOLEAN  eof; /* End of File Flag      */
  186. LONG  offset; /* Offset in BATCH file       */
  187. LONG  ret_offset[4]; /* return offset from gosub          */
  188. BYTE  *batcmd; /* Batch File Input parameters      */
  189. UWORD  batshift; /* Shift Offset       */
  190. BYTE  batfile[MAX_PATHLEN]; /* Batch File Name      */
  191. UWORD  stream; /* Stream for this Batch File      */
  192. FCONTROL *fcontrol; /* Pointer to previous FOR command   */
  193. BYTE  *heap_start; /* Heap pointer before extra bytes   */
  194. WORD  heap_size; /* are added to shift to segment     */
  195. BYTE     save_area[1]; /* boundary. - EJH      */
  196. } FAR *batch, FAR *batch_save; /* Master Batch Control Stucture     */
  197. #endif
  198. /* Handle 255 is closed */
  199. #define CLOSED 0xff
  200. /* Keyboard  Variables */
  201. GLOBAL BYTE kbdbuf[MAX_LINE+2]= {0};/* Keyboard Input Buffer      */
  202. GLOBAL BYTE *kbdptr = kbdbuf+2; /* Keyboard Buffer Pointer      */
  203. MLOCAL BOOLEAN keyin_flg = FALSE; /* This flag is set to TRUE when the */
  204. /* initial command line buffer setup */
  205. /* by INIT() has been exhausted.     */
  206. MLOCAL WORD batchflg_save; /* Used during INT 2E handling.      */
  207. MLOCAL WORD echoflg_save; /* ditto above                       */
  208. GLOBAL WORD echoflg_save2; /* saves echo state when batch file  */
  209. /* execed.      */
  210. /*
  211.  * Batch file buffering control structures.
  212.  */ 
  213. MLOCAL LONG batch_off; /* Offset of buffered data in File */
  214. MLOCAL WORD batch_cnt = 0; /* Number of bytes in buffer    */
  215. MLOCAL BYTE batch_buf[32];
  216. MLOCAL BYTE batch_eof[] = "x1a"; /* End of file string */
  217. MLOCAL BYTE batch_sep[] = "t ;,="; /* Batch Command line option delimiters */
  218. EXTERN VOID CDECL cmd_ver(BYTE *); /* COMINT.C Display Version */
  219. EXTERN VOID docmd(BYTE *, BOOLEAN); /* COM.C     */
  220. EXTERN VOID CDECL int_break(VOID); /* COM.C     */
  221. GLOBAL BOOLEAN getcmd(BYTE *);
  222. GLOBAL VOID for_end();
  223. GLOBAL VOID batch_start(BYTE *, BYTE *, BYTE *);
  224. GLOBAL VOID batch_end(VOID);
  225. GLOBAL VOID batch_close(VOID);
  226. MLOCAL VOID for_in(BYTE *);
  227. MLOCAL WORD batch_open(VOID);
  228. MLOCAL VOID batch_read(BYTE *, BOOLEAN);
  229. MLOCAL VOID batch_line(BYTE *, BOOLEAN);
  230. MLOCAL BYTE *batch_ptr(VOID);
  231. MLOCAL VOID prompt(VOID);
  232. MLOCAL BOOLEAN novell_extension(BYTE *, BYTE *);
  233. #if !defined(CDOSTMP)
  234. EXTERN UWORD FAR *batch_seg_ptr; /* For novell remote boot. see CSTART.ASM */
  235. #endif
  236. #if defined(CDOS) || defined(CDOSTMP)
  237. #define TmpPspEchoFlgPtr 0x58 /* Magic location to keep echo flag */
  238. #define TmpPspDataSeg 0x5a /* Magic location to keep Data Seg */
  239. #define TmpPspBatchSeg 0x5c /* Magic location to keep Batch Ptr */
  240. #define TmpPspMpad 0x5e /* Magic location to keep unlinked MPAD */
  241. #endif
  242. #if defined(CDOS)
  243. typedef struct _mpad
  244. {
  245. UWORD link; /* address of next MPAD */
  246. UWORD start; /* seg of allocation unit */
  247. UWORD length; /* length in paras */
  248. UWORD res0x06; /* reserved */
  249. UWORD xios; /* Process id */
  250. } MPAD;
  251. GLOBAL VOID inherit_TMP_state(VOID);
  252. #endif
  253. /*.pa*/
  254. GLOBAL BOOLEAN getcmd(line) /* read command line */
  255. BYTE *line;
  256. {
  257. BYTE *s;
  258. BOOLEAN quote = FALSE;
  259. BOOLEAN cancel_prompt = FALSE;
  260. #if defined(DOSPLUS)
  261. WORD i;
  262. BYTE cmd_name[16];
  263. #endif
  264. back_flag = FALSE; /* Disable BackGround Processing*/
  265. *line = '';
  266. FOREVER {
  267.     if(for_flag) { /* If Processing a FOR command */
  268. for_in(line); /* then call then use the FOR_IN*/
  269. return NO;   /* routine to fill the keyboard */
  270.     } /* buffer and then return */
  271.     if(!batchflg) /* If no batch processing then  */
  272.         break; /* skip further tests */
  273. batch_restart:
  274.     
  275. #if defined(DOSPLUS)
  276.     if (!*batch_seg_ptr) { /* if batch_seg_ptr has been set to */
  277.      batch_endall(); /* zero terminate all batch files   */
  278. return NO;
  279.     }
  280. #endif
  281.     
  282.     if(batchflg && batch->eof) {  /* Close the batch file if at */
  283. batch_end();   /* the end of the file. */
  284.         if(batchflg == 0)   /* BREAK if batch processing */
  285.    return NO;   /* is complete.  */
  286.         continue;
  287.     }     
  288.     if(!batch_open()) /* Open the file and read a line*/
  289. return YES; /* from the file */
  290.     batch_read(line, NO); /* Read Line */
  291.     if(batch->eof) /* If the end of the batch file */
  292.         batch_close(); /* has been detected then close */
  293. /* the file. */
  294.     if (*line == '?' || boot_key_scan_code == 0x4200) {
  295.         optional_line(line);
  296.     }
  297.     if(*line == '@') { /* If first character in the */
  298. strcpy(line, line+1); /* command line is '@' donot */
  299. return NO; /* echo the command and move the*/
  300.     } /* string down 1 character. */
  301.     if (!cancel_prompt) {
  302. if(crlfflg && echoflg)
  303.     crlf();
  304. prompt();
  305.     }
  306.     return echoflg;
  307. }
  308. if(!*kbdptr) { /* Set the Keyboard Input flag  */
  309.     keyin_flg = TRUE; /* after a initial command line */
  310. /* buffer has been exhausted */
  311. #if 1
  312.     if (c_option) { /* insert an EXIT command if we */
  313. kbdptr = &kbdbuf[2];    /* are processing a /C command  */
  314. strcpy(&kbdbuf[2],"exit");
  315.      }
  316. #endif
  317. }
  318. if (!*kbdptr) { /* Check for existing line      */
  319. /* NEIL */
  320.     if(crlfflg && echoflg)
  321. crlf();
  322. /* NEIL end */
  323.     prompt(); /* issue command line prompt */
  324.     allow_pexec = FALSE;
  325.     /* $x in prompt string may cause batchflg to be set. */
  326.     /* If so we must jump to batch processing code.  */
  327.     if (batchflg) {
  328.      cancel_prompt = TRUE;
  329. goto batch_restart;
  330.     }
  331.     
  332.     kbdptr = ""; /* Force KBDPTR to point to ''*/
  333. /* in case we get ABORTED and */
  334. /* drop through here again. */
  335.     kbdbuf[0] = MAX_LINE; /* set max. input length */
  336.     kbdbuf[kbdbuf[1]+2] = 'r'; /* Terminate current line. */
  337. #if defined(CDOSTMP)
  338.     system(C_READSTR, kbdbuf); /* read a line */
  339. #else
  340.     readline(kbdbuf);
  341. #endif
  342.     crlf();
  343.     
  344.             kbdbuf[kbdbuf[1] + 2]=''; /* terminate input */
  345.     kbdptr = kbdbuf + 2;
  346. }
  347. s = kbdptr;
  348. while(*s) {
  349.     if(*s == '"') /* Check for a " character and  */
  350. quote = !quote;  /* update the flag correctly */
  351. #if !defined(DOSPLUS)
  352.     if(*s == ESC_CHAR && /* If the Escape character has  */
  353.        !quote && /* been specified then do not */
  354.        ((*(s+1) == MULTI_CHAR) || (*(s+1) == BACK_CHAR))) {
  355. *line++ = *++s; /* process the following char. */
  356. s++;
  357. continue;
  358.     }
  359. #endif
  360. #if defined(DOSPLUS) /* Disable MULTI_CHAR support   */
  361.     if(!(keyin_flg||c_option||k_option))
  362.      /* after the init command line  */
  363. #endif /* has been exhausted. */
  364.         if(*s == MULTI_CHAR && /* If a Multiple command char */
  365.         !quote) { /* and the QUOTE flag is FALSE */
  366.     s++; /* then break the command here */
  367.     break; /* and save the rest of the line*/
  368.         } /* for next time. */
  369. #if FALSE /* defined(CDOSTMP) */
  370.     if(*s == BACK_CHAR && /* If a Back Ground processing */
  371. !quote) { /* and the QUOTE flag is FALSE */
  372. s++; /* then treat as for MULTI_CHAR */
  373. back_flag = TRUE; /* except that the current      */
  374. break; /* command is executed in the   */
  375.     } /* background. */
  376. #endif
  377.     if(*s == PIPE_CHAR && /* If a Pipe enable character */
  378. !quote) { /* and the QUOTE flag is FALSE */
  379. s++; /* then break the command here */
  380. pipe_out = YES;  /* and save the rest of the line*/
  381. break; /* for next time. */
  382.     }
  383.     copy_char(&line, &s); /* Just save the character */
  384. }
  385. *line = ''; /* Terminate the Buffer  */
  386. kbdptr = deblank(s); /* Copy the possibly null length*/
  387. return NO;   /* string to KBDBUF for next    */
  388. /* next invocation and save CCP */
  389. }
  390. MLOCAL VOID for_in(line)   /* A FOR command is currently */
  391. BYTE *line;  /* executing so build the line */
  392. { /* from the internal FOR data */
  393. BYTE *s,*t; /* initialized by CMD_FOR */
  394. BYTE *bp1, *fp;
  395. WORD i;
  396. FOREVER {
  397.     fp = forptr->files;  /* Get the next string and stop     */
  398.     if(strlen(fp) == 0) { /* if its the zero length string    */
  399. *line = ''; /* which marks the end of the FOR   */
  400. crlfflg = YES; /* search list.      */
  401. for_end();
  402. return;
  403.     }
  404.     if(!iswild(fp)) { /* If not an ambiguous file  */
  405. forptr->sflg = NO; /* then update the FOR      */
  406. forptr->files += strlen(fp)+1; /* pointer to the next file  */
  407. break; /* in the search list.      */
  408.     }
  409.     if(forptr->sflg) /* Search for the next file  */
  410. i = ms_x_next(&forptr->search); /* file on the disk if      */
  411.     else /* FOR_SFLG otherwise get first */
  412. i = ms_x_first(fp, ATTR_RO, &forptr->search);
  413.     if(i < 0) {  /* If the search failed      */
  414. forptr->sflg = NO; /* then update the FOR      */
  415. forptr->files += strlen(fp)+1; /* pointer to the next file  */
  416. continue; /* in the search list.      */
  417.     } /* and get the next  entry   */
  418.     fp = (BYTE *) heap();
  419.     strip_path(forptr->files, fp); /* Extract the Path      */
  420.     strcat(fp, forptr->search.fname); /* and then add the matching */
  421.     forptr->sflg = YES;  /* filename and update the   */
  422.     strupr(fp);  /* variables.      */
  423.     break; /* Force name to uppercase   */
  424. }
  425.   s = forptr->cmd;
  426.   t = line;
  427.   while (*s && (t - line) < MAX_LINE) { /* Copy the command   */
  428.       if(*s == '%' && *(s+1) == forptr->forvar) { /* line looking for  */
  429.   s += 2;  /* the imbedded %c and insert*/
  430.   bp1 = fp; /* the current substition    */
  431.   while(*bp1 && (t - line) < MAX_LINE) /* string pointed at by FP   */
  432.       copy_char(&t, &bp1);
  433.   continue;
  434.       }
  435.  
  436.       copy_char(&t, &s);
  437.   }
  438.  
  439.   *t = '';   /* and terminate the string */
  440. }
  441. /*.pa*/
  442. /*
  443.  * BATCH FILE CONTROL ROUTINES
  444.  * ===========================
  445.  *
  446.  * The following routines provide the interface from COMMAND.COM to
  447.  * a batch file. BATCH_START sets up all the local variables to enable
  448.  * batch processing while BATCH_END terminates batch processing. BATCH_READ
  449.  * reads a line of data from the batch file and expands it to contain the
  450.  * command line variables and variables from the environment.
  451.  */
  452. GLOBAL VOID batch_start(argv0, path, tail)
  453. BYTE *argv0; /* Invoking Command */ 
  454. BYTE *path; /* Complete filename */
  455. BYTE *tail; /* Command Line Options */
  456. {
  457. BYTE *s2;
  458. BYTE dirbuf[MAX_PATHLEN];
  459. WORD i;
  460. if(batchflg) /* If a batch file is currently */
  461.     batch_close(); /* close it. So minimum number */
  462. /* of handles are used.  */
  463. s2 = path; /* Save the original Path */
  464. if((path = d_check(path)) == NULL)  /* Check that the file */
  465.     return;     /* exists. */
  466. batch_new(); /* new incarnation of batch */
  467. forptr = (FCONTROL *) NULL; /* Disable current FOR control */
  468. for_flag = NO; /* and Global FOR flag */
  469. /*
  470.  * Generate the full path specification for the batch file
  471.  * and store in the batch control information. If the user
  472.  * has specified the full path use it otherwise determine the
  473.  * full path using ms_x_curdir.
  474.  */
  475. if (ddrive != -1 && *path != *pathchar) {
  476.     ms_x_curdir(ddrive+1, dirbuf);
  477.     sprintf(heap(), "%c:%s%s%s%s", ddrive + 'A',
  478.  pathchar,
  479.  dirbuf,
  480.  (*dirbuf ? pathchar : ""),
  481.  path);
  482. }
  483. else if (ddrive != -1)
  484.     sprintf(heap(), "%c:%s", ddrive + 'A', path);
  485. else
  486.     ms_x_expand(heap(), path);
  487. for (i=0; i<MAX_PATHLEN; i++) /* save the batch pathname */
  488.     batch->batfile[i] = heap()[i];
  489. batch->batfile[MAX_PATHLEN-1] = 0;
  490. /*
  491.  * Copy the invoking command and the individual elements
  492.  * of the command line into a buffer ready for processing
  493.  */
  494. batch->batcmd = (BYTE *)heap(); /* Initialize Parameter Buffer */
  495. strcpy(heap(), argv0); /* Copy the invoking command */
  496. heap_get(strlen(heap())+1); /* and protect the buffer */
  497. while(*tail) { /* While there are command line */
  498.     s2 = (BYTE *)heap(); /* parameters copy them  */
  499.     while(*tail && strchr(batch_sep, *tail))
  500. tail = skip_char(tail);
  501.     while(*tail && !strchr(batch_sep, *tail))
  502. copy_char(&s2, &tail);
  503.     *s2++ = '';
  504.     heap_get(strlen(heap()) + 1);
  505. }
  506. *(WORD *)heap_get(2) = 0; /* Double NULL is a terminator  */
  507. /* for command line params  */
  508. if(in_flag & REDIR_ACTIVE) /* If Input redirection has been */
  509.     in_flag |= REDIR_BATCH; /* enabled for this command force*/
  510. /* it on for the complete command*/
  511. if(out_flag & REDIR_ACTIVE) /* If Output redirection has been*/
  512.     out_flag |= REDIR_BATCH; /* enabled for this command force*/
  513. /* it on for the complete command*/
  514. batchflg++; /* increment batch flag */
  515. crlfflg  = YES; /* print CR/LF after this  */
  516. }
  517. GLOBAL VOID batch_endall() /* This terminates BATCH */
  518. { /* processing by closing ALL */
  519. while(batchflg) { /* active batch files */
  520.     batch_end();
  521. }
  522. }
  523. GLOBAL VOID batch_end() /* This function is called for */
  524. { /* both NORMAL and ABNORMAL */
  525. if(batchflg == 0) /* termination of batch file */
  526.     return; /* processing */
  527. boot_key_scan_code = 0;
  528. batch_close(); /* Close the Batch file  */
  529. for_end(); /* Terminate Any FOR command */
  530. batch_old(); /* Restore the previous batch  */
  531. /*  control structures to heap */
  532. if(--batchflg == 0) {
  533.     *batch_seg_ptr = 0;
  534.     echoflg = echoflg_save2; /* Restore the original ECHO */
  535.     crlfflg = YES; /* flag and set CR/LF flag when */
  536. } /* returning to the keyboard. */
  537. }
  538. MLOCAL BOOLEAN batch_open()
  539. {
  540. WORD h, i;
  541. BYTE *name;
  542. if(batch->eof) { /* If the End of the batch file */
  543.     batch_end(); /* was discovered last time then*/
  544.     return FALSE; /* End Batch file input and exit*/
  545. }
  546. if(batch->stream != CLOSED)
  547.     return batch->stream;
  548. name = heap();
  549. for (i=0; i<MAX_PATHLEN; i++)
  550.     name[i] = batch->batfile[i];
  551. while ((h = ms_x_open(name, OPEN_READ)) < 0) {
  552.     err_flag = TRUE;
  553.     eprintf(MSG_BATMISS, name); /* prompt for batch file    */
  554.     heap_get(strlen(name)+1);
  555.     cmd_pause("");
  556.     heap_set(name);
  557. }
  558. err_flag = FALSE;
  559. batch->stream = h;
  560. return TRUE;
  561. }
  562. GLOBAL VOID batch_close()
  563. {
  564. if(batchflg != 0 && 
  565.        batch->stream != CLOSED) { /* Check if the batch file  */
  566.     batch_cnt = 0; /* currently open if YES    */
  567.     ms_x_close(batch->stream); /* then flush the internal  */
  568.     batch->stream = CLOSED; /* buffer and close file.   */
  569. }
  570. }
  571. #if defined(DOSPLUS)
  572. GLOBAL VOID inherit_batch_file(bc)
  573. BCONTROL FAR *bc;
  574. {
  575. WORD i;
  576. BYTE FAR *p_heap;
  577. BYTE *l_heap;
  578. /* inherit any parent batch file first */
  579. if (bc->bcontrol) inherit_batch_file(bc->bcontrol);
  580. /* create a new batch structure */
  581. batch_new();
  582. batch->offset = bc->offset; /* continue at same offset */
  583. for (i=0;i<4;i++) batch->ret_offset[i] = bc->ret_offset[i];
  584. batch->batshift = bc->batshift;
  585. for (i=0; i<MAX_PATHLEN; i++) /* get the batch pathname */
  586.     batch->batfile[i] = bc->batfile[i];
  587. batch->batfile[MAX_PATHLEN-1] = 0;
  588. /* get command line */
  589. p_heap = MK_FP(*parent_psp+16,bc->batcmd);
  590. l_heap = heap();
  591. while (1) {
  592.      while(*p_heap) *l_heap++ = *p_heap++;
  593.      *l_heap++ = *p_heap++;
  594.      if (*p_heap == 0) {
  595.          *l_heap = 0;
  596.  break;
  597.      }
  598. }
  599. heap_get(l_heap-heap());
  600. batchflg++;
  601. }
  602. GLOBAL VOID inherit_parent_state()
  603. {
  604. UWORD FAR *p;
  605. BCONTROL FAR *bc;
  606. UWORD root_psp;
  607. root_psp = *parent_psp;
  608. while(1) {
  609.     p = MK_FP(root_psp-1,8);
  610.     if (p[0] == 0x4F43 && p[1] == 0x4D4D &&
  611.         p[2] == 0x4E41 && p[3] == 0x0044) break;
  612.     p = MK_FP(root_psp,0x16);
  613.     root_psp = *p;
  614. }               
  615. p = MK_FP(root_psp+16,batch_seg_ptr);
  616. #if 0
  617. printf("batch_seg_ptr = %04X:%04Xn",p);
  618. printf("parent batch_seg_ptr = %04Xn",*p); 
  619. #endif
  620. if (*p == 0 || *p == 0xFFFF) return;
  621. bc = MK_FP(*p,0);
  622. inherit_batch_file(bc);
  623. *p = 0;
  624. p = MK_FP(root_psp+16,&echoflg);
  625. echoflg = *p;
  626. }
  627. #endif
  628. GLOBAL VOID batch_new()
  629. /* save current batch file heap contexts to high memory */
  630. {
  631. BYTE   *hp_start;
  632. WORD hp_size;
  633. UWORD i;
  634. BCONTROL FAR *bc;
  635. #if defined(CDOSTMP)
  636. UWORD FAR *ptr;
  637. #endif
  638. if (batchflg != 0)
  639.     hp_start = batch->heap_start;
  640. else
  641.     hp_start = heap();
  642. hp_size = heap() - hp_start;
  643. i = (sizeof(BCONTROL) + hp_size + 15)/16;
  644. mem_alloc(&bc, &i, i, i); /* allocate new batch structure */
  645. if (i == 0) { /* if we can't allocate one */
  646.     longjmp(break_env, IA_HEAP);/* then pretend heap has run out*/
  647. } /* to force termination.        */
  648. bc->bcontrol = batch; /* Link to Previous Structure */
  649. batch = bc; /* make this current batch struc*/
  650. batch->eof = NO; /* Have not found the EOF yet */
  651. batch->offset = 0L; /* start at beginning of File */
  652. for (i=0;i<4;i++) batch->ret_offset[i] = 0L;
  653. batch->batshift = 0; /* No Shift Factor */
  654. batch->stream = CLOSED; /* Batch file is not open */
  655. batch->fcontrol = forptr; /* Save current FOR control */
  656. batch->heap_start = hp_start; /* Save original heap */
  657. batch->heap_size = hp_size;
  658. for (i=0; i < hp_size; i++) {
  659.     batch->save_area[i] = hp_start[i];
  660. }
  661. heap_set(hp_start); /* free up heap used by old batch */
  662. #if defined(CDOSTMP)
  663. ptr = MK_FP(pd->P_PSP, TmpPspEchoFlgPtr);
  664. *ptr = (UWORD)&echoflg;
  665. ptr = (UWORD FAR *) &ptr; /* coerce a FAR * to local data */
  666. i = FP_SEG(ptr); /* so we can get local data segment */
  667. ptr = MK_FP(pd->P_PSP, TmpPspDataSeg);
  668. *ptr = i; /* save local data segment */
  669. ptr = MK_FP(pd->P_PSP, TmpPspBatchSeg);
  670. *ptr = (UWORD)(((ULONG)batch) >> 16);
  671. #else
  672. /* Get segment address of batch and put it where novell */
  673. /* can find it. */
  674. *batch_seg_ptr = (UWORD)(((ULONG)batch) >> 16);
  675. #endif
  676. }
  677. MLOCAL VOID batch_old()
  678. /* restore current batch file heap contents from high memory */
  679. {
  680. BCONTROL FAR *bc;
  681. UWORD i;
  682. #if defined(CDOSTMP)
  683. UWORD FAR *ptr;
  684. #endif
  685. heap_set(batch->heap_start+batch->heap_size);
  686. for (i=0; i<batch->heap_size; i++) {
  687.     batch->heap_start[i] = batch->save_area[i];
  688. }
  689. bc = batch;
  690. forptr = batch->fcontrol; /* Restore the previous for */
  691. for_flag = (BOOLEAN) forptr; /*  control structures  */
  692. batch = batch->bcontrol; /* restore ptr to previous batch */
  693. mem_free(&bc); /* free up batch memory */
  694. #if defined(CDOSTMP)
  695. ptr = MK_FP(pd->P_PSP, TmpPspBatchSeg);
  696. *ptr = (UWORD)(((ULONG)batch) >> 16);
  697. #endif
  698. }
  699. /*
  700.  * Read lines repeatedly from the batch file until a line in 
  701.  * the correct format is read from the batch file or the EOF
  702.  * has been reached.
  703.  */
  704. MLOCAL VOID batch_read(line, goto_flg)
  705. BYTE *line; /* Command Line Buffer */
  706. BOOLEAN goto_flg; /* Goto Command Flag */
  707. {
  708. BYTE *l; /* we need to deblank line */
  709. do {
  710.     batch_line(line, goto_flg); /* Read the next line from  */
  711.     l = deblank(line); /* the batch file and return*/
  712.     if(*l != ';') {
  713. if(goto_flg && *l == ':') /* a line in the correct    */
  714.     return; /* format.     */
  715. if(!goto_flg && *l != ':')
  716.     return;
  717.     }
  718. } while(!batch->eof);
  719. }
  720. /*
  721.  * Read one line from the batch file and place the expanded data into
  722.  * the buffer LINE.
  723.  */
  724. MLOCAL VOID batch_line(line, goto_flg)
  725. BYTE *line; /* Command Line Buffer */
  726. BOOLEAN goto_flg; /* Goto Command Flag */
  727. {
  728. REG WORD i;
  729. REG BYTE *s;
  730. WORD n, env_start;
  731. BYTE c, *bp;
  732. BYTE env_str[128];
  733. BOOLEAN quote = FALSE;
  734. LONG old_offset;
  735. int j;
  736. env_start = NULL; /* Copy the environment into a  */
  737. #if 0
  738. /* 'eject any line starting with 'rem' */
  739. old_offset = batch->offset;
  740. i=0;
  741. do{
  742.  switch(c=*batch_ptr()){
  743.  case  0x1a: 
  744.             batch->eof = YES; /* We have come to the end  */
  745.                 c = 'r'; /* of the batch file so set */
  746.                  break; /* flag and mark end of line*/
  747.    default:
  748.      if (i < MAX_LINE)
  749. line[i++] = c;
  750.      if (dbcs_lead(c)) {
  751.  if ((c = *batch_ptr()) >= ' ' && i < MAX_LINE)
  752.      line[i++] = c;
  753. }
  754.  }/*switch*/
  755. }while(c!='r');
  756. if (*batch_ptr() != 'n')  batch->offset--;
  757.   line[i]=0;
  758. j=0;
  759. while(line[j]){
  760. if (line[j] != ' ')
  761. break;
  762. j++;
  763. }
  764. if (( strlwr(line[j])   == 'r') &&
  765.          ( strlwr(line[j+1]) == 'e') &&
  766.          ( strlwr(line[j+2]) == 'm') &&
  767.          ( strlwr(line[j+3]) == ' ')){
  768. if (echoflg)
  769. printf("%sn",line);
  770. line[0]='';  
  771. return;
  772. }
  773. batch->offset = old_offset;
  774. batch->eof    = NO;
  775. #endif
  776. /*rbf-end*/
  777. /* process line */
  778. i = 0;
  779. do {
  780.       switch(c = *batch_ptr()) {
  781. case '': /* In OS/2 install.bat file  */
  782. #if 0
  783.     if (i < MAX_LINE) /* "ECHO " displays blank  */
  784. line[i++] = 'r'; /* line - so we insert a CR  */
  785.     while (c != 'r') { /* then swallow rest of line */
  786. c = *batch_ptr(); /* read next character - if  */
  787. if (c == 0x1a) /* it's an EOF mark then use */
  788.     goto end_of_file; /* end-of-file code else end */
  789.     } /* up falling into 'r' code */
  790. #else
  791.     c = *batch_ptr();
  792.     if ((c == 'r') && (i < MAX_LINE))
  793. line[i++] = 'r';
  794. #endif
  795. case 'r': /* carriage return */
  796.     if(*batch_ptr() != 'n') /*  skip line feed */
  797. batch->offset--; /* if present    */
  798.     break;
  799. case '"': /* Support Quoted strings   */
  800.     quote = !quote; /* in batch files.     */
  801.     goto save_it;
  802. case PIPE_CHAR:  /* Handle Piped Output     */
  803.     if(goto_flg || quote) /* Ignore this character if */
  804. goto save_it; /* we are searching for a   */
  805. /* Label or Quote.     */
  806.     line[i] = '';
  807.     c = *deblank(line); /* normal case we just      */
  808.     if ((c !='') && (c != ':') && following_command()) {
  809. c = 'r'; /* simulate a CR and set    */
  810. pipe_out = YES; /* Pipe Output flag.     */
  811.     } else if (c == ':') { /* if it's a label */
  812.      for(;(c != 'r') && (c != 0x1A); c = *batch_ptr())
  813.     if (c == 0x1A) /* eat rest of the line     */
  814. batch->eof = YES;
  815. if(*batch_ptr() != 'n')/*  skip line feed */
  816.     batch->offset--; /* if present    */
  817. c = 'r';
  818.     } else { /* if it's a syntax error    */
  819. swallow_line(line); /* discard the rest of line  */
  820. i = 0; /* start again with new line */
  821.     }
  822.     break;
  823. case '%': /* The following code checks to see if the   */
  824. /* string starting at line[env_start-1] is   */
  825. /* define in the environment if it is then   */
  826. /* its definition replaces it in the input   */
  827. /* line. Otherwise no change is made.      */
  828.     if(env_start) {
  829. env_start--;
  830. line[i] = '';  /* Terminate Input   */
  831. strcpy(env_str, line+env_start);/* Copy the String   */
  832. strupr(env_str); /* and force string  */
  833. bp = (BYTE *)heap(); /* into Uppercase    */
  834. i = env_start;
  835. env_start = NULL;
  836. strcat(env_str,"=");
  837. if (env_scan(env_str,bp)) {
  838.     if (novell_extension(env_str,bp)) break;
  839. }
  840. while(*bp && i < MAX_LINE-1)
  841.     line[i++] = *bp++;
  842. break;
  843.     }
  844.     
  845.     c = *batch_ptr();
  846.     if (c == 'r') {
  847. batch->offset--; /* rewind to point to 'r'   */
  848.      break; /* then break to normal code */
  849.     }
  850.     if (c < '0' || c > '9') { /* if not a parameter      */
  851. if(c != '%') /* or a '%' character      */
  852.     env_start = i+1; /* save its start address in */
  853. goto save_it; /* the string and wait for   */
  854.     } /* the terminating '%'      */
  855.     
  856.     n = c - '0' + batch->batshift;     /* get parameter # 0-9 and   */
  857. /* add in SHIFT offset      */
  858.     s = batch->batcmd;
  859.     while(n-- && strlen(s)) /* skip all other parameters */
  860. s += strlen(s)+1; /*   before the one we want  */
  861.     if((strlen(s) + i) >= MAX_LINE) /* Break if Greater than MAX_LINE*/
  862. break;
  863.     strcpy (line + i, s); /* get the substitution */
  864.     i += strlen (s); /* add in its size */
  865.     break;
  866. case 0x1a:
  867.     end_of_file:
  868.     batch->eof = YES; /* We have come to the end  */
  869.     c = 'r'; /* of the batch file so set */
  870.     break; /* flag and mark end of line*/
  871.  default:
  872.     save_it:
  873.     if (i < MAX_LINE)
  874. line[i++] = c;
  875.     if (dbcs_lead(c)) {
  876. if ((c = *batch_ptr()) >= ' ' && i < MAX_LINE)
  877.     line[i++] = c;
  878.     }
  879. }
  880. } while (c != 'r'); /* repeat until CR    */
  881. line[i] = '';  /* Terminate the line and  */
  882. if(batch->eof)
  883.     return;
  884. #if 0 /* not DOS compatible */
  885. if(*batch_ptr() == 0x1A) /* Check if the next this  */
  886.     batch->eof = YES; /* the end of the file if  */
  887. else /* YES then set the flag   */
  888.     batch->offset--; /* force the character to  */
  889. #endif /* be re-read next time    */
  890. return;  /* return to the caller    */
  891. }
  892. MLOCAL BOOLEAN following_command()
  893. /* return true if we have a possible command on the rest of the line */
  894. {
  895. LONG old_offset;
  896. BOOLEAN res = FALSE;
  897. BYTE *s;
  898. old_offset = batch->offset; /* save batch offset */
  899. while (TRUE) {
  900.     s = batch_ptr(); /* look ahead at batch file */
  901.     if (*s == 'r' || *s == 0x1a || (!dbcs_lead(*s) && *s == PIPE_CHAR))
  902. break;
  903.     if (!is_blank(s)) {
  904.         res = TRUE; /* possible command if we   */
  905. break; /* hit non whitespace char  */
  906.     }
  907.     if (dbcs_lead(*s)) {
  908. s = batch_ptr();
  909. if (*s == 'r' || *s == 0x1a)
  910.     break;
  911.     }
  912. }
  913. batch->offset = old_offset; /* restore batch offset */
  914. return res;
  915. }
  916. MLOCAL VOID swallow_line(s)
  917. BYTE *s;
  918. /* there is a syntax error on this line - swallow it and say so */
  919. {
  920. BYTE c;
  921. prompt(); /* possibly echo the prompt */
  922. if (echoflg) /* echo to screen if wanted */
  923.     printf("%s%c",s,PIPE_CHAR);
  924. do {
  925.     c = *batch_ptr();
  926.     if (c ==  0x1a) {
  927. c = 'r'; /* pretend to be end of line*/
  928. batch->eof = YES; /* We have come to the end  */
  929. break; /* flag and mark end of line*/
  930.     }
  931.     if (echoflg) /* echo to screen if wanted */
  932. putc(c);
  933. } while (c != 'r');
  934. if (echoflg)
  935.     putc('n');
  936. if (*batch_ptr() != 'n') /*  skip line feed */
  937.    batch->offset--; /* if present    */
  938. eprintf(MSG_SYNTAX); /* report syntax error */
  939. }
  940. /*
  941.  * In order to improve performance of the batch file processing
  942.  * the Batch file is read in blocks of BATCH_BUF characters.
  943.  * and the routine BATCH_CHAR then returns a pointer to a character
  944.  * from the buffer (filling the buffer if required).
  945.  */
  946. MLOCAL BYTE *batch_ptr()
  947. {
  948. BYTE FAR *buf;
  949. UWORD bufsize;
  950. UWORD i;
  951. if(batch->eof)
  952.     return(batch_eof);
  953.     
  954. if (batch->offset < batch_off ||
  955. batch->offset >= (batch_off + (LONG) (batch_cnt - 1))) {
  956.     batch_off = batch->offset;
  957.     ms_x_lseek (batch->stream, batch->offset, 0);
  958.     batch_cnt = far_read(batch->stream, gp_far_buff, sizeof(batch_buf));
  959.     if(batch_cnt <= 0) {
  960. batch->eof = YES;
  961. return(batch_eof);
  962.     }
  963.     for (i=0; i<sizeof(batch_buf); i++) batch_buf[i] = gp_far_buff[i];
  964. }
  965. return(&batch_buf[(UWORD) (batch->offset++ - batch_off)]);
  966. }
  967. /*.pa*/
  968. /*
  969.  * BATCH FILE COMMANDS
  970.  * ===================
  971.  *
  972.  * The following commands are used almost entirely in BATCH files and
  973.  * have little or no meaning outside that environment.
  974.  */
  975. GLOBAL VOID CDECL cmd_shift ()
  976. {
  977. batch->batshift++; /* Increment the Shift Offset */
  978. }
  979. MLOCAL WORD label_ignore_char(s)
  980. BYTE *s;
  981. {
  982. if (*s == '=') return(1);
  983. if (*s == ';') return(1);
  984. if (*s == ',') return(1);
  985. if (*s == ' ') return(1);
  986. return(0);
  987. }
  988. /*
  989.  * Extract the first a valid characters from the label and then
  990.  * zero terminate the resulting string.
  991.  */
  992. MLOCAL BYTE * make_label(label)
  993. BYTE *label;  
  994. {
  995. REG BYTE *bp;
  996. UWORD i;
  997. label = deblank(label); /* remove leading white space */
  998. while (label_ignore_char(label))
  999.     label = skip_char(label);
  1000. bp = label;
  1001. while (is_filechar(bp)) /* skip over valid chars      */
  1002.     bp = skip_char(bp);
  1003. *bp = ''; /* make label zero terminated */
  1004. return label;
  1005. }
  1006. GLOBAL VOID CDECL cmd_goto (label)   /* goto label in batch file */
  1007. REG BYTE    *label;
  1008. {
  1009. UWORD i;
  1010. BYTE *bp, s[MAX_LINE+2];  /* Allocate buffer for Batch Input  */
  1011. if (!batchflg) /* if not in batch mode      */
  1012.     return; /* this command is ignored     */
  1013. if(*label == ':') /* Ignore any leading ':'     */
  1014.     label++;
  1015. label = make_label(label); /* Convert to Label Format     */
  1016. batch->offset = 0L; /* rewind the batch file     */
  1017. batch->eof = NO; /* So it cannot be EOF     */
  1018. if(!batch_open()) /* Check the Batch file is open     */
  1019.     return; /* and stop if the function fails.  */
  1020. while(!batch->eof) { /* while not end of file read next  */
  1021.     batch_read(s, YES);  /* line and return the next command  */
  1022.     bp = deblank(s);
  1023.     if((*bp == ':') && !strnicmp(make_label(bp+1),label, 8))
  1024. return;
  1025. }
  1026. batch_end(); /* Stop any further batch file    */
  1027. crlfflg = YES; /* processing and print the error  */
  1028. eprintf(MSG_LABEL, label);
  1029. }
  1030. GLOBAL VOID CDECL cmd_gosub (label)   /* gosub label in batch file */
  1031. REG BYTE    *label;
  1032. {
  1033. UWORD i;
  1034. BYTE *bp, s[MAX_LINE+2];  /* Allocate buffer for Batch Input  */
  1035. if (!batchflg) /* if not in batch mode      */
  1036.     return; /* this command is ignored     */
  1037. if (batch->ret_offset[3] != 0L) {
  1038. batch_end();
  1039. crlfflg = YES;
  1040. eprintf(MSG_GOSUB);
  1041. return;
  1042. }
  1043. if(*label == ':') /* Ignore any leading ':'     */
  1044.     label++;
  1045. label = make_label(label); /* Convert to Label Format     */
  1046. i = 0;
  1047. while (batch->ret_offset[i] != 0L) i++;
  1048. batch->ret_offset[i] = batch->offset;
  1049. batch->offset = 0L; /* rewind the batch file     */
  1050. batch->eof = NO; /* So it cannot be EOF     */
  1051. if(!batch_open()) /* Check the Batch file is open     */
  1052.     return; /* and stop if the function fails.  */
  1053. while(!batch->eof) { /* while not end of file read next  */
  1054.     batch_read(s, YES);  /* line and return the next command  */
  1055.     bp = deblank(s);
  1056.     if((*bp == ':') && !strnicmp(make_label(bp+1),label, 8))
  1057. return;
  1058. }
  1059. batch_end(); /* Stop any further batch file    */
  1060. crlfflg = YES; /* processing and print the error  */
  1061. eprintf(MSG_LABEL, label);
  1062. }
  1063. GLOBAL VOID CDECL cmd_return()
  1064. {
  1065. UWORD i;
  1066. if (!batchflg) return;
  1067. if (batch->ret_offset[0] == 0L) {
  1068. batch_end();
  1069. crlfflg = YES;
  1070. eprintf(MSG_RETURN);
  1071. return;
  1072. }
  1073. i = 0;
  1074. while ((batch->ret_offset[i] != 0L)&&(i<4)) i++;
  1075. batch->offset = batch->ret_offset[i-1];
  1076. batch->ret_offset[i-1] = 0L;
  1077. }
  1078. #if SWITCH_ENABLED
  1079. GLOBAL VOID CDECL cmd_switch(list)
  1080. REG BYTE *list;
  1081. {
  1082. BYTE *list_start;
  1083. BYTE *label;
  1084. WORD i,j;
  1085. BYTE c;
  1086. if (!batchflg) return;
  1087. list_start = list;
  1088. switch_retry:
  1089. list = list_start;
  1090. i = psp_poke(STDIN,1);
  1091. #if defined(CDOSTMP)
  1092. c =(BYTE) bdos(C_RAWIO, 0xFD); /* Get a character from console */
  1093. if ((c==0) ||(dbcs_lead(c)))
  1094.     bdos(C_RAWIO, 0xFD); /* skip second byte in DBCS pair */
  1095. #else
  1096. c = (BYTE) msdos(MS_C_RAWIN, 0);/* Get a character from console */
  1097. if ((c==0) || (dbcs_lead(c)))
  1098.     msdos(MS_C_RAWIN, 0); /* skip second byte in DBCS pair */
  1099. #endif
  1100. psp_poke(STDIN,i);
  1101. if (c==0x03) int_break(); /* check for CTRL-C */
  1102. if (c==0x0d) c = '1'; /* return gives default of 1 */
  1103. i = (WORD) (c - '1');
  1104. if (i<0 || i>8) goto switch_retry; /* ignore invalid keys */
  1105. j = 0;
  1106. while (j<i) {
  1107. while (*list != ',' && *list != 0) list++;
  1108. if (*list == 0) goto switch_retry;
  1109. j++;
  1110. list++;
  1111. list = deblank(list);
  1112. }
  1113. label = list;
  1114. while (*list != ',' && *list != 0) list++;
  1115. *list = 0;
  1116. cmd_gosub(label);
  1117. }
  1118. #endif
  1119. /*.pa*/
  1120. /*
  1121.  * The IF command supports the following syntax:-
  1122.  *
  1123.  * IF [NOT] string1 == string2 COMMAND
  1124.  * IF [NOT] ERRORLEVEL n COMMAND
  1125.  * IF [NOT] EXIST filename COMMAND
  1126. /*RG-02-
  1127.  * IF [NOT] USERID n COMMAND
  1128.  * IF [NOT] LOGINNAME string COMMAND
  1129.  * IF [NOT] GROUPNAME string COMMAND
  1130.  * IF [NOT] KEY ["string"] char COMMAND
  1131.  *
  1132.  */
  1133. #if defined(CDOSTMP) || defined(CDOS)
  1134. MLOCAL BYTE *if_opt[] = {"exist", "direxist", "errorlevel", "key", "userid", "loginname", "groupname", NULL };
  1135. #else
  1136. MLOCAL BYTE *if_opt[] = {"exist", "direxist", "errorlevel", NULL };
  1137. #endif
  1138. /*RG-02-end*/
  1139. MLOCAL UWORD if_index(cmd)
  1140. BYTE **cmd;
  1141. {
  1142. UWORD i, j;
  1143. for(i = 0; if_opt[i]; i++) { /* Scan Through the option   */
  1144.     j = strlen(if_opt[i]); /* list and return the index */
  1145. /* of the matching option    */
  1146.     if(strnicmp(*cmd, if_opt[i], j)) /* and update the string     */
  1147.         continue; /* pointer.      */
  1148.     *cmd = deblank(*cmd+j);
  1149.     while(*(*cmd) == '=') /* Remove any "=" string     */
  1150.         (*cmd)++; /* present in the command    */
  1151.     *cmd = deblank(*cmd); /* Used by many install files*/
  1152.     break;
  1153. }
  1154. return i;
  1155. }
  1156. #define OP_EQ 0
  1157. #define OP_NE 1
  1158. #define OP_LE 2
  1159. #define OP_LT 3
  1160. #define OP_GE 4
  1161. #define OP_GT 5
  1162. MLOCAL WORD get_operator(op)
  1163. BYTE *op;
  1164. {
  1165. if (op[0] == '=') return(OP_EQ);
  1166. if (op[0] == '!' && op[1] == '=') return(OP_NE);
  1167. if (op[0] == '<') {
  1168.     if (op[1] == '>') return(OP_NE);
  1169.     if (op[1] == '=') return(OP_LE);
  1170.     return(OP_LT);
  1171. }
  1172. if (op[0] == '>') {
  1173.     if (op[1] == '=') return(OP_GE);
  1174.     return(OP_GT);
  1175. }
  1176. return(-1);
  1177. }
  1178. MLOCAL LONG get_decimal(s)
  1179. BYTE *s;
  1180. {
  1181. LONG total = 0;
  1182. if (*s == '#') s++;
  1183. while (*s>='0' && *s<='9') {
  1184.     total *= 10;
  1185.     total += (LONG) (*s-'0');
  1186.     s++;
  1187. }
  1188. return(total);
  1189. }
  1190. MLOCAL BOOLEAN CDECL test_cond(cptr)
  1191. BYTE **cptr;
  1192. {
  1193. BYTE *cmd,*str1, *str2, *ptr;
  1194. DTA search;
  1195. BOOLEAN not, cond, neg,is_user;
  1196. BYTE level;
  1197.         BYTE    c[]=" n";
  1198.         WORD attr;
  1199. UWORD   userid;
  1200. LONG val1,val2;
  1201.         cmd=*cptr;
  1202.         not = cond = NO; /* Initialise the Flags     */
  1203. if(!strnicmp(cmd = deblank(cmd), "not", 3)) {
  1204.     not = YES;
  1205.     cmd = deblank(cmd+3);
  1206. }
  1207. switch(if_index(&cmd)) {
  1208.     /*
  1209.      * EXIST Option extract the possibly ambiguous filename
  1210.      * and check if it exists.
  1211.      */
  1212.     case 0:
  1213. cmd = deblank(get_filename(heap(), cmd, YES));
  1214. cond = !ms_x_first(heap(), ATTR_STD|ATTR_HID, &search);
  1215. break;
  1216.     /*
  1217.      * DIREXIST Option checks if the given directory exists
  1218.      */
  1219.     case 1:
  1220. cmd = deblank(get_filename(heap(), cmd, YES));
  1221. attr = ms_x_chmod(heap(), ATTR_ALL, 0);
  1222. if (attr < 0) cond = FALSE;
  1223. else cond = (attr & 0x10);
  1224. break;
  1225.     /*
  1226.      * ERRORLEVEL Option extract the decimal number from the
  1227.      * command line.
  1228.      */
  1229.     case 2:
  1230. level = 0;
  1231. neg = FALSE;
  1232. if(*cmd =='-') {
  1233.     neg = TRUE;
  1234.     cmd++;
  1235. }
  1236. if(!isdigit(*cmd)) { /* SYNTAX error if the     */ 
  1237.     syntax(); /* first character is not a */
  1238.     return FALSE; /* digit.     */
  1239. }
  1240. while(isdigit(*cmd))
  1241.     level = level * 10 + (*cmd++ - '0');
  1242. level = level & 0x00FF;
  1243. if (neg) level = -level;
  1244.         cond = (level<=(err_ret & 0x00FF)); 
  1245. break;
  1246. /*RG-02*/
  1247. #if !defined(NOXBATCH)
  1248. #if (defined(CDOSTMP) || defined(CDOS))
  1249.     /*
  1250.      * KEY ["string"] [==] [""] Search for the string "string" and
  1251.              *  display it if it exists, then read a key and echo it.
  1252.              *  However, if the string to match is null "" then do a keyboard
  1253.              *  status check and return TRUE if there is no key there
  1254.      */
  1255.     case 3:
  1256.     cmd = deblank(cmd);
  1257.                 ptr=cmd;
  1258.                 if (display_string(&ptr)!=0)
  1259.                     return FALSE;
  1260.              cmd = deblank(ptr); 
  1261.         while(*cmd == '=') /* Remove any "=" string     */
  1262.             cmd++;
  1263.         cmd = deblank(cmd);
  1264.                 if ((*cmd==0)||(*(cmd+1)!=' ')) { /* check for condition */
  1265.               syntax();
  1266.                     return FALSE;
  1267.                 }
  1268.                 /* read a character from the keyboard */
  1269.              c[0]=bdos(C_RAWIO, 0xFD); /* Get a character from console */
  1270.                 /* echo the char typed */
  1271.         if (echoflg)  /* echo to screen if wanted */
  1272.     putc(c[0]);
  1273.         crlf(); /* print cr/lf */
  1274.                 
  1275.                 /* check if it matches */
  1276.                 if((tolower(c[0])==*cmd)||(toupper(c[0])==*cmd))
  1277.                     cond=TRUE;
  1278.                 else 
  1279.                     cond=FALSE;
  1280.                 /* skip the condition */
  1281.         while (*cmd!=' ')
  1282.                     cmd++; /* skip the char */
  1283.         
  1284.     break;
  1285. #endif
  1286. #if !defined (NOSECURITY) && (defined(CDOSTMP) || defined(CDOS))
  1287.     /*
  1288.      * USERID Option extract the 4 digit hex user id
  1289.      * and check if it is us.
  1290.      */
  1291.     case 4:
  1292.                 if (!login_enabled())
  1293.                     return FALSE;
  1294.     cmd = deblank(cmd);
  1295.         if(aschextobin(cmd)==get_user_on_station())
  1296.                     cond=TRUE;
  1297.                 else
  1298.                     cond=FALSE;
  1299.                 
  1300.                 do {   /* skip past the user id */
  1301.                     if ((*cmd>='0' && *cmd<='9')
  1302.                         ||(tolower(*cmd)>='a' && tolower(*cmd)<='f'))
  1303.                         cmd++; /* skip the hex digit */
  1304.                     else {
  1305.                     syntax();
  1306.             return FALSE;
  1307.                     }
  1308.         } while (*cmd!=' ');
  1309. break;
  1310.             /*
  1311.      * LOGINNAME Option extract the loginname and check if it is us.
  1312.      */
  1313.     case 5:
  1314.                 if (!login_enabled())
  1315.                     return FALSE;
  1316.                 is_user=TRUE;
  1317.             /*
  1318.      * GROUPNAME Option extract the loginname and check if it is us.
  1319.      */
  1320.     case 6:
  1321.                 if (!login_enabled())
  1322.                     return FALSE;
  1323.     cmd = deblank(cmd);
  1324.                 if(aschextobin(user_info.userid)!=get_user_on_station()) {
  1325.             if(get_user_info(get_user_on_station())!=0) {
  1326.                         syntax();
  1327.                         is_user=cond=FALSE;
  1328. return FALSE;
  1329.                     }
  1330.                 }
  1331.                 if((is_user==TRUE)&&(strncmp(strlwr(cmd),strlwr(user_info.loginname),strlen(user_info.loginname))==0)) {
  1332.                     cond=TRUE;
  1333.                     cmd+=strlen(user_info.loginname);
  1334.                 }
  1335.                 else if((is_user!=TRUE)&&(strncmp(strlwr(cmd),strlwr(user_info.groupname),strlen(user_info.groupname))==0)) {
  1336.                     cond=TRUE;
  1337.                     cmd+=strlen(user_info.groupname);
  1338.                 }
  1339.                 else {
  1340.                     cond=FALSE;
  1341.             while (*cmd!=' ')
  1342.                         cmd++; /* skip the name */
  1343.                 }
  1344.                 if (*cmd!=' ') {
  1345.                     is_user=cond=FALSE;
  1346.                 }
  1347.                 is_user=FALSE;
  1348. break;
  1349. #endif
  1350. #endif /*NOXBATCH*/
  1351. /*RG-02-end*/            
  1352.             /*
  1353.      * String comparison option.
  1354.      */
  1355.     default:
  1356. str1 = cmd; /* Extract String 1     */
  1357. while ((!is_blank(cmd)) && (*cmd != '=') &&
  1358.        ((*cmd != '!') || (cmd[1]!= '=')) &&
  1359.        (*cmd != '<') && (*cmd != '>')) {
  1360.     cmd = skip_char(cmd);
  1361. }
  1362. str2 = cmd;
  1363. cmd = deblank(cmd);
  1364. attr = get_operator(cmd++);
  1365. if (attr == -1) {
  1366.     syntax();
  1367.     return(FALSE);
  1368. }
  1369. *str2 = 0;
  1370. if (*cmd == '=' || *cmd == '>') cmd++;
  1371. cmd = deblank(cmd);
  1372. str2 = cmd;
  1373. while (!is_blank(cmd)) cmd = skip_char(cmd);
  1374. *cmd++ = 0;
  1375. if (*str1 == '#') {
  1376.     val1 = get_decimal(str1);
  1377.     val2 = get_decimal(str2);    
  1378.     switch(attr) {
  1379.       case OP_EQ: cond = (val1==val2); break;
  1380.       case OP_NE: cond = (val1!=val2); break;
  1381.       case OP_LT: cond = (val1<val2); break;
  1382.       case OP_LE: cond = (val1<=val2); break;
  1383.       case OP_GT: cond = (val1>val2); break;
  1384.       case OP_GE: cond = (val1>=val2); break;
  1385.     }
  1386. }
  1387. else switch(attr) {
  1388. case OP_EQ:
  1389.     cond = (strcmp(str1,str2) == 0);
  1390.     break;
  1391. case OP_NE:
  1392.     cond = (strcmp(str1,str2) != 0);
  1393.     break;
  1394. case OP_LT:
  1395.     cond = (strcmp(str1,str2) < 0);
  1396.     break;
  1397. case OP_LE:
  1398.     cond = (strcmp(str1,str2) <= 0);
  1399.     break;
  1400. case OP_GT:
  1401.     cond = (strcmp(str1,str2) > 0);
  1402.     break;
  1403. case OP_GE:
  1404.     cond = (strcmp(str1,str2) >= 0);
  1405.     break;
  1406. }
  1407. break;
  1408. }
  1409. if(not)  /* if negated condition     */
  1410.     cond = !cond;
  1411.         *cptr=cmd;
  1412.         return cond; /* write result back */
  1413. }
  1414. #if !defined(NOXBATCH)
  1415. BOOLEAN is_it_or(BYTE *cmd)
  1416. {
  1417. cmd--;
  1418. if ((*cmd != 0) && (*cmd != 't') && (*cmd != ' '))
  1419.     return FALSE;
  1420.         cmd++;
  1421. if (strnicmp(cmd, "or", 2) != 0)
  1422.     return FALSE;
  1423. cmd+=2;    
  1424. if ((*cmd != 't') && (*cmd != ' '))
  1425.     return FALSE;
  1426. return TRUE;
  1427. }
  1428. #endif
  1429. GLOBAL VOID CDECL cmd_if(cmd)
  1430. BYTE *cmd;
  1431. {
  1432.         BOOLEAN cond;
  1433.         
  1434. ifcond=cond=test_cond(&cmd);
  1435. if(!*deblank(cmd)) { /* and return a SYNTAX error*/
  1436.     syntax(); /* if it is empty.     */
  1437.     return;
  1438. }
  1439.         if(!cond) {
  1440. #if !defined(NOXBATCH)
  1441.     while (!is_it_or(cmd) &&
  1442.        (*cmd != 0)) {
  1443.         if (strnicmp(cmd,"ECHO",4)==0) return;       
  1444.         cmd++;
  1445.     }
  1446.             if (*cmd==0) return; /* no OR's so quit now */
  1447.     
  1448.     if_context = TRUE;
  1449.     
  1450.     docmd(deblank(cmd), YES); /* New command starts at "or" */
  1451.             
  1452. #endif
  1453.         }
  1454. else {
  1455.     cmd = deblank(cmd);
  1456.     if (strnicmp(cmd,"AND",3)) {
  1457. if (parse(cmd)) return;   /* IF won't have been 'parsed' for */
  1458.   /* > or < redirectors so do it now */
  1459.     }
  1460.     if_context = TRUE;
  1461.        /* Execute command if the    */
  1462.     docmd(cmd, YES);              /* condition flag is TRUE    */
  1463. }
  1464.         if_context=FALSE;
  1465. }
  1466. /*RG-03*/
  1467. #if !defined(NOXBATCH)
  1468. GLOBAL VOID CDECL cmd_or(cmd)
  1469. BYTE *cmd;
  1470. {
  1471.         BOOLEAN cond;
  1472.         BYTE    *org_cmd;
  1473.         
  1474.         cond=test_cond(&cmd);
  1475. if(!*deblank(cmd)) { /* and return a SYNTAX error*/
  1476.     syntax(); /* if it is empty.     */
  1477.     return;
  1478. }
  1479.         if(!cond) {
  1480.             org_cmd = cmd; /* now look for "OR" */
  1481.     while (!is_it_or(cmd) &&
  1482.    (*cmd != 0)) {
  1483. if (strnicmp(cmd,"ECHO",4)==0) while(*cmd) cmd++;
  1484. else cmd++;
  1485.     }
  1486.             if (*cmd==0) { /* oh dear, no ORs */
  1487.                 if (ifcond) /* but so far so good, so do command anyway */
  1488.            docmd(deblank(org_cmd), YES); 
  1489.                 return;
  1490.             }
  1491.     docmd(deblank(cmd), YES); /* New command starts at "or" */
  1492.             return;
  1493.         }
  1494. else {
  1495.             cmd = deblank(cmd);
  1496.     
  1497.     if (strnicmp(cmd,"AND",3)) {
  1498.         if (parse(cmd)) return;   /* IF won't have been 'parsed' for */
  1499.   /* > or < redirectors so do it now */
  1500.     }
  1501.     
  1502.     ifcond=cond;                 /* Execute command if the    */
  1503.     docmd(cmd, YES);      /* condition flag is TRUE    */
  1504.         }
  1505. }
  1506. #endif /*NOXBATCH*/
  1507. /*RG-03-end*/
  1508. GLOBAL VOID CDECL cmd_for(s)
  1509. BYTE *s;
  1510. {
  1511. FCONTROL *fc;
  1512. BYTE *bp1;
  1513. fc = (FCONTROL *) heap_get(sizeof(FCONTROL));
  1514. /* Allocate Control Struct  */
  1515. if(forptr) /* and prevent nesting of  */
  1516.     goto for_error; /* FOR Command.     */
  1517. s = deblank(s);  /* Remove leading blanks   */
  1518. if ((*s++ != '%') || /* Get the FOR variable    */
  1519.     (fc->forvar = *s++) < ' ') /* character and save    */
  1520.     goto for_error;
  1521. if(strnicmp(s = deblank(s), "in", 2)) /* Check for the correct   */
  1522.     goto for_error; /* command syntax.    */
  1523. s = deblank(s+2);
  1524. if (*s++ != '(')
  1525.     goto for_error;
  1526. fc->files = (BYTE *)heap(); /* Allocate FOR parameter  */
  1527. while(*s && *s != ')') { /* buffer and scan the    */
  1528.     bp1 = (BYTE *)heap(); /* command line generating */
  1529. /* zero terminated strings */
  1530.     while(strchr(batch_sep, *s)) /* Skip any separators    */
  1531. s = skip_char(s);
  1532.     while(   *s != ')' && /* then copy all valid    */
  1533.      !strchr(batch_sep, *s)) /* characters into buffer  */
  1534.        /* then zero terminate    */
  1535. copy_char(&bp1, &s);
  1536.     *bp1++ = '';
  1537.     heap_get(strlen(heap()) + 1); /* Preserve String     */
  1538. }
  1539. *(BYTE *)heap_get(1) = '';  /* Final String is zero     */
  1540. /* bytes in length     */
  1541. s = deblank(s);
  1542. if(*s++ != ')')
  1543.     goto for_error;
  1544. if(strnicmp(s = deblank(s), "do", 2))
  1545.     goto for_error;
  1546. if(in_flag & REDIR_ACTIVE) /* If Input redirection has been */
  1547.     in_flag |= REDIR_FOR; /* enabled for this command force*/
  1548. /* it on for the complete command*/
  1549. if(out_flag & REDIR_ACTIVE) /* If Output redirection has been*/
  1550.     out_flag |= REDIR_FOR; /* enabled for this command force*/
  1551. /* it on for the complete command*/
  1552. fc->cmd = (BYTE *)heap_get(strlen(s = deblank(s+2)) +1);
  1553. strcpy(fc->cmd, s);
  1554. fc->sflg = NO; /* File matching inactive  */
  1555. for_flag = YES;  /* Turn FOR processing ON  */
  1556. forptr = fc; /* Save control Structure  */
  1557. return;
  1558. for_error: /* When a Syntax error occurs */
  1559. heap_set((BYTE *) fc); /* restore the heap and print */
  1560. syntax(); /* an error message. */
  1561. return;
  1562. }
  1563. GLOBAL VOID for_end()
  1564. {
  1565. if(for_flag) {
  1566.     heap_set((BYTE *) forptr); /* Terminate FOR processing */
  1567.     forptr = (FCONTROL *) NULL; /* restore the HEAP and reset */
  1568.     for_flag = NO; /* control flags. */
  1569. }
  1570. }
  1571. /*.pa*/
  1572. /*
  1573.  * This command generates the displayed prompt based on the contents
  1574.  * of the string PROMPT= in the environment. Otherwise the default
  1575.  * prompt string DEFAULT_PROMPT is used.
  1576.  */
  1577. MLOCAL BOOLEAN prompt_flg = FALSE; /* Prompt Flag  */
  1578. MLOCAL VOID prompt() /* display command line prompt */
  1579. {
  1580. REG BYTE *cp;
  1581. BYTE  buf[MAX_PATHLEN];
  1582. BYTE  c;
  1583. #if !STACK
  1584. BYTE  cpbuf[MAX_ENVLEN];
  1585. #endif
  1586. /*rbf*/
  1587. #if 1
  1588. BYTE prmptcpbuf[MAX_ENVLEN];
  1589. REG BYTE *prmptcp = prmptcpbuf;
  1590. #endif
  1591. if(!echoflg) /* Return if No Echo */
  1592.     return;
  1593. #if defined(CPM)
  1594. cp = heap();
  1595. strcpy(cp, "[CPM] $u$p$g");
  1596. #else
  1597. if(env_scan(msg_prmeq, cp = (BYTE *)heap()))
  1598.     strcpy(cp, DEFAULT_PROMPT);
  1599. #endif
  1600. if(prompt_flg) /* If the previous Prompt display   */
  1601.     strcpy(cp, "$n$g"); /* terminated due to a Critical     */
  1602. /* then just display the default    */
  1603. prompt_flg = TRUE; /* drive.     */
  1604. #if STACK
  1605. cp = stack(strlen(cp) + 1);
  1606. #else
  1607. cp = &cpbuf[0];
  1608. #endif
  1609. strcpy(cp, heap());
  1610. while((c = *cp++) != 0) { /* get next character */
  1611.     if (c != '$') /* if not '$', print as is */
  1612. putc (c);
  1613.     else {
  1614. c = *cp++;
  1615. switch(tolower(c)) { /* else get next character */
  1616.  case '': /* Treat "$" as an invalid      */
  1617.      cp--; /* prompt command sequence     */
  1618.      break;
  1619.  case 't': /* print current time */
  1620.     disp_systime();
  1621.     break;
  1622.  case 'd': /* print current date */
  1623.     disp_sysdate();
  1624.     break;
  1625.  case 'p': /* print current path */
  1626.     if (ms_x_curdir(drive+1, buf) < 0)
  1627.         printf(MSG_DRV_INVALID);
  1628.     else
  1629.         printf("%c:%s%s", drive+'A', pathchar, buf);
  1630.     break;
  1631.  case 'v': /* print version number */
  1632.     cmd_ver("");
  1633.     break;
  1634.  case 'n': /* print default drive */
  1635.     putc((BYTE) drive+'A');
  1636.     break;
  1637.  case 'g': /* print ">" */
  1638.     putc ('>');
  1639.     break;
  1640.  case 'l': /* print "<" */
  1641.     putc ('<');
  1642.     break;
  1643.  case 'b': /* print "|" */
  1644.     putc ('|');
  1645.     break;
  1646.  case 'q': /* print "=" */
  1647.     putc ('=');
  1648.     break;
  1649.  case '_': /* print CR,LF */
  1650.     crlf();
  1651.     break;
  1652.  case 'h': /* print backspace, space, backspace */
  1653.     printf("b b");
  1654.     break;
  1655.  case 'e': /* print ESC character */
  1656.     putc ('33');
  1657.     break;
  1658. /*RG-01 */ 
  1659. #if !defined(NOXBATCH)
  1660. #if !defined (NOSECURITY) 
  1661. #if defined(CDOSTMP) || defined(CDOS)
  1662.  case 'm': /* print mail status */
  1663.                 if (login_enabled()) {
  1664.                     if(chk_mail()) { /* we have mail */
  1665.                 if(env_scan("MAIL=", heap())) 
  1666.                             printf(MSG_UHAVEMAIL);
  1667.                         else
  1668.                             printf("%s",heap());
  1669.                     }
  1670.                 }
  1671.     break;
  1672.  case 'u': /* Display the User Name */
  1673.                 if (login_enabled()) {
  1674.                     if((aschextobin(user_info.userid)!=get_user_on_station())||(strlen(user_info.userid)==0)) {
  1675.                 if(get_user_info(get_user_on_station())!=0) 
  1676.                 printf("#%04X",get_user_on_station());
  1677.                         else
  1678.                 printf("%s",user_info.loginname);
  1679.                     }
  1680.                     else
  1681.             printf("%s",user_info.loginname);
  1682.                 }
  1683.                 break;
  1684. #endif
  1685. #endif
  1686. #endif /*NOXBATCH*/
  1687. /*RG-01-end*/
  1688. #if defined(CPM)
  1689.  case 'u': /* Display the User Number */
  1690.     printf("%d", user);
  1691.     break;
  1692. #endif
  1693. #if defined(DOSPLUS)
  1694.  case 'u':
  1695.     if (!env_scan("LOGINNAME=",heap()))
  1696.         printf("%s",heap());
  1697.     break;
  1698. #endif     
  1699.  case '$':
  1700.     putc ('$');  /* print single '$' */
  1701.     break;
  1702.  case 'x':
  1703.     if ((allow_pexec)&&(!batchflg)) prompt_exec();
  1704.     break;
  1705.  default: /* Otherwise the character */
  1706.     break;
  1707. }
  1708.     }
  1709. }
  1710. prompt_flg = FALSE; /* Prompt display completed OK */
  1711. }
  1712. #if !defined(CDOSTMP)
  1713. /* The following functions are called by the int2e_handler function in
  1714.  * COM.C. If a program is run from a batch file and calls INT 2E to
  1715.  * execute a new batch file the original batch file must NOT be terminated.
  1716.  * Therefore batch and batchflg must be saved, set to zero, and then
  1717.  * restored when INT 2E returns. - EJH 
  1718.  */
  1719.  
  1720. GLOBAL VOID int2e_start()
  1721. {
  1722. batchflg_save = batchflg;
  1723. batchflg = 0;
  1724. batch_save = batch;
  1725. echoflg_save = echoflg;
  1726. echoflg = ECHO_ON;
  1727. }
  1728. GLOBAL VOID int2e_finish()
  1729. {
  1730. batchflg = batchflg_save;
  1731. batch = batch_save;
  1732. echoflg = echoflg_save;
  1733. }
  1734. #endif
  1735. #if defined(CDOS)
  1736. MLOCAL VOID map_user_page(UWORD window_page, UWORD physical_page)
  1737. {
  1738. UWORD pblk[3];
  1739. pblk[0] = window_page;
  1740. pblk[1] = physical_page;
  1741. pblk[2] = 0;
  1742. bdos(181, pblk);
  1743. }
  1744. MLOCAL BYTE FAR * map_pd_mem(UWORD ppd, UWORD wp, UWORD seg, UWORD offset)
  1745. {
  1746. /* Map memory for another process into our memory space so we examine it */
  1747. UWORD base_seg;
  1748. UWORD page;
  1749. PD FAR * pdptr;
  1750. UWORD sysdat;
  1751. UWORD mptbl;
  1752. UWORD FAR * ptr;
  1753. UWORD mp_off;
  1754. UWORD i;
  1755. MPAD FAR * mp;
  1756. sysdat = FP_SEG(pd);
  1757. ptr = MK_FP(sysdat, 0xc8);
  1758. /* DEBUG */
  1759. if (*ptr == 0) /* for DEBUG under XM assume non-banked system */
  1760.     return(MK_FP(seg, offset));
  1761. /* DEBUG */
  1762. ptr = MK_FP(sysdat, *ptr + 8);
  1763. mptbl = *ptr;
  1764. /* get segment of 4k page to map */
  1765. base_seg = (seg + (offset+15)/16) & 0xff00;
  1766. /* now find physical page to map */
  1767. pdptr = (PD FAR *) MK_FP(sysdat, ppd);
  1768. for (mp_off = pdptr->P_MPAR; mp_off !=0;) {
  1769.     mp = MK_FP(sysdat, mp_off);
  1770.     mp_off = mp->link;
  1771.     if ((base_seg >= mp->start) && 
  1772. (base_seg < (mp->start + mp->length))) {
  1773. page = mp->xios;
  1774. for (i = 0; i < ((base_seg - mp->start)/1024); i++){
  1775.     ptr = MK_FP(mptbl, page*2);
  1776.     page = *ptr;
  1777. }
  1778. page = 4*page + (((base_seg - mp->start)/0x0100) & 3);
  1779. map_user_page(wp, page);
  1780. return(MK_FP(wp*0x0100,(seg*16+offset) & 0x0fff));
  1781.     }
  1782. }
  1783. /* not found in mpad's - must be non-banked address */
  1784. return(MK_FP(seg, offset));
  1785. }
  1786. MLOCAL VOID ip_poke(UWORD ppd, UWORD wp, UWORD seg, UWORD offset, UBYTE val)
  1787. {
  1788. UBYTE FAR *ptr;
  1789. ptr = map_pd_mem(ppd, wp, seg, offset);
  1790. *ptr = val;
  1791. }
  1792. MLOCAL UBYTE ip_peek(UWORD ppd, UWORD wp, UWORD seg, UWORD offset)
  1793. {
  1794. UBYTE FAR *ptr;
  1795. ptr = map_pd_mem(ppd, wp, seg, offset);
  1796. return(*ptr);
  1797. }
  1798. MLOCAL UWORD ip_peek_word(UWORD ppd, UWORD wp, UWORD seg, UWORD offset)
  1799. {
  1800. return (ip_peek(ppd, wp, seg, offset) + 
  1801. 256*ip_peek(ppd, wp, seg, offset+1));
  1802. }
  1803. GLOBAL VOID inherit_TMP_state(VOID)
  1804. /* inherit batch files */
  1805. /* NB. This is bodged - we don't inherit FOR state, or redirection */
  1806. {
  1807. PD FAR *parent;
  1808. UWORD batch_seg;
  1809. UWORD tmp_mpad;
  1810. UWORD mp_off;
  1811. MPAD FAR * mp;
  1812. VOID FAR *window;
  1813. UWORD win_page;
  1814. UWORD i;
  1815. parent = (PD FAR *) MK_FP(FP_SEG(pd), pd->P_PARENT);
  1816. /* verify our parent is a Tmp, forget if it isn't */
  1817. if ((parent->P_NAME[0] != 'T') ||
  1818.     (parent->P_NAME[1] != 'm') ||
  1819.     (parent->P_NAME[2] != 'p'))
  1820.     return;
  1821. /* allocate a 4k aligned window to bank data into */
  1822. i = 2*4096/16;
  1823. mem_alloc(&window, &i, i, i);
  1824. if (i==0)
  1825.     return;
  1826. win_page = (FP_SEG(window) + 0x0100) / 0x100;
  1827. batch_seg = ip_peek_word(pd->P_PARENT, win_page,
  1828. parent->P_PSP, TmpPspBatchSeg);
  1829. /* do we have any batch files to inherit */
  1830. if (batch_seg) {
  1831.             echoflg = (BOOLEAN)ip_peek_word(pd->P_PARENT, win_page,
  1832. ip_peek_word(pd->P_PARENT, win_page,
  1833.     parent->P_PSP, TmpPspDataSeg),
  1834. ip_peek_word(pd->P_PARENT, win_page,
  1835.     parent->P_PSP, TmpPspEchoFlgPtr));
  1836. /* recover Tmp's hidden mpads */
  1837.     tmp_mpad = ip_peek_word(pd->P_PARENT, win_page,
  1838. parent->P_PSP, TmpPspMpad);
  1839.     for (mp_off = parent->P_MPAR; mp_off != 0;) {
  1840. mp  = MK_FP(FP_SEG(parent), parent->P_MPAR);
  1841. mp_off  = mp->link;
  1842.     }
  1843.     mp->link = tmp_mpad;
  1844.     inherit_batch_file(pd->P_PARENT, win_page, batch_seg);
  1845.     mp->link = 0; /* unlink again */
  1846. }
  1847. map_user_page(0, 0); /* force user page to be unmapped */
  1848. bdos(141,0); /* dispatch to re-map TPA memory */
  1849. mem_free(&window); /* free the window */
  1850. }
  1851. MLOCAL VOID inherit_batch_file(UWORD ppd, UWORD win_page, UWORD batch_seg)
  1852. {
  1853. UBYTE FAR * dst;
  1854. BCONTROL FAR *save0;
  1855. FCONTROL *save1;
  1856. BYTE  *save2;
  1857. WORD  save3;
  1858. UWORD i;
  1859. UWORD data_seg;
  1860. PD FAR *parent;
  1861. /* if we are in a nested batch file, inherit older batch file first */
  1862. i = ip_peek_word(ppd, win_page, batch_seg, 2);
  1863. if (i != 0)
  1864.     inherit_batch_file( ppd, win_page, i);
  1865. batch_new(); /* new incarnation of batch */
  1866. save0 = batch->bcontrol; save1 = batch->fcontrol;
  1867. save2 = batch->heap_start; save3 = batch->heap_size;
  1868. dst = (BYTE FAR *) batch; /* copy batch structure */
  1869. for (i=0; i<sizeof(BCONTROL); i++) /* from parental PD */
  1870.     dst[i] = ip_peek(ppd, win_page, batch_seg, i);
  1871. /* now terminate parental batch processing by poking EOF */
  1872. ip_poke(ppd, win_page,
  1873. batch_seg, (UWORD) &batch->eof - (UWORD) &batch->bcontrol,
  1874. (UBYTE) TRUE);
  1875. /*
  1876.  * Copy the invoking command and the individual elements 
  1877.  * of the command line into a buffer ready for processing
  1878.  */
  1879. parent = (PD FAR *) MK_FP(FP_SEG(pd), pd->P_PARENT);
  1880. data_seg = ip_peek_word(pd->P_PARENT, win_page,
  1881. parent->P_PSP, TmpPspDataSeg);
  1882. i = (UWORD) batch->batcmd;
  1883. batch->batcmd = (BYTE *)heap(); /* Initialize Parameter Buffer */
  1884. while (ip_peek_word(ppd, win_page, data_seg, i) != 0)
  1885. *(BYTE *)heap_get(1) = ip_peek(ppd, win_page, data_seg, i++);
  1886. *(WORD *)heap_get(2) = 0; /* Double NULL is a terminator  */
  1887. /* for command line params  */
  1888. batch->bcontrol = save0; batch->fcontrol = save1;
  1889. batch->heap_start = save2; batch->heap_size = save3;
  1890. batchflg++; /* increment batch flag */
  1891. crlfflg  = YES; /* print CR/LF after this  */
  1892. }
  1893. #endif
  1894. EXTERN N_CMD novell_ext_list[];
  1895. EXTERN BYTE FAR * CDECL farptr(BYTE *);
  1896. EXTERN BYTE FAR * CDECL cgroupptr(BYTE *);
  1897. EXTERN BOOLEAN CDECL call_novell(BYTE *, BYTE *, WORD);
  1898. EXTERN BOOLEAN CDECL nov_station(WORD *);
  1899. EXTERN WORD    CDECL nov_connection();
  1900. MLOCAL BOOLEAN novell_extension(src,dst)
  1901. BYTE *src;
  1902. BYTE *dst;
  1903. /*
  1904.  * Check if src string is a novell string to be expanded. eg login_name.
  1905.  * if so, put expansion in dst.
  1906.  */
  1907. {
  1908. N_CMD FAR *n_cmd_p;
  1909. BYTE  FAR *cpf; 
  1910. WORD i;
  1911. for (i=0;src[i] && src[i]!='=';i++);
  1912. src[i] = 0;
  1913. n_cmd_p = (N_CMD FAR *)farptr((BYTE *)&novell_ext_list[0]);
  1914. while(n_cmd_p->string) {
  1915.     cpf = cgroupptr(n_cmd_p->string);
  1916.     for(i=0; (cpf[i]==src[i]) && src[i]; i++);
  1917.     if(cpf[i]==src[i]) {
  1918.         (*n_cmd_p->func)(dst);
  1919.      return(0);
  1920.     }
  1921.     
  1922.     n_cmd_p++;
  1923. }
  1924. return(1);
  1925. }
  1926. GLOBAL VOID CDECL get_login_name(dst)
  1927. BYTE *dst;
  1928. {
  1929. struct s_nov_e346_in {
  1930.     WORD len;
  1931.     BYTE code;
  1932. } nov_e346_in;
  1933. struct s_nov_e346_out {
  1934.     WORD len;
  1935.     BYTE level;
  1936.     LONG id;
  1937. } nov_e346_out;
  1938. struct s_nov_e336_in {
  1939.     WORD len;
  1940.     BYTE code;
  1941.     LONG id;
  1942. } nov_e336_in;
  1943. struct s_nov_e336_out {
  1944.     WORD len;
  1945.     LONG id;
  1946.     WORD type;
  1947.     BYTE name[48];
  1948. } nov_e336_out;
  1949. nov_e346_in.len  = 1;
  1950. nov_e346_in.code = 0x46;
  1951. nov_e346_out.len = 5;
  1952. nov_e346_out.id = -1L;
  1953. call_novell((BYTE *)&nov_e346_in, (BYTE *)&nov_e346_out, 0xE3);
  1954. if (nov_e346_out.id == -1L) {
  1955.     *dst = 0;
  1956.     return;
  1957. }
  1958. nov_e336_in.len  = 5;
  1959. nov_e336_in.code = 0x36;
  1960. nov_e336_in.id   = nov_e346_out.id;
  1961. nov_e336_out.len = 54;
  1962. call_novell((BYTE *)&nov_e336_in, (BYTE *)&nov_e336_out, 0xE3);
  1963. strcpy(dst,nov_e336_out.name);
  1964. }
  1965. GLOBAL VOID CDECL get_pstation(dst)
  1966. BYTE *dst;
  1967. {
  1968. WORD sn[3];
  1969. if (nov_station(sn)) {
  1970.     *dst = 0;
  1971.     return;
  1972. }
  1973. sprintf(dst,"%04X%04X%04X",sn[0],sn[1],sn[2]);
  1974. }
  1975. GLOBAL VOID CDECL get_full_name(dst)
  1976. BYTE *dst;
  1977. {
  1978. /* scan bindery */
  1979. struct s_nov_e337_in {
  1980. WORD len;
  1981. BYTE code;
  1982. LONG last_object_id;
  1983. WORD object_type;
  1984. BYTE object_name_len;
  1985. BYTE object_name[48];
  1986. } nov_e337_in;
  1987. struct s_nov_e337_out {
  1988. WORD len;
  1989. LONG object_id;
  1990. WORD object_type;
  1991. BYTE object_name[48];
  1992. BYTE object_flag;
  1993. BYTE object_security;
  1994. BYTE object_has_properties;
  1995. } nov_e337_out;
  1996. /* scan property */
  1997. struct s_nov_e33c_in {
  1998. WORD len;
  1999. BYTE code;
  2000. WORD object_type;
  2001. BYTE object_name_len;
  2002. BYTE object_name[48];
  2003. LONG sequence_num;
  2004. BYTE property_name_len;
  2005. BYTE property_name[16];
  2006. } nov_e33c_in;
  2007. struct s_nov_e33c_out {
  2008. WORD  len;
  2009. BYTE property_name[16];
  2010. BYTE property_flags;
  2011. BYTE property_security;
  2012. LONG sequence_num;
  2013. BYTE property_has_value;
  2014. BYTE more_properties;
  2015. } nov_e33c_out;
  2016. /* read property */
  2017. struct s_nov_e33d_in {
  2018. WORD  len;
  2019. BYTE code;
  2020. WORD object_type;
  2021. BYTE object_name_len;
  2022. BYTE object_name[48];
  2023. BYTE segment_num;
  2024. BYTE property_name_len;
  2025. BYTE property_name[16];
  2026. } nov_e33d_in;
  2027. struct s_nov_e33d_out {
  2028. WORD len;
  2029. BYTE property_value[128];
  2030. BYTE more_segments;
  2031. BYTE property_flags;
  2032. } nov_e33d_out;
  2033. int res;
  2034. get_login_name(nov_e337_in.object_name);
  2035. nov_e337_in.object_name_len = strlen(nov_e337_in.object_name);
  2036. if (!nov_e337_in.object_name_len){
  2037. *dst = 0;
  2038. return;
  2039. }
  2040. nov_e337_in.code = 0x37;
  2041. nov_e337_in.len = sizeof(struct s_nov_e337_in) - 2;
  2042. nov_e337_out.len = sizeof(struct s_nov_e337_out) -2 ;
  2043. nov_e337_in.last_object_id = -1L;
  2044. nov_e337_in.object_type = 0x0100;  /*user*/
  2045. for(;;){
  2046. res = call_novell((BYTE *)&nov_e337_in, (BYTE *)&nov_e337_out, 0xe3 );
  2047. if ( res == 0xfc )
  2048. break;
  2049. else if ( res ){
  2050. *dst= 0;
  2051. return;
  2052. }
  2053. if ( nov_e337_out.object_has_properties ){
  2054.    nov_e33c_in.code = 0x3c;
  2055.    nov_e33c_in.len = sizeof(struct s_nov_e33c_in) - 2;
  2056.    nov_e33c_out.len = sizeof(struct s_nov_e33c_out) - 2;
  2057.    nov_e33c_in.object_type = nov_e337_out.object_type;
  2058.    nov_e33c_in.object_name_len = sizeof( nov_e33c_in.object_name );
  2059.    strcpy( nov_e33c_in.object_name, nov_e337_out.object_name );
  2060.    nov_e33c_in.sequence_num = -1L;
  2061.    nov_e33c_in.property_name_len = 1;
  2062.    nov_e33c_in.property_name[0] = '*';
  2063.    for(;;){
  2064.           res = call_novell( (BYTE *)&nov_e33c_in, (BYTE *)&nov_e33c_out, 0xe3 );
  2065.   if ( res == 0xfb )
  2066. break;
  2067.   else if ( res ){
  2068. *dst = 0;
  2069. return;
  2070. }
  2071.   if ( nov_e33c_out.property_has_value ){
  2072. nov_e33d_in.code = 0x3d;
  2073. nov_e33d_in.len = sizeof (struct s_nov_e33d_in) - 2;
  2074. nov_e33d_out.len = sizeof (struct s_nov_e33d_out) - 2;
  2075. nov_e33d_in.object_type = nov_e337_out.object_type;
  2076. nov_e33d_in.object_name_len = sizeof( nov_e33d_in.object_name );
  2077. strcpy( nov_e33d_in.object_name, nov_e337_out.object_name );
  2078. nov_e33d_in.segment_num = 1;
  2079. nov_e33d_in.property_name_len = strlen( nov_e33c_out.property_name );
  2080. strcpy(nov_e33d_in.property_name, nov_e33c_out.property_name );
  2081. for(;;){
  2082. res = call_novell( (BYTE *)&nov_e33d_in, (BYTE *)&nov_e33d_out, 0xe3);
  2083. if ( res == 0xec )
  2084. break;
  2085. else if ( res ){
  2086. *dst = 0;
  2087. return;
  2088. }
  2089. if (!strcmp(nov_e33c_out.property_name,"IDENTIFICATION")){
  2090. strcpy(dst,nov_e33d_out.property_value);
  2091. return;
  2092. }
  2093. nov_e33d_in.segment_num++;
  2094. }/*for*/
  2095.           }/*if*/
  2096.       nov_e33c_in.sequence_num = nov_e33c_out.sequence_num;
  2097.   }/*for*/
  2098.     nov_e337_in.last_object_id = nov_e337_out.object_id;
  2099.     }/*if*/
  2100. }/*for*/
  2101. }
  2102. GLOBAL VOID CDECL get_hour(dst)
  2103. BYTE *dst;
  2104. {
  2105. SYSTIME  time;
  2106. ms_gettime(&time);
  2107. if (time.hour > 12) time.hour -= 12;
  2108. if (time.hour == 0) time.hour = 12;
  2109. sprintf(dst,"%d",time.hour);
  2110. }
  2111. GLOBAL VOID CDECL get_hour24(dst)
  2112. BYTE *dst;
  2113. {
  2114. SYSTIME  time;
  2115. ms_gettime(&time);
  2116. sprintf(dst,"%02d",time.hour);
  2117. }
  2118. GLOBAL VOID CDECL get_minute(dst)
  2119. BYTE *dst;
  2120. {
  2121. SYSTIME  time;
  2122. ms_gettime(&time);
  2123. sprintf(dst,"%02d",time.min);
  2124. }
  2125. GLOBAL VOID CDECL get_second(dst)
  2126. BYTE *dst;
  2127. {
  2128. SYSTIME  time;
  2129. ms_gettime(&time);
  2130. sprintf(dst,"%02d",time.sec);
  2131. }
  2132. GLOBAL VOID CDECL get_am_pm(dst)
  2133. BYTE *dst;
  2134. {
  2135. SYSTIME time;
  2136. BYTE FAR *p;
  2137. ms_gettime(&time);
  2138. if (time.hour >= 12) p = cgroupptr(PM_TIME);
  2139. else      p = cgroupptr(AM_TIME);
  2140. while (*p) *dst++ = *p++;
  2141. *dst = 0;
  2142. }
  2143. GLOBAL VOID CDECL get_greeting(dst)
  2144. BYTE *dst;
  2145. {
  2146. SYSTIME time;
  2147. BYTE FAR *p;
  2148. ms_gettime(&time);
  2149. if (time.hour < 12)
  2150.     p = cgroupptr(GREETING_MORNING);
  2151. else if (time.hour < 17)
  2152.     p = cgroupptr(GREETING_AFTERNOON);
  2153. else
  2154.     p = cgroupptr(GREETING_EVENING);
  2155. while (*p) *dst++ = *p++;
  2156. *dst = 0;
  2157. }
  2158. GLOBAL VOID CDECL get_year(dst)
  2159. BYTE *dst;
  2160. {
  2161. SYSDATE date;
  2162. ms_getdate(&date);
  2163. sprintf(dst,"%d",date.year);
  2164. }
  2165. GLOBAL VOID CDECL get_short_year(dst)
  2166. BYTE *dst;
  2167. {
  2168. SYSDATE date;
  2169. ms_getdate(&date);
  2170. sprintf(dst,"%d",date.year%100);
  2171. }
  2172. GLOBAL VOID CDECL get_month(dst)
  2173. BYTE *dst;
  2174. {
  2175. SYSDATE date;
  2176. ms_getdate(&date);
  2177. sprintf(dst,"%d",date.month);
  2178. }
  2179. GLOBAL VOID CDECL get_month_name(dst)
  2180. BYTE *dst;
  2181. {
  2182. SYSDATE date;
  2183. BYTE *m;
  2184. ms_getdate(&date);
  2185. switch(date.month) {
  2186. case 1:  m = JAN_M; break;
  2187. case 2:  m = FEB_M; break;
  2188. case 3:  m = MAR_M; break;
  2189. case 4:  m = APR_M; break;
  2190. case 5:  m = MAY_M; break;
  2191. case 6:  m = JUN_M; break;
  2192. case 7:  m = JUL_M; break;
  2193. case 8:  m = AUG_M; break;
  2194. case 9:  m = SEP_M; break;
  2195. case 10: m = OCT_M; break;
  2196. case 11: m = NOV_M; break;
  2197. case 12: m = DEC_M; break;
  2198. }
  2199. sprintf(dst,"%s",m);
  2200. }
  2201. GLOBAL VOID CDECL get_day(dst)
  2202. BYTE *dst;
  2203. {
  2204. SYSDATE date;
  2205. ms_getdate(&date);
  2206. sprintf(dst,"%d",date.day);
  2207. }
  2208. GLOBAL VOID CDECL get_nday_of_week(dst)
  2209. BYTE *dst;
  2210. {
  2211. SYSDATE date;
  2212. ms_getdate(&date);
  2213. sprintf(dst,"%d",date.dow+1);
  2214. }
  2215. GLOBAL VOID CDECL get_day_of_week(dst)
  2216. BYTE *dst;
  2217. {
  2218. SYSDATE date;
  2219. ms_getdate(&date);
  2220. sprintf(dst,"%s",day_names(date.dow));
  2221. }
  2222. GLOBAL VOID CDECL get_os_version(dst)
  2223. BYTE *dst;
  2224. {
  2225. env_scan("VER=",dst);
  2226. }
  2227. GLOBAL VOID CDECL get_connection(dst)
  2228. BYTE *dst;
  2229. {
  2230. int i;
  2231. i = nov_connection();
  2232. if (i==-1) {
  2233.     *dst = 0;
  2234.     return;
  2235. }
  2236. sprintf(dst,"%d",i);
  2237. }