1 /*
2 * Copyright (c) 2004 Sasha Vasko <sasha@aftercode.net>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #define LOCAL_DEBUG
20 #define EVENT_TRACE
21
22 #include "../../configure.h"
23 #include "../../libAfterStep/asapp.h"
24 #include <unistd.h>
25 #include "../../libAfterStep/screen.h"
26 #include "../../libAfterStep/module.h"
27 #include "../../libAfterStep/aswindata.h"
28 #include "../../libAfterStep/event.h"
29 #include "../../libAfterStep/wmprops.h"
30 #include "../../libAfterStep/parser.h"
31 #include "../../libAfterConf/afterconf.h"
32
33 #include "ASDocGen.h"
34 #include "xmlproc.h"
35 #include "robodoc.h"
36 #include "docfile.h"
37 #include "datadoc.h"
38
39 SyntaxDef* TopLevelSyntaxes[] =
40 {
41 &BaseSyntax,
42 &ColorSyntax,
43 &LookSyntax,
44 &FeelSyntax,
45 &AutoExecSyntax,
46 &DatabaseSyntax,
47 #define MODULE_SYNTAX_START 6
48 &PagerSyntax,
49 &WharfSyntax,
50 &WinListSyntax,
51 &WinTabsSyntax,
52 &AnimateSyntax,
53 &SoundSyntax,
54 &ArrangeSyntax,
55 &WinCommandSyntax,
56 NULL
57 };
58
59 const char *StandardSourceEntries[] =
60 {
61 "_related",
62 "_synopsis",
63 "_overview",
64 #define OPENING_PARTS_END 2
65 "_examples",
66 "_footnotes",
67 NULL
68 };
69
70 const char *PHPXrefFormat = " <? local_doc_url(\"%s.php\",\"%s\",\"%s%s\",$srcunset,$subunset) ?>\n ";
71 const char *PHPXrefFormatSetSrc = " <? local_doc_url(\"%s.php\",\"%s\",\"%s%s\",\"%s\",$subunset) ?>\n ";
72 const char *PHPXrefFormatUseSrc = " <? if ($src==\"\") $src=\"%s\"; local_doc_url(\"%s.php\",\"%s\",$src,$srcunset,$subunset) ?>\n ";
73 const char *PHPCurrPageFormat = " <b>%s</b>\n";
74
75 const char *AfterStepName = "AfterStep" ;
76 const char *UserGlossaryName = "Glossary" ;
77 const char *UserTopicIndexName = "Topic index" ;
78 const char *APIGlossaryName = "API Glossary" ;
79 const char *APITopicIndexName = "API Topic index" ;
80 const char *GlossaryName;
81 const char *TopicIndexName;
82
83 const char *ASDocTypeExtentions[DocTypes_Count] =
84 {
85 "txt",
86 "html",
87 "php",
88 "xml",
89 "man",
90 ""
91 };
92
93 const char *StandardOptionsEntry = "_standard_options" ;
94 const char *MyStylesOptionsEntry = "_mystyles" ;
95 const char *BaseOptionsEntry = "_base_config" ;
96
97 const char *DocClassStrings[4][2] =
98 {
99 {"Overview", ""},
100 {"Base options", "_base_config"},
101 {"MyStyles", "_mystyles"},
102 {"Configuration", "_options"}
103 };
104
105 typedef struct {
106 char *src_file ;
107 char *descr_short ;
108 char *descr_long ;
109 }ASApiSourceDescr;
110
111 ASApiSourceDescr libAfterImage_Sources[] =
112 {
113 {"afterimage.h", "AFTERImage", "overview of libAfterImage image library"},
114 {"asimagexml.c", "AFTERImage XML tags", "XML schema to be used for scripting image manipulation by AfterStep and ascompose"},
115 {"asvisual.h", "ASVisual", "abstraction layer on top of X Visuals, focusing on color handling" },
116 {"asimage.h", "ASImage", "internal structures and methods used for image manipulation in libAfterImage" },
117 {"blender.h", "ASImage Blending", "functionality for blending of image data using diofferent algorithms"},
118 {"export.h", "ASImage Export", "functionality for writing images into files"},
119 {"import.h", "ASImage Import", "functionality for reading images from files"},
120 {"imencdec.h", "ASImage Encoding/decoding", "encoding/decoding ASImage data from/to usable data structures"},
121 {"transform.h", "ASImage Transformations", "transformations available for ASImages"},
122 {"ximage.h", "XImage", "functionality for displaying ASImages on X display"},
123 {"ascmap.h", "Indexed Image handling", "defines main structures and function for image quantization"},
124 {"asfont.h", "ASFont", "text drawing functionality and handling of TTF and X11 fonts"},
125 {"char2uni.h", "Unicode", "handling on Unicode, UTF-8 and localized 8 bit encodings"},
126 {"apps/asview.c", "AFTERImage example 1: Image viewer","demonstrates loading and displaying of images"},
127 {"apps/asscale.c", "AFTERImage example 2: Image scaling","demonstrates image loading and scaling"},
128 {"apps/astile.c", "AFTERImage example 3: Image tiling/croping","demonstrates image tiling/cropping and tinting"},
129 {"apps/asmerge.c", "AFTERImage example 4: Image blending","demonstrates blending of multiple image using different algorithms"},
130 {"apps/asgrad.c", "AFTERImage example 5: Gradient rendering","demonstrates rendering of multi point linear gradients"},
131 {"apps/asflip.c", "AFTERImage example 6: Image rotation","demonstrates flipping image in 90 degree increments"},
132 {"apps/astext.c", "AFTERImage example 7: Text rendering","demonstrates antialiased texturized text rendering"},
133 {"apps/common.c", "AFTERImage examples common","common functions used in other examples "},
134 {"apps/ascompose.c", "AFTERImage XML script processor","provides access to libAfterImage functionality, using scripts written in custom XML dialect"},
135 {NULL, NULL, NULL}
136 };
137
138
139
140 const char *HTML_CSS_File = "html_styles.css" ;
141 const char *FAQ_HTML_CSS_File = "faq_html_styles.css" ;
142 static const char *HTML_DATA_BACKGROUND_File = "background.jpg" ;
143 /*static const char *HTML_HELP_BACKGROUND_File = NULL ; */
144 const char *CurrHtmlBackFile = NULL ;
145
146 ASHashTable *DocBookVocabulary = NULL ;
147
148 ASHashTable *ProcessedSyntaxes = NULL ;
149 ASHashTable *Glossary = NULL ;
150 ASHashTable *Index = NULL ;
151 ASHashTable *UserLinks = NULL ;
152 ASHashTable *APILinks = NULL ;
153 ASHashTable *Links = NULL ;
154
155 int DocGenerationPass = 0 ;
156 int CurrentManType = 1 ;
157
158 #define DATE_SIZE 64
159 char CurrentDateLong[DATE_SIZE] = "06/23/04";
160 char CurrentDateShort[DATE_SIZE] = "Jun 23,2004";
161
162 void check_syntax_source( const char *source_dir, SyntaxDef *syntax, Bool module );
163 void gen_syntax_doc( const char *source_dir, const char *dest_dir, SyntaxDef *syntax, ASDocType doc_type );
164 void gen_glossary( const char *dest_dir, const char *file, ASDocType doc_type );
165 void gen_index( const char *dest_dir, const char *file, ASDocType doc_type, Bool user_docs );
166 void gen_faq_doc( const char *source_dir, const char *dest_dir, ASDocType doc_type );
167
168 /*************************************************************************/
169 /*************************************************************************/
170 /*************************************************************************/
171 void
DeadPipe(int foo)172 DeadPipe (int foo)
173 {
174 {
175 static int already_dead = False ;
176 if( already_dead ) return;/* non-reentrant function ! */
177 already_dead = True ;
178 }
179 FreeMyAppResources();
180 #ifdef DEBUG_ALLOCS
181 print_unfreed_mem ();
182 #endif /* DEBUG_ALLOCS */
183
184 if( dpy )
185 {
186 XFlush (dpy);
187 XCloseDisplay (dpy);
188 }
189 exit (0);
190 }
191
192 void
asdocgen_usage(void)193 asdocgen_usage (void)
194 {
195 printf ("Usage:\n"
196 "%s\t\t[-t |--target plain|text|html|php|xml|nroff|source] [-s | -css stylesheets_file]\n"
197 "\t\t\t[--faq-css stylesheets_file] [--html-data-back background] [-d | --data]\n"
198 "\t\t\t[-S | --source source_dir] [-D | --dst destination_dir]\n"
199 "-t | --target - selects oputput file format\n"
200 "-s | --css - selects which file to get HTML style sheets from\n"
201 " --faq-css - selects which file to get HTML style sheets from for FAQs\n"
202 " --html-data-back - which image file to use as HTML background ( default background.jpg )\n"
203 "-d | --data - generate HTML catalogue of image/data files\n"
204 "-S | --source - specifies dir to read XML source or data source from\n"
205 "-D | --dst - specifies destination directory - where to wriote stuff to\n",
206 MyName);
207 exit (0);
208 }
209
210
211 int
main(int argc,char ** argv)212 main (int argc, char **argv)
213 {
214 int i ;
215 char *source_dir = NULL ;
216 const char *destination_dir = NULL ;
217 Bool do_data = False;
218 ASDocType target_type = DocType_Source ;
219 /* Save our program name - for error messages */
220 set_DeadPipe_handler(DeadPipe);
221 InitMyApp (CLASS_ASDOCGEN, argc, argv, NULL, asdocgen_usage, 0 );
222 LinkAfterStepConfig();
223 InitSession();
224 for( i = 1 ; i< argc ; ++i)
225 {
226 LOCAL_DEBUG_OUT( "argv[%d] = \"%s\", original argv[%d] = \"%s\"", i, argv[i]?argv[i]:"(null)", i, MyArgs.saved_argv[i]);
227 if( argv[i] != NULL )
228 {
229 if( (strcmp( argv[i], "-t" ) == 0 || strcmp( argv[i], "--target" ) == 0) && i+1 < argc && argv[i+1] != NULL )
230 {
231 ++i ;
232 if( mystrcasecmp( argv[i], "plain" ) == 0 || mystrcasecmp( argv[i], "text" ) == 0)
233 target_type = DocType_Plain ;
234 else if( mystrcasecmp( argv[i], "html" ) == 0 )
235 target_type = DocType_HTML ;
236 else if( mystrcasecmp( argv[i], "php" ) == 0 )
237 target_type = DocType_PHP ;
238 else if( mystrcasecmp( argv[i], "xml" ) == 0 )
239 target_type = DocType_XML ;
240 else if( mystrcasecmp( argv[i], "nroff" ) == 0 )
241 target_type = DocType_NROFF ;
242 else if( mystrcasecmp( argv[i], "source" ) == 0 )
243 target_type = DocType_Source ;
244 else
245 show_error( "unknown target type \"%s\"" );
246 }else if( (strcmp( argv[i], "-s" ) == 0 || strcmp( argv[i], "--css" ) == 0) && i+1 < argc && argv[i+1] != NULL )
247 {
248 ++i ;
249 HTML_CSS_File = argv[i] ;
250 }else if( strcmp( argv[i], "--faq-css" ) == 0 && i+1 < argc && argv[i+1] != NULL )
251 {
252 ++i ;
253 FAQ_HTML_CSS_File = argv[i] ;
254 }else if( strcmp( argv[i], "--html-data-back" ) == 0 && i+1 < argc && argv[i+1] != NULL )
255 {
256 ++i ;
257 if( strcasecmp( argv[i], "none") == 0 )
258 HTML_DATA_BACKGROUND_File = NULL ;
259 else
260 HTML_DATA_BACKGROUND_File = argv[i] ;
261 }else if( (strcmp( argv[i], "-d" ) == 0 || strcmp( argv[i], "--data" ) == 0) )
262 {
263 do_data = True ;
264 }else if( (strcmp( argv[i], "-S" ) == 0 || strcmp( argv[i], "--source" ) == 0) && i+1 < argc && argv[i+1] != NULL )
265 {
266 ++i ;
267 source_dir = argv[i] ;
268 }else if( (strcmp( argv[i], "-D" ) == 0 || strcmp( argv[i], "--dst" ) == 0) && i+1 < argc && argv[i+1] != NULL )
269 {
270 ++i ;
271 destination_dir = argv[i] ;
272 }
273 }
274 }
275 if( destination_dir == NULL )
276 destination_dir = do_data?"data":ASDocTypeExtentions[target_type] ;
277 if( source_dir == NULL )
278 source_dir = do_data?"../../afterstep":"source" ;
279
280 #if 0
281
282 ConnectAfterStep ( mask_reg, 0);
283
284 SendInfo ( "Nop \"\"", 0);
285 #endif
286 ProcessedSyntaxes = create_ashash( 7, pointer_hash_value, NULL, NULL );
287 Glossary = create_ashash( 4096, string_hash_value, string_compare, string_destroy );
288 Index = create_ashash( 4096, string_hash_value, string_compare, string_destroy );
289 UserLinks = create_ashash( 4096, string_hash_value, string_compare, string_destroy );
290 APILinks = create_ashash( 4096, string_hash_value, string_compare, string_destroy );
291
292 Links = UserLinks;
293
294 GlossaryName = UserGlossaryName ;
295 TopicIndexName = UserTopicIndexName ;
296
297 if( target_type < DocType_Source ) {
298 time_t curtime;
299 struct tm *loctime;
300 ASHashData hashd;
301
302 DocBookVocabulary = create_ashash( 7, casestring_hash_value, casestring_compare, string_destroy_without_data );
303 for( i = 1 ; i < DOCBOOK_SUPPORTED_IDS ; ++i ) {
304 hashd.i = SupportedDocBookTagInfo[i].tag_id;
305 add_hash_item( DocBookVocabulary, AS_HASHABLE(SupportedDocBookTagInfo[i].tag), hashd.vptr);
306 }
307
308 /* Get the current time. */
309 curtime = time (NULL);
310 /* Convert it to local time representation. */
311 loctime = localtime (&curtime);
312 strftime(CurrentDateLong, DATE_SIZE, "%b %e %Y", loctime);
313 strftime(CurrentDateShort, DATE_SIZE, "%m/%d/%Y", loctime);
314 }
315 i = 0 ;
316 LOCAL_DEBUG_OUT( "Starting main action... %s", "" );
317
318 if( target_type >= DocType_Source ) /* 1) generate HTML doc structure */
319 {
320 while( TopLevelSyntaxes[i] )
321 { /* create directory structure for source docs and all the missing files */
322 check_syntax_source( source_dir, TopLevelSyntaxes[i], (i >= MODULE_SYNTAX_START) );
323 ++i ;
324 }
325 check_syntax_source( source_dir, NULL, True );
326 }else if( do_data )
327 {
328 char *env_path1 = NULL, *env_path2 = NULL ;
329 ASColorScheme *cs = NULL ;
330
331 if ((dpy = XOpenDisplay (MyArgs.display_name)))
332 {
333 set_current_X_display (dpy);
334 Scr.MyDisplayWidth = DisplayWidth (dpy, Scr.screen);
335 Scr.MyDisplayHeight = DisplayHeight (dpy, Scr.screen);
336
337 Scr.asv = create_asvisual (dpy, Scr.screen, DefaultDepth(dpy,Scr.screen), NULL);
338 }else
339 {
340 Scr.asv = create_asvisual(NULL, 0, 32, NULL);
341 }
342
343 asxml_var_insert("xroot.width", 640);
344 asxml_var_insert("xroot.height", 480);
345
346 env_path1 = getenv( "IMAGE_PATH" ) ;
347 env_path2 = getenv( "PATH" );
348 if( env_path1 == NULL )
349 {
350 env_path1 = env_path2;
351 env_path2 = NULL ;
352 }
353 Scr.image_manager = create_image_manager( NULL, 2.2, env_path1, env_path2, NULL );
354 set_xml_image_manager( Scr.image_manager );
355
356 env_path1 = getenv( "FONT_PATH" ) ;
357 Scr.font_manager = create_font_manager( dpy, env_path1, NULL );
358 set_xml_font_manager( Scr.font_manager );
359
360 /*ReloadASEnvironment( NULL, NULL, NULL, False ); */
361 cs = make_default_ascolor_scheme();
362 populate_ascs_colors_rgb( cs );
363 populate_ascs_colors_xml( cs );
364 free( cs );
365
366 TopicIndexName = NULL ;
367
368 CurrHtmlBackFile = HTML_DATA_BACKGROUND_File ;
369 gen_data_doc( source_dir, destination_dir?destination_dir:"data", "",
370 "Installed data files - fonts, images and configuration",
371 target_type );
372
373 flush_ashash( Glossary );
374 flush_ashash( Index );
375 }else
376 {
377 char *api_dest_dir ;
378 api_dest_dir = make_file_name( destination_dir, "API" );
379
380 GlossaryName = UserGlossaryName ;
381 TopicIndexName = UserTopicIndexName ;
382 Links = UserLinks;
383
384 DocGenerationPass = 2 ;
385 while( --DocGenerationPass >= 0 )
386 {
387 gen_code_doc( "../../libAfterImage", destination_dir,
388 "asimagexml.c",
389 "AfterImage XML",
390 "XML schema to be used for scripting image manipulation by AfterStep and ascompose",
391 target_type );
392
393 /* we need to generate some top level files for afterstep itself : */
394 gen_syntax_doc( source_dir, destination_dir, NULL, target_type );
395
396 for( i = 0 ; TopLevelSyntaxes[i] ; ++i )
397 gen_syntax_doc( source_dir, destination_dir, TopLevelSyntaxes[i], target_type );
398
399 if( DocGenerationPass == 0 )
400 {
401 gen_faq_doc( source_dir, destination_dir, target_type );
402 gen_glossary( destination_dir, "Glossary", target_type );
403 gen_index( destination_dir, "index", target_type, True );
404 }
405 flush_ashash( ProcessedSyntaxes );
406 }
407 flush_ashash( Glossary );
408 flush_ashash( Index );
409
410 GlossaryName = APIGlossaryName ;
411 TopicIndexName = APITopicIndexName ;
412 Links = APILinks;
413 DocGenerationPass = 2 ;
414
415 CurrentManType = 3 ;
416
417 while( --DocGenerationPass >= 0 )
418 {
419 int s ;
420 for( s = 0 ; libAfterImage_Sources[s].src_file != NULL ; ++s )
421 {
422 gen_code_doc( "../../libAfterImage", api_dest_dir,
423 libAfterImage_Sources[s].src_file,
424 libAfterImage_Sources[s].descr_short,
425 libAfterImage_Sources[s].descr_long,
426 target_type );
427 }
428 if( DocGenerationPass == 0 )
429 {
430 gen_glossary( api_dest_dir, "Glossary", target_type );
431 gen_index( api_dest_dir, "index", target_type, False );
432 }
433 flush_ashash( Glossary );
434 flush_ashash( Index );
435 }
436
437
438 }
439
440 if( dpy )
441 XCloseDisplay (dpy);
442 return 0;
443 }
444
445 /*************************************************************************/
446
447 void
write_standard_options_source(FILE * f)448 write_standard_options_source( FILE *f )
449 {
450 int i = 0;
451 fprintf( f, "<anchor id=\"standard_options_list\"/>\n"
452 "<refsect1>\n"
453 "<title>STANDARD OPTIONS</title>\n"
454 "<para>The following is the list of command line options supported by"
455 " all AfterStep modules and applications.</para>"
456 "<variablelist>\n" );
457
458 while( as_standard_cmdl_options[i].long_opt )
459 {
460 fprintf( f, " <varlistentry>\n" );
461 if( as_standard_cmdl_options[i].short_opt )
462 fprintf( f, " <term>-%s | --%s", as_standard_cmdl_options[i].short_opt, as_standard_cmdl_options[i].long_opt );
463 else
464 fprintf( f, " <term> --%s", as_standard_cmdl_options[i].long_opt );
465
466 if( get_flags( as_standard_cmdl_options[i].flags, CMO_HasArgs ) )
467 fprintf( f, " <replaceable>val</replaceable>" );
468
469 fprintf( f, "</term>\n"
470 " <listitem>\n" );
471 fprintf( f, " <para>%s. ", as_standard_cmdl_options[i].descr1 );
472 if( as_standard_cmdl_options[i].descr2 )
473 fprintf( f, " %s.", as_standard_cmdl_options[i].descr2 );
474 fprintf( f, " </para>\n"
475 " </listitem>\n"
476 " </varlistentry>\n" );
477 ++i ;
478 }
479 fprintf( f, "</variablelist>\n"
480 "</refsect1>\n" );
481 }
482
483 void
check_option_source(const char * syntax_dir,const char * option,SyntaxDef * sub_syntax,const char * module_name)484 check_option_source( const char *syntax_dir, const char *option, SyntaxDef *sub_syntax, const char *module_name)
485 {
486 char *filename = make_file_name( syntax_dir, option );
487 if( CheckFile( filename ) != 0 || mystrcasecmp( option, StandardOptionsEntry ) == 0)
488 {
489 FILE *f = fopen( filename, "w" );
490 if( f )
491 {
492 if( option[0] != '_' )
493 {
494 fprintf( f, "<varlistentry id=\"options.%s\">\n"
495 " <term>%s</term>\n"
496 " <listitem>\n"
497 " <para>FIXME: add proper description here.</para>\n",
498 option, option );
499 if( sub_syntax )
500 fprintf( f, " <para>See Also: "
501 "<ulink url=\"%s#synopsis\">%s</ulink> for further details.</para>\n",
502 sub_syntax->doc_path, sub_syntax->display_name );
503 fprintf( f, " </listitem>\n"
504 "</varlistentry>\n" );
505 }else
506 {
507 fprintf( f, "<section label=\"%s\" id=\"%s\">\n", &(option[1]), &(option[1]) );
508 if( module_name )
509 {
510 if( mystrcasecmp( &(option[1]), "synopsis" ) == 0 )
511 {
512 fprintf( f, "<cmdsynopsis>\n"
513 "<command>%s</command> [<ulink url=\"%s#standard_options_list\">standard options</ulink>] \n"
514 "</cmdsynopsis>\n", module_name, AfterStepName );
515 }else if( mystrcasecmp( option, StandardOptionsEntry ) == 0 )
516 {
517 write_standard_options_source( f );
518 }
519 }
520
521 fprintf( f, "</section>\n" );
522 }
523 fclose(f);
524 }
525 show_progress( "Option %s is missing - created empty source \"%s\".", option, filename );
526 }
527 free( filename );
528 }
529
530 void
generate_main_source(const char * source_dir)531 generate_main_source( const char *source_dir )
532 {
533 int i ;
534 for (i = 0; StandardSourceEntries[i] != NULL ; ++i)
535 check_option_source( source_dir, StandardSourceEntries[i], NULL, "afterstep");
536 check_option_source( source_dir, StandardOptionsEntry, NULL, "afterstep");
537 }
538
539 void
check_syntax_source(const char * source_dir,SyntaxDef * syntax,Bool module)540 check_syntax_source( const char *source_dir, SyntaxDef *syntax, Bool module )
541 {
542 int i ;
543 char *syntax_dir = NULL ;
544 char *obsolete_dir ;
545 struct direntry **list = NULL;
546 int list_len ;
547
548 if( syntax )
549 {
550 if( get_hash_item( ProcessedSyntaxes, AS_HASHABLE(syntax), NULL ) == ASH_Success )
551 return ;
552
553 if( syntax->doc_path != NULL && syntax->doc_path[0] != '\0' )
554 syntax_dir = make_file_name (source_dir, syntax->doc_path);
555 }
556 if( syntax_dir == NULL )
557 syntax_dir = mystrdup( source_dir );
558
559 obsolete_dir = make_file_name (syntax_dir, "obsolete" );
560
561 if( CheckDir(syntax_dir) != 0 )
562 if( !make_doc_dir( syntax_dir ) )
563 {
564 free( syntax_dir );
565 return;
566 }
567
568 if( syntax )
569 {
570 add_hash_item( ProcessedSyntaxes, AS_HASHABLE(syntax), NULL );
571
572 /* pass one: lets see which of the existing files have no related options : */
573 list_len = my_scandir ((char*)syntax_dir, &list, ignore_dots, NULL);
574 for (i = 0; i < list_len; i++)
575 {
576 int k ;
577 if (!S_ISDIR (list[i]->d_mode))
578 {
579 char *name = list[i]->d_name ;
580 show_progress( "checking \"%s\" ... ", name );
581 if( name[0] != '_' )
582 {
583 for (k = 0; syntax->terms[k].keyword; k++)
584 if( mystrcasecmp(name, syntax->terms[k].keyword ) == 0 )
585 break;
586 if( syntax->terms[k].keyword == NULL || get_flags( syntax->terms[k].flags, TF_OBSOLETE) )
587 {
588 /* obsolete option - move it away */
589 char *obsolete_fname = make_file_name (obsolete_dir, name );
590 char *fname = make_file_name (syntax_dir, name );
591 Bool no_dir = False ;
592 if( CheckDir(obsolete_dir) != 0 )
593 no_dir = !make_doc_dir( obsolete_dir ) ;
594 if( !no_dir )
595 {
596 copy_file (fname, obsolete_fname);
597 show_progress( "Option \"%s\" is obsolete - moving away!", name );
598 unlink(fname);
599 }
600 free( fname );
601 free( obsolete_fname );
602 }
603 }
604 }
605 free( list[i] );
606 }
607 if( list )
608 free (list);
609 /* pass two: lets see which options are missing : */
610 for (i = 0; syntax->terms[i].keyword; i++)
611 {
612 if( !get_flags( syntax->terms[i].flags, TF_OBSOLETE) )
613 {
614 SyntaxDef *sub_syntax = syntax->terms[i].sub_syntax ;
615 if( sub_syntax == pPopupFuncSyntax )
616 sub_syntax = pFuncSyntax ;
617 if (sub_syntax)
618 check_syntax_source( source_dir, sub_syntax, False );
619 if( isalnum( syntax->terms[i].keyword[0] ) )
620 check_option_source( syntax_dir, syntax->terms[i].keyword, sub_syntax, module?syntax->doc_path:NULL ) ;
621 }
622 }
623 for (i = module?0:1; StandardSourceEntries[i] != NULL ; ++i)
624 check_option_source( syntax_dir, StandardSourceEntries[i], NULL, module?syntax->doc_path:NULL ) ;
625 if( module )
626 {
627 check_option_source( syntax_dir, BaseOptionsEntry, NULL, syntax->doc_path ) ;
628 check_option_source( syntax_dir, MyStylesOptionsEntry, NULL, syntax->doc_path ) ;
629 }
630 }else
631 generate_main_source( syntax_dir );
632
633 free( obsolete_dir );
634 free( syntax_dir );
635 }
636
637 int
sort_terms_by_alpha(const TermDef ** t1,const TermDef ** t2)638 sort_terms_by_alpha( const TermDef **t1, const TermDef **t2 )
639 {
640 return strcmp((**t1).keyword, (**t2).keyword);
641 }
642
643 void
write_options_keywords(const char * source_dir,const char * syntax_dir,SyntaxDef * syntax,ASXMLInterpreterState * state)644 write_options_keywords(const char *source_dir, const char *syntax_dir, SyntaxDef *syntax, ASXMLInterpreterState *state )
645 {
646 #define MAX_SYNTAX_RECURSION_LEVEL 32
647 static int syntax_recursion_level = -1;
648 static SyntaxDef* syntax_recursion_stack[MAX_SYNTAX_RECURSION_LEVEL];
649
650 int i, max_i = 0 ;
651 TermDef **sorted_list ;
652 while(syntax->terms[max_i].keyword) ++max_i;
653
654 if( max_i == 0 ) return ;
655
656 if (syntax_recursion_level+1 >= MAX_SYNTAX_RECURSION_LEVEL)
657 {
658 show_error ("Excessive recursion into nested Syntaxes. Syntax doc path = \"%s\".", syntax->doc_path );
659 return;
660 }
661 for (i = syntax_recursion_level; i >= 0 ; --i)
662 if (syntax_recursion_stack[i] == syntax)
663 return;
664 ++syntax_recursion_level;
665 syntax_recursion_stack[syntax_recursion_level] = syntax;
666
667 sorted_list = safecalloc( max_i, sizeof(TermDef*));
668 for (i = 0; i < max_i; i++)
669 sorted_list[i] = &(syntax->terms[i]) ;
670 qsort(sorted_list, max_i, sizeof(TermDef*), (int (*)())sort_terms_by_alpha );
671 for (i = 0; i < max_i; i++)
672 {
673 SyntaxDef *sub_syntax = sorted_list[i]->sub_syntax ;
674 if( sub_syntax == pPopupFuncSyntax )
675 sub_syntax = pFuncSyntax ;
676
677 if (sub_syntax)
678 gen_syntax_doc( source_dir, state->dest_dir, sub_syntax, state->doc_type );
679 if( isalnum( sorted_list[i]->keyword[0] ) )
680 convert_xml_file( syntax_dir, sorted_list[i]->keyword, state );
681 }
682 free( sorted_list );
683
684 syntax_recursion_stack[syntax_recursion_level] = NULL;
685 --syntax_recursion_level;
686 }
687
688 /*************************************************************************/
689 /*************************************************************************/
690 /* Document Generation code : */
691 /*************************************************************************/
692 void
gen_syntax_doc(const char * source_dir,const char * dest_dir,SyntaxDef * syntax,ASDocType doc_type)693 gen_syntax_doc( const char *source_dir, const char *dest_dir, SyntaxDef *syntax, ASDocType doc_type )
694 {
695 ASXMLInterpreterState state;
696 const char *doc_path = AfterStepName ;
697 char *syntax_dir = NULL ;
698 int i ;
699 ASFlagType doc_class_mask = 0 ;
700
701 if( syntax )
702 {
703 if( get_hash_item( ProcessedSyntaxes, AS_HASHABLE(syntax), NULL ) == ASH_Success )
704 return ;
705 doc_path = syntax->doc_path ;
706 }
707
708 if( syntax != NULL && syntax->doc_path != NULL && syntax->doc_path[0] != '\0' )
709 syntax_dir = make_file_name (source_dir, syntax->doc_path);
710 if( syntax_dir == NULL )
711 syntax_dir = mystrdup( source_dir );
712
713 if( doc_type == DocType_PHP )
714 {
715 int overview_size = 0 ;
716 int tmp ;
717 /* we generate upto 4 files in PHP mode : overview, Base config, MyStyles and Config Options
718 * Overview and Config Options are always present. Others may be ommited if source is missing
719 * If Overview is too small - say < 1024 bytes - it could be bundled with Config Options */
720
721 set_flags( doc_class_mask, DOC_CLASS_Overview );
722 LOCAL_DEBUG_OUT( "Checking what parts to generate ...%s", "");
723 if( (tmp = check_xml_contents( syntax_dir, MyStylesOptionsEntry )) > 0)
724 set_flags( doc_class_mask, DOC_CLASS_MyStyles );
725 LOCAL_DEBUG_OUT( "MyStyle size = %d", tmp );
726 if((tmp = check_xml_contents( syntax_dir, BaseOptionsEntry )) > 0)
727 set_flags( doc_class_mask, DOC_CLASS_BaseConfig );
728 LOCAL_DEBUG_OUT( "Base size = %d", tmp );
729 for( i = 0 ; StandardSourceEntries[i] ; ++i )
730 overview_size += check_xml_contents( syntax_dir, StandardSourceEntries[i] );
731 if( syntax == NULL )
732 overview_size += 0 ;
733 LOCAL_DEBUG_OUT( "overview size = %d", overview_size );
734 if( overview_size > OVERVIEW_SIZE_THRESHOLD )
735 set_flags( doc_class_mask, DOC_CLASS_Options );
736 }else
737 doc_class_mask = DOC_CLASS_None ;
738
739 if( !start_doc_file( dest_dir, doc_path, NULL, doc_type,
740 syntax?syntax->doc_path:NULL,
741 syntax?syntax->display_name:NULL,
742 syntax?syntax->display_purpose:NULL,
743 &state, doc_class_mask, DocClass_Overview ) )
744 return ;
745
746 if( doc_type != DocType_PHP )
747 {
748 /* BODY *************************************************************************/
749 i = 0 ;
750 if( syntax == NULL )
751 {
752 if ( doc_type != DocType_NROFF ) {
753 convert_xml_file( syntax_dir, StandardSourceEntries[0], &state );
754 ++i ;
755 }
756 convert_xml_file( syntax_dir, StandardOptionsEntry, &state );
757 }
758 for( ; doc_type != DocType_NROFF && i < OPENING_PARTS_END ; ++i )
759 convert_xml_file( syntax_dir, StandardSourceEntries[i], &state );
760 if( syntax )
761 {
762 convert_xml_file( syntax_dir, BaseOptionsEntry, &state );
763 convert_xml_file( syntax_dir, MyStylesOptionsEntry, &state );
764 }
765 }else
766 {
767 i = 0 ;
768 if( syntax == NULL )
769 {
770 convert_xml_file( syntax_dir, StandardSourceEntries[0], &state );
771 ++i ;
772 convert_xml_file( syntax_dir, StandardOptionsEntry, &state );
773 }
774 for( ; StandardSourceEntries[i] ; ++i ) {
775
776 if (( convert_xml_file( syntax_dir, StandardSourceEntries[i], &state ) == True) &&
777 ( i == 0 ) ) fprintf( state.dest_fp, "<hr>\n" );
778 }
779 if( get_flags( doc_class_mask, DOC_CLASS_Options ) )
780 {
781 end_doc_file( &state );
782 start_doc_file( dest_dir, doc_path, "_options", doc_type,
783 syntax?syntax->doc_path:NULL,
784 syntax?syntax->display_name:NULL,
785 syntax?syntax->display_purpose:NULL,
786 &state, doc_class_mask, DocClass_Options );
787 fprintf( state.dest_fp, "<UL>\n" );
788 }
789 }
790 LOCAL_DEBUG_OUT( "starting config_options%s", "" );
791 if( syntax && state.dest_fp )
792 {
793 write_options_header( &state );
794 write_options_keywords(source_dir, syntax_dir, syntax, &state );
795 write_options_footer( &state );
796 }
797 LOCAL_DEBUG_OUT( "done with config_options%s", "" );
798
799 if( doc_type != DocType_PHP )
800 {
801 for( i = OPENING_PARTS_END ; StandardSourceEntries[i] ; ++i )
802 convert_xml_file( syntax_dir, StandardSourceEntries[i], &state );
803 }else if( state.dest_fp )
804 {
805 if( state.doc_class == DocClass_Options )
806 fprintf( state.dest_fp, "</UL>\n" );
807 if( get_flags( doc_class_mask, DOC_CLASS_BaseConfig ) )
808 {
809 end_doc_file( &state );
810 start_doc_file( dest_dir, doc_path, BaseOptionsEntry, doc_type,
811 syntax?syntax->doc_path:NULL,
812 syntax?syntax->display_name:NULL,
813 syntax?syntax->display_purpose:NULL,
814 &state, doc_class_mask, DocClass_BaseConfig );
815 convert_xml_file( syntax_dir, BaseOptionsEntry, &state );
816 }
817 if( get_flags( doc_class_mask, DOC_CLASS_MyStyles ) )
818 {
819 end_doc_file( &state );
820 start_doc_file( dest_dir, doc_path, MyStylesOptionsEntry, doc_type,
821 syntax?syntax->doc_path:NULL,
822 syntax?syntax->display_name:NULL,
823 syntax?syntax->display_purpose:NULL,
824 &state, doc_class_mask, DocClass_MyStyles );
825 convert_xml_file( syntax_dir, MyStylesOptionsEntry, &state );
826 }
827 }
828
829
830 /* FOOTER ***********************************************************************/
831 end_doc_file( &state );
832
833 if( syntax )
834 add_hash_item( ProcessedSyntaxes, AS_HASHABLE(syntax), NULL );
835
836 free( syntax_dir );
837 }
838
839 void
gen_faq_doc(const char * source_dir,const char * dest_dir,ASDocType doc_type)840 gen_faq_doc( const char *source_dir, const char *dest_dir, ASDocType doc_type )
841 {
842 ASXMLInterpreterState state;
843 char *faq_dir = NULL ;
844 ASFlagType doc_class_mask = DOC_CLASS_None ;
845 struct direntry **list = NULL;
846 int list_len, i ;
847
848 faq_dir = make_file_name( source_dir, "FAQ" );
849
850 if( !start_doc_file( dest_dir, "afterstep_faq", NULL, doc_type,
851 "afterstep_faq",
852 "AfterStep FAQ",
853 "This document is an ever growing set of questions, statements, ideas and complaints about AfterStep version 2.0",
854 &state, doc_class_mask, DocClass_FAQ ) )
855 return ;
856
857 /* BODY *************************************************************************/
858 set_flags( state.flags, ASXMLI_OrderSections );
859 list_len = my_scandir ((char*)faq_dir, &list, ignore_dots, NULL);
860 for (i = 0; i < list_len; i++)
861 {
862 if ( !S_ISDIR (list[i]->d_mode) )
863 convert_xml_file( faq_dir, list[i]->d_name, &state );
864 free(list[i]);
865 }
866 if( list )
867 free( list );
868
869 /* FOOTER ***********************************************************************/
870 end_doc_file( &state );
871
872 free( faq_dir );
873 }
874
875
876 void
gen_glossary(const char * dest_dir,const char * file,ASDocType doc_type)877 gen_glossary( const char *dest_dir, const char *file, ASDocType doc_type )
878 {
879 ASXMLInterpreterState state;
880 LOCAL_DEBUG_OUT( "Glossary has %ld items", Glossary->items_num);
881 if( (doc_type == DocType_HTML || doc_type == DocType_PHP ) && Glossary->items_num > 0 )
882 {
883 ASHashableValue *values;
884 ASHashData *data;
885 int items_num, col_length, i ;
886 int col_end[3], col_curr[3], col_count = 3 ;
887 Bool has_items = True, col_skipped[3] = {True, True, True};
888 char c = '\0' ;
889
890 if( !start_doc_file( dest_dir, file, NULL, doc_type, NULL, NULL, NULL, &state, DOC_CLASS_None, DocClass_Glossary ) )
891 return ;
892
893 LOCAL_DEBUG_OUT( "sorting hash items : ... %s", "" );
894 values = safecalloc( Glossary->items_num, sizeof(ASHashableValue));
895 data = safecalloc( Glossary->items_num, sizeof(ASHashData));
896 items_num = sort_hash_items (Glossary, values, (void**)data, 0);
897
898 fprintf( state.dest_fp, "<p>\n" );
899 for( i = 0 ; i < items_num ; ++i )
900 {
901 if( ((char*)values[i])[0] != c )
902 {
903 c = ((char*)values[i])[0] ;
904 fprintf( state.dest_fp, "<A href=\"#glossary_%c\">%c</A> ", c, c );
905 }
906 }
907 fprintf( state.dest_fp, "<hr>\n<p><table width=100%% cellpadding=0 cellspacing=0>\n" );
908
909 if( state.doc_type == DocType_PHP )
910 col_count = 2 ;
911 col_length = (items_num+col_count-1)/col_count ;
912
913 col_curr[0] = 0 ;
914 col_end[0] = col_curr[1] = col_length ;
915 col_end[1] = col_curr[2] = col_length*2 ;
916 col_end[2] = items_num ;
917
918 while( has_items )
919 {
920 int col ;
921 fprintf( state.dest_fp, "<TR>" );
922 has_items = False ;
923 for( col = 0 ; col < col_count ; ++col )
924 {
925 int item = col_curr[col] ;
926 fprintf( state.dest_fp, "<TD width=33%% valign=top>" );
927 if( item < col_end[col] && item < items_num )
928 {
929 has_items = True ;
930 col_skipped[col] = !col_skipped[col] && item > 0 && ((char*)values[item])[0] != ((char*)values[item-1])[0] ;
931 if( !col_skipped[col] )
932 {
933 if( state.doc_type == DocType_HTML )
934 fprintf( state.dest_fp, "<A href=\"%s\">%s</A>", data[item].cptr, (char*)values[item] );
935 else if( doc_type == DocType_PHP )
936 fprintf( state.dest_fp, PHPXrefFormat, "visualdoc",(char*)values[item], data[item].cptr, "" );
937 ++(col_curr[col]) ;
938 col_skipped[col] = False ;
939 }else
940 fprintf( state.dest_fp, "<A name=\"glossary_%c\"> </A>", ((char*)values[item])[0] );
941 }
942 fprintf( state.dest_fp, " </TD>" );
943 }
944 fprintf( state.dest_fp, "</TR>\n" );
945 }
946 fprintf( state.dest_fp, "</table>\n" );
947
948 free( data );
949 free( values );
950 end_doc_file( &state );
951 }
952 }
953
954 void
gen_index(const char * dest_dir,const char * file,ASDocType doc_type,Bool user_docs)955 gen_index( const char *dest_dir, const char *file, ASDocType doc_type, Bool user_docs )
956 {
957 ASXMLInterpreterState state;
958 if( (doc_type == DocType_HTML || doc_type == DocType_PHP ) && Index->items_num > 0 )
959 {
960 ASHashableValue *values;
961 ASHashData *data;
962 int items_num, i ;
963 Bool sublist = False ;
964 char *sublist_name= NULL ;
965 int sublist_name_len = 1 ;
966 if( !start_doc_file( dest_dir, file, NULL, doc_type, NULL, NULL, NULL, &state, DOC_CLASS_None, DocClass_TopicIndex ) )
967 return ;
968 LOCAL_DEBUG_OUT( "sorting hash items : ... %s", "" );
969 values = safecalloc( Index->items_num, sizeof(ASHashableValue));
970 data = safecalloc( Index->items_num, sizeof(ASHashData));
971 items_num = sort_hash_items (Index, values, (void**)data, 0);
972
973 if( user_docs )
974 {
975 if( doc_type == DocType_PHP )
976 {
977 fprintf( state.dest_fp, PHPXrefFormat, "visualdoc","Developer documentation index","API/index", "" );
978 fprintf( state.dest_fp, PHPXrefFormat, "graphics","Installed data files catalogue","index", "" );
979 }else if( doc_type == DocType_HTML )
980 {
981 fprintf( state.dest_fp, "<A href=\"API/index.html\">Developer documentation index</A> \n" );
982 fprintf( state.dest_fp, "<A href=\"data/index.html\">Installed data files catalogue</A>\n" );
983 }
984 }else
985 {
986 if( doc_type == DocType_PHP )
987 {
988 fprintf( state.dest_fp, PHPXrefFormat, "visualdoc","User documentation index","index", "" );
989 fprintf( state.dest_fp, PHPXrefFormat, "graphics","Installed data files catalogue","index", "" );
990 }
991 else if( doc_type == DocType_HTML )
992 {
993 fprintf( state.dest_fp, "<A href=\"../index.html\">User documentation index</A> \n" );
994 fprintf( state.dest_fp, "<A href=\"../data/index.html\">Installed data files catalogue</A>\n" );
995 }
996 }
997 fprintf( state.dest_fp, "<hr>\n<p><UL class=\"dense\">\n" );
998 for( i = 0 ; i < items_num ; ++i )
999 {
1000 char *item_text = (char*)values[i];
1001 if( sublist_name )
1002 {
1003 if( strncmp( item_text, sublist_name, sublist_name_len ) == 0 )
1004 {
1005 if( !sublist )
1006 {
1007 fprintf( state.dest_fp, "\n<UL>\n" );
1008 sublist = True ;
1009 }
1010 item_text += sublist_name_len ;
1011 while( *item_text != '\0' && isspace( *item_text ) )
1012 ++item_text ;
1013 }else if( sublist )
1014 {
1015 sublist = False ;
1016 fprintf( state.dest_fp, "\n</UL>\n" );
1017 }
1018 }
1019 if( !sublist )
1020 {
1021 sublist_name = item_text ;
1022 sublist_name_len = strlen( sublist_name );
1023 }
1024 fprintf( state.dest_fp, "<LI class=\"dense\">" );
1025
1026 if( state.doc_type == DocType_HTML )
1027 fprintf( state.dest_fp, "<A href=\"%s\">%s</A>", data[i].cptr, item_text );
1028 else if( doc_type == DocType_PHP )
1029 {
1030 char *url = data[i].cptr ;
1031 char *ptr = &(url[strlen(url)-4]) ;
1032 if( *ptr == '.' )
1033 *ptr = '\0';
1034 fprintf( state.dest_fp, PHPXrefFormat, "visualdoc",item_text, url, "" );
1035 if( *ptr == '\0' )
1036 *ptr = '.';
1037 }
1038 fprintf( state.dest_fp, "</LI>\n" );
1039 }
1040 if( sublist )
1041 fprintf( state.dest_fp, "</UL>\n" );
1042 fprintf( state.dest_fp, "</UL>\n" );
1043 free( data );
1044 free( values );
1045 end_doc_file( &state );
1046 }
1047 }
1048
1049