mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
385 lines
10 KiB
C
385 lines
10 KiB
C
/*
|
|
* Copyright (C) 2014 Martine Lenders <mlenders@inf.fu-berlin.de>
|
|
*
|
|
* This file is subject to the terms and conditions of the GNU Lesser
|
|
* General Public License v2.1. See the file LICENSE in the top level
|
|
* directory for more details.
|
|
*/
|
|
|
|
/**
|
|
* @{
|
|
*
|
|
* @file
|
|
*/
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <inttypes.h>
|
|
|
|
#include "od.h"
|
|
|
|
#define _OCTAL_BYTE_LENGTH (3)
|
|
#define _INT_BYTE_LENGTH (3)
|
|
#define _HEX_BYTE_LENGTH (2)
|
|
|
|
static inline void _address_format(char *format, uint16_t flags)
|
|
{
|
|
switch (flags & OD_FLAGS_ADDRESS_MASK) {
|
|
case OD_FLAGS_ADDRESS_OCTAL:
|
|
strncpy(format, "%09o", sizeof("%09o"));
|
|
break;
|
|
|
|
case OD_FLAGS_ADDRESS_HEX:
|
|
strncpy(format, "%06x", sizeof("%06x"));
|
|
break;
|
|
|
|
case OD_FLAGS_ADDRESS_DECIMAL:
|
|
strncpy(format, "%07d", sizeof("%07d"));
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static inline uint8_t _length(uint16_t flags)
|
|
{
|
|
if (flags & OD_FLAGS_BYTES_CHAR) {
|
|
return 1;
|
|
}
|
|
|
|
switch (flags & OD_FLAGS_LENGTH_MASK) {
|
|
case OD_FLAGS_LENGTH_1:
|
|
return 1;
|
|
|
|
case OD_FLAGS_LENGTH_SHORT:
|
|
return sizeof(short);
|
|
|
|
case OD_FLAGS_LENGTH_2:
|
|
return 2;
|
|
|
|
case OD_FLAGS_LENGTH_LONG:
|
|
return sizeof(long);
|
|
|
|
case OD_FLAGS_LENGTH_8:
|
|
return 8;
|
|
|
|
case OD_FLAGS_LENGTH_4:
|
|
default:
|
|
return 4;
|
|
}
|
|
}
|
|
|
|
static inline void _bytes_format(char *format, uint16_t flags)
|
|
{
|
|
if (flags & OD_FLAGS_BYTES_CHAR) {
|
|
strncpy(format, " %c", sizeof(" %c"));
|
|
return;
|
|
}
|
|
|
|
switch (flags & (OD_FLAGS_BYTES_MASK | OD_FLAGS_LENGTH_MASK)) {
|
|
case OD_FLAGS_BYTES_OCTAL | OD_FLAGS_LENGTH_1:
|
|
strncpy(format, " %03o", sizeof(" %03o"));
|
|
break;
|
|
|
|
case OD_FLAGS_BYTES_OCTAL | OD_FLAGS_LENGTH_2:
|
|
strncpy(format, " %06" PRIo16, sizeof(" %06" PRIo16));
|
|
break;
|
|
|
|
case OD_FLAGS_BYTES_OCTAL | OD_FLAGS_LENGTH_4:
|
|
strncpy(format, " %012" PRIo32, sizeof(" %012" PRIo32));
|
|
break;
|
|
|
|
case OD_FLAGS_BYTES_OCTAL | OD_FLAGS_LENGTH_8:
|
|
strncpy(format, " %024" PRIo64, sizeof(" %024" PRIo64));
|
|
break;
|
|
|
|
#if !defined(__MACH__)
|
|
case OD_FLAGS_BYTES_OCTAL | OD_FLAGS_LENGTH_SHORT:
|
|
sprintf(format, " %%0%do", sizeof(short) * _OCTAL_BYTE_LENGTH);
|
|
break;
|
|
|
|
case OD_FLAGS_BYTES_OCTAL | OD_FLAGS_LENGTH_LONG:
|
|
sprintf(format, " %%0%dlo", sizeof(long) * _OCTAL_BYTE_LENGTH);
|
|
break;
|
|
#else /* !defined(__MACH__) */
|
|
case OD_FLAGS_BYTES_OCTAL | OD_FLAGS_LENGTH_SHORT:
|
|
sprintf(format, " %lu", sizeof(short) * _OCTAL_BYTE_LENGTH);
|
|
break;
|
|
|
|
case OD_FLAGS_BYTES_OCTAL | OD_FLAGS_LENGTH_LONG:
|
|
sprintf(format, " %lu", sizeof(long) * _OCTAL_BYTE_LENGTH);
|
|
break;
|
|
#endif /* !defined(__MACH__) */
|
|
|
|
case OD_FLAGS_BYTES_INT | OD_FLAGS_LENGTH_1:
|
|
strncpy(format, " %4d", sizeof(" %4d"));
|
|
break;
|
|
|
|
case OD_FLAGS_BYTES_INT | OD_FLAGS_LENGTH_2:
|
|
strncpy(format, " %6" PRId16, sizeof(" %6" PRId16));
|
|
break;
|
|
|
|
case OD_FLAGS_BYTES_INT | OD_FLAGS_LENGTH_4:
|
|
strncpy(format, " %12" PRId32, sizeof(" %12" PRId32));
|
|
break;
|
|
|
|
case OD_FLAGS_BYTES_INT | OD_FLAGS_LENGTH_8:
|
|
strncpy(format, " %24" PRId64, sizeof(" %24" PRId64));
|
|
break;
|
|
|
|
#if !defined(__MACH__)
|
|
case OD_FLAGS_BYTES_INT | OD_FLAGS_LENGTH_SHORT:
|
|
sprintf(format, " %%%dd", sizeof(short) * _INT_BYTE_LENGTH);
|
|
break;
|
|
|
|
case OD_FLAGS_BYTES_INT | OD_FLAGS_LENGTH_LONG:
|
|
sprintf(format, " %%%dld", sizeof(long) * _INT_BYTE_LENGTH);
|
|
break;
|
|
#else /* !defined(__MACH__) */
|
|
case OD_FLAGS_BYTES_INT | OD_FLAGS_LENGTH_SHORT:
|
|
sprintf(format, " %%%ld", sizeof(short) * _INT_BYTE_LENGTH);
|
|
break;
|
|
|
|
case OD_FLAGS_BYTES_INT | OD_FLAGS_LENGTH_LONG:
|
|
sprintf(format, " %%%ld", sizeof(long) * _INT_BYTE_LENGTH);
|
|
break;
|
|
#endif /* !defined(__MACH__) */
|
|
|
|
case OD_FLAGS_BYTES_UINT | OD_FLAGS_LENGTH_1:
|
|
strncpy(format, " %3u", sizeof(" %3u"));
|
|
break;
|
|
|
|
case OD_FLAGS_BYTES_UINT | OD_FLAGS_LENGTH_2:
|
|
strncpy(format, " %6" PRIu16, sizeof(" %6" PRIu16));
|
|
break;
|
|
|
|
case OD_FLAGS_BYTES_UINT | OD_FLAGS_LENGTH_4:
|
|
strncpy(format, " %12" PRIu32, sizeof(" %12" PRIu32));
|
|
break;
|
|
|
|
case OD_FLAGS_BYTES_UINT | OD_FLAGS_LENGTH_8:
|
|
strncpy(format, " %24" PRIu64, sizeof(" %24" PRIu64));
|
|
break;
|
|
|
|
#if !defined(__MACH__)
|
|
case OD_FLAGS_BYTES_UINT | OD_FLAGS_LENGTH_SHORT:
|
|
sprintf(format, " %%%uu", (unsigned)sizeof(short) * _INT_BYTE_LENGTH);
|
|
break;
|
|
|
|
case OD_FLAGS_BYTES_UINT | OD_FLAGS_LENGTH_LONG:
|
|
sprintf(format, " %%%ulu", sizeof(long) * _INT_BYTE_LENGTH);
|
|
break;
|
|
#else /* !defined(__MACH__) */
|
|
case OD_FLAGS_BYTES_UINT | OD_FLAGS_LENGTH_SHORT:
|
|
sprintf(format, " %%%lu", sizeof(short) * _INT_BYTE_LENGTH);
|
|
break;
|
|
|
|
case OD_FLAGS_BYTES_UINT | OD_FLAGS_LENGTH_LONG:
|
|
sprintf(format, " %%%lu", sizeof(long) * _INT_BYTE_LENGTH);
|
|
break;
|
|
#endif /* !defined(__MACH__) */
|
|
|
|
case OD_FLAGS_BYTES_HEX | OD_FLAGS_LENGTH_1:
|
|
strncpy(format, " %02x", sizeof(" %02x"));
|
|
break;
|
|
|
|
case OD_FLAGS_BYTES_HEX | OD_FLAGS_LENGTH_2:
|
|
strncpy(format, " %04" PRIx16, sizeof(" %04" PRIx16));
|
|
break;
|
|
|
|
case OD_FLAGS_BYTES_HEX | OD_FLAGS_LENGTH_4:
|
|
strncpy(format, " %08" PRIx32, sizeof(" %08" PRIx32));
|
|
break;
|
|
|
|
case OD_FLAGS_BYTES_HEX | OD_FLAGS_LENGTH_8:
|
|
strncpy(format, " %016" PRIx64, sizeof(" %016" PRIx64));
|
|
break;
|
|
|
|
#if !defined(__MACH__)
|
|
case OD_FLAGS_BYTES_HEX | OD_FLAGS_LENGTH_SHORT:
|
|
sprintf(format, " %%0%ux", (unsigned)sizeof(short) * _HEX_BYTE_LENGTH);
|
|
break;
|
|
|
|
case OD_FLAGS_BYTES_HEX | OD_FLAGS_LENGTH_LONG:
|
|
sprintf(format, " %%0%ulx", (unsigned)sizeof(long) * _HEX_BYTE_LENGTH);
|
|
break;
|
|
#else /* !defined(__MACH__) */
|
|
case OD_FLAGS_BYTES_HEX | OD_FLAGS_LENGTH_SHORT:
|
|
sprintf(format, " %%0%lx", sizeof(short) * _HEX_BYTE_LENGTH);
|
|
break;
|
|
|
|
case OD_FLAGS_BYTES_HEX | OD_FLAGS_LENGTH_LONG:
|
|
sprintf(format, " %%0%lx", sizeof(long) * _HEX_BYTE_LENGTH);
|
|
break;
|
|
#endif /* !defined(__MACH__) */
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void _print_date(const void *data, size_t offset, char *format, uint8_t length,
|
|
uint16_t flags)
|
|
{
|
|
switch (length) {
|
|
case 1:
|
|
if (flags & OD_FLAGS_BYTES_CHAR) {
|
|
switch (((signed char *)data)[offset]) {
|
|
case '\0':
|
|
printf(" \\0");
|
|
return;
|
|
|
|
case '\a':
|
|
printf(" \\a");
|
|
return;
|
|
|
|
case '\b':
|
|
printf(" \\b");
|
|
return;
|
|
|
|
case '\f':
|
|
printf(" \\f");
|
|
return;
|
|
|
|
case '\n':
|
|
printf(" \\n");
|
|
return;
|
|
|
|
case '\r':
|
|
printf(" \\r");
|
|
return;
|
|
|
|
case '\t':
|
|
printf(" \\t");
|
|
return;
|
|
|
|
case '\v':
|
|
printf(" \\v");
|
|
return;
|
|
|
|
default:
|
|
if (((signed char *)data)[offset] < 0) {
|
|
printf(" %03o", ((unsigned char *)data)[offset]);
|
|
return;
|
|
}
|
|
else if (((signed char *)data)[offset] < 32) {
|
|
printf(" %03o", ((char *)data)[offset]);
|
|
return;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
if (flags & OD_FLAGS_BYTES_INT) {
|
|
printf(format, ((int8_t *)data)[offset]);
|
|
}
|
|
else {
|
|
printf(format, ((uint8_t *)data)[offset]);
|
|
}
|
|
|
|
break;
|
|
|
|
case 2:
|
|
if (flags & OD_FLAGS_BYTES_INT) {
|
|
printf(format, ((int16_t *)data)[offset]);
|
|
}
|
|
else {
|
|
printf(format, ((uint16_t *)data)[offset]);
|
|
}
|
|
|
|
break;
|
|
|
|
case 4:
|
|
default:
|
|
if (flags & OD_FLAGS_BYTES_INT) {
|
|
printf(format, ((int32_t *)data)[offset]);
|
|
}
|
|
else {
|
|
printf(format, ((uint32_t *)data)[offset]);
|
|
}
|
|
|
|
break;
|
|
|
|
case 8:
|
|
#ifndef MODULE_NEWLIB
|
|
if (flags & OD_FLAGS_BYTES_INT) {
|
|
printf(format, ((int64_t *)data)[offset]);
|
|
}
|
|
else {
|
|
printf(format, ((uint64_t *)data)[offset]);
|
|
}
|
|
#else
|
|
printf("%s", format);
|
|
#endif
|
|
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
static int _log10(uint8_t a)
|
|
{
|
|
int res = 0;
|
|
|
|
while (a > 0) {
|
|
a /= 10;
|
|
++res;
|
|
}
|
|
|
|
return ++res;
|
|
}
|
|
|
|
void od(const void *data, size_t data_len, uint8_t width, uint16_t flags)
|
|
{
|
|
char address_format[5];
|
|
uint8_t date_length = _length(flags);
|
|
char bytes_format[_log10(date_length) + 7];
|
|
|
|
if (data_len == 0) {
|
|
return;
|
|
}
|
|
|
|
_address_format(address_format, flags);
|
|
_bytes_format(bytes_format, flags);
|
|
|
|
if (width == 0) {
|
|
width = OD_WIDTH_DEFAULT;
|
|
}
|
|
|
|
if (width < date_length) {
|
|
width = 1;
|
|
}
|
|
else {
|
|
width = (width / date_length);
|
|
}
|
|
|
|
if (data_len % date_length) {
|
|
data_len = (data_len / date_length) + 1;
|
|
}
|
|
else {
|
|
data_len = data_len / date_length;
|
|
}
|
|
|
|
if ((flags & OD_FLAGS_ADDRESS_MASK) != OD_FLAGS_ADDRESS_NONE) {
|
|
printf(address_format, 0);
|
|
}
|
|
|
|
for (size_t i = 0; i < data_len; i++) {
|
|
_print_date(data, i, bytes_format, date_length, flags);
|
|
|
|
if ((((i + 1) % width) == 0) || i == (data_len - 1)) {
|
|
printf("\n");
|
|
|
|
if (i != (data_len - 1)) {
|
|
if ((flags & OD_FLAGS_ADDRESS_MASK) != OD_FLAGS_ADDRESS_NONE) {
|
|
printf(address_format, date_length * (i + 1));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/** @} */
|