Fixes and updates in 1998/dorssel
Format fixes in README.md. Rename dorssel.hint -> dorssel.md and update formatting. Updated Makefile DATA variable for rename of dorssel.hint.
This commit is contained in:
1 parent
87c12f9e93
commit
c0e237528b
3 files changed
+102
-65
No files matched your search
@@ -111,7 +111,7 @@ ENTRY= dorssel
|
|||||||
PROG= ${ENTRY}
|
PROG= ${ENTRY}
|
||||||
#
|
#
|
||||||
OBJ= ${PROG}.o
|
OBJ= ${PROG}.o
|
||||||
DATA= dorssel.hint
|
DATA= dorssel.md
|
||||||
TARGET= ${PROG}
|
TARGET= ${PROG}
|
||||||
#
|
#
|
||||||
ALT_OBJ=
|
ALT_OBJ=
|
||||||
|
|||||||
+41
-30
@@ -1,29 +1,35 @@
|
|||||||
# Obsolescent Feature
|
# Obsolescent Feature
|
||||||
|
|
||||||
Frans van Dorsselaer
|
Frans van Dorsselaer
|
||||||
Bakker Industrial Automation
|
Bakker Industrial Automation
|
||||||
Kaiserstraat 35
|
Kaiserstraat 35
|
||||||
NL-2311 GP Leiden
|
NL-2311 GP Leiden
|
||||||
The Netherlands
|
The Netherlands
|
||||||
|
|
||||||
## To build:
|
## To build:
|
||||||
|
|
||||||
make all
|
```sh
|
||||||
|
make all
|
||||||
|
```
|
||||||
|
|
||||||
## To run:
|
## To run:
|
||||||
|
|
||||||
./dorssel
|
```sh
|
||||||
# input some text
|
./dorssel
|
||||||
|
# input some text
|
||||||
|
|
||||||
echo text | ./dorssel
|
echo text | ./dorssel
|
||||||
|
```
|
||||||
|
|
||||||
## Try:
|
## Try:
|
||||||
|
|
||||||
echo Simple as 123 | ./dorssel
|
```sh
|
||||||
echo 'Binary as simple as 1, 10 11.' | ./dorssel
|
echo Simple as 123 | ./dorssel
|
||||||
echo '.... --- .-- -.. --- . ... .. - -.. --- - .... .- -' | ./dorssel
|
echo 'Binary as simple as 1, 10 11.' | ./dorssel
|
||||||
echo 'HOW DOES IT DO THAT' | ./dorssel
|
echo '.... --- .-- -.. --- . ... .. - -.. --- - .... .- -' | ./dorssel
|
||||||
echo 'HOW DOES IT DO THAT' | ./dorssel | ./dorssel
|
echo 'HOW DOES IT DO THAT' | ./dorssel
|
||||||
|
echo 'HOW DOES IT DO THAT' | ./dorssel | ./dorssel
|
||||||
|
```
|
||||||
|
|
||||||
## Judges' remarks:
|
## Judges' remarks:
|
||||||
|
|
||||||
@@ -52,15 +58,14 @@ You might also want to read the [dorssel.hint](dorssel.hint) file.
|
|||||||
|
|
||||||
## Author's remarks:
|
## Author's remarks:
|
||||||
|
|
||||||
Usage
|
### Usage
|
||||||
=====
|
|
||||||
|
|
||||||
This program converts ASCII to Morse code, and vice versa.
|
This program converts ASCII to Morse code, and vice versa.
|
||||||
|
|
||||||
The program reads in lines from standard input and writes its result to
|
The program reads in lines from standard input and writes its result to
|
||||||
standard output. The direction of conversion is determined on a per
|
standard output. The direction of conversion is determined on a per
|
||||||
line basis. Each line must consist of a maximum of 952 characters
|
line basis. Each line must consist of a maximum of 952 characters
|
||||||
followed by a new line character, they must not contain any NUL
|
followed by a new line character and they must not contain any NUL
|
||||||
characters. Otherwise, some characters may be lost in the conversion.
|
characters. Otherwise, some characters may be lost in the conversion.
|
||||||
|
|
||||||
- Encoding to Morse code: The program knows the Morse codes for all Latin
|
- Encoding to Morse code: The program knows the Morse codes for all Latin
|
||||||
@@ -69,40 +74,46 @@ are replaced by an ASCII space ' '. Morse code per converted character is
|
|||||||
written as a sequence of '.' and '-' characters, each sequence followed by a
|
written as a sequence of '.' and '-' characters, each sequence followed by a
|
||||||
space.
|
space.
|
||||||
|
|
||||||
- Decoding from Morse code: Morse code should be typed as sequences of '.' and
|
- Decoding from Morse code: Morse code should be typed as sequences of `.` and
|
||||||
'-' characters, separated by a space. Extra spaces will be echoed back (to
|
`-` characters, separated by a space. Extra spaces will be echoed back (to
|
||||||
separate words). Unknown sequences will be converted to a '?' character.
|
separate words). Unknown sequences will be converted to a `?` character.
|
||||||
|
|
||||||
Notes
|
### Notes
|
||||||
=====
|
|
||||||
|
|
||||||
The program assumes both source and execution character sets to be
|
The program assumes both source and execution character sets to be
|
||||||
ASCII. As far as I can tell, the program is conforming and does not
|
ASCII. As far as I can tell, the program is conforming and does not
|
||||||
invoke undefined behavior.
|
invoke undefined behavior.
|
||||||
|
|
||||||
Hints
|
### Hints
|
||||||
=====
|
|
||||||
|
|
||||||
Try
|
Try:
|
||||||
|
|
||||||
./dorssel < dorssel.c | ./dorssel
|
```sh
|
||||||
|
./dorssel < dorssel.c | ./dorssel
|
||||||
|
```
|
||||||
|
|
||||||
to see what variables, numbers, and functions are used. (Does a
|
to see what variables, numbers, and functions are used. (Does a
|
||||||
better job than most C beautifiers).
|
better job than most C beautifiers).
|
||||||
|
|
||||||
- Filter your text twice (as in the previous sample) to obtain a version of your
|
- Filter your text twice (as in the previous sample) to obtain a version of your
|
||||||
text that can be reversibly morsified, i.e.
|
text that can be reversibly Morsified, i.e.
|
||||||
|
|
||||||
./dorssel | ./dorssel | ./dorssel | ./dorssel
|
```sh
|
||||||
|
./dorssel < dorssel.c | ./dorssel | ./dorssel | ./dorssel
|
||||||
|
```
|
||||||
|
|
||||||
is the same as
|
is the same as
|
||||||
|
|
||||||
./dorssel | ./dorssel
|
```sh
|
||||||
|
./dorssel < dorssel.c | ./dorssel
|
||||||
|
```
|
||||||
|
|
||||||
- The file "dorssel.hint" contains all the information needed to understand this
|
- The file "dorssel.hint" contains all the information needed to understand this
|
||||||
program. For an obfuscated spoiler, try
|
program. For an obfuscated spoiler, try
|
||||||
|
|
||||||
./dorssel < dorssel.hint
|
```sh
|
||||||
|
./dorssel < dorssel.hint
|
||||||
|
```
|
||||||
|
|
||||||
## Copyright and CC BY-SA 4.0 License:
|
## Copyright and CC BY-SA 4.0 License:
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
|
# Information about this entry
|
||||||
|
|
||||||
Morse codes for letters and digits use sequences of 1 to 5 (inclusive)
|
Morse codes for letters and digits use sequences of 1 to 5 (inclusive)
|
||||||
Morse symbols (denoted as '.' or '-'), e.g.
|
Morse symbols (denoted as '.' or '-'), e.g.
|
||||||
|
|
||||||
|
```
|
||||||
E .
|
E .
|
||||||
Z --..
|
Z --..
|
||||||
3 ...--
|
3 ...--
|
||||||
|
```
|
||||||
|
|
||||||
(BTW: digits always have 5 symbols, letters 1 to 4. I didn't use this fact)
|
(BTW: digits always have 5 symbols, letters 1 to 4. I didn't use this fact.)
|
||||||
|
|
||||||
Of course we can encode these symbols with bits in a byte. I chose '-'
|
Of course we can encode these symbols with bits in a byte. I chose `-`
|
||||||
to be a bit set to 0, '.' to be a bit set to 1. Characters in C are at
|
to be a bit set to 0, `.` to be a bit set to 1. Characters in C are at
|
||||||
least 8 bits, but they are either signed or unsigned. To be portable,
|
least 8 bits, but they are either signed or unsigned. To be portable,
|
||||||
I've used only values from 0 to 127 (inclusive) (both in the encoding
|
I've used only values from 0 to 127 (inclusive) (both in the encoding
|
||||||
of Morse codes, as well as in subexpressions in the program). Hence we
|
of Morse codes, as well as in subexpressions in the program). Hence we
|
||||||
@@ -18,42 +22,52 @@ the source code excessively large ;-)
|
|||||||
The least significant bit contains the first symbol of a Morse code, so
|
The least significant bit contains the first symbol of a Morse code, so
|
||||||
we have
|
we have
|
||||||
|
|
||||||
|
```
|
||||||
E > 0......1
|
E > 0......1
|
||||||
Z > 0...1100
|
Z > 0...1100
|
||||||
3 > 0..00111
|
3 > 0..00111
|
||||||
|
```
|
||||||
|
|
||||||
The dots have still to be determined. But we also need to encode the
|
The dots have still to be determined. But we also need to encode the
|
||||||
length of the sequence. Since there are only 4 different kind of lengths,
|
length of the sequence. Since there are only 4 different kind of lengths,
|
||||||
two bits would suffice, e.g.
|
two bits would suffice, e.g.
|
||||||
|
|
||||||
|
```
|
||||||
E > 000....1
|
E > 000....1
|
||||||
Z > 010.1100
|
Z > 010.1100
|
||||||
3 > 01100111
|
3 > 01100111
|
||||||
|
```
|
||||||
|
|
||||||
That means bits 6 and 5 set to 00 is length 1, set to 01 is length 2, etc.
|
That means bits 6 and 5 set to 00 is length 1, set to 01 is length 2, etc.
|
||||||
But this would mean that we would have to extract the length into a
|
But this would mean that we would have to extract the length into a
|
||||||
counter before shifting out each symbol, such as
|
counter before shifting out each symbol, such as
|
||||||
|
|
||||||
|
```c
|
||||||
length = (encoding & 96) >> 5;
|
length = (encoding & 96) >> 5;
|
||||||
do {
|
do {
|
||||||
putchar(encoding & 1 ? '-' : '.');
|
putchar(encoding & 1 ? '-' : '.');
|
||||||
encoding >>= 1;
|
encoding >>= 1;
|
||||||
} while (length--);
|
} while (length--);
|
||||||
|
```
|
||||||
|
|
||||||
We can also use the remaining bits to *include* the counter
|
We can also use the remaining bits to *include* the counter
|
||||||
|
|
||||||
|
```
|
||||||
length 1: 00000.1x E > 00000.11
|
length 1: 00000.1x E > 00000.11
|
||||||
length 2: 0000.1xx
|
length 2: 0000.1xx
|
||||||
length 3: 000.1xxx
|
length 3: 000.1xxx
|
||||||
length 4: 00.1xxxx Z > 00.11100
|
length 4: 00.1xxxx Z > 00.11100
|
||||||
length 5: 0.1xxxxx 3 > 0.100111
|
length 5: 0.1xxxxx 3 > 0.100111
|
||||||
|
```
|
||||||
|
|
||||||
With 1 bit still to be chosen freely (let's assume it is 0). Now we can do
|
With 1 bit still to be chosen freely (let's assume it is 0). Now we can do
|
||||||
|
|
||||||
|
```c
|
||||||
do {
|
do {
|
||||||
putchar(encoding & 1 ? '-' : '.');
|
putchar(encoding & 1 ? '-' : '.');
|
||||||
encoding >>= 1;
|
encoding >>= 1;
|
||||||
while (encoding > 1);
|
while (encoding > 1);
|
||||||
|
```
|
||||||
|
|
||||||
As you see, the encoded Morse sequence can be the counter itself. But
|
As you see, the encoded Morse sequence can be the counter itself. But
|
||||||
this is not very pleasant, as some Morse sequences will end up having
|
this is not very pleasant, as some Morse sequences will end up having
|
||||||
@@ -61,66 +75,75 @@ an ASCII value < 32, i.e. they will be control codes. This would make
|
|||||||
the initializing (encoding) string awkward. Hence I came up with the
|
the initializing (encoding) string awkward. Hence I came up with the
|
||||||
following
|
following
|
||||||
|
|
||||||
|
```
|
||||||
length 1: 0010010x E > 00100101 (= '%')
|
length 1: 0010010x E > 00100101 (= '%')
|
||||||
length 2: 001010xx
|
length 2: 001010xx
|
||||||
length 3: 00110xxx
|
length 3: 00110xxx
|
||||||
length 4: 0100xxxx Z > 01001100 (= 'L')
|
length 4: 0100xxxx Z > 01001100 (= 'L')
|
||||||
length 5: 011xxxxx 3 > 01100111 (= 'g')
|
length 5: 011xxxxx 3 > 01100111 (= 'g')
|
||||||
|
```
|
||||||
|
|
||||||
Notice these encodings in the initialization string. Only the coding for
|
Notice these encodings in the initialization string. Only the coding for
|
||||||
'5' needs an escape (5 = ..... > 01111111 = '\177'). The way the length
|
`5` needs an escape (`5 = ..... > 01111111 = '\177'`). The way the length
|
||||||
is encoded still allows the encoding to be its own counter:
|
is encoded still allows the encoding to be its own counter:
|
||||||
|
|
||||||
|
```c
|
||||||
do {
|
do {
|
||||||
putchar(encoding & 1 ? '-' : '.');
|
putchar(encoding & 1 ? '-' : '.');
|
||||||
encoding = (encoding + 32) >> 1;
|
encoding = (encoding + 32) >> 1;
|
||||||
} while (encoding > 35);
|
} while (encoding > 35);
|
||||||
|
```
|
||||||
|
|
||||||
The last shift will always result in 00100010, hence the test for >35.
|
The last shift will always result in `00100010`, hence the test for `>35`.
|
||||||
Note that the calculation for the next value of `encoding' is done at int
|
Note that the calculation for the next value of `encoding` is done at int
|
||||||
precision, so that the actual value of the char remains <= 127.
|
precision, so that the actual value of the char remains `<= 127`.
|
||||||
|
|
||||||
The character '-' (ASCII 45) and '.' (ASCII 46) are conveniently in
|
The character `'-'` (ASCII 45) and `'.'` (ASCII 46) are conveniently in
|
||||||
sequence, so the putchar can simply be
|
sequence, so the putchar can simply be
|
||||||
|
|
||||||
|
```c
|
||||||
putchar(45 + encoding % 2);
|
putchar(45 + encoding % 2);
|
||||||
|
```
|
||||||
|
|
||||||
I used the modulo operator this time, because '+' takes precedence over '&'.
|
I used the modulo operator this time, because `+` takes precedence over `&`.
|
||||||
The assignment can be incorporated into the while control test, and a
|
The assignment can be incorporated into the while control test, and a
|
||||||
do-while loop with a body of a single expression statement can be written
|
do-while loop with a body of a single expression statement can be written
|
||||||
as a while loop with a comma operator in the test:
|
as a while loop with a comma operator in the test:
|
||||||
|
|
||||||
|
```c
|
||||||
while(putchar(45 + encoding % 2), encoding = encoding + 32 >> 1);
|
while(putchar(45 + encoding % 2), encoding = encoding + 32 >> 1);
|
||||||
|
```
|
||||||
|
|
||||||
Voila.
|
Voila.
|
||||||
|
|
||||||
Now, the decoding of Morse codes is just the reverse. We shift in 0's
|
Now, the decoding of Morse codes is just the reverse. We shift in `0`s
|
||||||
and 1's as we scan the line. But: we have to scan from back to front
|
and `1`s as we scan the line. But: we have to scan from back to front
|
||||||
(the left most Morse symbol is in the least significant bit, and thus
|
(the left most Morse symbol is in the least significant bit, and thus
|
||||||
has to shifted in last). The test for the scanning while loop must
|
has to shifted in last). The test for the scanning while loop must
|
||||||
stop when there are no more '.' or '-' on the left. Hence we need a
|
stop when there are no more `.` or `-` on the left. Hence we need a
|
||||||
terminating character in front of the line. The input line is read one
|
terminating character in front of the line. The input line is read one
|
||||||
past the encoding string (into the same character array) the terminating
|
past the encoding string (into the same character array) the terminating
|
||||||
character for the reverse scan is therefore provided by the implicit '\0'
|
character for the reverse scan is therefore provided by the implicit `'\0'`
|
||||||
of the array initializer ! The test also stops when at most 5 symbols
|
of the array initializer ! The test also stops when at most 5 symbols
|
||||||
have been shifted in.
|
have been shifted in.
|
||||||
|
|
||||||
The encoded character is then looked up in the encoding string with
|
The encoded character is then looked up in the encoding string with
|
||||||
memchr (why memchr is explained later). Either a '?' (when there are
|
`memchr()` (why `memchr()` is explained later). Either a `?` (when there are
|
||||||
more than 5 consecutive Morse symbols, or if the sequence is unknown)
|
more than 5 consecutive Morse symbols, or if the sequence is unknown)
|
||||||
or the decoded character is printed. Or a ' ' if there was an extra
|
or the decoded character is printed. Or a `' '` if there was an extra
|
||||||
space in the source line. Note the use of "or" in these last sentences,
|
space in the source line. Note the use of "or" in these last sentences,
|
||||||
as they explain the use of the conditional operator.
|
as they explain the use of the conditional operator.
|
||||||
|
|
||||||
The strspn calls need either " .-" or ".-" as argument. Of course they
|
The `strspn` calls need either `" .-"` or `".-"` as argument. Of course they
|
||||||
are overlapped. I put these strings between the encodings for digits
|
are overlapped. I put these strings between the encodings for digits
|
||||||
and letters. This is OK, since neither of these characters, or the '\0',
|
and letters. This is OK, since neither of these characters, or the `'\0'`,
|
||||||
is a valid encoding ! We must, however, use memchr instead of strchr in
|
is a valid encoding ! We must, however, use `memchr()` instead of `strchr()` in
|
||||||
the decoding lookup because of this '\0'. Since it is far more obscure
|
the decoding lookup because of this `'\0'`. Since it is far more obscure
|
||||||
this way, I hope you'll forgive me.
|
this way, I hope you'll forgive me.
|
||||||
|
|
||||||
The outline of the program is roughly as follows
|
The outline of the program is roughly as follows
|
||||||
|
|
||||||
|
```
|
||||||
while (more lines) {
|
while (more lines) {
|
||||||
if (line is in morse) {
|
if (line is in morse) {
|
||||||
while (more characters) {
|
while (more characters) {
|
||||||
@@ -137,23 +160,25 @@ while (more lines) {
|
|||||||
putchar(' ');
|
putchar(' ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Because of the *two* while(more characters) loops are the same, I've
|
Because of the *two* `while(more characters)` loops are the same, I've
|
||||||
exchanged the if(line is in morse) and the two while loops (so there
|
exchanged the `if(line is in morse)` and the two while loops (so there
|
||||||
is *single* while loop). However, we must now store the if(line is in
|
is *single* while loop). However, we must now store the `if(line is in
|
||||||
morse) test for efficiency (it would be stupid to test the entire line
|
morse)` test for efficiency (it would be stupid to test the entire line
|
||||||
for every character). This is done in l[0] ! (the first encoding is
|
for every character). This is done in `l[0]` ! (the first encoding is
|
||||||
thus in l[1]). The memchr decoding lookup is not disturbed, because the
|
thus in `l[1]`). The `memchr()` decoding lookup is not disturbed, because the
|
||||||
test is always 0 for Morse lines, and '\0' is not a possible encoding.
|
test is always `0` for Morse lines, and `'\0'` is not a possible encoding.
|
||||||
l[0] is also used as the temporary shift character while encoding a
|
`l[0]` is also used as the temporary shift character while encoding a
|
||||||
line of text. This does not disturb the if (line is in morse) test,
|
line of text. This does not disturb the `if (line is in morse)` test,
|
||||||
as the temporary l[0] will remain != 0.
|
as the temporary `l[0]` will remain `!= 0`.
|
||||||
|
|
||||||
I've put the if's in the above layout into a single switch. Hope you don't
|
I've put the `if`s in the above layout into a single switch. Hope you don't
|
||||||
mind ;-)
|
mind ;-)
|
||||||
|
|
||||||
Summary of the use of l[999]:
|
Summary of the use of l[999]:
|
||||||
|
|
||||||
|
```
|
||||||
l[0] result of "is this line in morse" test
|
l[0] result of "is this line in morse" test
|
||||||
l[0] temporary shift during encoding
|
l[0] temporary shift during encoding
|
||||||
l[0] - l[33] Morse codings (letters and digits, plus garbage)
|
l[0] - l[33] Morse codings (letters and digits, plus garbage)
|
||||||
@@ -161,13 +186,14 @@ l[11] - l[14] strspn argument
|
|||||||
l[12] - l[14] strspn argument
|
l[12] - l[14] strspn argument
|
||||||
l[34] terminator for backward decoding
|
l[34] terminator for backward decoding
|
||||||
l[35] - l[998] input line
|
l[35] - l[998] input line
|
||||||
|
```
|
||||||
|
|
||||||
*****
|
---
|
||||||
|
|
||||||
Selected notes:
|
Selected notes:
|
||||||
- We don't need to declare isalnum() (or include ctype.h) as its implicit
|
- We don't need to declare `isalnum()` (or include ctype.h) as its implicit
|
||||||
declaration is correct (int argument, int result). This is not so for
|
declaration is correct (int argument, int result). This is not so for
|
||||||
strlen(), strspn(), and memchr() as they use size_t.
|
`strlen()`, `strspn()`, and `memchr()` as they use `size_t`.
|
||||||
- During development, my gcc 2.7.2.3 had an internal compiler error (signal
|
- During development, my gcc 2.7.2.3 had an internal compiler error (signal
|
||||||
6) on code that was correct !
|
6) on code that was correct !
|
||||||
- lclint 2.4b thinks that "the observer is modified" a couple of times,
|
- lclint 2.4b thinks that "the observer is modified" a couple of times,
|
||||||
@@ -176,7 +202,7 @@ Selected notes:
|
|||||||
- lclint 2.4b is positive the second while loop is infinite, whereas it is
|
- lclint 2.4b is positive the second while loop is infinite, whereas it is
|
||||||
not.
|
not.
|
||||||
|
|
||||||
*****
|
---
|
||||||
|
|
||||||
.. - .... .. -. -.- - .... .. ... ... .--. --- .. .-.. . .-. .. ... -- --- .-. . --- -... ..-. ..- ... -.-. .- - . -.. - .... .- -. - .... . .--. .-. --- --. .-. .- --
|
.. - .... .. -. -.- - .... .. ... ... .--. --- .. .-.. . .-. .. ... -- --- .-. . --- -... ..-. ..- ... -.-. .- - . -.. - .... .- -. - .... . .--. .-. --- --. .-. .- --
|
||||||
|
|
||||||
Reference in new issue
Block a user