candump/lib: convert to single output buffer
Build the CAN frame ASCII output inside a single (big) buffer as preparation for CAN XL support. This unifies different output modes (fprintf/sprintf/printf) at the time of the CAN frame text generation. Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>pull/504/head
parent
2522ec127b
commit
c6cc7151b7
89
candump.c
89
candump.c
|
|
@ -220,12 +220,16 @@ static int idx2dindex(int ifidx, int socket)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void sprint_timestamp(const char timestamp, const struct timeval *tv,
|
static int sprint_timestamp(char *ts_buffer, const char timestamp,
|
||||||
struct timeval *const last_tv, char *ts_buffer)
|
const struct timeval *tv, struct timeval *const last_tv)
|
||||||
{
|
{
|
||||||
|
int numchars = 0;
|
||||||
|
|
||||||
switch (timestamp) {
|
switch (timestamp) {
|
||||||
case 'a': /* absolute with timestamp */
|
case 'a': /* absolute with timestamp */
|
||||||
sprintf(ts_buffer, "(%010llu.%06llu) ", (unsigned long long)tv->tv_sec, (unsigned long long)tv->tv_usec);
|
numchars = sprintf(ts_buffer, "(%010llu.%06llu) ",
|
||||||
|
(unsigned long long)tv->tv_sec,
|
||||||
|
(unsigned long long)tv->tv_usec);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'A': /* absolute with date */
|
case 'A': /* absolute with date */
|
||||||
|
|
@ -235,7 +239,8 @@ static inline void sprint_timestamp(const char timestamp, const struct timeval *
|
||||||
|
|
||||||
tm = *localtime(&tv->tv_sec);
|
tm = *localtime(&tv->tv_sec);
|
||||||
strftime(timestring, 24, "%Y-%m-%d %H:%M:%S", &tm);
|
strftime(timestring, 24, "%Y-%m-%d %H:%M:%S", &tm);
|
||||||
sprintf(ts_buffer, "(%s.%06llu) ", timestring, (unsigned long long)tv->tv_usec);
|
numchars = sprintf(ts_buffer, "(%s.%06llu) ", timestring,
|
||||||
|
(unsigned long long)tv->tv_usec);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -252,7 +257,9 @@ static inline void sprint_timestamp(const char timestamp, const struct timeval *
|
||||||
diff.tv_sec--, diff.tv_usec += 1000000;
|
diff.tv_sec--, diff.tv_usec += 1000000;
|
||||||
if (diff.tv_sec < 0)
|
if (diff.tv_sec < 0)
|
||||||
diff.tv_sec = diff.tv_usec = 0;
|
diff.tv_sec = diff.tv_usec = 0;
|
||||||
sprintf(ts_buffer, "(%03llu.%06llu) ", (unsigned long long)diff.tv_sec, (unsigned long long)diff.tv_usec);
|
numchars = sprintf(ts_buffer, "(%03llu.%06llu) ",
|
||||||
|
(unsigned long long)diff.tv_sec,
|
||||||
|
(unsigned long long)diff.tv_usec);
|
||||||
|
|
||||||
if (timestamp == 'd')
|
if (timestamp == 'd')
|
||||||
*last_tv = *tv; /* update for delta calculation */
|
*last_tv = *tv; /* update for delta calculation */
|
||||||
|
|
@ -262,15 +269,8 @@ static inline void sprint_timestamp(const char timestamp, const struct timeval *
|
||||||
default: /* no timestamp output */
|
default: /* no timestamp output */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static inline void print_timestamp(const char timestamp, const struct timeval *tv,
|
return numchars;
|
||||||
struct timeval *const last_tv)
|
|
||||||
{
|
|
||||||
static char buffer[TIMESTAMPSZ];
|
|
||||||
|
|
||||||
sprint_timestamp(timestamp, tv, last_tv, buffer);
|
|
||||||
printf("%s", buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
|
|
@ -317,6 +317,8 @@ int main(int argc, char **argv)
|
||||||
FILE *logfile = NULL;
|
FILE *logfile = NULL;
|
||||||
char fname[83]; /* suggested by -Wformat-overflow= */
|
char fname[83]; /* suggested by -Wformat-overflow= */
|
||||||
const char *logname = NULL;
|
const char *logname = NULL;
|
||||||
|
static char abuf[10000]; /* ASCII buf FIXME - use calculated value */
|
||||||
|
static int alen;
|
||||||
|
|
||||||
signal(SIGTERM, sigterm);
|
signal(SIGTERM, sigterm);
|
||||||
signal(SIGHUP, sigterm);
|
signal(SIGHUP, sigterm);
|
||||||
|
|
@ -797,32 +799,29 @@ int main(int argc, char **argv)
|
||||||
extra_info = " R";
|
extra_info = " R";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (log) {
|
/* build common log format output */
|
||||||
char buf[CL_CFSZ]; /* max length */
|
if ((log) || ((logfrmt) && (silent == SILENT_OFF))) {
|
||||||
char ts_buf[TIMESTAMPSZ];
|
|
||||||
|
|
||||||
sprint_timestamp(logtimestamp, &tv, &last_tv, ts_buf);
|
alen = sprint_timestamp(abuf, logtimestamp,
|
||||||
|
&tv, &last_tv);
|
||||||
|
|
||||||
/* log CAN frame with absolute timestamp & device */
|
alen += sprintf(abuf + alen, "%*s ",
|
||||||
sprint_canframe(buf, &frame, 0);
|
max_devname_len, devname[idx]);
|
||||||
fprintf(logfile, "%s%*s %s%s\n", ts_buf,
|
|
||||||
max_devname_len, devname[idx], buf,
|
alen += sprint_canframe(abuf + alen, &frame, 0);
|
||||||
extra_info);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((logfrmt) && (silent == SILENT_OFF)) {
|
/* write CAN frame in log file style to logfile */
|
||||||
char buf[CL_CFSZ]; /* max length */
|
if (log)
|
||||||
|
fprintf(logfile, "%s%s\n", abuf, extra_info);
|
||||||
|
|
||||||
/* print CAN frame in log file style to stdout */
|
/* print CAN frame in log file style to stdout */
|
||||||
sprint_canframe(buf, &frame, 0);
|
if ((logfrmt) && (silent == SILENT_OFF)) {
|
||||||
print_timestamp(logtimestamp, &tv, &last_tv);
|
printf("%s%s\n", abuf, extra_info);
|
||||||
|
|
||||||
printf("%*s %s%s\n",
|
|
||||||
max_devname_len, devname[idx], buf,
|
|
||||||
extra_info);
|
|
||||||
goto out_fflush; /* no other output to stdout */
|
goto out_fflush; /* no other output to stdout */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* print only animation */
|
||||||
if (silent != SILENT_OFF) {
|
if (silent != SILENT_OFF) {
|
||||||
if (silent == SILENT_ANI) {
|
if (silent == SILENT_ANI) {
|
||||||
printf("%c\b", anichar[silentani %= MAXANI]);
|
printf("%c\b", anichar[silentani %= MAXANI]);
|
||||||
|
|
@ -831,25 +830,33 @@ int main(int argc, char **argv)
|
||||||
goto out_fflush; /* no other output to stdout */
|
goto out_fflush; /* no other output to stdout */
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(" %s", (color > 2) ? col_on[idx % MAXCOL] : "");
|
/* print (colored) long CAN frame style to stdout */
|
||||||
print_timestamp(timestamp, &tv, &last_tv);
|
alen = sprintf(abuf, " %s", (color > 2) ? col_on[idx % MAXCOL] : "");
|
||||||
printf(" %s", (color && (color < 3)) ? col_on[idx % MAXCOL] : "");
|
alen += sprint_timestamp(abuf + alen, timestamp, &tv, &last_tv);
|
||||||
printf("%*s", max_devname_len, devname[idx]);
|
alen += sprintf(abuf + alen, " %s%*s",
|
||||||
|
(color && (color < 3)) ? col_on[idx % MAXCOL] : "",
|
||||||
|
max_devname_len, devname[idx]);
|
||||||
|
|
||||||
if (extra_msg_info) {
|
if (extra_msg_info) {
|
||||||
if (msg.msg_flags & MSG_DONTROUTE)
|
if (msg.msg_flags & MSG_DONTROUTE)
|
||||||
printf(" TX %s", extra_m_info[frame.flags & 3]);
|
alen += sprintf(abuf + alen, " TX %s",
|
||||||
|
extra_m_info[frame.flags & 3]);
|
||||||
else
|
else
|
||||||
printf(" RX %s", extra_m_info[frame.flags & 3]);
|
alen += sprintf(abuf + alen, " RX %s",
|
||||||
|
extra_m_info[frame.flags & 3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("%s ", (color == 1) ? col_off : "");
|
alen += sprintf(abuf + alen, "%s ", (color == 1) ? col_off : "");
|
||||||
|
alen += sprint_long_canframe(abuf + alen, &frame, view);
|
||||||
|
|
||||||
fprint_long_canframe(stdout, &frame, NULL, view);
|
if ((view & CANLIB_VIEW_ERROR) && (frame.can_id & CAN_ERR_FLAG)) {
|
||||||
|
alen += sprintf(abuf + alen, "\n\t");
|
||||||
printf("%s", (color > 1) ? col_off : "");
|
alen += snprintf_can_error_frame(abuf + alen,
|
||||||
printf("\n");
|
sizeof(abuf) - alen,
|
||||||
|
&frame, "\n\t");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%s%s\n", abuf, (color > 1) ? col_off : "");
|
||||||
out_fflush:
|
out_fflush:
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
36
lib.c
36
lib.c
|
|
@ -270,7 +270,7 @@ void fprint_canframe(FILE *stream, struct canfd_frame *cf, char *eol, int sep)
|
||||||
fprintf(stream, "%s", eol);
|
fprintf(stream, "%s", eol);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sprint_canframe(char *buf, struct canfd_frame *cf, int sep)
|
int sprint_canframe(char *buf, struct canfd_frame *cf, int sep)
|
||||||
{
|
{
|
||||||
/* documentation see lib.h */
|
/* documentation see lib.h */
|
||||||
|
|
||||||
|
|
@ -317,7 +317,7 @@ void sprint_canframe(char *buf, struct canfd_frame *cf, int sep)
|
||||||
}
|
}
|
||||||
|
|
||||||
buf[offset] = 0;
|
buf[offset] = 0;
|
||||||
return;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* any CAN FD flags */
|
/* any CAN FD flags */
|
||||||
|
|
@ -349,6 +349,8 @@ void sprint_canframe(char *buf, struct canfd_frame *cf, int sep)
|
||||||
}
|
}
|
||||||
|
|
||||||
buf[offset] = 0;
|
buf[offset] = 0;
|
||||||
|
|
||||||
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fprint_long_canframe(FILE *stream, struct canfd_frame *cf, char *eol, int view)
|
void fprint_long_canframe(FILE *stream, struct canfd_frame *cf, char *eol, int view)
|
||||||
|
|
@ -367,7 +369,7 @@ void fprint_long_canframe(FILE *stream, struct canfd_frame *cf, char *eol, int v
|
||||||
fprintf(stream, "%s", eol);
|
fprintf(stream, "%s", eol);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sprint_long_canframe(char *buf, struct canfd_frame *cf, int view)
|
int sprint_long_canframe(char *buf, struct canfd_frame *cf, int view)
|
||||||
{
|
{
|
||||||
/* documentation see lib.h */
|
/* documentation see lib.h */
|
||||||
|
|
||||||
|
|
@ -422,8 +424,8 @@ void sprint_long_canframe(char *buf, struct canfd_frame *cf, int view)
|
||||||
|
|
||||||
/* standard CAN frames may have RTR enabled */
|
/* standard CAN frames may have RTR enabled */
|
||||||
if (cf->can_id & CAN_RTR_FLAG) {
|
if (cf->can_id & CAN_RTR_FLAG) {
|
||||||
sprintf(buf + offset + 5, " remote request");
|
offset += sprintf(buf + offset + 5, " remote request");
|
||||||
return;
|
return offset + 5;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
buf[offset] = '[';
|
buf[offset] = '[';
|
||||||
|
|
@ -477,10 +479,10 @@ void sprint_long_canframe(char *buf, struct canfd_frame *cf, int view)
|
||||||
* Does it make sense to write 64 ASCII byte behind 64 ASCII HEX data on the console?
|
* Does it make sense to write 64 ASCII byte behind 64 ASCII HEX data on the console?
|
||||||
*/
|
*/
|
||||||
if (len > CAN_MAX_DLEN)
|
if (len > CAN_MAX_DLEN)
|
||||||
return;
|
return offset;
|
||||||
|
|
||||||
if (cf->can_id & CAN_ERR_FLAG)
|
if (cf->can_id & CAN_ERR_FLAG)
|
||||||
sprintf(buf + offset, "%*s", dlen * (8 - len) + 13, "ERRORFRAME");
|
offset += sprintf(buf + offset, "%*s", dlen * (8 - len) + 13, "ERRORFRAME");
|
||||||
else if (view & CANLIB_VIEW_ASCII) {
|
else if (view & CANLIB_VIEW_ASCII) {
|
||||||
j = dlen * (8 - len) + 4;
|
j = dlen * (8 - len) + 4;
|
||||||
if (view & CANLIB_VIEW_SWAP) {
|
if (view & CANLIB_VIEW_SWAP) {
|
||||||
|
|
@ -492,7 +494,7 @@ void sprint_long_canframe(char *buf, struct canfd_frame *cf, int view)
|
||||||
else
|
else
|
||||||
buf[offset++] = '.';
|
buf[offset++] = '.';
|
||||||
|
|
||||||
sprintf(buf + offset, "`");
|
offset += sprintf(buf + offset, "`");
|
||||||
} else {
|
} else {
|
||||||
sprintf(buf + offset, "%*s", j, "'");
|
sprintf(buf + offset, "%*s", j, "'");
|
||||||
offset += j;
|
offset += j;
|
||||||
|
|
@ -502,9 +504,11 @@ void sprint_long_canframe(char *buf, struct canfd_frame *cf, int view)
|
||||||
else
|
else
|
||||||
buf[offset++] = '.';
|
buf[offset++] = '.';
|
||||||
|
|
||||||
sprintf(buf + offset, "'");
|
offset += sprintf(buf + offset, "'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *error_classes[] = {
|
static const char *error_classes[] = {
|
||||||
|
|
@ -668,7 +672,7 @@ static int snprintf_error_cnt(char *buf, size_t len, const struct canfd_frame *c
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
void snprintf_can_error_frame(char *buf, size_t len, const struct canfd_frame *cf,
|
int snprintf_can_error_frame(char *buf, size_t len, const struct canfd_frame *cf,
|
||||||
const char* sep)
|
const char* sep)
|
||||||
{
|
{
|
||||||
canid_t class, mask;
|
canid_t class, mask;
|
||||||
|
|
@ -676,12 +680,12 @@ void snprintf_can_error_frame(char *buf, size_t len, const struct canfd_frame *c
|
||||||
char *defsep = ",";
|
char *defsep = ",";
|
||||||
|
|
||||||
if (!(cf->can_id & CAN_ERR_FLAG))
|
if (!(cf->can_id & CAN_ERR_FLAG))
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
class = cf->can_id & CAN_EFF_MASK;
|
class = cf->can_id & CAN_EFF_MASK;
|
||||||
if (class > (1 << ARRAY_SIZE(error_classes))) {
|
if (class > (1 << ARRAY_SIZE(error_classes))) {
|
||||||
fprintf(stderr, "Error class %#x is invalid\n", class);
|
fprintf(stderr, "Error class %#x is invalid\n", class);
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sep)
|
if (!sep)
|
||||||
|
|
@ -695,13 +699,15 @@ void snprintf_can_error_frame(char *buf, size_t len, const struct canfd_frame *c
|
||||||
/* Fix for potential buffer overflow https://lgtm.com/rules/1505913226124/ */
|
/* Fix for potential buffer overflow https://lgtm.com/rules/1505913226124/ */
|
||||||
tmp_n = snprintf(buf + n, len - n, "%s", sep);
|
tmp_n = snprintf(buf + n, len - n, "%s", sep);
|
||||||
if (tmp_n < 0 || (size_t)tmp_n >= len - n) {
|
if (tmp_n < 0 || (size_t)tmp_n >= len - n) {
|
||||||
return;
|
buf[0] = 0; /* empty terminated string */
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
n += tmp_n;
|
n += tmp_n;
|
||||||
}
|
}
|
||||||
tmp_n = snprintf(buf + n, len - n, "%s", error_classes[i]);
|
tmp_n = snprintf(buf + n, len - n, "%s", error_classes[i]);
|
||||||
if (tmp_n < 0 || (size_t)tmp_n >= len - n) {
|
if (tmp_n < 0 || (size_t)tmp_n >= len - n) {
|
||||||
return;
|
buf[0] = 0; /* empty terminated string */
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
n += tmp_n;
|
n += tmp_n;
|
||||||
if (mask == CAN_ERR_LOSTARB)
|
if (mask == CAN_ERR_LOSTARB)
|
||||||
|
|
@ -721,6 +727,8 @@ void snprintf_can_error_frame(char *buf, size_t len, const struct canfd_frame *c
|
||||||
n += snprintf(buf + n, len - n, "%serror-counter-tx-rx", sep);
|
n += snprintf(buf + n, len - n, "%serror-counter-tx-rx", sep);
|
||||||
n += snprintf_error_cnt(buf + n, len - n, cf);
|
n += snprintf_error_cnt(buf + n, len - n, cf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t timespec_diff_ms(struct timespec *ts1,
|
int64_t timespec_diff_ms(struct timespec *ts1,
|
||||||
|
|
|
||||||
6
lib.h
6
lib.h
|
|
@ -161,7 +161,7 @@ int parse_canframe(char *cs, struct canfd_frame *cf);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void fprint_canframe(FILE *stream , struct canfd_frame *cf, char *eol, int sep);
|
void fprint_canframe(FILE *stream , struct canfd_frame *cf, char *eol, int sep);
|
||||||
void sprint_canframe(char *buf , struct canfd_frame *cf, int sep);
|
int sprint_canframe(char *buf , struct canfd_frame *cf, int sep);
|
||||||
/*
|
/*
|
||||||
* Creates a CAN frame hexadecimal output in compact format.
|
* Creates a CAN frame hexadecimal output in compact format.
|
||||||
* The CAN data[] is separated by '.' when sep != 0.
|
* The CAN data[] is separated by '.' when sep != 0.
|
||||||
|
|
@ -197,7 +197,7 @@ void sprint_canframe(char *buf , struct canfd_frame *cf, int sep);
|
||||||
#define SWAP_DELIMITER '`'
|
#define SWAP_DELIMITER '`'
|
||||||
|
|
||||||
void fprint_long_canframe(FILE *stream , struct canfd_frame *cf, char *eol, int view);
|
void fprint_long_canframe(FILE *stream , struct canfd_frame *cf, char *eol, int view);
|
||||||
void sprint_long_canframe(char *buf , struct canfd_frame *cf, int view);
|
int sprint_long_canframe(char *buf , struct canfd_frame *cf, int view);
|
||||||
/*
|
/*
|
||||||
* Creates a CAN frame hexadecimal output in user readable format.
|
* Creates a CAN frame hexadecimal output in user readable format.
|
||||||
*
|
*
|
||||||
|
|
@ -226,7 +226,7 @@ void sprint_long_canframe(char *buf , struct canfd_frame *cf, int view);
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void snprintf_can_error_frame(char *buf, size_t len, const struct canfd_frame *cf,
|
int snprintf_can_error_frame(char *buf, size_t len, const struct canfd_frame *cf,
|
||||||
const char *sep);
|
const char *sep);
|
||||||
/*
|
/*
|
||||||
* Creates a CAN error frame output in user readable format.
|
* Creates a CAN error frame output in user readable format.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue