Compare commits

..

8 Commits

Author SHA1 Message Date
9268fb8eba help2adoc: fix nawk
All checks were successful
Alpine 3.20 Success
2024-12-31 20:34:48 +01:00
b01df19b80 asciiman: have fewer "unexpected EOF" situations
Some checks failed
Alpine 3.20 Scripts failed
Easily caused by the new help2adoc.
2024-12-31 20:25:51 +01:00
09e635cf97 Add a --help/--version to AsciiDoc convertor
liberty is now self-contained, from opt_handler to manual page.
2024-12-31 20:25:51 +01:00
7560e8700e cmake-parser: improve portability 2024-12-31 06:47:31 +01:00
1930f138d4 IconUtils: add Apple Icon Image format support
All checks were successful
Alpine 3.20 Success
2024-12-17 06:20:12 +01:00
32cbb15266 Serialize integer-ish config keys properly
All checks were successful
Alpine 3.20 Success
2024-12-16 09:09:03 +01:00
149938cc44 lxdrgen-cpp: add a Qt backend
All checks were successful
Alpine 3.20 Success
Motivation: some Android NDKs do not have iconv.
2024-12-15 06:44:06 +01:00
62f8a7d05f lxdrgen-cpp: fix test build on macOS
All checks were successful
Alpine 3.20 Success
2024-12-04 17:44:30 +01:00
10 changed files with 554 additions and 23 deletions

View File

