Fossil

Check-in [ffe92f1a2f]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:The entire header, including the menu bar, is now generated by TH script. This allows the menu bar to be customized by editing the header script.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: ffe92f1a2f103efe35fa61d108a5ef060a50861e
User & Date: drh 2008-02-13 19:50:27.000
Context
2008-02-13
22:31
Cut over all code to use TH1 instead of subscript. Completely remove the subscript interpreter from the source tree. check-in: fde1d82372 user: drh tags: trunk
19:50
The entire header, including the menu bar, is now generated by TH script. This allows the menu bar to be customized by editing the header script. check-in: ffe92f1a2f user: drh tags: trunk
18:18
TH1 script now used to render the header and footer of each page. check-in: 3ad9a5e210 user: drh tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/style.c.
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
  return strcmp(A->zLabel, B->zLabel);
}

/*
** Draw the header.
*/
void style_header(const char *zTitle){
  const char *zLogInOut = "Login";
  const char *zHeader = db_get("header", (char*)zDefaultHeader);  
  login_check_credentials();
  
  cgi_destination(CGI_HEADER);

  /* Generate the header up through the main menu */
  Th_InitVar("project_name", db_get("project-name","Unnamed Fossil Project"));
  Th_InitVar("title", zTitle);
  Th_InitVar("baseurl", g.zBaseURL);
  Th_InitVar("manifest_version", MANIFEST_VERSION);
  Th_InitVar("manifest_date", MANIFEST_DATE);
  if( g.zLogin ){
    Th_InitVar("login", g.zLogin);
    zLogInOut = "Logout";
  }
  Th_Render(zHeader);

  /* Generate the main menu */
  @ <div class="mainmenu">
  @ <a href="%s(g.zBaseURL)/home">Home</a>
  if( g.okHistory ){
    @ <a href="%s(g.zBaseURL)/dir">Files</a>
  }
  if( g.okRead ){
    @ <a href="%s(g.zBaseURL)/leaves">Leaves</a>
    @ <a href="%s(g.zBaseURL)/timeline">Timeline</a>
    @ <a href="%s(g.zBaseURL)/tagview">Tags</a>
  }
  if( g.okRdWiki ){
    @ <a href="%s(g.zBaseURL)/wiki">Wiki</a>
  }
#if 0
  @ <font color="#888888">Search</font>
  @ <font color="#888888">Ticket</font>
  @ <font color="#888888">Reports</font>
#endif
  if( g.okSetup ){
    @ <a href="%s(g.zBaseURL)/setup">Setup</a>
  }
  if( !g.noPswd ){
    @ <a href="%s(g.zBaseURL)/login">%s(zLogInOut)</a>
  }
  @ </div>
  cgi_destination(CGI_BODY);
  g.cgiPanic = 1;
}

/*
** Draw the footer at the bottom of the page.
*/







<













<


<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







70
71
72
73
74
75
76

77
78
79
80
81
82
83
84
85
86
87
88
89

90
91



























92
93
94
95
96
97
98
  return strcmp(A->zLabel, B->zLabel);
}

/*
** Draw the header.
*/
void style_header(const char *zTitle){

  const char *zHeader = db_get("header", (char*)zDefaultHeader);  
  login_check_credentials();
  
  cgi_destination(CGI_HEADER);

  /* Generate the header up through the main menu */
  Th_InitVar("project_name", db_get("project-name","Unnamed Fossil Project"));
  Th_InitVar("title", zTitle);
  Th_InitVar("baseurl", g.zBaseURL);
  Th_InitVar("manifest_version", MANIFEST_VERSION);
  Th_InitVar("manifest_date", MANIFEST_DATE);
  if( g.zLogin ){
    Th_InitVar("login", g.zLogin);

  }
  Th_Render(zHeader);



























  cgi_destination(CGI_BODY);
  g.cgiPanic = 1;
}

/*
** Draw the footer at the bottom of the page.
*/
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187






















188
189
190
191
192
193
194
/* @-comment: // */
/*
** The default page header.
*/
const char zDefaultHeader[] = 
@ <html>
@ <head>
@ <title><th1>puts "$project_name: $title"</th1></title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@       href="$baseurl/timeline.rss">
@ <link rel="stylesheet" href="$baseurl/style.css" type="text/css"
@       media="screen">
@ </head>
@ <body>
@ <div class="header">
@   <div class="logo">
@     <!-- <img src="logo.gif" alt="logo"><br></br> -->
@     <nobr><th1>puts $project_name</th1></nobr>
@   </div>
@   <div class="title"><th1>puts $title</th1></div>
@   <div class="status"><nobr><th1>
@      if {[info exists login]} {
@        html "Logged in as <a href='$baseurl/my'>$login</a>"
@      } else {
@        puts "Not logged in"
@      }
@   </th1></nobr></div>
@ </div>






















;

