|
018a983…
|
drh
|
1 |
<title>Adding Features To Fossil</title> |
|
018a983…
|
drh
|
2 |
|
|
018a983…
|
drh
|
3 |
<h2>1.0 Introduction</h2> |
|
018a983…
|
drh
|
4 |
|
|
abf865b…
|
drh
|
5 |
This article provides a brief overview of how to write new C-code code that |
|
abf865b…
|
drh
|
6 |
extends or enhances the core Fossil binary. |
|
abf865b…
|
drh
|
7 |
|
|
abf865b…
|
drh
|
8 |
New features can be added to a Fossil server using |
|
abf865b…
|
drh
|
9 |
[./serverext.wiki|external CGI programs], |
|
abf865b…
|
drh
|
10 |
but that is not what this article is about. |
|
abf865b…
|
drh
|
11 |
This article focuses on how to make changes |
|
abf865b…
|
drh
|
12 |
to Fossil itself. |
|
018a983…
|
drh
|
13 |
|
|
018a983…
|
drh
|
14 |
<h2>2.0 Programming Language</h2> |
|
018a983…
|
drh
|
15 |
|
|
018a983…
|
drh
|
16 |
Fossil is written in C-89. There are specific [./style.wiki | style guidelines] |
|
018a983…
|
drh
|
17 |
that are required for any new code that will be accepted into the Fossil core. |
|
018a983…
|
drh
|
18 |
But, of course, if you are writing an extension just for yourself, you can |
|
018a983…
|
drh
|
19 |
use any programming style you want. |
|
018a983…
|
drh
|
20 |
|
|
c334fc9…
|
drh
|
21 |
The source code for Fossil is not sent directly into the C compiler. |
|
018a983…
|
drh
|
22 |
There are three separate code [./makefile.wiki#preprocessing|preprocessors] |
|
018a983…
|
drh
|
23 |
that run over the code first. |
|
018a983…
|
drh
|
24 |
|
|
018a983…
|
drh
|
25 |
1. The <b>mkindex</b> preprocessor scans all regular source files looking |
|
018a983…
|
drh
|
26 |
for special comments that contain "help" text and which identify routines |
|
018a983…
|
drh
|
27 |
that implement specific commands or which generate particular web pages. |
|
018a983…
|
drh
|
28 |
|
|
018a983…
|
drh
|
29 |
2. The <b>makeheaders</b> preprocessor generates all the ".h" files |
|
018a983…
|
drh
|
30 |
automatically. Fossil programmers write ".c" files only and let the |
|
018a983…
|
drh
|
31 |
makeheaders preprocessor create the ".h" files. |
|
018a983…
|
drh
|
32 |
|
|
f47b705…
|
jan.nijtmans
|
33 |
3. The <b>translate</b> preprocessor converts source code lines that |
|
018a983…
|
drh
|
34 |
begin with "@" into string literals, or into print statements that |
|
018a983…
|
drh
|
35 |
generate web page output, depending on context. |
|
018a983…
|
drh
|
36 |
|
|
018a983…
|
drh
|
37 |
The [./makefile.wiki|Makefile] for Fossil takes care of running these |
|
018a983…
|
drh
|
38 |
preprocessors with all the right arguments and in the right order. So it is |
|
018a983…
|
drh
|
39 |
not necessary to understand the details of how these preprocessors work. |
|
018a983…
|
drh
|
40 |
(Though, the sources for all three preprocessors are included in the source |
|
018a983…
|
drh
|
41 |
tree and are well commented, if you want to dig deeper.) It is only necessary |
|
efd79f8…
|
drh
|
42 |
to know that these preprocessors exist and hence will affect the way you |
|
018a983…
|
drh
|
43 |
write code. |
|
018a983…
|
drh
|
44 |
|
|
018a983…
|
drh
|
45 |
<h2>3.0 Adding New Source Code Files</h2> |
|
018a983…
|
drh
|
46 |
|
|
018a983…
|
drh
|
47 |
New source code files are added in the "src/" subdirectory of the Fossil |
|
018a983…
|
drh
|
48 |
source tree. Suppose one wants to add a new source code file named |
|
018a983…
|
drh
|
49 |
"xyzzy.c". The first step is to add this file to the various makefiles. |
|
b3460ed…
|
stephan
|
50 |
Do so by editing the file tools/makemake.tcl and adding "xyzzy" (without |
|
018a983…
|
drh
|
51 |
the final ".c") to the list of source modules at the top of that script. |
|
f47b705…
|
jan.nijtmans
|
52 |
Save the result and then run the makemake.tcl script using a TCL |
|
018a983…
|
drh
|
53 |
interpreter. The command to run the makemake.tcl script is: |
|
018a983…
|
drh
|
54 |
|
|
4003c65…
|
wyoung
|
55 |
<verbatim> |
|
4003c65…
|
wyoung
|
56 |
tclsh makemake.tcl |
|
4003c65…
|
wyoung
|
57 |
</verbatim> |
|
018a983…
|
drh
|
58 |
|
|
018a983…
|
drh
|
59 |
The working directory must be src/ when the command above is run. |
|
018a983…
|
drh
|
60 |
Note that TCL is not normally required to build Fossil, but |
|
018a983…
|
drh
|
61 |
it is required for this step. If you do not have a TCL interpreter on |
|
018a983…
|
drh
|
62 |
your system already, they are easy to install. A popular choice is the |
|
018a983…
|
drh
|
63 |
[http://www.activestate.com/activetcl|Active Tcl] installation from |
|
018a983…
|
drh
|
64 |
ActiveState. |
|
018a983…
|
drh
|
65 |
|
|
018a983…
|
drh
|
66 |
After the makefiles have been updated, create the xyzzy.c source file |
|
018a983…
|
drh
|
67 |
from the following template: |
|
018a983…
|
drh
|
68 |
|
|
8a1ba49…
|
wyoung
|
69 |
<verbatim> |
|
018a983…
|
drh
|
70 |
/* |
|
018a983…
|
drh
|
71 |
** Copyright boilerplate goes here. |
|
018a983…
|
drh
|
72 |
***************************************************** |
|
f47b705…
|
jan.nijtmans
|
73 |
** High-level description of what this module goes |
|
018a983…
|
drh
|
74 |
** here. |
|
018a983…
|
drh
|
75 |
*/ |
|
018a983…
|
drh
|
76 |
#include "config.h" |
|
018a983…
|
drh
|
77 |
#include "xyzzy.h" |
|
018a983…
|
drh
|
78 |
|
|
018a983…
|
drh
|
79 |
#if INTERFACE |
|
018a983…
|
drh
|
80 |
/* Exported object (structure) definitions or #defines |
|
018a983…
|
drh
|
81 |
** go here */ |
|
22a9fba…
|
andybradford
|
82 |
#endif /* INTERFACE */ |
|
018a983…
|
drh
|
83 |
|
|
018a983…
|
drh
|
84 |
/* New code goes here */ |
|
8a1ba49…
|
wyoung
|
85 |
</verbatim> |
|
018a983…
|
drh
|
86 |
|
|
018a983…
|
drh
|
87 |
Note in particular the <b>#include "xyzzy.h"</b> line near the top. |
|
018a983…
|
drh
|
88 |
The "xyzzy.h" file is automatically generated by makeheaders. Every |
|
018a983…
|
drh
|
89 |
normal Fossil source file must have a #include at the top that imports |
|
018a983…
|
drh
|
90 |
its private header file. (Some source files, such as "sqlite3.c" are |
|
018a983…
|
drh
|
91 |
exceptions to this rule. Don't worry about those exceptions. The |
|
018a983…
|
drh
|
92 |
files you write will require this #include line.) |
|
018a983…
|
drh
|
93 |
|
|
018a983…
|
drh
|
94 |
The "#if INTERFACE ... #endif" section is optional and is only needed |
|
018a983…
|
drh
|
95 |
if there are structure definitions or typedefs or macros that need to |
|
f47b705…
|
jan.nijtmans
|
96 |
be used by other source code files. The makeheaders preprocessor |
|
018a983…
|
drh
|
97 |
uses definitions in the INTERFACE section to help it generate header |
|
b3460ed…
|
stephan
|
98 |
files. See [../tools/makeheaders.html | makeheaders.html] for additional |
|
018a983…
|
drh
|
99 |
information. |
|
018a983…
|
drh
|
100 |
|
|
018a983…
|
drh
|
101 |
After creating a template file such as shown above, and after updating |
|
018a983…
|
drh
|
102 |
the makefiles, you should be able to recompile Fossil and have it include |
|
efd79f8…
|
drh
|
103 |
your new source file, even before your source file contains any code. |
|
018a983…
|
drh
|
104 |
It is recommended that you try this. |
|
018a983…
|
drh
|
105 |
|
|
018a983…
|
drh
|
106 |
Be sure to [/help/add|fossil add] your new source file to the self-hosting |
|
018a983…
|
drh
|
107 |
Fossil repository and then [/help/commit|commit] your changes! |
|
018a983…
|
drh
|
108 |
|
|
93cee1f…
|
wyoung
|
109 |
<h2 id="newcmd">4.0 Creating A New Command</h2> |
|
018a983…
|
drh
|
110 |
|
|
018a983…
|
drh
|
111 |
By "commands" we mean the keywords that follow "fossil" when invoking |
|
018a983…
|
drh
|
112 |
Fossil from the command-line. So, for example, in |
|
018a983…
|
drh
|
113 |
|
|
4003c65…
|
wyoung
|
114 |
<verbatim> |
|
4003c65…
|
wyoung
|
115 |
fossil diff xyzzy.c |
|
4003c65…
|
wyoung
|
116 |
</verbatim> |
|
018a983…
|
drh
|
117 |
|
|
018a983…
|
drh
|
118 |
The "command" is "diff". Commands may optionally be followed by |
|
018a983…
|
drh
|
119 |
arguments and/or options. To create new commands in Fossil, add code |
|
018a983…
|
drh
|
120 |
(either to an existing source file, or to a new source file created as |
|
018a983…
|
drh
|
121 |
described above) according to the following template: |
|
018a983…
|
drh
|
122 |
|
|
8a1ba49…
|
wyoung
|
123 |
<verbatim> |
|
018a983…
|
drh
|
124 |
/* |
|
018a983…
|
drh
|
125 |
** COMMAND: xyzzy |
|
018a983…
|
drh
|
126 |
** |
|
5c8f557…
|
danield
|
127 |
** Help text goes here. Backslashes must be escaped. |
|
018a983…
|
drh
|
128 |
*/ |
|
018a983…
|
drh
|
129 |
void xyzzy_cmd(void){ |
|
018a983…
|
drh
|
130 |
/* Implement the command here */ |
|
018a983…
|
drh
|
131 |
fossil_print("Hello, World!\n"); |
|
018a983…
|
drh
|
132 |
} |
|
8a1ba49…
|
wyoung
|
133 |
</verbatim> |
|
018a983…
|
drh
|
134 |
|
|
018a983…
|
drh
|
135 |
The example above creates a new command named "xyzzy" that prints the |
|
018a983…
|
drh
|
136 |
message "Hello, World!" on the console. This command is a normal command |
|
018a983…
|
drh
|
137 |
that will show up in the list of command from [/help/help|fossil help]. |
|
018a983…
|
drh
|
138 |
If you add an asterisk to the end of the command name, like this: |
|
018a983…
|
drh
|
139 |
|
|
8a1ba49…
|
wyoung
|
140 |
<verbatim> |
|
018a983…
|
drh
|
141 |
** COMMAND: xyzzy* |
|
8a1ba49…
|
wyoung
|
142 |
</verbatim> |
|
018a983…
|
drh
|
143 |
|
|
018a983…
|
drh
|
144 |
Then the command will only show up if you add the "--all" option to |
|
018a983…
|
drh
|
145 |
[/help/help|fossil help]. Or, if the command name starts with |
|
018a983…
|
drh
|
146 |
"test" then the command will be considered experimental and will only |
|
249ac41…
|
jan.nijtmans
|
147 |
show up when the --test option is used with [/help/help|fossil help]. |
|
018a983…
|
drh
|
148 |
|
|
018a983…
|
drh
|
149 |
The example above is a fully functioning Fossil command. You can add |
|
018a983…
|
drh
|
150 |
the text shown to an existing Fossil source file, recompiling then test |
|
018a983…
|
drh
|
151 |
it out by typing: |
|
018a983…
|
drh
|
152 |
|
|
4003c65…
|
wyoung
|
153 |
<verbatim> |
|
4003c65…
|
wyoung
|
154 |
./fossil xyzzy |
|
4003c65…
|
wyoung
|
155 |
./fossil help xyzzy |
|
4003c65…
|
wyoung
|
156 |
./fossil xyzzy --help |
|
4003c65…
|
wyoung
|
157 |
</verbatim> |
|
018a983…
|
drh
|
158 |
|
|
018a983…
|
drh
|
159 |
The name of the C function that implements the command can be anything |
|
018a983…
|
drh
|
160 |
you like (as long as it does not collide with some other symbol in the |
|
018a983…
|
drh
|
161 |
Fossil code) but it is traditional to name the function |
|
018a983…
|
drh
|
162 |
"<i>commandname</i><b>_cmd</b>", as is done in the example. |
|
018a983…
|
drh
|
163 |
|
|
018a983…
|
drh
|
164 |
You could also use "printf()" instead of "fossil_print()" to generate |
|
018a983…
|
drh
|
165 |
the output text, if desired. But "fossil_print()" is recommended as |
|
018a983…
|
drh
|
166 |
it has extra logic to insert \r characters at the right times on |
|
fe38a76…
|
drh
|
167 |
Windows systems. |
|
018a983…
|
drh
|
168 |
|
|
018a983…
|
drh
|
169 |
Once you have the command running, you can then start adding code to |
|
3947457…
|
jan.nijtmans
|
170 |
make it do useful things. There are lots of utility functions in |
|
018a983…
|
drh
|
171 |
Fossil for parsing command-line options and for |
|
018a983…
|
drh
|
172 |
opening and accessing and manipulating the repository and |
|
04af93e…
|
drh
|
173 |
the working check-out. Study implementations of existing commands |
|
018a983…
|
drh
|
174 |
to get an idea of how things are done. You can easily find the implementations |
|
018a983…
|
drh
|
175 |
of existing commands by searching for "COMMAND: <i>name</i>" in the |
|
018a983…
|
drh
|
176 |
files of the "src/" directory. |
|
018a983…
|
drh
|
177 |
|
|
93cee1f…
|
wyoung
|
178 |
<h2 id="newpage">5.0 Creating A New Web Page</h2> |
|
018a983…
|
drh
|
179 |
|
|
018a983…
|
drh
|
180 |
As with commands, new webpages can be added simply by inserting a function |
|
018a983…
|
drh
|
181 |
that generates the webpage together with a special header comment. A |
|
018a983…
|
drh
|
182 |
template follows: |
|
018a983…
|
drh
|
183 |
|
|
8a1ba49…
|
wyoung
|
184 |
<verbatim> |
|
018a983…
|
drh
|
185 |
/* |
|
018a983…
|
drh
|
186 |
** WEBPAGE: helloworld |
|
018a983…
|
drh
|
187 |
*/ |
|
018a983…
|
drh
|
188 |
void helloworld_page(void){ |
|
018a983…
|
drh
|
189 |
style_header("Hello World!"); |
|
018a983…
|
drh
|
190 |
@ <p>Hello, World!</p> |
|
018a983…
|
drh
|
191 |
style_footer(); |
|
018a983…
|
drh
|
192 |
} |
|
8a1ba49…
|
wyoung
|
193 |
</verbatim> |
|
018a983…
|
drh
|
194 |
|
|
018a983…
|
drh
|
195 |
Add the code above to a new or existing Fossil source code file, then |
|
018a983…
|
drh
|
196 |
recompile fossil and run [/help/ui|fossil ui] then enter |
|
018a983…
|
drh
|
197 |
"http://localhost:8080/helloworld" in your web browser and the routine |
|
018a983…
|
drh
|
198 |
above will generate a web page that says "Hello World." |
|
018a983…
|
drh
|
199 |
It really is that simple. |
|
018a983…
|
drh
|
200 |
|
|
018a983…
|
drh
|
201 |
The special "WEBPAGE:" comment is picked up by the "mkindex" preprocessor |
|
018a983…
|
drh
|
202 |
and used to generate a table that maps the "helloworld" webpage name |
|
018a983…
|
drh
|
203 |
into a pointer to the "helloworld_page()" function. The function that |
|
018a983…
|
drh
|
204 |
implements a webpage can be named anything you like (as long as it does |
|
018a983…
|
drh
|
205 |
not collide with another name) but the traditional name is |
|
018a983…
|
drh
|
206 |
"<i>pagename</i><b>_page</b>". |
|
018a983…
|
drh
|
207 |
|
|
018a983…
|
drh
|
208 |
HTML pages begin with a call to style_header() and end with the call to |
|
018a983…
|
drh
|
209 |
style_footer(). Content is generated by the "@" lines that are translated |
|
018a983…
|
drh
|
210 |
(by the "translate" preprocessor) into printf-like code that generates the |
|
018a983…
|
drh
|
211 |
content of the webpage. Different techniques are used to generate |
|
018a983…
|
drh
|
212 |
non-HTML content. In the unlikely event that you need to generate |
|
018a983…
|
drh
|
213 |
non-HTML content, look at existing webpage implementations |
|
018a983…
|
drh
|
214 |
(ex: "logo" or "style.css") to see how that is done. |
|
018a983…
|
drh
|
215 |
|
|
018a983…
|
drh
|
216 |
There are lots of other things that a real web-page implementation will |
|
efd79f8…
|
drh
|
217 |
need to do, such as verifying user credentials, parsing query parameters, |
|
018a983…
|
drh
|
218 |
and interacting with the repository. But now that you have the general |
|
018a983…
|
drh
|
219 |
idea of how webpages are implemented, you can look at the many other |
|
018a983…
|
drh
|
220 |
webpage implementations already built into Fossil to see how all that |
|
018a983…
|
drh
|
221 |
works. |
|
018a983…
|
drh
|
222 |
|
|
018a983…
|
drh
|
223 |
<h2>6.0 See Also</h2> |
|
018a983…
|
drh
|
224 |
|
|
018a983…
|
drh
|
225 |
* [./makefile.wiki|The Fossil Build Process] |
|
018a983…
|
drh
|
226 |
* [./tech_overview.wiki|A Technical Overview Of Fossil] |
|
018a983…
|
drh
|
227 |
* [./contribute.wiki|Contributing To The Fossil Project] |
|
abf865b…
|
drh
|
228 |
* [./serverext.wiki|Adding CGI Extensions To A Fossil Server] |