ときどきの雑記帖 RE* (新南口)
船を出すのなら九月
今週のしずえさん
ベーグル(の作り方の特徴的な部分)
風雲→怒濤→回天
アイザック・モフモフ……じゃなかった、アイザック・アシモフ『銀河帝国の興亡1 風雲編』(創元SF文庫)、鍛治靖子先生による新訳版が本日発売ニャ。三部作ぜんぶ新訳になるので楽しみにしていてほしいニャ。もふもふ。(くらり) #東京創元社 #創元SF文庫 https://t.co/Gb1Hs7CVQG
— 東京創元社 (@tokyosogensha) August 31, 2021
風雲編についていた帯によれば、続刊は怒涛編、回天編であるらしい。
二進数を理解するためのそろばん
安野光雅美術館のショップで見つけて目がテンに→思わず買ってしまったもの。その名も「二進数を理解するためのそろばん」。安野さんが算盤専門店に依頼して作ってもらった特注品なのですって。写真の二進数100100111は十進法にすると295に。 pic.twitter.com/rlJvjmG4P7
— 芸術新潮 (@G_Shincho) September 1, 2021
おもしろい。 ところで安野光雅美術館ってどこにあるのだっけと調べてみたら
島根(津和野)かー。
test
前回のtestの話の続き。
さてこちらに関して Vidar Holen さんは「なぜ(GNU 版の)/bin/test は /bin/[ よりも 4キロバイトもファイルサイズが小さいのか?」 というというなかなかユニークな記事を書かれています。記事を読む前にその理由を考えてみてください。
その「ユニークな記事」はこちら、 Why is /usr/bin/test 4kiB smaller than /usr/bin/[ ? ? Vidar’s Blog
まず(testと[の)動作の違い。
kbk@toybox4:/mnt/c/Users/kbk$ ls -lh /usr/bin/{test,[}
-rwxr-xr-x 1 root root 51K Jan 18 2018 '/usr/bin/['
-rwxr-xr-x 1 root root 47K Jan 18 2018 /usr/bin/test
kbk@toybox4:/mnt/c/Users/kbk$ /usr/bin/[ --version
[ (GNU coreutils) 8.28
Copyright (C) 2017 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by Kevin Braunsdorf and Matthew Bradburn.
kbk@toybox4:/mnt/c/Users/kbk$ /usr/bin/test --version
kbk@toybox4:/mnt/c/Users/kbk$
ふむふむ。次にいつものようにソースコードへ。 古のGNU grepでは 自分がgrepという名で起動されたのか あるいはegrepという名で起動されたのかで 動作を変えていたりしていたけど (今はやっていないはず)、 testではどうなのか。
起動されたときの自分の名前で動作を切り替えるのは POSIX的にはよろしくないという話らしい (未確認。前述のGNU grepもそれで動作の切り替えを止めたと記憶しているけれど)。
coreutils/test.c at master · coreutils/coreutils
/* GNU test program (ksb and mjb) */
/* Modified to run with the GNU shell by bfox. */
/* Copyright (C) 1987-2021 Free Software Foundation, Inc.
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 Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
/* Define TEST_STANDALONE to get the /bin/test version. Otherwise, you get
the shell builtin version. */
/* Without this pragma, gcc 4.6.2 20111027 mistakenly suggests that
the advance function might be candidate for attribute 'pure'. */
#if (__GNUC__ == 4 && 6 <= __GNUC_MINOR__) || 4 < __GNUC__
# pragma GCC diagnostic ignored "-Wsuggest-attribute=pure"
#endif
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#define TEST_STANDALONE 1
#ifndef LBRACKET
# define LBRACKET 0
#endif
/* The official name of this program (e.g., no 'g' prefix). */
#if LBRACKET
# define PROGRAM_NAME "["
#else
# define PROGRAM_NAME "test"
#endif
#include "system.h"
#include "quote.h"
#include "stat-time.h"
#include "strnumcmp.h"
#include <stdarg.h>
#include "verror.h"
#if HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif
/* Exit status for syntax errors, etc. */
enum { TEST_TRUE, TEST_FALSE, TEST_FAILURE };
#if defined TEST_STANDALONE
# define test_exit(val) exit (val)
# define test_main_return(val) return val
#else
static jmp_buf test_exit_buf;
static int test_error_return = 0;
# define test_exit(val) test_error_return = val, longjmp (test_exit_buf, 1)
# define test_main_return(val) test_exit (val)
#endif /* !TEST_STANDALONE */
途中のオペレーターなどの処理部分は飛ばして、
#if defined TEST_STANDALONE
void
usage (int status)
{
if (status != EXIT_SUCCESS)
emit_try_help ();
else
{
fputs (_("\
Usage: test EXPRESSION\n\
or: test\n\
or: [ EXPRESSION ]\n\
or: [ ]\n\
or: [ OPTION\n\
"), stdout);
fputs (_("\
Exit with the status determined by EXPRESSION.\n\
\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
\n\
An omitted EXPRESSION defaults to false. Otherwise,\n\
EXPRESSION is true or false and sets exit status. It is one of:\n\
"), stdout);
fputs (_("\
\n\
( EXPRESSION ) EXPRESSION is true\n\
! EXPRESSION EXPRESSION is false\n\
EXPRESSION1 -a EXPRESSION2 both EXPRESSION1 and EXPRESSION2 are true\n\
EXPRESSION1 -o EXPRESSION2 either EXPRESSION1 or EXPRESSION2 is true\n\
"), stdout);
fputs (_("\
\n\
-n STRING the length of STRING is nonzero\n\
STRING equivalent to -n STRING\n\
-z STRING the length of STRING is zero\n\
STRING1 = STRING2 the strings are equal\n\
STRING1 != STRING2 the strings are not equal\n\
"), stdout);
fputs (_("\
\n\
INTEGER1 -eq INTEGER2 INTEGER1 is equal to INTEGER2\n\
INTEGER1 -ge INTEGER2 INTEGER1 is greater than or equal to INTEGER2\n\
INTEGER1 -gt INTEGER2 INTEGER1 is greater than INTEGER2\n\
INTEGER1 -le INTEGER2 INTEGER1 is less than or equal to INTEGER2\n\
INTEGER1 -lt INTEGER2 INTEGER1 is less than INTEGER2\n\
INTEGER1 -ne INTEGER2 INTEGER1 is not equal to INTEGER2\n\
"), stdout);
fputs (_("\
\n\
FILE1 -ef FILE2 FILE1 and FILE2 have the same device and inode numbers\n\
FILE1 -nt FILE2 FILE1 is newer (modification date) than FILE2\n\
FILE1 -ot FILE2 FILE1 is older than FILE2\n\
"), stdout);
fputs (_("\
\n\
-b FILE FILE exists and is block special\n\
-c FILE FILE exists and is character special\n\
-d FILE FILE exists and is a directory\n\
-e FILE FILE exists\n\
"), stdout);
fputs (_("\
-f FILE FILE exists and is a regular file\n\
-g FILE FILE exists and is set-group-ID\n\
-G FILE FILE exists and is owned by the effective group ID\n\
-h FILE FILE exists and is a symbolic link (same as -L)\n\
-k FILE FILE exists and has its sticky bit set\n\
"), stdout);
fputs (_("\
-L FILE FILE exists and is a symbolic link (same as -h)\n\
-N FILE FILE exists and has been modified since it was last read\n\
-O FILE FILE exists and is owned by the effective user ID\n\
-p FILE FILE exists and is a named pipe\n\
-r FILE FILE exists and read permission is granted\n\
-s FILE FILE exists and has a size greater than zero\n\
"), stdout);
fputs (_("\
-S FILE FILE exists and is a socket\n\
-t FD file descriptor FD is opened on a terminal\n\
-u FILE FILE exists and its set-user-ID bit is set\n\
-w FILE FILE exists and write permission is granted\n\
-x FILE FILE exists and execute (or search) permission is granted\n\
"), stdout);
fputs (_("\
\n\
Except for -h and -L, all FILE-related tests dereference symbolic links.\n\
Beware that parentheses need to be escaped (e.g., by backslashes) for shells.\n\
INTEGER may also be -l STRING, which evaluates to the length of STRING.\n\
"), stdout);
fputs (_("\
\n\
NOTE: Binary -a and -o are inherently ambiguous. Use 'test EXPR1 && test\n\
EXPR2' or 'test EXPR1 || test EXPR2' instead.\n\
"), stdout);
fputs (_("\
\n\
NOTE: [ honors the --help and --version options, but test does not.\n\
test treats each of those as it treats any other nonempty STRING.\n\
"), stdout);
printf (USAGE_BUILTIN_WARNING, _("test and/or ["));
emit_ancillary_info (PROGRAM_NAME);
}
exit (status);
}
#endif /* TEST_STANDALONE */
#if !defined TEST_STANDALONE
# define main test_command
#endif
#define AUTHORS \
proper_name ("Kevin Braunsdorf"), \
proper_name ("Matthew Bradburn")
/*
* [:
* '[' expr ']'
* test:
* test expr
*/
int
main (int margc, char **margv)
{
bool value;
#if !defined TEST_STANDALONE
int code;
code = setjmp (test_exit_buf);
if (code)
return (test_error_return);
#else /* TEST_STANDALONE */
initialize_main (&margc, &margv);
set_program_name (margv[0]);
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
initialize_exit_failure (TEST_FAILURE);
atexit (close_stdout);
#endif /* TEST_STANDALONE */
argv = margv;
if (LBRACKET)
{
/* Recognize --help or --version, but only when invoked in the
"[" form, when the last argument is not "]". Use direct
parsing, rather than parse_long_options, to avoid accepting
abbreviations. POSIX allows "[ --help" and "[ --version" to
have the usual GNU behavior, but it requires "test --help"
and "test --version" to exit silently with status 0. */
if (margc == 2)
{
if (STREQ (margv[1], "--help"))
usage (EXIT_SUCCESS);
if (STREQ (margv[1], "--version"))
{
version_etc (stdout, PROGRAM_NAME, PACKAGE_NAME, Version, AUTHORS,
(char *) NULL);
test_main_return (EXIT_SUCCESS);
}
}
if (margc < 2 || !STREQ (margv[margc - 1], "]"))
test_syntax_error (_("missing %s"), quote ("]"));
--margc;
}
argc = margc;
pos = 1;
if (pos >= argc)
test_main_return (TEST_FALSE);
value = posixtest (argc - 1);
if (pos != argc)
test_syntax_error (_("extra argument %s"), quote (argv[pos]));
test_main_return (value ? TEST_TRUE : TEST_FALSE);
}
とまあLBRACKET
がdefineされているかどうかで変わっている模様。
これは($(CC) -DLNRACKET=1 みたいにして)コンパイラーに対する外部からの定義で渡している
のかと思ったら
ソースディレクトリにlbracket.c
というファイルがあって、
さらにその中身を見ると…
coreutils/lbracket.c at 00ea4bacf6063ccc125209d5186f8f2382c6f0d4 · coreutils/coreutils
#define LBRACKET 1
#include "test.c"
わはは。
あれ? でもなんで
#if defined(LBRACKET)
...
#endif
じゃなくて
if (LBRACKET)
{
...
}
なんだろう?
続く?
追記
LBRACKETは0か1のいずれかにdefineされるので、
defindで見るのは意味がない。
もしプリプロセッサで切り分ける(条件コンパイルにする)のなら
if LBRACKET == 1
などのようにするか?