• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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