Skip to content

Commit 1acfc15

Browse files
committed
Java Quelltextgenerierung für die deutsche Lohnsteuerberechnung anhand der vom ITZBund bereitgestellten XML Dokumente
0 parents  commit 1acfc15

65 files changed

Lines changed: 61936 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.DS_Store
2+
/.build
3+
/.swiftpm
4+
/Packages
5+
xcuserdata/
6+
DerivedData/
7+
.swiftpm/configuration/registries.json
8+
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
9+
.netrc

LICENSE

Lines changed: 661 additions & 0 deletions
Large diffs are not rendered by default.

Package.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// swift-tools-version: 5.9
2+
// The swift-tools-version declares the minimum version of Swift required to build this package.
3+
4+
import PackageDescription
5+
6+
let package = Package(
7+
name: "LStXML2Code",
8+
platforms: [.macOS(.v13)],
9+
products: [
10+
// Products define the executables and libraries a package produces, making them visible to other packages.
11+
.library(
12+
name: "LStXML2Code",
13+
targets: ["LStXML2Code"]),
14+
.executable(name: "BMF2Code", targets: ["BMF2Code"])
15+
],
16+
targets: [
17+
// Targets are the basic building blocks of a package, defining a module or a test suite.
18+
// Targets can depend on other targets in this package and products from dependencies.
19+
.target(
20+
name: "LStXML2Code"),
21+
.testTarget(
22+
name: "LStXML2CodeTests",
23+
dependencies: ["LStXML2Code"]),
24+
.executableTarget(
25+
name: "BMF2Code",
26+
dependencies: ["LStXML2Code"]),
27+
]
28+
)

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# LStXML2Code
2+
3+
Program is inspired by nice project https://github.com/MarcelLehmann/Lohnsteuer/forks but implemented in Swift and a side project because I want a LSt implementation for an other project.
4+
5+
## License
6+
7+
8+
## CLI
9+
10+
```bash
11+
swift run -c release BMF2Code --lang=Java -o test.txt ./Tests/LStXML2CodeTests/xml/Lohnsteuer2023AbJuli.xml
12+
```
13+
14+
Do not run in DEBUG mode.

