Fossil

Check-in [517223eca9]
Login

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

Overview
Comment:Improvements to help-text HTML formatting.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 517223eca965c361d6619aae668786be1203aa783c97fd517a3d32ba3e9e417b
User & Date: drh 2020-08-26 21:43:54.147
Context
2020-08-27
01:37
Fix the server-side clone so that it is able to operate on a read-only repository database. check-in: 147bf47d6e user: drh tags: trunk
2020-08-26
21:43
Improvements to help-text HTML formatting. check-in: 517223eca9 user: drh tags: trunk
14:46
Update the built-in SQLite to the latest 3.34.0 alpha that includes support for the sqlite3_txn_state() interface, with an eye toward using sqlite3_txn_state() to help prevent "busy" errors coming from high-load Fossil servers. check-in: e3ca34cb38 user: drh tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/dispatch.c.
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
  int i;
  for(i=3; i<n-1; i++){
    if( z[i]==' ' && z[i+1]!=' ' && z[i-1]==' ' && z[i-2]!='.' ) return i+1;
  }
  return 0 ;
}

/*
** Append text to pOut, adding formatting markup.  Terms that
** have all lower-case letters are within <tt>..</tt>.  Terms
** that have all upper-case letters are within <i>..</i>.
*/
static void appendMixedFont(Blob *pOut, const char *z, int n){
  const char *zEnd = "";
  int i = 0;
  int j;
  while( i<n ){
    if( z[i]==' ' || z[i]=='=' ){
      for(j=i+1; j<n && (z[j]==' ' || z[j]=='='); j++){}
      blob_append(pOut, z+i, j-i);
      i = j;
    }else{
      for(j=i; j<n && z[j]!=' ' && z[j]!='=' && !fossil_isalpha(z[j]); j++){}
      if( j>=n || z[j]==' ' || z[j]=='=' ){
        zEnd = "";
      }else{
        if( fossil_isupper(z[j]) && z[i]!='-' ){
          blob_append(pOut, "<i>",3);
          zEnd = "</i>";
        }else{
          blob_append(pOut, "<tt>", 4);
          zEnd = "</tt>";
        }
      }
      while( j<n && z[j]!=' ' && z[j]!='=' ){ j++; }
      blob_appendf(pOut, "%#h", j-i, z+i);
      if( zEnd[0] ) blob_append(pOut, zEnd, -1);
      i = j;
    }
  }
}

/*
** Input string zIn starts with '['.  If the content is a hyperlink of the
** form [[...]] then return the index of the closing ']'.  Otherwise return 0.
*/
static int help_is_link(const char *z, int n){
  int i;
  char c;
  if( n<5 ) return 0;
  if( z[1]!='[' ) return 0;
  for(i=3; i<n && (c = z[i])!=0; i++){
    if( c==']' && z[i-1]==']' ) return i;
  }
  return 0;
}

/*
** Append text to pOut, adding hyperlink markup for [...].




*/
static void appendLinked(Blob *pOut, const char *z, int n){
  int i = 0;
  int j;
  while( i<n ){

    if( z[i]=='[' && (j = help_is_link(z+i, n-i))>0 ){
      if( i ) blob_append(pOut, z, i);
      z += i+2;
      n -= i+2;
      blob_appendf(pOut, "<a href='%R/help?cmd=%.*s'>%.*s</a>",
         j-3, z, j-3, z);
      z += j-1;
      n -= j-1;
      i = 0;
























    }else{
      i++;
    }
  }
  blob_append(pOut, z, i);
}




































/*
** Attempt to reformat plain-text help into HTML for display on a webpage.
**
** The HTML output is appended to Blob pHtml, which should already be
** initialized.
**







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
















|
>
>
>
>





>
|








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






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







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
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
  int i;
  for(i=3; i<n-1; i++){
    if( z[i]==' ' && z[i+1]!=' ' && z[i-1]==' ' && z[i-2]!='.' ) return i+1;
  }
  return 0 ;
}




































/*
** Input string zIn starts with '['.  If the content is a hyperlink of the
** form [[...]] then return the index of the closing ']'.  Otherwise return 0.
*/
static int help_is_link(const char *z, int n){
  int i;
  char c;
  if( n<5 ) return 0;
  if( z[1]!='[' ) return 0;
  for(i=3; i<n && (c = z[i])!=0; i++){
    if( c==']' && z[i-1]==']' ) return i;
  }
  return 0;
}

