ASCII art diagram converter: Difference between revisions

m
(C++ - added description, and error case)
m (→‎{{header|Wren}}: Minor tidy)
 
(16 intermediate revisions by 11 users not shown)
Line 47:
=={{header|AArch64 Assembly}}==
{{works with|as|Raspberry Pi 3B version Buster 64 bits <br> or android 64 bits with application Termux }}
<syntaxhighlight lang="aarch64 assembly">
<lang AArch64 Assembly>
/* ARM assembly AARCH64 Raspberry PI 3B or android 64 bits */
/* program asciiDiagram64.s */
Line 506:
/* for this file see task include a file in language AArch64 assembly */
.include "../includeARM64.inc"
</syntaxhighlight>
</lang>
{{output}}
<pre>
Line 557:
=={{header|ARM Assembly}}==
{{works with|as|Raspberry Pi <br> or android 32 bits with application Termux}}
<syntaxhighlight lang="arm assembly">
<lang ARM Assembly>
/* ARM assembly Raspberry PI or android 32 bits */
/* program asciiDiagram.s */
Line 964:
/***************************************************/
.include "../affichage.inc"
</syntaxhighlight>
</lang>
{{Output}}
<pre>
Line 1,013:
Name ARCOUNT value : 0110100110100100
</pre>
 
=={{header|AutoHotkey}}==
<syntaxhighlight lang="AutoHotkey">Header := "
(LTrim
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ID |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| QDCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ANCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| NSCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ARCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
)"
 
Data := "78477BBF5496E12E1BF169A4"
MsgBox % result := ASCII_art_diagram_converter(Header, Data)
return
 
ASCII_art_diagram_converter(Header, Data){
oDataBin := []
for i, h in StrSplit(Data)
for i, v in StrSplit(SubStr("0000" . ConvertBase(16, 2, h), -3))
oDataBin.Push(v)
 
bitWidth := StrLen(StrSplit(Header, "+").2) + 1
prevW := 0
result := "Name`t`tSize`tBinary"
for i, line in StrSplit(Header, "`n", "`r")
{
if Mod(A_Index, 2)
continue
strtPos := 0
loop
{
if w := (strtPos := InStr(line, "|",, ++strtPos)) // bitWidth
{
b := ""
loop % width := w - prevW
b .= oDataBin.RemoveAt(1)
result .= "`n" Trim(StrSplit(line, "|")[A_Index]) "`t`t" width . "`t" b
}
prevW := w
}
until !strtPos
}
return result
}
 
ConvertBase(InputBase, OutputBase, nptr){ ; Base 2 - 36 ; https://www.autohotkey.com/boards/viewtopic.php?t=3925#p21143
static u := A_IsUnicode ? "_wcstoui64" : "_strtoui64"
static v := A_IsUnicode ? "_i64tow" : "_i64toa"
VarSetCapacity(s, 66, 0)
value := DllCall("msvcrt.dll\" u, "Str", nptr, "UInt", 0, "UInt", InputBase, "CDECL Int64")
DllCall("msvcrt.dll\" v, "Int64", value, "Str", s, "UInt", OutputBase, "CDECL")
return s
}</syntaxhighlight>
{{out}}
<pre>Name Size Binary
ID 16 0111100001000111
QR 1 0
Opcode 4 1111
AA 1 0
TC 1 1
RD 1 1
RA 1 1
Z 3 011
RCODE 4 1111
QDCOUNT 16 0101010010010110
ANCOUNT 16 1110000100101110
NSCOUNT 16 0001101111110001
ARCOUNT 16 0110100110100100</pre>
 
=={{header|C}}==
interpret text diagram as data structure
<syntaxhighlight lang="c">
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
enum { MAX_ROWS=14, MAX_NAMES=20, NAME_SZ=80 };
 
char *Lines[MAX_ROWS] = {
" +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+",
" | ID |",
" +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+",
" |QR| Opcode |AA|TC|RD|RA| Z | RCODE |",
" +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+",
" | QDCOUNT |",
" +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+",
" | ANCOUNT |",
" +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+",
" | NSCOUNT |",
" +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+",
" | ARCOUNT |",
" +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+"
};
typedef struct {
unsigned bit3s;
unsigned mask;
unsigned data;
char A[NAME_SZ+2];
}NAME_T;
NAME_T names[MAX_NAMES];
unsigned idx_name;
enum{ID,BITS,QDCOUNT,ANCOUNT,NSCOUNT,ARCOUNT,MAX_HDR};
unsigned header[MAX_HDR]; // for test
unsigned idx_hdr;
 
int bit_hdr(char *pLine);
int bit_names(char *pLine);
void dump_names(void);
void make_test_hdr(void);
 
int main(void){
char *p1; int rv;
printf("Extract meta-data from bit-encoded text form\n");
make_test_hdr();
idx_name = 0;
for( int i=0; i<MAX_ROWS;i++ ){
p1 = Lines[i];
if( p1==NULL ) break;
if( rv = bit_hdr(Lines[i]), rv>0) continue;
if( rv = bit_names(Lines[i]),rv>0) continue;
//printf("%s, %d\n",p1, numbits );
}
dump_names();
}
 
int bit_hdr(char *pLine){ // count the '+--'
char *p1 = strchr(pLine,'+');
if( p1==NULL ) return 0;
int numbits=0;
for( int i=0; i<strlen(p1)-1; i+=3 ){
if( p1[i] != '+' || p1[i+1] != '-' || p1[i+2] != '-' ) return 0;
numbits++;
}
return numbits;
}
 
int bit_names(char *pLine){ // count the bit-group names
char *p1,*p2 = pLine, tmp[80];
unsigned sz=0, maskbitcount = 15;
while(1){
p1 = strchr(p2,'|'); if( p1==NULL ) break;
p1++;
p2 = strchr(p1,'|'); if( p2==NULL ) break;
sz = p2-p1;
tmp[sz] = 0; // set end of string
int k=0;
for(int j=0; j<sz;j++){ // strip spaces
if( p1[j] > ' ') tmp[k++] = p1[j];
}
tmp[k]= 0; sz++;
NAME_T *pn = &names[idx_name++];
strcpy(&pn->A[0], &tmp[0]);
pn->bit3s = sz/3;
if( pn->bit3s < 16 ){
for( int i=0; i<pn->bit3s; i++){
pn->mask |= 1 << maskbitcount--;
}
pn->data = header[idx_hdr] & pn->mask;
unsigned m2 = pn->mask;
while( (m2 & 1)==0 ){
m2>>=1;
pn->data >>= 1;
}
if( pn->mask == 0xf ) idx_hdr++;
 
}
else{
pn->data = header[idx_hdr++];
}
}
return sz;
}
 
void dump_names(void){ // print extracted names and bits
NAME_T *pn;
printf("-name-bits-mask-data-\n");
for( int i=0; i<MAX_NAMES; i++ ){
pn = &names[i];
if( pn->bit3s < 1 ) break;
printf("%10s %2d X%04x = %u\n",pn->A, pn->bit3s, pn->mask, pn->data);
}
puts("bye..");
}
 
void make_test_hdr(void){
header[ID] = 1024;
header[QDCOUNT] = 12;
header[ANCOUNT] = 34;
header[NSCOUNT] = 56;
header[ARCOUNT] = 78;
// QR OP AA TC RD RA Z RCODE
// 1 0110 1 0 1 0 000 1010
// 1011 0101 0000 1010
// B 5 0 A
header[BITS] = 0xB50A;
}
</syntaxhighlight>
{{out}}
<pre>
Extract meta-data from bit-encoded text form
-name-bits-mask-data-
ID 16 X0000 = 1024
QR 1 X8000 = 1
Opcode 4 X7800 = 6
AA 1 X0400 = 1
TC 1 X0200 = 0
RD 1 X0100 = 1
RA 1 X0080 = 0
Z 3 X0070 = 0
RCODE 4 X000f = 10
QDCOUNT 16 X0000 = 12
ANCOUNT 16 X0000 = 34
NSCOUNT 16 X0000 = 56
ARCOUNT 16 X0000 = 78
bye..
</pre>
 
 
=={{header|C++}}==
Uses C++20
Line 1,018 ⟶ 1,243:
The ASCII diagram is parsed at compile time into a data structure that is used at runtime to encode and decode the fields.
 
<langsyntaxhighlight lang="cpp">#include <array>
#include <bitset>
#include <iostream>
Line 1,177 ⟶ 1,402:
cout << "Decoded raw data:\n";
Decode<art>(rawData);
}</langsyntaxhighlight>
{{out}}
<pre>
Line 1,202 ⟶ 1,427:
 
An invalid table will cause a compilation error - here the ANCOUNT field is missing.
<langsyntaxhighlight lang="cpp"> static constexpr char missingFieldArt[] = R"(
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ID |
Line 1,216 ⟶ 1,441:
| ARCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+)";
</syntaxhighlight>
</lang>
 
