Changes On Branch markdown
Not logged in

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

Changes In Branch markdown Excluding Merge-Ins

This is equivalent to a diff from 0bb8184e3c to de1ef7e99f

2012-12-08
00:41
Merge markdown support for embedded documentation into the trunk. check-in: 61079c3bef user: mistachkin tags: trunk
2012-12-07
20:58
Merge updates from trunk. Closed-Leaf check-in: de1ef7e99f user: mistachkin tags: markdown
14:57
Fix for click-to-diff in IE8, tested this time using IE9 in compatibility mode. check-in: 0bb8184e3c user: drh tags: trunk
14:33
Attempt to get click-to-diff working on IE8. check-in: ce99889c68 user: drh tags: trunk
2012-10-07
14:28
Update the 'makemake' script with the MinGW makefile changes for the markdown feature as well. check-in: 0db09a2061 user: mistachkin tags: markdown

Changes to auto.def.

     9      9       with-tcl:path        => {Enable Tcl integration, with Tcl in the specified path}
    10     10       with-tcl-stubs=0     => {Enable Tcl integration via stubs mechanism}
    11     11       internal-sqlite=1    => {Don't use the internal sqlite, use the system one}
    12     12       static=0             => {Link a static executable}
    13     13       lineedit=1           => {Disable line editing}
    14     14       fossil-debug=0       => {Build with fossil debugging enabled}
    15     15       json=0               => {Build with fossil JSON API enabled}
           16  +    markdown=0           => {Build with markdown engine enabled}
    16     17   }
    17     18   
    18     19   # sqlite wants these types if possible
    19     20   cc-with {-includes {stdint.h inttypes.h}} {
    20     21       cc-check-types uint32_t uint16_t int16_t uint8_t
    21     22   }
    22     23   
................................................................................
    71     72       # Reminder/FIXME (stephan): FOSSIL_ENABLE_JSON
    72     73       # is required in the CFLAGS because json*.c
    73     74       # have #ifdef guards around the whole file without
    74     75       # reading config.h first.
    75     76       define-append EXTRA_CFLAGS -DFOSSIL_ENABLE_JSON
    76     77       define FOSSIL_ENABLE_JSON
    77     78   }
           79  +
           80  +if {[opt-bool markdown]} {
           81  +    define-append EXTRA_CFLAGS -DFOSSIL_ENABLE_MARKDOWN
           82  +    define FOSSIL_ENABLE_MARKDOWN
           83  +}
    78     84   
    79     85   if {[opt-bool static]} {
    80     86       # XXX: This will not work on all systems.
    81     87       define-append EXTRA_LDFLAGS -static
    82     88   }
    83     89   
    84     90   # Check for zlib, using the given location if specified

Changes to src/db.c.

  2072   2072     { "https-login",   0,                0, 0, "off"                 },
  2073   2073     { "ignore-glob",   0,               40, 1, ""                    },
  2074   2074     { "empty-dirs",    0,               40, 1, ""                    },
  2075   2075     { "http-port",     0,               16, 0, "8080"                },
  2076   2076     { "localauth",     0,                0, 0, "off"                 },
  2077   2077     { "main-branch",   0,               40, 0, "trunk"               },
  2078   2078     { "manifest",      0,                0, 1, "off"                 },
         2079  +#ifdef FOSSIL_ENABLE_MARKDOWN
         2080  +  { "markdown",      0,                0, 0, "off"                 },
         2081  +#endif
  2079   2082     { "max-upload",    0,               25, 0, "250000"              },
  2080   2083     { "mtime-changes", 0,                0, 0, "on"                  },
  2081   2084     { "pgp-command",   0,               40, 0, "gpg --clearsign -o " },
  2082   2085     { "proxy",         0,               32, 0, "off"                 },
  2083   2086     { "relative-paths",0,                0, 0, "on"                  },
  2084   2087     { "repo-cksum",    0,                0, 0, "on"                  },
  2085   2088     { "self-register", 0,                0, 0, "off"                 },
................................................................................
  2203   2206   **
  2204   2207   **    main-branch      The primary branch for the project.  Default: trunk
  2205   2208   **
  2206   2209   **    manifest         If enabled, automatically create files "manifest" and
  2207   2210   **     (versionable)   "manifest.uuid" in every checkout.  The SQLite and
  2208   2211   **                     Fossil repositories both require this.  Default: off.
  2209   2212   **
         2213  +**    markdown         If enabled (and Fossil was compiled with markdown
         2214  +**                     support), the markdown engine will be used to render
         2215  +**                     embedded documentation conforming to the appropriate
         2216  +**                     content types (e.g. "text/x-markdown"). Default: off.
         2217  +**
  2210   2218   **    max-upload       A limit on the size of uplink HTTP requests.  The
  2211   2219   **                     default is 250000 bytes.
  2212   2220   **
  2213   2221   **    mtime-changes    Use file modification times (mtimes) to detect when
  2214   2222   **                     files have been modified.  (Default "on".)
  2215   2223   **
  2216   2224   **    pgp-command      Command used to clear-sign manifests at check-in.

Changes to src/doc.c.

   164    164       { "latex",      5, "application/x-latex"               },
   165    165       { "lha",        3, "application/octet-stream"          },
   166    166       { "lsp",        3, "application/x-lisp"                },
   167    167       { "lzh",        3, "application/octet-stream"          },
   168    168       { "m",          1, "text/plain"                        },
   169    169       { "m3u",        3, "audio/x-mpegurl"                   },
   170    170       { "man",        3, "application/x-troff-man"           },
          171  +    { "markdown",   8, "text/x-markdown"                   },
   171    172       { "me",         2, "application/x-troff-me"            },
   172    173       { "mesh",       4, "model/mesh"                        },
   173    174       { "mid",        3, "audio/midi"                        },
   174    175       { "midi",       4, "audio/midi"                        },
   175    176       { "mif",        3, "application/x-mif"                 },
   176    177       { "mime",       4, "www/mime"                          },
          178  +    { "mkd",        3, "text/x-markdown"                   },
   177    179       { "mov",        3, "video/quicktime"                   },
   178    180       { "movie",      5, "video/x-sgi-movie"                 },
   179    181       { "mp2",        3, "audio/mpeg"                        },
   180    182       { "mp3",        3, "audio/mpeg"                        },
   181    183       { "mpe",        3, "video/mpeg"                        },
   182    184       { "mpeg",       4, "video/mpeg"                        },
   183    185       { "mpg",        3, "video/mpeg"                        },
