/*
** MKMSG [-h cfile] [-inc afile] [-asm srcfile [-min|-max]] txtfile
**
** take message file and produce assembler source file. lines in txtfile
** can be of 6 types:
** 1) "<<NMSG>>" -- use near segment
** 2) "<<FMSG>>" -- use far segment
** 3) "#anything" -- comment line (ignore)
** 4) "" -- blank line (ignore)
** 5) "handle<tab>number<tab>message_text"
** -- message with number and symbolic handle
** 6) "<tab>number<tab>message_text"
** -- message with number but no symbolic handle
**
** the -h file gets "#define handle number" for those messages with handles.
** the -inc file gets "handle = number" for the same messages. the -asm file
** gets standard segment definitions, then the messages are placed either in
** a near segment (MSG) or a far segment (FAR_MSG) depending on if they follow
** a <<NMSG>> or a <<FMSG>>. if neither is present, <<NMSG>> is assumed. if
** -min or -max is given with -asm, the minimum or maximum amount of 0-padding
** is calculated and placed in the .asm file. any combination of the options
** may be given, and if none are present then the input is only checked for
** syntactic validity. maximum and minimum amount of padding depends on the
** length of the individual messages, and is defined in the cp/dos spec
**
** If the -32 switch is supplied then the -asm file will be compatible
** with a 32 bit flat model operating system. In which case <<NMSG>> and
** <<FMSG>> cause the messages to be placed in two tables. The tables are
** named MSG_tbl and FAR_MSG_tbl respectively. These are within the 32 bit
** small model data segment.
**
** NOTE: This file is no longer used for NT MASM. Instead its output was
** converted to asmmsg.h and asmmsg2.h and slimed. This was the quick and
** dirty way to be able to compile masm for other processors. (Jeff Spencer)
** For more info read the header on asmmsg2.h.
**
** randy nevin, microsoft, 4/86
** (c)copyright microsoft corp, 1986
**
** Modified for 32 bit by Jeff Spencer 10/90
*/
#include <stdio.h>
#include <ctype.h>
void SetNear( void );
void SetFar( void );
char usage[] =
"usage: MKMSG [-h cfile] [-inc afile] [-asm srcfile [-min|-max]] [-32] txtfile\n";
char ex[] = "expected escape sequence: %s\n";
char n1[] = "HDR segment byte public \'MSG\'\nHDR ends\n";
char n2[] = "MSG segment byte public \'MSG\'\nMSG ends\n";
char n3[] = "PAD segment byte public \'MSG\'\nPAD ends\n";
char n4[] = "EPAD segment byte common \'MSG\'\nEPAD ends\n";
char n5[] = "DGROUP group HDR,MSG,PAD,EPAD\n\n";
char f1[] = "FAR_HDR segment byte public \'FAR_MSG\'\nFAR_HDR ends\n";
char f2[] = "FAR_MSG segment byte public \'FAR_MSG\'\nFAR_MSG ends\n";
char f3[] = "FAR_PAD segment byte public \'FAR_MSG\'\nFAR_PAD ends\n";
char f4[] = "FAR_EPAD segment byte common \'FAR_MSG\'\nFAR_EPAD ends\n";
char f5[] = "FMGROUP group FAR_HDR,FAR_MSG,FAR_PAD,FAR_EPAD\n\n";
int f32Bit = 0; /* -32?, produce 32bit flat model code */
char didnear = 0;
char didfar = 0;
FILE *fasm = NULL; /* -asm stream */
_CRTAPI1 main( argc, argv )
int argc;
char **argv;
{
FILE *f; /* the input file */
char *h = NULL; /* -h file name */
FILE *fh = NULL; /* -h stream */
char *inc = NULL; /* -inc file name */
FILE *finc = NULL; /* -inc stream */
char *asm = NULL; /* -asm file name */
int min = 0; /* -min? */
int max = 0; /* -max? */
int asmstate = 0; /* 0=nothing, 1=doing nmsg, 2=doing fmsg */
int instring; /* db "... */
char buf[256]; /* line buffer */
int ch;
int i;
int number; /* index of message number in line */
int msg; /* index of message text in line */
int npad = 0; /* cumulative amount of near padding */
int fpad = 0; /* cumulative amount of far padding */
int length;
double factor;
double result;
argc--; /* skip argv[0] */
argv++;
while (argc && **argv == '-') /* process options */
if (!strcmp( "-h", *argv )) { /* create .h file */
argc--;
argv++;
if (!argc)
printf( "no -h file given\n" );
else if (h) {
printf( "extra -h file %s ignored\n", *argv );
argc--;
argv++;
}
else { /* remember -h file */
h = *argv;
argc--;
argv++;
}
}
else if (!strcmp( "-inc", *argv )) { /* create .inc file */
argc--;
argv++;
if (!argc)
printf( "no -inc file given\n" );
else if (inc) {
printf( "extra -inc file %s ignored\n", *argv );
argc--;
argv++;
}
else { /* remember -inc file */
inc = *argv;
argc--;
argv++;
}
}
else if (!strcmp( "-asm", *argv )) { /* create .asm file */
argc--;
argv++;
if (!argc)
printf( "no -asm file given\n" );
else if (asm) {
printf( "extra -asm file %s ignored\n", *argv );
argc--;
argv++;
}
else { /* remember -asm file */
asm = *argv;
argc--;
argv++;
}
}
else if (!strcmp( "-min", *argv )) { /* minimum padding */
argc--;
argv++;
if (min)
printf( "redundant -min\n" );
min = 1;
}
else if (!strcmp( "-max", *argv )) { /* maximum padding */
argc--;
argv++;
if (max)
printf( "redundant -max\n" );
max = 1;
}
else if (!strcmp( "-32", *argv )) { /* 32bit code */
argc--;
argv++;
f32Bit = 1;
}
else {
printf( "unknown option %s ignored\n", *argv );
argc--;
argv++;
}
if ((min || max) && !asm) {
printf( "-min/-max ignored; no -asm file\n" );
min = max = 0;
}
if (min && max) {
printf( "-min and -max are mutually exclusive; -min chosen\n" );
max = 0;
}
if (!argc) { /* no arguments */
printf( usage );
exit( -1 );
}
if (argc != 1) /* extra arguments */
printf( "ignoring extra arguments\n" );
if (!(f = fopen( *argv, "rb" ))) {
printf( "can't open txtfile %s for binary reading\n", *argv );
exit( -1 );
}
if (asm && !(fasm = fopen( asm, "w" ))) {
printf( "can't open -asm file %s for writing\n", asm );
exit( -1 );
}
if (h && !(fh = fopen( h, "w" ))) {
printf( "can't open -h file %s for writing\n", h );
exit( -1 );
}
if (inc && !(finc = fopen( inc, "w" ))) {
printf( "can't open -inc file %s for writing\n", inc );
exit( -1 );
}
if( fasm && f32Bit ){
fprintf( fasm, "\t.386\n" );
fprintf( fasm, "\t.model small,c\n" );
fprintf( fasm, "\t.data\n\n" );
}
while ((ch = getc( f )) != EOF) /* process lines */
if (ch == '<') { /* <<NMSG>> or <<FMSG>> */
buf[0] = ch;
i = 1;
while ((ch = getc( f )) != EOF && ch != '\r'
&& ch != '\n')
if (i < 255)
buf[i++] = ch;
buf[i] = '\0';
if (!strcmp( "<<NMSG>>", buf ))/*near msgs follow*/
if (asmstate == 0) {
if (fasm) {
SetNear();
asmstate = 1;
}
}
else if (asmstate == 1)
printf( "already in nmsg\n" );
else if (asmstate == 2) {
if (fasm) {
if( !f32Bit ){
fprintf( fasm, "FAR_MSG ends\n\n" );
}
SetNear();
asmstate = 1;
}
}
else {
printf( "internal error\n" );
exit( -1 );
}
else if (!strcmp( "<<FMSG>>", buf ))/*far msgs follow*/
if (asmstate == 0) {
if (fasm) {
SetFar();
asmstate = 2;
}
}
else if (asmstate == 1) {
if (fasm) {
if( !f32Bit ){
fprintf( fasm, "MSG ends\n\n" );
}
SetFar();
asmstate = 2;
}
}
else if (asmstate == 2)
printf( "already in fmsg\n" );
else {
printf( "internal error\n" );
exit( -1 );
}
else
printf( "ignoring bad line: %s\n", buf );
}
else if (ch == '#') /* comment line */
while ((ch = getc( f )) != EOF && ch != '\r'
&& ch != '\n')
;
else if (ch != '\r' && ch != '\n') { /* something to do */
buf[0] = ch;
i = 1;
while ((ch = getc( f )) != EOF && ch != '\r'
&& ch != '\n')
if (i < 255)
buf[i++] = ch;
buf[i] = '\0';
if (buf[i = 0] != '\t')
while (buf[i] && buf[i] != '\t')
i++;
if (!buf[i]) {
printf( "expected <TAB>: %s\n", buf );
continue;
}
else
i++;
if (!buf[i] || buf[i] == '\t') {
printf( "expected msgnum: %s\n", buf );
continue;
}
number = i;
while (buf[i] && buf[i] != '\t')
i++;
if (buf[i] != '\t') {
printf( "expected <TAB>: %s\n", buf );
continue;
}
msg = ++i;
if (buf[0] != '\t') { /* possible -h and/or -inc */
if (h) {
fprintf( fh, "#define\t" );
for (i = 0; i < msg-1; i++)
putc( buf[i], fh );
putc( '\n', fh );
}
if (inc) {
for (i = 0; i < number; i++)
putc( buf[i], finc );
fprintf( finc, "=\t" );
while (i < msg-1)
putc( buf[i++], finc );
putc( '\n', finc );
}
}
if (fasm) { /* write asmfile */
if (asmstate == 0) {
SetNear();
asmstate = 1;
}
fprintf( fasm, "\tdw\t" );
for (i = number; i < msg-1; i++)
putc( buf[i], fasm );
fprintf( fasm, "\n\tdb\t" );
instring = 0;
for (i = msg, length = 0; buf[i];
i++, length++)
/* allocate message */
if (buf[i] == '\\')
/* C escape sequence */
switch (buf[++i]) {
case 'r':
case 'n':
case 't':
case 'f':
case 'v':
case 'b':
case '\'':
case '"':
case '\\':
if (instring) {
putc( '"',
fasm );
putc( ',',
fasm );
instring = 0;
}
if (buf[i] == 'r')
fprintf( fasm,
"13" );
else if (buf[i] == 'n')
fprintf( fasm,
"10" );
else if (buf[i] == 't')
fprintf( fasm,
"9" );
else if (buf[i] == 'f')
fprintf( fasm,
"12" );
else if (buf[i] == 'v')
fprintf( fasm,
"11" );
else if (buf[i] == 'b')
fprintf( fasm,
"8" );
else if (buf[i] == '\'')
fprintf( fasm,
"39" );
else if (buf[i] == '"')
fprintf( fasm,
"34" );
else if (buf[i] == '\\')
fprintf( fasm,
"92" );
putc( ',', fasm );
break;
case '\0':
printf( ex, buf );
i--;
break;
default:
if (!instring) {
putc( '"',
fasm );
instring = 1;
}
putc( buf[i], fasm );
break;
}
else if (instring)
/* keep building string */
putc( buf[i], fasm );
else { /* start building string */
putc( '"', fasm );
instring = 1;
putc( buf[i], fasm );
}
if (instring) { /* close string */
putc( '"', fasm );
putc( ',', fasm );
}
putc( '0', fasm );
putc( '\n', fasm );
/* calculate padding */
/* depends on msg length */
if (min || max) {
if (min)
if (length <= 10)
factor = 1.01;
else if (length <= 20)
factor = 0.81;
else if (length <= 30)
factor = 0.61;
else if (length <= 50)
factor = 0.41;
else if (length <= 70)
factor = 0.31;
else
factor = 0.30;
else if (length <= 10)
factor = 2.00;
else if (length <= 20)
factor = 1.00;
else if (length <= 30)
factor = 0.80;
else if (length <= 50)
factor = 0.60;
else if (length <= 70)
factor = 0.40;
else
factor = 0.30;
result = (double)length * factor;
if (asmstate == 1) {
npad += (int)result;
if (result
> (float)((int)result))
npad++;
}
else if (asmstate == 2) {
fpad += (int)result;
if (result
> (float)((int)result))
fpad++;
}
}
}
}
if (fasm) { /* finish up asm file */
if( !f32Bit ){
if (asmstate == 1)
fprintf( fasm, "MSG ends\n\n");
else if (asmstate == 2)
fprintf( fasm, "FAR_MSG ends\n\n");
if (npad) { /* add near padding */
fprintf( fasm, "PAD segment\n\tdb\t%d dup(0)\n",
npad );
fprintf( fasm, "PAD ends\n\n" );
}
if (fpad) { /* add far padding */
fprintf( fasm, "FAR_PAD segment\n\tdb\t%d dup(0)\n",
fpad );
fprintf( fasm, "FAR_PAD ends\n\n" );
}
}
fprintf( fasm, "\tend\n" );
fclose( fasm );
}
if (fh)
fclose( fh );
if (finc)
fclose( finc );
fclose( f );
exit( 0 );
}
void SetNear()
{
if( f32Bit ) {
if( !didnear ){
fprintf( fasm, "MSG_tbl EQU $\n" );
fprintf( fasm, "\tpublic MSG_tbl\n" );
didnear++;
}
else{
/* Rather than modify mkmsg to handle mixed NEAR / FAR */
/* I (Jeff Spencer) chose the quick route of limiting it's capabilities */
/* As this capability wasn't needed for MASM 5.1 */
printf( "error - 32 bit version doesn't support alternating NEAR and FAR messages\n" );
exit( -1 );
}
}
else{
if (!didnear) {
didnear++;
fprintf( fasm, n1 );
fprintf( fasm, n2 );
fprintf( fasm, n3 );
fprintf( fasm, n4 );
fprintf( fasm, n5 );
}
fprintf( fasm,
"MSG segment\n" );
}
}
void SetFar()
{
if( f32Bit ){
if( !didfar ){
fprintf( fasm, "FAR_MSG_tbl EQU $\n" );
fprintf( fasm, "\tpublic FAR_MSG_tbl\n" );
didfar++;
}
else{
/* Rather than modify mkmsg to handle mixed NEAR / FAR */
/* I (Jeff Spencer) chose the quick route of limiting it's capabilities */
/* As this capability wasn't needed for MASM 5.1 */
printf( "error - 32 bit version doesn't support alternating NEAR and FAR messages\n" );
exit( -1 );
}
}
else{
if (!didfar) {
didfar++;
fprintf( fasm, f1 );
fprintf( fasm, f2 );
fprintf( fasm, f3 );
fprintf( fasm, f4 );
fprintf( fasm, f5 );
}
fprintf( fasm,
"FAR_MSG segment\n" );
}
}