blob: f4f35d58dabc5a263a82218dd66f1cb02d41b4ea [file] [log] [blame]
Nigel Tao79a94552017-11-30 16:37:20 +11001// Copyright 2017 The Wuffs Authors.
Nigel Taoe57c8d72017-11-03 15:05:19 +11002//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// +build ignore
16
17package main
18
19// inline-c-relative-includes.go echoes the given C file to stdout, expanding
20// #include lines that uses "quoted files" (but not <bracketed files>).
21//
22// The output should be a stand-alone C file that other people can easily
23// compile and run with no further dependencies, other than testdata files.
24//
25// Usage: go run inline-c-relative-includes.go path/to/foo.c
26
27import (
28 "bufio"
29 "bytes"
30 "fmt"
31 "os"
32 "path/filepath"
33)
34
35func main() {
36 if err := main1(); err != nil {
37 os.Stderr.WriteString(err.Error() + "\n")
38 os.Exit(1)
39 }
40}
41
42func main1() error {
43 if len(os.Args) != 2 {
44 return fmt.Errorf("inline-c-relative-includes takes exactly 1 argument")
45 }
46 w := bufio.NewWriter(os.Stdout)
47 defer w.Flush()
48 return do(w, ".", os.Args[1], 0)
49}
50
51var (
52 prefix = []byte(`#include "`)
53 suffix = []byte(`"`)
54
55 seen = map[string]bool{}
56)
57
58func do(w *bufio.Writer, dir string, filename string, depth int) error {
59 if depth == 100 {
60 return fmt.Errorf("recursion too deep")
61 }
62 if depth != 0 {
63 fmt.Fprintf(w, "// BEGIN INLINE #include %q\n", filename)
64 defer fmt.Fprintf(w, "// END INLINE #include %q\n", filename)
65 }
66 depth++
67
68 filename = filepath.Join(dir, filename)
69 if seen[filename] {
70 return fmt.Errorf("duplicate filename %q", filename)
71 }
72 seen[filename] = true
73
74 dir, _ = filepath.Split(filename)
75 f, err := os.Open(filename)
76 if err != nil {
77 return err
78 }
79 defer f.Close()
80
81 r := bufio.NewScanner(f)
82 for r.Scan() {
Nigel Taoe3643572017-11-03 15:33:23 +110083 line := r.Bytes()
Nigel Taoe57c8d72017-11-03 15:05:19 +110084
Nigel Taoe3643572017-11-03 15:33:23 +110085 if s := line; bytes.HasPrefix(s, prefix) {
Nigel Taoe57c8d72017-11-03 15:05:19 +110086 s = s[len(prefix):]
87 if bytes.HasSuffix(s, suffix) {
88 s = s[:len(s)-len(suffix)]
89 if err := do(w, dir, string(s), depth); err == nil {
90 continue
91 } else if os.IsNotExist(err) {
92 // This is probably an #include of a system header, like
93 // `#include "zlib.h"`, and not of Puffs code. Fall through
94 // and print the #include line as normal.
95 } else {
96 return err
97 }
98 }
99 }
100
Nigel Taoe3643572017-11-03 15:33:23 +1100101 w.Write(line)
Nigel Taoe57c8d72017-11-03 15:05:19 +1100102 w.WriteByte('\n')
103 }
104 return r.Err()
105}