home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c082_122 / 2.ddi / CLIBSRC3.ZIP / SCANTOL.CAS < prev    next >
Encoding:
Text File  |  1992-06-10  |  12.5 KB  |  393 lines

  1. /*-----------------------------------------------------------------------*
  2.  * filename - scantol.cas
  3.  *
  4.  * function(s)
  5.  *        stl_Digit - converts an ascii digit to a character digit
  6.  *        _scantol  - scans a source for an ascii long
  7.  *-----------------------------------------------------------------------*/
  8.  
  9. /*
  10.  *      C/C++ Run Time Library - Version 5.0
  11.  *
  12.  *      Copyright (c) 1987, 1992 by Borland International
  13.  *      All Rights Reserved.
  14.  *
  15.  */
  16.  
  17.  
  18. #pragma  inline
  19. #include <asmrules.h>
  20. #include <_scanf.h>
  21. #include <stdio.h>
  22. #include <ctype.h>
  23.  
  24.  
  25.  
  26. /*-----------------------------------------------------------------------*
  27.  
  28. Name            stl_Digit - converts an ascii digit to a character digit
  29.  
  30. Usage           static char near stl_Digit (void)
  31.  
  32. Description     This procedure converts a character in range '0..9',
  33.                 'a..z'|'A..Z' into a numeric digit.  The result is the
  34.                 unchanged character if it was not a digit.
  35.  
  36.                 The radix must be in CL at time of calling, and the character
  37.                 is in BL.
  38.  
  39.                 If the result is a digit carry is clear, else carry is set.
  40.                 On output AH = sign extend of AL and no other registers are
  41.                 changed.
  42.  
  43.                 The method is as follows:
  44.  
  45.                 - for any ASCII <= '9', map letters '0..9' onto values 0..9,
  46.                         discarding any ASCII below '0'.
  47.  
  48.                 - for any ASCII > '9', map letters 'A..Z' or 'a..z' onto
  49.                         values 10..36, and discard any ASCII which map to less
  50.                         than 10.
  51.  
  52.                 - for any value that passed correctly through the above
  53.                         mapping, discard it if it is not less than the radix.
  54.  
  55. Return value    the numeric value on success; the original character on
  56.                 failure.
  57.  
  58. *------------------------------------------------------------------------*/
  59. static void near stl_Digit (void)
  60. {
  61. asm             push    bx              /* remember original character. */
  62.  
  63. asm             sub     bl, '0'
  64. asm             jb      stld_badEnd
  65. asm             cmp     bl, 9
  66. asm             jna     stld_digitised  /* digitized values are 0..9 */
  67.  
  68. asm             cmp     bl, ('Z' - '0')
  69. asm             ja      stld_maybeLower
  70. asm             sub     bl, ('A' - '0' - 10)
  71. asm             jmp     short   stld_extended
  72.  
  73. stld_maybeLower:
  74. asm             sub     bl, ('a' - '0' - 10)
  75.  
  76. stld_extended:                          /* extended digits are 10..radix */
  77. asm             cmp     bl, 9
  78. asm             jna     stld_badEnd
  79.  
  80. stld_digitised:
  81. asm             cmp     bl, cl          /* is digit within radix range ? */
  82. asm             jnb     stld_badEnd
  83.  
  84. asm             inc     sp              /* forget the original char     */
  85. asm             inc     sp
  86. asm             clc                     /* since we found a true digit */
  87. asm             mov     bh, 0
  88.  
  89. stld_end:
  90.         return;
  91.  
  92. stld_badEnd:
  93. asm             pop     bx              /* recover original character   */
  94. asm             stc                     /* carry set, was not a char.   */
  95. }
  96.  
  97. /*-----------------------------------------------------------------------*
  98.  
  99. Name            _scantol - scans a source for an ascii long
  100.  
  101. Prototype in    _scanf.h
  102.  
  103. Description     Scan input to parse a long integer.  The syntax of the
  104.                 string must be:
  105.  
  106.                         long     ::= [isspace]* [sign] numeral;
  107.  
  108.                         numeral  ::= { '0' ['x'|'X'] digit [digit]* } |
  109.                                      { digit [digit] }
  110.  
  111.                 "srceP" must be a source of characters, such as a FILE *.
  112.                 Get() and UnGet() must operate on srceP to read and replace
  113.                 characters so that LR(1) parsing is permitted.
  114.  
  115.                 The radix may be zero, or any number 2..36.  If the radix
  116.                 is zero, then a radix will be chosen from the possibilities
  117.                 8, 10, or 16, by the usual "C" rules for distinguishing octal,
  118.                 decimal, and hex numerals.
  119.  
  120.                 If radix > 10 then the letters of the alphabet "A..Z" form
  121.                 the extended set of valid digits.
  122.  
  123.                 If the radix is invalid or no number could be found then the
  124.                 result value is zero and the next char pointer will equal
  125.                 the starting string pointer.
  126.  
  127.                 The width is the limit on the number of digits which may be
  128.                 accepted.  It includes the sign character, if any, but does
  129.                 not include any leading spaces.
  130.  
  131.                 The count value returned to the caller is a count of all the
  132.                 characters consumed, including leading spaces even if no
  133.                 numerals are found.  It is ADDED to the existing value of
  134.                 count.
  135.  
  136.                 The status returned is EOF if EOF was encountered before
  137.                 conversion could begin, 0 if no numerals were found before
  138.                 some other character occurred, 1 if the conversion proceeded
  139.                 correctly, and 2 if overflow occurred.
  140.  
  141. Return value
  142. *------------------------------------------------------------------------*/
  143. #pragma warn -sus
  144. #pragma warn -rvl
  145. long near _scantol( int   near  (*Get)   (void *srceP),
  146.                     void  near  (*UnGet) (int ch, void *srceP),
  147.                     const void   *srceP,
  148.                     int           radix,
  149.                     int           width,
  150.                     int          *countP,
  151.                     int          *statusP )
  152. {
  153.         char            sign = 0;
  154.         int             ct = 0;
  155.         int             status = 1;
  156.  
  157. /*              First skip over any white-space prefix.         */
  158. stl_skipSpace:
  159.         ct ++;
  160.         Get (srceP);
  161.  
  162. asm             or      ax, ax
  163. asm             jl      stl_EOF
  164. asm             cbw
  165.  
  166. asm             xchg    bx, ax
  167. asm             test    bl, 80h
  168. asm             jnz     stl_notSpace
  169. #ifdef __HUGE__
  170. asm             mov     ax, seg _ctype
  171. asm             mov     DS, ax
  172. #endif
  173. asm             mov     di, 1 + offset (ES_ _ctype)
  174. asm             test    BY0 ([bx+di]), _IS_SP   /* (1 + _ctype) [bx]    */
  175. asm             jnz     stl_skipSpace
  176.  
  177. stl_notSpace:
  178. asm             xchg    ax, bx
  179. asm             dec     W0 (width)
  180. asm             jl      stl_noDigitSeen
  181.         /* next check for an optional negative sign. */
  182. asm             cmp     al, '+'
  183. asm             je      stl_signSeen
  184. asm             cmp     al, '-'
  185. asm             jne     stl_signed
  186.         sign++;
  187.  
  188. stl_signSeen:
  189. asm             dec     W0 (width)
  190. asm             jl      stl_noDigitSeen
  191.         ct ++;
  192.         Get (srceP);
  193. asm             or      ax, ax
  194. asm             jl      stl_EOF
  195.  
  196. stl_signed:
  197. asm             sub     si, si  /*      DI:SI hold the result.          */
  198. asm             mov     di, si  /*      default result is zero.         */
  199.  
  200. asm             mov     cx, radix
  201. asm             jcxz    stl_autoRadix
  202. asm             cmp     cx, 36
  203. asm             ja      stl_badRadix
  204. asm             cmp     cl, 2
  205. asm             jb      stl_badRadix
  206.  
  207. /*
  208.   The first few digits are special cases.  Firstly, there must be
  209.   at least one digit.  Secondly, the second "digit" may be 'X' or 'x'
  210.   if the radix is hexadecimal.
  211. */
  212. stl_radixSet:
  213. asm             cmp     al, '0'
  214. asm             jne     stl_digitNeeded
  215. asm             cmp     cl, 16          /* is "0x.." allowed ?  */
  216. asm             jne     stl_nextWordDigitJmp
  217.  
  218. asm             dec     W0 (width)
  219. asm             jl      stl_resultJmp   /* DI:SI is the result  */
  220.         ct ++;
  221.         Get (srceP);
  222.  
  223. asm             cmp     al, 'x'
  224. asm             je      stl_nextWordDigitJmp
  225. asm             cmp     al, 'X'     /*  continue main part of the number */
  226. asm             je      stl_nextWordDigitJmp
  227. asm             jmp     stl_inspectDigit
  228.  
  229.  
  230. stl_EOF:        /*      source ended before any digit seen      */
  231.         status = EOF;
  232. asm             jmp     short   stl_backUp
  233.  
  234.  
  235. /*      When a syntax error occurs, the result is always zero.          */
  236. stl_badRadix:
  237. stl_noDigitSeen:
  238.         status = 0;
  239. stl_backUp:
  240.         UnGet (_AX, srceP);
  241.         ct --;
  242. asm             sub     ax, ax
  243. asm             cwd
  244.         goto  stl_end;
  245.  
  246.  
  247. stl_resultJmp:
  248. asm             jmp     stl_result      /* extend jump range    */
  249.  
  250.  
  251. /*
  252.   Automatic radix recognition:
  253.   Note: single digit "0" with no following digits is a valid octal zero.
  254. */
  255. stl_autoRadix:
  256. asm             cmp     al, '0'
  257.         radix = 10;      /* if first digit not '0', numeral is decimal. */
  258. asm             jne     stl_digitNeeded
  259.  
  260. asm             dec     W0 (width)
  261. asm             jl      stl_resultJmp
  262.         ct ++;
  263.         Get (srceP);
  264.  
  265.         radix = 8;              /* if begins "0.." then will be octal   */
  266.  
  267. asm             cmp     al, 'x'  /* unless "0x.." or "0X..", which is hex */
  268. asm             je      stl_autoHex
  269. asm             cmp     al, 'X'
  270. asm             jne     stl_inspectDigit
  271.  
  272. stl_autoHex:
  273.         radix = 16;
  274. stl_nextWordDigitJmp:
  275. asm             jmp     short   stl_nextWordDigit
  276.  
  277.  
  278. /*      If arrived here then a first true digit is still awaited.       */
  279. stl_digitNeeded:
  280. asm             mov     cx, radix
  281. asm             xchg    bx, ax
  282. asm             call    stl_Digit
  283. asm             xchg    ax, bx
  284. asm             jc      stl_noDigitSeen
  285. asm             xchg    si, ax
  286. asm             jmp     short   stl_nextWordDigit
  287.  
  288.  
  289. /*
  290.   This is the short (16-bit) loop which accumulates digits after
  291.   the radix and start digits have been processed, until either
  292.   the accumulated value overflows 16 bits or until there are no
  293.   more digits in the source string.
  294.  
  295.   The loop calculation is:      DI:SI = (radix * SI) + new digit.
  296. */
  297. stl_digitOnWord:
  298. asm             xchg    ax, si
  299. asm             mul     W0 (radix)
  300. asm             add     si, ax
  301. asm             adc     di, dx
  302. asm             jnz     stl_nextDigit
  303.  
  304. stl_nextWordDigit:
  305. asm             dec     W0 (width)
  306. asm             jl      stl_result
  307.         ct ++;
  308.         Get (srceP);
  309.  
  310. stl_inspectDigit:
  311. asm             mov     cx, radix
  312. asm             xchg    bx, ax
  313. asm             call    stl_Digit
  314. asm             xchg    ax, bx
  315. asm             jnc     stl_digitOnWord
  316.  
  317. asm             jmp     short   stl_term
  318.  
  319.  
  320. /*
  321.   Loop accumulating digits until overflow or the end of the digits.
  322.  
  323.   The loop calculation is  DI:SI = (DI:SI * radix) + new digit.
  324. */
  325. stl_digitOnLong:
  326. asm             xchg    ax, si
  327. asm             mul     cx              /* CX == radix  */
  328. asm             xchg    ax, di
  329. asm             xchg    cx, dx
  330. asm             mul     dx
  331. asm             add     si, di
  332. asm             adc     ax, cx
  333. asm             xchg    di, ax  /* result in DI:SI                  */
  334. asm             adc     dl, dh  /* bits beyond 32nd should be zero. */
  335. asm             jnz     stl_overflow
  336.  
  337. stl_nextDigit:
  338. asm             dec     W0 (width)
  339. asm             jl      stl_result
  340.         ct ++;
  341.         Get (srceP);
  342.  
  343. asm             mov     cx, radix
  344. asm             xchg    bx, ax
  345. asm             call    stl_Digit
  346. asm             xchg    ax, bx
  347. asm             jnc     stl_digitOnLong
  348.  
  349. /*
  350.   Arrive here if no error but terminator character has been seen.
  351.  
  352.   The original terminator character must be in AL.
  353. */
  354. stl_term:
  355.         UnGet (_AX, srceP);     /* unget to the terminator.             */
  356.         ct --;
  357.  
  358. stl_result:
  359. asm             mov     dx, di
  360. asm             xchg    ax, si  /* result is now in DX:AX               */
  361.  
  362. /*      Was '-' negative seen ?  If so, then negate the result.         */
  363.         if (sign)
  364.         {
  365. asm             neg     dx
  366. asm             neg     ax
  367. asm             sbb     dx, 0           /* negate (DX:AX)               */
  368.         }
  369.  
  370. stl_end:
  371. asm             LES_    di, countP
  372. asm             mov     bx, ct
  373. asm             add     ES_ [di], bx
  374. asm             LES_    di, statusP
  375. asm             mov     bx, status
  376. asm             mov     ES_ [di], bx
  377.  
  378.         return( MK_LONG );
  379.  
  380.         /*      An overflow produces a maximum result.          */
  381. stl_overflow:
  382. asm             mov     ax, 0FFFFh
  383. asm             mov     dx, 7FFFh
  384. asm             add     al, sign
  385. asm             adc     ah, 0
  386. asm             adc     dx, 0   /* result 8000:0000h if signed.  */
  387.         status = 2;
  388. asm             jmp     short   stl_end
  389. }
  390. #pragma warn .sus
  391. #pragma warn .rvl
  392.  
  393.