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