1 // idlcomp/languages/c++/main.cc -- C++ IDL binding
3 // This software is copyright (c) 2006 Scott Wood <scott@buserror.net>.
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.
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.
15 // FIXME: escape C++ reserved words
19 #include <sys/types.h>
25 CPPBinding cppbinding;
27 CPPFile::CPPFile(UserNameSpace *NS, const char *dir) :
30 indent.indent_level = 0;
31 indent.align_spaces = 0;
32 do_extra_newline = true;
35 dirname.append(1, '/');
36 dirname.append(ns->name);
37 string headername(dirname);
38 headername.append(".h");
40 file.open(headername.c_str());
41 if (!file.is_open()) {
42 fprintf(stderr, "Could not create output file \"%s\": %s.\n",
43 headername.c_str(), strerror(errno));
48 if (mkdir(dirname.c_str(), 0777) < 0) {
49 fprintf(stderr, "Could not create output directory \"%s\": %s.\n",
50 dir, strerror(errno));
55 file << "// " << *ns->get_fq_name()->flatten(".")
56 << "\n// This is a C++ language binding generated by idlc.\n"
57 << "// Do not modify this file directly.\n\n";
59 fqname = ns->get_fq_name();
60 String *fqname_flat = ns->get_fq_name()->flatten("_IDLNS_");
61 file << "#ifndef IDL_HDR_" << *fqname_flat
62 << "\n#define IDL_HDR_" << *fqname_flat << "\n\n";
64 file << "#include <orb.h>\n";
66 first_traversal = ++traversal;
67 assert(first_traversal >= 0);
69 for (NameSpace::const_iterator i = ns->begin(); i != ns->end(); ++i) {
70 Symbol *sym = (*i).second;
71 UserNameSpace *uns = dynamic_cast<UserNameSpace *>(sym);
74 file << "#include \"" << **ns->name << '/' << **uns->name << ".h\"\n";
76 // Process namespaces first, to minimize duplicate definitions
77 // if this namespace depends on something declared in a sub
84 for (NameSpace::const_iterator i = ns->begin(); i != ns->end(); ++i) {
85 Symbol *sym = (*i).second;
86 UserNameSpace *uns = dynamic_cast<UserNameSpace *>(sym);
89 output_pass(sym, trav_nsdecl);
92 for (NameSpace::const_iterator i = ns->begin(); i != ns->end(); ++i) {
93 Symbol *sym = (*i).second;
94 UserNameSpace *uns = dynamic_cast<UserNameSpace *>(sym);
97 output_pass(sym, trav_full);
105 assert(indent.indent_level == 0);
108 void CPPFile::ifndef_in(Symbol *sym, const char *extra)
110 StrList *fqname = sym->get_fq_name();
111 String *fqname_flat = fqname->flatten("_IDLNS_");
113 assert(indent.indent_level == 0);
115 file << "\n#ifndef IDL_DUP_" << extra << *fqname_flat
116 << "\n#define IDL_DUP_" << extra << *fqname_flat << "\n";
119 void CPPFile::ifndef_out()
121 file << "\n#endif\n";
124 void CPPFile::ns_in(Symbol *sym, const char *extra)
126 // Only output user namespaces here; if we're defining a nested type,
127 // it will have been forward declared already, and thus the
128 // non-user-namespaces can be specified directly in the definition.
130 // For non-forward-declarables such as metadata, use all_ns_in.
132 StrList *ns_fqname = sym->find_toplevel_type()->get_ns()->get_fq_name();
134 ifndef_in(sym, extra);
136 for (StrList::const_iterator i = ns_fqname->begin();
137 i != ns_fqname->end(); ++i) {
138 const String *str = *i;
139 file << "namespace " << *str << " {\n";
145 void CPPFile::ns_out(Symbol *sym)
148 assert(indent.indent_level == 0);
150 for (Symbol *s = sym->find_toplevel_type()->get_ns(); s != toplevel;
157 void CPPFile::all_ns_in(Symbol *sym, bool include_self, const char *extra)
159 NameSpace *ns = sym->find_toplevel_type()->get_ns();
160 StrList *ns_fqname = ns->get_fq_name();
162 ifndef_in(sym, extra);
164 for (StrList::const_iterator i = ns_fqname->begin();
165 i != ns_fqname->end(); ++i) {
166 const String *str = *i;
167 file << "namespace " << *str << " {\n";
170 stack<SymbolRef> typens;
175 for (Symbol *s = sym; s != ns; s = s->get_ns())
178 while (!typens.empty()) {
179 Symbol *s = typens.top();
181 file << "namespace " << **s->name << "_ns {\n";
187 void CPPFile::all_ns_out(Symbol *sym, bool include_self)
190 assert(indent.indent_level == 0);
195 for (Symbol *s = sym; s != toplevel; s = s->get_ns())
201 String &CPPFile::get_definition_name(Symbol *sym, const char *prefix)
203 NameSpace *ns = sym->get_ns();
204 UserNameSpace *uns = dynamic_cast<UserNameSpace *>(ns);
208 str = &get_definition_name(ns);
209 str->append("_ns::");
215 str->append(**sym->name);
219 void cpp_output_name(ostream &file, Symbol *sym, const char *prefix)
221 StrList *sl = sym->get_fq_name("_ns");
224 file << "::" << *sl->flatten("::") << "::" << prefix << **sym->name;
227 void CPPFile::output(UserNameSpace *sym, int pass, void *arg2)
229 assert(indent.indent_level == 0);
230 delete new CPPFile(sym, dirname.c_str());
233 static inline int round_up_bits(int bits)
235 assert(bits >= 1 && bits <= 64);
247 // FIXME: Inline arrays...
248 void cpp_output_type(ostream &file, Type *t, bool array, bool is_mutable)
251 file << "::System::RunTime::";
259 cpp_output_name(file, t);
267 // FIXME: Inline arrays...
268 void cpp_output_type(ostream &file, CompiledBasicType &t, bool is_mutable)
271 file << "::System::RunTime::";
279 if (t.flags.field.Bool) {
280 // Don't rely on C++ to provide any particular representation
283 } else if (t.flags.field.Float) {
289 if (t.flags.field.Unsigned)
292 file << "int" << round_up_bits(t.bits) << "_t";
301 // FIXME: implement padding
302 int CPPFile::output_datum(Struct *ns, Datum *d, int offset)
305 cpp_output_type(file, d->type, is_array(d->def.basictype),
306 !d->def.flags.field.Immutable);
308 Struct *dtype = dynamic_cast<Struct *>(*d->type);
309 if (dtype && !dtype->is_inline())
312 cpp_output_type(file, d->def.basictype,
313 !d->def.flags.field.Immutable);
319 void CPPFile::declare_type_dependency(Type *t, bool need_obj_def)
321 Symbol *toplevel_type = t->find_toplevel_type();
323 assert(indent.indent_level == 0);
325 output_pass(toplevel_type, trav_nsdecl);
327 if (t == toplevel_type)
328 output_pass(t, trav_forward);
330 if (dynamic_cast<Interface *>(t))
331 output_pass(t, need_obj_def ? trav_obj_def : trav_obj_stub);
332 else if (!dynamic_cast<Struct *>(t) || need_obj_def)
333 output_pass(t, trav_full);
336 void CPPFile::declare_dependencies(Interface *iface, bool need_obj_def)
338 for (Interface::methods_iterator i = iface->methods_begin();
339 i != iface->methods_end(); ++i)
342 for (Method::entries_iterator j = m->entries_begin();
343 j != m->entries_end(); ++j)
347 declare_type_dependency(p->type, need_obj_def);
351 for (Interface::supers_iterator i = iface->supers_begin();
352 i != iface->supers_end(); ++i)
354 Interface *super = *i;
355 declare_type_dependency(super);
359 void CPPFile::declare_dependencies(Struct *str)
361 for (NameSpace::const_iterator i = str->begin(); i != str->end(); ++i) {
362 Symbol *sym = (*i).second;
363 Datum *d = dynamic_cast<Datum *>(sym);
366 declare_type_dependency(d->type, d->is_inline());
371 Struct *mstr = dynamic_cast<Struct *>(sym);
373 declare_dependencies(mstr);
377 Interface *miface = dynamic_cast<Interface *>(sym);
379 declare_dependencies(miface);
383 void CPPFile::output_guid(const uint64_t *guid64)
385 const unsigned char *guid = reinterpret_cast<const unsigned char *>(guid64);
388 file << indent << "static const __attribute__((unused))\n"
389 << indent << "::System::RunTime::GUID _guid = {\n"
392 for (int i = 0; i < 16; i++) {
394 file << '\n' << indent << "\t ";
396 sprintf(guidhex, "0x%02x, ", *guid++);
403 do_extra_newline = true;
406 void CPPFile::output_nsdecl_begin(NameSpace *ns)
408 // If indent level is not zero, this is a nested struct or interface.
409 if (indent.indent_level == 0)
414 file << indent << "namespace " << **ns->name << "_ns {\n";
418 void CPPFile::output_nsdecl_children(NameSpace *ns)
420 for (NameSpace::const_iterator i = ns->begin(); i != ns->end(); ++i) {
421 Symbol *sym = (*i).second;
423 assert(pass_needed(sym, trav_forward));
424 assert(pass_needed(sym, trav_nsdecl));
426 // If it's a Method or a non-const Datum, this is a no-op.
427 output_pass(sym, trav_forward);
428 output_pass(sym, trav_nsdecl);
432 void CPPFile::output_nsdecl_end(NameSpace *ns)
436 file << indent << "}\n";
438 if (indent.indent_level == 1)
442 void CPPFile::output_nsdecl(NameSpace *ns)
444 output_nsdecl_begin(ns);
445 output_nsdecl_children(ns);
446 output_nsdecl_end(ns);
449 void CPPFile::output_aliases_and_types(NameSpace *ns)
451 for (NameSpace::const_iterator i = ns->begin(); i != ns->end(); ++i) {
452 Symbol *sym = (*i).second;
453 if (dynamic_cast<Alias *>(sym) || dynamic_cast<Type *>(sym))
454 output_pass(sym, trav_full);
458 void CPPFile::output_vstruct_info(Struct *sym)
460 all_ns_in(sym, true, "VINFO_");
462 file << indent << "static const __attribute__((unused)) "
463 "unsigned long *const _guids[] = {\n";
465 stack<StructRef> supers;
468 for (Struct *i = sym; i; i = i->get_super()) {
473 for (int i = 0; i < sym->chainlen; i++) {
474 Struct *super = supers.top();
477 file << indent << '\t';
478 cpp_output_name(file, super);
479 file << "_ns::_guid.l,\n";
482 file << indent << "};\n\n"
483 << indent << "static const __attribute__((unused)) "
484 "::System::RunTime::VStructInfo _info = {\n"
485 << indent << "\t_guids, " << sym->chainlen << ",\n"
487 << indent << "\t_marshall, _unmarshall,\n"
492 all_ns_out(sym, true);
495 void CPPFile::output_vstruct_main(Struct *sym)
497 assert(sym->is_virtual());
498 Struct *super = sym->get_super();
500 const char *name = sym->name->c_str();
503 assert(sym == System_VStruct);
504 file << indent << "const ::System::RunTime::VStructInfo "
505 "*const _infoptr;\n\n";
508 file << indent << name
509 << "(const ::System::RunTime::VStructInfo *realinfo = &"
510 << name << "_ns::_info) :\n"
516 cpp_output_name(file, super);
518 file << "(realinfo)\n"
524 << indent << "static " << name << " *downcast(::System::VStruct *base)\n"
526 << indent << "\tif (!base)\n"
527 << indent << "\t\treturn NULL;\n\n"
528 << indent << "\tconst ::System::RunTime::VStructInfo *info = base->_infoptr;\n\n"
529 << indent << "\tif (info->chainlen < " << sym->chainlen << ")\n"
530 << indent << "\t\treturn NULL;\n\n"
531 << indent << "\tif (::System::RunTime::guids_equal(info->guids["
532 << sym->chainlen - 1 << "], " << name << "_ns::_guid.l))\n"
533 << indent << "\t\treturn static_cast<" << name << " *>(base);\n\n"
534 << indent << "\treturn NULL;\n"
537 do_extra_newline = true;
540 // Output an init method that initializes all the elements in the
541 // struct; this is useful for throwing exceptions. Due to the
542 // annoying, apparently unwaiveable-by-the-struct requirement that any
543 // struct with a ctor be initialized using the ctor (and thus at
544 // runtime, not statically), this can't be an actual ctor in
545 // non-virtual structs.
547 // In virtual structs, there's already a ctor, so it wouldn't
548 // matter. It'd generally be best to be consistent and use the
549 // init method for both, but the main intended use for this is
550 // throwing exceptions (which are virtual), and it'd be
551 // unfortunate to cripple 99% of the uses with unnecessary
552 // syntactic cruft. The init method will remain available
553 // for vstructs so that things won't break if a non-vstruct
554 // gets made virtual (or if a user really wants to be consistent
555 // between both types in their own code).
557 void CPPFile::output_struct_ctor(Struct *sym, bool extra_vstruct)
559 const char *method_name = extra_vstruct ? sym->name->c_str() : " _init";
561 file << '\n' << indent << **sym->name;
562 indent.align_spaces = sym->name->length() + 1;
564 if (!extra_vstruct) {
566 indent.align_spaces += 7;
570 output_struct_ctor_rec1(sym, 0);
573 Struct *super = sym->get_super();
575 file << ",\n" << indent
576 << "const ::System::RunTime::VStructInfo *_realinfo = &"
577 << **sym->name << "_ns::_info) :\n";
579 indent.align_spaces = 0;
585 cpp_output_name(file, super);
587 file << "(_realinfo";
590 indent.align_spaces = 0;
591 file << ")\n" << indent << "{\n";
593 indent.indent_level++;
595 output_struct_ctor_rec2(sym, 0);
598 file << indent << "return *this;\n";
600 indent.indent_level--;
601 file << indent << "}\n";
604 int CPPFile::output_struct_ctor_rec1(Struct *sym, int num)
606 if (sym->get_super())
607 num = output_struct_ctor_rec1(sym->get_super(), num);
609 for (Struct::entries_iterator i = sym->entries_begin();
610 i != sym->entries_end(); ++i)
613 file << ",\n" << indent;
615 output_datum(sym, *i, -1);
616 file << "_arg" << num;
622 int CPPFile::output_struct_ctor_rec2(Struct *sym, int num)
624 if (sym->get_super())
625 num = output_struct_ctor_rec2(sym->get_super(), num);
627 for (Struct::entries_iterator i = sym->entries_begin();
628 i != sym->entries_end(); ++i)
631 file << indent << **d->name << " = _arg" << ++num << ";\n";
637 void CPPFile::output(Struct *sym, int pass, void *arg2)
641 if (sym->is_virtual()) {
642 output_nsdecl_begin(sym);
643 output_nsdecl_children(sym);
644 output_guid(sym->def.guid);
645 output_nsdecl_end(sym);
653 bool nested = indent.indent_level != 0;
660 file << indent << "struct " << **sym->name << ";\n";
669 output_pass(sym, trav_nsdecl);
670 Struct *super = sym->get_super();
673 output_pass(super, trav_full);
675 if (sym->is_virtual())
676 output_vstruct_info(sym);
678 declare_dependencies(sym);
681 file << indent << "struct " << get_definition_name(sym);
684 const String *supername = super->get_fq_name("_ns")
686 file << " :\n" << indent << "public ::" << *supername;
689 file << "\n" << indent << "{\n";
692 if (sym->is_virtual())
693 output_vstruct_main(sym);
696 for (Struct::entries_iterator i = sym->entries_begin();
697 i != sym->entries_end(); ++i)
702 offset = output_datum(sym, d, offset);
703 file << **d->name << ";\n";
706 bool empty_struct = true;
707 for (Struct *s = sym; s; s = s->get_super()) {
708 if (s->entries_begin() != s->entries_end()) {
709 empty_struct = false;
715 output_struct_ctor(sym, false);
717 if (sym->is_virtual())
718 output_struct_ctor(sym, true);
722 file << indent << "};\n";
726 output_aliases_and_types(sym);
728 for (NameSpace::const_iterator i = sym->begin(); i != sym->end(); ++i) {
729 Symbol *sym2 = (*i).second;
730 output_pass(sym2, trav_full);
741 void CPPFile::output(Interface *sym, int pass, void *arg2)
745 output_nsdecl_begin(sym);
746 output_nsdecl_children(sym);
748 output_guid(sym->def.guid);
749 output_ifaceinfo(sym);
751 output_nsdecl_end(sym);
755 bool nested = indent.indent_level != 0;
762 file << indent << "struct " << **sym->name << ";\n"
763 << indent << "struct _i_" << **sym->name << ";\n";
771 case trav_obj_stub: {
772 output_pass(sym, trav_forward);
774 for (Interface::supers_iterator i = sym->supers_begin();
775 i != sym->supers_end(); ++i)
777 Interface *super = *i;
778 output_pass(super, trav_obj_stub);
781 declare_dependencies(sym);
784 file << indent << "struct "
785 << get_definition_name(sym) << " {\n";
792 file << indent << "};\n";
799 output_pass(sym, trav_obj_stub);
801 for (Interface::supers_iterator i = sym->supers_begin();
802 i != sym->supers_end(); ++i)
804 Interface *super = *i;
805 output_pass(super, trav_full);
808 declare_dependencies(sym);
809 ns_in(sym, "OBJDEF_");
811 file << indent << "struct ";
812 file << get_definition_name(sym, "_i_") << " {\n";
816 output_internal(sym);
819 file << indent << "};\n\n";
827 output_pass(sym, trav_obj_def);
829 declare_dependencies(sym, true);
832 output_method_defs(sym);
835 output_aliases_and_types(sym);
837 for (NameSpace::const_iterator i = sym->begin(); i != sym->end(); ++i) {
838 Symbol *sym2 = (*i).second;
839 output_pass(sym2, trav_full);
850 void CPPFile::output_bf_elem(Datum *d, int pos, int bits,
854 BitField *bf = dynamic_cast<BitField *>(t);
855 Enum *en = dynamic_cast<Enum *>(t);
859 if (!d->name->compare(0, 4, "get_") ||
860 !d->name->compare(0, 4, "set_"))
863 fieldname.append(**d->name);
866 string newprefix(prefix);
867 newprefix.append(**d->name);
868 newprefix.append("_IDLNS_");
869 output_bf(bf, d->def.icon, bits, newprefix);
871 // FIXME: getters and setters
872 } else if (en || !t) {
873 file << indent << "uint" << bits << "_t "
874 << prefix << fieldname << ':' << d->def.icon << ";\n";
876 // This is checked here rather than in input.cc, because
879 fprintf(stderr, "idlc: Bad input: \"%s\" cannot be the type of \"%s\"\n",
880 t->get_fq_name()->flatten()->c_str(),
881 d->get_fq_name()->flatten()->c_str());
887 void CPPFile::output_bf(BitField *sym, int bits, int typebits,
892 assert(bits == sym->def.bits || bits == typebits);
894 for (BitField::entries_iterator i = sym->entries_begin();
895 i != sym->entries_end(); ++i)
896 size += (*i)->def.icon;
898 if (size > sym->def.bits) {
899 // FIXME: This isn't detected in the front end,
900 // but even once it is, this should stay as a
901 // replacement for input.cc checking.
903 fprintf(stderr, "idlc: \"%s\" is too small (%d bits) for its "
904 "contents (%d bits)\n",
905 sym->get_fq_name()->flatten()->c_str(),
906 sym->def.bits, size);
911 if (target->bitfield_big_endian) {
913 // The prefix is put at the end, so that we can avoid
914 // consecutive underscores or an underscore followed
915 // by a capital, both of which are reserved in C++.
917 file << indent << "uint" << bits << "_t _pad_" << prefix
918 << ':' << bits - size << ";\n";
921 int pos = sym->def.bits;
923 for (BitField::entries_reverse_iterator i = sym->entries_rbegin();
924 i != sym->entries_rend(); ++i)
928 output_bf_elem(d, pos, typebits, prefix);
933 for (BitField::entries_iterator i = sym->entries_begin();
934 i != sym->entries_end(); ++i)
937 output_bf_elem(d, pos, typebits, prefix);
943 void CPPFile::output(BitField *sym, int pass, void *arg2)
952 file << indent << "union " << **sym->name << ";\n";
956 int bits = round_up_bits(sym->def.bits);
959 file << indent << "union ";
960 file << get_definition_name(sym) << " {\n";
963 file << indent << "struct {\n";
967 output_bf(sym, bits, bits, nullprefix);
970 file << indent << "};\n\n"
971 << indent << "uint" << bits << "_t _raw;\n\n"
972 << indent << **sym->name << "()\n"
974 << indent << "\t_raw = 0;\n"
976 << indent << **sym->name << "(uint" << bits << "_t _init)\n"
978 << indent << "\t_raw = _init;\n"
980 << indent << "operator uint" << bits << "_t()\n"
982 << indent << "\treturn _raw;\n"
986 file << indent << "};\n";
989 output_aliases_and_types(sym);
999 void CPPFile::output(Enum *sym, int pass, void *arg2)
1006 case trav_forward: {
1007 bool do_ns_out = false;
1009 if (indent.indent_level == 0) {
1016 file << indent << "struct " << **sym->name << " {\n";
1019 for (Enum::entries_iterator i = sym->entries_begin();
1020 i != sym->entries_end(); ++i)
1024 file << indent << "static const uint"
1025 << round_up_bits(sym->def.bits) << "_t "
1026 << **d->name << " = " << d->def.ucon << ";\n";
1029 file << '\n' << indent << "unsigned int _val;\n\n";
1031 file << indent << **sym->name << "()\n"
1033 << indent << "\t_val = 0;\n"
1034 << indent << "}\n\n";
1036 file << indent << **sym->name << "(unsigned int val)\n"
1038 << indent << "\t_val = val;\n"
1039 << indent << "}\n\n";
1041 file << indent << "operator unsigned int()\n"
1043 << indent << "\treturn _val;\n"
1044 << indent << "}\n\n";
1047 file << indent << "};\n";
1056 // Nothing particular to do here, other than to make sure
1057 // that trav_forward has happened (which will always need to
1058 // be done here if it's not a nested type).
1060 output_pass(sym, trav_forward);
1068 void CPPFile::output(BasicType *sym, int pass, void *arg2)
1075 case trav_forward: {
1076 bool do_ns_out = false;
1078 if (indent.indent_level == 0) {
1085 file << indent << "typedef ";
1086 assert(!is_array(sym->def));
1087 cpp_output_type(file, sym->def, false);
1088 file << **sym->name << ";\n";
1097 output_pass(sym, trav_forward);
1105 void CPPFile::output(Alias *sym, int pass, void *arg2)
1112 case trav_forward: {
1113 bool do_ns_out = false;
1115 if (indent.indent_level == 0) {
1122 const String *type = sym->get_concrete_sym()->get_fq_name("_ns")
1125 file << indent << "typedef " << *type << " "
1126 << **sym->name << ";\n";
1135 output_pass(sym, trav_forward);
1143 void CPPFile::output(TypeDef *sym, int pass, void *arg2)
1152 output_pass(sym->get_concrete_sym(), trav_forward);
1154 bool do_ns_out = false;
1156 if (indent.indent_level == 0) {
1163 const String *type = sym->get_concrete_sym()->get_fq_name("_ns")
1166 file << indent << "typedef " << *type << " "
1167 << **sym->name << ";\n";
1180 void CPPFile::output(Datum *sym, int pass, void *arg2)
1182 assert(sym->def.flags.field.Const);
1192 declare_type_dependency(sym->type, false);
1194 bool do_ns_out = false;
1196 if (indent.indent_level == 0) {
1203 file << indent << "static const ";
1205 assert(!is_array(sym->def.basictype));
1208 cpp_output_type(file, sym->type, false, false);
1210 cpp_output_type(file, sym->def.basictype, false);
1212 file << **sym->name << " = ";
1214 CompiledBasicType *def;
1216 Symbol *real_type = sym->type->get_concrete_sym();
1217 BasicType *bt = dynamic_cast<BasicType *>(real_type);
1222 def = &sym->def.basictype;
1225 if (def->flags.field.Float) {
1226 file << sym->def.fcon;
1227 } else if (def->flags.field.Bool) {
1228 if (sym->def.ucon == 0)
1233 if (def->flags.field.Unsigned) {
1234 file << "0x" << std::hex << sym->def.ucon << std::dec << 'U';
1236 file << sym->def.icon;
1255 void CPPBinding::output_root(UserNameSpace *ns, const char *dir)
1257 delete new CPPFile(ns, dir);