📄 dump.c
字号:
/* * Support code for the hexdump and od applets, * based on code from util-linux v 2.11l * * Copyright (c) 1989 * The Regents of the University of California. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Original copyright notice is retained at the end of this file. */#include <stdlib.h>#include <string.h>#include <ctype.h> /* for isdigit() */#include "dump.h"#include "libbb.h"enum _vflag vflag = FIRST;FS *fshead; /* head of format strings */extern FS *fshead; /* head of format strings */extern int blocksize;static FU *endfu;static char **_argv;static off_t savaddress; /* saved address/offset in stream */static off_t eaddress; /* end address */static off_t address; /* address/offset in stream */off_t skip; /* bytes to skip */off_t saveaddress;int exitval; /* final exit value */int blocksize; /* data block size */int length = -1; /* max bytes to read */int size(FS *fs){ register FU *fu; register int bcnt, cursize; register char *fmt; int prec; /* figure out the data block size needed for each format unit */ for (cursize = 0, fu = fs->nextfu; fu; fu = fu->nextfu) { if (fu->bcnt) { cursize += fu->bcnt * fu->reps; continue; } for (bcnt = prec = 0, fmt = fu->fmt; *fmt; ++fmt) { if (*fmt != '%') continue; /* * skip any special chars -- save precision in * case it's a %s format. */ while (index(".#-+ 0123456789" + 1, *++fmt)); if (*fmt == '.' && isdigit(*++fmt)) { prec = atoi(fmt); while (isdigit(*++fmt)); } switch(*fmt) { case 'c': bcnt += 1; break; case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': bcnt += 4; break; case 'e': case 'E': case 'f': case 'g': case 'G': bcnt += 8; break; case 's': bcnt += prec; break; case '_': switch(*++fmt) { case 'c': case 'p': case 'u': bcnt += 1; break; } } } cursize += bcnt * fu->reps; } return(cursize);}void rewrite(FS *fs){ enum { NOTOKAY, USEBCNT, USEPREC } sokay; register PR *pr, **nextpr = NULL; register FU *fu; register char *p1, *p2; char savech, *fmtp; int nconv, prec = 0; for (fu = fs->nextfu; fu; fu = fu->nextfu) { /* * break each format unit into print units; each * conversion character gets its own. */ for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) { /* NOSTRICT */ pr = (PR *)xmalloc(sizeof(PR)); if (!fu->nextpr) fu->nextpr = pr; else *nextpr = pr; /* skip preceding text and up to the next % sign */ for (p1 = fmtp; *p1 && *p1 != '%'; ++p1); /* only text in the string */ if (!*p1) { pr->fmt = fmtp; pr->flags = F_TEXT; break; } /* * get precision for %s -- if have a byte count, don't * need it. */ if (fu->bcnt) { sokay = USEBCNT; /* skip to conversion character */ for (++p1; index(".#-+ 0123456789", *p1); ++p1); } else { /* skip any special chars, field width */ while (index(".#-+ 0123456789" + 1, *++p1)); if (*p1 == '.' && isdigit(*++p1)) { sokay = USEPREC; prec = atoi(p1); while (isdigit(*++p1)); } else sokay = NOTOKAY; } p2 = p1 + 1; /* set end pointer */ /* * figure out the byte count for each conversion; * rewrite the format as necessary, set up blank- * padding for end of data. */ switch(*p1) { case 'c': pr->flags = F_CHAR; switch(fu->bcnt) { case 0: case 1: pr->bcnt = 1; break; default: p1[1] = '\0'; error_msg_and_die("bad byte count for conversion character %s.", p1); } break; case 'd': case 'i': pr->flags = F_INT; goto sw1; case 'l': ++p2; switch(p1[1]) { case 'd': case 'i': ++p1; pr->flags = F_INT; goto sw1; case 'o': case 'u': case 'x': case 'X': ++p1; pr->flags = F_UINT; goto sw1; default: p1[2] = '\0'; error_msg_and_die("hexdump: bad conversion character %%%s.\n", p1); } /* NOTREACHED */ case 'o': case 'u': case 'x': case 'X': pr->flags = F_UINT;sw1: switch(fu->bcnt) { case 0: case 4: pr->bcnt = 4; break; case 1: pr->bcnt = 1; break; case 2: pr->bcnt = 2; break; default: p1[1] = '\0'; error_msg_and_die("bad byte count for conversion character %s.", p1); } break; case 'e': case 'E': case 'f': case 'g': case 'G': pr->flags = F_DBL; switch(fu->bcnt) { case 0: case 8: pr->bcnt = 8; break; case 4: pr->bcnt = 4; break; default: p1[1] = '\0'; error_msg_and_die("bad byte count for conversion character %s.", p1); } break; case 's': pr->flags = F_STR; switch(sokay) { case NOTOKAY: error_msg_and_die("%%s requires a precision or a byte count."); case USEBCNT: pr->bcnt = fu->bcnt; break; case USEPREC: pr->bcnt = prec; break; } break; case '_': ++p2; switch(p1[1]) { case 'A': endfu = fu; fu->flags |= F_IGNORE; /* FALLTHROUGH */ case 'a': pr->flags = F_ADDRESS; ++p2; switch(p1[2]) { case 'd': case 'o': case'x': *p1 = p1[2]; break; default: p1[3] = '\0'; error_msg_and_die("hexdump: bad conversion character %%%s.\n", p1); } break; case 'c': pr->flags = F_C; /* *p1 = 'c'; set in conv_c */ goto sw2; case 'p': pr->flags = F_P; *p1 = 'c'; goto sw2; case 'u': pr->flags = F_U; /* *p1 = 'c'; set in conv_u */sw2: switch(fu->bcnt) { case 0: case 1: pr->bcnt = 1; break; default: p1[2] = '\0'; error_msg_and_die("bad byte count for conversion character %s.", p1); } break; default: p1[2] = '\0'; error_msg_and_die("hexdump: bad conversion character %%%s.\n", p1); } break; default: p1[1] = '\0'; error_msg_and_die("hexdump: bad conversion character %%%s.\n", p1); } /* * copy to PR format string, set conversion character * pointer, update original. */ savech = *p2; p1[1] = '\0'; if (!(pr->fmt = strdup(fmtp))) perror_msg_and_die("hexdump"); *p2 = savech; pr->cchar = pr->fmt + (p1 - fmtp); fmtp = p2; /* only one conversion character if byte count */ if (!(pr->flags&F_ADDRESS) && fu->bcnt && nconv++) { error_msg_and_die("hexdump: byte count with multiple conversion characters.\n"); } } /* * if format unit byte count not specified, figure it out * so can adjust rep count later. */ if (!fu->bcnt) for (pr = fu->nextpr; pr; pr = pr->nextpr) fu->bcnt += pr->bcnt; } /* * if the format string interprets any data at all, and it's * not the same as the blocksize, and its last format unit * interprets any data at all, and has no iteration count, * repeat it as necessary. * * if, rep count is greater than 1, no trailing whitespace * gets output from the last iteration of the format unit. */ for (fu = fs->nextfu;; fu = fu->nextfu) { if (!fu->nextfu && fs->bcnt < blocksize && !(fu->flags&F_SETREP) && fu->bcnt) fu->reps += (blocksize - fs->bcnt) / fu->bcnt; if (fu->reps > 1) { for (pr = fu->nextpr;; pr = pr->nextpr) if (!pr->nextpr) break; for (p1 = pr->fmt, p2 = NULL; *p1; ++p1) p2 = isspace(*p1) ? p1 : NULL; if (p2) pr->nospace = p2; } if (!fu->nextfu) break; }}static void doskip(char *fname, int statok){ struct stat sbuf; if (statok) { if (fstat(fileno(stdin), &sbuf)) { perror_msg_and_die("hexdump: %s", fname); } if ( ( ! (S_ISCHR(sbuf.st_mode) || S_ISBLK(sbuf.st_mode) || S_ISFIFO(sbuf.st_mode)) ) && skip >= sbuf.st_size) { /* If size valid and skip >= size */ skip -= sbuf.st_size; address += sbuf.st_size; return; } } if (fseek(stdin, skip, SEEK_SET)) { perror_msg_and_die("hexdump: %s", fname); } savaddress = address += skip; skip = 0;}int next(char **argv){ static int done; int statok; if (argv) { _argv = argv; return(1); } for (;;) { if (*_argv) { if (!(freopen(*_argv, "r", stdin))) { perror_msg("%s", *_argv); 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 u_char *get(void){ static int ateof = 1; static u_char *curp, *savp; register int n; int need, nread; u_char *tmpp; if (!curp) { curp = (u_char *)xmalloc(blocksize); savp = (u_char *)xmalloc(blocksize); } else { tmpp = curp; curp = savp; savp = tmpp; address = savaddress += 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((char **)NULL))) { if (need == blocksize) { return((u_char *)NULL); } if (vflag != ALL && !bcmp(curp, savp, nread)) { if (vflag != DUP) { printf("*\n"); } return((u_char *)NULL); } bzero((char *)curp + nread, need); eaddress = address + nread; return(curp); } n = fread((char *)curp + nread, sizeof(u_char),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -