[net.bugs] Some improvements to "file"

guy@sun.uucp (Guy Harris) (09/03/85)

1) The SCCS ID contains an extraneous <ESC>, if anybody cares...

2) A new type "byte" has been added to the magic number types in /etc/magic
(the scaffolding was already there), and the numeric types now support an
optional masking operator.  If a mask is specified, the value is ANDed with
the specified mask before it is compared with any test values and before it
is printed.

3) The test values for the "string" type can now contain C string escape
sequences, such as "\n" for newline.

4) The return value of "malloc" is now tested, and the internal table of
/etc/magic file entries is now "realloc"ed if it fills up; printing a
message saying to change some magic number in the source and recompile is
rather dumb, considering most S5 users outside AT&T *don't* have the source
to do that with...

5) The error messages have been cleaned up, and error messages due to
"open"s or "stat"s failing now include the error message corresponding to
the value of "errno".

6) When it tries to reset the time of last access, it now uses "ustat" the
way the manual says you're supposed to.  Thus, it won't fail on systems like
4.2BSD, where "st_atime" and "st_mtime" aren't contiguous.  (Note that the
S3/S5 manual go out of their way *NOT* to tell you that they're contiguous;
somebody made an effort to prevent the very sort of crap that "file",
"cpio", and "pack" do.)

7) Several bits of code, such as the code that parses /etc/magic and the
code that prints the table built from /etc/magic, have been cleaned up.

Note that the bug report (in the referenced articles) about "unsigned short"
vs. "short" may be fixed in the original S5R2 version (they may have seen
the bug in S5R1) - some of the suggested changes seem to have been made).
The version here corrects the other two complaints about no "byte" type and
halfassed checking of the type field in general.

Note that the 4.2BSD version has a number of other useful tests (like tests
against "ditroff" output) which should be tossed into the S5 version.

The original reason I put in the stuff under 2) and 3) was to make it
possible to test for a "compress"ed file (see mod.sources for "compress"
version 4 - it blows "pack" and "compact" away), and to test for block
compression and to dump the number of bits required for decompression,
without having to hack the source.  Here's the entry for "compressed" files:

0	string		\037\235	compressed data
>2	byte&0x80	>0		block compressed
>2	byte&0x1f	x		%d bits

What it means is "test the two bytes starting at location 0 in the file.  If
they are equal to \037 and \235 respectively, print 'compressed data'.  Then
test whether the byte at location 2, when masked with 0x80, is non-zero.  If
so, print 'block compressed'.  Then print that byte, masked with 0x1f, in
the form '<N> bits'."

The gory details of how to construct a "magic" file are given (sketchily,
and *sans* these new features) in "/etc/magic".  This is the wrong place to
give them.  The correct place to give them is MAGIC(4), which I have whipped
up and posted in another article.

Here are the changes, in "diff -c" form:

*** /arch/s5r2/usr/src/cmd/file/file.c	Mon Oct 31 06:46:34 1983
--- ./file.c	Tue Sep  3 00:57:47 1985
***************
*** 2,8
  
  #include	<stdio.h>
  #include	<ctype.h>
- #include	<signal.h>
  #include	<sys/param.h>
  #include	<sys/types.h>
  #include	<sys/sysmacros.h>

--- 2,7 -----
  
  #include	<stdio.h>
  #include	<ctype.h>
  #include	<sys/param.h>
  #include	<sys/types.h>
  #include	<sys/sysmacros.h>
***************
*** 13,21
  */
  
  #define	BYTE	0
! #define	SHORT	2
! #define	LONG	4
! #define	STR	8
  
  /*
  **	Opcodes

--- 12,20 -----
  */
  
  #define	BYTE	0
! #define	SHORT	1
! #define	LONG	2
! #define	STR	3
  
  #define	NTYPES	4
  
***************
*** 17,22
  #define	LONG	4
  #define	STR	8
  
  /*
  **	Opcodes
  */

--- 16,30 -----
  #define	LONG	2
  #define	STR	3
  
+ #define	NTYPES	4
+ 
+ char	*typenames[NTYPES] = {
+ 	"byte",
+ 	"short",
+ 	"long",
+ 	"string"
+ };
+ 
  /*
  **	Opcodes
  */
***************
*** 28,33
  #define	ANY	4
  #define	SUB	64	/* or'ed in */
  
  /*
  **	Misc
  */

--- 36,51 -----
  #define	ANY	4
  #define	SUB	64	/* or'ed in */
  
