/***
*output.c - printf style output to a struct w4io
*
*   Copyright (c) 1989-1991, Microsoft Corporation. All rights reserved.
*
*Purpose:
*   This file contains the code that does all the work for the
*   printf family of functions.  It should not be called directly, only
*   by the *printf functions.  We don't make any assumtions about the
*   sizes of ints, longs, shorts, or long doubles, but if types do overlap, we
*   also try to be efficient.  We do assume that pointers are the same size
*   as either ints or longs.
*
*Revision History:
*   06-01-89  PHG   Module created
*   08-28-89  JCR   Added cast to get rid of warning (no object changes)
*   02-15-90  GJF   Fixed copyright
*   10-03-90  WHB   Defined LOCAL(x) to "static x" for local procedures
*
*******************************************************************************/

#if DBG == 1

#include <limits.h>
#include <string.h>
#include <stdarg.h>
#include "w4io.h"


/* this macro defines a function which is private and as fast as possible: */
/* for example, in C 6.0, it might be static _fastcall <type>. */
#define LOCAL(x) static x            // 100390--WHB

#define NOFLOATS			// Win 4 doesn't need floating point

/* int/long/short/pointer sizes */

/* the following should be set depending on the sizes of various types */
// FLAT or LARGE model is assumed
#ifdef FLAT
#  define LONG_IS_INT	     1	     /* 1 means long is same size as int */
#  define SHORT_IS_INT	     0	     /* 1 means short is same size as int */
#  define PTR_IS_INT	     1	     /* 1 means ptr is same size as int */
#  define PTR_IS_LONG	     0	     /* 1 means ptr is same size as long */
#else // LARGE model
#  define LONG_IS_INT	     0	     /* 1 means long is same size as int */
#  define SHORT_IS_INT	     1	     /* 1 means short is same size as int */
#  define PTR_IS_INT	     0	     /* 1 means ptr is same size as int */
#  define PTR_IS_LONG	     1	     /* 1 means ptr is same size as long */
#endif
#define LONGDOUBLE_IS_DOUBLE 0	     /* 1 means long double is same as double */

#if LONG_IS_INT
    #define get_long_arg(x) (long)get_int_arg(x)
#endif

#if PTR_IS_INT
    #define get_ptr_arg(x) (void FAR *)get_int_arg(x)
#elif PTR_IS_LONG
    #define get_ptr_arg(x) (void FAR *)get_long_arg(x)
#else
    #error Size of pointer must be same as size of int or long
#endif

#ifndef NOFLOATS
/* These are "fake" double and long doubles to fool the compiler,
   so we don't drag in floating point. */
typedef struct {
    char x[sizeof(double)];
} DOUBLE;
typedef struct {
    char x[sizeof(long double)];
} LONGDOUBLE;
#endif


/* CONSTANTS */

//#define BUFFERSIZE CVTBUFSIZE	    /* buffer size for maximum double conv */
#define BUFFERSIZE 20

/* flag definitions */
#define FL_SIGN       0x0001	  /* put plus or minus in front */
#define FL_SIGNSP     0x0002	  /* put space or minus in front */
#define FL_LEFT       0x0004	  /* left justify */
#define FL_LEADZERO   0x0008	  /* pad with leading zeros */
#define FL_LONG       0x0010	  /* long value given */
#define FL_SHORT      0x0020	  /* short value given */
#define FL_SIGNED     0x0040	  /* signed data given */
#define FL_ALTERNATE  0x0080	  /* alternate form requested */
#define FL_NEGATIVE   0x0100	  /* value is negative */
#define FL_FORCEOCTAL 0x0200	  /* force leading '0' for octals */
#define FL_LONGDOUBLE 0x0400	  /* long double value given */
#define FL_WIDE	      0x0800	  /* wide character/string given */

/* state definitions */
enum STATE {
    ST_NORMAL,		    /* normal state; outputting literal chars */
    ST_PERCENT, 	    /* just read '%' */
    ST_FLAG,		    /* just read flag character */
    ST_WIDTH,		    /* just read width specifier */
    ST_DOT,		    /* just read '.' */
    ST_PRECIS,		    /* just read precision specifier */
    ST_SIZE,		    /* just read size specifier */
    ST_TYPE		    /* just read type specifier */
};
#define NUMSTATES (ST_TYPE + 1)

