(root)/
util-linux-2.39/
text-utils/
hexdump-display.c
       1  /*
       2   * Copyright (c) 1989 The Regents of the University of California.
       3   * All rights reserved.
       4   *
       5   * Redistribution and use in source and binary forms, with or without
       6   * modification, are permitted provided that the following conditions
       7   * are met:
       8   * 1. Redistributions of source code must retain the above copyright
       9   *    notice, this list of conditions and the following disclaimer.
      10   * 2. Redistributions in binary form must reproduce the above copyright
      11   *    notice, this list of conditions and the following disclaimer in the
      12   *    documentation and/or other materials provided with the distribution.
      13   * 3. All advertising materials mentioning features or use of this software
      14   *    must display the following acknowledgement:
      15   *	This product includes software developed by the University of
      16   *	California, Berkeley and its contributors.
      17   * 4. Neither the name of the University nor the names of its contributors
      18   *    may be used to endorse or promote products derived from this software
      19   *    without specific prior written permission.
      20   *
      21   * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
      22   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      23   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      24   * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
      25   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      26   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      27   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      28   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      29   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      30   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      31   * SUCH DAMAGE.
      32   */
      33  
      34  #include <sys/param.h>
      35  #include <sys/stat.h>
      36  #include <sys/types.h>
      37  #include <unistd.h>
      38  #include <errno.h>
      39  #include <ctype.h>
      40  #include <stdio.h>
      41  #include <stdlib.h>
      42  #include <string.h>
      43  #include "hexdump.h"
      44  #include "xalloc.h"
      45  #include "c.h"
      46  #include "nls.h"
      47  #include "colors.h"
      48  
      49  static void doskip(const char *, int, struct hexdump *);
      50  static u_char *get(struct hexdump *);
      51  
      52  enum _vflag vflag = FIRST;
      53  
      54  static off_t address;			/* address/offset in stream */
      55  static off_t eaddress;			/* end address */
      56  
      57  static const char *color_cond(struct hexdump_pr *pr, unsigned char *bp, int bcnt)
      58  {
      59  	register struct list_head *p;
      60  	register struct hexdump_clr *clr;
      61  	off_t offt;
      62  	int match;
      63  
      64  	list_for_each(p, pr->colorlist) {
      65  		clr = list_entry(p, struct hexdump_clr, colorlist);
      66  		offt = clr->offt;
      67  		match = 0;
      68  
      69  		/* no offset or offset outside this print unit */
      70  		if (offt < 0)
      71  			offt = address;
      72  		if (offt < address || offt + clr->range > address + bcnt)
      73  			continue;
      74  
      75  		/* match a string */
      76  		if (clr->str) {
      77  			if (pr->flags == F_ADDRESS) {
      78  				/* TODO */
      79  			}
      80  			else if (!strncmp(clr->str, (char *)bp + offt
      81  				- address, clr->range))
      82  				match = 1;
      83  		/* match a value */
      84  		} else if (clr->val != -1) {
      85  			int val = 0;
      86  			/* addresses are not part of the input, so we can't
      87  			 * compare with the contents of bp */
      88  			if (pr->flags == F_ADDRESS) {
      89  				if (clr->val == address)
      90  					match = 1;
      91  			} else {
      92  				memcpy(&val, bp + offt - address, clr->range);
      93  				if (val == clr->val)
      94  					match = 1;
      95  			}
      96  		/* no conditions, only a color was specified */
      97  		} else
      98  			return clr->fmt;
      99  
     100  		/* return the format string or check for another */
     101  		if (match ^ clr->invert)
     102  			return clr->fmt;
     103  	}
     104  
     105  	/* no match */
     106  	return NULL;
     107  }
     108  
     109  static inline void
     110  print(struct hexdump_pr *pr, unsigned char *bp) {
     111  
     112  	const char *color = NULL;
     113  
     114  	if (pr->colorlist && (color = color_cond(pr, bp, pr->bcnt)))
     115  		color_enable(color);
     116  
     117  	switch(pr->flags) {
     118  	case F_ADDRESS:
     119  		printf(pr->fmt, address);
     120  		break;
     121  	case F_BPAD:
     122  		printf(pr->fmt, "");
     123  		break;
     124  	case F_C:
     125  		conv_c(pr, bp);
     126  		break;
     127  	case F_CHAR:
     128  		printf(pr->fmt, *bp);
     129  		break;
     130  	case F_DBL:
     131  	    {
     132  		double dval;
     133  		float fval;
     134  		switch(pr->bcnt) {
     135  		case 4:
     136  			memmove(&fval, bp, sizeof(fval));
     137  			printf(pr->fmt, fval);
     138  			break;
     139  		case 8:
     140  			memmove(&dval, bp, sizeof(dval));
     141  			printf(pr->fmt, dval);
     142  			break;
     143  		}
     144  		break;
     145  	    }
     146  	case F_INT:
     147  	    {
     148  		char cval;	/* int8_t */
     149  		short sval;	/* int16_t */
     150  		int ival;	/* int32_t */
     151  		long long Lval;	/* int64_t, int64_t */
     152  
     153  		switch(pr->bcnt) {
     154  		case 1:
     155  			memmove(&cval, bp, sizeof(cval));
     156  			printf(pr->fmt, (unsigned long long) cval);
     157  			break;
     158  		case 2:
     159  			memmove(&sval, bp, sizeof(sval));
     160  			printf(pr->fmt, (unsigned long long) sval);
     161  			break;
     162  		case 4:
     163  			memmove(&ival, bp, sizeof(ival));
     164  			printf(pr->fmt, (unsigned long long) ival);
     165  			break;
     166  		case 8:
     167  			memmove(&Lval, bp, sizeof(Lval));
     168  			printf(pr->fmt, Lval);
     169  			break;
     170  		}
     171  		break;
     172  	    }
     173  	case F_P:
     174  		printf(pr->fmt, isprint(*bp) ? *bp : '.');
     175  		break;
     176  	case F_STR:
     177  		printf(pr->fmt, (char *)bp);
     178  		break;
     179  	case F_TEXT:
     180  		printf("%s", pr->fmt);
     181  		break;
     182  	case F_U:
     183  		conv_u(pr, bp);
     184  		break;
     185  	case F_UINT:
     186  	    {
     187  		unsigned short sval;	/* u_int16_t */
     188  		unsigned int ival;	/* u_int32_t */
     189  		unsigned long long Lval;/* u_int64_t, u_int64_t */
     190  
     191  		switch(pr->bcnt) {
     192  		case 1:
     193  			printf(pr->fmt, (unsigned long long) *bp);
     194  			break;
     195  		case 2:
     196  			memmove(&sval, bp, sizeof(sval));
     197  			printf(pr->fmt, (unsigned long long) sval);
     198  			break;
     199  		case 4:
     200  			memmove(&ival, bp, sizeof(ival));
     201  			printf(pr->fmt, (unsigned long long) ival);
     202  			break;
     203  		case 8:
     204  			memmove(&Lval, bp, sizeof(Lval));
     205  			printf(pr->fmt, Lval);
     206  			break;
     207  		}
     208  		break;
     209  	    }
     210  	}
     211  	if (color) /* did we colorize something? */
     212  		color_disable();
     213  }
     214  
     215  static void bpad(struct hexdump_pr *pr)
     216  {
     217  	static const char *spec = " -0+#";
     218  	char *p1, *p2;
     219  
     220  	/*
     221  	 * remove all conversion flags; '-' is the only one valid
     222  	 * with %s, and it's not useful here.
     223  	 */
     224  	pr->flags = F_BPAD;
     225  	pr->cchar[0] = 's';
     226  	pr->cchar[1] = 0;
     227  
     228  	p1 = pr->fmt;
     229  	while (*p1 != '%')
     230  		++p1;
     231  
     232  	p2 = ++p1;
     233  	while (*p1 && strchr(spec, *p1))
     234  		++p1;
     235  
     236  	while ((*p2++ = *p1++))
     237  		;
     238  }
     239  
     240  void display(struct hexdump *hex)
     241  {
     242  	register struct list_head *fs;
     243  	register struct hexdump_fs *fss;
     244  	register struct hexdump_fu *fu;
     245  	register struct hexdump_pr *pr;
     246  	register int cnt;
     247  	register unsigned char *bp;
     248  	off_t saveaddress;
     249  	unsigned char savech = 0, *savebp;
     250  	struct list_head *p, *q, *r;
     251  
     252  	while ((bp = get(hex)) != NULL) {
     253  		fs = &hex->fshead; savebp = bp; saveaddress = address;
     254  
     255  		list_for_each(p, fs) {
     256  			fss = list_entry(p, struct hexdump_fs, fslist);
     257  
     258  			list_for_each(q, &fss->fulist) {
     259  				fu = list_entry(q, struct hexdump_fu, fulist);
     260  
     261  				if (fu->flags&F_IGNORE)
     262  					break;
     263  
     264  				cnt = fu->reps;
     265  
     266  				while (cnt) {
     267  					list_for_each(r, &fu->prlist) {
     268  						pr = list_entry(r, struct hexdump_pr, prlist);
     269  
     270  						if (eaddress && address >= eaddress
     271  						    && !(pr->flags&(F_TEXT|F_BPAD)))
     272  							bpad(pr);
     273  
     274  						if (cnt == 1 && pr->nospace) {
     275  							savech = *pr->nospace;
     276  							*pr->nospace = '\0';
     277  							print(pr, bp);
     278  							*pr->nospace = savech;
     279  						} else
     280  							print(pr, bp);
     281  
     282  						address += pr->bcnt;
     283  						bp += pr->bcnt;
     284  					}
     285  					--cnt;
     286  				}
     287  			}
     288  			bp = savebp;
     289  			address = saveaddress;
     290  		}
     291  	}
     292  	if (endfu) {
     293  		/*
     294  		 * if eaddress not set, error or file size was multiple of
     295  		 * blocksize, and no partial block ever found.
     296  		 */
     297  		if (!eaddress) {
     298  			if (!address)
     299  				return;
     300  			eaddress = address;
     301  		}
     302  		list_for_each (p, &endfu->prlist) {
     303  			const char *color = NULL;
     304  
     305  			pr = list_entry(p, struct hexdump_pr, prlist);
     306  			if (colors_wanted() && pr->colorlist
     307  			    && (color = color_cond(pr, bp, pr->bcnt))) {
     308  				color_enable(color);
     309  			}
     310  
     311  			switch(pr->flags) {
     312  			case F_ADDRESS:
     313  				printf(pr->fmt, eaddress);
     314  				break;
     315  			case F_TEXT:
     316  				printf("%s", pr->fmt);
     317  				break;
     318  			}
     319  			if (color) /* did we highlight something? */
     320  				color_disable();
     321  		}
     322  	}
     323  }
     324  
     325  static char **_argv;
     326  
     327  static u_char *
     328  get(struct hexdump *hex)
     329  {
     330  	static int ateof = 1;
     331  	static u_char *curp, *savp;
     332  	ssize_t n, need, nread;
     333  	u_char *tmpp;
     334  
     335  	if (!curp) {
     336  		curp = xcalloc(1, hex->blocksize);
     337  		savp = xcalloc(1, hex->blocksize);
     338  	} else {
     339  		tmpp = curp;
     340  		curp = savp;
     341  		savp = tmpp;
     342  		address += hex->blocksize;
     343  	}
     344  	need = hex->blocksize, nread = 0;
     345  	while (TRUE) {
     346  		/*
     347  		 * if read the right number of bytes, or at EOF for one file,
     348  		 * and no other files are available, zero-pad the rest of the
     349  		 * block and set the end flag.
     350  		 */
     351  		if (!hex->length || (ateof && !next(NULL, hex))) {
     352  			if (need == hex->blocksize)
     353  				goto retnul;
     354  			if (!need && vflag != ALL &&
     355  			    !memcmp(curp, savp, nread)) {
     356  				if (vflag != DUP)
     357  					printf("*\n");
     358  				goto retnul;
     359  			}
     360  			if (need > 0)
     361  				memset((char *)curp + nread, 0, need);
     362  			eaddress = address + nread;
     363  			return(curp);
     364  		}
     365  		if (fileno(stdin) == -1) {
     366  			warnx(_("all input file arguments failed"));
     367  			goto retnul;
     368  		}
     369  		n = fread((char *)curp + nread, sizeof(unsigned char),
     370  		    hex->length == -1 ? need : min(hex->length, need), stdin);
     371  		if (!n) {
     372  			if (ferror(stdin))
     373  				warn("%s", _argv[-1]);
     374  			ateof = 1;
     375  			continue;
     376  		}
     377  		ateof = 0;
     378  		if (hex->length != -1)
     379  			hex->length -= n;
     380  		if (!(need -= n)) {
     381  			if (vflag == ALL || vflag == FIRST ||
     382  			    memcmp(curp, savp, hex->blocksize) != 0) {
     383  				if (vflag == DUP || vflag == FIRST)
     384  					vflag = WAIT;
     385  				return(curp);
     386  			}
     387  			if (vflag == WAIT)
     388  				printf("*\n");
     389  			vflag = DUP;
     390  			address += hex->blocksize;
     391  			need = hex->blocksize;
     392  			nread = 0;
     393  		}
     394  		else
     395  			nread += n;
     396  	}
     397  retnul:
     398  	free (curp);
     399  	free (savp);
     400  	return NULL;
     401  }
     402  
     403  int next(char **argv, struct hexdump *hex)
     404  {
     405  	static int done;
     406  	int statok;
     407  
     408  	if (argv) {
     409  		_argv = argv;
     410  		return(1);
     411  	}
     412  	while (TRUE) {
     413  		if (*_argv) {
     414  			if (!(freopen(*_argv, "r", stdin))) {
     415  				warn("%s", *_argv);
     416  				hex->exitval = EXIT_FAILURE;
     417  				++_argv;
     418  				continue;
     419  			}
     420  			statok = done = 1;
     421  		} else {
     422  			if (done++)
     423  				return(0);
     424  			statok = 0;
     425  		}
     426  		if (hex->skip)
     427  			doskip(statok ? *_argv : "stdin", statok, hex);
     428  		if (*_argv)
     429  			++_argv;
     430  		if (!hex->skip)
     431  			return(1);
     432  	}
     433  	/* NOTREACHED */
     434  }
     435  
     436  static void
     437  doskip(const char *fname, int statok, struct hexdump *hex)
     438  {
     439  	struct stat sbuf;
     440  
     441  	if (statok) {
     442  		if (fstat(fileno(stdin), &sbuf))
     443  		        err(EXIT_FAILURE, "%s", fname);
     444  		if (S_ISREG(sbuf.st_mode) && hex->skip > sbuf.st_size) {
     445  		  /* If size valid and skip >= size */
     446  			hex->skip -= sbuf.st_size;
     447  			address += sbuf.st_size;
     448  			return;
     449  		}
     450  	}
     451  	/* sbuf may be undefined here - do not test it */
     452  	if (fseek(stdin, hex->skip, SEEK_SET))
     453  	        err(EXIT_FAILURE, "%s", fname);
     454  	address += hex->skip;
     455  	hex->skip = 0;
     456  }