code to install color themes for linux + OS X builds
[ardour.git] / tools / fmt-luadoc.php
1 #!/usr/bin/php
2 <?php
3 ## USAGE
4 #
5 ## generate doc/luadoc.json.gz (lua binding doc)
6 # ./waf configure --luadoc ....
7 # ./waf
8 # ./gtk2_ardour/arluadoc > doc/luadoc.json.gz
9 #
10 ## generate doc/ardourapi.json.gz (ardour header doxygen doc)
11 # cd ../../tools/doxy2json
12 # ./ardourdoc.sh
13 # cd -
14 #
15 ## format HTML (using this scripterl)
16 # php tools/fmt-luadoc.php > /tmp/luadoc.html
17 #
18
19 $options = getopt("m");
20 if (isset ($options['m'])) {
21         $HTMLOUTPUT = false; ## set to false to output ardour-manual
22 } else {
23         $HTMLOUTPUT = true; ## set to false to output ardour-manual
24 }
25
26 ################################################################################
27 ################################################################################
28
29 $json = gzdecode (file_get_contents (dirname (__FILE__).'/../doc/luadoc.json.gz'));
30 $doc = array ();
31 $ardourversion = '';
32 foreach (json_decode ($json, true) as $b) {
33         if (!isset ($b['type'])) {
34                 if (isset ($b['version'])) { $ardourversion = $b['version']; }
35                 continue;
36         }
37         # reserved lua words
38         $b ['lua'] = preg_replace ('/:_end/', ':end', $b ['lua']);
39         $b ['lua'] = preg_replace ('/:_type/', ':type', $b ['lua']);
40         $b ['ldec'] = preg_replace ('/ const/', '', preg_replace ('/ const&/', '', $b['decl']));
41         if (isset ($b['ret'])) {
42                 $b['ret'] = preg_replace ('/ const/', '', preg_replace ('/ const&/', '', $b['ret']));
43         }
44         $doc[] = $b;
45 }
46
47 if (count ($doc) == 0) {
48         fwrite (STDERR, "Failed to read luadoc.json\n");
49         exit (1);
50 }
51
52 ################################################################################
53 ## Global result variables
54 ################################################################################
55
56 $classlist = array ();
57 $constlist = array ();
58
59
60 ################################################################################
61 ## Pre-process the data, collect functions, parse arguments, cross reference
62 ################################################################################
63
64
65 ################################################################################
66 # some internal helper functions first
67
68 $funclist = array ();
69 $classes = array ();
70 $consts = array ();
71
72 function my_die ($msg) {
73         fwrite (STDERR, $msg."\n");
74         exit (1);
75 }
76
77 ##function ptr_strip ($ctype) {
78 #       # boost::shared_ptr<std::list<boost::shared_ptr<ARDOUR::Route>> > >
79 #       # -> std::list<ARDOUR::Route>
80 #       $ctype = preg_replace ('/boost::shared_ptr<([^>]*)[ ]*>/', '$1', $ctype);
81 #       return preg_replace ('/boost::shared_ptr<([^>]*)[ ]*>/', '$1', $ctype);
82 #}
83
84 function arg2lua ($argtype, $flags = 0) {
85         global $classes;
86         global $consts;
87
88         # LuaBridge abstracts C++ references
89         $flags |= preg_match ('/&$/', $argtype);
90         $arg = preg_replace ('/&$/', '', $argtype);
91         $arg = preg_replace ('/ $/', '', $arg);
92
93         # filter out basic types
94         $builtin = array ('float', 'double', 'bool', 'std::string', 'int', 'long', 'unsigned long', 'unsigned int', 'unsigned char', 'char', 'void', 'char*', 'unsigned char*', 'void*');
95         if (in_array ($arg, $builtin)) {
96                 return array ($arg => $flags);
97         }
98
99         # check Class declarations first
100         foreach (array_merge ($classes, $consts) as $b) {
101                 if ($b['ldec'] == $arg) {
102                         return array ($b['lua'] => $flags);
103                 }
104         }
105
106         # strip class pointers -- TODO Check C'tor for given class
107         $arg = preg_replace ('/[&*]*$/', '', $argtype);
108         foreach (array_merge ($classes, $consts) as $b) {
109                 if ($b['ldec'] == $arg) {
110                         return array ($b['lua'] => $flags);
111                 }
112         }
113         if ($flags & 2) {
114                 return array ($argtype => ($flags | 4));
115         } else {
116                 return array ('--MISSING (' . $argtype . ')--' => ($flags | 4));
117         }
118 }
119
120 function stripclass ($classname, $name) {
121         $classname .= ':';
122         if (strpos ($name, $classname) !== 0) {
123                 my_die ('invalid class prefix: ' .$classname. ' -- '. $name);
124         }
125         return substr ($name, strlen ($classname));
126 }
127
128 function datatype ($decl) {
129         # TODO handle spaces in type. Works because
130         # we don't yet have templated types (with_space <here >)
131         return substr ($decl, 0, strrpos ($decl, ' '));
132 }
133
134 function luafn2class ($lua) {
135         return substr ($lua, 0, strrpos ($lua, ':'));
136 }
137
138 function luafn2name ($lua) {
139         $fn = strrpos ($lua, ':');
140         if ($fn !== 0 && strlen($lua) > $fn + 1) {
141                 return substr ($lua, $fn + 1);
142         }
143         my_die ('invalid class prefix: '. $name);
144 }
145
146
147 function checkclass ($b) {
148         global $classlist;
149         if (!isset ($classlist[luafn2class ($b['lua'])])) {
150                 my_die ('MISSING CLASS FOR '. print_r ($b['lua'], true));
151         }
152 }
153
154 # parse functions argument list to lua-names
155 function decl2args ($decl) {
156         $start = strrpos ($decl, '(');
157         $end = strrpos ($decl, ')');
158         $args = substr ($decl, $start + 1, $end - $start - 1);
159         $arglist = preg_split ('/, */', $args);
160         $rv = array ();
161         foreach ($arglist as $a) {
162                 if (empty ($a)) { continue; }
163                 $rv[] = arg2lua ($a);
164         }
165         return $rv;
166 }
167
168 function canonical_ctor ($b) {
169         $rv = '';
170         if (preg_match('/[^(]*\(([^)*]*)\*\)(\(.*\))/', $b['decl'], $matches)) {
171                 $lc = luafn2class ($b['lua']);
172                 $cn = str_replace (':', '::', $lc);
173                 $fn = substr ($lc, 1 + strrpos ($lc, ':'));
174                 $rv = $cn . '::'. $fn . $matches[2];
175         }
176         return $rv;
177 }
178
179 function canonical_decl ($b) {
180         $rv = '';
181         $pfx = '';
182         # match clang's declatation format
183         if (preg_match('/[^(]*\(([^)*]*)\*\)\((.*)\)/', $b['decl'], $matches)) {
184                 if (strpos ($b['type'], 'Free Function') !== false) {
185                         $pfx = str_replace (':', '::', luafn2class ($b['lua'])) . '::';
186                 }
187                 $fn = substr ($b['lua'], 1 + strrpos ($b['lua'], ':'));
188                 $rv = $matches[1] . $fn . '(';
189                 $arglist = preg_split ('/, */', $matches[2]);
190                 $first = true;
191                 foreach ($arglist as $a) {
192                         if (!$first) { $rv .= ', '; }; $first = false;
193                         if (empty ($a)) { continue; }
194                         $a = preg_replace ('/([^>]) >/', '$1>', $a);
195                         $a = preg_replace ('/^Cairo::/', '', $a); // special case cairo enums
196                         $a = preg_replace ('/([^ ])&/', '$1 &', $a);
197                         $a = str_replace ('vector', 'std::vector', $a);
198                         $a = str_replace ('std::string', 'string', $a);
199                         $a = str_replace ('string const', 'const string', $a);
200                         $a = str_replace ('string', 'std::string', $a);
201                         $rv .= $a;
202                 }
203                 $rv .= ')';
204         }
205         return $pfx . $rv;
206 }
207
208 ################################################################################
209 # step 1: build class indices
210
211 foreach ($doc as $b) {
212         if (strpos ($b['type'], "[C] ") === 0) {
213                 $classes[] = $b;
214                 $classlist[$b['lua']] = $b;
215                 if (strpos ($b['type'], 'Pointer Class') === false) {
216                         $classdecl[$b['ldec']] = $b;
217                 }
218         }
219 }
220
221 foreach ($classes as $c) {
222         if (strpos ($c['type'], 'Pointer Class') !== false) { continue; }
223         if (isset ($c['parent'])) {
224                 if (isset ($classdecl[$c['parent']])) {
225                         $classlist[$c['lua']]['luaparent'][] = $classdecl[$c['parent']]['lua'];
226                 } else {
227                         my_die ('unknown parent class: ' . print_r ($c, true));
228                 }
229         }
230 }
231
232 # step 2: extract constants/enum
233 foreach ($doc as $b) {
234         switch ($b['type']) {
235         case "Constant/Enum":
236         case "Constant/Enum Member":
237                 if (strpos ($b['ldec'], '::') === false) {
238                         # for extern c enums, use the Lua Namespace
239                         $b['ldec'] = str_replace (':', '::', luafn2class ($b['lua']));
240                 }
241                 $ns = str_replace ('::', ':', $b['ldec']);
242                 $constlist[$ns][] = $b;
243                 # arg2lua lookup
244                 $b['lua'] = $ns;
245                 $consts[] = $b;
246                 break;
247         default:
248                 break;
249         }
250 }
251
252 # step 3: process functions
253 foreach ($doc as $b) {
254         switch ($b['type']) {
255         case "Constructor":
256         case "Weak/Shared Pointer Constructor":
257                 checkclass ($b);
258                 $classlist[luafn2class ($b['lua'])]['ctor'][] = array (
259                         'name' => luafn2class ($b['lua']),
260                         'args' => decl2args ($b['ldec']),
261                         'cand' => canonical_ctor ($b)
262                 );
263                 break;
264         case "Data Member":
265                 checkclass ($b);
266                 $classlist[luafn2class ($b['lua'])]['data'][] = array (
267                         'name' => $b['lua'],
268                         'ret'  => arg2lua (datatype ($b['ldec']))
269                 );
270                 break;
271         case "Static C Function":
272                 checkclass ($b);
273                 if (strpos ($b['lua'], 'ARDOUR:DataType:') === 0) {
274                         # special case ARDOUR:DataType convenience c'tor
275                         $args = array ();
276                         $ret = array (luafn2class ($b['lua']) => 0);
277                         $canon = 'ARDOUR::LuaAPI::datatype_ctor_'.strtolower (luafn2name ($b['lua'])).'(lua_State*)';
278                 } else {
279                         my_die ('unhandled Static C: ' . print_r($b, true));
280                 }
281                 $classlist[luafn2class ($b['lua'])]['func'][] = array (
282                         'bind' => $b,
283                         'name' => $b['lua'],
284                         'args' => $args,
285                         'ret'  => $ret,
286                         'ref'  => false,
287                         'ext'  => false,
288                         'cand' => $canon
289                 );
290                 break;
291         case "C Function":
292                 # we required C functions to be in a class namespace
293         case "Ext C Function":
294                 checkclass ($b);
295                 $args = array (array ('--lua--' => 0));
296                 $ret = array ('...' => 0);
297                 $ns = luafn2class ($b['lua']);
298                 $cls = $classlist[$ns];
299                 if (preg_match ('/.*<([^>]*)[ ]*>/', $cls['ldec'], $templ)) {
300                         # std::vector, std::list types
301                         switch (stripclass($ns, $b['lua'])) {
302                         case 'add':
303                                 #$args = array (array ('LuaTable {'.$templ[1].'}' => 0));
304                                 $args = array (arg2lua ($templ[1], 2));
305                                 $ret = array ('LuaTable' => 0);
306                                 break;
307                         case 'iter':
308                                 $args = array ();
309                                 $ret = array ('LuaIter' => 0);
310                                 break;
311                         case 'table':
312                                 $args = array ();
313                                 $ret = array ('LuaTable' => 0);
314                                 break;
315                         default:
316                                 break;
317                         }
318                 } else if (strpos ($cls['type'], ' Array') !== false) {
319                         # catches  C:FloatArray, C:IntArray
320                         $templ = preg_replace ('/[&*]*$/', '', $cls['ldec']);
321                         switch (stripclass($ns, $b['lua'])) {
322                         case 'array':
323                                 $args = array ();
324                                 $ret = array ('LuaMetaTable' => 0);
325                                 break;
326                         case 'get_table':
327                                 $args = array ();
328                                 $ret = array ('LuaTable' => 0);
329                                 break;
330                         case 'set_table':
331                                 $args = array (array ('LuaTable {'.$templ.'}' => 0));
332                                 $ret = array ('void' => 0);
333                                 break;
334                         default:
335                                 break;
336                         }
337                 }
338                 $classlist[luafn2class ($b['lua'])]['func'][] = array (
339                         'bind' => $b,
340                         'name' => $b['lua'],
341                         'args' => $args,
342                         'ret'  => $ret,
343                         'ref'  => true,
344                         'ext'  => true,
345                         'cand' => canonical_decl ($b)
346                 );
347                 break;
348         case "Free C Function":
349                 $funclist[luafn2class ($b['lua'])][] = array (
350                         'bind' => $b,
351                         'name' => $b['lua'],
352                         'args' => $args,
353                         'ret'  => $ret,
354                         'ref'  => false,
355                         'ext'  => true,
356                         'cand' => str_replace (':', '::', $b['lua']).'(lua_State*)'
357                 );
358                 break;
359         case "Free Function":
360         case "Free Function RefReturn":
361                 $funclist[luafn2class ($b['lua'])][] = array (
362                         'bind' => $b,
363                         'name' => $b['lua'],
364                         'args' => decl2args ($b['ldec']),
365                         'ret'  => arg2lua ($b['ret']),
366                         'ref'  => (strpos ($b['type'], "RefReturn") !== false),
367                         'cand' => canonical_decl ($b)
368                 );
369                 break;
370         case "Member Function":
371         case "Member Function RefReturn":
372         case "Member Pointer Function":
373         case "Weak/Shared Pointer Function":
374         case "Weak/Shared Pointer Function RefReturn":
375         case "Weak/Shared Null Check":
376         case "Static Member Function":
377                 checkclass ($b);
378                 $classlist[luafn2class ($b['lua'])]['func'][] = array (
379                         'bind' => $b,
380                         'name' => $b['lua'],
381                         'args' => decl2args ($b['ldec']),
382                         'ret'  => arg2lua ($b['ret']),
383                         'ref'  => (strpos ($b['type'], "RefReturn") !== false),
384                         'cand' => canonical_decl ($b)
385                 );
386                 break;
387         case "Weak/Shared Pointer Cast":
388                 checkclass ($b);
389                 $classlist[luafn2class ($b['lua'])]['cast'][] = array (
390                         'bind' => $b,
391                         'name' => $b['lua'],
392                         'args' => decl2args ($b['ldec']),
393                         'ret'  => arg2lua ($b['ret']),
394                         'ref'  => (strpos ($b['type'], "RefReturn") !== false),
395                         'cand' => canonical_decl ($b)
396                 );
397                 break;
398         case "Constant/Enum":
399         case "Constant/Enum Member":
400                 # already handled -> $consts
401                 break;
402         default:
403                 if (strpos ($b['type'], "[C] ") !== 0) {
404                         my_die ('unhandled type: ' . $b['type']);
405                 }
406                 break;
407         }
408 }
409
410
411 # step 4: collect/group/sort
412
413 # step 4a: unify weak/shared Ptr classes
414 foreach ($classlist as $ns => $cl) {
415         if (strpos ($cl['type'], ' Array') !== false) {
416                 $classlist[$ns]['arr'] = true;
417                 $classlist[$ns]['cdecl'] = $cl['decl'];
418                 continue;
419         }
420         foreach ($classes as $c) {
421                 if ($c['lua'] == $ns) {
422                         if (strpos ($c['type'], 'Pointer Class') !== false) {
423                                 $classlist[$ns]['ptr'] = true;
424                                 $classlist[$ns]['cdecl'] = 'boost::shared_ptr< '.$c['decl']. ' >, boost::weak_ptr< '.$c['decl']. ' >';
425                                 break;
426                         } else {
427                                 $classlist[$ns]['cdecl'] = $c['decl'];
428                         }
429                 }
430         }
431 }
432
433 # step4b: sanity check
434 foreach ($classlist as $ns => $cl) {
435         if (isset ($classes[$ns]['parent']) && !isset ($classlist[$ns]['luaparent'])) {
436                 my_die ('missing parent class: ' . print_r ($cl, true));
437         }
438 }
439
440 # step 4c: merge free functions into classlist
441 foreach ($funclist as $ns => $fl) {
442         if (isset ($classlist[$ns])) {
443                 my_die ('Free Funcion in existing namespace: '.$ns.' '. print_r ($ns, true));
444         }
445         $classlist[$ns]['func'] = $fl;
446         $classlist[$ns]['free'] = true;
447 }
448
449 # step 4d: order to chaos
450 # no array_multisort() here, sub-types are sorted after merging parents
451 ksort ($classlist);
452
453
454 ################################################################################
455 ################################################################################
456 ################################################################################
457
458
459 #### -- split here --  ####
460
461 # from here on, only $classlist and $constlist arrays are relevant.
462 # we also pull in C++ header annotation from doxygen to $api
463
464
465 # read documentation from doxygen
466 $json = gzdecode (file_get_contents (dirname (__FILE__).'/../doc/ardourapi.json.gz'));
467 $api = array ();
468 foreach (json_decode ($json, true) as $a) {
469         if (!isset ($a['decl'])) { continue; }
470         if (empty ($a['decl'])) { continue; }
471         $canon = str_replace (' *', '*', $a['decl']);
472         $api[$canon] = $a;
473 }
474
475 # keep track of found/missing doc
476 $dox_found = 0;
477 $dox_miss = 0;
478
479 # retrive a value from $api
480 function doxydoc ($canonical_declaration) {
481         global $api;
482         global $dox_found;
483         global $dox_miss;
484         if (isset ($api[$canonical_declaration])) {
485                 $dox_found++;
486                 return $api[$canonical_declaration]['doc'];
487         }
488         // remove template namespace e.g.
489         //  "ARDOUR::Track::bounceable(boost::shared_ptr<ARDOUR::Processor>"
490         //  "ARDOUR::Track::bounceable(boost::shared_ptr<Processor>"
491         $cn = preg_replace ('/<[^>]*::([^>]*)>/', '<$1>', $canonical_declaration);
492         if (isset ($api[$cn])) {
493                 $dox_found++;
494                 return $api[$cn]['doc'];
495         }
496         #fwrite (STDERR, $canonical_declaration."\n"); # XXX DEBUG
497
498         $dox_miss++;
499         return '';
500 }
501
502 ################################################################################
503 # OUTPUT
504 ################################################################################
505
506
507 ################################################################################
508 # Helper functions
509 define ('NL', "\n");
510
511 # constructors, enums (constants) use a dot.  (e.g. "LuaOSC.Address" -> "LuaOSC.Address" )
512 function ctorname ($name) {
513         return htmlentities (str_replace (':', '.', $name));
514 }
515
516 # strip class prefix (e.g "Evoral:MidiEvent:channel"  -> "channel")
517 function shortname ($name) {
518         return htmlentities (substr ($name, strrpos ($name, ':') + 1));
519 }
520
521 # retrieve variable name from    array["VARNAME"] => FLAGS
522 function varname ($a) {
523         return array_keys ($a)[0];
524 }
525
526 # recusively collect class parents (derived classes)
527 function traverse_parent ($ns, &$inherited) {
528         global $classlist;
529         $rv = '';
530         if (isset ($classlist[$ns]['luaparent'])) {
531                 $parents = array_unique ($classlist[$ns]['luaparent']);
532                 asort ($parents);
533                 foreach ($parents as $p) {
534                         if (!empty ($rv)) { $rv .= ', '; }
535                         $rv .= typelink ($p);
536                         $inherited[$p] = $classlist[$p];
537                         traverse_parent ($p, $inherited);
538                 }
539         }
540         return $rv;
541 }
542
543 # create a cross-reference to a type (class or enum)
544 # *all* <a> links are generated here, currently anchors on a single page.
545 function typelink ($a, $short = false, $argcls = '', $linkcls = '', $suffix = '') {
546         global $classlist;
547         global $constlist;
548         if (isset($classlist[$a]['free'])) {
549                 return '<a class="'.$linkcls.'" href="#'.htmlentities ($a).'">'.($short ? shortname($a) : ctorname($a)).$suffix.'</a>';
550         } else if (in_array ($a, array_keys ($classlist))) {
551                 return '<a class="'.$linkcls.'" href="#'.htmlentities($a).'">'.($short ? shortname($a) : htmlentities($a)).$suffix.'</a>';
552         } else if (in_array ($a, array_keys ($constlist))) {
553                 return '<a class="'.$linkcls.'" href="#'.ctorname ($a).'">'.($short ? shortname($a) : ctorname($a)).$suffix.'</a>';
554         } else {
555                 return '<span class="'.$argcls.'">'.htmlentities($a).$suffix.'</span>';
556         }
557 }
558
559 # output format function arguments
560 function format_args ($args) {
561         $rv = '<span class="functionargs"> (';
562         $first = true;
563         foreach ($args as $a) {
564                 if (!$first) { $rv .= ', '; }; $first = false;
565                 $flags = $a[varname ($a)];
566                 if ($flags & 2) {
567                         $rv .= '<em>LuaTable</em> {'.typelink (varname ($a), true, 'em').'}';
568                 }
569                 elseif ($flags & 1) {
570                         $rv .= typelink (varname ($a), true, 'em', '', '&amp;');
571                 }
572                 else {
573                         $rv .= typelink (varname ($a), true, 'em');
574                 }
575         }
576         $rv .= ')</span>';
577         return $rv;
578 }
579
580 # format doxygen documentation for class-definition
581 function format_doxyclass ($cl) {
582         $rv = '';
583         if (isset ($cl['decl'])) {
584                 $doc = doxydoc ($cl['decl']);
585                 if (!empty ($doc)) {
586                         $rv.= '<div class="classdox">'.$doc.'</div>'.NL;
587                 }
588         }
589         return $rv;
590 }
591
592 # format doxygen documentation for class-members
593 function format_doxydoc ($f) {
594         $rv = '';
595         if (isset ($f['cand'])) {
596                 $doc = doxydoc ($f['cand']);
597                 if (!empty ($doc)) {
598                         $rv.= '<tr><td></td><td class="doc" colspan="2"><div class="dox">'.$doc;
599                         $rv.= '</div></td></tr>'.NL;
600                 } else if (0) { # debug
601                         $rv.= '<tr><td></td><td class="doc" colspan="2"><p>'.htmlentities($f['cand']).'</p>';
602                         $rv.= '</td></tr>'.NL;
603                 }
604         }
605         return $rv;
606 }
607
608 # usort() callback for class-members
609 function name_sort_cb ($a, $b) {
610         return strcmp ($a['name'], $b['name']);
611 }
612
613 # main output function for every class
614 function format_class_members ($ns, $cl, &$dups) {
615         $rv = '';
616         # print contructor - if any
617         if (isset ($cl['ctor'])) {
618                 usort ($cl['ctor'], 'name_sort_cb');
619                 $rv.= ' <tr><th colspan="3">Constructor</th></tr>'.NL;
620                 foreach ($cl['ctor'] as $f) {
621                         $rv.= ' <tr><td class="def">&Copf;</td><td class="decl">';
622                         $rv.= '<span class="functionname">'.ctorname ($f['name']).'</span>';
623                         $rv.= format_args ($f['args']);
624                         $rv.= '</td><td class="fill"></td></tr>'.NL;
625                         # doxygen documentation (may be empty)
626                         $rv.= format_doxydoc($f);
627                 }
628         }
629
630         # strip duplicates (inherited or derived methods)
631         # e.g  AudioTrack -> Track -> Route -> SessionObject -> Stateful
632         # all 5 have "isnil()"
633         $nondups = array ();
634         if (isset ($cl['func'])) {
635                 foreach ($cl['func'] as $f) {
636                         if (in_array (stripclass ($ns, $f['name']), $dups)) { continue; }
637                         $nondups[] = $f;
638                 }
639         }
640
641         # print methods - if any
642         if (count ($nondups) > 0) {
643                 usort ($nondups, 'name_sort_cb');
644                 $rv.= ' <tr><th colspan="3">Methods</th></tr>'.NL;
645                 foreach ($nondups as $f) {
646                         $dups[] = stripclass ($ns, $f['name']);
647                         # return value/type
648                         $rv.= ' <tr><td class="def">';
649                         if ($f['ref'] && isset ($f['ext'])) {
650                                 # external C functions
651                                 $rv.= '<em>'.varname ($f['ret']).'</em>';
652                         } elseif ($f['ref'] && varname ($f['ret']) == 'void') {
653                                 # void functions with reference args
654                                 $rv.= '<em>LuaTable</em>(...)';
655                         } elseif ($f['ref']) {
656                                 # functions with reference args and return value
657                                 $rv.= '<em>LuaTable</em>('.typelink (varname ($f['ret']), true, 'em').', ...)';
658                         } else {
659                                 # normal class members
660                                 $rv.= typelink (varname ($f['ret']), true, 'em');
661                         }
662                         # function declaration and arguments
663                         $rv.= '</td><td class="decl">';
664                         $rv.= '<span class="functionname"><abbr title="'.htmlentities($f['bind']['decl']).'">'.stripclass ($ns, $f['name']).'</abbr></span>';
665                         $rv.= format_args ($f['args']);
666                         $rv.= '</td><td class="fill"></td></tr>'.NL;
667                         # doxygen documentation (may be empty)
668                         $rv.= format_doxydoc($f);
669                 }
670         }
671         # print cast - if any
672         if (isset ($cl['cast'])) {
673                 usort ($cl['cast'], 'name_sort_cb');
674                 $rv.= ' <tr><th colspan="3">Cast</th></tr>'.NL;
675                 foreach ($cl['cast'] as $f) {
676                         $rv.= ' <tr><td class="def">';
677                         $rv.= typelink (varname ($f['ret']), true, 'em');
678                         # function declaration and arguments
679                         $rv.= '</td><td class="decl">';
680                         $rv.= '<span class="functionname"><abbr title="'.htmlentities($f['bind']['decl']).'">'.stripclass ($ns, $f['name']).'</abbr></span>';
681                         $rv.= format_args ($f['args']);
682                         $rv.= '</td><td class="fill"></td></tr>'.NL;
683                         # doxygen documentation (may be empty)
684                         $rv.= format_doxydoc($f);
685                 }
686         }
687
688         # print data members - if any
689         if (isset ($cl['data'])) {
690                 usort ($cl['data'], 'name_sort_cb');
691                 $rv.= ' <tr><th colspan="3">Data Members</th></tr>'.NL;
692                 foreach ($cl['data'] as $f) {
693                         $rv.= ' <tr><td class="def">'.typelink (array_keys ($f['ret'])[0], false, 'em').'</td><td class="decl">';
694                         $rv.= '<span class="functionname">'.stripclass ($ns, $f['name']).'</span>';
695                         $rv.= '</td><td class="fill"></td></tr>'.NL;
696                 }
697         }
698         return $rv;
699 }
700
701
702 ################################################################################
703 # Start Output
704
705 if ($HTMLOUTPUT) {
706
707 ?><!DOCTYPE html>
708 <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
709 <head>
710 <title>Ardour Lua Bindings</title>
711 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
712 <style type="text/css">
713 div.header         { text-align:center; }
714 div.header h2      { margin:0; }
715 div.header p       { margin:.25em; text-align:center; }
716 div.luafooter      { text-align:center; font-size:80%; color: #888; margin: 2em 0; }
717 #luaref            { max-width:60em; margin: 1em auto; }
718
719 #luaref h2                 { margin:2em 0 0 0; padding:0em; border-bottom: 1px solid black; }
720 #luaref h3.cls             { margin:2em 0 0 0; padding: 0 0 0 1em; border: 1px dashed #6666ee; }
721 #luaref h3.cls abbr        { text-decoration:none; cursor:default; }
722 #luaref h4.cls             { margin:1em 0 0 0; }
723 #luaref h3.class           { background-color: #aaee66; }
724 #luaref h3.enum            { background-color: #aaaaaa; }
725 #luaref h3.pointerclass    { background-color: #eeaa66; }
726 #luaref h3.array           { background-color: #66aaee; }
727 #luaref h3.opaque          { background-color: #6666aa; }
728 #luaref p                  { text-align: justify; }
729 #luaref p.cdecl            { text-align: right; float:right; font-size:90%; margin:0; padding: 0 0 0 1em; }
730 #luaref ul.classindex      { columns: 2; -webkit-columns: 2; -moz-columns: 2; }
731 #luaref div.clear          { clear:both; }
732 #luaref p.classinfo        { margin: .25em 0; }
733 #luaref div.code           { width:80%; margin:.5em auto; }
734 #luaref div.code div       { width:45%; }
735 #luaref div.code pre       { line-height: 1.2em; margin: .25em 0; }
736 #luaref div.code samp      { color: green; font-weight: bold; background-color: #eee; }
737 #luaref div.classdox       { padding: .1em 1em; }
738 #luaref div.classdox p     { margin: .5em 0 .5em .6em; }
739 #luaref div.classdox p     { margin: .5em 0 .5em .6em; }
740 #luaref div.classdox       { padding: .1em 1em; }
741 #luaref div.classdox p     { margin: .5em 0 .5em .6em; }
742 #luaref table.classmembers { width: 100%; }
743 #luaref table.classmembers th      { text-align:left; border-bottom:1px solid black; padding-top:1em; }
744 #luaref table.classmembers td.def  { text-align:right; padding-right:.5em;  white-space: nowrap; }
745 #luaref table.classmembers td.decl { text-align:left; padding-left:.5em; white-space: nowrap; }
746 #luaref table.classmembers td.doc  { text-align:left; padding-left:.6em; line-height: 1.2em; font-size:80%; }
747 #luaref table.classmembers td.doc div.dox {background-color:#eee; padding: .1em 1em; }
748 #luaref table.classmembers td.doc p { margin: .5em 0; }
749 #luaref table.classmembers td.doc p.para-brief { font-size:120%; }
750 #luaref table.classmembers td.doc p.para-returns { font-size:120%; }
751 #luaref table.classmembers td.doc dl { font-size:120%; line-height: 1.3em; }
752 #luaref table.classmembers td.doc dt { font-style: italic; }
753 #luaref table.classmembers td.fill { width: 99%; }
754 #luaref table.classmembers span.em { font-style: italic; }
755 #luaref span.functionname abbr     { text-decoration:none; cursor:default; }
756 </style>
757 </head>
758 <body>
759 <div class="header">
760 <h2>Ardour Lua Bindings</h2>
761 <p>
762 <a href="#h_classes">Class Documentation</a>
763 &nbsp;|&nbsp;
764 <a href="#h_enum">Enum/Constants</a>
765 &nbsp;|&nbsp;
766 <a href="#h_index">Index</a>
767 </p>
768 </div>
769
770 <!-- #### SNIP #### !-->
771
772 <?php
773
774 } else {
775
776 ?>
777 ---
778 layout: default
779 style: luadoc
780 title: Class Reference
781 ---
782
783 <p class="warning">
784 This documentation is far from complete may be inaccurate and subject to change.
785 </p>
786
787 <?php
788 }
789 ?>
790
791 <div id="luaref">
792
793 <?php
794
795 ################################################################################
796 # some general documentation -- should really go elsehere
797
798 ?>
799
800 <h2 id="h_intro">Overview</h2>
801 <p>
802 The top-level entry point are <?=typelink('ARDOUR:Session')?> and <?=typelink('ArdourUI:Editor')?>.
803 Most other Classes are used indirectly starting with a Session function. e.g. Session:get_routes().
804 </p>
805 <p>
806 A few classes are dedicated to certain script types, e.g. Lua DSP processors have exclusive access to
807 <?=typelink('ARDOUR:DSP')?> and <?=typelink('ARDOUR:ChanMapping')?>. Action Hooks Scripts to
808 <?=typelink('LuaSignal:Set')?> etc.
809 </p>
810 <p>
811 Detailed documentation (parameter names, method description) is not yet available. Please stay tuned.
812 </p>
813 <h3>Short introduction to Ardour classes</h3>
814 <p>
815 Ardour's structure is object oriented. The main object is the Session. A Session contains Audio Tracks, Midi Tracks and Busses.
816 Audio and Midi tracks are derived from a more general "Track" Object,  which in turn is derived from a "Route" (aka Bus).
817 (We say "An Audio Track <em>is-a</em> Track <em>is-a</em> Route").
818 Tracks contain specifics. For Example a track <em>has-a</em> diskstream (for file i/o).
819 </p>
820 <p>
821 Operations are performed on objects. One gets a reference to an object and then calls a method.
822 e.g <code>obj = Session:route_by_name("Audio")   obj:set_name("Guitar")</code>.
823 </p>
824 <p>
825 Lua automatically follows C++ class inheritance. e.g one can directly call all SessionObject and Route methods on Track object. However lua does not automatically promote objects. A Route object which just happens to be a Track needs to be explicily cast to a Track. Methods for casts are provided with each class. Note that the cast may fail and return a <em>nil</em> reference.
826 </p>
827 <p>
828 Likewise multiple inheritance is a <a href="http://www.lua.org/pil/16.3.html">non-trivial issue</a> in lua. To avoid performance penalties involved with lookups, explicit casts are required in this case. One example is <?=typelink('ARDOUR:SessionObject')?> which is-a StatefulDestructible which inhertis from both Stateful and Destructible.
829 </p>
830 <p>
831 Object lifetimes are managed by the Session. Most Objects cannot be directly created, but one asks the Session to create or destroy them. This is mainly due to realtime constrains:
832 you cannot simply remove a track that is currently processing audio. There are various <em>factory</em> methods for object creation or removal.
833 </p>
834 <h3>Pass by Reference</h3>
835 <p>
836 Since lua functions are closures, C++ methods that pass arguments by reference cannot be used as-is.
837 All parameters passed to a C++ method which uses references are returned as Lua Table.
838 If the C++ method also returns a value it is prefixed. Two parameters are returned: the value and a Lua Table holding the parameters.
839 </p>
840
841 <div class="code">
842         <div style="float:left;">C++
843
844 <pre><code class="cxx">void set_ref (int&amp; var, long&amp; val)
845 {
846         printf ("%d %ld\n", var, val);
847         var = 5;
848         val = 7;
849 }
850 </code></pre>
851
852         </div>
853         <div style="float:right;">Lua
854
855 <pre><code class="lua">local var = 0;
856 ref = set_ref (var, 2);
857 -- output from C++ printf()
858 </code><samp class="lua">0 2</samp><code>
859 -- var is still 0 here
860 print (ref[1], ref[2])
861 </code><samp class="lua">5 7</samp></pre>
862
863         </div>
864 </div>
865 <div class="clear"></div>
866 <div class="code">
867         <div style="float:left;">
868
869 <pre><code class="cxx">int set_ref2 (int &amp;var, std::string unused)
870 {
871         var = 5;
872         return 3;
873 }
874 </code></pre>
875
876         </div>
877         <div style="float:right;">
878 <pre><code class="lua">rv, ref = set_ref2 (0, "hello");
879 print (rv, ref[1], ref[2])
880 </code><samp class="lua">3 5 hello</samp></pre>
881         </div>
882 </div>
883 <div class="clear"></div>
884
885 <h3>Pointer Classes</h3>
886 <p>
887 Libardour makes extensive use of reference counted <code>boost::shared_ptr</code> to manage lifetimes.
888 The Lua bindings provide a complete abstration of this. There are no pointers in lua.
889 For example a <?=typelink('ARDOUR:Route')?> is a pointer in C++, but lua functions operate on it like it was a class instance.
890 </p>
891 <p>
892 <code>shared_ptr</code> are reference counted. Once assigned to a lua variable, the C++ object will be kept and remains valid.
893 It is good practice to assign references to lua <code>local</code> variables or reset the variable to <code>nil</code> to drop the ref.
894 </p>
895 <p>
896 All pointer classes have a <code>isnil ()</code> method. This is for two cases:
897 Construction may fail. e.g. <code><?=typelink('ARDOUR:LuaAPI')?>.newplugin()</code>
898 may not be able to find the given plugin and hence cannot create an object.
899 </p>
900 <p>
901 The second case if for <code>boost::weak_ptr</code>. As opposed to <code>boost::shared_ptr</code> weak-pointers are not reference counted.
902 The object may vanish at any time.
903 If lua code calls a method on a nil object, the interpreter will raise an exception and the script will not continue.
904 This is not unlike <code>a = nil a:test()</code> which results in en error "<em>attempt to index a nil value</em>".
905 </p>
906 <p>
907 From the lua side of things there is no distinction between weak and shared pointers. They behave identically.
908 Below they're inidicated in orange and have an arrow to indicate the pointer type.
909 Pointer Classes cannot be created in lua scripts. It always requires a call to C++ to create the Object and obtain a reference to it.
910 </p>
911
912
913 <?php
914
915 #################################
916 # Main output function -- Classes
917
918 echo '<h2 id="h_classes">Class Documentation</h2>'.NL;
919 foreach ($classlist as $ns => $cl) {
920         $dups = array ();
921         $tbl =  format_class_members ($ns, $cl, $dups);
922
923         # format class title - depending on type
924         if (empty ($tbl)) {
925                 # classes with no members (no ctor, no methods, no data)
926                 echo '<h3 id="'.htmlentities ($ns).'" class="cls opaque"><abbr title="Opaque Object">&empty;</abbr>&nbsp;'.htmlentities ($ns).'</h3>'.NL;
927         }
928         else if (isset ($classlist[$ns]['free'])) {
929                 # free functions (no class)
930                 echo '<h3 id="'.htmlentities ($ns).'" class="cls freeclass"><abbr title="Namespace">&Nopf;</abbr>&nbsp;'.ctorname($ns).'</h3>'.NL;
931         }
932         else if (isset ($classlist[$ns]['arr'])) {
933                 # C Arrays
934                 echo '<h3 id="'.htmlentities ($ns).'" class="cls array"><abbr title="C Array">&ctdot;</abbr>&nbsp;'.htmlentities ($ns).'</h3>'.NL;
935         }
936         else if (isset ($classlist[$ns]['ptr'])) {
937                 # Pointer Classes
938                 echo '<h3 id="'.htmlentities ($ns).'" class="cls pointerclass"><abbr title="Pointer Class">&Rarr;</abbr>&nbsp;'. htmlentities ($ns).'</h3>'.NL;
939         }
940         else {
941                 # Normal Class
942                 echo '<h3 id="'.htmlentities ($ns).'" class="cls class"><abbr title="Class">&comp;</abbr>&nbsp;'.htmlentities ($ns).'</h3>'.NL;
943         }
944
945         # show original C++ declaration
946         if (isset ($cl['cdecl'])) {
947                 echo '<p class="cdecl"><em>C&#8225;</em>: '.htmlentities ($cl['cdecl']).'</p>'.NL;
948         }
949
950         # print class inheritance (direct parent *name* only)
951         $inherited = array ();
952         $isa = traverse_parent ($ns, $inherited);
953         if (!empty ($isa)) {
954                 echo ' <p class="classinfo">is-a: '.$isa.'</p>'.NL;
955         }
956         echo '<div class="clear"></div>'.NL;
957
958
959         # class documentation (if any)
960         echo format_doxyclass ($cl);
961
962         # member documentation
963         if (empty ($tbl)) {
964                 echo '<p class="classinfo">This class object is only used indirectly as return-value and function-parameter. It provides no methods by itself.</p>'.NL;
965         } else {
966                 echo '<table class="classmembers">'.NL;
967                 echo $tbl;
968                 echo ' </table>'.NL;
969         }
970
971         # traverse parent classes (all inherited members)
972         foreach ($inherited as $pns => $pcl) {
973                 $tbl = format_class_members ($pns, $pcl, $dups);
974                 if (!empty ($tbl)) {
975                         echo '<h4 class="cls">Inherited from '.$pns.'</h4>'.NL;
976                         echo '<table class="classmembers">'.NL;
977                         echo $tbl;
978                         echo '</table>'.NL;
979                 }
980         }
981 }
982
983 ####################
984 # Enum and Constants
985
986 echo '<h2 id="h_enum">Enum/Constants</h2>'.NL;
987 foreach ($constlist as $ns => $cs) {
988         echo '<h3 id="'.ctorname ($ns).'" class="cls enum"><abbr title="Enum">&isin;</abbr>&nbsp;'.ctorname ($ns).'</h3>'.NL;
989         echo '<ul class="enum">'.NL;
990         foreach ($cs as $c) {
991                 echo '<li class="const">'.ctorname ($c['lua']).'</li>'.NL;
992         }
993         echo '</ul>'.NL;
994 }
995
996 ######################
997 # Index of all classes
998
999 echo '<h2 id="h_index" >Class Index</h2>'.NL;
1000 echo '<ul class="classindex">'.NL;
1001 foreach ($classlist as $ns => $cl) {
1002         echo '<li>'.typelink($ns).'</li>'.NL;
1003 }
1004 echo '</ul>'.NL;
1005
1006
1007 # see how far there is still to go...
1008 fwrite (STDERR, "Found $dox_found annotations. missing: $dox_miss\n");
1009 echo '<!-- '.$dox_found.' / '.$dox_miss.' !-->'.NL;
1010
1011 ?>
1012 </div>
1013 <div class="luafooter">Ardour <?=$ardourversion?> &nbsp;-&nbsp; <?=date('r')?></div>
1014 <?php
1015
1016 if ($HTMLOUTPUT) {
1017         echo '<!-- #### SNIP #### !-->'.NL;
1018         echo '</body>'.NL;
1019         echo '</html>'.NL;
1020 }