/*
** The default page footer
*/
const char zDefaultFooter[] = 
@ <div class="footer">







|









|

|








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/* @-comment: // */
/*
** The default page header.
*/
const char zDefaultHeader[] = 
@ <html>
@ <head>
@ <title>$<project_name>: $<title></title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@       href="$baseurl/timeline.rss">
@ <link rel="stylesheet" href="$baseurl/style.css" type="text/css"
@       media="screen">
@ </head>
@ <body>
@ <div class="header">
@   <div class="logo">
@     <!-- <img src="logo.gif" alt="logo"><br></br> -->
@     <nobr>$<project_name></nobr>
@   </div>
@   <div class="title">$<title></div>
@   <div class="status"><nobr><th1>
@      if {[info exists login]} {
@        html "Logged in as <a href='$baseurl/my'>$login</a>"
@      } else {
@        puts "Not logged in"
@      }
@   </th1></nobr></div>
@ </div>
@ <div class="mainmenu"><th1>
@ html "<a href='$baseurl/home'>Home</a>"
@ if {[hascap h]} {
@   html "<a href='$baseurl/dir'>Files</a>"
@ }
@ if {[hascap i]} {
@   html "<a href='$baseurl/leaves'>Leaves</a>"
@   html "<a href='$baseurl/timeline'>Timeline</a>"
@   html "<a href='$baseurl/tagview'>Tags</a>"
@ }
@ if {[hascap j]} {
@   html "<a href='$baseurl/wiki'>Wiki</a>"
@ }
@ if {[hascap s]} {
@   html "<a href='$baseurl/setup'>Setup</a>"
@ }
@ if {[info exists login]} {
@   html "<a href='$baseurl/login'>Login</a>"
@ } else {
@   html "<a href='$baseurl/login'>Logout</a>"
@ }
@ </th1></div>
;

/*
** The default page footer
*/
const char zDefaultFooter[] = 
@ <div class="footer">
Changes to src/th_main.c.
82
83
84
85
86
87
88
89
90
91




92
93
94
95
96

97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156



















157
158
159
160
161
162
163
164
165
166
167

168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
  return Th_ToInt(interp, argv[1], argl[1], &enableOutput);
}

/*
** Send text to the appropriate output:  Either to the console
** or to the CGI reply buffer.
*/
static void sendText(const char *z, int n){
  if( enableOutput && n ){
    if( n<0 ) n = strlen(z);




    if( g.cgiPanic ){
      cgi_append_content(z, n);
    }else{
      fwrite(z, 1, n, stdout);
    }

  }
}

/*
** TH command:     puts STRING
** TH command:     html STRING
**
** Output STRING as HTML (html) or unchanged (puts).  
*/
static int putsCmd(
  Th_Interp *interp, 
  void *pConvert, 
  int argc, 
  const unsigned char **argv, 
  int *argl
){
  if( argc!=2 ){
    return Th_WrongNumArgs(interp, "puts STRING");
  }
  if( enableOutput ){
    int size;
    char *zOut;
    if( pConvert ){    
      zOut = htmlize((char*)argv[1], argl[1]);
      size = strlen(zOut);
    }else{
      zOut = (char*)argv[1];
      size = argl[1];
    }
    sendText(zOut, size);
    if( pConvert ){
      free(zOut);
    }
  }
  return TH_OK;
}

/*
** TH command:      wiki STRING
**
** Render the input string as wiki.
*/
static int wikiCmd(
  Th_Interp *interp, 
  void *p, 
  int argc, 
  const unsigned char **argv, 
  int *argl
){
  if( argc!=2 ){
    return Th_WrongNumArgs(interp, "puts STRING");
  }
  if( enableOutput ){
    Blob src;
    blob_init(&src, (char*)argv[1], argl[1]);
    wiki_convert(&src, 0, WIKI_INLINE);
    blob_reset(&src);
  }
  return TH_OK;
}




















/*
** Make sure the interpreter has been initialized.
*/
static void initializeInterp(void){
  static struct _Command {
    const char *zName;
    Th_CommandProc xProc;
    void *pContext;
  } aCommand[] = {
    {"enable_output", enableOutputCmd,      0},

    {"html",          putsCmd,              0},
    {"puts",          putsCmd,       (void*)1},
    {"wiki",          wikiCmd,              0},
  };
  if( interp==0 ){
    int i;
    interp = Th_CreateInterp(&vtab);
    th_register_language(interp);       /* Basic scripting commands. */
    for(i=0; i<sizeof(aCommand)/sizeof(aCommand[0]); i++){
      Th_CreateCommand(interp, aCommand[i].zName, aCommand[i].xProc,
                       aCommand[i].pContext, 0);
    }
  }
}

/*
** Initialize a variable in the interpreter.
*/
void Th_InitVar(const char *zName, const char *zValue){
  initializeInterp();
  Th_SetVar(interp, zName, -1, zValue, strlen(zValue));
}

