blob: 3477e94da33854fff9a5b08a1e6c9b37bf36771c [file] [log] [blame]
// Copyright 2017 The Wuffs Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build ignore
package main
// inline-c-relative-includes.go echoes the given C file to stdout, expanding
// #include lines that uses "quoted files" (but not <bracketed files>).
//
// The output should be a stand-alone C file that other people can easily
// compile and run with no further dependencies, other than test/data files.
//
// Usage: go run inline-c-relative-includes.go path/to/foo.c
import (
"bufio"
"bytes"
"fmt"
"os"
"path/filepath"
)
func main() {
if err := main1(); err != nil {
os.Stderr.WriteString(err.Error() + "\n")
os.Exit(1)
}
}
func main1() error {
if len(os.Args) != 2 {
return fmt.Errorf("inline-c-relative-includes takes exactly 1 argument")
}
w := bufio.NewWriter(os.Stdout)
defer w.Flush()
return do(w, ".", os.Args[1], 0)
}
var (
prefix = []byte(`#include "`)
suffix = []byte(`"`)
seen = map[string]bool{}
)
func do(w *bufio.Writer, dir string, filename string, depth int) error {
if depth == 100 {
return fmt.Errorf("recursion too deep")
}
if depth != 0 {
fmt.Fprintf(w, "// BEGIN INLINE #include %q\n", filename)
defer fmt.Fprintf(w, "// END INLINE #include %q\n", filename)
}
depth++
filename = filepath.Join(dir, filename)
if seen[filename] {
return fmt.Errorf("duplicate filename %q", filename)
}
seen[filename] = true
dir, _ = filepath.Split(filename)
f, err := os.Open(filename)
if err != nil {
return err
}
defer f.Close()
r := bufio.NewScanner(f)
for r.Scan() {
line := r.Bytes()
if s := line; bytes.HasPrefix(s, prefix) {
s = s[len(prefix):]
if bytes.HasSuffix(s, suffix) {
s = s[:len(s)-len(suffix)]
if err := do(w, dir, string(s), depth); err == nil {
continue
} else if os.IsNotExist(err) {
// This is probably an #include of a system header, like
// `#include "zlib.h"`, and not of Wuffs code. Fall through
// and print the #include line as normal.
} else {
return err
}
}
}
w.Write(line)
w.WriteByte('\n')
}
return r.Err()
}