/*static char *SCCSID = "@(#)tkerr.c    6.1 90/11/17";*/
#define SCCSID  "@(#)tkerr.c 13.17 90/09/24"

/*
 *  C-callable error message functions:
 *
 *      IBM/Microsoft Confidential
 *
 *      Copyright (c) IBM Corporation 1987, 1989
 *      Copyright (c) Microsoft Corporation 1987, 1989
 *
 *      All Rights Reserved
 *
 *      int TKVSprintf(pchbuf, cch, pchfmt, plparms);
 *   ifdef PMDEBUG
 *      void TKDebugHardError(cstring, msgno, pchzz);
 *   endif
 *******************************************************************************
 *   Modifications
 *      18:Nov-95       MLM     Defect 72417, moved find.inc after tkexport.inc
 *
 */

char _acrtused = 0;                     /* Dummy compiler runtime hook */

#include <fnotask.h>
#define FNO_NUM FNO_TKERR_C

#include <osconst.h>
#include <ostypes.h>
#include <osmac.h>

///*
// * suppress TKVsprintf for os2krnlr (if non-debug and non-INTERRPRT)
// */
//
//#if defined(PMDEBUG) || defined(INTERRPRT)
#ifdef PMDEBUG
#define INCL_TYPES
#include <basedef.h>
#include <curdir.h>
#include <dirent.h>
#include <dossymc.h>
#include <except.h>
#include <mi.h>
#include <screen.h>
#include <sem.h>
#include <sigdef.h>
#include <vmexport.h>
#include <pgexport.h>
#include <infoseg.h>
#include <tkexport.h>
#include <find.h>
#include <tkptda.h>
#define FOR_EXEHDR      1
#include <exe386.h>
#endif
#include <string.h>

#ifdef PMDEBUG
extern void dputs(void);                /* debugger terminal output */
extern char *pprintfbuf;                /* dputs() implicit buffer */
extern int cprintfbuf;                  /* sizeof *pprintfbuf */
extern char *DHGetMessage32(USHORT);    /* get message from DosHlp */
#endif /* PMDEBUG */

#define INTBUFLEN       9               /* At most 8 hex characters */


/***EP  TKVSprintf - format a string
 *
 *      TKVSPrintf is a variant of the C runtime library routine, vsprintf.
 *      It supports only a subset of the vsprintf format types, and it takes
 *      a buffer length parameter in order to prevent buffer overrun when
 *      formatting a message.  The formatted string is silently truncated
 *      if it would overflow the passed buffer.
 *
 *      if PMDEBUG is defined and the pchbuf parameter is NULL:
 *          the formatted string is placed in a buffer reserved for dputs(),
 *          and dputs() is called to display the formatted string on the
 *          debugger's COM port.  Unreasonable field width specifiers (>> 100)
 *          will cause padding to be truncated to fit in dputs()'s buffer
 *          as necessary, but no limit is imposed on the length of the rest
 *          of the formatted output.
 *
 *      Supported types are:
 *
 *      %%
 *      %c
 *      %[-][0][#][.#][l]d
 *      %[-][#][.#]s
 *      %[-][0][#][.#][l]u
 *      %[-][0][#][.#][l]x
 *
 *      Where # is a decimal number or the '*' character; '*' causes the
 *      field width or precision to be picked up from the next parameter.
 *      []'ed parameters are optional.
 *
 *      ENTRY   pchbuf          - pointer to buffer
 *              cch             - size of buffer
 *              pchfmt          - message format string
 *              plparms         - pointer to parameter array
 *      RETURN  int             - number of characters in formatted string
 *                                (excluding the null terminator)
 */