/*
** Append text to pOut with changes:
**
**    *   Add hyperlink markup for [[...]]
**    *   Escape HTML characters: < > & and "
**    *   Change "%fossil" to just "fossil"
*/
static void appendLinked(Blob *pOut, const char *z, int n){
  int i = 0;
  int j;
  while( i<n ){
    char c = z[i];
    if( c=='[' && (j = help_is_link(z+i, n-i))>0 ){
      if( i ) blob_append(pOut, z, i);
      z += i+2;
      n -= i+2;
      blob_appendf(pOut, "<a href='%R/help?cmd=%.*s'>%.*s</a>",
         j-3, z, j-3, z);
      z += j-1;
      n -= j-1;
      i = 0;
    }else if( c=='%' && n-i>=7 && strncmp(z+i,"%fossil",7)==0 ){
      if( i ) blob_append(pOut, z, i);
      z += i+7;
      n -= i+7;
      blob_append(pOut, "fossil", 6);
      i = 0;
    }else if( c=='<' ){
      if( i ) blob_append(pOut, z, i);
      blob_append(pOut, "&lt;", 4);
      z += i+1;
      n -= i+1;
      i = 0;
    }else if( c=='>' ){
      if( i ) blob_append(pOut, z, i);
      blob_append(pOut, "&gt;", 4);
      z += i+1;
      n -= i+1;
      i = 0;
    }else if( c=='&' ){
      if( i ) blob_append(pOut, z, i);
      blob_append(pOut, "&amp;", 5);
      z += i+1;
      n -= i+1;
      i = 0;
    }else{
      i++;
    }
  }
  blob_append(pOut, z, i);
}

/*
** Append text to pOut, adding formatting markup.  Terms that
** have all lower-case letters are within <tt>..</tt>.  Terms
** that have all upper-case letters are within <i>..</i>.
*/
static void appendMixedFont(Blob *pOut, const char *z, int n){
  const char *zEnd = "";
  int i = 0;
  int j;
  while( i<n ){
    if( z[i]==' ' || z[i]=='=' ){
      for(j=i+1; j<n && (z[j]==' ' || z[j]=='='); j++){}
      appendLinked(pOut, z+i, j-i);
      i = j;
    }else{
      for(j=i; j<n && z[j]!=' ' && z[j]!='=' && !fossil_isalpha(z[j]); j++){}
      if( j>=n || z[j]==' ' || z[j]=='=' ){
        zEnd = "";
      }else{
        if( fossil_isupper(z[j]) && z[i]!='-' ){
          blob_append(pOut, "<i>",3);
          zEnd = "</i>";
        }else{
          blob_append(pOut, "<tt>", 4);
          zEnd = "</tt>";
        }
      }
      while( j<n && z[j]!=' ' && z[j]!='=' ){ j++; }
      appendLinked(pOut, z+i, j-i);
      if( zEnd[0] ) blob_append(pOut, zEnd, -1);
      i = j;
    }
  }
}

