1805 lines
37 KiB
C
Executable File
1805 lines
37 KiB
C
Executable File
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
|
|
/* All Rights Reserved */
|
|
|
|
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
|
|
/* The copyright notice above does not evidence any */
|
|
/* actual or intended publication of such source code. */
|
|
|
|
/* Portions Copyright(c) 1988, Sun Microsystems Inc. */
|
|
/* All Rights Reserved */
|
|
|
|
#ident "@(#)od.c 1.14 95/03/02 SMI" /* SVr4.0 1.11.1.4 */
|
|
/*
|
|
* od -- octal (also hex, decimal, and character) dump
|
|
*/
|
|
|
|
/*
|
|
* COPYRIGHT NOTICE
|
|
*
|
|
* This source code is designated as Restricted Confidential Information
|
|
* and is subject to special restrictions in a confidential disclosure
|
|
* agreement between HP, IBM, SUN, NOVELL and OSF. Do not distribute
|
|
* this source code outside your company without OSF's specific written
|
|
* approval. This source code, and all copies and derivative works
|
|
* thereof, must be returned or destroyed at request. You must retain
|
|
* this notice on any copies which you make.
|
|
*
|
|
* (c) Copyright 1990, 1991, 1992, 1993 OPEN SOFTWARE FOUNDATION, INC.
|
|
* ALL RIGHTS RESERVED
|
|
*/
|
|
/*
|
|
* OSF/1 1.2
|
|
*/
|
|
|
|
/*
|
|
* COMPONENT_NAME: (CMDSCAN) commands that scan files
|
|
*
|
|
* FUNCTIONS:
|
|
*
|
|
*
|
|
* (C) COPYRIGHT International Business Machines Corp. 1989, 1990
|
|
* All Rights Reserved
|
|
*
|
|
* US Government Users Restricted Rights - Use, duplication or
|
|
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
|
|
*
|
|
* Copyright (c) 1980 Regents of the University of California.
|
|
* All rights reserved. The Berkeley software License Agreement
|
|
* specifies the terms and conditions for redistribution.
|
|
*
|
|
* Copyright 1976, Bell Telephone Laboratories, Inc.
|
|
*
|
|
* 1.24 com/cmd/scan/od.c, cmdscan, bos320, 9143320 10/17/91 14:32:24
|
|
*
|
|
*/
|
|
|
|
#include <unistd.h>
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <limits.h>
|
|
#include <locale.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <wchar.h>
|
|
#include <wctype.h>
|
|
|
|
#define DBUF_SIZE BUFSIZ
|
|
#define BSIZE 512
|
|
#define KSIZE 1024
|
|
#define MSIZE 1048576
|
|
#define LBUFSIZE 16
|
|
#define NO 0
|
|
#define YES 1
|
|
#define UNSIGNED 0
|
|
#define SIGNED 1
|
|
#define PADDR 1
|
|
#define MAX_CONV 32 /* Limit on number of conversions */
|
|
|
|
static struct dfmt {
|
|
int df_field; /* external field required for object */
|
|
int df_size; /* size (bytes) of object */
|
|
int df_radix; /* conversion radix */
|
|
int df_signed; /* signed? flag */
|
|
int df_paddr; /* "put address on each line?" flag */
|
|
int (*df_put)(); /* function to output object */
|
|
char *df_fmt; /* output string format */
|
|
} *conv_vec[MAX_CONV]; /* vector of conversions to be done */
|
|
|
|
static void put_addr(long addrs, char chr);
|
|
static void line(int n);
|
|
static int s_put(unsigned short *n, struct dfmt *d);
|
|
static int us_put(unsigned short *n, struct dfmt *d);
|
|
static int l_put(unsigned long *n, struct dfmt *d);
|
|
static int sl_put(unsigned long *n, struct dfmt *d);
|
|
static int d_put(double *f, struct dfmt *d);
|
|
static int f_put(float *f, struct dfmt *d);
|
|
static int a_put(unsigned char *cc, struct dfmt *d);
|
|
static int b_put(unsigned char *b, struct dfmt *d);
|
|
static int sb_put(char *bc, struct dfmt *d);
|
|
static char *scvt(int c, struct dfmt *d);
|
|
static char *icvt(long value, int radix, int issigned, int ndigits);
|
|
static long get_addr(register char *s);
|
|
static long get_offset(register char *s);
|
|
static int offset(long a, long *bytes_read);
|
|
static void usage(char *progname);
|
|
static int mbswidth(const char *s, size_t n);
|
|
static int C_put(unsigned char *cc, struct dfmt *d);
|
|
#ifndef XPG4
|
|
static int c_put(unsigned char *cc, struct dfmt *d);
|
|
static void cput(int c);
|
|
#endif
|
|
static void odopen(int *argcnt, char **argvec, int *exitstat, int fd,
|
|
int max_bytes);
|
|
static void pre(int f, int n);
|
|
static void putn(unsigned long n, int b, int c);
|
|
static void last_addr();
|
|
|
|
/* -t a */
|
|
static struct dfmt ascii = {3, sizeof (char), 10, 0, PADDR, a_put, 0};
|
|
/* -t o1, -b */
|
|
static struct dfmt byte = {3, sizeof (char), 8, UNSIGNED, PADDR, b_put, 0};
|
|
#ifndef XPG4
|
|
/* Solaris -c */
|
|
static struct dfmt cchar = {3, sizeof (char), 8, UNSIGNED, PADDR, c_put, 0};
|
|
#endif
|
|
/* -t c, -C, XPG4 -c */
|
|
static struct dfmt Cchar = {3, sizeof (char), 8, UNSIGNED, PADDR, C_put, 0};
|
|
/* -t o2, -o */
|
|
static struct dfmt u_s_oct = {6, sizeof (short), 8, UNSIGNED, PADDR, us_put, 0};
|
|
/* -t u1 */
|
|
static struct dfmt u_c_dec = {3, sizeof (char), 10, UNSIGNED, PADDR, b_put, 0};
|
|
/* -t u2, -d */
|
|
static struct dfmt u_s_dec = {5, sizeof (short), 10, UNSIGNED, PADDR, us_put,
|
|
0};
|
|
/* -t x2, -x */
|
|
static struct dfmt u_s_hex = {4, sizeof (short), 16, UNSIGNED, PADDR, us_put,
|
|
0};
|
|
/* -t x1 */
|
|
static struct dfmt u_c_hex = {2, sizeof (char), 16, UNSIGNED, PADDR, b_put, 0};
|
|
/* -t o4, -O */
|
|
static struct dfmt u_l_oct = {11, sizeof (long), 8, UNSIGNED, PADDR, l_put, 0};
|
|
/* -t u4, -D */
|
|
static struct dfmt u_l_dec = {10, sizeof (long), 10, UNSIGNED, PADDR, l_put, 0};
|
|
/* -t x4, -X */
|
|
static struct dfmt u_l_hex = {8, sizeof (long), 16, UNSIGNED, PADDR, l_put, 0};
|
|
/* -t d1 */
|
|
static struct dfmt s_c_dec = {3, sizeof (char), 10, SIGNED, PADDR, sb_put, 0};
|
|
/* -t d2, -s */
|
|
static struct dfmt s_s_dec = {6, sizeof (short), 10, SIGNED, PADDR, s_put, 0};
|
|
/* -t d4, -S */
|
|
static struct dfmt s_l_dec = {11, sizeof (long), 10, SIGNED, PADDR, sl_put, 0};
|
|
/* -t f4, -f */
|
|
static struct dfmt flt = {14, sizeof (float), 10, SIGNED, PADDR, f_put, 0};
|
|
/* -t f8, -F */
|
|
static struct dfmt dble = {21, sizeof (double), 10, SIGNED, PADDR, d_put, 0};
|
|
|
|
|
|
static wchar_t wdbuf[DBUF_SIZE/sizeof (wchar_t)+1]; /* input buffer */
|
|
static char dbuf[DBUF_SIZE]; /* input buffer */
|
|
static char mbuf[DBUF_SIZE]; /* buffer used if 2-byte crosses line */
|
|
static char lastdbuf[DBUF_SIZE];
|
|
static int addr_base = 8; /* default address base is OCTAL */
|
|
static long addr = 0L; /* current file offset */
|
|
static int dbuf_size = 16; /* file bytes / display line */
|
|
static char fmt[] = " %s"; /* 12 blanks */
|
|
|
|
/*
|
|
* We must save global values and reset them for each call to double byte
|
|
* routines. For example if you call -CCCCCC, you want print the same line
|
|
* six times.
|
|
*/
|
|
static int straggle = 0; /* Did word cross line boundary? */
|
|
static int straggle_save = 0;
|
|
static int nls_shift_save = 0; /* last character was a shift char */
|
|
static int nls_skip_save = 0; /* need to skip this byte */
|
|
static int already_read = 0; /* next buffer already read in. */
|
|
static int nls_skip = 0;
|
|
static int changed = 0;
|
|
static int nls_shift = 0;
|
|
static int Aflag = 0; /* -A option */
|
|
static int jflag = 0; /* -j option */
|
|
static int tflag = 0; /* -t option */
|
|
static int Nflag = 0; /* -N option */
|
|
static int max_llen = 0;
|
|
static int bytes = 0; /* number of bytes read */
|
|
|
|
void
|
|
main(int argc, char **argv)
|
|
{
|
|
register char *p;
|
|
register char *l;
|
|
register same;
|
|
struct dfmt *d = NULL;
|
|
struct dfmt **cv = conv_vec;
|
|
int showall = NO;
|
|
int field, llen, nelm;
|
|
int max_bytes = 0;
|
|
int posixflag = 0;
|
|
char *ptr;
|
|
char *addr_ptr;
|
|
int xbytes;
|
|
extern char *optarg; /* getopt support */
|
|
extern int optind;
|
|
int c;
|
|
int fd;
|
|
int retval = 0;
|
|
int offsetfound = 0;
|
|
long seekval, bytes_read;
|
|
|
|
(void) setlocale(LC_ALL, "");
|
|
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
|
|
#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
|
|
#endif
|
|
(void) textdomain(TEXT_DOMAIN);
|
|
|
|
errno = 0;
|
|
|
|
/*
|
|
* Parse arguments and set up conversion vector
|
|
*/
|
|
|
|
while ((c = getopt(argc, argv,
|
|
":A:bCcDdFfj:N:oOsSt:vxX?0123456789")) != EOF) {
|
|
|
|
switch (c) {
|
|
/*
|
|
* Specify the input offset base
|
|
*/
|
|
case 'A':
|
|
Aflag = 1;
|
|
switch (*optarg) {
|
|
case 'd':
|
|
addr_base = 10;
|
|
break;
|
|
case 'o':
|
|
addr_base = 8;
|
|
break;
|
|
case 'n':
|
|
Aflag = 2;
|
|
break;
|
|
case 'x':
|
|
addr_base = 16;
|
|
break;
|
|
default:
|
|
(void) fprintf(stderr, gettext(
|
|
"-A option only accepts the following: d, o, n, and x\n"));
|
|
usage("od");
|
|
}
|
|
continue;
|
|
case 'b':
|
|
d = &byte;
|
|
break;
|
|
case 'C':
|
|
d = &Cchar;
|
|
break;
|
|
case 'c':
|
|
#ifdef XPG4
|
|
d = &Cchar;
|
|
#else
|
|
d = &cchar;
|
|
#endif
|
|
break;
|
|
case 'd':
|
|
d = &u_s_dec;
|
|
break;
|
|
case 'D':
|
|
d = &u_l_dec;
|
|
break;
|
|
case 'F':
|
|
d = &dble;
|
|
break;
|
|
case 'f':
|
|
d = &flt;
|
|
break;
|
|
case 'x':
|
|
d = &u_s_hex;
|
|
break;
|
|
case 'X':
|
|
d = &u_l_hex;
|
|
break;
|
|
case 's':
|
|
d = &s_s_dec;
|
|
break;
|
|
case 'S':
|
|
d = &s_l_dec;
|
|
break;
|
|
/*
|
|
* Specify number of bytes to interpret
|
|
*/
|
|
case 'N':
|
|
Nflag++;
|
|
max_bytes = strtol(optarg, &ptr, 0);
|
|
if ((max_bytes <= 0) || errno || (optarg == ptr)) {
|
|
(void) fprintf(stderr, gettext(
|
|
"Invalid number of bytes to interpret\n"));
|
|
usage("od");
|
|
}
|
|
continue;
|
|
case 'o':
|
|
d = &u_s_oct;
|
|
break;
|
|
case 'O':
|
|
d = &u_l_oct;
|
|
break;
|
|
/*
|
|
* Specify number of bytes to skip
|
|
*/
|
|
case 'j':
|
|
jflag++;
|
|
addr_ptr = optarg;
|
|
continue;
|
|
/*
|
|
* Parse type_string
|
|
*/
|
|
case 't':
|
|
tflag++;
|
|
p = optarg;
|
|
for (; *p; p++) {
|
|
switch (*p) {
|
|
case 'a':
|
|
d = &ascii;
|
|
break;
|
|
case 'c':
|
|
d = &Cchar;
|
|
break;
|
|
|
|
/*
|
|
* Type specifier d may be followed
|
|
* by a letter or number indicating
|
|
* the number
|
|
* of bytes to be transformed. If
|
|
* invalid, use default.
|
|
*/
|
|
case 'd':
|
|
d = &s_l_dec;
|
|
if (isupper(*(p+1)) || isdigit(*(p+1))) {
|
|
switch (*(++p)) {
|
|
case '1':
|
|
case 'C':
|
|
d = &s_c_dec;
|
|
break;
|
|
case '2':
|
|
case 'S':
|
|
d = &s_s_dec;
|
|
break;
|
|
case '4':
|
|
case 'I':
|
|
break;
|
|
case 'L':
|
|
d = &s_l_dec;
|
|
break;
|
|
default:
|
|
(void) fprintf(stderr,
|
|
gettext("d may only be followed with C, S, I, L, 1, 2, or 4\n"));
|
|
usage("od");
|
|
}
|
|
}
|
|
break;
|
|
|
|
/*
|
|
* Type specifier f may be followed
|
|
* by F, D, or L indicating that
|
|
* coversion should be applied to
|
|
* an item of type float, double
|
|
* or long double. OR a number
|
|
* indicating the number of bytes.
|
|
*/
|
|
case 'f':
|
|
d = &dble;
|
|
if (isupper(*(p+1)) || isdigit(*(p+1))) {
|
|
switch (*(++p)) {
|
|
case '4':
|
|
case 'F':
|
|
d = &flt;
|
|
break;
|
|
case '8':
|
|
case 'D':
|
|
break;
|
|
case 'L':
|
|
d = &dble;
|
|
break;
|
|
default:
|
|
(void) fprintf(stderr,
|
|
gettext("f may only be followed with F, D, L, 4, or 8\n"));
|
|
usage("od");
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
/*
|
|
* Type specifier o may be followed
|
|
* by a letter or a number indicating the number
|
|
* of bytes to be transformed. If
|
|
* invalid, use default.
|
|
*/
|
|
case 'o':
|
|
d = &u_l_oct;
|
|
if (isupper(*(p+1)) || isdigit(*(p+1))) {
|
|
switch (*(++p)) {
|
|
case '1':
|
|
case 'C':
|
|
d = &byte;
|
|
break;
|
|
case '2':
|
|
case 'S':
|
|
d = &u_s_oct;
|
|
break;
|
|
case '4':
|
|
case 'I':
|
|
break;
|
|
case 'L':
|
|
d = &u_l_oct;
|
|
break;
|
|
default:
|
|
(void) fprintf(stderr,
|
|
gettext("o may only be followed with C, S, I, L, 1, 2, or 4\n"));
|
|
usage("od");
|
|
}
|
|
}
|
|
break;
|
|
|
|
/*
|
|
* Type specifier u may be followed
|
|
* by a letter or a number indicating the number
|
|
* of bytes to be transformed. If
|
|
* invalid, use default.
|
|
*/
|
|
case 'u':
|
|
d = &u_l_dec;
|
|
if (isupper(*(p+1)) || isdigit(*(p+1))) {
|
|
switch (*(++p)) {
|
|
case '1':
|
|
case 'C':
|
|
d = &u_c_dec;
|
|
break;
|
|
case '2':
|
|
case 'S':
|
|
d = &u_s_dec;
|
|
break;
|
|
case '4':
|
|
case 'I':
|
|
break;
|
|
case 'L':
|
|
d = &u_l_dec;
|
|
break;
|
|
default:
|
|
(void) fprintf(stderr,
|
|
gettext("u may only be followed with C, S, I, L, 1, 2, or 4\n"));
|
|
usage("od");
|
|
}
|
|
}
|
|
break;
|
|
|
|
/*
|
|
* Type specifier x may be followed
|
|
* by a letter or a number indicating the number
|
|
* of bytes to be transformed. If
|
|
* invalid, use default.
|
|
*/
|
|
case 'x':
|
|
d = &u_l_hex;
|
|
if (isupper(*(p+1)) || isdigit(*(p+1))) {
|
|
switch (*(++p)) {
|
|
case '1':
|
|
case 'C':
|
|
d = &u_c_hex;
|
|
break;
|
|
case '2':
|
|
case 'S':
|
|
d = &u_s_hex;
|
|
break;
|
|
case '4':
|
|
case 'I':
|
|
break;
|
|
case 'L':
|
|
d = &u_l_hex;
|
|
break;
|
|
default:
|
|
(void) fprintf(stderr,
|
|
gettext("x may only be followed with C, S, I, L, 1, 2, or 4\n"));
|
|
usage("od");
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
usage("od");
|
|
}
|
|
if ((cv - conv_vec) < MAX_CONV)
|
|
*(cv++) = d;
|
|
else {
|
|
(void) fprintf(stderr,
|
|
gettext("Too many conversions specified.\n"));
|
|
usage("od");
|
|
}
|
|
}
|
|
continue;
|
|
case 'v':
|
|
showall = YES;
|
|
continue;
|
|
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
usage("od");
|
|
continue;
|
|
|
|
case '?':
|
|
default:
|
|
usage("od");
|
|
}
|
|
if (cv - conv_vec < MAX_CONV)
|
|
*(cv++) = d;
|
|
else {
|
|
(void) fprintf(stderr, gettext("Too many conversions specified\n"));
|
|
usage("od");
|
|
}
|
|
|
|
} /* while getopt */
|
|
|
|
if (Aflag || jflag || Nflag || tflag)
|
|
posixflag++; /* Filename can begin w/ '+' */
|
|
|
|
argv += optind;
|
|
argc -= optind;
|
|
|
|
/*
|
|
* if nothing spec'd, setup default conversion.
|
|
*/
|
|
if (cv == conv_vec)
|
|
*(cv++) = &u_s_oct;
|
|
|
|
*cv = (struct dfmt *)0;
|
|
|
|
/*
|
|
* calculate display parameters
|
|
*/
|
|
for (cv = conv_vec; d = *cv; cv++) {
|
|
nelm = (dbuf_size + d->df_size - 1) / d->df_size;
|
|
llen = nelm * (d->df_field + 1);
|
|
if (llen > max_llen)
|
|
max_llen = llen;
|
|
}
|
|
|
|
/*
|
|
* setup df_fmt to point to uniform output fields.
|
|
*/
|
|
for (cv = conv_vec; d = *cv; cv++) {
|
|
if (d->df_field) /* only if external field is known */
|
|
{
|
|
nelm = (dbuf_size + d->df_size - 1) / d->df_size;
|
|
field = max_llen / nelm;
|
|
d->df_fmt = fmt + 12 - (field - d->df_field);
|
|
}
|
|
}
|
|
|
|
fd = dup(0);
|
|
if (argc > 0) {
|
|
/*
|
|
* Check first operand whether input file specified. If so,
|
|
* freopen stdin as new file.
|
|
*/
|
|
if (argc > 1 || **argv != '+' || posixflag) {
|
|
/* this operand is not an offset; open the file */
|
|
if (argv[0][0] != '-' || argv[0][1] != '\0') {
|
|
/*
|
|
* Not "-", ie: didn't specify to use stdin in
|
|
* addition to any files given.
|
|
*/
|
|
odopen(&argc, argv, &retval, fd, max_bytes);
|
|
}
|
|
argv++;
|
|
argc--;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Advance into the concatenated input files the number of bytes
|
|
* specified via -j
|
|
*/
|
|
if (jflag) {
|
|
seekval = get_addr(addr_ptr);
|
|
/* file already open */
|
|
while (!offsetfound && argc >= 0) {
|
|
if (offset(seekval, &bytes_read))
|
|
offsetfound = 1;
|
|
else {
|
|
seekval -= bytes_read;
|
|
/* open next file */
|
|
odopen(&argc, argv, &retval, fd, max_bytes);
|
|
argv++;
|
|
argc--;
|
|
}
|
|
}
|
|
if (!offsetfound) {
|
|
(void) fprintf(stderr, gettext("EOF\n"));
|
|
exit(1);
|
|
}
|
|
#ifdef XPG4
|
|
} else if (argc == 1 && !posixflag &&
|
|
(**argv == '+' || isdigit(**argv))) {
|
|
/*
|
|
* XPG4:
|
|
* If there are no more than two operands,
|
|
* none of the -A, -j, -N, or -t options is specified,
|
|
* and any of the following are true:
|
|
* 1. the first character of the last operand is a
|
|
* plus sign (+)
|
|
* 2. the first character of the second operand is
|
|
* numeric
|
|
* then the corresponding operand is assumed to be an
|
|
* offset operand rather than a file operand.
|
|
*/
|
|
#else
|
|
} else if (argc == 1 && !posixflag &&
|
|
(**argv == '+' || isdigit(**argv) ||
|
|
(**argv == '.' && argv[0][1] == '\0') ||
|
|
(**argv == 'x' && argv[0][1] == '\0') ||
|
|
(**argv == 'x' && isxdigit(argv[0][1]) &&
|
|
argv[0][1] != 'A' && argv[0][1] != 'B' &&
|
|
argv[0][1] != 'C' && argv[0][1] != 'D' &&
|
|
argv[0][1] != 'E' && argv[0][1] != 'F'))) {
|
|
/*
|
|
* Solaris:
|
|
* If there are no more than two operands,
|
|
* none of the -A, -j, -N, or -t options is specified,
|
|
* and any of the following are true:
|
|
* 1. the first character of the last operand is a
|
|
* plus sign (+)
|
|
* 2. the first character of the second operand is
|
|
* numeric
|
|
* 3. the second operand is named "x"
|
|
* 4. the second operand is named "."
|
|
* 5. the first character of the second operand is x
|
|
* and the the second character of the second
|
|
* operand is a lower case hex character or digit
|
|
* then the corresponding operand is assumed to be an
|
|
* offset operand rather than a file operand.
|
|
*/
|
|
#endif
|
|
addr = get_offset(*argv);
|
|
if (!offset(addr, &bytes_read)) {
|
|
put_addr(addr, '\n');
|
|
exit(0);
|
|
}
|
|
argv++;
|
|
argc--;
|
|
}
|
|
|
|
same = -1;
|
|
/*
|
|
* Process either file or stdin. Open new files and
|
|
* continue processing as necessary.
|
|
*/
|
|
while (argc >= 0) {
|
|
/*
|
|
* main dump loop
|
|
*/
|
|
while (already_read || (bytes = fread((void *)dbuf,
|
|
(size_t)1, (size_t)dbuf_size, stdin)) > 0) {
|
|
if (already_read) {
|
|
already_read = 0;
|
|
(void) memcpy(dbuf, mbuf, dbuf_size);
|
|
}
|
|
|
|
/*
|
|
* If more than one file is specified and
|
|
* the current file does not fill the buffer,
|
|
* open the next file and continue processing.
|
|
*/
|
|
while ((bytes < dbuf_size) && (argc > 0)) {
|
|
if (Nflag && bytes >= max_bytes) {
|
|
/*
|
|
* We have already read the amount of
|
|
* data requested via -N option.
|
|
*/
|
|
break;
|
|
}
|
|
odopen(&argc, argv, &retval, fd, max_bytes);
|
|
argv++;
|
|
argc--;
|
|
ptr = dbuf + bytes;
|
|
if ((xbytes = fread((void *)ptr, (size_t)1,
|
|
(size_t)(dbuf_size-bytes), stdin)) > 0)
|
|
bytes += xbytes;
|
|
}
|
|
if (same >= 0 && memcmp((void *)dbuf, (void *)lastdbuf,
|
|
(size_t)dbuf_size) == 0 && !showall) {
|
|
if (same == 0) {
|
|
(void) printf("*\n");
|
|
same = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* If Nflag is specified, only print
|
|
* max_bytes bytes
|
|
*/
|
|
if (!Nflag)
|
|
line(bytes);
|
|
else {
|
|
if (max_bytes > bytes) {
|
|
line(bytes);
|
|
max_bytes -= bytes;
|
|
} else {
|
|
if (max_bytes < bytes) {
|
|
(void) memset(dbuf+max_bytes,
|
|
0, bytes - max_bytes);
|
|
line(max_bytes);
|
|
/*
|
|
* XCU4: P1003.2/D8 Sect. 4.45.5.2 052(A)
|
|
* GA34: using the 'file' operand.
|
|
* When a standard utility reads a seekable input file and
|
|
* terminates without an error before it reaches end-of-file, then the
|
|
* utility ensures that the file offset in the open file description is
|
|
* properly positioned just past the last byte processed by the utility.
|
|
*/
|
|
/*
|
|
* not an error if
|
|
* fseek() fails
|
|
* ie: not a seekable
|
|
* input file
|
|
*/
|
|
(void) fseek(stdin,
|
|
-(bytes - max_bytes), SEEK_CUR);
|
|
} else
|
|
line(max_bytes);
|
|
addr += max_bytes;
|
|
last_addr();
|
|
exit(retval);
|
|
}
|
|
}
|
|
|
|
same = 0;
|
|
p = dbuf;
|
|
l = lastdbuf;
|
|
for (nelm = 0; nelm < dbuf_size; nelm++) {
|
|
*l++ = *p;
|
|
*p++ = '\0';
|
|
}
|
|
}
|
|
addr += bytes;
|
|
|
|
}
|
|
|
|
/*
|
|
* If there are more files, open and
|
|
* continue processing.
|
|
*/
|
|
if (argc == 0)
|
|
break;
|
|
else
|
|
{
|
|
odopen(&argc, argv, &retval, fd, max_bytes);
|
|
argv++;
|
|
argc--;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Some conversions require "flushing".
|
|
*/
|
|
bytes = 0;
|
|
for (cv = conv_vec; *cv; cv++) {
|
|
if ((*cv)->df_paddr) {
|
|
if (bytes++ == 0) {
|
|
if (Aflag == 2)
|
|
(void) fputc('\n', stdout);
|
|
else if (argc <= 0)
|
|
put_addr(addr, '\n');
|
|
}
|
|
}
|
|
else
|
|
(*((*cv)->df_put))(0, *cv);
|
|
}
|
|
exit(retval);
|
|
}
|
|
|
|
/*
|
|
* NAME: put_addr
|
|
*
|
|
* FUNCTION: Print out the current file address.
|
|
*
|
|
*/
|
|
|
|
void
|
|
put_addr(long addrs, char chr)
|
|
{
|
|
(void) fputs(icvt(addrs, addr_base, UNSIGNED, 7), stdout);
|
|
if (chr != '\0')
|
|
(void) putchar(chr);
|
|
|
|
}
|
|
|
|
/*
|
|
* NAME: line
|
|
*
|
|
* FUNCTION: When line is called we have determined the line is different
|
|
* from the previous line. We then print it out in all the
|
|
* formats called for in the command line.
|
|
*
|
|
*/
|
|
void
|
|
line(int n)
|
|
{
|
|
register i, first;
|
|
register struct dfmt *c;
|
|
register struct dfmt **cv = conv_vec;
|
|
int newstraggle = 0,
|
|
newnls_skip = 0,
|
|
newnls_shift = 0;
|
|
|
|
straggle_save = straggle;
|
|
nls_shift_save = nls_shift;
|
|
nls_skip_save = nls_skip;
|
|
first = YES;
|
|
while (c = *cv++) {
|
|
straggle = straggle_save;
|
|
nls_shift = nls_shift_save;
|
|
nls_skip = nls_skip_save;
|
|
if (c->df_paddr) {
|
|
if (first) {
|
|
if (Aflag == 2)
|
|
(void) fputc('\t', stdout);
|
|
else
|
|
put_addr(addr, '\0');
|
|
first = NO;
|
|
}
|
|
else
|
|
(void) putchar('\t');
|
|
}
|
|
i = 0;
|
|
changed = 0;
|
|
#ifdef XPG4
|
|
if (c == &Cchar) {
|
|
#else
|
|
if (c == &Cchar || c == &cchar) {
|
|
#endif
|
|
/*
|
|
* -t c, -C, -c
|
|
* Keep data in dbuf for char handling.
|
|
*/
|
|
while (i < n)
|
|
i += (*(c->df_put))(dbuf+i, c);
|
|
} else {
|
|
/*
|
|
* Data is copied to wdbuf to avoid address alignment
|
|
* problems caused by passing dbuf.
|
|
*/
|
|
while (i < n) {
|
|
(void) memcpy(wdbuf, dbuf+i, c->df_size);
|
|
i += (*(c->df_put))(wdbuf, c);
|
|
}
|
|
}
|
|
|
|
if (changed) {
|
|
newstraggle |= straggle;
|
|
newnls_shift |= nls_shift;
|
|
newnls_skip |= nls_skip;
|
|
}
|
|
|
|
if (c->df_paddr)
|
|
(void) putchar('\n');
|
|
}
|
|
straggle = newstraggle;
|
|
nls_skip = newnls_skip;
|
|
nls_shift = newnls_shift;
|
|
}
|
|
|
|
/*
|
|
* NAME: s_put
|
|
*
|
|
* FUNCTION: Print out a signed short.
|
|
*
|
|
* RETURN VALUE DESCRIPTION: size of a short.
|
|
*
|
|
*/
|
|
|
|
int
|
|
s_put(unsigned short *n, struct dfmt *d)
|
|
{
|
|
(void) putchar(' ');
|
|
if (*n > 32767) {
|
|
pre(d->df_field, d->df_size);
|
|
(void) putchar('-');
|
|
*n = (~(*n) + 1) & 0177777;
|
|
} else
|
|
pre(d->df_field-1, d->df_size);
|
|
putn((long)*n, d->df_radix, d->df_field-1);
|
|
return (d->df_size);
|
|
}
|
|
|
|
/*
|
|
* NAME: us_put
|
|
*
|
|
* FUNCTION: Print out an unsigned short (hex, oct, dec).
|
|
*
|
|
* RETURN VALUE DESCRIPTION: size of a short
|
|
*
|
|
*/
|
|
int
|
|
us_put(unsigned short *n, struct dfmt *d)
|
|
{
|
|
pre(d->df_field, d->df_size);
|
|
putn((long)*n, d->df_radix, d->df_field);
|
|
return (d->df_size);
|
|
}
|
|
|
|
#ifndef XPG4
|
|
/*
|
|
* NAME: c_put
|
|
*
|
|
* FUNCTION: print out a single byte character
|
|
*
|
|
* RETURN VALUE: number of bytes in character (1)
|
|
*
|
|
*/
|
|
int
|
|
c_put(unsigned char *cc, struct dfmt *d)
|
|
{
|
|
pre(d->df_field, d->df_size);
|
|
cput(*cc);
|
|
return (d->df_size);
|
|
}
|
|
|
|
void
|
|
cput(int c)
|
|
{
|
|
c &= 0377;
|
|
if (c >= 0200 && MB_CUR_MAX > 1)
|
|
putn((long)c, 8, 3); /* Multi Envir. with Multi byte char */
|
|
else {
|
|
if (isprint(c)) {
|
|
(void) printf(" ");
|
|
(void) putchar(c);
|
|
return;
|
|
}
|
|
switch (c) {
|
|
case '\0':
|
|
(void) printf(" \\0");
|
|
break;
|
|
case '\b':
|
|
(void) printf(" \\b");
|
|
break;
|
|
case '\f':
|
|
(void) printf(" \\f");
|
|
break;
|
|
case '\n':
|
|
(void) printf(" \\n");
|
|
break;
|
|
case '\r':
|
|
(void) printf(" \\r");
|
|
break;
|
|
case '\t':
|
|
(void) printf(" \\t");
|
|
break;
|
|
default:
|
|
putn((long)c, 8, 3);
|
|
}
|
|
}
|
|
}
|
|
#endif /* XPG4 not defined, ie: Solaris -c option */
|
|
|
|
/*
|
|
* NAME: l_put
|
|
*
|
|
* FUNCTION: Print out an unsigned long (octal, hex, decimal).
|
|
*
|
|
* RETURN VALUE DESCRIPTION: size of a long.
|
|
*
|
|
*/
|
|
int
|
|
l_put(unsigned long *n, struct dfmt *d)
|
|
{
|
|
pre(d->df_field, d->df_size);
|
|
putn((long)*n, d->df_radix, d->df_field);
|
|
return (d->df_size);
|
|
}
|
|
|
|
/*
|
|
* NAME: sl_put
|
|
*
|
|
* FUNCTION: Print out a signed long.
|
|
*
|
|
* RETURN VALUE DESCRIPTION: size of a long.
|
|
*
|
|
*/
|
|
int
|
|
sl_put(unsigned long *n, struct dfmt *d)
|
|
{
|
|
if (*n > 2147483647) {
|
|
pre(d->df_field, d->df_size);
|
|
(void) putchar('-');
|
|
*n = (~(*n)+1) & 037777777777;
|
|
}
|
|
else
|
|
pre(d->df_field-1, d->df_size);
|
|
putn((long)*n, d->df_radix, d->df_field-1);
|
|
return (d->df_size);
|
|
}
|
|
|
|
void
|
|
pre(int f, int n)
|
|
{
|
|
int i, m;
|
|
|
|
m = (max_llen/(LBUFSIZE/n)) - f;
|
|
for (i = 0; i < m; i++)
|
|
(void) putchar(' ');
|
|
}
|
|
|
|
void
|
|
putn(unsigned long n, int b, int c)
|
|
{
|
|
register d;
|
|
|
|
if (!c)
|
|
return;
|
|
putn(n/b, b, c-1);
|
|
d = n%b;
|
|
if (d > 9)
|
|
(void) putchar(d-10+'a');
|
|
else
|
|
(void) putchar(d+'0');
|
|
}
|
|
|
|
/*
|
|
* NAME: d_put
|
|
*
|
|
* FUNCTION: Print out a double.
|
|
*
|
|
* RETURN VALUE DESCRIPTION: size of a double
|
|
*
|
|
*/
|
|
int
|
|
d_put(double *f, struct dfmt *d)
|
|
{
|
|
pre(d->df_field, d->df_size);
|
|
(void) printf("%21.14e", *f);
|
|
return (d->df_size);
|
|
}
|
|
|
|
/*
|
|
* NAME: f_put
|
|
*
|
|
* FUNCTION: Print out a float.
|
|
*
|
|
* RETURN VALUE DESCRIPTION: size of a float.
|
|
*
|
|
*/
|
|
int
|
|
f_put(float *f, struct dfmt *d)
|
|
{
|
|
pre(d->df_field, d->df_size);
|
|
(void) printf("%14.7e", *f);
|
|
return (d->df_size);
|
|
}
|
|
|
|
|
|
static char asc_name[34][4] = {
|
|
/* 000 */ "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
|
|
/* 010 */ " bs", " ht", " lf", " vt", " ff", " cr", " so", " si",
|
|
/* 020 */ "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb",
|
|
/* 030 */ "can", " em", "sub", "esc", " fs", " gs", " rs", " us",
|
|
/* 040 */ " sp", "del"
|
|
};
|
|
|
|
/*
|
|
* NAME: a_put
|
|
*
|
|
* FUNCTION: print out value in ascii, using known values for unprintables.
|
|
*
|
|
* RETURN VALUE: 1
|
|
*
|
|
*/
|
|
int
|
|
a_put(unsigned char *cc, struct dfmt *d)
|
|
{
|
|
int c = *cc;
|
|
char s[4] = {' ', ' ', ' ', 0 }; /* 3 spaces, NUL terminated */
|
|
|
|
c &= 0177;
|
|
if (isgraph(c)) {
|
|
s[2] = c;
|
|
(void) printf(d->df_fmt, s);
|
|
}
|
|
else
|
|
{
|
|
if (c == 0177)
|
|
c = ' ' + 1;
|
|
(void) printf(d->df_fmt, asc_name[c]);
|
|
}
|
|
return (1);
|
|
}
|
|
|
|
/*
|
|
* NAME: b_put
|
|
*
|
|
* FUNCTION: Print out an unsigned byte (hex, oct, dec).
|
|
*
|
|
* RETURN VALUE: 1
|
|
*
|
|
*/
|
|
int
|
|
b_put(unsigned char *b, struct dfmt *d)
|
|
{
|
|
pre(d->df_field, d->df_size);
|
|
putn((long)(*b)&0377, d->df_radix, d->df_field);
|
|
return (1);
|
|
}
|
|
|
|
/*
|
|
* NAME: sb_put
|
|
*
|
|
* FUNCTION: Print out a signed byte.
|
|
*
|
|
* RETURN VALUE: 1
|
|
*
|
|
*/
|
|
int
|
|
sb_put(char *bc, struct dfmt *d)
|
|
{
|
|
(void) printf(d->df_fmt,
|
|
icvt((long)*bc, d->df_radix, d->df_signed, d->df_field));
|
|
return (1);
|
|
}
|
|
|
|
/*
|
|
* NAME: C_put
|
|
*
|
|
* FUNCTION: print out a character (multibyte or single byte)
|
|
*
|
|
* RETURN VALUE: number of bytes in character (usually 1)
|
|
*
|
|
*/
|
|
|
|
int
|
|
C_put(unsigned char *cc, struct dfmt *d)
|
|
{
|
|
register char *s;
|
|
register int n;
|
|
register int c = *cc;
|
|
int mbcnt;
|
|
int mbufcnt = 0;
|
|
char mbchar[MB_LEN_MAX+1];
|
|
static wchar_t pcode;
|
|
int rc;
|
|
|
|
changed++;
|
|
mbcnt = mblen((const char *)cc, MB_CUR_MAX);
|
|
if ((!nls_shift) && (mbcnt != 1 && mbcnt != 0)) {
|
|
/*
|
|
* Either found the start of a multibyte character (mbcnt > 1)
|
|
* or an illegal sequence, _OR_ we have a character crossing a
|
|
* block-boundary (and need to read some more in...)
|
|
*/
|
|
int mbl = 1;
|
|
|
|
|
|
nls_shift += (mbcnt > 0)? (mbcnt - 1) : 0;
|
|
nls_skip += (mbcnt > 0)? (mbcnt - 1) : 0;
|
|
mbchar[0] = c;
|
|
|
|
loop:
|
|
if (cc[mbl] == '\0') /* Was end of buffer, get some more */
|
|
{
|
|
straggle++;
|
|
if (!already_read) {
|
|
if ((bytes = fread((void *)mbuf, (size_t)1,
|
|
(size_t)dbuf_size, stdin)) <= 0) {
|
|
/*
|
|
* Only part of a double byte character
|
|
* found.
|
|
*/
|
|
straggle = 0;
|
|
already_read = 0;
|
|
mbchar[mbl] = 0;
|
|
mbcnt = mbl;
|
|
}
|
|
else
|
|
{
|
|
already_read++;
|
|
mbchar[mbl] = mbuf[mbufcnt];
|
|
mbl++;
|
|
mbufcnt++;
|
|
}
|
|
} else {
|
|
mbchar[mbl] = mbuf[mbufcnt];
|
|
mbl++;
|
|
mbufcnt++;
|
|
if (mbl > bytes) {
|
|
mbchar[mbl] = '\0';
|
|
mbcnt = nls_skip = nls_shift = mbl;
|
|
goto next;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
mbchar[mbl] = cc[mbl];
|
|
mbl++;
|
|
|
|
mbchar[mbl] = '\0';
|
|
mbcnt = mblen(mbchar, MB_CUR_MAX);
|
|
if (!nls_shift)
|
|
nls_shift += (mbcnt > 0)? (mbcnt - 1) : 0;
|
|
if (!nls_skip)
|
|
nls_skip += (mbcnt > 0)? (mbcnt - 1) : 0;
|
|
/*
|
|
* we must handle the case if the
|
|
* multi byte char is split on a line
|
|
* boundary, mblen will return -1, but
|
|
* we have to check next char to see if
|
|
* it's part of multi byte char therefore
|
|
* we go to loop.
|
|
*/
|
|
if (mbcnt == -1) {
|
|
if (mbl < (int)MB_CUR_MAX)
|
|
goto loop;
|
|
else {
|
|
mbcnt = 1;
|
|
mbchar[mbcnt] = '\0';
|
|
nls_skip = 0;
|
|
nls_shift = 0;
|
|
}
|
|
}
|
|
next:
|
|
rc = mbtowc(&pcode, mbchar, sizeof (mbchar));
|
|
if (rc <= 0 || !iswprint(pcode))
|
|
s = scvt(c, d);
|
|
else
|
|
s = mbchar;
|
|
|
|
} else if (nls_skip) {
|
|
nls_skip = (nls_skip > 0)? nls_skip - 1: 0;
|
|
nls_shift = (nls_shift > 0)? nls_shift - 1: 0;
|
|
rc = mbtowc(&pcode, mbchar, sizeof (mbchar));
|
|
if (rc <= 0 || !iswprint(pcode)) {
|
|
s = scvt(c, d);
|
|
(void) printf(d->df_fmt, s);
|
|
} else
|
|
(void) fputs(" **", stdout);
|
|
|
|
straggle = 0;
|
|
return (1);
|
|
}
|
|
else
|
|
{
|
|
s = scvt(c, d);
|
|
}
|
|
for (n = d->df_field - mbswidth(s, d->df_field); n > 0; n--)
|
|
(void) putchar(' ');
|
|
(void) printf(d->df_fmt, s);
|
|
|
|
return ((nls_skip > 0 && mbcnt > 2)? mbcnt - 1 : 1);
|
|
}
|
|
|
|
/*
|
|
* NAME: scvt
|
|
*
|
|
* FUNCTION: convert the character to a representable string.
|
|
*
|
|
* RETURN VALUE: A pointer to the string.
|
|
*
|
|
*/
|
|
char *
|
|
scvt(int c, struct dfmt *d)
|
|
{
|
|
static char s[2];
|
|
|
|
c &= 0377;
|
|
if (c >= 0200 && MB_CUR_MAX > 1) {
|
|
/* Multi Envir. with Multi byte char */
|
|
nls_skip = 0; /* don't skip the next byte */
|
|
return (icvt((long)c, d->df_radix, d->df_signed, d->df_field));
|
|
} else {
|
|
switch (c) {
|
|
case '\0':
|
|
return ("\\0");
|
|
|
|
case '\a':
|
|
if (tflag)
|
|
return ("\\a");
|
|
else
|
|
return (icvt((long)c, d->df_radix, d->df_signed, d->df_field));
|
|
|
|
case '\b':
|
|
return ("\\b");
|
|
|
|
case '\f':
|
|
return ("\\f");
|
|
|
|
case '\n':
|
|
return ("\\n");
|
|
|
|
case '\r':
|
|
return ("\\r");
|
|
|
|
case '\t':
|
|
return ("\\t");
|
|
|
|
case '\v':
|
|
if (tflag)
|
|
return ("\\v");
|
|
else
|
|
return (icvt((long)c, d->df_radix, d->df_signed, d->df_field));
|
|
|
|
default:
|
|
if (isprint(c)) {
|
|
/*
|
|
* Depends on "s" being STATIC initialized
|
|
* to zero
|
|
*/
|
|
s[0] = c;
|
|
return (s);
|
|
}
|
|
return (icvt((long)c, d->df_radix, d->df_signed,
|
|
d->df_field));
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* integer to ascii conversion
|
|
*
|
|
* This code has been rearranged to produce optimized runtime code.
|
|
*/
|
|
|
|
#define MAXINTLENGTH 32
|
|
static char _digit[] = "0123456789abcdef";
|
|
static char _icv_buf[MAXINTLENGTH+1];
|
|
static long _mask = 0x7fffffff;
|
|
|
|
/*
|
|
* NAME: icvt
|
|
*
|
|
* FUNCTION: return from a given stream the first value.
|
|
*
|
|
* RETURN VALUE: the value is an ascii stream printed in the RADIX given.
|
|
*/
|
|
char *
|
|
icvt(long value, int radix, int issigned, int ndigits)
|
|
{
|
|
register long val = value;
|
|
register long rad = radix;
|
|
register char *b = &_icv_buf[MAXINTLENGTH];
|
|
register char *d = _digit;
|
|
register long tmp1;
|
|
register long tmp2;
|
|
long rem;
|
|
long kludge;
|
|
int sign;
|
|
|
|
if (val == 0) {
|
|
*--b = '0';
|
|
sign = 0;
|
|
goto done;
|
|
}
|
|
|
|
if (issigned && (sign = (val < 0))) /* signed conversion */
|
|
{
|
|
/*
|
|
* It is necessary to do the first divide
|
|
* before the absolute value, for the case -2^31
|
|
*
|
|
* This is actually what is being done...
|
|
* tmp1 = (int)(val % rad);
|
|
* val /= rad;
|
|
* val = -val
|
|
* *--b = d[-tmp1];
|
|
*/
|
|
tmp1 = val / rad;
|
|
*--b = d[(tmp1 * rad) - val];
|
|
val = -tmp1;
|
|
} else /* unsigned conversion */
|
|
{
|
|
sign = 0;
|
|
if (val < 0) {
|
|
/* ALL THIS IS TO SIMULATE UNSIGNED LONG MOD & DIV */
|
|
kludge = _mask - (rad - 1);
|
|
val &= _mask;
|
|
/*
|
|
* This is really what's being done...
|
|
* rem = (kludge % rad) + (val % rad);
|
|
* val = (kludge / rad) + (val / rad) + (rem / rad) + 1;
|
|
* *--b = d[rem % rad];
|
|
*/
|
|
tmp1 = kludge / rad;
|
|
tmp2 = val / rad;
|
|
rem = (kludge - (tmp1 * rad)) + (val - (tmp2 * rad));
|
|
val = ++tmp1 + tmp2;
|
|
tmp1 = rem / rad;
|
|
val += tmp1;
|
|
*--b = d[rem - (tmp1 * rad)];
|
|
}
|
|
}
|
|
|
|
while (val) {
|
|
/*
|
|
* This is really what's being done ...
|
|
* *--b = d[val % rad];
|
|
* val /= rad;
|
|
*/
|
|
tmp1 = val / rad;
|
|
*--b = d[val - (tmp1 * rad)];
|
|
val = tmp1;
|
|
}
|
|
|
|
done:
|
|
if (sign)
|
|
*--b = '-';
|
|
|
|
tmp1 = ndigits - (&_icv_buf[MAXINTLENGTH] - b);
|
|
tmp2 = issigned? ' ':'0';
|
|
while (tmp1 > 0) {
|
|
*--b = tmp2;
|
|
tmp1--;
|
|
}
|
|
|
|
return (b);
|
|
}
|
|
|
|
/*
|
|
* NAME: get_addr
|
|
*
|
|
* FUNCTION: return the address to jump to (-j option)
|
|
*/
|
|
long
|
|
get_addr(register char *s)
|
|
{
|
|
register long a;
|
|
char *ptr;
|
|
int base = 10;
|
|
|
|
/*
|
|
* Parse type_string to determine input base
|
|
*/
|
|
if ((s[0] == '0') && ((s[1] == 'x') || (s[1] == 'X'))) {
|
|
s += 2;
|
|
base = 16;
|
|
} else if (*s == '0') {
|
|
++s;
|
|
base = 8;
|
|
}
|
|
|
|
|
|
/*
|
|
* Parse input base
|
|
*/
|
|
errno = 0;
|
|
a = strtol(s, &ptr, base);
|
|
|
|
if ((a < 0) || errno || (s == ptr)) {
|
|
(void) fprintf(stderr, gettext("Invalid offset\n"));
|
|
usage("od");
|
|
}
|
|
|
|
s = ptr;
|
|
|
|
/*
|
|
* Offset may be followed by a multiplier
|
|
*/
|
|
switch (*s) {
|
|
case 'b':
|
|
a *= BSIZE;
|
|
break;
|
|
case 'k':
|
|
a *= KSIZE;
|
|
break;
|
|
case 'm':
|
|
a *= MSIZE;
|
|
break;
|
|
}
|
|
|
|
return (a);
|
|
}
|
|
|
|
|
|
/*
|
|
* NAME: offset
|
|
*
|
|
* FUNCTION: seek to the appropriate starting place.
|
|
*
|
|
* RETURN: 1 -> offset found
|
|
* 0 -> reached EOF (set bytes_read)
|
|
*/
|
|
|
|
int
|
|
offset(long s_offset, long *bytes_read)
|
|
{
|
|
char buf[BUFSIZ];
|
|
int n;
|
|
int nr;
|
|
|
|
*bytes_read = 0L;
|
|
while (s_offset > 0) {
|
|
nr = (s_offset > BUFSIZ) ? BUFSIZ : (int)s_offset;
|
|
if ((n = fread((void *)buf, (size_t)1, (size_t)nr,
|
|
stdin)) != nr) {
|
|
*bytes_read += n;
|
|
return (0);
|
|
}
|
|
s_offset -= n;
|
|
}
|
|
return (1);
|
|
}
|
|
|
|
|
|
void
|
|
usage(char *progname)
|
|
{
|
|
(void) fprintf(stderr, gettext(
|
|
"usage: %s [-bcCdDfFoOsSvxX] [-] [file] [offset_string]\n"), progname);
|
|
|
|
(void) fprintf(stderr, gettext(" \
|
|
%s [-bcCdDfFoOsSvxX] [-t type_string]... [-A address_base] [-j skip] \
|
|
[-N count] [-] [file...]\n"), progname);
|
|
|
|
exit(1);
|
|
}
|
|
|
|
/*
|
|
* NAME: odopen
|
|
*
|
|
* FUNCTION: Open next file in argument list.
|
|
*
|
|
* RETURN VALUE: Set exitstat and increment argcnt and argvec to try opening
|
|
* next file if error occurs when opening the file.
|
|
*/
|
|
void
|
|
odopen(int *argcnt, char **argvec, int *exitstat, int fd, int max_bytes)
|
|
{
|
|
int try_open;
|
|
|
|
try_open = 1;
|
|
while (*argcnt > 0 && try_open) {
|
|
if (argvec[0][0] == '-' && argvec[0][1] == '\0') {
|
|
if (dup2(fd, 0) == -1) {
|
|
last_addr();
|
|
(void) fprintf(stderr, gettext(
|
|
"od: dup2() failed: "));
|
|
perror("");
|
|
exit(1);
|
|
}
|
|
rewind(stdin);
|
|
try_open = 0;
|
|
} else {
|
|
if (freopen(*argvec, "r", stdin) == NULL) {
|
|
if (*argcnt == 1) {
|
|
if (bytes > 0 && bytes < dbuf_size) {
|
|
if (Nflag && max_bytes < bytes)
|
|
bytes = max_bytes;
|
|
/*
|
|
* od has read some
|
|
* data, but has
|
|
* not printed the
|
|
* partial line yet
|
|
*/
|
|
line(bytes);
|
|
addr += bytes;
|
|
}
|
|
last_addr();
|
|
(void) fprintf(stderr, gettext(
|
|
"od: cannot open %s: "), *argvec);
|
|
perror("");
|
|
exit(2);
|
|
} else {
|
|
(void) fprintf(stderr, gettext(
|
|
"od: cannot open %s: "), *argvec);
|
|
perror("");
|
|
*exitstat = 2;
|
|
/* freopen() has closed stdin */
|
|
if (fdopen(0, "r") == NULL) {
|
|
last_addr();
|
|
(void) fprintf(stderr,
|
|
gettext(
|
|
"od: fdopen(): unable to open stdin: "));
|
|
perror("");
|
|
exit(1);
|
|
}
|
|
}
|
|
argvec++;
|
|
/*
|
|
* If the following statement is changed,
|
|
* make sure "od -c noread - noexist <file"
|
|
* still works
|
|
*/
|
|
*argcnt--;
|
|
} else
|
|
try_open = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* NAME: last_addr
|
|
*
|
|
* FUNCTION: Put address on last line.
|
|
*
|
|
*/
|
|
void
|
|
last_addr()
|
|
{
|
|
if (addr > 0) {
|
|
if (Aflag == 2)
|
|
(void) fputc('\n', stdout);
|
|
else
|
|
put_addr(addr, '\n');
|
|
}
|
|
}
|
|
|
|
/*
|
|
* NAME: get_offset
|
|
*
|
|
* FUNCTION: Interpret old style offset entered.
|
|
*
|
|
* RETURN VALUE: offset address
|
|
*/
|
|
long
|
|
get_offset(register char *offset)
|
|
{
|
|
register char *p, *s;
|
|
long a;
|
|
register int d;
|
|
|
|
s = offset;
|
|
if (*s == '+')
|
|
s++;
|
|
if (*s == 'x') {
|
|
s++;
|
|
addr_base = 16;
|
|
} else if (*s == '0' && s[1] == 'x') {
|
|
s += 2;
|
|
addr_base = 16;
|
|
}
|
|
p = s;
|
|
/* determine if addr base 10 and do error checking */
|
|
while (*p) {
|
|
if (*p == '.') {
|
|
if ((p == s && *(p+1) != '\0') || addr_base == 16 ||
|
|
(p != s && *(p+1) != 'b' && *(p+1) != 'B' &&
|
|
*(p+1) != '\0')) {
|
|
/*
|
|
* Ensure mutually exclusive usage
|
|
* except that decimal overrides
|
|
* octal when '0' is used with '.'.
|
|
* Differences between Solaris usage and
|
|
* XPG4 usage are taken care of in main()
|
|
* when get_offset() is called.
|
|
* Solaris:
|
|
* [+][0]offset[.][b|B]
|
|
* [+][0][offset][.]
|
|
* XPG4:
|
|
* [+][0]offset[.][b|B]
|
|
* +[offset][.]
|
|
*/
|
|
(void) fprintf(stderr, gettext(
|
|
"od: invalid offset %s\n"), offset);
|
|
usage("od");
|
|
}
|
|
addr_base = 10;
|
|
}
|
|
++p;
|
|
}
|
|
for (a = 0; *s; s++) {
|
|
d = *s;
|
|
if ((d >= '0' && d <= '7' && addr_base == 8) ||
|
|
(d >= '0' && d <= '9' &&
|
|
(addr_base == 10 || addr_base == 16)))
|
|
a = a*addr_base + d - '0';
|
|
else if (d >= 'a' && d <= 'f' && addr_base == 16)
|
|
a = a*addr_base + d + 10 - 'a';
|
|
else
|
|
break;
|
|
}
|
|
if (*s == '.')
|
|
s++;
|
|
if (*s == 'b' || *s == 'B') {
|
|
if (a == 0) {
|
|
/* need offset value when specifying 'b' or 'B' */
|
|
(void) fprintf(stderr, gettext(
|
|
"od: invalid offset %s\n"), offset);
|
|
usage("od");
|
|
}
|
|
++s;
|
|
a *= BSIZE;
|
|
}
|
|
if (*s != '\0') {
|
|
/*
|
|
* Don't disregard invalid trailing characters.
|
|
* Differences between Solaris usage and XPG4 usage are
|
|
* taken care of in main() when get_offset() is called.
|
|
* Solaris:
|
|
* [+][0]offset[.][b|B]
|
|
* [+][0][offset][.]
|
|
* [+][0x|x][offset]
|
|
* [+][0x|x]offset[B]
|
|
* XPG4:
|
|
* [+][0]offset[.][b|B]
|
|
* +[offset][.]
|
|
* [+][0x][offset]
|
|
* [+][0x]offset[B]
|
|
* +x[offset]
|
|
* +xoffset[B]
|
|
*/
|
|
(void) fprintf(stderr, gettext(
|
|
"od: invalid offset %s\n"), offset);
|
|
usage("od");
|
|
}
|
|
return (a);
|
|
}
|
|
|
|
/*
|
|
* COMPONENT_NAME: (LIBCCHR) LIBC Character Classification Funcions
|
|
*
|
|
* FUNCTIONS: mbswidth
|
|
*
|
|
* ORIGINS: 27
|
|
*
|
|
* This module contains IBM CONFIDENTIAL code. -- (IBM
|
|
* Confidential Restricted when combined with the aggregated
|
|
* modules for this product)
|
|
* OBJECT CODE ONLY SOURCE MATERIALS
|
|
* (C) COPYRIGHT International Business Machines Corp. 1991
|
|
* All Rights Reserved
|
|
*
|
|
* US Government Users Restricted Rights - Use, duplication or
|
|
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
*
|
|
* FUNCTION: mbswidth
|
|
*
|
|
* RETURN VALUE: number of bytes in multibyte char
|
|
*
|
|
*/
|
|
|
|
int
|
|
mbswidth(const char *s, size_t n)
|
|
{
|
|
int len;
|
|
wchar_t *wcs;
|
|
int rc;
|
|
char *str_ptr;
|
|
wchar_t wcsbuf[BSIZE/sizeof (wchar_t)+1];
|
|
char strbuf[256];
|
|
|
|
if ((s == (char *)NULL) || (*s == '\0'))
|
|
return ((int)NULL);
|
|
|
|
/*
|
|
* Get the space for the process code. There cannot be more
|
|
* process codes than characters.
|
|
*/
|
|
if ((n + 1) * sizeof (wchar_t) <= sizeof (wcsbuf))
|
|
wcs = wcsbuf;
|
|
else if ((wcs = (wchar_t *) malloc((n+1) *
|
|
sizeof (wchar_t))) == (wchar_t *)NULL) {
|
|
(void) fprintf(stderr, gettext("od: cannot allocate memory: "));
|
|
perror("");
|
|
return ((int)NULL);
|
|
}
|
|
|
|
/* get space for a temp string */
|
|
if ((n + 1) * sizeof (char) <= sizeof (strbuf))
|
|
str_ptr = strbuf;
|
|
else if ((str_ptr = (char *) malloc(n+1)) == (char *)NULL) {
|
|
if (wcs != wcsbuf)
|
|
free(wcs);
|
|
(void) fprintf(stderr, gettext("od: cannot allocate memory: "));
|
|
perror("");
|
|
return ((int)NULL);
|
|
}
|
|
/* copy s into the temp string */
|
|
(void) strncpy(str_ptr, s, n);
|
|
str_ptr[n] = '\0';
|
|
|
|
rc = mbstowcs(wcs, str_ptr, n+1);
|
|
|
|
/* was there an invalid character found */
|
|
if (rc == -1)
|
|
len = -1;
|
|
else
|
|
len = wcswidth(wcs, (size_t)rc+1);
|
|
|
|
/* free up the malloced space */
|
|
if (wcs != wcsbuf)
|
|
free(wcs);
|
|
if (str_ptr != strbuf)
|
|
free(str_ptr);
|
|
|
|
return (len);
|
|
}
|