2008-05-08 Julien Chaffraix <jchaffraix@webkit.org>
[WebKit-https.git] / WebCore / dom / make_names.pl
1 #!/usr/bin/perl -w
2
3 # Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
4 #
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions
7 # are met:
8 #
9 # 1.  Redistributions of source code must retain the above copyright
10 #     notice, this list of conditions and the following disclaimer. 
11 # 2.  Redistributions in binary form must reproduce the above copyright
12 #     notice, this list of conditions and the following disclaimer in the
13 #     documentation and/or other materials provided with the distribution. 
14 # 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 #     its contributors may be used to endorse or promote products derived
16 #     from this software without specific prior written permission. 
17 #
18 # THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 # DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 use strict;
30 use Getopt::Long;
31 use File::Path;
32 use Config;
33
34 my $printFactory = 0;
35 my $cppNamespace = "";
36 my $namespace = "";
37 my $namespacePrefix = "";
38 my $namespaceURI = "";
39 my $tagsFile = "";
40 my $attrsFile = "";
41 my $outputDir = ".";
42 my @tags = ();
43 my @attrs = ();
44 my $tagsNullNamespace = 0;
45 my $attrsNullNamespace = 0;
46 my $extraDefines = 0;
47 my $preprocessor = "/usr/bin/gcc -E -P -x c++";
48 my $guardFactoryWith = 0;
49
50 GetOptions('tags=s' => \$tagsFile, 
51     'attrs=s' => \$attrsFile,
52     'outputDir=s' => \$outputDir,
53     'namespace=s' => \$namespace,
54     'namespacePrefix=s' => \$namespacePrefix,
55     'namespaceURI=s' => \$namespaceURI,
56     'cppNamespace=s' => \$cppNamespace,
57     'factory' => \$printFactory,
58     'tagsNullNamespace' => \$tagsNullNamespace,
59     'attrsNullNamespace' => \$attrsNullNamespace,
60     'extraDefines=s' => \$extraDefines,
61     'preprocessor=s' => \$preprocessor,
62     'guardFactoryWith=s' => \$guardFactoryWith);
63
64 die "You must specify a namespace (e.g. SVG) for <namespace>Names.h" unless $namespace;
65 die "You must specify a namespaceURI (e.g. http://www.w3.org/2000/svg)" unless $namespaceURI;
66 die "You must specify a cppNamespace (e.g. DOM) used for <cppNamespace>::<namespace>Names::fooTag" unless $cppNamespace;
67 die "You must specify at least one of --tags <file> or --attrs <file>" unless (length($tagsFile) || length($attrsFile));
68
69 $namespacePrefix = $namespace unless $namespacePrefix;
70
71 @tags = readNames($tagsFile) if length($tagsFile);
72 @attrs = readNames($attrsFile) if length($attrsFile);
73
74 mkpath($outputDir);
75 my $namesBasePath = "$outputDir/${namespace}Names";
76 my $factoryBasePath = "$outputDir/${namespace}ElementFactory";
77
78 printNamesHeaderFile("$namesBasePath.h");
79 printNamesCppFile("$namesBasePath.cpp");
80 if ($printFactory) {
81     printFactoryCppFile("$factoryBasePath.cpp");
82     printFactoryHeaderFile("$factoryBasePath.h");
83 }
84
85
86 ## Support routines
87
88 sub readNames
89 {
90     my $namesFile = shift;
91
92     if ($extraDefines eq 0) {
93         die "Failed to open file: $namesFile" unless open NAMES, $preprocessor . " " . $namesFile . "|" or die;
94     } else {
95         die "Failed to open file: $namesFile" unless open NAMES, $preprocessor . " -D" . join(" -D", split(" ", $extraDefines)) . " " . $namesFile . "|" or die;
96     }
97
98     my @names = ();
99     while (<NAMES>) {
100         next if (m/#/);
101         next if (m/^[ \t]*$/);
102         s/-/_/g;
103         chomp $_;
104         push @names, $_;
105     }    
106     close(NAMES);
107     
108     die "Failed to read names from file: $namesFile" unless (scalar(@names));
109     
110     return @names
111 }
112
113 sub printMacros
114 {
115     my ($F, $macro, $suffix, @names) = @_;
116     for my $name (@names) {
117         print F "    $macro $name","$suffix;\n";
118     }
119 }
120
121 sub printConstructors
122 {
123     my ($F, @names) = @_;
124     print F "#if $guardFactoryWith\n" if $guardFactoryWith;
125     for my $name (@names) {
126         my $upperCase = upperCaseName($name);
127     
128         print F "${namespace}Element *${name}Constructor(Document *doc, bool createdByParser)\n";
129         print F "{\n";
130         print F "    return new ${namespace}${upperCase}Element(${name}Tag, doc);\n";
131         print F "}\n\n";
132     }
133     print F "#endif\n" if $guardFactoryWith;
134 }
135
136 sub printFunctionInits
137 {
138     my ($F, @names) = @_;
139     for my $name (@names) {
140         print F "    gFunctionMap->set(${name}Tag.localName().impl(), ${name}Constructor);\n";
141     }
142 }
143
144 sub svgCapitalizationHacks
145 {
146     my $name = shift;
147     
148     if ($name =~ /^fe(.+)$/) {
149         $name = "FE" . ucfirst $1;
150     }
151     $name =~ s/kern/Kern/;
152     $name =~ s/mpath/MPath/;
153     $name =~ s/svg/SVG/;
154     $name =~ s/tref/TRef/;
155     $name =~ s/tspan/TSpan/;
156     
157     return $name;
158 }
159
160 sub upperCaseName
161 {
162     my $name = shift;
163     
164     $name = svgCapitalizationHacks($name) if ($namespace eq "SVG");
165     
166     while ($name =~ /^(.*?)_(.*)/) {
167         $name = $1 . ucfirst $2;
168     }
169     
170     return ucfirst $name;
171 }
172
173 sub printLicenseHeader
174 {
175     my $F = shift;
176     print F "/*
177  * THIS FILE IS AUTOMATICALLY GENERATED, DO NOT EDIT.
178  *
179  *
180  * Copyright (C) 2005 Apple Computer, Inc.  All rights reserved.
181  *
182  * Redistribution and use in source and binary forms, with or without
183  * modification, are permitted provided that the following conditions
184  * are met:
185  * 1. Redistributions of source code must retain the above copyright
186  *    notice, this list of conditions and the following disclaimer.
187  * 2. Redistributions in binary form must reproduce the above copyright
188  *    notice, this list of conditions and the following disclaimer in the
189  *    documentation and/or other materials provided with the distribution.
190  *
191  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
192  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
193  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
194  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
195  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
196  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
197  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
198  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
199  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
200  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
201  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
202  */
203
204
205 ";
206 }
207
208 sub printNamesHeaderFile
209 {
210     my ($headerPath) = shift;
211     my $F;
212     open F, ">$headerPath";
213     
214     printLicenseHeader($F);
215     print F "#ifndef DOM_${namespace}NAMES_H\n";
216     print F "#define DOM_${namespace}NAMES_H\n\n";
217     print F "#include \"QualifiedName.h\"\n\n";
218     
219     print F "namespace $cppNamespace { namespace ${namespace}Names {\n\n";
220     
221     my $lowerNamespace = lc($namespacePrefix);
222     print F "#ifndef DOM_${namespace}NAMES_HIDE_GLOBALS\n";
223     print F "// Namespace\n";
224     print F "extern const WebCore::AtomicString ${lowerNamespace}NamespaceURI;\n\n";
225
226     if (scalar(@tags)) {
227         print F "// Tags\n";
228         printMacros($F, "extern const WebCore::QualifiedName", "Tag", @tags);
229         print F "\n\nWebCore::QualifiedName** get${namespace}Tags(size_t* size);\n";
230     }
231     
232     if (scalar(@attrs)) {
233         print F "// Attributes\n";
234         printMacros($F, "extern const WebCore::QualifiedName", "Attr", @attrs);
235         print F "\n\nWebCore::QualifiedName** get${namespace}Attr(size_t* size);\n";
236     }
237     print F "#endif\n\n";
238     print F "void init();\n\n";
239     print F "} }\n\n";
240     print F "#endif\n\n";
241     
242     close F;
243 }
244
245 sub printNamesCppFile
246 {
247     my $cppPath = shift;
248     my $F;
249     open F, ">$cppPath";
250     
251     printLicenseHeader($F);
252     
253     my $lowerNamespace = lc($namespacePrefix);
254
255 print F "#include \"config.h\"\n";
256
257 print F "#ifdef AVOID_STATIC_CONSTRUCTORS\n";
258 print F "#define DOM_${namespace}NAMES_HIDE_GLOBALS 1\n";
259 print F "#else\n";
260 print F "#define QNAME_DEFAULT_CONSTRUCTOR 1\n";
261 print F "#endif\n\n";
262
263
264 print F "#include \"${namespace}Names.h\"\n\n";
265 print F "#include \"StaticConstructors.h\"\n";
266
267 print F "namespace $cppNamespace { namespace ${namespace}Names {
268
269 using namespace WebCore;
270
271 DEFINE_GLOBAL(AtomicString, ${lowerNamespace}NamespaceURI, \"$namespaceURI\")
272 ";
273
274     if (scalar(@tags)) {
275         print F "// Tags\n";
276         for my $name (@tags) {
277             print F "DEFINE_GLOBAL(QualifiedName, ", $name, "Tag, nullAtom, \"$name\", ${lowerNamespace}NamespaceURI);\n";
278         }
279         
280         print F "\n\nWebCore::QualifiedName** get${namespace}Tags(size_t* size)\n";
281         print F "{\n    static WebCore::QualifiedName* ${namespace}Tags[] = {\n";
282         for my $name (@tags) {
283             print F "        (WebCore::QualifiedName*)&${name}Tag,\n";
284         }
285         print F "    };\n";
286         print F "    *size = ", scalar(@tags), ";\n";
287         print F "    return ${namespace}Tags;\n";
288         print F "}\n";
289         
290     }
291
292     if (scalar(@attrs)) {
293         print F "\n// Attributes\n";
294         for my $name (@attrs) {
295             print F "DEFINE_GLOBAL(QualifiedName, ", $name, "Attr, nullAtom, \"$name\", ${lowerNamespace}NamespaceURI);\n";
296         }
297         print F "\n\nWebCore::QualifiedName** get${namespace}Attrs(size_t* size)\n";
298         print F "{\n    static WebCore::QualifiedName* ${namespace}Attr[] = {\n";
299         for my $name (@attrs) {
300             print F "        (WebCore::QualifiedName*)&${name}Attr,\n";
301         }
302         print F "    };\n";
303         print F "    *size = ", scalar(@attrs), ";\n";
304         print F "    return ${namespace}Attr;\n";
305         print F "}\n";
306     }
307
308 print F "\nvoid init()
309 {
310     static bool initialized = false;
311     if (initialized)
312         return;
313     initialized = true;
314     
315     // Use placement new to initialize the globals.
316     
317     AtomicString::init();
318 ";
319     
320     print(F "    AtomicString ${lowerNamespace}NS(\"$namespaceURI\");\n\n");
321
322     print(F "    // Namespace\n");
323     print(F "    new ((void*)&${lowerNamespace}NamespaceURI) AtomicString(${lowerNamespace}NS);\n\n");
324     if (scalar(@tags)) {
325         my $tagsNamespace = $tagsNullNamespace ? "nullAtom" : "${lowerNamespace}NS";
326         printDefinitions($F, \@tags, "tags", $tagsNamespace);
327     }
328     if (scalar(@attrs)) {
329         my $attrsNamespace = $attrsNullNamespace ? "nullAtom" : "${lowerNamespace}NS";
330         printDefinitions($F, \@attrs, "attributes", $attrsNamespace);
331     }
332
333     print F "}\n\n} }\n\n";
334     close F;
335 }
336
337 sub printElementIncludes
338 {
339     my ($F, @names) = @_;
340     for my $name (@names) {
341         my $upperCase = upperCaseName($name);
342         print F "#include \"${namespace}${upperCase}Element.h\"\n";
343     }
344 }
345
346 sub printDefinitions
347 {
348     my ($F, $namesRef, $type, $namespaceURI) = @_;
349     my $singularType = substr($type, 0, -1);
350     my $shortType = substr($singularType, 0, 4);
351     my $shortCamelType = ucfirst($shortType);
352     my $shortUpperType = uc($shortType);
353     
354     print F "    // " . ucfirst($type) . "\n";
355
356     for my $name (@$namesRef) {
357         print F "    const char *$name","${shortCamelType}String = \"$name\";\n";
358     }
359         
360     for my $name (@$namesRef) {
361         if ($name =~ /_/) {
362             my $realName = $name;
363             $realName =~ s/_/-/g;
364             print F "    ${name}${shortCamelType}String = \"$realName\";\n";
365         }
366     }
367     print F "\n";
368
369     for my $name (@$namesRef) {
370         print F "    new ((void*)&$name","${shortCamelType}) QualifiedName(nullAtom, $name","${shortCamelType}String, $namespaceURI);\n";
371     }
372
373 }
374
375 sub printFactoryCppFile
376 {
377     my $cppPath = shift;
378     my $F;
379     open F, ">$cppPath";
380
381 printLicenseHeader($F);
382
383 print F <<END
384 #include "config.h"
385 #include "${namespace}ElementFactory.h"
386 #include "${namespace}Names.h"
387 #include "Page.h"
388 #include "Settings.h"
389 END
390 ;
391
392 printElementIncludes($F, @tags);
393
394 print F <<END
395 #include <wtf/HashMap.h>
396
397 using namespace WebCore;
398 using namespace ${cppNamespace}::${namespace}Names;
399
400 typedef ${namespace}Element *(*ConstructorFunc)(Document *doc, bool createdByParser);
401 typedef WTF::HashMap<AtomicStringImpl*, ConstructorFunc> FunctionMap;
402
403 static FunctionMap *gFunctionMap = 0;
404
405 namespace ${cppNamespace} {
406
407 END
408 ;
409
410 printConstructors($F, @tags);
411
412 print F "#if $guardFactoryWith\n" if $guardFactoryWith;
413
414 print F <<END
415 static inline void createFunctionMapIfNecessary()
416 {
417     if (gFunctionMap)
418         return;
419     // Create the table.
420     gFunctionMap = new FunctionMap;
421     
422     // Populate it with constructor functions.
423 END
424 ;
425
426 printFunctionInits($F, @tags);
427
428 print F "}\n";
429 print F "#endif\n\n" if $guardFactoryWith;
430
431 print F <<END
432 ${namespace}Element *${namespace}ElementFactory::create${namespace}Element(const QualifiedName& qName, Document* doc, bool createdByParser)
433 {
434 END
435 ;
436
437 print F "#if $guardFactoryWith\n" if $guardFactoryWith;
438
439 print F <<END
440     // Don't make elements without a document
441     if (!doc)
442         return 0;
443
444 #if ENABLE(DASHBOARD_SUPPORT)
445     Settings* settings = doc->settings();
446     if (settings && settings->usesDashboardBackwardCompatibilityMode())
447         return 0;
448 #endif
449
450     createFunctionMapIfNecessary();
451     ConstructorFunc func = gFunctionMap->get(qName.localName().impl());
452     if (func)
453         return func(doc, createdByParser);
454
455     return new ${namespace}Element(qName, doc);
456 END
457 ;
458
459 if ($guardFactoryWith) {
460
461 print F <<END
462 #else
463     return 0;
464 #endif
465 END
466 ;
467
468 }
469
470 print F <<END
471 }
472
473 } // namespace
474
475 END
476 ;
477
478     close F;
479 }
480
481 sub printFactoryHeaderFile
482 {
483     my $headerPath = shift;
484     my $F;
485     open F, ">$headerPath";
486
487     printLicenseHeader($F);
488
489 print F "#ifndef ${namespace}ELEMENTFACTORY_H\n";
490 print F "#define ${namespace}ELEMENTFACTORY_H\n\n";
491
492 print F "
493 namespace WebCore {
494     class Element;
495     class Document;
496     class QualifiedName;
497     class AtomicString;
498 }
499
500 namespace ${cppNamespace}
501 {
502     class ${namespace}Element;
503
504     // The idea behind this class is that there will eventually be a mapping from namespace URIs to ElementFactories that can dispense
505     // elements.  In a compound document world, the generic createElement function (will end up being virtual) will be called.
506     class ${namespace}ElementFactory
507     {
508     public:
509         WebCore::Element *createElement(const WebCore::QualifiedName& qName, WebCore::Document *doc, bool createdByParser = true);
510         static ${namespace}Element *create${namespace}Element(const WebCore::QualifiedName& qName, WebCore::Document *doc, bool createdByParser = true);
511     };
512 }
513
514 #endif
515
516 ";
517
518     close F;
519 }