/*
** Attempt to reformat plain-text help into HTML for display on a webpage.
**
** The HTML output is appended to Blob pHtml, which should already be
** initialized.
**
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
370



371

372
373
374
375
376
377
378
  static const char *zEndUL = "</ul>";
  static const char *zEndDD = "</dd>";

  aIndent[0] = 0;
  azEnd[0] = "";
  while( zHelp[0] ){
    i = 0;
    while( (c = zHelp[i])!=0
        && c!='\n'
        && c!='<'
        && (c!='%' || strncmp(zHelp+i,"%fossil",7)!=0)
    ){ i++; }
    if( c=='%' ){
      if( i ) blob_appendf(pHtml, "%#h", i, zHelp);
      zHelp += i + 1;

      wantBR = 1;
      continue;
    }else if( c=='<' ){
      if( i ) blob_appendf(pHtml, "%#h", i, zHelp);
      blob_append(pHtml, "&amp;", 5);
      zHelp += i + 1;

      continue;
    }
    if( i>2 && zHelp[0]=='>' && zHelp[1]==' ' ){
      isDT = 1;
      for(nIndent=1; nIndent<i && zHelp[nIndent]==' '; nIndent++){}
    }else{
      isDT = 0;
      for(nIndent=0; nIndent<i && zHelp[nIndent]==' '; nIndent++){}
    }
    if( nIndent==i ){
      if( c==0 ) break;



      blob_append(pHtml, "\n", 1);

      wantP = 1;
      wantBR = 0;
      zHelp += i+1;
      continue;
    }
    if( nIndent+2<i && zHelp[nIndent]=='*' && zHelp[nIndent+1]==' ' ){
      nIndent += 2;







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










>
>
>
|
>







368
369
370
371
372
373
374
375


376


377
378
379
380
381




382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
  static const char *zEndUL = "</ul>";
  static const char *zEndDD = "</dd>";

  aIndent[0] = 0;
  azEnd[0] = "";
  while( zHelp[0] ){
    i = 0;
    while( (c = zHelp[i])!=0 && c!='\n' ){


      if( c=='%' && i>2 && zHelp[i-2]==':' && strncmp(zHelp+i,"%fossil",7)==0 ){


        appendLinked(pHtml, zHelp, i);
        zHelp += i+1;
        i = 0;
        wantBR = 1;
        continue;




      }
      i++;
    }
    if( i>2 && zHelp[0]=='>' && zHelp[1]==' ' ){
      isDT = 1;
      for(nIndent=1; nIndent<i && zHelp[nIndent]==' '; nIndent++){}
    }else{
      isDT = 0;
      for(nIndent=0; nIndent<i && zHelp[nIndent]==' '; nIndent++){}
    }
    if( nIndent==i ){
      if( c==0 ) break;
      if( iLevel && azEnd[iLevel]==zEndPRE ){
        /* Skip the newline at the end of a <pre> */
      }else{
        blob_append_char(pHtml, '\n');
      }
      wantP = 1;
      wantBR = 0;
      zHelp += i+1;
      continue;
    }
    if( nIndent+2<i && zHelp[nIndent]=='*' && zHelp[nIndent+1]==' ' ){
      nIndent += 2;
425
426
427
428
429
430
431
432

433
434
435
436

437
438
439
440
441
442
443
      if( iDD ){
        int x;
        assert( iLevel<ArraySize(aIndent)-1 );
        iLevel++;
        aIndent[iLevel] = x = nIndent+iDD;
        azEnd[iLevel] = zEndDD;
        appendMixedFont(pHtml, zHelp+nIndent, iDD-2);
        blob_appendf(pHtml, "</dt><dd>%#h\n", i-x, zHelp+x);

      }else{
        appendMixedFont(pHtml, zHelp+nIndent, i-nIndent);
        blob_append(pHtml, "</dt>\n", 6);
      }

    }else if( wantBR ){
      appendMixedFont(pHtml, zHelp+nIndent, i-nIndent);
      blob_append(pHtml, "<br>\n", 5);
      wantBR = 0;
    }else{
      appendLinked(pHtml, zHelp+nIndent, i-nIndent);
      blob_append_char(pHtml, '\n');







|
>


<

>







452
453
454
455
456
457
458
459
460
461
462

463
464
465
466
467
468
469
470
471
      if( iDD ){
        int x;
        assert( iLevel<ArraySize(aIndent)-1 );
        iLevel++;
        aIndent[iLevel] = x = nIndent+iDD;
        azEnd[iLevel] = zEndDD;
        appendMixedFont(pHtml, zHelp+nIndent, iDD-2);
        blob_append(pHtml, "</dt><dd>",9);
        appendLinked(pHtml, zHelp+x, i-x);
      }else{
        appendMixedFont(pHtml, zHelp+nIndent, i-nIndent);

      }
      blob_append(pHtml, "</dt>\n", 6);
    }else if( wantBR ){
      appendMixedFont(pHtml, zHelp+nIndent, i-nIndent);
      blob_append(pHtml, "<br>\n", 5);
      wantBR = 0;
    }else{
      appendLinked(pHtml, zHelp+nIndent, i-nIndent);
      blob_append_char(pHtml, '\n');
Changes to src/main.c.
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
**    redirect: REPO URL       Extract the "name" query parameter and search
**                             REPO for a check-in or ticket that matches the
**                             value of "name", then redirect to URL.  There
**                             can be multiple "redirect:" lines that are
**                             processed in order.  If the REPO is "*", then
**                             an unconditional redirect to URL is taken.
**
**     jsmode: VALUE           Specifies the delivery mode for JavaScript
**                             files. See the help text for the --jsmode
**                             flag of the http command.
**
** Most CGI files contain only a "repository:" line.  It is uncommon to
** use any other option.
**
** See also: [[http]], [[server]], [[winsrv]]







|







2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
**    redirect: REPO URL       Extract the "name" query parameter and search
**                             REPO for a check-in or ticket that matches the
**                             value of "name", then redirect to URL.  There
**                             can be multiple "redirect:" lines that are
**                             processed in order.  If the REPO is "*", then
**                             an unconditional redirect to URL is taken.
**
**    jsmode: VALUE            Specifies the delivery mode for JavaScript
**                             files. See the help text for the --jsmode
**                             flag of the http command.
**
** Most CGI files contain only a "repository:" line.  It is uncommon to
** use any other option.
**
** See also: [[http]], [[server]], [[winsrv]]