................................................................................
   496    498         style_header(blob_str(&title));
   497    499         wiki_convert(&tail, 0, WIKI_BUTTONS);
   498    500       }else{
   499    501         style_header("Documentation");
   500    502         wiki_convert(&filebody, 0, WIKI_BUTTONS);
   501    503       }
   502    504       style_footer();
          505  +#ifdef FOSSIL_ENABLE_MARKDOWN
          506  +  }else if( fossil_strcmp(zMime, "text/x-markdown")==0
          507  +         && db_get_boolean("markdown", 0) ){
          508  +    Blob title = BLOB_INITIALIZER;
          509  +    Blob tail = BLOB_INITIALIZER;
          510  +    markdown_to_html(&filebody, &title, &tail);
          511  +    if( blob_size(&title)>0 ){
          512  +      style_header(blob_str(&title));
          513  +    }else{
          514  +      style_header("Documentation");
          515  +    }
          516  +    blob_append(cgi_output_blob(), blob_buffer(&tail), blob_size(&tail));
          517  +    style_footer();
          518  +#endif
   503    519     }else if( fossil_strcmp(zMime, "text/plain")==0 ){
   504    520       style_header("Documentation");
   505    521       @ <blockquote><pre>
   506    522       @ %h(blob_str(&filebody))
   507    523       @ </pre></blockquote>
   508    524       style_footer();
   509    525     }else{

Changes to src/main.mk.

    66     66     $(SRCDIR)/json_timeline.c \
    67     67     $(SRCDIR)/json_user.c \
    68     68     $(SRCDIR)/json_wiki.c \
    69     69     $(SRCDIR)/leaf.c \
    70     70     $(SRCDIR)/login.c \
    71     71     $(SRCDIR)/main.c \
    72     72     $(SRCDIR)/manifest.c \
           73  +  $(SRCDIR)/markdown.c \
           74  +  $(SRCDIR)/markdown_html.c \
    73     75     $(SRCDIR)/md5.c \
    74     76     $(SRCDIR)/merge.c \
    75     77     $(SRCDIR)/merge3.c \
    76     78     $(SRCDIR)/moderate.c \
    77     79     $(SRCDIR)/name.c \
    78     80     $(SRCDIR)/path.c \
    79     81     $(SRCDIR)/pivot.c \
................................................................................
   168    170     $(OBJDIR)/json_timeline_.c \
   169    171     $(OBJDIR)/json_user_.c \
   170    172     $(OBJDIR)/json_wiki_.c \
   171    173     $(OBJDIR)/leaf_.c \
   172    174     $(OBJDIR)/login_.c \
   173    175     $(OBJDIR)/main_.c \
   174    176     $(OBJDIR)/manifest_.c \
          177  +  $(OBJDIR)/markdown_.c \
          178  +  $(OBJDIR)/markdown_html_.c \
   175    179     $(OBJDIR)/md5_.c \
   176    180     $(OBJDIR)/merge_.c \
   177    181     $(OBJDIR)/merge3_.c \
   178    182     $(OBJDIR)/moderate_.c \
   179    183     $(OBJDIR)/name_.c \
   180    184     $(OBJDIR)/path_.c \
   181    185     $(OBJDIR)/pivot_.c \
................................................................................
   270    274    $(OBJDIR)/json_timeline.o \
   271    275    $(OBJDIR)/json_user.o \
   272    276    $(OBJDIR)/json_wiki.o \
   273    277    $(OBJDIR)/leaf.o \
   274    278    $(OBJDIR)/login.o \
   275    279    $(OBJDIR)/main.o \
   276    280    $(OBJDIR)/manifest.o \
          281  + $(OBJDIR)/markdown.o \
          282  + $(OBJDIR)/markdown_html.o \
   277    283    $(OBJDIR)/md5.o \
   278    284    $(OBJDIR)/merge.o \
   279    285    $(OBJDIR)/merge3.o \
   280    286    $(OBJDIR)/moderate.o \
   281    287    $(OBJDIR)/name.o \
   282    288    $(OBJDIR)/path.o \
   283    289    $(OBJDIR)/pivot.o \
................................................................................
   382    388   clean:	
   383    389   	rm -rf $(OBJDIR)/* $(APPNAME)
   384    390   
   385    391   
   386    392   $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex
   387    393   	$(OBJDIR)/mkindex $(TRANS_SRC) >$@
   388    394   $(OBJDIR)/headers:	$(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h
   389         -	$(OBJDIR)/makeheaders  $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h $(OBJDIR)/bag_.c:$(OBJDIR)/bag.h $(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h $(OBJDIR)/blob_.c:$(OBJDIR)/blob.h $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/json_.c:$(OBJDIR)/json.h $(OBJDIR)/json_artifact_.c:$(OBJDIR)/json_artifact.h $(OBJDIR)/json_branch_.c:$(OBJDIR)/json_branch.h $(OBJDIR)/json_config_.c:$(OBJDIR)/json_config.h $(OBJDIR)/json_diff_.c:$(OBJDIR)/json_diff.h $(OBJDIR)/json_dir_.c:$(OBJDIR)/json_dir.h $(OBJDIR)/json_finfo_.c:$(OBJDIR)/json_finfo.h $(OBJDIR)/json_login_.c:$(OBJDIR)/json_login.h $(OBJDIR)/json_query_.c:$(OBJDIR)/json_query.h $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/moderate_.c:$(OBJDIR)/moderate.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/wysiwyg_.c:$(OBJDIR)/wysiwyg.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h
          395  +	$(OBJDIR)/makeheaders  $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h $(OBJDIR)/bag_.c:$(OBJDIR)/bag.h $(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h $(OBJDIR)/blob_.c:$(OBJDIR)/blob.h $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/json_.c:$(OBJDIR)/json.h $(OBJDIR)/json_artifact_.c:$(OBJDIR)/json_artifact.h $(OBJDIR)/json_branch_.c:$(OBJDIR)/json_branch.h $(OBJDIR)/json_config_.c:$(OBJDIR)/json_config.h $(OBJDIR)/json_diff_.c:$(OBJDIR)/json_diff.h $(OBJDIR)/json_dir_.c:$(OBJDIR)/json_dir.h $(OBJDIR)/json_finfo_.c:$(OBJDIR)/json_finfo.h $(OBJDIR)/json_login_.c:$(OBJDIR)/json_login.h $(OBJDIR)/json_query_.c:$(OBJDIR)/json_query.h $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/markdown_.c:$(OBJDIR)/markdown.h $(OBJDIR)/markdown_html_.c:$(OBJDIR)/markdown_html.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/moderate_.c:$(OBJDIR)/moderate.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/wysiwyg_.c:$(OBJDIR)/wysiwyg.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h
   390    396   	touch $(OBJDIR)/headers
   391    397   $(OBJDIR)/headers: Makefile
   392    398   $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/json_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
   393    399   Makefile:
   394    400   $(OBJDIR)/add_.c:	$(SRCDIR)/add.c $(OBJDIR)/translate
   395    401   	$(OBJDIR)/translate $(SRCDIR)/add.c >$(OBJDIR)/add_.c
   396    402   
................................................................................
   779    785   $(OBJDIR)/manifest_.c:	$(SRCDIR)/manifest.c $(OBJDIR)/translate
   780    786   	$(OBJDIR)/translate $(SRCDIR)/manifest.c >$(OBJDIR)/manifest_.c
   781    787   
   782    788   $(OBJDIR)/manifest.o:	$(OBJDIR)/manifest_.c $(OBJDIR)/manifest.h  $(SRCDIR)/config.h
   783    789   	$(XTCC) -o $(OBJDIR)/manifest.o -c $(OBJDIR)/manifest_.c
   784    790   
   785    791   $(OBJDIR)/manifest.h:	$(OBJDIR)/headers
          792  +$(OBJDIR)/markdown_.c:	$(SRCDIR)/markdown.c $(OBJDIR)/translate
          793  +	$(OBJDIR)/translate $(SRCDIR)/markdown.c >$(OBJDIR)/markdown_.c
          794  +
          795  +$(OBJDIR)/markdown.o:	$(OBJDIR)/markdown_.c $(OBJDIR)/markdown.h  $(SRCDIR)/config.h
          796  +	$(XTCC) -o $(OBJDIR)/markdown.o -c $(OBJDIR)/markdown_.c
          797  +
          798  +$(OBJDIR)/markdown.h:	$(OBJDIR)/headers
          799  +$(OBJDIR)/markdown_html_.c:	$(SRCDIR)/markdown_html.c $(OBJDIR)/translate
          800  +	$(OBJDIR)/translate $(SRCDIR)/markdown_html.c >$(OBJDIR)/markdown_html_.c
          801  +
          802  +$(OBJDIR)/markdown_html.o:	$(OBJDIR)/markdown_html_.c $(OBJDIR)/markdown_html.h  $(SRCDIR)/config.h
          803  +	$(XTCC) -o $(OBJDIR)/markdown_html.o -c $(OBJDIR)/markdown_html_.c
          804  +
          805  +$(OBJDIR)/markdown_html.h:	$(OBJDIR)/headers
   786    806   $(OBJDIR)/md5_.c:	$(SRCDIR)/md5.c $(OBJDIR)/translate
   787    807   	$(OBJDIR)/translate $(SRCDIR)/md5.c >$(OBJDIR)/md5_.c
   788    808   
   789    809   $(OBJDIR)/md5.o:	$(OBJDIR)/md5_.c $(OBJDIR)/md5.h  $(SRCDIR)/config.h
   790    810   	$(XTCC) -o $(OBJDIR)/md5.o -c $(OBJDIR)/md5_.c
   791    811   
   792    812   $(OBJDIR)/md5.h:	$(OBJDIR)/headers

Changes to src/makemake.tcl.

    69     69     json_timeline
    70     70     json_user
    71     71     json_wiki
    72     72     leaf
    73     73     login
    74     74     main
    75     75     manifest
           76  +  markdown
           77  +  markdown_html
    76     78     md5
    77     79     merge
    78     80     merge3
    79     81     moderate
    80     82     name
    81     83     path
    82     84     pivot
................................................................................
   371    373   #### Enable compiling with debug symbols (much larger binary)
   372    374   #
   373    375   # FOSSIL_ENABLE_SYMBOLS = 1
   374    376   
   375    377   #### Enable JSON (http://www.json.org) support using "cson"
   376    378   #
   377    379   # FOSSIL_ENABLE_JSON = 1
          380  +
          381  +#### Enable markdown support
          382  +#
          383  +# FOSSIL_ENABLE_MARKDOWN = 1
   378    384   
   379    385   #### Enable HTTPS support via OpenSSL (links to libssl and libcrypto)
   380    386   #
   381    387   # FOSSIL_ENABLE_SSL = 1
   382    388   
   383    389   #### Enable scripting support via Tcl/Tk
   384    390   #
................................................................................
   512    518   endif
   513    519   
   514    520   # With JSON support
   515    521   ifdef FOSSIL_ENABLE_JSON
   516    522   TCC += -DFOSSIL_ENABLE_JSON=1
   517    523   RCC += -DFOSSIL_ENABLE_JSON=1
   518    524   endif
          525  +
          526  +# With markdown support
          527  +ifdef FOSSIL_ENABLE_MARKDOWN
          528  +TCC += -DFOSSIL_ENABLE_MARKDOWN=1
          529  +RCC += -DFOSSIL_ENABLE_MARKDOWN=1
          530  +endif
   519    531   
   520    532   #### We add the -static option here so that we can build a static
   521    533   #    executable that will run in a chroot jail.
   522    534   #
   523    535   LIB = -static
   524    536   
   525    537   # MinGW: If available, use the Unicode capable runtime startup code.

Added src/markdown.c.

            1  +/*
            2  +** Copyright (c) 2012 D. Richard Hipp
            3  +**
            4  +** This program is free software; you can redistribute it and/or
            5  +** modify it under the terms of the Simplified BSD License (also
            6  +** known as the "2-Clause License" or "FreeBSD License".)
            7  +
            8  +** This program is distributed in the hope that it will be useful,
            9  +** but without any warranty; without even the implied warranty of
           10  +** merchantability or fitness for a particular purpose.
           11  +**
           12  +** Author contact information:
           13  +**   drh@hwaci.com
           14  +**   http://www.hwaci.com/drh/
           15  +**
           16  +*******************************************************************************
           17  +**
           18  +** This file contains code to parse a blob containing markdown text,
           19  +** using an external renderer.
           20  +*/
           21  +
           22  +#ifdef FOSSIL_ENABLE_MARKDOWN
           23  +
           24  +#include "config.h"
           25  +#include "markdown.h"
           26  +
           27  +#include <assert.h>
           28  +#include <string.h>
           29  +#include <stdlib.h>
           30  +
           31  +#define MKD_LI_END 8  /* internal list flag */
           32  +
           33  +/********************
           34  + * TYPE DEFINITIONS *
           35  + ********************/
           36  +
           37  +#if INTERFACE
           38  +
           39  +/* mkd_autolink -- type of autolink */
           40  +enum mkd_autolink {
           41  +  MKDA_NOT_AUTOLINK,    /* used internally when it is not an autolink*/
           42  +  MKDA_NORMAL,          /* normal http/http/ftp/etc link */
           43  +  MKDA_EXPLICIT_EMAIL,  /* e-mail link with explit mailto: */
           44  +  MKDA_IMPLICIT_EMAIL   /* e-mail link without mailto: */
           45  +};
           46  +
           47  +/* mkd_renderer -- functions for rendering parsed data */
           48  +struct mkd_renderer {
           49  +  /* document level callbacks */
           50  +  void (*prolog)(struct Blob *ob, void *opaque);
           51  +  void (*epilog)(struct Blob *ob, void *opaque);
           52  +
           53  +  /* block level callbacks - NULL skips the block */
           54  +  void (*blockcode)(struct Blob *ob, struct Blob *text, void *opaque);
           55  +  void (*blockquote)(struct Blob *ob, struct Blob *text, void *opaque);
           56  +  void (*blockhtml)(struct Blob *ob, struct Blob *text, void *opaque);
           57  +  void (*header)(struct Blob *ob, struct Blob *text,
           58  +            int level, void *opaque);
           59  +  void (*hrule)(struct Blob *ob, void *opaque);
           60  +  void (*list)(struct Blob *ob, struct Blob *text, int flags, void *opaque);
           61  +  void (*listitem)(struct Blob *ob, struct Blob *text,
           62  +            int flags, void *opaque);
           63  +  void (*paragraph)(struct Blob *ob, struct Blob *text, void *opaque);
           64  +  void (*table)(struct Blob *ob, struct Blob *head_row, struct Blob *rows,
           65  +              void *opaque);
           66  +  void (*table_cell)(struct Blob *ob, struct Blob *text, int flags,
           67  +              void *opaque);
           68  +  void (*table_row)(struct Blob *ob, struct Blob *cells, int flags,
           69  +              void *opaque);
           70  +
           71  +  /* span level callbacks - NULL or return 0 prints the span verbatim */
           72  +  int (*autolink)(struct Blob *ob, struct Blob *link,
           73  +          enum mkd_autolink type, void *opaque);
           74  +  int (*codespan)(struct Blob *ob, struct Blob *text, void *opaque);
           75  +  int (*double_emphasis)(struct Blob *ob, struct Blob *text,
           76  +            char c, void *opaque);
           77  +  int (*emphasis)(struct Blob *ob, struct Blob *text, char c,void*opaque);
           78  +  int (*image)(struct Blob *ob, struct Blob *link, struct Blob *title,
           79  +            struct Blob *alt, void *opaque);
           80  +  int (*linebreak)(struct Blob *ob, void *opaque);
           81  +  int (*link)(struct Blob *ob, struct Blob *link, struct Blob *title,
           82  +          struct Blob *content, void *opaque);
           83  +  int (*raw_html_tag)(struct Blob *ob, struct Blob *tag, void *opaque);
           84  +  int (*triple_emphasis)(struct Blob *ob, struct Blob *text,
           85  +            char c, void *opaque);
           86  +
           87  +  /* low level callbacks - NULL copies input directly into the output */
           88  +  void (*entity)(struct Blob *ob, struct Blob *entity, void *opaque);
           89  +  void (*normal_text)(struct Blob *ob, struct Blob *text, void *opaque);
           90  +
           91  +  /* renderer data */
           92  +  int max_work_stack; /* prevent arbitrary deep recursion, cf README */
           93  +  const char *emph_chars; /* chars that trigger emphasis rendering */
           94  +  void *opaque; /* opaque data send to every rendering callback */
           95  +};
           96  +
           97  +
           98  +
           99  +/*********
          100  + * FLAGS *
          101  + *********/
          102  +
          103  +/* list/listitem flags */
          104  +#define MKD_LIST_ORDERED  1
          105  +#define MKD_LI_BLOCK      2  /* <li> containing block data */
          106  +
          107  +/* table cell flags */
          108  +#define MKD_CELL_ALIGN_DEFAULT  0
          109  +#define MKD_CELL_ALIGN_LEFT     1
          110  +#define MKD_CELL_ALIGN_RIGHT    2
          111  +#define MKD_CELL_ALIGN_CENTER   3  /* LEFT | RIGHT */
          112  +#define MKD_CELL_ALIGN_MASK     3
          113  +#define MKD_CELL_HEAD           4
          114  +
          115  +
          116  +
          117  +/**********************
          118  + * EXPORTED FUNCTIONS *
          119  + **********************/
          120  +
          121  +/* markdown -- parses the input buffer and renders it into the output buffer */
          122  +void markdown(
          123  +  struct Blob *ob,
          124  +  struct Blob *ib,
          125  +  const struct mkd_renderer *rndr);
          126  +
          127  +
          128  +#endif /* INTERFACE */
          129  +
          130  +
          131  +/***************
          132  + * LOCAL TYPES *
          133  + ***************/
          134  +
          135  +/* link_ref -- reference to a link */
          136  +struct link_ref {
          137  +  struct Blob id;
          138  +  struct Blob link;
          139  +  struct Blob title;
          140  +};
          141  +
          142  +
          143  +/* char_trigger -- function pointer to render active chars */
          144  +/*   returns the number of chars taken care of */
          145  +/*   data is the pointer of the beginning of the span */
          146  +/*   offset is the number of valid chars before data */
          147  +struct render;
          148  +typedef size_t (*char_trigger)(
          149  +  struct Blob *ob,
          150  +  struct render *rndr,
          151  +  char *data,
          152  +  size_t offset,
          153  +  size_t size);
          154  +
          155  +
          156  +/* render -- structure containing one particular render */
          157  +struct render {
          158  +  struct mkd_renderer make;
          159  +  struct Blob refs;
          160  +  char_trigger active_char[256];
          161  +  int work_active;
          162  +  struct Blob *work;
          163  +};
          164  +
          165  +
          166  +/* html_tag -- structure for quick HTML tag search (inspired from discount) */
          167  +struct html_tag {
          168  +  char *text;
          169  +  int size;
          170  +};
          171  +
          172  +
          173  +
          174  +/********************
          175  + * GLOBAL VARIABLES *
          176  + ********************/
          177  +
          178  +/* block_tags -- recognised block tags, sorted by cmp_html_tag */
          179  +static struct html_tag block_tags[] = {
          180  +  { "p",            1 },
          181  +  { "dl",           2 },
          182  +  { "h1",           2 },
          183  +  { "h2",           2 },
          184  +  { "h3",           2 },
          185  +  { "h4",           2 },
          186  +  { "h5",           2 },
          187  +  { "h6",           2 },
          188  +  { "ol",           2 },
          189  +  { "ul",           2 },
          190  +  { "del",          3 },
          191  +  { "div",          3 },
          192  +  { "ins",          3 },
          193  +  { "pre",          3 },
          194  +  { "form",         4 },
          195  +  { "math",         4 },
          196  +  { "table",        5 },
          197  +  { "iframe",       6 },
          198  +  { "script",       6 },
          199  +  { "fieldset",     8 },
          200  +  { "noscript",     8 },
          201  +  { "blockquote",  10 }
          202  +};
          203  +
          204  +#define INS_TAG (block_tags + 12)
          205  +#define DEL_TAG (block_tags + 10)
          206  +
          207  +
          208  +
          209  +/***************************
          210  + * STATIC HELPER FUNCTIONS *
          211  + ***************************/
          212  +
          213  +/* build_ref_id -- collapse whitespace from input text to make it a ref id */
          214  +static int build_ref_id(struct Blob *id, const char *data, size_t size){
          215  +  size_t beg, i;
          216  +  char *id_data;
          217  +
          218  +  /* skip leading whitespace */
          219  +  while( size>0 && (data[0]==' ' || data[0]=='\t' || data[0]=='\n') ){
          220  +    data++;
          221  +    size--;
          222  +  }
          223  +
          224  +  /* skip trailing whitespace */
          225  +  while( size>0 && (data[size-1]==' '
          226  +   || data[size-1]=='\t'
          227  +   || data[size-1]=='\n')
          228  +  ){
          229  +    size--;
          230  +  }
          231  +  if( size==0 ) return -1;
          232  +
          233  +  /* making the ref id */
          234  +  i = 0;
          235  +  blob_reset(id);
          236  +  while( i<size ){
          237  +    /* copy non-whitespace into the output buffer */
          238  +    beg = i;
          239  +    while( i<size && !(data[i]==' ' || data[i]=='\t' || data[i]=='\n') ){
          240  +      i++;
          241  +    }
          242  +    blob_append(id, data+beg, i-beg);
          243  +
          244  +    /* add a single space and skip all consecutive whitespace */
          245  +    if( i<size ) blob_append(id, " ", 1);
          246  +    while( i<size && (data[i]==' ' || data[i]=='\t' || data[i]=='\n') ){ i++; }
          247  +  }
          248  +
          249  +  /* turn upper-case ASCII into their lower-case counterparts */
          250  +  id_data = blob_buffer(id);
          251  +  for(i=0; i<blob_size(id); i++){
          252  +    if( id_data[i]>='A' && id_data[i]<='Z' ) id_data[i] += 'a' - 'A';
          253  +  }
          254  +  return 0;
          255  +}
          256  +
          257  +
          258  +/* cmp_link_ref -- comparison function for link_ref sorted arrays */
          259  +static int cmp_link_ref(const void *key, const void *array_entry){
          260  +  struct link_ref *lr = (void *)array_entry;
          261  +  return blob_compare((void *)key, &lr->id);
          262  +}
          263  +
          264  +
          265  +/* cmp_link_ref_sort -- comparison function for link_ref qsort */
          266  +static int cmp_link_ref_sort(const void *a, const void *b){
          267  +  struct link_ref *lra = (void *)a;
          268  +  struct link_ref *lrb = (void *)b;
          269  +  return blob_compare(&lra->id, &lrb->id);
          270  +}
          271  +
          272  +
          273  +/* cmp_html_tag -- comparison function for bsearch() (stolen from discount) */
          274  +static int cmp_html_tag(const void *a, const void *b){
          275  +  const struct html_tag *hta = a;
          276  +  const struct html_tag *htb = b;
          277  +  if( hta->size!=htb->size ) return hta->size-htb->size;
          278  +  return strncasecmp(hta->text, htb->text, hta->size);
          279  +}
          280  +
          281  +
          282  +/* find_block_tag -- returns the current block tag */
          283  +static struct html_tag *find_block_tag(char *data, size_t size){
          284  +  size_t i = 0;
          285  +  struct html_tag key;
          286  +
          287  +  /* looking for the word end */
          288  +  while( i<size
          289  +   && ((data[i]>='0' && data[i]<='9')
          290  +       || (data[i]>='A' && data[i]<='Z')
          291  +       || (data[i]>='a' && data[i]<='z'))
          292  +  ){
          293  +    i++;
          294  +  }
          295  +  if( i>=size ) return 0;
          296  +
          297  +  /* binary search of the tag */
          298  +  key.text = data;
          299  +  key.size = i;
          300  +  return bsearch(&key,
          301  +                 block_tags,
          302  +                 (sizeof block_tags)/(sizeof block_tags[0]),
          303  +                 sizeof block_tags[0],
          304  +                 cmp_html_tag);
          305  +}
          306  +
          307  +
          308  +/* new_work_buffer -- get a new working buffer from the stack or create one */
          309  +static struct Blob *new_work_buffer(struct render *rndr){
          310  +  struct Blob *ret = 0;
          311  +
          312  +  if( rndr->work_active < rndr->make.max_work_stack ){
          313  +    ret = rndr->work + rndr->work_active;
          314  +    rndr->work_active += 1;
          315  +    blob_reset(ret);
          316  +  }
          317  +  return ret;
          318  +}
          319  +
          320  +
          321  +/* release_work_buffer -- release the given working buffer */
          322  +static void release_work_buffer(struct render *rndr, struct Blob *buf){
          323  +  if( !buf ) return;
          324  +  assert(rndr->work_active>0 && buf==(rndr->work+rndr->work_active-1));
          325  +  rndr->work_active -= 1;
          326  +}
          327  +
          328  +
          329  +
          330  +/****************************
          331  + * INLINE PARSING FUNCTIONS *
          332  + ****************************/
          333  +
          334  +/* is_mail_autolink -- looks for the address part of a mail autolink and '>' */
          335  +/* this is less strict than the original markdown e-mail address matching */
          336  +static size_t is_mail_autolink(char *data, size_t size){
          337  +  size_t i = 0, nb = 0;
          338  +  /* address is assumed to be: [-@._a-zA-Z0-9]+ with exactly one '@' */
          339  +  while( i<size && (data[i]=='-'
          340  +   || data[i]=='.'
          341  +   || data[i]=='_'
          342  +   || data[i]=='@'
          343  +   || (data[i]>='a' && data[i]<='z')
          344  +   || (data[i]>='A' && data[i]<='Z')
          345  +   || (data[i]>='0' && data[i]<='9'))
          346  +  ){
          347  +    if( data[i]=='@' ) nb++;
          348  +    i++;
          349  +  }
          350  +  if( i>=size || data[i]!='>' || nb!=1 ) return 0;
          351  +  return i+1;
          352  +}
          353  +
          354  +
          355  +/* tag_length -- returns the length of the given tag, or 0 is it's not valid */
          356  +static size_t tag_length(char *data, size_t size, enum mkd_autolink *autolink){
          357  +  size_t i, j;
          358  +
          359  +  /* a valid tag can't be shorter than 3 chars */
          360  +  if( size<3 ) return 0;
          361  +
          362  +  /* begins with a '<' optionally followed by '/', followed by letter */
          363  +  if( data[0]!='<' ) return 0;
          364  +  i = (data[1]=='/') ? 2 : 1;
          365  +  if( (data[i]<'a' || data[i]>'z') &&  (data[i]<'A' || data[i]>'Z') ){
          366  +    return 0;
          367  +  }
          368  +
          369  +  /* scheme test */
          370  +  *autolink = MKDA_NOT_AUTOLINK;
          371  +  if( size>6
          372  +   && strncasecmp(data+1, "http", 4)==0
          373  +   && (data[5]==':'
          374  +       || ((data[5]=='s' || data[5]=='S') && data[6]==':'))
          375  +  ){
          376  +    i = (data[5]==':') ? 6 : 7;
          377  +    *autolink = MKDA_NORMAL;
          378  +  }else if( size>5 && strncasecmp(data+1, "ftp:", 4)==0 ){
          379  +    i = 5;
          380  +    *autolink = MKDA_NORMAL;
          381  +  }else if( size>7 && strncasecmp(data+1, "mailto:", 7)==0 ){
          382  +    i = 8;
          383  +    /* not changing *autolink to go to the address test */
          384  +   }
          385  +
          386  +  /* completing autolink test: no whitespace or ' or " */
          387  +  if( i>=size || i=='>' ){
          388  +    *autolink = MKDA_NOT_AUTOLINK;
          389  +  }else if( *autolink ){
          390  +    j = i;
          391  +    while( i<size
          392  +     && data[i]!='>'
          393  +     && data[i]!='\''
          394  +     && data[i]!='"'
          395  +     && data[i]!=' '
          396  +     && data[i]!='\t'
          397  +     && data[i]!='\t'
          398  +    ){
          399  +      i++;
          400  +    }
          401  +    if( i>=size ) return 0;
          402  +    if( i>j && data[i]=='>' ) return i+1;
          403  +    /* one of the forbidden chars has been found */
          404  +    *autolink = MKDA_NOT_AUTOLINK;
          405  +  }else if( (j = is_mail_autolink(data+i, size-i))!=0 ){
          406  +    *autolink = (i==8) ? MKDA_EXPLICIT_EMAIL : MKDA_IMPLICIT_EMAIL;
          407  +    return i+j;
          408  +  }
          409  +
          410  +  /* looking for sometinhg looking like a tag end */
          411  +  while( i<size && data[i]!='>' ){ i++; }
          412  +  if( i>=size ) return 0;
          413  +  return i+1;
          414  +}
          415  +
          416  +
          417  +/* parse_inline -- parses inline markdown elements */
          418  +static void parse_inline(
          419  +  struct Blob *ob,
          420  +  struct render *rndr,
          421  +  char *data,
          422  +  size_t size
          423  +){
          424  +  size_t i = 0, end = 0;
          425  +  char_trigger action = 0;
          426  +  struct Blob work = BLOB_INITIALIZER;
          427  +
          428  +  while( i<size ){
          429  +    /* copying inactive chars into the output */
          430  +    while( end<size
          431  +     && (action = rndr->active_char[(unsigned char)data[end]])==0
          432  +    ){
          433  +      end++;
          434  +    }
          435  +    if( end>i ){
          436  +      if( rndr->make.normal_text ){
          437  +        blob_init(&work, data+i, end-i);
          438  +        rndr->make.normal_text(ob, &work, rndr->make.opaque);
          439  +      }else{
          440  +        blob_append(ob, data+i, end-i);
          441  +      }
          442  +    }
          443  +    if( end>=size ) break;
          444  +    i = end;
          445  +
          446  +    /* calling the trigger */
          447  +    end = action(ob, rndr, data+i, i, size-i);
          448  +    if( !end ){
          449  +      /* no action from the callback */
          450  +      end = i+1;
          451  +    }else{
          452  +      i += end;
          453  +      end = i;
          454  +    }
          455  +  }
          456  +}
          457  +
          458  +
          459  +/* find_emph_char -- looks for the next emph char, skipping other constructs */
          460  +static size_t find_emph_char(char *data, size_t size, char c){
          461  +  size_t i = 1;
          462  +
          463  +  while( i<size ){
          464  +    while( i<size && data[i]!=c && data[i]!='`' && data[i]!='[' ){ i++; }
          465  +    if( i>=size ) return 0;
          466  +    if( data[i]==c ) return i;
          467  +
          468  +    /* not counting escaped chars */
          469  +    if( i && data[i-1]=='\\' ){
          470  +      i++;
          471  +      continue;
          472  +    }
          473  +
          474  +    /* skipping a code span */
          475  +    if( data[i]=='`' ){
          476  +      size_t span_nb = 0, bt;
          477  +      size_t tmp_i = 0;
          478  +
          479  +      /* counting the number of opening backticks */
          480  +      while( i<size && data[i]=='`' ){
          481  +        i++;
          482  +        span_nb++;
          483  +      }
          484  +      if( i>=size ) return 0;
          485  +
          486  +      /* finding the matching closing sequence */
          487  +      bt = 0;
          488  +      while( i<size && bt<span_nb ){
          489  +        if( !tmp_i && data[i]==c ) tmp_i = i;
          490  +        if( data[i]=='`' ) bt += 1; else bt = 0;
          491  +        i++;
          492  +      }
          493  +      if( i>=size ) return tmp_i;
          494  +      i++;
          495  +
          496  +    /* skipping a link */
          497  +    }else if( data[i]=='[' ){
          498  +      size_t tmp_i = 0;
          499  +      char cc;
          500  +      i++;
          501  +      while( i<size && data[i]!=']' ){
          502  +        if( !tmp_i && data[i]==c ) tmp_i = i;
          503  +        i++;
          504  +      }
          505  +      i++;
          506  +      while( i<size && (data[i]==' ' || data[i]=='\t' || data[i]=='\n') ){
          507  +        i++;
          508  +      }
          509  +      if( i>=size ) return tmp_i;
          510  +      if( data[i]!='[' && data[i]!='(' ){ /* not a link*/
          511  +        if( tmp_i ) return tmp_i; else continue;
          512  +      }
          513  +      cc = data[i];
          514  +      i++;
          515  +      while( i<size && data[i]!=cc ){
          516  +        if( !tmp_i && data[i]==c ) tmp_i = i;
          517  +        i++;
          518  +      }
          519  +      if( i>=size ) return tmp_i;
          520  +      i++;
          521  +    }
          522  +  }
          523  +  return 0;
          524  +}
          525  +
          526  +
          527  +/* parse_emph1 -- parsing single emphase */
          528  +/* closed by a symbol not preceded by whitespace and not followed by symbol */
          529  +static size_t parse_emph1(
          530  +  struct Blob *ob,
          531  +  struct render *rndr,
          532  +  char *data,
          533  +  size_t size,
          534  +  char c
          535  +){
          536  +  size_t i = 0, len;
          537  +  struct Blob *work = 0;
          538  +  int r;
          539  +
          540  +  if( !rndr->make.emphasis ) return 0;
          541  +
          542  +  /* skipping one symbol if coming from emph3 */
          543  +  if( size>1 && data[0]==c && data[1]==c ) i = 1;
          544  +
          545  +  while( i<size ){
          546  +    len = find_emph_char(data+i, size-i, c);
          547  +    if( !len ) return 0;
          548  +    i += len;
          549  +    if( i>=size ) return 0;
          550  +
          551  +    if( i+1<size && data[i+1]==c ){
          552  +      i++;
          553  +      continue;
          554  +    }
          555  +    if( data[i]==c
          556  +     && data[i-1]!=' '
          557  +     && data[i-1]!='\t'
          558  +     && data[i-1]!='\n'
          559  +    ){
          560  +      work = new_work_buffer(rndr);
          561  +      if( !work ) return 0;
          562  +      parse_inline(work, rndr, data, i);
          563  +      r = rndr->make.emphasis(ob, work, c, rndr->make.opaque);
          564  +      release_work_buffer(rndr, work);
          565  +      return r ? i+1 : 0;
          566  +    }
          567  +  }
          568  +  return 0;
          569  +}
          570  +
          571  +
          572  +/* parse_emph2 -- parsing single emphase */
          573  +static size_t parse_emph2(
          574  +  struct Blob *ob,
          575  +  struct render *rndr,
          576  +  char *data,
          577  +  size_t size,
          578  +  char c
          579  +){
          580  +  size_t i = 0, len;
          581  +  struct Blob *work = 0;
          582  +  int r;
          583  +
          584  +  if( !rndr->make.double_emphasis ) return 0;
          585  +
          586  +  while( i<size ){
          587  +    len = find_emph_char(data+i, size-i, c);
          588  +    if( !len ) return 0;
          589  +    i += len;
          590  +    if( i+1<size
          591  +     && data[i]==c
          592  +     && data[i+1]==c
          593  +     && i
          594  +     && data[i-1]!=' '
          595  +     && data[i-1]!='\t'
          596  +     && data[i-1]!='\n'
          597  +    ){
          598  +      work = new_work_buffer(rndr);
          599  +      if( !work ) return 0;
          600  +      parse_inline(work, rndr, data, i);
          601  +      r = rndr->make.double_emphasis(ob, work, c, rndr->make.opaque);
          602  +      release_work_buffer(rndr, work);
          603  +      return r ? i+2 : 0;
          604  +    }
          605  +    i++;
          606  +  }
          607  +  return 0;
          608  +}
          609  +
          610  +
          611  +/* parse_emph3 -- parsing single emphase */
          612  +/* finds the first closing tag, and delegates to the other emph */
          613  +static size_t parse_emph3(
          614  +  struct Blob *ob,
          615  +  struct render *rndr,
          616  +  char *data,
          617  +  size_t size,
          618  +  char c
          619  +){
          620  +  size_t i = 0, len;
          621  +  int r;
          622  +
          623  +  while( i<size ){
          624  +    len = find_emph_char(data+i, size-i, c);
          625  +    if( !len ) return 0;
          626  +    i += len;
          627  +
          628  +    /* skip whitespace preceded symbols */
          629  +    if( data[i]!=c || data[i-1]==' ' || data[i-1]=='\t' || data[i-1]=='\n' ){
          630  +      continue;
          631  +    }
          632  +
          633  +    if( i+2<size
          634  +     && data[i+1]==c
          635  +     && data[i+2] == c
          636  +     && rndr->make.triple_emphasis
          637  +    ){
          638  +      /* triple symbol found */
          639  +      struct Blob *work = new_work_buffer(rndr);
          640  +      if( !work ) return 0;
          641  +      parse_inline(work, rndr, data, i);
          642  +      r = rndr->make.triple_emphasis(ob, work, c, rndr->make.opaque);
          643  +      release_work_buffer(rndr, work);
          644  +      return r ? i+3 : 0;
          645  +    }else if( i+1<size && data[i+1]==c ){
          646  +      /* double symbol found, handing over to emph1 */
          647  +      len = parse_emph1(ob, rndr, data-2, size+2, c);
          648  +      return len ? len-2 : 0;
          649  +    }else{
          650  +      /* single symbol found, handing over to emph2 */
          651  +      len = parse_emph2(ob, rndr, data-1, size+1, c);
          652  +      return len ? len-1 : 0;
          653  +    }
          654  +  }
          655  +  return 0;
          656  +}
          657  +
          658  +
          659  +/* char_emphasis -- single and double emphasis parsing */
          660  +static size_t char_emphasis(
          661  +  struct Blob *ob,
          662  +  struct render *rndr,
          663  +  char *data,
          664  +  size_t offset,
          665  +  size_t size
          666  +){
          667  +  char c = data[0];
          668  +  size_t ret;
          669  +
          670  +  if( size>2 && data[1]!=c ){
          671  +    /* whitespace cannot follow an opening emphasis */
          672  +    if( data[1]==' '
          673  +     || data[1]=='\t'
          674  +     || data[1]=='\n'
          675  +     || (ret = parse_emph1(ob, rndr, data+1, size-1, c))==0
          676  +    ){
          677  +      return 0;
          678  +    }
          679  +    return ret+1;
          680  +  }
          681  +
          682  +  if( size>3 && data[1]==c && data[2]!=c ){
          683  +    if( data[2]==' '
          684  +     || data[2]=='\t'
          685  +     || data[2]=='\n'
          686  +     || (ret = parse_emph2(ob, rndr, data+2, size-2, c))==0
          687  +    ){
          688  +      return 0;
          689  +    }
          690  +    return ret+2;
          691  +  }
          692  +
          693  +  if( size>4 && data[1]==c && data[2]==c && data[3]!=c ){
          694  +    if( data[3]==' '
          695  +     || data[3]=='\t'
          696  +     || data[3]=='\n'
          697  +     || (ret = parse_emph3(ob, rndr, data+3, size-3, c))==0
          698  +    ){
          699  +      return 0;
          700  +    }
          701  +    return ret+3;
          702  +  }
          703  +  return 0;
          704  +}
          705  +
          706  +
          707  +/* char_linebreak -- '\n' preceded by two spaces (assuming linebreak != 0) */
          708  +static size_t char_linebreak(
          709  +  struct Blob *ob,
          710  +  struct render *rndr,
          711  +  char *data,
          712  +  size_t offset,
          713  +  size_t size
          714  +){
          715  +  if( offset<2 || data[-1]!=' ' || data[-2]!=' ' ) return 0;
          716  +  /* removing the last space from ob and rendering */
          717  +  if( blob_size(ob)>0 && blob_buffer(ob)[blob_size(ob)-1]==' ' ) ob->nUsed--;
          718  +  return rndr->make.linebreak(ob, rndr->make.opaque) ? 1 : 0;
          719  +}
          720  +
          721  +
          722  +/* char_codespan -- '`' parsing a code span (assuming codespan != 0) */
          723  +static size_t char_codespan(
          724  +  struct Blob *ob,
          725  +  struct render *rndr,
          726  +  char *data,
          727  +  size_t offset,
          728  +  size_t size
          729  +){
          730  +  size_t end, nb = 0, i, f_begin, f_end;
          731  +
          732  +  /* counting the number of backticks in the delimiter */
          733  +  while( nb<size && data[nb]=='`' ){ nb++; }
          734  +
          735  +  /* finding the next delimiter */
          736  +  i = 0;
          737  +  for(end=nb; end<size && i<nb; end++){
          738  +    if( data[end]=='`' ) i++; else i = 0;
          739  +  }
          740  +  if( i<nb && end>=size ) return 0; /* no matching delimiter */
          741  +
          742  +  /* trimming outside whitespaces */
          743  +  f_begin = nb;
          744  +  while( f_begin<end && (data[f_begin]==' ' || data[f_begin]=='\t') ){
          745  +    f_begin++;
          746  +  }
          747  +  f_end = end-nb;
          748  +  while( f_end>nb && (data[f_end-1]==' ' || data[f_end-1]=='\t') ){ f_end--; }
          749  +
          750  +  /* real code span */
          751  +  if( f_begin<f_end ){
          752  +    struct Blob work = BLOB_INITIALIZER;
          753  +    blob_init(&work, data+f_begin, f_end-f_begin);
          754  +    if( !rndr->make.codespan(ob, &work, rndr->make.opaque) ) end = 0;
          755  +  }else{
          756  +    if( !rndr->make.codespan(ob, 0, rndr->make.opaque) ) end = 0;
          757  +  }
          758  +  return end;
          759  +}
          760  +
          761  +
          762  +/* char_escape -- '\\' backslash escape */
          763  +static size_t char_escape(
          764  +  struct Blob *ob,
          765  +  struct render *rndr,
          766  +  char *data,
          767  +  size_t offset,
          768  +  size_t size
          769  +){
          770  +  struct Blob work = BLOB_INITIALIZER;
          771  +  if( size>1 ){
          772  +    if( rndr->make.normal_text ){
          773  +      blob_init(&work, data+1,1);
          774  +      rndr->make.normal_text(ob, &work, rndr->make.opaque);
          775  +    }else{
          776  +      blob_append(ob, data+1, 1);
          777  +    }
          778  +  }
          779  +  return 2;
          780  +}
          781  +
          782  +
          783  +/* char_entity -- '&' escaped when it doesn't belong to an entity */
          784  +/* valid entities are assumed to be anything mathing &#?[A-Za-z0-9]+; */
          785  +static size_t char_entity(
          786  +  struct Blob *ob,
          787  +  struct render *rndr,
          788  +  char *data,
          789  +  size_t offset,
          790  +  size_t size
          791  +){
          792  +  size_t end = 1;
          793  +  struct Blob work = BLOB_INITIALIZER;
          794  +  if( end<size && data[end]=='#' ) end++;
          795  +  while( end<size
          796  +   && ((data[end]>='0' && data[end]<='9')
          797  +       || (data[end]>='a' && data[end]<='z')
          798  +       || (data[end]>='A' && data[end]<='Z'))
          799  +  ){
          800  +    end++;
          801  +  }
          802  +  if( end<size && data[end]==';' ){
          803  +    /* real entity */
          804  +    end++;
          805  +  }else{
          806  +    /* lone '&' */
          807  +    return 0;
          808  +  }
          809  +  if( rndr->make.entity ){
          810  +    blob_init(&work, data, end);
          811  +    rndr->make.entity(ob, &work, rndr->make.opaque);
          812  +  }else{
          813  +    blob_append(ob, data, end);
          814  +  }
          815  +  return end;
          816  +}
          817  +
          818  +
          819  +/* char_langle_tag -- '<' when tags or autolinks are allowed */
          820  +static size_t char_langle_tag(
          821  +  struct Blob *ob,
          822  +  struct render *rndr,
          823  +  char *data,
          824  +  size_t offset,
          825  +  size_t size
          826  +){
          827  +  enum mkd_autolink altype = MKDA_NOT_AUTOLINK;
          828  +  size_t end = tag_length(data, size, &altype);
          829  +  struct Blob work = BLOB_INITIALIZER;
          830  +  int ret = 0;
          831  +  if( end ){
          832  +    if( rndr->make.autolink && altype!=MKDA_NOT_AUTOLINK ){
          833  +      blob_init(&work, data+1, end-2);
          834  +      ret = rndr->make.autolink(ob, &work, altype, rndr->make.opaque);
          835  +    }else if( rndr->make.raw_html_tag ){
          836  +      blob_init(&work, data, end);
          837  +      ret = rndr->make.raw_html_tag(ob, &work, rndr->make.opaque);
          838  +    }
          839  +  }
          840  +
          841  +  if( !ret ){
          842  +    return 0;
          843  +  }else{
          844  +    return end;
          845  +  }
          846  +}
          847  +
          848  +
          849  +/* get_link_inline -- extract inline-style link and title from parenthesed data*/
          850  +static int get_link_inline(
          851  +  struct Blob *link,
          852  +  struct Blob *title,
          853  +  char *data,
          854  +  size_t size
          855  +){
          856  +  size_t i = 0, mark;
          857  +  size_t link_b, link_e;
          858  +  size_t title_b = 0, title_e = 0;
          859  +
          860  +  /* skipping initial whitespace */
          861  +  while( i<size && (data[i]==' ' || data[i]=='\t' || data[i]=='\n') ){ i++; }
          862  +  link_b = i;
          863  +
          864  +  /* looking for link end: ' " */
          865  +  while( i<size && data[i]!='\'' && data[i]!='"' ){ i++; }
          866  +  link_e = i;
          867  +
          868  +  /* looking for title end if present */
          869  +  if( data[i]=='\'' || data[i]=='"' ){
          870  +    i++;
          871  +    title_b = i;
          872  +
          873  +    /* skipping whitespaces after title */
          874  +    title_e = size-1;
          875  +    while( title_e>title_b
          876  +     && (data[title_e]==' '
          877  +         || data[title_e]=='\t'
          878  +         || data[title_e]=='\n')
          879  +    ){
          880  +      title_e--;
          881  +    }
          882  +
          883  +    /* checking for closing quote presence */
          884  +    if (data[title_e] != '\'' &&  data[title_e] != '"') {
          885  +      title_b = title_e = 0;
          886  +      link_e = i;
          887  +    }
          888  +  }
          889  +
          890  +  /* remove whitespace at the end of the link */
          891  +  while( link_e>link_b
          892  +   && (data[link_e-1]==' '
          893  +       || data[link_e-1]=='\t'
          894  +       || data[link_e-1]=='\n')
          895  +  ){
          896  +    link_e--;
          897  +  }
          898  +
          899  +  /* remove optional angle brackets around the link */
          900  +  if( data[link_b]=='<' ) link_b += 1;
          901  +  if( data[link_e-1]=='>' ) link_e -= 1;
          902  +
          903  +  /* escape backslashed character from link */
          904  +  blob_reset(link);
          905  +  i = link_b;
          906  +  while( i<link_e ){
          907  +    mark = i;
          908  +    while( i<link_e && data[i]!='\\' ){ i++; }
          909  +    blob_append(link, data+mark, i-mark);
          910  +    while( i<link_e && data[i]=='\\' ){ i++; }
          911  +  }
          912  +
          913  +  /* handing back title */
          914  +  blob_reset(title);
          915  +  if( title_e>title_b ) blob_append(title, data+title_b, title_e-title_b);
          916  +
          917  +  /* this function always succeed */
          918  +  return 0;
          919  +}
          920  +
          921  +
          922  +/* get_link_ref -- extract referenced link and title from id */
          923  +static int get_link_ref(
          924  +  struct render *rndr,
          925  +  struct Blob *link,
          926  +  struct Blob *title,
          927  +  char *data,
          928  +  size_t size
          929  +){
          930  +  struct link_ref *lr;
          931  +
          932  +  /* find the link from its id (stored temporarily in link) */
          933  +  blob_reset(link);
          934  +  if( build_ref_id(link, data, size)<0 ) return -1;
          935  +  lr = bsearch(link,
          936  +               blob_buffer(&rndr->refs),
          937  +               blob_size(&rndr->refs)/sizeof(struct link_ref),
          938  +               sizeof (struct link_ref),
          939  +               cmp_link_ref);
          940  +  if( !lr ) return -1;
          941  +
          942  +  /* fill the output buffers */
          943  +  blob_reset(link);
          944  +  blob_reset(title);
          945  +  blob_append(link, blob_buffer(&lr->link), blob_size(&lr->link));
          946  +  blob_append(title, blob_buffer(&lr->title), blob_size(&lr->title));
          947  +  return 0;
          948  +}
          949  +
          950  +
          951  +/* char_link -- '[': parsing a link or an image */
          952  +static size_t char_link(
          953  +  struct Blob *ob,
          954  +  struct render *rndr,
          955  +  char *data,
          956  +  size_t offset,
          957  +  size_t size
          958  +){
          959  +  int is_img = (offset && data[-1] == '!'), level;
          960  +  size_t i = 1, txt_e;
          961  +  struct Blob *content = 0;
          962  +  struct Blob *link = 0;
          963  +  struct Blob *title = 0;
          964  +  int text_has_nl = 0, ret;
          965  +
          966  +  /* checking whether the correct renderer exists */
          967  +  if( (is_img && !rndr->make.image) || (!is_img && !rndr->make.link) ){
          968  +    return 0;
          969  +  }
          970  +
          971  +  /* looking for the matching closing bracket */
          972  +  for(level=1; i<size; i++){
          973  +    if( data[i]=='\n' )        text_has_nl = 1;
          974  +    else if( data[i-1]=='\\' ) continue;
          975  +    else if( data[i]=='[' )    level += 1;
          976  +    else if( data[i]==']' ){
          977  +      level--;
          978  +      if( level<=0 ) break;
          979  +    }
          980  +  }
          981  +  if( i>=size ) return 0;
          982  +  txt_e = i;
          983  +  i++;
          984  +
          985  +  /* skip any amount of whitespace or newline */
          986  +  /* (this is much more laxist than original markdown syntax) */
          987  +  while( i<size && (data[i]==' ' || data[i]=='\t' || data[i]=='\n') ){ i++; }
          988  +
          989  +  /* allocate temporary buffers to store content, link and title */
          990  +  content = new_work_buffer(rndr);
          991  +  link = new_work_buffer(rndr);
          992  +  title = new_work_buffer(rndr);
          993  +  if( !title ) return 0;
          994  +  ret = 0; /* error if we don't get to the callback */
          995  +
          996  +  /* inline style link */
          997  +  if( i<size && data[i]=='(' ){
          998  +    size_t span_end = i;
          999  +    while( span_end<size
         1000  +     && !(data[span_end]==')' && (span_end==i || data[span_end-1]!='\\'))
         1001  +    ){
         1002  +      span_end++;
         1003  +    }
         1004  +
         1005  +    if( span_end>=size
         1006  +     || get_link_inline(link, title, data+i+1, span_end-(i+1))<0
         1007  +    ){
         1008  +      goto char_link_cleanup;
         1009  +    }
         1010  +
         1011  +    i = span_end+1;
         1012  +
         1013  +  /* reference style link */
         1014  +  }else if( i<size && data[i]=='[' ){
         1015  +    char *id_data;
         1016  +    size_t id_size, id_end = i;
         1017  +
         1018  +    while( id_end<size && data[id_end]!=']' ){ id_end++; }
         1019  +
         1020  +    if( id_end>=size ) goto char_link_cleanup;
         1021  +
         1022  +    if( i+1==id_end ){
         1023  +      /* implicit id - use the contents */
         1024  +      id_data = data+1;
         1025  +      id_size = txt_e-1;
         1026  +    }else{
         1027  +      /* explici id - between brackets */
         1028  +      id_data = data+i+1;
         1029  +      id_size = id_end-(i+1);
         1030  +    }
         1031  +
         1032  +    if( get_link_ref(rndr, link, title, id_data, id_size)<0 ){
         1033  +      goto char_link_cleanup;
         1034  +    }
         1035  +
         1036  +    i = id_end+1;
         1037  +
         1038  +  /* shortcut reference style link */
         1039  +  }else{
         1040  +    if( get_link_ref(rndr, link, title, data+1, txt_e-1)<0 ){
         1041  +      goto char_link_cleanup;
         1042  +    }
         1043  +
         1044  +    /* rewinding the whitespace */
         1045  +    i = txt_e+1;
         1046  +  }
         1047  +
         1048  +  /* building content: img alt is escaped, link content is parsed */
         1049  +  if( txt_e>1 ){
         1050  +    if( is_img ) blob_append(content, data+1, txt_e-1);
         1051  +    else parse_inline(content, rndr, data+1, txt_e-1);
         1052  +  }
         1053  +
         1054  +  /* calling the relevant rendering function */
         1055  +  if( is_img ){
         1056  +    if( blob_size(ob)>0 && blob_buffer(ob)[blob_size(ob)-1]=='!' ) ob->nUsed--;
         1057  +    ret = rndr->make.image(ob, link, title, content, rndr->make.opaque);
         1058  +  }else{
         1059  +    ret = rndr->make.link(ob, link, title, content, rndr->make.opaque);
         1060  +  }
         1061  +
         1062  +  /* cleanup */
         1063  +char_link_cleanup:
         1064  +  release_work_buffer(rndr, title);
         1065  +  release_work_buffer(rndr, link);
         1066  +  release_work_buffer(rndr, content);
         1067  +  return ret ? i : 0;
         1068  +}
         1069  +
         1070  +
         1071  +
         1072  +/*********************************
         1073  + * BLOCK-LEVEL PARSING FUNCTIONS *
         1074  + *********************************/
         1075  +
         1076  +/* is_empty -- returns the line length when it is empty, 0 otherwise */
         1077  +static size_t is_empty(char *data, size_t size){
         1078  +  size_t i;
         1079  +  for(i=0; i<size && data[i]!='\n'; i++){
         1080  +    if( data[i]!=' ' && data[i]!='\t' ) return 0;
         1081  +  }
         1082  +  return i+1;
         1083  +}
         1084  +
         1085  +
         1086  +/* is_hrule -- returns whether a line is a horizontal rule */
         1087  +static int is_hrule(char *data, size_t size){
         1088  +  size_t i = 0, n = 0;
         1089  +  char c;
         1090  +
         1091  +  /* skipping initial spaces */
         1092  +  if( size<3 ) return 0;
         1093  +  if( data[0]==' ' ){
         1094  +    i++;
         1095  +    if( data[1]==' ' ){
         1096  +      i++;
         1097  +       if( data[2]==' ' ){
         1098  +         i++;
         1099  +       }
         1100  +     }
         1101  +   }
         1102  +
         1103  +  /* looking at the hrule char */
         1104  +  if( i+2>=size || (data[i]!='*' && data[i]!='-' && data[i]!='_') ) return 0;
         1105  +  c = data[i];
         1106  +
         1107  +  /* the whole line must be the char or whitespace */
         1108  +  while (i < size && data[i] != '\n') {
         1109  +    if( data[i]==c ){
         1110  +      n += 1;
         1111  +    }else if( data[i]!=' ' && data[i]!='\t' ){
         1112  +      return 0;
         1113  +    }
         1114  +    i++;
         1115  +  }
         1116  +
         1117  +  return n>=3;
         1118  +}
         1119  +
         1120  +
         1121  +/* is_headerline -- returns whether the line is a setext-style hdr underline */
         1122  +static int is_headerline(char *data, size_t size){
         1123  +  size_t i = 0;
         1124  +
         1125  +  /* test of level 1 header */
         1126  +  if( data[i]=='=' ){
         1127  +    for(i=1; i<size && data[i]=='='; i++);
         1128  +    while( i<size && (data[i]==' ' || data[i]=='\t') ){ i++; }
         1129  +    return (i>=size || data[i]=='\n') ? 1 : 0;
         1130  +  }
         1131  +
         1132  +  /* test of level 2 header */
         1133  +  if( data[i]=='-' ){
         1134  +    for(i=1; i<size && data[i]=='-'; i++);
         1135  +    while( i<size && (data[i]==' ' || data[i]=='\t') ){ i++; }
         1136  +    return (i>=size || data[i]=='\n') ? 2 : 0;
         1137  +  }
         1138  +
         1139  +  return 0;
         1140  +}
         1141  +
         1142  +
         1143  +/* is_table_sep -- returns wether there is a table separator at the given pos */
         1144  +static int is_table_sep(char *data, size_t pos){
         1145  +  return data[pos]=='|' && (pos==0 || data[pos-1]!='\\');
         1146  +}
         1147  +
         1148  +
         1149  +/* is_tableline -- returns the number of column tables in the given line */
         1150  +static int is_tableline(char *data, size_t size){
         1151  +  size_t i = 0;
         1152  +  int n_sep = 0, outer_sep = 0;
         1153  +
         1154  +  /* skip initial blanks */
         1155  +  while( i<size && (data[i]==' ' || data[i]=='\t') ){ i++; }
         1156  +
         1157  +  /* check for initial '|' */
         1158  +  if( i<size && data[i]=='|') outer_sep++;
         1159  +
         1160  +  /* count the number of pipes in the line */
         1161  +  for(n_sep=0; i<size && data[i]!='\n'; i++){
         1162  +    if( is_table_sep(data, i) ) n_sep++;
         1163  +  }
         1164  +
         1165  +  /* march back to check for optional last '|' before blanks and EOL */
         1166  +  while( i && (data[i-1]==' ' || data[i-1]=='\t' || data[i-1]=='\n') ){ i--; }
         1167  +  if( i && is_table_sep(data, i-1) ) outer_sep += 1;
         1168  +
         1169  +  /* return the number of column or 0 if it's not a table line */
         1170  +  return (n_sep>0) ? (n_sep-outer_sep+1) : 0;
         1171  +}
         1172  +
         1173  +
         1174  +/* prefix_quote -- returns blockquote prefix length */
         1175  +static size_t prefix_quote(char *data, size_t size){
         1176  +  size_t i = 0;
         1177  +  if( i<size && data[i]==' ' ) i++;
         1178  +  if( i<size && data[i]==' ' ) i++;
         1179  +  if( i<size && data[i]==' ' ) i++;
         1180  +  if( i<size && data[i]=='>' ){
         1181  +    if( i+1<size && (data[i+1]==' ' || data[i+1]=='\t') ){
         1182  +      return i + 2;
         1183  +    }else{
         1184  +      return i + 1;
         1185  +    }
         1186  +  }else{
         1187  +    return 0;
         1188  +  }
         1189  +}
         1190  +
         1191  +
         1192  +/* prefix_code -- returns prefix length for block code*/
         1193  +static size_t prefix_code(char *data, size_t size){
         1194  +  if( size>0 && data[0]=='\t' ) return 1;
         1195  +  if( size>3 && data[0]==' ' && data[1]==' ' && data[2]==' ' && data[3]==' ' ){
         1196  +    return 4;
         1197  +  }
         1198  +  return 0;
         1199  +}
         1200  +
         1201  +/* prefix_oli -- returns ordered list item prefix */
         1202  +static size_t prefix_oli(char *data, size_t size){
         1203  +  size_t i = 0;
         1204  +  if( i<size && data[i]==' ') i++;
         1205  +  if( i<size && data[i]==' ') i++;
         1206  +  if( i<size && data[i]==' ') i++;
         1207  +
         1208  +  if( i>=size || data[i]<'0' || data[i]>'9' ) return 0;
         1209  +  while( i<size && data[i]>='0' && data[i]<='9' ){ i++; }
         1210  +
         1211  +  if( i+1>=size
         1212  +   || data[i]!='.'
         1213  +   || (data[i+1]!=' ' && data[i+1]!='\t')
         1214  +  ){
         1215  +   return 0;
         1216  +  }
         1217  +  i = i+2;
         1218  +  while( i<size && (data[i]==' ' || data[i]=='\t') ){ i++; }
         1219  +  return i;
         1220  +}
         1221  +
         1222  +
         1223  +/* prefix_uli -- returns ordered list item prefix */
         1224  +static size_t prefix_uli(char *data, size_t size){
         1225  +  size_t i = 0;
         1226  +  if( i<size && data[i]==' ') i++;
         1227  +  if( i<size && data[i]==' ') i++;
         1228  +  if( i<size && data[i]==' ') i++;
         1229  +  if( i+1>=size
         1230  +   || (data[i]!='*' && data[i]!='+' && data[i]!='-')
         1231  +   || (data[i+1]!=' ' && data[i+1]!='\t')
         1232  +  ){
         1233  +    return 0;
         1234  +  }
         1235  +  i = i+2;
         1236  +  while( i<size && (data[i]==' ' || data[i]=='\t') ){ i++; }
         1237  +  return i;
         1238  +}
         1239  +
         1240  +
         1241  +/* parse_block predeclaration */
         1242  +static void parse_block(
         1243  +  struct Blob *ob,
         1244  +  struct render *rndr,
         1245  +  char *data,
         1246  +  size_t size);
         1247  +
         1248  +
         1249  +/* parse_blockquote -- hanldes parsing of a blockquote fragment */
         1250  +static size_t parse_blockquote(
         1251  +  struct Blob *ob,
         1252  +  struct render *rndr,
         1253  +  char *data,
         1254  +  size_t size
         1255  +){
         1256  +  size_t beg, end = 0, pre, work_size = 0;
         1257  +  char *work_data = 0;
         1258  +  struct Blob *out = new_work_buffer(rndr);
         1259  +
         1260  +  beg = 0;
         1261  +  while( beg<size ){
         1262  +    for(end=beg+1; end<size && data[end-1]!='\n'; end++);
         1263  +    pre = prefix_quote(data+beg, end-beg);
         1264  +    if( pre ){
         1265  +      beg += pre; /* skipping prefix */
         1266  +    }else if( is_empty(data+beg, end-beg)
         1267  +     && (end>=size
         1268  +         || (prefix_quote(data+end, size-end)==0
         1269  +             && !is_empty(data+end, size-end)))
         1270  +    ){
         1271  +      /* empty line followed by non-quote line */
         1272  +      break;
         1273  +    }
         1274  +    if( beg<end ){ /* copy into the in-place working buffer */
         1275  +      if( !work_data ){
         1276  +        work_data = data+beg;
         1277  +      }else if( (data+beg)!=(work_data+work_size) ){
         1278  +        memmove(work_data+work_size, data+beg, end-beg);
         1279  +      }
         1280  +      work_size += end-beg;
         1281  +    }
         1282  +    beg = end;
         1283  +  }
         1284  +
         1285  +  if( rndr->make.blockquote ){
         1286  +    struct Blob fallback = BLOB_INITIALIZER;
         1287  +    if( out ){
         1288  +      parse_block(out, rndr, work_data, work_size);
         1289  +    }else{
         1290  +      blob_init(&fallback, work_data, work_size);
         1291  +    }
         1292  +    rndr->make.blockquote(ob, out ? out : &fallback, rndr->make.opaque);
         1293  +  }
         1294  +  release_work_buffer(rndr, out);
         1295  +  return end;
         1296  +}
         1297  +
         1298  +
         1299  +/* parse_blockquote -- hanldes parsing of a regular paragraph */
         1300  +static size_t parse_paragraph(
         1301  +  struct Blob *ob,
         1302  +  struct render *rndr,
         1303  +  char *data,
         1304  +  size_t size
         1305  +){
         1306  +  size_t i = 0, end = 0;
         1307  +  int level = 0;
         1308  +  char *work_data = data;
         1309  +  size_t work_size = 0;
         1310  +  struct Blob fallback = BLOB_INITIALIZER;
         1311  +
         1312  +  while( i<size ){
         1313  +    for(end=i+1; end<size && data[end-1]!='\n'; end++);
         1314  +    if( is_empty(data+i, size-i)
         1315  +     || (level = is_headerline(data+i, size-i))!= 0
         1316  +    ){
         1317  +      break;
         1318  +    }
         1319  +    if( (i && data[i]=='#') || is_hrule(data+i, size-i) ){
         1320  +      end = i;
         1321  +      break;
         1322  +    }
         1323  +    i = end;
         1324  +  }
         1325  +
         1326  +  work_size = i;
         1327  +  while( work_size && data[work_size-1]=='\n' ){ work_size--; }
         1328  +
         1329  +  if( !level ){
         1330  +    if( rndr->make.paragraph ){
         1331  +      struct Blob *tmp = new_work_buffer(rndr);
         1332  +      if( tmp ){
         1333  +        parse_inline(tmp, rndr, work_data, work_size);
         1334  +      }else{
         1335  +        blob_init(&fallback, work_data, work_size);
         1336  +      }
         1337  +      rndr->make.paragraph(ob, tmp ? tmp : &fallback, rndr->make.opaque);
         1338  +      release_work_buffer(rndr, tmp);
         1339  +    }
         1340  +  }else{
         1341  +    if( work_size ){
         1342  +      size_t beg;
         1343  +      i = work_size;
         1344  +      work_size -= 1;
         1345  +      while( work_size && data[work_size]!='\n' ){ work_size--; }
         1346  +      beg = work_size+1;
         1347  +      while( work_size && data[work_size-1]=='\n'){ work_size--; }
         1348  +      if( work_size ){
         1349  +        struct Blob *tmp = new_work_buffer(rndr);
         1350  +        if( tmp ){
         1351  +          parse_inline(tmp, rndr, work_data, work_size);
         1352  +        }else{
         1353  +          blob_init (&fallback, work_data, work_size);
         1354  +        }
         1355  +        if( rndr->make.paragraph ){
         1356  +          rndr->make.paragraph(ob, tmp ? tmp : &fallback, rndr->make.opaque);
         1357  +        }
         1358  +        release_work_buffer(rndr, tmp);
         1359  +        work_data += beg;
         1360  +        work_size = i - beg;
         1361  +      }else{
         1362  +        work_size = i;
         1363  +      }
         1364  +    }
         1365  +
         1366  +    if( rndr->make.header ){
         1367  +      struct Blob *span = new_work_buffer(rndr);
         1368  +      if( span ){
         1369  +        parse_inline(span, rndr, work_data, work_size);
         1370  +        rndr->make.header(ob, span, level, rndr->make.opaque);
         1371  +      }else{
         1372  +        blob_init(&fallback, work_data, work_size);
         1373  +        rndr->make.header(ob, &fallback, level, rndr->make.opaque);
         1374  +      }
         1375  +      release_work_buffer(rndr, span);
         1376  +    }
         1377  +  }
         1378  +  return end;
         1379  +}
         1380  +
         1381  +
         1382  +/* parse_blockquote -- hanldes parsing of a block-level code fragment */
         1383  +static size_t parse_blockcode(
         1384  +  struct Blob *ob,
         1385  +  struct render *rndr,
         1386  +  char *data,
         1387  +  size_t size
         1388  +){
         1389  +  size_t beg, end, pre;
         1390  +  struct Blob *work = new_work_buffer(rndr);
         1391  +  if( !work ) work = ob;
         1392  +
         1393  +  beg = 0;
         1394  +  while( beg<size ){
         1395  +    for(end=beg+1; end<size && data[end-1]!='\n'; end++);
         1396  +    pre = prefix_code(data+beg, end-beg);
         1397  +    if( pre ){
         1398  +      beg += pre; /* skipping prefix */
         1399  +    }else if( !is_empty(data+beg, end-beg) ){
         1400  +      /* non-empty non-prefixed line breaks the pre */
         1401  +      break;
         1402  +    }
         1403  +    if( beg<end ){
         1404  +      /* verbatim copy to the working buffer, escaping entities */
         1405  +      if( is_empty(data + beg, end - beg) ){
         1406  +        blob_append(work, "\n", 1);
         1407  +      }else{
         1408  +        blob_append(work, data+beg, end-beg);
         1409  +      }
         1410  +    }
         1411  +    beg = end;
         1412  +  }
         1413  +
         1414  +  end = blob_size(work);
         1415  +  while( end>0 && blob_buffer(work)[end-1]=='\n' ){ end--; }
         1416  +  work->nUsed = end;
         1417  +  blob_append(work, "\n", 1);
         1418  +
         1419  +  if( work!=ob ){
         1420  +    if( rndr->make.blockcode ){
         1421  +      rndr->make.blockcode(ob, work, rndr->make.opaque);
         1422  +    }
         1423  +    release_work_buffer(rndr, work);
         1424  +  }
         1425  +  return beg;
         1426  +}
         1427  +
         1428  +
         1429  +/* parse_listitem -- parsing of a single list item */
         1430  +/*  assuming initial prefix is already removed */
         1431  +static size_t parse_listitem(
         1432  +  struct Blob *ob,
         1433  +  struct render *rndr,
         1434  +  char *data,
         1435  +  size_t size,
         1436  +  int *flags
         1437  +){
         1438  +  struct Blob fallback = BLOB_INITIALIZER;
         1439  +  struct Blob *work = 0, *inter = 0;
         1440  +  size_t beg = 0, end, pre, sublist = 0, orgpre = 0, i;
         1441  +  int in_empty = 0, has_inside_empty = 0;
         1442  +
         1443  +  /* keeping track of the first indentation prefix */
         1444  +  if( size>1 && data[0]==' ' ){
         1445  +    orgpre = 1;
         1446  +    if( size>2 && data[1]==' ' ){
         1447  +      orgpre = 2;
         1448  +      if( size>3 && data[2]==' ' ){
         1449  +        orgpre = 3;
         1450  +      }
         1451  +    }
         1452  +   }
         1453  +  beg = prefix_uli(data, size);
         1454  +  if( !beg ) beg = prefix_oli(data, size);
         1455  +  if( !beg ) return 0;
         1456  +  /* skipping to the beginning of the following line */
         1457  +  end = beg;
         1458  +  while( end<size && data[end-1]!='\n' ){ end++; }
         1459  +
         1460  +  /* getting working buffers */
         1461  +  work = new_work_buffer(rndr);
         1462  +  inter = new_work_buffer(rndr);
         1463  +  if( !work ) work = &fallback;
         1464  +
         1465  +  /* putting the first line into the working buffer */
         1466  +  blob_append(work, data+beg, end-beg);
         1467  +  beg = end;
         1468  +
         1469  +  /* process the following lines */
         1470  +  while( beg<size ){
         1471  +    end++;
         1472  +    while( end<size && data[end-1]!='\n' ){ end++; }
         1473  +
         1474  +    /* process an empty line */
         1475  +    if( is_empty(data+beg, end-beg) ){
         1476  +      in_empty = 1;
         1477  +      beg = end;
         1478  +      continue;
         1479  +    }
         1480  +
         1481  +    /* computing the indentation */
         1482  +    i = 0;
         1483  +    if( end-beg>1 && data[beg]==' ' ){
         1484  +      i = 1;
         1485  +      if( end-beg>2 && data[beg+1]==' ' ){
         1486  +        i = 2;
         1487  +        if( end-beg>3 && data[beg+2]==' ' ){
         1488  +          i = 3;
         1489  +          if( end-beg>3 && data[beg+3]==' ' ){
         1490  +            i = 4;
         1491  +          }
         1492  +        }
         1493  +      }
         1494  +    }
         1495  +    pre = i;
         1496  +    if( data[beg]=='\t' ){ i = 1; pre = 8; }
         1497  +
         1498  +    /* checking for a new item */
         1499  +    if( (prefix_uli(data+beg+i, end-beg-i) && !is_hrule(data+beg+i, end-beg-i))
         1500  +     || prefix_oli(data+beg+i, end-beg-i)
         1501  +    ){
         1502  +      if( in_empty ) has_inside_empty = 1;
         1503  +      if( pre == orgpre ){ /* the following item must have */
         1504  +        break;             /* the same indentation */
         1505  +      }
         1506  +      if( !sublist ) sublist = blob_size(work);
         1507  +
         1508  +    /* joining only indented stuff after empty lines */
         1509  +    }else if( in_empty && i<4 && data[beg]!='\t' ){
         1510  +        *flags |= MKD_LI_END;
         1511  +        break;
         1512  +    }else if( in_empty ){
         1513  +      blob_append(work, "\n", 1);
         1514  +      has_inside_empty = 1;
         1515  +    }
         1516  +    in_empty = 0;
         1517  +
         1518  +    /* adding the line without prefix into the working buffer */
         1519  +    blob_append(work, data+beg+i, end-beg-i);
         1520  +    beg = end;
         1521  +  }
         1522  +
         1523  +  /* non-recursive fallback when working buffer stack is full */
         1524  +  if( !inter ){
         1525  +    if( rndr->make.listitem ){
         1526  +      rndr->make.listitem(ob, work, *flags, rndr->make.opaque);
         1527  +    }
         1528  +    if( work!=&fallback ) release_work_buffer(rndr, work);
         1529  +    blob_zero(&fallback);
         1530  +    return beg;
         1531  +  }
         1532  +
         1533  +  /* render of li contents */
         1534  +  if( has_inside_empty ) *flags |= MKD_LI_BLOCK;
         1535  +  if( *flags & MKD_LI_BLOCK ){
         1536  +    /* intermediate render of block li */
         1537  +    if( sublist && sublist<blob_size(work) ){
         1538  +      parse_block(inter, rndr, blob_buffer(work), sublist);
         1539  +      parse_block(inter,
         1540  +                  rndr,
         1541  +                  blob_buffer(work)+sublist,
         1542  +                  blob_size(work)-sublist);
         1543  +    }else{
         1544  +      parse_block(inter, rndr, blob_buffer(work), blob_size(work));
         1545  +    }
         1546  +  }else{
         1547  +    /* intermediate render of inline li */
         1548  +    if( sublist && sublist<blob_size(work) ){
         1549  +      parse_inline(inter, rndr, blob_buffer(work), sublist);
         1550  +      parse_block(inter,
         1551  +                  rndr,
         1552  +                  blob_buffer(work)+sublist,
         1553  +                  blob_size(work)-sublist);
         1554  +    }else{
         1555  +      parse_inline(inter, rndr, blob_buffer(work), blob_size(work));
         1556  +    }
         1557  +  }
         1558  +
         1559  +  /* render of li itself */
         1560  +  if( rndr->make.listitem ){
         1561  +    rndr->make.listitem(ob, inter, *flags, rndr->make.opaque);
         1562  +  }
         1563  +  release_work_buffer(rndr, inter);
         1564  +  if( work!=&fallback ) release_work_buffer(rndr, work);
         1565  +  blob_zero(&fallback);
         1566  +  return beg;
         1567  +}
         1568  +
         1569  +
         1570  +/* parse_list -- parsing ordered or unordered list block */
         1571  +static size_t parse_list(
         1572  +  struct Blob *ob,
         1573  +  struct render *rndr,
         1574  +  char *data,
         1575  +  size_t size,
         1576  +  int flags
         1577  +){
         1578  +  struct Blob fallback = BLOB_INITIALIZER;
         1579  +  struct Blob *work = new_work_buffer(rndr);
         1580  +  size_t i = 0, j;
         1581  +  if( !work ) work = &fallback;
         1582  +
         1583  +  while( i<size ){
         1584  +    j = parse_listitem(work, rndr, data+i, size-i, &flags);
         1585  +    i += j;
         1586  +    if( !j || (flags & MKD_LI_END) ) break;
         1587  +  }
         1588  +
         1589  +  if( rndr->make.list ) rndr->make.list(ob, work, flags, rndr->make.opaque);
         1590  +  if( work!=&fallback ) release_work_buffer(rndr, work);
         1591  +  blob_zero(&fallback);
         1592  +  return i;
         1593  +}
         1594  +
         1595  +
         1596  +/* parse_atxheader -- parsing of atx-style headers */
         1597  +static size_t parse_atxheader(
         1598  +  struct Blob *ob,
         1599  +  struct render *rndr,
         1600  +  char *data,
         1601  +  size_t size
         1602  +){
         1603  +  int level = 0;
         1604  +  size_t i, end, skip, span_beg, span_size;
         1605  +
         1606  +  if( !size || data[0]!='#' ) return 0;
         1607  +
         1608  +  while( level<size && level<6 && data[level]=='#' ){ level++; }
         1609  +  for(i=level; i<size && (data[i]==' ' || data[i]=='\t'); i++);
         1610  +  span_beg = i;
         1611  +
         1612  +  for(end=i; end<size && data[end]!='\n'; end++);
         1613  +  skip = end;
         1614  +  if( end<=i ) return parse_paragraph(ob, rndr, data, size);
         1615  +  while( end && data[end-1]=='#' ){ end--; }
         1616  +  while( end && (data[end-1]==' ' || data[end-1]=='\t') ){ end--; }
         1617  +  if( end<=i ) return parse_paragraph(ob, rndr, data, size);
         1618  +
         1619  +  span_size = end-span_beg;
         1620  +  if( rndr->make.header ){
         1621  +    struct Blob fallback = BLOB_INITIALIZER;
         1622  +    struct Blob *span = new_work_buffer(rndr);
         1623  +
         1624  +    if( span ){
         1625  +      parse_inline(span, rndr, data+span_beg, span_size);
         1626  +    }else{
         1627  +      blob_init(&fallback, data+span_beg, span_size);
         1628  +    }
         1629  +    rndr->make.header(ob, span ? span : &fallback, level, rndr->make.opaque);
         1630  +    release_work_buffer(rndr, span);
         1631  +  }
         1632  +  return skip;
         1633  +}
         1634  +
         1635  +
         1636  +/* htmlblock_end -- checking end of HTML block : </tag>[ \t]*\n[ \t*]\n */
         1637  +/*  returns the length on match, 0 otherwise */
         1638  +static size_t htmlblock_end(struct html_tag *tag, char *data, size_t size){
         1639  +  size_t i, w;
         1640  +
         1641  +  /* assuming data[0]=='<' && data[1]=='/' already tested */
         1642  +
         1643  +  /* checking tag is a match */
         1644  +  if( (tag->size+3)>=size
         1645  +    || strncasecmp(data+2, tag->text, tag->size)
         1646  +    || data[tag->size+2]!='>'
         1647  +  ){
         1648  +    return 0;
         1649  +  }
         1650  +
         1651  +  /* checking white lines */
         1652  +  i = tag->size + 3;
         1653  +  w = 0;
         1654  +  if( i<size && (w = is_empty(data+i, size-i))==0 ){
         1655  +    return 0; /* non-blank after tag */
         1656  +  }
         1657  +  i += w;
         1658  +  w = 0;
         1659  +
         1660  +  if( i<size && (w = is_empty(data + i, size - i))==0 ){
         1661  +    return 0; /* non-blank line after tag line */
         1662  +  }
         1663  +  return i+w;
         1664  +}
         1665  +
         1666  +
         1667  +/* parse_htmlblock -- parsing of inline HTML block */
         1668  +static size_t parse_htmlblock(
         1669  +  struct Blob *ob,
         1670  +  struct render *rndr,
         1671  +  char *data,
         1672  +  size_t size
         1673  +){
         1674  +  size_t i, j = 0;
         1675  +  struct html_tag *curtag;
         1676  +  int found;
         1677  +  size_t work_size = 0;
         1678  +  struct Blob work = BLOB_INITIALIZER;
         1679  +
         1680  +  /* identification of the opening tag */
         1681  +  if( size<2 || data[0]!='<' ) return 0;
         1682  +  curtag = find_block_tag(data+1, size-1);
         1683  +
         1684  +  /* handling of special cases */
         1685  +  if( !curtag ){
         1686  +
         1687  +    /* HTML comment, laxist form */
         1688  +    if( size>5 && data[1]=='!' && data[2]=='-' && data[3]=='-' ){
         1689  +      i = 5;
         1690  +      while( i<size && !(data[i-2]=='-' && data[i-1]=='-' && data[i]=='>') ){
         1691  +        i++;
         1692  +      }
         1693  +      i++;
         1694  +      if( i<size ){
         1695  +        j = is_empty(data+i, size-i);
         1696  +        if( j ){
         1697  +          work_size = i+j;
         1698  +          if( !rndr->make.blockhtml ) return work_size;
         1699  +          blob_init(&work, data, work_size);
         1700  +          rndr->make.blockhtml(ob, &work, rndr->make.opaque);
         1701  +          return work_size;
         1702  +        }
         1703  +      }
         1704  +    }
         1705  +
         1706  +    /* HR, which is the only self-closing block tag considered */
         1707  +    if( size>4
         1708  +      && (data[1]=='h' || data[1]=='H')
         1709  +      && (data[2]=='r' || data[2]=='R')
         1710  +    ){
         1711  +      i = 3;
         1712  +      while( i<size && data[i]!='>' ){ i++; }
         1713  +      if( i+1<size ){
         1714  +        i += 1;
         1715  +        j = is_empty(data+i, size-i);
         1716  +        if( j ){
         1717  +          work_size = i+j;
         1718  +          if( !rndr->make.blockhtml ) return work_size;
         1719  +          blob_init(&work, data, work_size);
         1720  +          rndr->make.blockhtml(ob, &work, rndr->make.opaque);
         1721  +          return work_size;
         1722  +        }
         1723  +      }
         1724  +    }
         1725  +
         1726  +    /* no special case recognised */
         1727  +    return 0;
         1728  +  }
         1729  +
         1730  +  /* looking for an unindented matching closing tag */
         1731  +  /*  followed by a blank line */
         1732  +  i = 1;
         1733  +  found = 0;
         1734  +#if 0
         1735  +  while( i<size ){
         1736  +    i++;
         1737  +    while( i<size && !(data[i-2]=='\n' && data[i-1]=='<' && data[i]=='/') ){
         1738  +      i++;
         1739  +    }
         1740  +    if( (i+2+curtag->size)>=size ) break;
         1741  +    j = htmlblock_end(curtag, data+i-1, size-i+1);
         1742  +    if (j) {
         1743  +      i += j-1;
         1744  +      found = 1;
         1745  +      break;
         1746  +    }
         1747  +  }
         1748  +#endif
         1749  +
         1750  +  /* if not found, trying a second pass looking for indented match */
         1751  +  /* but not if tag is "ins" or "del" (following original Markdown.pl) */
         1752  +  if( !found && curtag!=INS_TAG && curtag!=DEL_TAG ){
         1753  +    i = 1;
         1754  +    while( i<size ){
         1755  +      i++;
         1756  +      while( i<size && !(data[i-1]=='<' && data[i]=='/') ){ i++; }
         1757  +      if( (i+2+curtag->size)>=size ) break;
         1758  +      j = htmlblock_end(curtag, data+i-1, size-i+1);
         1759  +      if (j) {
         1760  +        i += j-1;
         1761  +        found = 1;
         1762  +        break;
         1763  +      }
         1764  +    }
         1765  +  }
         1766  +
         1767  +  if( !found ) return 0;
         1768  +
         1769  +  /* the end of the block has been found */
         1770  +  blob_init(&work, data, i);
         1771  +  if( rndr->make.blockhtml ){
         1772  +    rndr->make.blockhtml(ob, &work, rndr->make.opaque);
         1773  +  }
         1774  +  return i;
         1775  +}
         1776  +
         1777  +
         1778  +/* parse_table_cell -- parse a cell inside a table */
         1779  +static void parse_table_cell(
         1780  +  struct Blob *ob,     /* output blob */
         1781  +  struct render *rndr, /* renderer description */
         1782  +  char *data,          /* input text */
         1783  +  size_t size,         /* input text size */
         1784  +  int flags            /* table flags */
         1785  +){
         1786  +  struct Blob fallback = BLOB_INITIALIZER;
         1787  +  struct Blob *span = new_work_buffer(rndr);
         1788  +
         1789  +  if( span ){
         1790  +    parse_inline(span, rndr, data, size);
         1791  +  }else{
         1792  +    blob_init(&fallback, data, size);
         1793  +  }
         1794  +  rndr->make.table_cell(ob, span ? span : &fallback, flags, rndr->make.opaque);
         1795  +  release_work_buffer(rndr, span);
         1796  +}
         1797  +
         1798  +
         1799  +/* parse_table_row -- parse an input line into a table row */
         1800  +static size_t parse_table_row(
         1801  +  struct Blob *ob,        /* output blob for rendering */
         1802  +  struct render *rndr,    /* renderer description */
         1803  +  char *data,             /* input text */
         1804  +  size_t size,            /* input text size */
         1805  +  int *aligns,            /* array of default alignment for columns */
         1806  +  size_t align_size,      /* number of columns with default alignment */
         1807  +  int flags               /* table flags */
         1808  +){
         1809  +  size_t i = 0, col = 0;
         1810  +  size_t beg, end, total = 0;
         1811  +  struct Blob *cells = new_work_buffer(rndr);
         1812  +  int align;
         1813  +
         1814  +  /* skip leading blanks and sperator */
         1815  +  while( i<size && (data[i]==' ' || data[i]=='\t') ){ i++; }
         1816  +  if( i<size && data[i]=='|' ) i++;
         1817  +
         1818  +  /* go over all the cells */
         1819  +  while( i<size && total==0 ){
         1820  +    /* check optional left/center align marker */
         1821  +    align = 0;
         1822  +    if( data[i]==':' ){
         1823  +      align |= MKD_CELL_ALIGN_LEFT;
         1824  +      i++;
         1825  +    }
         1826  +
         1827  +    /* skip blanks */
         1828  +    while( i<size && (data[i]==' ' || data[i]=='\t') ){ i++; }
         1829  +    beg = i;
         1830  +
         1831  +    /* forward to the next separator or EOL */
         1832  +    while( i<size && !is_table_sep(data, i) && data[i]!='\n' ){ i++; }
         1833  +    end = i;
         1834  +    if( i<size ){
         1835  +      i++;
         1836  +      if( data[i-1]=='\n' ) total = i;
         1837  +    }
         1838  +
         1839  +    /* check optional right/center align marker */
         1840  +    if( i>beg && data[end-1]==':' ){
         1841  +      align |= MKD_CELL_ALIGN_RIGHT;
         1842  +      end--;
         1843  +    }
         1844  +
         1845  +    /* remove trailing blanks */
         1846  +    while( end>beg && (data[end-1]==' ' || data[end-1]=='\t') ){ end--; }
         1847  +
         1848  +    /* skip the last cell if it was only blanks */
         1849  +    /* (because it is only the optional end separator) */
         1850  +    if( total && end<=beg ) continue;
         1851  +
         1852  +    /* fallback on default alignment if not explicit */
         1853  +    if( align==0 && aligns && col<align_size ) align = aligns[col];
         1854  +
         1855  +    /* render cells */
         1856  +    if( cells ) parse_table_cell(cells, rndr, data+beg, end-beg, align|flags);
         1857  +
         1858  +    col++;
         1859  +  }
         1860  +
         1861  +  /* render the whole row and clean up */
         1862  +  if( cells ){
         1863  +    rndr->make.table_row(ob, cells, flags, rndr->make.opaque);
         1864  +  }else{
         1865  +    struct Blob fallback = BLOB_INITIALIZER;
         1866  +    blob_init(&fallback, data, total ? total : size);
         1867  +    rndr->make.table_row(ob, &fallback, flags, rndr->make.opaque);
         1868  +  }
         1869  +  release_work_buffer(rndr, cells);
         1870  +  return total ? total : size;
         1871  +}
         1872  +
         1873  +
         1874  +/* parse_table -- parsing of a whole table */
         1875  +static size_t parse_table(
         1876  +  struct Blob *ob,
         1877  +  struct render *rndr,
         1878  +  char *data,
         1879  +  size_t size
         1880  +){
         1881  +  size_t i = 0, head_end, col;
         1882  +  size_t align_size = 0;
         1883  +  int *aligns = 0;
         1884  +  struct Blob fallback = BLOB_INITIALIZER;
         1885  +  struct Blob *head = 0;
         1886  +  struct Blob *rows = new_work_buffer(rndr);
         1887  +  if( !rows ) rows = &fallback;
         1888  +
         1889  +  /* skip the first (presumably header) line */
         1890  +  while( i<size && data[i]!='\n' ){ i++; }
         1891  +  head_end = i;
         1892  +
         1893  +  /* fallback on end of input */
         1894  +  if( i>=size ){
         1895  +    parse_table_row(rows, rndr, data, size, 0, 0, 0);
         1896  +    rndr->make.table(ob, 0, rows, rndr->make.opaque);
         1897  +    if( rows!=&fallback ) release_work_buffer(rndr, rows);
         1898  +    return i;
         1899  +  }
         1900  +
         1901  +  /* attempt to parse a table rule, i.e. blanks, dash, colons and sep */
         1902  +  i++;
         1903  +  col = 0;
         1904  +  while( i<size
         1905  +    && (data[i]==' '
         1906  +      || data[i]=='\t'
         1907  +      || data[i]=='-'
         1908  +      || data[i] == ':'
         1909  +      || data[i] =='|')
         1910  +  ){
         1911  +    if( data[i] == '|' ) align_size++;
         1912  +    if( data[i] == ':' ) col = 1;
         1913  +    i += 1;
         1914  +  }
         1915  +
         1916  +  if( i<size && data[i]=='\n' ){
         1917  +    align_size++;
         1918  +
         1919  +    /* render the header row */
         1920  +    head = new_work_buffer(rndr);
         1921  +    if( head ){
         1922  +      parse_table_row(head, rndr, data, head_end, 0, 0, MKD_CELL_HEAD);
         1923  +    }
         1924  +
         1925  +    /* parse alignments if provided */
         1926  +    if( col && (aligns=malloc(align_size * sizeof *aligns))!=0 ){
         1927  +      for(i=0; i<align_size; i++) aligns[i] = 0;
         1928  +      col = 0;
         1929  +      i = head_end+1;
         1930  +
         1931  +      /* skip initial white space and optional separator */
         1932  +      while( i<size && (data[i]==' ' || data[i]=='\t') ){ i++; }
         1933  +      if( data[i]=='|' ) i++;
         1934  +
         1935  +      /* compute default alignment for each column */
         1936  +      while (i < size && data[i] != '\n') {
         1937  +        if (data[i] == ':')
         1938  +          aligns[col] |= MKD_CELL_ALIGN_LEFT;
         1939  +        while (i < size
         1940  +        && data[i] != '|' && data[i] != '\n')
         1941  +          i += 1;
         1942  +        if (data[i - 1] == ':')
         1943  +          aligns[col] |= MKD_CELL_ALIGN_RIGHT;
         1944  +        if (i < size && data[i] == '|')
         1945  +          i += 1;
         1946  +        col += 1; }
         1947  +    }
         1948  +
         1949  +    /* point i to the beginning of next line/row */
         1950  +    i++;
         1951  +
         1952  +  }else{
         1953  +    /* there is no valid ruler, continuing without header */
         1954  +    i = 0;
         1955  +  }
         1956  +
         1957  +  /* render the table body lines */
         1958  +  while( i<size && is_tableline(data + i, size - i) ){
         1959  +    i += parse_table_row(rows, rndr, data+i, size-i, aligns, align_size, 0);
         1960  +  }
         1961  +
         1962  +  /* render the full table */
         1963  +  rndr->make.table(ob, head, rows, rndr->make.opaque);
         1964  +
         1965  +  /* cleanup */
         1966  +  if( head ) release_work_buffer(rndr, head);
         1967  +  if( rows!=&fallback ) release_work_buffer(rndr, rows);
         1968  +  free(aligns);
         1969  +  return i;
         1970  +}
         1971  +
         1972  +
         1973  +/* parse_block -- parsing of one block, returning next char to parse */
         1974  +static void parse_block(
         1975  +  struct Blob *ob,        /* output blob */
         1976  +  struct render *rndr,    /* renderer internal state */
         1977  +  char *data,             /* input text */
         1978  +  size_t size             /* input text size */
         1979  +){
         1980  +  size_t beg, end, i;
         1981  +  char *txt_data;
         1982  +  int has_table = (rndr->make.table
         1983  +    && rndr->make.table_row
         1984  +    && rndr->make.table_cell);
         1985  +
         1986  +  beg = 0;
         1987  +  while( beg<size ){
         1988  +    txt_data = data+beg;
         1989  +    end = size-beg;
         1990  +    if( data[beg]=='#' ){
         1991  +      beg += parse_atxheader(ob, rndr, txt_data, end);
         1992  +    }else if( data[beg]=='<'
         1993  +      && rndr->make.blockhtml
         1994  +      && (i = parse_htmlblock(ob, rndr, txt_data, end))!=0
         1995  +    ){
         1996  +      beg += i;
         1997  +    }else if( (i=is_empty(txt_data, end))!=0 ){
         1998  +      beg += i;
         1999  +    }else if( is_hrule(txt_data, end) ){
         2000  +      if( rndr->make.hrule ) rndr->make.hrule(ob, rndr->make.opaque);
         2001  +      while( beg<size && data[beg]!='\n' ){ beg++; }
         2002  +      beg++;
         2003  +    }else if( prefix_quote(txt_data, end) ){
         2004  +      beg += parse_blockquote(ob, rndr, txt_data, end);
         2005  +    }else if( prefix_code(txt_data, end) ){
         2006  +      beg += parse_blockcode(ob, rndr, txt_data, end);
         2007  +    }else if( prefix_uli(txt_data, end) ){
         2008  +      beg += parse_list(ob, rndr, txt_data, end, 0);
         2009  +    }else if( prefix_oli(txt_data, end) ){
         2010  +      beg += parse_list(ob, rndr, txt_data, end, MKD_LIST_ORDERED);
         2011  +    }else if( has_table && is_tableline(txt_data, end) ){
         2012  +      beg += parse_table(ob, rndr, txt_data, end);
         2013  +    }else{
         2014  +      beg += parse_paragraph(ob, rndr, txt_data, end);
         2015  +    }
         2016  +  }
         2017  +}
         2018  +
         2019  +
         2020  +
         2021  +/*********************
         2022  + * REFERENCE PARSING *
         2023  + *********************/
         2024  +
         2025  +/* is_ref -- returns whether a line is a reference or not */
         2026  +static int is_ref(
         2027  +  char *data,         /* input text */
         2028  +  size_t beg,         /* offset of the beginning of the line */
         2029  +  size_t end,         /* offset of the end of the text */
         2030  +  size_t *last,       /* last character of the link */
         2031  +  struct Blob *refs   /* arry of link references */
         2032  +){
         2033  +  size_t i = 0;
         2034  +  size_t id_offset, id_end;
         2035  +  size_t link_offset, link_end;
         2036  +  size_t title_offset, title_end;
         2037  +  size_t line_end;
         2038  +  struct link_ref lr = {
         2039  +    BLOB_INITIALIZER,
         2040  +    BLOB_INITIALIZER,
         2041  +    BLOB_INITIALIZER
         2042  +  };
         2043  +
         2044  +  /* up to 3 optional leading spaces */
         2045  +  if( beg+3>=end ) return 0;
         2046  +  if( data[beg]==' ' ){
         2047  +    i = 1;
         2048  +    if( data[beg+1]==' ' ){
         2049  +      i = 2;
         2050  +      if( data[beg+2]==' ' ){
         2051  +        i = 3;
         2052  +        if( data[beg+3]==' ' ) return 0;
         2053  +      }
         2054  +    }
         2055  +  }
         2056  +  i += beg;
         2057  +
         2058  +  /* id part: anything but a newline between brackets */
         2059  +  if( data[i]!='[' ) return 0;
         2060  +  i++;
         2061  +  id_offset = i;
         2062  +  while( i<end && data[i]!='\n' && data[i]!='\r' && data[i]!=']' ){ i++; }
         2063  +  if( i>=end || data[i]!=']' ) return 0;
         2064  +  id_end = i;
         2065  +
         2066  +  /* spacer: colon (space | tab)* newline? (space | tab)* */
         2067  +  i++;
         2068  +  if( i>=end || data[i]!=':' ) return 0;
         2069  +  i++;
         2070  +  while( i<end && (data[i]==' ' || data[i]=='\t') ){ i++; }
         2071  +  if( i<end && (data[i]=='\n' || data[i]=='\r') ){
         2072  +    i++;
         2073  +    if( i<end && data[i]=='\r' && data[i-1] == '\n' ) i++;
         2074  +  }
         2075  +  while( i<end && (data[i]==' ' || data[i]=='\t') ){ i++; }
         2076  +  if( i>=end ) return 0;
         2077  +
         2078  +  /* link: whitespace-free sequence, optionally between angle brackets */
         2079  +  if( data[i]=='<' ) i++;
         2080  +  link_offset = i;
         2081  +  while( i<end
         2082  +   && data[i]!=' '
         2083  +   && data[i]!='\t'
         2084  +   && data[i]!='\n'
         2085  +   && data[i]!='\r'
         2086  +  ){
         2087  +    i += 1;
         2088  +  }
         2089  +  if( data[i-1]=='>' ) link_end = i-1; else link_end = i;
         2090  +
         2091  +  /* optional spacer: (space | tab)* (newline | '\'' | '"' | '(' ) */
         2092  +  while( i<end && (data[i]==' ' || data[i]=='\t') ){ i++; }
         2093  +  if( i<end
         2094  +   && data[i]!='\n'
         2095  +   && data[i]!='\r'
         2096  +   && data[i]!='\''
         2097  +   && data[i]!='"'
         2098  +   && data[i]!='('
         2099  +  ){
         2100  +    return 0;
         2101  +  }
         2102  +  line_end = 0;
         2103  +  /* computing end-of-line */
         2104  +  if( i>=end || data[i]=='\r' || data[i]=='\n' ) line_end = i;
         2105  +  if( i+1<end && data[i]=='\n' && data[i+1]=='\r' ) line_end = i+1;
         2106  +
         2107  +  /* optional (space|tab)* spacer after a newline */
         2108  +  if( line_end ){
         2109  +    i = line_end+1;
         2110  +    while( i<end && (data[i]==' ' || data[i]=='\t') ){ i++; }
         2111  +  }
         2112  +
         2113  +  /* optional title: any non-newline sequence enclosed in '"()
         2114  +          alone on its line */
         2115  +  title_offset = title_end = 0;
         2116  +  if( i+1<end && (data[i]=='\'' || data[i]=='"' || data[i]=='(') ){
         2117  +    i += 1;
         2118  +    title_offset = i;
         2119  +    /* looking for EOL */
         2120  +    while( i<end && data[i]!='\n' && data[i]!='\r' ){ i++; }
         2121  +    if( i+1<end && data[i]=='\n' && data[i+1]=='\r' ){
         2122  +      title_end = i + 1;
         2123  +    }else{
         2124  +      title_end = i;
         2125  +    }
         2126  +    /* stepping back */
         2127  +    i--;
         2128  +    while( i>title_offset && (data[i]==' ' || data[i]=='\t') ){ i--; }
         2129  +    if( i>title_offset && (data[i]=='\'' || data[i]=='"' || data[i]==')') ){
         2130  +      line_end = title_end;
         2131  +      title_end = i;
         2132  +    }
         2133  +  }
         2134  +  if( !line_end ) return 0; /* garbage after the link */
         2135  +
         2136  +  /* a valid ref has been found, filling-in return structures */
         2137  +  if( last ) *last = line_end;
         2138  +  if( !refs ) return 1;
         2139  +  if( build_ref_id(&lr.id, data+id_offset, id_end-id_offset)<0 ) return 0;
         2140  +  blob_append(&lr.link, data+link_offset, link_end-link_offset);
         2141  +  if( title_end>title_offset ){
         2142  +    blob_append(&lr.title, data+title_offset, title_end-title_offset);
         2143  +  }
         2144  +  blob_append(refs, (char *)&lr, sizeof lr);
         2145  +  return 1;
         2146  +}
         2147  +
         2148  +
         2149  +
         2150  +/**********************
         2151  + * EXPORTED FUNCTIONS *
         2152  + **********************/
         2153  +
         2154  +/* markdown -- parses the input buffer and renders it into the output buffer */
         2155  +void markdown(
         2156  +  struct Blob *ob,                   /* output blob for rendered text */
         2157  +  struct Blob *ib,                   /* input blob in markdown */
         2158  +  const struct mkd_renderer *rndrer  /* renderer descriptor (callbacks) */
         2159  +){
         2160  +  struct link_ref *lr;
         2161  +  struct Blob text = BLOB_INITIALIZER;
         2162  +  size_t i, beg, end;
         2163  +  struct render rndr;
         2164  +  char *ib_data;
         2165  +
         2166  +  /* filling the render structure */
         2167  +  if( !rndrer ) return;
         2168  +  rndr.make = *rndrer;
         2169  +  if( rndr.make.max_work_stack<1 ) rndr.make.max_work_stack = 1;
         2170  +  rndr.work_active = 0;
         2171  +  rndr.work = fossil_malloc(rndr.make.max_work_stack * sizeof *rndr.work);
         2172  +  for(i=0; i<rndr.make.max_work_stack; i++) rndr.work[i] = text;
         2173  +  rndr.refs = text;
         2174  +  for(i=0; i<256; i++) rndr.active_char[i] = 0;
         2175  +  if( (rndr.make.emphasis
         2176  +    || rndr.make.double_emphasis
         2177  +    || rndr.make.triple_emphasis)
         2178  +   && rndr.make.emph_chars
         2179  +  ){
         2180  +    for(i=0; rndr.make.emph_chars[i]; i++){
         2181  +      rndr.active_char[(unsigned char)rndr.make.emph_chars[i]] = char_emphasis;
         2182  +    }
         2183  +  }
         2184  +  if( rndr.make.codespan ) rndr.active_char['`'] = char_codespan;
         2185  +  if( rndr.make.linebreak ) rndr.active_char['\n'] = char_linebreak;
         2186  +  if( rndr.make.image || rndr.make.link ) rndr.active_char['['] = char_link;
         2187  +  rndr.active_char['<'] = char_langle_tag;
         2188  +  rndr.active_char['\\'] = char_escape;
         2189  +  rndr.active_char['&'] = char_entity;
         2190  +
         2191  +  /* first pass: looking for references, copying everything else */
         2192  +  beg = 0;
         2193  +  ib_data = blob_buffer(ib);
         2194  +  while( beg<blob_size(ib) ){ /* iterating over lines */
         2195  +    if( is_ref(ib_data, beg, blob_size(ib), &end, &rndr.refs) ){
         2196  +      beg = end;
         2197  +    }else{ /* skipping to the next line */
         2198  +      end = beg;
         2199  +      while( end<blob_size(ib) && ib_data[end]!='\n' && ib_data[end]!='\r' ){
         2200  +        end += 1;
         2201  +      }
         2202  +      /* adding the line body if present */
         2203  +      if( end>beg ) blob_append(&text, ib_data + beg, end - beg);
         2204  +      while( end<blob_size(ib) && (ib_data[end]=='\n' || ib_data[end]=='\r') ){
         2205  +        /* add one \n per newline */
         2206  +        if( ib_data[end]=='\n'
         2207  +         || (end+1<blob_size(ib) && ib_data[end+1]!='\n')
         2208  +        ){
         2209  +          blob_append(&text, "\n", 1);
         2210  +        }
         2211  +        end += 1;
         2212  +      }
         2213  +      beg = end;
         2214  +    }
         2215  +  }
         2216  +
         2217  +  /* sorting the reference array */
         2218  +  if( blob_size(&rndr.refs) ){
         2219  +    qsort(blob_buffer(&rndr.refs),
         2220  +          blob_size(&rndr.refs)/sizeof(struct link_ref),
         2221  +          sizeof(struct link_ref),
         2222  +          cmp_link_ref_sort);
         2223  +  }
         2224  +
         2225  +  /* second pass: actual rendering */
         2226  +  if( rndr.make.prolog ) rndr.make.prolog(ob, rndr.make.opaque);
         2227  +  parse_block(ob, &rndr, blob_buffer(&text), blob_size(&text));
         2228  +  if( rndr.make.epilog ) rndr.make.epilog(ob, rndr.make.opaque);
         2229  +
         2230  +  /* clean-up */
         2231  +  blob_zero(&text);
         2232  +  lr = (struct link_ref *)blob_buffer(&rndr.refs);
         2233  +  end = blob_size(&rndr.refs)/sizeof(struct link_ref);
         2234  +  for(i=0; i<end; i++){
         2235  +    blob_zero(&lr[i].id);
         2236  +    blob_zero(&lr[i].link);
         2237  +    blob_zero(&lr[i].title);
         2238  +  }
         2239  +  blob_zero(&rndr.refs);
         2240  +  blobarray_zero(rndr.work, rndr.make.max_work_stack);
         2241  +  fossil_free(rndr.work);
         2242  +}
         2243  +
         2244  +#endif /* def FOSSIL_ENABLE_MARKDOWN */

Added src/markdown_html.c.

            1  +/*
            2  +** Copyright (c) 2012 D. Richard Hipp
            3  +**
            4  +** This program is free software; you can redistribute it and/or
            5  +** modify it under the terms of the Simplified BSD License (also
            6  +** known as the "2-Clause License" or "FreeBSD License".)
            7  +
            8  +** This program is distributed in the hope that it will be useful,
            9  +** but without any warranty; without even the implied warranty of
           10  +** merchantability or fitness for a particular purpose.
           11  +**
           12  +** Author contact information:
           13  +**   drh@hwaci.com
           14  +**   http://www.hwaci.com/drh/
           15  +**
           16  +*******************************************************************************
           17  +**
           18  +** This file contains callbacks for the markdown parser that generate
           19  +** XHTML output.
           20  +*/
           21  +
           22  +#ifdef FOSSIL_ENABLE_MARKDOWN
           23  +
           24  +#include "config.h"
           25  +#include "markdown_html.h"
           26  +
           27  +#if INTERFACE
           28  +
           29  +void markdown_to_html(
           30  +  struct Blob *input_markdown,
           31  +  struct Blob *output_title,
           32  +  struct Blob *output_body);
           33  +
           34  +#endif /* INTERFACE */
           35  +
           36  +
           37  +/* INTER_BLOCK -- skip a line between block level elements */
           38  +#define INTER_BLOCK(ob) \
           39  +  do { if( blob_size(ob)>0 ) blob_append(ob, "\n", 1); } while (0)
           40  +
           41  +/* BLOB_APPEND_LITTERAL -- append a string litteral to a blob */
           42  +#define BLOB_APPEND_LITTERAL(blob, litteral) \
           43  +  blob_append((blob), "" litteral, (sizeof litteral)-1)
           44  +  /*
           45  +   * The empty string in the second argument leads to a syntax error
           46  +   * when the macro is not used with a string litteral. Unfortunately
           47  +   * the error is not overly explicit.
           48  +   */
           49  +
           50  +/* BLOB_APPEND_BLOB -- append blob contents to another */
           51  +#define BLOB_APPEND_BLOB(dest, src) \
           52  +  blob_append((dest), blob_buffer(src), blob_size(src))
           53  +
           54  +
           55  +/* HTML escape */
           56  +
           57  +static void html_escape(struct Blob *ob, const char *data, size_t size){
           58  +  size_t beg = 0, i = 0;
           59  +  while( i<size ){
           60  +    beg = i;
           61  +    while( i<size
           62  +     && data[i]!='<'
           63  +     && data[i]!='>'
           64  +     && data[i]!='"'
           65  +     && data[i]!='&'
           66  +    ){
           67  +      i++;
           68  +    }
           69  +    blob_append(ob, data+beg, i-beg);
           70  +    while( i<size ){
           71  +      if( data[i]=='<' ){
           72  +        BLOB_APPEND_LITTERAL(ob, "&lt;");
           73  +      }else if( data[i]=='>' ){
           74  +        BLOB_APPEND_LITTERAL(ob, "&gt;");
           75  +      }else if( data[i]=='&' ){
           76  +        BLOB_APPEND_LITTERAL(ob, "&amp;");
           77  +      }else if( data[i]=='"' ){
           78  +        BLOB_APPEND_LITTERAL(ob, "&quot;");
           79  +      }else{
           80  +        break;
           81  +      }
           82  +      i++;
           83  +    }
           84  +  }
           85  +}
           86  +
           87  +
           88  +/* HTML block tags */
           89  +
           90  +static void html_raw_block(struct Blob *ob, struct Blob *text, void *opaque){
           91  +  char *data = blob_buffer(text);
           92  +  size_t first = 0, size = blob_size(text);
           93  +  INTER_BLOCK(ob);
           94  +  while( first<size && data[first]=='\n' ) first++;
           95  +  while( size>first && data[size-1]=='\n' ) size--;
           96  +  blob_append(ob, data+first, size-first);
           97  +  BLOB_APPEND_LITTERAL(ob, "\n");
           98  +}
           99  +
          100  +static void html_blockcode(struct Blob *ob, struct Blob *text, void *opaque){
          101  +  INTER_BLOCK(ob);
          102  +  BLOB_APPEND_LITTERAL(ob, "<pre><code>");
          103  +  html_escape(ob, blob_buffer(text), blob_size(text));
          104  +  BLOB_APPEND_LITTERAL(ob, "</code></pre>\n");
          105  +}
          106  +
          107  +static void html_blockquote(struct Blob *ob, struct Blob *text, void *opaque){
          108  +  INTER_BLOCK(ob);
          109  +  BLOB_APPEND_LITTERAL(ob, "<blockquote>\n");
          110  +  BLOB_APPEND_BLOB(ob, text);
          111  +  BLOB_APPEND_LITTERAL(ob, "</blockquote>\n");
          112  +}
          113  +
          114  +static void html_header(
          115  +  struct Blob *ob,
          116  +  struct Blob *text,
          117  +  int level,
          118  +  void *opaque
          119  +){
          120  +  struct Blob *title = opaque;
          121  +  /* The first header at the beginning of a text is considered as
          122  +   * a title and not output. */
          123  +  if( blob_size(ob)==0 && blob_size(title)==0 ){
          124  +    BLOB_APPEND_BLOB(title, text);
          125  +    return;
          126  +  }
          127  +  INTER_BLOCK(ob);
          128  +  blob_appendf(ob, "<h%d>", level);
          129  +  BLOB_APPEND_BLOB(ob, text);
          130  +  blob_appendf(ob, "</h%d>", level);
          131  +}
          132  +
          133  +static void html_hrule(struct Blob *ob, void *opaque){
          134  +  INTER_BLOCK(ob);
          135  +  BLOB_APPEND_LITTERAL(ob, "<hr />\n");
          136  +}
          137  +
          138  +
          139  +static void html_list(
          140  +  struct Blob *ob,
          141  +  struct Blob *text,
          142  +  int flags,
          143  +  void *opaque
          144  +){
          145  +  char ol[] = "ol";
          146  +  char ul[] = "ul";
          147  +  char *tag = (flags & MKD_LIST_ORDERED) ? ol : ul;
          148  +  INTER_BLOCK(ob);
          149  +  blob_appendf(ob, "<%s>\n", tag);
          150  +  BLOB_APPEND_BLOB(ob, text);
          151  +  blob_appendf(ob, "</%s>\n", tag);
          152  +}
          153  +
          154  +static void html_list_item(
          155  +  struct Blob *ob,
          156  +  struct Blob *text,
          157  +  int flags,
          158  +  void *opaque
          159  +){
          160  +  char *text_data = blob_buffer(text);
          161  +  size_t text_size = blob_size(text);
          162  +  while( text_size>0 && text_data[text_size-1]=='\n' ) text_size--;
          163  +  BLOB_APPEND_LITTERAL(ob, "<li>");
          164  +  blob_append(ob, text_data, text_size);
          165  +  BLOB_APPEND_LITTERAL(ob, "</li>\n");
          166  +}
          167  +
          168  +static void html_paragraph(struct Blob *ob, struct Blob *text, void *opaque){
          169  +  INTER_BLOCK(ob);
          170  +  BLOB_APPEND_LITTERAL(ob, "<p>");
          171  +  BLOB_APPEND_BLOB(ob, text);
          172  +  BLOB_APPEND_LITTERAL(ob, "</p>\n");
          173  +}
          174  +
          175  +
          176  +static void html_table(
          177  +  struct Blob *ob,
          178  +  struct Blob *head_row,
          179  +  struct Blob *rows,
          180  +  void *opaque
          181  +){
          182  +  INTER_BLOCK(ob);
          183  +  BLOB_APPEND_LITTERAL(ob, "<table>\n");
          184  +  if( head_row && blob_size(head_row)>0 ){
          185  +    BLOB_APPEND_LITTERAL(ob, "<thead>\n");
          186  +    BLOB_APPEND_BLOB(ob, head_row);
          187  +    BLOB_APPEND_LITTERAL(ob, "</thead>\n<tbody>\n");
          188  +  }
          189  +  if( rows ){
          190  +    BLOB_APPEND_BLOB(ob, rows);
          191  +  }
          192  +  if( head_row && blob_size(head_row)>0 ){
          193  +    BLOB_APPEND_LITTERAL(ob, "</tbody>\n");
          194  +  }
          195  +  BLOB_APPEND_LITTERAL(ob, "</table>\n");
          196  +}
          197  +
          198  +static void html_table_cell(
          199  +  struct Blob *ob,
          200  +  struct Blob *text,
          201  +  int flags,
          202  +  void *opaque
          203  +){
          204  +  if( flags & MKD_CELL_HEAD ){
          205  +    BLOB_APPEND_LITTERAL(ob, "    <th");
          206  +  }else{
          207  +    BLOB_APPEND_LITTERAL(ob, "    <td");
          208  +  }
          209  +  switch( flags & MKD_CELL_ALIGN_MASK ){
          210  +    case MKD_CELL_ALIGN_LEFT: {
          211  +      BLOB_APPEND_LITTERAL(ob, " align=\"left\"");
          212  +      break;
          213  +    }
          214  +    case MKD_CELL_ALIGN_RIGHT: {
          215  +      BLOB_APPEND_LITTERAL(ob, " align=\"right\"");
          216  +      break;
          217  +    }
          218  +    case MKD_CELL_ALIGN_CENTER: {
          219  +      BLOB_APPEND_LITTERAL(ob, " align=\"center\"");
          220  +      break;
          221  +    }
          222  +  }
          223  +  BLOB_APPEND_LITTERAL(ob, ">");
          224  +  BLOB_APPEND_BLOB(ob, text);
          225  +  if( flags & MKD_CELL_HEAD ){
          226  +    BLOB_APPEND_LITTERAL(ob, "</th>\n");
          227  +  }else{
          228  +    BLOB_APPEND_LITTERAL(ob, "</td>\n");
          229  +  }
          230  +}
          231  +
          232  +static void html_table_row(
          233  +  struct Blob *ob,
          234  +  struct Blob *cells,
          235  +  int flags,
          236  +  void *opaque
          237  +){
          238  +  BLOB_APPEND_LITTERAL(ob, "  <tr>\n");
          239  +  BLOB_APPEND_BLOB(ob, cells);
          240  +  BLOB_APPEND_LITTERAL(ob, "  </tr>\n");
          241  +}
          242  +
          243  +
          244  +
          245  +/* HTML span tags */
          246  +
          247  +static int html_raw_span(struct Blob *ob, struct Blob *text, void *opaque){
          248  +  BLOB_APPEND_BLOB(ob, text);
          249  +  return 1;
          250  +}
          251  +
          252  +static int html_autolink(
          253  +  struct Blob *ob,
          254  +  struct Blob *link,
          255  +  enum mkd_autolink type,
          256  +  void *opaque
          257  +){
          258  +  if( !link || blob_size(link)<=0 ) return 0;
          259  +  BLOB_APPEND_LITTERAL(ob, "<a href=\"");
          260  +  if( type==MKDA_IMPLICIT_EMAIL ) BLOB_APPEND_LITTERAL(ob, "mailto:");
          261  +  html_escape(ob, blob_buffer(link), blob_size(link));
          262  +  BLOB_APPEND_LITTERAL(ob, "\">");
          263  +  if( type==MKDA_EXPLICIT_EMAIL && blob_size(link)>7 ){
          264  +    /* remove "mailto:" from displayed text */
          265  +    html_escape(ob, blob_buffer(link)+7, blob_size(link)-7);
          266  +  }else{
          267  +    html_escape(ob, blob_buffer(link), blob_size(link));
          268  +  }
          269  +  BLOB_APPEND_LITTERAL(ob, "</a>");
          270  +  return 1;
          271  +}
          272  +
          273  +static int html_code_span(struct Blob *ob, struct Blob *text, void *opaque){
          274  +  BLOB_APPEND_LITTERAL(ob, "<code>");
          275  +  html_escape(ob, blob_buffer(text), blob_size(text));
          276  +  BLOB_APPEND_LITTERAL(ob, "</code>");
          277  +  return 1;
          278  +}
          279  +
          280  +static int html_double_emphasis(
          281  +  struct Blob *ob,
          282  +  struct Blob *text,
          283  +  char c,
          284  +  void *opaque
          285  +){
          286  +  BLOB_APPEND_LITTERAL(ob, "<strong>");
          287  +  BLOB_APPEND_BLOB(ob, text);
          288  +  BLOB_APPEND_LITTERAL(ob, "</strong>");
          289  +  return 1;
          290  +}
          291  +
          292  +static int html_emphasis(
          293  +  struct Blob *ob,
          294  +  struct Blob *text,
          295  +  char c,
          296  +  void *opaque
          297  +){
          298  +  BLOB_APPEND_LITTERAL(ob, "<em>");
          299  +  BLOB_APPEND_BLOB(ob, text);
          300  +  BLOB_APPEND_LITTERAL(ob, "</em>");
          301  +  return 1;
          302  +}
          303  +
          304  +static int html_image(
          305  +  struct Blob *ob,
          306  +  struct Blob *link,
          307  +  struct Blob *title,
          308  +  struct Blob *alt,
          309  +  void *opaque
          310  +){
          311  +  BLOB_APPEND_LITTERAL(ob, "<img src=\"");
          312  +  html_escape(ob, blob_buffer(link), blob_size(link));
          313  +  BLOB_APPEND_LITTERAL(ob, "\" alt=\"");
          314  +  html_escape(ob, blob_buffer(alt), blob_size(alt));
          315  +  if( title && blob_size(title)>0 ){
          316  +    BLOB_APPEND_LITTERAL(ob, "\" title=\"");
          317  +    html_escape(ob, blob_buffer(title), blob_size(title));
          318  +  }
          319  +  BLOB_APPEND_LITTERAL(ob, "\" />");
          320  +  return 1;
          321  +}
          322  +
          323  +static int html_line_break(struct Blob *ob, void *opaque){
          324  +  BLOB_APPEND_LITTERAL(ob, "<br />\n");
          325  +  return 1;
          326  +}
          327  +
          328  +static int html_link(
          329  +  struct Blob *ob,
          330  +  struct Blob *link,
          331  +  struct Blob *title,
          332  +  struct Blob *content,
          333  +  void *opaque
          334  +){
          335  +  BLOB_APPEND_LITTERAL(ob, "<a href=\"");
          336  +  html_escape(ob, blob_buffer(link), blob_size(link));
          337  +  if( title && blob_size(title)>0 ){
          338  +    BLOB_APPEND_LITTERAL(ob, "\" title=\"");
          339  +    html_escape(ob, blob_buffer(title), blob_size(title));
          340  +  }
          341  +  BLOB_APPEND_LITTERAL(ob, "\">");
          342  +  BLOB_APPEND_BLOB(ob, content);
          343  +  BLOB_APPEND_LITTERAL(ob, "</a>");
          344  +  return 1;
          345  +}
          346  +
          347  +static int html_triple_emphasis(
          348  +  struct Blob *ob,
          349  +  struct Blob *text,
          350  +  char c,
          351  +  void *opaque
          352  +){
          353  +  BLOB_APPEND_LITTERAL(ob, "<strong><em>");
          354  +  BLOB_APPEND_BLOB(ob, text);
          355  +  BLOB_APPEND_LITTERAL(ob, "</em></strong>");
          356  +  return 1;
          357  +}
          358  +
          359  +
          360  +static void html_normal_text(struct Blob *ob, struct Blob *text, void *opaque){
          361  +  html_escape(ob, blob_buffer(text), blob_size(text));
          362  +}
          363  +
          364  +
          365  +void markdown_to_html(
          366  +  struct Blob *input_markdown,
          367  +  struct Blob *output_title,
          368  +  struct Blob *output_body
          369  +){
          370  +  struct mkd_renderer html_renderer = {
          371  +    0, 0,  /* no prolog or epilog */
          372  +
          373  +    /* block level elements */
          374  +    html_blockcode,
          375  +    html_blockquote,
          376  +    html_raw_block,
          377  +    html_header,
          378  +    html_hrule,
          379  +    html_list,
          380  +    html_list_item,
          381  +    html_paragraph,
          382  +    html_table,
          383  +    html_table_cell,
          384  +    html_table_row,
          385  +
          386  +    /* span level elements */
          387  +    html_autolink,
          388  +    html_code_span,
          389  +    html_double_emphasis,
          390  +    html_emphasis,
          391  +    html_image,
          392  +    html_line_break,
          393  +    html_link,
          394  +    html_raw_span,
          395  +    html_triple_emphasis,
          396  +
          397  +    /* low level elements */
          398  +    0,  /* entities are copied verbatim */
          399  +    html_normal_text,
          400  +
          401  +    /* misc. parameters */
          402  +    64, /* maximum stack */
          403  +    "*_", /* emphasis characters */
          404  +    output_title /* opaque data */
          405  +  };
          406  +  blob_reset(output_title);
          407  +  blob_reset(output_body);
          408  +  markdown(output_body, input_markdown, &html_renderer);
          409  +}
          410  +
          411  +#endif /* def FOSSIL_ENABLE_MARKDOWN */

Changes to src/th_main.c.

   263    263   ** Return true if the fossil binary has the given compile-time feature
   264    264   ** enabled. The set of features includes:
   265    265   **
   266    266   ** "json"     = FOSSIL_ENABLE_JSON
   267    267   ** "ssl"      = FOSSIL_ENABLE_SSL
   268    268   ** "tcl"      = FOSSIL_ENABLE_TCL
   269    269   ** "tclStubs" = FOSSIL_ENABLE_TCL_STUBS
          270  +** "markdown" = FOSSIL_ENABLE_MARKDOWN
   270    271   **
   271    272   */
   272    273   static int hasfeatureCmd(
   273    274     Th_Interp *interp, 
   274    275     void *p, 
   275    276     int argc, 
   276    277     const char **argv, 
................................................................................
   300    301       rc = 1;
   301    302     }
   302    303   #endif
   303    304   #if defined(FOSSIL_ENABLE_TCL_STUBS)
   304    305     else if( 0 == fossil_strnicmp( zArg, "tclStubs", 8 ) ){
   305    306       rc = 1;
   306    307     }
          308  +#endif
          309  +#if defined(FOSSIL_ENABLE_MARKDOWN)
          310  +  else if( 0 == fossil_strnicmp( zArg, "markdown", 8 ) ){
          311  +    rc = 1;
          312  +  }
   307    313   #endif
   308    314     if( g.thTrace ){
   309    315       Th_Trace("[hasfeature %#h] => %d<br />\n", argl[1], zArg, rc);
   310    316     }
   311    317     Th_SetResultInt(interp, rc);
   312    318     return TH_OK;
   313    319   }

