Merge pull request #186 from xexyl/1992-adrian

Make 1992/adrian use fgets() not gets()
This commit is contained in:
Landon Curt Noll authored and GitHub committed 2023-03-28 14:33:17 -07:00
commit 096a39ed74
2 files changed
+56 -29

No files matched your search

+55 -27
View File
@@ -11,6 +11,20 @@
make all make all
[Cody Boone Ferguson](/winners.html#Cody_Boone_Ferguson) changed the location
that it used `gets()` to be `fgets()` instead to make it safer. One might think
that simply changing the gets() to fgets() (with stdin) would work but it did
not because `fgets()` stores the newline and `gets()` does not. The code was
relying on not having this newline. With `fgets()` the code `if(A(Y)) puts(Y);`
ended up printing an extra line which made the generation of some files (like
`adhead.c`) fail to compile (`gets()` does not store the newline but `fgets()`
does). Why? There was a blank line after a `\` at the end of the first line of a
macro definition! Thus the code now first trims off the last character of the
buffer read to get the same correct functionality but in a safe way. Thank you
Cody for your assistance!
## Try: ## Try:
./adrian adrian.grep.try < README.md ./adrian adrian.grep.try < README.md
@@ -19,14 +33,14 @@ For the slow minded, try:
./adsleep 32767 ./adsleep 32767
## Judges' comments ## Judges' comments:
Once you get past the obfuscation, you have an opportunity to learn Once you get past the obfuscation, you have an opportunity to learn
about regular expressions and state machines. about regular expressions and state machines.
NOTE: Some compilers have had trouble optimizing this entry. NOTE: Some compilers have had trouble optimizing this entry.
## Author's comments ## Author's comments:
ADrian's GREP (adgrep) ADrian's GREP (adgrep)
@@ -48,13 +62,13 @@ For the slow minded, try:
<state> chars1 <dest1> chars2 <dest2> ... <state> chars1 <dest1> chars2 <dest2> ...
chars1 is a list of characters (only the first 8 are significant) which `chars1` is a list of characters (only the first 8 are significant) which
should trigger a transition to <dest1>. <dest1> is another state which should trigger a transition to `<dest1>`. `<dest1>` is another state which
should have a similar specification somewhere. A state is accepting if should have a similar specification somewhere. A state is accepting if
it is specified in square brackets: [final], and state strings are it is specified in square brackets: `[final]`, and state strings are
significant to only eight characters. significant to only eight characters.
Example 1: matches ^abc$ ### Example 1: matches `^abc$`
<q0> a <q1> The first state to appear is the start state <q0> a <q1> The first state to appear is the start state
<q1> b <q2> <q1> b <q2>
@@ -64,11 +78,11 @@ For the slow minded, try:
Technically, a deterministic finite automaton should have a rule for each Technically, a deterministic finite automaton should have a rule for each
possible input character at each state. To simplify descriptions of the possible input character at each state. To simplify descriptions of the
automata, if no rule is present, the string will not be accepted. Also, automata, if no rule is present, the string will not be accepted. Also,
the '.' character matches any character if it occurs first in the the `'.'` character matches any character if it occurs first in the
character list. character list.
Example 2: ^abc ### Example 2: `^abc`
<q0> a <q1> <q0> a <q1>
<q1> b <q2> <q1> b <q2>
@@ -76,7 +90,7 @@ For the slow minded, try:
[q3] . [q3] [q3] . [q3]
Example 3: abc$ ### Example 3: `abc$`
<q0> a <q1> . <q0> <q0> a <q1> . <q0>
<q1> b <q2> a <q1> . <q0> <q1> b <q2> a <q1> . <q0>
@@ -84,14 +98,14 @@ For the slow minded, try:
[q3] . <q1> [q3] . <q1>
Example 4: ^(abc)*$ ### Example 4: `^(abc)*$`
[q0] a <q1> [q0] a <q1>
<q1> b <q2> <q1> b <q2>
<q2> c [q0] <q2> c [q0]
Example 5: ^[ab][cd][ef]$ ### Example 5: `^[ab][cd][ef]$`
<q0> ab <q1> <q0> ab <q1>
<q1> cd <q2> <q1> cd <q2>
@@ -99,7 +113,7 @@ For the slow minded, try:
[q3] [q3]
Example 6: ^(abc|efg)$ ### Example 6: `^(abc|efg)$`
<q0> a <q1> e <q3> <q0> a <q1> e <q3>
<q1> b <q2> <q1> b <q2>
@@ -112,47 +126,58 @@ For the slow minded, try:
With the automaton specification in 'filename', invoke the program by With the automaton specification in 'filename', invoke the program by
typing typing
adgrep 'filename' ```sh
./adgrep 'filename'
```
It will read stdin and print out all the lines which the automaton It will read stdin and print out all the lines which the automaton
accepts. If the file cannot be opened, a system error message will accepts. If the file cannot be opened, a system error message will
be printed. If the input contains errors, then an error message along be printed. If the input contains errors, then an error message along
with the number of the offending line will be printed to stderr. The with the number of the offending line will be printed to stderr. The
number of rules for each state is limited to 17. If more than 17 rules number of rules for each state is limited to 17. If more than 17 rules
are present, you get the error to_many_rules, and the state that was are present, you get the error `too_many_rules`, and the state that was
being processed is printed. Error no_destination occurs if you specify a being processed is printed. Error `no_destination` occurs if you specify a
set of characters, but no destination state, and error too_many_states set of characters, but no destination state, and error `too_many_states`
occurs if your automaton has more than 257 states. occurs if your automaton has more than 257 states.
Running Running:
adgrep from < your_mailbox
```sh
./adgrep from < your_mailbox
```
will perform a function similar to that of the unix from command. will perform a function similar to that of the unix from command.
If no filename is specified on the command line, then "adgrep.c" is used If no filename is specified on the command line, then `"adgrep.c"` is used
as the specification for the automaton. (This file has been renamed as the specification for the automaton. (This file has been renamed
to adrian.c by the judges.) In this case, the program will search for to `adrian.c` by the judges.) In this case, the program will search for
matches to the regular expression: matches to the regular expression:
^.[^|C][^w[Q]*(Q|[w[]c).*|^.[C|]$ ^.[^|C][^w[Q]*(Q|[w[]c).*|^.[C|]$
I suggest using adgrep.c as input, and storing the output in adwc.c: I suggest using `adgrep.c` as input, and storing the output in `adwc.c`:
adgrep < adgrep.c > adwc.c ```sh
./adgrep < adgrep.c > adwc.c
```
Compiling the new file, mywc.c, yields a clone of the unix wc command. It Compiling the new file, `mywc.c`, yields a clone of the unix wc command. It
runs on one file (defaulting to "adgrep.c" if no file is given) and runs on one file (defaulting to `"adgrep.c"` if no file is given) and
displays the number of lines, words, and bytes in the input file. displays the number of lines, words, and bytes in the input file.
Another possibly interesting automaton can be created by slightly Another possibly interesting automaton can be created by slightly
adjusting the adgrep.c file. Change the first line to read adjusting the `adgrep.c` file. Change the first line to read
/* . echo| . */ /* . echo| . */
and repeat the process above and repeat the process above
adgrep <adgrep.c > adecho.c ```sh
./adgrep <adgrep.c > adecho.c
```
The new file now contains all lines which match The new file now contains all lines which match
@@ -164,6 +189,7 @@ For the slow minded, try:
Two other adjustments to the first line also yield useful results. By Two other adjustments to the first line also yield useful results. By
changing it to changing it to
/* . head; . */ /* . head; . */
you can search for matches to you can search for matches to
@@ -181,6 +207,7 @@ For the slow minded, try:
a clone of the unix basename command can be unearthed. The automaton will a clone of the unix basename command can be unearthed. The automaton will
search for search for
^.[^j]*jr.*$ ^.[^j]*jr.*$
on standard input. And the program which results by running adgrep.c on standard input. And the program which results by running adgrep.c
@@ -203,7 +230,8 @@ For the slow minded, try:
If either adbasename or adsleep is invoked with too few parameters, If either adbasename or adsleep is invoked with too few parameters,
the program will print the error message: the program will print the error message:
Segmentation fault (core dumped)
> Segmentation fault (core dumped)
(The exact text of the above error messages varies from machine to (The exact text of the above error messages varies from machine to
machine.) The four programs which read from stdin require lines machine.) The four programs which read from stdin require lines
+1 -2
View File
@@ -8,7 +8,6 @@
int W ,head; int W ,head;
#define S(W,b,f) strncpy(W,b,f),W[f]=0\ #define S(W,b,f) strncpy(W,b,f),W[f]=0\
char *wcs=" \t\n"; char *wcs=" \t\n";
struct{ char X[z+1]; struct{ char X[z+1];
char f ; char f ;
@@ -105,7 +104,7 @@ while( s = strtok(0,wcs)) {
< 10 && printf((W,Y)); } < 10 && printf((W,Y)); }
if(j+28) { { if(j+28) { {
; } printf("%7u%7u%7u\n", wcl , wcw , wcc); } ; } printf("%7u%7u%7u\n", wcl , wcw , wcc); }
while( gets(Y) ) if(A(Y)) puts(Y); while( fgets(Y,998,stdin) ){ Y[strlen(Y)-1]='\0'; if(A(Y)) puts(Y); }
W, jr; } W, jr; }
O(int wc,char**V) { O(int wc,char**V) {