From 1b65c59cd454983127b421b17a3d93a97d8214a5 Mon Sep 17 00:00:00 2001 From: Cody Boone Ferguson <53008573+xexyl@users.noreply.github.com> Date: Sun, 15 Oct 2023 05:39:49 -0700 Subject: [PATCH] Improve my fixes to 1998/schweikh1 To make this slightly more portable still I have removed the hard-coding of gcc to make it just be cc. In modern systems this should be fine. This involved updating the magic numbers by subtracting one from each, making them (in the primary version 43 and 45 and 94 and 96 in the alternate code for macOS) but since one of the purposes of the fixes of code include making them work in more systems I have made it use cc as it should work (gcc is most likely in all systems anyway but it seemed like a better idea for 2023). I previously noted in the thanks-for-fixes.md that the mode in fopen() could remain 44+__FILE__ (though as noted above it's now 43) but that I had changed it to "r". This was a mistake and it is now restored though again it is now 43 not 44. The FILE * which was renamed to G has been changed back to H. Observe how there is a macro with the same name. There was actually no need to change it. I have restored some of the control codes in the C preprocessor directives. Unfortunately that is only prior to the #define because some systems will give an annoying warning otherwise. For instance fedora linux shows: schweikh1.c:6:8: warning: form feed in preprocessing directive 6 | #define x ) == 0 ?__LINE__:0){O =__LINE__;break;} } | and possibly vertical tab too. So although it would be ideal to have them closer to the original I deem that preventing warnings that cannot be, for whatever reason, disabled. The thanks-for-fixes.md was updated for these changes and now includes more details on the fixes to match the rest of the other entries (though some might also be lacking in details). --- 1998/schweikh1/Makefile | 1 + 1998/schweikh1/README.md | 103 +++++++++++++++++++++++---------- 1998/schweikh1/schweikh1.alt.c | 20 +++---- 1998/schweikh1/schweikh1.c | 18 +++--- thanks-for-fixes.md | 78 +++++++++++++++++++------ 5 files changed, 152 insertions(+), 68 deletions(-) diff --git a/1998/schweikh1/Makefile b/1998/schweikh1/Makefile index a9d08c7fe..6904f00e3 100644 --- a/1998/schweikh1/Makefile +++ b/1998/schweikh1/Makefile @@ -128,6 +128,7 @@ all: data ${TARGET} ${PROG}: ${PROG}.c ${CC} ${CFLAGS} $< -o $@ ${LDFLAGS} + @echo "NOTE: for macOS use the alternate code through make alt. See README.md for details." # alternative executable # diff --git a/1998/schweikh1/README.md b/1998/schweikh1/README.md index 05a9583bd..11d827ea3 100644 --- a/1998/schweikh1/README.md +++ b/1998/schweikh1/README.md @@ -14,8 +14,9 @@ Germany make all ``` -An alternate version for this entry works with macOS. See the Alternate code -section below for more details. +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. ## To run: @@ -24,60 +25,100 @@ section below for more details. ./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: -As noted above the alternate version works with macOS but there are some -important notes as well as a description of how it works (spoilers for the -original version as well). +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). -With a MacBook Pro Max with the M1 chip some header files report an -unsupported architecture and unsupported compiler (error, warning). -However the defines are still found okay. +#### macOS changes: -For this alternate version you will need the command line tools which you can -install like: +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, 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 ``` -Finally as far as how this works if you look at line 55 you see a funny command. -This goes for both versions. Now the key are two magic numbers, one on a -different line shortly below the string. In the original the numbers are, -respectively, 44 and 46. But how does this work? Well the string is: +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 (" ``` -The first number 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? 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. +which has been changed to be: -This allows for opening the right files. The problem with the macOS is -`/usr/include` does not exist: instead it's +``` +"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 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 ``` Use `schweikh1.alt` as you would `schweikh1` above. +Bonus exercise: modify the code to provide a different compiler. ## Judges' remarks: What does it do? It seems to print a list of system headers, perhaps with words after them. Curiously, if you look at the list of words defined in a given standard header, they are never printed directly -after that header's name. Ah-hah! It's a conformance test for the +after that header's name. Aha! It's a conformance test for the standard headers. This code is a wonder; it's a wonder that it compiles. I wonder @@ -90,15 +131,17 @@ 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. -NOTE: Some non-gcc compilers that are not fully ANSI standard do not -compile this entry correctly. Using cc by default is not helpful -most of the time on this entry, because the program has a hardcoded +#### Historical note: + +Some non-gcc compilers that were not fully ANSI standard did not +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 use gcc. +right thing with `${CC}`. So one should have used gcc. -## Author's remarks +## Author's remarks: Important! This program, if it compiles at all, is mis-compiled by many compilers due to compiler bugs. It could be the "least likely diff --git a/1998/schweikh1/schweikh1.alt.c b/1998/schweikh1/schweikh1.alt.c index 02569351b..089e134ad 100644 --- a/1998/schweikh1/schweikh1.alt.c +++ b/1998/schweikh1/schweikh1.alt.c @@ -3,9 +3,9 @@ /*#include H(dlib)*/ /*#include H(ring)*/ - #define x ) == 0 ?__LINE__:0){O =__LINE__;break;} } - #define X(x) __LINE__ x __LINE__ - #define t(a)\ + #define x ) == 0 ?__LINE__:0){O =__LINE__;break;} } + #define X(x) __LINE__ x __LINE__ + #define t(a)\ for (c = 0; c :\n" char *I = L + __LINE__; int O = printf (__FILE__, n[nn]) + -#line 2 "0gcc -ansi -E -dM -undef %s /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/%s>r\0 (" +#line 2 "0cc -ansi -E -dM -undef %s /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/%s>r\0 (" sprintf (K, 1+__FILE__, f[S-*__FILE__] + __LINE__, n[nn]); O += system (K); - if ((G = fopen (__FILE__+95, "r"))) - while ((fgets (L, (int)sizeof L, G)) != 0) { - I[strcspn (I, 97+__FILE__)] = O = 0; + if ((H = fopen (__FILE__+94, __FILE__+94))) + while ((fgets (L, (int)sizeof L, H)) != 0) { + I[strcspn (I, 96+__FILE__)] = O = 0; #line 1 "*r" t (n) t (e) if (0 == O) O = puts (L); } - if (G != NULL) nn = fclose (G); + if (H != NULL) nn = fclose (H); } } } diff --git a/1998/schweikh1/schweikh1.c b/1998/schweikh1/schweikh1.c index 88a8a135f..e42152b93 100644 --- a/1998/schweikh1/schweikh1.c +++ b/1998/schweikh1/schweikh1.c @@ -3,9 +3,9 @@ /*#include H(dlib)*/ /*#include H(ring)*/ - #define x ) == 0 ?__LINE__:0){O =__LINE__;break;} } - #define X(x) __LINE__ x __LINE__ - #define t(a)\ + #define x ) == 0 ?__LINE__:0){O =__LINE__;break;} } + #define X(x) __LINE__ x __LINE__ + #define t(a)\ for (c = 0; c :\n" char *I = L + __LINE__; int O = printf (__FILE__, n[nn]) + -#line 2 "0gcc -ansi -E -dM -undef %s /usr/include/%s>r\0 (" +#line 2 "0cc -ansi -E -dM -undef %s /usr/include/%s>r\0 (" sprintf (K, 1+__FILE__, f[S-*__FILE__] + __LINE__, n[nn]); O += system (K); - if ((G = fopen (__FILE__+44, "r"))) - while ((fgets (L, (int)sizeof L, G)) != 0) { - I[strcspn (I, 46+__FILE__)] = O = 0; + if ((H = fopen (__FILE__+43, 43+__FILE__))) + while ((fgets (L, (int)sizeof L, H)) != 0) { + I[strcspn (I, 45+__FILE__)] = O = 0; #line 1 "*r" t (n) t (e) if (0 == O) O = puts (L); } - if (G != NULL) nn = fclose (G); + if (H != NULL) nn = fclose (H); } } } diff --git a/thanks-for-fixes.md b/thanks-for-fixes.md index 2c3483110..2f40e91b5 100644 --- a/thanks-for-fixes.md +++ b/thanks-for-fixes.md @@ -17,13 +17,13 @@ bug fixes** such as [2001/anonymous](2001/anonymous/README.md) and compile with clang, fixing entries to work with macOS (some of which are **very complicated** such as [1998/schweikh1](1998/schweikh1/README.md)), fixing code to work with both 32-bit and 64-bit (such as -[2001/herrmann2](2001/herrmann2/README.md)) which can be **quite complicated** -(though not always even if it seems it), providing alternate code where useful -or necessary, fixing where possible dead links and otherwise removing them, typo -and consistency fixes, improving **ALL _Makefiles_** and writing the [sgit -tool](https://github.com/xexyl/sgit) that we installed locally and have used to -easily run `sed` on files in the repository to help build the website. Thank -you **very much** for your extensive efforts in helping improve the IOCCC +[2001/herrmann2](2001/herrmann2/README.md)) which *can be* **quite complicated +too** (though not always even if it seems it), providing alternate code where +useful or necessary, fixing where possible dead links and otherwise removing +them, typo and consistency fixes, improving **ALL _Makefiles_** and writing the +[sgit tool](https://github.com/xexyl/sgit) that we installed locally and have +used to easily run `sed` on files in the repository to help build the website. +Thank you **very much** for your extensive efforts in helping improve the IOCCC presentation of past IOCCC winners and making many many past entries work with modern systems! @@ -921,20 +921,60 @@ segfault fixes should be made because the program is so beautiful. ## [1998/schweikh1](1998/schweikh1/schweikh1.c) ([README.md](1998/schweikh1/README.md])) -Cody fixed this for modern systems (it did not work at all). He also made it so -that if a file fails to open it does not return but rather skips the reading of -the file. Without this fix the entry did not work. +Cody fixed this for modern systems (it did not work at all) and added an +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. -What was wrong? The call to `freopen()` was incorrect with the second arg (the -mode) being instead `5+__FILE__`. It now is `"r"`. There was also a call to -`fopen()` that was wrong where the mode was instead `44+__FILE__`. Interestingly -enough though this did not seem to be an issue though I cannot explain why. He -notes that it works fine with `clang` as well as `gcc` (which is what is used -but in macOS - see below for alternate code - `gcc` is clang). +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. -Additionally Cody provided an alternate version for macOS. The fix is -rather complicated but very interesting. See the README.md file for details on -how it works and how to use it. +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()` +call is: `44+__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.) + +Another important change is that the files are only closed if the `FILE *H` is +`!= NULL`. Without this check, because it's almost certain that some files will +not exist, it would dereference a NULL pointer and very likely crash or halt and +catch fire :-), preventing the entry from working. Notice how `H` is a funny +macro defined as: + +```c +%:define H(x) +``` + +and yet the `FILE *` can be called `H`! This might or might not make sense to +you but if it doesn't can you figure out why? + +Another fix is that previously the program would `return 1` if a file failed to +open but for the same reason as above, it being very likely some files will not +exist, the return was removed so that if the statement of the `if` is true the +`while` loop run, rather than having the loop by itself. It was done this way to +make it as close to the original as possible and to maintain the obfuscation as +close as possible as well. + +Also crucial, and the final fixes to make it work, is that the arrays `K` and +`L` had to be increased in size. They were originally (somewhat bewildering at +first glance) defined as `K[X(*)], L[X(<<)]` but they were changed to +`K[(X(*))*4], L[4*X(<<)]` though it is no longer clear just how necessary this +might be. + +As noted, a limitation of `gcc` existing was removed by Cody to make it so that +`gcc` is not required as `cc` should exist in every system with a C compiler and +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. ## [1998/schweikh2](1998/schweikh2/schweikh2.c) ([README.md](1998/schweikh2/README.md]))