Changes to win/Makefile.dmc.

    24     24   CFLAGS = -o
    25     25   BCC    = $(DMDIR)\bin\dmc $(CFLAGS)
    26     26   TCC    = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL)
    27     27   LIBS   = $(DMDIR)\extra\lib\ zlib wsock32 advapi32
    28     28   
    29     29   SQLITE_OPTIONS = -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0
    30     30   
    31         -SRC   = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c glob_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c login_.c main_.c manifest_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c sqlcmd_.c stash_.c stat_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c update_.c url_.c user_.c utf8_.c verify_.c vfile_.c wiki_.c wikiformat_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c 
           31  +SRC   = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c glob_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c login_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c sqlcmd_.c stash_.c stat_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c update_.c url_.c user_.c utf8_.c verify_.c vfile_.c wiki_.c wikiformat_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c 
    32     32   
    33         -OBJ   = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\login$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\rebuild$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\skins$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winhttp$O $(OBJDIR)\wysiwyg$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O 
           33  +OBJ   = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\login$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\rebuild$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\skins$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winhttp$O $(OBJDIR)\wysiwyg$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O 
    34     34   
    35     35   
    36     36   RC=$(DMDIR)\bin\rcc
    37     37   RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__
    38     38   
    39     39   APPNAME = $(OBJDIR)\fossil$(E)
    40     40   
