[comp.sources.bugs] Mask operations for PD file

cudcv@warwick.ac.uk (Rob McMahon) (09/02/89)

Ian Darwin's PD file command which came over the net supported a very limited
form of the `&' operator, which apparenty Sun added to the file command.  The
file as distributed allowed:

	>2	byte	&0200

but there was no way to do

	>2	byte&0177	=2

Here are some diffs to give it the full functionality.  Also one small fix for
ANSI pre-processors which demand matching quotes even within comments, one not
to print a space if the description string from the magic file is empty
(useful when everything is going to be printed by continuation lines), and a
bug fix for strtol which meant that the pointer was incremented one to many
characters.

After the diffs are my modified versions of magdir/{sun,compress}.  Note,
though, that I have to do

	>0	byte&0200	0200	...
rather than
	>0	byte&0200	>0	...

is it right that these comparisons should be signed ?  When I think of a byte
I think 0--255, not -128--127 ...

Anyway, do with these patches what you will.  Any improvements gratefully
received.  Have fun.

===================================================================
RCS file: apprentice.c,v
retrieving revision 1.1
diff -c -r1.1 apprentice.c
*** /tmp/,RCSt1026546	Fri Sep  1 21:50:12 1989
--- apprentice.c	Fri Sep  1 21:29:41 1989
***************
*** 67,73 ****
  
  	/* parse it */
  	if (check)	/* print silly verbose header for USG compat. */
! 		(void) printf("cont\toffset\ttype\topcode\tvalue\tdesc\n");
  
  	while (fgets(line, MAXSTR, f) != NULL) {
  		if (line[0]=='#')	/* comment, do not parse */
--- 67,73 ----
  
  	/* parse it */
  	if (check)	/* print silly verbose header for USG compat. */
! 		(void) printf("cont\toffset\ttype\topcode\tmask\tvalue\tdesc\n");
  
  	while (fgets(line, MAXSTR, f) != NULL) {
  		if (line[0]=='#')	/* comment, do not parse */
***************
*** 92,98 ****
  int *ndx, check;
  {
  	int i = 0, nd = *ndx;
- 	int slen;
  	static int warned = 0;
  	struct magic *m;
  	extern int errno;
--- 92,97 ----
***************
*** 152,161 ****
--- 151,205 ----
  		m->reln = '=';
  	EATAB;
  
+ 	if (getvalue(m, &l))
+ 		return -1;
  /*
   * TODO finish this macro and start using it!
   * #define offsetcheck {if (offset > HOWMANY-1) warning("offset too big"); }
   */
+ 	/* 
+ 	 * if the relation was ``&'',
+ 	 * change it to a MASK op relation.
+ 	 */
+ 	EATAB;
+ 	if (m->reln == '&') {
+ 		if (*l == '>' || *l == '<' || *l == '=') {
+ 			m->reln = *l | MASK;
+ 			++l;
+ 		} else
+ 			m->reln = '=' | MASK;
+ 		m->mask = m->value.l;
+ 		EATAB;
+ 		if (getvalue(m, &l))
+ 			return -1;
+ 	}
+ 
+ 	/*
+ 	 * now get last part - the description
+ 	 */
+ 	EATAB;
+ 	while ((m->desc[i++] = *l++) != '\0' && i<MAXDESC)
+ 		/* NULLBODY */;
+ 
+ 	if (check) {
+ 		mdump(m);
+ 	}
+ 	++(*ndx);		/* make room for next */
+ 	return 0;
+ }
+ 
+ /* 
+  * Read a numeric value from a pointer, into the value union of a magic 
+  * pointer, according to the magic type.  Update the string pointer to point 
+  * just after the number read.  Return 0 for success, non-zero for failure.
+  */
+ int
+ getvalue(m, p)
+ 	struct magic *m;
+ 	char **p;
+ {
+ 	int slen;
+ 
  	switch(m->type) {
  	/*
  	 * Do not remove the casts below.  They are vital.
***************
*** 163,178 ****
  	 * have happened.
  	 */
  	case BYTE:
! 		m->value.l = (char) strtol(l,&l,0);
  		break;
  	case SHORT:
! 		m->value.l = (short) strtol(l,&l,0);
  		break;
  	case LONG:
! 		m->value.l = (long) strtol(l,&l,0);
  		break;
  	case STRING:
! 		l = getstr(l, m->value.s, sizeof(m->value.s), &slen);
  		m->vallen = slen;
  		break;
  	default:
--- 207,222 ----
  	 * have happened.
  	 */
  	case BYTE:
! 		m->value.l = (char) strtol(*p,p,0);
  		break;
  	case SHORT:
! 		m->value.l = (short) strtol(*p,p,0);
  		break;
  	case LONG:
! 		m->value.l = (long) strtol(*p,p,0);
  		break;
  	case STRING:
! 		*p = getstr(*p, m->value.s, sizeof(m->value.s), &slen);
  		m->vallen = slen;
  		break;
  	default:
***************
*** 179,196 ****
  		warning("can't happen: m->type=%d\n", m->type);
  		return -1;
  	}
- 
- 	/*
- 	 * now get last part - the description
- 	 */
- 	EATAB;
- 	while ((m->desc[i++] = *l++) != '\0' && i<MAXDESC)
- 		/* NULLBODY */;
- 
- 	if (check) {
- 		mdump(m);
- 	}
- 	++(*ndx);		/* make room for next */
  	return 0;
  }
  
--- 223,228 ----
===================================================================
RCS file: file.1,v
retrieving revision 1.1
diff -c -r1.1 file.1
*** /tmp/,RCSt1026546	Fri Sep  1 21:50:16 1989
--- file.1	Fri Sep  1 21:49:56 1989
***************
*** 149,165 ****
  The Sun Microsystems implementation of System V compatibility
  includes a file(1) command that has some extentions.
  My version differs from Sun's only in minor ways.
! The significant one is the `&' operator, which Sun's program expects as,
  for example,
  ..br
  >16	long&0x7fffffff	>0		not stripped