/* character type values */
enum CHARTYPE {
    CH_OTHER,		    /* character with no special meaning */
    CH_PERCENT, 	    /* '%' */
    CH_DOT,		    /* '.' */
    CH_STAR,		    /* '*' */
    CH_ZERO,		    /* '0' */
    CH_DIGIT,		    /* '1'..'9' */
    CH_FLAG,		    /* ' ', '+', '-', '#' */
    CH_SIZE,		    /* 'h', 'l', 'L', 'N', 'F' */
    CH_TYPE		    /* type specifying character */
};

/* static data (read only, since we are re-entrant) */
char *nullstring = "(null)";	/* string to print on null ptr */

/* The state table.  This table is actually two tables combined into one. */
/* The lower nybble of each byte gives the character class of any	  */
/* character; while the uper nybble of the byte gives the next state	  */
/* to enter.  See the macros below the table for details.		  */
/*									  */
/* The table is generated by maketab.c -- use the maketab program to make */
/* changes.								  */

static char lookuptable[] = {
    0x06, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00,
    0x10, 0x00, 0x03, 0x06, 0x00, 0x06, 0x02, 0x10,
    0x04, 0x45, 0x45, 0x45, 0x05, 0x05, 0x05, 0x05,
    0x05, 0x35, 0x30, 0x00, 0x50, 0x00, 0x00, 0x00,
    0x00, 0x20, 0x28, 0x38, 0x50, 0x58, 0x07, 0x08,
    0x00, 0x30, 0x30, 0x30, 0x57, 0x50, 0x07, 0x00,
    0x00, 0x20, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00,
    0x08, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00,
    0x00, 0x70, 0x70, 0x78, 0x78, 0x78, 0x78, 0x08,
    0x07, 0x08, 0x00, 0x00, 0x07, 0x00, 0x08, 0x08,
    0x08, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x07,
    0x08
};

#define find_char_class(c)		\
	((c) < ' ' || (c) > 'x' ?	\
	    CH_OTHER			\
	:				\
	    lookuptable[(c)-' '] & 0xF)

#define find_next_state(class, state)	\
	(lookuptable[(class) * NUMSTATES + (state)] >> 4)

#if !LONG_IS_INT
LOCAL(long) get_long_arg(va_list FAR *pargptr);
#endif
LOCAL(int) get_int_arg(va_list FAR *pargptr);
LOCAL(void) writestring(char FAR *string,
			int len,
			struct w4io FAR *f,
			int FAR *pcchwritten,
			int fwide);

#ifndef NOFLOATS
/* extern float convert routines */
typedef int (FAR * PFI)();
extern PFI _cfltcvt_tab[5];
#define _cfltcvt(a,b,c,d,e) (*_cfltcvt_tab[0])(a,b,c,d,e)
#define _cropzeros(a)	    (*_cfltcvt_tab[1])(a)
#define _fassign(a,b,c)     (*_cfltcvt_tab[2])(a,b,c)
#define _forcdecpt(a)	    (*_cfltcvt_tab[3])(a)
#define _positive(a)	    (*_cfltcvt_tab[4])(a)
#define _cldcvt(a,b,c,d,e)  (*_cfltcvt_tab[5])(a,b,c,d,e)
#endif


/***
*int w4iooutput(f, format, argptr)
*
*Purpose:
*   Output performs printf style output onto a stream.	It is called by
*   printf/fprintf/sprintf/vprintf/vfprintf/vsprintf to so the dirty
*   work.  In multi-thread situations, w4iooutput assumes that the given
*   stream is already locked.
*
*   Algorithm:
*	The format string is parsed by using a finite state automaton
*	based on the current state and the current character read from
*	the format string.  Thus, looping is on a per-character basis,
*	not a per conversion specifier basis.  Once the format specififying
*	character is read, output is performed.
*
*Entry:
*   struct w4io *f   - stream for output
*   char *format   - printf style format string
*   va_list argptr - pointer to list of subsidiary arguments
*
*Exit:
*   Returns the number of characters written, or -1 if an output error
*   occurs.
*
*Exceptions:
*
*******************************************************************************/

int _cdecl w4iooutput(struct w4io FAR *f, const char FAR *format, va_list argptr)
{
    int hexadd; 	/* offset to add to number to get 'a'..'f' */
    char ch;		/* character just read */
    wchar_t wc;		/* wide character temp */
    wchar_t FAR *pwc;	/* wide character temp pointer */
    int flags;		/* flag word -- see #defines above for flag values */
    enum STATE state;	/* current state */
    enum CHARTYPE chclass; /* class of current character */
    int radix;		/* current conversion radix */
    int charsout;	/* characters currently written so far, -1 = IO error */
    int fldwidth;	/* selected field with -- 0 means default */
    int fwide;
    int precision;	/* selected precision -- -1 means default */
    char prefix[2];	/* numeric prefix -- up to two characters */
    int prefixlen;	/* length of prefix -- 0 means no prefix */
    int capexp; 	/* non-zero = 'E' exponent signifiet, zero = 'e' */
    int no_output;	/* non-zero = prodcue no output for this specifier */
    char FAR *text; 	/* pointer text to be printed, not zero terminated */
    char FAR *text2; 	/* pointer text to be printed, not zero terminated */
    int textlen;	/* length of the text to be printed */
    char buffer[BUFFERSIZE];	/* buffer for conversions */

    charsout = 0;		/* no characters written yet */
    state = ST_NORMAL;		/* starting state */

    /* main loop -- loop while format character exist and no I/O errors */
    while ((ch = *format++) != '\0' && charsout >= 0) {
	chclass = find_char_class(ch);	/* find character class */
	state = find_next_state(chclass, state); /* find next state */

	/* execute code for each state */
	switch (state) {

	case ST_NORMAL:
	    /* normal state -- just write character */
	    f->writechar(ch, 1, f, &charsout);
	    break;

	case ST_PERCENT:
	    /* set default value of conversion parameters */
	    prefixlen = fldwidth = no_output = capexp = 0;
	    flags = 0;
	    precision = -1;
	    fwide = 0;
	    break;

	case ST_FLAG:
	    /* set flag based on which flag character */
	    switch (ch) {
	    case '-':
		flags |= FL_LEFT;	/* '-' => left justify */
		break;
	    case '+':
		flags |= FL_SIGN;	/* '+' => force sign indicator */
		break;
	    case ' ':
		flags |= FL_SIGNSP;	/* ' ' => force sign or space */
		break;
	    case '#':
		flags |= FL_ALTERNATE;	/* '#' => alternate form */
		break;
	    case '0':
		flags |= FL_LEADZERO;	/* '0' => pad with leading zeros */
		break;
	    }
	    break;

	case ST_WIDTH:
	    /* update width value */
	    if (ch == '*') {
		/* get width from arg list */
		fldwidth = get_int_arg(&argptr);
		if (fldwidth < 0) {
		    /* ANSI says neg fld width means '-' flag and pos width */
		    flags |= FL_LEFT;
		    fldwidth = -fldwidth;
		}
	    }
	    else {
		/* add digit to current field width */
		fldwidth = fldwidth * 10 + (ch - '0');
	    }
	    break;

	case ST_DOT:
	    /* zero the precision, since dot with no number means 0
	       not default, according to ANSI */
	    precision = 0;
	    break;

	case ST_PRECIS:
	    /* update precison value */
	    if (ch == '*') {
		/* get precision from arg list */
		precision = get_int_arg(&argptr);
		if (precision < 0)
		    precision = -1;	/* neg precision means default */
	    }
	    else {
		/* add digit to current precision */
		precision = precision * 10 + (ch - '0');
	    }
	    break;

	case ST_SIZE:
	    /* just read a size specifier, set the flags based on it */
	    switch (ch) {
#if !LONG_IS_INT
	    case 'l':
		flags |= FL_LONG;   /* 'l' => long int */
		break;
#endif

#if !LONGDOUBLE_IS_DOUBLE
	    case 'L':
		flags |= FL_LONGDOUBLE; /* 'L' => long double */
		break;
#endif

#if !SHORT_IS_INT
	    case 'h':
		flags |= FL_SHORT;  /* 'h' => short int */
		break;
#endif
	    case 'w':
		flags |= FL_WIDE;   /* 'w' => wide character */
		break;
	    }
	    break;

	case ST_TYPE:
	    /* we have finally read the actual type character, so we	   */
	    /* now format and "print" the output.  We use a big switch	   */
	    /* statement that sets 'text' to point to the text that should */
	    /* be printed, and 'textlen' to the length of this text.	   */
	    /* Common code later on takes care of justifying it and	   */
	    /* other miscellaneous chores.  Note that cases share code,    */
	    /* in particular, all integer formatting is doen in one place. */
	    /* Look at those funky goto statements!			   */

	    switch (ch) {

	    case 'c': {
		/* print a single character specified by int argument */
		wc = (wchar_t) get_int_arg(&argptr);	/* get char to print */
		* (wchar_t FAR *) buffer = wc;
		text = buffer;
		textlen = 1;	    /* print just a single character */
	    }
	    break;

	    case 'S': {
		/* print a Counted String

		int i;
		char FAR *p;       /* temps */
                struct string {
                    short Length;
                    short MaximumLength;
                    char FAR *Buffer;
                } *pstr;

		pstr = get_ptr_arg(&argptr);
		if (pstr == NULL || pstr->Buffer == NULL) {
		    /* null ptr passed, use special string */
		    text = nullstring;
#ifdef FLAT
                    textlen = strlen(text);
#else
                    textlen = _fstrlen(text);
#endif
		    flags &= ~FL_WIDE;
		} else {
                    text = pstr->Buffer;
                    textlen = pstr->Length;
                }

	    }
	    break;

	    case 's': {
		/* print a string --				*/
		/* ANSI rules on how much of string to print:	*/
		/*   all if precision is default,		*/
		/*   min(precision, length) if precision given. */
		/* prints '(null)' if a null string is passed	*/

		int i;
		char FAR *p;       /* temps */

		text = get_ptr_arg(&argptr);
		if (text == NULL) {
		    /* null ptr passed, use special string */
		    text = nullstring;
		    flags &= ~FL_WIDE;
		}

		/* At this point it is tempting to use strlen(), but */
		/* if a precision is specified, we're not allowed to */
		/* scan past there, because there might be no null   */
		/* at all.  Thus, we must do our own scan.	     */

		i = (precision == -1) ? INT_MAX : precision;

		/* scan for null upto i characters */
		if (flags & FL_WIDE) {
		    pwc = (wchar_t FAR *) text;
		    while (i-- && (wc = *pwc) && (wc & 0x00ff)) {
			++pwc;
			if (wc & 0xff00) {	// if high byte set,
			    break;		// error will be indicated
			}
		    }
		    textlen = (int) (pwc - (wchar_t FAR *) text) ;  /* length of string */
		} else {
		    p = text;
		    while (i-- && *p) {
			++p;
		    }
		    textlen = (int) (p - text);    /* length of the string */
		}
	    }
	    break;

	    case 'n': {
		/* write count of characters seen so far into */
		/* short/int/long thru ptr read from args */

		void FAR *p;	    /* temp */

		p = get_ptr_arg(&argptr);

		/* store chars out into short/long/int depending on flags */
#if !LONG_IS_INT
		if (flags & FL_LONG)
		    *(long FAR *)p = charsout;
		else
#endif

#if !SHORT_IS_INT
		if (flags & FL_SHORT)
		    *(short FAR *)p = (short) charsout;
		else
#endif
		    *(int FAR *)p = charsout;

		no_output = 1;		    /* force no output */
	    }
	    break;


#ifndef NOFLOATS
	    case 'E':
	    case 'G':
		capexp = 1;		    /* capitalize exponent */
		ch += 'a' - 'A';	    /* convert format char to lower */
		/* DROP THROUGH */
	    case 'e':
	    case 'f':
	    case 'g':	{
		/* floating point conversion -- we call cfltcvt routines */
		/* to do the work for us.				 */
		flags |= FL_SIGNED;	    /* floating point is signed conversion */
		text = buffer;		    /* put result in buffer */
		flags &= ~FL_WIDE;	    /* 8 bit string */

		/* compute the precision value */
		if (precision < 0)
		    precision = 6;	/* default precision: 6 */
		else if (precision == 0 && ch == 'g')
		    precision = 1;	/* ANSI specified */

#if !LONGDOUBLE_IS_DOUBLE
		/* do the conversion */
		if (flags & FL_LONGDOUBLE) {
		    _cldcvt(argptr, text, ch, precision, capexp);
		    va_arg(argptr, LONGDOUBLE);
		}
		else
#endif
		{
		    _cfltcvt(argptr, text, ch, precision, capexp);
		    va_arg(argptr, DOUBLE);
		}

		/* '#' and precision == 0 means force a decimal point */
		if ((flags & FL_ALTERNATE) && precision == 0)
		    _forcdecpt(text);

		/* 'g' format means crop zero unless '#' given */
		if (ch == 'g' && !(flags & FL_ALTERNATE))
		    _cropzeros(text);

		/* check if result was negative, save '-' for later */
		/* and point to positive part (this is for '0' padding) */
		if (*text == '-') {
		    flags |= FL_NEGATIVE;
		    ++text;
		}

		textlen = strlen(text);     /* compute length of text */
	    }
	    break;
#endif // NOFLOATS

	    case 'd':
	    case 'i':
		/* signed decimal output */
		flags |= FL_SIGNED;
		radix = 10;
		goto COMMON_INT;

	    case 'u':
		radix = 10;
		goto COMMON_INT;

	    case 'p':
		/* write a pointer -- this is like an integer or long */
		/* except we force precision to pad with zeros and */
		/* output in big hex. */

		precision = 2 * sizeof(void FAR *);     /* number of hex digits needed */
#if !PTR_IS_INT
		flags |= FL_LONG;	/* assume we're converting a long */
#endif
		/* DROP THROUGH to hex formatting */

	    case 'C':
	    case 'X':
		/* unsigned upper hex output */
		hexadd = 'A' - '9' - 1;     /* set hexadd for uppercase hex */
		goto COMMON_HEX;

	    case 'x':
		/* unsigned lower hex output */
		hexadd = 'a' - '9' - 1;     /* set hexadd for lowercase hex */
		/* DROP THROUGH TO COMMON_HEX */

	    COMMON_HEX:
		radix = 16;
		if (flags & FL_ALTERNATE) {
		    /* alternate form means '0x' prefix */
		    prefix[0] = '0';
		    prefix[1] = (char)('x' - 'a' + '9' + 1 + hexadd);	/* 'x' or 'X' */
		    prefixlen = 2;
		}
		goto COMMON_INT;

	    case 'o':
		/* unsigned octal output */
		radix = 8;
		if (flags & FL_ALTERNATE) {
		    /* alternate form means force a leading 0 */
		    flags |= FL_FORCEOCTAL;
		}
		/* DROP THROUGH to COMMON_INT */

	    COMMON_INT: {
		/* This is the general integer formatting routine. */
		/* Basically, we get an argument, make it positive */
		/* if necessary, and convert it according to the */
		/* correct radix, setting text and textlen */
		/* appropriately. */

		unsigned long number;	/* number to convert */
		int digit;		/* ascii value of digit */
		long l; 		/* temp long value */

		/* 1. read argument into l, sign extend as needed */
#if !LONG_IS_INT
		if (flags & FL_LONG)
		    l = get_long_arg(&argptr);
		else
#endif

#if !SHORT_IS_INT
		if (flags & FL_SHORT) {
		    if (flags & FL_SIGNED)
			l = (short) get_int_arg(&argptr); /* sign extend */
		    else
			l = (unsigned short) get_int_arg(&argptr);    /* zero-extend*/
		}
		else
#endif
		{
		    if (flags & FL_SIGNED)
			l = get_int_arg(&argptr); /* sign extend */
		    else
			l = (unsigned int) get_int_arg(&argptr);    /* zero-extend*/
		}

		/* 2. check for negative; copy into number */
		if ( (flags & FL_SIGNED) && l < 0) {
		    number = -l;
		    flags |= FL_NEGATIVE;   /* remember negative sign */
		}
		else {
		    number = l;
		}

		/* 3. check precision value for default; non-default */
		/*    turns off 0 flag, according to ANSI. */
		if (precision < 0)
		    precision = 1;		/* default precision */
		else
		    flags &= ~FL_LEADZERO;

		/* 4. Check if data is 0; if so, turn off hex prefix */
		if (number == 0)
		    prefixlen = 0;

		/* 5. Convert data to ASCII -- note if precision is zero */
		/*    and number is zero, we get no digits at all.	 */

		text2 = text = &buffer[BUFFERSIZE-1];	// last digit at end of buffer
		flags &= ~FL_WIDE;		// 8 bit characters

		while (precision-- > 0 || number != 0) {
		    digit = (int)(number % radix) + '0';
		    number /= radix;		/* reduce number */
		    if (digit > '9') {
			/* a hex digit, make it a letter */
			digit += hexadd;
		    }
		    *text-- = (char)digit;	/* store the digit */
		}

		textlen = text2 - text; /* compute length of number */
		++text; 	/* text points to first digit now */


		/* 6. Force a leading zero if FORCEOCTAL flag set */
		if ((flags & FL_FORCEOCTAL) && (text[0] != '0' || textlen == 0)) {
		    *--text = '0';
		    ++textlen;		/* add a zero */
		}
	    }
	    break;
	    }

	    /* At this point, we have done the specific conversion, and */
	    /* 'text' points to text to print; 'textlen' is length.  Now we */
	    /* justify it, put on prefixes, leading zeros, and then */
	    /* print it. */

	    if (!no_output) {
		int padding;	/* amount of padding, negative means zero */

		if (flags & FL_SIGNED) {
		    if (flags & FL_NEGATIVE) {
			/* prefix is a '-' */
			prefix[0] = '-';
			prefixlen = 1;
		    }
		    else if (flags & FL_SIGN) {
			/* prefix is '+' */
			prefix[0] = '+';
			prefixlen = 1;
		    }
		    else if (flags & FL_SIGNSP) {
			/* prefix is ' ' */
			prefix[0] = ' ';
			prefixlen = 1;
		    }
		}

		/* calculate amount of padding -- might be negative, */
		/* but this will just mean zero */
		padding = fldwidth - textlen - prefixlen;

		/* put out the padding, prefix, and text, in the correct order */

		if (!(flags & (FL_LEFT | FL_LEADZERO))) {
		    /* pad on left with blanks */
		    f->writechar(' ', padding, f, &charsout);
		}

		/* write prefix */
		writestring(prefix, prefixlen, f, &charsout, 0);

		if ((flags & FL_LEADZERO) && !(flags & FL_LEFT)) {
		    /* write leading zeros */
		    f->writechar('0', padding, f, &charsout);
		}

		/* write text */
		writestring(text, textlen, f, &charsout, flags & FL_WIDE);

		if (flags & FL_LEFT) {
		    /* pad on right with blanks */
		    f->writechar(' ', padding, f, &charsout);
		}

		/* we're done! */
	    }
	    break;
	}
    }

    return charsout;	    /* return value = number of characters written */
}


