diff options
| author | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-02 18:25:12 +0300 |
|---|---|---|
| committer | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-02 18:25:12 +0300 |
| commit | 0e49ba0e7b8b9bc8bdc61f8c80228252392e758e (patch) | |
| tree | e20be9b031f07f02879f21c9e23ef57869534dd7 /corebinutils/echo | |
| parent | 46f7aa5f7802807c850fcfdd3ec1e2072f7e9d94 (diff) | |
| parent | 74324d021b4424d2b9b21a8593f4c7680837a275 (diff) | |
| download | Project-Tick-0e49ba0e7b8b9bc8bdc61f8c80228252392e758e.tar.gz Project-Tick-0e49ba0e7b8b9bc8bdc61f8c80228252392e758e.zip | |
Add 'corebinutils/echo/' from commit '74324d021b4424d2b9b21a8593f4c7680837a275'
git-subtree-dir: corebinutils/echo
git-subtree-mainline: 46f7aa5f7802807c850fcfdd3ec1e2072f7e9d94
git-subtree-split: 74324d021b4424d2b9b21a8593f4c7680837a275
Diffstat (limited to 'corebinutils/echo')
| -rw-r--r-- | corebinutils/echo/.gitignore | 25 | ||||
| -rw-r--r-- | corebinutils/echo/GNUmakefile | 35 | ||||
| -rw-r--r-- | corebinutils/echo/LICENSE | 32 | ||||
| -rw-r--r-- | corebinutils/echo/LICENSES/BSD-3-Clause.txt | 11 | ||||
| -rw-r--r-- | corebinutils/echo/README.md | 39 | ||||
| -rw-r--r-- | corebinutils/echo/echo.1 | 139 | ||||
| -rw-r--r-- | corebinutils/echo/echo.c | 120 | ||||
| -rw-r--r-- | corebinutils/echo/tests/test.sh | 124 |
8 files changed, 525 insertions, 0 deletions
diff --git a/corebinutils/echo/.gitignore b/corebinutils/echo/.gitignore new file mode 100644 index 0000000000..a74d30b48c --- /dev/null +++ b/corebinutils/echo/.gitignore @@ -0,0 +1,25 @@ +*.a +*.core +*.lo +*.nossppico +*.o +*.orig +*.pico +*.pieo +*.po +*.rej +*.so +*.so.[0-9]* +*.sw[nop] +*~ +.*DS_Store +.cache +.clangd +.ccls-cache +.depend* +compile_commands.json +compile_commands.events.json +tags +build/ +out/ +.linux-obj/ diff --git a/corebinutils/echo/GNUmakefile b/corebinutils/echo/GNUmakefile new file mode 100644 index 0000000000..9cffad8fe0 --- /dev/null +++ b/corebinutils/echo/GNUmakefile @@ -0,0 +1,35 @@ +.DEFAULT_GOAL := all + +CC ?= cc +CPPFLAGS += -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 +CFLAGS ?= -O2 +CFLAGS += -std=c17 -g -Wall -Wextra -Wpedantic -Wno-unused-parameter +LDFLAGS ?= +LDLIBS ?= + +OBJDIR := $(CURDIR)/build +OUTDIR := $(CURDIR)/out +TARGET := $(OUTDIR)/echo +OBJS := $(OBJDIR)/echo.o + +.PHONY: all clean dirs test status + +all: $(TARGET) + +dirs: + @mkdir -p "$(OBJDIR)" "$(OUTDIR)" + +$(TARGET): $(OBJS) | dirs + $(CC) $(LDFLAGS) -o "$@" $(OBJS) $(LDLIBS) + +$(OBJDIR)/echo.o: $(CURDIR)/echo.c | dirs + $(CC) $(CPPFLAGS) $(CFLAGS) -c "$(CURDIR)/echo.c" -o "$@" + +test: $(TARGET) + ECHO_BIN="$(TARGET)" sh "$(CURDIR)/tests/test.sh" + +status: + @printf '%s\n' "$(TARGET)" + +clean: + @rm -rf "$(CURDIR)/build" "$(CURDIR)/out" diff --git a/corebinutils/echo/LICENSE b/corebinutils/echo/LICENSE new file mode 100644 index 0000000000..edea21b918 --- /dev/null +++ b/corebinutils/echo/LICENSE @@ -0,0 +1,32 @@ +Copyright (c) 1989, 1993 + The Regents of the University of California. All rights reserved. + +Copyright (c) 2026 + Project Tick. All rights reserved. + +This code is derived from software contributed to Berkeley by +the Institute of Electrical and Electronics Engineers, Inc. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. 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. +3. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. diff --git a/corebinutils/echo/LICENSES/BSD-3-Clause.txt b/corebinutils/echo/LICENSES/BSD-3-Clause.txt new file mode 100644 index 0000000000..ea890afbc7 --- /dev/null +++ b/corebinutils/echo/LICENSES/BSD-3-Clause.txt @@ -0,0 +1,11 @@ +Copyright (c) <year> <owner>. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +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. diff --git a/corebinutils/echo/README.md b/corebinutils/echo/README.md new file mode 100644 index 0000000000..af99e2432b --- /dev/null +++ b/corebinutils/echo/README.md @@ -0,0 +1,39 @@ +# echo + +Standalone musl-libc-based Linux port of FreeBSD `echo` for Project Tick BSD/Linux Distribution. + +## Build + +```sh +gmake -f GNUmakefile +gmake -f GNUmakefile CC=musl-gcc +``` + +Binary output: + +```sh +out/echo +``` + +## Test + +```sh +gmake -f GNUmakefile test +``` + +## Port Strategy + +- The standalone layout matches sibling Linux ports such as `bin/cat` and `bin/chmod`. +- FreeBSD Capsicum entry points were removed instead of stubbed; this utility only needs stdout and writes directly through `write(2)`. +- The Linux port no longer batches output with `writev(2)`. It streams arguments with a retry-safe `write(2)` loop, which avoids `IOV_MAX` handling and correctly deals with partial writes on Linux and musl. + +## Supported Semantics On Linux + +- A single leading literal `-n` suppresses the trailing newline. +- A trailing `\c` only has special meaning when it appears at the end of the final operand; it suppresses the trailing newline and is not printed. +- `--` is not treated as an end-of-options marker and is printed literally. + +## Intentionally Unsupported Semantics + +- GNU `echo` option parsing is not implemented. `-e`, `-E`, `--help`, and `--version` are treated as literal operands, matching FreeBSD `echo` rather than GNU coreutils. +- Backslash escape processing other than the historical final-operand `\c` rule is not supported. diff --git a/corebinutils/echo/echo.1 b/corebinutils/echo/echo.1 new file mode 100644 index 0000000000..afc7567059 --- /dev/null +++ b/corebinutils/echo/echo.1 @@ -0,0 +1,139 @@ +.\"- +.\" Copyright (c) 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Copyright (c) 2026 +.\" Project Tick. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, Inc. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. 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. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. +.\" +.Dd October 5, 2016 +.Dt ECHO 1 +.Os +.Sh NAME +.Nm echo +.Nd write arguments to the standard output +.Sh SYNOPSIS +.Nm +.Op Fl n +.Op Ar string ... +.Sh DESCRIPTION +The +.Nm +utility writes any specified operands, separated by single blank +.Pq Ql "\ " +characters and followed by a newline +.Pq Ql \en +character, to the standard +output. +.Pp +The following option is available: +.Bl -tag -width flag +.It Fl n +Do not print the trailing newline character. +.El +.Pp +The end-of-options marker +.Fl Fl +is not recognized and written literally. +.Pp +The newline may also be suppressed by appending +.Ql \ec +to the end of the string, as is done +by iBCS2 compatible systems. +Note that the +.Fl n +option as well as the effect of +.Ql \ec +are implementation-defined in +.St -p1003.1-2001 +as amended by Cor.\& 1-2002. +For portability, +.Nm +should only be used if the first argument does not start with a hyphen +.Pq Ql "-" +and does not contain any backslashes +.Pq Ql "\e" . +If this is not sufficient, +.Xr printf 1 +should be used. +.Pp +Most shells provide a builtin +.Nm +command which tends to differ from this utility +in the treatment of options and backslashes. +Consult the +.Xr builtin 1 +manual page. +.Sh EXIT STATUS +.Ex -std +.Sh EXAMPLES +Special treatment of options and backslashes: +.Bd -literal -offset indent +$ /bin/echo "-hello\\tworld" +-hello\tworld +.Ed +.Pp +Avoid new line character: +.Bd -literal -offset indent +$ /bin/echo -n hello;/bin/echo world +helloworld +.Ed +.Pp +Or to achieve the same result: +.Bd -literal -offset indent +$ /bin/echo "hello\\c";/bin/echo world +helloworld +.Ed +.Sh SEE ALSO +.Xr builtin 1 , +.Xr csh 1 , +.Xr printf 1 , +.Xr sh 1 +.Sh STANDARDS +The +.Nm +utility conforms to +.St -p1003.1-2001 +as amended by Cor.\& 1-2002. +.Sh HISTORY +The +.Nm +command appeared in +.At v2 . +.Sh CAVEATS +The +.Nm +command behaves differently with regards to the built-in +.Nm +shell command in a number of ways including escaped characters handling. +It also differs in behavior between different systems hence complicating writing +portable scripts. +It is advised to use the +.Xr printf 1 +command to avoid these shortcomings. diff --git a/corebinutils/echo/echo.c b/corebinutils/echo/echo.c new file mode 100644 index 0000000000..0074f968db --- /dev/null +++ b/corebinutils/echo/echo.c @@ -0,0 +1,120 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Copyright (c) 2026 + * Project Tick. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 <errno.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +static int +write_all(const char *data, size_t len) +{ + while (len > 0) { + ssize_t written; + + written = write(STDOUT_FILENO, data, len); + if (written < 0) { + if (errno == EINTR) + continue; + return -1; + } + data += (size_t)written; + len -= (size_t)written; + } + + return 0; +} + +static void +warn_errno(const char *context) +{ + fprintf(stderr, "echo: %s: %s\n", context, strerror(errno)); +} + +static bool +trim_trailing_backslash_c(const char *arg, size_t *len) +{ + if (*len < 2) + return false; + if (arg[*len - 2] != '\\' || arg[*len - 1] != 'c') + return false; + + *len -= 2; + return true; +} + +int +main(int argc, char *argv[]) +{ + bool suppress_newline; + int first_arg; + + suppress_newline = false; + first_arg = 1; + + /* + * FreeBSD echo intentionally does not use getopt(3); only a leading + * literal "-n" is treated as an option. + */ + if (argc > 1 && strcmp(argv[1], "-n") == 0) { + suppress_newline = true; + first_arg = 2; + } + + for (int i = first_arg; i < argc; i++) { + size_t len; + + len = strlen(argv[i]); + if (i == argc - 1 && trim_trailing_backslash_c(argv[i], &len)) + suppress_newline = true; + + if (write_all(argv[i], len) < 0) { + warn_errno("write"); + return 1; + } + + if (i + 1 < argc && write_all(" ", 1) < 0) { + warn_errno("write"); + return 1; + } + } + + if (!suppress_newline && write_all("\n", 1) < 0) { + warn_errno("write"); + return 1; + } + + return 0; +} diff --git a/corebinutils/echo/tests/test.sh b/corebinutils/echo/tests/test.sh new file mode 100644 index 0000000000..edd12e877b --- /dev/null +++ b/corebinutils/echo/tests/test.sh @@ -0,0 +1,124 @@ +#!/bin/sh +# +# Copyright (c) 2026 +# Project Tick. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. 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 AUTHOR 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 AUTHOR 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. +# +set -eu + +LC_ALL=C +LANG=C +export LC_ALL LANG + +ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd) +ECHO_BIN=${ECHO_BIN:-"$ROOT/out/echo"} +TMPDIR=${TMPDIR:-/tmp} +WORKDIR=$(mktemp -d "$TMPDIR/echo-test.XXXXXX") +trap 'rm -rf "$WORKDIR"' EXIT INT TERM + +fail() { + printf '%s\n' "FAIL: $1" >&2 + exit 1 +} + +assert_status() { + name=$1 + expected=$2 + actual=$3 + + [ "$expected" -eq "$actual" ] || fail "$name: expected exit $expected got $actual" +} + +assert_file_eq() { + name=$1 + expected_text=$2 + actual_file=$3 + expected_file=$WORKDIR/expected.$$ + + printf '%s' "$expected_text" > "$expected_file" + if ! cmp -s "$expected_file" "$actual_file"; then + printf '%s\n' "FAIL: $name" >&2 + printf '%s\n' "--- expected ---" >&2 + od -An -tx1 -v "$expected_file" >&2 + printf '%s\n' "--- actual ---" >&2 + od -An -tx1 -v "$actual_file" >&2 + exit 1 + fi +} + +run_case() { + name=$1 + expected_status=$2 + expected_stdout=$3 + expected_stderr=$4 + shift 4 + + stdout_file=$WORKDIR/stdout + stderr_file=$WORKDIR/stderr + + if "$ECHO_BIN" "$@" >"$stdout_file" 2>"$stderr_file"; then + status=0 + else + status=$? + fi + + assert_status "$name status" "$expected_status" "$status" + assert_file_eq "$name stdout" "$expected_stdout" "$stdout_file" + assert_file_eq "$name stderr" "$expected_stderr" "$stderr_file" +} + +[ -x "$ECHO_BIN" ] || fail "missing binary: $ECHO_BIN" + +run_case "no arguments" 0 " +" "" +run_case "basic output" 0 "hello world +" "" "hello" "world" +run_case "bare -n suppresses newline" 0 "" "" "-n" +run_case "single leading -n" 0 "hello world" "" "-n" "hello" "world" +run_case "second -n is literal" 0 "-n literal" "" "-n" "-n" "literal" +run_case "double hyphen stays literal" 0 "-- +" "" "--" +run_case "gnu-style -e stays literal" 0 "-e \t +" "" "-e" "\\t" +run_case "non-final backslash-c stays literal" 0 "left\\c right +" "" "left\\c" "right" +run_case "final backslash-c suppresses newline" 0 "hello" "" "hello\\c" +run_case "empty final backslash-c suppresses newline" 0 "" "" "\\c" + +stdout_file=$WORKDIR/write-fail.stdout +stderr_file=$WORKDIR/write-fail.stderr +if ( + exec 1>&- + "$ECHO_BIN" "write-test" +) >"$stdout_file" 2>"$stderr_file"; then + status=0 +else + status=$? +fi + +assert_status "write failure status" 1 "$status" +assert_file_eq "write failure stdout" "" "$stdout_file" +assert_file_eq "write failure stderr" "echo: write: Bad file descriptor +" "$stderr_file" + +printf '%s\n' "PASS" |