Sources/BMF2Code/BMF2Code.swift

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2023 - Sebastian Ritter <bastie@users.noreply.github.com>
3+
* SPDX-License-Identifier: AGPL-3.0-or-later
4+
*/
5+
import Foundation
6+
import LStXML2Code
7+
8+
@main
9+
public struct BMF2Code {
10+
11+
private static let VERSION = "0.1.0"
12+
13+
14+
// MARK: main entry point
15+
static func main () {
16+
var cmdLineArgs = CommandLine.arguments
17+
#if DEBUG
18+
debugPrint(cmdLineArgs)
19+
// if run in xcode use invocation instead of xcode edit scheme
20+
if let _ = ProcessInfo().environment["__XCODE_BUILT_PRODUCTS_DIR_PATHS"] {
21+
let documents = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].path()
22+
let project = "workspace/LStXML2Code/"
23+
let xmls = "Tests/LStXML2CodeTests/xml/"
24+
let test = "Lohnsteuer2023AbJuli.xml"
25+
let lang = "Java"
26+
cmdLineArgs = [CommandLine.arguments[0],"lang=\(lang)","\(documents)\(project)\(xmls)\(test)"]
27+
}
28+
#endif
29+
let prg = BMF2Code()
30+
let runtimeParameter = prg.evalArgs(arguments: cmdLineArgs)
31+
32+
if let stopNow = runtimeParameter["skipRunning"]{
33+
if stopNow == "true" {
34+
exit(0)
35+
}
36+
}
37+
38+
do {
39+
let source = runtimeParameter["in"]!
40+
41+
let sourceURL : URL? = source.starts(with: "https://") ? URL(string: source) : URL(filePath: source)
42+
43+
// TODO: checkResourceIsReachable with Swift 5.9 only implemented for file system - implement something for other protocols to support these
44+
// URL ist reachable?
45+
guard ((try? sourceURL?.checkResourceIsReachable()) != nil) else {
46+
print ("Input not exist \(source)")
47+
_ = exit(3)
48+
}
49+
50+
let input = try Data(contentsOf: sourceURL!)
51+
let ast = XmlPAP.parse(xmlData: input)
52+
53+
let encoder = switch runtimeParameter["lang"] {
54+
case "java" : AbstractTreeEncoder(encoding:JavaEncoding())
55+
case "swift": AbstractTreeEncoder(encoding:SwiftEncoding())
56+
default:
57+
AbstractTreeEncoder(encoding:JavaEncoding())
58+
}
59+
let encodedData = try encoder.encode(ast)
60+
if let encodedString = String (data: encodedData, encoding: .utf8) {
61+
if let outputFileName = runtimeParameter["out"] {
62+
try encodedString.write(to: URL(filePath: outputFileName), atomically: true, encoding: String.Encoding.utf8)
63+
}
64+
else {
65+
print("\(encodedString)")
66+
}
67+
}
68+
else {
69+
fatalError("@encoding")
70+
}
71+
}
72+
catch {
73+
print ("Unknown error")
74+
exit(255)
75+
}
76+
}
77+
78+
79+
// MARK: handling argument
80+
// handwritten parameter evaluation
81+
func evalArgs (arguments : [String], reversedCall : Bool = false) -> [String:String] {
82+
let supportedLang = ["java"]//, "swift"]
83+
let supportedLanguages = "\(supportedLang)".replacingOccurrences(of: "[", with: "").replacingOccurrences(of: "]", with: "").replacingOccurrences(of: "\"", with: "")
84+
85+
var result : [String:String] = [:]
86+
87+
let args = splitArgs(arguments: arguments)
88+
89+
for var index in 1..<args.count {
90+
let arg = args[index]
91+
switch true {
92+
case arg == "-H" :
93+
print ("""
94+
Return codes:
95+
0 = ok
96+
1 = argument -o without follow parameter
97+
2 = unsupported programming language, accepted:
98+
\(supportedLanguages)
99+
3 = missing input
100+
255 = not specific error
101+
""")
102+
break
103+
case arg == "--help" || arg == "-h" :
104+
_ = evalArgs(arguments: [args[0],"-V"],reversedCall: true)
105+
var prgName = CommandLine.arguments[0].split(separator: "/").last!
106+
prgName = CommandLine.arguments[0].split(separator: "\\").last!
107+
print ("""
108+
109+
Usage:
110+
\(prgName) [-HhVvo output] [--lang=<name>] input
111+
112+
Arguments:
113+
-H = print RC of programm
114+
-h --help = print this help and exit
115+
--lang=<name> = target output for programming language <name>
116+
supported: \(supportedLanguages)
117+
-o <name> = print output in file named <name>
118+
-v --version = short version string
119+
-V = long version string
120+
121+
""")
122+
_ = evalArgs(arguments: [args[0],"-H"],reversedCall: true)
123+
result["skipRunning"] = "true"
124+
case arg.starts(with: "--lang=") :
125+
let actuallyLang = arg.split(separator: "=")[1].lowercased()
126+
guard supportedLang.contains(actuallyLang) else {
127+
print ("Argument --lang accepts only \(supportedLang)".replacingOccurrences(of: "[", with: "").replacingOccurrences(of: "]", with: ""))
128+
_ = exit(2)
129+
}
130+
result ["lang"] = actuallyLang
131+
break
132+
case arg == "-o" :
133+
index += 1
134+
guard index < args.count else {
135+
print ("Argument -o need parameter with target file")
136+
_ = exit(1)
137+
}
138+
result ["out"] = args[index]
139+
break
140+
case arg == "-v" || arg == "--version" :
141+
print("""
142+
BMF2Code v\(BMF2Code.VERSION)
143+
""")
144+
break
145+
case arg == "-V" :
146+
print("""
147+
BMF2Code v\(BMF2Code.VERSION)
148+
Copyright:\t\t Copyright © 2023 Sebastian Ritter
149+
Home:\t\t\t https://github.com/bastie
150+
License:\t\t MIT
151+
Started executable:\t \(args[0])
152+
""")
153+
default :
154+
break
155+
}
156+
}
157+
158+
if (!reversedCall) {
159+
// check for input file
160+
guard args.count > 1 else {
161+
print ("Missing input file name")
162+
_ = exit (3)
163+
}
164+
guard !["-o"].contains(args[args.count - 1]) else {
165+
print ("Missing input file name at end")
166+
_ = exit(3)
167+
}
168+
guard !args[args.count - 1].starts(with: "-") else {
169+
print ("Missing input file name at end.")
170+
_ = exit(3)
171+
}
172+
// set input file
173+
result["in"] = args[args.count-1]
174+
175+
// check default runtime values
176+
// check for missing default language
177+
if !result.keys.contains("lang") {
178+
result["lang"] = "java"
179+
}
180+
}
181+
return result
182+
}
183+
184+
/// Separate concatenated short arguments
185+
/// - Parameters:
186+
/// - Parameter arguments as String array
187+
/// - Returns arguments as String array
188+
func splitArgs (arguments : [String]) -> [String]{
189+
var result : [String] = []
190+
for arg in arguments {
191+
// long argument
192+
if arg.starts(with: "--") {
193+
result.append(arg)
194+
}
195+
// short argument
196+
else if arg.starts(with: "-") {
197+
// concatenated arguments
198+
if arg.count > 2 {
199+
arg.enumerated().forEach {
200+
offset, next in
201+
if offset > 0 {
202+
result.append("-\(next)")
203+
}
204+
}
205+
}
206+
else {
207+
result.append(arg)
208+
}
209+
}
210+
// untyped argument
211+
else {
212+
result.append(arg)
213+
}
214+
}
215+
return result
216+
}
217+
218+
}
219+
220+

0 commit comments

Comments
 (0)