/***
*int get_int_arg(va_list pargptr)
*
*Purpose:
*   Gets an int argument off the given argument list and updates *pargptr.
*
*Entry:
*   va_list pargptr - pointer to argument list; updated by function
*
*Exit:
*   Returns the integer argument read from the argument list.
*
*Exceptions:
*
*******************************************************************************/

LOCAL(int) get_int_arg(va_list FAR *pargptr)
{
    return va_arg(*pargptr, int);
}

/***
*long get_long_arg(va_list pargptr)
*
*Purpose:
*   Gets an long argument off the given argument list and updates pargptr.
*
*Entry:
*   va_list pargptr - pointer to argument list; updated by function
*
*Exit:
*   Returns the long argument read from the argument list.
*
*Exceptions:
*
*******************************************************************************/


#if !LONG_IS_INT
LOCAL(long) get_long_arg(va_list FAR *pargptr)
{
    return va_arg(*pargptr, long);
}
#endif



/***
*void writestring(char *string, int len, struct w4io *f, int *pcchwritten, int fwide)
*
*Purpose:
*   Writes a string of the given length to the given file.  If no error occurs,
*   then *pcchwritten is incremented by len; otherwise, *pcchwritten is set
*   to -1.  If len is negative, it is treated as zero.
*
*Entry:
*   char *string     - string to write (NOT null-terminated)
*   int len	     - length of string
*   struct w4io *f   - file to write to
*   int *pcchwritten - pointer to integer to update with total chars written
*   int fwide	     - wide character flag
*
*Exit:
*   No return value.
*
*Exceptions:
*
*******************************************************************************/

LOCAL(void) writestring(
	char FAR *string,
	int len,
	struct w4io FAR *f,
	int FAR *pcchwritten,
	int fwide)
{
    wchar_t FAR *pwc;

    //printf("string: str=%.*s, len=%d, cch=%d, f=%d\n", len, string, len, *pcchwritten, fwide);
    if (fwide) {
	pwc = (wchar_t FAR *) string;
	while (len-- > 0) {
	    if (*pwc & 0xff00) {
		f->writechar('^', 1, f, pcchwritten);
	    }
	    f->writechar((char) *pwc++, 1, f, pcchwritten);
	}
    } else {
	while (len-- > 0) {
	    f->writechar(*string++, 1, f, pcchwritten);
	}
    }
}

#endif // DBG == 1