Just in time processing on a character stream: Difference between revisions

From Rosetta Code
Content added Content deleted
(Added Go)
m (→‎{{header|11l}}: new way of specifying file open mode)
 
(29 intermediate revisions by 11 users not shown)
Line 1: Line 1:
{{draft task}}
{{draft task}}
Given a stream of characters, presumably (simulated) from a keyboard, that contain the separators "formfeed", "linefeed", "tab" and "space" characters. Print out the i<sup>th</sup> character of the i<sup>th</sup> tab-field of the i<sup>th</sup> line of the i<sup>th</sup> page to reveal a secret password.
Given a stream of characters containing the separator characters "formfeed", "linefeed", "tab" and "space", print out the i<sup>th</sup> character of the i<sup>th</sup> tab-field of the i<sup>th</sup> line of the i<sup>th</sup> page to reveal a secret password.


Stop processing immediately upon encountering a "!" found uniquely in this <i>i,i,i,i</i> position (least the system self destruct). The "!" may be found/permitted else where however, in which case it should be ignored.
Stop processing immediately upon encountering a "!" found uniquely in this <i>i,i,i,i</i> position (lest the system self-destruct). The "!" may be found elsewhere however, in which case it should be ignored.


Ideally this can be generalise as follows:
Ideally this can be generalised as follows:
* The separators (formfeed, linefeed, tab, space) provided from a user supplied array and can include additional/alternative separators, e.g. (formfeed, linefeed, ".", "," ," ",...).
* The separator characters are defined by a user-supplied array that can include additional or alternative separators, e.g. (formfeed, linefeed, ".", "," ," ",...).
* These selection criterial is generalised i<sup>th</sup>,i<sup>th</sup>,i<sup>th</sup>,i<sup>th</sup> to a boolean function of <i>f(page,line,field,word,...) <b>or</b> f(i<sup>th</sup>,j<sup>th</sup>,k<sup>th</sup>,l<sup>th</sup>,m<sup>th</sup>,etc...)</i>
* The selection criterion is generalised i<sup>th</sup>,i<sup>th</sup>,i<sup>th</sup>,i<sup>th</sup> to a boolean function of <i>f(page,line,field,word,...) <b>or</b> f(i<sup>th</sup>,j<sup>th</sup>,k<sup>th</sup>,l<sup>th</sup>,m<sup>th</sup>,etc...)</i>


Provide a reasonably interesting message to be decoded, e.g. Silence-Dogood. Your choice.
Provide a reasonably interesting message to be decoded, e.g. "Silence-Dogood". Your choice.


This task was inspired by the movie "[[wp:National_Treasure_%28film%29|National Treasure]]" with refers to a "[[wp:Book cipher|book cipher]]".
This task was inspired by the movie "[[wp:National_Treasure_%28film%29|National Treasure]]", which refers to a "[[wp:Book cipher|book cipher]]".

=={{header|11l}}==
{{trans|Python}}

<syntaxhighlight lang="11l">T UserInput
Int formFeed
Int lineFeed
Int tab
Int space

F (chunk)
.formFeed = chunk[0]
.lineFeed = chunk[1]
.tab = chunk[2]
.space = chunk[3]

