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

操作系统开发

开发平台:

Asm

  1. /*
  2. ;    File              : $Workfile: SUPPORT.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. ;
  34. ;    ENDLOG
  35. */
  36. /*
  37. File SUPPORT.C
  38. Title SUPPORT routines for command.com 
  39. Revision History:-
  40. ==================
  41. Date       Description
  42. -----------------------------------------------------------------------------
  43. 10 Apr 86  EQU function now makes a case independant match.
  44. 29 Apr 86  Single $ preceeds the screen control variables
  45.            Fix bug where if the last character of a screen control
  46.            variable was an octal character it was not printed
  47.  6 May 86  yes() now requires a default to be specified previously
  48.            it assumed the default was NO.
  49. 21 May 86  Fixed bug with yes() function when default is NO.
  50. 22 May 86  Allow the screen control codes to be patched to longer strings
  51.            Upd`te ZAP_SPACES to delete all white space
  52. Version 1.2
  53. ===========
  54. 31 Jul 86  Conditionally remove functions that cannot be fully supported
  55.            in a CDOS version of COMMAND.COM
  56.  4 Aug 86  ANSI C compatibility MSC /W1
  57. 30 Oct 86  FREE_DRIVE now forces the drive to point to the root
  58.            directory of the current drive.
  59. 17 Feb 87  Rewrote repwild() function to fix minor problems 
  60.    Aug 87  Make all routines PASCAL calling convention  (for Concurrent 6)
  61. 26 Oct 87  Update the F_CHECK routine to support multiple switches ie
  62.            "/wc" as well as "/w /c".
  63. 27 Oct 87  Stop F_CHECK from forcing the input line to lower case.
  64. 10 Nov 87  Modify F_CHECK flag zapping
  65. 18 Nov 87  Prevent GET_FILENAME copying a filename > than MAX_PATHLEN
  66. 16 Dec 87  Update D_CHECK to make fewer system calls.
  67. 29 Feb 88  Tidy the REPWILD routine - No Functional Change
  68. 15 Mar 88  Use ANSI Escape sequences for DOS Plus
  69. 27 Apr 88  Restore Range check to D_CHECK routine
  70. 25 May 88  Print a CR after a CLS to reset the current column count.
  71. 26 May 88  Change the Default HighLight and LowLight strings to NULL
  72.            for DOSPLUS. 
  73. 27 May 88  Added string undefs.
  74. 23 Jun 88  Add new ONOFF function for XXX [=] ON|OFF parsing 
  75. 28 Jun 88  Correct bug in YES routine for FAR messages
  76.  1 Jul 88  Support Control-C from YES for TMP.
  77.  6 Jul 88  Support the CON:filename syntax for COPY.
  78. 19 Sep 88  Enhance error checking on the F_CHECK routine. Now traps the
  79.            condition when switchar is at the end of the line.
  80.  1 Dec 88  Convert all path parsing routines to be KANJI friendly.
  81. 21 Dec 88  Add generic ISDEV routine to SUPPORT.C
  82. 21 Dec 88  "*" to "*.*" conversion moved to CMD_DIR. 
  83. 18 Apr 89  c_write: write to STDERR if err_flag set
  84. 6 Jun 89   Correct GET_FILENAME to parse path passwords.
  85. 6 Jun 89   echo: check for endline after on/off.
  86. 10 Aug 89  get rid of sysdate_fmt (year does not need to be %04d, which
  87.            upsets Japanese day)
  88. 10 Aug 89  day_name_len for day_names array elements
  89. 22 Aug 89  Japanese dayname comes after date
  90.            Remove day_name_len & work out length from array.
  91. 11 Sep 89  strupr(), strlwr() and stricmp() are now Kanji aware.
  92.            toupper() is now in DOSIF.ASM and uses international routine.
  93. 16 Oct 89  Kanji specific routines replaced with DBCS routines.
  94. 30 Oct 89  "Internal Error" moved to message.c (and no longer resident)
  95. 15 Dec 89  errors 50-72 give "Network error" rather than "Internal error"
  96. 6-Mar-90   Watcom C v 7.0
  97. 13-Mar-90  Output CR/LF after errors
  98. 4-May-90   append_slash added
  99. 4-May-90   get_filename stops at ';' unless followed by pathchar(s)
  100.            ("append;" bug)
  101. 20-Sep-90  Created skip_char() and copy_char().
  102.            Created is_blank() and amended deblank(), zap_spaces(),
  103.            is_filechar() and is_pathchar() to use it.
  104. 13-Mar-91  changed nofiles() function to cope with DIR.. on NOVELL drives.
  105. 18-Mar-91  tolower() ( and therefore strlwr() ) is now aware of TURKISH
  106.            capital I's with dots. 
  107. 6-Aug-91   prompt_exec() function no longer uses the heap. This screwed us
  108.            up if the file to be execed was a batch file.
  109. 09-Jun-92  is_pathchar and d_check now cope with drive '[', etc, as used
  110.            by some novell applications. See also INVALID_DRV in command.h.
  111. 18-Jun-92  Added optional_line() function for '?' support in batch files.
  112. -----------------------------------------------------------------------------
  113. */
  114. #include "defines.h"
  115. #include <setjmp.h>
  116. /*#include <string.h>*/
  117. #if defined(MWC) && defined(strlen)
  118. #undef strcmp /* These are defined as macros in string.h */
  119. #undef strcpy /* which are expaneded in line under */
  120. #undef strlen /* Metaware C. These undefs avoid this. */
  121. #endif
  122. #include <portab.h>
  123. #include <mserror.h>
  124. #if defined(CDOSTMP)
  125. #include <ccpm.h>
  126. #include <sysdat.h>
  127. #endif
  128. #include "command.h"
  129. #include "toupper.h"
  130. #include "dosif.h"
  131. #include "global.h"
  132. #include "dos.h"
  133. EXTERN jmp_buf break_env;
  134. EXTERN VOID CDECL printf(BYTE *, ...);
  135. EXTERN VOID CDECL eprintf(BYTE *, ...);
  136. EXTERN VOID CDECL sprintf(BYTE *, BYTE *, ...);
  137. #if defined(CDOSTMP)
  138. EXTERN VOID CDECL int_break(VOID); /* COM.C Internal Break */
  139. #endif
  140. MLOCAL VOID screen(BYTE *, BYTE *);
  141. MLOCAL VOID outs(BYTE *);
  142. GLOBAL VOID crlf(VOID);
  143. GLOBAL VOID putc(BYTE);
  144. GLOBAL VOID c_write(BYTE *, UWORD);
  145. GLOBAL BYTE * fptr(BYTE *);
  146. GLOBAL BYTE * day_names(UWORD);
  147. /*.pa*/
  148. /*
  149.  * The following screen control sequences can be redefined or removed
  150.  * by entries in the environment or the OEM can patch these areas in the
  151.  * COMMAND.COM object and change the default values.
  152.  *
  153.  */
  154. #define CLS_KEY  "$CLS="  /* CLS entry in environment     */
  155. #define REVON_KEY "$ON=" /* REVON entry in environment     */
  156. #define REVOFF_KEY "$OFF="  /* REVOFF entry in environment     */
  157. #ifdef DOSPLUS
  158. /*
  159.  * For DOSPLUS the default screen control sequences are for an
  160.  * ANSI Terminal (IBM Sub-Set).
  161.  */
  162. #define CLS_DEF  "33[2J***" /* Default CLS string "ESC [2J"*/
  163. #define REVON_DEF "********" /* Default REVON string NULL   */
  164. #define REVOFF_DEF "********" /* Default REVOFF string NULL  */
  165. EXTERN BOOLEAN CDECL int10_cls(VOID); /* Dirty Clear Screen Subroutine    */
  166. #else
  167. /*
  168.  * For Concurrent DOS the default screen control sequences are for a
  169.  * standard VT52 Terminal.
  170.  */
  171. #define CLS_DEF  "33E*****" /* Default CLS string "ESC E"     */
  172. #define REVON_DEF "33p*****" /* Default REVON string "ESC p"     */
  173. #define REVOFF_DEF "33q*****" /* Default REVOFF string "ESC q"    */
  174. #endif
  175. /* Invalid FileName Characters as   */
  176. /* specified by the IBM DOS Tech    */
  177. /* Reference Page 6-96 "func 29"    */
  178. MLOCAL BYTE invalid_filechar[] = "*?\.:;,=+<>|/"[]";
  179. /*.pa*/
  180. /*
  181.  * TIME AND DATE SUPPORT ROUTINES
  182.  * ==============================
  183.  *
  184.  * The following routines print the TIME and DATE using the international
  185.  * data. Two sets of routines are provided to display the SYSTEM Time and
  186.  * Date the second routine displays FILE based time and date.
  187.  */
  188. MLOCAL BYTE date_fmt []    = "%2d%c%02d%c%02d";
  189. GLOBAL VOID disp_filetime(time)
  190. unsigned time;
  191. {
  192. WORD h, m;
  193. BYTE ap;
  194. ap = ' '; /* assume no AM/PM used */
  195. h = (time >> 11);
  196. m = (time >> 5) & 0x3f;
  197. if (country.ampm == 0) /* if anglo saxon fashion */
  198. { /* need to convert things */
  199.     ap = 'a'; /* assume morning */
  200.     if (h == 0)  /* 00:00 through 00:59 */
  201. h = 12;  /*    is special... */
  202.     else if (h >= 12) /* test if afternoon */
  203.     {
  204. ap = 'p'; /* mark as afternoon */
  205. if (h > 12) /* if 13:00 through 23:59 */
  206.     h -= 12; /* need to make " 1:00p" */
  207.     }
  208. }
  209. printf ("%2d%c%02d%c",
  210. h, country.dtime[0], /* print hour, delimiter */
  211. m, ap);  /* print minute, am/pm (if enabled) */
  212. }
  213. GLOBAL VOID disp_filedate(date)
  214. unsigned date;
  215. {
  216. WORD y, m, d;
  217. WORD b;
  218. y = ((date >> 9) + 80)%100;
  219. m = (date >> 5) & 0x0f;
  220. d = date & 0x1f;
  221. b = country.ddate[0];
  222. switch (country.dt_fmt)
  223. {
  224.  case 1: /* European format dd/mm/yy */
  225.     printf (date_fmt, d,b,m,b,y);
  226.     break;
  227.  case 2: /* Japanese format yy/mm/dd */
  228.     printf (date_fmt, y,b,m,b,d);
  229.     break;
  230.  default: /* US format mm/dd/yy for the rest*/
  231.     printf (date_fmt, m,b,d,b,y);
  232.     break;
  233. };
  234. }
  235. GLOBAL VOID disp_systime()
  236. {
  237. SYSTIME  time;
  238. WORD b = country.dtime[0];
  239. ms_gettime(&time);
  240. printf ("%2d%c%02d%c%02d.%02d",
  241. time.hour, b, /* print hour, delimiter */
  242. time.min, b, /* print minute, delimiter */
  243. time.sec, time.hsec); /* Print the second and Hundredths */
  244. }
  245. /* Return address of null terminated day name, given index (day). */
  246. GLOBAL BYTE * day_names(day)
  247. UWORD day; /* day of week: 0=sunday, 1=monday, .. */
  248. {
  249.     switch (day)
  250.     {
  251.     case 0: return SUN_D;
  252.     case 1: return MON_D;
  253.     case 2: return TUE_D;
  254.     case 3: return WED_D;
  255.     case 4: return THU_D;
  256.     case 5: return FRI_D;
  257.     default: break;
  258.     }
  259.     return SAT_D;
  260. }
  261. GLOBAL VOID disp_sysdate()
  262. {
  263. SYSDATE date;
  264. WORD y, m, d;
  265. WORD b;
  266. ms_getdate(&date); /* Get the current date */
  267. y = date.year;
  268. m = date.month;
  269. d = date.day;
  270. b = country.ddate[0];
  271. if (country.dt_fmt != 2) /* Japanese day comes after date */
  272.     printf("%s ", day_names(date.dow));
  273. switch (country.dt_fmt)
  274. {
  275.  case 1: /* European format dd/mm/yy */
  276.     printf (date_fmt, d,b,m,b,y);
  277.     break;
  278.  case 2: /* Japanese format yy/mm/dd */
  279.     printf (date_fmt, y,b,m,b,d);
  280.     printf(" %s", day_names(date.dow));
  281.     break;
  282.  default: /* US format mm/dd/yy for the rest*/
  283.     printf (date_fmt, m,b,d,b,y);
  284.     break;
  285. };
  286. }
  287. /*.pa*/
  288. /*
  289.  * Screen handling routines to CLEAR the screen and emphasise text
  290. */
  291. GLOBAL VOID CDECL cmd_cls()
  292. {
  293. #if defined(DOSPLUS)
  294.   if(!int10_cls()) /* If no console device is */
  295.     screen(CLS_KEY, CLS_DEF); /* active use the default  */
  296. /* $CLS string.    */
  297. #else /* For Concurrent DOS never*/
  298. screen(CLS_KEY, CLS_DEF); /* use INT 10    */
  299. #endif /* Finally print a CR to   */
  300. putc('r'); /* reset the internal    */
  301. /* Column count.    */
  302. }
  303. GLOBAL VOID revon()
  304. {
  305. screen(REVON_KEY, REVON_DEF);
  306. }
  307. GLOBAL VOID revoff()
  308. {
  309. screen(REVOFF_KEY, REVOFF_DEF);
  310. }
  311. MLOCAL VOID screen(key, def)
  312. BYTE *key; /* Key name to match in the environment */
  313. BYTE *def; /* Default string to output if no match */
  314. {
  315. REG BYTE *cp;
  316. if(!env_scan(key, cp = (BYTE *)heap()))
  317. /* and then search for the key  */
  318.     outs(cp); /* output the string on a match */
  319. else /* otherwise use the default */
  320.     printf(def); /* supplied on entry */
  321. }
  322. /*
  323.  * This string output function will output a string containing
  324.  * a C format imbedded Octal number. This is mainly used for the
  325.  * CLS function.
  326.  */
  327. MLOCAL VOID outs(s)
  328. BYTE *s;
  329. {
  330. BYTE b = 0;
  331. REG WORD f = 0;
  332. for(; *s; s++) {
  333. if(f) {  /* Generating an OCTAL number*/
  334.     if(*s >= '0' && *s < '8') { /* check for a valid number  */
  335. b <<= 3; /* and flush the buffer if it*/
  336. b += *s - '0'; /* is illegal. Otherwise add */
  337.     } /* to the buffer and flush   */
  338.     else { /* after three characters    */
  339. if(f != 3)
  340.     putc(b);
  341. putc(*s);
  342. f = 0;
  343. continue;
  344.     }
  345.     if(f-- == 1)
  346. putc(b);
  347.     continue;
  348. }
  349. if(*s == '\') {
  350.     f = 3; /* Initialise the Character count */
  351.     b = 0; /* Zero the display value   */
  352.     continue;
  353. }
  354. putc(*s);
  355. }
  356. if(f && b)
  357.     putc(b);
  358. }
  359. /*.pa*/
  360. /*
  361.  * GENERAL PURPOSE STRING MANIPULATION ROUTINES
  362.  * ============================================
  363.  *
  364.  */
  365. GLOBAL BYTE tolower(b)
  366. BYTE b;
  367. {
  368. if (b==0x8D) return('i'); /* For turkish dotted capital I */
  369. return((b < 'A' || b > 'Z') ? b : b + 0x20);
  370. }
  371. GLOBAL BOOLEAN isdigit(b)
  372. BYTE b;
  373. {
  374. return (b >= '0' && b <= '9');
  375. }
  376. GLOBAL BYTE * skip_char(s)
  377. REG BYTE *s;
  378. {
  379. s++;
  380. if (dbcs_lead(*(s - 1)) && *s >= ' ')
  381.     s++;
  382. return(s);
  383. }
  384. GLOBAL BYTE * copy_char(dest, source)
  385. REG BYTE **dest, **source;
  386. {
  387. if (dbcs_lead(**source))
  388. {
  389.     if (*(*source + 1) >= ' ')
  390.     {
  391. *(*dest)++ = *(*source)++;
  392. *(*dest)++ = *(*source);
  393.     }
  394. }
  395. else
  396. {
  397.     *(*dest)++ = *(*source);
  398. }
  399. (*source)++;
  400. return(*source);
  401. }
  402. /* Check if character in string is blank.
  403.    Return size in bytes of blank character, zero if not blank character. */
  404. GLOBAL WORD is_blank(s)
  405. REG BYTE *s;
  406. {
  407. WORD blank_size;
  408. if (*s == ' ' || *s == 't')
  409.     blank_size = 1;
  410. else if (dbcs_expected() && *s == 0x81 && *(s + 1) == 0x40)
  411.     blank_size = 2; /* KANJI space */
  412. else
  413.     blank_size = 0;
  414. return(blank_size);
  415. }
  416. GLOBAL BYTE * deblank(s)  /* scan off leading white space */
  417. REG BYTE *s; /* starting address of scan */
  418. {
  419. REG WORD blank_size;
  420. while ((blank_size = is_blank(s)) != 0)
  421.     s += blank_size;
  422. return (s); /* return deblanked string */
  423. }
  424. #if !(defined(MSC) || defined(MWC) || defined(TURBOC) || defined(WATCOMC))
  425. GLOBAL BYTE * strchr(s, b)
  426. BYTE *s, b;
  427. {
  428. while(b != *s && *s)
  429.     s++;
  430. if(*s)
  431.     return s;
  432. else
  433.     return NULL;
  434. }
  435. #endif
  436. /* Convert all uppercase characters in ASCIIZ string to lowercase. 
  437.    If country code is JAPAN Kanji character code pairs (ie 8 bit Kanji
  438.    escape code followed immediatly by 8 bit Kanji character code) are 
  439.    not changed. */
  440. GLOBAL BYTE  *strlwr(s)
  441. BYTE *s;
  442. {
  443. REG BYTE *bp;
  444.     if (dbcs_expected()) /* are we looking out for DBCS? */
  445.     { /*  yes - DON'T CHANGE DBCS CODES */
  446. for (bp = s; *bp; bp++)
  447. {
  448.          if (dbcs_lead(*bp)) /* is this first of a DBCS pair? */
  449.     {
  450.      bp++; /*  yes - skip over it */
  451. if (*bp == '') /* it is followed by its partner? */
  452.     break; /*  no - invalid DBCS, exit loop */
  453.     }
  454.     else
  455.      *bp = tolower(*bp); /*  no - lower case it */
  456. }
  457.     }
  458.     else
  459.      for (bp = s; *bp; bp++)
  460.          *bp = tolower(*bp);
  461.     return s;
  462. }
  463. /* Convert all lowercase characters in ASCIIZ string to uppercase. 
  464.    Double byte characters are not changed. */
  465. GLOBAL BYTE  *strupr(s)
  466. BYTE *s;
  467. {
  468. REG BYTE *bp;
  469.     if (dbcs_expected()) /* are we looking out for DBCS? */
  470.     { /*  yes - DON'T CHANGE DBCS CODES */
  471. for (bp = s; *bp; bp++)
  472. {
  473.          if (dbcs_lead(*bp)) /* is this first of a DBCS pair? */
  474.     {
  475.      bp++; /*  yes - skip over it */
  476. if (*bp == '') /* it is followed by its partner? */
  477.     break; /*  no - invalid DBCS, exit loop */
  478.     }
  479.     else
  480.      *bp = toupper(*bp); /*  no - upper case it */
  481. }
  482.     }
  483.     else
  484.      for (bp = s; *bp; bp++)
  485.          *bp = toupper(*bp);
  486.     return s;
  487. }
  488. /*
  489.  * STRNICMP does a caseless match on the two input strings for LEN
  490.  * characters. This function is only used for token matching for
  491.  * commands like FOR and IF. Double byte character set aware.
  492.  */
  493. GLOBAL WORD  strnicmp(str1, str2, len)
  494. REG BYTE *str1, *str2;
  495. UWORD  len;
  496. {
  497. while (len--) /* loop until len == 0 */
  498. {
  499.     if (dbcs_lead(*str1) || dbcs_lead(*str2))
  500.     { /* one or both characters are DBCS */
  501.      if (*str1 != *str2) /* are they identical? */
  502.     return -1; /*  no - return SMALER */
  503. if(!*str1)
  504.             break;
  505. str1++; str2++; /* skip DBCS escape */
  506. if (*str1 != *str2) /* are DBCS char codes identical? */
  507.     return -1; /*  no - return SMALLER */
  508.     }
  509.     else
  510.      if (toupper(*str1) != toupper(*str2))
  511.     return -1;
  512.     if(!*str1)
  513.         break;
  514.     str1++; str2++;
  515. }
  516. return 0; /* return EQUAL */
  517. }
  518. /*
  519.  * ZAP_SPACES removes all white space from a string
  520.  */
  521. GLOBAL VOID zap_spaces(cp)
  522. REG BYTE *cp;
  523. {
  524. REG BYTE *cp1;
  525. do {
  526.     cp1 = deblank(cp); /* Skip leading whitespace   */
  527.     if (cp1 != cp) /* If whitespace has been    */
  528. strcpy(cp, cp1); /* skipped then move string  */
  529.     while (*cp && !is_blank(cp)) /* Now skip over     */
  530. cp++; /* normal characters */
  531. /* and repeat till the end    */
  532. } while (*cp);
  533. }
  534. GLOBAL VOID strip_path(path, dir)
  535. BYTE *path;
  536. BYTE *dir;
  537. {
  538. REG BYTE *cp;
  539. REG WORD i;
  540. i = 0; /* assume empty path */
  541. for (cp=path; *cp; cp++) { /* scan the file name */
  542.     if(dbcs_lead(*cp)) { /* If this is a DBCS */
  543.         cp++; /* character then skip  */
  544. continue; /* the next char */
  545.     }
  546.     if ((*cp == *pathchar) || /* if path delimiter */
  547. (*cp == ':')) /* or drive specifier */
  548. i = (cp+1)-path; /* remember offset */
  549. }
  550. strcpy (dir, path); /* make a copy */
  551. dir[i] = ''; /* discard all but path */
  552. }
  553. GLOBAL BOOLEAN getdigit(n, s)
  554. WORD *n; /* Pointer to the word number to save */
  555. BYTE **s; /* String to Process */
  556. {
  557. *n = 0;  /* Zero the number */
  558. while(!isdigit(**s) && **s) /* Skip all non digits */
  559.     (*s)++;
  560. if(**s) {
  561.     while(isdigit(**s)) { /* Add all the digits in */
  562. *n = **s - '0' + *n * 10;
  563. (*s)++;
  564.     }
  565.     return TRUE; /* and return success */
  566. }
  567. else
  568.     return FALSE;
  569. }
  570. /*
  571.  * Check that the number input by the user and held in S is in
  572.  * the range specified by MIN and MAX if this is so then update
  573.  * VALUE and return SUCCESS otherwise VALUE is unchabged and 
  574.  * return FAILURE.
  575.  */
  576. GLOBAL BOOLEAN check_num(s, min, max, value)
  577. BYTE *s; /* Input String */
  578. WORD min, max; /* Minimum and Maximum values */
  579. UWORD *value;  /* Value Input */
  580. {
  581. WORD u;
  582. deblank(s);
  583. if(getdigit(&u, &s) == FALSE)
  584.     return FAILURE;
  585. if(*s)
  586.     return FAILURE;
  587. if(u < min || u > max)
  588.     return FAILURE;
  589. *value = u;
  590. return SUCCESS;
  591. }
  592. GLOBAL BOOLEAN iswild (path)
  593. REG BYTE *path;
  594. {
  595. while (*path && (*path != '*') && (*path != '?'))
  596.     path ++;
  597. return (*path != '');
  598. }
  599. GLOBAL BOOLEAN is_filechar(s)
  600. REG BYTE *s;
  601. {
  602. if (*s == 0) return FALSE;
  603. if (is_blank(s) || strchr(invalid_filechar, *s))
  604.     return FALSE;
  605. return TRUE;
  606. }
  607. GLOBAL BOOLEAN is_pathchar(s)
  608. REG BYTE *s;
  609. {
  610. if (is_filechar(s) ||
  611.    *s == *pathchar ||
  612.    *s == '.' ||
  613.    *s == ':' ||
  614.    (*s >= 'Z'+1 && *s <= 'Z'+6))
  615. return TRUE;
  616. return FALSE;
  617. }
  618. /*
  619.  * Copy the file specification from OLDPATH to the buffer NEWPATH
  620.  * and return a pointer to the first byte after the extracted name.
  621.  * Remove any terminating ':' character from the file specification
  622.  * as the FDOS/PCMODE will try to match all characters in the string.
  623.  */
  624. GLOBAL BYTE * get_filename(newpath, oldpath, ambiguous)
  625. REG BYTE *oldpath, *newpath;
  626. BOOLEAN ambiguous;
  627. {
  628. UWORD count = 0;
  629. BYTE *pathname = oldpath;
  630. #if defined(PASSWORD)
  631. while(is_pathchar(oldpath) ||
  632.       ((*oldpath == *pwdchar) && (is_pathchar(oldpath + 1))) ||
  633.       (ambiguous && (*oldpath == '*' || *oldpath == '?'))) {
  634. #else
  635. while(is_pathchar(oldpath) ||
  636.       (ambiguous && (*oldpath == '*' || *oldpath == '?'))) {
  637. #endif
  638.     if(++count < MAX_PATHLEN) {
  639.         *newpath++ = *oldpath;
  640. if(dbcs_lead(*oldpath)) {
  641.       *newpath++=*++oldpath;
  642.     count++;
  643. }
  644.     }
  645.     if(*oldpath++ == ':' && count > 2 && !is_pathchar(oldpath)) {
  646. /* Handle the CON:filename  */
  647.         newpath--; /* so loved by the users of */
  648. break; /* the COPY command.     */
  649.     }
  650. }
  651. *newpath = ''; /* Terminate newpath with  */
  652. if(count >= MAX_PATHLEN) {
  653.     longjmp(break_env, IA_FILENAME);
  654. }
  655. return oldpath;
  656. }
  657. /*
  658.  * Returns the offset of the filename in a correctly formatted 
  659.  * pathname string.
  660.  */
  661. GLOBAL BYTE * fptr(s)
  662. REG BYTE  *s;
  663. {
  664. REG BYTE  *tp;
  665. for(tp = s; *s; s++) {
  666.     if(dbcs_lead(*s)) {
  667.         s++;
  668. continue;
  669.     }
  670.     if(*s == ':' || *s == *pathchar)
  671. tp = s+1;  
  672. }
  673. return(tp);        
  674. }
  675. /* repwild replaces the wildcards in the destination filespec with
  676.  *      the relevant information from the source filespec 
  677.  * src is an explicit filename
  678.  * dest is a filename with wildcards
  679.  *
  680.  * eg  src = fred.lst
  681.  *     dest = *.txt      becomes  fred.txt
  682.  *     dest = ?.*       becomes  f.lst
  683.  *     dest = z*.*       becomes  zred.lst
  684.  * 
  685.  * nb dest must be in a buffer with room for expansion
  686.  */
  687. GLOBAL VOID repwild(src,dest)
  688. REG BYTE  *src,*dest;
  689. {
  690.         BYTE    t[13];
  691. BYTE *temp;
  692. temp=&t[0]; /* ptr to temp array */
  693.         if(!iswild(dest)) /* return if not wild */
  694.             return;
  695.         src = fptr(src);         /* point to filename  */
  696. if(!*src) /* If a blank filename has been */
  697.     return; /* specified then return as an */
  698. /* invalid source specification */
  699. dest = fptr(dest);
  700. strcpy(temp,dest); /* copy wild dest to temp, as dest will get overwritten */
  701. while (*temp) { /* while still more temp to process */
  702.     if(*temp=='.') { /* advance src ptr to '.' */
  703. while(*src && *src!='.')
  704.     src++;
  705.     } /* drop into next check */
  706.     if(*src=='.') {
  707. if(*temp=='.') {
  708.     *dest=*temp; /* copy '.' */
  709.     goto inc;
  710. }
  711. else {            /* advance temp to '.' or '', copying valid chars to dest */
  712.     while(*temp && *temp!='.') {
  713. if(*temp!='*' && *temp!='?') { 
  714.     *dest=*temp;  
  715.     dest++;
  716. }
  717. temp++;
  718.     } 
  719.     goto skipinc;
  720. }
  721.     }
  722.     if(*temp=='*') {
  723. while(*src && *src!='.') { /* copy rest of src till */
  724.     *dest=*src; /* src = '.' or ''   */
  725.     dest++;
  726.     src++;
  727. }
  728. while(*temp && *temp!='.') /* inc temp past '*' */
  729.     temp++;
  730. goto skipinc;
  731.     }
  732.     if (*temp=='?')
  733. *dest=*src; /* copy src character to dest */
  734.     else    /* else  *temp==normal char */
  735. *dest=*temp; /* copy temp character to dest */
  736. inc:
  737.     if(*src) /* dont advance past terminator */
  738. src++;
  739.     dest++;
  740.     temp++;
  741. skipinc:
  742.     ;
  743. } /* loop till end of while */
  744. *dest=''; /* add terminator to dest */
  745. }
  746. /*.pa*/
  747. /*
  748.  * Read a character from the console. The ABORT flag determines
  749.  * whether a ^C will abort the command or be treated as a negative
  750.  * reponse. DEF determines the default value that yes() will use.
  751.  *
  752.  */
  753. EXTERN BYTE FAR * CDECL farptr(BYTE *);
  754. #define YES_CHAR (*farptr(YES_NO+0))
  755. #define NO_CHAR (*farptr(YES_NO+1))
  756. GLOBAL BOOLEAN yes(abort, def)
  757. BOOLEAN abort, def;
  758. {
  759. BYTE yn;
  760. #if defined(CDOSTMP)
  761. yn = (BYTE) bdos(C_RAWIO, 0xFD); /* Input a character and */
  762. if(abort && yn == 0x03) /* check for Control-C   */
  763.     int_break();
  764. #else
  765. yn = (BYTE) msdos((abort ? MS_C_NOECHO : MS_C_RAWIN), NULL);  
  766. #endif /* read the response */
  767. if(yn >= ' ') /* If its printable then*/
  768.     putc(yn); /* display the charcter */
  769. crlf();  /* new line */
  770. if(def)  /* Now using the correct*/
  771.     return((yn & 0xdf) != NO_CHAR); /* default value return */
  772. else /* process the users */
  773.     return((yn & 0xdf) == YES_CHAR); /* input and return. */
  774. }
  775. /*
  776.  * ONOFF scans the command line for [=](ON|OFF) and returns
  777.  * YES, NO or FAILURE 
  778.  */
  779. GLOBAL WORD onoff(cmd)
  780. BYTE *cmd;
  781. {
  782. cmd = deblank(cmd); /* Deblank the string and    */
  783. if (*cmd == '=') /* remove optional '='      */
  784.     cmd = deblank(cmd+1);
  785. sprintf(heap(), "%s", MSG_ON); /* Check for ON     */
  786. if(!strnicmp(cmd, heap(), strlen(heap())))
  787.     if (*(deblank (cmd + strlen(heap()))) == 0) /* end of line?     */
  788. return YES;
  789. sprintf(heap(), "%s", MSG_OFF); /* Check for OFF     */
  790. if(!strnicmp(cmd, heap(), strlen(heap())))
  791.     if (*(deblank (cmd + strlen(heap()))) == 0) /* end of line?     */
  792. return NO;
  793. return FAILURE;
  794. }
  795. GLOBAL VOID syntax()
  796. {
  797. eprintf(MSG_SYNTAX);
  798. crlfflg = YES;
  799. }
  800. GLOBAL VOID crlf()
  801. {
  802. printf("n");
  803. }
  804. GLOBAL VOID putc(c)
  805. BYTE c;
  806. {
  807. printf("%c", c);
  808. }
  809. GLOBAL VOID puts(s)
  810. BYTE *s;
  811. {
  812. printf("%s",s);
  813. }
  814. GLOBAL VOID c_write(s, l)
  815. BYTE *s;
  816. UWORD  l;
  817. {
  818. ms_x_write (err_flag ? STDERR : STDOUT, s, l);
  819. }
  820. GLOBAL WORD e_check(ret)
  821. REG WORD    ret;
  822. {
  823. REG BYTE   *s;
  824.     if (ret >= 0) /* if no error code */
  825. return ret;  /* it's O.K. */
  826.     if (ret == ED_GENFAIL) ret = extended_error();
  827.     crlfflg = YES; /* Force a CR LF after the error    */
  828.     switch (ret)
  829.     {
  830. case ED_ROOM:   /* Force ED_ROOM to return File Not Found msg */
  831. case ED_FILE:   s = ERR02; break; /* File Not Found Error */
  832. case -1:
  833. case ED_PATH:   s = ERR03; break; /* Path Not Found */
  834. case ED_HANDLE:   s = ERR04; break; /* Too many Open Files */
  835. case ED_ACCESS:   s = ERR05; break; /* Access denied */
  836. case ED_MEMORY:   s = ERR08; break; /* Insufficient Memory */
  837. case ED_ENVIRON:  s = MSG_ENVERR;break; /* Invalid Environment */
  838. case ED_DRIVE:   s = ERR15; break; /* Invalid Drive Spec */
  839. case ED_PROTECT:  s = ERR19; break; /* Write Protect Disk */
  840. case ED_SHAREFAIL:s = ERR20; break; /* Sharing Conflict */
  841. default:
  842.     if(ret==ED_FAIL)
  843.    {s = ERR83; break;} /* Physical Media - FAILED */
  844.     if(ret==ED_PASSWORD)
  845.  {s = ERR86; break;} /* Invalid Password */
  846. #if defined(CDOS) || defined(CDOSTMP)
  847.     if(ret==(-255))
  848.       {s = ERR_RSC; break;} /* Resource is not Available */
  849. #endif
  850.     if (ED_NET >= ret && ret > ED_NETPWD)
  851.       {s = MSG_NETWORK; break;} /* Network Error */
  852.     s = MSG_INTERNAL; break; /* Internal Error */
  853.     }
  854.     eprintf(s, 0-ret);
  855.     eprintf("n");
  856.     return ret;
  857. }
  858. #if 0
  859. MLOCAL BYTE *err_tab[] =  { NULLPTR, /* 01 - Invalid Function Code */
  860.     err02, /* 02 - File Not Found Error */
  861.     err03, /* 03 - Path Not Found */
  862.     err04, /* 04 - Too many Open Files */
  863.     err05, /* 05 - Access denied */
  864.     NULLPTR, /* 06 - Invalid Handle */
  865.     NULLPTR, /* 07 - Invalid Memory Cntl Blk */
  866.     err08, /* 08 - Insufficient Memory */
  867.     NULLPTR, /* 09 - Invalid Memory Cntl Blk */
  868.     msg_enverr, /* 10 - Invalid Environment */
  869.     NULLPTR, /* 11 - Invalid Format */
  870.     NULLPTR, /* 12 - Invalid Access Code */
  871.     NULLPTR, /* 13 - Invalid Data */
  872.     NULLPTR, /* 14 - Unused Error Code */
  873.     err15, /* 15 - Invalid Drive Spec */
  874.     err20, /* 20 - Sharing Conflict */
  875.     err83, /* 83 - Physical Media - FAILED */
  876.     err86, /* 86 - Invalid Password */
  877.     err_rsc}; /* Resource is not Available */
  878. GLOBAL WORD e_check(ret)
  879. REG WORD    ret;
  880. {
  881. REG WORD    error; /* Local copy of the error code */
  882. if (ret >= 0) /* if no error code */
  883.     return ret;  /* it's O.K. */
  884. crlfflg = YES; /* Force a CR LF after the error    */
  885. error = ret; /* message has been displayed     */
  886. if(error == ED_ROOM)  /* Force ED_ROOM to return File Not */
  887.     error = ED_FILE; /* found message.     */
  888. if(error < ED_DRIVE) { /* Check for error codes which have */
  889.     if(error == ED_SHAREFAIL) /* been remapped so save space     */
  890. error = (-16);
  891.     if(error == ED_FAIL) /* Check for FAIL     */
  892.         error = (-17);
  893.     if(error == ED_PASSWORD) /* Password Error     */
  894.         error = (-18);
  895. }
  896. error = -error;
  897. if(error <= sizeof(err_tab)/sizeof(BYTE *) && err_tab[error-1])
  898.     eprintf(err_tab[error-1]);
  899. else
  900.     eprintf("Internal Error Code %03d", error);
  901. return ret;
  902. }
  903. #endif
  904. GLOBAL BOOLEAN UNC(char *path) {
  905. if (*path == '\' && path[1] == '\') return TRUE;
  906. if (!*(path++) || !*(path++)) return FALSE;
  907. while (*path) if (*(path++) == ':') return TRUE;
  908. return FALSE;
  909. }
  910. GLOBAL BYTE * d_check(path)
  911. REG BYTE *path;
  912. {
  913. ddrive = -1; /* return -1 for UNC names  */
  914. if (UNC(path)) return(path);
  915. ddrive = drive; /* if no drive is specified */
  916. if(!*path || path[1] != ':') /* then DDRIVE is set to    */
  917.     return(path); /* the default drive.     */
  918. ddrive = toupper(path[0]) - 'A'; /* Otherwise the requested  */
  919. path += 2; /* drive is selected and    */
  920. /* range checked     */
  921. if(ddrive == drive) /* If the requested drive is*/
  922.     return(path);  /* the default drive is OK. */
  923. /*
  924.  * If TRUE the D_CHECK only range checks the selected drive and
  925.  * returns a pointer to the next element of the path. If FALSE
  926.  * the drive is phyically selected.
  927.  */
  928. #if TRUE
  929. if(!INVALID_DRV(ddrive))
  930.     return(path);
  931. #else
  932. if(!INVALID_DRV(ddrive) && ms_drv_set(ddrive) == ddrive) {
  933.     ms_drv_set(drive); /* Restore Original Drive   */
  934.     return(path); /* and return Path     */
  935. }
  936. #endif
  937. e_check(ED_DRIVE); /* Print an error message   */
  938. return (NULL); /* and return a NULLPTR     */
  939. }
  940. GLOBAL BOOLEAN f_check(cmd, fchars, farray, ignore)
  941. REG BYTE *cmd;
  942. BYTE  *fchars;
  943. UWORD  *farray;
  944. BOOLEAN  ignore; /* Ignore Illegal Options */
  945. {
  946. BYTE  *s, *flg_start;
  947. BOOLEAN  flg_skip, flg_error;
  948. BYTE  c;
  949. *farray = 0; /* assume none of the flags present */
  950. while(*cmd) {
  951.     if(*cmd++ != *switchar)
  952.         continue;
  953.     flg_start = cmd - 1; /* Save switchar offset     */
  954.     flg_skip = FALSE; /* No Chars skipped     */
  955.     flg_error = TRUE; /* Assume first char is bad */
  956.     FOREVER {
  957.         c = tolower(*cmd); /* Scan the string till the */
  958. if(!((c>='a' && c<='z')||(c>='0' && c<='9')))
  959.     break; /* first non-alpha character*/
  960. if((s=(BYTE *)strchr(fchars, c))) {/* check each char against  */
  961.     *farray |= 1 << (s-fchars); /* options string passed by */
  962.     strcpy(cmd, cmd+1);  /* the calling routine.     */
  963.     flg_error = FALSE; /* Reset error flag and set */
  964. } /* correct flag bit.     */
  965. else {
  966.     flg_skip = flg_error = TRUE;/* On error set flg_skip and*/
  967.     if(!ignore) /* break out of the loop if */
  968.         break; /* ignore is FALSE.     */
  969.     cmd++;
  970. }
  971.     }
  972.     if(!flg_skip) /* If all characters have    */
  973.         *flg_start = ' '; /* been used then remove '/' */
  974.     if(flg_error && !ignore) { /* If an invalid char and    */
  975. eprintf(MSG_BADOPT, *switchar, c); /* ignore is FALSE then    */
  976. crlfflg = YES; /* print the error message   */
  977. return FAILURE;
  978.     }
  979. }
  980. return SUCCESS;
  981. }
  982. GLOBAL BOOLEAN nofiles(path, attrib, exist, append_stardotstar)
  983. REG BYTE *path;  /* Search Path */
  984. WORD  attrib; /* Search Attributes */
  985. BOOLEAN  exist;  /* Must files exist */
  986. BOOLEAN  append_stardotstar;
  987. {
  988. REG BYTE *cp;
  989. DTA search;
  990. WORD ret;
  991. if ((cp = d_check (path)) == NULLPTR) /* if bad drive letter */
  992.     return FAILURE; /*    don't do it */
  993. if (!*fptr(cp)) { /* If only a path has been */
  994.     strcat(cp, d_slash_stardotstar+3); /* specified expand to *.* */
  995. }
  996. else if(!iswild (cp)) /* else is it path or file? */
  997. { /* wild cards imply files */
  998.     ret = ms_x_first(path, ATTR_ALL, &search); /* get attributes */
  999.     if(ret == ED_ROOM)
  1000.         ret = ED_FILE;
  1001.     if (ret < 0) /* if any errors      */
  1002. if(!exist && (ret == ED_FILE || ret == ED_PATH)) {
  1003. /* If file does not exist and*/
  1004. /* this is NOT an error...   */
  1005.     if (append_stardotstar) {
  1006.         append_slash(path); /* "DIR .." on NOVELL drives */
  1007.         strcat(path, d_slash_stardotstar+3);
  1008.     /* requires that we append   */
  1009. /* "*.*" here                */
  1010.     }
  1011.     return SUCCESS; /* return OK.                */
  1012. }
  1013. else {
  1014.     e_check (ret); /* otherwise print message   */
  1015.     return FAILURE; /* no files found      */
  1016. }
  1017.     if (search.fattr & ATTR_DIR) { /* if path names directory   */
  1018. append_slash(path);  /* make it all files in it   */
  1019. strcat(path, d_slash_stardotstar+3);
  1020.     }
  1021.     
  1022.     if(!exist) /* Must we check the file(s) */
  1023. return SUCCESS;  /* exist. If no return      */
  1024. }
  1025. ret = ms_x_first(path, attrib, &search);  /* Search for the file     */
  1026. if(ret < 0) /* Check the error returned  */
  1027.     if(!exist && (ret==ED_FILE || ret==ED_ROOM)) /* If file does not exist but*/
  1028. return SUCCESS;  /* this is not an error then */
  1029.     else { /* return Ok.      */
  1030. e_check (ret); /* otherwise print message   */
  1031. return FAILURE;  /* no files found      */
  1032.     }
  1033. return SUCCESS;
  1034. }
  1035. /*
  1036.  * Check if FILENAME can be opened in Read Only mode and return the
  1037.  * result. The file is then closed
  1038.  */
  1039. GLOBAL BOOLEAN file_exist(filename)
  1040. BYTE *filename;
  1041. {
  1042. BYTE filebuf[MAX_PATHLEN];
  1043. WORD h;
  1044. get_filename(filebuf, filename, NO);
  1045. if((h = ms_x_open(filebuf, OPEN_READ)) > 0) {
  1046.     ms_x_close(h);
  1047.     return TRUE;
  1048. }
  1049. return FALSE;      
  1050. }
  1051. /*
  1052.  * Check if the handle passed to this routine is open on a FILE
  1053.  * or a DEVICE.
  1054.  */
  1055. GLOBAL BOOLEAN isdev(handle)
  1056. UWORD handle;
  1057. {
  1058. return (0x0080 & ms_x_ioctl(handle) ? TRUE : FALSE);
  1059. }
  1060. /*
  1061.  * If the string that has been passed doesn't end with a '' add one
  1062.  */
  1063. GLOBAL append_slash(s)
  1064. BYTE *s;
  1065. {
  1066. BYTE lastchar;
  1067.     while (*s) {
  1068.      lastchar = *s;
  1069. if (dbcs_lead(*s)) /* is this first of a DBCS pair? */
  1070.     s++;
  1071. s++;
  1072.     }
  1073.     if ((lastchar != '\') && (lastchar != '/'))
  1074. strcat(s, pathchar); /* append a slash */
  1075. }
  1076. GLOBAL VOID prompt_exec()
  1077. {
  1078. BYTE temp[128];
  1079. if (!env_scan("PEXEC=",temp)) docmd(temp,TRUE);
  1080. }
  1081. GLOBAL VOID optional_line(line)
  1082. BYTE *line;
  1083. {
  1084. BYTE c;
  1085. BYTE *s;
  1086. if (*line == 13 || *line == 10 || *line == 0) return;
  1087. if (*line == '?') strcpy(line,line+1);
  1088. if (*line == '"') {
  1089.     s = line+1;
  1090.     while (*s && *s != '"') putc(*s++);     
  1091.     s++;
  1092.     strcpy(line,s);
  1093. }
  1094. else printf(MSG_OPTLINE,line);
  1095. if (!yes(NO,NO)) *line = 0;
  1096. /*printf("n");*/
  1097. }