Commit 9074533a authored by ROOL's avatar ROOL 🤖
Browse files

Add minimalist (text only) libxo implementation

Detail:
  libxo is a printf-like library used by some command line tools which then
  have the option to write output in various textual forms. In the case of the
  disc based utilities only a limited subset of the library functionality is
  required, and this implementation provides only text generation from the
  various xo formatting/command strings.
  Its RISC OS name is xolib, and like UnixLib this is intended to assist in
  porting command line tools that use libxo, rather than being a full
  implementation.
  xo.h - the complete header file from Juniper Networks
  textonly.c - a text only implementation for RISC OS command line tools
Admin:
  Submission for TCP/IP bounty.
parent fa67ab47
......@@ -40,6 +40,12 @@ Echo
Dir <TCPIPLibBuild$Dir>.rpclib.rpc
Obey -c !MkClean
Echo
Echo ** Part 5 of 5: xolib **
Echo
Dir <TCPIPLibBuild$Dir>.xolib
Obey -c !MkClean
UnSet TCPIPLibBuild$Dir
Echo
......
......@@ -17,35 +17,41 @@ Echo Starting full TCPIPLibs build and export...
Set TCPIPLibBuild$Dir <Obey$Dir>
Echo
Echo ** Part 1 of 5: Headers **
Echo ** Part 1 of 6: Headers **
Echo
Dir <TCPIPLibBuild$Dir>.headers
Obey -c !MkExport
Echo
Echo ** Part 2 of 5: inetlib **
Echo ** Part 2 of 6: inetlib **
Echo
Dir <TCPIPLibBuild$Dir>.inetlib
Obey -c !MkExport
Echo
Echo ** Part 3 of 5: socklib **
Echo ** Part 3 of 6: socklib **
Echo
Dir <TCPIPLibBuild$Dir>.socklib
Obey -c !MkExport
Echo
Echo ** Part 4 of 5: unixlib **
Echo ** Part 4 of 6: unixlib **
Echo
Dir <TCPIPLibBuild$Dir>.unixlib
Obey -c !MkExport
Echo
Echo ** Part 5 of 5: rpclib **
Echo ** Part 5 of 6: rpclib **
Echo
Dir <TCPIPLibBuild$Dir>.rpclib.rpc
Obey -c !MkExport
Echo
Echo ** Part 6 of 6: xolib **
Echo
Dir <TCPIPLibBuild$Dir>.xolib
Obey -c !MkExport
UnSet TCPIPLibBuild$Dir
Echo
......
|
| Copyright (c) 2022, RISC OS Open Ltd
| All rights reserved.
|
| Redistribution and use in source and binary forms, with or without
| modification, are permitted provided that the following conditions are met:
| * Redistributions of source code must retain the above copyright
| notice, this list of conditions and the following disclaimer.
| * Redistributions in binary form must reproduce the above copyright
| notice, this list of conditions and the following disclaimer in the
| documentation and/or other materials provided with the distribution.
|
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
| ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
| LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
| CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
| SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
| INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
| CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
| ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
| POSSIBILITY OF SUCH DAMAGE.
|
Dir <Obey$Dir>
amu_machine clean
stripdepnd
|
| Copyright (c) 2022, RISC OS Open Ltd
| All rights reserved.
|
| Redistribution and use in source and binary forms, with or without
| modification, are permitted provided that the following conditions are met:
| * Redistributions of source code must retain the above copyright
| notice, this list of conditions and the following disclaimer.
| * Redistributions in binary form must reproduce the above copyright
| notice, this list of conditions and the following disclaimer in the
| documentation and/or other materials provided with the distribution.
|
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
| ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
| LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
| CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
| SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
| INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
| CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
| ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
| POSSIBILITY OF SUCH DAMAGE.
|
Dir <Obey$Dir>
amu_machine export_hdrs
amu_machine export_libs
Copyright (c) 2014, Juniper Networks
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Copyright (c) 2022, RISC OS Open Ltd
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# Makefile for xolib
#
COMPONENT = xolib
ifeq ($(filter, install%,${MAKECMDGOALS}),)
EXPDIR = ${LIBDIR}${SEP}TCPIPLibs
else
EXPDIR = ${INSTDIR}${SEP}TCPIPLibs
endif
CINCLUDES = ${TCPIPINC}
CFLAGS = ${C_NOWARN_NON_ANSI_INCLUDES}
OBJS = textonly
HDRS = xo
include CLibrary
# Dynamic dependencies:
/*
* Copyright (c) 2022, RISC OS Open Ltd
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stdint.h>
#include "xo.h"
#include "DebugLib/DebugLib.h"
#define UNUSED(k) ((k)=(k))
extern char *__progname; /* Program name */
int xo_parse_args(int argc, char **argv)
{
debug_initialise("xolib", "", NULL);
debug_set_device(PRINTF_OUTPUT);
UNUSED(argv);
return argc; /* Text consumes no args */
}
void xo_set_version(const char *version)
{
UNUSED(version); /* Text has no version */
}
xo_ssize_t xo_open_container(const char *name)
{
UNUSED(name); /* Text isn't containerised */
return 0;
}
xo_ssize_t xo_open_list(const char *name)
{
UNUSED(name); /* No lists */
return 0;
}
xo_ssize_t xo_open_instance(const char *name)
{
UNUSED(name); /* No instances */
return 0;
}
xo_ssize_t xo_close_instance(const char *name)
{
UNUSED(name); /* No instances */
return 0;
}
xo_ssize_t xo_close_list(const char *name)
{
UNUSED(name); /* No lists */
return 0;
}
xo_ssize_t xo_close_container(const char *name)
{
UNUSED(name); /* Text isn't containerised */
return 0;
}
void xo_error(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
}
void xo_message(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vfprintf(stdout, fmt, args);
va_end(args);
}
xo_ssize_t xo_flush(void)
{
fflush(stdout);
return 0;
}
xo_ssize_t xo_finish(void)
{
fflush(stdout);
return 0;
}
#define CONSUME_CHAR(ch,ptr) (ch) = *(ptr); (ptr)++
#define PEEP_CHAR(ch,ptr) (ch) = *(ptr)
#define CHECK_ZERO_END(ch) if ((ch) == '\0') \
{ dprintf(("", "Unexpected end of formatter at line %d\n", __LINE__)); \
goto zeroend; \
}
#define SKIP_XO_FORMAT(ptr) { char temp; \
do { CONSUME_CHAR(temp,ptr); } while (temp != '\0' && temp != '}'); \
if (temp == '\0') fmt--; /* Rewind to terminator */ \
}
typedef enum
{
FIELD_NOT_FOUND,
FIELD_P,
FIELD_32I,
FIELD_64I,
FIELD_C
} field_type_t;
typedef union
{
uint32_t all;
struct
{
uint32_t add_space:1;
uint32_t add_colon:1;
uint32_t add_quote:1;
uint32_t encoding:1;
} flags;
} field_qual_t;
static const char *xo_extract_field(const char **fmt, field_type_t *basefmt)
{
static char field[7] = { '%' }; /* Longest '%llhhx' */
const char *scan = *fmt;
int ch, out = 1, nl = 0, nh = 0;
/* From an xo field, extract the next printf compatible formatter.
* The formatter pointer on entry is at the first character after the % and
* the formatter is known not to be the escaped %% form.
* No flag/width/precision modifiers or floating point.
*/
*basefmt = FIELD_NOT_FOUND;
do
{
/* Consume one formatter character */
ch = *scan; scan++;
*fmt = *fmt + 1;
switch (ch)
{
case 'l':
nl++; if (nl > 2) return ""; /* Too many */
field[out] = 'l'; out++;
break;
case 'h':
nh++; if (nh > 2) return ""; /* Too many */
field[out] = 'h'; out++;
break;
case 0:
default:
break;
case 'o':
case 'u':
case 'd':
case 'i':
case 'x':
case 'X':
*basefmt = (nl < 2) ? FIELD_32I : FIELD_64I;
field[out] = ch; out++;
field[out] = '\0';
return field;
case 'p':
*basefmt = FIELD_P;
return "%p";
case 's':
*basefmt = FIELD_P;
return "%s";
case 'c':
*basefmt = FIELD_C;
return "%c";
}
} while (ch != 0);
return "";
}
xo_ssize_t xo_emit(const char *fmt, ...)
{
xo_ssize_t count = 0;
va_list args;
field_qual_t quals;
char role, c;
const char *fieldfmt;
/* Check for no-op */
if (fmt == NULL) return 0;
va_start(args, fmt);
while (*fmt)
{
CONSUME_CHAR(c, fmt);
if (c == '{')
{
CONSUME_CHAR(role, fmt);
CHECK_ZERO_END(role);
switch (role)
{
case 'E': /* Error */
case 'W': /* Warning */
case '[': /* Start anchor */
case ']': /* Stop anchor */
case 'G': /* Use gettext() */
case 'D': /* Decoration */
case 'L': /* Label prefix */
case 'N': /* Note suffix */
dprintf(("", "Unsupported field '%c' by this xolib\n", role));
SKIP_XO_FORMAT(fmt);
break;
case 'C': /* Colour */
case 'T': /* Title */
case 'U': /* Units */
dprintf(("", "Ignoring field '%c' for text-only output\n", role));
SKIP_XO_FORMAT(fmt);
break;
default:
if (strchr("acdeghklnpqtw", role) == NULL)
{
dprintf(("", "Unrecognised modifier after missing role\n"));
SKIP_XO_FORMAT(fmt);
break;
}
/* Started with a modifier, so set the default role */
role = 'V';
fmt--;
/* Fall through */
case 'P': /* Padding */
case 'V': /* Value */
case ':':
c = role;
quals.all = 0;
while (c != ':')
{
CONSUME_CHAR(c, fmt);
CHECK_ZERO_END(c);
switch (c)
{
case 'd': quals.flags.encoding = 0; break;
case 'e': quals.flags.encoding = 1; break;
default: dprintf(("", "Unsupported modifier '%c' by this xolib\n", c));
break;
}
}
/* Skip any field name */
do
{
CONSUME_CHAR(c, fmt);
CHECK_ZERO_END(c);
if (role == 'P' && c == ' ')
{
putchar(' ');
count++;
}
} while (c != '/' && c != '}');
if (role == 'P' && c == '}') break; /* No default field for padding */
fieldfmt = (c == '/') ? fmt : "%s}"; /* String if no field given */
/* Now process the field format one character at a time */
while (!quals.flags.encoding)
{
CONSUME_CHAR(c, fieldfmt);
CHECK_ZERO_END(c);
if (c == '/' || c == '}') break;
if (c == '%')
{
PEEP_CHAR(c, fieldfmt);
if (c == '%')
{
/* An escaped percent */
fieldfmt++;
putchar('%');
count++;
}
else
{
field_type_t base;
const char *printfmt = xo_extract_field(&fieldfmt, &base);
/* Pop the next arg and print it */
switch (base)
{
case FIELD_P:
count += printf(printfmt, va_arg(args, void *));
break;
case FIELD_C:
count += printf(printfmt, va_arg(args, int));
break;
case FIELD_32I:
count += printf(printfmt, va_arg(args, uint32_t));
break;
case FIELD_64I:
count += printf(printfmt, va_arg(args, uint64_t));
case FIELD_NOT_FOUND:
break;
}
}
continue;
}
putchar(c);
count++;
}
/* Dispose of the encoding format, if any */
do
{
CONSUME_CHAR(c, fmt);
CHECK_ZERO_END(c);
} while (c != '}');
break;
}
}
else
{
putchar(c);
count++;
}
}
zeroend:
va_end(args);
return count;
}
static void do_va_msgx(const char *fmt, va_list args)
{
#ifndef __riscos
int report = errno;
#endif
/* Common tail for warnx and errx */
fprintf(stderr, "%s: ", __progname);
if (fmt)
{
vfprintf(stderr, fmt, args);
fprintf(stderr, ": ");
}
#ifdef __riscos
fprintf(stderr, "%s\n", _inet_err());
#else
fprintf(stderr, "%s\n", strerror(report));
#endif
}
void xo_errx(int eval, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
do_va_msgx(fmt, args);
va_end(args);
exit(eval);
}
void xo_warnx(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
do_va_msgx(fmt, args);
va_end(args);
}
static void do_va_msg(const char *fmt, va_list args)
{
/* Common tail for warnx and errx */
fprintf(stderr, "%s: ", __progname);
if (fmt)
{
vfprintf(stderr, fmt, args);
}
fprintf(stderr, "\n");
}
void xo_err(int eval, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
do_va_msg(fmt, args);
va_end(args);
exit(eval);
}
void xo_warn(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
do_va_msg(fmt, args);
va_end(args);
}
/*
* Copyright (c) 2014-2015, Juniper Networks, Inc.
* All rights reserved.
* This SOFTWARE is licensed under the LICENSE provided in the
* ../Copyright file. By downloading, installing, copying, or otherwise
* using the SOFTWARE, you agree to be bound by the terms of that
* LICENSE.
* Phil Shafer, July 2014
*/
/**
* libxo provides a means of generating text, XML, JSON, and HTML output
* using a single set of function calls, maximizing the value of output
* while minimizing the cost/impact on the code.
*
* Full documentation is available in ./doc/libxo.txt or online at:
* http://juniper.github.io/libxo/libxo-manual.html
*/
#ifndef INCLUDE_XO_H
#define INCLUDE_XO_H
#include <stdio.h>
#include <sys/types.h>
#include <stdarg.h>
#include <limits.h>
#include <stdlib.h>
#ifdef __riscos
#include "sys/errno.h"