slw2gmi

Конвертор из slweb-а у Џемини
git clone https://git.sr.ht/~strahinja/slw2gmi
Дневник | Датотеке | Референце | ПРОЧИТАЈМЕ | ЛИЦЕНЦА

чување 75006bfb2b148789953ba9ec66f26712367eafab
родитељ 9f26df4d8d247754f750b2885b4ec40b5df014e2
Аутор: Страхиња Радић <contact@strahinja.org>
Датум:   Wed, 10 Apr 2024 21:56:08 +0200

Sync with slweb 0.9.6

Signed-off-by: Страхиња Радић <contact@strahinja.org>

Diffstat:
MINSTALL | 33+++++++++++++++------------------
AMakefile | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MREADME | 2+-
Dall.do | 2--
Aclean | 0
Dclean.do | 2--
Aconfig.mk | 20++++++++++++++++++++
Mconfig.redo | 12++++++------
Ddate.do | 20--------------------
Ddefault.do | 10----------
Ddefault.gz.do | 2--
Ddefault.o.do | 5-----
Ddefault.pdf.do | 2--
Mdefs.h | 13++++++++++---
Ddo | 446-------------------------------------------------------------------------------
Dinstall.do | 12------------
Alib/makedate | 35+++++++++++++++++++++++++++++++++++
Alib/makeversion | 33+++++++++++++++++++++++++++++++++
Alib/mkpack | 12++++++++++++
Alib/replacepat | 5+++++
Alib/runtests | 24++++++++++++++++++++++++
Dpack.do | 13-------------
Drebuild.do | 2--
Mslw2gmi.1.in | 2+-
Mslw2gmi.c | 672++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Dslw2gmi.do | 10----------
Astrlcat.c | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Astrlcpy.c | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Duninstall.do | 10----------
Mutf8.c | 2+-
Mutf8.h | 2+-
Dversion.do | 17-----------------
Mversion.h.in | 2+-
измењених датотека: 33, додавања: 813(+), брисања: 777(-)

