Make 1992/adrian use fgets() not gets()
There was only one call to gets() and one call to fgets(). gets() reads from stdin so the fgets() call has to as well. But why was it using gets() and not fgets()? My guess is because fgets() stores the final newline which means that the output had extra lines. The entry was relying on this string NOT having a newline printed after the line matched! Having a newline in turn broke the generation of some output like that of adhead.c. Thus if fgets() != NULL we trim off the trailing newline first. This allows the entry and all generated code to compile successfully (adhead.c ended up having a multi-line macro messed up because of an empty line after the \ at the end of the line). Since gets() does not store the final newline and since we trim that off the code is functionally equivalent but now safer.
This commit is contained in:
1 parent
4594e02036
commit
59c95a86d5
2 files changed
+56
-29
No files matched your search
+55
-27
@@ -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
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
Reference in new issue
Block a user