5 #define sflnprintln(...) PrintLn(__FILE__, ":", __LINE__, ": ", ##__VA_ARGS__)
7 static Context globalContext { };
8 static OldList defines { };
9 static OldList imports { };
10 static NameSpace globalData;
11 static OldList excludedSymbols { offset = (uint)(uintptr)&((Symbol)0).left };
13 define app = (Convertor)__thisModule.application;
15 #define UTF8_NUM_BYTES(x) (__extension__({ byte b = x; (b & 0x80 && b & 0x40) ? ((b & 0x20) ? ((b & 0x10) ? 4 : 3) : 2) : 1; }))
18 /*extern */int __ecereVMethodID_class_OnGetString;
22 static __attribute__((unused)) void Dummy()
25 a.OnGetString(null, null, null);
28 static String ConvertReadDoc(const char * filePath)
31 String contents = null;
33 f = FileOpen(filePath, read);
36 if((len = f.GetSize()))
38 contents = new char[len+1];
39 f.Read(contents, 1, len);
47 for(s = contents; *s; s++)
48 if(!isspace(*s)) break;
54 String buffer = new char[len+1];
55 char * i, * o = buffer;
56 for(i = contents; *i; i++)
58 if(i[0] == '<' && (i[1] == 'b' || i[1] == 'B') && (i[2] == 'r' || i[2] == 'R') && i[3] == '>' && i[4] == '\n')
73 void ConvertModuleDoc(Module module, bool isDll)
77 char oldDocFilePath[MAX_LOCATION];
78 char docFilePath[MAX_LOCATION];
79 NameSpace * nameSpace = null;
80 if(module.name && (!strcmp(module.name, "ecere") || !strcmp(module.name, "ecereCOM")))
81 nameSpace = &module.application.systemNameSpace;
82 if(module.name && strcmp(module.name, "ecereCOM"))
83 nameSpace = &module.publicNameSpace;
85 getDocFilePath(oldDocFilePath, null, module, nameSpace, false, true);
86 getDocFilePath(docFilePath, null, module, nameSpace, false, false);
87 PrintLn("ConvertModuleDoc:",
88 " convertDocDir(", app.convertDocDir, ")",
89 " outputDocDir(", app.outputDocDir, ")",
90 " oldDocFile(", oldDocFilePath, ")",
91 " docFile(", docFilePath, ")");
93 getDocFilePath(oldDocFilePath, app.convertDocDir, module, nameSpace, true, true);
94 getDocFilePath(docFilePath, app.outputDocDir, module, nameSpace, true, false);
96 if(FileExists(oldDocFilePath))
98 if(FileExists(docFilePath).isDirectory)
100 char writeTestFilePath[MAX_LOCATION];
102 sprintf(writeTestFilePath, "%s/_", docFilePath);
103 f = FileOpen(writeTestFilePath, write);
104 PrintLn("Info: Directory exists for eCdoc in eCon format. Conversion is not required. Proceeding anyway.");
108 DeleteFile(writeTestFilePath);
114 PrintLn("Error: Directory for eCdoc in eCon format is not writable.");
119 MakeDir(docFilePath);
120 if(FileExists(docFilePath).isDirectory)
127 PrintLn("Error: Unable to create directory for eCdoc conversion to eCon.");
133 char fileName[MAX_LOCATION];
134 DocConvertIterator fsi
136 bool onFolder(const char * folderPath, const char * folderName)
138 DocConvertLocType type = typeStack.lastIterator.data;
141 if(type == namespaces)
143 PathCatSlash(nsDir, folderName);
144 namespaces.Add((ns = { namespaceDoc = { name = CopyString(folderName) }, nsPath = CopyString(nsDir) }));
147 else if(type == functions)
149 functionDoc = FunctionDoc { };
150 if(!ns.namespaceDoc.functions)
151 ns.namespaceDoc.functions = { };
152 ns.namespaceDoc.functions[folderName] = functionDoc;
154 else if(type == classes)
156 classDoc = ClassDoc { name = CopyString(folderName) };
157 ns.classes.Add(classDoc);
159 else if(type == methods)
161 methodDoc = MethodDoc { };
162 if(!classDoc.methods)
163 classDoc.methods = { };
164 classDoc.methods[folderName] = methodDoc;
167 sflnprintln("what?");
168 nameStack.Add(CopyString(folderName));
170 if(!strcmp(folderName, "namespaces"))
171 sflnprintln("what?");
172 else if(!strcmp(folderName, "functions"))
173 sflnprintln("what?");
174 else if(!strcmp(folderName, "parameters"))
175 sflnprintln("what?");
176 else if(!strcmp(folderName, "classes"))
177 sflnprintln("what?");
178 else if(!strcmp(folderName, "enumeration values"))
179 sflnprintln("what?");
180 else if(!strcmp(folderName, "data members"))
181 sflnprintln("what?");
182 else if(!strcmp(folderName, "properties"))
183 sflnprintln("what?");
184 else if(!strcmp(folderName, "conversions"))
185 sflnprintln("what?");
186 else if(!strcmp(folderName, "methods"))
187 sflnprintln("what?");
189 else if((type == root || type == namespaces) && !strcmp(folderName, "namespaces"))
191 else if((type == root || type == namespaces) && !strcmp(folderName, "functions"))
193 else if((type == functions || type == methods) && !strcmp(folderName, "parameters"))
195 else if((type == root || type == namespaces) && !strcmp(folderName, "classes"))
197 else if(type == classes && !strcmp(folderName, "enumeration values"))
199 else if(type == classes && !strcmp(folderName, "data members"))
201 else if(type == classes && !strcmp(folderName, "properties"))
203 else if(type == classes && !strcmp(folderName, "conversions"))
204 addType(conversions);
205 else if(type == classes && !strcmp(folderName, "methods"))
210 void outFolder(const char * folderPath, const char * folderName, bool isRoot)
212 DocConvertLocType type = typeStack.lastIterator.data;
215 if(!strcmp(folderName, "namespaces"))
217 else if(!strcmp(folderName, "functions"))
219 else if(!strcmp(folderName, "parameters"))
221 else if(!strcmp(folderName, "classes"))
223 else if(!strcmp(folderName, "enumeration values"))
225 else if(!strcmp(folderName, "data members"))
227 else if(!strcmp(folderName, "properties"))
229 else if(!strcmp(folderName, "conversions"))
231 else if(!strcmp(folderName, "methods"))
233 else if(!strcmp(folderName, nameStack.lastIterator.data))
235 if(type == namespaces)
237 StripLastDirectory(nsDir, nsDir);
238 nsStack.Remove(nsStack.lastIterator.pointer);
239 ns = nsStack.lastIterator.data;
241 delete nameStack.lastIterator.data;
242 nameStack.Remove(nameStack.lastIterator.pointer);
248 bool onFile(const char * filePath, const char * fileName)
250 DocConvertLocType type = typeStack.lastIterator.data;
251 if(!strstr(fileName, ".eCdoc"))
253 String doc = ConvertReadDoc(filePath);
254 if((type == root || type == namespaces || type == classes || type == methods || type == functions) && !strcmp(fileName, "description"))
256 if(type == root || type == namespaces) { ns.namespaceDoc.description = doc; doc = null; }
257 else if(type == classes) { classDoc.description = doc; doc = null; }
258 else if(type == methods) { methodDoc.description = doc; doc = null; }
259 else if(type == functions) { functionDoc.description = doc; doc = null; }
261 else if((type == classes || type == methods || type == functions) && !strcmp(fileName, "usage"))
263 if(type == classes) { classDoc.usage = doc; doc = null; }
264 else if(type == methods) { methodDoc.usage = doc; doc = null; }
265 else if(type == functions) { functionDoc.usage = doc; doc = null; }
267 else if((type == classes || type == methods || type == functions) && !strcmp(fileName, "example"))
269 if(type == classes) { classDoc.example = doc; doc = null; }
270 else if(type == methods) { methodDoc.example = doc; doc = null; }
271 else if(type == functions) { functionDoc.example = doc; doc = null; }
273 else if((type == classes || type == methods || type == functions) && !strcmp(fileName, "remarks"))
275 if(type == classes) { classDoc.remarks = doc; doc = null; }
276 else if(type == methods) { methodDoc.remarks = doc; doc = null; }
277 else if(type == functions) { functionDoc.remarks = doc; doc = null; }
279 else if((type == classes || type == methods || type == functions) && !strcmp(fileName, "seeAlso"))
281 if(type == classes) { classDoc.also = doc; doc = null; }
282 else if(type == methods) { methodDoc.also = doc; doc = null; }
283 else if(type == functions) { functionDoc.also = doc; doc = null; }
285 else if((type == methods || type == functions) && !strcmp(fileName, "returnValue"))
287 if(type == methods) { methodDoc.returnValue = doc; doc = null; }
288 else if(type == functions) { functionDoc.returnValue = doc; doc = null; }
292 if(type == parameters)
296 char name[MAX_FILENAME];
297 ParameterDoc parameterDoc;
298 DocConvertLocType parentType = typeStack[typeStack.count-2];
299 strcpy(name, fileName);
300 s = strstr(name, ".");
308 sflnprintln("what?");
309 if(parentType == functions)
311 parameterDoc = ParameterDoc { description = doc, position = pos };
313 if(!functionDoc.parameters)
314 functionDoc.parameters = { };
315 functionDoc.parameters[name] = parameterDoc;
317 else if(parentType == methods)
319 parameterDoc = ParameterDoc { description = doc, position = pos };
321 if(!methodDoc.parameters)
322 methodDoc.parameters = { };
323 methodDoc.parameters[name] = parameterDoc;
326 sflnprintln("what?");
328 else if(type == values)
330 ValueDoc valueDoc { description = doc };
333 classDoc.values = { };
334 classDoc.values[fileName] = valueDoc;
336 else if(type == fields)
338 FieldDoc fieldDoc { description = doc };
341 classDoc.fields = { };
342 classDoc.fields[fileName] = fieldDoc;
344 else if(type == properties)
346 PropertyDoc propertyDoc { description = doc };
348 if(!classDoc.properties)
349 classDoc.properties = { };
350 classDoc.properties[fileName] = propertyDoc;
352 else if(type == conversions)
354 ConversionDoc conversionDoc { description = doc };
356 if(!classDoc.conversions)
357 classDoc.conversions = { };
358 classDoc.conversions[fileName] = conversionDoc;
361 sflnprintln("what?");
369 PathCatSlash(fsi.nsDir, docFilePath);
370 fsi.typeStack.Add(root);
371 fsi.namespaces.Add((fsi.ns = { namespaceDoc = { }, nsPath = CopyString(fsi.nsDir) }));
372 fsi.nsStack.Add(fsi.ns);
373 sprintf(fileName, "<%s>", oldDocFilePath);
374 fsi.iterate(fileName);
375 for(ns : fsi.namespaces)
377 writeNamespaceDocFile(ns.namespaceDoc, ns.nsPath);
380 writeClassDocFile(c, ns.nsPath);
387 PrintLn("Info: old eCdoc format file (", oldDocFilePath, ") does not exist.");
390 for(m = module.modules.first; m; m = m.next)
392 if(m.importMode == publicAccess || !isDll)
393 ConvertModuleDoc(m.module, true);
397 void getDocFilePath(char * docFilePath, char * docDir, Module module, NameSpace * ns, bool includeDir, bool old)
399 sprintf(docFilePath, old ? "%s%s%s.eCdoc" : "%s%s%s", includeDir ? docDir : "", includeDir ? "/" : "",
400 (!module || !module.name ||
401 (ns && ns->name && !strcmp(ns->name, "namespaces/ecere/namespaces/com"))) ? "ecereCOM" : module.name);
404 static void writeNamespaceDocFile(NamespaceDoc namespaceDoc, const char * path)
406 if(!namespaceDoc.isEmpty)
408 char * filePath = new char[MAX_LOCATION];
410 strcpy(filePath, path);
411 PathCatSlash(filePath, "_global-defs");
412 ChangeExtension(filePath, "econ", filePath);
414 DeleteFile(filePath);
415 f = FileOpen(filePath, write);
418 WriteJSONObject(f, class(NamespaceDoc), namespaceDoc, 0, true);
423 PrintLn("error: writeNamespaceDocFile -- problem opening file: ", filePath);
429 static void writeClassDocFile(ClassDoc classDoc, const char * path)
431 if(!classDoc.isEmpty)
433 char * name = getDocFileNameFromTypeName(classDoc.name);
434 char * filePath = new char[MAX_LOCATION];
436 strcpy(filePath, path);
437 PathCatSlash(filePath, name);
438 ChangeExtension(filePath, "econ", filePath);
439 DeleteFile(filePath);
440 f = FileOpen(filePath, write);
443 WriteJSONObject(f, class(ClassDoc), classDoc, 0, true);
448 PrintLn("error: writeClassDocFile -- problem opening file: ", filePath);
455 Application componentsApp;
457 class Convertor : Application
460 char * convertDocDir;
465 SetGlobalContext(globalContext);
466 SetExcludedSymbols(&excludedSymbols);
467 SetDefines(&::defines);
468 SetImports(&imports);
469 SetInDocumentor(true);
471 SetGlobalData(globalData);
473 if(argc == 3 || argc == 4)
475 convertDocDir = CopyString(argv[1]);
476 outputDocDir = CopyString(argv[2]);
478 moduleName = CopyString(argv[3]);
480 moduleName = CopyString("ecere");
490 OpenModule(moduleName);
494 PrintLn($"Syntax: exename <old doc dir> <new doc dir> [<module name>]");
502 delete convertDocDir;
505 FreeContext(globalContext);
506 FreeExcludedSymbols(excludedSymbols);
507 ::defines.Free(FreeModuleDefine);
508 imports.Free(FreeModuleImport);
510 FreeGlobalData(globalData);
511 FreeTypeData(componentsApp);
513 delete componentsApp;
516 void OpenModule(const char * filePath)
518 char moduleName[MAX_LOCATION];
519 char extension[MAX_EXTENSION];
520 Module module = null;
521 static char symbolsDir[MAX_LOCATION];
523 FreeContext(globalContext);
524 FreeExcludedSymbols(excludedSymbols);
525 ::defines.Free(FreeModuleDefine);
526 imports.Free(FreeModuleImport);
528 FreeGlobalData(globalData);
532 FreeTypeData(componentsApp);
533 delete componentsApp;
536 componentsApp = __ecere_COM_Initialize(false, 1, null);
537 SetPrivateModule(componentsApp);
539 StripLastDirectory(filePath, symbolsDir);
540 SetSymbolsDir(symbolsDir);
542 GetExtension(filePath, extension);
544 ImportModule(filePath, normalImport, publicAccess, false);
546 if(extension[0] && strcmpi(extension, "so") && strcmpi(extension, "dll") && strcmpi(extension, "dylib"))
547 componentsApp.name = CopyString(filePath);
549 for(module = componentsApp.allModules.first; module; module = module.next)
551 if(module.name && (!strcmp(module.name, "ecere") || !strcmp(module.name, "ecereCOM")))
555 eModule_LoadStrict(componentsApp, "ecereCOM", publicAccess /*privateAccess*/);
557 GetLastDirectory(filePath, moduleName);
558 // Extension, path and lib prefix get removed in Module::name
561 StripExtension(moduleName);
562 if((!strcmpi(extension, "so") || !strcmpi(extension, "dylib")) && strstr(moduleName, "lib") == moduleName)
564 int len = strlen(moduleName) - 3;
565 memmove(moduleName, moduleName + 3, len);
570 ConvertModuleDoc(componentsApp, false);
574 class DocConvertNamespaceStackFrame
576 NamespaceDoc namespaceDoc { };
577 Array<ClassDoc> classes { };
581 enum DocConvertLocType { root, namespaces, functions, parameters, classes, values, fields, properties, conversions, methods };
583 class DocConvertIterator : NormalFileSystemIterator
588 Array<String> nameStack { };
589 Array<DocConvertLocType> typeStack { };
590 Array<DocConvertNamespaceStackFrame> nsStack { };
591 Array<DocConvertNamespaceStackFrame> namespaces { };
592 DocConvertNamespaceStackFrame ns;
594 FunctionDoc functionDoc;
598 void addType(DocConvertLocType type)
605 typeStack.Remove(typeStack.lastIterator.pointer);
611 nsDir = new char[MAX_LOCATION];
613 ~DocConvertIterator()
619 public class NormalFileSystemIterator : FileSystemIterator
622 Array<StackFrame> stack { };
625 property char * extensions { set { delete extensions; if(value) extensions = CopyString(value); } }
627 ~NormalFileSystemIterator()
632 void iterate(const char * startPath)
635 char startName[MAX_FILENAME];
637 GetLastDirectory(startPath, startName);
639 onInit(startPath, startName);
641 frame = StackFrame { };
643 frame.path = CopyString(startPath);
644 frame.listing = FileListing { startPath, extensions = extensions };
649 FileAttribs attribs = FileExists(startPath);
654 if(attribs.isDirectory)
655 onFolder(startPath, startName);
656 else if(attribs.isFile)
657 onFile(startPath, startName);
663 if(frame.listing.Find())
665 bool peek = frame.listing.stats.attribs.isDirectory && onFolder(frame.listing.path, frame.listing.name);
666 if(!frame.listing.stats.attribs.isDirectory)
668 onFile(frame.listing.path, frame.listing.name);
672 StackFrame newFrame { };
674 newFrame.path = CopyString(frame.listing.path);
675 newFrame.listing = FileListing { newFrame.path, extensions = frame.listing.extensions };
681 StackFrame parentFrame = stack.count > 1 ? stack[stack.count - 2] : null;
682 outFolder(parentFrame ? parentFrame.listing.path : startPath, parentFrame ? parentFrame.listing.name : startName, !parentFrame);
683 stack.lastIterator.Remove();
685 frame = stack.lastIterator.data;
693 public class FileSystemIterator
696 bool iterateStartPath;
698 virtual bool onInit(const char * startPath, const char * startName)
703 virtual bool onFile(const char * filePath, const char * fileName)
708 virtual bool onFolder(const char * folderPath, const char * folderName)
713 virtual bool onVolume(const char * volumePath)
718 virtual void outFolder(const char * folderPath, const char * folderName, bool isRoot)
723 public class StackFrame