Skip to content

Commit 98803ab

Browse files
committed
added second tool + source reorg
1 parent 1633a3f commit 98803ab

File tree

8 files changed

+344
-67
lines changed

8 files changed

+344
-67
lines changed

README.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,7 @@
22
Various tools related to the Jacobin JVM project (see [jacobin.org](http://www.jacobin.org))
33

44
These include:
5-
* **gob2csv** which converts the .gob file creates of the classes in the JDK 17 distribution into a CSV file.
5+
* **gob2csv** - Converts the .gob file creates of the classes in the JDK 17 distribution into a CSV file format on standard output.
6+
* **cleansrc** - Cleans source files of non-displayable characters with options for replacement and deletion.
7+
8+
The jacobin tools are installed by executing ```install.sh``` (Linux, MacOS, and Unix) or ```install.bat``` (Windows). After compilation, they reside in ```$GOPATH/bin```. It is recommended that ```$GOPATH/bin``` be an element of the user's executable PATH.

gob2csv/go.mod

-3
This file was deleted.

gob2csv/gob2csv.go

-63
This file was deleted.

installer.bat

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
cd src
2+
go install -v ./...

installer.sh

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
cd src
2+
go install -v ./...

src/cleansrc/main.go

+253
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
/*
2+
3+
cleansrc utility - For a given input source code file, either show any invalid characters without modifying the file or fix it,
4+
depending on the command line options. Multiple input files can be specified as a list and/or wild-card specifications
5+
on the command line.
6+
7+
Valid source code characters: printable, \n, \r, or \t.
8+
9+
*/
10+
11+
package main
12+
13+
import (
14+
"encoding/hex"
15+
"fmt"
16+
"os"
17+
"path/filepath"
18+
"strings"
19+
"unicode"
20+
)
21+
22+
// Show help and then exit to the O/S
23+
func showHelp() {
24+
suffix := filepath.Base(os.Args[0])
25+
fmt.Printf("\nUsage: %s [-h] [-s <one-character> | -d] [-u] [-v] Input file(s)...\n\nwhere\n", suffix)
26+
fmt.Printf("\t-h : This display.\n")
27+
fmt.Printf("\t-s <one-character>: Substitute the specified character for invalid source characters.\n")
28+
fmt.Printf("\t CAUTION: This causes a rewrite of the input source code file.\n")
29+
fmt.Printf("\t Examples:\n")
30+
fmt.Printf("\t\t-s A --> The letter A is the substitute.\n")
31+
fmt.Printf("\t\t-s space --> The space character (' ') is the substitute.\n")
32+
fmt.Printf("\t\t-s tab --> The tab character ('\\t') is the substitute.\n")
33+
fmt.Printf("\t\t-s nl --> The newline character ('\\n') is the substitute.\n")
34+
fmt.Printf("\t\t-s cr --> The carriage return character ('\\r') is the substitute.\n")
35+
fmt.Printf("\t\t-s 0x23 --> The pound sign character ('#') is the substitute.\n")
36+
fmt.Printf("\t-d : Instead of replacing invalid source characters, delete them.\n")
37+
fmt.Printf("\t-u : Update the source file.\n")
38+
fmt.Printf("\t-v : Verbose output.\n")
39+
fmt.Printf("\nExit codes:\n")
40+
fmt.Printf("\t0\tNormal completion.\n")
41+
fmt.Printf("\t1\tSomething went wrong during execution.\n\n")
42+
os.Exit(1)
43+
}
44+
45+
// Is the argument byte valid?
46+
func isValidSrcByte(argByte byte) bool {
47+
if unicode.IsPrint(rune(argByte)) {
48+
return true
49+
}
50+
if argByte == '\n' || argByte == '\r' || argByte == '\t' {
51+
return true
52+
}
53+
return false
54+
}
55+
56+
/*
57+
Main function
58+
*/
59+
func main() {
60+
61+
var Args []string
62+
var flagSubstitute = false
63+
var flagDelete = false
64+
var flagUpdate = false
65+
var flagVerbose = false
66+
var nilByte = byte(0x00)
67+
var replByte = byte('?')
68+
var err error
69+
var inPathSet []string
70+
var inPath string
71+
modFileCount := 0
72+
errFileCount := 0
73+
74+
// Parse command line arguments.
75+
for _, singleVar := range os.Args[1:] {
76+
Args = append(Args, singleVar)
77+
}
78+
if len(Args) < 1 {
79+
showHelp()
80+
}
81+
for ii := 0; ii < len(Args); ii++ {
82+
if !strings.HasPrefix(Args[ii], "-") {
83+
inPath, err = filepath.Abs(Args[ii])
84+
if err != nil {
85+
fmt.Printf(fmt.Sprintf("Input file (%s) cannot be accessed: %s", Args[ii], err.Error()))
86+
showHelp()
87+
}
88+
inPathSet = append(inPathSet, inPath)
89+
continue
90+
}
91+
switch Args[ii] {
92+
case "-d":
93+
flagDelete = true
94+
case "-h":
95+
showHelp()
96+
case "-s":
97+
flagSubstitute = true
98+
ii += 1
99+
if Args[ii] == "space" {
100+
replByte = ' '
101+
break
102+
}
103+
if Args[ii] == "tab" {
104+
replByte = '\t'
105+
break
106+
}
107+
if Args[ii] == "nl" {
108+
replByte = '\n'
109+
break
110+
}
111+
if Args[ii] == "cr" {
112+
replByte = '\r'
113+
break
114+
}
115+
if strings.HasPrefix(Args[ii], "0x") {
116+
// Hexstring for one character: 0xn or 0xnn
117+
if len(Args[ii]) > 4 {
118+
fmt.Printf(fmt.Sprintf("-s %s value too large for one character", Args[ii]))
119+
showHelp()
120+
}
121+
decoded, err := hex.DecodeString(Args[ii][2:])
122+
if err != nil {
123+
fmt.Printf(fmt.Sprintf("-s %s is not hexidecimal (0xH or 0xHH where H is from 0123456789ABCDEFabcdef)", Args[ii]))
124+
showHelp()
125+
}
126+
replByte = decoded[0]
127+
if replByte == nilByte {
128+
fmt.Printf("-s 0x00 ---> invalid source characters will not be replaced but discarded (squeezed out)")
129+
}
130+
break
131+
}
132+
if len(Args[ii]) == 1 {
133+
replByte = Args[ii][0]
134+
break
135+
}
136+
fmt.Printf("Use -s to specify only ONE character")
137+
showHelp()
138+
case "-u":
139+
flagUpdate = true
140+
case "-v":
141+
flagVerbose = true
142+
default:
143+
fmt.Printf(fmt.Sprintf("Unrecognizable command option: %s", Args[ii]))
144+
showHelp()
145+
}
146+
}
147+
148+
// Check for contradiction.
149+
if flagDelete && flagSubstitute {
150+
fmt.Printf("-s and -d together makes no sense")
151+
showHelp()
152+
}
153+
154+
// Make sure that at least one input file path specification is present.
155+
if len(inPathSet) < 1 {
156+
fmt.Printf("At least one input file specification is required")
157+
showHelp()
158+
}
159+
160+
// For each input file path in the set, process it.
161+
for _, inPath := range inPathSet {
162+
163+
// Read entire input file contents.
164+
inBytes, err := os.ReadFile(inPath)
165+
if err != nil {
166+
errFileCount++
167+
errMsg := fmt.Sprintf("os.ReadFile(%s) failed: %s", inPath, err.Error())
168+
fmt.Printf(errMsg)
169+
continue
170+
}
171+
if flagVerbose {
172+
fmt.Printf("Read %d input characters from %s", len(inBytes), inPath)
173+
}
174+
175+
// Copy inBytes to outBytes.
176+
// Check outBytes for source code validity.
177+
// If a byte deviates, make a substitution or discard it.
178+
var outBytes = inBytes
179+
numTotalBytes := len(inBytes)
180+
numInvalidBytes := 0
181+
lineNum := 1
182+
offset := 0
183+
for ii := 0; ii < numTotalBytes; ii++ {
184+
if outBytes[ii] == '\n' {
185+
lineNum += 1
186+
offset = 0
187+
continue
188+
}
189+
if !isValidSrcByte(outBytes[ii]) {
190+
// Not a valid source code byte.
191+
nastyOne := outBytes[ii]
192+
numInvalidBytes += 1
193+
if flagDelete {
194+
// Discard byte.
195+
tempBytes := inBytes[:ii]
196+
outBytes = append(tempBytes, outBytes[ii+1:]...)
197+
numTotalBytes -= 1
198+
fmt.Printf("\t%s Line %d, offset %d: discarded 0x%x\n", inPath, lineNum, offset, nastyOne)
199+
} else {
200+
// Replace byte.
201+
outBytes[ii] = replByte
202+
fmt.Printf("\t%s Line %d, offset %d: replaced 0x%x with 0x%x\n", inPath, lineNum, offset, nastyOne, replByte)
203+
}
204+
}
205+
offset += 1
206+
}
207+
208+
// If clean input file, continue to next file.
209+
if numInvalidBytes < 1 {
210+
fmt.Printf("Clean input source code file: %s", inPath)
211+
continue
212+
}
213+
if flagVerbose {
214+
// Report how many invalid source file characters were detected.
215+
fmt.Printf("Detected %d invalid source file character(s) in %s", numInvalidBytes, inPath)
216+
}
217+
218+
// If not rewriting the input file, continue to next file.
219+
if !flagSubstitute && !flagDelete {
220+
continue
221+
}
222+
223+
// Replace input file contents with outBytes.
224+
if flagUpdate {
225+
err = os.WriteFile(inPath, outBytes, 0666)
226+
if err != nil {
227+
errFileCount++
228+
errMsg := fmt.Sprintf("os.WriteFile (%s) failed: %s", inPath, err.Error())
229+
fmt.Printf(errMsg)
230+
continue
231+
}
232+
modFileCount += 1
233+
if flagVerbose {
234+
fmt.Printf("Wrote %d output characters to %s", len(outBytes), inPath)
235+
}
236+
}
237+
}
238+
239+
// Done with input source files.
240+
// Return 1 to O/S if any errors were diagnosed.
241+
// Else, return 0.
242+
if errFileCount > 0 {
243+
fmt.Printf("%d input file(s) had I/O errors", errFileCount)
244+
os.Exit(1)
245+
}
246+
if modFileCount > 0 {
247+
fmt.Printf("%d input file(s) were modified", modFileCount)
248+
} else {
249+
fmt.Printf("No input file(s) were modified")
250+
}
251+
os.Exit(0)
252+
253+
}

src/go.mod

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module src
2+
3+
go 1.21.4

0 commit comments

Comments
 (0)