Fossil SCM

Merge in some changes to the CGI reply generator that we made back in early December but got lost on an abandoned branch. Distributed version control is nice, but it also leaves open the real danger of losing changes this way. We need to work on interface features to minimize the risk of losing changes like this, and to identify lost changes quickly.

drh 2008-02-03 02:41 trunk merge
Commit b312f5ff5b0c4ef57eaf21ecb274928a87817ce6
3 files changed +73 -15 +25 -13 +25 -13
+73 -15
--- src/cgi.c
+++ src/cgi.c
@@ -57,10 +57,17 @@
5757
#define P(x) cgi_parameter((x),0)
5858
#define PD(x,y) cgi_parameter((x),(y))
5959
#define QP(x) quotable_string(cgi_parameter((x),0))
6060
#define QPD(x,y) quotable_string(cgi_parameter((x),(y)))
6161
62
+
63
+/*
64
+** Destinations for output text.
65
+*/
66
+#define CGI_HEADER 0
67
+#define CGI_BODY 1
68
+
6269
#endif /* INTERFACE */
6370
6471
/*
6572
** Provide a reliable implementation of a caseless string comparison
6673
** function.
@@ -67,40 +74,80 @@
6774
*/
6875
#define stricmp sqlite3StrICmp
6976
extern int sqlite3StrICmp(const char*, const char*);
7077
7178
/*
72
-** The body of the HTTP reply text is stored here.
79
+** The HTTP reply is generated in two pieces: the header and the body.
80
+** These pieces are generated separately because they are not necessary
81
+** produced in order. Parts of the header might be built after all or
82
+** part of the body. The header and body are accumulated in separate
83
+** Blob structures then output sequentially once everything has been
84
+** built.
85
+**
86
+** The cgi_destination() interface switch between the buffers.
87
+*/
88
+static Blob *pContent;
89
+static Blob cgiContent[2] = { BLOB_INITIALIZER, BLOB_INITIALIZER };
90
+
91
+/*
92
+** Set the destination buffer into which to accumulate CGI content.
7393
*/
74
-static Blob cgiContent = BLOB_INITIALIZER;
94
+void cgi_destination(int dest){
95
+ switch( dest ){
96
+ case CGI_HEADER: {
97
+ pContent = &cgiContent[0];
98
+ break;
99
+ }
100
+ case CGI_BODY: {
101
+ pContent = &cgiContent[1];
102
+ break;
103
+ }
104
+ default: {
105
+ cgi_panic("bad destination");
106
+ }
107
+ }
108
+}
75109
76110
/*
77111
** Append reply content to what already exists.
78112
*/
79113
void cgi_append_content(const char *zData, int nAmt){
80
- blob_append(&cgiContent, zData, nAmt);
114
+ blob_append(pContent, zData, nAmt);
81115
}
82116
83117
/*
84118
** Reset the HTTP reply text to be an empty string.
85119
*/
86120
void cgi_reset_content(void){
87
- blob_reset(&cgiContent);
121
+ blob_reset(&cgiContent[0]);
122
+ blob_reset(&cgiContent[1]);
88123
}
89124
90125
/*
91126
** Return a pointer to the CGI output blob.
92127
*/
93128
Blob *cgi_output_blob(void){
94
- return &cgiContent;
129
+ return pContent;
130
+}
131
+
132
+/*
133
+** Combine the header and body of the CGI into a single string.
134
+*/
135
+static void cgi_combine_header_and_body(void){
136
+ int size = blob_size(&cgiContent[1]);
137
+ if( size>0 ){
138
+ blob_append(&cgiContent[0], blob_buffer(&cgiContent[1]), size);
139
+ blob_reset(&cgiContent[1]);
140
+ }
95141
}
96142
97143
/*
98144
** Return a pointer to the HTTP reply text.
99145
*/
100146
char *cgi_extract_content(int *pnAmt){
101
- return blob_buffer(&cgiContent);
147
+ cgi_combine_header_and_body();
148
+ return blob_buffer(&cgiContent[0]);
102149
}
103150
104151
/*
105152
** Additional information used to form the HTTP reply
106153
*/
@@ -119,12 +166,13 @@
119166
120167
/*
121168
** Set the reply content to the specified BLOB.
122169
*/
123170
void cgi_set_content(Blob *pNewContent){
124
- blob_reset(&cgiContent);
125
- cgiContent = *pNewContent;
171
+ cgi_reset_content();
172
+ cgi_destination(CGI_HEADER);
173
+ cgiContent[0] = *pNewContent;
126174
blob_zero(pNewContent);
127175
}
128176
129177
/*
130178
** Set the reply status code
@@ -220,10 +268,11 @@
220268
221269
/*
222270
** Do a normal HTTP reply
223271
*/
224272
void cgi_reply(void){
273
+ int total_size;
225274
if( iReplyStatus<=0 ){
226275
iReplyStatus = 200;
227276
zReplyStatus = "OK";
228277
}
229278
@@ -273,19 +322,27 @@
273322
printf( "Content-Type: %s; charset=%s\r\n", zContentType, nl_langinfo(CODESET));
274323
#else
275324
printf( "Content-Type: %s; charset=ISO-8859-1\r\n", zContentType);
276325
#endif
277326
if( strcmp(zContentType,"application/x-fossil")==0 ){
278
- blob_compress(&cgiContent, &cgiContent);
327
+ cgi_combine_header_and_body();
328
+ blob_compress(&cgiContent[0], &cgiContent[0]);
279329
}
280330
281331
if( iReplyStatus != 304 ) {
282
- printf( "Content-Length: %d\r\n", blob_size(&cgiContent) );
332
+ total_size = blob_size(&cgiContent[0]) + blob_size(&cgiContent[1]);
333
+ printf( "Content-Length: %d\r\n", total_size);
283334
}
284335
printf("\r\n");
285
- if( blob_size(&cgiContent)>0 && iReplyStatus != 304 ){
286
- fwrite(blob_buffer(&cgiContent), 1, blob_size(&cgiContent), stdout);
336
+ if( total_size>0 && iReplyStatus != 304 ){
337
+ int i, size;
338
+ for(i=0; i<2; i++){
339
+ size = blob_size(&cgiContent[i]);
340
+ if( size>0 ){
341
+ fwrite(blob_buffer(&cgiContent[i]), 1, size, stdout);
342
+ }
343
+ }
287344
}
288345
CGIDEBUG(("DONE\n"));
289346
}
290347
291348
/*
@@ -611,10 +668,11 @@
611668
*/
612669
void cgi_init(void){
613670
char *z;
614671
const char *zType;
615672
int len;
673
+ cgi_destination(CGI_BODY);
616674
z = (char*)P("QUERY_STRING");
617675
if( z ){
618676
z = mprintf("%s",z);
619677
add_param_list(z, '&');
620678
}
@@ -939,20 +997,20 @@
939997
** extra formatting capabilities such as %h and %t.
940998
*/
941999
void cgi_printf(const char *zFormat, ...){
9421000
va_list ap;
9431001
va_start(ap,zFormat);
944
- vxprintf(&cgiContent,zFormat,ap);
1002
+ vxprintf(pContent,zFormat,ap);
9451003
va_end(ap);
9461004
}
9471005
9481006
/*
9491007
** This routine works like "vprintf" except that it has the
9501008
** extra formatting capabilities such as %h and %t.
9511009
*/
9521010
void cgi_vprintf(const char *zFormat, va_list ap){
953
- vxprintf(&cgiContent,zFormat,ap);
1011
+ vxprintf(pContent,zFormat,ap);
9541012
}
9551013
9561014
9571015
/*
9581016
** Send a reply indicating that the HTTP request was malformed
@@ -976,11 +1034,11 @@
9761034
cgi_printf(
9771035
"<html><body><h1>Internal Server Error</h1>\n"
9781036
"<plaintext>"
9791037
);
9801038
va_start(ap, zFormat);
981
- vxprintf(&cgiContent,zFormat,ap);
1039
+ vxprintf(pContent,zFormat,ap);
9821040
va_end(ap);
9831041
cgi_reply();
9841042
exit(1);
9851043
}
9861044
9871045
--- src/cgi.c
+++ src/cgi.c
@@ -57,10 +57,17 @@
57 #define P(x) cgi_parameter((x),0)
58 #define PD(x,y) cgi_parameter((x),(y))
59 #define QP(x) quotable_string(cgi_parameter((x),0))
60 #define QPD(x,y) quotable_string(cgi_parameter((x),(y)))
61
 
 
 
 
 
 
 
62 #endif /* INTERFACE */
63
64 /*
65 ** Provide a reliable implementation of a caseless string comparison
66 ** function.
@@ -67,40 +74,80 @@
67 */
68 #define stricmp sqlite3StrICmp
69 extern int sqlite3StrICmp(const char*, const char*);
70
71 /*
72 ** The body of the HTTP reply text is stored here.
 
 
 
 
 
 
 
 
 
 
 
 
 
73 */
74 static Blob cgiContent = BLOB_INITIALIZER;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
76 /*
77 ** Append reply content to what already exists.
78 */
79 void cgi_append_content(const char *zData, int nAmt){
80 blob_append(&cgiContent, zData, nAmt);
81 }
82
83 /*
84 ** Reset the HTTP reply text to be an empty string.
85 */
86 void cgi_reset_content(void){
87 blob_reset(&cgiContent);
 
88 }
89
90 /*
91 ** Return a pointer to the CGI output blob.
92 */
93 Blob *cgi_output_blob(void){
94 return &cgiContent;
 
 
 
 
 
 
 
 
 
 
 
95 }
96
97 /*
98 ** Return a pointer to the HTTP reply text.
99 */
100 char *cgi_extract_content(int *pnAmt){
101 return blob_buffer(&cgiContent);
 
102 }
103
104 /*
105 ** Additional information used to form the HTTP reply
106 */
@@ -119,12 +166,13 @@
119
120 /*
121 ** Set the reply content to the specified BLOB.
122 */
123 void cgi_set_content(Blob *pNewContent){
124 blob_reset(&cgiContent);
125 cgiContent = *pNewContent;
 
126 blob_zero(pNewContent);
127 }
128
129 /*
130 ** Set the reply status code
@@ -220,10 +268,11 @@
220
221 /*
222 ** Do a normal HTTP reply
223 */
224 void cgi_reply(void){
 
225 if( iReplyStatus<=0 ){
226 iReplyStatus = 200;
227 zReplyStatus = "OK";
228 }
229
@@ -273,19 +322,27 @@
273 printf( "Content-Type: %s; charset=%s\r\n", zContentType, nl_langinfo(CODESET));
274 #else
275 printf( "Content-Type: %s; charset=ISO-8859-1\r\n", zContentType);
276 #endif
277 if( strcmp(zContentType,"application/x-fossil")==0 ){
278 blob_compress(&cgiContent, &cgiContent);
 
279 }
280
281 if( iReplyStatus != 304 ) {
282 printf( "Content-Length: %d\r\n", blob_size(&cgiContent) );
 
283 }
284 printf("\r\n");
285 if( blob_size(&cgiContent)>0 && iReplyStatus != 304 ){
286 fwrite(blob_buffer(&cgiContent), 1, blob_size(&cgiContent), stdout);
 
 
 
 
 
 
287 }
288 CGIDEBUG(("DONE\n"));
289 }
290
291 /*
@@ -611,10 +668,11 @@
611 */
612 void cgi_init(void){
613 char *z;
614 const char *zType;
615 int len;
 
616 z = (char*)P("QUERY_STRING");
617 if( z ){
618 z = mprintf("%s",z);
619 add_param_list(z, '&');
620 }
@@ -939,20 +997,20 @@
939 ** extra formatting capabilities such as %h and %t.
940 */
941 void cgi_printf(const char *zFormat, ...){
942 va_list ap;
943 va_start(ap,zFormat);
944 vxprintf(&cgiContent,zFormat,ap);
945 va_end(ap);
946 }
947
948 /*
949 ** This routine works like "vprintf" except that it has the
950 ** extra formatting capabilities such as %h and %t.
951 */
952 void cgi_vprintf(const char *zFormat, va_list ap){
953 vxprintf(&cgiContent,zFormat,ap);
954 }
955
956
957 /*
958 ** Send a reply indicating that the HTTP request was malformed
@@ -976,11 +1034,11 @@
976 cgi_printf(
977 "<html><body><h1>Internal Server Error</h1>\n"
978 "<plaintext>"
979 );
980 va_start(ap, zFormat);
981 vxprintf(&cgiContent,zFormat,ap);
982 va_end(ap);
983 cgi_reply();
984 exit(1);
985 }
986
987
--- src/cgi.c
+++ src/cgi.c
@@ -57,10 +57,17 @@
57 #define P(x) cgi_parameter((x),0)
58 #define PD(x,y) cgi_parameter((x),(y))
59 #define QP(x) quotable_string(cgi_parameter((x),0))
60 #define QPD(x,y) quotable_string(cgi_parameter((x),(y)))
61
62
63 /*
64 ** Destinations for output text.
65 */
66 #define CGI_HEADER 0
67 #define CGI_BODY 1
68
69 #endif /* INTERFACE */
70
71 /*
72 ** Provide a reliable implementation of a caseless string comparison
73 ** function.
@@ -67,40 +74,80 @@
74 */
75 #define stricmp sqlite3StrICmp
76 extern int sqlite3StrICmp(const char*, const char*);
77
78 /*
79 ** The HTTP reply is generated in two pieces: the header and the body.
80 ** These pieces are generated separately because they are not necessary
81 ** produced in order. Parts of the header might be built after all or
82 ** part of the body. The header and body are accumulated in separate
83 ** Blob structures then output sequentially once everything has been
84 ** built.
85 **
86 ** The cgi_destination() interface switch between the buffers.
87 */
88 static Blob *pContent;
89 static Blob cgiContent[2] = { BLOB_INITIALIZER, BLOB_INITIALIZER };
90
91 /*
92 ** Set the destination buffer into which to accumulate CGI content.
93 */
94 void cgi_destination(int dest){
95 switch( dest ){
96 case CGI_HEADER: {
97 pContent = &cgiContent[0];
98 break;
99 }
100 case CGI_BODY: {
101 pContent = &cgiContent[1];
102 break;
103 }
104 default: {
105 cgi_panic("bad destination");
106 }
107 }
108 }
109
110 /*
111 ** Append reply content to what already exists.
112 */
113 void cgi_append_content(const char *zData, int nAmt){
114 blob_append(pContent, zData, nAmt);
115 }
116
117 /*
118 ** Reset the HTTP reply text to be an empty string.
119 */
120 void cgi_reset_content(void){
121 blob_reset(&cgiContent[0]);
122 blob_reset(&cgiContent[1]);
123 }
124
125 /*
126 ** Return a pointer to the CGI output blob.
127 */
128 Blob *cgi_output_blob(void){
129 return pContent;
130 }
131
132 /*
133 ** Combine the header and body of the CGI into a single string.
134 */
135 static void cgi_combine_header_and_body(void){
136 int size = blob_size(&cgiContent[1]);
137 if( size>0 ){
138 blob_append(&cgiContent[0], blob_buffer(&cgiContent[1]), size);
139 blob_reset(&cgiContent[1]);
140 }
141 }
142
143 /*
144 ** Return a pointer to the HTTP reply text.
145 */
146 char *cgi_extract_content(int *pnAmt){
147 cgi_combine_header_and_body();
148 return blob_buffer(&cgiContent[0]);
149 }
150
151 /*
152 ** Additional information used to form the HTTP reply
153 */
@@ -119,12 +166,13 @@
166
167 /*
168 ** Set the reply content to the specified BLOB.
169 */
170 void cgi_set_content(Blob *pNewContent){
171 cgi_reset_content();
172 cgi_destination(CGI_HEADER);
173 cgiContent[0] = *pNewContent;
174 blob_zero(pNewContent);
175 }
176
177 /*
178 ** Set the reply status code
@@ -220,10 +268,11 @@
268
269 /*
270 ** Do a normal HTTP reply
271 */
272 void cgi_reply(void){
273 int total_size;
274 if( iReplyStatus<=0 ){
275 iReplyStatus = 200;
276 zReplyStatus = "OK";
277 }
278
@@ -273,19 +322,27 @@
322 printf( "Content-Type: %s; charset=%s\r\n", zContentType, nl_langinfo(CODESET));
323 #else
324 printf( "Content-Type: %s; charset=ISO-8859-1\r\n", zContentType);
325 #endif
326 if( strcmp(zContentType,"application/x-fossil")==0 ){
327 cgi_combine_header_and_body();
328 blob_compress(&cgiContent[0], &cgiContent[0]);
329 }
330
331 if( iReplyStatus != 304 ) {
332 total_size = blob_size(&cgiContent[0]) + blob_size(&cgiContent[1]);
333 printf( "Content-Length: %d\r\n", total_size);
334 }
335 printf("\r\n");
336 if( total_size>0 && iReplyStatus != 304 ){
337 int i, size;
338 for(i=0; i<2; i++){
339 size = blob_size(&cgiContent[i]);
340 if( size>0 ){
341 fwrite(blob_buffer(&cgiContent[i]), 1, size, stdout);
342 }
343 }
344 }
345 CGIDEBUG(("DONE\n"));
346 }
347
348 /*
@@ -611,10 +668,11 @@
668 */
669 void cgi_init(void){
670 char *z;
671 const char *zType;
672 int len;
673 cgi_destination(CGI_BODY);
674 z = (char*)P("QUERY_STRING");
675 if( z ){
676 z = mprintf("%s",z);
677 add_param_list(z, '&');
678 }
@@ -939,20 +997,20 @@
997 ** extra formatting capabilities such as %h and %t.
998 */
999 void cgi_printf(const char *zFormat, ...){
1000 va_list ap;
1001 va_start(ap,zFormat);
1002 vxprintf(pContent,zFormat,ap);
1003 va_end(ap);
1004 }
1005
1006 /*
1007 ** This routine works like "vprintf" except that it has the
1008 ** extra formatting capabilities such as %h and %t.
1009 */
1010 void cgi_vprintf(const char *zFormat, va_list ap){
1011 vxprintf(pContent,zFormat,ap);
1012 }
1013
1014
1015 /*
1016 ** Send a reply indicating that the HTTP request was malformed
@@ -976,11 +1034,11 @@
1034 cgi_printf(
1035 "<html><body><h1>Internal Server Error</h1>\n"
1036 "<plaintext>"
1037 );
1038 va_start(ap, zFormat);
1039 vxprintf(pContent,zFormat,ap);
1040 va_end(ap);
1041 cgi_reply();
1042 exit(1);
1043 }
1044
1045
+25 -13
--- src/style.c
+++ src/style.c
@@ -82,10 +82,11 @@
8282
const char *zLogInOut = "Login";
8383
const char *zHeader = db_get("header", (char*)zDefaultHeader);
8484
login_check_credentials();
8585
8686
if( pInterp ) return;
87
+ cgi_destination(CGI_HEADER);
8788
8889
/* Generate the header up through the main menu */
8990
pInterp = SbS_Create();
9091
SbS_Store(pInterp, "project_name",
9192
db_get("project-name","Unnamed Fossil Project"), 0);
@@ -97,11 +98,11 @@
9798
SbS_Store(pInterp, "login", g.zLogin, 0);
9899
zLogInOut = "Logout";
99100
}
100101
SbS_Render(pInterp, zHeader);
101102
102
- /* Generate the main menu and the submenu (if any) */
103
+ /* Generate the main menu */
103104
@ <div class="mainmenu">
104105
@ <a href="%s(g.zBaseURL)/home">Home</a>
105106
if( g.okRead ){
106107
@ <a href="%s(g.zBaseURL)/leaves">Leaves</a>
107108
@ <a href="%s(g.zBaseURL)/timeline">Timeline</a>
@@ -120,12 +121,29 @@
120121
}
121122
if( !g.noPswd ){
122123
@ <a href="%s(g.zBaseURL)/login">%s(zLogInOut)</a>
123124
}
124125
@ </div>
126
+ cgi_destination(CGI_BODY);
127
+ g.cgiPanic = 1;
128
+}
129
+
130
+/*
131
+** Draw the footer at the bottom of the page.
132
+*/
133
+void style_footer(void){
134
+ const char *zFooter;
135
+
136
+ if( pInterp==0 ) return;
137
+
138
+ /* Go back and put the submenu at the top of the page. We delay the
139
+ ** creation of the submenu until the end so that we can add elements
140
+ ** to the submenu while generating page text.
141
+ */
125142
if( nSubmenu>0 ){
126143
int i;
144
+ cgi_destination(CGI_HEADER);
127145
@ <div class="submenu">
128146
qsort(aSubmenu, nSubmenu, sizeof(aSubmenu[0]), submenuCompare);
129147
for(i=0; i<nSubmenu; i++){
130148
struct Submenu *p = &aSubmenu[i];
131149
if( p->zLink==0 ){
@@ -133,22 +151,16 @@
133151
}else{
134152
@ <a class="label" href="%s(p->zLink)">%h(p->zLabel)</a>
135153
}
136154
}
137155
@ </div>
138
- }
139
- @ <div class="content">
140
- g.cgiPanic = 1;
141
-}
142
-
143
-/*
144
-** Draw the footer at the bottom of the page.
145
-*/
146
-void style_footer(void){
147
- const char *zFooter;
148
-
149
- if( pInterp==0 ) return;
156
+ cgi_destination(CGI_BODY);
157
+ }
158
+
159
+ /* Put the footer at the bottom of the page.
160
+ */
161
+ @ <div class="content">
150162
zFooter = db_get("footer", (char*)zDefaultFooter);
151163
@ </div>
152164
SbS_Render(pInterp, zFooter);
153165
SbS_Destroy(pInterp);
154166
pInterp = 0;
155167
--- src/style.c
+++ src/style.c
@@ -82,10 +82,11 @@
82 const char *zLogInOut = "Login";
83 const char *zHeader = db_get("header", (char*)zDefaultHeader);
84 login_check_credentials();
85
86 if( pInterp ) return;
 
87
88 /* Generate the header up through the main menu */
89 pInterp = SbS_Create();
90 SbS_Store(pInterp, "project_name",
91 db_get("project-name","Unnamed Fossil Project"), 0);
@@ -97,11 +98,11 @@
97 SbS_Store(pInterp, "login", g.zLogin, 0);
98 zLogInOut = "Logout";
99 }
100 SbS_Render(pInterp, zHeader);
101
102 /* Generate the main menu and the submenu (if any) */
103 @ <div class="mainmenu">
104 @ <a href="%s(g.zBaseURL)/home">Home</a>
105 if( g.okRead ){
106 @ <a href="%s(g.zBaseURL)/leaves">Leaves</a>
107 @ <a href="%s(g.zBaseURL)/timeline">Timeline</a>
@@ -120,12 +121,29 @@
120 }
121 if( !g.noPswd ){
122 @ <a href="%s(g.zBaseURL)/login">%s(zLogInOut)</a>
123 }
124 @ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125 if( nSubmenu>0 ){
126 int i;
 
127 @ <div class="submenu">
128 qsort(aSubmenu, nSubmenu, sizeof(aSubmenu[0]), submenuCompare);
129 for(i=0; i<nSubmenu; i++){
130 struct Submenu *p = &aSubmenu[i];
131 if( p->zLink==0 ){
@@ -133,22 +151,16 @@
133 }else{
134 @ <a class="label" href="%s(p->zLink)">%h(p->zLabel)</a>
135 }
136 }
137 @ </div>
138 }
139 @ <div class="content">
140 g.cgiPanic = 1;
141 }
142
143 /*
144 ** Draw the footer at the bottom of the page.
145 */
146 void style_footer(void){
147 const char *zFooter;
148
149 if( pInterp==0 ) return;
150 zFooter = db_get("footer", (char*)zDefaultFooter);
151 @ </div>
152 SbS_Render(pInterp, zFooter);
153 SbS_Destroy(pInterp);
154 pInterp = 0;
155
--- src/style.c
+++ src/style.c
@@ -82,10 +82,11 @@
82 const char *zLogInOut = "Login";
83 const char *zHeader = db_get("header", (char*)zDefaultHeader);
84 login_check_credentials();
85
86 if( pInterp ) return;
87 cgi_destination(CGI_HEADER);
88
89 /* Generate the header up through the main menu */
90 pInterp = SbS_Create();
91 SbS_Store(pInterp, "project_name",
92 db_get("project-name","Unnamed Fossil Project"), 0);
@@ -97,11 +98,11 @@
98 SbS_Store(pInterp, "login", g.zLogin, 0);
99 zLogInOut = "Logout";
100 }
101 SbS_Render(pInterp, zHeader);
102
103 /* Generate the main menu */
104 @ <div class="mainmenu">
105 @ <a href="%s(g.zBaseURL)/home">Home</a>
106 if( g.okRead ){
107 @ <a href="%s(g.zBaseURL)/leaves">Leaves</a>
108 @ <a href="%s(g.zBaseURL)/timeline">Timeline</a>
@@ -120,12 +121,29 @@
121 }
122 if( !g.noPswd ){
123 @ <a href="%s(g.zBaseURL)/login">%s(zLogInOut)</a>
124 }
125 @ </div>
126 cgi_destination(CGI_BODY);
127 g.cgiPanic = 1;
128 }
129
130 /*
131 ** Draw the footer at the bottom of the page.
132 */
133 void style_footer(void){
134 const char *zFooter;
135
136 if( pInterp==0 ) return;
137
138 /* Go back and put the submenu at the top of the page. We delay the
139 ** creation of the submenu until the end so that we can add elements
140 ** to the submenu while generating page text.
141 */
142 if( nSubmenu>0 ){
143 int i;
144 cgi_destination(CGI_HEADER);
145 @ <div class="submenu">
146 qsort(aSubmenu, nSubmenu, sizeof(aSubmenu[0]), submenuCompare);
147 for(i=0; i<nSubmenu; i++){
148 struct Submenu *p = &aSubmenu[i];
149 if( p->zLink==0 ){
@@ -133,22 +151,16 @@
151 }else{
152 @ <a class="label" href="%s(p->zLink)">%h(p->zLabel)</a>
153 }
154 }
155 @ </div>
156 cgi_destination(CGI_BODY);
157 }
158
159 /* Put the footer at the bottom of the page.
160 */
161 @ <div class="content">
 
 
 
 
 
 
162 zFooter = db_get("footer", (char*)zDefaultFooter);
163 @ </div>
164 SbS_Render(pInterp, zFooter);
165 SbS_Destroy(pInterp);
166 pInterp = 0;
167
+25 -13
--- src/style.c
+++ src/style.c
@@ -82,10 +82,11 @@
8282
const char *zLogInOut = "Login";
8383
const char *zHeader = db_get("header", (char*)zDefaultHeader);
8484
login_check_credentials();
8585
8686
if( pInterp ) return;
87
+ cgi_destination(CGI_HEADER);
8788
8889
/* Generate the header up through the main menu */
8990
pInterp = SbS_Create();
9091
SbS_Store(pInterp, "project_name",
9192
db_get("project-name","Unnamed Fossil Project"), 0);
@@ -97,11 +98,11 @@
9798
SbS_Store(pInterp, "login", g.zLogin, 0);
9899
zLogInOut = "Logout";
99100
}
100101
SbS_Render(pInterp, zHeader);
101102
102
- /* Generate the main menu and the submenu (if any) */
103
+ /* Generate the main menu */
103104
@ <div class="mainmenu">
104105
@ <a href="%s(g.zBaseURL)/home">Home</a>
105106
if( g.okRead ){
106107
@ <a href="%s(g.zBaseURL)/leaves">Leaves</a>
107108
@ <a href="%s(g.zBaseURL)/timeline">Timeline</a>
@@ -120,12 +121,29 @@
120121
}
121122
if( !g.noPswd ){
122123
@ <a href="%s(g.zBaseURL)/login">%s(zLogInOut)</a>
123124
}
124125
@ </div>
126
+ cgi_destination(CGI_BODY);
127
+ g.cgiPanic = 1;
128
+}
129
+
130
+/*
131
+** Draw the footer at the bottom of the page.
132
+*/
133
+void style_footer(void){
134
+ const char *zFooter;
135
+
136
+ if( pInterp==0 ) return;
137
+
138
+ /* Go back and put the submenu at the top of the page. We delay the
139
+ ** creation of the submenu until the end so that we can add elements
140
+ ** to the submenu while generating page text.
141
+ */
125142
if( nSubmenu>0 ){
126143
int i;
144
+ cgi_destination(CGI_HEADER);
127145
@ <div class="submenu">
128146
qsort(aSubmenu, nSubmenu, sizeof(aSubmenu[0]), submenuCompare);
129147
for(i=0; i<nSubmenu; i++){
130148
struct Submenu *p = &aSubmenu[i];
131149
if( p->zLink==0 ){
@@ -133,22 +151,16 @@
133151
}else{
134152
@ <a class="label" href="%s(p->zLink)">%h(p->zLabel)</a>
135153
}
136154
}
137155
@ </div>
138
- }
139
- @ <div class="content">
140
- g.cgiPanic = 1;
141
-}
142
-
143
-/*
144
-** Draw the footer at the bottom of the page.
145
-*/
146
-void style_footer(void){
147
- const char *zFooter;
148
-
149
- if( pInterp==0 ) return;
156
+ cgi_destination(CGI_BODY);
157
+ }
158
+
159
+ /* Put the footer at the bottom of the page.
160
+ */
161
+ @ <div class="content">
150162
zFooter = db_get("footer", (char*)zDefaultFooter);
151163
@ </div>
152164
SbS_Render(pInterp, zFooter);
153165
SbS_Destroy(pInterp);
154166
pInterp = 0;
155167
--- src/style.c
+++ src/style.c
@@ -82,10 +82,11 @@
82 const char *zLogInOut = "Login";
83 const char *zHeader = db_get("header", (char*)zDefaultHeader);
84 login_check_credentials();
85
86 if( pInterp ) return;
 
87
88 /* Generate the header up through the main menu */
89 pInterp = SbS_Create();
90 SbS_Store(pInterp, "project_name",
91 db_get("project-name","Unnamed Fossil Project"), 0);
@@ -97,11 +98,11 @@
97 SbS_Store(pInterp, "login", g.zLogin, 0);
98 zLogInOut = "Logout";
99 }
100 SbS_Render(pInterp, zHeader);
101
102 /* Generate the main menu and the submenu (if any) */
103 @ <div class="mainmenu">
104 @ <a href="%s(g.zBaseURL)/home">Home</a>
105 if( g.okRead ){
106 @ <a href="%s(g.zBaseURL)/leaves">Leaves</a>
107 @ <a href="%s(g.zBaseURL)/timeline">Timeline</a>
@@ -120,12 +121,29 @@
120 }
121 if( !g.noPswd ){
122 @ <a href="%s(g.zBaseURL)/login">%s(zLogInOut)</a>
123 }
124 @ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125 if( nSubmenu>0 ){
126 int i;
 
127 @ <div class="submenu">
128 qsort(aSubmenu, nSubmenu, sizeof(aSubmenu[0]), submenuCompare);
129 for(i=0; i<nSubmenu; i++){
130 struct Submenu *p = &aSubmenu[i];
131 if( p->zLink==0 ){
@@ -133,22 +151,16 @@
133 }else{
134 @ <a class="label" href="%s(p->zLink)">%h(p->zLabel)</a>
135 }
136 }
137 @ </div>
138 }
139 @ <div class="content">
140 g.cgiPanic = 1;
141 }
142
143 /*
144 ** Draw the footer at the bottom of the page.
145 */
146 void style_footer(void){
147 const char *zFooter;
148
149 if( pInterp==0 ) return;
150 zFooter = db_get("footer", (char*)zDefaultFooter);
151 @ </div>
152 SbS_Render(pInterp, zFooter);
153 SbS_Destroy(pInterp);
154 pInterp = 0;
155
--- src/style.c
+++ src/style.c
@@ -82,10 +82,11 @@
82 const char *zLogInOut = "Login";
83 const char *zHeader = db_get("header", (char*)zDefaultHeader);
84 login_check_credentials();
85
86 if( pInterp ) return;
87 cgi_destination(CGI_HEADER);
88
89 /* Generate the header up through the main menu */
90 pInterp = SbS_Create();
91 SbS_Store(pInterp, "project_name",
92 db_get("project-name","Unnamed Fossil Project"), 0);
@@ -97,11 +98,11 @@
98 SbS_Store(pInterp, "login", g.zLogin, 0);
99 zLogInOut = "Logout";
100 }
101 SbS_Render(pInterp, zHeader);
102
103 /* Generate the main menu */
104 @ <div class="mainmenu">
105 @ <a href="%s(g.zBaseURL)/home">Home</a>
106 if( g.okRead ){
107 @ <a href="%s(g.zBaseURL)/leaves">Leaves</a>
108 @ <a href="%s(g.zBaseURL)/timeline">Timeline</a>
@@ -120,12 +121,29 @@
121 }
122 if( !g.noPswd ){
123 @ <a href="%s(g.zBaseURL)/login">%s(zLogInOut)</a>
124 }
125 @ </div>
126 cgi_destination(CGI_BODY);
127 g.cgiPanic = 1;
128 }
129
130 /*
131 ** Draw the footer at the bottom of the page.
132 */
133 void style_footer(void){
134 const char *zFooter;
135
136 if( pInterp==0 ) return;
137
138 /* Go back and put the submenu at the top of the page. We delay the
139 ** creation of the submenu until the end so that we can add elements
140 ** to the submenu while generating page text.
141 */
142 if( nSubmenu>0 ){
143 int i;
144 cgi_destination(CGI_HEADER);
145 @ <div class="submenu">
146 qsort(aSubmenu, nSubmenu, sizeof(aSubmenu[0]), submenuCompare);
147 for(i=0; i<nSubmenu; i++){
148 struct Submenu *p = &aSubmenu[i];
149 if( p->zLink==0 ){
@@ -133,22 +151,16 @@
151 }else{
152 @ <a class="label" href="%s(p->zLink)">%h(p->zLabel)</a>
153 }
154 }
155 @ </div>
156 cgi_destination(CGI_BODY);
157 }
158
159 /* Put the footer at the bottom of the page.
160 */
161 @ <div class="content">
 
 
 
 
 
 
162 zFooter = db_get("footer", (char*)zDefaultFooter);
163 @ </div>
164 SbS_Render(pInterp, zFooter);
165 SbS_Destroy(pInterp);
166 pInterp = 0;
167

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button