d: Merge upstream dmd 4d1bfcf14, druntime 9ba9a6ae, phobos c0cc5e917.
[official-gcc.git] / gcc / d / dmd / json.d
blobfc270390fa4ac18662696f36eea667828277a09e
1 /**
2 * Code for generating .json descriptions of the module when passing the `-X` flag to dmd.
4 * Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved
5 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
6 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/json.d, _json.d)
8 * Documentation: https://dlang.org/phobos/dmd_json.html
9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/json.d
12 module dmd.json;
14 import core.stdc.stdio;
15 import core.stdc.string;
16 import dmd.aggregate;
17 import dmd.arraytypes;
18 import dmd.astenums;
19 import dmd.attrib;
20 import dmd.cond;
21 import dmd.dclass;
22 import dmd.declaration;
23 import dmd.denum;
24 import dmd.dimport;
25 import dmd.dmodule;
26 import dmd.dsymbol;
27 import dmd.dtemplate;
28 import dmd.errors;
29 import dmd.expression;
30 import dmd.func;
31 import dmd.globals;
32 import dmd.hdrgen;
33 import dmd.id;
34 import dmd.identifier;
35 import dmd.mtype;
36 import dmd.common.outbuffer;
37 import dmd.root.rootobject;
38 import dmd.root.string;
39 import dmd.target;
40 import dmd.visitor;
42 version(Windows) {
43 extern (C) char* getcwd(char* buffer, size_t maxlen);
44 } else {
45 import core.sys.posix.unistd : getcwd;
48 private extern (C++) final class ToJsonVisitor : Visitor
50 alias visit = Visitor.visit;
51 public:
52 OutBuffer* buf;
53 int indentLevel;
54 const(char)[] filename;
56 extern (D) this(OutBuffer* buf)
58 this.buf = buf;
62 void indent()
64 if (buf.length >= 1 && (*buf)[buf.length - 1] == '\n')
65 for (int i = 0; i < indentLevel; i++)
66 buf.writeByte(' ');
69 void removeComma()
71 if (buf.length >= 2 && (*buf)[buf.length - 2] == ',' && ((*buf)[buf.length - 1] == '\n' || (*buf)[buf.length - 1] == ' '))
72 buf.setsize(buf.length - 2);
75 void comma()
77 if (indentLevel > 0)
78 buf.writestring(",\n");
81 void stringStart()
83 buf.writeByte('\"');
86 void stringEnd()
88 buf.writeByte('\"');
91 extern(D) void stringPart(const char[] s)
93 foreach (char c; s)
95 switch (c)
97 case '\n':
98 buf.writestring("\\n");
99 break;
100 case '\r':
101 buf.writestring("\\r");
102 break;
103 case '\t':
104 buf.writestring("\\t");
105 break;
106 case '\"':
107 buf.writestring("\\\"");
108 break;
109 case '\\':
110 buf.writestring("\\\\");
111 break;
112 case '\b':
113 buf.writestring("\\b");
114 break;
115 case '\f':
116 buf.writestring("\\f");
117 break;
118 default:
119 if (c < 0x20)
120 buf.printf("\\u%04x", c);
121 else
123 // Note that UTF-8 chars pass through here just fine
124 buf.writeByte(c);
126 break;
131 // Json value functions
132 /*********************************
133 * Encode string into buf, and wrap it in double quotes.
135 extern(D) void value(const char[] s)
137 stringStart();
138 stringPart(s);
139 stringEnd();
142 void value(int value)
144 if (value < 0)
146 buf.writeByte('-');
147 value = -value;
149 buf.print(value);
152 void valueBool(bool value)
154 buf.writestring(value ? "true" : "false");
157 /*********************************
158 * Item is an intented value and a comma, for use in arrays
160 extern(D) void item(const char[] s)
162 indent();
163 value(s);
164 comma();
167 void item(int i)
169 indent();
170 value(i);
171 comma();
174 void itemBool(const bool b)
176 indent();
177 valueBool(b);
178 comma();
181 // Json array functions
182 void arrayStart()
184 indent();
185 buf.writestring("[\n");
186 indentLevel++;
189 void arrayEnd()
191 indentLevel--;
192 removeComma();
193 if (buf.length >= 2 && (*buf)[buf.length - 2] == '[' && (*buf)[buf.length - 1] == '\n')
194 buf.setsize(buf.length - 1);
195 else if (!(buf.length >= 1 && (*buf)[buf.length - 1] == '['))
197 buf.writestring("\n");
198 indent();
200 buf.writestring("]");
201 comma();
204 // Json object functions
205 void objectStart()
207 indent();
208 buf.writestring("{\n");
209 indentLevel++;
212 void objectEnd()
214 indentLevel--;
215 removeComma();
216 if (buf.length >= 2 && (*buf)[buf.length - 2] == '{' && (*buf)[buf.length - 1] == '\n')
217 buf.setsize(buf.length - 1);
218 else
220 buf.writestring("\n");
221 indent();
223 buf.writestring("}");
224 comma();
227 // Json object property functions
228 extern(D) void propertyStart(const char[] name)
230 indent();
231 value(name);
232 buf.writestring(" : ");
236 Write the given string object property only if `s` is not null.
238 Params:
239 name = the name of the object property
240 s = the string value of the object property
242 extern(D) void property(const char[] name, const char[] s)
244 if (s is null)
245 return;
246 propertyStart(name);
247 value(s);
248 comma();
252 Write the given string object property.
254 Params:
255 name = the name of the object property
256 s = the string value of the object property
258 extern(D) void requiredProperty(const char[] name, const char[] s)
260 propertyStart(name);
261 if (s is null)
262 buf.writestring("null");
263 else
264 value(s);
265 comma();
268 extern(D) void property(const char[] name, int i)
270 propertyStart(name);
271 value(i);
272 comma();
275 extern(D) void propertyBool(const char[] name, const bool b)
277 propertyStart(name);
278 valueBool(b);
279 comma();
282 extern(D) void property(const char[] name, TRUST trust)
284 final switch (trust)
286 case TRUST.default_:
287 // Should not be printed
288 //property(name, "default");
289 break;
290 case TRUST.system: return property(name, "system");
291 case TRUST.trusted: return property(name, "trusted");
292 case TRUST.safe: return property(name, "safe");
296 extern(D) void property(const char[] name, PURE purity)
298 final switch (purity)
300 case PURE.impure:
301 // Should not be printed
302 //property(name, "impure");
303 break;
304 case PURE.weak: return property(name, "weak");
305 case PURE.const_: return property(name, "strong");
306 case PURE.fwdref: return property(name, "fwdref");
310 extern(D) void property(const char[] name, const LINK linkage)
312 final switch (linkage)
314 case LINK.default_:
315 // Should not be printed
316 //property(name, "default");
317 break;
318 case LINK.d:
319 // Should not be printed
320 //property(name, "d");
321 break;
322 case LINK.system: return property(name, "system");
323 case LINK.c: return property(name, "c");
324 case LINK.cpp: return property(name, "cpp");
325 case LINK.windows: return property(name, "windows");
326 case LINK.objc: return property(name, "objc");
330 extern(D) void propertyStorageClass(const char[] name, StorageClass stc)
332 stc &= STC.visibleStorageClasses;
333 if (stc)
335 propertyStart(name);
336 arrayStart();
337 while (stc)
339 auto p = stcToString(stc);
340 assert(p.length);
341 item(p);
343 arrayEnd();
347 extern(D) void property(const char[] linename, const char[] charname, const ref Loc loc)
349 if (loc.isValid())
351 if (auto filename = loc.filename.toDString)
353 if (filename != this.filename)
355 this.filename = filename;
356 property("file", filename);
359 if (loc.linnum)
361 property(linename, loc.linnum);
362 if (loc.charnum)
363 property(charname, loc.charnum);
368 extern(D) void property(const char[] name, Type type)
370 if (type)
372 property(name, type.toString());
376 extern(D) void property(const char[] name, const char[] deconame, Type type)
378 if (type)
380 if (type.deco)
381 property(deconame, type.deco.toDString);
382 else
383 property(name, type.toString());
387 extern(D) void property(const char[] name, Parameters* parameters)
389 if (parameters is null || parameters.dim == 0)
390 return;
391 propertyStart(name);
392 arrayStart();
393 if (parameters)
395 for (size_t i = 0; i < parameters.dim; i++)
397 Parameter p = (*parameters)[i];
398 objectStart();
399 if (p.ident)
400 property("name", p.ident.toString());
401 property("type", "deco", p.type);
402 propertyStorageClass("storageClass", p.storageClass);
403 if (p.defaultArg)
404 property("default", p.defaultArg.toString());
405 objectEnd();
408 arrayEnd();
411 /* ========================================================================== */
412 void jsonProperties(Dsymbol s)
414 if (s.isModule())
415 return;
416 if (!s.isTemplateDeclaration()) // TemplateDeclaration::kind() acts weird sometimes
418 property("name", s.toString());
419 if (s.isStaticCtorDeclaration())
421 property("kind", s.isSharedStaticCtorDeclaration()
422 ? "shared static constructor" : "static constructor");
424 else if (s.isStaticDtorDeclaration())
426 property("kind", s.isSharedStaticDtorDeclaration()
427 ? "shared static destructor" : "static destructor");
429 else
430 property("kind", s.kind.toDString);
432 // TODO: How about package(names)?
433 property("protection", visibilityToString(s.visible().kind));
434 if (EnumMember em = s.isEnumMember())
436 if (em.origValue)
437 property("value", em.origValue.toString());
439 property("comment", s.comment.toDString);
440 property("line", "char", s.loc);
443 void jsonProperties(Declaration d)
445 if (d.storage_class & STC.local)
446 return;
447 jsonProperties(cast(Dsymbol)d);
448 propertyStorageClass("storageClass", d.storage_class);
449 property("linkage", d.linkage);
450 property("type", "deco", d.type);
451 // Emit originalType if it differs from type
452 if (d.type != d.originalType && d.originalType)
454 auto ostr = d.originalType.toString();
455 if (d.type)
457 auto tstr = d.type.toString();
458 if (ostr != tstr)
460 //printf("tstr = %s, ostr = %s\n", tstr, ostr);
461 property("originalType", ostr);
464 else
465 property("originalType", ostr);
469 void jsonProperties(TemplateDeclaration td)
471 jsonProperties(cast(Dsymbol)td);
472 if (td.onemember && td.onemember.isCtorDeclaration())
473 property("name", "this"); // __ctor -> this
474 else
475 property("name", td.ident.toString()); // Foo(T) -> Foo
478 /* ========================================================================== */
479 override void visit(Dsymbol s)
483 override void visit(Module s)
485 objectStart();
486 if (s.md)
487 property("name", s.md.toString());
488 property("kind", s.kind.toDString);
489 filename = s.srcfile.toString();
490 property("file", filename);
491 property("comment", s.comment.toDString);
492 propertyStart("members");
493 arrayStart();
494 for (size_t i = 0; i < s.members.dim; i++)
496 (*s.members)[i].accept(this);
498 arrayEnd();
499 objectEnd();
502 override void visit(Import s)
504 if (s.id == Id.object)
505 return;
506 objectStart();
507 propertyStart("name");
508 stringStart();
509 foreach (const pid; s.packages){
510 stringPart(pid.toString());
511 buf.writeByte('.');
513 stringPart(s.id.toString());
514 stringEnd();
515 comma();
516 property("kind", s.kind.toDString);
517 property("comment", s.comment.toDString);
518 property("line", "char", s.loc);
519 if (s.visible().kind != Visibility.Kind.public_)
520 property("protection", visibilityToString(s.visible().kind));
521 if (s.aliasId)
522 property("alias", s.aliasId.toString());
523 bool hasRenamed = false;
524 bool hasSelective = false;
525 for (size_t i = 0; i < s.aliases.dim; i++)
527 // avoid empty "renamed" and "selective" sections
528 if (hasRenamed && hasSelective)
529 break;
530 else if (s.aliases[i])
531 hasRenamed = true;
532 else
533 hasSelective = true;
535 if (hasRenamed)
537 // import foo : alias1 = target1;
538 propertyStart("renamed");
539 objectStart();
540 for (size_t i = 0; i < s.aliases.dim; i++)
542 const name = s.names[i];
543 const _alias = s.aliases[i];
544 if (_alias)
545 property(_alias.toString(), name.toString());
547 objectEnd();
549 if (hasSelective)
551 // import foo : target1;
552 propertyStart("selective");
553 arrayStart();
554 foreach (i, name; s.names)
556 if (!s.aliases[i])
557 item(name.toString());
559 arrayEnd();
561 objectEnd();
564 override void visit(AttribDeclaration d)
566 Dsymbols* ds = d.include(null);
567 if (ds)
569 for (size_t i = 0; i < ds.dim; i++)
571 Dsymbol s = (*ds)[i];
572 s.accept(this);
577 override void visit(ConditionalDeclaration d)
579 if (d.condition.inc != Include.notComputed)
581 visit(cast(AttribDeclaration)d);
582 return; // Don't visit the if/else bodies again below
584 Dsymbols* ds = d.decl ? d.decl : d.elsedecl;
585 for (size_t i = 0; i < ds.dim; i++)
587 Dsymbol s = (*ds)[i];
588 s.accept(this);
592 override void visit(TypeInfoDeclaration d)
596 override void visit(PostBlitDeclaration d)
600 override void visit(Declaration d)
602 objectStart();
603 //property("unknown", "declaration");
604 jsonProperties(d);
605 objectEnd();
608 override void visit(AggregateDeclaration d)
610 objectStart();
611 jsonProperties(d);
612 ClassDeclaration cd = d.isClassDeclaration();
613 if (cd)
615 if (cd.baseClass && cd.baseClass.ident != Id.Object)
617 property("base", cd.baseClass.toPrettyChars(true).toDString);
619 if (cd.interfaces.length)
621 propertyStart("interfaces");
622 arrayStart();
623 foreach (b; cd.interfaces)
625 item(b.sym.toPrettyChars(true).toDString);
627 arrayEnd();
630 if (d.members)
632 propertyStart("members");
633 arrayStart();
634 for (size_t i = 0; i < d.members.dim; i++)
636 Dsymbol s = (*d.members)[i];
637 s.accept(this);
639 arrayEnd();
641 objectEnd();
644 override void visit(FuncDeclaration d)
646 objectStart();
647 jsonProperties(d);
648 TypeFunction tf = cast(TypeFunction)d.type;
649 if (tf && tf.ty == Tfunction)
650 property("parameters", tf.parameterList.parameters);
651 property("endline", "endchar", d.endloc);
652 if (d.foverrides.dim)
654 propertyStart("overrides");
655 arrayStart();
656 for (size_t i = 0; i < d.foverrides.dim; i++)
658 FuncDeclaration fd = d.foverrides[i];
659 item(fd.toPrettyChars().toDString);
661 arrayEnd();
663 if (d.fdrequire)
665 propertyStart("in");
666 d.fdrequire.accept(this);
668 if (d.fdensure)
670 propertyStart("out");
671 d.fdensure.accept(this);
673 objectEnd();
676 override void visit(TemplateDeclaration d)
678 objectStart();
679 // TemplateDeclaration::kind returns the kind of its Aggregate onemember, if it is one
680 property("kind", "template");
681 jsonProperties(d);
682 propertyStart("parameters");
683 arrayStart();
684 for (size_t i = 0; i < d.parameters.dim; i++)
686 TemplateParameter s = (*d.parameters)[i];
687 objectStart();
688 property("name", s.ident.toString());
690 if (auto type = s.isTemplateTypeParameter())
692 if (s.isTemplateThisParameter())
693 property("kind", "this");
694 else
695 property("kind", "type");
696 property("type", "deco", type.specType);
697 property("default", "defaultDeco", type.defaultType);
700 if (auto value = s.isTemplateValueParameter())
702 property("kind", "value");
703 property("type", "deco", value.valType);
704 if (value.specValue)
705 property("specValue", value.specValue.toString());
706 if (value.defaultValue)
707 property("defaultValue", value.defaultValue.toString());
710 if (auto _alias = s.isTemplateAliasParameter())
712 property("kind", "alias");
713 property("type", "deco", _alias.specType);
714 if (_alias.specAlias)
715 property("specAlias", _alias.specAlias.toString());
716 if (_alias.defaultAlias)
717 property("defaultAlias", _alias.defaultAlias.toString());
720 if (auto tuple = s.isTemplateTupleParameter())
722 property("kind", "tuple");
725 objectEnd();
727 arrayEnd();
728 Expression expression = d.constraint;
729 if (expression)
731 property("constraint", expression.toString());
733 propertyStart("members");
734 arrayStart();
735 for (size_t i = 0; i < d.members.dim; i++)
737 Dsymbol s = (*d.members)[i];
738 s.accept(this);
740 arrayEnd();
741 objectEnd();
744 override void visit(EnumDeclaration d)
746 if (d.isAnonymous())
748 if (d.members)
750 for (size_t i = 0; i < d.members.dim; i++)
752 Dsymbol s = (*d.members)[i];
753 s.accept(this);
756 return;
758 objectStart();
759 jsonProperties(d);
760 property("base", "baseDeco", d.memtype);
761 if (d.members)
763 propertyStart("members");
764 arrayStart();
765 for (size_t i = 0; i < d.members.dim; i++)
767 Dsymbol s = (*d.members)[i];
768 s.accept(this);
770 arrayEnd();
772 objectEnd();
775 override void visit(EnumMember s)
777 objectStart();
778 jsonProperties(cast(Dsymbol)s);
779 property("type", "deco", s.origType);
780 objectEnd();
783 override void visit(VarDeclaration d)
785 if (d.storage_class & STC.local)
786 return;
787 objectStart();
788 jsonProperties(d);
789 if (d._init)
790 property("init", d._init.toString());
791 if (d.isField())
792 property("offset", d.offset);
793 if (!d.alignment.isUnknown() && !d.alignment.isDefault())
794 property("align", d.alignment.get());
795 objectEnd();
798 override void visit(TemplateMixin d)
800 objectStart();
801 jsonProperties(d);
802 objectEnd();
806 Generate an array of module objects that represent the syntax of each
807 "root module".
809 Params:
810 modules = array of the "root modules"
812 private void generateModules(Modules* modules)
814 arrayStart();
815 if (modules)
817 foreach (m; *modules)
819 if (global.params.verbose)
820 message("json gen %s", m.toChars());
821 m.accept(this);
824 arrayEnd();
828 Generate the "compilerInfo" object which contains information about the compiler
829 such as the filename, version, supported features, etc.
831 private void generateCompilerInfo()
833 import dmd.target : target;
834 objectStart();
835 requiredProperty("vendor", global.vendor);
836 requiredProperty("version", global.versionString());
837 property("__VERSION__", global.versionNumber());
838 requiredProperty("interface", determineCompilerInterface());
839 property("size_t", size_t.sizeof);
840 propertyStart("platforms");
841 arrayStart();
842 if (target.os == Target.OS.Windows)
844 item("windows");
846 else
848 item("posix");
849 if (target.os == Target.OS.linux)
850 item("linux");
851 else if (target.os == Target.OS.OSX)
852 item("osx");
853 else if (target.os == Target.OS.FreeBSD)
855 item("freebsd");
856 item("bsd");
858 else if (target.os == Target.OS.OpenBSD)
860 item("openbsd");
861 item("bsd");
863 else if (target.os == Target.OS.Solaris)
865 item("solaris");
866 item("bsd");
869 arrayEnd();
871 propertyStart("architectures");
872 arrayStart();
873 item(target.architectureName);
874 arrayEnd();
876 propertyStart("predefinedVersions");
877 arrayStart();
878 if (global.versionids)
880 foreach (const versionid; *global.versionids)
882 item(versionid.toString());
885 arrayEnd();
887 propertyStart("supportedFeatures");
889 objectStart();
890 scope(exit) objectEnd();
891 propertyBool("includeImports", true);
893 objectEnd();
897 Generate the "buildInfo" object which contains information specific to the
898 current build such as CWD, importPaths, configFile, etc.
900 private void generateBuildInfo()
902 objectStart();
903 requiredProperty("cwd", getcwd(null, 0).toDString);
904 requiredProperty("argv0", global.params.argv0);
905 requiredProperty("config", global.inifilename);
906 requiredProperty("libName", global.params.libname);
908 propertyStart("importPaths");
909 arrayStart();
910 if (global.params.imppath)
912 foreach (importPath; *global.params.imppath)
914 item(importPath.toDString);
917 arrayEnd();
919 propertyStart("objectFiles");
920 arrayStart();
921 foreach (objfile; global.params.objfiles)
923 item(objfile.toDString);
925 arrayEnd();
927 propertyStart("libraryFiles");
928 arrayStart();
929 foreach (lib; global.params.libfiles)
931 item(lib.toDString);
933 arrayEnd();
935 propertyStart("ddocFiles");
936 arrayStart();
937 foreach (ddocFile; global.params.ddocfiles)
939 item(ddocFile.toDString);
941 arrayEnd();
943 requiredProperty("mapFile", global.params.mapfile);
944 requiredProperty("resourceFile", global.params.resfile);
945 requiredProperty("defFile", global.params.deffile);
947 objectEnd();
951 Generate the "semantics" object which contains a 'modules' field representing
952 semantic information about all the modules used in the compilation such as
953 module name, isRoot, contentImportedFiles, etc.
955 private void generateSemantics()
957 objectStart();
958 propertyStart("modules");
959 arrayStart();
960 foreach (m; Module.amodules)
962 objectStart();
963 requiredProperty("name", m.md ? m.md.toString() : null);
964 requiredProperty("file", m.srcfile.toString());
965 propertyBool("isRoot", m.isRoot());
966 if(m.contentImportedFiles.dim > 0)
968 propertyStart("contentImports");
969 arrayStart();
970 foreach (file; m.contentImportedFiles)
972 item(file.toDString);
974 arrayEnd();
976 objectEnd();
978 arrayEnd();
979 objectEnd();
983 extern (C++) void json_generate(OutBuffer* buf, Modules* modules)
985 scope ToJsonVisitor json = new ToJsonVisitor(buf);
986 // write trailing newline
987 scope(exit) buf.writeByte('\n');
989 if (global.params.jsonFieldFlags == 0)
991 // Generate the original format, which is just an array
992 // of modules representing their syntax.
993 json.generateModules(modules);
994 json.removeComma();
996 else
998 // Generate the new format which is an object where each
999 // output option is its own field.
1001 json.objectStart();
1002 if (global.params.jsonFieldFlags & JsonFieldFlags.compilerInfo)
1004 json.propertyStart("compilerInfo");
1005 json.generateCompilerInfo();
1007 if (global.params.jsonFieldFlags & JsonFieldFlags.buildInfo)
1009 json.propertyStart("buildInfo");
1010 json.generateBuildInfo();
1012 if (global.params.jsonFieldFlags & JsonFieldFlags.modules)
1014 json.propertyStart("modules");
1015 json.generateModules(modules);
1017 if (global.params.jsonFieldFlags & JsonFieldFlags.semantics)
1019 json.propertyStart("semantics");
1020 json.generateSemantics();
1022 json.objectEnd();
1027 A string listing the name of each JSON field. Useful for errors messages.
1029 enum jsonFieldNames = () {
1030 string s;
1031 string prefix = "";
1032 foreach (idx, enumName; __traits(allMembers, JsonFieldFlags))
1034 static if (idx > 0)
1036 s ~= prefix ~ "`" ~ enumName ~ "`";
1037 prefix = ", ";
1040 return s;
1041 }();
1044 Parse the given `fieldName` and return its corresponding JsonFieldFlags value.
1046 Params:
1047 fieldName = the field name to parse
1049 Returns: JsonFieldFlags.none on error, otherwise the JsonFieldFlags value
1050 corresponding to the given fieldName.
1052 extern (C++) JsonFieldFlags tryParseJsonField(const(char)* fieldName)
1054 auto fieldNameString = fieldName.toDString();
1055 foreach (idx, enumName; __traits(allMembers, JsonFieldFlags))
1057 static if (idx > 0)
1059 if (fieldNameString == enumName)
1060 return __traits(getMember, JsonFieldFlags, enumName);
1063 return JsonFieldFlags.none;
1067 Determines and returns the compiler interface which is one of `dmd`, `ldc`,
1068 `gdc` or `sdc`. Returns `null` if no interface can be determined.
1070 private extern(D) string determineCompilerInterface()
1072 if (global.vendor == "Digital Mars D")
1073 return "dmd";
1074 if (global.vendor == "LDC")
1075 return "ldc";
1076 if (global.vendor == "GNU D")
1077 return "gdc";
1078 if (global.vendor == "SDC")
1079 return "sdc";
1080 return null;