1// Copyright 2017 The Wuffs Authors. 2// 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 test/data 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() { 83 line := r.Bytes() 84 85 if s := line; bytes.HasPrefix(s, prefix) { 86 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 Wuffs code. Fall through 94 // and print the #include line as normal. 95 } else { 96 return err 97 } 98 } 99 } 100 101 w.Write(line) 102 w.WriteByte('\n') 103 } 104 return r.Err() 105} 106