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