+ #define	NOPS	5
+ 
+ char	opnames[NOPS] = {
+ 	'=',
+ 	'>',
+ 	'<',
+ 	'=',
+ 	'x'
+ };
+ 
  /*
  **	Misc
  */
***************
*** 51,56
  	char	e_level;	/* 0 or 1 */
  	long	e_off;		/* in bytes */
  	char	e_type;
  	char	e_opcode;
  	union	{
  		long	num;

--- 69,75 -----
  	char	e_level;	/* 0 or 1 */
  	long	e_off;		/* in bytes */
  	char	e_type;
+ 	long	e_mask;		/* if non-zero, mask value with this */
  	char	e_opcode;
  	union	{
  		long	num;
***************
*** 61,67
  
  typedef	struct entry	Entry;
  
! Entry	*mtab;
  char	fbuf[FBSZ];
  char	*mfile = "/etc/magic";
  char	*fort[] = {

--- 80,89 -----
  
  typedef	struct entry	Entry;
  
! Entry	*mtab, *mend;
! int	errno;
! int	sys_nerr;
! char	*sys_errlist[];
  char	fbuf[FBSZ];
  char	*mfile = "/etc/magic";
  char	*fort[] = {
***************
*** 76,81
  char	*strchr();
  char	*malloc();
  long	atolo();
  int	i = 0;
  int	fbsz;
  int	ifd;

--- 98,105 -----
  char	*strchr();
  char	*malloc();
  long	atolo();
+ char	*getstr();
+ void	showstr();
  int	i = 0;
  int	fbsz;
  int	ifd = -1;
***************
*** 78,84
  long	atolo();
  int	i = 0;
  int	fbsz;
! int	ifd;
  
  #define	prf(x)	printf("%s:%s", x, strlen(x)>6 ? "\t" : "\t\t");
  

--- 102,108 -----
  void	showstr();
  int	i = 0;
  int	fbsz;
! int	ifd = -1;
  
  #define	prf(x)	printf("%s:%s", x, strlen(x)>6 ? "\t" : "\t\t");
  
***************
*** 102,108
  	case 'f':
  		fflg++;
  		if ((fl = fopen(optarg, "r")) == NULL) {
! 			fprintf(stderr, "cannot open %s\n", optarg);
  			goto use;
  		}
  		break;

--- 126,133 -----
  	case 'f':
  		fflg++;
  		if ((fl = fopen(optarg, "r")) == NULL) {
! 			fprintf(stderr, "file: %s: %s\n", optarg,
! 			    errno < sys_nerr? sys_errlist[errno]: "Can't open");
  			goto use;
  		}
  		break;
***************
*** 125,134
  		reg	Entry	*ep;
  
  		mkmtab(1);
! 		printf("level	off	type	opcode	value	string\n");
! 		for(ep = mtab; ep->e_off != -1L; ep++) {
! 			printf("%d\t%d\t%d\t%d\t", ep->e_level, ep->e_off,
! 				ep->e_type, ep->e_opcode);
  			if(ep->e_type == STR)
  				printf("%s\t", ep->e_value.str);
  			else

--- 150,162 -----
  		reg	Entry	*ep;
  
  		mkmtab(1);
! 		printf("level\toff\ttype\topcode\tvalue\tstring\n");
! 		for(ep = mtab; ep < mend; ep++) {
! 			printf("%d\t%d\t%s", ep->e_level, ep->e_off,
! 				typenames[ep->e_type]);
! 			if(ep->e_mask != 0L)
! 				printf("&%#lo", ep->e_mask);
! 			printf("\t%c\t", opnames[ep->e_opcode & ~SUB]);
  			if(ep->e_type == STR)
  				showstr(ep->e_value.str);
  			else
***************
*** 130,136
  			printf("%d\t%d\t%d\t%d\t", ep->e_level, ep->e_off,
  				ep->e_type, ep->e_opcode);
  			if(ep->e_type == STR)
! 				printf("%s\t", ep->e_value.str);
  			else
  				printf("%lo\t", ep->e_value.num);
  			printf("%s", ep->e_str);

--- 158,164 -----
  				printf("&%#lo", ep->e_mask);
  			printf("\t%c\t", opnames[ep->e_opcode & ~SUB]);
  			if(ep->e_type == STR)
! 				showstr(ep->e_value.str);
  			else
  				printf("%lo\t", ep->e_value.num);
  			printf("%s", ep->e_str);
***************
*** 156,162
  			p = argv[optind];
  		prf(p);
  		type(p);
! 		if(ifd)
  			close(ifd);
  	}
  	exit(0);

--- 184,190 -----
  			p = argv[optind];
  		prf(p);
  		type(p);
! 		if(ifd >= 0)
  			close(ifd);
  	}
  	exit(0);
***************
*** 168,173
  	int	j,nl;
  	char	ch;
  	struct	stat	mbuf;
  
  	ifd = -1;
  	if(stat(file, &mbuf) < 0) {

--- 196,205 -----
  	int	j,nl;
  	char	ch;
  	struct	stat	mbuf;
+ 	struct	utimbuf {
+ 		time_t	actime;
+ 		time_t	modtime;
+ 	}	utb;
  
  	ifd = -1;
  	if(stat(file, &mbuf) < 0) {
***************
*** 171,177
  
  	ifd = -1;
  	if(stat(file, &mbuf) < 0) {
! 		printf("cannot open\n");
  		return;
  	}
  	switch (mbuf.st_mode & S_IFMT) {

--- 203,210 -----
  
  	ifd = -1;
  	if(stat(file, &mbuf) < 0) {
! 		printf("%s\n",
! 		(unsigned)errno < sys_nerr? sys_errlist[errno]: "Cannot stat");
  		return;
  	}
  	switch (mbuf.st_mode & S_IFMT) {
***************
*** 197,203
  	}
  	ifd = open(file, 0);
  	if(ifd < 0) {
! 		printf("cannot open for reading\n");
  		return;
  	}
  	fbsz = read(ifd, fbuf, FBSZ);

--- 230,237 -----
  	}
  	ifd = open(file, 0);
  	if(ifd < 0) {
! 		printf("%s\n",
! 		(unsigned)errno < sys_nerr? sys_errlist[errno]: "Cannot read");
  		return;
  	}
  	fbsz = read(ifd, fbuf, FBSZ);
***************
*** 206,212
  		goto out;
  	}
  	if(sccs()) {
! 		printf("sccs \n");
  		goto out;
  	}
  	if(ckmtab())

--- 240,246 -----
  		goto out;
  	}
  	if(sccs()) {
! 		printf("sccs\n");
  		goto out;
  	}
  	if(ckmtab())
***************
*** 318,324
  	for(i=0; i < fbsz; i++)
  		if(fbuf[i]&0200) {
  			if (fbuf[0]=='\100' && fbuf[1]=='\357') {
! 				printf("troff output\n");
  				goto out;
  			}
  			printf("data\n"); 

--- 352,358 -----
  	for(i=0; i < fbsz; i++)
  		if(fbuf[i]&0200) {
  			if (fbuf[0]=='\100' && fbuf[1]=='\357') {
! 				printf("otroff output\n");
  				goto out;
  			}
  			printf("data\n"); 
***************
*** 338,344
  		}
  	printf("\n");
  out:
! 	utime(file, &mbuf.st_atime);
  }
  
  mkmtab(cflg)

--- 372,380 -----
  		}
  	printf("\n");
  out:
! 	utb.actime = mbuf.st_atime;
! 	utb.modtime = mbuf.st_mtime;
! 	(void)utime(file, &utb);
  }
  
  mkmtab(cflg)
***************
*** 347,352
  	reg	Entry	*ep;
  	reg	FILE	*fp;
  	reg	int	lcnt = 0;
  	auto	char	buf[BSZ];
  	auto	Entry	*mend;
  

--- 383,389 -----
  	reg	Entry	*ep;
  	reg	FILE	*fp;
  	reg	int	lcnt = 0;
+ 	reg	int	i;
  	auto	char	buf[BSZ];
  	auto	int	curentry;
  	auto	int	nentries;
***************
*** 348,354
  	reg	FILE	*fp;
  	reg	int	lcnt = 0;
  	auto	char	buf[BSZ];
! 	auto	Entry	*mend;
  
  	ep = (Entry *) calloc(sizeof(Entry), NENT);
  	if(ep == NULL) {

--- 385,392 -----
  	reg	int	lcnt = 0;
  	reg	int	i;
  	auto	char	buf[BSZ];
! 	auto	int	curentry;
! 	auto	int	nentries;
  
  	mtab = (Entry *) malloc(sizeof(Entry)*NENT);
  	if(mtab == NULL) {
***************
*** 350,358
  	auto	char	buf[BSZ];
  	auto	Entry	*mend;
  
! 	ep = (Entry *) calloc(sizeof(Entry), NENT);
! 	if(ep == NULL) {
! 		fprintf(stderr, "no memory for magic table\n");
  		exit(2);
  	}
  	mtab = ep;

--- 388,396 -----
  	auto	int	curentry;
  	auto	int	nentries;
  
! 	mtab = (Entry *) malloc(sizeof(Entry)*NENT);
! 	if(mtab == NULL) {
! 		fprintf(stderr, "file: no memory for magic table\n");
  		exit(2);
  	}
  	curentry = 0;
***************
*** 355,362
  		fprintf(stderr, "no memory for magic table\n");
  		exit(2);
  	}
! 	mtab = ep;
! 	mend = &mtab[NENT];
  	fp = fopen(mfile, "r");
  	if(fp == NULL) {
  		fprintf(stderr, "cannot open magic file <%s>.\n", mfile);

--- 393,400 -----
  		fprintf(stderr, "file: no memory for magic table\n");
  		exit(2);
  	}
! 	curentry = 0;
! 	nentries = NENT;
  	fp = fopen(mfile, "r");
  	if(fp == NULL) {
  		fprintf(stderr, "file: cannot open magic file <%s>: %s\n",
***************
*** 359,365
  	mend = &mtab[NENT];
  	fp = fopen(mfile, "r");
  	if(fp == NULL) {
! 		fprintf(stderr, "cannot open magic file <%s>.\n", mfile);
  		exit(2);
  	}
  	while(fgets(buf, BSZ, fp) != NULL) {

--- 397,404 -----
  	nentries = NENT;
  	fp = fopen(mfile, "r");
  	if(fp == NULL) {
! 		fprintf(stderr, "file: cannot open magic file <%s>: %s\n",
! 		    mfile, errno < sys_nerr? sys_errlist[errno]: "Can't open");
  		exit(2);
  	}
  	while(fgets(buf, BSZ, fp) != NULL) {
***************
*** 365,370
  	while(fgets(buf, BSZ, fp) != NULL) {
  		reg	char	*p = buf;
  		reg	char	*p2;
  		reg	char	opc;
  
  		if(*p == '\n' || *p == '#')

--- 404,410 -----
  	while(fgets(buf, BSZ, fp) != NULL) {
  		reg	char	*p = buf;
  		reg	char	*p2;
+ 		reg	char	*p3;
  		reg	char	opc;
  
  		ep = &mtab[curentry];
***************
*** 367,372
  		reg	char	*p2;
  		reg	char	opc;
  
  		if(*p == '\n' || *p == '#')
  			continue;
  		lcnt++;

--- 407,413 -----
  		reg	char	*p3;
  		reg	char	opc;
  
+ 		ep = &mtab[curentry];
  		if(*p == '\n' || *p == '#')
  			continue;
  		lcnt++;
***************
*** 397,409
  			continue;
  		}
  		*p2++ = NULL;
! 		if(*p == 's') {
! 			if(*(p+1) == 'h')
! 				ep->e_type = SHORT;
! 			else
! 				ep->e_type = STR;
! 		} else if (*p == 'l')
! 			ep->e_type = LONG;
  		while(*p2 == '\t')
  			*p2++;
  			/* OP-VALUE */

--- 438,458 -----
  			continue;
  		}
  		*p2++ = NULL;
! 		p3 = strchr(p, '&');
! 		if(p3 != NULL) {
! 			*p3++ = '\0';
! 			ep->e_mask = atolo(p3);
! 		} else
! 			ep->e_mask = 0L;
! 		for (i = 0; i < NTYPES; i++) {
! 			if (strcmp(p, typenames[i]) == 0)
! 				goto foundtype;
! 		}
! 		if(cflg)
! 			fprintf(stderr, "file: illegal type %s\n", p);
! 		continue;
! foundtype:
! 		ep->e_type = i;
  		while(*p2 == '\t')
  			*p2++;
  			/* OP-VALUE */
***************
*** 411,417
  		p2 = strchr(p, '\t');
  		if(p2 == NULL) {
  			if(cflg)
! 				fprintf(stderr, "fmt error, no tab after %son line %d\n", p, lcnt);
  			continue;
  		}
  		*p2++ = NULL;

--- 460,466 -----
  		p2 = strchr(p, '\t');
  		if(p2 == NULL) {
  			if(cflg)
! 				fprintf(stderr, "file: fmt error, no tab after %son line %d\n", p, lcnt);
  			continue;
  		}
  		*p2++ = '\0';
***************
*** 414,420
  				fprintf(stderr, "fmt error, no tab after %son line %d\n", p, lcnt);
  			continue;
  		}
! 		*p2++ = NULL;
  		if(ep->e_type != STR) {
  			opc = *p++;
  			switch(opc) {

--- 463,469 -----
  				fprintf(stderr, "file: fmt error, no tab after %son line %d\n", p, lcnt);
  			continue;
  		}
! 		*p2++ = '\0';
  		if(ep->e_type != STR) {
  			opc = *p++;
  			for (i = 0; i < NOPS; i++) {
***************
*** 417,441
  		*p2++ = NULL;
  		if(ep->e_type != STR) {
  			opc = *p++;
! 			switch(opc) {
! 			case '=':
! 				ep->e_opcode = EQ;
! 				break;
! 
! 			case '>':
! 				ep->e_opcode = GT;
! 				break;
! 
! 			case '<':
! 				ep->e_opcode = LT;
! 				break;
! 
! 			case 'x':
! 				ep->e_opcode = ANY;
! 				break;
! 
! 			default:
! 				p--;
  			}
  		}
  		if(ep->e_opcode != ANY) {

--- 466,474 -----
  		*p2++ = '\0';
  		if(ep->e_type != STR) {
  			opc = *p++;
! 			for (i = 0; i < NOPS; i++) {
! 				if (opc == opnames[i])
! 					goto foundop;
  			}
  			p--;
  			goto notfound;
***************
*** 437,442
  			default:
  				p--;
  			}
  		}
  		if(ep->e_opcode != ANY) {
  			if(ep->e_type != STR)

--- 470,479 -----
  				if (opc == opnames[i])
  					goto foundop;
  			}
+ 			p--;
+ 			goto notfound;
+ 	foundop:
+ 			ep->e_opcode = i;
  		}
  notfound:
  		if(ep->e_opcode != ANY) {
***************
*** 438,443
  				p--;
  			}
  		}
  		if(ep->e_opcode != ANY) {
  			if(ep->e_type != STR)
  				ep->e_value.num = atolo(p);

--- 475,481 -----
  	foundop:
  			ep->e_opcode = i;
  		}
+ notfound:
  		if(ep->e_opcode != ANY) {
  			if(ep->e_type != STR)
  				ep->e_value.num = atolo(p);
***************
*** 441,450
  		if(ep->e_opcode != ANY) {
  			if(ep->e_type != STR)
  				ep->e_value.num = atolo(p);
! 			else {
! 				ep->e_value.str = malloc(strlen(p) + 1);
! 				strcpy(ep->e_value.str, p);
! 			}
  		}
  		while(*p2 == '\t')
  			*p2++;

--- 479,486 -----
  		if(ep->e_opcode != ANY) {
  			if(ep->e_type != STR)
  				ep->e_value.num = atolo(p);
! 			else
! 				ep->e_value.str = getstr(p);
  		}
  		while(*p2 == '\t')
  			*p2++;
***************
*** 450,455
  			*p2++;
  			/* STRING */
  		ep->e_str = malloc(strlen(p2) + 1);
  		p = ep->e_str;
  		while(*p2 != '\n') {
  			if(*p2 == '%')

--- 486,495 -----
  			*p2++;
  			/* STRING */
  		ep->e_str = malloc(strlen(p2) + 1);
+ 		if(ep->e_str == NULL) {
+ 			fprintf(stderr, "file: no memory for magic table\n");
+ 			exit(2);
+ 		}
  		p = ep->e_str;
  		while(*p2 != '\n') {
  			if(*p2 == '%')
***************
*** 457,466
  			*p++ = *p2++;
  		}
  		*p = NULL;
! 		ep++;
! 		if(ep >= mend) {
! 			fprintf(stderr, "file: magic tab overflow - increase NENT in file.c.\n");
! 			exit(2);
  		}
  	}
  	ep->e_off = -1L;

--- 497,510 -----
  			*p++ = *p2++;
  		}
  		*p = NULL;
! 		curentry++;
! 		if(curentry >= nentries) {
! 			mtab = (Entry *) realloc(mtab, sizeof(Entry)*NENT);
! 			if(mtab == NULL) {
! 				fprintf(stderr, "file: no memory for magic table\n");
! 				exit(2);
! 			}
! 			nentries += NENT;
  		}
  	}
  	mend = &mtab[curentry];
***************
*** 463,469
  			exit(2);
  		}
  	}
! 	ep->e_off = -1L;
  }
  
  long

--- 507,513 -----
  			nentries += NENT;
  		}
  	}
! 	mend = &mtab[curentry];
  }
  
  long
