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