ASCII art diagram converter: Difference between revisions

m
m (→‎{{header|Wren}}: Minor tidy)
 
(23 intermediate revisions by 15 users not shown)
Line 44:
 
Bonus: perform a thoroughly validation of the input string.
 
=={{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">
/* ARM assembly AARCH64 Raspberry PI 3B or android 64 bits */
/* program asciiDiagram64.s */
 
/*******************************************/
/* Constantes file */
/*******************************************/
/* for this file see task include a file in language AArch64 assembly*/
.include "../includeConstantesARM64.inc"
 
/*******************************************/
/* Structures */
/********************************************/
/* Structure result */
.struct 0
res_name: //
.struct res_name + 8
res_startzone: //
.struct res_startzone + 8
res_endzone: //
.struct res_endzone + 8
res_size: //
.struct res_size + 8
res_end:
 
/*********************************/
/* Initialized data */
/*********************************/
.data
szMessDiagram: .asciz "Display diagramm :\n"
szMessValBin: .asciz "\nBinary Value :\n"
szMessValZone: .asciz "\nZones values : \n"
szMessResultTab: .asciz "Name @ start @ end @ size @ \n"
szMessSplitZone: .asciz "Name @ value : @ \n"
 
szMessErrSep: .asciz "Error : no séparator in first position of line.\n"
szMessErrlong: .asciz "Error : string hexa size not multiple to 4. \n"
szCarriageReturn: .asciz "\n"
 
szLine1: .asciz "+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+"
.equ LGLINE, . - szLine1
szLine2: .asciz "| ID |"
szLine3: .asciz "+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+"
szLine4: .asciz "|QR| Opcode |AA|TC|RD|RA| Z | RCODE |"
szLine5: .asciz "+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+"
szLine6: .asciz "| QDCOUNT |"
szLine7: .asciz "+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+"
szLine8: .asciz "| ANCOUNT |"
szLine9: .asciz "+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+"
szLine10: .asciz "| NSCOUNT |"
szLine11: .asciz "+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+"
szLine12: .asciz "| ARCOUNT |"
szLine13: .asciz "+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+"
.equ NBLINES, (. - szLine1) / LGLINE
bSeparator: .byte '|'
 
szValueHex: .asciz "78477bbf5496e12e1bf169a4"
szValueHexTest: .asciz "0ABCDEFabcdef123"
/*********************************/
/* UnInitialized data */
/*********************************/
.bss
sZoneConv: .skip 24
tbZones: .skip res_end * NBLINES * 5
sBuffer: .skip 100
/*********************************/
/* code section */
/*********************************/
.text
.global main
main: // entry of program
ldr x0,qAdrszMessDiagram
bl affichageMess
ldr x1,qAdrszLine1
mov x3,#LGLINE
mov x2,#0
1: // display diagram lines
madd x0,x2,x3,x1
bl affichageMess
ldr x0,qAdrszCarriageReturn
bl affichageMess
add x2,x2,#1
cmp x2,#NBLINES
blt 1b
ldr x0,qAdrszLine1 // first line address of diagram
bl decode // decode the diagram
mov x8,x0 // save result number
mov x3,#0 // indice
mov x4,#res_end // one result size
ldr x5,qAdrtbZones // table result address
2:
madd x6,x3,x4,x5 // compute result offset
ldr x1,[x6,#res_name] // zone name
ldr x0,qAdrszMessResultTab
bl strInsertAtCharInc // insertion in message
mov x7,x0
ldr x0,[x6,#res_startzone]
ldr x1,qAdrsZoneConv
bl conversion10 // call decimal conversion
mov x0,x7
ldr x1,qAdrsZoneConv // insert value conversion in message
bl strInsertAtCharInc
mov x7,x0
ldr x0,[x6,#res_endzone]
ldr x1,qAdrsZoneConv // else display odd message
bl conversion10 // call decimal conversion
mov x0,x7
ldr x1,qAdrsZoneConv // insert value conversion in message
bl strInsertAtCharInc
mov x7,x0
ldr x0,[x6,#res_size]
ldr x1,qAdrsZoneConv // else display odd message
bl conversion10 // call decimal conversion
mov x0,x7
ldr x1,qAdrsZoneConv // insert value conversion in message
bl strInsertAtCharInc
mov x7,x0
bl affichageMess
bl libererPlace // liberation heap area
add x3,x3,#1
cmp x3,x8
blt 2b
ldr x0,qAdrtbZones
ldr x1,qAdrszValueHex
//ldr x1,qAdrszValueHexTest
bl extractValue // convert string value hexa in binary string
mov x7,x0 // string binary address
ldr x0,qAdrszMessValZone
bl affichageMess
mov x0,x7
ldr x1,qAdrtbZones
mov x2,x8 // result number
bl splitZone
 
100: // standard end of the program
mov x0, #0 // return code
mov x8, #EXIT // request to exit program
svc #0 // perform the system call
qAdrszCarriageReturn: .quad szCarriageReturn
qAdrszMessResultTab: .quad szMessResultTab
qAdrszMessDiagram: .quad szMessDiagram
qAdrszMessValZone: .quad szMessValZone
qAdrsZoneConv: .quad sZoneConv
qAdrszLine1: .quad szLine1
qAdrszValueHex: .quad szValueHex
qAdrszValueHexTest: .quad szValueHexTest
/***************************************************/
/* decode lines */
/***************************************************/
// x0 contains diagram address
// x0 return result counter
decode:
stp x1,lr,[sp,-16]! // save registres
stp x2,x3,[sp,-16]! // save registres
stp x4,x5,[sp,-16]! // save registres
stp x6,x7,[sp,-16]! // save registres
mov x5,x0
mov x7,#LGLINE // size line diagram
ldr x3,qAdrbSeparator // séparator
ldrb w3,[x3]
ldr x1,qAdrtbZones // result table address
mov x2,#0 // result counter
mov x6,#1 // line 2
1:
madd x0,x6,x7,x5 // compute line offset
ldrb w4,[x0] // load one byte
cmp w4,w3 // separator ?
bne 99f // no -> error
bl decodeOneLine // decode a line
mov x2,x0 // new result number
add x6,x6,#2 // new line
cmp x6,#NBLINES // end ?
blt 1b
mov x0,x2 // return result counter
b 100f
99:
ldr x0,qAdrszMessErrSep
bl affichageMess
mov x0,#-1
100:
ldp x6,x7,[sp],16 // restaur des 2 registres
ldp x4,x5,[sp],16 // restaur des 2 registres
ldp x2,x3,[sp],16 // restaur des 2 registres
ldp x1,lr,[sp],16 // restaur des 2 registres
ret
qAdrbSeparator: .quad bSeparator
qAdrszMessErrSep: .quad szMessErrSep
qAdrtbZones: .quad tbZones
/***************************************************/
/* decode one line */
/***************************************************/
// x0 contains line diagram address
// x1 contains table result
// x2 contains result number
// x3 contains séparator
// x0 return new result number
decodeOneLine:
stp x1,lr,[sp,-16]! // save registres
stp x2,x3,[sp,-16]! // save registres
stp x4,x5,[sp,-16]! // save registres
stp x6,x7,[sp,-16]! // save registres
stp x8,x9,[sp,-16]! // save registres
stp x10,x11,[sp,-16]! // save registres
stp x12,x13,[sp,-16]! // save registres
mov x11,x0 // save address diagram
mov x7,x1 // save address table result
mov x4,x2 // save result counter
mov x0,#0 // zone size
mov x5,#-1 // name text begin address
mov x6,x3 // séparator
mov x8,#res_end
mov x10,#0 // zone start
mov x12,#1 // character indice
1:
ldrb w1,[x11,x12] // load one byte
cmp w1,#0 // line end ?
beq 10f
cmp w1,w6 // separator ?
beq 3f
cmp w1,#' ' // space ?
bne 2f
cmp x5,#0 // text name found ?
mov x1,#0
blt 11f
strb w1,[x11,x12] // yes -> 0 final text
11:
add x0,x0,#1 // increment zone size
add x12,x12,#1 // new byte
b 1b // and loop
2:
cmp x5,#0 // text name found ?
add x1,x11,x12 // no -> start zone
csel x5,x1,x5,lt
add x0,x0,#1 // increment zone size
add x12,x12,#1 // new byte
b 1b // and loop
3: // separator
cmp x5,#0 // zone name ?
blt 31f
mov x1,#0
strb w1,[x11,x12] // yes -> 0 final
31:
madd x9,x4,x8,x7 // compute result offset
str x5,[x9,#res_name] // store address start name
add x0,x0,#1 // compute zone size
cmp x0,#3
mov x1,#2
mov x5,#3
csel x1,x5,x1,gt
udiv x2,x0,x1 // / by size characters zone
str x2,[x9,#res_size]
cmp x4,#0 // first result ?
csel x10,xzr,x10,eq
beq 4f
sub x10,x9,x8 // else start zone = prev end zone + 1
ldr x10,[x10,#res_endzone]
add x10,x10,#1
4:
str x10,[x9,#res_startzone]
add x10,x10,x2 // end zone = start zone + size - 1
sub x10,x10,#1
str x10,[x9,#res_endzone]
add x4,x4,#1 // increment counter result
mov x0,#0 // raz size zone
add x10,x10,#1 // next byte
mov x5,#-1 // no text name
add x12,x12,#1 // next byte
b 1b // and loop
10:
mov x0,x4 // return result counter
100:
ldp x12,x13,[sp],16 // restaur des 2 registres
ldp x10,x11,[sp],16 // restaur des 2 registres
ldp x8,x9,[sp],16 // restaur des 2 registres
ldp x6,x7,[sp],16 // restaur des 2 registres
ldp x4,x5,[sp],16 // restaur des 2 registres
ldp x2,x3,[sp],16 // restaur des 2 registres
ldp x1,lr,[sp],16 // restaur des 2 registres
ret
/***************************************************/
/* convert strinh value hexa in binary string */
/***************************************************/
// x0 contains diagram address
// x1 contains string hex value
extractValue:
stp x1,lr,[sp,-16]! // save registres
stp x2,x3,[sp,-16]! // save registres
stp x4,x5,[sp,-16]! // save registres
stp x6,x7,[sp,-16]! // save registres
stp x8,x9,[sp,-16]! // save registres
mov x5,x0 // save address
ldr x0,qAdrszMessValBin
bl affichageMess
mov x6,x1 // save address string hexa
mov x2,#0
mov x3,#0
1: // compute string size
ldrb w4,[x1,x2] // load byte
cmp w4,#0 // end string ?
cinc x2,x2,ne
bne 1b
lsr x8,x2,#2 // control if multiple of 4
lsl x3,x8,#2
cmp x3,x2
bne 99f // no -> error
lsl x0,x2,#3 // compute size string * 8
add x0,x0,#1 // zero final
bl reserverPlace // reserve array on the heap
mov x7,x0 // address of heap array
mov x1,x0 // for routine
mov x0,x6 // address string value hexa
bl conversionBin // conversion string hexa -> binary
mov x0,x7
bl affichageMess
ldr x0,qAdrszCarriageReturn
bl affichageMess
mov x0,x7 // return address string binary
b 100f
99:
ldr x0,qAdrszMessErrlong
bl affichageMess
mov x0,#-1
100:
ldp x8,x9,[sp],16 // restaur des 2 registres
ldp x6,x7,[sp],16 // restaur des 2 registres
ldp x4,x5,[sp],16 // restaur des 2 registres
ldp x2,x3,[sp],16 // restaur des 2 registres
ldp x1,lr,[sp],16 // restaur des 2 registres
ret
qAdrszMessValBin: .quad szMessValBin
qAdrszMessErrlong: .quad szMessErrlong
/***************************************************/
/* decode lines */
/***************************************************/
// x0 contains address string binary
// x1 contains table zones address
// x2 contains result number
splitZone:
stp x1,lr,[sp,-16]! // save registres
stp x2,x3,[sp,-16]! // save registres
stp x4,x5,[sp,-16]! // save registres
stp x6,x7,[sp,-16]! // save registres
stp x8,x9,[sp,-16]! // save registres
stp x10,x11,[sp,-16]! // save registres
stp x12,x13,[sp,-16]! // save registres
mov x5,x0
mov x6,x1
mov x3,#0 // indice table
mov x4,#0 // indice string
mov x8,#res_end
1: // loop
madd x7,x3,x8,x6 // compute result offset
ldr x0,[x7,#res_startzone]
ldr x1,[x7,#res_size] // zone size
ldr x12,qAdrsBuffer
mov x9,#0
add x0,x0,x5
2: // copy bytes
ldrb w10,[x0,x9]
strb w10,[x12,x9]
add x9,x9,#1
cmp x9,x1 // zone size maxi ?
blt 2b // no -> loop
mov x10,#0 // 0 final
strb w10,[x12,x9]
// dislay name and value
ldr x0,qAdrszMessSplitZone
ldr x1,[x7,#res_name]
bl strInsertAtCharInc
mov x1,x12
bl strInsertAtCharInc
bl affichageMess
bl libererPlace
add x3,x3,#1
cmp x3,x2 // end result ?
blt 1b // no -> loop
100:
 
ldp x12,x13,[sp],16 // restaur des 2 registres
ldp x10,x11,[sp],16 // restaur des 2 registres
ldp x8,x9,[sp],16 // restaur des 2 registres
ldp x6,x7,[sp],16 // restaur des 2 registres
ldp x4,x5,[sp],16 // restaur des 2 registres
ldp x2,x3,[sp],16 // restaur des 2 registres
ldp x1,lr,[sp],16 // restaur des 2 registres
ret
qAdrszMessSplitZone: .quad szMessSplitZone
qAdrsBuffer: .quad sBuffer
/***************************************************/
/* conversion chaine hexa en */
/***************************************************/
// x0 contains string address
// x1 contains buffer address
conversionBin:
stp x1,lr,[sp,-16]! // save registres
stp x2,x3,[sp,-16]! // save registres
stp x4,x5,[sp,-16]! // save registres
stp x6,x7,[sp,-16]! // save registres
stp x8,x9,[sp,-16]! // save registres
mov x2,#0
mov x3,#0
1:
ldrb w4,[x0,x2]
cmp w4,#0 // string end
beq 10f
subs w4,w4,#0x30 // conversion digits
blt 5f
cmp w4,#10
blt 2f // digits 0 à 9 OK
cmp w4,#18 // < A ?
blt 5f
cmp w4,#24
sub w5,w4,#8 // letters A-F
csel w4,w5,w4,lt
blt 2f
cmp w4,#49 // < a ?
blt 5f
cmp w4,#54 // > f ?
bgt 5f
sub w4,w4,#39 // letters a-f
2: // x4 contains value on right 4 bits
mov x5,#0
add x3,x3,#4 // size ' bits
sub x7,x3,#1 // store indice
3:
tst x4,#1 // test first right bit
mov x6,#48 // character '0'
mov x8,#49 // character '1'
csel x6,x8,x6,ne
lsr x4,x4,1
strb w6,[x1,x7] // character -> display zone
sub x7,x7,#1 // prev position
add x5,x5,#1 // next bit
cmp x5,#4 // end ?
blt 3b
5: // loop to next byte
add x2,x2,#1
b 1b
10:
mov x6,#0
strb w6,[x1,x3] // zéro final
100:
ldp x8,x9,[sp],16 // restaur des 2 registres
ldp x6,x7,[sp],16 // restaur des 2 registres
ldp x4,x5,[sp],16 // restaur des 2 registres
ldp x2,x3,[sp],16 // restaur des 2 registres
ldp x1,lr,[sp],16 // restaur des 2 registres
ret
/********************************************************/
/* File Include fonctions */
/********************************************************/
/* for this file see task include a file in language AArch64 assembly */
.include "../includeARM64.inc"
</syntaxhighlight>
{{output}}
<pre>
Display diagramm :
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ID |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| QDCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ANCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| NSCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ARCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
Name ID start 0 end 15 size 16
Name QR start 16 end 16 size 1
Name Opcode start 17 end 20 size 4
Name AA start 21 end 21 size 1
Name TC start 22 end 22 size 1
Name RD start 23 end 23 size 1
Name RA start 24 end 24 size 1
Name Z start 25 end 27 size 3
Name RCODE start 28 end 31 size 4
Name QDCOUNT start 32 end 47 size 16
Name ANCOUNT start 48 end 63 size 16
Name NSCOUNT start 64 end 79 size 16
Name ARCOUNT start 80 end 95 size 16
 
Binary Value :
011110000100011101111011101111110101010010010110111000010010111000011011111100010110100110100100
 
Zones values :
Name ID value : 0111100001000111
Name QR value : 0
Name Opcode value : 1111
Name AA value : 0
Name TC value : 1
Name RD value : 1
Name RA value : 1
Name Z value : 011
Name RCODE value : 1111
Name QDCOUNT value : 0101010010010110
Name ANCOUNT value : 1110000100101110
Name NSCOUNT value : 0001101111110001
Name ARCOUNT value : 0110100110100100
</pre>
=={{header|ARM Assembly}}==
{{works with|as|Raspberry Pi <br> or android 32 bits with application Termux}}
<syntaxhighlight lang="arm assembly">
/* ARM assembly Raspberry PI or android 32 bits */
/* program asciiDiagram.s */
 
/* REMARK 1 : this program use routines in a include file
see task Include a file language arm assembly
for the routine affichageMess conversion10
see at end of this program the instruction include */
/* for constantes see task include a file in arm assembly */
/************************************/
/* Constantes */
/************************************/
.include "../constantes.inc"
 
/*******************************************/
/* Structures */
/********************************************/
/* Structure result */
.struct 0
res_name: //
.struct res_name + 4
res_startzone: //
.struct res_startzone + 4
res_endzone: //
.struct res_endzone + 4
res_size: //
.struct res_size + 4
res_end:
 
/*********************************/
/* Initialized data */
/*********************************/
.data
szMessDiagram: .asciz "Display diagramm :\n"
szMessValBin: .asciz "\nBinary Value :\n"
szMessValZone: .asciz "\nZones values : \n"
szMessResultTab: .asciz "Name @ start @ end @ size @ \n"
szMessSplitZone: .asciz "Name @ value : @ \n"
 
szMessErrSep: .asciz "Error : no séparator in first position of line.\n"
szMessErrlong: .asciz "Error : string hexa size not multiple to 4. \n"
szCarriageReturn: .asciz "\n"
 
szLine1: .asciz "+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+"
.equ LGLINE, . - szLine1
szLine2: .asciz "| ID |"
szLine3: .asciz "+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+"
szLine4: .asciz "|QR| Opcode |AA|TC|RD|RA| Z | RCODE |"
szLine5: .asciz "+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+"
szLine6: .asciz "| QDCOUNT |"
szLine7: .asciz "+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+"
szLine8: .asciz "| ANCOUNT |"
szLine9: .asciz "+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+"
szLine10: .asciz "| NSCOUNT |"
szLine11: .asciz "+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+"
szLine12: .asciz "| ARCOUNT |"
szLine13: .asciz "+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+"
.equ NBLINES, (. - szLine1) / LGLINE
bSeparator: .byte '|'
 
szValueHex: .asciz "78477bbf5496e12e1bf169a4"
szValueHexTest: .asciz "0ABCDEFabcdef123"
/*********************************/
/* UnInitialized data */
/*********************************/
.bss
sZoneConv: .skip 24
tbZones: .skip res_end * NBLINES * 5
sBuffer: .skip 100
/*********************************/
/* code section */
/*********************************/
.text
.global main
main: @ entry of program
ldr r0,iAdrszMessDiagram
bl affichageMess
ldr r1,iAdrszLine1
mov r3,#LGLINE
mov r2,#0
1: @ display diagram lines
mla r0,r2,r3,r1
bl affichageMess
ldr r0,iAdrszCarriageReturn
bl affichageMess
add r2,r2,#1
cmp r2,#NBLINES
blt 1b
ldr r0,iAdrszLine1 @ first line address of diagram
bl decode @ decode the diagram
mov r8,r0 @ save result number
mov r3,#0 @ indice
mov r4,#res_end @ one result size
ldr r5,iAdrtbZones @ table result address
2:
mla r6,r3,r4,r5 @ compute result offset
ldr r1,[r6,#res_name] @ zone name
ldr r0,iAdrszMessResultTab
bl strInsertAtCharInc @ insertion in message
mov r7,r0
ldr r0,[r6,#res_startzone]
ldr r1,iAdrsZoneConv
bl conversion10 @ call decimal conversion
mov r0,r7
ldr r1,iAdrsZoneConv @ insert value conversion in message
bl strInsertAtCharInc
mov r7,r0
ldr r0,[r6,#res_endzone]
ldr r1,iAdrsZoneConv @ else display odd message
bl conversion10 @ call decimal conversion
mov r0,r7
ldr r1,iAdrsZoneConv @ insert value conversion in message
bl strInsertAtCharInc
mov r7,r0
ldr r0,[r6,#res_size]
ldr r1,iAdrsZoneConv @ else display odd message
bl conversion10 @ call decimal conversion
mov r0,r7
ldr r1,iAdrsZoneConv @ insert value conversion in message
bl strInsertAtCharInc
mov r7,r0
bl affichageMess
bl libererPlace @ liberation heap area
add r3,r3,#1
cmp r3,r8
blt 2b
ldr r0,iAdrtbZones
ldr r1,iAdrszValueHex
//ldr r1,iAdrszValueHexTest
bl extractValue @ convert string value hexa in binary string
mov r7,r0 @ string binary address
ldr r0,iAdrszMessValZone
bl affichageMess
mov r0,r7
ldr r1,iAdrtbZones
mov r2,r8 @ result number
bl splitZone
 
100: @ standard end of the program
mov r0, #0 @ return code
mov r7, #EXIT @ request to exit program
svc #0 @ perform the system call
iAdrszCarriageReturn: .int szCarriageReturn
iAdrszMessResultTab: .int szMessResultTab
iAdrszMessDiagram: .int szMessDiagram
iAdrszMessValZone: .int szMessValZone
iAdrsZoneConv: .int sZoneConv
iAdrszLine1: .int szLine1
iAdrszValueHex: .int szValueHex
iAdrszValueHexTest: .int szValueHexTest
/***************************************************/
/* decode lines */
/***************************************************/
// r0 contains diagram address
// r0 return result counter
decode:
push {r1-r7,lr} @ save registers
mov r5,r0
mov r7,#LGLINE @ size line diagram
ldr r3,iAdrbSeparator @ séparator
ldrb r3,[r3]
ldr r1,iAdrtbZones @ result table address
mov r2,#0 @ result counter
mov r6,#1 @ line 2
1:
mla r0,r6,r7,r5 @ compute line offset
ldrb r4,[r0] @ load one byte
cmp r4,r3 @ separator ?
bne 99f @ no -> error
bl decodeOneLine @ decode a line
mov r2,r0 @ new result number
add r6,r6,#2 @ new line
cmp r6,#NBLINES @ end ?
blt 1b
mov r0,r2 @ return result counter
b 100f
99:
ldr r0,iAdrszMessErrSep
bl affichageMess
mov r0,#-1
100:
pop {r1-r7,lr} @ restaur registers
bx lr @ return
iAdrbSeparator: .int bSeparator
iAdrszMessErrSep: .int szMessErrSep
iAdrtbZones: .int tbZones
/***************************************************/
/* decode one line */
/***************************************************/
// r0 contains line diagram address
// r1 contains table result
// r2 contains result number
// r3 contains séparator
// r0 return new result number
decodeOneLine:
push {r1-r12,lr} @ save registers
mov r11,r0 @ save address diagram
mov r7,r1 @ save address table result
mov r4,r2 @ save result counter
mov r0,#0 @ zone size
mov r5,#-1 @ name text begin address
mov r6,r3 @ séparator
mov r8,#res_end
mov r10,#0 @ zone start
mov r12,#1 @ character indice
1:
ldrb r1,[r11,r12] @ load one byte
cmp r1,#0 @ line end ?
beq 10f
cmp r1,r6 @ separator ?
beq 3f
cmp r1,#' ' @ space ?
bne 2f
cmp r5,#0 @ text name found ?
mov r1,#0
strgeb r1,[r11,r12] @ yes -> 0 final text
add r0,r0,#1 @ increment zone size
add r12,r12,#1 @ new byte
b 1b @ and loop
2:
cmp r5,#0 @ text name found ?
addlt r5,r11,r12 @ no -> start zone
add r0,r0,#1 @ increment zone size
add r12,r12,#1 @ new byte
b 1b @ and loop
3: @ separator
cmp r5,#0 @ zone name ?
mov r1,#0
strgeb r1,[r11,r12] @ yes -> 0 final
mla r9,r4,r8,r7 @ compute result offset
str r5,[r9,#res_name] @ store address start name
add r0,r0,#1 @ compute zone size
cmp r0,#3
movle r1,#2
movgt r1,#3
bl division @ / by size characters zone
str r2,[r9,#res_size]
cmp r4,#0 @ first result ?
moveq r10,#0 @ yes -> start zone = 0
beq 4f
sub r10,r9,r8 @ else start zone = prev end zone + 1
ldr r10,[r10,#res_endzone]
add r10,r10,#1
4:
str r10,[r9,#res_startzone]
add r10,r10,r2 @ end zone = start zone + size - 1
sub r10,r10,#1
str r10,[r9,#res_endzone]
add r4,r4,#1 @ increment counter result
mov r0,#0 @ raz size zone
add r10,r10,#1 @ next byte
mov r5,#-1 @ no text name
add r12,r12,#1 @ next byte
b 1b @ and loop
10:
mov r0,r4 @ return result counter
100:
pop {r1-r12,lr} @ restaur registers
bx lr @ return
/***************************************************/
/* convert strinh value hexa in binary string */
/***************************************************/
// r0 contains diagram address
// r1 contains string hex value
extractValue:
push {r1-r8,lr} @ save registers
mov r5,r0 @ save address
ldr r0,iAdrszMessValBin
bl affichageMess
mov r6,r1 @ save address string hexa
mov r2,#0
mov r3,#0
1: @ compute string size
ldrb r4,[r1,r2] @ load byte
cmp r4,#0 @ end string ?
addne r2,r2,#1
bne 1b
lsr r8,r2,#2 @ control if multiple of 4
lsl r3,r8,#2
cmp r3,r2
bne 99f @ no -> error
lsl r0,r2,#3 @ compute size string * 8
add r0,r0,#1 @ zero final
bl reserverPlace @ reserve array on the heap
mov r7,r0 @ address of heap array
mov r1,r0 @ for routine
mov r0,r6 @ address string value hexa
bl conversionBin @ conversion string hexa -> binary
mov r0,r7
bl affichageMess
ldr r0,iAdrszCarriageReturn
bl affichageMess
mov r0,r7 @ return address string binary
b 100f
99:
ldr r0,iAdrszMessErrlong
bl affichageMess
mov r0,#-1
100:
pop {r1-r8,lr} @ restaur registers
bx lr @ return
iAdrszMessValBin: .int szMessValBin
iAdrszMessErrlong: .int szMessErrlong
/***************************************************/
/* decode lines */
/***************************************************/
// r0 contains address string binary
// r1 contains table zones address
// r2 contains result number
splitZone:
push {r1-r12,lr} @ save registers
mov r5,r0
mov r6,r1
mov r3,#0 @ indice table
mov r4,#0 @ indice string
mov r8,#res_end
1: @ loop
mla r7,r3,r8,r6 @ compute result offset
ldr r0,[r7,#res_startzone]
ldr r1,[r7,#res_size] @ zone size
ldr r12,iAdrsBuffer
mov r9,#0
add r0,r0,r5
2: @ copy bytes
ldrb r10,[r0,r9]
strb r10,[r12,r9]
add r9,r9,#1
cmp r9,r1 @ zone size maxi ?
blt 2b @ no -> loop
mov r10,#0 @ 0 final
str r10,[r12,r9]
@ dislay name and value
ldr r0,iAdrszMessSplitZone
ldr r1,[r7,#res_name]
bl strInsertAtCharInc
mov r1,r12
bl strInsertAtCharInc
bl affichageMess
bl libererPlace
add r3,r3,#1
cmp r3,r2 @ end result ?
blt 1b @ no -> loop
100:
pop {r1-r12,lr} @ restaur registers
bx lr @ return
iAdrszMessSplitZone: .int szMessSplitZone
iAdrsBuffer: .int sBuffer
/***************************************************/
/* conversion chaine hexa en */
/***************************************************/
// r0 contains string address
// r1 contains buffer address
conversionBin:
push {r2-r7,lr} @ save registers
mov r2,#0
mov r3,#0
1:
ldrb r4,[r0,r2]
cmp r4,#0 @ string end
beq 10f
subs r4,r4,#0x30 @ conversion digits
blt 5f
cmp r4,#10
blt 2f @ digits 0 à 9 OK
cmp r4,#18 @ < A ?
blt 5f
//vidregtit inter
cmp r4,#24
sublt r4,r4,#8 @ letters A-F
blt 2f
cmp r4,#49 @ < a ?
blt 5f
cmp r4,#54 @ > f ?
bgt 5f
sub r4,r4,#39 @ letters a-f
2: @ r4 contains value on right 4 bits
mov r5,#0
add r3,r3,#4 @ size bits
sub r7,r3,#1 @ store indice
3:
lsrs r4,#1 @ right bit in carry
movcc r6,#48 @ flag carry off character '0'
movcs r6,#49 @ flag carry on character '1'
strb r6,[r1,r7] @ character -> display zone
sub r7,r7,#1 @ prev position
add r5,r5,#1 @ next bit
cmp r5,#4 @ end ?
blt 3b
5: @ loop to next byte
add r2,r2,#1
b 1b
10:
mov r6,#0
strb r6,[r1,r3] @ zéro final
100:
pop {r2-r7,lr} @ restaur registers
bx lr @ return
/***************************************************/
/* ROUTINES INCLUDE */
/***************************************************/
.include "../affichage.inc"
</syntaxhighlight>
{{Output}}
<pre>
Display diagramm :
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ID |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| QDCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ANCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| NSCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ARCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
Name ID start 0 end 15 size 16
Name QR start 16 end 16 size 1
Name Opcode start 17 end 20 size 4
Name AA start 21 end 21 size 1
Name TC start 22 end 22 size 1
Name RD start 23 end 23 size 1
Name RA start 24 end 24 size 1
Name Z start 25 end 27 size 3
Name RCODE start 28 end 31 size 4
Name QDCOUNT start 32 end 47 size 16
Name ANCOUNT start 48 end 63 size 16
Name NSCOUNT start 64 end 79 size 16
Name ARCOUNT start 80 end 95 size 16
 
Binary Value :
011110000100011101111011101111110101010010010110111000010010111000011011111100010110100110100100
 
Zones values :
Name ID value : 0111100001000111
Name QR value : 0
Name Opcode value : 1111
Name AA value : 0
Name TC value : 1
Name RD value : 1
Name RA value : 1
Name Z value : 011
Name RCODE value : 1111
Name QDCOUNT value : 0101010010010110
Name ANCOUNT value : 1110000100101110
Name NSCOUNT value : 0001101111110001
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
 
The ASCII diagram is parsed at compile time into a data structure that is used at runtime to encode and decode the fields.
 
<syntaxhighlight lang="cpp">#include <array>
#include <bitset>
#include <iostream>
 
using namespace std;
 
struct FieldDetails {string_view Name; int NumBits;};
 
// parses the ASCII diagram and returns the field name, bit sizes, and the
// total byte size
template <const char *T> consteval auto ParseDiagram()
{
// trim the ASCII diagram text
constexpr string_view rawArt(T);
constexpr auto firstBar = rawArt.find("|");
constexpr auto lastBar = rawArt.find_last_of("|");
constexpr auto art = rawArt.substr(firstBar, lastBar - firstBar);
static_assert(firstBar < lastBar, "ASCII Table has no fields");
// make an array for all of the fields
constexpr auto numFields =
count(rawArt.begin(), rawArt.end(), '|') -
count(rawArt.begin(), rawArt.end(), '\n') / 2;
array<FieldDetails, numFields> fields;
// parse the diagram
bool isValidDiagram = true;
int startDiagramIndex = 0;
int totalBits = 0;
for(int i = 0; i < numFields; )
{
auto beginningBar = art.find("|", startDiagramIndex);
auto endingBar = art.find("|", beginningBar + 1);
auto field = art.substr(beginningBar + 1, endingBar - beginningBar - 1);
if(field.find("-") == field.npos)
{
int numBits = (field.size() + 1) / 3;
auto nameStart = field.find_first_not_of(" ");
auto nameEnd = field.find_last_not_of(" ");
if (nameStart > nameEnd || nameStart == string_view::npos)
{
// the table cannot be parsed
isValidDiagram = false;
field = ""sv;
}
else
{
field = field.substr(nameStart, 1 + nameEnd - nameStart);
}
fields[i++] = FieldDetails {field, numBits};
totalBits += numBits;
}
startDiagramIndex = endingBar;
}
int numRawBytes = isValidDiagram ? (totalBits - 1) / 8 + 1 : 0;
return make_pair(fields, numRawBytes);
}
 
// encode the values of the fields into a raw data array
template <const char *T> auto Encode(auto inputValues)
{
constexpr auto parsedDiagram = ParseDiagram<T>();
static_assert(parsedDiagram.second > 0, "Invalid ASCII talble");
array<unsigned char, parsedDiagram.second> data;
 
int startBit = 0;
int i = 0;
for(auto value : inputValues)
{
const auto &field = parsedDiagram.first[i++];
int remainingValueBits = field.NumBits;
while(remainingValueBits > 0)
{
// pack the bits from an input field into the data array
auto [fieldStartByte, fieldStartBit] = div(startBit, 8);
int unusedBits = 8 - fieldStartBit;
int numBitsToEncode = min({unusedBits, 8, field.NumBits});
int divisor = 1 << (remainingValueBits - numBitsToEncode);
unsigned char bitsToEncode = value / divisor;
data[fieldStartByte] <<= numBitsToEncode;
data[fieldStartByte] |= bitsToEncode;
value %= divisor;
startBit += numBitsToEncode;
remainingValueBits -= numBitsToEncode;
}
}
return data;
}
 
// decode the raw data into the format of the ASCII diagram
template <const char *T> void Decode(auto data)
{
cout << "Name Bit Pattern\n";
cout << "======= ================\n";
constexpr auto parsedDiagram = ParseDiagram<T>();
static_assert(parsedDiagram.second > 0, "Invalid ASCII talble");
 
int startBit = 0;
for(const auto& field : parsedDiagram.first)
{
// unpack the bits from the data into a single field
auto [fieldStartByte, fieldStartBit] = div(startBit, 8);
unsigned char firstByte = data[fieldStartByte];
firstByte <<= fieldStartBit;
firstByte >>= fieldStartBit;
int64_t value = firstByte;
auto endBit = startBit + field.NumBits;
auto [fieldEndByte, fieldEndBit] = div(endBit, 8);
fieldEndByte = min(fieldEndByte, (int)(ssize(data) - 1));
for(int index = fieldStartByte + 1; index <= fieldEndByte; index++)
{
value <<= 8;
value += data[index];
}
value >>= fieldEndBit;
startBit = endBit;
cout << field.Name <<
string_view(" ", (7 - field.Name.size())) << " " <<
string_view(bitset<64>(value).to_string()).substr(64 - field.NumBits, 64) << "\n";
}
}
 
int main(void)
{
static constexpr char art[] = R"(
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ID |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| QDCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ANCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| NSCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ARCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+)";
// using the table above, encode the data below
auto rawData = Encode<art> (initializer_list<int64_t> {
30791,
0, 15, 0, 1, 1, 1, 3, 15,
21654,
57646,
7153,
27044
});
cout << "Raw encoded data in hex:\n";
for (auto v : rawData) printf("%.2X", v);
cout << "\n\n";
cout << "Decoded raw data:\n";
Decode<art>(rawData);
}</syntaxhighlight>
{{out}}
<pre>
Raw encoded data in hex:
78477BBF5496E12E1BF169A4
 
Decoded raw data:
Name Bit Pattern
======= ================
ID 0100011101111011
QR 1
Opcode 0011
AA 0
TC 0
RD 1
RA 1
Z 011
RCODE 0100
QDCOUNT 1001011011100001
ANCOUNT 0010111000011011
NSCOUNT 1111000101101001
ARCOUNT 0110100110100100
</pre>
 
An invalid table will cause a compilation error - here the ANCOUNT field is missing.
<syntaxhighlight lang="cpp"> static constexpr char missingFieldArt[] = R"(
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ID |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| QDCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| NSCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ARCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+)";
</syntaxhighlight>
 
GCC 11 gives this error
 
{{out}}
<pre>
../ascii-art-diagram-converter.cpp: In instantiation of 'void Decode(auto:12) [with const char* T = (& missingFieldArt); auto:12 = std::array<unsigned char, 12>]':
../ascii-art-diagram-converter.cpp:181:36: required from here
../ascii-art-diagram-converter.cpp:98:40: error: static assertion failed: Invalid ASCII talble
98 | static_assert(parsedDiagram.second > 0, "Invalid ASCII talble");
| ~~~~~~~~~~~~~~~~~~~~~^~~
../ascii-art-diagram-converter.cpp:98:40: note: '(((int)parsedDiagram.std::pair<std::array<FieldDetails, 13>, int>::second) > 0)' evaluates to false
</pre>
 
=={{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 247 ⟶ 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 261 ⟶ 1,671:
 
=={{header|Go}}==
<langsyntaxhighlight lang="go">package main
 
import (
Line 388 ⟶ 1,798:
hex := "78477bbf5496e12e1bf169a4" // test string
unpack(results, hex)
}</langsyntaxhighlight>
 
{{out}}
Line 450 ⟶ 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 486 ⟶ 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 511 ⟶ 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 523 ⟶ 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 539 ⟶ 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 694 ⟶ 2,267:
 
}
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 756 ⟶ 2,329:
 
=={{header|JavaScript}}==
<langsyntaxhighlight lang="javascript">// ------------------------------------------------------------[ Boilerplate ]--
const trimWhitespace = s => s.trim();
const isNotEmpty = s => s !== '';
Line 765 ⟶ 2,338:
const alignLeft = n => s => `${s}`.padEnd(n, ' ');
const repeatChar = c => n => c.padStart(n, c);
const joinWith = c => arr => arr.join(c);
const joinNl = joinWith('\n');
const joinSp = joinWith(' ');
 
const printDiagramInfo = map => {
const pName = alignLeft(8);
Line 770 ⟶ 2,347:
const line = repeatChar('-');
const res = [];
res.push(joinSp([pName('Name'), p5('Size'), p5('Start'), p5('End')].join(' '));
res.push(joinSp([line(8), line(5), line(5), line(5)].join(' '));
[...map.values()].forEach(({label, bitLength, start, end}) => {
res.push(joinSp([pName(label), p5(bitLength), p5(start), p5(end)].join(' '));
})
return res;
Line 808 ⟶ 2,385:
}, new Map());
 
const pName = alignLeft(8);
const pBit = alignRight(5);
const pPat = alignRight(18);
const line = repeatChar('-');
const nl = '\n';
return hexStr => {
const pName = alignLeft(8);
const pBit = alignRight(5);
const pPat = alignLeft(16);
const line = repeatChar('-')
const binString = [...hexStr].reduce(concatHexToBin, '');
 
const res = printDiagramInfo(fieldMetaMap);
res.unshift(joinNl(['Diagram:', ...arr, '\n'nl].join('\n'));
res.push(joinNl(['\n'nl, 'Test string in hex:', hexStr].join('\n'));
res.push(joinNl(['Test string in binary:', binString, '\n'nl].join('\n'));
res.push(joinSp([pName('Name'), pBit('Size'), pPat('Pattern')].join(' '));
res.push(joinSp([line(8), line(5), line(1618)].join(' '));
 
[...fieldMetaMap.values()].forEach(({label, bitLength, start, end}) => {
res.push(joinSp(
res.push([pName(label), pBit(bitLength), pPat(binString.substr(start, bitLength))].join(' '))
[pName(label), pBit(bitLength),
pPat(binString.substr(start, bitLength))]))
})
return res.joinjoinNl('\n'res);
}
}
Line 849 ⟶ 2,429:
const parser = parseDiagram(dia);
 
parser('78477bbf5496e12e1bf169a4');</langsyntaxhighlight>
{{out}}
<pre>
Line 891 ⟶ 2,471:
 
 
Name Size Pattern Pattern
-------- ----- ------------------
ID 16 0111100001000111
QR 1 0 0
Opcode 4 1111 1111
AA 1 0 0
TC 1 1 1
RD 1 1 1
RA 1 1 1
Z 3 011 011
RCODE 4 1111 1111
QDCOUNT 16 0101010010010110
ANCOUNT 16 1110000100101110
NSCOUNT 16 0001101111110001
ARCOUNT 16 0110100110100100</pre>
 
=={{header|Julia}}==
The validator() function can be customized. The one used only checks length.
<langsyntaxhighlight lang="julia">diagram = """
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ID |
Line 975 ⟶ 2,555:
 
bitreader(decoded, testhexdata)
</langsyntaxhighlight>{{out}}
<pre>
Diagram as bit fields:
Line 1,011 ⟶ 2,591:
ARCOUNT 16 0110100110100100
</pre>
 
=={{header|Lua}}==
Provided mainly to illustrate the string-parsing aspect, not necessarily the bit-structure aspect...
<syntaxhighlight lang="lua">local function validate(diagram)
local lines = {}
for s in diagram:gmatch("[^\r\n]+") do
s = s:match("^%s*(.-)%s*$")
if s~="" then lines[#lines+1]=s end
end
-- "a little of validation".."for brevity"
assert(#lines>0, "FAIL: no non-empty lines")
assert(#lines%2==1, "FAIL: even number of lines")
return lines
end
 
local function parse(lines)
local schema, offset = {}, 0
for i = 2,#lines,2 do
for part in lines[i]:gmatch("\|([^\|]+)") do
schema[#schema+1] = { name=part:match("^%s*(.-)%s*$"), numbits=(#part+1)/3, offset=offset }
offset = offset + (#part+1)/3
end
end
return schema
end
 
local diagram = [[
 
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ID |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| QDCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
 
| ANCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| NSCOUNT |
 
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ARCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
 
]] -- extra whitespace added for testing
 
local schema = parse(validate(diagram))
print("NAME NUMBITS OFFSET")
print("-------- -------- --------")
for i = 1,#schema do
local item = schema[i]
print(string.format("%-8s %8d %8d", item.name, item.numbits, item.offset))
end</syntaxhighlight>
{{out}}
<pre>NAME NUMBITS OFFSET
-------- -------- --------
ID 16 0
QR 1 16
Opcode 4 17
AA 1 21
TC 1 22
RD 1 23
RA 1 24
Z 3 25
RCODE 4 28
QDCOUNT 16 32
ANCOUNT 16 48
NSCOUNT 16 64
ARCOUNT 16 80</pre>
 
=={{header|Nim}}==
Line 1,027 ⟶ 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 1,521 ⟶ 3,170:
 
# Hexadecimal representation.
echo "Hexadecimal representation: ", header2.toHex()</langsyntaxhighlight>
 
{{out}}
Line 1,563 ⟶ 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 1,603 ⟶ 3,353:
 
print "\ntemplate = $template\n\n";
use Data::Dump 'dd'; dd 'datastructure', \%datastructure;</langsyntaxhighlight>
{{out}}
<pre>
Line 1,644 ⟶ 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 1,784 ⟶ 3,536:
ARCOUNT, 16 bits: 0110100110100100
</pre>
 
=={{header|Python}}==
<langsyntaxhighlight lang="python">
"""
http://rosettacode.org/wiki/ASCII_art_diagram_converter
Line 1,940 ⟶ 3,693:
unpack(results, hex)
</syntaxhighlight>
</lang>
 
{{out}}
Line 2,014 ⟶ 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 2,072 ⟶ 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 2,142 ⟶ 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 2,247 ⟶ 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 2,256 ⟶ 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 2,312 ⟶ 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 2,352 ⟶ 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 2,405 ⟶ 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 2,442 ⟶ 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 2,464 ⟶ 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 2,476 ⟶ 4,288:
See the output below the source code.
 
<langsyntaxhighlight Rustlang="rust">use std::{borrow::Cow, io::Write};
 
pub type Bit = bool;
Line 2,866 ⟶ 4,678:
}) => eprintln!("Could not parse the input: {:?}", e),
}
}</langsyntaxhighlight>
 
{{out}}
Line 2,940 ⟶ 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 3,018 ⟶ 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 3,060 ⟶ 4,872:
}
test
</syntaxhighlight>
</lang>
{{Out}}
<pre>
Line 3,077 ⟶ 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