Skip to content

Commit 31a8b16

Browse files
committed
Define simple example CLI tool
1 parent ea7969a commit 31a8b16

File tree

2 files changed

+210
-0
lines changed

2 files changed

+210
-0
lines changed

Package.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ let package = Package(
2525
.target(
2626
name: "StructuredHeaders",
2727
dependencies: []),
28+
.target(
29+
name: "sh-parser",
30+
dependencies: ["StructuredHeaders"]),
2831
.testTarget(
2932
name: "StructuredHeadersTests",
3033
dependencies: ["StructuredHeaders"]),

Sources/sh-parser/main.swift

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the SwiftNIO open source project
4+
//
5+
// Copyright (c) 2020 Apple Inc. and the SwiftNIO project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import Foundation
16+
import StructuredHeaders
17+
18+
struct Flags {
19+
var headerType: HeaderType
20+
21+
init() {
22+
// Default to item
23+
self.headerType = .item
24+
25+
for argument in CommandLine.arguments.dropFirst() {
26+
switch argument {
27+
case "--dictionary":
28+
self.headerType = .dictionary
29+
30+
case "--list":
31+
self.headerType = .list
32+
33+
case "--item":
34+
self.headerType = .item
35+
36+
default:
37+
Self.helpAndExit()
38+
}
39+
}
40+
}
41+
42+
private static func helpAndExit() -> Never {
43+
print("Flags:")
44+
print("")
45+
print("\t--dictionary: Parse as dictionary field")
46+
print("\t--list: Parse as list field")
47+
print("\t--item: Parse as item field (default)")
48+
exit(2)
49+
}
50+
}
51+
52+
extension Flags {
53+
enum HeaderType {
54+
case dictionary
55+
case list
56+
case item
57+
}
58+
}
59+
60+
enum Header {
61+
case dictionary(OrderedMap<String, ItemOrInnerList<Data>>)
62+
case list([ItemOrInnerList<Data>])
63+
case item(Item<Data>)
64+
65+
func prettyPrint() {
66+
switch self {
67+
case .dictionary(let dict):
68+
print("- dictionary (\(dict.count) entries):")
69+
dict.prettyPrint(depth: 1)
70+
case .list(let list):
71+
print("- list (\(list.count) entries):")
72+
list.prettyPrint(depth: 1)
73+
case .item(let item):
74+
print("- item:")
75+
item.prettyPrint(depth: 1)
76+
}
77+
}
78+
}
79+
80+
extension Array where Element == ItemOrInnerList<Data> {
81+
func prettyPrint(depth: Int) {
82+
let tabs = String(repeating: "\t", count: depth)
83+
for (offset, element) in self.enumerated() {
84+
print("\(tabs)- [\(offset)]:")
85+
element.prettyPrint(depth: depth + 1)
86+
}
87+
}
88+
}
89+
90+
extension OrderedMap where Key == String, Value == ItemOrInnerList<Data> {
91+
func prettyPrint(depth: Int) {
92+
let tabs = String(repeating: "\t", count: depth)
93+
for (key, value) in self {
94+
print("\(tabs)- \(key):")
95+
value.prettyPrint(depth: depth + 1)
96+
}
97+
}
98+
}
99+
100+
extension OrderedMap where Key == String, Value == BareItem<Data> {
101+
func prettyPrint(depth: Int) {
102+
let tabs = String(repeating: "\t", count: depth)
103+
104+
for (key, value) in self {
105+
print("\(tabs)- \(key): \(value.prettyFormat())")
106+
}
107+
}
108+
}
109+
110+
extension ItemOrInnerList where BaseData == Data {
111+
func prettyPrint(depth: Int) {
112+
switch self {
113+
case .item(let item):
114+
item.prettyPrint(depth: depth)
115+
case .innerList(let list):
116+
list.prettyPrint(depth: depth)
117+
}
118+
}
119+
}
120+
121+
extension Item where BaseData == Data {
122+
func prettyPrint(depth: Int) {
123+
let tabs = String(repeating: "\t", count: depth)
124+
125+
print("\(tabs)- item: \(self.bareItem.prettyFormat())")
126+
print("\(tabs)- parameters (\(parameters.count) entries):")
127+
self.parameters.prettyPrint(depth: depth + 1)
128+
}
129+
}
130+
131+
extension InnerList where BaseData == Data {
132+
func prettyPrint(depth: Int) {
133+
let tabs = String(repeating: "\t", count: depth)
134+
135+
print("\(tabs)- innerList (\(parameters.count) entries):")
136+
self.bareInnerList.prettyPrint(depth: depth + 1)
137+
print("\(tabs)- parameters (\(parameters.count) entries):")
138+
self.parameters.prettyPrint(depth: depth + 1)
139+
}
140+
}
141+
142+
extension BareInnerList where BaseData == Data {
143+
func prettyPrint(depth: Int) {
144+
let tabs = String(repeating: "\t", count: depth)
145+
for (offset, element) in self.enumerated() {
146+
print("\(tabs)- [\(offset)]:")
147+
element.prettyPrint(depth: depth + 1)
148+
}
149+
}
150+
}
151+
152+
extension BareItem where BaseData == Data {
153+
func prettyFormat() -> String {
154+
switch self {
155+
case .bool(let bool):
156+
return "boolean \(bool)"
157+
case .integer(let int):
158+
return "integer \(int)"
159+
case .string(let string):
160+
return "string \"\(string)\""
161+
case .token(let token):
162+
return "token \(token)"
163+
case .undecodedByteSequence(let bytes):
164+
return "byte sequence \(bytes)"
165+
case .decimal(let decimal):
166+
let d = Decimal(sign: decimal.mantissa > 0 ? .plus : .minus,
167+
exponent: Int(decimal.exponent), significand: Decimal(decimal.mantissa))
168+
return "decimal \(d)"
169+
}
170+
}
171+
}
172+
173+
func main() {
174+
do {
175+
let flags = Flags()
176+
var data = FileHandle.standardInput.readDataToEndOfFile()
177+
178+
// We need to strip trailing newlines.
179+
var index = data.endIndex
180+
while index > data.startIndex {
181+
data.formIndex(before: &index)
182+
if data[index] != UInt8(ascii: "\n") {
183+
break
184+
}
185+
}
186+
data = data[...index]
187+
var parser = StructuredFieldParser(data)
188+
189+
let result: Header
190+
switch flags.headerType {
191+
case .dictionary:
192+
result = .dictionary(try parser.parseDictionaryField())
193+
case .list:
194+
result = .list(try parser.parseListField())
195+
case .item:
196+
result = .item(try parser.parseItemField())
197+
}
198+
199+
result.prettyPrint()
200+
} catch {
201+
print("error: \(error)")
202+
exit(1)
203+
}
204+
}
205+
206+
main()
207+

0 commit comments

Comments
 (0)