Logo Search packages:      
Sourcecode: util-linux version File versions  Download package

display.c

/*
 * Copyright (c) 1989 The Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    This product includes software developed by the University of
 *    California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <sys/param.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "hexdump.h"

static void doskip(const char *, int);
static u_char *get(void);

#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif

enum _vflag vflag = FIRST;

static off_t address;               /* address/offset in stream */
static off_t eaddress;              /* end address */

static inline void
print(PR *pr, u_char *bp) {

      switch(pr->flags) {
      case F_ADDRESS:
            (void)printf(pr->fmt, (quad_t)address);
            break;
      case F_BPAD:
            (void)printf(pr->fmt, "");
            break;
      case F_C:
            conv_c(pr, bp);
            break;
      case F_CHAR:
            (void)printf(pr->fmt, *bp);
            break;
      case F_DBL:
          {
            double dval;
            float fval;
            switch(pr->bcnt) {
            case 4:
                  memmove(&fval, bp, sizeof(fval));
                  (void)printf(pr->fmt, fval);
                  break;
            case 8:
                  memmove(&dval, bp, sizeof(dval));
                  (void)printf(pr->fmt, dval);
                  break;
            }
            break;
          }
      case F_INT:
          {
            short sval; /* int16_t */
            int ival;   /* int32_t */
            long long Lval;   /* int64_t, quad_t */

            switch(pr->bcnt) {
            case 1:
                  (void)printf(pr->fmt, (quad_t)*bp);
                  break;
            case 2:
                  memmove(&sval, bp, sizeof(sval));
                  (void)printf(pr->fmt, (quad_t)sval);
                  break;
            case 4:
                  memmove(&ival, bp, sizeof(ival));
                  (void)printf(pr->fmt, (quad_t)ival);
                  break;
            case 8:
                  memmove(&Lval, bp, sizeof(Lval));
                  (void)printf(pr->fmt, (quad_t)Lval);
                  break;
            }
            break;
          }
      case F_P:
            (void)printf(pr->fmt, isprint(*bp) ? *bp : '.');
            break;
      case F_STR:
            (void)printf(pr->fmt, (char *)bp);
            break;
      case F_TEXT:
            (void)printf("%s", pr->fmt);
            break;
      case F_U:
            conv_u(pr, bp);
            break;
      case F_UINT:
          {
            unsigned short sval;    /* u_int16_t */
            unsigned int ival;      /* u_int32_t */
            unsigned long long Lval;/* u_int64_t, u_quad_t */

            switch(pr->bcnt) {
            case 1:
                  (void)printf(pr->fmt, (u_quad_t)*bp);
                  break;
            case 2:
                  memmove(&sval, bp, sizeof(sval));
                  (void)printf(pr->fmt, (u_quad_t)sval);
                  break;
            case 4:
                  memmove(&ival, bp, sizeof(ival));
                  (void)printf(pr->fmt, (u_quad_t)ival);
                  break;
            case 8:
                  memmove(&Lval, bp, sizeof(Lval));
                  (void)printf(pr->fmt, (u_quad_t)Lval);
                  break;
            }
            break;
          }
      }
}

static void bpad(PR *pr)
{
      static const char *spec = " -0+#";
      char *p1, *p2;

      /*
       * remove all conversion flags; '-' is the only one valid
       * with %s, and it's not useful here.
       */
      pr->flags = F_BPAD;
      pr->cchar[0] = 's';
      pr->cchar[1] = 0;
      for (p1 = pr->fmt; *p1 != '%'; ++p1);
      for (p2 = ++p1; *p1 && index(spec, *p1); ++p1);
      while ((*p2++ = *p1++) != 0) ;
}

void display(void)
{
      register FS *fs;
      register FU *fu;
      register PR *pr;
      register int cnt;
      register u_char *bp;
      off_t saveaddress;
      u_char savech = 0, *savebp;

      while ((bp = get()) != NULL)
          for (fs = fshead, savebp = bp, saveaddress = address; fs;
            fs = fs->nextfs, bp = savebp, address = saveaddress)
                for (fu = fs->nextfu; fu; fu = fu->nextfu) {
                  if (fu->flags&F_IGNORE)
                        break;
                  for (cnt = fu->reps; cnt; --cnt)
                      for (pr = fu->nextpr; pr; address += pr->bcnt,
                        bp += pr->bcnt, pr = pr->nextpr) {
                            if (eaddress && address >= eaddress &&
                              !(pr->flags&(F_TEXT|F_BPAD)))
                                  bpad(pr);
                            if (cnt == 1 && pr->nospace) {
                              savech = *pr->nospace;
                              *pr->nospace = '\0';
                            }
                            print(pr, bp);
                            if (cnt == 1 && pr->nospace)
                              *pr->nospace = savech;
                      }
                }
      if (endfu) {
            /*
             * if eaddress not set, error or file size was multiple of
             * blocksize, and no partial block ever found.
             */
            if (!eaddress) {
                  if (!address)
                        return;
                  eaddress = address;
            }
            for (pr = endfu->nextpr; pr; pr = pr->nextpr)
                  switch(pr->flags) {
                  case F_ADDRESS:
                        (void)printf(pr->fmt, (quad_t)eaddress);
                        break;
                  case F_TEXT:
                        (void)printf("%s", pr->fmt);
                        break;
                  }
      }
}

static char **_argv;

static u_char *
get(void)
{
      static int ateof = 1;
      static u_char *curp, *savp;
      int n;
      int need, nread;
      u_char *tmpp;

      if (!curp) {
            curp = emalloc(blocksize);
            savp = emalloc(blocksize);
      } else {
            tmpp = curp;
            curp = savp;
            savp = tmpp;
            address += blocksize;
      }
      for (need = blocksize, nread = 0;;) {
            /*
             * if read the right number of bytes, or at EOF for one file,
             * and no other files are available, zero-pad the rest of the
             * block and set the end flag.
             */
            if (!length || (ateof && !next(NULL))) {
                  if (need == blocksize)
                        return(NULL);
                  if (!need && vflag != ALL &&
                      !memcmp(curp, savp, nread)) {
                        if (vflag != DUP)
                              (void)printf("*\n");
                        return(NULL);
                  }
                  memset((char *)curp + nread, 0, need);
                  eaddress = address + nread;
                  return(curp);
            }
            n = fread((char *)curp + nread, sizeof(u_char),
                length == -1 ? need : MIN(length, need), stdin);
            if (!n) {
                  if (ferror(stdin))
                        (void)fprintf(stderr, "hexdump: %s: %s\n",
                            _argv[-1], strerror(errno));
                  ateof = 1;
                  continue;
            }
            ateof = 0;
            if (length != -1)
                  length -= n;
            if (!(need -= n)) {
                  if (vflag == ALL || vflag == FIRST ||
                      memcmp(curp, savp, blocksize)) {
                        if (vflag == DUP || vflag == FIRST)
                              vflag = WAIT;
                        return(curp);
                  }
                  if (vflag == WAIT)
                        (void)printf("*\n");
                  vflag = DUP;
                  address += blocksize;
                  need = blocksize;
                  nread = 0;
            }
            else
                  nread += n;
      }
}

int next(char **argv)
{
      static int done;
      int statok;

      if (argv) {
            _argv = argv;
            return(1);
      }
      for (;;) {
            if (*_argv) {
                  if (!(freopen(*_argv, "r", stdin))) {
                        (void)fprintf(stderr, "hexdump: %s: %s\n",
                            *_argv, strerror(errno));
                        exitval = 1;
                        ++_argv;
                        continue;
                  }
                  statok = done = 1;
            } else {
                  if (done++)
                        return(0);
                  statok = 0;
            }
            if (skip)
                  doskip(statok ? *_argv : "stdin", statok);
            if (*_argv)
                  ++_argv;
            if (!skip)
                  return(1);
      }
      /* NOTREACHED */
}

static void
doskip(const char *fname, int statok)
{
      struct stat sbuf;

      if (statok) {
            if (fstat(fileno(stdin), &sbuf)) {
                  (void)fprintf(stderr, "hexdump: %s: %s.\n",
                      fname, strerror(errno));
                  exit(1);
            }
            if (S_ISREG(sbuf.st_mode) && skip >= sbuf.st_size) {
              /* If size valid and skip >= size */
                  skip -= sbuf.st_size;
                  address += sbuf.st_size;
                  return;
            }
      }
      /* sbuf may be undefined here - do not test it */
      if (fseek(stdin, skip, SEEK_SET)) {
            (void)fprintf(stderr, "hexdump: %s: %s.\n",
                fname, strerror(errno));
            exit(1);
      }
      address += skip;
      skip = 0;
}

void *
emalloc(int sz) {
      void *p;

      if (!(p = malloc((u_int)sz)))
            nomem();
      memset(p, 0, sz);
      return(p);
}

void nomem() {
      (void)fprintf(stderr, "hexdump: %s.\n", strerror(errno));
      exit(1);
}

Generated by  Doxygen 1.6.0   Back to index