F String()
R ‘(ff=#.; lf=#.; tb=#.; sp#.)’.format(.formFeed, .lineFeed, .tab, .space)

F chunks(l, n)
[[Int]] r
L(i) (0 .< l.len).step(n)
r.append(l[i .+ n])
R r

F getUserInput()
V h = ‘0 18 0 0 0 68 0 1 0 100 0 32 0 114 0 45 0 38 0 26 0 16 0 21 0 17 0 59 0 11 ’""
‘0 29 0 102 0 0 0 10 0 50 0 39 0 42 0 33 0 50 0 46 0 54 0 76 0 47 0 84 2 28’
V ha = h.split(‘ ’).map(Int)
R chunks(ha, 4).map(chunk -> UserInput(chunk))

F decode(filename, uiList)
V f = File(filename)
V text = f.read()

F decode2(ui)
V f = 0
V l = 0
V t = 0
V s = 0
L(c) @text
I f == ui.formFeed & l == ui.lineFeed & t == ui.tab & s == ui.space
I c == ‘!’
R 0B
print(c, end' ‘’)
R 1B
I c.code == 0'C
f = f + 1
l = 0
t = 0
s = 0
E I c == "\n"
l = l + 1
t = 0
s = 0
E I c == "\t"
t = t + 1
s = 0
E
s = s + 1
R 0B

L(ui) uiList
I !decode2(ui)
L.break
print()

V uiList = getUserInput()
decode(‘theRaven.txt’, uiList)</syntaxhighlight>

{{out}}
<pre>
Silence-Dogood.
</pre>

=={{header|C}}==
{{trans|C++}}
<syntaxhighlight lang="c">#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

struct UserInput {
char formFeed;
char lineFeed;
char tab;
char space;
};

struct UserInputNode {
struct UserInput ui;
struct UserInputNode *next;
};

bool decode(FILE *fp, const struct UserInput ui) {
char f = 0, l = 0, t = 0, s = 0;
char buffer[1];

while (fread(buffer, 1, 1, fp)) {
char c = buffer[0];

if (f == ui.formFeed && l == ui.lineFeed && t == ui.tab && s == ui.space) {
if (c == '!')
return false;
putchar(c);
return true;
} else if (c == '\f') {
f++;
l = t = s = 0;
} else if (c == '\n') {
l++;
t = s = 0;
} else if (c == '\t') {
t++;
s = 0;
} else {
s++;
}
}

return false;
}

void decodeFile(char *fileName, struct UserInputNode *uin) {
FILE *fp;

fp = fopen(fileName, "r");
if (NULL == fp) {
fprintf(stderr, "Could not find %s\n", fileName);
return;
}

if (NULL == uin) {
fprintf(stderr, "No user input detected!\n");
return;
}

while (NULL != uin) {
if (!decode(fp, uin->ui)) {
break;
}
fseek(fp, 0, SEEK_SET);
uin = uin->next;
}
printf("\n\n");
}

struct UserInputNode *getUserInput() {
struct UserInputNode *uip, *temp;

// 0 18 0 0
temp = malloc(sizeof(struct UserInputNode));
temp->ui.formFeed = 0;
temp->ui.lineFeed = 18;
temp->ui.tab = 0;
temp->ui.space = 0;
uip = temp;

// 0 68 0 1
temp->next = malloc(sizeof(struct UserInputNode));
temp = temp->next;
temp->ui.formFeed = 0;
temp->ui.lineFeed = 68;
temp->ui.tab = 0;
temp->ui.space = 1;

// 0 100 0 32
temp->next = malloc(sizeof(struct UserInputNode));
temp = temp->next;
temp->ui.formFeed = 0;
temp->ui.lineFeed = 100;
temp->ui.tab = 0;
temp->ui.space = 32;

// 0 114 0 45
temp->next = malloc(sizeof(struct UserInputNode));
temp = temp->next;
temp->ui.formFeed = 0;
temp->ui.lineFeed = 114;
temp->ui.tab = 0;
temp->ui.space = 45;

// 0 38 0 26
temp->next = malloc(sizeof(struct UserInputNode));
temp = temp->next;
temp->ui.formFeed = 0;
temp->ui.lineFeed = 38;
temp->ui.tab = 0;
temp->ui.space = 26;

// 0 16 0 21
temp->next = malloc(sizeof(struct UserInputNode));
temp = temp->next;
temp->ui.formFeed = 0;
temp->ui.lineFeed = 16;
temp->ui.tab = 0;
temp->ui.space = 21;

// 0 17 0 59
temp->next = malloc(sizeof(struct UserInputNode));
temp = temp->next;
temp->ui.formFeed = 0;
temp->ui.lineFeed = 17;
temp->ui.tab = 0;
temp->ui.space = 59;

// 0 11 0 29
temp->next = malloc(sizeof(struct UserInputNode));
temp = temp->next;
temp->ui.formFeed = 0;
temp->ui.lineFeed = 11;
temp->ui.tab = 0;
temp->ui.space = 29;

// 0 102 0 0
temp->next = malloc(sizeof(struct UserInputNode));
temp = temp->next;
temp->ui.formFeed = 0;
temp->ui.lineFeed = 102;
temp->ui.tab = 0;
temp->ui.space = 0;

// 0 10 0 50
temp->next = malloc(sizeof(struct UserInputNode));
temp = temp->next;
temp->ui.formFeed = 0;
temp->ui.lineFeed = 10;
temp->ui.tab = 0;
temp->ui.space = 50;

// 0 39 0 42
temp->next = malloc(sizeof(struct UserInputNode));
temp = temp->next;
temp->ui.formFeed = 0;
temp->ui.lineFeed = 39;
temp->ui.tab = 0;
temp->ui.space = 42;

// 0 33 0 50
temp->next = malloc(sizeof(struct UserInputNode));
temp = temp->next;
temp->ui.formFeed = 0;
temp->ui.lineFeed = 33;
temp->ui.tab = 0;
temp->ui.space = 50;

// 0 46 0 54
temp->next = malloc(sizeof(struct UserInputNode));
temp = temp->next;
temp->ui.formFeed = 0;
temp->ui.lineFeed = 46;
temp->ui.tab = 0;
temp->ui.space = 54;

// 0 76 0 47
temp->next = malloc(sizeof(struct UserInputNode));
temp = temp->next;
temp->ui.formFeed = 0;
temp->ui.lineFeed = 76;
temp->ui.tab = 0;
temp->ui.space = 47;

// 0 84 2 28
temp->next = malloc(sizeof(struct UserInputNode));
temp = temp->next;
temp->ui.formFeed = 0;
temp->ui.lineFeed = 84;
temp->ui.tab = 2;
temp->ui.space = 28;

temp->next = NULL;
return uip;
}

void freeUserInput(struct UserInputNode *uip) {
if (NULL == uip) {
return;
}

freeUserInput(uip->next);
uip->next = NULL;

free(uip);
}

int main() {
struct UserInputNode *uip;

uip = getUserInput();
decodeFile("theRaven.txt", uip);
freeUserInput(uip);

return 0;
}</syntaxhighlight>
{{out}}
<pre>Silence-Dogood.</pre>

=={{header|C sharp|C#}}==
{{trans|D}}
<syntaxhighlight lang="csharp">using System;
using System.Collections.Generic;
using System.Linq;

namespace JustInTimeProcessing {
struct UserInput {
public UserInput(string ff, string lf, string tb, string sp) {
FormFeed = (char)int.Parse(ff);
LineFeed = (char)int.Parse(lf);
Tab = (char)int.Parse(tb);
Space = (char)int.Parse(sp);
}

public char FormFeed { get; }
public char LineFeed { get; }
public char Tab { get; }
public char Space { get; }
}

class Program {
static List<UserInput> GetUserInput() {
string h = "0 18 0 0 0 68 0 1 0 100 0 32 0 114 0 45 0 38 0 26 0 16 0 21 0 17 0 59 0 11 "
+ "0 29 0 102 0 0 0 10 0 50 0 39 0 42 0 33 0 50 0 46 0 54 0 76 0 47 0 84 2 28";
return h.Split(' ')
.Select((x, idx) => new { x, idx })
.GroupBy(x => x.idx / 4)
//.Select(g => g.Select(a => a.x))
.Select(g => {
var ge = g.Select(a => a.x).ToArray();
return new UserInput(ge[0], ge[1], ge[2], ge[3]);
})
.ToList();
}

static void Decode(string filename, List<UserInput> uiList) {
string text = System.IO.File.ReadAllText(filename);

bool Decode2(UserInput ui) {
char f = (char)0;
char l = (char)0;
char t = (char)0;
char s = (char)0;

foreach (char c in text) {
if (f == ui.FormFeed && l == ui.LineFeed && t == ui.Tab && s == ui.Space) {
if (c == '!') return false;
Console.Write(c);
return true;
}
if (c == '\u000c') {
f++; l = (char)0; t = (char)0; s = (char)0;
} else if (c == '\n') {
l++; t = (char)0; s = (char)0;
} else if (c == '\t') {
t++; s = (char)0;
} else {
s++;
}
}

return false;
}

foreach (UserInput ui in uiList) {
if (!Decode2(ui)) {
break;
}
}
Console.WriteLine();
}

static void Main(string[] args) {
var uiList = GetUserInput();
Decode("theraven.txt", uiList);

Console.ReadLine();
}
}
}</syntaxhighlight>
{{out}}
<pre>Silence-Dogood.</pre>


=={{header|C++}}==
=={{header|C++}}==
Text used to encode:[http://paulo-jorente.de/text/theRaven.txt The Raven - by E.A.Poe]
Text used to encode:[http://paulo-jorente.de/text/theRaven.txt The Raven - by E.A.Poe]
<lang cpp>
<syntaxhighlight lang="cpp">
#include <vector>
#include <vector>
#include <iostream>
#include <iostream>
Line 75: Line 454:
return 0;
return 0;
}
}
</syntaxhighlight>
</lang>
{{out}}
{{out}}
<pre>
<pre>
Line 83: Line 462:
=={{header|D}}==
=={{header|D}}==
{{trans|Kotlin}}
{{trans|Kotlin}}
<lang D>import std.algorithm;
<syntaxhighlight lang="d">import std.algorithm;
import std.array;
import std.array;
import std.conv;
import std.conv;
Line 147: Line 526:
auto uiList = getUserInput();
auto uiList = getUserInput();
decode("theRaven.txt", uiList);
decode("theRaven.txt", uiList);
}</lang>
}</syntaxhighlight>
{{out}}
{{out}}
<pre>Silence-Dogood.</pre>
<pre>Silence-Dogood.</pre>


=={{header|Go}}==
=={{header|Go}}==
[[trans|C++}}
{{trans|C++}}
<lang go>package main
<syntaxhighlight lang="go">package main


import (
import (
"fmt"
"fmt"
"io/ioutil"
"io/ioutil"
"log"
"strconv"
"strconv"
"strings"
"strings"
Line 166: Line 546:
func getUserInput() []userInput {
func getUserInput() []userInput {
h := "0 18 0 0 0 68 0 1 0 100 0 32 0 114 0 45 0 38 0 26 0 16 0 21 0 17 0 59 0 11 " +
h := "0 18 0 0 0 68 0 1 0 100 0 32 0 114 0 45 0 38 0 26 0 16 0 21 0 17 0 59 0 11 " +
"0 29 0 102 0 0 0 10 0 50 0 39 0 42 0 33 0 50 0 46 0 54 0 76 0 47 0 84 2 28"
"0 29 0 102 0 0 0 10 0 50 0 39 0 42 0 33 0 50 0 46 0 54 0 76 0 47 0 84 2 28"
flds := strings.Fields(h)
flds := strings.Fields(h)
var uis []userInput
var uis []userInput
Line 179: Line 559:
}
}


func decode(fileName string, uis []userInput) {
func decode(fileName string, uis []userInput) error {
text, err := ioutil.ReadFile(fileName)
text, err := ioutil.ReadFile(fileName)
if err != nil {
if err != nil {
panic("Unable to read file")
return err
}
}


Line 221: Line 601:
}
}
fmt.Println()
fmt.Println()
return nil
}
}


func main() {
func main() {
uis := getUserInput()
uis := getUserInput()
decode("theRaven.txt", uis)
err := decode("theRaven.txt", uis)
if err != nil {
}</lang>
log.Fatal(err)
}
}</syntaxhighlight>


{{out}}
{{out}}
Line 232: Line 616:
Silence-Dogood.
Silence-Dogood.
</pre>
</pre>

=={{header|Java}}==
{{trans|Kotlin}}
<syntaxhighlight lang="java">import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;

public class Processing {
private static class UserInput {
private char formFeed;
private char lineFeed;
private char tab;
private char space;

private UserInput(char formFeed, char lineFeed, char tab, char space) {
this.formFeed = formFeed;
this.lineFeed = lineFeed;
this.tab = tab;
this.space = space;
}

char getFormFeed() {
return formFeed;
}

char getLineFeed() {
return lineFeed;
}

char getTab() {
return tab;
}

char getSpace() {
return space;
}
}

private static List<UserInput> getUserInput() {
String h = "0 18 0 0 0 68 0 1 0 100 0 32 0 114 0 45 0 38 0 26 0 16 0 21 0 17 0 59 0 11 " +
"0 29 0 102 0 0 0 10 0 50 0 39 0 42 0 33 0 50 0 46 0 54 0 76 0 47 0 84 2 28";
String[] s = h.split(" ");

List<UserInput> uiList = new ArrayList<>();
for (int idx = 0; idx + 3 < s.length; idx += 4) {
char c0 = (char) Integer.parseInt(s[idx + 0]);
char c1 = (char) Integer.parseInt(s[idx + 1]);
char c2 = (char) Integer.parseInt(s[idx + 2]);
char c3 = (char) Integer.parseInt(s[idx + 3]);

UserInput userInput = new UserInput(c0, c1, c2, c3);
uiList.add(userInput);
}
return uiList;
}

private static void decode(String fileName, List<UserInput> uiList) throws IOException {
Path path = Paths.get(fileName);
byte[] bytes = Files.readAllBytes(path);
String text = new String(bytes, StandardCharsets.UTF_8);

Predicate<UserInput> decode2 = (UserInput ui) -> {
char f = 0;
char l = 0;
char t = 0;
char s = 0;
char ff = ui.getFormFeed();
char lf = ui.getLineFeed();
char tb = ui.getTab();
char sp = ui.getSpace();

for (char c : text.toCharArray()) {
if (f == ff && l == lf && t == tb && s == sp) {
if (c == '!') {
return false;
}
System.out.print(c);
return true;
}
switch (c) {
case '\u000c':
f++;
l = 0;
t = 0;
s = 0;
break;
case '\n':
l++;
t = 0;
s = 0;
break;
case '\t':
t++;
s = 0;
break;
default:
s++;
break;
}
}

return false;
};

for (UserInput ui : uiList) {
if (!decode2.test(ui)) {
break;
}
}
System.out.println();
}

public static void main(String[] args) throws IOException {
List<UserInput> uiList = getUserInput();
decode("theRaven.txt", uiList);
}
}</syntaxhighlight>
{{out}}
<pre>Silence-Dogood.</pre>

=={{header|jq}}==
'''Adapted from [[#Wren|Wren]]'''
{{works with|jq}}
'''Works with gojq, the Go implementation of jq'''
<syntaxhighlight lang="jq"># User input takes the form of quadtuples of integers: [formFeed, lineFeed, tab, space]
def getUserInput:
def nwise($n):
def n: if length <= $n then . else .[0:$n] , (.[$n:] | n) end;
n;

"0 18 0 0 0 68 0 1 0 100 0 32 0 114 0 45 0 38 0 26 0 16 0 21 0 17 0 59 0 11 " +
"0 29 0 102 0 0 0 10 0 50 0 39 0 42 0 33 0 50 0 46 0 54 0 76 0 47 0 84 2 28"
| split(" ") | map(tonumber) | nwise(4)
| {formFeed: .[0], lineFeed: .[1], tab: .[2], space: .[3]} ;

def emit_until(cond; stream):
label $out | stream | if cond then break $out else . end;

# Input should be the text as a (long) string
def decode($uiList):
def stream: explode[] | [.] | implode;
def decode2(ui):
. as $text
| label $out
| foreach stream as $c (
{ f: 0, l: 0, t: 0, s: 0 };
if .f == ui.formFeed and .l == ui.lineFeed and .t == ui.tab and .s == ui.space
then .out = $c
elif $c == "\f"
then .f += 1
| .l = 0
| .t = 0
| .s = 0
elif $c == "\n"
then .l += 1
| .t = 0
| .s = 0
elif $c == "\t"
then .t += 1
| .s = 0
else .s += 1
end;
if .out then .out, break $out else empty end )
// "" ;
decode2($uiList) ;

# Input: the text
[emit_until(. == "!"; getUserInput as $ui | decode($ui)) ] | add</syntaxhighlight>
{{out}}
Invocation: jq -Rsr -f program.jq theRaven.txt
<pre>
Silence-Dogood.
</pre>

=={{header|Julia}}==
Customization is via adding to or deleting from the chars dictionary.
<syntaxhighlight lang="julia">@enum streamstate GET_FF GET_LF GET_TAB GET_CHAR ABORT
chars = Dict(GET_FF => ['\f'], GET_LF => ['\n'], GET_TAB => ['\t'])

function stream_decode_jit(iostream)
msg, state, ffcount, lfcount, tabcount, charcount = "", GET_FF, 0, 0, 0, 0
while true
if state == ABORT || eof(iostream)
return msg
end
ch = read(iostream, Char)
if state == GET_FF && ch in chars[GET_FF]
ffcount += 1
state = GET_LF
lfcount = 0
elseif state == GET_LF && ch in chars[GET_LF]
if (lfcount += 1) == ffcount
state = GET_TAB
tabcount = 0
end
elseif state == GET_TAB && ch in chars[GET_TAB]
if (tabcount += 1) == ffcount
state = GET_CHAR
charcount = 0
end
elseif state == GET_CHAR
if (charcount += 1) == ffcount
print(ch)
msg *= ch
if ch == '!'
state = ABORT
else
state = GET_FF
end
end
end
end
end

stream_decode_jit(open("filename.txt", "r"))
</syntaxhighlight>


=={{header|Kotlin}}==
=={{header|Kotlin}}==
{{trans|C++}}
{{trans|C++}}
<lang scala>// version 1.2.10
<syntaxhighlight lang="scala">// version 1.2.10


import java.io.File
import java.io.File
Line 284: Line 889:
val uiList = getUserInput()
val uiList = getUserInput()
decode("theRaven.txt", uiList)
decode("theRaven.txt", uiList)
}</lang>
}</syntaxhighlight>


{{out}}
{{out}}
Line 290: Line 895:
Silence-Dogood.
Silence-Dogood.
</pre>
</pre>

=={{header|Nim}}==
{{trans|Kotlin}}
With some modifications compared to the model.

<syntaxhighlight lang="nim">import options, sequtils, strutils

type Position = tuple[ff, lf, tab, sp: int]

func buildUserInput(s: string): seq[Position] =
let valList = s.splitWhitespace().map(parseInt)
doAssert valList.len mod 4 == 0, "Number of values must be a multiple of four."
doAssert valList.allIt(it >= 0), "Expected non negative values."
let posList = valList.distribute(valList.len div 4)
result = posList.mapIt((ff: it[0], lf: it[1], tab: it[2], sp: it[3]))


proc decode(filename: string; uiList: seq[Position]): string =

func decode(text: string; ui: Position): Option[char] =
var f, l, t, s = 0
let (ff, lf, tab, sp) = ui
for c in text:
if f == ff and l == lf and t == tab and s == sp:
return if c == '!': none(char) else: some(c)
case c
of '\f': inc f; l = 0; t = 0; s = 0
of '\l': inc l; t = 0; s = 0
of '\t': inc t; s = 0
else: inc s

let text = filename.readFile()
for ui in uiList:
let c = text.decode(ui)
if c.isNone: break
result.add c.get()

const UiList = buildUserInput("0 18 0 0 0 68 0 1 0 100 0 32 0 114 0 " &
"45 0 38 0 26 0 16 0 21 0 17 0 59 0 11 " &
"0 29 0 102 0 0 0 10 0 50 0 39 0 42 0 " &
"33 0 50 0 46 0 54 0 76 0 47 0 84 2 28")

echo "theRaven.txt".decode(UiList)</syntaxhighlight>

{{out}}
<pre>Silence-Dogood.</pre>

=={{header|Perl}}==
{{trans|Raku}}
{{libheader|ntheory}}
<syntaxhighlight lang="perl">use strict;
use warnings;
use feature 'say';
use feature 'state';

use ntheory qw/fromdigits todigitstring/;

my $key = 'perl5';
srand fromdigits($key,36) % 2**63;

my @stream;

sub stream {
my($i) = shift;
state @chars;
push @chars, chr($_) for 14..127;
$stream[$i] = $chars[rand 1+127-14] unless $stream[$i];
}

