Imported Robodoc.
[robodoc.git] / Source / troff_generator.c
1 /*
2 Copyright (C) 1994-2007  Frans Slothouber, Jacco van Weert, Petteri Kettunen,
3 Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner,
4 Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai.
5
6 This file is part of ROBODoc
7
8 ROBODoc is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
21 */
22
23
24 #include <string.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <time.h>
28 #include <assert.h>
29 #include <errno.h>
30 #include <ctype.h>
31
32 #if defined(__MINGW32__) || defined( RB_MSVC )
33
34 #include "items.h"
35 #include "headers.h"
36 #include "robodoc.h"
37
38 /* Set of dummy functions just to make it compile. */
39 char               *RB_TROFF_Get_Default_Extension(
40     void )
41 {
42     return ".3";                /* Section 3 of manual */
43 }
44
45 void RB_TROFF_Generate_Doc_End(
46     FILE *dest_doc,
47     char *name )
48 {
49     USE( dest_doc );
50     USE( name );
51 }
52
53 FILE               *RB_TROFF_Generate_Header_Start(
54     FILE *dest_doc,
55     struct RB_header *cur_header )
56 {
57     USE( dest_doc );
58     USE( cur_header );
59     return NULL;
60 }
61
62 void RB_TROFF_Generate_Header_End(
63     FILE *dest_doc,
64     struct RB_header *cur_header )
65 {
66     USE( dest_doc );
67     USE( cur_header );
68 }
69
70
71 void RB_TROFF_Generate_Char(
72     FILE *dest_doc,
73     int c )
74 {
75     USE( dest_doc );
76     USE( c );
77 }
78
79 void RB_TROFF_Generate_False_Link(
80     FILE *out,
81     char *name )
82 {
83     USE( out );
84     USE( name );
85
86 }
87
88 void RB_TROFF_Generate_Item_Name(
89     FILE *out,
90     char *name,
91     int pre )
92 {
93     USE( out );
94     USE( name );
95     USE( pre );
96 }
97
98 void RB_TROFF_Start_New_Line(
99     FILE *out )
100 {
101     USE( out );
102 }
103
104 int RB_TROFF_Generate_Extra(
105     FILE *out,
106     enum ItemType item_type,
107     char *str )
108 {
109     USE( out );
110     USE( item_type );
111     USE( str );
112     return -1;
113 }
114
115 void RB_TROFF_Set_Param(
116     char *compress,
117     char *section )
118 {
119     USE( compress );
120     USE( section );
121 }
122
123 void TROFF_Generate_Begin_List_Item(
124     FILE *out )
125 {
126     USE( out );
127 }
128
129 void TROFF_Generate_End_List_Item(
130     FILE *out )
131 {
132     USE( out );
133 }
134
135 void TROFF_Generate_Begin_Preformatted(
136     FILE *out )
137 {
138     USE( out );
139 }
140
141 void TROFF_Generate_End_Preformatted(
142     FILE *out )
143 {
144     USE( out );
145 }
146
147 void TROFF_Generate_End_Paragraph(
148     FILE *out )
149 {
150     USE( out );
151 }
152
153 void TROFF_Generate_Begin_Paragraph(
154     FILE *out )
155 {
156     USE( out );
157 }
158
159 #else
160
161 #include <sys/param.h>
162
163 #include "troff_generator.h"
164 #include "util.h"
165 #include "robodoc.h"
166 #include "items.h"
167 #include "headers.h"
168 #include "generator.h"
169 #include "file.h"
170 #include "part.h"
171
172 static int          skip_space = 1;
173 static int          in_list = 0;
174 static int          preformat = 0;
175 static int          skippre = 0;
176 static int          end_of_line = 0;
177 static int          end_of_para = 0;
178
179 static char        *compress_cmd = NULL;
180 static char        *compress_ext = NULL;
181 static char        *man_section = NULL;
182
183 /****h* ROBODoc/TROFF_Generator
184  * FUNCTION
185  *   Generator for TROFF output.
186  * NOTE
187  *   Almost finished.
188  ******
189  */
190
191 char               *RB_TROFF_Get_Default_Extension(
192     void )
193 {
194     return ".3";                /* Section 3 of manual */
195 }
196
197 /****f* TROFF_Generator/RB_TROFF_Generate_Doc_End
198  * NAME
199  *   RB_TROFF_Generate_Doc_End --
200  *****
201  */
202
203 void RB_TROFF_Generate_Doc_End(
204     FILE *dest_doc,
205     char *name )
206 {
207
208 }
209
210 static FILE        *open_output_file(
211     char *out )
212 {
213     if ( compress_cmd )
214     {
215         FILE               *file;
216         char               *cmd =
217             malloc( strlen( out ) + 10 + strlen( compress_cmd ) );
218
219         sprintf( cmd, "%s > %s", compress_cmd, out );
220
221         file = popen( cmd, "w" );
222         free( cmd );
223         return file;
224     }
225     else
226         return fopen( out, "w" );
227 }
228
229 static void write_comment(
230     FILE *out,
231     char *str )
232 {
233     int                 start = 1;
234
235     while ( *str )
236     {
237         if ( start )
238         {
239             fputs( ".\\\" ", out );
240             start = 0;
241         }
242         switch ( *str )
243         {
244         case '.':
245             fputs( "\\.", out );
246             break;
247         case '-':
248             fputs( "\\-", out );
249             break;
250         case '\\':
251             fputs( "\\\\", out );
252             break;
253         case '\n':
254             start = 1;          /* no break; */
255         default:
256             fputc( *str, out );
257         }
258         str++;
259     }
260     if ( start == 0 )
261         fputc( '\n', out );
262 }
263
264 static char        *basename(
265     char *str )
266 {
267     char               *base = strrchr( str, '/' );
268
269     return base ? base + 1 : str;
270 }
271
272 /****f* TROFF_Generator/RB_TROFF_Generate_Header_Start
273  * NAME
274  *   RB_TROFF_Generate_Header_Start
275  ******
276  */
277
278 FILE               *RB_TROFF_Generate_Header_Start(
279     FILE *dest_doc,
280     struct RB_header *cur_header )
281 {
282     static char        *manpage = NULL;
283
284     if ( manpage == NULL )
285         manpage = malloc( MAXPATHLEN );
286
287     if ( cur_header->name )
288     {
289         char               *file =
290             RB_Get_FullDocname( cur_header->owner->filename );
291         char               *name = basename( cur_header->name );
292         char               *path = basename( file );
293         int                 len, i;
294
295         len = path - file;
296         memcpy( manpage, file, len );
297         sprintf( manpage + len, "%s.%s%s", name, man_section, compress_ext );
298
299         dest_doc = open_output_file( manpage );
300         if ( dest_doc == NULL )
301         {
302             RB_Panic( "Cannot open %s: %s\n", manpage, strerror( errno ) );
303         }
304
305         RB_Say( "+ Generating man page \"%s\"\n", SAY_INFO, manpage );
306
307         /* Check for aliases */
308         for ( i = 1; i < cur_header->no_names; i++ )
309         {
310             char               *base = basename( cur_header->names[i] );
311             char               *buf = strchr( manpage, 0 ) + 1;
312
313             memcpy( buf, file, len );
314             sprintf( buf + len, "%s.%s%s", base, man_section, compress_ext );
315             unlink( buf );
316             symlink( basename( manpage ), buf );
317             RB_Say( "+ Linked with \"%s\"\n", SAY_INFO, buf );
318         }
319
320         /* Append document type and title */
321         fprintf( dest_doc, ".\\\" Source: %s\n",
322                  cur_header->owner->filename->fullname );
323
324         write_comment( dest_doc, COMMENT_ROBODOC COMMENT_COPYRIGHT );
325
326         fprintf( dest_doc, ".TH %s %s \"", name, man_section );
327         {
328             time_t              ttp;
329             char                timeBuffer[255];
330
331             time( &ttp );
332             strftime( timeBuffer, sizeof timeBuffer, "%b %d, %Y",
333                       localtime( &ttp ) );
334             fputs( timeBuffer, dest_doc );
335
336             if ( name > cur_header->name )
337             {
338                 path = cur_header->name;
339                 len = name - path - 1;
340             }
341             else
342                 len = strlen( path = name );
343             if ( len >= sizeof timeBuffer )
344                 len = sizeof timeBuffer - 1;
345             memcpy( timeBuffer, path, len );
346             timeBuffer[len] = 0;
347             fprintf( dest_doc, "\" %s \"%s Reference\"\n", timeBuffer,
348                      timeBuffer );
349         }
350     }
351     return dest_doc;
352 }
353
354
355 /****f* TROFF_Generator/RB_TROFF_Generate_Header_End
356  * NAME
357  *   RB_TROFF_Generate_Header_End --
358  *****
359  */
360 void RB_TROFF_Generate_Header_End(
361     FILE *dest_doc,
362     struct RB_header *cur_header )
363 {
364     fclose( dest_doc );
365 }
366
367
368 void RB_TROFF_Generate_Char(
369     FILE *dest_doc,
370     int c )
371 {
372     if ( skip_space && utf8_isspace( c ) )
373         return;
374     skip_space = 0;
375     if ( in_list == 1 && utf8_isspace( c ) )
376     {
377         fprintf( dest_doc, "\n\\-\\ " );
378         in_list = 2;
379         skip_space = 1;
380         return;
381     }
382     else
383         switch ( c )
384         {
385         case '\n':
386             assert( 0 );
387             break;
388         case '\t':
389             assert( 0 );
390             break;
391         case '\\':
392         case '-':
393         case '.':
394             fputc( '\\', dest_doc );
395             fputc( c, dest_doc );
396             break;
397         default:
398             fputc( c, dest_doc );
399         }
400     end_of_para = 0;
401 }
402
403 void RB_TROFF_Generate_False_Link(
404     FILE *out,
405     char *name )
406 {
407     fprintf( out, "\\fB%s\\fR", name );
408     if ( in_list )
409         fprintf( out, " \\- " );
410     in_list = 0;
411 }
412
413 void RB_TROFF_Generate_Item_Name(
414     FILE *out,
415     char *name,
416     int pre )
417 {
418     if ( preformat )
419     {
420         fprintf( out, "\n.fi" );
421     }
422     fprintf( out, "\n.SH %s\n", name );
423     if ( ( preformat = pre ) )
424     {
425         fprintf( out, ".nf\n" );
426         skippre = -1;
427     }
428     else
429         skippre = 0;
430     in_list = 0;
431 }
432
433 void RB_TROFF_Start_New_Line(
434     FILE *out )
435 {
436     if ( end_of_para && in_list )
437     {
438         fprintf( out, "\n.PP" );
439         in_list = 0;
440     }
441     skip_space = 1;
442     end_of_line = 1;
443     end_of_para = 1;
444 }
445
446 int RB_TROFF_Generate_Extra(
447     FILE *out,
448     enum ItemType item_type,
449     char *str )
450 {
451     if ( end_of_line == 0 )
452         return -1;
453     end_of_line = 0;
454     if ( preformat )
455     {
456         int                 len = strlen( str );
457
458         if ( skippre == -1 )
459         {
460             for ( skippre = 0; utf8_isspace( *str ); skippre++, str++ );
461             if ( skippre == 0 )
462                 skippre--;
463         }
464
465         len = skippre > len ? len : skippre;
466         skip_space = 0;
467         return len > 0 ? len - 1 : -1;
468     }
469     else
470     {
471         char               *p = str;
472         char               *skip;
473         char               *item;
474
475         /* Start of a line */
476         while ( utf8_isspace( *p ) )
477             p++;
478         skip = p;
479         if ( strchr( "-o*", *p ) == NULL )
480         {
481             while ( !utf8_isspace( *p ) && *p )
482                 p++;
483             item = p;
484             while ( utf8_isspace( *p ) )
485                 p++;
486             if ( *p != '-' )
487                 return -1;
488             p++;
489             if ( *p == '-' )
490                 p++;
491             if ( !utf8_isspace( p[1] ) )
492                 return -1;
493             in_list = 1;
494             *item = 0;
495             fprintf( out, ".TP\n.I %s\n\\-\\ ", skip );
496             strcpy( p, p + 2 );
497             skip = item;
498             *item = ' ';
499         }
500         else
501         {
502             if ( !utf8_isspace( p[1] ) )
503                 return -1;
504             fprintf( out, ".IP -\n" );
505             skip++;
506         }
507         in_list = 2;
508         skip_space = 1;
509         return skip > str ? skip - str - 1 : -1;
510     }
511     return -1;
512 }
513
514 void RB_TROFF_Set_Param(
515     char *compress,
516     char *section )
517 {
518     if ( compress == NULL || *compress == 0
519          || strcasecmp( compress, "none" ) == 0 )
520     {
521         compress_cmd = NULL;
522         compress_ext = "";
523     }
524     else if ( strcasecmp( compress, "gzip" ) == 0 )
525     {
526         compress_cmd = "gzip -c";
527         compress_ext = ".gz";
528     }
529     else if ( strcasecmp( compress, "bzip2" ) == 0 )
530     {
531         compress_cmd = "bzip2 -c";
532         compress_ext = ".bz2";
533     }
534     else
535     {
536         RB_Panic( "Unknown compression compress \"%s\"\n", compress );
537     }
538     if ( section == NULL || *section == 0 )
539         man_section = "3";
540     else
541         man_section = section;
542 }
543
544 void TROFF_Generate_Begin_List_Item(
545     FILE *out )
546 {
547 /*      fprintf( out, ".IP -\n" ); */
548 }
549
550 void TROFF_Generate_End_List_Item(
551     FILE *out )
552 {
553 /*      fprintf( out, ".PP\n" ); */
554 }
555
556 void TROFF_Generate_Begin_Preformatted(
557     FILE *out )
558 {
559 /*      fprintf( out, ".nf\n" ); */
560 }
561
562 void TROFF_Generate_End_Preformatted(
563     FILE *out )
564 {
565 /*      fprintf( out, ".fi\n" ); */
566 }
567
568 void TROFF_Generate_End_Paragraph(
569     FILE *out )
570 {
571 /*      fputc( '\n', out ); */
572 }
573
574 void TROFF_Generate_Begin_Paragraph(
575     FILE *out )
576 {
577 /*      fprintf( out, ".PP\n" ); */
578 }
579
580 #endif
581