GCC 11 gives this error
Line 1,232 ⟶ 1,457:
=={{header|D}}==
This solution generates anonymous struct code at compile-time, that can be mixed-in inside a struct or class.
<langsyntaxhighlight lang="d">string makeStructFromDiagram(in string rawDiagram) pure @safe {
import std.conv: text;
import std.format: format;
Line 1,432 ⟶ 1,657:
assert(h.ARCOUNT == 255);
assert(h.Opcode == 7);
}</langsyntaxhighlight>
{{out}}
<pre>[0, 10, 56, 128, 0, 0, 0, 0, 0, 0, 0, 255]</pre>
Line 1,446 ⟶ 1,671:
 
=={{header|Go}}==
<langsyntaxhighlight lang="go">package main
 
import (
Line 1,573 ⟶ 1,798:
hex := "78477bbf5496e12e1bf169a4" // test string
unpack(results, hex)
}</langsyntaxhighlight>
 
{{out}}
Line 1,635 ⟶ 1,860:
ARCOUNT 16 0110100110100100
</pre>
 
=={{header|Haskell}}==
===Variant based on parsing===
 
<syntaxhighlight lang="haskell">import Text.ParserCombinators.ReadP
import Control.Monad (guard)
 
data Field a = Field { fieldName :: String
, fieldSize :: Int
, fieldValue :: Maybe a}
 
instance Show a => Show (Field a) where
show (Field n s a) = case a of
Nothing -> n ++ "\t" ++ show s
Just x -> n ++ "\t" ++ show s ++ "\t" ++ show x
 
newtype Data a = Data { fields :: [Field a] }
 
instance Show a => Show (Data a) where
show (Data fs) = "NAME\tSIZE\tVALUE\n" ++ unlines (show <$> fs)
 
instance Read (Data a) where
readsPrec _ = readP_to_S parseData
 
parseData = do n <- parseHeader
guard (n `elem` [8,16,32,64]) -- check size of the table
Data . concat <$> many1 (parseRow n)
where
parseRow n = do
fs <- char '|' *> many parseField <* char '\n'
guard $ sum (fieldSize <$> fs) == n -- check that size of all fields match the row size
m <- parseHeader
guard $ m == n -- check that all rows have the same size
return fs
parseHeader = do
char '+'
n <- length <$> many1 (string "--+")
char '\n'
return n
parseField = do
s1 <- many (char ' ')
f <- munch1 $ not . (`elem` " |")
s2 <- many (char ' ')
char '|'
let n = (length (s1 ++ f ++ s2) + 1) `div` 3
return $ Field f n Nothing
-- emulation of reading a stream of bits
readData :: Data a -> [b] -> Data [b]
readData d = Data . go (fields d)
where
go fs [] = (\f -> f {fieldValue = Nothing}) <$> fs
go (f:fs) s =
let (x, xs) = splitAt (fieldSize f) s
in f {fieldValue = Just x} : go fs xs
 
diagram = unlines
["+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+"
,"| ID |"
,"+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+"
,"|QR| Opcode |AA|TC|RD|RA| Z | RCODE |"
,"+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+"
,"| QDCOUNT |"
,"+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+"
,"| ANCOUNT |"
,"+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+"
,"| NSCOUNT |"
,"+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+"
,"| ARCOUNT |"
,"+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+"]
dataSample = concat
["011110000100011101111011101111110101010010010110",
"111000010010111000011011111100010110100110100100"]
</syntaxhighlight>
 
<pre>λ> let d = read diagram :: Data Int
λ> d
NAME SIZE VALUE
ID 16
QR 1
Opcode 4
AA 1
TC 1
RD 1
RA 1
Z 3
RCODE 4
QDCOUNT 16
ANCOUNT 16
NSCOUNT 16
ARCOUNT 16
 
λ> dataSample
"011110000100011101111011101111110101010010010110111000010010111000011011111100010110100110100100"
 
λ> readData d dataSample
NAME SIZE VALUE
ID 16 "0111100001000111"
QR 1 "0"
Opcode 4 "1111"
AA 1 "0"
TC 1 "1"
RD 1 "1"
RA 1 "1"
Z 3 "011"
RCODE 4 "1111"
QDCOUNT 16 "0101010010010110"
ANCOUNT 16 "1110000100101110"
NSCOUNT 16 "0001101111110001"
ARCOUNT 16 "0110100110100100"
 
λ> readData d (take 70 dataSample) -- corrupted input
NAME SIZE VALUE
ID 16 "0111100001000111"
QR 1 "0"
Opcode 4 "1111"
AA 1 "0"
TC 1 "1"
RD 1 "1"
RA 1 "1"
Z 3 "011"
RCODE 4 "1111"
QDCOUNT 16 "0101010010010110"
ANCOUNT 16 "1110000100101110"
NSCOUNT 16
ARCOUNT 16
</pre>
 
===List-based interpretation with validation===
 
<syntaxhighlight lang="haskell">import Data.List (nub)
import Data.List.Split (splitOn)
import Control.Monad (unless)
 
readData :: String -> Either String (Data a)
readData d = process $ lines d
where
process d = do
let l = length (head d)
unless (all ((l ==) . length) d) $ Left "Table is not aligned!"
w <- readHLine (head d)
let rows = filter ((/= "+-") . nub) d
Data . concat <$> traverse (readRow w) rows
readHLine s = do
let cols = splitOn "--" s
unless (nub cols == ["+"]) $ Left ("Invalid header: " ++ s)
return $ length cols - 1
 
readField s = do
let n = length s + 1
unless (n `mod` 3 == 0) $ Left ("Field is not aligned: " ++ s)
return $ Field (filter (/= ' ') s) (n `div` 3) Nothing
 
readRow n s = do
let fields = filter (not.null) $ splitOn "|" s
row <- traverse readField fields
unless (sum (fieldSize <$> row) == n) $ Left $ "Fields are not aligned at row\n " ++ s
return row</syntaxhighlight>
 
=={{header|J}}==
 
<langsyntaxhighlight Jlang="j">require'strings'
 
soul=: -. {.
Line 1,671 ⟶ 2,059:
starter=:1 :0
0"0 labels normalize m
)</langsyntaxhighlight>
 
Sample definition (note the deliberate introduction of extraneous whitespace in locations the task requires us to ignore it.
 
<langsyntaxhighlight lang="j">sample=: 0 :0
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ID |
Line 1,696 ⟶ 2,084:
get=: sample getter
set=: sample setter
start=: sample starter</langsyntaxhighlight>
 
Example data for sample definition:
 
<syntaxhighlight lang="j">
<lang J>
4095 13 5 6144 4096 'ID Opcode RCODE ARCOUNT QDCOUNT' set start
4095 0 13 0 0 0 0 0 5 4096 0 0 6144
Line 1,708 ⟶ 2,096:
10 0 7 0 0 0 1 0 0 0 0 0 255
'Opcode' get unpack 0 10 56 128 0 0 0 0 0 0 0 255
7</langsyntaxhighlight>
 
In other words:
Line 1,724 ⟶ 2,112:
Separate methods to validate, display, decode ASCII art, and decode hex value.
 
<syntaxhighlight lang="java">
<lang Java>
import java.math.BigInteger;
import java.util.ArrayList;
Line 1,879 ⟶ 2,267:
 
}
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 1,941 ⟶ 2,329:
 
=={{header|JavaScript}}==
<langsyntaxhighlight lang="javascript">// ------------------------------------------------------------[ Boilerplate ]--
const trimWhitespace = s => s.trim();
const isNotEmpty = s => s !== '';
Line 2,041 ⟶ 2,429:
const parser = parseDiagram(dia);
 
parser('78477bbf5496e12e1bf169a4');</langsyntaxhighlight>
{{out}}
<pre>
Line 2,101 ⟶ 2,489:
=={{header|Julia}}==
The validator() function can be customized. The one used only checks length.
<langsyntaxhighlight lang="julia">diagram = """
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ID |
Line 2,167 ⟶ 2,555:
 
bitreader(decoded, testhexdata)
</langsyntaxhighlight>{{out}}
<pre>
Diagram as bit fields:
Line 2,206 ⟶ 2,594:
=={{header|Lua}}==
Provided mainly to illustrate the string-parsing aspect, not necessarily the bit-structure aspect...
<langsyntaxhighlight lang="lua">local function validate(diagram)
local lines = {}
for s in diagram:gmatch("[^\r\n]+") do
Line 2,255 ⟶ 2,643:
local item = schema[i]
print(string.format("%-8s %8d %8d", item.name, item.numbits, item.offset))
end</langsyntaxhighlight>
{{out}}
<pre>NAME NUMBITS OFFSET
Line 2,288 ⟶ 2,676:
Of course, the second mechanism may be used for all cases. The first mechanism is mainly interesting to show how it is possible, using Nim powerful macro system, to create a type ''ex nihilo''.
 
<langsyntaxhighlight Nimlang="nim">import macros
import strutils
import tables
Line 2,782 ⟶ 3,170:
 
# Hexadecimal representation.
echo "Hexadecimal representation: ", header2.toHex()</langsyntaxhighlight>
 
{{out}}
Line 2,824 ⟶ 3,212:
 
Hexadecimal representation: 78477BBF5496E12E1BF169A4</pre>
 
=={{header|Ol}}==
<syntaxhighlight lang="scheme">
(import (owl parse))
 
(define format "
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ID |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| QDCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ANCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| NSCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ARCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+")
(define (subA x) (- x #\A -1))
 
(define whitespace (byte-if (lambda (x) (has? '(#\newline #\return #\+ #\- #\|) x))))
(define maybe-whitespaces (greedy* whitespace))
 
(define format-parser
(let-parse* (
(key (greedy* (let-parse* (
(* maybe-whitespaces)
(sp1 (greedy* (imm #\space)))
(name (greedy+ (byte-if (lambda (x) (or (<= #\A x #\Z) (<= #\a x #\z))))))
(sp2 (greedy* (imm #\space))))
(cons
(/ (+ (length sp1) (length name) (length sp2) 1) 3)
(list->string name)))))
(* maybe-whitespaces))
key))
 
(define table (parse format-parser (str-iter format) #f #f #f))
(unless table
(print "Invalid template. Exiting.")
(halt 1))
 
(print "table structure:" format)
(print "is encoded as " table " ")
 
(define (decode table data)
(let loop ((table (reverse table)) (bits data) (out #null))
(if (null? table)
out
else
(define name (cdar table))
(define width (caar table))
(define val (band bits (- (<< 1 width) 1)))
 
(loop (cdr table) (>> bits width) (cons (cons name val) out)))))
 
(define binary-input-data #b011110000100011101111011101111110101010010010110111000010010111000011011111100010110100110100100)
(print "decoding input data " binary-input-data)
 
(define datastructure (decode table binary-input-data))
 
(print)
(print "parsed datastructure:")
(for-each (lambda (x)
(print (car x) " == " (cdr x) " (" (number->string (cdr x) 2) ")"))
datastructure)
</syntaxhighlight>
{{out}}
<pre>$ ol ascii_art_diagram_converter.scm
table structure:
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ID |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| QDCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ANCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| NSCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ARCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
is encoded as ((16 . ID) (1 . QR) (4 . Opcode) (1 . AA) (1 . TC) (1 . RD) (1 . RA) (3 . Z) (4 . RCODE) (16 . QDCOUNT) (16 . ANCOUNT) (16 . NSCOUNT) (16 . ARCOUNT))
decoding input data 37224619292254864697109604772
 
parsed datastructure:
ID == 30791 (111100001000111)
QR == 0 (0)
Opcode == 15 (1111)
AA == 0 (0)
TC == 1 (1)
RD == 1 (1)
RA == 1 (1)
Z == 3 (11)
RCODE == 15 (1111)
QDCOUNT == 21654 (101010010010110)
ANCOUNT == 57646 (1110000100101110)
NSCOUNT == 7153 (1101111110001)
ARCOUNT == 27044 (110100110100100)
</pre>
 
=={{header|Perl}}==
<langsyntaxhighlight lang="perl">#!/usr/bin/perl
 
use strict;
Line 2,864 ⟶ 3,353:
 
print "\ntemplate = $template\n\n";
use Data::Dump 'dd'; dd 'datastructure', \%datastructure;</langsyntaxhighlight>
{{out}}
<pre>
Line 2,905 ⟶ 3,394:
=={{header|Phix}}==
Should work on any width, but didn't actually test, or verify width is 8/16/32/64.
<!--<syntaxhighlight lang="phix">(phixonline)-->
<lang Phix>function interpret(sequence lines)
<span style="color: #008080;">function</span> <span style="color: #000000;">interpret</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">lines</span><span style="color: #0000FF;">)</span>
if remainder(length(lines),2)!=1 then
<span style="color: #008080;">if</span> <span style="color: #7060A8;">remainder</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lines</span><span style="color: #0000FF;">),</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)!=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
crash("missing header/footer?")
<span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"missing header/footer?"</span><span style="color: #0000FF;">)</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
string l1 = lines[1]
<span style="color: #004080;">string</span> <span style="color: #000000;">l1</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">lines</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
integer w = length(l1)
<span style="color: #004080;">integer</span> <span style="color: #000000;">w</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">l1</span><span style="color: #0000FF;">)</span>
integer bits = (w-1)/3 -- sug: check this is 8/16/32/64
<span style="color: #004080;">integer</span> <span style="color: #000000;">bits</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">w</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">3</span> <span style="color: #000080;font-style:italic;">-- sug: check this is 8/16/32/64</span>
if l1!=join(repeat("+",bits+1),"--") then
<span style="color: #008080;">if</span> <span style="color: #000000;">l1</span><span style="color: #0000FF;">!=</span><span style="color: #7060A8;">join</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"+"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">bits</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">),</span><span style="color: #008000;">"--"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
crash("malformed header?")
<span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"malformed header?"</span><span style="color: #0000FF;">)</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
sequence res = {}
<span style="color: #004080;">sequence</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
integer offset = 0
<span style="color: #004080;">integer</span> <span style="color: #000000;">offset</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
for i=1 to length(lines) do
<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;">lines</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
string li = lines[i]
<span style="color: #004080;">string</span> <span style="color: #000000;">li</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">lines</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
if remainder(i,2) then
<span style="color: #008080;">if</span> <span style="color: #7060A8;">remainder</span><span style="color: #0000FF;">(</span><span style="color: #000000;">i</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
if li!=l1 then
<span style="color: #008080;">if</span> <span style="color: #000000;">li</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">l1</span> <span style="color: #008080;">then</span>
crash("missing separator (line %d)?",{i})
<span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"missing separator (line %d)?"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">i</span><span style="color: #0000FF;">})</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
else
<span style="color: #008080;">else</span>
if li[1]!='|' or li[w]!='|' then
<span style="color: #008080;">if</span> <span style="color: #000000;">li</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]!=</span><span style="color: #008000;">'|'</span> <span style="color: #008080;">or</span> <span style="color: #000000;">li</span><span style="color: #0000FF;">[</span><span style="color: #000000;">w</span><span style="color: #0000FF;">]!=</span><span style="color: #008000;">'|'</span> <span style="color: #008080;">then</span>
crash("missing separator on line %d",{i})
<span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"missing separator on line %d"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">i</span><span style="color: #0000FF;">})</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
integer k = 1
<span style="color: #004080;">integer</span> <span style="color: #000000;">k</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
while true do
<span style="color: #008080;">while</span> <span style="color: #004600;">true</span> <span style="color: #008080;">do</span>
integer l = find('|',li,k+1)
<span style="color: #004080;">integer</span> <span style="color: #000000;">l</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'|'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">li</span><span style="color: #0000FF;">,</span><span style="color: #000000;">k</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
string desc = trim(li[k+1..l-1])
<span style="color: #004080;">string</span> <span style="color: #000000;">desc</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">trim</span><span style="color: #0000FF;">(</span><span style="color: #000000;">li</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</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;">1</span><span style="color: #0000FF;">])</span>
{k,l} = {l,(l-k)/3}
<span style="color: #0000FF;">{</span><span style="color: #000000;">k</span><span style="color: #0000FF;">,</span><span style="color: #000000;">l</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">l</span><span style="color: #0000FF;">,(</span><span style="color: #000000;">l</span><span style="color: #0000FF;">-</span><span style="color: #000000;">k</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">3</span><span style="color: #0000FF;">}</span>
res = append(res,{desc,l,offset})
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">desc</span><span style="color: #0000FF;">,</span><span style="color: #000000;">l</span><span style="color: #0000FF;">,</span><span style="color: #000000;">offset</span><span style="color: #0000FF;">})</span>
offset += l
<span style="color: #000000;">offset</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">l</span>
if k=w then exit end if
<span style="color: #008080;">if</span> <span style="color: #000000;">k</span><span style="color: #0000FF;">=</span><span style="color: #000000;">w</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>
end while
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end for
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
res = append(res,{"total",0,offset})
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,{</span><span style="color: #008000;">"total"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">offset</span><span style="color: #0000FF;">})</span>
return res
<span style="color: #008080;">return</span> <span style="color: #000000;">res</span>
end function
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
 
procedure unpack(string data, sequence res)
<span style="color: #008080;">procedure</span> <span style="color: #000000;">unpack</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">data</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">sequence</span> <span style="color: #000000;">res</span><span style="color: #0000FF;">)</span>
if length(data)*8!=res[$][3] then
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">data</span><span style="color: #0000FF;">)*</span><span style="color: #000000;">8</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">res</span><span style="color: #0000FF;">[$][</span><span style="color: #000000;">3</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">then</span>
crash("wrong length")
<span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"wrong length"</span><span style="color: #0000FF;">)</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
string bin = ""
<span style="color: #004080;">string</span> <span style="color: #000000;">bin</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span>
for i=1 to length(data) do
<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;">data</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
bin &= sprintf("%08b",data[i])
<span style="color: #000000;">bin</span> <span style="color: #0000FF;">&=</span> <span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"%08b"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">data</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span>
end for
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
printf(1,"\n\nTest bit string:\n%s\n\nUnpacked:\n",{bin})
<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\nTest bit string:\n%s\n\nUnpacked:\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">bin</span><span style="color: #0000FF;">})</span>
for i=1 to length(res)-1 do
<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;">res</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
{string name, integer bits, integer offset} = res[i]
<span style="color: #0000FF;">{</span><span style="color: #004080;">string</span> <span style="color: #000000;">name</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">bits</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">offset</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">res</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
printf(1,"%7s, %02d bits: %s\n",{name,bits,bin[offset+1..offset+bits]})
<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;">"%7s, %02d bits: %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">name</span><span style="color: #0000FF;">,</span><span style="color: #000000;">bits</span><span style="color: #0000FF;">,</span><span style="color: #000000;">bin</span><span style="color: #0000FF;">[</span><span style="color: #000000;">offset</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">offset</span><span style="color: #0000FF;">+</span><span style="color: #000000;">bits</span><span style="color: #0000FF;">]})</span>
end for
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
end procedure
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
 
function trimskip(string diagram)
<span style="color: #008080;">function</span> <span style="color: #000000;">trimskip</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">diagram</span><span style="color: #0000FF;">)</span>
--
<span style="color: #000080;font-style:italic;">--
-- split's ",no_empty:=true)" is not quite enough here.
-- split's ",no_empty:=true)" is not quite enough here.
-- Note that if copy/paste slips in any tab characters,
-- Note that if copy/paste slips in any tab characters,
-- it will most likely trigger a length mismatch error.
-- it will most likely trigger a length mismatch error.
--
--</span>
sequence lines = split(diagram,'\n')
<span style="color: #004080;">sequence</span> <span style="color: #000000;">lines</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">split</span><span style="color: #0000FF;">(</span><span style="color: #000000;">diagram</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'\n'</span><span style="color: #0000FF;">)</span>
integer prevlli = 0
<span style="color: #004080;">integer</span> <span style="color: #000000;">prevlli</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
for i=length(lines) to 1 by -1 do
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lines</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">to</span> <span style="color: #000000;">1</span> <span style="color: #008080;">by</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
string li = trim(lines[i])
<span style="color: #004080;">string</span> <span style="color: #000000;">li</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">trim</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lines</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span>
integer lli = length(li)
<span style="color: #004080;">integer</span> <span style="color: #000000;">lli</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">li</span><span style="color: #0000FF;">)</span>
if lli then
<span style="color: #008080;">if</span> <span style="color: #000000;">lli</span> <span style="color: #008080;">then</span>
if prevlli=0 then
<span style="color: #008080;">if</span> <span style="color: #000000;">prevlli</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
prevlli = lli
<span style="color: #000000;">prevlli</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">lli</span>
elsif lli!=prevlli then
<span style="color: #008080;">elsif</span> <span style="color: #000000;">lli</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">prevlli</span> <span style="color: #008080;">then</span>
crash("mismatching lengths")
<span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"mismatching lengths"</span><span style="color: #0000FF;">)</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
lines[i] = li
<span style="color: #000000;">lines</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">li</span>
else
<span lines[i..i] style="color: {}#008080;">else</span>
<span style="color: #000000;">lines</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">..</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end for
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
return lines
<span style="color: #008080;">return</span> <span style="color: #000000;">lines</span>
end function
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
 
constant diagram = """
<span style="color: #008080;">constant</span> <span style="color: #000000;">diagram</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"""
 
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ID |
| ID |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR| Opcode |AA|TC|RD|RA| Z | RCODE |
|QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| QDCOUNT |
| QDCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ANCOUNT |
| ANCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| NSCOUNT |
| NSCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ARCOUNT |
| ARCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
 
"""
"""</span>
 
sequence lines = trimskip(diagram)
<span style="color: #004080;">sequence</span> <span style="color: #000000;">lines</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">trimskip</span><span style="color: #0000FF;">(</span><span style="color: #000000;">diagram</span><span style="color: #0000FF;">)</span>
sequence res = interpret(lines)
<span style="color: #004080;">sequence</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">interpret</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lines</span><span style="color: #0000FF;">)</span>
printf(1,"--Name-- Size Offset\n")
<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;">"--Name-- Size Offset\n"</span><span style="color: #0000FF;">)</span>
for i=1 to length(res) do
<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;">res</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
printf(1," %-7s %2d %5d\n",res[i])
<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;">" %-7s %2d %5d\n"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">res</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span>
end for
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
 
unpack(x"78477bbf5496e12e1bf169a4",res)</lang>
<span style="color: #000000;">unpack</span><span style="color: #0000FF;">(</span>x"<span style="color: #0000FF;">78477bbf5496e12e1bf169a4</span>"<span style="color: #0000FF;">,</span><span style="color: #000000;">res</span><span style="color: #0000FF;">)</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
Line 3,045 ⟶ 3,536:
ARCOUNT, 16 bits: 0110100110100100
</pre>
 
=={{header|Python}}==
<langsyntaxhighlight lang="python">
"""
http://rosettacode.org/wiki/ASCII_art_diagram_converter
Line 3,201 ⟶ 3,693:
unpack(results, hex)
</syntaxhighlight>
</lang>
 
{{out}}
Line 3,275 ⟶ 3,767:
<b><code>ascii-art-parser.rkt</code></b>
Note that this is in the <code>racket/base</code> language so it doesn't overburden the modules that import it, especially since they're at the suntax phase.
<langsyntaxhighlight lang="racket">#lang racket/base
(require (only-in racket/list drop-right)
(only-in racket/string string-trim))
Line 3,333 ⟶ 3,825:
(define cell-end-bit (hash-ref pos->bit-end# (cdr cp)))
(list word cell-start-bit cell-end-bit (string->symbol (string-trim (substring cnt 1))))))))
(values fields bits/word))</langsyntaxhighlight>
 
<b><code>ascii-art-reader.rkt</code></b>
<langsyntaxhighlight lang="racket">#lang racket
(require (for-syntax "ascii-art-parser.rkt"))
(require (for-syntax racket/syntax))
Line 3,403 ⟶ 3,895:
(define rv (make-bytes (* word-size #,(quotient bits/word 8))))
set-fields-bits
rv))))]))</langsyntaxhighlight>
 
<b><code>test-ascii-art-reader.rkt</code></b>
<langsyntaxhighlight lang="racket">#lang racket
(require "ascii-art-reader.rkt")
(require "ascii-art-parser.rkt")
Line 3,508 ⟶ 4,000:
(test
(rfc-1035-header-Z (bytes->rfc-1035-header (rfc-1035-header->bytes h))) => 7
(rfc-1035-header-RA (bytes->rfc-1035-header (rfc-1035-header->bytes h))) => 0)</langsyntaxhighlight>
 
{{out}}
Line 3,517 ⟶ 4,009:
{{works with|Rakudo|2018.05}}
 
<syntaxhighlight lang="raku" perl6line>grammar RFC1025 {
rule TOP { <.line-separator> [<line> <.line-separator>]+ }
rule line-separator { <.ws> '+--'+ '+' }
Line 3,573 ⟶ 4,065:
say "\nAnd unpack it";
printf("%7s, %02d bits: %s\n", %structure<fields>[$_]<ID>, %structure<fields>[$_]<bits>,
deconstruct($bitstr, %structure)[$_]) for ^@(%structure<fields>);</langsyntaxhighlight>
{{out}}
<pre>Line width: 16 bits
Line 3,613 ⟶ 4,105:
=={{header|REXX}}==
Some code was added to the REXX program to validate the input file.
<langsyntaxhighlight lang="rexx">/*REXX program interprets an ASCII art diagram for names and their bit length(s).*/
numeric digits 100 /*be able to handle large numbers. */
er= '***error*** illegal input txt' /*a literal used for error messages. */
Line 3,666 ⟶ 4,158:
exit 0 /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
lower: l= 'abcdefghijklmnopqrstuvwxyz'; u=l; upper u; return translate( arg(1), l, u)</langsyntaxhighlight>
{{out|output|text=&nbsp; when using the default input:}}
<pre>
Line 3,703 ⟶ 4,195:
test (hex)= cafe8050800000808080000a length= 24 hexadecimal digits.
 
test (bit)= 11001010 11111110 hex= CAca FEfe
test (bit)= 10000000 01010000 hex= 80 50
test (bit)= 10000000 00000000 hex= 80 00
Line 3,725 ⟶ 4,217:
</pre>
 
=={{header|Ruby}}==
<syntaxhighlight lang="ruby">header = <<HEADER
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ID |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| QDCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ANCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| NSCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ARCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
HEADER
 
Item = Struct.new(:name, :bits, :range)
RE = /\| *\w+ */
 
i = 0
table = header.scan(RE).map{|m| Item.new( m.delete("^A-Za-z"), b = m.size/3, i...(i += b)) }
 
teststr = "78477bbf5496e12e1bf169a4"
padding = table.sum(&:bits)
binstr = teststr.hex.to_s(2).rjust(padding, "0")
 
table.each{|el| p el.values}; puts
table.each{|el| puts "%7s, %2d bits: %s" % [el.name, el.bits, binstr[el.range] ]}
</syntaxhighlight>
{{out}}
<pre>["ID", 16, 0...16]
["QR", 1, 16...17]
["Opcode", 4, 17...21]
["AA", 1, 21...22]
["TC", 1, 22...23]
["RD", 1, 23...24]
["RA", 1, 24...25]
["Z", 3, 25...28]
["RCODE", 4, 28...32]
["QDCOUNT", 16, 32...48]
["ANCOUNT", 16, 48...64]
["NSCOUNT", 16, 64...80]
["ARCOUNT", 16, 80...96]
 
ID, 16 bits: 0111100001000111
QR, 1 bits: 0
Opcode, 4 bits: 1111
AA, 1 bits: 0
TC, 1 bits: 1
RD, 1 bits: 1
RA, 1 bits: 1
Z, 3 bits: 011
RCODE, 4 bits: 1111
QDCOUNT, 16 bits: 0101010010010110
ANCOUNT, 16 bits: 1110000100101110
NSCOUNT, 16 bits: 0001101111110001
ARCOUNT, 16 bits: 0110100110100100
</pre>
=={{header|Rust}}==
The solution implements a few additional features:
Line 3,737 ⟶ 4,288:
See the output below the source code.
 
<langsyntaxhighlight Rustlang="rust">use std::{borrow::Cow, io::Write};
 
pub type Bit = bool;
Line 4,127 ⟶ 4,678:
}) => eprintln!("Could not parse the input: {:?}", e),
}
}</langsyntaxhighlight>
 
{{out}}
Line 4,201 ⟶ 4,752:
 
In this implementation, '''parse''' produces a dictionary from names to bit-lengths. '''encode''' and '''decode''' use these to produce appropriate binary format strings, and then do what they say on the tin. As implemented, this is limited to unsigned numeric values in fields. Supporting unsigned values, strings and enums would require parsing a more complex annotation than only the ASCII art packet structure, but ought not take much more code.
<syntaxhighlight lang="tcl">
<lang Tcl>
namespace eval asciipacket {
proc assert {expr} { ;# for "static" assertions that throw nice errors
Line 4,279 ⟶ 4,830:
}
}
</syntaxhighlight>
</lang>
And here is how to use it with the original test data:
<syntaxhighlight lang="tcl">
<lang Tcl>
proc test {} {
set header {
Line 4,321 ⟶ 4,872:
}
test
</syntaxhighlight>
</lang>
{{Out}}
<pre>
Line 4,338 ⟶ 4,889:
decoded(TC) = 0
decoded(Z) = 100
</pre>
 
=={{header|V (Vlang)}}==
{{trans|go}}
<syntaxhighlight lang="v (vlang)">import math.big
import strings
 
struct Result {
name string
size int
start int
end int
}
fn (r Result) str() string {
return "${r.name:-7} ${r.size:2} ${r.start:3} ${r.end:3}"
}
fn validate(diagram string) ?[]string {
mut lines := []string{}
for mut line in diagram.split("\n") {
line = line.trim(" \t")
if line != "" {
lines << line
}
}
if lines.len == 0 {
return error("diagram has no non-empty lines!")
}
width := lines[0].len
cols := (width - 1) / 3
if cols != 8 && cols != 16 && cols != 32 && cols != 64 {
return error("number of columns should be 8, 16, 32 or 64")
}
if lines.len%2 == 0 {
return error("number of non-empty lines should be odd")
}
if lines[0] != "${strings.repeat_string("+--", cols)}+" {
return error("incorrect header line")
}
for i, line in lines {
if i == 0 {
continue
} else if i%2 == 0 {
if line != lines[0] {
return error("incorrect separator line")
}
} else if line.len != width {
return error("inconsistent line widths")
} else if line[0..1] != '|' || line[width-1..width] != '|' {
return error("non-separator lines must begin and end with '|'")
}
}
return lines
}
fn decode(lines []string) []Result {
println("Name Bits Start End")
println("======= ==== ===== ===")
mut start := 0
width := lines[0].len
mut results := []Result{}
for i, l in lines {
if i%2 == 0 {
continue
}
line := l[1..width-1]
for n in line.split("|") {
mut name := n
size := (name.len + 1) / 3
name = name.trim_space()
res := Result{name, size, start, start + size - 1}
results << res
println(res)
start += size
}
}
return results
}
fn unpack(results []Result, hex string) {
println("\nTest string in hex:")
println(hex)
println("\nTest string in binary:")
bin := hex2bin(hex) or {'ERROR'}
println(bin)
println("\nUnpacked:\n")
println("Name Size Bit pattern")
println("======= ==== ================")
for res in results {
println("${res.name:-7} ${res.size:2} ${bin[res.start..res.end+1]}")
}
}
fn hex2bin(hex string) ?string {
z := big.integer_from_radix(hex, 16)?
return "${z.binary_str():096}"
}
fn main() {
diagram := '
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ID |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| QDCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ANCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| NSCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ARCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
'
lines := validate(diagram)?
println("Diagram after trimming whitespace and removal of blank lines:\n")
for line in lines {
println(line)
}
println("\nDecoded:\n")
results := decode(lines)
hex := "78477bbf5496e12e1bf169a4" // test string
unpack(results, hex)
}</syntaxhighlight>
 
{{out}}
<pre>
Same as Go entry
</pre>
 
=={{header|Wren}}==
{{trans|Go}}
{{libheader|Wren-dynamic}}
{{libheader|Wren-fmt}}
{{libheader|Wren-big}}
<syntaxhighlight lang="wren">import "./dynamic" for Tuple
import "./fmt" for Fmt
import "./big" for BigInt
 
var Result = Tuple.create("Result", ["name", "size", "start", "end"])
 
var validate = Fn.new { |diagram|
var lines = []
for (line in diagram.split("\n")) {
line = line.trim(" \t")
if (line != "") lines.add(line)
}
if (lines.count == 0) Fiber.abort("diagram has no non-empty lines!")
var width = lines[0].count
var cols = ((width - 1) / 3).floor
if (cols != 8 && cols != 16 && cols != 32 && cols != 64) {
Fiber.abort("number of columns should be 8, 16, 32 or 64")
}
if (lines.count%2 == 0) {
Fiber.abort("number of non-empty lines should be odd")
}
if (lines[0] != "+--" * cols + "+") Fiber.abort("incorrect header line")
var i = 0
for (line in lines) {
if (i == 0) {
continue
} else if (i%2 == 0) {
if (line != lines[0]) Fiber.abort("incorrect separator line")
} else if (line.count != width) {
Fiber.abort("inconsistent line widths")
} else if (line[0] != "|" || line[width-1] != "|") {
Fiber.abort("non-separator lines must begin and end with '|'")
}
i = i + 1
}
return lines
}
 
var decode = Fn.new { |lines|
System.print("Name Bits Start End")
System.print("======= ==== ===== ===")
var start = 0
var width = lines[0].count
var results = []
var i = 0
for (line in lines) {
if (i%2 == 0) {
i = i + 1
continue
}
line = line[1...width-1]
for (name in line.split("|")) {
var size = ((name.count + 1) / 3).floor
name = name.trim()
var r = Result.new(name, size, start, start + size - 1)
results.add(r)
Fmt.print("$-7s $2d $3d $3d", r.name, r.size, r.start, r.end)
start = start + size
}
i = i + 1
}
return results
}
 
var hex2bin = Fn.new { |hex|
var z = BigInt.fromBaseString(hex, 16)
return Fmt.swrite("$0%(4*hex.count)s", z.toBaseString(2))
}
 
var unpack = Fn.new { |results, hex|
System.print("\nTest string in hex:")
System.print(hex)
System.print("\nTest string in binary:")
var bin = hex2bin.call(hex)
System.print(bin)
System.print("\nUnpacked:\n")
System.print("Name Size Bit pattern")
System.print("======= ==== ================")
for (res in results) {
Fmt.print("$-7s $2d $s", res.name, res.size, bin[res.start..res.end])
}
}
 
var diagram = """
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ID |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| QDCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
 
| ANCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| NSCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ARCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
"""
var lines = validate.call(diagram)
System.print("Diagram after trimming whitespace and removal of blank lines:\n")
for (line in lines) System.print(line)
System.print("\nDecoded:\n")
var results = decode.call(lines)
var hex = "78477bbf5496e12e1bf169a4" // test string
unpack.call(results, hex)</syntaxhighlight>
 
{{out}}
<pre>
Diagram after trimming whitespace and removal of blank lines:
 
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ID |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| QDCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ANCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| NSCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ARCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
 
Decoded:
 
Name Bits Start End
======= ==== ===== ===
ID 16 0 15
QR 1 16 16
Opcode 4 17 20
AA 1 21 21
TC 1 22 22
RD 1 23 23
RA 1 24 24
Z 3 25 27
RCODE 4 28 31
QDCOUNT 16 32 47
ANCOUNT 16 48 63
NSCOUNT 16 64 79
ARCOUNT 16 80 95
 
Test string in hex:
78477bbf5496e12e1bf169a4
 
Test string in binary:
011110000100011101111011101111110101010010010110111000010010111000011011111100010110100110100100
 
Unpacked:
 
Name Size Bit pattern
======= ==== ================
ID 16 0111100001000111
QR 1 0
Opcode 4 1111
AA 1 0
TC 1 1
RD 1 1
RA 1 1
Z 3 011
RCODE 4 1111
QDCOUNT 16 0101010010010110
ANCOUNT 16 1110000100101110
NSCOUNT 16 0001101111110001
ARCOUNT 16 0110100110100100
</pre>
9,482

edits