int
TKVSprintf(pchbuf, cch, pchfmt, plparms)
char *pchbuf;                           /* Buffer */
int cch;                                /* Buffer length */
register char *pchfmt;                  /* Format string */
int *plparms;                           /* Parameter vector */
{
    unsigned long x;                    /* Integer to decode */
    register char *pch;                 /* Char pointer */
    char *pchparm;                      /* Parameter pointer */
    unsigned ubase;                     /* Base for integer display */
    int cchparm;                        /* Parameter length */
    int cchwidth;                       /* Field width */
    int cchprecision;                   /* Field precision */
    char chpad;                         /* Pad character */
    char fleft;                         /* Left-justify flag */
    char fsign;                         /* Sign */
    char achint[INTBUFLEN];             /* Integer buffer */

#ifdef PMDEBUG
    char fcomport = 0;
    int cchcomport = 0;

    if (pchbuf == NULL) {
        pchbuf = pprintfbuf;            /* dputs() implicit buffer */
        cch = cprintfbuf;               /* sizeof *pprintfbuf */
        fcomport = 1;
    }
#endif /* PMDEBUG */
    pch = pchbuf;                       /* Initialize pointer */
    cch -= 2;                           /* Space for nul and ('\r' or '-') */
    while (*pchfmt) {                   /* While not at end of format string */
        if (pch - pchbuf >= cch) {      /* if buffer would overflow */
#ifdef PMDEBUG
            if (fcomport && pch != pchbuf) {
                *pch = '\0';            /* nul-terminate string and print it */
                dputs();
                cchcomport += pch - pchbuf;
                pch = pchbuf;           /* reset pointer */
                continue;
            }
#endif /* PMDEBUG */
            break;                      /* stop formatting */
        }
        if (*pchfmt != '%') {           /* If not a parameter specifier */
            if ((chpad = *pchfmt++) == '\n') {
                *pch++ = '\r';          /* Insert CR before LF */
            }
            if (chpad != '\r') {        /* skip explicit CRs, else ... */
                *pch++ = chpad;         /* Copy the character */
            }
            continue;                   /* Continue */
        }
        fsign = 0;                      /* Assume no sign needed */
        if (fleft = (char)(*++pchfmt == '-')) {
            pchfmt++;                   /* Check for left-justify flag */
        }
        chpad = ' ';                    /* Assume padding with spaces */
        if (*pchfmt == '0') {           /* If zero-padding wanted */
            chpad = '0';                /* Set pad character */
            pchfmt++;                   /* Skip '0' */
        }
        if (*pchfmt == '*') {
            pchfmt++;
            cchwidth = *plparms++;      /* Get field width */
        } else {
            cchwidth = 0;               /* Calculate field width */
            while (*pchfmt >= '0' && *pchfmt <= '9') {
                cchwidth = cchwidth*10 + *pchfmt++ - '0';
            }
        }
        cchprecision = 0x7fffffff;      /* Set maximum precision */
        if (*pchfmt == '.') {           /* Check if precision field */
            pchfmt++;
            if (*pchfmt == '*') {
                pchfmt++;
                cchprecision = *plparms++; /* Get precision */
            } else {
                cchprecision = 0;       /* Calculate field precision */
                while (*pchfmt >= '0' && *pchfmt <= '9') {
                    cchprecision = cchprecision*10 + *pchfmt++ - '0';
                }
            }
        }
        if (*pchfmt == 'l') {
            pchfmt++;                   /* Skip long integer flag */
        }
        switch (*pchfmt) {              /* Switch on format character */
            default:                    /* Bad format type */
            case '%':                   /* Percent sign */
              pchparm = pchfmt;         /* Set pointer */
              cchparm = 1;              /* Set length */
              break;

            case 'c':                   /* Character */
              pchparm = (char *) plparms; /* Set pointer */
              cchparm = 1;                /* Set length */
              if (*pchparm == '\0') {
                  cchparm = 0;          /* If nul char, set length to 0 */
              }
              ++plparms;                /* Increment pointer */
              break;

            case 'd':                   /* Decimal signed integer */
            case 'u':                   /* Decimal unsigned integer */
            case 'x':                   /* Hex integer */
              x = *plparms++;           /* Get integer */
              pchparm = SSToDS(achint + INTBUFLEN);
                                        /* Initialize pointer */
              ubase = 10;               /* Assume decimal */
              if (*pchfmt == 'x') {
                  ubase = 16;           /* If 'x', then decode in hex */
              } else if (fsign = (char)(*pchfmt == 'd' && (long) x < 0L)) {
                  x = -x;               /* Set flag and flip sign if needed */
              }
              *--pchparm = '\0';        /* Null terminate */
              do {                      /* Loop to decode integer */
                  *--pchparm = "0123456789abcdef"[(int)(x % ubase)];
                                        /* Set the digit */
                  x /= ubase;           /* Divide by base */
              } while (x != 0L && --cchprecision);
                                        /* Loop until x == 0 or prec == 0 */
              cchparm = (char *) SSToDS(achint + INTBUFLEN) - pchparm - 1;
                                        /* Set length */
              break;

            case 's':                   /* String */
              pchparm = (char *) *plparms;
                                        /* Set pointer */
              cchparm = strlen(pchparm);/* Set length */
              cchparm = cchparm > cchprecision? cchprecision : cchparm;
                                        /* Adjust the field width */
              ++plparms;                /* Increment pointer */
              break;
        }
        cchwidth -= cchparm + fsign;    /* Calculate needed padding */
        if (chpad == '0' || !fleft) {   /* If padding before parameter */
            if (fsign && chpad == '0'){ /* If sign wanted and zero-padding */
                *pch++ = '-';           /* Put sign first */
                fsign = 0;              /* Done */
            }
            if (cchwidth > 0) {
#ifdef PMDEBUG
                if (fcomport && pch != pchbuf && (pch-pchbuf)+cchwidth > cch) {
                    *pch = '\0';        /* nul-terminate string and print it */
                    dputs();
                    cchcomport += pch - pchbuf;
                    pch = pchbuf;       /* reset pointer */
                }
#endif /* PMDEBUG */
                if ((pch - pchbuf) + cchwidth > cch) {
                    cchwidth = cch - (pch - pchbuf);
                }                       /* truncate pad if it won't fit */
                while (cchwidth > 0) {  /* Loop to pad field */
                    *pch++ = chpad;     /* Pad with zeroes or spaces */
                    --cchwidth;         /* Decrement counter */
                }
            }
        }
        if (fsign) {
            *pch++ = '-';               /* Add sign if needed */
        }
#ifdef PMDEBUG
        if (fcomport && (pch - pchbuf) + cchparm > cch) {
            *pch = '\0';                /* nul-terminate string and print it */
            dputs();
            cchcomport += pch - pchbuf;
            pch = pchbuf;               /* reset pointer */
            pch[cch] = '\0';
            while (cchparm > cch) {
                memcpy(pch, pchparm, cch);
                dputs();
                cchcomport += cch;
                pchparm += cch;
                cchparm -= cch;
            }
        }
#endif /* PMDEBUG */
        if ((pch - pchbuf) + cchparm > cch) {
            cchparm = cch - (pch - pchbuf);
        }                               /* truncate string if it won't fit */
        memcpy(pch, pchparm, cchparm);  /* Copy parameter to buffer */
        pch += cchparm;                 /* And skip over it */
        if (cchwidth > 0) {
#ifdef PMDEBUG
            if (fcomport && pch != pchbuf && (pch - pchbuf) + cchwidth > cch) {
                *pch = '\0';            /* nul-terminate string and print it */
                dputs();
                cchcomport += pch - pchbuf;
                pch = pchbuf;           /* reset pointer */
            }
#endif /* PMDEBUG */
            if ((pch - pchbuf) + cchwidth > cch) {
                cchwidth = cch - (pch - pchbuf);
            }                           /* truncate pad if it won't fit */
            while (cchwidth-- > 0) {
                *pch++ = ' ';           /* Pad remainder of field */
            }
        }
        if (*pchfmt != '\0') {
            pchfmt++;                   /* Increment pointer */
        }
    }
    *pch = '\0';                        /* End of buffer */
#ifdef PMDEBUG
    if (fcomport) {
        dputs();
        return(cchcomport + (pch - pchbuf));
    }
#endif /* PMDEBUG */
    return(pch - pchbuf);               /* Return length of formatted string */
}


