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]))