- ..br
- would be entered in my version as
- ..br
- >16	long	&0x7fffffff	not stripped
- ..br
- which is a little less general; it simply tests (location 16)&0x7ffffff
- and returns its truth value as a C expression.
  ..SH MAGIC DIRECTORY
  The magic file entries have been collected from various sources,
  mainly USENET, and contributed by various authors.
--- 149,158 ----
  The Sun Microsystems implementation of System V compatibility
  includes a file(1) command that has some extentions.
  My version differs from Sun's only in minor ways.
! It includes the extension of the `&' operator, used as,
  for example,
  ..br
  >16	long&0x7fffffff	>0		not stripped
  ..SH MAGIC DIRECTORY
  The magic file entries have been collected from various sources,
  mainly USENET, and contributed by various authors.
***************
*** 199,204 ****
--- 192,200 ----
  Written by Ian F. Darwin, UUCP address {utzoo | ihnp4}!darwin!ian,
  Internet address ian@sq.com,
  postal address: P.O. Box 603, Station F, Toronto, Ontario, CANADA M4Y 2L8.
+ ..PP
+ Altered by Rob McMahon, cudcv@warwick.ac.uk, 1989, to extend the `&' operator
+ from simple `x&y != 0' to `x&y op z'.
  ..PP
  ..I Strtok.c
  and
===================================================================
RCS file: file.h,v
retrieving revision 1.1
diff -c -r1.1 file.h
*** /tmp/,RCSt1026546	Fri Sep  1 21:50:23 1989
--- file.h	Fri Sep  1 21:29:44 1989
***************
*** 35,41 ****
  struct magic {
  	short contflag;		/* 1 if '>0' appears */
  	long offset;		/* offset to magic number */
! 	char reln;		/* relation (0=eq, '>'=gt, etc) */
  	char type;		/* int, short, long or string. */
  	char vallen;		/* length of string value, if any */
  #define 			BYTE	1
--- 35,42 ----
  struct magic {
  	short contflag;		/* 1 if '>0' appears */
  	long offset;		/* offset to magic number */
! #define	MASK	0200		/* this is a masked op, like & v1 = v2 */
! 	unsigned char reln;	/* relation (0=eq, '>'=gt, etc) */
  	char type;		/* int, short, long or string. */
  	char vallen;		/* length of string value, if any */
  #define 			BYTE	1
***************
*** 48,53 ****
--- 49,55 ----
  		long l;
  		char s[MAXstring];
  	} value;		/* either number or string */
+ 	long mask;		/* mask before comparison with value */
  	char desc[MAXDESC];	/* description */
  };
  