diff --git a/INSTALL b/INSTALL @@ -1,14 +1,13 @@ Prerequisites ============= -* C compiler - defaults in config.redo +* C compiler - defaults in config.mk Optional dependencies --------------------- * git (for {git-log}) -* gzip (autodetected, for manpage compression) Install @@ -17,33 +16,31 @@ Install $ git clone https://git.sr.ht/~strahinja/slw2gmi $ cd slw2gmi $ su - -If you have djb redo: - - # redo install - -if you don't: - - # ./do install + # make install Persistent build configuration file ----------------------------------- -The file config.redo will be sourced when building targets which also accept +The file config.mk will be sourced when building targets which also accept configuration through environment variables. For example, CC and PREFIX -are specified in config.redo. +are specified in config.mk. OpenBSD ------- -Replace gcc in CC with cc and add -D_BSD_SOURCE, eg: +Before running make(1), comment the CPPFLAGS definition in config.mk above the +line with the "OpenBSD" comment and uncomment the one below it: - # CC='cc -g -Wall -pedantic -std=c99 -D_POSIX_C_SOURCE=200809L - -D_XOPEN_SOURCE=700 -D_BSD_SOURCE}' \ - ./do install + #CPPFLAGS = -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200809L \ + # -D_XOPEN_SOURCE=700 + # OpenBSD + CPPFLAGS = -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200809L \ + -D_XOPEN_SOURCE=700 -D_BSD_SOURCE -and change MANPREFIX to +Also, do the same for MANPREFIX: - MANPREFIX=$PREFIX/man + #MANPREFIX = $(PREFIX)/share/man + # OpenBSD + MANPREFIX = $(PREFIX)/man diff --git a/Makefile b/Makefile @@ -0,0 +1,65 @@ +.POSIX: + +include config.mk + +.SUFFIXES: .1.in .1 .h.in .h .c .o + +.1.in.1: + sh lib/replacepat $< $@ + +.h.in.h: + sh lib/replacepat $< $@ + +all: makedate makeversion $(PROG) $(MANPAGE) + if [ -f .rebuild ]; then rm .rebuild; make -e all; else true; fi + +date: + sh lib/makedate + +version: + sh lib/makeversion + +makedate: + sh lib/makedate -l + +makeversion: + sh lib/makeversion -l + +slw2gmi.o: slw2gmi.c defs.h utf8.h version.h + +$(MANPAGE): $(MANPAGE).in date version + +version.h: version.h.in date version + +utf8.o: utf8.c utf8.h + +$(PROG): $(OBJS) + $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) + +clean: + rm -f version date version.h *.o *.xz *~ $(PROG) $(MANPAGE) + +install: all + umask 022 + $(INSTALL) -Dm 0644 $(MANPAGE) $(MANPREFIX)/man1/$(MANPAGE) + $(INSTALL) -Dm 0644 README $(DOCDIR)/README + $(INSTALL) -Dm 0644 LICENSE $(DOCDIR)/LICENSE + $(INSTALL) -Dm 0755 $(PROG) $(BINDIR)/$(PROG) + +uninstall: + rm -f $(MANPREFIX)/man1/$(MANPAGE) + rmdir $(MANPREFIX)/man1 2>/dev/null || true + rmdir $(MANPREFIX) 2>/dev/null || true + rm -f $(DOCDIR)/README + rm -f $(DOCDIR)/LICENSE + rmdir $(DOCDIR) 2>/dev/null || true + rm -f $(PROG) $(BINDIR)/$(PROG) + rmdir $(BINDIR) 2>/dev/null || true + +test: all + sh lib/runtests + +pack: all version + sh -x lib/mkpack + +.PHONY: all clean examples install makedate makeversion pack test uninstall diff --git a/README b/README @@ -19,7 +19,7 @@ License ------- slw2gmi - slweb to Gemini converter -Copyright (C) 2021-2023 Страхиња Радић +Copyright (C) 2021-2024 Страхиња Радић This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software diff --git a/all.do b/all.do @@ -1,2 +0,0 @@ -. ./config.redo -redo-ifchange slw2gmi slw2gmi.1"$MANSUFFIX" diff --git a/clean b/clean diff --git a/clean.do b/clean.do @@ -1,2 +0,0 @@ -. ./config.redo -rm -f *.o *~ slw2gmi $MANPAGES *.1 version.h version date *.pdf diff --git a/config.mk b/config.mk @@ -0,0 +1,20 @@ +#CC = cc +CFLAGS = -Os -Wall -pedantic -std=c99 +#CPPFLAGS = -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200809L \ +# -D_XOPEN_SOURCE=700 +# OpenBSD +CPPFLAGS = -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200809L \ + -D_XOPEN_SOURCE=700 -D_BSD_SOURCE +INSTALL = install +LIBS = +OBJS = slw2gmi.o strlcat.o strlcpy.o utf8.o +PREFIX = /usr/local +PROG = slw2gmi + +# Derived macros +BINDIR = $(PREFIX)/bin +DOCDIR = $(PREFIX)/share/doc/$(PROG) +#MANPREFIX = $(PREFIX)/share/man +# OpenBSD +MANPREFIX = $(PREFIX)/man +MANPAGE = $(PROG).1 diff --git a/config.redo b/config.redo @@ -2,20 +2,20 @@ PREFIX=${PREFIX:-/usr/local} BINDIR=$PREFIX/bin DOCDIR=$PREFIX/share/doc/slw2gmi -MANPREFIX=$PREFIX/share/man +#MANPREFIX=$PREFIX/share/man # OpenBSD -#MANPREFIX=$PREFIX/man +MANPREFIX=$PREFIX/man PROGS="slw2gmi" DOCS="README LICENSE" MANSUFFIX=${MANSUFFIX-$(command -v gzip >/dev/null && printf ".gz")} MANPAGES="slw2gmi.1${MANSUFFIX}" -CC=${CC:-gcc -g -Wall -pedantic -std=c99 -D_POSIX_C_SOURCE=200809L \ --D_XOPEN_SOURCE=700} +#CC=${CC:-gcc -g -Wall -pedantic -std=c99 -D_POSIX_C_SOURCE=200809L \ +#-D_XOPEN_SOURCE=700} STRIP=${STRIP:-:} # OpenBSD -#CC=${CC:-cc -g -Wall -pedantic -std=c99 -D_POSIX_C_SOURCE=200809L \ -#-D_XOPEN_SOURCE=700 -D_BSD_SOURCE} +CC=${CC:-cc -g -Wall -pedantic -std=c99 -D_POSIX_C_SOURCE=200809L \ +-D_XOPEN_SOURCE=700 -D_BSD_SOURCE} diff --git a/date.do b/date.do @@ -1,20 +0,0 @@ -FALLBACKDATE=${FALLBACKDATE:-unknown} -LC_ALL=C -export LC_ALL -user=$(unalias ls >/dev/null 2>&1 || true; \ - command ls -ld . | awk '{print $3}') -e_user=$(id -un) -if [ -d .git ] && command -v git >/dev/null 2>&1; then - if [ "$e_user" = "$user" ]; then - git log --format=format:%cd \ - --date=format:"%B %d, %Y" -1 @ >$3 - else - su "${user}" -c 'env LC_ALL=C git log --format=format:%cd \ - --date=format:"%B %d, %Y" -1 @' >$3 - fi - echo >>$3 -else - printf "%s\n" "$FALLBACKDATE" >$3 -fi -redo-always -redo-stamp <$3 diff --git a/default.do b/default.do @@ -1,10 +0,0 @@ -if [ -r $1.in ]; then - redo-ifchange $1.in version date - read VERSION <version - read DATE <date - sed -e "s/%VERSION%/$VERSION/g" \ - -e "s/%DATE%/$DATE/g" <$1.in -else - echo "$0: don't know how to build '$1'" >&2 - exit 99 -fi diff --git a/default.gz.do b/default.gz.do @@ -1,2 +0,0 @@ -redo-ifchange $2 -gzip -cf $2 >$3 diff --git a/default.o.do b/default.o.do @@ -1,5 +0,0 @@ -sed -n 's/^#include "\([^"]*\)"/\1/p' ${2%.o}.c | \ - xargs redo-ifchange -redo-ifchange $2.c -. ./config.redo -${CC} -o $3 -c $2.c diff --git a/default.pdf.do b/default.pdf.do @@ -1,2 +0,0 @@ -redo-ifchange $2.1 -groff -mandoc -t -T pdf $2.1 >$3 diff --git a/defs.h b/defs.h @@ -1,5 +1,5 @@ /* This program is licensed under the terms of GNU GPL v3 or (at your option) - * any later version. Copyright (C) 2021-2023 Страхиња Радић. + * any later version. Copyright (C) 2021-2024 Страхиња Радић. * See the file LICENSE for exact copyright and license details. */ #ifndef __DEFS_H @@ -8,21 +8,28 @@ #include <ctype.h> #include <dirent.h> #include <errno.h> +#include <signal.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> -#include <sys/prctl.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> +#ifndef strlcpy +size_t strlcpy(char *dst, const char *src, size_t dsize); +#endif +#ifndef strlcat +size_t strlcat(char *dst, const char *src, size_t dsize); +#endif + #include "version.h" #include "utf8.h" -#define COPYRIGHTYEAR "2021-2023" +#define COPYRIGHTYEAR "2021-2024" #define MADEBY_URL "gemini://gemini.strahinja.org/slw2gmi/" #define BUFSIZE 1024 diff --git a/do b/do @@ -1,446 +0,0 @@ -#!/usr/bin/env sh -# -# A minimal alternative to djb redo that doesn't support incremental builds. -# For the full version, visit http://github.com/apenwarr/redo -# -# The author disclaims copyright to this source file and hereby places it in -# the public domain. (2010 12 14; updated 2019 02 24) -# -USAGE=" -usage: do [-d] [-x] [-v] [-c] <targets...> - -d print extra debug messages (mostly about dependency checks) - -v run .do files with 'set -v' - -x run .do files with 'set -x' - -c clean up all old targets before starting - - Note: do is an implementation of redo that does *not* check dependencies. - It will never rebuild a target it has already built, unless you use -c. -" - -# CDPATH apparently causes unexpected 'cd' output on some platforms. -unset CDPATH - -# By default, no output coloring. -green="" -bold="" -plain="" - -if [ -n "$TERM" -a "$TERM" != "dumb" ] && tty <&2 >/dev/null 2>&1; then - green="$(printf '\033[32m')" - bold="$(printf '\033[1m')" - plain="$(printf '\033[m')" -fi - -# The 'seq' command is not available on all platforms. -_seq() { - local x=0 max="$1" - while [ "$x" -lt "$max" ]; do - x=$((x + 1)) - echo "$x" - done -} - -# Split $1 into a dir part ($_dirsplit_dir) and base filename ($_dirsplit_base) -_dirsplit() { - _dirsplit_base=${1##*/} - _dirsplit_dir=${1%$_dirsplit_base} -} - -# Like /usr/bin/dirname, but avoids a fork and uses _dirsplit semantics. -qdirname() ( - _dirsplit "$1" - dir=${_dirsplit_dir%/} - echo "${dir:-.}" -) - -_dirsplit "$0" -REDO=$(cd "$(pwd -P)" && - cd "${_dirsplit_dir:-.}" && - echo "$PWD/$_dirsplit_base") -export REDO -_cmd=$_dirsplit_base - -DO_TOP= -if [ -z "$DO_BUILT" ]; then - export _do_opt_debug= - export _do_opt_exec= - export _do_opt_verbose= - export _do_opt_clean= -fi -while getopts 'dxvcj:h?' _opt; do - case $_opt in - d) _do_opt_debug=1 ;; - x) _do_opt_exec=x ;; - v) _do_opt_verbose=v ;; - c) _do_opt_clean=1 ;; - j) ;; # silently ignore, for compat with real redo - \?|h|*) printf "%s" "$USAGE" >&2 - exit 99 - ;; - esac -done -shift "$((OPTIND - 1))" -_debug() { - [ -z "$_do_opt_debug" ] || echo "$@" >&2 -} - -if [ -z "$DO_BUILT" -a "$_cmd" != "redo-whichdo" ]; then - DO_TOP=1 - if [ "$#" -eq 0 ] && [ "$_cmd" = "do" -o "$_cmd" = "redo" ]; then - set all # only toplevel redo has a default target - fi - export DO_STARTDIR="$(pwd -P)" - # If starting /bin/pwd != $PWD, this will fix it. - # That can happen when $PWD contains symlinks that the shell is - # trying helpfully (but unsuccessfully) to hide from the user. - cd "$DO_STARTDIR" || exit 99 - export DO_BUILT="$PWD/.do_built" - if [ -z "$_do_opt_clean" -a -e "$DO_BUILT" ]; then - echo "do: Incremental mode. Use -c for clean rebuild." >&2 - fi - : >>"$DO_BUILT" - sort -u "$DO_BUILT" >"$DO_BUILT.new" - while read f; do - [ -n "$_do_opt_clean" ] && printf "%s\0%s.did\0" "$f" "$f" - printf "%s.did.tmp\0" "$f" - done <"$DO_BUILT.new" | - xargs -0 rm -f 2>/dev/null - mv "$DO_BUILT.new" "$DO_BUILT" - export DO_PATH="$DO_BUILT.dir" - export PATH="$DO_PATH:$PATH" - rm -rf "$DO_PATH" - mkdir "$DO_PATH" - for d in redo redo-ifchange redo-whichdo; do - ln -s "$REDO" "$DO_PATH/$d" - done - for d in redo-ifcreate redo-stamp redo-always redo-ood \ - redo-targets redo-sources; do - echo "#!/bin/sh" >"$DO_PATH/$d" - chmod a+rx "$DO_PATH/$d" - done -fi - - -# Chop the "file" part off a /path/to/file pathname. -# Note that if the filename already ends in a /, we just remove the slash. -_updir() -{ - local v="${1%/*}" - [ "$v" != "$1" ] && echo "$v" - # else "empty" which means we went past the root -} - - -# Returns true if $1 starts with $2. -_startswith() -{ - [ "${1#"$2"}" != "$1" ] -} - - -# Returns true if $1 ends with $2. -_endswith() -{ - [ "${1%"$2"}" != "$1" ] -} - - -# Prints $1 if it's absolute, or $2/$1 if $1 is not absolute. -_abspath() -{ - local here="$2" there="$1" - if _startswith "$1" "/"; then - echo "$1" - else - echo "$2/$1" - fi -} - - -# Prints $1 as a path relative to $PWD (not starting with /). -# If it already doesn't start with a /, doesn't change the string. -_relpath() -{ - local here="$2" there="$1" out= hadslash= - #echo "RP start '$there' hs='$hadslash'" >&2 - _startswith "$there" "/" || { echo "$there" && return; } - [ "$there" != "/" ] && _endswith "$there" "/" && hadslash=/ - here=${here%/}/ - while [ -n "$here" ]; do - #echo "RP out='$out' here='$here' there='$there'" >&2 - [ "${here%/}" = "${there%/}" ] && there= && break; - [ "${there#$here}" != "$there" ] && break - out=../$out - _dirsplit "${here%/}" - here=$_dirsplit_dir - done - there=${there#$here} - if [ -n "$there" ]; then - echo "$out${there%/}$hadslash" - else - echo "${out%/}$hadslash" - fi -} - - -# Prints a "normalized relative" path, with ".." resolved where possible. -# For example, a/b/../c will be reduced to just a/c. -_normpath() -( - local path="$1" relto="$2" out= isabs= - #echo "NP start '$path'" >&2 - if _startswith "$path" "/"; then - isabs=1 - else - path="${relto%/}/$path" - fi - set -f - IFS=/ - for d in ${path%/}; do - #echo "NP out='$out' d='$d'" >&2 - if [ "$d" = ".." ]; then - out=$(_updir "${out%/}")/ - else - out=$out$d/ - fi - done - #echo "NP out='$out' (done)" >&2 - out=${out%/} - if [ -n "$isabs" ]; then - echo "${out:-/}" - else - _relpath "${out:-/}" "$relto" - fi -) - - -# Prints a "real" path, with all symlinks resolved where possible. -_realpath() -{ - local path="$1" relto="$2" isabs= rest= - if _startswith "$path" "/"; then - isabs=1 - else - path="${relto%/}/$path" - fi - ( - for d in $(_seq 100); do - #echo "Trying: $PWD--$path" >&2 - if cd -P "$path" 2>/dev/null; then - # success - pwd=$(pwd -P) - #echo " chdir ok: $pwd--$rest" >&2 - np=$(_normpath "${pwd%/}/$rest" "$relto") - if [ -n "$isabs" ]; then - echo "$np" - else - _relpath "$np" "$relto" - fi - break - fi - _dirsplit "${path%/}" - path=$_dirsplit_dir - rest="$_dirsplit_base/$rest" - done - ) -} - - -# List the possible names for default*.do files in dir $1 matching the target -# pattern in $2. We stop searching when we find the first one that exists. -_find_dofiles_pwd() -{ - local dodir="$1" dofile="$2" - _startswith "$dofile" "default." || dofile=${dofile#*.} - while :; do - dofile=default.${dofile#default.*.} - echo "$dodir$dofile" - [ -e "$dodir$dofile" ] && return 0 - [ "$dofile" = default.do ] && break - done - return 1 -} - - -# List the possible names for default*.do files in $PWD matching the target -# pattern in $1. We stop searching when we find the first name that works. -# If there are no matches in $PWD, we'll search in .., and so on, to the root. -_find_dofiles() -{ - local target="$1" dodir= dofile= newdir= - _debug "find_dofile: '$PWD' '$target'" - dofile="$target.do" - echo "$dofile" - [ -e "$dofile" ] && return 0 - - # Try default.*.do files, walking up the tree - _dirsplit "$dofile" - dodir=$_dirsplit_dir - dofile=$_dirsplit_base - [ -n "$dodir" ] && dodir=${dodir%/}/ - [ -e "$dodir$dofile" ] && return 0 - for i in $(_seq 100); do - [ -n "$dodir" ] && dodir=${dodir%/}/ - #echo "_find_dofiles: '$dodir' '$dofile'" >&2 - _find_dofiles_pwd "$dodir" "$dofile" && return 0 - newdir=$(_realpath "${dodir}.." "$PWD") - [ "$newdir" = "$dodir" ] && break - dodir=$newdir - done - return 1 -} - - -# Print the last .do file returned by _find_dofiles. -# If that file exists, returns 0, else 1. -_find_dofile() -{ - local files="$(_find_dofiles "$1")" - rv=$? - #echo "files='$files'" >&2 - [ "$rv" -ne 0 ] && return $rv - echo "$files" | { - while read -r linex; do line=$linex; done - printf "%s\n" "$line" - } -} - - -# Actually run the given $dofile with the arguments in $@. -# Note: you should always run this in a subshell. -_run_dofile() -{ - export DO_DEPTH="$DO_DEPTH " - export REDO_TARGET="$PWD/$target" - local line1 - set -e - read line1 <"$PWD/$dofile" || true - cmd=${line1#"#!/"} - if [ "$cmd" != "$line1" ]; then - set -$_do_opt_verbose$_do_opt_exec - exec /$cmd "$PWD/$dofile" "$@" - else - set -$_do_opt_verbose$_do_opt_exec - # If $dofile is empty, "." might not change $? at - # all, so we clear it first with ":". - :; . "$PWD/$dofile" - fi -} - - -# Find and run the right .do file, starting in dir $1, for target $2, -# providing a temporary output file as $3. Renames the temp file to $2 when -# done. -_do() -{ - local dir="$1" target="$1$2" tmp="$1$2.redo.tmp" tdir= - local dopath= dodir= dofile= ext= - if [ "$_cmd" = "redo" ] || - ( [ ! -e "$target" -o -d "$target" ] && - [ ! -e "$target.did" ] ); then - printf '%sdo %s%s%s%s\n' \ - "$green" "$DO_DEPTH" "$bold" "$target" "$plain" >&2 - dopath=$(_find_dofile "$target") - if [ ! -e "$dopath" ]; then - echo "do: $target: no .do file ($PWD)" >&2 - return 1 - fi - _dirsplit "$dopath" - dodir=$_dirsplit_dir dofile=$_dirsplit_base - if _startswith "$dofile" "default."; then - ext=${dofile#default} - ext=${ext%.do} - else - ext= - fi - target=$PWD/$target - tmp=$PWD/$tmp - cd "$dodir" || return 99 - target=$(_relpath "$target" "$PWD") || return 98 - tmp=$(_relpath "$tmp" "$PWD") || return 97 - base=${target%$ext} - tdir=$(qdirname "$target") - [ ! -e "$DO_BUILT" ] || [ ! -w "$tdir/." ] || - : >>"$target.did.tmp" - # $qtmp is a temporary file used to capture stdout. - # Since it might be accidentally deleted as a .do file - # does its work, we create it, then open two fds to it, - # then immediately delete the name. We use one fd to - # redirect to stdout, and the other to read from after, - # because there's no way to fseek(fd, 0) in sh. - qtmp=$DO_PATH/do.$$.tmp - ( - rm -f "$qtmp" - ( _run_dofile "$target" "$base" "$tmp" >&3 3>&- 4<&- ) - rv=$? - if [ $rv != 0 ]; then - printf "do: %s%s\n" "$DO_DEPTH" \ - "$target: got exit code $rv" >&2 - rm -f "$tmp.tmp" "$tmp.tmp2" "$target.did" - return $rv - fi - echo "$PWD/$target" >>"$DO_BUILT" - if [ ! -e "$tmp" ]; then - # if $3 wasn't created, copy from stdout file - cat <&4 >$tmp - # if that's zero length too, forget it - [ -s "$tmp" ] || rm -f "$tmp" - fi - ) 3>$qtmp 4<$qtmp # can't use "|| return" here... - # ...because "|| return" would mess up "set -e" inside the () - # on some shells. Running commands in "||" context, even - # deep inside, will stop "set -e" from functioning. - rv=$? - [ "$rv" = 0 ] || return "$rv" - mv "$tmp" "$target" 2>/dev/null - [ -e "$target.did.tmp" ] && - mv "$target.did.tmp" "$target.did" || - : >>"$target.did" - else - _debug "do $DO_DEPTH$target exists." >&2 - fi -} - - -# Implementation of the "redo" command. -_redo() -{ - local i startdir="$PWD" dir base - set +e - for i in "$@"; do - i=$(_abspath "$i" "$startdir") - ( - cd "$DO_STARTDIR" || return 99 - i=$(_realpath "$(_relpath "$i" "$PWD")" "$PWD") - _dirsplit "$i" - dir=$_dirsplit_dir base=$_dirsplit_base - _do "$dir" "$base" - ) - [ "$?" = 0 ] || return 1 - done -} - - -# Implementation of the "redo-whichdo" command. -_whichdo() -{ - _find_dofiles "$1" -} - - -case $_cmd in - do|redo|redo-ifchange) _redo "$@" ;; - redo-whichdo) _whichdo "$1" ;; - do.test) ;; - *) printf "do: '%s': unexpected redo command" "$_cmd" >&2; exit 99 ;; -esac -[ "$?" = 0 ] || exit 1 - -if [ -n "$DO_TOP" ]; then - if [ -n "$_do_opt_clean" ]; then - echo "do: Removing stamp files..." >&2 - [ ! -e "$DO_BUILT" ] || - while read f; do printf "%s.did\0" "$f"; done <"$DO_BUILT" | - xargs -0 rm -f 2>/dev/null - fi -fi diff --git a/install.do b/install.do @@ -1,12 +0,0 @@ -redo-ifchange all -. ./config.redo -install -d "$DOCDIR" "$BINDIR" "${MANPREFIX}/man1" -for docfile in $DOCS; do - install -Dm 0644 "${docfile}" "${DOCDIR}/${docfile}" -done -for binfile in $PROGS; do - install -Dm 0755 "${binfile}" "${BINDIR}/${binfile}" -done -for manfile in $MANPAGES; do - install -Dm 0644 "${manfile}" "${MANPREFIX}/man1/${manfile}" -done diff --git a/lib/makedate b/lib/makedate @@ -0,0 +1,35 @@ +#!/bin/sh -x +# vim: set ft=bash: +FALLBACKDATE=${FALLBACKDATE:-unknown} +LC_ALL=C +export LC_ALL +user=$(unalias ls >/dev/null 2>&1 || true; \ + command ls -ld . | awk '{print $3}') +e_user=$(id -un) +if [ -d .git ] && command -v git >/dev/null 2>&1; then + if [ "$e_user" = "$user" ]; then + git log --format=format:%cd \ + --date=format:"%B %d, %Y" -1 @ >date.new + else + su "${user}" -c 'env LC_ALL=C git log --format=format:%cd \ + --date=format:"%B %d, %Y" -1 @' >date.new + fi + echo >>date.new +else + printf "%s\n" "$FALLBACKDATE" >date.new +fi + +if [ -f date ]; then + if diff date date.new >/dev/null; then + rm date.new + else + mv date.new date + touch .rebuild + fi +else + mv date.new date + touch .rebuild +fi +if [ "$1" = "-l" ]; then + printf "DATE=\"%s\"\n" "$(cat date)" +fi diff --git a/lib/makeversion b/lib/makeversion @@ -0,0 +1,33 @@ +#!/bin/sh -x +# vim: set ft=bash: +FALLBACKVER=${FALLBACKVER:-unknown} +LC_ALL=C +export LC_ALL +user=$(unalias ls >/dev/null 2>&1 || true; \ + command ls -ld . | awk '{print $3}') +e_user=$(id -un) +if [ -d .git ] && command -v git >/dev/null 2>&1; then + if [ "$e_user" = "$user" ]; then + git describe 2>/dev/null | sed 's/^v//' >version.new + else + su "${user}" -c 'git describe' 2>/dev/null | + sed 's/^v//' >version.new + fi +else + printf "%s\n" "$FALLBACKVER" >version.new +fi + +if [ -f version ]; then + if diff version version.new >/dev/null; then + rm version.new + else + mv version.new version + touch .rebuild + fi +else + mv version.new version + touch .rebuild +fi +if [ "$1" = "-l" ]; then + printf "VERSION=\"%s\"\n" "$(cat version)" +fi diff --git a/lib/mkpack b/lib/mkpack @@ -0,0 +1,12 @@ +#!/bin/sh -x +# vim: set ft=bash: +DISTDIR=$(grep ^PROG config.mk | + sed -E 's,.*=[[:space:]]+([[:alpha:]]+),\1,')-$(cat version) +mkdir "$DISTDIR" +for f in $(git ls-files); do + d="$DISTDIR"/"$(dirname "$f")" + mkdir -p "$d" + cp "$f" "$d"/ +done +tar -cf - "$DISTDIR" | xz -9v - > "$DISTDIR".tar.xz +rm -fr "$DISTDIR" diff --git a/lib/replacepat b/lib/replacepat @@ -0,0 +1,5 @@ +#!/bin/sh -x +# vim: set ft=bash: +DATE=$(cat date) +VERSION=$(cat version) +sed -e 's|%VERSION%|'"$VERSION"'|g' -e 's|%DATE%|'"$DATE"'|g' "$1" > "$2" diff --git a/lib/runtests b/lib/runtests @@ -0,0 +1,24 @@ +#!/bin/sh +testdir=tests +cat <<! >&2 +TEST RESULTS +=========================================================== +! +error='' +find "$testdir" -type f \( -perm -100 -o -perm -010 -o -perm -001 \) -exec {} \; | +awk 'BEGIN { FS="\t"; maxlen = 60; status = 0 } +{ + printf "%s%*s%s\n", $1, maxlen-5-length($1), " ", $2; + if ($2 == "FAIL") + status = 1 +} +END { exit status }' >&2 || error=1 +cat <<! >&2 +=========================================================== +! +if [ -n "$error" ]; then + printf "Some tests were unsuccessful - please report\n" >&2 + exit 99 +else + printf "All tests passed\n" >&2 +fi diff --git a/pack.do b/pack.do @@ -1,13 +0,0 @@ -redo all -redo-ifchange version -read VERSION <version -VERSION=$(echo $VERSION | sed 's/^v//') -DISTDIR=slw2gmi-$VERSION -mkdir $DISTDIR -for f in $(git ls-files); do - d=$DISTDIR/$(dirname $f) - mkdir -p $d - cp $f $d -done -tar cvf $DISTDIR.tar.xz $DISTDIR >/dev/null -rm -fr $DISTDIR diff --git a/rebuild.do b/rebuild.do @@ -1,2 +0,0 @@ -redo clean -redo all diff --git a/slw2gmi.1.in b/slw2gmi.1.in @@ -35,7 +35,7 @@ slw2gmi \- slweb to Gemini converter .YS . .SH COPYRIGHT -slw2gmi Copyright \(co 2021, 2022, 2023 Strahinya Radich. +slw2gmi Copyright \(co 2021\-2024 Strahinya Radich. .br This program is licensed under GNU GPL v3 or later. See the file .I LICENSE diff --git a/slw2gmi.c b/slw2gmi.c @@ -1,5 +1,5 @@ /* This program is licensed under the terms of GNU GPL v3 or (at your option) - * any later version. Copyright (C) 2021-2023 Страхиња Радић. + * any later version. Copyright (C) 2021-2024 Страхиња Радић. * See the file LICENSE for exact copyright and license details. */ #include "defs.h" @@ -94,15 +94,19 @@ static int incdir_only_summary = 0; ptoken = token; \ } while (0) +int slweb_cleanup(void); +int usage(void); +int version(void); + int -version() +version(void) { printf("%s %s, committed on %s\n", PROGRAMNAME, VERSION, DATE); return 0; } int -usage() +usage(void) { printf("Usage: %s [-d|--basedir <dir>]" " [-p|--global-link-prefix <URL>] [-h|--help]" @@ -153,7 +157,7 @@ free_keyvalue(KeyValue** list, const size_t list_count) } int -slweb_cleanup() +slweb_cleanup(void) { free(basedir); free(input_dirname); @@ -174,6 +178,7 @@ slweb_cleanup() return 0; } +u8* format_date(const u8* date_arg, const char* timestamp_format); int simple_parse_yaml_line(const u8* line, KeyValue** vars, size_t* vars_count, KeyValue** pvars); int slweb_parse(FILE* output, const char* source_filename, const u8* buffer, @@ -232,7 +237,8 @@ all_numeric(const u8* start, const u8* end) } u8* -get_value(KeyValue* list, const size_t list_count, const u8* key) +get_value(KeyValue* list, const size_t list_count, const u8* key, + KeyValue** cursor) { if (!list) return NULL; @@ -240,9 +246,20 @@ get_value(KeyValue* list, const size_t list_count, const u8* key) while (plist < list + list_count) { if (!strcmp((char*)plist->key, (char*)key)) + { + if (cursor) + { + if (plist + 1 < list + list_count) + *cursor = plist + 1; + else + *cursor = NULL; + } return plist->value; + } plist++; } + if (cursor) + *cursor = NULL; return NULL; } @@ -260,9 +277,10 @@ set_basedir(char** basedir, size_t* basedir_size, const char* arg) *basedir_size = arg_len + 1; REALLOC(*basedir, char, *basedir_size); } - strcpy(*basedir, arg); - *(*basedir + arg_len) = 0; - basedir_len = strlen(*basedir); + + if (strlcpy(*basedir, arg, *basedir_size) >= *basedir_size) + warning(1, (u8*)"strlcpy:%d: Overflow", __LINE__); + basedir_len = strlen(*basedir); if (*(*basedir + basedir_len - 1) == '/') *(*basedir + basedir_len - 1) = 0; @@ -283,7 +301,9 @@ set_global_link_prefix(char** global_link_prefix, *global_link_prefix_size = arg_len + 1; REALLOC(*global_link_prefix, char, *global_link_prefix_size); } - strcpy(*global_link_prefix, arg); + if (strlcpy(*global_link_prefix, arg, *global_link_prefix_size) + >= *global_link_prefix_size) + warning(1, (u8*)"strlcpy:%d: Overflow", __LINE__); *(*global_link_prefix + arg_len) = 0; return 0; @@ -326,7 +346,7 @@ print_output(FILE* output, const char* fmt, ...) va_start(args, fmt); var_incdir_only_summary - = get_value(vars, vars_count, (u8*)"incdir-only-summary"); + = get_value(vars, vars_count, (u8*)"incdir-only-summary", NULL); incdir_only_summary = var_incdir_only_summary && *var_incdir_only_summary == '1'; @@ -343,7 +363,10 @@ print_output(FILE* output, const char* fmt, ...) { csv_template_size = BUFSIZE; CALLOC(csv_template, u8, csv_template_size); - strcpy((char*)csv_template, buf); + if (strlcpy((char*)csv_template, buf, csv_template_size) + >= csv_template_size) + warning(1, (u8*)"strlcpy:%d: Overflow", + __LINE__); } else { @@ -353,7 +376,10 @@ print_output(FILE* output, const char* fmt, ...) csv_template_size += BUFSIZE; REALLOC(csv_template, u8, csv_template_size); } - strcat((char*)csv_template, buf); + if (strlcat((char*)csv_template, buf, csv_template_size) + > csv_template_size) + warning(1, (u8*)"strlcat:%d: Overflow", + __LINE__); } } else if (IN(state, ST_TSV_BODY)) @@ -365,7 +391,10 @@ print_output(FILE* output, const char* fmt, ...) { tsv_template_size = BUFSIZE; CALLOC(tsv_template, u8, tsv_template_size); - strcpy((char*)tsv_template, buf); + if (strlcpy((char*)tsv_template, buf, tsv_template_size) + >= tsv_template_size) + warning(1, (u8*)"strlcpy:%d: Overflow", + __LINE__); } else { @@ -375,7 +404,10 @@ print_output(FILE* output, const char* fmt, ...) tsv_template_size += BUFSIZE; REALLOC(tsv_template, u8, tsv_template_size); } - strcat((char*)tsv_template, buf); + if (strlcat((char*)tsv_template, buf, tsv_template_size) + > tsv_template_size) + warning(1, (u8*)"strlcat:%d: Overflow", + __LINE__); } } else @@ -408,8 +440,6 @@ print_command(FILE* output, const char* command, const u8* pass_arguments[], close(arg_pipe_fds[PIPE_WRITE_INDEX]); close(output_pipe_fds[PIPE_READ_INDEX]); - prctl(PR_SET_PDEATHSIG, SIGTERM); - dup2(arg_pipe_fds[PIPE_READ_INDEX], STDIN_FILENO); dup2(output_pipe_fds[PIPE_WRITE_INDEX], STDOUT_FILENO); @@ -553,9 +583,16 @@ process_git_log(FILE* output) pid_t result = 0; if (slash) - strcpy(basename, slash + 1); + { + if (strlcpy(basename, slash + 1, basename_size) >= basename_size) + warning(1, (u8*)"strlcpy:%d: Overflow", __LINE__); + } else - strcpy(basename, input_filename); + { + if (strlcpy(basename, input_filename, basename_size) + >= basename_size) + warning(1, (u8*)"strlcpy:%d: Overflow", __LINE__); + } u8* pipe_args[] = {(u8*)basename, NULL}; @@ -757,7 +794,8 @@ read_tsv(FILE* output, const char* filename, tsv_callback_t callback) while (!feof(tsv) && (!tsv_iter || tsv_lineno <= tsv_iter)) { - u8* eol = NULL; + u8* eol = NULL; + size_t res = 0; if (!fgets((char*)bufline, BUFSIZE, tsv)) break; eol = (u8*)strchr((char*)bufline, '\n'); @@ -776,12 +814,25 @@ read_tsv(FILE* output, const char* filename, tsv_callback_t callback) *ptoken = 0; if (tsv_lineno > 0 && current_register < MAX_TSV_REGISTERS) - strcpy((char*)tsv_register[current_register++], - (char*)token); + { + if ((res = strlcpy((char*)tsv_register + [current_register], + (char*)token, BUFSIZE)) + >= BUFSIZE) + warning(1, (u8*)"strlcpy:%d: Overflow", + __LINE__); + current_register++; + } else if (tsv_lineno <= 0 && current_header < MAX_TSV_REGISTERS) - strcpy((char*)tsv_header[current_header++], - (char*)token); + { + if (strlcpy((char*)tsv_header[current_header], + (char*)token, BUFSIZE) + >= BUFSIZE) + warning(1, (u8*)"strlcpy:%d: Overflow", + __LINE__); + current_header++; + } RESET_TOKEN(token, ptoken, token_size); pbufline++; break; @@ -794,14 +845,26 @@ read_tsv(FILE* output, const char* filename, tsv_callback_t callback) if (tsv_lineno > 0) { if (current_register < MAX_TSV_REGISTERS) - strcpy((char*)tsv_register[current_register++], - (char*)token); + { + if (strlcpy((char*)tsv_register[current_register], + (char*)token, BUFSIZE) + >= BUFSIZE) + warning(1, (u8*)"strlcpy:%d: Overflow", + __LINE__); + current_register++; + } } else { if (current_header < MAX_TSV_REGISTERS) - strcpy((char*)tsv_header[current_header++], - (char*)token); + { + if (strlcpy((char*)tsv_header[current_header], + (char*)token, BUFSIZE) + >= BUFSIZE) + warning(1, (u8*)"strlcpy:%d: Overflow", + __LINE__); + current_header++; + } } RESET_TOKEN(token, ptoken, token_size); @@ -1059,7 +1122,8 @@ read_csv(FILE* output, const char* filename, csv_callback_t callback) UBYTE current_header = 0; u8* csv_register[MAX_CSV_REGISTERS]; UBYTE current_register = 0; - u8* csv_delimiter = get_value(vars, vars_count, (u8*)"csv-delimiter"); + u8* csv_delimiter + = get_value(vars, vars_count, (u8*)"csv-delimiter", NULL); if (!(csv = fopen(filename, "rt"))) exit(error(ENOENT, (u8*)"csv: No such file: %s", filename)); @@ -1105,13 +1169,26 @@ read_csv(FILE* output, const char* filename, csv_callback_t callback) *ptoken = 0; if (csv_lineno > 0 && current_register < MAX_CSV_REGISTERS) - strcpy((char*)csv_register - [current_register++], - (char*)token); + { + if (strlcpy((char*)csv_register + [current_register], + (char*)token, BUFSIZE) + >= BUFSIZE) + warning(1, (u8*)"strlcpy:%d: Overflow", + __LINE__); + current_register++; + } else if (csv_lineno <= 0 && current_header < MAX_CSV_REGISTERS) - strcpy((char*)csv_header[current_header++], - (char*)token); + { + if (strlcpy((char*)csv_header + [current_header], + (char*)token, BUFSIZE) + >= BUFSIZE) + warning(1, (u8*)"strlcpy:%d: Overflow", + __LINE__); + current_header++; + } RESET_TOKEN(token, ptoken, token_size); pbufline++; } @@ -1124,13 +1201,26 @@ read_csv(FILE* output, const char* filename, csv_callback_t callback) *ptoken = 0; if (csv_lineno > 0 && current_register < MAX_CSV_REGISTERS) - strcpy((char*)csv_register - [current_register++], - (char*)token); + { + if (strlcpy((char*)csv_register + [current_register], + (char*)token, BUFSIZE) + >= BUFSIZE) + warning(1, (u8*)"strlcpy:%d: Overflow", + __LINE__); + current_register++; + } else if (csv_lineno <= 0 && current_header < MAX_CSV_REGISTERS) - strcpy((char*)csv_header[current_header++], - (char*)token); + { + if (strlcpy((char*)csv_header + [current_header], + (char*)token, BUFSIZE) + >= BUFSIZE) + warning(1, (u8*)"strlcpy:%d: Overflow", + __LINE__); + current_header++; + } RESET_TOKEN(token, ptoken, token_size); pbufline++; } @@ -1143,14 +1233,26 @@ read_csv(FILE* output, const char* filename, csv_callback_t callback) if (csv_lineno > 0) { if (current_register < MAX_CSV_REGISTERS) - strcpy((char*)csv_register[current_register++], - (char*)token); + { + if (strlcpy((char*)csv_register[current_register], + (char*)token, BUFSIZE) + >= BUFSIZE) + warning(1, (u8*)"strlcpy:%d: Overflow", + __LINE__); + current_register++; + } } else { if (current_header < MAX_CSV_REGISTERS) - strcpy((char*)csv_header[current_header++], - (char*)token); + { + if (strlcpy((char*)csv_header[current_header], + (char*)token, BUFSIZE) + >= BUFSIZE) + warning(1, (u8*)"strlcpy:%d: Overflow", + __LINE__); + current_header++; + } } RESET_TOKEN(token, ptoken, token_size); @@ -1304,7 +1406,6 @@ process_include(FILE* output, const u8* token, int result = 0; FILE* child_output = NULL; - prctl(PR_SET_PDEATHSIG, SIGTERM); close(arg_pipe_fds[PIPE_WRITE_INDEX]); close(output_pipe_fds[PIPE_READ_INDEX]); if (!(child_output @@ -1491,7 +1592,7 @@ int process_incdir_subdir(FILE* output, const char* subdirname, const u8* link_prefix, const int details_open, const u8* macro_body, const u8* footer_permalink_text, const char* permalink_url, - const int ext_in_permalink) + const int ext_in_permalink, const int list_only) { struct dirent** namelist; struct dirent** pnamelist; @@ -1532,17 +1633,17 @@ process_incdir_subdir(FILE* output, const char* subdirname, int result = 0; ULLONG saved_state = ST_NONE; char* filename = NULL; - char* basename = strip_ext((*pnamelist)->d_name); char* link = NULL; + u8* title = NULL; + u8* date = NULL; - CALLOC(link, char, BUFSIZE); + if (!strcmp(basedir, ".")) + set_basedir(&basedir, &basedir_size, + abs_subdirname); CALLOC(filename, char, BUFSIZE); - - snprintf(link, BUFSIZE, "%s/%s", subdirname, basename); - - set_basedir(&basedir, &basedir_size, abs_subdirname); snprintf(filename, BUFSIZE, "%s/%s", abs_subdirname, (*pnamelist)->d_name); + link = strip_ext(filename); read_file_into_buffer(&input, &buffer, &buffer_size, filename, &input_dirname); @@ -1575,25 +1676,27 @@ process_incdir_subdir(FILE* output, const char* subdirname, output_firstcol = 1; skip_para_end = 0; - /* Read YAML, macros and links */ + /* First pass: read YAML, macros and links */ result = slweb_parse(output, filename, buffer, 1); - if (result) { - slweb_cleanup(); - free(filename); - free(buffer); - free(link); - free(basename); - free(abs_subdirname); - while (names_total--) - free(namelist[names_total]); - free(namelist); - return result; + warning(1, (u8*)"slweb_parse error"); + goto incdir_subdir_child_cleanup; } - u8* date = get_value(vars, vars_count, (u8*)"date"); - u8* title = get_value(vars, vars_count, (u8*)"title"); + title = get_value(vars, vars_count, (u8*)"title", NULL); + date = get_value(vars, vars_count, (u8*)"date", NULL); + + incdir_subdir_child_cleanup: + slweb_cleanup(); + free(link); + free(filename); + free(buffer); + free(abs_subdirname); + while (names_total--) + free(namelist[names_total]); + free(namelist); + exit(result); process_timestamp(output, link_prefix, link, NULL, date, title, ext_in_permalink); @@ -1602,10 +1705,9 @@ process_incdir_subdir(FILE* output, const char* subdirname, fflush(output); slweb_cleanup(); + free(link); free(filename); free(buffer); - free(link); - free(basename); free(abs_subdirname); while (names_total--) free(namelist[names_total]); @@ -1615,6 +1717,9 @@ process_incdir_subdir(FILE* output, const char* subdirname, else exit(error(1, (u8*)"Fork failed")); + /*if (!list_only) + print_output(output, "</article>\n");*/ + pnamelist++; names_output++; } @@ -1624,6 +1729,12 @@ process_incdir_subdir(FILE* output, const char* subdirname, free(namelist); free(abs_subdirname); + /*if (list_only) + ; / *print_output(output, "</ul>\n");* / + else + print_output(output, "</div>\n</details>\n</li>\n");*/ + + output_firstcol = 0; return 0; } @@ -1643,6 +1754,9 @@ process_incdir(FILE* output, const u8* token, const u8* link_prefix, struct dirent** pnamelist; long names_output; int details_open = 1; + int list_only = 0; + int pass; + u8* parg = NULL; if (read_yaml_macros_and_links) return 0; @@ -1658,22 +1772,26 @@ process_incdir(FILE* output, const u8* token, const u8* link_prefix, exit(error(1, (u8*)"incdir: First argument not string")); incdir = strdup((char*)(arg + 1)); - *(incdir + strlen(incdir) - 1) = 0; + *(incdir + strlen(incdir) - 1) = 0; /* trim ending " */ + + pass = 0; +incdir_next_arg: arg = (u8*)strtok_r(NULL, " ", (char**)&saveptr); if (!arg) - exit(error(1, (u8*)"incdir: Second argument required")); + goto incdir_done_args; - if (*arg == '=') - macro_body = get_value(macros, macros_count, arg + 1); + parg = arg; + if (*parg == '=') + macro_body = get_value(macros, macros_count, arg + 1, NULL); + else if (!strcmp((const char*)arg, "listonly")) + list_only = 1; else { - u8* parg = arg; while (parg && *parg) { if (*parg < '0' || *parg > '9') - exit(error(1, - (u8*)"incdir: Non-numeric argument")); + exit(error(1, (u8*)"incdir: Invalid argument")); parg++; } errno = 0; @@ -1681,19 +1799,13 @@ process_incdir(FILE* output, const u8* token, const u8* link_prefix, if (errno) exit(error(errno, (u8*)"incdir: Invalid parameter 'num'")); - arg = (u8*)strtok_r(NULL, " ", (char**)&saveptr); - if (arg) - { - if (*arg != '=') - { - free(incdir); - exit(error(1, - (u8*)"incdir: Third argument not " - "macro")); - } - macro_body = get_value(macros, macros_count, arg + 1); - } } + pass++; + if (pass < 3) + goto incdir_next_arg; + +incdir_done_args: + /*print_output(output, "<ul class=\"incdir\">\n")*/; if ((names_total = scandir(incdir, &namelist, &filter_subdirs, &reverse_alphacompare)) @@ -1707,12 +1819,17 @@ process_incdir(FILE* output, const u8* token, const u8* link_prefix, names_output = 0; while (names_output < MIN(names_total, num)) { + /*if (list_only) + print_output(output, "<li>%s\n", + (*pnamelist)->d_name);*/ process_incdir_subdir(output, (*pnamelist)->d_name, link_prefix, details_open, macro_body, footer_permalink_text, - permalink_url, ext_in_permalink); + permalink_url, ext_in_permalink, list_only); details_open = 0; pnamelist++; names_output++; + /*if (list_only) + print_output(output, "</li>\n");*/ } /*print_output(output, "\n");*/ output_firstcol = 1; @@ -1727,46 +1844,87 @@ process_incdir(FILE* output, const u8* token, const u8* link_prefix, int url_is_local(const char* url); -int -process_timestamp(FILE* output, const u8* link_prefix, const char* link, - const u8* permalink_macro, const u8* date, const u8* title, - const int ext_in_permalink) +u8* +format_date(const u8* date_arg, const char* timestamp_format) { + const char* ptimestamp_format = NULL; u8* day = NULL; u8* month = NULL; u8* year = NULL; u8* formatted_date = NULL; u8* ptr = NULL; - const char* ptimestamp_format = NULL; - char* in_filename = NULL; - char* in_line = NULL; + u8* date = NULL; + + date = (u8*)strdup((const char*)date_arg); + if (!date) + goto format_date_cleanup; CALLOC(formatted_date, u8, DATEBUFSIZE); ptr = NULL; year = (u8*)strtok_r((char*)date, "-", (char**)&ptr); if (!year) - goto process_timestamp_cleanup; + goto format_date_cleanup; month = (u8*)strtok_r(NULL, "-", (char**)&ptr); if (!month) - goto process_timestamp_cleanup; + goto format_date_cleanup; day = (u8*)strtok_r(NULL, "T", (char**)&ptr); if (!day) - goto process_timestamp_cleanup; + goto format_date_cleanup; ptimestamp_format = timestamp_format; while (*ptimestamp_format) { if (*ptimestamp_format == 'd' || *ptimestamp_format == 'D') - strcat((char*)formatted_date, (char*)day); + { + if (strlcat((char*)formatted_date, (char*)day, + DATEBUFSIZE) + > DATEBUFSIZE) + warning(1, (u8*)"strlcat:%d: Overflow", + __LINE__); + } else if (*ptimestamp_format == 'm' || *ptimestamp_format == 'M') - strcat((char*)formatted_date, (char*)month); + { + if (strlcat((char*)formatted_date, (char*)month, + DATEBUFSIZE) + > DATEBUFSIZE) + warning(1, (u8*)"strlcat:%d: Overflow", + __LINE__); + } else if (*ptimestamp_format == 'y' || *ptimestamp_format == 'Y') - strcat((char*)formatted_date, (char*)year); + { + if (strlcat((char*)formatted_date, (char*)year, + DATEBUFSIZE) + > DATEBUFSIZE) + warning(1, (u8*)"strlcat:%d: Overflow", + __LINE__); + } else *(formatted_date + strlen((char*)formatted_date)) = *ptimestamp_format; ptimestamp_format++; } + return formatted_date; + +format_date_cleanup: + free(formatted_date); + free(date); + + return NULL; +} + +int +process_timestamp(FILE* output, const u8* link_prefix, const char* link, + const u8* permalink_macro, const u8* date, const u8* title, + const int ext_in_permalink) +{ + char* in_filename = NULL; + char* in_line = NULL; + u8* formatted_date = NULL; + + formatted_date = format_date(date, timestamp_format); + if (!formatted_date) + goto process_timestamp_cleanup; + print_output(output, "=> %s%s%s%s\t%s %s\n", url_is_local(link) && global_link_prefix ? (const char*)global_link_prefix @@ -1776,8 +1934,8 @@ process_timestamp(FILE* output, const u8* link_prefix, const char* link, link, ext_in_permalink ? timestamp_output_ext : "", formatted_date, title ? (const char*)title : ""); output_firstcol = 1; -process_timestamp_cleanup: +process_timestamp_cleanup: free(formatted_date); free(in_line); free(in_filename); @@ -1815,7 +1973,9 @@ process_macro_def(FILE* output, const u8* token, pmacros = macros + macros_count - 1; } CALLOC(pmacros->key, u8, KEYSIZE); - strcpy((char*)pmacros->key, (char*)token + 2); + if (strlcpy((char*)pmacros->key, (char*)token + 2, KEYSIZE) + >= KEYSIZE) + warning(1, (u8*)"strlcpy:%d: Overflow", __LINE__); pmacros->value = NULL; pmacros->value_size = 0; } @@ -1832,7 +1992,7 @@ process_macro(FILE* output, const u8* token, const int end_tag) u8* eol; size_t macro_body_len; - macro_body = get_value(macros, macros_count, token + 1); + macro_body = get_value(macros, macros_count, token + 1, NULL); if (!macro_body) exit(error(1, (u8*)"Macro '%s' undefined", token + 1)); @@ -2232,8 +2392,10 @@ process_inline_footnote(const u8* token, const int read_yaml_macros_and_links, CALLOC(inline_footnotes[inline_footnote_count - 1], u8, token_len + 1); - strcpy((char*)inline_footnotes[inline_footnote_count - 1], - (char*)token); + if (strlcpy((char*)inline_footnotes[inline_footnote_count - 1], + (char*)token, token_len + 1) + >= token_len + 1) + warning(1, (u8*)"strlcpy:%d: Overflow", __LINE__); *(inline_footnotes[inline_footnote_count - 1] + token_len) = 0; } else @@ -2269,7 +2431,9 @@ process_footnote(FILE* output, const u8* token, const int footnote_definition, pfootnotes = footnotes + footnote_count - 1; } CALLOC(pfootnotes->key, u8, KEYSIZE); - strcpy((char*)pfootnotes->key, (char*)token); + if (strlcpy((char*)pfootnotes->key, (char*)token, KEYSIZE) + >= KEYSIZE) + warning(1, (u8*)"strlcpy:%d: Overflow", __LINE__); pfootnotes->value = NULL; pfootnotes->value_size = 0; } @@ -2328,8 +2492,10 @@ begin_article(FILE* output, const char* source_filename, const u8* link_prefix, { char* link = strip_ext((const char*)source_filename); - if (ext_in_permalink) - strcat(link, timestamp_output_ext); + if (ext_in_permalink + && strlcat(link, timestamp_output_ext, sizeof link) + > sizeof link) + warning(1, (u8*)"strlcat:%d: Overflow", __LINE__); free(link); } @@ -2453,10 +2619,18 @@ simple_parse_yaml_line(const u8* line, KeyValue** vars, size_t* vars_count, *pvars = *vars + *vars_count - 1; } CALLOC((*pvars)->key, u8, KEYSIZE); - strcpy((char*)(*pvars)->key, (char*)var_key); + if (strlcpy((char*)(*pvars)->key, (char*)var_key, + KEYSIZE) + >= KEYSIZE) + warning(1, (u8*)"strlcpy:%d: Overflow", + __LINE__); (*pvars)->value_size = strlen((char*)token) + 1; CALLOC((*pvars)->value, u8, (*pvars)->value_size); - strcpy((char*)(*pvars)->value, (char*)token); + if (strlcpy((char*)(*pvars)->value, (char*)token, + (*pvars)->value_size) + >= (*pvars)->value_size) + warning(1, (u8*)"strlcpy:%d: Overflow", + __LINE__); } } free(var_key); @@ -2468,22 +2642,26 @@ int slweb_parse(FILE* output, const char* source_filename, const u8* buffer, const int read_yaml_macros_and_links) { - u8* title = NULL; - u8* title_heading_level = NULL; - u8* header_text = NULL; - u8* author = NULL; - u8* date = NULL; - u8* permalink_url = NULL; - u8* ext_in_permalink = NULL; - u8* var_add_article_header = NULL; - u8* var_add_footnote_div = NULL; - u8* footer_permalink_text = NULL; - u8* var_incdir_only_summary = NULL; + u8* title = NULL; + u8* title_heading_level = NULL; + u8* header_text = NULL; + u8* author = NULL; + u8* date = NULL; + u8* permalink_url = NULL; + u8* ext_in_permalink = NULL; + u8* var_add_article_header = NULL; + /*u8* var_add_image_links = NULL; + u8* var_add_figcaption = NULL;*/ + u8* var_add_footnote_div = NULL; + u8* footer_permalink_text = NULL; + u8* var_incdir_only_summary = NULL; + /*u8* image_file_prefix = NULL;*/ u8* link_prefix = NULL; const u8* pbuffer = NULL; u8* line = NULL; u8* pline = NULL; size_t line_len = 0; + size_t line_size = 0; u8* token = NULL; u8* ptoken = NULL; size_t token_size = 0; @@ -2499,37 +2677,50 @@ slweb_parse(FILE* output, const char* source_filename, const u8* buffer, int previous_line_blank = 0; int previous_line_block = 0; int processed_start_of_line = 0; - int add_footnote_div = 0; - int list_para = 0; - int footnote_at_line_start = 0; - size_t pline_len = 0; - int madeby_present = 0; + /*int add_image_links = 1; + int add_figcaption = 1;*/ + int add_footnote_div = 0; + int list_para = 0; + int footnote_at_line_start = 0; + size_t pline_len = 0; + int madeby_present = 0; + u8* eol = NULL; if (!buffer) exit(error(1, (u8*)"Empty buffer")); - title = get_value(vars, vars_count, (u8*)"title"); + title = get_value(vars, vars_count, (u8*)"title", NULL); title_heading_level - = get_value(vars, vars_count, (u8*)"title-heading-level"); - header_text = get_value(vars, vars_count, (u8*)"header-text"); - author = get_value(vars, vars_count, (u8*)"author"); - date = get_value(vars, vars_count, (u8*)"date"); - permalink_url = get_value(vars, vars_count, (u8*)"permalink-url"); - ext_in_permalink = get_value(vars, vars_count, (u8*)"ext-in-permalink"); + = get_value(vars, vars_count, (u8*)"title-heading-level", NULL); + header_text = get_value(vars, vars_count, (u8*)"header-text", NULL); + author = get_value(vars, vars_count, (u8*)"author", NULL); + date = get_value(vars, vars_count, (u8*)"date", NULL); + permalink_url = get_value(vars, vars_count, (u8*)"permalink-url", NULL); + /*image_file_prefix + = get_value(vars, vars_count, (u8*)"image-file-prefix", NULL);*/ + ext_in_permalink + = get_value(vars, vars_count, (u8*)"ext-in-permalink", NULL); var_add_article_header - = get_value(vars, vars_count, (u8*)"add-article-header"); + = get_value(vars, vars_count, (u8*)"add-article-header", NULL); + /*var_add_image_links + = get_value(vars, vars_count, (u8*)"add-image-links", NULL); + add_image_links = !(var_add_image_links && *var_add_image_links == '0'); + var_add_figcaption + = get_value(vars, vars_count, (u8*)"add-figcaption", NULL); + add_figcaption = !(var_add_figcaption && *var_add_figcaption == '0');*/ var_add_footnote_div - = get_value(vars, vars_count, (u8*)"add-footnote-div"); + = get_value(vars, vars_count, (u8*)"add-footnote-div", NULL); add_footnote_div = var_add_footnote_div && *var_add_footnote_div == '1'; - link_prefix = get_value(vars, vars_count, (u8*)"link-prefix"); + link_prefix = get_value(vars, vars_count, (u8*)"link-prefix", NULL); footer_permalink_text = get_value(vars, vars_count, - (u8*)"incdir-footer-permalink-text"); + (u8*)"incdir-footer-permalink-text", NULL); var_incdir_only_summary - = get_value(vars, vars_count, (u8*)"incdir-only-summary"); + = get_value(vars, vars_count, (u8*)"incdir-only-summary", NULL); incdir_only_summary = var_incdir_only_summary && *var_incdir_only_summary == '1'; - CALLOC(line, u8, BUFSIZE); + line_size = BUFSIZE; + CALLOC(line, u8, line_size); token_size = BUFSIZE; CALLOC(token, u8, BUFSIZE); CALLOC(link_macro, u8, BUFSIZE); @@ -2553,15 +2744,19 @@ slweb_parse(FILE* output, const char* source_filename, const u8* buffer, RESET_TOKEN(token, ptoken, token_size); output_firstcol = 1; -do_buffer:; - u8* eol = (u8*)strchr((char*)pbuffer, '\n'); + +do_buffer: + eol = (u8*)strchr((char*)pbuffer, '\n'); if (!eol) goto done_buffer; pline = line; while (pbuffer != eol) - *pline++ = *pbuffer++; - pbuffer++; + CHECKCOPY(line, pline, line_size, pbuffer); + + if (pbuffer == eol) + pbuffer++; + *pline = 0; pline = line; line_len = strlen((char*)line); @@ -2690,7 +2885,10 @@ do_line: pvars = vars + vars_count - 1; } CALLOC(pvars->key, u8, KEYSIZE); - strcpy((char*)pvars->key, (char*)token); + if (strlcpy((char*)pvars->key, (char*)token, KEYSIZE) + >= KEYSIZE) + warning(1, (u8*)"strlcpy:%d: Overflow", + __LINE__); pvars->value = NULL; pvars->value_size = 0; @@ -2748,7 +2946,11 @@ do_line: if (token_len + entity_len < BUFSIZE) { - strcat((char*)token, (char*)entity); + if (strlcat((char*)token, (char*)entity, + token_size) + > token_size) + warning(1, (u8*)"strlcat:%d: Overflow", + __LINE__); ptoken += entity_len; } } @@ -2789,7 +2991,11 @@ do_line: if (token_len + entity_len < BUFSIZE) { - strcat((char*)token, (char*)entity); + if (strlcat((char*)token, (char*)entity, + token_size) + > token_size) + warning(1, (u8*)"strlcat:%d: Overflow", + __LINE__); ptoken += entity_len; } } @@ -2831,7 +3037,11 @@ do_line: if (token_len + tag_len < BUFSIZE) { - strcat((char*)token, (char*)tag); + if (strlcat((char*)token, (char*)tag, + token_size) + > token_size) + warning(1, (u8*)"strlcat:%d: Overflow", + __LINE__); ptoken += tag_len; } } @@ -3363,7 +3573,11 @@ do_line: if (strlen((char*)pline) == 2 && *(pline + 1) == ' ') { *ptoken = 0; - strcat((char*)ptoken, "\n"); + if (strlcat((char*)ptoken, "\n", + token_size - (ptoken - token)) + > token_size - (ptoken - token)) + warning(1, (u8*)"strlcat:%d: Overflow", + __LINE__); ptoken++; output_firstcol = 1; pline += 2; @@ -3372,7 +3586,10 @@ do_line: else if (IN(state, ST_LINK_MACRO)) { *ptoken = 0; - strncpy((char*)link_macro, (char*)token, BUFSIZE - 1); + if (strlcpy((char*)link_macro, (char*)token, BUFSIZE) + >= BUFSIZE) + warning(1, (u8*)"strlcpy:%d: Overflow", + __LINE__); *(link_macro + strlen((char*)token)) = 0; RESET_TOKEN(token, ptoken, token_size); state &= ~ST_LINK_MACRO; @@ -3427,18 +3644,24 @@ do_line: REALLOC(pmacros->value, u8, pmacros->value_size); } - strncat((char*)pmacros->value, - (char*)token, - pmacros->value_size - 1); + if (strlcat((char*)pmacros->value, + (char*)token, + pmacros->value_size) + > pmacros->value_size) + warning(1, (u8*)"strlcat:%d: Overflow", + __LINE__); } else { pmacros->value_size = token_len + 1; CALLOC(pmacros->value, u8, pmacros->value_size); - strncpy((char*)pmacros->value, - (char*)token, - pmacros->value_size - 1); + if (strlcpy((char*)pmacros->value, + (char*)token, + pmacros->value_size) + >= pmacros->value_size) + warning(1, (u8*)"strlcpy:%d: Overflow", + __LINE__); } } } @@ -4031,6 +4254,7 @@ do_line: RESET_TOKEN(token, ptoken, token_size); state &= ~(ST_LINK | ST_LINK_SECOND_ARG | ST_IMAGE | ST_IMAGE_SECOND_ARG); + /* Difference from slweb: could be NULL */ if (pline) pline++; } @@ -4100,7 +4324,8 @@ do_line: { if (!read_yaml_macros_and_links) { - u8* url = get_value(links, links_count, token); + u8* url = get_value(links, links_count, token, + NULL); if (!url) exit(error(EINVAL, (u8*)"get_" @@ -4144,6 +4369,7 @@ do_line: } RESET_TOKEN(token, ptoken, token_size); state &= ~(ST_LINK | ST_LINK_SECOND_ARG); + /* Difference from slweb: could be NULL */ if (pline) { pline++; @@ -4154,7 +4380,8 @@ do_line: { if (!read_yaml_macros_and_links) { - u8* url = get_value(links, links_count, token); + u8* url = get_value(links, links_count, token, + NULL); if (!url) exit(error(EINVAL, (u8*)"get_" @@ -4198,6 +4425,7 @@ do_line: } RESET_TOKEN(token, ptoken, token_size); state &= ~(ST_IMAGE | ST_IMAGE_SECOND_ARG); + /* Difference from slweb: could be NULL */ if (pline) { pline++; @@ -4224,7 +4452,11 @@ do_line: plinks = links + links_count - 1; } CALLOC(plinks->key, u8, KEYSIZE); - strcpy((char*)plinks->key, (char*)token); + if (strlcpy((char*)plinks->key, (char*)token, + KEYSIZE) + >= KEYSIZE) + warning(1, (u8*)"strlcpy:%d: Overflow", + __LINE__); plinks->value = NULL; plinks->value_size = 0; pline += 2; @@ -4253,7 +4485,11 @@ do_line: link_size = token_len + 1; CALLOC(link_text, u8, link_size); } - strcpy((char*)link_text, (char*)token); + if (strlcpy((char*)link_text, (char*)token, + link_size) + >= link_size) + warning(1, (u8*)"strlcpy:%d: Overflow", + __LINE__); *(link_text + token_len) = 0; pline += 2; colno += 2; @@ -4539,7 +4775,9 @@ done_line: } pvars->value_size = strlen((char*)token) + 1; CALLOC(pvars->value, u8, pvars->value_size); - strcpy((char*)pvars->value, (char*)token); + if (strlcpy((char*)pvars->value, (char*)token, pvars->value_size) + >= pvars->value_size) + warning(1, (u8*)"strlcpy:%d: Overflow", __LINE__); } else if (keep_token) { @@ -4550,8 +4788,11 @@ done_line: REALLOC(token, u8, token_size); ptoken = token + old_size - 1; } - strcat((char*)token, - ANY(state, ST_IMAGE | ST_LINK) ? " " : "\n"); + if (strlcat((char*)token, + ANY(state, ST_IMAGE | ST_LINK) ? " " : "\n", + token_size) + > token_size) + warning(1, (u8*)"strlcat:%d: Overflow", __LINE__); ptoken++; *ptoken = 0; } @@ -4584,18 +4825,34 @@ done_line: REALLOC(pmacros->value, u8, pmacros->value_size); } - strcat((char*)pmacros->value, - (char*)token); - strcat((char*)pmacros->value, " "); + if (strlcat((char*)pmacros->value, + (char*)token, + pmacros->value_size) + > pmacros->value_size) + warning(1, (u8*)"strlcat:%d: Overflow", + __LINE__); + if (strlcat((char*)pmacros->value, " ", + pmacros->value_size) + > pmacros->value_size) + warning(1, (u8*)"strlcat:%d: Overflow", + __LINE__); } else { pmacros->value_size = BUFSIZE; CALLOC(pmacros->value, u8, pmacros->value_size); - strcpy((char*)pmacros->value, - (char*)token); - strcat((char*)pmacros->value, " "); + if (strlcpy((char*)pmacros->value, + (char*)token, + pmacros->value_size) + >= pmacros->value_size) + warning(1, (u8*)"strlcpy:%d: Overflow", + __LINE__); + if (strlcat((char*)pmacros->value, " ", + pmacros->value_size) + > pmacros->value_size) + warning(1, (u8*)"strlcat:%d: Overflow", + __LINE__); } skip_macro_read:; } @@ -4624,18 +4881,34 @@ done_line: REALLOC(pfootnotes->value, u8, pfootnotes->value_size); } - strcat((char*)pfootnotes->value, - (char*)token); - strcat((char*)pfootnotes->value, " "); + if (strlcat((char*)pfootnotes->value, + (char*)token, + pfootnotes->value_size) + > pfootnotes->value_size) + warning(1, (u8*)"strlcat:%d: Overflow", + __LINE__); + if (strlcat((char*)pfootnotes->value, + " ", pfootnotes->value_size) + > pfootnotes->value_size) + warning(1, (u8*)"strlcat:%d: Overflow", + __LINE__); } else { pfootnotes->value_size = BUFSIZE; CALLOC(pfootnotes->value, u8, pfootnotes->value_size); - strcpy((char*)pfootnotes->value, - (char*)token); - strcat((char*)pfootnotes->value, " "); + if (strlcpy((char*)pfootnotes->value, + (char*)token, + pfootnotes->value_size) + >= pfootnotes->value_size) + warning(1, (u8*)"strlcpy:%d: Overflow", + __LINE__); + if (strlcat((char*)pfootnotes->value, + " ", pfootnotes->value_size) + > pfootnotes->value_size) + warning(1, (u8*)"strlcat:%d: Overflow", + __LINE__); } *token = 0; ptoken = token; @@ -4658,8 +4931,12 @@ done_line: = strlen((char*)token) + 1; CALLOC(plinks->value, u8, plinks->value_size); - strcpy((char*)plinks->value, - (char*)token); + if (strlcpy((char*)plinks->value, + (char*)token, + plinks->value_size) + >= plinks->value_size) + warning(1, (u8*)"strlcpy:%d: Overflow", + __LINE__); } } else if (IN(state, ST_HEADING)) @@ -4689,11 +4966,11 @@ done_line: { if (IN(state, ST_PARA_OPEN)) { - if (!read_yaml_macros_and_links) + /*if (!read_yaml_macros_and_links) { - /*print_output(output, "\n;"); - output_firstcol = 1;*/ - } + print_output(output, "\n;"); + output_firstcol = 1; + }*/ if (IN(state, ST_LIST)) skip_eol = 1; state &= ~ST_PARA_OPEN; @@ -4768,16 +5045,24 @@ done_line: REALLOC(pfootnotes->value, u8, pfootnotes->value_size); } - strcat((char*)pfootnotes->value, - (char*)token); + if (strlcat((char*)pfootnotes->value, + (char*)token, + pfootnotes->value_size) + > pfootnotes->value_size) + warning(1, (u8*)"strlcat:%d: Overflow", + __LINE__); } else { pfootnotes->value_size = token_len + 1; CALLOC(pfootnotes->value, u8, pfootnotes->value_size); - strcpy((char*)pfootnotes->value, - (char*)token); + if (strlcpy((char*)pfootnotes->value, + (char*)token, + pfootnotes->value_size) + >= pfootnotes->value_size) + warning(1, (u8*)"strlcpy:%d: Overflow", + __LINE__); } *token = 0; ptoken = token; @@ -4881,16 +5166,16 @@ done_line: if (pbuffer && *pbuffer) goto do_buffer; done_buffer: - if (!read_yaml_macros_and_links - && (footnote_count > 0 || inline_footnote_count > 0)) - end_footnotes(output, link_prefix, add_footnote_div, - previous_line_blank, read_yaml_macros_and_links); - - if (!read_yaml_macros_and_links && (paralinks_count > 0)) - process_paralinks(output, link_prefix); - if (!read_yaml_macros_and_links) { + if (footnote_count > 0 || inline_footnote_count > 0) + end_footnotes(output, link_prefix, add_footnote_div, + previous_line_blank, + read_yaml_macros_and_links); + + if (paralinks_count > 0) + process_paralinks(output, link_prefix); + if (madeby_present) { process_madeby(output); @@ -5047,7 +5332,10 @@ main(const int argc, const char** argv) buffer_size += BUFSIZE; REALLOC(buffer, u8, buffer_size); } - strcat((char*)buffer, (char*)bufline); + if (strlcat((char*)buffer, (char*)bufline, buffer_size) + > buffer_size) + warning(1, (u8*)"strlcat:%d: Overflow", + __LINE__); buffer_len += bufline_len; } free(bufline); diff --git a/slw2gmi.do b/slw2gmi.do @@ -1,10 +0,0 @@ -. ./config.redo -for f in *.h.in; do - echo $f | sed -e's/\.in$//g' -done | xargs redo-ifchange -for f in *.h *.c; do - echo $f - echo $f | sed -e's/\.c$/.o/g' -done | xargs redo-ifchange -${CC} -o $3 slw2gmi.o utf8.o -${STRIP} $3 diff --git a/strlcat.c b/strlcat.c @@ -0,0 +1,54 @@ +/* $OpenBSD: strlcat.c,v 1.9 2019/01/25 00:19:26 millert Exp $ */ + +/* + * Copyright (c) 1998, 2015 Todd C. Miller <millert@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <string.h> + +/* + * Appends src to string dst of size dsize (unlike strncat, dsize is the + * full size of dst, not space left). At most dsize-1 characters + * will be copied. Always NUL terminates (unless dsize <= strlen(dst)). + * Returns strlen(src) + MIN(dsize, strlen(initial dst)). + * If retval >= siz, truncation occurred. + */ +size_t +strlcat(char *dst, const char *src, size_t dsize) +{ + const char *odst = dst; + const char *osrc = src; + size_t n = dsize; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end. */ + while (n-- != 0 && *dst != '\0') + dst++; + dlen = dst - odst; + n = dsize - dlen; + + if (n-- == 0) + return(dlen + strlen(src)); + while (*src != '\0') { + if (n != 0) { + *dst++ = *src; + n--; + } + src++; + } + *dst = '\0'; + + return(dlen + (src - osrc)); /* count does not include NUL */ +} diff --git a/strlcpy.c b/strlcpy.c @@ -0,0 +1,49 @@ +/* $OpenBSD: strlcpy.c,v 1.9 2019/01/25 00:19:26 millert Exp $ */ + +/* + * Copyright (c) 1998, 2015 Todd C. Miller <millert@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <string.h> + +/* + * Copy string src to buffer dst of size dsize. At most dsize-1 + * chars will be copied. Always NUL terminates (unless dsize == 0). + * Returns strlen(src); if retval >= dsize, truncation occurred. + */ +size_t +strlcpy(char *dst, const char *src, size_t dsize) +{ + const char *osrc = src; + size_t nleft = dsize; + + /* Copy as many bytes as will fit. */ + if (nleft != 0) { + while (--nleft != 0) { + if ((*dst++ = *src++) == '\0') + break; + } + } + + /* Not enough room in dst, add NUL and traverse rest of src. */ + if (nleft == 0) { + if (dsize != 0) + *dst = '\0'; /* NUL-terminate dst */ + while (*src++) + ; + } + + return(src - osrc - 1); /* count does not include NUL */ +} diff --git a/uninstall.do b/uninstall.do @@ -1,10 +0,0 @@ -. ./config.redo -for docfile in $DOCS; do - rm -f "${DOCDIR}/${docfile}" -done -for binfile in $PROGS; do - rm -f "${BINDIR}/${binfile}" -done -for manfile in $MANPAGES; do - rm -f "${MANPREFIX}/man1/${manfile}" -done diff --git a/utf8.c b/utf8.c @@ -1,5 +1,5 @@ /* This program is licensed under the terms of GNU GPL v3 or (at your option) - * any later version. Copyright (C) 2021-2023 Страхиња Радић. + * any later version. Copyright (C) 2021-2024 Страхиња Радић. * See the file LICENSE for exact copyright and license details. */ #include "utf8.h" diff --git a/utf8.h b/utf8.h @@ -1,5 +1,5 @@ /* This program is licensed under the terms of GNU GPL v3 or (at your option) - * any later version. Copyright (C) 2021-2023 Страхиња Радић. + * any later version. Copyright (C) 2021-2024 Страхиња Радић. * See the file LICENSE for exact copyright and license details. */ #include <stdint.h> diff --git a/version.do b/version.do @@ -1,17 +0,0 @@ -FALLBACKVER=${FALLBACKVER:-unknown} -LC_ALL=C -export LC_ALL -user=$(unalias ls >/dev/null 2>&1 || true; \ - command ls -ld . | awk '{print $3}') -e_user=$(id -un) -if [ -d .git ] && command -v git >/dev/null 2>&1; then - if [ "$e_user" = "$user" ]; then - git describe 2>/dev/null | sed 's/^v//' >$3 - else - su "${user}" -c 'git describe' 2>/dev/null | sed 's/^v//' >$3 - fi -else - printf "%s\n" "$FALLBACKVER" >$3 -fi -redo-always -redo-stamp <$3 diff --git a/version.h.in b/version.h.in @@ -1,5 +1,5 @@ /* This program is licensed under the terms of GNU GPL v3 or (at your option) - * any later version. Copyright (C) 2021-2023 Страхиња Радић. + * any later version. Copyright (C) 2021-2024 Страхиња Радић. * See the file LICENSE for exact copyright and license details. */ #define PROGRAMNAME "slw2gmi"