summaryrefslogtreecommitdiffstats
path: root/tools/rmtool/src/output.c
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-02 10:58:21 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-02 10:58:21 -0400
commitf909a5f822c5c4a4e9526b861d4171f8925f5113 (patch)
treeed362021c83569f49b48079a774f05775e84b0bd /tools/rmtool/src/output.c
parent09f241601423b1ae98e97846ee451768ff8a0a9e (diff)
downloadopen-iov-f909a5f822c5c4a4e9526b861d4171f8925f5113.tar.gz
open-iov-f909a5f822c5c4a4e9526b861d4171f8925f5113.zip
debug: green-eye wave 3 - RM harness, local simulator, device map, MCP plugin, value-validation demos, CI pipeline, toolchain docs; add host RM tools rmtool/rmtop
Diffstat (limited to 'tools/rmtool/src/output.c')
-rw-r--r--tools/rmtool/src/output.c251
1 files changed, 251 insertions, 0 deletions
diff --git a/tools/rmtool/src/output.c b/tools/rmtool/src/output.c
new file mode 100644
index 0000000..6de5d02
--- /dev/null
+++ b/tools/rmtool/src/output.c
@@ -0,0 +1,251 @@
+/* output.c - table/JSON/CSV formatting helpers shared by rmtool commands. */
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "rmtool.h"
+
+enum rm_format rm_format_parse(const char *name)
+{
+ if (name == NULL || strcmp(name, "table") == 0)
+ return RM_FMT_TABLE;
+ if (strcmp(name, "json") == 0)
+ return RM_FMT_JSON;
+ if (strcmp(name, "csv") == 0)
+ return RM_FMT_CSV;
+ return (enum rm_format)-1;
+}
+
+const char *rm_human_kib(NvU64 kib, char *buf, size_t len)
+{
+ if (kib >= 1024ULL * 1024ULL)
+ snprintf(buf, len, "%.2f GiB", (double)kib / (1024.0 * 1024.0));
+ else if (kib >= 1024ULL)
+ snprintf(buf, len, "%.1f MiB", (double)kib / 1024.0);
+ else
+ snprintf(buf, len, "%llu KiB", (unsigned long long)kib);
+ return buf;
+}
+
+static int json_plain_number(const char *value)
+{
+ char *end;
+ double d;
+
+ if (value == NULL || *value == '\0')
+ return 0;
+ d = strtod(value, &end);
+ if (end == value || *end != '\0')
+ return 0;
+ (void)d;
+ return 1;
+}
+
+static void json_string(FILE *out, const char *value)
+{
+ const unsigned char *p = (const unsigned char *)value;
+
+ fputc('"', out);
+ for (; p != NULL && *p != '\0'; p++) {
+ switch (*p) {
+ case '"':
+ fputs("\\\"", out);
+ break;
+ case '\\':
+ fputs("\\\\", out);
+ break;
+ case '\n':
+ fputs("\\n", out);
+ break;
+ case '\r':
+ fputs("\\r", out);
+ break;
+ case '\t':
+ fputs("\\t", out);
+ break;
+ default:
+ if (*p < 0x20)
+ fprintf(out, "\\u%04x", *p);
+ else
+ fputc(*p, out);
+ break;
+ }
+ }
+ fputc('"', out);
+}
+
+static void json_value(FILE *out, const char *value)
+{
+ if (value == NULL) {
+ fputs("null", out);
+ } else if (json_plain_number(value)) {
+ fputs(value, out);
+ } else {
+ json_string(out, value);
+ }
+}
+
+static void csv_value(FILE *out, const char *value)
+{
+ const char *p;
+ int needs_quote = 0;
+
+ if (value == NULL)
+ value = "";
+ for (p = value; *p != '\0'; p++) {
+ if (*p == ',' || *p == '"' || *p == '\n' || *p == '\r') {
+ needs_quote = 1;
+ break;
+ }
+ }
+ if (!needs_quote) {
+ fputs(value, out);
+ return;
+ }
+ fputc('"', out);
+ for (p = value; *p != '\0'; p++) {
+ if (*p == '"')
+ fputc('"', out);
+ fputc(*p, out);
+ }
+ fputc('"', out);
+}
+
+void rm_print_kv(const char *title, const struct rm_kv *kv, int n,
+ enum rm_format format)
+{
+ int i;
+
+ if (format == RM_FMT_JSON) {
+ printf("{\"title\": ");
+ json_string(stdout, title);
+ printf(", \"values\": {");
+ for (i = 0; i < n; i++) {
+ if (i)
+ fputs(", ", stdout);
+ json_string(stdout, kv[i].key);
+ fputs(": ", stdout);
+ json_value(stdout, kv[i].value);
+ }
+ printf("}}\n");
+ return;
+ }
+ if (format == RM_FMT_CSV) {
+ for (i = 0; i < n; i++) {
+ csv_value(stdout, kv[i].key);
+ fputc(',', stdout);
+ csv_value(stdout, kv[i].value);
+ fputc('\n', stdout);
+ }
+ return;
+ }
+ printf("%s\n", title);
+ for (i = 0; i < n; i++)
+ printf(" %-28s %s\n", kv[i].key,
+ kv[i].value ? kv[i].value : "-");
+}
+
+static const char *cell_at(const char *cells, size_t stride, int row,
+ int col, int cols)
+{
+ return cells + (size_t)(row * cols + col) * stride;
+}
+
+void rm_print_table(const char *title, const char *const *headers,
+ const char *cells, size_t stride, int rows, int cols,
+ enum rm_format format)
+{
+ int *width;
+ int r, c;
+
+ if (format == RM_FMT_JSON) {
+ printf("[");
+ for (r = 0; r < rows; r++) {
+ if (r)
+ fputs(", ", stdout);
+ fputc('{', stdout);
+ for (c = 0; c < cols; c++) {
+ if (c)
+ fputs(", ", stdout);
+ json_string(stdout, headers[c]);
+ fputs(": ", stdout);
+ json_value(stdout, cell_at(cells, stride, r,
+ c, cols));
+ }
+ fputc('}', stdout);
+ }
+ printf("]\n");
+ return;
+ }
+ if (format == RM_FMT_CSV) {
+ for (c = 0; c < cols; c++) {
+ if (c)
+ fputc(',', stdout);
+ csv_value(stdout, headers[c]);
+ }
+ fputc('\n', stdout);
+ for (r = 0; r < rows; r++) {
+ for (c = 0; c < cols; c++) {
+ if (c)
+ fputc(',', stdout);
+ csv_value(stdout, cell_at(cells, stride, r,
+ c, cols));
+ }
+ fputc('\n', stdout);
+ }
+ return;
+ }
+ width = calloc((size_t)cols, sizeof(*width));
+ if (width == NULL)
+ return;
+ for (c = 0; c < cols; c++)
+ width[c] = (int)strlen(headers[c]);
+ for (r = 0; r < rows; r++) {
+ for (c = 0; c < cols; c++) {
+ const char *v = cell_at(cells, stride, r, c, cols);
+ int len = v ? (int)strlen(v) : 0;
+
+ if (len > width[c])
+ width[c] = len;
+ }
+ }
+ printf("%s\n", title);
+ for (c = 0; c < cols; c++)
+ printf("%-*s%s", width[c], headers[c],
+ c + 1 < cols ? " " : "\n");
+ for (r = 0; r < rows; r++) {
+ for (c = 0; c < cols; c++)
+ printf("%-*s%s", width[c],
+ cell_at(cells, stride, r, c, cols),
+ c + 1 < cols ? " " : "\n");
+ }
+ free(width);
+}
+
+void rm_hexdump(const void *data, size_t len)
+{
+ const unsigned char *p = data;
+ size_t off;
+
+ for (off = 0; off < len; off += 16) {
+ size_t i;
+
+ printf(" %04zx ", off);
+ for (i = 0; i < 16; i++) {
+ if (off + i < len)
+ printf("%02x ", p[off + i]);
+ else
+ fputs(" ", stdout);
+ if (i == 7)
+ fputc(' ', stdout);
+ }
+ fputs(" |", stdout);
+ for (i = 0; i < 16 && off + i < len; i++) {
+ unsigned char ch = p[off + i];
+
+ fputc(isprint(ch) ? ch : '.', stdout);
+ }
+ puts("|");
+ }
+}