/*
** Return true if the string begins with the TH1 begin-script
** tag:  <th1>.
*/
static int isBeginScriptTag(const char *z){







|


>
>
>
>





>



















<
<
<
<
|
<
<
<
<
<
<
<
<
<
<
















|









>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>











>




















|







82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120




121










122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
  return Th_ToInt(interp, argv[1], argl[1], &enableOutput);
}

/*
** Send text to the appropriate output:  Either to the console
** or to the CGI reply buffer.
*/
static void sendText(const char *z, int n, int encode){
  if( enableOutput && n ){
    if( n<0 ) n = strlen(z);
    if( encode ){
      z = htmlize(z, n);
      n = strlen(z);
    }
    if( g.cgiPanic ){
      cgi_append_content(z, n);
    }else{
      fwrite(z, 1, n, stdout);
    }
    if( encode ) free((char*)z);
  }
}

/*
** TH command:     puts STRING
** TH command:     html STRING
**
** Output STRING as HTML (html) or unchanged (puts).  
*/
static int putsCmd(
  Th_Interp *interp, 
  void *pConvert, 
  int argc, 
  const unsigned char **argv, 
  int *argl
){
  if( argc!=2 ){
    return Th_WrongNumArgs(interp, "puts STRING");
  }




  sendText((char*)argv[1], argl[1], pConvert!=0);










  return TH_OK;
}

/*
** TH command:      wiki STRING
**
** Render the input string as wiki.
*/
static int wikiCmd(
  Th_Interp *interp, 
  void *p, 
  int argc, 
  const unsigned char **argv, 
  int *argl
){
  if( argc!=2 ){
    return Th_WrongNumArgs(interp, "wiki STRING");
  }
  if( enableOutput ){
    Blob src;
    blob_init(&src, (char*)argv[1], argl[1]);
    wiki_convert(&src, 0, WIKI_INLINE);
    blob_reset(&src);
  }
  return TH_OK;
}

/*
** TH command:     hascap STRING
**
** Return true if the user has all of the capabilities listed in STRING.
*/
static int hascapCmd(
  Th_Interp *interp, 
  void *p, 
  int argc, 
  const unsigned char **argv, 
  int *argl
){
  if( argc!=2 ){
    return Th_WrongNumArgs(interp, "hascap STRING");
  }
  Th_SetResultInt(interp, login_has_capability((char*)argv[1],argl[1]));
  return TH_OK;
}

/*
** Make sure the interpreter has been initialized.
*/
static void initializeInterp(void){
  static struct _Command {
    const char *zName;
    Th_CommandProc xProc;
    void *pContext;
  } aCommand[] = {
    {"enable_output", enableOutputCmd,      0},
    {"hascap",        hascapCmd,            0},
    {"html",          putsCmd,              0},
    {"puts",          putsCmd,       (void*)1},
    {"wiki",          wikiCmd,              0},
  };
  if( interp==0 ){
    int i;
    interp = Th_CreateInterp(&vtab);
    th_register_language(interp);       /* Basic scripting commands. */
    for(i=0; i<sizeof(aCommand)/sizeof(aCommand[0]); i++){
      Th_CreateCommand(interp, aCommand[i].zName, aCommand[i].xProc,
                       aCommand[i].pContext, 0);
    }
  }
}

/*
** Initialize a variable in the interpreter.
*/
void Th_InitVar(const char *zName, const char *zValue){
  initializeInterp();
  Th_SetVar(interp, (uchar*)zName, -1, (uchar*)zValue, strlen(zValue));
}

/*
** Return true if the string begins with the TH1 begin-script
** tag:  <th1>.
*/
static int isBeginScriptTag(const char *z){
215
216
217
218
219
220
221





222
223
224
225
226
227
228
229
230
231
232
233
234




235
236
237
238
239
240




241
242
243
244
245
246
247
248
249
250
251


252









253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284

/*
** If string z[0...] contains a valid variable name, return
** the number of characters in that name.  Otherwise, return 0.
*/
static int validVarName(const char *z){
  int i = 0;





  if( z[0]==':' && z[1]==':' && isalpha(z[2]) ){
    z += 3;
    i = 3;
  }else if( isalpha(z[0]) ){
    z ++;
    i = 1;
  }else{
    return 0;
  }
  while( isalnum(z[0]) || z[0]=='_' ){
    z++;
    i++;
  }




  return i;
}

/*
** The z[] input contains text mixed with TH1 scripts.
** The TH1 scripts are contained within <th1>...</th1>.  This routine




** processes the template and writes the results on either
** stdout or into CGI.
*/
int Th_Render(const char *z){
  int i = 0;
  int n;
  int rc = TH_OK;
  uchar *zResult;
  initializeInterp();
  while( z[i] ){
    if( z[i]=='$' && (n = validVarName(&z[i+1]))>0 ){


      sendText(z, i);









      rc = Th_GetVar(interp, &z[i+1], n);
      z += i+1+n;
      i = 0;
      zResult = Th_GetResult(interp, &n);
      sendText(zResult, n);
    }else if( z[i]=='<' && isBeginScriptTag(&z[i]) ){
      sendText(z, i);
      z += i+5;
      for(i=0; z[i] && (z[i]!='<' || !isEndScriptTag(&z[i])); i++){}
      rc = Th_Eval(interp, 0, (const uchar*)z, i);
      if( rc!=SBS_OK ) break;
      z += i;
      if( z[0] ){ z += 6; }
      i = 0;
    }else{
      i++;
    }
  }
  if( rc==TH_ERROR ){
    sendText("<hr><p><font color=\"red\"><b>ERROR: ", -1);
    zResult = Th_GetResult(interp, &n);
    sendText(zResult, n);
    sendText("</b></font></p>", -1);
  }else{
    sendText(z, i);
  }
  return rc;
}

/*
** COMMAND: test-th-render
*/







>
>
>
>
>


|


|







>
>
>
>





|
>
>
>
>
|
|









>
>
|
>
>
>
>
>
>
>
>
>
|


|
|

|












|
|
|
|

|







226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319

/*
** If string z[0...] contains a valid variable name, return
** the number of characters in that name.  Otherwise, return 0.
*/
static int validVarName(const char *z){
  int i = 0;
  int inBracket = 0;
  if( z[0]=='<' ){
    inBracket = 1;
    z++;
  }
  if( z[0]==':' && z[1]==':' && isalpha(z[2]) ){
    z += 3;
    i += 3;
  }else if( isalpha(z[0]) ){
    z ++;
    i += 1;
  }else{
    return 0;
  }
  while( isalnum(z[0]) || z[0]=='_' ){
    z++;
    i++;
  }
  if( inBracket ){
    if( z[0]!='>' ) return 0;
    i += 2;
  }
  return i;
}

/*
** The z[] input contains text mixed with TH1 scripts.
** The TH1 scripts are contained within <th1>...</th1>. 
** TH1 variables are $aaa or $<aaa>.  The first form of
** variable is literal.  The second is run through htmlize
** before being inserted.
**
** This routine processes the template and writes the results
** on either stdout or into CGI.
*/
int Th_Render(const char *z){
  int i = 0;
  int n;
  int rc = TH_OK;
  uchar *zResult;
  initializeInterp();
  while( z[i] ){
    if( z[i]=='$' && (n = validVarName(&z[i+1]))>0 ){
      const char *zVar;
      int nVar;
      sendText(z, i, 0);
      if( z[i+1]=='<' ){
        /* Variables of the form $<aaa> */
        zVar = &z[i+2];
        nVar = n-2;
      }else{
        /* Variables of the form $aaa */
        zVar = &z[i+1];
        nVar = n;
      }
      rc = Th_GetVar(interp, (uchar*)zVar, nVar);
      z += i+1+n;
      i = 0;
      zResult = (uchar*)Th_GetResult(interp, &n);
      sendText((char*)zResult, n, n>nVar);
    }else if( z[i]=='<' && isBeginScriptTag(&z[i]) ){
      sendText(z, i, 0);
      z += i+5;
      for(i=0; z[i] && (z[i]!='<' || !isEndScriptTag(&z[i])); i++){}
      rc = Th_Eval(interp, 0, (const uchar*)z, i);
      if( rc!=SBS_OK ) break;
      z += i;
      if( z[0] ){ z += 6; }
      i = 0;
    }else{
      i++;
    }
  }
  if( rc==TH_ERROR ){
    sendText("<hr><p><font color=\"red\"><b>ERROR: ", -1, 0);
    zResult = (uchar*)Th_GetResult(interp, &n);
    sendText((char*)zResult, n, 1);
    sendText("</b></font></p>", -1, 0);
  }else{
    sendText(z, i, 0);
  }
  return rc;
}

/*
** COMMAND: test-th-render
*/
Changes to src/tktconfig.c.
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147

148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167


168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215








216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251

252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
** This is a sample "ticket configuration" file for fossil.
**
** There is considerable flexibility in how tickets are defined
** in fossil.  Each repository can define its own ticket setup
** differently.  Each repository has an instance of a file, like
** this one that defines how that repository deals with tickets.
**
** This file is in the form of a script in an exceedingly 
** minimalist scripting language called "subscript".  Here are
** the rules:
**
** SYNTAX
**
**     *  The script consists of a sequence of whitespace
**        separated tokens.  Whitespace is ignored, except
**        as its role as a token separator.
**
**     *  Lines that begin with '#' are considered to be whitespace.
**
**     *  Text within matching {...} is consider to be a single "string"
**        token, even if the text spans multiple lines and includes
**        embedded whitespace.  The outermost {...} are not part of
**        the text of the token.
**
**     *  A token that begins with "/" is a string token.
**
**     *  A token that looks like a number is a string token.
**
**     *  Tokens that do not fall under the previous three rules
**        are "verb" tokens.
**
**  PROCESSING:
**
**     *  When a script is processed, the engine reads tokens
**        one by one.
**
**     *  String tokens are pushed onto the stack.
**
**     *  Verb tokens which correspond to the names of variables
**        cause the corresponding variable to be pushed onto the
**        stack.
**
**     *  Verb tokens which correspond to procedures cause the
**        procedures to run.  The procedures might push or pull 
**        values from the stack.
**
** There are just a handful of verbs.  For the purposes of this
** configuration script, there is only a single verb: "set".  The
** "set" verb pops two arguments from the stack.  The topmost is
** the name of a variable.  The second element is the value.  The
** "set" verb sets the value of the named variable.
**
**      VALUE NAME set
**
** This configuration file just sets the values of various variables.
** Some of the variables have special meanings.  The content of some
** of the variables are additional subscript scripts.
*/

/* @-comment: ** */
const char zDefaultTicketConfig[] = 
@ ############################################################################
@ # Every ticket configuration *must* define an SQL statement that creates
@ # the TICKET table.  This table must have three columns named
@ # tkt_id, tkt_uuid, and tkt_mtime.  tkt_id must be the integer primary
@ # key and tkt_uuid and tkt_mtime must be unique.  A configuration should
@ # define addition columns as necessary.  All columns should be in all
@ # lower-case letters and should not begin with "tkt".
@ #
@ {
@    CREATE TABLE ticket(
@      -- Do not change any column that begins with tkt_
@      tkt_id INTEGER PRIMARY KEY,
@      tkt_uuid TEXT,
@      tkt_mtime DATE,
@      -- Add as many field as required below this line
@      type TEXT,
@      status TEXT,
@      subsystem TEXT,
@      priority TEXT,
@      severity TEXT,
@      foundin TEXT,
@      contact TEXT,
@      title TEXT,
@      comment TEXT,
@      -- Do not alter this UNIQUE clause:
@      UNIQUE(tkt_uuid, tkt_mtime)
@    );
@    -- Add indices as desired
@ } /ticket_sql set
@ 
@ ############################################################################
@ # You can define additional variables here.  These variables will be
@ # accessible to the page templates when they run.
@ #
@ {
@    Code_Defect
@    Build_Problem
@    Documentation
@    Feature_Request
@    Incident
@ } /type_choices set
@ {Immediate High Medium Low Zero} /priority_choices set
@ {Critical Severe Important Minor Cosmetic} /severity_choices set
@ {
@   Open
@   Fixed
@   Rejected
@   Unable_To_Reproduce
@   Works_As_Designed
@   External_Bug
@   Not_A_Bug
@   Duplicate
@   Overcome_By_Events
@   Drive_By_Patch
@ } /resolution_choices set
@ {

@   Open
@   Verified
@   In_Process
@   Deferred
@   Fixed
@   Tested
@   Closed
@ } /status_choices set
@ {one two three} /subsystem_choices set
@ 
@ ##########################################################################
@ # The "tktnew_template" variable is set to text which is a template for
@ # the HTML of the "New Ticket" page.  Within this template, text contained
@ # within [...] is subscript.  That subscript runs when the page is
@ # rendered.
@ #
@ {
@   <!-- load database field names not found in CGI with an empty string -->
@   <!-- start a form -->
@   [{


@      {Open} /status set
@       submit_ticket
@   } /submit exists if]
@   <table cellpadding="5">
@   <tr>
@   <td colspan="2">
@   Enter a one-line summary of the problem:<br>
@   <input type="text" name="title" size="60" value="[{} /title get html]">
@   </td>
@   </tr>
@   
@   <tr>
@   <td align="right">Type:
@   [/type type_choices 1 combobox]
@   </td>
@   <td>What type of ticket is this?</td>
@   </tr>
@   
@   <tr>
@   <td align="right">Version: 
@   <input type="text" name="foundin" size="20" value="[{} /foundin get html]">
@   </td>
@   <td>In what version or build number do you observer the problem?</td>
@   </tr>
@   
@   <tr>
@   <td align="right">Severity:
@   [/severity severity_choices 1 combobox]
@   </td>
@   <td>How debilitating is the problem?  How badly does the problem
@   effect the operation of the product?</td>
@   </tr>
@   
@   <tr>
@   <td align="right">EMail:
@   <input type="text" name="contact" value="[{} /contact get html]" size="30">
@   </td>
@   <td>Not publically visible. Used by developers to contact you with
@   questions.</td>
@   </tr>
@   
@   <tr>
@   <td colspan="2">
@   Enter a detailed description of the problem.
@   For code defects, be sure to provide details on exactly how
@   the problem can be reproduced.  Provide as much detail as
@   possible.
@   <br>








@   <textarea name="comment" cols="80"
@    rows="[{} /comment get linecount 50 max 10 min html]"
@    wrap="virtual" class="wikiedit">[{} /comment get html]</textarea><br>
@   <input type="submit" name="preview" value="Preview">
@   </tr>
@ 
@   [/preview exists enable_output]
@   <tr><td colspan="2">
@   Description Preview:<br><hr>
@   [{} /comment get wiki]
@   <hr>
@   </td></tr>
@   [1 enable_output]
@   
@   <tr>
@   <td align="right">
@   <input type="submit" name="submit" value="Submit">
@   </td>
@   <td>After filling in the information above, press this button to create
@   the new ticket</td>
@   </tr>
@   </table>
@   <!-- end of form -->
@ } /tktnew_template set
@ 
@ ##########################################################################
@ # The template for the "edit ticket" page
@ #
@ # Then generated text is inserted inside a form which feeds back to itself.
@ # All CGI parameters are loaded into variables.  All database files are
@ # loaded into variables if they have not previously been loaded by
@ # CGI parameters.
@ {
@   [
@     login /username get /username set
@     {

@       {
@         username login eq /samename set
@         {
@            "\n\n<hr><i>" login " added on " date ":</i><br>\n"
@            cmappnd 6 concat /comment append_field
@         } samename if
@         {
@            "\n\n<hr><i>" login " claiming to be " username " added on " date
@            "</i><br>\n" cmappnd 8 concat /comment append_field
@         } samename not if
@       } 0 {} /cmappnd get length lt if
@       submit_ticket
@     } /submit exists if
@   ]
@   <table cellpadding="5">
@   <tr><td align="right">Title:</td><td>
@   <input type="text" name="title" value="[title html]" size="60">
@   </td></tr>
@   <tr><td align="right">Status:</td><td>
@   [/status status_choices 1 combobox]
@   </td></tr>
@   <tr><td align="right">Type:</td><td>
@   [/type type_choices 1 combobox]
@   </td></tr>
@   <tr><td align="right">Severity:</td><td>
@   [/severity severity_choices 1 combobox]
@   </td></tr>
@   <tr><td align="right">Priority:</td><td>
@   [/priority priority_choices 1 combobox]
@   </td></tr>
@   <tr><td align="right">Resolution:</td><td>
@   [/resolution resolution_choices 1 combobox]
@   </td></tr>
@   <tr><td align="right">Subsystem:</td><td>
@   [/subsystem subsystem_choices 1 combobox]
@   </td></tr>
@   [/e hascap enable_output]
@     <tr><td align="right">Contact:</td><td>
@     <input type="text" name="contact" size="40" value="[contact html]">
@     </td></tr>
@   [1 enable_output]
@   <tr><td align="right">Version&nbsp;Found&nbsp;In:</td><td>
@   <input type="text" name="foundin" size="50" value="[foundin html]">
@   </td></tr>
@   <tr><td colspan="2">
@
@   [
@      0 /eall get /eall set           # eall means "edit all".  default==no
@      /aonlybtn exists not /eall set  # Edit all if no aonlybtn CGI param
@      /eallbtn exists /eall set       # Edit all if eallbtn CGI param







|
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<












|



















|





|





|
|
|
|










<
|
>







|
|







|


|
>
>
|
|
|




|





|






|






|







|












>
>
>
>
>
>
>
>
|
<
|



|


|


|










|








|
|
|
|
>
|
|
|
|
|
|
|
|
<
|
<

|
|


|


|


|


|


|


|


|

|

|

|

|







31
32
33
34
35
36
37
38


39














































40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97

98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178

179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221

222

223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
** This is a sample "ticket configuration" file for fossil.
**
** There is considerable flexibility in how tickets are defined
** in fossil.  Each repository can define its own ticket setup
** differently.  Each repository has an instance of a file, like
** this one that defines how that repository deals with tickets.
**
** This file is in the form of a script in TH1 - a minimalist


** TCL clone.














































*/

/* @-comment: ** */
const char zDefaultTicketConfig[] = 
@ ############################################################################
@ # Every ticket configuration *must* define an SQL statement that creates
@ # the TICKET table.  This table must have three columns named
@ # tkt_id, tkt_uuid, and tkt_mtime.  tkt_id must be the integer primary
@ # key and tkt_uuid and tkt_mtime must be unique.  A configuration should
@ # define addition columns as necessary.  All columns should be in all
@ # lower-case letters and should not begin with "tkt".
@ #
@ set ticket_sql {
@    CREATE TABLE ticket(
@      -- Do not change any column that begins with tkt_
@      tkt_id INTEGER PRIMARY KEY,
@      tkt_uuid TEXT,
@      tkt_mtime DATE,
@      -- Add as many field as required below this line
@      type TEXT,
@      status TEXT,
@      subsystem TEXT,
@      priority TEXT,
@      severity TEXT,
@      foundin TEXT,
@      contact TEXT,
@      title TEXT,
@      comment TEXT,
@      -- Do not alter this UNIQUE clause:
@      UNIQUE(tkt_uuid, tkt_mtime)
@    );
@    -- Add indices as desired
@ }
@ 
@ ############################################################################
@ # You can define additional variables here.  These variables will be
@ # accessible to the page templates when they run.
@ #
@ set type_choices {
@    Code_Defect
@    Build_Problem
@    Documentation
@    Feature_Request
@    Incident
@ }
@ set priority_choices {Immediate High Medium Low Zero}
@ set severity_choices {Critical Severe Important Minor Cosmetic}
@ set resolution_choices {
@   Open
@   Fixed
@   Rejected
@   Unable_To_Reproduce
@   Works_As_Designed
@   External_Bug
@   Not_A_Bug
@   Duplicate
@   Overcome_By_Events
@   Drive_By_Patch

@ }
@ set status_choices {
@   Open
@   Verified
@   In_Process
@   Deferred
@   Fixed
@   Tested
@   Closed
@ }
@ set subsystem_choices {one two three}
@ 
@ ##########################################################################
@ # The "tktnew_template" variable is set to text which is a template for
@ # the HTML of the "New Ticket" page.  Within this template, text contained
@ # within [...] is subscript.  That subscript runs when the page is
@ # rendered.
@ #
@ set tktnew_template {
@   <!-- load database field names not found in CGI with an empty string -->
@   <!-- start a form -->
@   <th1>
@     if {[info exists submit]} {
@        set status Open
@        submit_ticket
@     }
@   </th1>
@   <table cellpadding="5">
@   <tr>
@   <td colspan="2">
@   Enter a one-line summary of the problem:<br>
@   <input type="text" name="title" size="60" value="$<title>">
@   </td>
@   </tr>
@   
@   <tr>
@   <td align="right">Type:
@   <th1>combobox type $type_choices 1</th1>
@   </td>
@   <td>What type of ticket is this?</td>
@   </tr>
@   
@   <tr>
@   <td align="right">Version: 
@   <input type="text" name="foundin" size="20" value="$<foundin>">
@   </td>
@   <td>In what version or build number do you observer the problem?</td>
@   </tr>
@   
@   <tr>
@   <td align="right">Severity:
@   <th1>comboboxy severity severity_choices 1</th1>
@   </td>
@   <td>How debilitating is the problem?  How badly does the problem
@   effect the operation of the product?</td>
@   </tr>
@   
@   <tr>
@   <td align="right">EMail:
@   <input type="text" name="contact" value="$<contact>" size="30">
@   </td>
@   <td>Not publically visible. Used by developers to contact you with
@   questions.</td>
@   </tr>
@   
@   <tr>
@   <td colspan="2">
@   Enter a detailed description of the problem.
@   For code defects, be sure to provide details on exactly how
@   the problem can be reproduced.  Provide as much detail as
@   possible.
@   <br>
@   <th1>
@      if {![info exists comment]} {
@        set nline 10
@      } else {
@        set nline [linecount $comment]
@        if {$nline>50} {set nline 50}
@      }
@   </th1>
@   <textarea name="comment" cols="80" rows="$nline"

@    wrap="virtual" class="wikiedit">$<comment></textarea><br>
@   <input type="submit" name="preview" value="Preview">
@   </tr>
@ 
@   <th1>enable_output [info exists preview]</th1>
@   <tr><td colspan="2">
@   Description Preview:<br><hr>
@   <th1>wiki $comment</th1>
@   <hr>
@   </td></tr>
@   <th1>enable_output 1</th1>
@   
@   <tr>
@   <td align="right">
@   <input type="submit" name="submit" value="Submit">
@   </td>
@   <td>After filling in the information above, press this button to create
@   the new ticket</td>
@   </tr>
@   </table>
@   <!-- end of form -->
@ }
@ 
@ ##########################################################################
@ # The template for the "edit ticket" page
@ #
@ # Then generated text is inserted inside a form which feeds back to itself.
@ # All CGI parameters are loaded into variables.  All database files are
@ # loaded into variables if they have not previously been loaded by
@ # CGI parameters.
@ set tktedit_template {
@   <th1>
@     if {![info exists username]} {set username $login}
@     if {[info exists submit]} {
@       if {[info exists $cmappnd] && [string length $cmappnd]>0} {
@         set ctxt "\n\n<hr><i>"
@         if {$username==$login} {
@           set usr "$ctxt[htmlize $login]"
@         } else {
@           set usr "[htmlize $login claimingn to be [htmlize $username]"
@         }
@         append_field comment \
@            "\n\n<hr><i>$usr added on [date]:</i><br>\n$comment"

@       }

@       submit_ticket
@     }
@   </th1>
@   <table cellpadding="5">
@   <tr><td align="right">Title:</td><td>
@   <input type="text" name="title" value="$<title>" size="60">
@   </td></tr>
@   <tr><td align="right">Status:</td><td>
@   <th1>combobox status $status_choices 1</th1>
@   </td></tr>
@   <tr><td align="right">Type:</td><td>
@   <th1>combobox type $type_choices 1</th1>
@   </td></tr>
@   <tr><td align="right">Severity:</td><td>
@   <th1>combobox severity $severity_choices 1</th1>
@   </td></tr>
@   <tr><td align="right">Priority:</td><td>
@   <th1>combobox priority $priority_choices 1</th1>
@   </td></tr>
@   <tr><td align="right">Resolution:</td><td>
@   <th1>combobox resolution $resolution_choices 1</th1>
@   </td></tr>
@   <tr><td align="right">Subsystem:</td><td>
@   <th1>combobox subsystem $subsystem_choices 1</th1>
@   </td></tr>
@   <th1>enable_output [hascap e]</th1>
@     <tr><td align="right">Contact:</td><td>
@     <input type="text" name="contact" size="40" value="$<contact>">
@     </td></tr>
@   <th1>enable_output 1</th1>
@   <tr><td align="right">Version&nbsp;Found&nbsp;In:</td><td>
@   <input type="text" name="foundin" size="50" value="$<foundin>">
@   </td></tr>
@   <tr><td colspan="2">
@
@   [
@      0 /eall get /eall set           # eall means "edit all".  default==no
@      /aonlybtn exists not /eall set  # Edit all if no aonlybtn CGI param
@      /eallbtn exists /eall set       # Edit all if eallbtn CGI param
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
@   <input type="submit" name="submit" value="Submit Changes">
@   </td></tr>
@   </table>
@ } /tktedit_template set
@ 
@ ##########################################################################
@ # The template for the "view ticket" page
@ {
@   <!-- load database fields automatically loaded into variables -->
@   <table cellpadding="5">
@   <tr><td align="right">Title:</td><td>
@   [title html]
@   </td></tr>
@   <tr><td align="right">Status:</td><td>
@   [status html]
@   </td></tr>
@   <tr><td align="right">Type:</td><td>
@   [type html]
@   </td></tr>
@   <tr><td align="right">Severity:</td><td>
@   [severity html]
@   </td></tr>
@   <tr><td align="right">Priority:</td><td>
@   [priority html]
@   </td></tr>
@   <tr><td align="right">Resolution:</td><td>
@   [priority html]
@   </td></tr>
@   <tr><td align="right">Subsystem:</td><td>
@   [subsystem html]
@   </td></tr>
@   [{e} hascap enable_output]
@     <tr><td align="right">Contact:</td><td>
@     [contact html]
@     </td></tr>
@   [1 enable_output]
@   <tr><td align="right">Version&nbsp;Found&nbsp;In:</td><td>
@   [foundin html]
@   </td></tr>
@   <tr><td colspan="2">
@   Description And Comments:<br>
@   [comment wiki]
@   </td></tr>
@   </table>
@ } /tktview_template set
;







|



|


|


|


|


|


|


|

|

|

|

|



|


|

284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
@   <input type="submit" name="submit" value="Submit Changes">
@   </td></tr>
@   </table>
@ } /tktedit_template set
@ 
@ ##########################################################################
@ # The template for the "view ticket" page
@ set tktview_template {
@   <!-- load database fields automatically loaded into variables -->
@   <table cellpadding="5">
@   <tr><td align="right">Title:</td><td>
@   $<title>
@   </td></tr>
@   <tr><td align="right">Status:</td><td>
@   $<status>
@   </td></tr>
@   <tr><td align="right">Type:</td><td>
@   $<type>
@   </td></tr>
@   <tr><td align="right">Severity:</td><td>
@   $<severity>
@   </td></tr>
@   <tr><td align="right">Priority:</td><td>
@   $<priority>
@   </td></tr>
@   <tr><td align="right">Resolution:</td><td>
@   $<resolution>
@   </td></tr>
@   <tr><td align="right">Subsystem:</td><td>
@   $<subsystem>
@   </td></tr>
@   <th1>enable_output [hascap e]</th1>
@     <tr><td align="right">Contact:</td><td>
@     $<contact>
@     </td></tr>
@   <th1>enable_output 1</th1>
@   <tr><td align="right">Version&nbsp;Found&nbsp;In:</td><td>
@   $<foundin>
@   </td></tr>
@   <tr><td colspan="2">
@   Description And Comments:<br>
@   <th1>wiki $comment</th1>
@   </td></tr>
@   </table>
@ }
;