1 // Code to load symbols from a legacy filesystem
3 // This software is copyright (c) 2006 Scott Wood <scott@buserror.net>.
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:
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
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
34 // To deal with namespaces on a case-insensitive filesystem, names
35 // are annotated with a hexadecimal prefix indicating the case of each
36 // letter. Each bit in the number represents a letter, with 0 being
37 // lowercase (or a non-letter) and 1 being uppercase. The
38 // least-significant bit is the first letter. This is done on both
39 // case sensitive and case insensitive filesystems so that the output
40 // can be freely copied between them (it also simplifies the code).
41 // As such, hex digits should be in upper case so that case-sensitive
42 // lookups can be used. This prefix is separated from the actual name
45 // When the time comes along that UTF-8 is supported, this applies to
46 // UTF-8 characters, not ASCII characters.
48 // This mangling can also be used (with a leading underscore or
49 // whatever) in case-insensitive languages, though ideally there
50 // should be aliases with the unannotated name if there is no
53 // I don't want to go the CORBA route of disallowing case conflicts,
54 // as I find using capitals for types and lowercase for instances to
55 // be a useful convention (and less ugly than appending _t, except
56 // when case sensitivity is missing), and would rather not be limited
57 // at such a fundamental level by broken languages.
59 static char tohex(int digit)
64 return digit + 'A' - 10;
67 const String *NameSpace::mangle(const String *name)
69 String *mangled_string = new String;
71 // The conversion is done manually so that I don't have to deal
72 // with bignum arithmetic.
74 std::vector<bool> hex;
75 std::vector<bool>::size_type name_len = name->length();
77 // Pad out the first digit with leading zeroes, so that
78 // we don't have to deal with that later.
81 for (int i = name_len & 3; i < 4; ++i)
84 for (string::const_iterator i = name->begin(); i != name->end(); ++i)
85 hex.push_back(isupper(*i));
87 assert((hex.size() & 3) == 0);
89 for (std::vector<bool>::size_type i = 0; i < hex.size(); i += 4) {
90 int digit = hex[i] * 8 +
95 *mangled_string += tohex(digit);
98 *mangled_string += '_';
99 *mangled_string += *name;
100 return mangled_string;
110 msg = strerror(ferror(f));
116 struct ImportContext {
118 const char *filename;
124 CompiledDefHeader hdr;
127 static void import_and_validate_array(ImportContext &ctx,
131 out.bounds[0] = swap64(in.bounds[0], ctx.swap);
132 out.bounds[1] = swap64(in.bounds[1], ctx.swap);
134 if (out.bounds[0] < 0) {
135 fprintf(stderr, "\"%s\" is not a valid object "
136 "(bad array lower bound %" PRId64 ").\n",
137 ctx.filename, out.bounds[0]);
141 if (out.bounds[1] < -1) {
142 fprintf(stderr, "\"%s\" is not a valid object "
143 "(bad array upper bound %" PRId64 ").\n",
144 ctx.filename, out.bounds[0]);
148 if (out.bounds[1] > 0 &&
149 out.bounds[1] < out.bounds[0]) {
150 fprintf(stderr, "\"%s\" is not a valid object "
151 "(array upper bound %" PRId64 " less than lower bound %" PRId64 ").\n",
152 ctx.filename, out.bounds[1], out.bounds[0]);
157 static void import_and_validate_basictype(ImportContext &ctx,
158 CompiledBasicType &out,
159 CompiledBasicType &in)
161 out.bits = swap32(in.bits, ctx.swap);
162 out.flags.raw = swap32(in.flags.raw, ctx.swap);
165 if (out.flags.field.Unsigned)
167 if (out.flags.field.Float)
169 if (out.flags.field.Bool)
172 fprintf(stderr, "\"%s\" is not a valid object "
173 "(bad flags 0x%08x).\n",
174 ctx.filename, out.flags.raw);
178 if (out.flags.field.Bool) {
180 fprintf(stderr, "\"%s\" is not a valid object "
181 "(bad bits %d for bool type).\n",
182 ctx.filename, out.bits);
185 } else if (out.flags.field.Float) {
186 if (out.bits != 32 && out.bits != 64) {
187 fprintf(stderr, "\"%s\" is not a valid object "
188 "(bad bits %d for floating point type).\n",
189 ctx.filename, out.bits);
192 } else if (!dynamic_cast<BitField *>(ctx.parent) &&
193 !dynamic_cast<Enum *>(ctx.parent)) {
194 if (out.bits != 8 && out.bits != 16 &&
195 out.bits != 32 && out.bits != 64) {
196 fprintf(stderr, "\"%s\" is not a valid object "
197 "(bad bits %d for integer type).\n",
198 ctx.filename, out.bits);
202 if (out.bits == 8 && !out.flags.field.Unsigned) {
203 fprintf(stderr, "\"%s\" is not a valid object "
204 "(octet type must be unsigned).\n",
210 // Bitfield entries can take anywhere from 1 to 64 bits, but
211 // will be verified by the parent after all entries have loaded,
212 // so it can verify that the sum does not exceed the size of
215 import_and_validate_array(ctx, out.array, in.array);
218 BasicType *BasicType::import(ImportContext &ctx)
221 fprintf(stderr, "\"%s\" is not a valid object "
222 "(a BasicType must be a file).\n",
227 CompiledBasicType def;
228 if (fread(&def, sizeof(def), 1, ctx.f) != 1)
229 throw IOError(ctx.f);
231 BasicType *bt = new BasicType(ctx.name);
232 ctx.parent->add_import(bt, ctx.filename);
234 import_and_validate_basictype(ctx, bt->def, def);
240 static String *read_string_raw(ImportContext &ctx, int32_t length)
242 if (length < 0 || length > 4096) {
243 fprintf(stderr, "\"%s\" is not a valid object "
244 "(unreasonable string length %d).\n",
245 ctx.filename, length);
249 // Is there a way to reserve space in a C++ string, and pass
250 // the buffer into fread?
252 char *buf = new char[length + 1];
254 if (fread(buf, length + 1, 1, ctx.f) != 1)
255 throw IOError(ctx.f);
257 String *s = new String(buf);
262 static const String *read_string(ImportContext &ctx)
264 off_t pos = ftello(ctx.f);
265 int pad = ((pos + 3) & ~3) - pos;
267 if (pad != 0 && fseeko(ctx.f, pad, SEEK_CUR) != 0)
268 throw IOError(ctx.f);
271 if (fread(&length, sizeof(length), 1, ctx.f) != 1)
272 throw IOError(ctx.f);
274 return read_string_raw(ctx, swap32(length, ctx.swap));
277 StrList::StrList(const String *input, char delimeter)
279 const char *cur = input->c_str();
282 char *next = strchr(cur, delimeter);
283 String *s = new String();
284 s->token = TOK_IDENT;
286 if (next == cur || *cur == 0)
287 throw InvalidArgument();
290 s->append(cur, next - cur);
301 // FIXME: Handle illegal recursion.
302 static Symbol *lookup_sym_noyyerror(ImportContext &ctx, const String *name)
307 sl = new StrList(name);
310 catch (InvalidArgument) {
311 fprintf(stderr, "\"%s\" is not a valid object "
312 "(\"%s\" is not a valid identifier).\n",
313 ctx.filename, name->c_str());
318 return lookup_sym(toplevel, sl, toplevel);
322 fprintf(stderr, "\"%s\" is not a valid object "
323 "(\"%s\" could not be loaded).\n",
324 ctx.filename, name->c_str());
330 // FIXME: Handle illegal recursion.
331 static Symbol *lookup_sym_in_ns_noyyerror(ImportContext &ctx,
335 Symbol *sym = ns->lookup_noex(name);
337 fprintf(stderr, "\"%s\" is not a valid object "
338 "(\"%s\" is not found).\n",
339 ctx.filename, name->c_str());
347 Datum *Datum::import(ImportContext &ctx)
350 fprintf(stderr, "\"%s\" is not a valid object "
351 "(a Datum must be a file).\n",
357 if (fread(&def, sizeof(def), 1, ctx.f) != 1)
358 throw IOError(ctx.f);
360 Datum *d = new Datum(ctx.name);
361 d->def.flags.raw = swap32(def.flags.raw, ctx.swap);
363 if (d->def.flags.field.Invalid) {
364 fprintf(stderr, "\"%s\" is not a valid object "
365 "(bad flags 0x%08x).\n",
366 ctx.filename, d->def.flags.raw);
370 ctx.parent->add_import(d, ctx.filename);
372 d->def.type.length = swap32(def.type.length, ctx.swap);
374 if (d->def.type.length != 0) {
375 d->type_fq_name = read_string_raw(ctx, d->def.type.length);
376 Symbol *sym = lookup_sym_noyyerror(ctx, d->type_fq_name);
377 d->type = dynamic_cast<Type *>(sym);
380 fprintf(stderr, "\"%s\" is not a valid object "
381 "(\"%s\" is not a type).\n",
382 ctx.filename, d->type_fq_name->c_str());
386 import_and_validate_array(ctx, d->def.basictype.array,
387 def.basictype.array);
389 BasicType *bt = dynamic_cast<BasicType *>(*d->type);
396 import_and_validate_basictype(ctx, d->def.basictype,
398 d->cbt = &d->def.basictype;
401 d->def.ucon = swap64(def.ucon, ctx.swap);
403 if (d->def.flags.field.Const) {
405 fprintf(stderr, "\"%s\" is not a valid object "
406 "(constant, but non-basic type).\n",
411 if (d->cbt->flags.field.Float)
412 d->con_type = TOK_FCON;
413 else if (!d->cbt->flags.field.Unsigned)
414 d->con_type = TOK_ICON;
416 d->con_type = TOK_UCON;
418 if (!d->verify_const()) {
419 fprintf(stderr, "\"%s\" is not a valid object "
425 d->con_type = TOK_NONE;
431 // OPT: Importing methods and supers isn't necessary for idlc to
432 // work; it could be made optional to speed up large compilations.
434 Interface *Interface::import(ImportContext &ctx)
437 fprintf(stderr, "\"%s\" is not a valid object "
438 "(an Interface must be a directory).\n",
443 CompiledInterface def;
444 if (fread(&def, sizeof(def), 1, ctx.f) != 1)
445 throw IOError(ctx.f);
447 Interface *iface = new Interface(ctx.name);
448 iface->path = new String(ctx.filename);
449 ctx.parent->add_import(iface, ctx.filename);
451 iface->def.guid[0] = def.guid[0];
452 iface->def.guid[1] = def.guid[1];
454 int32_t num_methods = swap32(def.num_methods, ctx.swap);
455 int32_t num_supers = swap32(def.num_supers, ctx.swap);
457 if (num_methods < 0 || num_methods > 4096) {
458 fprintf(stderr, "\"%s\" is not a valid object "
459 "(unreasonable num_methods %d).\n",
460 ctx.filename, num_methods);
464 if (num_supers < 0 || num_supers > 4096) {
465 fprintf(stderr, "\"%s\" is not a valid object "
466 "(unreasonable num_supers %d).\n",
467 ctx.filename, num_supers);
471 for (int32_t i = 0; i < num_methods; i++) {
472 const String *str = read_string(ctx);
473 Symbol *sym = lookup_sym_in_ns_noyyerror(ctx, iface, str);
474 Method *m = dynamic_cast<Method *>(sym);
477 fprintf(stderr, "\"%s\" is not a valid object "
478 "(\"%s\" is not a method).\n",
479 ctx.filename, str->c_str());
486 // FIXME: Check for bad recursion again
488 for (int32_t i = 0; i < num_supers; i++) {
489 const String *str = read_string(ctx);
490 Symbol *sym = lookup_sym_noyyerror(ctx, str);
491 Interface *super = dynamic_cast<Interface *>(sym);
494 fprintf(stderr, "\"%s\" is not a valid object "
495 "(\"%s\" is not an interface).\n",
496 ctx.filename, str->c_str());
500 iface->add_super(super);
503 assert(num_methods == iface->def.num_methods);
504 assert(num_supers == iface->def.num_supers);
506 iface->sort_chains();
510 Method *Method::import(ImportContext &ctx)
513 fprintf(stderr, "\"%s\" is not a valid object "
514 "(a Method must be a directory).\n",
520 if (fread(&def, sizeof(def), 1, ctx.f) != 1)
521 throw IOError(ctx.f);
523 Method *m = new Method(ctx.name);
524 m->path = new String(ctx.filename);
525 ctx.parent->add_import(m, ctx.filename);
527 int32_t num_entries = swap32(def.num_entries, ctx.swap);
529 m->def.flags.raw = swap32(def.flags.raw, ctx.swap);
531 if (num_entries < 0 || num_entries > 4096) {
532 fprintf(stderr, "\"%s\" is not a valid object "
533 "(unreasonable num_entries %d).\n",
534 ctx.filename, num_entries);
538 for (int32_t i = 0; i < num_entries; i++) {
539 const String *str = read_string(ctx);
540 Symbol *sym = lookup_sym_in_ns_noyyerror(ctx, m, str);
541 Param *p = dynamic_cast<Param *>(sym);
544 fprintf(stderr, "\"%s\" is not a valid object "
545 "(\"%s\" is not a parameter).\n",
546 ctx.filename, str->c_str());
553 assert(num_entries == m->def.num_entries);
557 Param *Param::import(ImportContext &ctx)
560 fprintf(stderr, "\"%s\" is not a valid object "
561 "(a Parameter must be a file).\n",
567 if (fread(&def, sizeof(def), 1, ctx.f) != 1)
568 throw IOError(ctx.f);
570 Param *p = new Param(ctx.name);
571 ctx.parent->add_import(p, ctx.filename);
573 p->def.type.length = swap32(def.type.length, ctx.swap);
575 if (p->def.type.length != 0) {
576 p->type_fq_name = read_string_raw(ctx, p->def.type.length);
577 Symbol *sym = lookup_sym_noyyerror(ctx, p->type_fq_name);
578 p->type = dynamic_cast<Type *>(sym);
581 fprintf(stderr, "\"%s\" is not a valid object "
582 "(\"%s\" is not a type).\n",
583 ctx.filename, p->type_fq_name->c_str());
587 import_and_validate_array(ctx, p->def.basictype.array,
588 def.basictype.array);
590 import_and_validate_basictype(ctx, p->def.basictype,
594 p->def.flags.raw = swap32(def.flags.raw, ctx.swap);
598 // OPT: Importing data and super isn't necessary for idlc to
599 // work; it could be made optional to speed up large compilations.
601 Struct *Struct::import(ImportContext &ctx)
604 fprintf(stderr, "\"%s\" is not a valid object "
605 "(a Struct must be a directory).\n",
611 if (fread(&def, sizeof(def), 1, ctx.f) != 1)
612 throw IOError(ctx.f);
614 Struct *s = new Struct(ctx.name);
615 s->path = new String(ctx.filename);
616 ctx.parent->add_import(s, ctx.filename);
618 s->def.guid[0] = def.guid[0];
619 s->def.guid[1] = def.guid[1];
621 int32_t num_entries = swap32(def.num_entries, ctx.swap);
623 s->def.flags.raw = swap32(def.flags.raw, ctx.swap);
625 if (num_entries < 0 || num_entries > 4096) {
626 fprintf(stderr, "\"%s\" is not a valid object "
627 "(unreasonable num_entries %d).\n",
628 ctx.filename, num_entries);
632 for (int32_t i = 0; i < num_entries; i++) {
633 const String *str = read_string(ctx);
635 Symbol *sym = lookup_sym_in_ns_noyyerror(ctx, s, str);
636 Datum *d = dynamic_cast<Datum *>(sym);
639 fprintf(stderr, "\"%s\" is not a valid object "
640 "(\"%s\" is not a datum).\n",
641 ctx.filename, str->c_str());
648 if (s->def.flags.field.Super) {
649 const String *str = read_string(ctx);
650 Symbol *sym = lookup_sym_noyyerror(ctx, str);
651 Struct *super = dynamic_cast<Struct *>(sym);
654 fprintf(stderr, "\"%s\" is not a valid object "
655 "(\"%s\" is not a struct).\n",
656 ctx.filename, str->c_str());
662 if (super->is_virtual() && !s->is_virtual()) {
663 fprintf(stderr, "\"%s\" is not a valid object "
664 "(not virtual but parent is).\n",
670 assert(num_entries == s->def.num_entries);
674 // OPT: Importing elements isn't necessary for idlc to work (at
675 // least, not unless inheritance is implemented); it could be made
676 // optional to speed up large compilations.
678 BitField *BitField::import(ImportContext &ctx)
681 fprintf(stderr, "\"%s\" is not a valid object "
682 "(a BitField must be a directory).\n",
687 CompiledBitField def;
688 if (fread(&def, sizeof(def), 1, ctx.f) != 1)
689 throw IOError(ctx.f);
691 BitField *bf = new BitField(ctx.name);
692 bf->path = new String(ctx.filename);
693 ctx.parent->add_import(bf, ctx.filename);
695 int32_t num_entries = swap32(def.num_entries, ctx.swap);
696 bf->def.bits = swap32(def.bits, ctx.swap);
698 if (num_entries < 0 || num_entries > 4096) {
699 fprintf(stderr, "\"%s\" is not a valid object "
700 "(unreasonable num_entries %d).\n",
701 ctx.filename, num_entries);
705 // FIXME: bits can only be 16, 32, or 64 when not in another bitfield.
707 if (bf->def.bits < 1 || bf->def.bits > 64) {
708 fprintf(stderr, "\"%s\" is not a valid object "
709 "(unreasonable bits %d).\n",
710 ctx.filename, num_entries);
714 for (int32_t i = 0; i < num_entries; i++) {
715 const String *str = read_string(ctx);
716 Symbol *sym = lookup_sym_in_ns_noyyerror(ctx, bf, str);
717 Datum *d = dynamic_cast<Datum *>(sym);
720 fprintf(stderr, "\"%s\" is not a valid object "
721 "(\"%s\" is not a datum).\n",
722 ctx.filename, str->c_str());
729 assert(num_entries == bf->def.num_entries);
733 // OPT: Importing elements isn't necessary for idlc to work (at
734 // least, not unless inheritance is implemented); it could be made
735 // optional to speed up large compilations.
737 Enum *Enum::import(ImportContext &ctx)
740 fprintf(stderr, "\"%s\" is not a valid object "
741 "(a Enum must be a directory).\n",
747 if (fread(&def, sizeof(def), 1, ctx.f) != 1)
748 throw IOError(ctx.f);
750 Enum *e = new Enum(ctx.name);
751 e->path = new String(ctx.filename);
752 ctx.parent->add_import(e, ctx.filename);
754 int32_t num_entries = swap32(def.num_entries, ctx.swap);
755 e->def.bits = swap32(def.bits, ctx.swap);
757 if (num_entries < 0 || num_entries > 4096) {
758 fprintf(stderr, "\"%s\" is not a valid object "
759 "(unreasonable num_entries %d).\n",
760 ctx.filename, num_entries);
764 // FIXME: bits can only be 16, 32, or 64 when not in another bitfield.
766 if (e->def.bits < 1 || e->def.bits > 64) {
767 fprintf(stderr, "\"%s\" is not a valid object "
768 "(unreasonable bits %d).\n",
769 ctx.filename, num_entries);
773 for (int32_t i = 0; i < num_entries; i++) {
774 const String *str = read_string(ctx);
775 Symbol *sym = lookup_sym_in_ns_noyyerror(ctx, e, str);
776 Datum *d = dynamic_cast<Datum *>(sym);
779 fprintf(stderr, "\"%s\" is not a valid object "
780 "(\"%s\" is not a datum).\n",
781 ctx.filename, str->c_str());
788 assert(num_entries == e->def.num_entries);
792 Alias *Alias::import(ImportContext &ctx)
795 fprintf(stderr, "\"%s\" is not a valid object "
796 "(an Alias must be a file).\n",
801 Alias *a = new Alias(ctx.name);
802 ctx.parent->add_import(a, ctx.filename);
804 const String *str = read_string(ctx);
805 Symbol *sym = lookup_sym_noyyerror(ctx, str);
807 Alias *aptr = dynamic_cast<Alias *>(sym);
809 fprintf(stderr, "\"%s\" is not a valid object "
810 "(points to \"%s\", which is an alias).\n",
811 ctx.filename, str->c_str());
816 a->sym_fq_name = str;
817 a->def.length = str->length();
822 TypeDef *TypeDef::import(ImportContext &ctx)
825 fprintf(stderr, "\"%s\" is not a valid object "
826 "(a TypeDef must be a file).\n",
831 TypeDef *td = new TypeDef(ctx.name);
832 ctx.parent->add_import(td, ctx.filename);
834 const String *str = read_string(ctx);
835 Symbol *sym = lookup_sym_noyyerror(ctx, str);
837 Alias *aptr = dynamic_cast<Alias *>(sym);
839 fprintf(stderr, "\"%s\" is not a valid object "
840 "(points to \"%s\", which is an alias).\n",
841 ctx.filename, str->c_str());
846 td->sym_fq_name = str;
847 td->def.length = str->length();
852 UserNameSpace *UserNameSpace::import(ImportContext &ctx)
855 fprintf(stderr, "\"%s\" is not a valid object "
856 "(a NameSpace must be a directory).\n",
861 UserNameSpace *uns = new UserNameSpace();
862 uns->path = new String(ctx.filename);
864 // FIXME: sanity check the mount point
866 uns->name = ctx.name;
867 ctx.parent->add_import(uns, ctx.filename);
871 Symbol *do_load(ImportContext &ctx)
873 int type = swap32(ctx.hdr.type, ctx.swap);
876 case CompiledDefHeader::NameSpace:
877 return UserNameSpace::import(ctx);
880 case CompiledDefHeader::BasicType:
881 return BasicType::import(ctx);
884 case CompiledDefHeader::Datum:
885 return Datum::import(ctx);
888 case CompiledDefHeader::Interface:
889 return Interface::import(ctx);
892 case CompiledDefHeader::Method:
893 return Method::import(ctx);
896 case CompiledDefHeader::Param:
897 return Param::import(ctx);
900 case CompiledDefHeader::Struct:
901 return Struct::import(ctx);
904 case CompiledDefHeader::Enum:
905 return Enum::import(ctx);
908 case CompiledDefHeader::BitField:
909 return BitField::import(ctx);
912 case CompiledDefHeader::Alias:
913 ctx.is_typedef = false;
914 return Alias::import(ctx);
917 case CompiledDefHeader::TypeDef:
918 ctx.is_typedef = true;
919 return TypeDef::import(ctx);
923 fprintf(stderr, "\"%s\" is not a valid object "
924 "(bad type %08x).\n",
931 Symbol *NameSpace::load(const String *symname)
934 const String *mangled = mangle(symname);
936 ctx.name = new String(*symname);
940 string filename_no_self(path);
941 filename_no_self += '/';
942 filename_no_self += *mangled;
943 ctx.filename = filename_no_self.c_str();
945 string filename(filename_no_self);
946 filename.append("/.self");
948 ctx.f = fopen(filename.c_str(), "rb");
951 ctx.f = fopen(ctx.filename, "rb");
956 filename = filename_no_self;
961 if (fread(&ctx.hdr, sizeof(ctx.hdr), 1, ctx.f) != 1)
962 throw IOError(ctx.f);
964 if (ctx.hdr.magic == CompiledDefHeader::magic_normal)
966 else if (ctx.hdr.magic == CompiledDefHeader::magic_reversed)
969 fprintf(stderr, "\"%s\" is not a valid object "
970 "(bad magic 0x%08x).\n",
971 ctx.filename, ctx.hdr.magic);
980 fprintf(stderr, "Cannot read from file \"%s\": %s.\n",
981 ctx.filename, e.msg);
989 NameSpace *check_for_imports(NameSpace *ns)
1001 void UserNameSpace::declare_import(const char *path)
1004 UserNameSpace *ns = new UserNameSpace();
1005 string filename(path);
1006 filename.append("/.self");
1009 ctx.filename = path;
1011 ctx.f = fopen(filename.c_str(), "rb");
1013 fprintf(stderr, "Cannot import \"%s\": %s.\n",
1014 path, strerror(errno));
1019 const String *mount;
1021 if (fread(&ctx.hdr, sizeof(ctx.hdr), 1, ctx.f) != 1)
1022 throw IOError(ctx.f);
1024 if (ctx.hdr.magic == CompiledDefHeader::magic_normal)
1026 else if (ctx.hdr.magic == CompiledDefHeader::magic_reversed)
1029 fprintf(stderr, "\"%s\" is not a valid object "
1030 "(bad magic 0x%08x).\n",
1031 ctx.filename, ctx.hdr.magic);
1036 mount = read_string(ctx);
1039 catch (IOError &e) {
1040 fprintf(stderr, "Cannot read from file \"%s\": %s.\n",
1041 ctx.filename, e.msg);
1046 StrList *strl = new StrList(mount);
1048 fprintf(stderr, "\"%s\" is not a valid object "
1049 "(mount point \"%s\" is not valid).\n",
1050 ctx.filename, mount->c_str());
1055 ns->name = strl->back();
1058 if (strl->size() != 0) {
1059 ctx.parent = add_nspace(strl, false);
1064 NameSpace *conflict = check_for_imports(ctx.parent);
1066 fprintf(stderr, "Import \"%s\" conflicts"
1067 " with \"%s\" at \"%s\".\n",
1068 path, conflict->get_fq_name()->flatten()->c_str(),
1069 conflict->get_path()->c_str());
1074 ctx.parent = toplevel;
1077 ns->path = new String(path);
1078 ctx.parent->add_import(ns, ctx.filename);
1081 void NameSpace::import_all()
1086 DIR *dir = opendir(path->c_str());
1088 fprintf(stderr, "Cannot open directory \"%s\".\n", path->c_str());
1092 struct dirent ent, *entp;
1094 // readdir_r is buggy on osx 10.2, and will fail if errno is
1098 if (readdir_r(dir, &ent, &entp)) {
1099 fprintf(stderr, "1 Cannot readdir on \"%s\": %s.\n",
1100 path->c_str(), strerror(errno));
1109 // Ignore ".", "..", and ".self".
1110 if (ent.d_name[0] == '.')
1114 char *under = strchr(ent.d_name, '_');
1116 fprintf(stderr, "\"%s\" is not a valid namespace "
1117 "(bad member \"%s\").\n",
1118 path->c_str(), ent.d_name);
1123 String *s = new String(under + 1);
1127 catch (SymbolNotFound) {
1128 fprintf(stderr, "\"%s\" is not a valid namespace "
1129 "(member \"%s\" disappeared).\n",
1130 path->c_str(), ent.d_name);
1140 void NameSpace::import_all_recursive()
1144 for (const_iterator i = begin(); i != end(); ++i) {
1145 Symbol *sym = (*i).second;
1146 NameSpace *ns = dynamic_cast<NameSpace *>(sym);
1148 ns->import_all_recursive();