home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c082_144 / 2.ddi / CLIBSRC3.ZIP / SCANNER.CAS < prev    next >
Encoding:
Text File  |  1992-06-10  |  38.8 KB  |  1,271 lines

  1. /*-----------------------------------------------------------------------*
  2.  * filename - scanner.cas
  3.  *
  4.  * function(s)
  5.  *        _scanner - reads formatted input
  6.  *-----------------------------------------------------------------------*/
  7.  
  8. /*
  9.  *      C/C++ Run Time Library - Version 5.0
  10.  *
  11.  *      Copyright (c) 1987, 1992 by Borland International
  12.  *      All Rights Reserved.
  13.  *
  14.  */
  15.  
  16.  
  17. #pragma  inline
  18. #include <asmrules.h>
  19.  
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <_scanf.h>
  23.  
  24. #define I asm
  25.  
  26. /*-----------------------------------------------------------------------*
  27.  
  28. The scanner is a simple table-driven design, for speed and flexibility.
  29. There are two tables.  The first table classifies all 7-bit ASCII chars
  30. and then the second table is the switch table which points to the function
  31. blocks which handle the various classes of characters.
  32.  
  33. All characters with the 8'th bit set are currently classed as don't cares,
  34. which is the class of character also used for normal alphabetics.
  35.  
  36. Warning: If you reject gotos you will be allergic to this.  Normally
  37.         I avoid gotos but for fast lexical analysis I make an exception.
  38.  
  39. *------------------------------------------------------------------------*/
  40.  
  41. typedef enum
  42. {
  43.     _zz,        /* terminator   */
  44.     _ws,        /* space        */
  45.     _dc,        /* dont care    */
  46.     _pc,        /* percent      */
  47.     _su,        /* suppress     */
  48.     _nu,        /* numeral      */
  49.     _ch,        /* character    */
  50.     _de,        /* decimal      */
  51.     _un,        /* unsigned decimal - same as decimal   */
  52.     _in,        /* general int  */
  53.     _fl,        /* float        */
  54.     _ld,        /* long double  */
  55.     _ha,        /* half         */
  56.     _lo,        /* long         */
  57.     _oc,        /* octal        */
  58.     _st,        /* string       */
  59.     _sc,        /* scanset      */
  60.     _ct,        /* count of characters scanned  */
  61.     _he,        /* hexadecimal  */
  62.     _pt,        /* pointer      */
  63.     _ne,        /* near         */
  64.     _fa,        /* far          */
  65. }
  66.     charClass;
  67.  
  68.  
  69. static  const   char    scanCtype [128] =
  70. {
  71. /*  NUL SOH STX ETX EOT ENQ ACK BEL  BS  HT  LF  VT  FF  CR  SO  SI     */
  72.     _zz,_dc,_dc,_dc,_dc,_dc,_dc,_dc,_dc,_ws,_ws,_ws,_ws,_ws,_dc,_dc,
  73.  
  74. /*  DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN  EM SUB ESC  FS  GS  RS  US     */
  75.     _dc,_dc,_dc,_dc,_dc,_dc,_dc,_dc,_dc,_dc,_dc,_dc,_dc,_dc,_dc,_dc,
  76.  
  77. /*  SP   !   "   #   $   %   &   '   (   )   *   +   ,   -   .   /      */
  78.     _ws,_dc,_dc,_dc,_dc,_pc,_dc,_dc,_dc,_dc,_su,_dc,_dc,_dc,_dc,_dc,
  79.  
  80. /*   0   1   2   3   4   5   6   7   8   9   :   ;   <   =   >   ?      */
  81.     _nu,_nu,_nu,_nu,_nu,_nu,_nu,_nu,_nu,_nu,_dc,_dc,_dc,_dc,_dc,_dc,
  82.  
  83. /*   @   A   B   C   D   E   F   G   H   I   J   K   L   M   N   O      */
  84.     _dc,_dc,_dc,_dc,_de,_fl,_fa,_fl,_ha,_in,_dc,_dc,_ld,_dc,_ne,_oc,
  85.  
  86. /*   P   Q   R   S   T   U   V   W   X   Y   Z   [   \   ]   ^   _      */
  87.     _dc,_dc,_dc,_dc,_dc,_un,_dc,_dc,_he,_dc,_dc,_sc,_dc,_sc,_dc,_dc,
  88.  
  89. /*   `   a   b   c   d   e   f   g   h   i   j   k   l   m   n   o      */
  90.     _dc,_dc,_dc,_ch,_de,_fl,_fl,_fl,_ha,_in,_dc,_dc,_lo,_dc,_ct,_oc,
  91.  
  92. /*   p   q   r   s   t   u   v   w   x   y   z   {   |   }   ~ DEL      */
  93.     _pt,_dc,_dc,_st,_dc,_un,_dc,_dc,_he,_dc,_dc,_dc,_dc,_dc,_dc,_dc,
  94. };
  95.  
  96.  
  97.  
  98. /*-----------------------------------------------------------------------*
  99.  
  100. Name            _scanner - reads formatted input
  101.  
  102. Usage           int  _scanner ( int   (*Get)(void *srceP),
  103.                                 void  (*UnGet) (int ch, void *srceP),
  104.                                 void   *srceP,
  105.                                 const char   *formP,
  106.                                 va_list varPP )
  107.  
  108. Prototype in
  109.  
  110. Description     _scanner does all the work for the scanf family of
  111.                 functions.
  112.  
  113.                 The "source" *srceP is scanned according to the rules found in the
  114.                 format string *formP and the results are put to the places pointed
  115.                 to by the array of pointers *varPP.
  116.  
  117.                 The "Get" and "UnGet" functions allow the redefinition of the
  118.                 source to be a file or any other serial character stream.  They
  119.                 may be the fget()/ungetc() or any equivalent pair which operates
  120.                 on the srceP data stream/string.
  121.  
  122.  
  123.                 The syntax of the format string is:
  124.  
  125.                 format ::= ([isspace] [literal | '%%' | '%' conversion])*
  126.  
  127.                 conversion ::= ['*'] [width] ['l' | 'h'] [type]
  128.  
  129.                 width ::= number;
  130.  
  131.                 type ::= 'd'|'D'|'u'|'U'|'o'|'O'|'x'|'X'|'i'|'I'|'n'|
  132.                          'e'|'E'|'f'|'F'|'g'|'G'|'p'|'N'|'F'|'s'|'c'|'['
  133.  
  134. Return value
  135.  
  136. *------------------------------------------------------------------------*/
  137. #pragma warn -use
  138. #pragma warn -rvl
  139. int  near _scanner( int   near (*Get)   (void *srceP),
  140.                     void  near (*UnGet) (int ch, void *srceP),
  141.                     void       *srceP,
  142.                     const char *formP,
  143.                     va_list     varPP )
  144. {
  145.  
  146.  
  147.         char    flags;
  148.         int     count = 0;
  149.         int     charCt = 0;
  150.         int     status;
  151.         int     width;
  152.         char    bitSet [32];    /* for scan sets */
  153.  
  154.         register SI, DI;        /* prevent the compiler making its own usage */
  155.  
  156.  
  157. /**************************************************************************
  158.         'C' equivalent of inline code( for documentation )
  159. **************************************************************************/
  160. #if 0
  161. REG     char    a, b;
  162. REG     short   wP;
  163. REG     char   *cP;
  164.         long    lRes;
  165.  
  166.         long double  ldRes;
  167.  
  168. #error  /* The C text is algorithm commentary, not tested source ! */
  169.         /* It is provided to clarify the intent of the assembler.  */
  170.  
  171. ssNEXT:
  172.         if (\0 == (b = *(formP++)))
  173.                 return  count;  /* the normal end */
  174.  
  175.         if ((b != '%')  || ('%' == (b = *(formP++)))
  176.         {
  177.                 charCtt ++;
  178.                 if ((a = Get (srceP)) == EOF)
  179.                         goto ssNextEOF;
  180.                 if (!(b & 0x80) && (_ws == scanCtype [b]))  /* white space ? */
  181.                 {
  182.                         while (!(a & 0x80) && (_ws == scanCtype [a]))
  183.                         {
  184.                                 charCt ++;
  185.                                 if ((a = Get (srceP)) == EOF)
  186.                                         goto ssNextEOF;
  187.                         }
  188.                         UnGet (a, srceP);
  189.                         charCt --;
  190.                 }
  191.                 else    /* literal match required */
  192.                         if (a != b)
  193.                                 goto  ssEND;
  194.                 goto  ssNEXT;
  195.         }
  196.  
  197. /* if fall through to here then begin a conversion specification  */
  198. #if LDATA
  199.         flags = isFarPtr;
  200. #else
  201.         flags = 0;
  202. #endif
  203.         width  = -1;
  204.  
  205. ssSwitch:
  206.         switch ((b & 0x80) ? _dc : scanCtype [b])
  207.         {
  208.                 case (_su) :    flags |= isSuppressed;
  209.                                 b = *(formP++);
  210.                                 goto  ssSwitch;
  211.  
  212.                 case (_ha) :    flags |= isHalf;
  213.                                 b = *(formP++);
  214.                                 goto  ssSwitch;
  215.  
  216.                 case (_lo) :    flags |= isLong;
  217.                                 b = *(formP++);
  218.                                 goto  ssSwitch;
  219.  
  220.                 case (_ld) :    flags |= isLongDouble;
  221.                                 b = *(formP++);
  222.                                 goto  ssSwitch;
  223.  
  224.                 case (_nu) :    width = (width < 0) ? b - '0' :
  225.                                         10 * width + b - '0';
  226.                                 b = *(formP++);
  227.                                 goto  ssSwitch;
  228.  
  229.                 case (_ne) :    flags &= ~isFarPtr;
  230.                                 b = *(formP++);
  231.                                 goto  ssSwitch;
  232.  
  233.                 case (_fa) :    flags |= isFarPtr;
  234.                                 b = *(formP++);
  235.                                 goto  ssSwitch;
  236.  
  237.                 case (_pt) :    goto  ssPTR;
  238.  
  239.                 case (_de) :    base = 10;
  240.                                 goto  ssINT;
  241.  
  242.                 case (_oc) :    base = 8;
  243.                                 goto  ssINT;
  244.  
  245.                 case (_he) :    base = 16:
  246.                                 goto  ssINT;
  247.  
  248.                 case (_in) :    base = 0;
  249.                                 goto  ssINT;
  250.  
  251.                 case (_ct) :    lRes = charCt;
  252.                                 if ((flags & isSuppressed) == 0)
  253.                                         goto  ssPUTINT;
  254.                                 b = *(formP++);
  255.                                 goto  ssSwitch;
  256.  
  257.                 case (_fl) :    goto  ssFLOAT;
  258.                 case (_st) :    goto  ssTOKEN;
  259.                 case (_ch) :    goto  ssCHAR;
  260.                 case (_sc) :    goto  ssSCANSET;
  261.                 case (_dc) :    goto  ssEND;
  262.  
  263.                 default: /*  never occurs.  */;
  264.         }
  265.  
  266. ssINT:
  267.         lRes = _scantol (Get, UnGet, srceP, base, width & 0x7FFF,
  268.                         &charCt, &status);
  269. ssPUTINT;
  270.         if (('A' <= b) && (b <= 'Z'))
  271.                 flags |= isLong;
  272.  
  273.         if ((flags & isSuppressed) == 0)
  274.         {
  275.                 if (flags & isLong)
  276.                         (long *) *(*(varPP++)) = lRes;
  277.                 else if (flags & isHalf)
  278.                         (short *) *(*(varPP++)) = lRes;
  279.                 else (int   *) *(*(varPP++)) = lRes;
  280.                 if (b != 'n')
  281.                         count ++;
  282.         }
  283.         goto  ssNEXT;
  284.  
  285. ssPTR:
  286.         lRes = _scantol (Get, UnGet, srceP, 16, 4, &charCt, &status);
  287.         if (status <= 0)
  288.                 goto ssEND;
  289.         if (flags & isFarPtr)
  290.         {
  291.                 if (':' != (b = Get (srceP)))
  292.                 {
  293.                         UnGet (b, srceP);
  294.                         goto  ssEND;
  295.                 }
  296.                 charCt ++;
  297.                 lRes = (lRes << 16) + _scantol (Get, UnGet, srceP, 16, 4,
  298.                                                 &charCt, &status);
  299.                 if (status <= 0)
  300.                         goto ssEND;
  301.         }
  302.         if ((flags & isSuppressed) == 0)
  303.         {
  304.                 if (flags & isFarPtr)
  305.                         (long *) *(*(varPP++)) = lRes;
  306.                 else    (short *) *(*(varPP++)) = lRes;
  307.                         count ++;
  308.         }
  309.         goto  ssNEXT;
  310.  
  311.  
  312. ssFLOAT:
  313.         ldRes = _scantod (Get, UnGet, srceP, width & 0x7FFF, &charCt, &status);
  314.         if ((flags & isSuppressed) == 0)
  315.         {
  316.                 if (flags & isLong)
  317.                         (double *) *(*(varPP++)) = ldRes;
  318.                 else if (flags & isLongDouble)
  319.                         (long double *) *(*(varPP++)) = ldRes;
  320.                 else
  321.                         (float *) *(*(varPP++)) = ldRes;
  322.                 count ++;
  323.         }
  324.         goto  ssNEXT;
  325.  
  326. ssTOKEN:
  327.         while (_ws == scanCtype [a = Get (srceP)])
  328.                 charCt ++;
  329.         charCt ++;
  330.         if (EOF == a)
  331.                 goto ssEND;
  332.         if ((flags & isSuppressed) == 0)
  333.         {
  334.                 cP = *(varPP++);
  335.                 count ++;
  336.         }
  337.         while (_ws < scanCtype [a])   /* \0 or white space will terminate */
  338.         {
  339.                 if ((flags & isSuppressed) = 0)
  340.                         *(cP++) = a;
  341.                 charCt ++;
  342.                 a = Get (srceP);
  343.         }
  344.         if ((flags & isSuppressed) == 0)
  345.                 *cP = \0;
  346.         goto  ssNEXT;
  347.  
  348. ssCHAR:
  349.         if (width < 0)
  350.                 width = 1;
  351.         if (width)
  352.         {
  353.                 charCt ++;
  354.                 if ((a = Get (srceP)) == EOF)
  355.                         goto ssEOF;
  356.         }
  357.         if ((flags & isSuppressed) == 0)
  358.         {
  359.                 cP = *(varPP++);
  360.                 count ++;
  361.         }
  362.         if (width)
  363.         do
  364.         {
  365.                 if ((flags & isSuppressed) == 0)
  366.                         *(cP++) = a;
  367.                 if (width --)
  368.                         break;
  369.                 charCt ++;
  370.                 if (EOF == (a = Get (srceP)))
  371.                         break;
  372.         }
  373.         goto  ssNEXT;
  374.  
  375.  
  376. ssSCANSET:
  377.  
  378. /*      scanset ::= ['^'] [']'] [nonFinalSet] ']'       */
  379.  
  380.         wP = & bitSet;
  381.         for (i = 16; *(wP++) = 0; i--);
  382.  
  383.         exclude = false;
  384.         if ('^' == (a = *(formP++)))
  385.         {
  386.                 exclude = true;
  387.                 a = *(formP++);
  388.         }
  389.  
  390.         for (;;)            /* fill in the bit set */
  391.         {
  392.                 b = a;
  393.                 if (0 == a)          /* unexpected end of format */
  394.                         goto ssEND;
  395.                 bitSet [a] = true;
  396.                 if (']' == (a = *(formP++)))
  397.                         break;
  398.                 if (('-' == a) && (b < *formP) && (']' != *formP))
  399.                 {
  400.                         a = *(formP++);
  401.                         while ( ++b < a)
  402.                                 bitSet [b] = true;
  403.                 }
  404.         }
  405.  
  406.         if (width = -1)
  407.                 width = 0x7FFF;
  408.         if (width)
  409.         {
  410.                 charCt ++;
  411.                 if ((a = Get (srceP)) == EOF)
  412.                         goto ssEOF;
  413.         }
  414.         if ((flags & isSuppressed) == 0)
  415.         {
  416.                 cP = *(varPP++);
  417.                 count ++;
  418.         }
  419.         while ((--width >= 0) && (exclude != (bitSet [a])) && (EOF != a))
  420.         {
  421.                 if ((flags & isSuppressed) == 0)
  422.                         *(cP++) = a;
  423.                 charCt ++;
  424.                 a = Get (srceP);
  425.         }
  426.         if (width >= 0)
  427.         {
  428.                 UnGet (a, srceP);
  429.                 charCt --;
  430.         }
  431.         if ((flags & isSuppressed) == 0)
  432.                 *(cP++) = '\0';
  433.         goto  ssNEXT;
  434.  
  435.  
  436. ssEND:
  437.         return (count) ? count : -1;
  438.  
  439. #endif
  440. /************************** End of C documentation *************************/
  441.  
  442.         goto RealCodeStart;
  443. scn_Label_it:
  444. /*-------------------Start of Local nested PROCs --------------------------*/
  445.  
  446. /*
  447.   This function returns with the 'carry bit' set if an error occurred in a HUGE
  448.   model program. A HUGE program being asked to scan NEAR pointers is a runtime
  449.   error. The macro SCANNEXTARGPOINTER is used to call this function. This
  450.   resolves all the memory model dependant junk right here so we don't
  451.   have to pepper the code with it all over.  Note that since TC's preprocessor
  452.   will 'see' the macro before TASM, we can use TC's conditional compilation
  453.   within the MACRO and TASM sees the preprocessed result.
  454. */
  455.  
  456. I SCANNEXTARGPOINTER MACRO      /* Note, Preprocessor sees this before TASM! */
  457. I       call scn_NextArgPtr
  458. #ifdef __HUGE__
  459. I       jnc     $+5
  460. I       jmp     scn_END         /* Can't scan NEAR w/HUGE model */
  461. #endif
  462. I       ENDM
  463.  
  464. I scn_NextArgPtr PROC NEAR
  465. I       LES_    di, varPP
  466. I       test    BY0 (flags), isFarPtr
  467. I       jz      scn_nextNear
  468.  
  469. I       les     di, ES_ [di]            /* ES: [di] = & result          */
  470. I       add     W0 (varPP), 4
  471. #ifdef __HUGE__
  472. I       clc                             /* Clear carry bit              */
  473. #endif
  474. I       ret
  475.  
  476. scn_nextNear:
  477. #ifdef __HUGE__
  478. I       stc                             /* Set carry bit                */
  479. #else
  480. I       mov     di, ES_ [di]            /* [di] = & DS: result          */
  481. I       push    ds
  482. I       pop     es
  483. I       add     W0 (varPP), 2
  484. #endif
  485. I       ret
  486. I scn_NextArgPtr ENDP
  487.  
  488. /*---------------------End of Local nested PROCs --------------------------*/
  489.  
  490. RealCodeStart :
  491.  
  492. I       push    ES
  493. I       cld
  494.  
  495. scn_NEXT:
  496. I       mov     si, formP
  497.  
  498. scn_nextChar:
  499. #if LDATA
  500. I       mov     ES, W1 (formP)
  501. #endif
  502. I       lods    BY0 (ES_ [si])   /* *(formP++)   */
  503. I       or      al, al
  504. I       jz      scn_respondJmp   /* '\0' terminates the format string    */
  505.  
  506. I       cmp     al, '%'
  507. I       je      scn_CONV         /* conversion specs begin with '%'      */
  508.  
  509. scn_percent:                     /* but "%%" returns to here     */
  510. I       cbw
  511. I       xchg    di, ax
  512.         charCt ++;
  513.         Get (srceP);
  514.  
  515. I       or      ax, ax
  516. I       jl      scn_EOFjmp
  517. I       cbw
  518. I       or      di, di
  519. I       js      scn_mustMatch
  520. I       cmp     BY0 (scanCtype [di]), _ws  /* does format specify space ? */
  521. I       jne     scn_mustMatch
  522.  
  523. scn_matchSpace:                         /* a format space matches any   */
  524. I       xchg    ax, bx                  /*   number of source spaces    */
  525. I       or      bl, bl
  526. I       js      scn_spaceEnded
  527. I       cmp     BY0 (scanCtype [bx]), _ws
  528. I       jne     scn_spaceEnded
  529.  
  530.         charCt ++;
  531.         Get (srceP);
  532.  
  533. I       or      ax, ax
  534. I       jg      scn_matchSpace
  535.  
  536. scn_EOFjmp:
  537. I       jmp     scn_EOF
  538.  
  539.  
  540. scn_spaceEnded:
  541.         UnGet (_BX, srceP);             /*   part of the next field     */
  542.         charCt --;
  543. I       jmp     short scn_nextChar
  544.  
  545.  
  546. scn_mustMatch:                      /* non-space format characters must be  */
  547. I       cmp     ax, di              /*   matched in the input source.       */
  548. I       je      scn_nextChar
  549.         UnGet (_AX, srceP);             /*   part of the next field     */
  550.         charCt --;
  551.         goto  scn_END;
  552.  
  553.  
  554. /*    Jump via here in the normal case of end of format string.   */
  555. scn_respondJmp:
  556.         goto  scn_respond;
  557.  
  558.  
  559. /*   If arrive here then a conversion specification has been entered.  */
  560. scn_CONV:
  561. I       mov     W0 (width), -1
  562. #if LDATA
  563. I       mov     ES, W1 (formP)
  564. I       mov     BY0 (flags), isFarPtr
  565. #else
  566. I       mov     BY0 (flags), 0
  567. #endif
  568.  
  569. scn_convNext:
  570. I       lods    BY0 (ES_ [si])          /* *(formP++)   */
  571. I       cbw
  572. I       mov     W0 (formP), si          /* remember the position        */
  573. I       xchg    di, ax
  574. I       or      di, di
  575. I       jl      scn_anyOther
  576. I       mov     bl, scanCtype [di]
  577. I       xor     bh,bh
  578.  
  579.         switch ((charClass) _BX)
  580.         {                               /***    Switch Begins   ***/
  581.  
  582. case (_pc):
  583. I   xchg    ax, di
  584.         goto scn_percent;               /* "%%"  is literal '%' */
  585.  
  586. case (_zz):             /* zero */
  587. case (_dc):             /* "don't care" came in spot where we 'care' */
  588. case (_ws):             /* unwanted space occurred.      */
  589. scn_anyOther:
  590.         goto  scn_END;  /* any invalid specifier causes abrupt end. */
  591.  
  592.  
  593. case (_su):             /* Suppressed fields are scanned */
  594. I       or      BY0 (flags), isSuppressed /*   but the result is not stored. */
  595. I       jmp     short   scn_convNext
  596.  
  597. case (_nu):                     /* Scan widths set limits on field sizes. */
  598. I       sub     di, '0'
  599. I       xchg    width, di
  600. I       or      di, di
  601. I       jl      scn_convNext
  602.  
  603. I       mov     ax, 10
  604. I       mul     di
  605. I       add     width, ax
  606. I       jmp     short   scn_convNext
  607.  
  608.  
  609. case (_ld):                             /* The LongDouble flag is used  */
  610. I       or      BY0 (flags),isLongDouble /* scanning for long doubles,  */
  611.         goto scn_convNext;              /* nothing else                 */
  612.  
  613. case (_lo):                             /* The "long" flag is used when */
  614. I       or      BY0 (flags), isLong     /*   scanning for long integers */
  615.         goto scn_convNext;              /*     or doubles.              */
  616.  
  617. case (_ha):                             /* The "half" flag is used when */
  618. I       or      BY0 (flags), isHalf     /*   scanning for short ints    */
  619.         goto scn_convNext;              /*     or floats                */
  620.  
  621. case (_ne):                             /* The "near" flag is used      */
  622. I       and     BY0 (flags), NOT isFarPtr /*  when scanning for */
  623.         goto scn_convNext;              /*     16-bit pointers          */
  624.  
  625. case (_fa):                             /* The "far" flag is used       */
  626. I       or      BY0 (flags), isFarPtr   /*   when scanning for          */
  627.         goto scn_convNext;              /*     32-bit pointers          */
  628.  
  629. case (_ct):                             /* The count of source chars read */
  630. I       mov     ax, charCt              /*   characters used.   */
  631. I       sub     dx, dx
  632. I       test    BY0 (flags), isSuppressed
  633. I       jz      scn_PUTINT
  634.         goto scn_convNext;
  635.  
  636. case (_oc):
  637. I       mov     si, 8                   /* radix = 8    */
  638. I       jmp     short   scn_INT
  639.  
  640. case (_un):
  641. case (_de):
  642. I       mov     si, 10                  /* radix = 10   */
  643. I       jmp     short   scn_INT
  644.  
  645. case (_he):
  646. I       mov     si, 16                  /* radix = 16   */
  647. I       jmp     short   scn_INT
  648.  
  649. case (_in):
  650. I       xor     si, si           /* source syntax will decide radix      */
  651.  
  652. /*
  653.   Arrive here if an integer is expected.  Signed or unsigned are treated
  654.   similarly, the _scantol routine will handle either and there is no method
  655.   (or good purpose) to complaining about a '-' if the user enters it.
  656. */
  657. scn_INT:
  658. scn_UINT:
  659.     if (((_DI & 0x20) == 0) && (_DI != 'X'))
  660.             flags |= isLong;  /* bit 5 is set if lower case */
  661.  
  662.     _scantol (Get, UnGet, srceP, _SI, width & 0x7FFF, &charCt, &status);
  663.  
  664. I       cmp     W0 (status), 0
  665. I       jle     scn_intEnd
  666.  
  667. I       test    BY0 (flags), isSuppressed
  668. I       jnz     scn_intUpdated
  669.  
  670. I       inc     W0 (count)
  671.  
  672. scn_PUTINT:                             /* from %n specifications       */
  673. I       SCANNEXTARGPOINTER              /* This is a MACRO! */
  674.  
  675. /*   On the iAPX-86 family  int == short,  so we can ignore "isHalf".   */
  676. scn_intStos:
  677. I       stosw
  678. I       test    BY0 (flags), isLong
  679. I       jz      scn_intUpdated
  680. I       xchg    ax, dx
  681. I       stosw
  682.  
  683. scn_intUpdated:
  684.         goto  scn_NEXT;
  685.  
  686. scn_intEnd:
  687. I       jl      scn_intEOF
  688.         goto  scn_END;
  689.  
  690. scn_intEOF:
  691.         goto  scn_EOF;
  692.  
  693.  
  694. /*
  695.   Pointer formats are in Intel style, either hhhh (DS default) or
  696.   hhhh:hhhh for far.
  697. */
  698. case (_pt):
  699.         _SimLocalCall_
  700. I       jmp     scn_SkipSpace           /* CX zapped, result in AL      */
  701.         UnGet (_AX, srceP);
  702.         charCt --;
  703.  
  704. I       and     W0 (width), 7FFFh
  705.  
  706.         _SimLocalCall_
  707. I       jmp     scn_InHex4              /* CX zapped, next char in AX,  */
  708.                                         /*   numeric result in DX       */
  709. I       push    dx                      /* save the MSW of pointer */
  710.  
  711. I       cmp     al, ':'
  712. I       je      scn_ptrLSW
  713.  
  714. I       or      ax, ax
  715. I       jle     scn_noLookAhead
  716.  
  717.         UnGet (_AX, srceP);
  718.         charCt --;
  719. scn_noLookAhead:
  720.  
  721. I       pop     dx                      /* retrieve, use as LSW         */
  722.  
  723. #ifdef __HUGE__
  724. I       jmp     short   scn_ptrEndJmp
  725. #else
  726. I       mov     bx, DS
  727. I       jmp     short   scn_pointerReady
  728. #endif
  729.  
  730. scn_ptrLSW:
  731.         _SimLocalCall_
  732. I       jmp     scn_InHex4              /* CX zapped, next char in AX,  */
  733.                                         /*   numeric result in DX       */
  734. I       pop     bx                      /* retrieve the MSW     */
  735.  
  736. I       or      ax, ax
  737. I       jle     scn_notAhead
  738.  
  739. I       push    dx
  740. I       push    bx
  741.     UnGet (_AX, srceP);
  742.     charCt --;
  743. I       pop     bx
  744. I       pop     dx
  745. scn_notAhead:
  746.  
  747. scn_pointerReady:
  748. I       test    BY0 (flags), isSuppressed
  749. I       jnz     scn_ptrUpdated
  750.  
  751. I       SCANNEXTARGPOINTER              /* This is a MACRO! */
  752.  
  753. I       inc     W0 (count)
  754.  
  755. I       xchg    ax, dx
  756. I       stosw
  757. I       test    BY0 (flags), isFarPtr
  758. I       jz      scn_ptrUpdated
  759. I       xchg    ax, bx
  760. I       stosw
  761.  
  762. scn_ptrUpdated:
  763.     goto  scn_NEXT;
  764.  
  765. scn_ptrEnd:
  766. I       jl      scn_jmpEOF
  767. scn_ptrEndJmp:
  768.     goto  scn_END;
  769.  
  770. scn_jmpEOF:
  771. I       jmp     scn_EOF
  772.  
  773.  
  774. /*-------------------------------------------------------------------------
  775.   'e', 'f', 'g', 'E' and 'G' formats are all equivalent for input
  776.   since  _scantod and _scantoLd  recognize all variants.
  777. -------------------------------------------------------------------------*/
  778.  
  779. case (_fl):
  780.  
  781. #if LDATA
  782. I       push    SS
  783. #endif
  784. I       lea     ax, status
  785. I       push    ax                      /*      , &status */
  786. #if LDATA
  787. I       push    SS
  788. #endif
  789. I       lea     ax, charCt
  790. I       push    ax                      /*      , &charCt */
  791. I       mov     ax, 07FFFh
  792. I       and     ax, width               /*      , 0x7FFF & width */
  793. I       push    ax
  794. #if LDATA
  795. I       push    W1 (srceP)
  796. #endif
  797. I       push    W0 (srceP)              /*      , srceP */
  798. I       push    W0 (UnGet)              /*      , UnGet */
  799. I       push    W0 (Get)                /*      , Get */
  800. I       call    near ptr _scantod       /* ST(0) = _scantod (   */
  801. I       add     sp, (3 * dPtrSize) + 2 + (2 * 2)   /* code pointer size is 2 */
  802.  
  803. I       cmp     W0 (status), 0
  804. I       jle     scn_endFloat
  805.  
  806.         if (!(flags & isSuppressed))
  807.         {
  808. I               SCANNEXTARGPOINTER              /* This is a MACRO!     */
  809.  
  810. I               inc     W0 (count)
  811.  
  812. I               test    BY0 (flags), isLong     /* is it 'double'       */
  813. I               jz      test_LongDOuble
  814. I               mov     ax, isLong
  815. I               jmp     short push_type
  816.  
  817. test_LongDOuble:
  818. I               test    BY0 (flags), isLongDouble /* is it 'long double'*/
  819. I               jz      its_default_float
  820. I               mov     ax, isLongDouble
  821. I               jmp     short push_type
  822.  
  823. its_default_float:
  824. I               xor     ax, ax                  /* default is 'float'   */
  825.  
  826. push_type:
  827. I               push    ax
  828. #if LDATA
  829. I               push    es
  830. #endif
  831. I               push    di
  832. I               call    near ptr _scanrslt
  833. I               add     sp, dPtrSize + 2
  834.  
  835.                 goto scn_NEXT;                  /* This item is complete*/
  836.         }
  837.  
  838. scn_popFloat:           /* if suppressed then discard result of _scantod. */
  839.         _scanpop();                             /* pop stack    */
  840.  
  841. scn_UpdatedReal:
  842.         goto scn_NEXT;
  843.  
  844. scn_endFloat:           /* if failed then discard result of _scantod. */
  845.         _scanpop();                             /* pop stack    */
  846. I       jl      scn_jmpEOF
  847.         goto scn_END;
  848.  
  849.  
  850. /***************************************************************************
  851.   The 's' conversion specifies to take a "token" from the source.
  852.   The token is the next contiguous group of non-space characters.
  853. ***************************************************************************/
  854.  
  855. case (_st):
  856.  
  857. scn_untilToken:
  858.         _SimLocalCall_
  859. I       jmp     scn_SkipSpace           /* CX zapped, result in AL      */
  860.  
  861. scn_maybeToken:
  862. I       test    BY0 (flags), isSuppressed
  863. I       jnz     scn_tokenWidth
  864.  
  865. I       SCANNEXTARGPOINTER              /* This is a MACRO! */
  866.  
  867. I       inc     W0 (count)
  868.  
  869. scn_tokenWidth:
  870. I       and     width, 7FFFh            /* default width becomes 7FFFh  */
  871. I       jz      scn_tokenEnd
  872.  
  873. scn_whileToken:
  874. I       test    BY0 (flags), isSuppressed
  875. I       jnz     scn_tokenNextCh
  876. I       stosb
  877.  
  878. scn_tokenNextCh:
  879.     charCt ++;
  880. I       push    ES
  881.     Get (srceP);
  882. I       pop     ES
  883.  
  884. I       or      ax, ax
  885. I       jle     scn_tokenEnd            /* end if \0 or EOF    */
  886. I       or      al, al
  887. I       js      scn_isToken
  888. I       xchg    bx, ax
  889. I       cmp     scanCtype [bx], _ws
  890. I       xchg    ax, bx
  891. I       jng     scn_tokenEnd            /* end if space */
  892.  
  893. scn_isToken:
  894. I       dec     W0 (width)
  895. I       jg      scn_whileToken          /* width limits loop count      */
  896.  
  897. scn_tokenEnd:
  898. I       push    ES
  899.     UnGet (_AX, srceP);
  900. I       pop     ES
  901.     charCt --;
  902.  
  903. I       test    BY0 (flags), isSuppressed
  904. I       jnz     scn_tokenUpdated
  905. I       mov     al, 0           /* terminate result token string.       */
  906. I       stosb
  907.  
  908. scn_tokenUpdated:
  909.     goto  scn_NEXT;
  910.  
  911.  
  912. /*
  913.   The 'c' option captures a literal character array.  Leading and embedded
  914.   space characters are taken, not skipped.  The array size must be filled:
  915.   if too few characters are in the source then the conversion fails and is
  916.   not counted.
  917. */
  918. case (_ch):
  919. I       test    BY0 (flags), isSuppressed
  920. I       jnz     scn_checkWidth
  921.  
  922. I       SCANNEXTARGPOINTER              /* This is a MACRO! */
  923.  
  924. scn_checkWidth:
  925. I       mov     si, width               /* if width was -1 (default), then  */
  926. I       or      si, si                  /*  set it to 1.  Note that a zero  */
  927. I       jnl     scn_charWidened         /*    width is valid (consider how  */
  928. I       mov     si, 1                   /*     an '*' width might be used). */
  929.  
  930. scn_charWidened:
  931. I       jz      scn_charEnd             /* skip if user set a zero width */
  932.  
  933. scn_charLoop:
  934.         charCt ++;
  935. I       push    ES
  936.         Get (srceP);
  937. I       pop     ES
  938. I       or      ax, ax
  939. I       jl      scn_charEOF
  940. I       test    BY0 (flags), isSuppressed
  941. I       jnz     scn_charNoPut
  942. I       stosb
  943.  
  944. scn_charNoPut:
  945. I       dec     si                      /* width */
  946. I       jg      scn_charLoop
  947.  
  948. scn_charEnd:
  949. I       test    BY0 (flags), isSuppressed
  950. I       jnz     scn_charNext
  951. I       inc     W0 (count)
  952.  
  953. scn_charNext:
  954.         goto  scn_NEXT;
  955.  
  956. scn_charEOF:                            /* source was incomplete */
  957.         goto  scn_EOF;
  958.  
  959.  
  960. /*
  961.   The '[' conversion is the most complicated.  The contents of "[...]"
  962.   form a scan set.  Basically it is similar to the 's' format, except that
  963.   the contents (or complement) of the scan set decide the valid characters
  964.   of the token, and leading or embedded spaces are not ignored.
  965.  
  966.         scanset ::= ['^'] [']'] [nonFinalSet] ']'
  967.  
  968.   The nonFinalSet includes any set of characters, and also allows ranges
  969.   such as "A-Z".  The '-' standing for itself is distinguished from the
  970.   range range indicator by ordering: a range is understood if the first
  971.   and last characters are in ascending order, otherwise all three
  972.   characters are simply themselves.
  973.  
  974.   The scanning is performed using a bit set, with one bit for every 8-bit
  975.   character.  This imposes some set-up time (around 40 microseconds on a
  976.   PC to clear the bit set) but it quickly pays off in speed per character.
  977.   It is also the only sensible way to implement large scan sets including
  978.   ranges.
  979. */
  980. case (_sc):
  981. #if LDATA
  982. I       push    ES
  983. #endif
  984. I       sub     ax, ax
  985. I       cld
  986. I       push    SS
  987. I       pop     ES
  988. I       lea     di, bitSet
  989. I       mov     cx, 16
  990. I       rep stosw                       /* clear 256 bits.      */
  991. #if LDATA
  992. I       pop     ES
  993. #endif
  994. /*
  995.   Now the format must be processed to decide the rules of the scan set.
  996.   If the first character is '^' then it means the scan set is to be
  997.   exclusive (ie.  any matching character will terminate a scan).
  998. */
  999. I       lods    BY0 (ES_ [si])                  /* *(formP++)   */
  1000. I       and     BY0 (flags), NOT isExclusive
  1001. I       cmp     al, '^'
  1002. I       jne     scn_scanInc
  1003. I       or      BY0 (flags), isExclusive
  1004. I       lods    BY0 (ES_ [si])                  /* *(formP++)   */
  1005. scn_scanInc:
  1006. /*
  1007.   If the ']' character is wanted as part of the scan set then it must be
  1008.   first character to appear.  A consequence is that a scan set must have
  1009.   at least one member character.  The syntax of the scan set requires up
  1010.   to three characters to be considered (since ranges have three chars).
  1011.   DL holds the previous character, AL the current, and [si] the next.
  1012. */
  1013. I       mov     ah, 0
  1014.  
  1015. scn_scanSetBit:
  1016. I       mov     dl, al
  1017. I       mov     di, ax
  1018. I       mov     cl, 3
  1019. I       shr     di, cl
  1020. I       mov     cx, 107h
  1021. I       and     cl, dl
  1022. I       shl     ch, cl
  1023. I       or      bitSet [di], ch
  1024.  
  1025. scn_setNext:
  1026. I       lods    BY0 (ES_ [si])          /* *(formP++)   */
  1027.  
  1028. I       cmp     al, 0                   /* unexpected end of format ?   */
  1029. I       jz      scn_scanOpen
  1030. I       cmp     al, ']'                 /* normal end of scan set specification */
  1031. I       je      scn_scanBounded
  1032. I       cmp     al, '-'                 /* possible range specification */
  1033. I       jne     scn_scanSetBit
  1034. I       cmp     dl, ES_ [si]
  1035. I       ja      scn_scanSetBit
  1036. I       cmp     BY0 (ES_ [si]), ']'
  1037. I       je      scn_scanSetBit
  1038. /*
  1039.   If arrived here then a range has been specified, and note that the first
  1040.   bit of the range has already been set.
  1041. */
  1042. I       lods    BY0 (ES_ [si])                  /* *(formP++)   */
  1043. I       sub     al, dl                  /* AL is count of bits needed.  */
  1044. I       je      scn_setNext
  1045. I       add     dl, al                  /* DL = (A + Z-A) = Z, final char. */
  1046. scn_setRange:
  1047. I       rol     ch, 1                   /* next bit position is in ..   */
  1048. I       adc     di, 0                   /* .. next byte if wrap-around. */
  1049. I       or      bitSet [di], ch
  1050. I       dec     al
  1051. I       jnz     scn_setRange
  1052. I       jmp     short   scn_setNext
  1053.  
  1054.  
  1055. scn_scanOpen:                        /* scan set was not written correctly */
  1056.     goto  scn_END;                   /* abandon the conversion       */
  1057.  
  1058.  
  1059. scn_scanBounded:                     /* the closing ']' has been found. */
  1060. I       mov     formP, si            /* remember formP next position */
  1061.  
  1062. I       and     W0 (width), 7FFFh    /* convert default -1 to large positive */
  1063. I       mov     si, width
  1064.  
  1065. I       test    BY0 (flags), isSuppressed /* if suppressed, then just skip */
  1066. I       jnz     scn_scanLoop              /*   input, generate no result  */
  1067.  
  1068. I       SCANNEXTARGPOINTER              /* This is a MACRO! */
  1069.  
  1070. scn_scanLoop:
  1071. I       dec     si
  1072. I       jl      scn_scanLimited
  1073.  
  1074.         charCt ++;
  1075. I       push    ES
  1076.         Get (srceP);
  1077. I       pop     ES
  1078.  
  1079. I       or      ax, ax
  1080. I       jl      scn_scanEOF
  1081.  
  1082. I       xchg    si, ax
  1083. I       mov     bx, si
  1084. I       mov     cl, 3                   /* calculate bit equivalent of char */
  1085. I       shr     si, cl
  1086. I       mov     cx, 107h
  1087. I       and     cl, bl
  1088. I       shl     ch, cl
  1089. I       test    ch, bitSet [si] /* is the character in the scan set ?   */
  1090. I       xchg    ax, si
  1091. I       xchg    ax, bx
  1092. I       jz      scn_scanNotIn
  1093.  
  1094.  
  1095. /*      If arrived here then the char was in the scan set.     */
  1096. I       test    BY0 (flags), isExclusive        /* exclusive scan ?     */
  1097. I       jz      scn_scanAccept
  1098. I       jmp     short   scn_scanTerminate
  1099.  
  1100. /*      If arrived here then the char was not in the scan set.     */
  1101. scn_scanNotIn:
  1102. I       test    BY0 (flags), isExclusive        /* exclusive scan ?     */
  1103. I       jz      scn_scanTerminate
  1104.  
  1105. /*      If arrived here, then AL holds an acceptable character     */
  1106. scn_scanAccept:
  1107. I       test    BY0 (flags), isSuppressed /* if suppressed, then just skip */
  1108. I       jnz     scn_scanLoop              /*   input, generate no result. */
  1109.  
  1110. I       stosb                           /* move character to result string */
  1111. I       jmp     short   scn_scanLoop
  1112.  
  1113. I
  1114. /*    If arrived here then the end of the scanned token has been found.   */
  1115. scn_scanTerminate:
  1116. I       push    ES
  1117.         UnGet (_AX, srceP);         /* unget the terminator */
  1118. I       pop     ES
  1119.         charCt --;
  1120.  
  1121. I       inc     si
  1122. I       cmp     si, width
  1123. I       jnl     scn_scanEND     /* No match at all was seen */
  1124.  
  1125. /*     If arrived here then the maximum width was hit or scan is complete.   */
  1126. scn_scanLimited:
  1127. I       test    BY0 (flags), isSuppressed   /* if suppressed, then just skip */
  1128. I       jnz     scn_scanUpdated             /*   input, generate no result  */
  1129. I       inc     W0 (count)
  1130. scn_scanEND:
  1131. I       test    BY0 (flags), isSuppressed   /* if suppressed, then just skip */
  1132. I       jnz     scn_scanUpdated             /*   input, generate no result  */
  1133. I       mov     al, 0
  1134. I       stosb
  1135.  
  1136. scn_scanUpdated:
  1137.         goto  scn_NEXT;
  1138.  
  1139. scn_scanEOF:
  1140. I       inc     si
  1141. I       cmp     si, width
  1142. I       jnl     scn_EOF             /* input failed before token */
  1143.  
  1144. I       test    BY0 (flags), isSuppressed       /* if suppressed, just skip */
  1145. I       jnz     scn_EOF
  1146. I       mov     al, 0
  1147. I       stosb
  1148. I       inc     W0 (count)
  1149.  
  1150. /*      jmp     scn_EOF         */
  1151. }                               /***    End of Switch   ***/
  1152.  
  1153. /*
  1154.   Input failure before a conversion succeeds.  Give a count of
  1155.   the number or input fields successfully taken: if failed before
  1156.   any input accepted, return EOF;
  1157. */
  1158. scn_EOF:
  1159.         UnGet (EOF, srceP);
  1160. I       cmp     W0 (count), 1           /* generates carry if count = 0 */
  1161. I       sbb     W0 (count), 0           /*    so bad count becomes -1   */
  1162.  
  1163.         /*      Arrive here for conversion failures.    */
  1164. scn_END:
  1165.  
  1166. /*
  1167.   If arrived here then the scan ended gracefully.  Return a count of input
  1168.   fields accepted.
  1169. */
  1170. scn_respond:
  1171.  
  1172. scn_exit:
  1173. I       pop     ES
  1174.         return count;
  1175.  
  1176.  
  1177. /*      --- Local Subroutines ---       */
  1178.  
  1179. /*      --- SkipSpace ---       skip spaces at beginning of a spec      */
  1180. scn_SkipSpace:
  1181.         charCt ++;
  1182.         Get (srceP);
  1183.  
  1184. I       or      ax, ax
  1185. I       jle     scn_skipEOF             /* \0 or EOF    */
  1186. I       or      al, al
  1187. I       js      scn_skipEnd
  1188. I       xchg    bx, ax
  1189. I       cmp     scanCtype [bx], _ws     /* white space ?        */
  1190. I       xchg    ax, bx
  1191. I       je      scn_SkipSpace
  1192.  
  1193. scn_skipEnd:
  1194. I       pop     cx              /* get return address           */
  1195. I       add     cx, 3           /* avoid the 3-byte jump        */
  1196. I       jmp     cx              /* RETNEAR                      */
  1197.  
  1198. scn_skipEOF:
  1199. I       jz      scn_skipEnd
  1200. I       pop     cx                      /* discard normal return  */
  1201. I       jmp     short   scn_EOF         /* HUGE has no default DS */
  1202.  
  1203.  
  1204.  
  1205. /*      --- InHex4---           Collect up to 4 hex digits
  1206.  
  1207. result: CX zapped, next char in AX, numeric result in DX.
  1208. */
  1209. scn_InHex4:
  1210. I       sub     dx, dx
  1211. I       mov     cx, 4
  1212.  
  1213. scn_h4loop:
  1214. I       dec     W0 (width)
  1215. I       jl      scn_h4limited
  1216.  
  1217. I       push    dx
  1218. I       push    cx
  1219.         charCt ++;
  1220.         Get (srceP);
  1221. I       pop     cx
  1222. I       pop     dx
  1223.  
  1224. I       or      ax, ax
  1225. I       jle     scn_h4end       /* \0 or EOF    */
  1226. I       dec     cl
  1227. I       jl      scn_h4end       /* maximum of 4 digits  */
  1228.  
  1229. I       mov     ch, al
  1230. I       sub     ch, '0'
  1231. I       jb      scn_h4end
  1232. I       cmp     ch, 10
  1233. I       jb      scn_h4isDigit
  1234. I       sub     ch, 'A' - '0'
  1235. I       jb      scn_h4end
  1236. I       cmp     ch, 6
  1237. I       jb      scn_h4isHex
  1238. I       sub     ch, 'a' - 'A'
  1239. I       jb      scn_h4end
  1240. I       cmp     ch, 6
  1241. I       jnb     scn_h4end
  1242.  
  1243. scn_h4isHex:
  1244. I       add     ch, 10
  1245. scn_h4isDigit:
  1246. I       shl     dx, 1
  1247. I       shl     dx, 1
  1248. I       shl     dx, 1
  1249. I       shl     dx, 1
  1250. I       add     dl, ch
  1251. I       jmp     scn_h4loop
  1252.  
  1253. scn_h4limited:
  1254. I       sub     ax, ax          /* no lookahead                 */
  1255.  
  1256. scn_h4end:
  1257. I       cmp     cl, 4
  1258. I       je      scn_h4eof
  1259. I       pop     cx              /* get return address           */
  1260. I       add     cx, 3           /* avoid the 3-byte jump        */
  1261. I       jmp     cx              /* RETNEAR                      */
  1262.  
  1263. scn_h4eof:
  1264. I       pop     cx              /* discard normal return */
  1265. I       jmp     scn_EOF         /* reject input         */
  1266.  
  1267. }
  1268. #pragma warn .use
  1269. #pragma warn .rvl
  1270.  
  1271.