1
0
Files
irix-657m-src/irix/cmd/netman/lib/pv_stdio.c
2022-09-29 17:59:04 +03:00

340 lines
7.1 KiB
C

/*
* Copyright 1988 Silicon Graphics, Inc. All rights reserved.
*
* A packet viewer based on stdio.
*/
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <termio.h>
#include <time.h>
#include <sys/types.h>
#include <net/raw.h>
#include "heap.h"
#include "macros.h"
#include "packetview.h"
#include "protocol.h"
DefinePacketViewOperations(stdio_pvops,spv)
#define MAXDEPTH 16 /* stack at most 16 frames */
typedef struct {
int prid; /* frame's protocol id */
char *name; /* name and name length */
int namlen;
} StdioViewFrame;
typedef struct {
FILE *file; /* stdio output file */
int indentflag; /* whether to add indentation */
unsigned int indent; /* number of spaces to indent */
unsigned int fieldskip; /* space before next field */
unsigned int columns; /* number of output columns */
unsigned int cursor; /* current column offset */
StdioViewFrame *top; /* frame stack and pointer */
StdioViewFrame stack[MAXDEPTH];
PacketView view; /* base class state */
} StdioPacketView;
#define SPV(pv) ((StdioPacketView *) (pv)->pv_private)
#define PROTONAMEINDENT 4 /* hanging protocol name indent */
#define PROTOFRAMEINDENT 12 /* protocol frame data indent */
#define FIELDWIDTHGRAIN 10 /* field width granularity */
#define DEFAULTCOLUMNS 80 /* used if output not a tty */
static int fieldwidthbasis[] = {
2 * FIELDWIDTHGRAIN, /* PV_TERSE */
2 * FIELDWIDTHGRAIN, /* PV_DEFAULT */
FIELDWIDTHGRAIN, /* PV_VERBOSE */
};
PacketView *
stdio_packetview(FILE *file, char *name, int level)
{
StdioPacketView *spv;
struct winsize ws;
spv = new(StdioPacketView);
spv->file = file;
spv->indentflag = 1;
spv->indent = 0;
spv->fieldskip = 0;
if (ioctl(fileno(file), TIOCGWINSZ, &ws) < 0
|| ws.ws_col < FIELDWIDTHGRAIN) {
spv->columns = DEFAULTCOLUMNS;
} else
spv->columns = ws.ws_col;
spv->cursor = 0;
spv->top = &spv->stack[-1];
pv_init(&spv->view, spv, &stdio_pvops, name, level);
return &spv->view;
}
static void
newline(StdioPacketView *spv)
{
putc('\n', spv->file);
spv->cursor = 0;
spv->indentflag = 1;
spv->fieldskip = 0;
}
static void
breakline(StdioPacketView *spv)
{
if (spv->cursor && spv->cursor != spv->indent)
newline(spv);
}
#define SPACE(spv, count) { \
int n = (count); \
(spv)->cursor += n; \
while (--n >= 0) \
putc(' ', (spv)->file); \
}
static void
indent(StdioPacketView *spv)
{
SPACE(spv, spv->indent);
spv->indentflag = 0;
}
#define CHECKERROR(spv) \
(!ferror((spv)->file) ? 1 \
: (clearerr((spv)->file), (spv)->view.pv_error = errno, 0))
static int
spv_head(PacketView *pv, struct snoopheader *sh, struct tm *tm)
{
StdioPacketView *spv;
FILE *file;
spv = SPV(pv);
file = spv->file;
fprintf(file, "%04lu:%c len %4d time %02d:%02d:%02d.%06ld",
sh->snoop_seq, (sh->snoop_flags & SN_ERROR) ? '!' : ' ',
sh->snoop_packetlen, tm->tm_hour, tm->tm_min, tm->tm_sec,
sh->snoop_timestamp.tv_usec);
if (sh->snoop_flags & SN_ERROR) {
if (sh->snoop_flags & SNERR_FRAME)
fputs(" FRAME", file);
if (sh->snoop_flags & SNERR_CHECKSUM)
fputs(" CHECKSUM", file);
if (sh->snoop_flags & SNERR_TOOBIG)
fputs(" TOOBIG", file);
if (sh->snoop_flags & SNERR_TOOSMALL)
fputs(" TOOSMALL", file);
if (sh->snoop_flags & SNERR_NOBUFS)
fputs(" NOBUFS", file);
if (sh->snoop_flags & SNERR_OVERFLOW)
fputs(" OVERFLOW", file);
if (sh->snoop_flags & SNERR_MEMORY)
fputs(" MEMORY", file);
}
newline(spv);
return CHECKERROR(spv);
}
static int
spv_tail(PacketView *pv)
{
StdioPacketView *spv;
spv = SPV(pv);
breakline(spv);
newline(spv);
fflush(spv->file);
spv->indent = 0;
return CHECKERROR(spv);
}
/* ARGSUSED */
static int
spv_push(PacketView *pv, Protocol *pr, char *name, int namlen, char *title)
{
StdioPacketView *spv;
StdioViewFrame *svf;
int offset;
spv = SPV(pv);
svf = ++spv->top;
if (svf >= &spv->stack[MAXDEPTH])
svf = 0;
else {
svf->prid = pr->pr_id;
svf->name = name;
svf->namlen = namlen;
}
spv->indent = PROTONAMEINDENT;
breakline(spv);
indent(spv);
if (svf && svf > &spv->stack[0]) {
--svf;
if (pr->pr_id == svf->prid) {
fprintf(spv->file, "%s.", svf->name);
spv->cursor += svf->namlen + 1;
}
}
fprintf(spv->file, "%s%c",
name, (pr->pr_flags & PR_DECODESTALE) ? '?' : ':');
namlen++;
offset = spv->cursor + namlen;
spv->indent = PROTOFRAMEINDENT;
if (offset < spv->indent) {
spv->cursor = offset;
SPACE(spv, spv->indent - offset);
} else {
newline(spv);
indent(spv);
}
return CHECKERROR(spv);
}
static int
spv_pop(PacketView *pv)
{
--SPV(pv)->top;
return 1;
}
/* ARGSUSED */
static int
spv_field(PacketView *pv, void *base, int size, ProtoField *pf,
char *contents, int contlen)
{
StdioPacketView *spv;
int minwidth, width, level;
spv = SPV(pv);
if (spv->indentflag)
indent(spv);
minwidth = pf->pf_namlen + 1 + contlen;
width = ROUNDUP(minwidth + 1, FIELDWIDTHGRAIN);
level = MIN(pv->pv_level, PV_VERBOSE);
if (width < fieldwidthbasis[level])
width = fieldwidthbasis[level];
if (spv->cursor + spv->fieldskip + minwidth < spv->columns) {
/* above should be <=, but wsh isn't a vt100 */
SPACE(spv, spv->fieldskip);
} else {
breakline(spv);
if (spv->indentflag)
indent(spv);
}
fputs(pf->pf_name, spv->file); /* pf->pf_namlen */
putc(' ', spv->file); /* 1 */
fputs(contents, spv->file); /* contlen */
spv->cursor += minwidth;
spv->fieldskip = width - minwidth;
return CHECKERROR(spv);
}
static int
spv_break(PacketView *pv)
{
StdioPacketView *spv;
spv = SPV(pv);
breakline(spv);
return CHECKERROR(spv);
}
static int
spv_text(PacketView *pv, char *buf, int len)
{
StdioPacketView *spv;
spv = SPV(pv);
if (spv->indentflag)
indent(spv);
if (fputs(buf, spv->file) == EOF) {
pv->pv_error = errno;
return 0;
}
spv->cursor += len;
return 1;
}
static int
spv_newline(PacketView *pv)
{
StdioPacketView *spv;
spv = SPV(pv);
newline(spv);
return CHECKERROR(spv);
}
static int
spv_hexdump(PacketView *pv, unsigned char *bp, int off, int len)
{
StdioPacketView *spv;
int indent, step, skip, grab, n;
unsigned char *save;
spv = SPV(pv);
if (!spv->indentflag)
newline(spv);
indent = spv->indent;
if (indent < PROTOFRAMEINDENT)
indent = PROTOFRAMEINDENT;
step = (spv->columns - indent - 1) / (3 + 1); /* -1+3+1 */
if (step == 0)
step = 1;
else if (step > 2)
step &= ~01;
indent -= constrlen("ddddd: ");
for (;;) {
fprintf(spv->file, "%*s%05d: ", indent, "", off);
skip = off % step;
for (n = skip; n > 0; --n)
fputs(" ", spv->file);
grab = step - skip;
if (grab > len)
grab = len;
save = bp;
for (n = grab; --n >= 0; bp++)
fprintf(spv->file, "%02x ", *bp); /* 3 */
for (n = step - skip - len; n > 0; --n)
fputs(" ", spv->file);
putc(' ', spv->file); /* -1 */
for (n = skip; n > 0; --n)
putc(' ', spv->file);
bp = save;
for (n = grab; --n >= 0; bp++) {
unsigned char c;
c = isprint(*bp) ? *bp : '.'; /* 1 */
putc(c, spv->file);
}
newline(spv);
len -= grab;
if (len == 0)
break;
off += grab;
}
return CHECKERROR(spv);
}
static void
spv_destroy(PacketView *pv)
{
StdioPacketView *spv;
spv = SPV(pv);
if (spv->cursor)
newline(spv);
fflush(spv->file);
pv_finish(pv);
delete(spv);
}