Instantly share code, notes, and snippets.

@rgchris /simf.reb
Last active Feb 11, 2018

Embed
What would you like to do?
Simple IMF Parser
Rebol [
Title: "Simple IMF Parser"
Author: "Christopher Ross-Gill"
Date: 11-Feb-2018
Home: https://github.com/rgchris/Scripts
File: %simf.reb
Rights: http://opensource.org/licenses/Apache-2.0
Type: module
Name: rgchris.simf
Exports: [load-message]
Comment: [
; Standard for Email Messages
https://tools.ietf.org/html/rfc5322 "Internet Message Format (IMF)"
; Standard for HTTP Messages (v1.1)
https://tools.ietf.org/html/rfc7230 "HTTP/1.1 Message Syntax and Routing"
]
]
load-message: use [
message name value part mark error-message ; Values
token space chars crlf line ; Components
states current-state switch-to ; State Machine
][
crlf: #{0D0A}
space: use [space*][
space*: charset " ^-"
[some space*]
]
chars: use [chars*][
chars*: charset [33 - 126]
[some chars*]
]
token: use [token*][
; token*: [!#$%&'*+-.0-9A-Z^_`a-z|~]
token*: charset [33 42 43 45 46 48 - 57 65 - 90 94 95 96 97 - 122 124 126]
[some token*]
]
line: [chars any [space chars]]
switch-to: func [state [word!]][
; probe uppercase spelling-of state
current-state: select states to-set-word state
]
states: [
before-headers: [
mark: end (error-message: "Empty Message") fail
|
(
message: make block! 16
error-message: _
switch-to 'before-header
)
]
before-header: [
copy name token (
repend message [
to word! to string! name
value: make string! 1024
]
switch-to 'after-header-name
)
|
mark: [
end (error-message: "Premature End of Message")
|
(error-message: "Expected Header Name")
] fail
]
after-header-name: [
#":" opt space (
switch-to 'before-value-line
)
|
[
mark: end (error-message: "Premature End of Message")
|
(error-message: "Expected ':'")
] fail
]
before-value-line: [
copy part line (
append value to string! part
switch-to 'after-value-line
)
|
crlf (
switch-to 'after-header
)
|
[
mark: end (error-message: "Premature End of Message")
|
(error-message: "Expected Value")
] fail
]
after-value-line: [
space crlf (
switch-to 'after-header
)
|
crlf (
switch-to 'continue-value-line
)
]
continue-value-line: [
space (
append value " "
switch-to 'before-value-line
)
|
(
switch-to 'after-header
)
]
after-header: [
crlf (
switch-to 'before-body
)
|
(
switch-to 'before-header
)
]
before-body: [
end ; DONE!
|
mark: to end (
append message 'Content
append message copy mark
) break
]
]
load-message: func [
{Returns a header object with header fields and their values}
data [binary!] "Message to parse"
/with parent [object! blank!] "Default header object"
][
either parse data [
(switch-to 'before-headers)
while [end current-state break | current-state]
][
new-line/skip message true 2
][
fail delimit [error-message mold copy/part mark 50] ": "
]
]
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment