2020-09-30 17:12:29 +02:00

303 lines
5.3 KiB
C

// getmsg.c
#include <io.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <ctype.h>
#include <mbctype.h>
#include <string.h>
#include <getmsg.h>
// Local helper functions
static char * get_msg(int num, char *pbuf, int len);
static char * get_message(register char *p);
static char * get_int(register char *, int *);
static long nearest(int num);
static void mark_pos(long pos, int num);
void __cdecl CleanUp(void);
// TODO: Make these local?
static FILE *phErrorFile = NULL;
static char *pErrorFilename = NULL;
char *
get_err(int msg_num)
{
static char Errbuff[1024];
if (!phErrorFile)
{
/* try to open the error file */
if (!pErrorFilename || (phErrorFile = fopen(pErrorFilename, "r")) == NULL)
{
phErrorFile = (FILE *)-1;
return("");
}
else
{
// File Opened OK, install the clean up routine to
// close file & deallocate memory used by the filename
atexit(CleanUp);
}
}
else if (phErrorFile == (FILE *)-1)
{
return("");
}
fseek(phErrorFile, (long)nearest(msg_num), 0);
return(get_msg(msg_num, Errbuff, sizeof(Errbuff)));
} // get_err
//
// get_msg
//
static char *
get_msg(int num, char *pbuf, int len)
{
int val;
long pos;
register char *p;
for (;;)
{
pos = ftell(phErrorFile);
p = pbuf;
if (fgets(p, len, phErrorFile) == NULL)
{
// Reaches end-of-file, can't find the message, so just return
// an empty string.
return "";
}
p = get_int(p, &val);
if (val == num || ((val % 1000) == 999))
{
// if val % 1000 == 999, then we have reached the unknown error
// message, don't put it in the error message table in this case
if (val == num)
{
mark_pos(pos, num);
}
else if ((val / 1000) != (num / 1000))
{
// found UNKNOWN msg, but wrong error class - continue
continue;
}
return(get_message(p));
} // if (val == num ...)
} // for
// When all else failed, returns an empty string
return "";
} // get_msg()
//
// get_message
//
static char *
get_message(register char *p)
{
char *retp;
register char *cp;
while (*p++ != '"')
;
retp = cp = p;
while (*p != '"')
{
if (_ismbblead(*p))
{
*cp++ = *p++;
}
else if (*p == '\\')
{
p++;
if (*p == 'n')
*p = '\n';
else if (*p == 't')
*p = '\t';
else if (*p == '\"')
*p = '\"';
else
*cp++ = '\\';
} // else
*cp++ = *p++;
} // while
*cp = '\0';
return(retp);
}
//
// get_int
//
static char *
get_int(register char *p, int *pval)
{
register int val;
val = 0;
while (*p && isdigit(*p))
{
val = val * 10 + (*p - '0');
p++;
} // while
*pval = val;
return(p);
} // get_int()
//
// SetErrorFile
//
int
SetErrorFile(char *pFilename, char *pExeName, int bSearchExePath)
{
char szPath[_MAX_PATH];
char szDrive[_MAX_DRIVE];
char szDir[_MAX_DIR];
char szFilename[_MAX_FNAME];
char szExtension[_MAX_EXT];
if (!bSearchExePath)
{
if (0 == _access(pFilename, 0))
{
pErrorFilename = _strdup(pFilename);
return 0;
}
return 1;
}
// Find in the executable's directory
_splitpath(pExeName, szDrive, szDir, NULL, NULL);
_splitpath(pFilename, NULL, NULL, szFilename, szExtension);
_makepath(szPath, szDrive, szDir, szFilename, szExtension);
if (0 == _access(szPath, 0))
{
pErrorFilename = _strdup(szPath);
return 0;
}
// Still not found, find in current directory
_makepath(szPath, NULL, NULL, szFilename, szExtension);
if (0 == _access(szPath, 0))
{
pErrorFilename = _strdup(szPath);
return 0;
}
// We can't find the error message file, so display an error
// message in English. This error message must be embedded
// in the .EXE, otherwise, what's the point?
fprintf(stderr,
"WARNING: missing %s; "
"displaying error numbers without messages.\n",
pFilename);
return 1;
}
//
// CleanUp
//
static void __cdecl
CleanUp(void)
{
if (phErrorFile)
fclose(phErrorFile);
if (pErrorFilename)
free(pErrorFilename);
}
//
// Error message cache
//
#define MAX_MSGLOCS 20
static struct ErrInfo
{
int num; // Message number
long pos; // File position
} Err_Info[MAX_MSGLOCS] = {0};
//
// mark_pos
//
static void
mark_pos(long pos, int num)
{
register int i;
for (i = 0; i < MAX_MSGLOCS && Err_Info[i].num != 0; i++)
{
if (Err_Info[i].num == num)
return; /* already in table */
} // for
if (i < MAX_MSGLOCS)
{
/* save location of this message */
Err_Info[i].num = num;
Err_Info[i].pos = pos;
} // if
return;
} // mark_pos()
/*
** Try to position the error file close to previously located
** messages. This assumes that the message numbers in the error
** file are in ascending order within each category.
*/
static long
nearest(int num)
{
register int i,n;
int diff, ix;
diff = 32767;
ix = -1;
for (i = 0; ((i < MAX_MSGLOCS) && ((n = Err_Info[i].num) != 0)); i++)
{
n = num - n;
if (n == 0)
{
ix = i;
break;
}
else if ((n > 0) && (n < diff) && (num / 1000) == (Err_Info[i].num / 1000))
{
diff = n;
ix = i;
}
} // for
return((ix >= 0) ? Err_Info[ix].pos : 0L);
} // nearest()
#ifdef TEST
int
main(int argc, char *argv[])
{
char *pMessage;
int nErrorNumber;
if (argc < 3)
{
fprintf(stderr, "USAGE: GETMSG <MsgFilename> <MsgNumber>...\n\n");
return 1;
}
SetErrorFile(*(argv+1), *argv, 1);
argc--; argv++;
while (--argc)
{
nErrorNumber = atoi(*++argv);
pMessage = get_err(nErrorNumber);
printf("%d: [%s]\n", nErrorNumber, pMessage);
}
return 0;
} // main()
#endif // TEST