sub jit_encode {
my($str) = shift;
my $i = 0;
my $last = 0;
my $enc = '';
for my $c (split '', $str) {
my $h;
my $l = '';
++$i until $c eq stream($i);
my $o = $i - $last;
$l = $o % 26;
$h = $o - $l if $o > 26;
$l += 10;
$enc .= ($h ? uc todigitstring($h,36) : '') . lc todigitstring($l,36);
$last = $i;
}
$enc
}

sub jit_decode {
my($str) = shift;
my @matches = $str =~ /((.*?) ([a-z]))/gx;
my $dec = '';
my $i = 0;
for my $j (0 .. @matches/3 - 1) {
my $o = ( fromdigits($matches[3*$j+1],36) - 10 // 0) +
( fromdigits($matches[3*$j+2],36) // 0);
$i += $o;
$dec .= $stream[$i];
}
$dec
}

my $enc = jit_encode('The slithey toves did gyre and gimble in the wabe');
say my $result = "Encoded\n$enc\n\nDecoded\n" . jit_decode($enc);</syntaxhighlight>
{{out}}
<pre>Encoded
bQh52yf9Ex2Wi4Cv1GcyoAUcBKbke3Mo5Ss2WybQlvQs1GviQc1GnQg5Sv26j1Gm26m3Mp26iQz78lQx2Wel1Gcs52y5Sds3Me26l52au1Gwe1Gl

Decoded
The slithey toves did gyre and gimble in the wabe</pre>

=={{header|Phix}}==
{{trans|C}}
{{libheader|Phix/libcurl}}
<!--<syntaxhighlight lang="phix">(notonline)-->
<span style="color: #000080;font-style:italic;">-- demo/rosetta/BookCipher.exw</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">decode</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">fn</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">sequence</span> <span style="color: #000000;">ui</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">ff</span><span style="color: #0000FF;">,</span><span style="color: #000000;">lf</span><span style="color: #0000FF;">,</span><span style="color: #000000;">tab</span><span style="color: #0000FF;">,</span><span style="color: #000000;">sp</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">ui</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">f</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">l</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">t</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">while</span> <span style="color: #004600;">true</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">c</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">getc</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">=-</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #004600;">false</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">f</span><span style="color: #0000FF;">==</span><span style="color: #000000;">ff</span> <span style="color: #008080;">and</span> <span style="color: #000000;">l</span><span style="color: #0000FF;">==</span><span style="color: #000000;">lf</span> <span style="color: #008080;">and</span> <span style="color: #000000;">t</span><span style="color: #0000FF;">==</span><span style="color: #000000;">tab</span> <span style="color: #008080;">and</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">==</span><span style="color: #000000;">sp</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">==</span><span style="color: #008000;">'!'</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #004600;">false</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">c</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">true</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">==</span><span style="color: #000000;">#0C</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">f</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">l</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">t</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">==</span><span style="color: #008000;">'\n'</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">l</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">t</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">==</span><span style="color: #008000;">'\t'</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">t</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">else</span>
<span style="color: #000000;">s</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">false</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">include</span> <span style="color: #000000;">builtins</span><span style="color: #0000FF;">\</span><span style="color: #000000;">libcurl</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">decodeFile</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">filename</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">url</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">sequence</span> <span style="color: #000000;">code</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #008080;">not</span> <span style="color: #7060A8;">file_exists</span><span style="color: #0000FF;">(</span><span style="color: #000000;">filename</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Downloading %s...\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">filename</span><span style="color: #0000FF;">})</span>
<span style="color: #004080;">CURLcode</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">curl_easy_get_file</span><span style="color: #0000FF;">(</span><span style="color: #000000;">url</span><span style="color: #0000FF;">,</span><span style="color: #008000;">""</span><span style="color: #0000FF;">,</span><span style="color: #000000;">filename</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- (no proxy)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">res</span><span style="color: #0000FF;">!=</span><span style="color: #004600;">CURLE_OK</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">error</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"%d"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">res</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">res</span><span style="color: #0000FF;">=</span><span style="color: #000000;">CURLE_COULDNT_RESOLVE_HOST</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">error</span> <span style="color: #0000FF;">&=</span> <span style="color: #008000;">" [CURLE_COULDNT_RESOLVE_HOST]"</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Error %s downloading file\n"</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">error</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">fn</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">open</span><span style="color: #0000FF;">(</span><span style="color: #000000;">filename</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"r"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">fn</span><span style="color: #0000FF;">=-</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> <span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"could not open %s"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">filename</span><span style="color: #0000FF;">})</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">code</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">if</span> <span style="color: #008080;">not</span> <span style="color: #000000;">decode</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">,</span><span style="color: #000000;">code</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">seek</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">)!=</span><span style="color: #004600;">SEEK_OK</span> <span style="color: #008080;">then</span> <span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"seek error"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\n\n"</span><span style="color: #0000FF;">);</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">code</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">18</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">68</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">100</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">32</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">114</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">45</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">38</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">26</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">16</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">21</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">17</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">59</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">11</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">29</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">102</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">10</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">50</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">39</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">42</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">33</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">50</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">46</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">54</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">76</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">47</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">84</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">28</span><span style="color: #0000FF;">}}</span>
<span style="color: #000000;">decodeFile</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"theRaven.txt"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"http://paulo-jorente.de/text/theRaven.txt"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">code</span><span style="color: #0000FF;">)</span>
<span style="color: #0000FF;">{}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">wait_key</span><span style="color: #0000FF;">()</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
Silence-Dogood.
</pre>

=={{header|Python}}==
{{trans|D}}
<syntaxhighlight lang="python">import sys

class UserInput:
def __init__(self,chunk):
self.formFeed = int(chunk[0])
self.lineFeed = int(chunk[1])
self.tab = int(chunk[2])
self.space = int(chunk[3])

def __str__(self):
return "(ff=%d; lf=%d; tb=%d; sp%d)" % (self.formFeed,self.lineFeed,self.tab,self.space)

def chunks(l,n):
for i in xrange(0, len(l), n):
yield l[i:i+n]

def getUserInput():
h = "0 18 0 0 0 68 0 1 0 100 0 32 0 114 0 45 0 38 0 26 0 16 0 21 0 17 0 59 0 11 "\
"0 29 0 102 0 0 0 10 0 50 0 39 0 42 0 33 0 50 0 46 0 54 0 76 0 47 0 84 2 28"
ha = h.split()
return [UserInput(chunk) for chunk in chunks(ha, 4)]

def decode(filename,uiList):
f = open(filename, "r")
text = f.read()

def decode2(ui):
f = 0
l = 0
t = 0
s = 0
for c in text:
if f == ui.formFeed and l == ui.lineFeed and t == ui.tab and s == ui.space:
if c == '!':
return False
sys.stdout.write(c)
return True
if c == '\u000c':
f=f+1
l=0
t=0
s=0
elif c == '\n':
l=l+1
t=0
s=0
elif c == '\t':
t=t+1
s=0
else:
s=s+1
return False

for ui in uiList:
if not decode2(ui):
break
print

##### Main #####

uiList = getUserInput()
decode("theRaven.txt", uiList)</syntaxhighlight>
{{out}}
<pre>Silence-Dogood.</pre>

=={{header|Racket}}==

{{trans|Kotlin}}

<syntaxhighlight lang="racket">#lang racket

(define user-input
(~a "0 18 0 0 0 68 0 1 0 100 0 32 0 114 0 45 0 38 0 26 0 16 0 21 0 17 0 59 0 11 "
"0 29 0 102 0 0 0 10 0 50 0 39 0 42 0 33 0 50 0 46 0 54 0 76 0 47 0 84 2 28"))

(define content (file->string "theRaven.txt"))

(define (decode slice)
(match-define (list ff lf tb sp) slice)
(let loop ([f 0] [l 0] [t 0] [s 0] [xs (string->list content)])
(define next (curryr loop (rest xs)))
(match (first xs)
[c #:when (and (= f ff) (= l lf) (= t tb) (= s sp)) c]
[#\u000c (next (add1 f) 0 0 0)]
[#\newline (next f (add1 l) 0 0)]
[#\tab (next f l (add1 t) 0)]
[_ (next f l t (add1 s))])))

(for ([slice (in-slice 4 (map string->number (string-split user-input)))])
(define c (decode slice))
#:break (char=? #\! c)
(display c))</syntaxhighlight>

{{in}}
http://paulo-jorente.de/text/theRaven.txt

{{out}}
<pre>
Silence-Dogood.
</pre>

=={{header|Raku}}==
(formerly Perl 6)
{{works with|Rakudo|2019.03}}

This is a something of a toy encoder / decoder and probably shouldn't be used for anything serious.

Default encode/decode key is 'Raku' Feed it a pass phrase at the command line to use that instead.

Will handle any visible character in the ASCII range as well as space and new-line.

<syntaxhighlight lang="raku" line>#`[
Set srand to set the encode / decode "key".
Need to use the same "key" and same implementation
of Raku to encode / decode. Gain "security" by
exchanging "keys" by a second channel. Default
"key" is "Raku"
]

unit sub MAIN ($key = 'Raku');

srand $key.comb(/<.alnum>/).join.parse-base(36) % 2**63;

my @stream = (flat "\n", ' ' .. '~').roll(*);

sub jit-encode (Str $str) {
my $i = 0;
my $last = 0;
my $enc = '';
for $str.comb -> $c {
my $h;
my $l = '';
++$i until $i > 1 && $c eq @stream[$i];
my $o = $i - $last;
$l = $o % 26;
$h = $o - $l if $o >= 26;
$l += 10;
$enc ~= ($h ?? $h.base(36).uc !! '') ~ ($l.base(36).lc);
$last = $i;
}
my $block = 60;
$enc.comb($block).join: "\n"
}

sub jit-decode (Str $str is copy) {
$str.=subst("\n", '', :g);
$str ~~ m:g/((.*?) (<:Ll>))/;
my $dec = '';
my $i = 0;
for $/.List -> $l {
my $o = ($l[0][1].Str.parse-base(36) - 10 // 0) +
($l[0][0].Str.parse-base(36) // 0);
$i += $o;
$dec ~= @stream[$i];
}
$dec
}

my $secret = q:to/END/;
In my opinion, this task is pretty silly.

'Twas brillig, and the slithy toves
Did gyre and gimble in the wabe.

!@#$%^&*()_+}{[].,><\|/?'";:1234567890
END

say "== Secret: ==\n$secret";

say "\n== Encoded: ==";
say my $enc = jit-encode($secret);

say "\n== Decoded: ==";
say jit-decode($enc);</syntaxhighlight>

<pre>== Secret: ==
In my opinion, this task is pretty silly.

'Twas brillig, and the slithy toves
Did gyre and gimble in the wabe.

!@#$%^&*()_+}{[].,><\|/?'";:1234567890


== Encoded: ==
Qv26e26q1Gi2Ww5SiQr26h3Mk1GbQy52e1Gg6Ib52kQfQk26n26l26cQm26q
2Wk26vwme52qy6Ia1GuQfa3MbQxtd26aa3MvQu2Wuat26p2Wbe2Wc1Ga26g2
6h26pQha26h4Cf26jrz7Yz3MaA4h2WxFWf52zyg2WrQn2Wj26pQyQy78x1Gd
dk4Cu26k26qaaap26j26xqQf7Yr8Op3Me3Me5Sv1Ge1Gt2WxlQz5Si1GeQg4
CjQc5Sb2WbQo1GycQr1Gm1Gy1GsQei3MrQsai1Gq2WnQdt2Wj1Gff1Gg26le
2Wd1Go9Ek1Gm9Eh2Wb1Gd52h2WdQae4Chu3MeQd1Gg1Gw4CqbEGh52u2Wr1G
t52xhvQmx

== Decoded: ==
In my opinion, this task is pretty silly.

'Twas brillig, and the slithy toves
Did gyre and gimble in the wabe.

!@#$%^&*()_+}{[].,><\|/?'";:1234567890</pre>


=={{header|REXX}}==
=={{header|REXX}}==
The input file used by this REXX program only contains one page; &nbsp; it has no &nbsp; ''FF'' &nbsp; (''formfeed'') &nbsp; characters in it),
The input file used by this REXX program only contains one page; &nbsp; it has no &nbsp; ''FF'' &nbsp; (''formfeed'') &nbsp; characters in it),
<br>and the injection of &nbsp; ''FF'' &nbsp; characters into the file would be like putting pencil marks into a holy book. &nbsp; <big><big><big> ☺ </big></big></big>
<br>and the injection of &nbsp; ''FF'' &nbsp; characters into the file would be like putting pencil marks into a holy book. &nbsp; <big><big><big> ☺ </big></big></big>
<lang rexx>/*REXX program extracts characters by using a book cipher from a text file. */
<syntaxhighlight lang="rexx">/*REXX program extracts characters by using a book cipher (that is a text file). */
parse arg iFID /*obtain optional name of file (book).*/
parse arg iFID . /*obtain optional name of file (book).*/
if iFID=='' | iFID=="," then iFID="JIT.TXT" /*Not specified? Then use the default.*/
if iFID=='' | iFID=="," then iFID= 'JIT.TXT' /*Not specified? Then use the default.*/
$= 'abcdefghijklmnopqrstuvwxyz'; _=$; upper _; $= '0123456789'$ || _
$= 'abcdefghijklmnopqrstuvwxyz'; _=$; upper _; $= "0123456789"$ || _; $$=$ || xrange()
prompt= '──────────enter four parameters (all positive integers) or QUIT'
prompt= '────────── enter four positive integers or Quit'
pag=1; lin=1; FF='c'x /*assume start of page 1, line 1. */
pag=1; lin=1; FF= 'c'x /*assume start of page 1, line 1. */
@.= /*read the entire book from the file. */
@.= /*read the entire book from the file. */
do while lines(iFID)\==0 /*process lines from input stream(file)*/
do while lines(iFID)\==0 /*process lines from input stream(file)*/
_=translate( linein(iFID), , '9'x) /*obtain a single line from input file.*/
_= translate( linein(iFID), , '9'x) /*obtain a single line from input file.*/
if pos(FF, _)\==0 then do; pag=pag+1; lin=1 /*bump page counter; reset line counter*/
if pos(FF, _)\==0 then do; pag=pag+1; lin=1 /*bump page counter; reset line counter*/
end /* [↑] handle finding of FF (formfeed)*/
end /* [↑] handle finding of FF (formfeed)*/
@.pag.lin=_ /*obtain a single line from input file.*/
@.pag.lin= _ /*obtain a single line from input file.*/
lin=lin+1 /*bump the line counter. */
lin= lin + 1 /*bump the line counter. */
end /*while lines···*/ /* [↑] read the entire input stream. */
end /*while*/ /* [↑] read the entire input stream. */
?= /*define the phrase to be null (so far)*/
?= /*define the phrase to be null (so far)*/
do ask=0; bad=1; say prompt; pull y /*get just─in─time positional numbers. */
do ask=0; say prompt; pull y /*get just─in─time positional numbers. */
if y='QUIT' then exit 0 /*the user wants out of this loop, exit*/
if abbrev('QUIT', y, 1) then exit 0 /*the user wants out of here, so exit. */
y=space( translate(y, $, $ || xrange() )) /*allow any separator the user wants. */
y=space( translate(y, $, $$) ) /*allow any separator the user wants. */
parse var y a.1 a.2 a.3 a.4 /*parse the pertinent parameters. */
parse var y a.1 a.2 a.3 a.4 /*parse the pertinent parameters. */
if words(y)>4 then do; say 'too many parameters entered.'
if words(y)>4 then do; say 'too many parameters entered.'
iterate ask
iterate ask
end /*go and try again to obtain the parms.*/
end /*go and try again to obtain the parms.*/
do k=1 for 4 /*validate parms {positive integers}.*/
do k=1 for 4; is#= datatype(a.k, 'W') /*validate parms {positive integers}.*/
if datatype(a.k,'W') & a.k>0 then iterate /*found a bad parameter. */
if is# then a.k= a.k / 1 /*normalize the number (for indexing). */
say 'parameter ' k " is missing or not a positive integer: " a.k
if is# & a.k>0 then iterate /*found a good parameter? Then skip. */
say 'parameter ' k " is missing or not a positive integer: " a.k
iterate ask /*go and ask for another set of parms. */
iterate ask /*go and ask for another set of parms. */
a.k=a.k / 1 /*normalize the user's parm (number). */
end /*k*/ /* [↑] done with the validations. */
end /*k*/ /* [↑] done with the validations. */
parse value a.1 a.2 a.3 a.4 with p l w c /*parse parameters for specific names. */
parse value a.1 a.2 a.3 a.4 with p L w c /*parse parameters for specific names. */
x=substr( word( @.p.l, w), c, 1) /*extract a character from the book. */
x=substr( word( @.p.L, w), c, 1) /*extract a character from the book. */
if x=='!' then leave /*if the stop char was found, done. */
if x=='!' then leave /*if the stop char was found, done. */
say right(x '◄─── a letter',46) /*might as well echo char to terminal. */
say right(x '◄─── a letter', 46) /*might as well echo char to terminal. */
?=? || x /*append the character to the phrase. */
?= ? || x /*append the character to the phrase. */
end /*j*/ /* [↑] display letters found in book. */
end /*j*/ /* [↑] display letters found in book. */
say '═════►' ? /*stick a fork in it, we're all done. */</lang>
say '═════►' ? /*stick a fork in it, we're all done. */</syntaxhighlight>
{{out|input|text=&nbsp; supplied to the console (terminal) by the user in response to the prompts, &nbsp; (the commas are optional):}}
{{out|input|text=&nbsp; supplied to the console (terminal) by the user in response to the prompts, &nbsp; (the commas are optional):}}
<pre>
<pre>
Line 360: Line 1,355:
=={{header|Tcl}}==
=={{header|Tcl}}==
{{works with|Tcl|8.6}}
{{works with|Tcl|8.6}}
<lang tcl>package require Tcl 8.6
<syntaxhighlight lang="tcl">package require Tcl 8.6


oo::class create JustInTimeStreamExtract {
oo::class create JustInTimeStreamExtract {
Line 429: Line 1,424:
tcl::mathop::== $counter $counters(page) $counters(line) $counters(field) $counters(char)
tcl::mathop::== $counter $counters(page) $counters(line) $counters(field) $counters(char)
}
}
}</lang>
}</syntaxhighlight>
Demonstration of use:
Demonstration of use:
<lang tcl>[JustInTimeStreamExtract new] stream [open "sample.txt"]</lang>
<syntaxhighlight lang="tcl">[JustInTimeStreamExtract new] stream [open "sample.txt"]</syntaxhighlight>
<!-- no output; I'll wait for someone else to invent something to decode… -->
<!-- no output; I'll wait for someone else to invent something to decode… -->

=={{header|Visual Basic .NET}}==
{{trans|C#}}
<syntaxhighlight lang="vbnet">Module Module1

Structure UserInput
ReadOnly FormFeed As Char
ReadOnly LineFeed As Char
ReadOnly Tab As Char
ReadOnly Space As Char

Sub New(ff As String, lf As String, tb As String, sp As String)
FormFeed = ChrW(Integer.Parse(ff))
LineFeed = ChrW(Integer.Parse(lf))
Tab = ChrW(Integer.Parse(tb))
Space = ChrW(Integer.Parse(sp))
End Sub
End Structure

Function GetUserInput() As List(Of UserInput)
Dim h = "0 18 0 0 0 68 0 1 0 100 0 32 0 114 0 45 0 38 0 26 0 16 0 21 0 17 0 59 0 11 " &
"0 29 0 102 0 0 0 10 0 50 0 39 0 42 0 33 0 50 0 46 0 54 0 76 0 47 0 84 2 28"
Return h.Split(" ") _
.Select(Function(x, idx) New With {x, idx}) _
.GroupBy(Function(x) x.idx \ 4) _
.Select(Function(g)
Dim ge = g.Select(Function(a) a.x).ToArray()
Return New UserInput(ge(0), ge(1), ge(2), ge(3))
End Function) _
.ToList()
End Function

Sub Decode(filename As String, uiList As List(Of UserInput))
Dim text = IO.File.ReadAllText(filename)

Dim Inc = Function(a As Char) As Char
Return ChrW(AscW(a) + 1)
End Function

Dim DecodeImpl = Function(ui As UserInput) As Boolean
Dim f = ChrW(0)
Dim l = ChrW(0)
Dim t = ChrW(0)
Dim s = ChrW(0)

For Each c In text
If f = ui.FormFeed AndAlso l = ui.LineFeed AndAlso t = ui.Tab AndAlso s = ui.Space Then
If c = "!" Then
Return False
End If
Console.Write(c)
Return True
End If
If vbFormFeed = c Then
f = Inc(f)
l = ChrW(0)
t = ChrW(0)
s = ChrW(0)
ElseIf vbLf = c Then
l = Inc(l)
t = ChrW(0)
s = ChrW(0)
ElseIf vbTab = c Then
t = Inc(t)
s = ChrW(0)
Else
s = Inc(s)
End If
Next

Return False
End Function

For Each ui In uiList
If Not DecodeImpl(ui) Then
Exit For
End If
Next

Console.WriteLine()
End Sub

Sub Main()
Dim uiList = GetUserInput()
Decode("theRaven.txt", uiList)
End Sub

End Module</syntaxhighlight>
{{out}}
<pre>Silence-Dogood.</pre>

=={{header|Wren}}==
{{trans|Kotlin}}
{{libheader|Wren-dynamic}}
{{libheader|wren-seq}}
<syntaxhighlight lang="wren">import "io" for File
import "./dynamic" for Tuple
import "./seq" for Lst

var UserInput = Tuple.create("UserINput", ["formFeed", "lineFeed", "tab", "space"])

var getUserInput = Fn.new {
var h = "0 18 0 0 0 68 0 1 0 100 0 32 0 114 0 45 0 38 0 26 0 16 0 21 0 17 0 59 0 11 " +
"0 29 0 102 0 0 0 10 0 50 0 39 0 42 0 33 0 50 0 46 0 54 0 76 0 47 0 84 2 28"
return Lst.chunks(h.split(" "), 4).map { |chunk|
var flts = chunk.map { |c| Num.fromString(c) }.toList
return UserInput.new(flts[0], flts[1], flts[2], flts[3])
}
}

var decode = Fn.new { |fileName, uiList|
var text = File.read(fileName)

var decode2 = Fn.new { |ui|
var f = 0
var l = 0
var t = 0
var s = 0
for (c in text) {
if (f == ui.formFeed && l == ui.lineFeed && t == ui.tab && s == ui.space) {
if (c == "!") return false
System.write(c)
return true
}
if (c == "\f") {
f = f + 1
l = 0
t = 0
s = 0
} else if (c == "\n") {
l = l + 1
t = 0
s = 0
} else if (c == "\t") {
t = t + 1
s = 0
} else {
s = s + 1
}
}
return false
}

for (ui in uiList) if (!decode2.call(ui)) break
System.print()
}

var uiList = getUserInput.call()
decode.call("theRaven.txt", uiList)</syntaxhighlight>

{{out}}
<pre>
Silence-Dogood.
</pre>


=={{header|zkl}}==
=={{header|zkl}}==
{{trans|C++}}
{{trans|C++}}
<lang zkl>class FlyBy{
<syntaxhighlight lang="zkl">class FlyBy{
fcn decode(file,tuplets){
fcn decode(file,tuplets){
codePad:=File(file).read().mode(String); // blob of text
codePad:=File(file).read().mode(String); // blob of text
Line 460: Line 1,609:
h.split(" ").pump(List,T(Void.Read,3),
h.split(" ").pump(List,T(Void.Read,3),
fcn(ff,lf,t,s){ vm.arglist.apply("toInt") });
fcn(ff,lf,t,s){ vm.arglist.apply("toInt") });
}</lang>
}</syntaxhighlight>
<lang zkl>input:=getUserInput();
<syntaxhighlight lang="zkl">input:=getUserInput();
// our code pad is: http://paulo-jorente.de/text/theRaven.txt
// our code pad is: http://paulo-jorente.de/text/theRaven.txt
FlyBy.decode("theRaven.txt",input);</lang>
FlyBy.decode("theRaven.txt",input);</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>

Latest revision as of 09:39, 23 March 2024

Just in time processing on a character stream is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Given a stream of characters containing the separator characters "formfeed", "linefeed", "tab" and "space", print out the ith character of the ith tab-field of the ith line of the ith page to reveal a secret password.

Stop processing immediately upon encountering a "!" found uniquely in this i,i,i,i position (lest the system self-destruct). The "!" may be found elsewhere however, in which case it should be ignored.

Ideally this can be generalised as follows:

  • The separator characters are defined by a user-supplied array that can include additional or alternative separators, e.g. (formfeed, linefeed, ".", "," ," ",...).
  • The selection criterion is generalised ith,ith,ith,ith to a boolean function of f(page,line,field,word,...) or f(ith,jth,kth,lth,mth,etc...)

Provide a reasonably interesting message to be decoded, e.g. "Silence-Dogood". Your choice.

This task was inspired by the movie "National Treasure", which refers to a "book cipher".

11l

Translation of: Python
T UserInput
   Int formFeed
   Int lineFeed
   Int tab
   Int space

   F (chunk)
      .formFeed = chunk[0]
      .lineFeed = chunk[1]
      .tab = chunk[2]
      .space = chunk[3]

   F String()
      R ‘(ff=#.; lf=#.; tb=#.; sp#.)’.format(.formFeed, .lineFeed, .tab, .space)

F chunks(l, n)
   [[Int]] r
   L(i) (0 .< l.len).step(n)
      r.append(l[i .+ n])
   R r

F getUserInput()
   V h = ‘0 18 0 0 0 68 0 1 0 100 0 32 0 114 0 45 0 38 0 26 0 16 0 21 0 17 0 59 0 11 ’""
         ‘0 29 0 102 0 0 0 10 0 50 0 39 0 42 0 33 0 50 0 46 0 54 0 76 0 47 0 84 2 28’
   V ha = h.split(‘ ’).map(Int)
   R chunks(ha, 4).map(chunk -> UserInput(chunk))

F decode(filename, uiList)
   V f = File(filename)
   V text = f.read()

   F decode2(ui)
      V f = 0
      V l = 0
      V t = 0
      V s = 0
      L(c) @text
         I f == ui.formFeed & l == ui.lineFeed & t == ui.tab & s == ui.space
            I c == ‘!’
               R 0B
            print(c, end' ‘’)
            R 1B
         I c.code == 0'C
            f = f + 1
            l = 0
            t = 0
            s = 0
         E I c == "\n"
            l = l + 1
            t = 0
            s = 0
         E I c == "\t"
            t = t + 1
            s = 0
         E
            s = s + 1
      R 0B

   L(ui) uiList
      I !decode2(ui)
         L.break
   print()

V uiList = getUserInput()
decode(‘theRaven.txt’, uiList)
Output:
Silence-Dogood.

C

Translation of: C++
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

struct UserInput {
    char formFeed;
    char lineFeed;
    char tab;
    char space;
};

struct UserInputNode {
    struct UserInput ui;
    struct UserInputNode *next;
};

bool decode(FILE *fp, const struct UserInput ui) {
    char f = 0, l = 0, t = 0, s = 0;
    char buffer[1];

    while (fread(buffer, 1, 1, fp)) {
        char c = buffer[0];

        if (f == ui.formFeed && l == ui.lineFeed && t == ui.tab && s == ui.space) {
            if (c == '!')
                return false;
            putchar(c);
            return true;
        } else if (c == '\f') {
            f++;
            l = t = s = 0;
        } else if (c == '\n') {
            l++;
            t = s = 0;
        } else if (c == '\t') {
            t++;
            s = 0;
        } else {
            s++;
        }
    }

    return false;
}

void decodeFile(char *fileName, struct UserInputNode *uin) {
    FILE *fp;

    fp = fopen(fileName, "r");
    if (NULL == fp) {
        fprintf(stderr, "Could not find %s\n", fileName);
        return;
    }

    if (NULL == uin) {
        fprintf(stderr, "No user input detected!\n");
        return;
    }

    while (NULL != uin) {
        if (!decode(fp, uin->ui)) {
            break;
        }
        fseek(fp, 0, SEEK_SET);
        uin = uin->next;
    }
    printf("\n\n");
}

struct UserInputNode *getUserInput() {
    struct UserInputNode *uip, *temp;

    // 0 18 0 0
    temp = malloc(sizeof(struct UserInputNode));
    temp->ui.formFeed = 0;
    temp->ui.lineFeed = 18;
    temp->ui.tab = 0;
    temp->ui.space = 0;
    uip = temp;

    // 0 68 0 1
    temp->next = malloc(sizeof(struct UserInputNode));
    temp = temp->next;
    temp->ui.formFeed = 0;
    temp->ui.lineFeed = 68;
    temp->ui.tab = 0;
    temp->ui.space = 1;

    // 0 100 0 32
    temp->next = malloc(sizeof(struct UserInputNode));
    temp = temp->next;
    temp->ui.formFeed = 0;
    temp->ui.lineFeed = 100;
    temp->ui.tab = 0;
    temp->ui.space = 32;

    // 0 114 0 45
    temp->next = malloc(sizeof(struct UserInputNode));
    temp = temp->next;
    temp->ui.formFeed = 0;
    temp->ui.lineFeed = 114;
    temp->ui.tab = 0;
    temp->ui.space = 45;

    // 0 38 0 26
    temp->next = malloc(sizeof(struct UserInputNode));
    temp = temp->next;
    temp->ui.formFeed = 0;
    temp->ui.lineFeed = 38;
    temp->ui.tab = 0;
    temp->ui.space = 26;

    // 0 16 0 21
    temp->next = malloc(sizeof(struct UserInputNode));
    temp = temp->next;
    temp->ui.formFeed = 0;
    temp->ui.lineFeed = 16;
    temp->ui.tab = 0;
    temp->ui.space = 21;

    // 0 17 0 59
    temp->next = malloc(sizeof(struct UserInputNode));
    temp = temp->next;
    temp->ui.formFeed = 0;
    temp->ui.lineFeed = 17;
    temp->ui.tab = 0;
    temp->ui.space = 59;

    // 0 11 0 29
    temp->next = malloc(sizeof(struct UserInputNode));
    temp = temp->next;
    temp->ui.formFeed = 0;
    temp->ui.lineFeed = 11;
    temp->ui.tab = 0;
    temp->ui.space = 29;

    // 0 102 0 0
    temp->next = malloc(sizeof(struct UserInputNode));
    temp = temp->next;
    temp->ui.formFeed = 0;
    temp->ui.lineFeed = 102;
    temp->ui.tab = 0;
    temp->ui.space = 0;

    // 0 10 0 50
    temp->next = malloc(sizeof(struct UserInputNode));
    temp = temp->next;
    temp->ui.formFeed = 0;
    temp->ui.lineFeed = 10;
    temp->ui.tab = 0;
    temp->ui.space = 50;

    // 0 39 0 42
    temp->next = malloc(sizeof(struct UserInputNode));
    temp = temp->next;
    temp->ui.formFeed = 0;
    temp->ui.lineFeed = 39;
    temp->ui.tab = 0;
    temp->ui.space = 42;

    // 0 33 0 50
    temp->next = malloc(sizeof(struct UserInputNode));
    temp = temp->next;
    temp->ui.formFeed = 0;
    temp->ui.lineFeed = 33;
    temp->ui.tab = 0;
    temp->ui.space = 50;

    // 0 46 0 54
    temp->next = malloc(sizeof(struct UserInputNode));
    temp = temp->next;
    temp->ui.formFeed = 0;
    temp->ui.lineFeed = 46;
    temp->ui.tab = 0;
    temp->ui.space = 54;

    // 0 76 0 47
    temp->next = malloc(sizeof(struct UserInputNode));
    temp = temp->next;
    temp->ui.formFeed = 0;
    temp->ui.lineFeed = 76;
    temp->ui.tab = 0;
    temp->ui.space = 47;

    // 0 84 2 28
    temp->next = malloc(sizeof(struct UserInputNode));
    temp = temp->next;
    temp->ui.formFeed = 0;
    temp->ui.lineFeed = 84;
    temp->ui.tab = 2;
    temp->ui.space = 28;

    temp->next = NULL;
    return uip;
}

void freeUserInput(struct UserInputNode *uip) {
    if (NULL == uip) {
        return;
    }

    freeUserInput(uip->next);
    uip->next = NULL;

    free(uip);
}

int main() {
    struct UserInputNode *uip;

    uip = getUserInput();
    decodeFile("theRaven.txt", uip);
    freeUserInput(uip);

    return 0;
}
Output:
Silence-Dogood.

C#

Translation of: D
using System;
using System.Collections.Generic;
using System.Linq;

namespace JustInTimeProcessing {
    struct UserInput {
        public UserInput(string ff, string lf, string tb, string sp) {
            FormFeed = (char)int.Parse(ff);
            LineFeed = (char)int.Parse(lf);
            Tab = (char)int.Parse(tb);
            Space = (char)int.Parse(sp);
        }

        public char FormFeed { get; }
        public char LineFeed { get; }
        public char Tab { get; }
        public char Space { get; }
    }

    class Program {
        static List<UserInput> GetUserInput() {
            string h = "0 18 0 0 0 68 0 1 0 100 0 32 0 114 0 45 0 38 0 26 0 16 0 21 0 17 0 59 0 11 "
                + "0 29 0 102 0 0 0 10 0 50 0 39 0 42 0 33 0 50 0 46 0 54 0 76 0 47 0 84 2 28";
            return h.Split(' ')
                .Select((x, idx) => new { x, idx })
                .GroupBy(x => x.idx / 4)
                //.Select(g => g.Select(a => a.x))
                .Select(g => {
                    var ge = g.Select(a => a.x).ToArray();
                    return new UserInput(ge[0], ge[1], ge[2], ge[3]);
                })
                .ToList();
        }

        static void Decode(string filename, List<UserInput> uiList) {
            string text = System.IO.File.ReadAllText(filename);

            bool Decode2(UserInput ui) {
                char f = (char)0;
                char l = (char)0;
                char t = (char)0;
                char s = (char)0;

                foreach (char c in text) {
                    if (f == ui.FormFeed && l == ui.LineFeed && t == ui.Tab && s == ui.Space) {
                        if (c == '!') return false;
                        Console.Write(c);
                        return true;
                    }
                    if (c == '\u000c') {
                        f++; l = (char)0; t = (char)0; s = (char)0;
                    } else if (c == '\n') {
                        l++; t = (char)0; s = (char)0;
                    } else if (c == '\t') {
                        t++; s = (char)0;
                    } else {
                        s++;
                    }
                }

                return false;
            }

            foreach (UserInput ui in uiList) {
                if (!Decode2(ui)) {
                    break;
                }
            }
            Console.WriteLine();
        }

        static void Main(string[] args) {
            var uiList = GetUserInput();
            Decode("theraven.txt", uiList);

            Console.ReadLine();
        }
    }
}
Output:
Silence-Dogood.

C++

Text used to encode:The Raven - by E.A.Poe

#include <vector>
#include <iostream>
#include <fstream>
#include <sstream>

typedef struct {
    int s[4];
}userI;

class jit{
public:
    void decode( std::string& file, std::vector<userI>& ui ) {
        std::ifstream f( file.c_str(), std::ios_base::in );
        fileBuffer = std::string( ( std::istreambuf_iterator<char>( f ) ), std::istreambuf_iterator<char>() );
        f.close();
        for( std::vector<userI>::iterator t = ui.begin(); t != ui.end(); t++ ) {
            if( !decode( ( *t ).s ) ) break;
        }
        std::cout << "\n\n";
    }
private:
    bool decode( int* ui ) {
        int l = 0, t = 0, p = 0, c = 0, a = 0;
        for( std::string::iterator i = fileBuffer.begin(); i != fileBuffer.end(); i++ ) {
            if( p == ui[0] && l == ui[1] && t == ui[2] && c == ui[3] ) {
                if( *i == '!' )  return false;
                std::cout << *i; return true;
            }
            if( *i == '\n' )      { l++; t = c = 0; }  
            else if( *i == '\t' ) { t++; c = 0; }
            else if( *i == '\f' ) { p++; l = t = c = 0; }
            else                  { c++;}
        }
        return false;
    }
    std::string fileBuffer;
};
void getUserInput( std::vector<userI>& u ) {
    std::string h = "0 18 0 0 0 68 0 1 0 100 0 32 0 114 0 45 0 38 0 26 0 16 0 21 0 17 0 59 0 11 "
                    "0 29 0 102 0 0 0 10 0 50 0 39 0 42 0 33 0 50 0 46 0 54 0 76 0 47 0 84 2 28";
    //std::getline( std::cin, h );
    std::stringstream ss( h );
    userI a;
    int x = 0;
    while( std::getline( ss, h, ' ' ) ) {
        a.s[x] = atoi( h.c_str() );
        if( ++x == 4 ) {
            u.push_back( a );
            x = 0;
        }
    }
}
int main( int argc, char* argv[] ) {
    std::vector<userI> ui;
    getUserInput( ui );

    jit j;
    j.decode( std::string( "theRaven.txt" ), ui );
    return 0;
}
Output:
Silence-Dogood.

D

Translation of: Kotlin
import std.algorithm;
import std.array;
import std.conv;
import std.file;
import std.range;
import std.stdio;

struct UserInput {
    char formFeed;
    char lineFeed;
    char tab;
    char space;

    this(string ff, string lf, string tb, string sp) {
        formFeed = cast(char) ff.to!int;
        lineFeed = cast(char) lf.to!int;
        tab = cast(char) tb.to!int;
        space = cast(char) sp.to!int;
    }
}

auto getUserInput() {
    auto h = "0 18 0 0 0 68 0 1 0 100 0 32 0 114 0 45 0 38 0 26 0 16 0 21 0 17 0 59 0 11 "
           ~ "0 29 0 102 0 0 0 10 0 50 0 39 0 42 0 33 0 50 0 46 0 54 0 76 0 47 0 84 2 28";
    auto ctor = (string[] a) => UserInput(a[0], a[1], a[2], a[3]);
    return h.split(' ').chunks(4).map!ctor.array;
}

void decode(string fileName, UserInput[] uiList) {
    auto text = readText(fileName);

    bool decode2(UserInput ui) {
        char f = 0;
        char l = 0;
        char t = 0;
        char s = 0;
        foreach (c; text) {
            if (f == ui.formFeed && l == ui.lineFeed && t == ui.tab && s == ui.space) {
                if (c == '!') return false;
                write(c);
                return true;
            }
            if (c == '\u000c') {
                f++; l=0; t=0; s=0;
            } else if (c == '\n') {
                l++; t=0; s=0;
            } else if (c == '\t') {
                t++; s=0;
            } else {
                s++;
            }
        }
        return false;
    }

    foreach (ui; uiList) {
        if (!decode2(ui)) break;
    }
    writeln;
}

void main() {
    auto uiList = getUserInput();
    decode("theRaven.txt", uiList);
}
Output:
Silence-Dogood.

Go

Translation of: C++
package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "strconv"
    "strings"
)

type userInput struct{ formFeed, lineFeed, tab, space int }

func getUserInput() []userInput {
    h := "0 18 0 0 0 68 0 1 0 100 0 32 0 114 0 45 0 38 0 26 0 16 0 21 0 17 0 59 0 11 " +
        "0 29 0 102 0 0 0 10 0 50 0 39 0 42 0 33 0 50 0 46 0 54 0 76 0 47 0 84 2 28"
    flds := strings.Fields(h)
    var uis []userInput
    var uif [4]int
    for i := 0; i < len(flds); i += 4 {
        for j := 0; j < 4; j++ {
            uif[j], _ = strconv.Atoi(flds[i+j])
        }
        uis = append(uis, userInput{uif[0], uif[1], uif[2], uif[3]})
    }
    return uis
}

func decode(fileName string, uis []userInput) error {
    text, err := ioutil.ReadFile(fileName)
    if err != nil {
        return err
    }

    decode2 := func(ui userInput) bool {
        var f, l, t, s int
        for _, c := range text {
            if f == ui.formFeed && l == ui.lineFeed && t == ui.tab && s == ui.space {
                if c == '!' {
                    return false
                }
                fmt.Printf("%c", c)
                return true
            }
            switch c {
            case '\f':
                f++
                l = 0
                t = 0
                s = 0
            case '\n':
                l++
                t = 0
                s = 0
            case '\t':
                t++
                s = 0
            default:
                s++
            }
        }
        return true
    }

    for _, ui := range uis {
        if !decode2(ui) {
            break
        }
    }
    fmt.Println()
    return nil
}

func main() {
    uis := getUserInput()
    err := decode("theRaven.txt", uis)
    if err != nil {
        log.Fatal(err)
    }
}
Output:
Silence-Dogood.

Java

Translation of: Kotlin
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;

public class Processing {
    private static class UserInput {
        private char formFeed;
        private char lineFeed;
        private char tab;
        private char space;

        private UserInput(char formFeed, char lineFeed, char tab, char space) {
            this.formFeed = formFeed;
            this.lineFeed = lineFeed;
            this.tab = tab;
            this.space = space;
        }

        char getFormFeed() {
            return formFeed;
        }

        char getLineFeed() {
            return lineFeed;
        }

        char getTab() {
            return tab;
        }

        char getSpace() {
            return space;
        }
    }

    private static List<UserInput> getUserInput() {
        String h = "0 18 0 0 0 68 0 1 0 100 0 32 0 114 0 45 0 38 0 26 0 16 0 21 0 17 0 59 0 11 " +
            "0 29 0 102 0 0 0 10 0 50 0 39 0 42 0 33 0 50 0 46 0 54 0 76 0 47 0 84 2 28";
        String[] s = h.split(" ");

        List<UserInput> uiList = new ArrayList<>();
        for (int idx = 0; idx + 3 < s.length; idx += 4) {
            char c0 = (char) Integer.parseInt(s[idx + 0]);
            char c1 = (char) Integer.parseInt(s[idx + 1]);
            char c2 = (char) Integer.parseInt(s[idx + 2]);
            char c3 = (char) Integer.parseInt(s[idx + 3]);

            UserInput userInput = new UserInput(c0, c1, c2, c3);
            uiList.add(userInput);
        }
        return uiList;
    }

    private static void decode(String fileName, List<UserInput> uiList) throws IOException {
        Path path = Paths.get(fileName);
        byte[] bytes = Files.readAllBytes(path);
        String text = new String(bytes, StandardCharsets.UTF_8);

        Predicate<UserInput> decode2 = (UserInput ui) -> {
            char f = 0;
            char l = 0;
            char t = 0;
            char s = 0;
            char ff = ui.getFormFeed();
            char lf = ui.getLineFeed();
            char tb = ui.getTab();
            char sp = ui.getSpace();

            for (char c : text.toCharArray()) {
                if (f == ff && l == lf && t == tb && s == sp) {
                    if (c == '!') {
                        return false;
                    }
                    System.out.print(c);
                    return true;
                }
                switch (c) {
                    case '\u000c':
                        f++;
                        l = 0;
                        t = 0;
                        s = 0;
                        break;
                    case '\n':
                        l++;
                        t = 0;
                        s = 0;
                        break;
                    case '\t':
                        t++;
                        s = 0;
                        break;
                    default:
                        s++;
                        break;
                }
            }

            return false;
        };

        for (UserInput ui : uiList) {
            if (!decode2.test(ui)) {
                break;
            }
        }
        System.out.println();
    }

    public static void main(String[] args) throws IOException {
        List<UserInput> uiList = getUserInput();
        decode("theRaven.txt", uiList);
    }
}
Output:
Silence-Dogood.

jq

Adapted from Wren

Works with: jq

Works with gojq, the Go implementation of jq

# User input takes the form of quadtuples of integers: [formFeed, lineFeed, tab, space]
def getUserInput:
  def nwise($n):
    def n: if length <= $n then . else .[0:$n] , (.[$n:] | n) end;
  n;

  "0 18 0 0 0 68 0 1 0 100 0 32 0 114 0 45 0 38 0 26 0 16 0 21 0 17 0 59 0 11 " +
  "0 29 0 102 0 0 0 10 0 50 0 39 0 42 0 33 0 50 0 46 0 54 0 76 0 47 0 84 2 28"
  | split(" ") | map(tonumber) | nwise(4)
  | {formFeed: .[0], lineFeed: .[1], tab: .[2], space: .[3]} ;

def emit_until(cond; stream):
  label $out | stream | if cond then break $out else . end;

# Input should be the text as a (long) string
def decode($uiList):
  def stream: explode[] | [.] | implode;
  def decode2(ui):
    . as $text
    | label $out  
    | foreach stream as $c (
          { f: 0, l: 0, t: 0, s: 0 };
          if .f == ui.formFeed and .l == ui.lineFeed and .t == ui.tab and .s == ui.space
          then .out = $c
          elif $c == "\f"
          then .f += 1
          | .l = 0
          | .t = 0
          | .s = 0
          elif $c == "\n"
          then .l += 1
          | .t = 0
          | .s = 0
          elif $c == "\t"
          then .t += 1
          | .s = 0
          else .s += 1
	  end;
	if .out then .out, break $out else empty end )
    // "" ;
  decode2($uiList) ;

# Input: the text
[emit_until(. == "!"; getUserInput as $ui | decode($ui)) ] | add
Output:

Invocation: jq -Rsr -f program.jq theRaven.txt

Silence-Dogood.

Julia

Customization is via adding to or deleting from the chars dictionary.

@enum streamstate GET_FF GET_LF GET_TAB GET_CHAR ABORT
chars = Dict(GET_FF => ['\f'], GET_LF => ['\n'], GET_TAB => ['\t'])

function stream_decode_jit(iostream)
    msg, state, ffcount, lfcount, tabcount, charcount = "", GET_FF, 0, 0, 0, 0
    while true
        if state == ABORT || eof(iostream)
            return msg
        end
        ch = read(iostream, Char)
        if state == GET_FF && ch in chars[GET_FF]
            ffcount += 1
            state = GET_LF
            lfcount = 0
        elseif state == GET_LF && ch in chars[GET_LF]
            if (lfcount += 1) == ffcount
                state = GET_TAB
                tabcount = 0
            end
        elseif state == GET_TAB && ch in chars[GET_TAB]
            if (tabcount += 1) == ffcount
                state = GET_CHAR
                charcount = 0
            end
        elseif state == GET_CHAR
            if (charcount += 1) == ffcount
                print(ch)
                msg *= ch
                if ch == '!'
                    state = ABORT
                else
                    state = GET_FF
                end
            end
        end
    end
end

stream_decode_jit(open("filename.txt", "r"))

Kotlin

Translation of: C++
// version 1.2.10

import java.io.File

data class UserInput(val formFeed: Int, val lineFeed: Int, val tab: Int, val space: Int)

fun getUserInput(): List<UserInput> {
    val h = "0 18 0 0 0 68 0 1 0 100 0 32 0 114 0 45 0 38 0 26 0 16 0 21 0 17 0 59 0 11 " +
            "0 29 0 102 0 0 0 10 0 50 0 39 0 42 0 33 0 50 0 46 0 54 0 76 0 47 0 84 2 28"
    return h.split(' ').chunked(4).map {
        val (ff, lf, tb, sp) = it
        UserInput(ff.toInt(), lf.toInt(), tb.toInt(), sp.toInt())
    }
}

fun decode(fileName: String, uiList: List<UserInput>) {
    val text = File(fileName).readText()

    fun decode2(ui: UserInput): Boolean {
        var f = 0
        var l = 0
        var t = 0
        var s = 0
        val (ff, lf, tb, sp) = ui
        for (c in text) {
            if (f == ff && l == lf && t == tb && s == sp) {
                if (c == '!') return false
                print(c)
                return true
            }
            when (c) {
                '\u000c' -> { f++; l = 0; t = 0; s = 0 }
                '\n'     -> { l++; t = 0; s = 0 }
                '\t'     -> { t++; s = 0 }
                else     -> { s++ }
            }
        }
        return false
    }

    for (ui in uiList) {
        if (!decode2(ui)) break
    }
    println()
}

fun main(args: Array<String>) {
    val uiList = getUserInput()
    decode("theRaven.txt", uiList)
}
Output:
Silence-Dogood.

Nim

Translation of: Kotlin

With some modifications compared to the model.

import options, sequtils, strutils

type Position = tuple[ff, lf, tab, sp: int]

func buildUserInput(s: string): seq[Position] =
  let valList = s.splitWhitespace().map(parseInt)
  doAssert valList.len mod 4 == 0, "Number of values must be a multiple of four."
  doAssert valList.allIt(it >= 0), "Expected non negative values."
  let posList = valList.distribute(valList.len div 4)
  result = posList.mapIt((ff: it[0], lf: it[1], tab: it[2], sp: it[3]))


proc decode(filename: string; uiList: seq[Position]): string =

  func decode(text: string; ui: Position): Option[char] =
    var f, l, t, s = 0
    let (ff, lf, tab, sp) = ui
    for c in text:
      if f == ff and l == lf and t == tab and s == sp:
        return if c == '!': none(char) else: some(c)
      case c
      of '\f': inc f; l = 0; t = 0; s = 0
      of '\l': inc l; t = 0; s = 0
      of '\t': inc t; s = 0
      else: inc s

  let text = filename.readFile()
  for ui in uiList:
    let c = text.decode(ui)
    if c.isNone: break
    result.add c.get()

const UiList = buildUserInput("0 18 0 0 0 68 0 1 0 100 0 32 0 114 0 " &
                              "45 0 38 0 26 0 16 0 21 0 17 0 59 0 11 " &
                              "0 29 0 102 0 0 0 10 0 50 0 39 0 42 0 " &
                              "33 0 50 0 46 0 54 0 76 0 47 0 84 2 28")

echo "theRaven.txt".decode(UiList)
Output:
Silence-Dogood.

Perl

Translation of: Raku
Library: ntheory
use strict;
use warnings;
use feature 'say';
use feature 'state';

use ntheory qw/fromdigits todigitstring/;

my $key = 'perl5';
srand fromdigits($key,36) % 2**63;

my @stream;

sub stream {
    my($i) = shift;
    state @chars;
    push @chars, chr($_) for 14..127;
    $stream[$i] = $chars[rand 1+127-14] unless $stream[$i];
}

sub jit_encode {
    my($str) = shift;
    my $i = 0;
    my $last = 0;
    my $enc = '';
    for my $c (split '', $str) {
        my $h;
        my $l = '';
        ++$i until $c eq stream($i);
        my $o = $i - $last;
        $l    = $o % 26;
        $h    = $o - $l if $o > 26;
        $l   += 10;
        $enc .= ($h ? uc todigitstring($h,36) : '') . lc todigitstring($l,36);
        $last = $i;
    }
    $enc
}

sub jit_decode {
    my($str) = shift;
    my @matches = $str =~ /((.*?) ([a-z]))/gx;
    my $dec = '';
    my $i = 0;
    for my $j (0 .. @matches/3 - 1) {
        my $o = ( fromdigits($matches[3*$j+1],36) - 10 // 0) +
                ( fromdigits($matches[3*$j+2],36)      // 0);
        $i   += $o;
        $dec .= $stream[$i];
    }
    $dec
}

my $enc = jit_encode('The slithey toves did gyre and gimble in the wabe');
say my $result = "Encoded\n$enc\n\nDecoded\n" . jit_decode($enc);
Output:
Encoded
bQh52yf9Ex2Wi4Cv1GcyoAUcBKbke3Mo5Ss2WybQlvQs1GviQc1GnQg5Sv26j1Gm26m3Mp26iQz78lQx2Wel1Gcs52y5Sds3Me26l52au1Gwe1Gl

Decoded
The slithey toves did gyre and gimble in the wabe

Phix

Translation of: C
Library: Phix/libcurl
-- demo/rosetta/BookCipher.exw
function decode(integer fn, sequence ui)
    integer {ff,lf,tab,sp} = ui,
             f = 0, l = 0, t = 0, s = 0
    while true do
        integer c = getc(fn)
        if c=-1 then return false end if
        if f==ff and l==lf and t==tab and s==sp then
            if c=='!' then return false end if
            puts(1,c)
            return true
        elsif c==#0C then
            f += 1
            {l, t, s} = {0, 0, 0}
        elsif c=='\n' then
            l += 1
            {t, s} = {0, 0}
        elsif c=='\t' then
            t += 1
            s = 0
        else
            s += 1
        end if
    end while
    return false
end function
 
include builtins\libcurl.e
 
procedure decodeFile(string filename, url, sequence code)
    if not file_exists(filename) then
        printf(1,"Downloading %s...\n",{filename})
        CURLcode res = curl_easy_get_file(url,"",filename) -- (no proxy)
        if res!=CURLE_OK then
            string error = sprintf("%d",res)
            if res=CURLE_COULDNT_RESOLVE_HOST then
                error &= " [CURLE_COULDNT_RESOLVE_HOST]"
            end if
            crash("Error %s downloading file\n", {error})
        end if  
    end if  
    integer fn = open(filename, "r")
    if fn=-1 then crash("could not open %s",{filename}) end if
    for i=1 to length(code) do
        if not decode(fn,code[i]) then exit end if
        if seek(fn, 0)!=SEEK_OK then crash("seek error") end if
    end for
    printf(1,"\n\n");
end procedure
 
constant code = {{0,18,0,0},
                 {0,68,0,1},
                 {0,100,0,32},
                 {0,114,0,45},
                 {0,38,0,26},
                 {0,16,0,21},
                 {0,17,0,59},
                 {0,11,0,29},
                 {0,102,0,0},
                 {0,10,0,50},
                 {0,39,0,42},
                 {0,33,0,50},
                 {0,46,0,54},
                 {0,76,0,47},
                 {0,84,2,28}}
decodeFile("theRaven.txt", "http://paulo-jorente.de/text/theRaven.txt", code)
{} = wait_key()
Output:
Silence-Dogood.

Python

Translation of: D
import sys

class UserInput:
    def __init__(self,chunk):
        self.formFeed = int(chunk[0])
        self.lineFeed = int(chunk[1])
        self.tab = int(chunk[2])
        self.space = int(chunk[3])

    def __str__(self):
        return "(ff=%d; lf=%d; tb=%d; sp%d)" % (self.formFeed,self.lineFeed,self.tab,self.space)

def chunks(l,n):
    for i in xrange(0, len(l), n):
        yield l[i:i+n]

def getUserInput():
    h = "0 18 0 0 0 68 0 1 0 100 0 32 0 114 0 45 0 38 0 26 0 16 0 21 0 17 0 59 0 11 "\
        "0 29 0 102 0 0 0 10 0 50 0 39 0 42 0 33 0 50 0 46 0 54 0 76 0 47 0 84 2 28"
    ha = h.split()
    return [UserInput(chunk) for chunk in chunks(ha, 4)]

def decode(filename,uiList):
    f = open(filename, "r")
    text = f.read()

    def decode2(ui):
        f = 0
        l = 0
        t = 0
        s = 0
        for c in text:
            if f == ui.formFeed and l == ui.lineFeed and t == ui.tab and s == ui.space:
                if c == '!':
                    return False
                sys.stdout.write(c)
                return True
            if c == '\u000c':
                f=f+1
                l=0
                t=0
                s=0
            elif c == '\n':
                l=l+1
                t=0
                s=0
            elif c == '\t':
                t=t+1
                s=0
            else:
                s=s+1
        return False

    for ui in uiList:
        if not decode2(ui):
            break
    print

##### Main #####

uiList = getUserInput()
decode("theRaven.txt", uiList)
Output:
Silence-Dogood.

Racket

Translation of: Kotlin
#lang racket

(define user-input
  (~a "0 18 0 0 0 68 0 1 0 100 0 32 0 114 0 45 0 38 0 26 0 16 0 21 0 17 0 59 0 11 "
      "0 29 0 102 0 0 0 10 0 50 0 39 0 42 0 33 0 50 0 46 0 54 0 76 0 47 0 84 2 28"))

(define content (file->string "theRaven.txt"))

(define (decode slice)
  (match-define (list ff lf tb sp) slice)
  (let loop ([f 0] [l 0] [t 0] [s 0] [xs (string->list content)])
    (define next (curryr loop (rest xs)))
    (match (first xs)
      [c #:when (and (= f ff) (= l lf) (= t tb) (= s sp)) c]
      [#\u000c   (next (add1 f) 0 0 0)]
      [#\newline (next f (add1 l) 0 0)]
      [#\tab     (next f l (add1 t) 0)]
      [_         (next f l t (add1 s))])))

(for ([slice (in-slice 4 (map string->number (string-split user-input)))])
  (define c (decode slice))
  #:break (char=? #\! c)
  (display c))
Input:

http://paulo-jorente.de/text/theRaven.txt

Output:
Silence-Dogood.

Raku

(formerly Perl 6)

Works with: Rakudo version 2019.03

This is a something of a toy encoder / decoder and probably shouldn't be used for anything serious.

Default encode/decode key is 'Raku' Feed it a pass phrase at the command line to use that instead.

Will handle any visible character in the ASCII range as well as space and new-line.

#`[
Set srand to set the encode / decode "key".
Need to use the same "key" and same implementation
of Raku to encode / decode. Gain "security" by
exchanging "keys" by a second channel. Default
"key" is "Raku"
]

unit sub MAIN ($key = 'Raku');

srand $key.comb(/<.alnum>/).join.parse-base(36) % 2**63;

my @stream = (flat "\n", ' ' .. '~').roll(*);

sub jit-encode (Str $str) {
    my $i = 0;
    my $last = 0;
    my $enc = '';
    for $str.comb -> $c {
        my $h;
        my $l = '';
        ++$i until $i > 1 && $c eq @stream[$i];
        my $o = $i - $last;
        $l    = $o % 26;
        $h    = $o - $l if $o >= 26;
        $l   += 10;
        $enc ~= ($h ?? $h.base(36).uc !! '') ~ ($l.base(36).lc);
        $last = $i;
    }
    my $block = 60;
    $enc.comb($block).join: "\n"
}

sub jit-decode (Str $str is copy) {
    $str.=subst("\n", '', :g);
    $str ~~ m:g/((.*?) (<:Ll>))/;
    my $dec = '';
    my $i = 0;
    for $/.List -> $l {
        my $o = ($l[0][1].Str.parse-base(36) - 10 // 0) +
                ($l[0][0].Str.parse-base(36) // 0);
        $i += $o;
        $dec ~= @stream[$i];
    }
    $dec
}

my $secret = q:to/END/;
In my opinion, this task is pretty silly.

'Twas brillig, and the slithy toves
    Did gyre and gimble in the wabe.

!@#$%^&*()_+}{[].,><\|/?'";:1234567890
END

say "== Secret: ==\n$secret";

say "\n== Encoded: ==";
say my $enc = jit-encode($secret);

say "\n== Decoded: ==";
say jit-decode($enc);
== Secret: ==
In my opinion, this task is pretty silly.

'Twas brillig, and the slithy toves
    Did gyre and gimble in the wabe.

!@#$%^&*()_+}{[].,><\|/?'";:1234567890


== Encoded: ==
Qv26e26q1Gi2Ww5SiQr26h3Mk1GbQy52e1Gg6Ib52kQfQk26n26l26cQm26q
2Wk26vwme52qy6Ia1GuQfa3MbQxtd26aa3MvQu2Wuat26p2Wbe2Wc1Ga26g2
6h26pQha26h4Cf26jrz7Yz3MaA4h2WxFWf52zyg2WrQn2Wj26pQyQy78x1Gd
dk4Cu26k26qaaap26j26xqQf7Yr8Op3Me3Me5Sv1Ge1Gt2WxlQz5Si1GeQg4
CjQc5Sb2WbQo1GycQr1Gm1Gy1GsQei3MrQsai1Gq2WnQdt2Wj1Gff1Gg26le
2Wd1Go9Ek1Gm9Eh2Wb1Gd52h2WdQae4Chu3MeQd1Gg1Gw4CqbEGh52u2Wr1G
t52xhvQmx

== Decoded: ==
In my opinion, this task is pretty silly.

'Twas brillig, and the slithy toves
    Did gyre and gimble in the wabe.

!@#$%^&*()_+}{[].,><\|/?'";:1234567890

REXX

The input file used by this REXX program only contains one page;   it has no   FF   (formfeed)   characters in it),
and the injection of   FF   characters into the file would be like putting pencil marks into a holy book.  

/*REXX program  extracts characters  by using a  book cipher  (that is a  text file).   */
parse arg iFID .                                 /*obtain optional name of file  (book).*/
if iFID=='' | iFID==","  then iFID= 'JIT.TXT'    /*Not specified?  Then use the default.*/
$= 'abcdefghijklmnopqrstuvwxyz';  _=$;  upper _;  $= "0123456789"$ || _;  $$=$ || xrange()
prompt= '────────── enter four positive integers         or        Quit'
pag=1;    lin=1;    FF= 'c'x                     /*assume start of  page 1,  line 1.    */
@.=                                              /*read the entire book from the file.  */
    do  while  lines(iFID)\==0                   /*process lines from input stream(file)*/
    _= translate( linein(iFID), , '9'x)          /*obtain a single line from input file.*/
    if pos(FF, _)\==0  then do; pag=pag+1; lin=1 /*bump page counter; reset line counter*/
                            end                  /* [↑]  handle finding of FF (formfeed)*/
    @.pag.lin= _                                 /*obtain a single line from input file.*/
          lin= lin + 1                           /*bump the line counter.               */
    end   /*while*/                              /* [↑]  read the entire input stream.  */
?=                                               /*define the phrase to be null (so far)*/
       do ask=0;       say prompt;       pull y  /*get just─in─time positional numbers. */
       if abbrev('QUIT', y, 1)  then exit 0      /*the user wants out of here, so exit. */
       y=space( translate(y, $, $$) )            /*allow any separator the user wants.  */
       parse var  y    a.1   a.2   a.3   a.4     /*parse the pertinent parameters.      */
       if words(y)>4   then do;    say 'too many parameters entered.'
                                   iterate  ask
                            end                  /*go and try again to obtain the parms.*/
         do k=1  for 4;  is#= datatype(a.k, 'W') /*validate  parms  {positive integers}.*/
         if is#  then a.k= a.k / 1               /*normalize the number (for indexing). */
         if is#  &  a.k>0  then iterate          /*found a good parameter?   Then skip. */
         say 'parameter '      k      " is missing or not a positive integer: "      a.k
         iterate  ask                            /*go and ask for another set of parms. */
         end   /*k*/                             /* [↑]  done with the validations.     */
       parse value a.1 a.2 a.3 a.4  with p L w c /*parse parameters for specific names. */
       x=substr( word( @.p.L, w), c,  1)         /*extract a character from the book.   */
       if x=='!'  then leave                     /*if the  stop  char was found,  done. */
       say right(x  '◄─── a letter', 46)         /*might as well echo char to terminal. */
       ?= ? || x                                 /*append the character to the phrase.  */
       end   /*j*/                               /* [↑]  display letters found in book. */
say '═════►'   ?                                 /*stick a fork in it,  we're all done. */
input   supplied to the console (terminal) by the user in response to the prompts,   (the commas are optional):
  1,   133,   4,   5
  1,    34,   9,   3
  1,  1377,   2,   2
  1,     4,   8,   4
  1,   265,   3,   5
  1,   413,  10,   2
  1,    10,  12,   1
  1,   144,  10,  10
  1,   571,   4,  12
input   (abbridged)
──────────enter four parameters  (all positive integers)   or   QUIT
  1,   133,   4,   5                            ◄■■■■■■■■■ user input (first reponse).     
                               s ◄─── a letter

    ∙
    ∙                                           (some prompts and reponses elided.)  
    ∙

──────────enter four parameters  (all positive integers)   or   QUIT
  1,   571,   4,  12                            ◄■■■■■■■■■ user input (ninth reponse). 
═════► so─true. 

The input file used (the IBM jargon file) in the above REXX program can be found here ───►   Just_in_time_processing_on_a_character_stream/REXX/JIT.TXT.

Tcl

Works with: Tcl version 8.6
package require Tcl 8.6

oo::class create JustInTimeStreamExtract {
    variable map counter counters last
    constructor {{pageSeparator "\f"} {lineSeparator "\n"} {fieldSeparator "\t"}} {
	dict set map $pageSeparator NextPage
	dict set map $lineSeparator NextLine
	dict set map $fieldSeparator NextField
	set counter 1
	array set counters {page 0 line 0 field 0 char 0}
	set last ""
    }

    method emit {char} {
	puts -nonewline $char
	set last $char
    }
    method finished {} {
	if {$last ne "\n"} {
	    puts ""
	}
    }

    method stream {{channel stdin} {length 1}} {
	try {
	    while 1 {
		set str [read $channel $length]
		if {[eof $channel]} break
		foreach c [split $str ""] {
		    if {[dict exists $map $c]} {
			my [dict get $map $c]
		    } else {
			my NextChar $c
		    }
		}
	    }
	} trap STOP {} {
	    # Do nothing
	}
	my finished
    }

    method NextPage {} {
	incr counters(page)
	array set counters {line 0 field 0 char 0}
    }
    method NextLine {} {
	incr counters(line)
	array set counters {field 0 char 0}
    }
    method NextField {} {
	incr counters(field)
	set counters(char) 0
    }
    method NextChar {char} {
	incr counters(char)
	if {[my PrintThisOne?]} {
	    if {$char eq "!"} {
		throw STOP "stop character found"
	    }
	    incr counter
	    my emit $char
	    array set counters {page 0 line 0 field 0 char 0}
	}
    }

    method PrintThisOne? {} {
	tcl::mathop::== $counter $counters(page) $counters(line) $counters(field) $counters(char)
    }
}

Demonstration of use:

[JustInTimeStreamExtract new] stream [open "sample.txt"]

Visual Basic .NET

Translation of: C#
Module Module1

    Structure UserInput
        ReadOnly FormFeed As Char
        ReadOnly LineFeed As Char
        ReadOnly Tab As Char
        ReadOnly Space As Char

        Sub New(ff As String, lf As String, tb As String, sp As String)
            FormFeed = ChrW(Integer.Parse(ff))
            LineFeed = ChrW(Integer.Parse(lf))
            Tab = ChrW(Integer.Parse(tb))
            Space = ChrW(Integer.Parse(sp))
        End Sub
    End Structure

    Function GetUserInput() As List(Of UserInput)
        Dim h = "0 18 0 0 0 68 0 1 0 100 0 32 0 114 0 45 0 38 0 26 0 16 0 21 0 17 0 59 0 11 " &
            "0 29 0 102 0 0 0 10 0 50 0 39 0 42 0 33 0 50 0 46 0 54 0 76 0 47 0 84 2 28"
        Return h.Split(" ") _
            .Select(Function(x, idx) New With {x, idx}) _
            .GroupBy(Function(x) x.idx \ 4) _
            .Select(Function(g)
                        Dim ge = g.Select(Function(a) a.x).ToArray()
                        Return New UserInput(ge(0), ge(1), ge(2), ge(3))
                    End Function) _
                    .ToList()
    End Function

    Sub Decode(filename As String, uiList As List(Of UserInput))
        Dim text = IO.File.ReadAllText(filename)

        Dim Inc = Function(a As Char) As Char
                      Return ChrW(AscW(a) + 1)
                  End Function

        Dim DecodeImpl = Function(ui As UserInput) As Boolean
                             Dim f = ChrW(0)
                             Dim l = ChrW(0)
                             Dim t = ChrW(0)
                             Dim s = ChrW(0)

                             For Each c In text
                                 If f = ui.FormFeed AndAlso l = ui.LineFeed AndAlso t = ui.Tab AndAlso s = ui.Space Then
                                     If c = "!" Then
                                         Return False
                                     End If
                                     Console.Write(c)
                                     Return True
                                 End If
                                 If vbFormFeed = c Then
                                     f = Inc(f)
                                     l = ChrW(0)
                                     t = ChrW(0)
                                     s = ChrW(0)
                                 ElseIf vbLf = c Then
                                     l = Inc(l)
                                     t = ChrW(0)
                                     s = ChrW(0)
                                 ElseIf vbTab = c Then
                                     t = Inc(t)
                                     s = ChrW(0)
                                 Else
                                     s = Inc(s)
                                 End If
                             Next

                             Return False
                         End Function

        For Each ui In uiList
            If Not DecodeImpl(ui) Then
                Exit For
            End If
        Next

        Console.WriteLine()
    End Sub

    Sub Main()
        Dim uiList = GetUserInput()
        Decode("theRaven.txt", uiList)
    End Sub

End Module
Output:
Silence-Dogood.

Wren

Translation of: Kotlin
Library: Wren-dynamic
Library: wren-seq
import "io" for File
import "./dynamic" for Tuple
import "./seq" for Lst

var UserInput = Tuple.create("UserINput", ["formFeed", "lineFeed", "tab", "space"])

var getUserInput = Fn.new {
    var h = "0 18 0 0 0 68 0 1 0 100 0 32 0 114 0 45 0 38 0 26 0 16 0 21 0 17 0 59 0 11 " +
            "0 29 0 102 0 0 0 10 0 50 0 39 0 42 0 33 0 50 0 46 0 54 0 76 0 47 0 84 2 28"
    return Lst.chunks(h.split(" "), 4).map { |chunk|
        var flts = chunk.map { |c| Num.fromString(c) }.toList      
        return UserInput.new(flts[0], flts[1], flts[2], flts[3])
    }
}

var decode = Fn.new { |fileName, uiList|
    var text = File.read(fileName)

    var decode2 = Fn.new { |ui|
        var f = 0
        var l = 0
        var t = 0
        var s = 0
        for (c in text) {
            if (f == ui.formFeed && l == ui.lineFeed && t == ui.tab && s == ui.space) {
                if (c == "!") return false
                System.write(c)
                return true
            }
            if (c == "\f") {
                f = f + 1
                l = 0
                t = 0
                s = 0
            } else if (c == "\n") {
                l = l + 1
                t = 0
                s = 0
            } else if (c == "\t") {
                t = t + 1
                s = 0
            } else {
                s = s + 1
            }
        }
        return false
    }

    for (ui in uiList) if (!decode2.call(ui)) break
    System.print()
}

var uiList = getUserInput.call()
decode.call("theRaven.txt", uiList)
Output:
Silence-Dogood.

zkl

Translation of: C++
class FlyBy{
   fcn decode(file,tuplets){
      codePad:=File(file).read().mode(String); // blob of text
      tuplets.pump(Console.print, _decode.fp1(codePad));
      println();
    }
    fcn [private] _decode(idx,codePad){ // idx is (ff,lf,tab,chr) offset info codePad
       z:=-1;
       foreach n,c in (idx.zip(T("\f","\n","\t"))){
          do(n){ if(Void==(z=codePad.find(c,z+1))) return(Void.Stop); }
       }
       if(z==-1) z=0;  // (0,0,0,n)
       try{ return(codePad[z + idx[-1] + 1]) }catch{ return(Void.Stop) }
    }
}

fcn getUserInput{
   // I don't know a user would enter this but we have
   // a string of 4 item tuplets : (formfeeds, linefeeds, tabs, characters), ...
   // each tuplet is an offset into a code pad (text)
   h:="0 18 0 0 0 68 0 1 0 100 0 32 0 114 0 45 0 38 0 26 0 16 0 21 0 17 0 59 0 11 "
      "0 29 0 102 0 0 0 10 0 50 0 39 0 42 0 33 0 50 0 46 0 54 0 76 0 47 0 84 2 28";
   h.split(" ").pump(List,T(Void.Read,3),
      fcn(ff,lf,t,s){ vm.arglist.apply("toInt") });
}
input:=getUserInput();
   // our code pad is: http://paulo-jorente.de/text/theRaven.txt
FlyBy.decode("theRaven.txt",input);
Output:
Silence-Dogood.