From d1669ce40e35a4ee44077b2fdb871dc34279934c Mon Sep 17 00:00:00 2001 From: Cody Boone Ferguson <53008573+xexyl@users.noreply.github.com> Date: Sun, 12 Nov 2023 06:29:11 -0800 Subject: [PATCH] Updates and fixes to 1998/schweikh1 The perl script that the author said they use to count chars in the code (according to the IOCCC rules at the time) was added as charcount.pl. Moved the macOS details/spoiler (though it has information about the main entry as well) to macos.md. README.md file format and typo checked. This should complete this entry's review. --- 1998/schweikh1/README.md | 144 ++++++++++++------------------------ 1998/schweikh1/charcount.pl | 8 ++ 1998/schweikh1/macos.md | 70 ++++++++++++++++++ thanks-for-fixes.md | 18 ++--- 4 files changed, 135 insertions(+), 105 deletions(-) create mode 100755 1998/schweikh1/charcount.pl create mode 100644 1998/schweikh1/macos.md diff --git a/1998/schweikh1/README.md b/1998/schweikh1/README.md index fdd3110cb..ce383538b 100644 --- a/1998/schweikh1/README.md +++ b/1998/schweikh1/README.md @@ -5,8 +5,9 @@ make all ``` There is an alternate version of this entry that will work with macOS. See the -[Alternate code](#alternate-code) section below for details on how it works and -how to use it. +[Alternate code](#alternate-code) section below. We recommend you look at it +even if you don't have a Mac, unless you want to figure it out yourself, as it +includes some interesting details about the entry. ## To use: @@ -15,9 +16,6 @@ how to use it. ./schweikh1 ``` -NOTE: a limitation with the entry was that it required `gcc` but this limitation -has been removed to make it more portable, requiring only `cc`. - ## Alternate code: @@ -25,83 +23,25 @@ As noted above this entry will not work as it stands for macOS and there are some important notes as well as a description of how the fixed version works (the details of which are relevant to the original entry that no longer works as well as the fixed version but are described in the context of the macOS -adjustments). +adjustments). For details of what had to change, see [macos.md](macos.md). +Unless you wish to figure it out yourself, we recommend that you read this even +if you don't have a Mac as it has some interesting details about the entry. -#### macOS changes: -As an aside: if you have a Mac with the Apple chip, some of the header files -will report an unsupported architecture and unsupported compiler (error, -warning). This will not make the program abort, however, but even with an Intel -CPU though, the original entry will not work in macOS as it stands because -`/usr/include` is hard-coded in the code and macOS does not have it. +### Alternate build: -Nevertheless, although some of it would not work in other systems where -`/usr/include` exists, the `#define`s would still be found okay, at least until -a file was not found (this limitation was removed in both versions, see -[thanks-for-fixes.md](/thanks-for-fixes.md) for details). - -However, as noted, macOS does **not** have `/usr/include` so this would not ever -work for macOS without some changes, described next. For macOS you will need the -command line tools installed which can be done like: - -```sh -sudo xcode-select --install -``` - -An important point is that the original version hard-coded `gcc` but just like -the entry, the alternate version has also removed this limitation despite `gcc` -existing (though it's `clang`) in macOS. - -Now as far as how this works if you look at the code of -[schweikh1.c](schweikh1.c), on line 55 you'll see a funny command (this goes for -the alternate version as well but a bit different). - -Now the key is two magic numbers, one (two of this exist) on a different line shortly below the -string and the other a couple lines further below. - -In the original the numbers are, respectively, 44 and 46, but with the gcc -limitation removed the numbers now are 43 and 45. But how does this work? Well -the command is: - -``` -"0gcc -ansi -E -dM -undef %s /usr/include/%s>r\0 (" -``` - -which has been changed to be: - -``` -"0cc -ansi -E -dM -undef %s /usr/include/%s>r\0 (" -``` - -Shortly below that you will see, as noted above, the numbers: - -```c -if ((H = fopen (__FILE__+43, 43+__FILE__))) -while ((fgets (L, (int)sizeof L, H)) != 0) { - I[strcspn (I, 45+__FILE__)] = O = 0; -``` - -The first number in the above C means the length starting from 0 up through the -`>`. The second number is the same starting point but up through the `\0` which -is why it's `+2`. But what happens if only the first number is updated (from the -original)? Most of the output will be just `#define` by itself; in the cases -where there was text after that it was macros that certainly were not defined. -There might have been other errors as well. - -Changing this for macOS allows for opening the right files; the problem with the -macOS is `/usr/include` does not exist: instead it's -`/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include` which is why -the different command line and the different numbers. The change of the numbers -can be found in the alternate code and the explanation is the same. - -To use this version use: ```sh make alt ``` + +### Alternate build: + Use `schweikh1.alt` as you would `schweikh1` above. +### Alternate try: + Bonus exercise: modify the code to provide a different compiler. @@ -123,6 +63,7 @@ Do not read them if you want to figure this out yourself. "Amendment One" refers to "NA1", the add-on to C89 which added some fairly crufty internationalization support. + #### Historical note: Some non-gcc compilers that were not fully ANSI standard did not @@ -130,7 +71,8 @@ compile this entry correctly. Using cc by default was not helpful most of the time on this entry, because the program had a hardcoded gcc invocation anyway. Anyone who uses egcs and has no plain gcc will need to frob the source anyway and can be expected to do the -right thing with `${CC}`. So one should have used gcc. +right thing with `${CC}`. This limitation was removed in 2023 but in the past +one should have used gcc. ## Author's remarks: @@ -162,16 +104,17 @@ Bug your vendor for an upgrade. The format of the info file is straightforward and described in the file itself. Just load it in your favorite editor. + ### Requirements `gcc` (the GNU C compiler) must be available at runtime. It is assumed that your -C implementation keeps headers as files in the /usr/include directory. The info -file must be readable and reside in the current working directory. The current -working directory must be writable in order to create a temporary file (which is -removed upon program termination). In case you don't have gcc at runtime, not -all is lost if your compiler or preprocessor can produce a list of defined -macros in the format output by `gcc -dM`, i.e. lines of the form `#define MACRO -value`. +C implementation keeps headers as files in the `/usr/include` directory. The +[info](info) file must be readable and reside in the current working directory. +The current working directory must be writable in order to create a temporary +file (which is removed upon program termination). In case you don't have gcc at +runtime, not all is lost if your compiler or preprocessor can produce a list of +defined macros in the format output by `gcc -dM`, i.e. lines of the form +`#define MACRO value`. Edit the source at line 55 in this case. @@ -180,7 +123,7 @@ Edit the source at line 55 in this case. ISO C has a very strict idea of visibility of identifiers. All possible macros are explicitly enumerated. In a compliant implementation no other macros can be defined, because you could write strictly conforming -programs that may fail to compile due to syntax errors: suppose +programs that may fail to compile due to syntax errors: supposing that `` defines `PIPE_BUF`, then the conforming ```c @@ -200,6 +143,7 @@ int main (void) is expected to compile and meet the assertion. If it does not, your compiler compiles some other language than ISO C. + ### Why I think my program is obfuscated Not only is the program's purpose a thorough standard conformance @@ -232,7 +176,7 @@ C compilers. ``` To be honest, I don't know if the rules for pp-tokens and token - pasting don't forbid what I do (and tcc is correct in rejecting it). + pasting don't forbid what I do (and thus tcc is correct in rejecting it). In this case, all other compilers I tried are buggy, or the Standard itself :-) @@ -263,21 +207,21 @@ foo\0bar 9 tcc 4.1.2, Sunsoft cc turn "\0" into "\\0", ugh! 3. The `%:` and `%:%:` digraphs test for conformance to Amendment One. -Ask your local guru if C allows the same case label in the same switch -statement to appear more than once. Ask him/her to think real hard. -The answer will be "no". The true guru will cite a constraint in -ISO 6.6.4.2. Then make fun of the guru's answer by waving `case __LINE__:` -under his/her nose. Easy money from a bet! Make sure your guru has -no chance to use Standardese weasel words as an escape: can I have + Ask your local guru if C allows the same case label in the same switch + statement to appear more than once. Ask him/her to think real hard. + The answer will be "no". The true guru will cite a constraint in + ISO 6.6.4.2. Then make fun of the guru's answer by waving `case __LINE__:` + under his/her nose. Easy money from a bet! Make sure your guru has + no chance to use Standardese weasel words as an escape: can I have ```c case : case : ``` -in the same switch? (Note that you need the [invisible] newline. You -can generously allow the additional constraint that no `#undef`s or -`#define`s are allowed between the two cases.) + in the same switch? (Note that you need the [invisible] newline. You + can generously allow the additional constraint that no `#undef`s or + `#define`s are allowed between the two cases.) Lots of integer constants and string literals come into the source via `__LINE__` and `__FILE__` which are redefined at various places. @@ -289,7 +233,7 @@ This makes the source and header input depend on ASCII. A few old obfuscations, like one character identifiers, not too many macros, a `goto O`, "needless" assignments to satisfy lint with its "function value ignored" warnings. My lint has nothing -to complain. +to complain about. There's more whitespace in the Standard than just space, tab and newline. In particular, there are vertical tab and form-feed that can be used in certain @@ -303,13 +247,14 @@ printer when you make a hard copy of the source... While I'm at it, the rules state that only space, tab and newline are ignored for the count (plus '`{`', '`}`', '`;`' followed by -whitespace). The mkentry.c program, however, uses `isspace()` which -returns nonzero for vtab and form-feed and other characters as well. -I could have used a lot more ^K and ^L probably undetected by your +whitespace). The [mkentry.c](../mkentry.c) program, however, uses `isspace(3)` which +returns nonzero for `\v` and `\f` and other characters as well. +I could have used a lot more `^K` and `^L` probably undetected by your counter but decided to err on the side of safety. I use a perl script to compute the character count according to the rules. The advantages of an independent clean room approach... + ```perl #!/usr/bin/perl -w $/ = "\0"; @@ -320,10 +265,17 @@ print length ($_),"\n"; ``` +To use, try: + +```sh +perl ./charcount.pl schweikh1.c +``` + + I have tried, as suggested in the guidelines, to let the code look like ordinary C code. Apart from a few long lines I think I left the indentation like I would in RL. You should however not try to -use indent on the source. The code is extremely fragile because of the +use `indent` on the source. The code is extremely fragile because of the myriads of `__LINE__` macros -- indenting is a sure way to break the program. Don't even think of maintaining that beast; I've had my share of core dumps during development :-) A test suite diff --git a/1998/schweikh1/charcount.pl b/1998/schweikh1/charcount.pl new file mode 100755 index 000000000..f4f70e301 --- /dev/null +++ b/1998/schweikh1/charcount.pl @@ -0,0 +1,8 @@ +#!/usr/bin/perl -w +$/ = "\0"; +$_ = <>; +s/[;{}][ \t\n]/\n/g; +s/[ \t\n]+//g; +print length ($_),"\n"; + + diff --git a/1998/schweikh1/macos.md b/1998/schweikh1/macos.md new file mode 100644 index 000000000..19b2a8502 --- /dev/null +++ b/1998/schweikh1/macos.md @@ -0,0 +1,70 @@ +This document describes how this was fixed to work with macOS as well as some of +the magic in the entry. Even if you don't have a Mac it might be worth your time +reading especially as some of it details some important fixes and changes in the +original entry as well. + +# macOS changes + +As an aside: if you have a Mac with the Apple chip, some of the header files +will report an unsupported architecture and unsupported compiler (error, +warning). This will not make the program abort, however, but even with an Intel +CPU though, the original entry will not work in macOS as it stands because +`/usr/include` is hard-coded in the code and macOS does not have it. + +Nevertheless, although some of it would not work in other systems where +`/usr/include` exists, the `#define`s would still be found okay, at least until +a file was not found (this limitation was removed in both versions in 2023). see + +However, as noted, macOS does **not** have `/usr/include` so this would never +work for macOS without some changes, described next. For macOS you will need the +command line tools installed which can be done like: + +```sh +sudo xcode-select --install +``` + +An important point is that the original version hard-coded `gcc` but just like +the entry, the alternate version has also removed this limitation despite `gcc` +existing (though it's `clang`) in macOS. + +Now as far as how this works if you look at the code of +[schweikh1.c](schweikh1.c), on line 55 you'll see a funny command (this goes for +the alternate version as well but a bit different). + +Now the key is two magic numbers, one (two times) on a different line shortly below the +string and the other a couple lines further below. + +In the original the numbers are, respectively, `44` and `46`, but with the gcc +limitation removed the numbers now are `43` and `45`. But how does this work? Well +the command is: + +``` +"0gcc -ansi -E -dM -undef %s /usr/include/%s>r\0 (" +``` + +which has been changed to be: + +``` +"0cc -ansi -E -dM -undef %s /usr/include/%s>r\0 (" +``` + +Shortly below that you will see, as noted above, the numbers: + +```c +if ((H = fopen (__FILE__+43, 43+__FILE__))) +while ((fgets (L, (int)sizeof L, H)) != 0) { + I[strcspn (I, 45+__FILE__)] = O = 0; +``` + +The first number in the above C means the length starting from 0 up through the +`>`. The second number is the same starting point but up through the `\0` which +is why it's `+2`. But what happens if only the first number is updated (from the +original)? Most of the output will be just `#define` by itself; in the cases +where there was text after that it was macros that certainly were not defined. +There might have been other errors as well. + +Changing this for macOS allows for opening the right files; the problem with +macOS is `/usr/include` does not exist: instead it's +`/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include` which is why +the different command line and the different numbers. The change of the numbers +can be found in the alternate code and the explanation is the same. diff --git a/thanks-for-fixes.md b/thanks-for-fixes.md index 2ec1643bc..db2e07236 100644 --- a/thanks-for-fixes.md +++ b/thanks-for-fixes.md @@ -2086,16 +2086,16 @@ alternate version that works with macOS. Cody also made it ever so slightly more portable by removing the hard-coding of `gcc`, instead hard-coding it `cc`. Doing this not only lets it work with systems without `gcc` (though in macOS it does exist but is actually `clang`) as `cc` always should. - Getting this entry to work was quite complicated but is also very interesting. -To see how the macOS fixes works, see the README.md but do note that this -includes spoilers for both versions! The fixes to get it to work at all are -described next. + +To see how the macOS fixes works, see the [macos.md](1998/schweikh1/macos.md) +file but do note that this includes spoilers for both versions! The fixes to get +it to work at all are described next. So what was wrong with the original? -The call to `freopen()` was incorrect with the second arg (the mode) being -`5+__FILE__`; it is now `"r"`. (Observe that the mode to the `fopen()` +The call to `freopen(3)` was incorrect with the second arg (the mode) being +`5+__FILE__`; it is now `"r"`. (Observe that the mode to the `fopen(3)` call is: `43+__FILE__`. This might seem incorrect and indeed it can be changed to `"r"` as well but this was not actually necessary so once this was noticed it was changed back to the original.) @@ -2132,9 +2132,9 @@ as the author stated: as long as the options `-E -dM` of the compiler prints out the macros in the form of `gcc -dM` i.e. the lines are in the form `#define MACRO value` it will work, assuming that compiler can run, of course. -As for the version for macOS, the even more complicated details are described in -the [Alternate code](1998/schweikh1/README#alternate-code) section of the -README.md file as these changes pertain to the described version therein. +Cody also added the perl script that the author provided that they used to +compute the character count in the code according to the contest rules of 1998 +in the file [charcount.pl](1998/schweikh1/charcount.pl). ## [1998/schweikh2](1998/schweikh2/schweikh2.c) ([README.md](1998/schweikh2/README.md]))