]> git.buserror.net Git - polintos/scott/priv.git/blob - idlcomp/output.cc
Add copyright to idlcomp files that were previously just "Written by:".
[polintos/scott/priv.git] / idlcomp / output.cc
1 // Code to output symbols to a legacy filesystem
2 //
3 // This software is copyright (c) 2006 Scott Wood <scott@buserror.net>.
4 // 
5 // Permission is hereby granted, free of charge, to any person obtaining a copy of
6 // this software and associated documentation files (the "Software"), to deal with
7 // the Software without restriction, including without limitation the rights to
8 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9 // of the Software, and to permit persons to whom the Software is furnished to do
10 // so, subject to the following condition:
11 // 
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
14 // 
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18 // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
21 // SOFTWARE.
22
23 #include <cstring>
24 #include <cerrno>
25 #include <vector>
26 #include <memory>
27 #include <cctype>
28
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32
33 #include <idlc.h>
34 #include <parser.h>
35
36 static string *map_sym(const char *root, Symbol *sym)
37 {
38         typedef std::vector<StringRef> StringVec;
39         StringVec path;
40         
41         while (sym && sym != output_ns && sym->name) {
42                 const String *name = NameSpace::mangle(sym->name);
43                 path.push_back(name);
44                 sym = sym->get_ns();
45         }
46         
47         return stringvec_to_path(path, root);
48 }
49
50 string *stringvec_to_path(StringVec &stringvec, const char *prepend)
51 {
52         string *s = new string();
53         
54         if (prepend)
55                 *s += string(prepend);
56
57         for (StringVec::reverse_iterator i = stringvec.rbegin();
58              i != stringvec.rend(); ++i)
59         {
60                 *s += '/';
61                 *s += *i;
62         }
63         
64         return s;
65 }
66
67 void NameSpace::output(const char *root)
68 {
69         std::auto_ptr<string> path(map_sym(root, this));
70
71         if (mkdir(path->c_str(), 0777) && errno != EEXIST) {
72                 fprintf(stderr, "Cannot create directory \"%s\": %s.\n",
73                         path->c_str(), strerror(errno));
74
75                 throw UserError();
76         }
77
78         for (tbl_type::iterator i = tbl.begin(); i != tbl.end(); ++i) {
79                 Symbol *sym = (*i).second;
80
81                 if (!sym->priv)
82                         sym->output(root);
83         }
84 }
85
86 void Def::output_self(const char *root, Symbol *sym, bool dir)
87 {
88         std::auto_ptr<string> path(map_sym(root, sym));
89
90         if (dir)
91                 *path += "/.self";
92         
93         int fd = open(path->c_str(), O_CREAT | O_EXCL | O_WRONLY, 0666);
94         if (fd < 0) {
95                 fprintf(stderr, "Cannot create file \"%s\": %s.\n",
96                         path->c_str(), strerror(errno));
97
98                 throw UserError();
99         }
100         
101         // open() is used so that O_EXCL can be specified, but 
102         // fwrite is used for buffering.
103         File f = fdopen(fd, "wb");
104         if (!f) {
105                 fprintf(stderr, "Cannot fdopen \"%s\": %s.\n",
106                         path->c_str(), strerror(errno));
107
108                 BUG();
109         }
110
111         if (fwrite(&hdr, sizeof(hdr), 1, f) != 1)
112                 goto err;
113         if (fwrite(self, self_len, 1, f) != 1)
114                 goto err;
115         if (!output_extra(f))
116                 goto err;
117
118         return;
119         
120 err:
121         fprintf(stderr, "Cannot write to file \"%s\": %s.\n",
122                 path->c_str(), strerror(ferror(f)));
123
124         throw UserError();
125 }
126
127 template<typename T, bool namespace_qual>
128 bool output_list(list<T> &entries, int count, FILE *f)
129 {
130         int index = 0;
131
132         for (typename list<T>::iterator i = entries.begin();
133              i != entries.end(); ++i)
134         {
135                 StringRef s;
136                 
137                 if (index >= count)
138                         BUG();
139                 
140                 if (namespace_qual)
141                         s = (*i)->get_fq_name()->flatten();
142                 else
143                         s = (*i)->name;
144                         
145                 int32_t len = s->length();
146
147                 if (fwrite(&len, sizeof(len), 1, f) != 1)
148                         return false;
149                 
150                 if (fwrite(s->c_str(), len + 1, 1, f) != 1)
151                         return false;
152                 
153                 // Make sure the next string's byte count is aligned on a
154                 // 4-byte boundary.  Len now includes the null.
155                 
156                 len++;
157
158                 int pad = ((len + 3) & ~3) - len;
159                 int32_t zero = 0;
160                 
161                 if (pad && fwrite(&zero, pad, 1, f) != 1)
162                         return false;
163                 
164                 index++;
165         }
166         
167         if (index != count)
168                 BUG();
169         
170         return true;
171 }
172
173 void Enum::output(const char *root)
174 {
175         NameSpace::output(root);
176         output_self(root, this, true);
177 }
178
179 bool Enum::output_extra(FILE *f)
180 {
181         return output_list<DatumRef, false>(entries, def.num_entries, f);
182 }
183
184 void Interface::output(const char *root)
185 {
186         NameSpace::output(root);
187         output_self(root, this, true);
188 }
189
190 bool Interface::output_extra(FILE *f)
191 {
192         return output_list<MethodRef, false>(methods, def.num_methods, f) &&
193                output_list<InterfaceRef, true>(supers, def.num_supers, f);      
194 }
195
196 void Method::output(const char *root)
197 {
198         NameSpace::output(root);
199         output_self(root, this, true);
200 }
201
202 bool Method::output_extra(FILE *f)
203 {
204         return output_list<ParamRef, false>(entries, def.num_entries, f);
205 }
206
207 void Param::output(const char *root)
208 {
209         output_self(root, this, false);
210 }
211
212 bool Param::output_extra(FILE *f)
213 {
214         if (!basic)
215                 return fwrite(type_fq_name->c_str(), def.type.length + 1, 1, f) == 1;
216         else
217                 return true;
218 }
219
220 void Struct::output(const char *root)
221 {
222         NameSpace::output(root);
223         output_self(root, this, true);
224 }
225
226 bool Struct::output_extra(FILE *f)
227 {
228         if (!output_list<DatumRef, false>(entries, def.num_entries, f))
229                 return false;
230
231         if (super) {
232                 list<Struct *> superlist;
233                 superlist.push_back(super);
234                 return output_list<Struct *, true>(superlist, 1, f);
235         }
236         
237         return true;
238 }
239
240 void BitField::output(const char *root)
241 {
242         NameSpace::output(root);
243         output_self(root, this, true);
244 }
245
246 bool BitField::output_extra(FILE *f)
247 {
248         return output_list<DatumRef, false>(entries, def.num_entries, f);
249 }
250
251 void Datum::output(const char *root)
252 {
253         if (def.flags.field.Const && !const_init) {
254                 resolve_constant_chain();
255         
256                 if (!const_init)
257                         throw UserError();
258         }
259
260         output_self(root, this, false);
261 }
262
263 bool Datum::output_extra(FILE *f)
264 {
265         if (!basic)
266                 return fwrite(type_fq_name->c_str(), def.type.length + 1, 1, f) == 1;
267         else
268                 return true;
269 }
270
271 void BasicType::output(const char *root)
272 {
273         if (!complete)
274                 BUG();
275
276         output_self(root, this, false);
277 }
278
279 void Alias::output(const char *root)
280 {
281         output_self(root, this, false);
282 }
283
284 bool Alias::output_extra(FILE *f)
285 {
286         return fwrite(sym_fq_name->c_str(), def.length + 1, 1, f) == 1;
287 }
288
289 void UserNameSpace::output(const char *root)
290 {
291         NameSpace::output(root);
292         output_self(root, this, true);
293 }
294
295 bool UserNameSpace::output_extra(FILE *f)
296 {
297         return fwrite(mountpoint_name->c_str(), def.length + 1, 1, f) == 1;
298 }