@@ -2,6 +2,7 @@ cmake_minimum_required (VERSION 3.0...3.27)
project (liberty C CXX) project (liberty C CXX)
# Moar warnings # Moar warnings
set (CMAKE_CXX_STANDARD 11)
if ("${CMAKE_C_COMPILER_ID}" MATCHES "GNU" OR CMAKE_COMPILER_IS_GNUCC) if ("${CMAKE_C_COMPILER_ID}" MATCHES "GNU" OR CMAKE_COMPILER_IS_GNUCC)
# -Wunused-function is pretty annoying here, as everything is static # -Wunused-function is pretty annoying here, as everything is static
set (wdisabled "-Wno-unused-function") set (wdisabled "-Wno-unused-function")
@@ -9,7 +10,7 @@ if ("${CMAKE_C_COMPILER_ID}" MATCHES "GNU" OR CMAKE_COMPILER_IS_GNUCC)
endif () endif ()
# Dependencies # Dependencies
set (CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) set (CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
include (AddThreads) include (AddThreads)
find_package (PkgConfig REQUIRED) find_package (PkgConfig REQUIRED)
@@ -34,7 +35,7 @@ foreach (extra iconv rt)
endforeach () endforeach ()
# Build some unit tests # Build some unit tests
include_directories (${PROJECT_SOURCE_DIR}) include_directories ("${PROJECT_SOURCE_DIR}")
enable_testing () enable_testing ()
set (tests liberty proto xdg) set (tests liberty proto xdg)
@@ -56,7 +57,7 @@ endforeach ()
# --- Tools -------------------------------------------------------------------- # --- Tools --------------------------------------------------------------------
# Test the AsciiDoc manual page generator for a successful parse # Test the AsciiDoc manual page generator for a successful parse
set (ASCIIMAN ${PROJECT_SOURCE_DIR}/tools/asciiman.awk) set (ASCIIMAN "${PROJECT_SOURCE_DIR}/tools/asciiman.awk")
add_custom_command (OUTPUT libertyxdr.7 add_custom_command (OUTPUT libertyxdr.7
COMMAND env LC_ALL=C awk -f ${ASCIIMAN} COMMAND env LC_ALL=C awk -f ${ASCIIMAN}
"${PROJECT_SOURCE_DIR}/libertyxdr.adoc" > libertyxdr.7 "${PROJECT_SOURCE_DIR}/libertyxdr.adoc" > libertyxdr.7
@@ -64,10 +65,14 @@ add_custom_command (OUTPUT libertyxdr.7
COMMENT "Generating man page for libertyxdr" VERBATIM) COMMENT "Generating man page for libertyxdr" VERBATIM)
add_custom_target (docs ALL DEPENDS libertyxdr.7) add_custom_target (docs ALL DEPENDS libertyxdr.7)
# Test the --help/--version to AsciiDoc convertor
add_test (test-help2adoc
env LC_ALL=C "${PROJECT_SOURCE_DIR}/tests/help2adoc.sh")
# Test CMake script parsing # Test CMake script parsing
add_test (test-cmake-parser add_test (test-cmake-parser
env LC_ALL=C awk -f ${PROJECT_SOURCE_DIR}/tools/cmake-parser.awk env LC_ALL=C awk -f "${PROJECT_SOURCE_DIR}/tools/cmake-parser.awk"
-f ${PROJECT_SOURCE_DIR}/tools/cmake-dump.awk ${CMAKE_CURRENT_LIST_FILE}) -f "${PROJECT_SOURCE_DIR}/tools/cmake-dump.awk" ${CMAKE_CURRENT_LIST_FILE})
# Test protocol code generation # Test protocol code generation
set (lxdrgen_outputs) set (lxdrgen_outputs)
@@ -76,15 +81,15 @@ foreach (backend c cpp go mjs swift)
list (APPEND lxdrgen_outputs ${lxdrgen_base}.${backend}) list (APPEND lxdrgen_outputs ${lxdrgen_base}.${backend})
add_custom_command (OUTPUT ${lxdrgen_base}.${backend} add_custom_command (OUTPUT ${lxdrgen_base}.${backend}
COMMAND env LC_ALL=C awk COMMAND env LC_ALL=C awk
-f ${PROJECT_SOURCE_DIR}/tools/lxdrgen.awk -f "${PROJECT_SOURCE_DIR}/tools/lxdrgen.awk"
-f ${PROJECT_SOURCE_DIR}/tools/lxdrgen-${backend}.awk -f "${PROJECT_SOURCE_DIR}/tools/lxdrgen-${backend}.awk"
-v PrefixCamel=ProtoGen -v PrefixCamel=ProtoGen
${PROJECT_SOURCE_DIR}/tests/lxdrgen.lxdr "${PROJECT_SOURCE_DIR}/tests/lxdrgen.lxdr"
> ${lxdrgen_base}.${backend} > ${lxdrgen_base}.${backend}
DEPENDS DEPENDS
${PROJECT_SOURCE_DIR}/tools/lxdrgen.awk "${PROJECT_SOURCE_DIR}/tools/lxdrgen.awk"
${PROJECT_SOURCE_DIR}/tools/lxdrgen-${backend}.awk "${PROJECT_SOURCE_DIR}/tools/lxdrgen-${backend}.awk"
${PROJECT_SOURCE_DIR}/tests/lxdrgen.lxdr "${PROJECT_SOURCE_DIR}/tests/lxdrgen.lxdr"
COMMENT "Generating test protocol code (${backend})" VERBATIM) COMMENT "Generating test protocol code (${backend})" VERBATIM)
endforeach () endforeach ()
add_custom_target (test-lxdrgen-outputs ALL DEPENDS ${lxdrgen_outputs}) add_custom_target (test-lxdrgen-outputs ALL DEPENDS ${lxdrgen_outputs})
@@ -104,6 +109,7 @@ else ()
add_executable (test-lxdrgen-cpp tests/lxdrgen.cpp add_executable (test-lxdrgen-cpp tests/lxdrgen.cpp
${lxdrgen_base}.cpp tools/lxdrgen-cpp-posix.cpp) ${lxdrgen_base}.cpp tools/lxdrgen-cpp-posix.cpp)
endif () endif ()
target_link_libraries (test-lxdrgen-cpp ${common_libraries})
target_include_directories (test-lxdrgen-cpp PUBLIC ${PROJECT_BINARY_DIR}) target_include_directories (test-lxdrgen-cpp PUBLIC ${PROJECT_BINARY_DIR})
add_test (NAME test-lxdrgen-cpp COMMAND test-lxdrgen-cpp) add_test (NAME test-lxdrgen-cpp COMMAND test-lxdrgen-cpp)

View File

@@ -36,6 +36,9 @@ cmake-dump.awk::
This can be used in conjunction with the previous script to dump CMake This can be used in conjunction with the previous script to dump CMake
scripts in a normalized format for further processing. scripts in a normalized format for further processing.
help2adoc.awk::
Produces AsciiDoc manual pages from --version/--help output.
lxdrgen.awk:: lxdrgen.awk::
Protocol code generator for a variant of XDR, Protocol code generator for a variant of XDR,
which is link:libertyxdr.adoc[documented separately]. which is link:libertyxdr.adoc[documented separately].
@@ -45,8 +48,9 @@ lxdrgen-c.awk::
LibertyXDR backend that builds on top of the C pseudolibrary. LibertyXDR backend that builds on top of the C pseudolibrary.
lxdrgen-cpp.awk:: lxdrgen-cpp.awk::
lxdrgen-cpp-win32.cpp::
lxdrgen-cpp-posix.cpp:: lxdrgen-cpp-posix.cpp::
lxdrgen-cpp-qt.cpp::
lxdrgen-cpp-win32.cpp::
LibertyXDR backend for C++, primarily targeting Win32 and its wide strings. LibertyXDR backend for C++, primarily targeting Win32 and its wide strings.
Link the result together with one of the accompanied source files. Link the result together with one of the accompanied source files.

View File

@@ -38,3 +38,47 @@ function (icon_for_win32 ico pngs pngs_raw)
DEPENDS ${pngs} ${pngs_raw} DEPENDS ${pngs} ${pngs_raw}
COMMENT "Generating Windows program icon" VERBATIM) COMMENT "Generating Windows program icon" VERBATIM)
endfunction () endfunction ()
function (icon_to_iconset_size name svg size iconset outputs)
math (EXPR _size2x "${size} * 2")
set (_dimensions "${size}x${size}")
set (_png1x "${iconset}/icon_${_dimensions}.png")
set (_png2x "${iconset}/icon_${_dimensions}@2x.png")
set (${outputs} "${_png1x};${_png2x}" PARENT_SCOPE)
set (_find_program_REQUIRE)
if (NOT ${CMAKE_VERSION} VERSION_LESS 3.18.0)
set (_find_program_REQUIRE REQUIRED)
endif ()
find_program (rsvg_convert_EXECUTABLE rsvg-convert ${_find_program_REQUIRE})
add_custom_command (OUTPUT "${_png1x}" "${_png2x}"
COMMAND ${CMAKE_COMMAND} -E make_directory "${iconset}"
COMMAND ${rsvg_convert_EXECUTABLE} "--output=${_png1x}"
"--width=${size}" "--height=${size}" -- "${svg}"
COMMAND ${rsvg_convert_EXECUTABLE} "--output=${_png2x}"
"--width=${_size2x}" "--height=${_size2x}" -- "${svg}"
DEPENDS "${svg}"
COMMENT "Generating ${name} ${_dimensions} icons" VERBATIM)
endfunction ()
function (icon_to_icns svg output_basename output)
get_filename_component (_name "${output_basename}" NAME_WE)
set (_iconset "${PROJECT_BINARY_DIR}/${_name}.iconset")
set (_icon "${PROJECT_BINARY_DIR}/${output_basename}")
set (${output} "${_icon}" PARENT_SCOPE)
set (_icon_png_list)
foreach (_icon_size 16 32 128 256 512)
icon_to_iconset_size ("${_name}" "${svg}"
"${_icon_size}" "${_iconset}" _icon_pngs)
list (APPEND _icon_png_list ${_icon_pngs})
endforeach ()
# XXX: This will not normally work from within Nix.
add_custom_command (OUTPUT "${_icon}"
COMMAND iconutil -c icns -o "${_icon}" "${_iconset}"
DEPENDS ${_icon_png_list}
COMMENT "Generating ${_name} icon" VERBATIM)
set_source_files_properties ("${_icon}" PROPERTIES
MACOSX_PACKAGE_LOCATION Resources)
endfunction ()

