home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c065 / 2.ddi / CLIB2.ZIP / SCANNER.CAS < prev    next >
Encoding:
Text File  |  1990-06-07  |  32.2 KB  |  1,268 lines

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