home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1999 / MacHack 1999.toast / The Hacks / DesktopDoubler / Common / Sources / MacPrint.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-06-25  |  17.7 KB  |  803 lines  |  [TEXT/CWIE]

  1. #include <ctype.h>
  2. #include <LowMem.h>
  3. #include <NumberFormatting.h>
  4. #include <QDOffscreen.h>
  5. #include <string.h>
  6. #include <string_io.h>
  7. #include "MacPrint.h"
  8.  
  9.  
  10.  
  11.  
  12.  
  13. #ifdef __cplusplus
  14. extern "C" {
  15. #endif
  16.  
  17. // how many pixels should we let free for the menu bar?
  18. #define kLeaveFreeAtTop    21
  19.  
  20. #define kGlobalsID                 ('FDj™')
  21. #define kFontID                    ('Fon™')
  22.  
  23. #define kReinitInterval            (120)
  24.  
  25. #define GLOBALS_ROW                *(SInt16*)0x02EC
  26. #define GLOBALS_COL                *(SInt16*)0x02EE
  27.  
  28. typedef struct MacPrintFont
  29. {
  30.     UInt32                id;
  31.     UInt16                numChars;
  32.     UInt16                offset;
  33.     UInt8                data[];
  34. } MacPrintFont, *MacPrintFontPtr;
  35.  
  36. typedef struct MacPrintGlobals
  37. {
  38.     UInt32                id;
  39.     UInt8                *pixBase;
  40.     MacPrintFontPtr     font;
  41.     UInt32                ticksToReinit;
  42.     UInt32                rowBytes;
  43.     UInt16                depth;
  44.     SInt16                maxrow;
  45.     SInt16                maxcol;
  46. } MacPrintGlobals;
  47.  
  48. typedef struct VPrintfInfo
  49. {
  50.     UInt32    len;
  51. } VPrintfInfo;
  52.  
  53. extern void vdprintf(const char *format,va_list arg);
  54.  
  55. static void MacPrint(char *str);
  56. static void MacPrint_init(void);
  57. static void MacPrint_initqd(void);
  58. static MacPrintFontPtr GetFontPointer(void);
  59. static UInt32 *GetLookupTable(void);
  60. #if SMALLER_MACPRINT
  61.     static int MacPrint_vsprintf(char *sbuffer, char *fmt, va_list arg);
  62. #else
  63.     static int vprintf_write_string(__file_handle handle,unsigned char *buffer,size_t *count,__idle_proc idle_proc);
  64. #endif
  65.  
  66. #ifdef __cplusplus
  67. }
  68. #endif
  69.  
  70.  
  71.  
  72.  
  73.  
  74. static UInt8                gPrintTable[256];
  75. static MacPrintGlobals        globals;
  76.  
  77.  
  78.  
  79.  
  80.  
  81. void MacPrint(char *str)
  82. {
  83.     MacPrintFontPtr     font;
  84.     UInt8                 *charPtr;
  85.     UInt8                *destPtr;
  86.     SInt16                charRow;
  87.     SInt16                charsInString;
  88.     SInt16                fontOffset;
  89.     SInt32                i;
  90.     char                charByte;
  91.     char                theChar;
  92.     SInt32                *longPtr;
  93.     SInt16                *shortPtr;
  94.     UInt32                *nibbleTable;
  95.     SInt16                nibbleIndex;
  96.     SInt16                bitCount;
  97.     
  98.     
  99.     if (globals.id != kGlobalsID)
  100.         MacPrint_init();
  101.     
  102.     if (LMGetTicks() > globals.ticksToReinit)
  103.         MacPrint_initqd();
  104.     
  105.     charsInString = strlen(str);
  106.     if (charsInString == 0)
  107.         return;
  108.     
  109.     font = globals.font;
  110.     fontOffset = font->offset;
  111.     
  112.     nibbleTable = GetLookupTable();
  113.     for (i = 0; i < charsInString; i++) // loop through the string
  114.     {
  115.         theChar = str[i];
  116.         
  117.         if ((theChar == '\n') || (theChar == '\r'))
  118.         {
  119.             GLOBALS_ROW += 1;
  120.             if (GLOBALS_ROW > globals.maxrow)
  121.                 GLOBALS_ROW = 0;
  122.             
  123.             GLOBALS_COL = 0;
  124.         }
  125.         else
  126.         {
  127.             charPtr    = font->data + 8 * (theChar - fontOffset);
  128.             
  129.             destPtr    = globals.pixBase + 
  130.                             (GLOBALS_COL * globals.depth) + 
  131.                             (GLOBALS_ROW * globals.rowBytes * 8);
  132.                             
  133.             switch (globals.depth)
  134.             {
  135.                 case 8: // 256 colors/greys
  136.                     charRow = 8;
  137.                     while(charRow--)
  138.                     {
  139.                         charByte = *charPtr++;
  140.                         
  141.                         longPtr = (SInt32 *)destPtr;
  142.                         
  143.                         nibbleIndex = ((SInt16)charByte) >> 4;
  144.                         *longPtr++ = nibbleTable[nibbleIndex];
  145.                         
  146.                         nibbleIndex = ((SInt16)charByte) & 0x0F;
  147.                         *longPtr   = nibbleTable[nibbleIndex];
  148.                         destPtr += globals.rowBytes;
  149.                     }
  150.                     
  151.                     longPtr = (SInt32 *)destPtr;
  152.                     
  153.                     *longPtr++ = -1L;
  154.                     *longPtr++ = -1L;
  155.                     break;
  156.                 
  157.                 case 16: // thousands
  158.                     charRow = 8;
  159.                     while(charRow--)
  160.                     {
  161.                         charByte = *charPtr++;
  162.                         
  163.                         shortPtr = (SInt16 *)destPtr;
  164.  
  165.                         *shortPtr++ = ((charByte & (1 << 7)) != 0) ? 0 : -1;
  166.                         *shortPtr++ = ((charByte & (1 << 6)) != 0) ? 0 : -1;
  167.                         *shortPtr++ = ((charByte & (1 << 5)) != 0) ? 0 : -1;
  168.                         *shortPtr++ = ((charByte & (1 << 4)) != 0) ? 0 : -1;
  169.                         *shortPtr++ = ((charByte & (1 << 3)) != 0) ? 0 : -1;
  170.                         *shortPtr++ = ((charByte & (1 << 2)) != 0) ? 0 : -1;
  171.                         *shortPtr++ = ((charByte & (1 << 1)) != 0) ? 0 : -1;
  172.                         *shortPtr++ = ((charByte & (1 << 0)) != 0) ? 0 : -1;
  173.                         
  174.                         destPtr += globals.rowBytes;
  175.                     }
  176.  
  177.                     longPtr = (SInt32 *)destPtr;
  178.                     *longPtr++ = 0L; *longPtr++ = 0L; *longPtr++ = 0L; *longPtr++ = 0L;
  179.                     break;
  180.  
  181.                     
  182.                 case 32: // millions
  183.                     charRow = 8;
  184.                     while(charRow--)
  185.                     {
  186.                         charByte = *charPtr++;
  187.                         
  188.                         longPtr = (SInt32 *)destPtr;
  189.                         
  190.                         for (bitCount = 8; bitCount > 0; bitCount --)
  191.                             *longPtr++ = 
  192.                                 ((charByte & (1 << bitCount)) != 0) ? 0L : -1L;
  193.                         
  194.  
  195.                         destPtr += globals.rowBytes;
  196.                     }
  197.  
  198.                     longPtr = (SInt32 *)destPtr;
  199.                     *longPtr++ = 0L; *longPtr++ = 0L; *longPtr++ = 0L; *longPtr++ = 0L;
  200.                     *longPtr++ = 0L; *longPtr++ = 0L; *longPtr++ = 0L; *longPtr++ = 0L;
  201.                     break;
  202.             }
  203.             
  204.             GLOBALS_COL += 1;
  205.             if (GLOBALS_COL > globals.maxcol)
  206.             {
  207.                 GLOBALS_ROW += 1;
  208.                 if (GLOBALS_ROW > globals.maxrow)
  209.                     GLOBALS_ROW = 0;
  210.                 
  211.                 GLOBALS_COL = 0;
  212.             }
  213.         }
  214.     }
  215. }
  216.  
  217.  
  218.  
  219.  
  220.  
  221. void MacPrint_printf(const char *format,...)
  222. {
  223.     va_list        arg;
  224.     
  225.     
  226.     va_start(arg,format);
  227.     MacPrint_vprintf(format,arg);
  228.     va_end(arg);
  229. }
  230.  
  231.  
  232.  
  233.  
  234.  
  235. void MacPrint_vprintf(const char *format,va_list arg)
  236. {
  237.     if (*(SInt8*)0x910 <= 0)
  238.     {
  239.         #if SMALLER_MACPRINT
  240.             char    buffer[512];
  241.             
  242.             MacPrint_vsprintf(buffer,(char*)format,arg);
  243.             MacPrint(buffer);
  244.         #else
  245.             char        text[sizeof(VPrintfInfo) + 513];
  246.             VPrintfInfo    *info = (VPrintfInfo*)&text[0];
  247.             SInt32        len;
  248.             FILE        file;
  249.             
  250.             
  251.             info->len = 0;
  252.             
  253.             __open_string_file(&file,&text[sizeof(VPrintfInfo)],(sizeof(text) - 1) - sizeof(VPrintfInfo),__writing);
  254.             file.write_proc = vprintf_write_string;
  255.             
  256.             len = vfprintf(&file,format,arg);
  257.             len -= info->len;
  258.             
  259.             if (len > 0)
  260.             {
  261.                 text[sizeof(VPrintfInfo) + len] = '\0';
  262.                 MacPrint(&text[sizeof(VPrintfInfo)]);
  263.             }
  264.         #endif
  265.     }
  266.     
  267.     #undef vdprintf
  268.     vdprintf(format,arg);
  269. }
  270.  
  271.  
  272.  
  273.  
  274.  
  275. void MacPrint_printmem(const void *data,size_t len)
  276. {
  277.     char        bin2hex[] = "0123456789ABCDEF";
  278.     char        ascii[17],hex[41],*hstr,*astr;
  279.     Boolean        partial = (len < 16);
  280.     UInt32        spaces;
  281.     UInt8        byte;
  282.     
  283.     
  284.     // Print header line.
  285.     MacPrint_printf("Displaying %lu bytes from %08lX\r",len,data);
  286.     
  287.     // Print full lines.
  288.     for (ascii[16] = '\0';len >= 16;len -= 16,(UInt8*)data += 16)
  289.     {
  290.         for (UInt32 index = 0;index < 16;index++)
  291.             ascii[index] = gPrintTable[*((UInt8*)data + index)];
  292.         
  293.         MacPrint_printf("%08lX  %04X %04X %04X %04X  %04X %04X %04X %04X  '%s'\r",data,*((UInt16*)data + 0),
  294.                 *((UInt16*)data + 1),*((UInt16*)data + 2),*((UInt16*)data + 3),*((UInt16*)data + 4),
  295.                 *((UInt16*)data + 5),*((UInt16*)data + 6),*((UInt16*)data + 7),ascii);
  296.     }
  297.     
  298.     // Print remainder/partial line.
  299.     if (len > 0)
  300.     {
  301.         spaces = 0;
  302.         hstr = &hex[0];
  303.         astr = &ascii[0];
  304.         for (UInt32 index = 0;index < len;index++)
  305.         {
  306.             spaces = 0;
  307.             byte = *((UInt8*)data + index);
  308.             *astr++ = gPrintTable[byte];
  309.             *hstr++ = bin2hex[byte >> 4];
  310.             *hstr++ = bin2hex[byte & 15];
  311.             
  312.             if ((index & 7) == 7)
  313.             {
  314.                 *hstr++ = ' ';
  315.                 spaces += 1;
  316.             }
  317.             
  318.             if ((index & 1) == 1)
  319.             {
  320.                 *hstr++ = ' ';
  321.                 spaces += 1;
  322.             }
  323.         }
  324.         
  325.         while(spaces < 2)
  326.         {
  327.             *hstr++ = ' ';
  328.             spaces += 1;
  329.         }
  330.         
  331.         *hstr = '\0';
  332.         *astr = '\0';
  333.         
  334.         MacPrint_printf("%08lX  %s%*s'%s'\r",data,hex,partial ? 0 : (42 - strlen(hex)),"",ascii);
  335.     }
  336. }
  337.  
  338.  
  339.  
  340.  
  341.  
  342. void MacPrint_fprintf(const char *log,const char *format,...)
  343. {
  344.     #pragma unused(log)
  345.     va_list        arg;
  346.     
  347.     
  348.     va_start(arg,format);
  349.     MacPrint_vprintf(format,arg);
  350.     va_end(arg);
  351. }
  352.  
  353.  
  354.  
  355.  
  356.  
  357. void MacPrint_vfprintf(const char *log,const char *format,va_list arg)
  358. {
  359.     #pragma unused(log)
  360.     MacPrint_vprintf(format,arg);
  361. }
  362.  
  363.  
  364.  
  365.  
  366.  
  367. void MacPrint_fprintmem(const char *log,const void *data,size_t len)
  368. {
  369.     #pragma unused(log)
  370.     MacPrint_printmem(data,len);
  371. }
  372.  
  373.  
  374. #if 0
  375. #pragma mark -
  376. #endif
  377.  
  378.  
  379. static void MacPrint_init(void)
  380. {
  381.     #if SMALLER_MACPRINT
  382.         for (UInt32 index = 0;index < 256;index++)
  383.             gPrintTable[index] = (index & 0x80) ? '.' : index;
  384.     #else
  385.         for (UInt32 index = 0;index < 256;index++)
  386.             gPrintTable[index] = (index & 0x80) ? '.' : isprint(index) ? index : '.';
  387.     #endif
  388.     
  389.     globals.id = 0;
  390.     globals.font = GetFontPointer();
  391.     
  392.     MacPrint_initqd();
  393.     
  394.     if (*(UInt16*)0x02EA != 0x4D50)
  395.     {
  396.         GLOBALS_ROW = 0;
  397.         GLOBALS_COL = 0;
  398.         *(UInt16*)0x02EA = 0x4D50;
  399.     }
  400.     
  401.     globals.id = kGlobalsID;    // these globals are valid
  402. }
  403.  
  404.  
  405.  
  406.  
  407.  
  408. static void MacPrint_initqd(void)
  409. {
  410.     GDHandle        gdh;
  411.     PixMapHandle    pmh;
  412.     
  413.     
  414.     gdh = GetMainDevice();
  415.     pmh = (**gdh).gdPMap;
  416.  
  417.     globals.pixBase  = (UInt8*)GetPixBaseAddr(pmh);
  418.     globals.depth    = (**pmh).pixelSize;
  419.     globals.rowBytes = (0x3fff & (**pmh).rowBytes);
  420.     globals.maxrow   = ((**pmh).bounds.bottom - (**pmh).bounds.top - kLeaveFreeAtTop) / 8 - 1;
  421.     globals.maxcol   = ((**pmh).bounds.right - (**pmh).bounds.left) / 8;
  422.     globals.pixBase += (globals.rowBytes * kLeaveFreeAtTop);
  423.     
  424.     globals.ticksToReinit = LMGetTicks() + kReinitInterval;
  425.  
  426.     if (GLOBALS_COL > globals.maxcol)
  427.     {
  428.         GLOBALS_ROW += 1;
  429.         if (GLOBALS_ROW > globals.maxrow)
  430.             GLOBALS_ROW = 0;
  431.         
  432.         GLOBALS_COL = 0;
  433.     }
  434.     
  435.     if (GLOBALS_ROW > globals.maxrow)
  436.         GLOBALS_ROW = GLOBALS_COL = 0;
  437. }
  438.  
  439.  
  440.  
  441.  
  442.  
  443. static MacPrintFontPtr GetFontPointer(void)
  444. {
  445.     static UInt16 theFont[] = {
  446.         0x466F, 0x6EAA, 0x005A, 0x0020, // id1, id2, numChars, offset
  447.         0x0000, 0x0000, 0x0000, 0x0000, // blank
  448.         0x1818, 0x1818, 0x1800, 0x1800, // !
  449.         0x1414, 0x0000, 0x0000, 0x0000, // "
  450.         0x2424, 0x7E24, 0x7E24, 0x2400, // #
  451.         0x183E, 0x583C, 0x1A7C, 0x1800, // $
  452.         0x43A6, 0x4C18, 0x3265, 0xC200, // %
  453.         0x386C, 0x306A, 0x6C6A, 0x3000, // &
  454.         0x1818, 0x0800, 0x0000, 0x0000, // '
  455.         0x1830, 0x3030, 0x3030, 0x1800, // (
  456.         0x180C, 0x0C0C, 0x0C0C, 0x1800, // )
  457.         0x185A, 0x3C18, 0x3C5A, 0x1800, // *
  458.         0x0018, 0x187E, 0x1818, 0x0000, // +
  459.         0x0000, 0x0000, 0x1818, 0x0810, // ,
  460.         0x0000, 0x003C, 0x0000, 0x0000, // -
  461.         0x0000, 0x0000, 0x0018, 0x1800, // .
  462.         0x0006, 0x0C18, 0x3060, 0x0000, // /
  463.         0x3C66, 0x6E76, 0x6666, 0x3C00, // 0
  464.         0x0C3C, 0x0C0C, 0x0C0C, 0x0C00, // 1
  465.         0x3C66, 0x060C, 0x1830, 0x7E00, // 2
  466.         0x3C66, 0x060C, 0x0666, 0x3C00, // 3
  467.         0x0C1C, 0x3C6C, 0x7E0C, 0x0C00, // 4
  468.         0x7E60, 0x7C06, 0x0666, 0x3C00, // 5
  469.         0x3C60, 0x607C, 0x6666, 0x3C00, // 6
  470.         0x7E0C, 0x0C18, 0x1830, 0x3000, // 7
  471.         0x3C66, 0x663C, 0x6666, 0x3C00, // 8
  472.         0x3C66, 0x663E, 0x0606, 0x3C00, // 9
  473.         0x0000, 0x1818, 0x0018, 0x1800, // :
  474.         0x0018, 0x1800, 0x1818, 0x0810, // ;
  475.         0x0C18, 0x3060, 0x3018, 0x0C00, // <
  476.         0x0000, 0x003C, 0x003C, 0x0000, // =
  477.         0x3018, 0x0C06, 0x0C18, 0x3000, // >
  478.         0x3C66, 0x060C, 0x1800, 0x1800, // ?
  479.         0x3E41, 0x5D55, 0x5E40, 0x3E00, // @
  480.         0x3C66, 0x667E, 0x6666, 0x6600, // A
  481.         0x7C66, 0x667C, 0x6666, 0x7C00, // B
  482.         0x3C66, 0x6060, 0x6066, 0x3C00, // C
  483.         0x7C66, 0x6666, 0x6666, 0x7C00, // D
  484.         0x7E60, 0x6078, 0x6060, 0x7E00, // E
  485.         0x7E60, 0x6078, 0x6060, 0x6000, // F
  486.         0x3C66, 0x606E, 0x6666, 0x3C00, // G
  487.         0x6666, 0x667E, 0x6666, 0x6600, // H
  488.         0x3C18, 0x1818, 0x1818, 0x3C00, // I
  489.         0x7E06, 0x0606, 0x0666, 0x3C00, // J
  490.         0x6666, 0x6C78, 0x6C66, 0x6600, // K
  491.         0x6060, 0x6060, 0x6060, 0x7E00, // L
  492.         0x6276, 0x6A62, 0x6262, 0x6200, // M
  493.         0x6272, 0x6A66, 0x6262, 0x6200, // N
  494.         0x3C66, 0x6666, 0x6666, 0x3C00, // O
  495.         0x7C66, 0x667C, 0x6060, 0x6000, // P
  496.         0x3C66, 0x6666, 0x6E6E, 0x3E00, // Q
  497.         0x7C66, 0x667C, 0x6666, 0x6600, // R
  498.         0x3C66, 0x603C, 0x0666, 0x3C00, // S
  499.         0x7E18, 0x1818, 0x1818, 0x1800, // T
  500.         0x6666, 0x6666, 0x6666, 0x3E00, // U
  501.         0x6666, 0x6666, 0x6624, 0x1800, // V
  502.         0x6262, 0x6262, 0x6A76, 0x6200, // W
  503.         0x6666, 0x2418, 0x2466, 0x6600, // X
  504.         0x6666, 0x2418, 0x1818, 0x1800, // Y
  505.         0x7E06, 0x0C18, 0x3060, 0x7E00, // Z
  506.         0x1C10, 0x1010, 0x1010, 0x1C00, // [
  507.         0x4060, 0x3018, 0x0C06, 0x0200, // '\'
  508.         0x3808, 0x0808, 0x0808, 0x3800, // ]
  509.         0x1C36, 0x6300, 0x0000, 0x0000, // ^
  510.         0x0000, 0x0000, 0x0000, 0xFF00, // _
  511.         0x3018, 0x0C00, 0x0000, 0x0000, // `
  512.         0x3C66, 0x667E, 0x6666, 0x6600, // A
  513.         0x7C66, 0x667C, 0x6666, 0x7C00, // B
  514.         0x3C66, 0x6060, 0x6066, 0x3C00, // C
  515.         0x7C66, 0x6666, 0x6666, 0x7C00, // D
  516.         0x7E60, 0x6078, 0x6060, 0x7E00, // E
  517.         0x7E60, 0x6078, 0x6060, 0x6000, // F
  518.         0x3C66, 0x606E, 0x6666, 0x3C00, // G
  519.         0x6666, 0x667E, 0x6666, 0x6600, // H
  520.         0x3C18, 0x1818, 0x1818, 0x3C00, // I
  521.         0x7E06, 0x0606, 0x0666, 0x3C00, // J
  522.         0x6666, 0x6C78, 0x6C66, 0x6600, // K
  523.         0x6060, 0x6060, 0x6060, 0x7E00, // L
  524.         0x6276, 0x6A62, 0x6262, 0x6200, // M
  525.         0x6272, 0x6A66, 0x6262, 0x6200, // N
  526.         0x3C66, 0x6666, 0x6666, 0x3C00, // O
  527.         0x7C66, 0x667C, 0x6060, 0x6000, // P
  528.         0x3C66, 0x6666, 0x6E6E, 0x3E00, // Q
  529.         0x7C66, 0x667C, 0x6666, 0x6600, // R
  530.         0x3C66, 0x603C, 0x0666, 0x3C00, // S
  531.         0x7E18, 0x1818, 0x1818, 0x1800, // T
  532.         0x6666, 0x6666, 0x6666, 0x3E00, // U
  533.         0x6666, 0x6666, 0x6624, 0x1800, // V
  534.         0x6262, 0x6262, 0x6A76, 0x6200, // W
  535.         0x6666, 0x2418, 0x2466, 0x6600, // X
  536.         0x6666, 0x2418, 0x1818, 0x1800, // Y
  537.         0x7E06, 0x0C18, 0x3060, 0x7E00, // Z
  538.     };
  539.  
  540.     return (MacPrintFontPtr)theFont;
  541. }
  542.  
  543.  
  544.  
  545.  
  546.  
  547. UInt32 *GetLookupTable(void)
  548. {
  549.     static UInt32 table[] = {
  550.         ~0x00000000, 
  551.         ~0x000000FF,
  552.         ~0x0000FF00,
  553.         ~0x0000FFFF,
  554.         ~0x00FF0000,
  555.         ~0x00FF00FF,
  556.         ~0x00FFFF00,
  557.         ~0x00FFFFFF,
  558.         ~0xFF000000, 
  559.         ~0xFF0000FF,
  560.         ~0xFF00FF00,
  561.         ~0xFF00FFFF,
  562.         ~0xFFFF0000,
  563.         ~0xFFFF00FF,
  564.         ~0xFFFFFF00,
  565.         ~0xFFFFFFFF
  566.     };
  567.     
  568.     
  569.     return table;
  570. }
  571.  
  572.  
  573.  
  574.  
  575. #if !SMALLER_MACPRINT
  576. int vprintf_write_string(__file_handle handle,unsigned char *buffer,size_t *count,__idle_proc idle_proc)
  577. {
  578.     VPrintfInfo    *info = (VPrintfInfo*)((UInt32)buffer - sizeof(VPrintfInfo));
  579.     
  580.     
  581.     if (*count > 0)
  582.     {
  583.         buffer[*count] = '\0';
  584.         MacPrint((char*)buffer);
  585.     }
  586.     
  587.     info->len += *count;
  588.     return(__no_io_error);
  589. }
  590. #endif
  591.  
  592.  
  593.  
  594.  
  595. #if SMALLER_MACPRINT
  596. static struct format
  597.     {
  598.     unsigned         leftJustify : 1;
  599.     unsigned         forceSign : 1;
  600.     unsigned         altForm : 1;
  601.     unsigned         zeroPad : 1;
  602.     unsigned         havePrecision : 1;
  603.     unsigned         hSize : 1;
  604.     unsigned         lSize : 1;
  605.     unsigned         LSize : 1;
  606.     char            sign;
  607.     char            exponent;
  608.     int                fieldWidth;
  609.     int                precision;
  610.     } default_format;
  611.  
  612. struct decrec
  613.     {
  614.     char            sgn;
  615.     short            exp;
  616. //    char            sig[SIGDIGLEN];
  617.     short            pad;
  618.     // following fields aren't used by SANE
  619.     short            min;
  620.     short            dot;
  621.     short            max;
  622.     };
  623.  
  624. #define BUFLEN            512
  625.  
  626. int MacPrint_vsprintf(char *sbuffer, char *fmt, va_list arg)
  627.     {
  628.     register int c, i, j, nwritten = 0;
  629.     register unsigned long n;
  630.     register char *s;
  631.     char buf[BUFLEN], *digits, *t;
  632.     struct format F;
  633.     struct decrec D;
  634.  
  635.     for (c = *fmt; c; c = *++fmt)
  636.         {
  637.         if (c != '%') goto copy1;
  638.         F = default_format;
  639.  
  640.             //  decode flags
  641.  
  642.         for (;;)
  643.             {
  644.             c = *++fmt;
  645.             if      (c == '-')    F.leftJustify = true;
  646.             else if (c == '+')    F.forceSign = true;
  647.             else if (c == ' ')    F.sign = ' ';
  648.             else if (c == '#')    F.altForm = true;
  649.             else if (c == '0')    F.zeroPad = true;
  650.             else break;
  651.             }
  652.  
  653.             //  decode field width
  654.  
  655.         if (c == '*')
  656.             {
  657.             if ((F.fieldWidth = va_arg(arg, int)) < 0)
  658.                 {
  659.                 F.leftJustify = true;
  660.                 F.fieldWidth = -F.fieldWidth;
  661.                 }
  662.             c = *++fmt;
  663.             }
  664.         else
  665.             {
  666.             for (; c >= '0' && c <= '9'; c = *++fmt)
  667.                 F.fieldWidth = (10 * F.fieldWidth) + (c - '0');
  668.             }
  669.  
  670.             //  decode precision
  671.  
  672.         if (c == '.')
  673.             {
  674.             if ((c = *++fmt) == '*')
  675.                 { F.precision = va_arg(arg, int); c = *++fmt; }
  676.             else for (; c >= '0' && c <= '9'; c = *++fmt)
  677.                     F.precision = (10 * F.precision) + (c - '0');
  678.             if (F.precision >= 0) F.havePrecision = true;
  679.             }
  680.  
  681.             //  perform appropriate conversion
  682.  
  683.         s = &buf[BUFLEN];
  684.         if (F.leftJustify) F.zeroPad = false;
  685.  
  686. conv:    switch (c)
  687.             {
  688.             case 'h' :    F.hSize = true; c = *++fmt; goto conv;
  689.             case 'l' :    F.lSize = true; c = *++fmt; goto conv;
  690.             case 'L' :    F.LSize = true; c = *++fmt; goto conv;
  691.             case 'd' :
  692.             case 'i' :    if (F.lSize) n = va_arg(arg, long);
  693.                         else n = va_arg(arg, int);
  694.                         if (F.hSize) n = (short) n;
  695.                         if ((long) n < 0) { n = -n; F.sign = '-'; }
  696.                         else if (F.forceSign) F.sign = '+';
  697.                         goto decimal;
  698.             case 'u' :    if (F.lSize) n = va_arg(arg, unsigned long);
  699.                         else n = va_arg(arg, unsigned int);
  700.                         if (F.hSize) n = (unsigned short) n;
  701.                         F.sign = 0;
  702.                         goto decimal;
  703.             decimal:    if (!F.havePrecision)
  704.                             {
  705.                             if (F.zeroPad)
  706.                                 {
  707.                                 F.precision = F.fieldWidth;
  708.                                 if (F.sign) --F.precision;
  709.                                 }
  710.                             if (F.precision < 1) F.precision = 1;
  711.                             }
  712.                         for (i = 0; n; n /= 10, i++) *--s = n % 10 + '0';
  713.                         for (; i < F.precision; i++) *--s = '0';
  714.                         if (F.sign) { *--s = F.sign; i++; }
  715.                         break;
  716.  
  717.             case 'o' :    if (F.lSize) n = va_arg(arg, unsigned long);
  718.                         else n = va_arg(arg, unsigned int);
  719.                         if (F.hSize) n = (unsigned short) n;
  720.                         if (!F.havePrecision)
  721.                             {
  722.                             if (F.zeroPad) F.precision = F.fieldWidth;
  723.                             if (F.precision < 1) F.precision = 1;
  724.                             }
  725.                         for (i = 0; n; n /= 8, i++) *--s = n % 8 + '0';
  726.                         if (F.altForm && i && *s != '0') { *--s = '0'; i++; }
  727.                         for (; i < F.precision; i++) *--s = '0';
  728.                         break;
  729.  
  730.             case 'p' :    F.havePrecision = F.lSize = true;
  731.                         F.precision = 8;
  732.             case 'X' :    digits = "0123456789ABCDEF";
  733.                         goto hexadecimal;
  734.             case 'x' :    digits = "0123456789abcdef";
  735.             hexadecimal:if (F.lSize) n = va_arg(arg, unsigned long);
  736.                         else n = va_arg(arg, unsigned int);
  737.                         if (F.hSize) n = (unsigned short) n;
  738.                         if (!F.havePrecision)
  739.                             {
  740.                             if (F.zeroPad)
  741.                                 {
  742.                                 F.precision = F.fieldWidth;
  743.                                 if (F.altForm) F.precision -= 2;
  744.                                 }
  745.                             if (F.precision < 1) F.precision = 1;
  746.                             }
  747.                         for (i = 0; n; n /= 16, i++) *--s = digits[n % 16];
  748.                         for (; i < F.precision; i++) *--s = '0';
  749.                         if (F.altForm) { *--s = c; *--s = '0'; i += 2; }
  750.                         break;
  751.  
  752.             case 'c' :    *--s = va_arg(arg, int); i = 1; break;
  753.  
  754.             case 's' :    s = va_arg(arg, char *);
  755.                         if (F.altForm)
  756.                             {
  757.                             i = (unsigned char) *s++;
  758.                             if (F.havePrecision && i > F.precision) i = F.precision;
  759.                             }
  760.                         else
  761.                             {
  762.                             i = strlen(s);
  763.                             if (F.havePrecision && i > F.precision) i = F.precision;
  764.                             }
  765.                         break;
  766.  
  767.             case 'n' :    s = (char*)va_arg(arg, void *);
  768.                         if      (F.hSize) * (short *) s = nwritten;
  769.                         else if (F.lSize) * (long  *) s = nwritten;
  770.                         else              * (int   *) s = nwritten;
  771.                         continue;
  772.  
  773.                 //  oops - unknown conversion, abort
  774.  
  775.             case 'M': case 'N': case 'O': case 'P': case 'Q':
  776.             case 'R': case 'S': case 'T': case 'U': case 'V':
  777.             // (extra cases force this to be an indexed switch)
  778.             default: goto done;
  779.  
  780.             case '%' :
  781.             copy1    :    *sbuffer++ = c; ++nwritten; continue;
  782.             }
  783.  
  784.             //  pad on the left
  785.  
  786.         if (i < F.fieldWidth && !F.leftJustify)
  787.             do { *sbuffer++ = ' '; ++nwritten; } while (i < --F.fieldWidth);
  788.  
  789.             //  write the converted result
  790.  
  791.         for (j=0; j<i; j++) *sbuffer++ = *s++;
  792.         nwritten += i;
  793.  
  794.             //  pad on the right
  795.  
  796.         for (; i < F.fieldWidth; i++)
  797.             { *sbuffer++ = ' '; ++nwritten; }
  798.         }
  799.  
  800. done: return(nwritten);
  801. }
  802. #endif
  803.