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 = "&nbsp;<? local_doc_url(\"%s.php\",\"%s\",\"%s%s\",$srcunset,$subunset) ?>\n ";
71 const char *PHPXrefFormatSetSrc = "&nbsp;<? local_doc_url(\"%s.php\",\"%s\",\"%s%s\",\"%s\",$subunset) ?>\n ";
72 const char *PHPXrefFormatUseSrc = "&nbsp;<? if ($src==\"\") $src=\"%s\"; local_doc_url(\"%s.php\",\"%s\",$src,$srcunset,$subunset) ?>\n ";
73 const char *PHPCurrPageFormat = "&nbsp;<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>&nbsp;&nbsp;\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>&nbsp;&nbsp;\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