................................................................................
    44     44   	cd $(OBJDIR) 
    45     45   	$(DMDIR)\bin\link @link
    46     46   
    47     47   $(OBJDIR)\fossil.res:	$B\win\fossil.rc
    48     48   	$(RC) $(RCFLAGS) -o$@ $**
    49     49   
    50     50   $(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res
    51         -	+echo add allrepo attach bag bisect blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo glob graph gzip http http_socket http_ssl http_transport import info json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_tag json_timeline json_user json_wiki leaf login main manifest md5 merge merge3 moderate name path pivot popen pqueue printf rebuild report rss schema search setup sha1 shun skins sqlcmd stash stat style sync tag tar th_main timeline tkt tktsetup undo update url user utf8 verify vfile wiki wikiformat winhttp wysiwyg xfer xfersetup zip shell sqlite3 th th_lang > $@
           51  +	+echo add allrepo attach bag bisect blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo glob graph gzip http http_socket http_ssl http_transport import info json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_tag json_timeline json_user json_wiki leaf login main manifest markdown markdown_html md5 merge merge3 moderate name path pivot popen pqueue printf rebuild report rss schema search setup sha1 shun skins sqlcmd stash stat style sync tag tar th_main timeline tkt tktsetup undo update url user utf8 verify vfile wiki wikiformat winhttp wysiwyg xfer xfersetup zip shell sqlite3 th th_lang > $@
    52     52   	+echo fossil >> $@
    53     53   	+echo fossil >> $@
    54     54   	+echo $(LIBS) >> $@
    55     55   	+echo. >> $@
    56     56   	+echo fossil >> $@
    57     57   
    58     58   translate$E: $(SRCDIR)\translate.c
................................................................................
   443    443   	+translate$E $** > $@
   444    444   
   445    445   $(OBJDIR)\manifest$O : manifest_.c manifest.h
   446    446   	$(TCC) -o$@ -c manifest_.c
   447    447   
   448    448   manifest_.c : $(SRCDIR)\manifest.c
   449    449   	+translate$E $** > $@
          450  +
          451  +$(OBJDIR)\markdown$O : markdown_.c markdown.h
          452  +	$(TCC) -o$@ -c markdown_.c
          453  +
          454  +markdown_.c : $(SRCDIR)\markdown.c
          455  +	+translate$E $** > $@
          456  +
          457  +$(OBJDIR)\markdown_html$O : markdown_html_.c markdown_html.h
          458  +	$(TCC) -o$@ -c markdown_html_.c
          459  +
          460  +markdown_html_.c : $(SRCDIR)\markdown_html.c
          461  +	+translate$E $** > $@
   450    462   
   451    463   $(OBJDIR)\md5$O : md5_.c md5.h
   452    464   	$(TCC) -o$@ -c md5_.c
   453    465   
   454    466   md5_.c : $(SRCDIR)\md5.c
   455    467   	+translate$E $** > $@
   456    468   
................................................................................
   709    721   $(OBJDIR)\zip$O : zip_.c zip.h
   710    722   	$(TCC) -o$@ -c zip_.c
   711    723   
   712    724   zip_.c : $(SRCDIR)\zip.c
   713    725   	+translate$E $** > $@
   714    726   
   715    727   headers: makeheaders$E page_index.h VERSION.h
   716         -	 +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h moderate_.c:moderate.h name_.c:name.h path_.c:path.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h utf8_.c:utf8.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h wysiwyg_.c:wysiwyg.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h
          728  +	 +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h markdown_.c:markdown.h markdown_html_.c:markdown_html.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h moderate_.c:moderate.h name_.c:name.h path_.c:path.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h utf8_.c:utf8.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h wysiwyg_.c:wysiwyg.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h
   717    729   	@copy /Y nul: headers

Changes to win/Makefile.mingw.

    41     41   #### Enable compiling with debug symbols (much larger binary)
    42     42   #
    43     43   # FOSSIL_ENABLE_SYMBOLS = 1
    44     44   
    45     45   #### Enable JSON (http://www.json.org) support using "cson"
    46     46   #
    47     47   # FOSSIL_ENABLE_JSON = 1
           48  +
           49  +#### Enable markdown support
           50  +#
           51  +# FOSSIL_ENABLE_MARKDOWN = 1
    48     52   
    49     53   #### Enable HTTPS support via OpenSSL (links to libssl and libcrypto)
    50     54   #
    51     55   # FOSSIL_ENABLE_SSL = 1
    52     56   
    53     57   #### Enable scripting support via Tcl/Tk
    54     58   #
................................................................................
   182    186   endif
   183    187   
   184    188   # With JSON support
   185    189   ifdef FOSSIL_ENABLE_JSON
   186    190   TCC += -DFOSSIL_ENABLE_JSON=1
   187    191   RCC += -DFOSSIL_ENABLE_JSON=1
   188    192   endif
          193  +
          194  +# With markdown support
          195  +ifdef FOSSIL_ENABLE_MARKDOWN
          196  +TCC += -DFOSSIL_ENABLE_MARKDOWN=1
          197  +RCC += -DFOSSIL_ENABLE_MARKDOWN=1
          198  +endif
   189    199   
   190    200   #### We add the -static option here so that we can build a static
   191    201   #    executable that will run in a chroot jail.
   192    202   #
   193    203   LIB = -static
   194    204   
   195    205   # MinGW: If available, use the Unicode capable runtime startup code.
................................................................................
   297    307     $(SRCDIR)/json_timeline.c \
   298    308     $(SRCDIR)/json_user.c \
   299    309     $(SRCDIR)/json_wiki.c \
   300    310     $(SRCDIR)/leaf.c \
   301    311     $(SRCDIR)/login.c \
   302    312     $(SRCDIR)/main.c \
   303    313     $(SRCDIR)/manifest.c \
          314  +  $(SRCDIR)/markdown.c \
          315  +  $(SRCDIR)/markdown_html.c \
   304    316     $(SRCDIR)/md5.c \
   305    317     $(SRCDIR)/merge.c \
   306    318     $(SRCDIR)/merge3.c \
   307    319     $(SRCDIR)/moderate.c \
   308    320     $(SRCDIR)/name.c \
   309    321     $(SRCDIR)/path.c \
   310    322     $(SRCDIR)/pivot.c \
................................................................................
   399    411     $(OBJDIR)/json_timeline_.c \
   400    412     $(OBJDIR)/json_user_.c \
   401    413     $(OBJDIR)/json_wiki_.c \
   402    414     $(OBJDIR)/leaf_.c \
   403    415     $(OBJDIR)/login_.c \
   404    416     $(OBJDIR)/main_.c \
   405    417     $(OBJDIR)/manifest_.c \
          418  +  $(OBJDIR)/markdown_.c \
          419  +  $(OBJDIR)/markdown_html_.c \
   406    420     $(OBJDIR)/md5_.c \
   407    421     $(OBJDIR)/merge_.c \
   408    422     $(OBJDIR)/merge3_.c \
   409    423     $(OBJDIR)/moderate_.c \
   410    424     $(OBJDIR)/name_.c \
   411    425     $(OBJDIR)/path_.c \
   412    426     $(OBJDIR)/pivot_.c \
................................................................................
   501    515    $(OBJDIR)/json_timeline.o \
   502    516    $(OBJDIR)/json_user.o \
   503    517    $(OBJDIR)/json_wiki.o \
   504    518    $(OBJDIR)/leaf.o \
   505    519    $(OBJDIR)/login.o \
   506    520    $(OBJDIR)/main.o \
   507    521    $(OBJDIR)/manifest.o \
          522  + $(OBJDIR)/markdown.o \
          523  + $(OBJDIR)/markdown_html.o \
   508    524    $(OBJDIR)/md5.o \
   509    525    $(OBJDIR)/merge.o \
   510    526    $(OBJDIR)/merge3.o \
   511    527    $(OBJDIR)/moderate.o \
   512    528    $(OBJDIR)/name.o \
   513    529    $(OBJDIR)/path.o \
   514    530    $(OBJDIR)/pivot.o \
................................................................................
   660    676   setup: $(OBJDIR) $(APPNAME)
   661    677   	$(MAKENSIS) ./fossil.nsi
   662    678   
   663    679   $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex
   664    680   	$(MKINDEX) $(TRANS_SRC) >$@
   665    681   
   666    682   $(OBJDIR)/headers:	$(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h
   667         -	$(MAKEHEADERS)  $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h $(OBJDIR)/bag_.c:$(OBJDIR)/bag.h $(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h $(OBJDIR)/blob_.c:$(OBJDIR)/blob.h $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/json_.c:$(OBJDIR)/json.h $(OBJDIR)/json_artifact_.c:$(OBJDIR)/json_artifact.h $(OBJDIR)/json_branch_.c:$(OBJDIR)/json_branch.h $(OBJDIR)/json_config_.c:$(OBJDIR)/json_config.h $(OBJDIR)/json_diff_.c:$(OBJDIR)/json_diff.h $(OBJDIR)/json_dir_.c:$(OBJDIR)/json_dir.h $(OBJDIR)/json_finfo_.c:$(OBJDIR)/json_finfo.h $(OBJDIR)/json_login_.c:$(OBJDIR)/json_login.h $(OBJDIR)/json_query_.c:$(OBJDIR)/json_query.h $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/moderate_.c:$(OBJDIR)/moderate.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/wysiwyg_.c:$(OBJDIR)/wysiwyg.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h
          683  +	$(MAKEHEADERS)  $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h $(OBJDIR)/bag_.c:$(OBJDIR)/bag.h $(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h $(OBJDIR)/blob_.c:$(OBJDIR)/blob.h $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/json_.c:$(OBJDIR)/json.h $(OBJDIR)/json_artifact_.c:$(OBJDIR)/json_artifact.h $(OBJDIR)/json_branch_.c:$(OBJDIR)/json_branch.h $(OBJDIR)/json_config_.c:$(OBJDIR)/json_config.h $(OBJDIR)/json_diff_.c:$(OBJDIR)/json_diff.h $(OBJDIR)/json_dir_.c:$(OBJDIR)/json_dir.h $(OBJDIR)/json_finfo_.c:$(OBJDIR)/json_finfo.h $(OBJDIR)/json_login_.c:$(OBJDIR)/json_login.h $(OBJDIR)/json_query_.c:$(OBJDIR)/json_query.h $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/markdown_.c:$(OBJDIR)/markdown.h $(OBJDIR)/markdown_html_.c:$(OBJDIR)/markdown_html.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/moderate_.c:$(OBJDIR)/moderate.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/wysiwyg_.c:$(OBJDIR)/wysiwyg.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h
   668    684   	echo Done >$(OBJDIR)/headers
   669    685   
   670    686   $(OBJDIR)/headers: Makefile
   671    687   
   672    688   Makefile:
   673    689   
   674    690   $(OBJDIR)/add_.c:	$(SRCDIR)/add.c $(OBJDIR)/translate
................................................................................
  1114   1130   $(OBJDIR)/manifest_.c:	$(SRCDIR)/manifest.c $(OBJDIR)/translate
  1115   1131   	$(TRANSLATE) $(SRCDIR)/manifest.c >$(OBJDIR)/manifest_.c
  1116   1132   
  1117   1133   $(OBJDIR)/manifest.o:	$(OBJDIR)/manifest_.c $(OBJDIR)/manifest.h  $(SRCDIR)/config.h
  1118   1134   	$(XTCC) -o $(OBJDIR)/manifest.o -c $(OBJDIR)/manifest_.c
  1119   1135   
  1120   1136   $(OBJDIR)/manifest.h:	$(OBJDIR)/headers
         1137  +
         1138  +$(OBJDIR)/markdown_.c:	$(SRCDIR)/markdown.c $(OBJDIR)/translate
         1139  +	$(TRANSLATE) $(SRCDIR)/markdown.c >$(OBJDIR)/markdown_.c
         1140  +
         1141  +$(OBJDIR)/markdown.o:	$(OBJDIR)/markdown_.c $(OBJDIR)/markdown.h  $(SRCDIR)/config.h
         1142  +	$(XTCC) -o $(OBJDIR)/markdown.o -c $(OBJDIR)/markdown_.c
         1143  +
         1144  +$(OBJDIR)/markdown.h:	$(OBJDIR)/headers
         1145  +
         1146  +$(OBJDIR)/markdown_html_.c:	$(SRCDIR)/markdown_html.c $(OBJDIR)/translate
         1147  +	$(TRANSLATE) $(SRCDIR)/markdown_html.c >$(OBJDIR)/markdown_html_.c
         1148  +
         1149  +$(OBJDIR)/markdown_html.o:	$(OBJDIR)/markdown_html_.c $(OBJDIR)/markdown_html.h  $(SRCDIR)/config.h
         1150  +	$(XTCC) -o $(OBJDIR)/markdown_html.o -c $(OBJDIR)/markdown_html_.c
         1151  +
         1152  +$(OBJDIR)/markdown_html.h:	$(OBJDIR)/headers
  1121   1153   
  1122   1154   $(OBJDIR)/md5_.c:	$(SRCDIR)/md5.c $(OBJDIR)/translate
  1123   1155   	$(TRANSLATE) $(SRCDIR)/md5.c >$(OBJDIR)/md5_.c
  1124   1156   
  1125   1157   $(OBJDIR)/md5.o:	$(OBJDIR)/md5_.c $(OBJDIR)/md5.h  $(SRCDIR)/config.h
  1126   1158   	$(XTCC) -o $(OBJDIR)/md5.o -c $(OBJDIR)/md5_.c
  1127   1159   

Changes to win/Makefile.mingw.mistachkin.

    36     36   #    to compile code-generator programs as part of the build process.
    37     37   #    See TCC below for the C compiler for building the finished binary.
    38     38   #
    39     39   BCC = gcc
    40     40   
    41     41   #### Enable compiling with debug symbols (much larger binary)
    42     42   #
    43         -# FOSSIL_ENABLE_SYMBOLS = 1
           43  +FOSSIL_ENABLE_SYMBOLS = 1
    44     44   
    45     45   #### Enable JSON (http://www.json.org) support using "cson"
    46     46   #
    47     47   FOSSIL_ENABLE_JSON = 1
           48  +
           49  +#### Enable markdown support
           50  +#
           51  +FOSSIL_ENABLE_MARKDOWN = 1
    48     52   
    49     53   #### Enable HTTPS support via OpenSSL (links to libssl and libcrypto)
    50     54   #
    51     55   FOSSIL_ENABLE_SSL = 1
    52     56   
    53     57   #### Enable scripting support via Tcl/Tk
    54     58   #
................................................................................
   182    186   endif
   183    187   
   184    188   # With JSON support
   185    189   ifdef FOSSIL_ENABLE_JSON
   186    190   TCC += -DFOSSIL_ENABLE_JSON=1
   187    191   RCC += -DFOSSIL_ENABLE_JSON=1
   188    192   endif
          193  +
          194  +# With markdown support
          195  +ifdef FOSSIL_ENABLE_MARKDOWN
          196  +TCC += -DFOSSIL_ENABLE_MARKDOWN=1
          197  +RCC += -DFOSSIL_ENABLE_MARKDOWN=1
          198  +endif
   189    199   
   190    200   #### We add the -static option here so that we can build a static
   191    201   #    executable that will run in a chroot jail.
   192    202   #
   193    203   LIB = -static
   194    204   
   195    205   # MinGW: If available, use the Unicode capable runtime startup code.
................................................................................
   297    307     $(SRCDIR)/json_timeline.c \
   298    308     $(SRCDIR)/json_user.c \
   299    309     $(SRCDIR)/json_wiki.c \
   300    310     $(SRCDIR)/leaf.c \
   301    311     $(SRCDIR)/login.c \
   302    312     $(SRCDIR)/main.c \
   303    313     $(SRCDIR)/manifest.c \
          314  +  $(SRCDIR)/markdown.c \
          315  +  $(SRCDIR)/markdown_html.c \
   304    316     $(SRCDIR)/md5.c \
   305    317     $(SRCDIR)/merge.c \
   306    318     $(SRCDIR)/merge3.c \
   307    319     $(SRCDIR)/moderate.c \
   308    320     $(SRCDIR)/name.c \
   309    321     $(SRCDIR)/path.c \
   310    322     $(SRCDIR)/pivot.c \
................................................................................
   399    411     $(OBJDIR)/json_timeline_.c \
   400    412     $(OBJDIR)/json_user_.c \
   401    413     $(OBJDIR)/json_wiki_.c \
   402    414     $(OBJDIR)/leaf_.c \
   403    415     $(OBJDIR)/login_.c \
   404    416     $(OBJDIR)/main_.c \
   405    417     $(OBJDIR)/manifest_.c \
          418  +  $(OBJDIR)/markdown_.c \
          419  +  $(OBJDIR)/markdown_html_.c \
   406    420     $(OBJDIR)/md5_.c \
   407    421     $(OBJDIR)/merge_.c \
   408    422     $(OBJDIR)/merge3_.c \
   409    423     $(OBJDIR)/moderate_.c \
   410    424     $(OBJDIR)/name_.c \
   411    425     $(OBJDIR)/path_.c \
   412    426     $(OBJDIR)/pivot_.c \
................................................................................
   501    515    $(OBJDIR)/json_timeline.o \
   502    516    $(OBJDIR)/json_user.o \
   503    517    $(OBJDIR)/json_wiki.o \
   504    518    $(OBJDIR)/leaf.o \
   505    519    $(OBJDIR)/login.o \
   506    520    $(OBJDIR)/main.o \
   507    521    $(OBJDIR)/manifest.o \
          522  + $(OBJDIR)/markdown.o \
          523  + $(OBJDIR)/markdown_html.o \
   508    524    $(OBJDIR)/md5.o \
   509    525    $(OBJDIR)/merge.o \
   510    526    $(OBJDIR)/merge3.o \
   511    527    $(OBJDIR)/moderate.o \
   512    528    $(OBJDIR)/name.o \
   513    529    $(OBJDIR)/path.o \
   514    530    $(OBJDIR)/pivot.o \
................................................................................
   660    676   setup: $(OBJDIR) $(APPNAME)
   661    677   	$(MAKENSIS) ./fossil.nsi
   662    678   
   663    679   $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex
   664    680   	$(MKINDEX) $(TRANS_SRC) >$@
   665    681   
   666    682   $(OBJDIR)/headers:	$(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h
   667         -	$(MAKEHEADERS)  $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h $(OBJDIR)/bag_.c:$(OBJDIR)/bag.h $(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h $(OBJDIR)/blob_.c:$(OBJDIR)/blob.h $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/json_.c:$(OBJDIR)/json.h $(OBJDIR)/json_artifact_.c:$(OBJDIR)/json_artifact.h $(OBJDIR)/json_branch_.c:$(OBJDIR)/json_branch.h $(OBJDIR)/json_config_.c:$(OBJDIR)/json_config.h $(OBJDIR)/json_diff_.c:$(OBJDIR)/json_diff.h $(OBJDIR)/json_dir_.c:$(OBJDIR)/json_dir.h $(OBJDIR)/json_finfo_.c:$(OBJDIR)/json_finfo.h $(OBJDIR)/json_login_.c:$(OBJDIR)/json_login.h $(OBJDIR)/json_query_.c:$(OBJDIR)/json_query.h $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/moderate_.c:$(OBJDIR)/moderate.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/wysiwyg_.c:$(OBJDIR)/wysiwyg.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h
          683  +	$(MAKEHEADERS)  $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h $(OBJDIR)/bag_.c:$(OBJDIR)/bag.h $(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h $(OBJDIR)/blob_.c:$(OBJDIR)/blob.h $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/json_.c:$(OBJDIR)/json.h $(OBJDIR)/json_artifact_.c:$(OBJDIR)/json_artifact.h $(OBJDIR)/json_branch_.c:$(OBJDIR)/json_branch.h $(OBJDIR)/json_config_.c:$(OBJDIR)/json_config.h $(OBJDIR)/json_diff_.c:$(OBJDIR)/json_diff.h $(OBJDIR)/json_dir_.c:$(OBJDIR)/json_dir.h $(OBJDIR)/json_finfo_.c:$(OBJDIR)/json_finfo.h $(OBJDIR)/json_login_.c:$(OBJDIR)/json_login.h $(OBJDIR)/json_query_.c:$(OBJDIR)/json_query.h $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/markdown_.c:$(OBJDIR)/markdown.h $(OBJDIR)/markdown_html_.c:$(OBJDIR)/markdown_html.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/moderate_.c:$(OBJDIR)/moderate.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/wysiwyg_.c:$(OBJDIR)/wysiwyg.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h
   668    684   	echo Done >$(OBJDIR)/headers
   669    685   
   670    686   $(OBJDIR)/headers: Makefile
   671    687   
   672    688   Makefile:
   673    689   
   674    690   $(OBJDIR)/add_.c:	$(SRCDIR)/add.c $(OBJDIR)/translate
................................................................................
  1114   1130   $(OBJDIR)/manifest_.c:	$(SRCDIR)/manifest.c $(OBJDIR)/translate
  1115   1131   	$(TRANSLATE) $(SRCDIR)/manifest.c >$(OBJDIR)/manifest_.c
  1116   1132   
  1117   1133   $(OBJDIR)/manifest.o:	$(OBJDIR)/manifest_.c $(OBJDIR)/manifest.h  $(SRCDIR)/config.h
  1118   1134   	$(XTCC) -o $(OBJDIR)/manifest.o -c $(OBJDIR)/manifest_.c
  1119   1135   
  1120   1136   $(OBJDIR)/manifest.h:	$(OBJDIR)/headers
         1137  +
         1138  +$(OBJDIR)/markdown_.c:	$(SRCDIR)/markdown.c $(OBJDIR)/translate
         1139  +	$(TRANSLATE) $(SRCDIR)/markdown.c >$(OBJDIR)/markdown_.c
         1140  +
         1141  +$(OBJDIR)/markdown.o:	$(OBJDIR)/markdown_.c $(OBJDIR)/markdown.h  $(SRCDIR)/config.h
         1142  +	$(XTCC) -o $(OBJDIR)/markdown.o -c $(OBJDIR)/markdown_.c
         1143  +
         1144  +$(OBJDIR)/markdown.h:	$(OBJDIR)/headers
         1145  +
         1146  +$(OBJDIR)/markdown_html_.c:	$(SRCDIR)/markdown_html.c $(OBJDIR)/translate
         1147  +	$(TRANSLATE) $(SRCDIR)/markdown_html.c >$(OBJDIR)/markdown_html_.c
         1148  +
         1149  +$(OBJDIR)/markdown_html.o:	$(OBJDIR)/markdown_html_.c $(OBJDIR)/markdown_html.h  $(SRCDIR)/config.h
         1150  +	$(XTCC) -o $(OBJDIR)/markdown_html.o -c $(OBJDIR)/markdown_html_.c
         1151  +
         1152  +$(OBJDIR)/markdown_html.h:	$(OBJDIR)/headers
  1121   1153   
  1122   1154   $(OBJDIR)/md5_.c:	$(SRCDIR)/md5.c $(OBJDIR)/translate
  1123   1155   	$(TRANSLATE) $(SRCDIR)/md5.c >$(OBJDIR)/md5_.c
  1124   1156   
  1125   1157   $(OBJDIR)/md5.o:	$(OBJDIR)/md5_.c $(OBJDIR)/md5.h  $(SRCDIR)/config.h
  1126   1158   	$(XTCC) -o $(OBJDIR)/md5.o -c $(OBJDIR)/md5_.c
  1127   1159   

Changes to win/Makefile.msc.

    92     92           json_timeline_.c \
    93     93           json_user_.c \
    94     94           json_wiki_.c \
    95     95           leaf_.c \
    96     96           login_.c \
    97     97           main_.c \
    98     98           manifest_.c \
           99  +        markdown_.c \
          100  +        markdown_html_.c \
    99    101           md5_.c \
   100    102           merge_.c \
   101    103           merge3_.c \
   102    104           moderate_.c \
   103    105           name_.c \
   104    106           path_.c \
   105    107           pivot_.c \
................................................................................
   193    195           $(OX)\json_timeline$O \
   194    196           $(OX)\json_user$O \
   195    197           $(OX)\json_wiki$O \
   196    198           $(OX)\leaf$O \
   197    199           $(OX)\login$O \
   198    200           $(OX)\main$O \
   199    201           $(OX)\manifest$O \
          202  +        $(OX)\markdown$O \
          203  +        $(OX)\markdown_html$O \
   200    204           $(OX)\md5$O \
   201    205           $(OX)\merge$O \
   202    206           $(OX)\merge3$O \
   203    207           $(OX)\moderate$O \
   204    208           $(OX)\name$O \
   205    209           $(OX)\path$O \
   206    210           $(OX)\pivot$O \
................................................................................
   311    315   	echo $(OX)\json_timeline.obj >> $@
   312    316   	echo $(OX)\json_user.obj >> $@
   313    317   	echo $(OX)\json_wiki.obj >> $@
   314    318   	echo $(OX)\leaf.obj >> $@
   315    319   	echo $(OX)\login.obj >> $@
   316    320   	echo $(OX)\main.obj >> $@
   317    321   	echo $(OX)\manifest.obj >> $@
          322  +	echo $(OX)\markdown.obj >> $@
          323  +	echo $(OX)\markdown_html.obj >> $@
   318    324   	echo $(OX)\md5.obj >> $@
   319    325   	echo $(OX)\merge.obj >> $@
   320    326   	echo $(OX)\merge3.obj >> $@
   321    327   	echo $(OX)\moderate.obj >> $@
   322    328   	echo $(OX)\name.obj >> $@
   323    329   	echo $(OX)\path.obj >> $@
   324    330   	echo $(OX)\pivot.obj >> $@
................................................................................
   767    773   	translate$E $** > $@
   768    774   
   769    775   $(OX)\manifest$O : manifest_.c manifest.h
   770    776   	$(TCC) /Fo$@ -c manifest_.c
   771    777   
   772    778   manifest_.c : $(SRCDIR)\manifest.c
   773    779   	translate$E $** > $@
          780  +
          781  +$(OX)\markdown$O : markdown_.c markdown.h
          782  +	$(TCC) /Fo$@ -c markdown_.c
          783  +
          784  +markdown_.c : $(SRCDIR)\markdown.c
          785  +	translate$E $** > $@
          786  +
          787  +$(OX)\markdown_html$O : markdown_html_.c markdown_html.h
          788  +	$(TCC) /Fo$@ -c markdown_html_.c
          789  +
          790  +markdown_html_.c : $(SRCDIR)\markdown_html.c
          791  +	translate$E $** > $@
   774    792   
   775    793   $(OX)\md5$O : md5_.c md5.h
   776    794   	$(TCC) /Fo$@ -c md5_.c
   777    795   
   778    796   md5_.c : $(SRCDIR)\md5.c
   779    797   	translate$E $** > $@
   780    798   
................................................................................
  1089   1107   			json_timeline_.c:json_timeline.h \
  1090   1108   			json_user_.c:json_user.h \
  1091   1109   			json_wiki_.c:json_wiki.h \
  1092   1110   			leaf_.c:leaf.h \
  1093   1111   			login_.c:login.h \
  1094   1112   			main_.c:main.h \
  1095   1113   			manifest_.c:manifest.h \
         1114  +			markdown_.c:markdown.h \
         1115  +			markdown_html_.c:markdown_html.h \
  1096   1116   			md5_.c:md5.h \
  1097   1117   			merge_.c:merge.h \
  1098   1118   			merge3_.c:merge3.h \
  1099   1119   			moderate_.c:moderate.h \
  1100   1120   			name_.c:name.h \
  1101   1121   			path_.c:path.h \
  1102   1122   			pivot_.c:pivot.h \