===================================================================
RCS file: fsmagic.c,v
retrieving revision 1.1
diff -c -r1.1 fsmagic.c
*** /tmp/,RCSt1026546	Fri Sep  1 21:50:29 1989
--- fsmagic.c	Fri Sep  1 21:29:47 1989
***************
*** 35,41 ****
  		/* On most systems cpp will discard it automatically */
  		Congratulations, you have found a portability bug.
  		Please grep /usr/include/sys and edit the above #include 
! 		to point at the file that defines the `major' macro.
  #endif	/*major*/
  #include <sys/stat.h>
  #include "file.h"
--- 35,41 ----
  		/* On most systems cpp will discard it automatically */
  		Congratulations, you have found a portability bug.
  		Please grep /usr/include/sys and edit the above #include 
! 		to point at the file that defines the ``major'' macro.
  #endif	/*major*/
  #include <sys/stat.h>
  #include "file.h"
===================================================================
RCS file: magic.4,v
retrieving revision 1.1
diff -c -r1.1 magic.4
*** /tmp/,RCSt1026546	Fri Sep  1 21:50:33 1989
--- magic.4	Fri Sep  1 21:50:00 1989
***************
*** 35,40 ****
--- 35,45 ----
  ..IP string
  A string of bytes.
  ..RE
+ The numeric types may optionally be followed by
+ ..B &
+ and a numeric value,
+ to specify that the value is to be AND'ed with the
+ numeric value before any comparisons are done.
  ..IP test
  The value to be compared with the value from the file.  If the type is
  numeric, this value
***************
*** 49,61 ****
  ..BR < ,
  to specify that the value from the file must be less than the specified
  value,
  ..BR > ,
  to specify that the value from the file must be greater than the specified
! value,
  or
- ..BR & ,
- to specify that the value is to be AND'ed with the
- numeric value before any comparisons are done.
  Numeric values are specified in C form; e.g.
  ..B 13
  is decimal,
--- 54,64 ----
  ..BR < ,
  to specify that the value from the file must be less than the specified
  value,
+ or
  ..BR > ,
  to specify that the value from the file must be greater than the specified
! value.
  or
  Numeric values are specified in C form; e.g.
  ..B 13
  is decimal,
===================================================================
RCS file: print.c,v
retrieving revision 1.1
diff -c -r1.1 print.c
*** /tmp/,RCSt1026546	Fri Sep  1 21:50:36 1989
--- print.c	Fri Sep  1 21:29:49 1989
***************
*** 44,55 ****
  mdump(m)
  struct magic *m;
  {
! 	(void) printf("%d\t%d\t%d\t%c\t",
  		m->contflag,
  		m->offset,
  		m->type,
! 		m->reln,
  		0);
  	if (m->type == STRING)
  		showstr(m->value.s);
  	else
--- 44,59 ----
  mdump(m)
  struct magic *m;
  {
! 	(void) printf("%d\t%d\t%d\t%s%c\t",
  		m->contflag,
  		m->offset,
  		m->type,
! 		m->reln & MASK ? "&" : "",
! 		m->reln & ~MASK,
  		0);
+ 	if (m->reln & MASK)
+ 		(void) printf("%d",m->mask);
+ 	(void) putchar('\t');
  	if (m->type == STRING)
  		showstr(m->value.s);
  	else
===================================================================
RCS file: softmagic.c,v
retrieving revision 1.1
diff -c -r1.1 softmagic.c
*** /tmp/,RCSt1026546	Fri Sep  1 21:50:41 1989
--- softmagic.c	Fri Sep  1 21:29:52 1989
***************
*** 71,77 ****
  				magindex < nmagic) {
  				++magindex;
  				if (mcheck(s, &magic[magindex])){
! 					(void) putchar(' ');
  					mprint(&magic[magindex],s);
  				}
  			}
--- 71,79 ----
  				magindex < nmagic) {
  				++magindex;
  				if (mcheck(s, &magic[magindex])){
! 					/* no space if nothing printed */
! 					if (magic[magindex-1].desc[0])
! 						(void) putchar(' ');
  					mprint(&magic[magindex],s);
  				}
  			}
***************
*** 98,110 ****
  
  	switch (m->type) {
  	case BYTE:
! 		(void) printf(m->desc, p->b);
  		break;
  	case SHORT:
! 		(void) printf(m->desc, p->h);
  		break;
  	case LONG:
! 		(void) printf(m->desc, p->l);
  		break;
  	case STRING:
  		if ((pp=strchr(p->s, '\n')) != NULL)
--- 100,115 ----
  
  	switch (m->type) {
  	case BYTE:
! 		(void) printf(m->desc,
! 			      (m->reln & MASK) ? p->b & m->mask : p->b);
  		break;
  	case SHORT:
! 		(void) printf(m->desc,
! 			      (m->reln & MASK) ? p->h & m->mask : p->h);
  		break;
  	case LONG:
! 		(void) printf(m->desc,
! 			      (m->reln & MASK) ? p->l & m->mask : p->l);
  		break;
  	case STRING:
  		if ((pp=strchr(p->s, '\n')) != NULL)
***************
*** 123,128 ****
--- 128,134 ----
  {
  	register union VALUETYPE *p = (union VALUETYPE *)(s+m->offset);
  	register long l = m->value.l;
+ 	register long mask = m->mask;
  	register long v;
  
  	if (debug) {
***************
*** 167,172 ****
--- 173,184 ----
  		return v < l;
  	case '&':
  		return v & l;
+ 	case MASK | '=':
+ 		return (v & mask) == l;
+ 	case MASK | '>':
+ 		return (v & mask) > l;
+ 	case MASK | '<':
+ 		return (v & mask) < l;
  	default:
  		warning("mcheck: can't happen: invalid relation %d", m->reln);
  		return 0;
===================================================================
RCS file: strtol.c,v
retrieving revision 1.1
diff -c -r1.1 strtol.c
*** /tmp/,RCSt1026546	Fri Sep  1 21:50:44 1989
--- strtol.c	Fri Sep  1 21:29:54 1989
***************
*** 89,95 ****
  			valid = 0;
  			break;
  		}
! 		++s;
  	}
  
  	/*
--- 89,96 ----
  			valid = 0;
  			break;
  		}
! 		if (valid)
! 		    ++s;
  	}
  
  	/*

------------------------------------------------------------------------------
# Values for Sun binaries
0	long&0x7cfffff0	0x30100		sparc
>2	short		0407		
>2	short		0410		pure
>2	short		0413		demand paged
>0	byte&0200	0200		dynamically linked
>16	long		>0		executable not stripped
>16	long		=0		executable stripped
0	long&0x7cfffff0	0x20100		mc68020
>2	short		0407		
>2	short		0410		pure
>2	short		0413		demand paged
>0	byte&0200	0200		dynamically linked
>16	long		>0		executable not stripped
>16	long		=0		executable stripped
0	long&0x7cfffff0	0x10100		mc68010
>2	short		0407		
>2	short		0410		pure
>2	short		0413		demand paged
>0	byte&0200	0200		dynamically linked
>16	long		>0		executable not stripped
>16	long		=0		executable stripped
0	long&0x7cfffff0	0x100		
#>2	short		0407		
>2	short		0410		pure
>2	short		0413		demand paged
>0	byte&0200	0200		dynamically linked
>16	long		>0		executable not stripped
>16	long		=0		executable stripped
0	long		0x080456	core file
>128	string		>0		from '%s'
#
0	short		05401		byte-swapped demand paged executable
0	short		010001		byte-swapped demand paged executable
------------------------------------------------------------------------------
0	short		017037		packed data
# CPL 	- added pack to /etc/magic
0	short		017436		packed data
0	short		0145405		huf output

0	string		\037\235	compressed data
>2	byte&0200	0200		block compressed
# non block compressed
>2	byte&0177	>0		- with %d bits
------------------------------------------------------------------------------

Rob-- 
UUCP:   ...!mcvax!ukc!warwick!cudcv	PHONE:  +44 203 523037
JANET:  cudcv@uk.ac.warwick             ARPA:   cudcv@warwick.ac.uk
Rob McMahon, Computing Services, Warwick University, Coventry CV4 7AL, England