View File

@@ -4833,7 +4833,8 @@ config_item_write_kv_pair (struct config_writer *self,
str_append_printf (self->output, str_append_printf (self->output,
"%s# %s\n", indent, value->schema->comment); "%s# %s\n", indent, value->schema->comment);
bool can_use_word = true; char *end = NULL;
bool can_use_word = ((void) strtoll (key, &end, 10), end == key);
for (const char *p = key; *p; p++) for (const char *p = key; *p; p++)
if (!config_tokenizer_is_word_char (*p)) if (!config_tokenizer_is_word_char (*p))
can_use_word = false; can_use_word = false;

214
tests/help2adoc.sh Executable file
View File

@@ -0,0 +1,214 @@
#!/bin/sh -e
# This test very exactly matches the output,
# but help2adoc is more or less feature-complete already.
self=$(realpath "$0")
help2adoc=$(realpath "$(dirname "$0")/../tools/help2adoc.awk")
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
test_oneline_help() {
cat <<END
Usage: $self [--brightness [+-]BRIGHTNESS] [--input NAME] [--restart]
END
}
test_oneline_version() {
cat <<'END'
eizoctl 1.0
END
}
test_oneline_out() {
cat <<'END'
eizoctl(1)
==========
:doctype: manpage
:manmanual: eizoctl Manual
:mansource: eizoctl 1.0
Name
----
eizoctl - manual page for eizoctl 1.0
Synopsis
--------
*eizoctl* [**--brightness** [+-]__BRIGHTNESS__] [**--input** __NAME__] [**--restart**]
END
}
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
test_simple_help() {
cat <<'END'
Usage: elksmart-comm [OPTION]... [COMMAND...]
Usage: elksmart-comm
Transmit or receive infrared commands.
-d, --debug elksmart-comm will run in debug mode
-f, --frequency HZ frequency (38000 Hz by default)
-n, --nec use the NEC transmission format
-h, --help display this help and exit
-V, --version output version information and exit
END
}
test_simple_version() {
cat <<'END'
elksmart-comm (usb-drivers) dev
END
}
test_simple_out() {
cat <<'END'
elksmart-comm(1)
================
:doctype: manpage
:manmanual: elksmart-comm Manual
:mansource: usb-drivers dev
Name
----
elksmart-comm - manual page for elksmart-comm dev
Synopsis
--------
*elksmart-comm* [__OPTION__]... [__COMMAND__...]
*elksmart-comm*
Description
-----------
Transmit or receive infrared commands.
*-d*, **--debug**::
**elksmart-comm** will run in debug mode
*-f*, **--frequency** __HZ__::
frequency (38000 Hz by default)
*-n*, **--nec**::
use the NEC transmission format
*-h*, **--help**::
display this help and exit
*-V*, **--version**::
output version information and exit
END
}
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
test_wild_help() {
cat <<'END'
Usage:
wild [option]… <command>… — Be wild
What's happening?
-f, --frequency hz-2-foo frequency to --foo at
--foo=bar
Foobar.
Boo far.
Subsection:
--help
--version
Oh my.
Major section:
And now for something completely different.
Very wild
END
}
test_wild_version() {
cat <<'END'
wild 1
Copies left and right.
END
}
test_wild_out() {
cat <<'END'
wild(1)
=======
:doctype: manpage
:manmanual: wild Manual
:mansource: wild 1
Name
----
wild - manual page for wild 1
Synopsis
--------
*wild* [__option__]... <__command__>...
Description
-----------
Be **wild**
What's happening?
*-f*, **--frequency** __hz-2-foo__::
frequency to **--foo** at
*--foo*=__bar__::
Foobar.
Boo far.
Subsection
~~~~~~~~~~
*--help*::
*--version*::
Oh my.
Major section
-------------
And now for something completely different.
Very wild
END
}
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
run() {
echo "-- help2adoc/$1"
local selfquoted=$(echo "$self" | sed 's/\\/&&/g')
local output=$(TEST=$1 awk -f "$help2adoc" -v Target="$selfquoted")
local expect="$($1_out)"
if [ "$output" = "$expect" ]
then return
fi
echo "== Expected"
sed 's/^/ /' <<-END
$expect
END
echo "== Received"
sed 's/^/ /' <<-END
$output
END
exit 1
}
if [ -z "$TEST" ]
then
run test_oneline
run test_simple
run test_wild
echo "-- OK"
elif [ "$1" = "--help" ]
then ${TEST}_help
elif [ "$1" = "--version" ]
then ${TEST}_version
else
echo "Wrong usage"
exit 1
fi

View File

@@ -647,7 +647,7 @@ static const struct config_schema g_config_test[] =
.type = CONFIG_ITEM_INTEGER, .type = CONFIG_ITEM_INTEGER,
.validate = test_config_validate_nonnegative, .validate = test_config_validate_nonnegative,
.default_ = "1" }, .default_ = "1" },
{ .name = "foobar", { .name = "123",
.type = CONFIG_ITEM_STRING, .type = CONFIG_ITEM_STRING,
.default_ = "\"qux\\x01`\" \"\"`a`" }, .default_ = "\"qux\\x01`\" \"\"`a`" },
{} {}
@@ -676,10 +676,11 @@ test_config (void)
config_item_destroy (invalid); config_item_destroy (invalid);
hard_assert (!strcmp ("qux\001`a", hard_assert (!strcmp ("qux\001`a",
config_item_get (config.root, "top.foobar", NULL)->value.string.str)); config_item_get (config.root, "top.123", NULL)->value.string.str));
struct str s = str_make (); struct str s = str_make ();
config_item_write (config.root, true, &s); config_item_write (config.root, true, &s);
print_debug ("%s", s.str);
struct config_item *parsed = config_item_parse (s.str, s.len, false, NULL); struct config_item *parsed = config_item_parse (s.str, s.len, false, NULL);
hard_assert (parsed); hard_assert (parsed);
config_item_destroy (parsed); config_item_destroy (parsed);