#ifdef PMDEBUG
/***EP  TKDebugHardError - display hard error info on debugger port
 *
 *      TKDebugHardError uses printf to display the message number
 *      and strings passed being saved for a hard error to be displayed
 *      later via the hard error daemon.
 *
 *      ENTRY   cstring - count of strings
 *              msgno   - message number
 *              pch     - pointer to asciiz nul-separated strings
 *      RETURN  NONE
 */

struct msg_s {
    ushort_t    msg_cbmsg;      /* message length */
    uchar_t     msg_achmsg[1];  /* message string */
};

void
TKDebugHardError(cstring, msgno, pchzz)
int cstring;
int msgno;
register char *pchzz;
{
    register char *pchmsg;
    register char *pch;


    printf("DelayHardError SYS%04d: %d string(s):\n", msgno, cstring);
    printf(" Pid %04x  Tid %04x  Slot %04x  HobMte %04x\n",
            pPTDACur->ptda_Pid,
            pTCBCur->TCBOrdinal,
            pTCBCur->TCBNumber,
            pPTDACur->ptda_module);
    if (pPTDACur->ptda_pszproc != NULL) {
       printf(" %s\n", pPTDACur->ptda_pszproc);
    }
    if (pchmsg = DHGetMessage32((USHORT) msgno)) {      // if message found
        pch = pchmsg;
        while (*pch) {
            if (*pch == '%' && pch[1] >= '1' && pch[1] <= '9' && cstring) {
                printf("%.*s%s", pch - pchmsg, pchmsg, pchzz);
                pch++;
                pchmsg = &pch[1];
                cstring--;
                while (*pchzz++);
            }
            pch++;
        }
        printf("%.*s\n", pch - pchmsg, pchmsg);
        return;
    }
    while (cstring--) {
        printf("%s\n", pchzz);
        while (*pchzz++)
            ;
    }
}
#endif /* PMDEBUG */
//#endif /* defined(PMDEBUG) || defined(INTERRPRT) */