***************
*** 486,491
  	return(j);
  }
  
  ckmtab()
  {
  

--- 530,661 -----
  	return(j);
  }
  
+ char *
+ getstr(s)
+ reg	char	*s;
+ {
+ 	auto	char	*store;
+ 	reg	char	*p;
+ 	reg	char	c;
+ 	reg	int	val;
+ 
+ 	if((store = malloc(strlen(s) + 1)) == NULL) {
+ 		fprintf(stderr, "file: no memory for magic table\n");
+ 		exit(2);
+ 	}
+ 	p = store;
+ 	while((c = *s++) != '\0') {
+ 		if(c == '\\') {
+ 			switch(c = *s++) {
+ 
+ 			case '\0':
+ 				goto out;
+ 
+ 			default:
+ 				*p++ = c;
+ 				break;
+ 
+ 			case 'n':
+ 				*p++ = '\n';
+ 				break;
+ 
+ 			case 'r':
+ 				*p++ = '\r';
+ 				break;
+ 
+ 			case 'b':
+ 				*p++ = '\b';
+ 				break;
+ 
+ 			case 't':
+ 				*p++ = '\t';
+ 				break;
+ 
+ 			case 'f':
+ 				*p++ = '\f';
+ 				break;
+ 
+ 			case 'v':
+ 				*p++ = '\v';
+ 				break;
+ 
+ 			case '0':
+ 			case '1':
+ 			case '2':
+ 			case '3':
+ 			case '4':
+ 			case '5':
+ 			case '6':
+ 			case '7':
+ 				val = c - '0';
+ 				c = *s++;  /* try for 2 */
+ 				if(c >= '0' && c <= '7') {
+ 					val = (val<<3) | (c - '0');
+ 					c = *s++;  /* try for 3 */
+ 					if(c >= '0' && c <= '7')
+ 						val = (val<<3) | (c-'0');
+ 					else
+ 						--s;
+ 				}
+ 				else
+ 					--s;
+ 				*p++ = val;
+ 				break;
+ 			}
+ 		} else
+ 			*p++ = c;
+ 	}
+ out:
+ 	*p = '\0';
+ 	return(store);
+ }
+ 
+ void
+ showstr(s)
+ reg	char	*s;
+ {
+ 	reg	char	c;
+ 
+ 	while((c = *s++) != '\0') {
+ 		if(c >= 040 && c <= 0176)
+ 			putchar(c);
+ 		else {
+ 			putchar('\\');
+ 			switch (c) {
+ 			
+ 			case '\n':
+ 				putchar('n');
+ 				break;
+ 
+ 			case '\r':
+ 				putchar('r');
+ 				break;
+ 
+ 			case '\b':
+ 				putchar('b');
+ 				break;
+ 
+ 			case '\t':
+ 				putchar('t');
+ 				break;
+ 
+ 			case '\f':
+ 				putchar('f');
+ 				break;
+ 
+ 			case '\v':
+ 				putchar('v');
+ 				break;
+ 
+ 			default:
+ 				printf("%.3o", c & 0377);
+ 				break;
+ 			}
+ 		}
+ 	}
+ 	putchar('\t');
+ }
+ 
  ckmtab()
  {
  
***************
*** 502,508
  		mkmtab(0);
  		init = 1;
  	}
! 	for(ep = mtab; ep->e_off != -1L; ep++) {
  		if(lev1) {
  			if(ep->e_level != 1)
  				break;

--- 672,678 -----
  		mkmtab(0);
  		init = 1;
  	}
! 	for(ep = mtab; ep < mend; ep++) {
  		if(lev1) {
  			if(ep->e_level != 1)
  				break;
***************
*** 534,539
  			val.l = (*(long *) p);
  			break;
  		}
  		switch(ep->e_opcode & ~SUB) {
  		case EQ:
  #ifdef u3b

--- 704,711 -----
  			val.l = (*(long *) p);
  			break;
  		}
+ 		if(ep->e_mask)
+ 			val.l &= ep->e_mask;
  		switch(ep->e_opcode & ~SUB) {
  		case EQ:
  #ifdef u3b