View File

@@ -200,7 +200,7 @@ function inline(line) {
} }
# Returns 1 iff the left-over $0 should be processed further. # Returns 1 iff the left-over $0 should be processed further.
function process(firstline, posattrs, namedattrs) { function process(firstline, posattrs, namedattrs, ok) {
if (readattribute(firstline)) if (readattribute(firstline))
return 0 return 0
if (getline <= 0) { if (getline <= 0) {
@@ -281,9 +281,11 @@ function process(firstline, posattrs, namedattrs) {
while ($0) { while ($0) {
sub(/^[[:space:]]+/, "") sub(/^[[:space:]]+/, "")
sub(/^[+]$/, "") sub(/^[+]$/, "")
if (!process($0) && getline <= 0) if (!process($0) && (ok = getline) <= 0) {
fatal("unexpected EOF") if (ok < 0)
if (match($0, /^[[:space:]]*[*][[:space:]]+/)) fatal("getline failed")
$0 = ""
} else if (match($0, /^[[:space:]]*[*][[:space:]]+/))
break break
} }
print ".RE" print ".RE"
@@ -318,9 +320,11 @@ function process(firstline, posattrs, namedattrs) {
while ($0) { while ($0) {
sub(/^[[:space:]]+/, "") sub(/^[[:space:]]+/, "")
sub(/^[+]$/, "") sub(/^[+]$/, "")
if (!process($0) && getline <= 0) if (!process($0) && (ok = getline) <= 0) {
fatal("unexpected EOF") if (ok < 0)
if (match($0, /::$/)) fatal("getline failed")
$0 = ""
} else if (match($0, /::$/))
break break
} }
print ".RE" print ".RE"

View File

@@ -75,7 +75,7 @@ function line_ending() {
# it doesn't seem to be worth the effort. # it doesn't seem to be worth the effort.
function expand(s, v) { function expand(s, v) {
v = s v = s
while (match(v, /\\*[$](|ENV|CACHE)[{]/)) { while (match(v, /\\*[$](ENV|CACHE)?[{]/)) {
if (index(substr(v, RSTART), "$") % 2 != 0) { if (index(substr(v, RSTART), "$") % 2 != 0) {
warning("variable expansion is not supported: " s) warning("variable expansion is not supported: " s)
return s return s

234
tools/help2adoc.awk Normal file
View File

@@ -0,0 +1,234 @@
# help2adoc.awk: convert --version/--help to AsciiDoc manual pages
#
# Copyright (c) 2024, Přemysl Eric Janouch <p@janouch.name>
# SPDX-License-Identifier: 0BSD
#
# Usage: awk -f help2adoc.awk -v Target=cat
#
# This is not intended to produce great output, merely useful output,
# if only because there is no real standard of what the input should look like.
#
# The only target that needs to work is liberty's own opt_handler.
# The expected input format is roughly that of GNU utilites.
function fatal(message) {
print "// " message
print "fatal error: " message > "/dev/stderr"
exit 1
}
# The input model of this script is that function take the next line on $0,
# read further lines as necessary, and leave the next line in $0 again.
function readline( ok) {
if ((ok = (Command | getline)) < 0)
fatal("read error")
if (!ok)
exit
}
function emboldenoptions(line) {
# -N, --newer=DATE-OR-FILE, --after-date=DATE-OR-FILE
sub(/^-[^-=,[:space:]{[<]/, "*&*", line)
while (match(line, /[^-_[:alnum:]*'+]-[^-=,[:space:]{[<]/)) {
line = substr(line, 1, RSTART) \
"**" substr(line, RSTART + 1, RLENGTH - 1) "**" \
substr(line, RSTART + RLENGTH)
}
sub(/^--[-_[:alnum:]]+/, "*&*", line)
while (match(line, /[^-_[:alnum:]*'+]--[-_[:alnum:]]+/)) {
line = substr(line, 1, RSTART) \
"**" substr(line, RSTART + 1, RLENGTH - 1) "**" \
substr(line, RSTART + RLENGTH)
}
return line
}
function formatinline(line, programname, last, i) {
# Go the extra step of emboldening the program name at word boundaries.
programname = ProgramName
gsub(/[][\\.^$(){}|*+?]/, "\\\\&", programname)
if (match(line, "^" programname "[^-_[:alnum:]*'+/]")) {
line = "**" substr(line, RSTART, RLENGTH - 1) "**" \
substr(line, RSTART + RLENGTH - 1)
}
while (match(line, "[^-_[:alnum:]*'+/]" programname "[^-_[:alnum:]*'+/]")) {
line = substr(line, 1, RSTART) \
"**" substr(line, RSTART + 1, RLENGTH - 2) "**" \
substr(line, RSTART + RLENGTH - 1)
}
if (match(line, "[^-_[:alnum:]*'+/]" programname "$")) {
line = substr(line, 1, RSTART) \
"**" substr(line, RSTART + 1, RLENGTH - 1) "**"
}
return emboldenoptions(line)
}
function printusage(usage, description) {
gsub(/…/, "...", usage)
gsub(/—|/, "-", usage)
# --help output will more likely than not simply include argv[0],
# or perhaps program_invocation_short_name (not addressed here).
if (substr(usage, 1, length(Target) + 1) == Target " ")
usage = ProgramName substr(usage, length(Target) + 1)
# A lot of GNOME software includes the description here.
if (match(usage, / +- +/) && usage !~ / - [^[:alnum:]]/) {
description = substr(usage, RSTART + RLENGTH)
usage = substr(usage, 1, RSTART - 1)
}
while (match(usage, /[^-_[:alnum:]*'+.][[:alnum:]][-_[:alnum:]]+/)) {
usage = substr(usage, 1, RSTART) \
"__" substr(usage, RSTART + 1, RLENGTH - 1) "__" \
substr(usage, RSTART + RLENGTH)
}
sub(/^[^[:space:]]+/, "*&*", usage)
print emboldenoptions(usage)
print ""
if (description) {
flushsections()
print formatinline(description)
print ""
}
}
# We're going with Setext headers, because that's what asciiman.awk supports.
function printheader(text, underline) {
print text
gsub(/./, underline, text)
print text
}
BEGIN {
if (!Target)
fatal("missing Target")
TargetQuoted = Target
gsub(/'/, "'\\''", TargetQuoted)
TargetQuoted = "'" TargetQuoted "'"
# Remaining --version lines could be about copyright (GNU),
# or something else entirely.
Command = TargetQuoted " --version"
if ((Command | getline) > 0) {
# GNU --version output can place the package name in parentheses.
Package = $0
if (match($0, /[[:space:]][(][^)]*[)]/)) {
Package = substr($0, RSTART + 2, RLENGTH - 3) \
substr($0, RSTART + RLENGTH)
sub(/[[:space:]]+[(][^)]*[)]/, "")
}
Version = $0
sub(/[[:space:]]+[^[:space:]]+$/, "")
Name = $0
} else {
fatal("failed to get --version output")
}
if (Name !~ /[[:space:]]/)
ProgramName = Name
else if (match(Target, /[^\/]+$/))
ProgramName = substr(Target, RSTART, RLENGTH)
printheader(ProgramName "(1)", "=")
print ":doctype: manpage"
print ":manmanual: " Name " Manual"
print ":mansource: " Package
print ""
printheader("Name", "-")
print ProgramName " - manual page for " Version
print ""
close(Command)
Command = TargetQuoted " --help"
if ((Command | getline) <= 0)
fatal("failed to get --help output")
NextSection = "Description"
NextSubsection = ""
# The SYNOPSIS section is mandatory, so just put it there.
printheader("Synopsis", "-")
while (1) {
if (match($0, /^[Uu]sage:[[:space:]]*/)) {
if (($0 = substr($0, RSTART + RLENGTH)))
printusage($0)
} else if (match($0, /^[[:space:]]+/) && !/^[[:space:]]*-/) {
if (($0 = substr($0, RSTART + RLENGTH)))
printusage($0)
} else if ($0) {
break
}
readline()
}
while (1) {
if (match($0, /^[[:alpha:]][-[:alnum:][:space:]]+:$/)) {
# We don't flush sections here,
# so that we don't unnecessarily enforce DESCRIPTION first.
NextSection = substr($0, RSTART, RLENGTH - 1)
} else if (match($0, /^ [[:alpha:]][-[:alnum:][:space:]]+:$/)) {
flushsections()
NextSubsection = substr($0, RSTART + 1, RLENGTH - 2)
} else if (match($0, /^ +-/)) {
flushsections()
parseoption(substr($0, RSTART + RLENGTH - 1))
continue
} else if ($0) {
flushsections()
# That will be probably interpreted as a literal block.
if (!/^[[:space:]]/)
$0 = formatinline($0)
print
} else {
print
}
readline()
}
}
function flushsections() {
if (NextSection) {
print ""
printheader(NextSection, "-")
NextSection = ""
}
if (NextSubsection) {
print ""
printheader(NextSubsection, "~")
NextSubsection = ""
}
}
function parseoption(line, usage) {
# Often enough you will see it separated with only one space,
# which will simply not work for us.
if (match(line, /[[:space:]]{2,}/)) {
usage = substr(line, 1, RSTART - 1)
line = substr(line, RSTART + RLENGTH)
} else {
usage = line
line = ""
}
usage = emboldenoptions(usage)
while (match(usage, /[=<, ][[:alnum:]][-_[:alnum:]]*/)) {
usage = substr(usage, 1, RSTART) \
"__" substr(usage, RSTART + 1, RLENGTH - 1) "__" \
substr(usage, RSTART + RLENGTH)
}
print ""
print usage "::"
if (line)
print "\t" formatinline(line)
readline()
while (match($0, /^ +[^-[:space:]]|^ {7,}./)) {
print "\t" formatinline(substr($0, RSTART + RLENGTH - 1))
readline()
}
}

23
tools/lxdrgen-cpp-qt.cpp Normal file
View File

@@ -0,0 +1,23 @@
// lxdrgen-cpp-qt.cpp: Qt support code for lxdrgen-cpp.awk.
//
// Copyright (c) 2024, Přemysl Eric Janouch <p@janouch.name>
// SPDX-License-Identifier: 0BSD
#include <QString>
#include <string>
namespace LibertyXDR {
bool utf8_to_wstring(const uint8_t *utf8, size_t length, std::wstring &wide) {
QByteArrayView view(reinterpret_cast<const char *>(utf8), length);
if (!view.isValidUtf8())
return false;
wide = QString::fromUtf8(view).toStdWString();
return true;
}
bool wstring_to_utf8(const std::wstring &wide, std::string &utf8) {
utf8 = QString::fromStdWString(wide).toUtf8().toStdString();
return true;
}
} // namespace LibertyXDR