1 // Copyright 2009 The Archiveopteryx Developers <info@aox.org>
2
3 #include "manpage.h"
4
5 #include "class.h"
6 #include "function.h"
7 #include "file.h"
8
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <sys/fcntl.h>
12 #include <unistd.h>
13
14
15 static ManPage * mp = 0;
16
17
18 /*! \class ManPage manpage.h
19 The ManPage class provides documentation output to a UNIX man page.
20
21 It implements the same functions as Output, but they're not static,
22 and is called when Output's static functions are called.
23 */
24
25
26 /*! Constructs an empty man page generator which will write man pages
27 in the \a dir directory. */
28
ManPage(const char * dir)29 ManPage::ManPage( const char * dir )
30 : para( false ), fd( -1 ), directory( dir )
31 {
32 mp = this;
33 }
34
35
36 /*! Destroys the man page object, flushing and closing the generated file. */
37
~ManPage()38 ManPage::~ManPage()
39 {
40 endPage();
41 mp = 0;
42 }
43
44
45 /*! Returns a pointer to the most recently constructed ManPage object,
46 or a null pointer if none has been constructed yet. */
47
current()48 ManPage * ManPage::current()
49 {
50 return mp;
51 }
52
53
54 /*! For the moment, we do not generate introductory manual
55 pages. Perhaps it would be possible. This function makes ManPage
56 discard output until startHeadline() is called for a Class.
57 */
58
startHeadline(Intro *)59 void ManPage::startHeadline( Intro * )
60 {
61 endPage();
62 }
63
64
65 /*! As Output::startHeadline(). \a c is used only to generate a
66 suitable man page named.
67 */
68
startHeadline(Class * c)69 void ManPage::startHeadline( Class * c )
70 {
71 endPage();
72 EString filename = directory + "/" + c->name().lower() + ".3oryx";
73 fd = ::open( filename.cstr(), O_CREAT|O_WRONLY|O_TRUNC, 0644 );
74 para = true;
75 output( ".\\\" generated by udoc from source code\n"
76 ".TH " );
77 addText( c->name() );
78 output( " 3oryx x/x/x Oryx Oryx\n"
79 ".nh\n"
80 ".SH NAME\n" );
81 addText( c->name() );
82 output( " class\n"
83 ".SH SYNOPSIS\n"
84 "\\fC#include <" );
85 addText( c->file()->name() );
86 output( ">\\fR\n"
87 ".SH DESCRIPTION\n" );
88 }
89
90
91 /*! As Output::startHeadline().
92 */
93
startHeadline(Function *)94 void ManPage::startHeadline( Function * )
95 {
96 output( ".SH " );
97 para = true;
98 }
99
100
101 /*! As Output::endParagraph(). */
102
endParagraph()103 void ManPage::endParagraph()
104 {
105 if ( para )
106 output( "\n" );
107 para = false;
108 }
109
110
111 /*! As Output::addText(). \a text is escaped (how?). */
112
addText(const EString & text)113 void ManPage::addText( const EString & text )
114 {
115 if ( !para ) {
116 output( ".PP\n" );
117 para = true;
118 }
119
120 EString s;
121 uint i = 0;
122 while ( i < text.length() ) {
123 if ( text[i] == '\\' )
124 s.append( "\\\\" );
125 else
126 s.append( text[i] );
127 i++;
128 }
129 output( s );
130 }
131
132
133 /*! As Output::addArgument(). \a text is used italicized. */
134
addArgument(const EString & text)135 void ManPage::addArgument( const EString & text )
136 {
137 addText( "" );
138 output( "\\fI" );
139 addText( text );
140 output( "\\fR" );
141 }
142
143
144 /*! As Output::addFunction(). At present this outputs \a text in the
145 regular font, maybe it should use a different font?
146
147 The class to which \a f belongs is mentioned in the "see also" section.
148 */
149
addFunction(const EString & text,Function * f)150 void ManPage::addFunction( const EString & text, Function * f )
151 {
152 addText( text );
153 addClass( "", f->parent() ); // no text, but make a See Also
154 }
155
156
157 /*! As Output::addClass(). \a text is output as-is, and the name of \a
158 c is remembered for later mention in the See Also section.
159 */
160
addClass(const EString & text,Class * c)161 void ManPage::addClass( const EString & text, Class * c )
162 {
163 addText( text );
164 EString n = c->name() + "(3oryx)";
165 if ( !references.find( n ) )
166 references.insert( new EString( n ) );
167 }
168
169
170 /*! Write \a s to the output file. */
171
output(const EString & s)172 void ManPage::output( const EString & s )
173 {
174 if ( fd < 0 || s.isEmpty() )
175 return;
176 int r = ::write( fd, s.data(), s.length() );
177 r = r;
178 }
179
180
181 /*! Adds a See Also section mentioning everything we've mentioned
182 (using addClass()).
183 */
184
addReferences()185 void ManPage::addReferences()
186 {
187 if ( references.isEmpty() )
188 return;
189 endParagraph();
190 output( ".SH SEE ALSO\n.ad l\n" );
191 SortedList<EString>::Iterator it( references );
192 while ( it ) {
193 EString s( *it );
194 ++it;
195 addText( s );
196 if ( !it )
197 addText( "." );
198 else if ( it == references.last() )
199 addText( " and " );
200 else
201 addText( ", " );
202 }
203 references.clear();
204 }
205
206
207 /*! Add boilerplate describing the author. Will need configurability. */
208
addAuthor()209 void ManPage::addAuthor()
210 {
211 endParagraph();
212 output( ".SH AUTHOR\n" );
213 addText( "Automatically generated from source code belonging to " );
214 addText( Output::owner() );
215 if ( !Output::ownerHome().isEmpty() ) {
216 addText( " (" );
217 addText( Output::ownerHome() );
218 addText( ")" );
219 }
220 addText( ". All rights reserved." );
221 endParagraph();
222 }
223
224
225 /*! Emits the routing verbiage at the end of a manpage. */
226
endPage()227 void ManPage::endPage()
228 {
229 if ( fd < 0 )
230 return;
231
232 addAuthor();
233 addReferences();
234 endParagraph();
235 ::close( fd );
236 }
237