add some tests - webdump_tests - Testfiles for webdump
 (HTM) git clone git://git.codemadness.org/webdump_tests
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
       ---
 (DIR) commit 5a6db78a46e4f5742799fcfefc2e2580860db3ef
 (DIR) parent 5f5b757714a91ec9e436533b128112fb1aca0422
 (HTM) Author: Hiltjo Posthuma <hiltjo@codemadness.org>
       Date:   Tue, 22 Aug 2023 16:35:37 +0200
       
       add some tests
       
       Diffstat:
         A realworld/stagit_file.html          |    1106 +++++++++++++++++++++++++++++++
         A tests/indent.html                   |      47 +++++++++++++++++++++++++++++++
         M tests/pre.html                      |      46 ++++++++++++++++++-------------
         A tests/pre_code.html                 |       3 +++
       
       4 files changed, 1183 insertions(+), 19 deletions(-)
       ---
 (DIR) diff --git a/realworld/stagit_file.html b/realworld/stagit_file.html
       @@ -0,0 +1,1106 @@
       +<!DOCTYPE html>
       +<html>
       +<head>
       +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
       +<meta name="viewport" content="width=device-width, initial-scale=1" />
       +<title>sfeed.c - sfeed - RSS and Atom parser
       +</title>
       +<link rel="icon" type="image/png" href="../favicon.png" />
       +<link rel="alternate" type="application/atom+xml" title="sfeed Atom Feed" href="../atom.xml" />
       +<link rel="alternate" type="application/atom+xml" title="sfeed Atom Feed (tags)" href="../tags.xml" />
       +<link rel="stylesheet" type="text/css" href="../style.css" />
       +</head>
       +<body>
       +<table><tr><td><a href="../../"><img src="../logo.png" alt="" width="32" height="32" /></a></td><td><h1>sfeed</h1><span class="desc">RSS and Atom parser
       +</span></td></tr><tr class="url"><td></td><td>git clone <a href="git://git.codemadness.org/sfeed">git://git.codemadness.org/sfeed</a></td></tr><tr><td></td><td>
       +<a href="../log.html">Log</a> | <a href="../files.html">Files</a> | <a href="../refs.html">Refs</a> | <a href="../file/README.html">README</a> | <a href="../file/LICENSE.html">LICENSE</a></td></tr></table>
       +<hr/>
       +<div id="content">
       +<p> sfeed.c (30040B)</p><hr/><pre id="blob">
       +<a href="#l1" class="line" id="l1">      1</a> #include &lt;errno.h&gt;
       +<a href="#l2" class="line" id="l2">      2</a> #include &lt;stdint.h&gt;
       +<a href="#l3" class="line" id="l3">      3</a> #include &lt;stdio.h&gt;
       +<a href="#l4" class="line" id="l4">      4</a> #include &lt;stdlib.h&gt;
       +<a href="#l5" class="line" id="l5">      5</a> #include &lt;string.h&gt;
       +<a href="#l6" class="line" id="l6">      6</a> #include &lt;strings.h&gt;
       +<a href="#l7" class="line" id="l7">      7</a> 
       +<a href="#l8" class="line" id="l8">      8</a> #include &quot;util.h&quot;
       +<a href="#l9" class="line" id="l9">      9</a> #include &quot;xml.h&quot;
       +<a href="#l10" class="line" id="l10">     10</a> 
       +<a href="#l11" class="line" id="l11">     11</a> #define ISINCONTENT(ctx)  ((ctx).iscontent &amp;&amp; !((ctx).iscontenttag))
       +<a href="#l12" class="line" id="l12">     12</a> #define ISCONTENTTAG(ctx) (!((ctx).iscontent) &amp;&amp; (ctx).iscontenttag)
       +<a href="#l13" class="line" id="l13">     13</a> 
       +<a href="#l14" class="line" id="l14">     14</a> /* these feed fields support multiple separated values */
       +<a href="#l15" class="line" id="l15">     15</a> #define ISFEEDFIELDMULTI(t) ((t) == FeedFieldCategory)
       +<a href="#l16" class="line" id="l16">     16</a> 
       +<a href="#l17" class="line" id="l17">     17</a> /* string and byte-length */
       +<a href="#l18" class="line" id="l18">     18</a> #define STRP(s)           s,sizeof(s)-1
       +<a href="#l19" class="line" id="l19">     19</a> 
       +<a href="#l20" class="line" id="l20">     20</a> enum FeedType {
       +<a href="#l21" class="line" id="l21">     21</a>         FeedTypeNone = 0,
       +<a href="#l22" class="line" id="l22">     22</a>         FeedTypeRSS  = 1,
       +<a href="#l23" class="line" id="l23">     23</a>         FeedTypeAtom = 2
       +<a href="#l24" class="line" id="l24">     24</a> };
       +<a href="#l25" class="line" id="l25">     25</a> 
       +<a href="#l26" class="line" id="l26">     26</a> enum ContentType {
       +<a href="#l27" class="line" id="l27">     27</a>         ContentTypeNone  = 0,
       +<a href="#l28" class="line" id="l28">     28</a>         ContentTypePlain = 1,
       +<a href="#l29" class="line" id="l29">     29</a>         ContentTypeHTML  = 2
       +<a href="#l30" class="line" id="l30">     30</a> };
       +<a href="#l31" class="line" id="l31">     31</a> static const char *contenttypes[] = { &quot;&quot;, &quot;plain&quot;, &quot;html&quot; };
       +<a href="#l32" class="line" id="l32">     32</a> 
       +<a href="#l33" class="line" id="l33">     33</a> /* String data / memory pool */
       +<a href="#l34" class="line" id="l34">     34</a> typedef struct string {
       +<a href="#l35" class="line" id="l35">     35</a>         char   *data;   /* data */
       +<a href="#l36" class="line" id="l36">     36</a>         size_t  len;    /* string length */
       +<a href="#l37" class="line" id="l37">     37</a>         size_t  bufsiz; /* allocated size */
       +<a href="#l38" class="line" id="l38">     38</a> } String;
       +<a href="#l39" class="line" id="l39">     39</a> 
       +<a href="#l40" class="line" id="l40">     40</a> /* NOTE: the order of these fields (content, date, author) indicate the
       +<a href="#l41" class="line" id="l41">     41</a>  *       priority to use them, from least important to high. */
       +<a href="#l42" class="line" id="l42">     42</a> enum TagId {
       +<a href="#l43" class="line" id="l43">     43</a>         TagUnknown = 0,
       +<a href="#l44" class="line" id="l44">     44</a>         /* RSS */
       +<a href="#l45" class="line" id="l45">     45</a>         RSSTagDcdate, RSSTagPubdate, /* creation date has higher priority */
       +<a href="#l46" class="line" id="l46">     46</a>         RSSTagTitle,
       +<a href="#l47" class="line" id="l47">     47</a>         RSSTagMediaDescription, RSSTagDescription, RSSTagContentEncoded,
       +<a href="#l48" class="line" id="l48">     48</a>         RSSTagGuid,
       +<a href="#l49" class="line" id="l49">     49</a>         RSSTagGuidPermalinkFalse,
       +<a href="#l50" class="line" id="l50">     50</a>         RSSTagGuidPermalinkTrue,
       +<a href="#l51" class="line" id="l51">     51</a>         /* must be defined after GUID, because it can be a link (isPermaLink) */
       +<a href="#l52" class="line" id="l52">     52</a>         RSSTagLink,
       +<a href="#l53" class="line" id="l53">     53</a>         RSSTagEnclosure,
       +<a href="#l54" class="line" id="l54">     54</a>         RSSTagAuthor, RSSTagDccreator,
       +<a href="#l55" class="line" id="l55">     55</a>         RSSTagCategory,
       +<a href="#l56" class="line" id="l56">     56</a>         /* Atom */
       +<a href="#l57" class="line" id="l57">     57</a>         /* creation date has higher priority */
       +<a href="#l58" class="line" id="l58">     58</a>         AtomTagModified, AtomTagUpdated, AtomTagIssued, AtomTagPublished,
       +<a href="#l59" class="line" id="l59">     59</a>         AtomTagTitle,
       +<a href="#l60" class="line" id="l60">     60</a>         AtomTagMediaDescription, AtomTagSummary, AtomTagContent,
       +<a href="#l61" class="line" id="l61">     61</a>         AtomTagId,
       +<a href="#l62" class="line" id="l62">     62</a>         AtomTagLink,
       +<a href="#l63" class="line" id="l63">     63</a>         AtomTagLinkAlternate,
       +<a href="#l64" class="line" id="l64">     64</a>         AtomTagLinkEnclosure,
       +<a href="#l65" class="line" id="l65">     65</a>         AtomTagAuthor, AtomTagAuthorName,
       +<a href="#l66" class="line" id="l66">     66</a>         AtomTagCategory,
       +<a href="#l67" class="line" id="l67">     67</a>         TagLast
       +<a href="#l68" class="line" id="l68">     68</a> };
       +<a href="#l69" class="line" id="l69">     69</a> 
       +<a href="#l70" class="line" id="l70">     70</a> typedef struct feedtag {
       +<a href="#l71" class="line" id="l71">     71</a>         char       *name; /* name of tag to match */
       +<a href="#l72" class="line" id="l72">     72</a>         size_t      len;  /* len of `name` */
       +<a href="#l73" class="line" id="l73">     73</a>         enum TagId  id;   /* unique ID */
       +<a href="#l74" class="line" id="l74">     74</a> } FeedTag;
       +<a href="#l75" class="line" id="l75">     75</a> 
       +<a href="#l76" class="line" id="l76">     76</a> typedef struct field {
       +<a href="#l77" class="line" id="l77">     77</a>         String     str;
       +<a href="#l78" class="line" id="l78">     78</a>         enum TagId tagid; /* tagid set previously, used for tag priority */
       +<a href="#l79" class="line" id="l79">     79</a> } FeedField;
       +<a href="#l80" class="line" id="l80">     80</a> 
       +<a href="#l81" class="line" id="l81">     81</a> enum {
       +<a href="#l82" class="line" id="l82">     82</a>         FeedFieldTime = 0, FeedFieldTitle, FeedFieldLink, FeedFieldContent,
       +<a href="#l83" class="line" id="l83">     83</a>         FeedFieldId, FeedFieldAuthor, FeedFieldEnclosure, FeedFieldCategory,
       +<a href="#l84" class="line" id="l84">     84</a>         FeedFieldLast
       +<a href="#l85" class="line" id="l85">     85</a> };
       +<a href="#l86" class="line" id="l86">     86</a> 
       +<a href="#l87" class="line" id="l87">     87</a> typedef struct feedcontext {
       +<a href="#l88" class="line" id="l88">     88</a>         String          *field;        /* current FeedItem field String */
       +<a href="#l89" class="line" id="l89">     89</a>         FeedField        fields[FeedFieldLast]; /* data for current item */
       +<a href="#l90" class="line" id="l90">     90</a>         FeedTag          tag;          /* unique current parsed tag */
       +<a href="#l91" class="line" id="l91">     91</a>         int              iscontent;    /* in content data */
       +<a href="#l92" class="line" id="l92">     92</a>         int              iscontenttag; /* in content tag */
       +<a href="#l93" class="line" id="l93">     93</a>         enum ContentType contenttype;  /* content-type for item */
       +<a href="#l94" class="line" id="l94">     94</a>         enum FeedType    feedtype;
       +<a href="#l95" class="line" id="l95">     95</a>         int              attrcount;    /* count item HTML element attributes */
       +<a href="#l96" class="line" id="l96">     96</a> } FeedContext;
       +<a href="#l97" class="line" id="l97">     97</a> 
       +<a href="#l98" class="line" id="l98">     98</a> static long long datetounix(long long, int, int, int, int, int);
       +<a href="#l99" class="line" id="l99">     99</a> static FeedTag * gettag(enum FeedType, const char *, size_t);
       +<a href="#l100" class="line" id="l100">    100</a> static long gettzoffset(const char *);
       +<a href="#l101" class="line" id="l101">    101</a> static int  isattr(const char *, size_t, const char *, size_t);
       +<a href="#l102" class="line" id="l102">    102</a> static int  istag(const char *, size_t, const char *, size_t);
       +<a href="#l103" class="line" id="l103">    103</a> static int  parsetime(const char *, long long *);
       +<a href="#l104" class="line" id="l104">    104</a> static void printfields(void);
       +<a href="#l105" class="line" id="l105">    105</a> static void string_append(String *, const char *, size_t);
       +<a href="#l106" class="line" id="l106">    106</a> static void string_buffer_realloc(String *, size_t);
       +<a href="#l107" class="line" id="l107">    107</a> static void string_clear(String *);
       +<a href="#l108" class="line" id="l108">    108</a> static void string_print_encoded(String *);
       +<a href="#l109" class="line" id="l109">    109</a> static void string_print_timestamp(String *);
       +<a href="#l110" class="line" id="l110">    110</a> static void string_print_trimmed(String *);
       +<a href="#l111" class="line" id="l111">    111</a> static void string_print_trimmed_multi(String *);
       +<a href="#l112" class="line" id="l112">    112</a> static void string_print_uri(String *);
       +<a href="#l113" class="line" id="l113">    113</a> static void xmlattr(XMLParser *, const char *, size_t, const char *, size_t,
       +<a href="#l114" class="line" id="l114">    114</a>                     const char *, size_t);
       +<a href="#l115" class="line" id="l115">    115</a> static void xmlattrentity(XMLParser *, const char *, size_t, const char *,
       +<a href="#l116" class="line" id="l116">    116</a>                           size_t, const char *, size_t);
       +<a href="#l117" class="line" id="l117">    117</a> static void xmlattrend(XMLParser *, const char *, size_t, const char *,
       +<a href="#l118" class="line" id="l118">    118</a>                        size_t);
       +<a href="#l119" class="line" id="l119">    119</a> static void xmlattrstart(XMLParser *, const char *, size_t, const char *,
       +<a href="#l120" class="line" id="l120">    120</a>                          size_t);
       +<a href="#l121" class="line" id="l121">    121</a> static void xmldata(XMLParser *, const char *, size_t);
       +<a href="#l122" class="line" id="l122">    122</a> static void xmldataentity(XMLParser *, const char *, size_t);
       +<a href="#l123" class="line" id="l123">    123</a> static void xmltagend(XMLParser *, const char *, size_t, int);
       +<a href="#l124" class="line" id="l124">    124</a> static void xmltagstart(XMLParser *, const char *, size_t);
       +<a href="#l125" class="line" id="l125">    125</a> static void xmltagstartparsed(XMLParser *, const char *, size_t, int);
       +<a href="#l126" class="line" id="l126">    126</a> 
       +<a href="#l127" class="line" id="l127">    127</a> /* map tag name to TagId type */
       +<a href="#l128" class="line" id="l128">    128</a> /* RSS, must be alphabetical order */
       +<a href="#l129" class="line" id="l129">    129</a> static const FeedTag rsstags[] = {
       +<a href="#l130" class="line" id="l130">    130</a>         { STRP(&quot;author&quot;),            RSSTagAuthor            },
       +<a href="#l131" class="line" id="l131">    131</a>         { STRP(&quot;category&quot;),          RSSTagCategory          },
       +<a href="#l132" class="line" id="l132">    132</a>         { STRP(&quot;content:encoded&quot;),   RSSTagContentEncoded    },
       +<a href="#l133" class="line" id="l133">    133</a>         { STRP(&quot;dc:creator&quot;),        RSSTagDccreator         },
       +<a href="#l134" class="line" id="l134">    134</a>         { STRP(&quot;dc:date&quot;),           RSSTagDcdate            },
       +<a href="#l135" class="line" id="l135">    135</a>         { STRP(&quot;description&quot;),       RSSTagDescription       },
       +<a href="#l136" class="line" id="l136">    136</a>         /* RSS: &lt;enclosure url=&quot;&quot; /&gt;, Atom has &lt;link rel=&quot;enclosure&quot; /&gt; */
       +<a href="#l137" class="line" id="l137">    137</a>         { STRP(&quot;enclosure&quot;),         RSSTagEnclosure         },
       +<a href="#l138" class="line" id="l138">    138</a>         { STRP(&quot;guid&quot;),              RSSTagGuid              },
       +<a href="#l139" class="line" id="l139">    139</a>         { STRP(&quot;link&quot;),              RSSTagLink              },
       +<a href="#l140" class="line" id="l140">    140</a>         { STRP(&quot;media:description&quot;), RSSTagMediaDescription  },
       +<a href="#l141" class="line" id="l141">    141</a>         { STRP(&quot;pubdate&quot;),           RSSTagPubdate           },
       +<a href="#l142" class="line" id="l142">    142</a>         { STRP(&quot;title&quot;),             RSSTagTitle             }
       +<a href="#l143" class="line" id="l143">    143</a> };
       +<a href="#l144" class="line" id="l144">    144</a> 
       +<a href="#l145" class="line" id="l145">    145</a> /* Atom, must be alphabetical order */
       +<a href="#l146" class="line" id="l146">    146</a> static const FeedTag atomtags[] = {
       +<a href="#l147" class="line" id="l147">    147</a>         { STRP(&quot;author&quot;),            AtomTagAuthor           },
       +<a href="#l148" class="line" id="l148">    148</a>         { STRP(&quot;category&quot;),          AtomTagCategory         },
       +<a href="#l149" class="line" id="l149">    149</a>         { STRP(&quot;content&quot;),           AtomTagContent          },
       +<a href="#l150" class="line" id="l150">    150</a>         { STRP(&quot;id&quot;),                AtomTagId               },
       +<a href="#l151" class="line" id="l151">    151</a>         { STRP(&quot;issued&quot;),            AtomTagIssued           }, /* Atom 0.3 */
       +<a href="#l152" class="line" id="l152">    152</a>         /* Atom: &lt;link href=&quot;&quot; /&gt;, RSS has &lt;link&gt;&lt;/link&gt; */
       +<a href="#l153" class="line" id="l153">    153</a>         { STRP(&quot;link&quot;),              AtomTagLink             },
       +<a href="#l154" class="line" id="l154">    154</a>         { STRP(&quot;media:description&quot;), AtomTagMediaDescription },
       +<a href="#l155" class="line" id="l155">    155</a>         { STRP(&quot;modified&quot;),          AtomTagModified         }, /* Atom 0.3 */
       +<a href="#l156" class="line" id="l156">    156</a>         { STRP(&quot;published&quot;),         AtomTagPublished        },
       +<a href="#l157" class="line" id="l157">    157</a>         { STRP(&quot;summary&quot;),           AtomTagSummary          },
       +<a href="#l158" class="line" id="l158">    158</a>         { STRP(&quot;title&quot;),             AtomTagTitle            },
       +<a href="#l159" class="line" id="l159">    159</a>         { STRP(&quot;updated&quot;),           AtomTagUpdated          }
       +<a href="#l160" class="line" id="l160">    160</a> };
       +<a href="#l161" class="line" id="l161">    161</a> 
       +<a href="#l162" class="line" id="l162">    162</a> /* special case: nested &lt;author&gt;&lt;name&gt; */
       +<a href="#l163" class="line" id="l163">    163</a> static const FeedTag atomtagauthor = { STRP(&quot;author&quot;), AtomTagAuthor };
       +<a href="#l164" class="line" id="l164">    164</a> static const FeedTag atomtagauthorname = { STRP(&quot;name&quot;), AtomTagAuthorName };
       +<a href="#l165" class="line" id="l165">    165</a> 
       +<a href="#l166" class="line" id="l166">    166</a> /* reference to no / unknown tag */
       +<a href="#l167" class="line" id="l167">    167</a> static const FeedTag notag = { STRP(&quot;&quot;), TagUnknown };
       +<a href="#l168" class="line" id="l168">    168</a> 
       +<a href="#l169" class="line" id="l169">    169</a> /* map TagId type to RSS/Atom field, all tags must be defined */
       +<a href="#l170" class="line" id="l170">    170</a> static const int fieldmap[TagLast] = {
       +<a href="#l171" class="line" id="l171">    171</a>         [TagUnknown]               = -1,
       +<a href="#l172" class="line" id="l172">    172</a>         /* RSS */
       +<a href="#l173" class="line" id="l173">    173</a>         [RSSTagDcdate]             = FeedFieldTime,
       +<a href="#l174" class="line" id="l174">    174</a>         [RSSTagPubdate]            = FeedFieldTime,
       +<a href="#l175" class="line" id="l175">    175</a>         [RSSTagTitle]              = FeedFieldTitle,
       +<a href="#l176" class="line" id="l176">    176</a>         [RSSTagMediaDescription]   = FeedFieldContent,
       +<a href="#l177" class="line" id="l177">    177</a>         [RSSTagDescription]        = FeedFieldContent,
       +<a href="#l178" class="line" id="l178">    178</a>         [RSSTagContentEncoded]     = FeedFieldContent,
       +<a href="#l179" class="line" id="l179">    179</a>         [RSSTagGuid]               = -1,
       +<a href="#l180" class="line" id="l180">    180</a>         [RSSTagGuidPermalinkFalse] = FeedFieldId,
       +<a href="#l181" class="line" id="l181">    181</a>         [RSSTagGuidPermalinkTrue]  = FeedFieldId, /* special-case: both a link and an id */
       +<a href="#l182" class="line" id="l182">    182</a>         [RSSTagLink]               = FeedFieldLink,
       +<a href="#l183" class="line" id="l183">    183</a>         [RSSTagEnclosure]          = FeedFieldEnclosure,
       +<a href="#l184" class="line" id="l184">    184</a>         [RSSTagAuthor]             = FeedFieldAuthor,
       +<a href="#l185" class="line" id="l185">    185</a>         [RSSTagDccreator]          = FeedFieldAuthor,
       +<a href="#l186" class="line" id="l186">    186</a>         [RSSTagCategory]           = FeedFieldCategory,
       +<a href="#l187" class="line" id="l187">    187</a>         /* Atom */
       +<a href="#l188" class="line" id="l188">    188</a>         [AtomTagModified]          = FeedFieldTime,
       +<a href="#l189" class="line" id="l189">    189</a>         [AtomTagUpdated]           = FeedFieldTime,
       +<a href="#l190" class="line" id="l190">    190</a>         [AtomTagIssued]            = FeedFieldTime,
       +<a href="#l191" class="line" id="l191">    191</a>         [AtomTagPublished]         = FeedFieldTime,
       +<a href="#l192" class="line" id="l192">    192</a>         [AtomTagTitle]             = FeedFieldTitle,
       +<a href="#l193" class="line" id="l193">    193</a>         [AtomTagMediaDescription]  = FeedFieldContent,
       +<a href="#l194" class="line" id="l194">    194</a>         [AtomTagSummary]           = FeedFieldContent,
       +<a href="#l195" class="line" id="l195">    195</a>         [AtomTagContent]           = FeedFieldContent,
       +<a href="#l196" class="line" id="l196">    196</a>         [AtomTagId]                = FeedFieldId,
       +<a href="#l197" class="line" id="l197">    197</a>         [AtomTagLink]              = -1,
       +<a href="#l198" class="line" id="l198">    198</a>         [AtomTagLinkAlternate]     = FeedFieldLink,
       +<a href="#l199" class="line" id="l199">    199</a>         [AtomTagLinkEnclosure]     = FeedFieldEnclosure,
       +<a href="#l200" class="line" id="l200">    200</a>         [AtomTagAuthor]            = -1,
       +<a href="#l201" class="line" id="l201">    201</a>         [AtomTagAuthorName]        = FeedFieldAuthor,
       +<a href="#l202" class="line" id="l202">    202</a>         [AtomTagCategory]          = FeedFieldCategory
       +<a href="#l203" class="line" id="l203">    203</a> };
       +<a href="#l204" class="line" id="l204">    204</a> 
       +<a href="#l205" class="line" id="l205">    205</a> static const int FieldSeparator = &#39;\t&#39;;
       +<a href="#l206" class="line" id="l206">    206</a> /* separator for multiple values in a field, separator should be 1 byte */
       +<a href="#l207" class="line" id="l207">    207</a> static const char FieldMultiSeparator[] = &quot;|&quot;;
       +<a href="#l208" class="line" id="l208">    208</a> static struct uri baseuri;
       +<a href="#l209" class="line" id="l209">    209</a> static const char *baseurl;
       +<a href="#l210" class="line" id="l210">    210</a> 
       +<a href="#l211" class="line" id="l211">    211</a> static FeedContext ctx;
       +<a href="#l212" class="line" id="l212">    212</a> static XMLParser parser; /* XML parser state */
       +<a href="#l213" class="line" id="l213">    213</a> static String attrispermalink, attrrel, attrtype, tmpstr;
       +<a href="#l214" class="line" id="l214">    214</a> 
       +<a href="#l215" class="line" id="l215">    215</a> static int
       +<a href="#l216" class="line" id="l216">    216</a> tagcmp(const void *v1, const void *v2)
       +<a href="#l217" class="line" id="l217">    217</a> {
       +<a href="#l218" class="line" id="l218">    218</a>         return strcasecmp(((FeedTag *)v1)-&gt;name, ((FeedTag *)v2)-&gt;name);
       +<a href="#l219" class="line" id="l219">    219</a> }
       +<a href="#l220" class="line" id="l220">    220</a> 
       +<a href="#l221" class="line" id="l221">    221</a> /* Unique tagid for parsed tag name. */
       +<a href="#l222" class="line" id="l222">    222</a> static FeedTag *
       +<a href="#l223" class="line" id="l223">    223</a> gettag(enum FeedType feedtype, const char *name, size_t namelen)
       +<a href="#l224" class="line" id="l224">    224</a> {
       +<a href="#l225" class="line" id="l225">    225</a>         FeedTag f, *r = NULL;
       +<a href="#l226" class="line" id="l226">    226</a> 
       +<a href="#l227" class="line" id="l227">    227</a>         f.name = (char *)name;
       +<a href="#l228" class="line" id="l228">    228</a> 
       +<a href="#l229" class="line" id="l229">    229</a>         switch (feedtype) {
       +<a href="#l230" class="line" id="l230">    230</a>         case FeedTypeRSS:
       +<a href="#l231" class="line" id="l231">    231</a>                 r = bsearch(&amp;f, rsstags, sizeof(rsstags) / sizeof(rsstags[0]),
       +<a href="#l232" class="line" id="l232">    232</a>                         sizeof(rsstags[0]), tagcmp);
       +<a href="#l233" class="line" id="l233">    233</a>                 break;
       +<a href="#l234" class="line" id="l234">    234</a>         case FeedTypeAtom:
       +<a href="#l235" class="line" id="l235">    235</a>                 r = bsearch(&amp;f, atomtags, sizeof(atomtags) / sizeof(atomtags[0]),
       +<a href="#l236" class="line" id="l236">    236</a>                         sizeof(atomtags[0]), tagcmp);
       +<a href="#l237" class="line" id="l237">    237</a>                 break;
       +<a href="#l238" class="line" id="l238">    238</a>         default:
       +<a href="#l239" class="line" id="l239">    239</a>                 break;
       +<a href="#l240" class="line" id="l240">    240</a>         }
       +<a href="#l241" class="line" id="l241">    241</a> 
       +<a href="#l242" class="line" id="l242">    242</a>         return r;
       +<a href="#l243" class="line" id="l243">    243</a> }
       +<a href="#l244" class="line" id="l244">    244</a> 
       +<a href="#l245" class="line" id="l245">    245</a> static char *
       +<a href="#l246" class="line" id="l246">    246</a> ltrim(const char *s)
       +<a href="#l247" class="line" id="l247">    247</a> {
       +<a href="#l248" class="line" id="l248">    248</a>         for (; ISSPACE((unsigned char)*s); s++)
       +<a href="#l249" class="line" id="l249">    249</a>                 ;
       +<a href="#l250" class="line" id="l250">    250</a>         return (char *)s;
       +<a href="#l251" class="line" id="l251">    251</a> }
       +<a href="#l252" class="line" id="l252">    252</a> 
       +<a href="#l253" class="line" id="l253">    253</a> static char *
       +<a href="#l254" class="line" id="l254">    254</a> rtrim(const char *s)
       +<a href="#l255" class="line" id="l255">    255</a> {
       +<a href="#l256" class="line" id="l256">    256</a>         const char *e;
       +<a href="#l257" class="line" id="l257">    257</a> 
       +<a href="#l258" class="line" id="l258">    258</a>         for (e = s + strlen(s); e &gt; s &amp;&amp; ISSPACE((unsigned char)*(e - 1)); e--)
       +<a href="#l259" class="line" id="l259">    259</a>                 ;
       +<a href="#l260" class="line" id="l260">    260</a>         return (char *)e;
       +<a href="#l261" class="line" id="l261">    261</a> }
       +<a href="#l262" class="line" id="l262">    262</a> 
       +<a href="#l263" class="line" id="l263">    263</a> /* Clear string only; don&#39;t free, prevents unnecessary reallocation. */
       +<a href="#l264" class="line" id="l264">    264</a> static void
       +<a href="#l265" class="line" id="l265">    265</a> string_clear(String *s)
       +<a href="#l266" class="line" id="l266">    266</a> {
       +<a href="#l267" class="line" id="l267">    267</a>         if (s-&gt;data)
       +<a href="#l268" class="line" id="l268">    268</a>                 s-&gt;data[0] = &#39;\0&#39;;
       +<a href="#l269" class="line" id="l269">    269</a>         s-&gt;len = 0;
       +<a href="#l270" class="line" id="l270">    270</a> }
       +<a href="#l271" class="line" id="l271">    271</a> 
       +<a href="#l272" class="line" id="l272">    272</a> static void
       +<a href="#l273" class="line" id="l273">    273</a> string_buffer_realloc(String *s, size_t newlen)
       +<a href="#l274" class="line" id="l274">    274</a> {
       +<a href="#l275" class="line" id="l275">    275</a>         size_t alloclen;
       +<a href="#l276" class="line" id="l276">    276</a> 
       +<a href="#l277" class="line" id="l277">    277</a>         if (newlen &gt; SIZE_MAX / 2) {
       +<a href="#l278" class="line" id="l278">    278</a>                 alloclen = SIZE_MAX;
       +<a href="#l279" class="line" id="l279">    279</a>         } else {
       +<a href="#l280" class="line" id="l280">    280</a>                 for (alloclen = 64; alloclen &lt;= newlen; alloclen *= 2)
       +<a href="#l281" class="line" id="l281">    281</a>                         ;
       +<a href="#l282" class="line" id="l282">    282</a>         }
       +<a href="#l283" class="line" id="l283">    283</a>         if (!(s-&gt;data = realloc(s-&gt;data, alloclen)))
       +<a href="#l284" class="line" id="l284">    284</a>                 err(1, &quot;realloc&quot;);
       +<a href="#l285" class="line" id="l285">    285</a>         s-&gt;bufsiz = alloclen;
       +<a href="#l286" class="line" id="l286">    286</a> }
       +<a href="#l287" class="line" id="l287">    287</a> 
       +<a href="#l288" class="line" id="l288">    288</a> /* Append data to String, s-&gt;data and data may not overlap. */
       +<a href="#l289" class="line" id="l289">    289</a> static void
       +<a href="#l290" class="line" id="l290">    290</a> string_append(String *s, const char *data, size_t len)
       +<a href="#l291" class="line" id="l291">    291</a> {
       +<a href="#l292" class="line" id="l292">    292</a>         if (!len)
       +<a href="#l293" class="line" id="l293">    293</a>                 return;
       +<a href="#l294" class="line" id="l294">    294</a> 
       +<a href="#l295" class="line" id="l295">    295</a>         if (s-&gt;len &gt;= SIZE_MAX - len) {
       +<a href="#l296" class="line" id="l296">    296</a>                 errno = ENOMEM;
       +<a href="#l297" class="line" id="l297">    297</a>                 err(1, &quot;realloc&quot;);
       +<a href="#l298" class="line" id="l298">    298</a>         }
       +<a href="#l299" class="line" id="l299">    299</a> 
       +<a href="#l300" class="line" id="l300">    300</a>         /* check if allocation is necessary, never shrink the buffer. */
       +<a href="#l301" class="line" id="l301">    301</a>         if (s-&gt;len + len &gt;= s-&gt;bufsiz)
       +<a href="#l302" class="line" id="l302">    302</a>                 string_buffer_realloc(s, s-&gt;len + len + 1);
       +<a href="#l303" class="line" id="l303">    303</a>         memcpy(s-&gt;data + s-&gt;len, data, len);
       +<a href="#l304" class="line" id="l304">    304</a>         s-&gt;len += len;
       +<a href="#l305" class="line" id="l305">    305</a>         s-&gt;data[s-&gt;len] = &#39;\0&#39;;
       +<a href="#l306" class="line" id="l306">    306</a> }
       +<a href="#l307" class="line" id="l307">    307</a> 
       +<a href="#l308" class="line" id="l308">    308</a> /* Print text, encode TABs, newlines and &#39;\&#39;, remove other whitespace.
       +<a href="#l309" class="line" id="l309">    309</a>  * Remove leading and trailing whitespace. */
       +<a href="#l310" class="line" id="l310">    310</a> static void
       +<a href="#l311" class="line" id="l311">    311</a> string_print_encoded(String *s)
       +<a href="#l312" class="line" id="l312">    312</a> {
       +<a href="#l313" class="line" id="l313">    313</a>         const char *p, *e;
       +<a href="#l314" class="line" id="l314">    314</a> 
       +<a href="#l315" class="line" id="l315">    315</a>         if (!s-&gt;data || !s-&gt;len)
       +<a href="#l316" class="line" id="l316">    316</a>                 return;
       +<a href="#l317" class="line" id="l317">    317</a> 
       +<a href="#l318" class="line" id="l318">    318</a>         p = ltrim(s-&gt;data);
       +<a href="#l319" class="line" id="l319">    319</a>         e = rtrim(p);
       +<a href="#l320" class="line" id="l320">    320</a> 
       +<a href="#l321" class="line" id="l321">    321</a>         for (; *p &amp;&amp; p != e; p++) {
       +<a href="#l322" class="line" id="l322">    322</a>                 switch (*p) {
       +<a href="#l323" class="line" id="l323">    323</a>                 case &#39;\n&#39;: putchar(&#39;\\&#39;); putchar(&#39;n&#39;); break;
       +<a href="#l324" class="line" id="l324">    324</a>                 case &#39;\\&#39;: putchar(&#39;\\&#39;); putchar(&#39;\\&#39;); break;
       +<a href="#l325" class="line" id="l325">    325</a>                 case &#39;\t&#39;: putchar(&#39;\\&#39;); putchar(&#39;t&#39;); break;
       +<a href="#l326" class="line" id="l326">    326</a>                 default:
       +<a href="#l327" class="line" id="l327">    327</a>                         /* ignore control chars */
       +<a href="#l328" class="line" id="l328">    328</a>                         if (!ISCNTRL((unsigned char)*p))
       +<a href="#l329" class="line" id="l329">    329</a>                                 putchar(*p);
       +<a href="#l330" class="line" id="l330">    330</a>                         break;
       +<a href="#l331" class="line" id="l331">    331</a>                 }
       +<a href="#l332" class="line" id="l332">    332</a>         }
       +<a href="#l333" class="line" id="l333">    333</a> }
       +<a href="#l334" class="line" id="l334">    334</a> 
       +<a href="#l335" class="line" id="l335">    335</a> static void
       +<a href="#l336" class="line" id="l336">    336</a> printtrimmed(const char *s)
       +<a href="#l337" class="line" id="l337">    337</a> {
       +<a href="#l338" class="line" id="l338">    338</a>         char *p, *e;
       +<a href="#l339" class="line" id="l339">    339</a> 
       +<a href="#l340" class="line" id="l340">    340</a>         p = ltrim(s);
       +<a href="#l341" class="line" id="l341">    341</a>         e = rtrim(p);
       +<a href="#l342" class="line" id="l342">    342</a>         for (; *p &amp;&amp; p != e; p++) {
       +<a href="#l343" class="line" id="l343">    343</a>                 if (ISSPACE((unsigned char)*p))
       +<a href="#l344" class="line" id="l344">    344</a>                         putchar(&#39; &#39;); /* any whitespace to space */
       +<a href="#l345" class="line" id="l345">    345</a>                 else if (!ISCNTRL((unsigned char)*p))
       +<a href="#l346" class="line" id="l346">    346</a>                         /* ignore other control chars */
       +<a href="#l347" class="line" id="l347">    347</a>                         putchar(*p);
       +<a href="#l348" class="line" id="l348">    348</a>         }
       +<a href="#l349" class="line" id="l349">    349</a> }
       +<a href="#l350" class="line" id="l350">    350</a> 
       +<a href="#l351" class="line" id="l351">    351</a> /* Print text, replace TABs, carriage return and other whitespace with &#39; &#39;.
       +<a href="#l352" class="line" id="l352">    352</a>  * Other control chars are removed. Remove leading and trailing whitespace. */
       +<a href="#l353" class="line" id="l353">    353</a> static void
       +<a href="#l354" class="line" id="l354">    354</a> string_print_trimmed(String *s)
       +<a href="#l355" class="line" id="l355">    355</a> {
       +<a href="#l356" class="line" id="l356">    356</a>         if (!s-&gt;data || !s-&gt;len)
       +<a href="#l357" class="line" id="l357">    357</a>                 return;
       +<a href="#l358" class="line" id="l358">    358</a> 
       +<a href="#l359" class="line" id="l359">    359</a>         printtrimmed(s-&gt;data);
       +<a href="#l360" class="line" id="l360">    360</a> }
       +<a href="#l361" class="line" id="l361">    361</a> 
       +<a href="#l362" class="line" id="l362">    362</a> /* Print each field with trimmed whitespace, separated by &#39;|&#39;. */
       +<a href="#l363" class="line" id="l363">    363</a> static void
       +<a href="#l364" class="line" id="l364">    364</a> string_print_trimmed_multi(String *s)
       +<a href="#l365" class="line" id="l365">    365</a> {
       +<a href="#l366" class="line" id="l366">    366</a>         char *p, *e;
       +<a href="#l367" class="line" id="l367">    367</a>         int c;
       +<a href="#l368" class="line" id="l368">    368</a> 
       +<a href="#l369" class="line" id="l369">    369</a>         if (!s-&gt;data || !s-&gt;len)
       +<a href="#l370" class="line" id="l370">    370</a>                 return;
       +<a href="#l371" class="line" id="l371">    371</a> 
       +<a href="#l372" class="line" id="l372">    372</a>         for (p = s-&gt;data; ; p = e + 1) {
       +<a href="#l373" class="line" id="l373">    373</a>                 if ((e = strstr(p, FieldMultiSeparator))) {
       +<a href="#l374" class="line" id="l374">    374</a>                         c = *e;
       +<a href="#l375" class="line" id="l375">    375</a>                         *e = &#39;\0&#39;;
       +<a href="#l376" class="line" id="l376">    376</a>                         printtrimmed(p);
       +<a href="#l377" class="line" id="l377">    377</a>                         *e = c; /* restore NUL byte to original character */
       +<a href="#l378" class="line" id="l378">    378</a>                         fputs(FieldMultiSeparator, stdout);
       +<a href="#l379" class="line" id="l379">    379</a>                 } else {
       +<a href="#l380" class="line" id="l380">    380</a>                         printtrimmed(p);
       +<a href="#l381" class="line" id="l381">    381</a>                         break;
       +<a href="#l382" class="line" id="l382">    382</a>                 }
       +<a href="#l383" class="line" id="l383">    383</a>         }
       +<a href="#l384" class="line" id="l384">    384</a> }
       +<a href="#l385" class="line" id="l385">    385</a> 
       +<a href="#l386" class="line" id="l386">    386</a> /* Print URL, if it is a relative URL then it uses the global `baseurl`. */
       +<a href="#l387" class="line" id="l387">    387</a> static void
       +<a href="#l388" class="line" id="l388">    388</a> printuri(char *s)
       +<a href="#l389" class="line" id="l389">    389</a> {
       +<a href="#l390" class="line" id="l390">    390</a>         char link[4096], *p, *e;
       +<a href="#l391" class="line" id="l391">    391</a>         struct uri newuri, olduri;
       +<a href="#l392" class="line" id="l392">    392</a>         int c, r = -1;
       +<a href="#l393" class="line" id="l393">    393</a> 
       +<a href="#l394" class="line" id="l394">    394</a>         p = ltrim(s);
       +<a href="#l395" class="line" id="l395">    395</a>         e = rtrim(p);
       +<a href="#l396" class="line" id="l396">    396</a>         c = *e;
       +<a href="#l397" class="line" id="l397">    397</a>         *e = &#39;\0&#39;;
       +<a href="#l398" class="line" id="l398">    398</a> 
       +<a href="#l399" class="line" id="l399">    399</a>         if (baseurl &amp;&amp; !uri_hasscheme(p) &amp;&amp;
       +<a href="#l400" class="line" id="l400">    400</a>             uri_parse(p, &amp;olduri) != -1 &amp;&amp; !olduri.proto[0] &amp;&amp;
       +<a href="#l401" class="line" id="l401">    401</a>             uri_makeabs(&amp;newuri, &amp;olduri, &amp;baseuri) != -1 &amp;&amp; newuri.proto[0])
       +<a href="#l402" class="line" id="l402">    402</a>                 r = uri_format(link, sizeof(link), &amp;newuri);
       +<a href="#l403" class="line" id="l403">    403</a> 
       +<a href="#l404" class="line" id="l404">    404</a>         if (r &gt;= 0 &amp;&amp; (size_t)r &lt; sizeof(link))
       +<a href="#l405" class="line" id="l405">    405</a>                 printtrimmed(link);
       +<a href="#l406" class="line" id="l406">    406</a>         else
       +<a href="#l407" class="line" id="l407">    407</a>                 printtrimmed(p);
       +<a href="#l408" class="line" id="l408">    408</a> 
       +<a href="#l409" class="line" id="l409">    409</a>         *e = c; /* restore NUL byte to original character */
       +<a href="#l410" class="line" id="l410">    410</a> }
       +<a href="#l411" class="line" id="l411">    411</a> 
       +<a href="#l412" class="line" id="l412">    412</a> /* Print URL, if it is a relative URL then it uses the global `baseurl`. */
       +<a href="#l413" class="line" id="l413">    413</a> static void
       +<a href="#l414" class="line" id="l414">    414</a> string_print_uri(String *s)
       +<a href="#l415" class="line" id="l415">    415</a> {
       +<a href="#l416" class="line" id="l416">    416</a>         if (!s-&gt;data || !s-&gt;len)
       +<a href="#l417" class="line" id="l417">    417</a>                 return;
       +<a href="#l418" class="line" id="l418">    418</a> 
       +<a href="#l419" class="line" id="l419">    419</a>         printuri(s-&gt;data);
       +<a href="#l420" class="line" id="l420">    420</a> }
       +<a href="#l421" class="line" id="l421">    421</a> 
       +<a href="#l422" class="line" id="l422">    422</a> /* Print as UNIX timestamp, print nothing if the time is empty or invalid. */
       +<a href="#l423" class="line" id="l423">    423</a> static void
       +<a href="#l424" class="line" id="l424">    424</a> string_print_timestamp(String *s)
       +<a href="#l425" class="line" id="l425">    425</a> {
       +<a href="#l426" class="line" id="l426">    426</a>         long long t;
       +<a href="#l427" class="line" id="l427">    427</a> 
       +<a href="#l428" class="line" id="l428">    428</a>         if (!s-&gt;data || !s-&gt;len)
       +<a href="#l429" class="line" id="l429">    429</a>                 return;
       +<a href="#l430" class="line" id="l430">    430</a> 
       +<a href="#l431" class="line" id="l431">    431</a>         if (parsetime(s-&gt;data, &amp;t) != -1)
       +<a href="#l432" class="line" id="l432">    432</a>                 printf(&quot;%lld&quot;, t);
       +<a href="#l433" class="line" id="l433">    433</a> }
       +<a href="#l434" class="line" id="l434">    434</a> 
       +<a href="#l435" class="line" id="l435">    435</a> /* Convert time fields. Returns a signed (at least) 64-bit UNIX timestamp.
       +<a href="#l436" class="line" id="l436">    436</a>    Parameters should be passed as they are in a struct tm:
       +<a href="#l437" class="line" id="l437">    437</a>    that is: year = year - 1900, month = month - 1. */
       +<a href="#l438" class="line" id="l438">    438</a> static long long
       +<a href="#l439" class="line" id="l439">    439</a> datetounix(long long year, int mon, int day, int hour, int min, int sec)
       +<a href="#l440" class="line" id="l440">    440</a> {
       +<a href="#l441" class="line" id="l441">    441</a>         /* seconds in a month in a regular (non-leap) year */
       +<a href="#l442" class="line" id="l442">    442</a>         static const long secs_through_month[] = {
       +<a href="#l443" class="line" id="l443">    443</a>                 0, 31 * 86400, 59 * 86400, 90 * 86400,
       +<a href="#l444" class="line" id="l444">    444</a>                 120 * 86400, 151 * 86400, 181 * 86400, 212 * 86400,
       +<a href="#l445" class="line" id="l445">    445</a>                 243 * 86400, 273 * 86400, 304 * 86400, 334 * 86400 };
       +<a href="#l446" class="line" id="l446">    446</a>         int is_leap = 0, cycles, centuries = 0, leaps = 0, rem;
       +<a href="#l447" class="line" id="l447">    447</a>         long long t;
       +<a href="#l448" class="line" id="l448">    448</a> 
       +<a href="#l449" class="line" id="l449">    449</a>         /* optimization: handle common range year 1902 up to and including 2038 */
       +<a href="#l450" class="line" id="l450">    450</a>         if (year - 2ULL &lt;= 136) {
       +<a href="#l451" class="line" id="l451">    451</a>                 /* amount of leap days relative to 1970: every 4 years */
       +<a href="#l452" class="line" id="l452">    452</a>                 leaps = (year - 68) &gt;&gt; 2;
       +<a href="#l453" class="line" id="l453">    453</a>                 if (!((year - 68) &amp; 3)) {
       +<a href="#l454" class="line" id="l454">    454</a>                         leaps--;
       +<a href="#l455" class="line" id="l455">    455</a>                         is_leap = 1;
       +<a href="#l456" class="line" id="l456">    456</a>                 } else {
       +<a href="#l457" class="line" id="l457">    457</a>                         is_leap = 0;
       +<a href="#l458" class="line" id="l458">    458</a>                 }
       +<a href="#l459" class="line" id="l459">    459</a>                 t = 31536000 * (year - 70) + (86400 * leaps); /* 365 * 86400 = 31536000 */
       +<a href="#l460" class="line" id="l460">    460</a>         } else {
       +<a href="#l461" class="line" id="l461">    461</a>                 /* general leap year calculation:
       +<a href="#l462" class="line" id="l462">    462</a>                    leap years occur mostly every 4 years but every 100 years
       +<a href="#l463" class="line" id="l463">    463</a>                    a leap year is skipped unless the year is divisible by 400 */
       +<a href="#l464" class="line" id="l464">    464</a>                 cycles = (year - 100) / 400;
       +<a href="#l465" class="line" id="l465">    465</a>                 rem = (year - 100) % 400;
       +<a href="#l466" class="line" id="l466">    466</a>                 if (rem &lt; 0) {
       +<a href="#l467" class="line" id="l467">    467</a>                         cycles--;
       +<a href="#l468" class="line" id="l468">    468</a>                         rem += 400;
       +<a href="#l469" class="line" id="l469">    469</a>                 }
       +<a href="#l470" class="line" id="l470">    470</a>                 if (!rem) {
       +<a href="#l471" class="line" id="l471">    471</a>                         is_leap = 1;
       +<a href="#l472" class="line" id="l472">    472</a>                 } else {
       +<a href="#l473" class="line" id="l473">    473</a>                         if (rem &gt;= 300) {
       +<a href="#l474" class="line" id="l474">    474</a>                                 centuries = 3;
       +<a href="#l475" class="line" id="l475">    475</a>                                 rem -= 300;
       +<a href="#l476" class="line" id="l476">    476</a>                         } else if (rem &gt;= 200) {
       +<a href="#l477" class="line" id="l477">    477</a>                                 centuries = 2;
       +<a href="#l478" class="line" id="l478">    478</a>                                 rem -= 200;
       +<a href="#l479" class="line" id="l479">    479</a>                         } else if (rem &gt;= 100) {
       +<a href="#l480" class="line" id="l480">    480</a>                                 centuries = 1;
       +<a href="#l481" class="line" id="l481">    481</a>                                 rem -= 100;
       +<a href="#l482" class="line" id="l482">    482</a>                         }
       +<a href="#l483" class="line" id="l483">    483</a>                         if (rem) {
       +<a href="#l484" class="line" id="l484">    484</a>                                 leaps = rem / 4U;
       +<a href="#l485" class="line" id="l485">    485</a>                                 rem %= 4U;
       +<a href="#l486" class="line" id="l486">    486</a>                                 is_leap = !rem;
       +<a href="#l487" class="line" id="l487">    487</a>                         }
       +<a href="#l488" class="line" id="l488">    488</a>                 }
       +<a href="#l489" class="line" id="l489">    489</a>                 leaps += (97 * cycles) + (24 * centuries) - is_leap;
       +<a href="#l490" class="line" id="l490">    490</a> 
       +<a href="#l491" class="line" id="l491">    491</a>                 /* adjust 8 leap days from 1970 up to and including 2000:
       +<a href="#l492" class="line" id="l492">    492</a>                    ((30 * 365) + 8) * 86400 = 946771200 */
       +<a href="#l493" class="line" id="l493">    493</a>                 t = ((year - 100) * 31536000LL) + (leaps * 86400LL) + 946771200LL;
       +<a href="#l494" class="line" id="l494">    494</a>         }
       +<a href="#l495" class="line" id="l495">    495</a>         t += secs_through_month[mon];
       +<a href="#l496" class="line" id="l496">    496</a>         if (is_leap &amp;&amp; mon &gt;= 2)
       +<a href="#l497" class="line" id="l497">    497</a>                 t += 86400;
       +<a href="#l498" class="line" id="l498">    498</a>         t += 86400LL * (day - 1);
       +<a href="#l499" class="line" id="l499">    499</a>         t += 3600LL * hour;
       +<a href="#l500" class="line" id="l500">    500</a>         t += 60LL * min;
       +<a href="#l501" class="line" id="l501">    501</a>         t += sec;
       +<a href="#l502" class="line" id="l502">    502</a> 
       +<a href="#l503" class="line" id="l503">    503</a>         return t;
       +<a href="#l504" class="line" id="l504">    504</a> }
       +<a href="#l505" class="line" id="l505">    505</a> 
       +<a href="#l506" class="line" id="l506">    506</a> /* Get timezone from string, return time offset in seconds from UTC.
       +<a href="#l507" class="line" id="l507">    507</a>  * NOTE: only parses timezones in RFC 822, many other timezone names are
       +<a href="#l508" class="line" id="l508">    508</a>  * ambiguous anyway.
       +<a href="#l509" class="line" id="l509">    509</a>  * ANSI and military zones are defined wrong in RFC 822 and are unsupported,
       +<a href="#l510" class="line" id="l510">    510</a>  * see note on RFC 2822 4.3 page 32. */
       +<a href="#l511" class="line" id="l511">    511</a> static long
       +<a href="#l512" class="line" id="l512">    512</a> gettzoffset(const char *s)
       +<a href="#l513" class="line" id="l513">    513</a> {
       +<a href="#l514" class="line" id="l514">    514</a>         static const struct {
       +<a href="#l515" class="line" id="l515">    515</a>                 char *name;
       +<a href="#l516" class="line" id="l516">    516</a>                 int offhour;
       +<a href="#l517" class="line" id="l517">    517</a>         } tzones[] = {
       +<a href="#l518" class="line" id="l518">    518</a>                 { &quot;CDT&quot;, -5 * 3600 },
       +<a href="#l519" class="line" id="l519">    519</a>                 { &quot;CST&quot;, -6 * 3600 },
       +<a href="#l520" class="line" id="l520">    520</a>                 { &quot;EDT&quot;, -4 * 3600 },
       +<a href="#l521" class="line" id="l521">    521</a>                 { &quot;EST&quot;, -5 * 3600 },
       +<a href="#l522" class="line" id="l522">    522</a>                 { &quot;MDT&quot;, -6 * 3600 },
       +<a href="#l523" class="line" id="l523">    523</a>                 { &quot;MST&quot;, -7 * 3600 },
       +<a href="#l524" class="line" id="l524">    524</a>                 { &quot;PDT&quot;, -7 * 3600 },
       +<a href="#l525" class="line" id="l525">    525</a>                 { &quot;PST&quot;, -8 * 3600 },
       +<a href="#l526" class="line" id="l526">    526</a>         };
       +<a href="#l527" class="line" id="l527">    527</a>         const char *p;
       +<a href="#l528" class="line" id="l528">    528</a>         long tzhour = 0, tzmin = 0;
       +<a href="#l529" class="line" id="l529">    529</a>         size_t i;
       +<a href="#l530" class="line" id="l530">    530</a> 
       +<a href="#l531" class="line" id="l531">    531</a>         for (; ISSPACE((unsigned char)*s); s++)
       +<a href="#l532" class="line" id="l532">    532</a>                 ;
       +<a href="#l533" class="line" id="l533">    533</a>         switch (*s) {
       +<a href="#l534" class="line" id="l534">    534</a>         case &#39;-&#39;: /* offset */
       +<a href="#l535" class="line" id="l535">    535</a>         case &#39;+&#39;:
       +<a href="#l536" class="line" id="l536">    536</a>                 for (i = 0, p = s + 1; i &lt; 2 &amp;&amp; ISDIGIT((unsigned char)*p); i++, p++)
       +<a href="#l537" class="line" id="l537">    537</a>                         tzhour = (tzhour * 10) + (*p - &#39;0&#39;);
       +<a href="#l538" class="line" id="l538">    538</a>                 if (*p == &#39;:&#39;)
       +<a href="#l539" class="line" id="l539">    539</a>                         p++;
       +<a href="#l540" class="line" id="l540">    540</a>                 for (i = 0; i &lt; 2 &amp;&amp; ISDIGIT((unsigned char)*p); i++, p++)
       +<a href="#l541" class="line" id="l541">    541</a>                         tzmin = (tzmin * 10) + (*p - &#39;0&#39;);
       +<a href="#l542" class="line" id="l542">    542</a>                 return ((tzhour * 3600) + (tzmin * 60)) * (s[0] == &#39;-&#39; ? -1 : 1);
       +<a href="#l543" class="line" id="l543">    543</a>         default: /* timezone name */
       +<a href="#l544" class="line" id="l544">    544</a>                 for (i = 0; ISALPHA((unsigned char)s[i]); i++)
       +<a href="#l545" class="line" id="l545">    545</a>                         ;
       +<a href="#l546" class="line" id="l546">    546</a>                 if (i != 3)
       +<a href="#l547" class="line" id="l547">    547</a>                         return 0;
       +<a href="#l548" class="line" id="l548">    548</a>                 /* compare timezone and adjust offset relative to UTC */
       +<a href="#l549" class="line" id="l549">    549</a>                 for (i = 0; i &lt; sizeof(tzones) / sizeof(*tzones); i++) {
       +<a href="#l550" class="line" id="l550">    550</a>                         if (!memcmp(s, tzones[i].name, 3))
       +<a href="#l551" class="line" id="l551">    551</a>                                 return tzones[i].offhour;
       +<a href="#l552" class="line" id="l552">    552</a>                 }
       +<a href="#l553" class="line" id="l553">    553</a>         }
       +<a href="#l554" class="line" id="l554">    554</a>         return 0;
       +<a href="#l555" class="line" id="l555">    555</a> }
       +<a href="#l556" class="line" id="l556">    556</a> 
       +<a href="#l557" class="line" id="l557">    557</a> /* Parse time string `s` into the UNIX timestamp `tp`.
       +<a href="#l558" class="line" id="l558">    558</a>    Returns 0 on success or -1 on failure. */
       +<a href="#l559" class="line" id="l559">    559</a> static int
       +<a href="#l560" class="line" id="l560">    560</a> parsetime(const char *s, long long *tp)
       +<a href="#l561" class="line" id="l561">    561</a> {
       +<a href="#l562" class="line" id="l562">    562</a>         static const struct {
       +<a href="#l563" class="line" id="l563">    563</a>                 char *name;
       +<a href="#l564" class="line" id="l564">    564</a>                 int len;
       +<a href="#l565" class="line" id="l565">    565</a>         } mons[] = {
       +<a href="#l566" class="line" id="l566">    566</a>                 { STRP(&quot;January&quot;),   },
       +<a href="#l567" class="line" id="l567">    567</a>                 { STRP(&quot;February&quot;),  },
       +<a href="#l568" class="line" id="l568">    568</a>                 { STRP(&quot;March&quot;),     },
       +<a href="#l569" class="line" id="l569">    569</a>                 { STRP(&quot;April&quot;),     },
       +<a href="#l570" class="line" id="l570">    570</a>                 { STRP(&quot;May&quot;),       },
       +<a href="#l571" class="line" id="l571">    571</a>                 { STRP(&quot;June&quot;),      },
       +<a href="#l572" class="line" id="l572">    572</a>                 { STRP(&quot;July&quot;),      },
       +<a href="#l573" class="line" id="l573">    573</a>                 { STRP(&quot;August&quot;),    },
       +<a href="#l574" class="line" id="l574">    574</a>                 { STRP(&quot;September&quot;), },
       +<a href="#l575" class="line" id="l575">    575</a>                 { STRP(&quot;October&quot;),   },
       +<a href="#l576" class="line" id="l576">    576</a>                 { STRP(&quot;November&quot;),  },
       +<a href="#l577" class="line" id="l577">    577</a>                 { STRP(&quot;December&quot;),  },
       +<a href="#l578" class="line" id="l578">    578</a>         };
       +<a href="#l579" class="line" id="l579">    579</a>         int va[6] = { 0 }, i, j, v, vi;
       +<a href="#l580" class="line" id="l580">    580</a>         size_t m;
       +<a href="#l581" class="line" id="l581">    581</a> 
       +<a href="#l582" class="line" id="l582">    582</a>         for (; ISSPACE((unsigned char)*s); s++)
       +<a href="#l583" class="line" id="l583">    583</a>                 ;
       +<a href="#l584" class="line" id="l584">    584</a>         if (!ISDIGIT((unsigned char)*s) &amp;&amp; !ISALPHA((unsigned char)*s))
       +<a href="#l585" class="line" id="l585">    585</a>                 return -1;
       +<a href="#l586" class="line" id="l586">    586</a> 
       +<a href="#l587" class="line" id="l587">    587</a>         if (ISDIGIT((unsigned char)s[0]) &amp;&amp;
       +<a href="#l588" class="line" id="l588">    588</a>             ISDIGIT((unsigned char)s[1]) &amp;&amp;
       +<a href="#l589" class="line" id="l589">    589</a>             ISDIGIT((unsigned char)s[2]) &amp;&amp;
       +<a href="#l590" class="line" id="l590">    590</a>             ISDIGIT((unsigned char)s[3])) {
       +<a href="#l591" class="line" id="l591">    591</a>                 /* formats &quot;%Y-%m-%d %H:%M:%S&quot;, &quot;%Y-%m-%dT%H:%M:%S&quot; or &quot;%Y%m%d%H%M%S&quot; */
       +<a href="#l592" class="line" id="l592">    592</a>                 vi = 0;
       +<a href="#l593" class="line" id="l593">    593</a>         } else {
       +<a href="#l594" class="line" id="l594">    594</a>                 /* format: &quot;[%a, ]%d %b %Y %H:%M:%S&quot; */
       +<a href="#l595" class="line" id="l595">    595</a>                 /* parse &quot;[%a, ]%d %b %Y &quot; part, then use time parsing as above */
       +<a href="#l596" class="line" id="l596">    596</a>                 for (; ISALPHA((unsigned char)*s); s++)
       +<a href="#l597" class="line" id="l597">    597</a>                         ;
       +<a href="#l598" class="line" id="l598">    598</a>                 for (; ISSPACE((unsigned char)*s); s++)
       +<a href="#l599" class="line" id="l599">    599</a>                         ;
       +<a href="#l600" class="line" id="l600">    600</a>                 if (*s == &#39;,&#39;)
       +<a href="#l601" class="line" id="l601">    601</a>                         s++;
       +<a href="#l602" class="line" id="l602">    602</a>                 for (; ISSPACE((unsigned char)*s); s++)
       +<a href="#l603" class="line" id="l603">    603</a>                         ;
       +<a href="#l604" class="line" id="l604">    604</a>                 for (v = 0, i = 0; i &lt; 2 &amp;&amp; ISDIGIT((unsigned char)*s); s++, i++)
       +<a href="#l605" class="line" id="l605">    605</a>                         v = (v * 10) + (*s - &#39;0&#39;);
       +<a href="#l606" class="line" id="l606">    606</a>                 va[2] = v; /* day */
       +<a href="#l607" class="line" id="l607">    607</a>                 for (; ISSPACE((unsigned char)*s); s++)
       +<a href="#l608" class="line" id="l608">    608</a>                         ;
       +<a href="#l609" class="line" id="l609">    609</a>                 /* end of word month */
       +<a href="#l610" class="line" id="l610">    610</a>                 for (j = 0; ISALPHA((unsigned char)s[j]); j++)
       +<a href="#l611" class="line" id="l611">    611</a>                         ;
       +<a href="#l612" class="line" id="l612">    612</a>                 /* check month name */
       +<a href="#l613" class="line" id="l613">    613</a>                 if (j &lt; 3 || j &gt; 9)
       +<a href="#l614" class="line" id="l614">    614</a>                         return -1; /* month cannot match */
       +<a href="#l615" class="line" id="l615">    615</a>                 for (m = 0; m &lt; sizeof(mons) / sizeof(*mons); m++) {
       +<a href="#l616" class="line" id="l616">    616</a>                         /* abbreviation (3 length) or long name */
       +<a href="#l617" class="line" id="l617">    617</a>                         if ((j == 3 || j == mons[m].len) &amp;&amp;
       +<a href="#l618" class="line" id="l618">    618</a>                             !strncasecmp(mons[m].name, s, j)) {
       +<a href="#l619" class="line" id="l619">    619</a>                                 va[1] = m + 1;
       +<a href="#l620" class="line" id="l620">    620</a>                                 s += j;
       +<a href="#l621" class="line" id="l621">    621</a>                                 break;
       +<a href="#l622" class="line" id="l622">    622</a>                         }
       +<a href="#l623" class="line" id="l623">    623</a>                 }
       +<a href="#l624" class="line" id="l624">    624</a>                 if (m &gt;= 12)
       +<a href="#l625" class="line" id="l625">    625</a>                         return -1; /* no month found */
       +<a href="#l626" class="line" id="l626">    626</a>                 for (; ISSPACE((unsigned char)*s); s++)
       +<a href="#l627" class="line" id="l627">    627</a>                         ;
       +<a href="#l628" class="line" id="l628">    628</a>                 for (v = 0, i = 0; i &lt; 4 &amp;&amp; ISDIGIT((unsigned char)*s); s++, i++)
       +<a href="#l629" class="line" id="l629">    629</a>                         v = (v * 10) + (*s - &#39;0&#39;);
       +<a href="#l630" class="line" id="l630">    630</a>                 /* obsolete short year: RFC 2822 4.3 */
       +<a href="#l631" class="line" id="l631">    631</a>                 if (i == 2 || i == 3)
       +<a href="#l632" class="line" id="l632">    632</a>                         v += (i == 2 &amp;&amp; v &gt;= 0 &amp;&amp; v &lt;= 49) ? 2000 : 1900;
       +<a href="#l633" class="line" id="l633">    633</a>                 va[0] = v; /* year */
       +<a href="#l634" class="line" id="l634">    634</a>                 for (; ISSPACE((unsigned char)*s); s++)
       +<a href="#l635" class="line" id="l635">    635</a>                         ;
       +<a href="#l636" class="line" id="l636">    636</a>                 /* parse only regular time part, see below */
       +<a href="#l637" class="line" id="l637">    637</a>                 vi = 3;
       +<a href="#l638" class="line" id="l638">    638</a>         }
       +<a href="#l639" class="line" id="l639">    639</a> 
       +<a href="#l640" class="line" id="l640">    640</a>         /* parse time parts (and possibly remaining date parts) */
       +<a href="#l641" class="line" id="l641">    641</a>         for (; *s &amp;&amp; vi &lt; 6; vi++) {
       +<a href="#l642" class="line" id="l642">    642</a>                 for (i = 0, v = 0; i &lt; ((vi == 0) ? 4 : 2) &amp;&amp;
       +<a href="#l643" class="line" id="l643">    643</a>                                    ISDIGIT((unsigned char)*s); s++, i++) {
       +<a href="#l644" class="line" id="l644">    644</a>                         v = (v * 10) + (*s - &#39;0&#39;);
       +<a href="#l645" class="line" id="l645">    645</a>                 }
       +<a href="#l646" class="line" id="l646">    646</a>                 va[vi] = v;
       +<a href="#l647" class="line" id="l647">    647</a> 
       +<a href="#l648" class="line" id="l648">    648</a>                 if ((vi &lt; 2 &amp;&amp; *s == &#39;-&#39;) ||
       +<a href="#l649" class="line" id="l649">    649</a>                     (vi == 2 &amp;&amp; (*s == &#39;T&#39; || ISSPACE((unsigned char)*s))) ||
       +<a href="#l650" class="line" id="l650">    650</a>                     (vi &gt; 2 &amp;&amp; *s == &#39;:&#39;))
       +<a href="#l651" class="line" id="l651">    651</a>                         s++;
       +<a href="#l652" class="line" id="l652">    652</a>         }
       +<a href="#l653" class="line" id="l653">    653</a> 
       +<a href="#l654" class="line" id="l654">    654</a>         /* skip milliseconds in for example: &quot;%Y-%m-%dT%H:%M:%S.000Z&quot; */
       +<a href="#l655" class="line" id="l655">    655</a>         if (*s == &#39;.&#39;) {
       +<a href="#l656" class="line" id="l656">    656</a>                 for (s++; ISDIGIT((unsigned char)*s); s++)
       +<a href="#l657" class="line" id="l657">    657</a>                         ;
       +<a href="#l658" class="line" id="l658">    658</a>         }
       +<a href="#l659" class="line" id="l659">    659</a> 
       +<a href="#l660" class="line" id="l660">    660</a>         /* invalid range */
       +<a href="#l661" class="line" id="l661">    661</a>         if (va[0] &lt; 0 || va[0] &gt; 9999 ||
       +<a href="#l662" class="line" id="l662">    662</a>             va[1] &lt; 1 || va[1] &gt; 12 ||
       +<a href="#l663" class="line" id="l663">    663</a>             va[2] &lt; 1 || va[2] &gt; 31 ||
       +<a href="#l664" class="line" id="l664">    664</a>             va[3] &lt; 0 || va[3] &gt; 23 ||
       +<a href="#l665" class="line" id="l665">    665</a>             va[4] &lt; 0 || va[4] &gt; 59 ||
       +<a href="#l666" class="line" id="l666">    666</a>             va[5] &lt; 0 || va[5] &gt; 60) /* allow leap second */
       +<a href="#l667" class="line" id="l667">    667</a>                 return -1;
       +<a href="#l668" class="line" id="l668">    668</a> 
       +<a href="#l669" class="line" id="l669">    669</a>         *tp = datetounix(va[0] - 1900, va[1] - 1, va[2], va[3], va[4], va[5]) -
       +<a href="#l670" class="line" id="l670">    670</a>               gettzoffset(s);
       +<a href="#l671" class="line" id="l671">    671</a> 
       +<a href="#l672" class="line" id="l672">    672</a>         return 0;
       +<a href="#l673" class="line" id="l673">    673</a> }
       +<a href="#l674" class="line" id="l674">    674</a> 
       +<a href="#l675" class="line" id="l675">    675</a> static void
       +<a href="#l676" class="line" id="l676">    676</a> printfields(void)
       +<a href="#l677" class="line" id="l677">    677</a> {
       +<a href="#l678" class="line" id="l678">    678</a>         string_print_timestamp(&amp;ctx.fields[FeedFieldTime].str);
       +<a href="#l679" class="line" id="l679">    679</a>         putchar(FieldSeparator);
       +<a href="#l680" class="line" id="l680">    680</a>         string_print_trimmed(&amp;ctx.fields[FeedFieldTitle].str);
       +<a href="#l681" class="line" id="l681">    681</a>         putchar(FieldSeparator);
       +<a href="#l682" class="line" id="l682">    682</a>         string_print_uri(&amp;ctx.fields[FeedFieldLink].str);
       +<a href="#l683" class="line" id="l683">    683</a>         putchar(FieldSeparator);
       +<a href="#l684" class="line" id="l684">    684</a>         string_print_encoded(&amp;ctx.fields[FeedFieldContent].str);
       +<a href="#l685" class="line" id="l685">    685</a>         putchar(FieldSeparator);
       +<a href="#l686" class="line" id="l686">    686</a>         fputs(contenttypes[ctx.contenttype], stdout);
       +<a href="#l687" class="line" id="l687">    687</a>         putchar(FieldSeparator);
       +<a href="#l688" class="line" id="l688">    688</a>         string_print_trimmed(&amp;ctx.fields[FeedFieldId].str);
       +<a href="#l689" class="line" id="l689">    689</a>         putchar(FieldSeparator);
       +<a href="#l690" class="line" id="l690">    690</a>         string_print_trimmed(&amp;ctx.fields[FeedFieldAuthor].str);
       +<a href="#l691" class="line" id="l691">    691</a>         putchar(FieldSeparator);
       +<a href="#l692" class="line" id="l692">    692</a>         string_print_uri(&amp;ctx.fields[FeedFieldEnclosure].str);
       +<a href="#l693" class="line" id="l693">    693</a>         putchar(FieldSeparator);
       +<a href="#l694" class="line" id="l694">    694</a>         string_print_trimmed_multi(&amp;ctx.fields[FeedFieldCategory].str);
       +<a href="#l695" class="line" id="l695">    695</a>         putchar(&#39;\n&#39;);
       +<a href="#l696" class="line" id="l696">    696</a> 
       +<a href="#l697" class="line" id="l697">    697</a>         if (ferror(stdout)) /* check for errors but do not flush */
       +<a href="#l698" class="line" id="l698">    698</a>                 checkfileerror(stdout, &quot;&lt;stdout&gt;&quot;, &#39;w&#39;);
       +<a href="#l699" class="line" id="l699">    699</a> }
       +<a href="#l700" class="line" id="l700">    700</a> 
       +<a href="#l701" class="line" id="l701">    701</a> static int
       +<a href="#l702" class="line" id="l702">    702</a> istag(const char *name, size_t len, const char *name2, size_t len2)
       +<a href="#l703" class="line" id="l703">    703</a> {
       +<a href="#l704" class="line" id="l704">    704</a>         return (len == len2 &amp;&amp; !strcasecmp(name, name2));
       +<a href="#l705" class="line" id="l705">    705</a> }
       +<a href="#l706" class="line" id="l706">    706</a> 
       +<a href="#l707" class="line" id="l707">    707</a> static int
       +<a href="#l708" class="line" id="l708">    708</a> isattr(const char *name, size_t len, const char *name2, size_t len2)
       +<a href="#l709" class="line" id="l709">    709</a> {
       +<a href="#l710" class="line" id="l710">    710</a>         return (len == len2 &amp;&amp; !strcasecmp(name, name2));
       +<a href="#l711" class="line" id="l711">    711</a> }
       +<a href="#l712" class="line" id="l712">    712</a> 
       +<a href="#l713" class="line" id="l713">    713</a> static void
       +<a href="#l714" class="line" id="l714">    714</a> xmlattr(XMLParser *p, const char *t, size_t tl, const char *n, size_t nl,
       +<a href="#l715" class="line" id="l715">    715</a>         const char *v, size_t vl)
       +<a href="#l716" class="line" id="l716">    716</a> {
       +<a href="#l717" class="line" id="l717">    717</a>         /* handles transforming inline XML to data */
       +<a href="#l718" class="line" id="l718">    718</a>         if (ISINCONTENT(ctx)) {
       +<a href="#l719" class="line" id="l719">    719</a>                 if (ctx.contenttype == ContentTypeHTML)
       +<a href="#l720" class="line" id="l720">    720</a>                         xmldata(p, v, vl);
       +<a href="#l721" class="line" id="l721">    721</a>                 return;
       +<a href="#l722" class="line" id="l722">    722</a>         }
       +<a href="#l723" class="line" id="l723">    723</a> 
       +<a href="#l724" class="line" id="l724">    724</a>         if (!ctx.tag.id)
       +<a href="#l725" class="line" id="l725">    725</a>                 return;
       +<a href="#l726" class="line" id="l726">    726</a> 
       +<a href="#l727" class="line" id="l727">    727</a>         /* content-type may be for Atom: text, xhtml, html or a mime-type.
       +<a href="#l728" class="line" id="l728">    728</a>            for MRSS (media:description): plain, html. */
       +<a href="#l729" class="line" id="l729">    729</a>         if (ISCONTENTTAG(ctx)) {
       +<a href="#l730" class="line" id="l730">    730</a>                 if (isattr(n, nl, STRP(&quot;type&quot;)))
       +<a href="#l731" class="line" id="l731">    731</a>                         string_append(&amp;attrtype, v, vl);
       +<a href="#l732" class="line" id="l732">    732</a>                 return;
       +<a href="#l733" class="line" id="l733">    733</a>         }
       +<a href="#l734" class="line" id="l734">    734</a> 
       +<a href="#l735" class="line" id="l735">    735</a>         if (ctx.feedtype == FeedTypeRSS) {
       +<a href="#l736" class="line" id="l736">    736</a>                 if (ctx.tag.id == RSSTagEnclosure &amp;&amp;
       +<a href="#l737" class="line" id="l737">    737</a>                     isattr(n, nl, STRP(&quot;url&quot;))) {
       +<a href="#l738" class="line" id="l738">    738</a>                         string_append(&amp;tmpstr, v, vl);
       +<a href="#l739" class="line" id="l739">    739</a>                 } else if (ctx.tag.id == RSSTagGuid &amp;&amp;
       +<a href="#l740" class="line" id="l740">    740</a>                            isattr(n, nl, STRP(&quot;ispermalink&quot;))) {
       +<a href="#l741" class="line" id="l741">    741</a>                         string_append(&amp;attrispermalink, v, vl);
       +<a href="#l742" class="line" id="l742">    742</a>                 }
       +<a href="#l743" class="line" id="l743">    743</a>         } else if (ctx.feedtype == FeedTypeAtom) {
       +<a href="#l744" class="line" id="l744">    744</a>                 if (ctx.tag.id == AtomTagLink) {
       +<a href="#l745" class="line" id="l745">    745</a>                         if (isattr(n, nl, STRP(&quot;rel&quot;))) {
       +<a href="#l746" class="line" id="l746">    746</a>                                 string_append(&amp;attrrel, v, vl);
       +<a href="#l747" class="line" id="l747">    747</a>                         } else if (isattr(n, nl, STRP(&quot;href&quot;))) {
       +<a href="#l748" class="line" id="l748">    748</a>                                 string_append(&amp;tmpstr, v, vl);
       +<a href="#l749" class="line" id="l749">    749</a>                         }
       +<a href="#l750" class="line" id="l750">    750</a>                 } else if (ctx.tag.id == AtomTagCategory &amp;&amp;
       +<a href="#l751" class="line" id="l751">    751</a>                            isattr(n, nl, STRP(&quot;term&quot;))) {
       +<a href="#l752" class="line" id="l752">    752</a>                         string_append(&amp;tmpstr, v, vl);
       +<a href="#l753" class="line" id="l753">    753</a>                 }
       +<a href="#l754" class="line" id="l754">    754</a>         }
       +<a href="#l755" class="line" id="l755">    755</a> }
       +<a href="#l756" class="line" id="l756">    756</a> 
       +<a href="#l757" class="line" id="l757">    757</a> static void
       +<a href="#l758" class="line" id="l758">    758</a> xmlattrentity(XMLParser *p, const char *t, size_t tl, const char *n, size_t nl,
       +<a href="#l759" class="line" id="l759">    759</a>               const char *data, size_t datalen)
       +<a href="#l760" class="line" id="l760">    760</a> {
       +<a href="#l761" class="line" id="l761">    761</a>         char buf[8];
       +<a href="#l762" class="line" id="l762">    762</a>         int len;
       +<a href="#l763" class="line" id="l763">    763</a> 
       +<a href="#l764" class="line" id="l764">    764</a>         /* handles transforming inline XML to data */
       +<a href="#l765" class="line" id="l765">    765</a>         if (ISINCONTENT(ctx)) {
       +<a href="#l766" class="line" id="l766">    766</a>                 if (ctx.contenttype == ContentTypeHTML)
       +<a href="#l767" class="line" id="l767">    767</a>                         xmldata(p, data, datalen);
       +<a href="#l768" class="line" id="l768">    768</a>                 return;
       +<a href="#l769" class="line" id="l769">    769</a>         }
       +<a href="#l770" class="line" id="l770">    770</a> 
       +<a href="#l771" class="line" id="l771">    771</a>         if (!ctx.tag.id)
       +<a href="#l772" class="line" id="l772">    772</a>                 return;
       +<a href="#l773" class="line" id="l773">    773</a> 
       +<a href="#l774" class="line" id="l774">    774</a>         /* try to translate entity, else just pass as data to
       +<a href="#l775" class="line" id="l775">    775</a>          * xmlattr handler. */
       +<a href="#l776" class="line" id="l776">    776</a>         if ((len = xml_entitytostr(data, buf, sizeof(buf))) &gt; 0)
       +<a href="#l777" class="line" id="l777">    777</a>                 xmlattr(p, t, tl, n, nl, buf, (size_t)len);
       +<a href="#l778" class="line" id="l778">    778</a>         else
       +<a href="#l779" class="line" id="l779">    779</a>                 xmlattr(p, t, tl, n, nl, data, datalen);
       +<a href="#l780" class="line" id="l780">    780</a> }
       +<a href="#l781" class="line" id="l781">    781</a> 
       +<a href="#l782" class="line" id="l782">    782</a> static void
       +<a href="#l783" class="line" id="l783">    783</a> xmlattrend(XMLParser *p, const char *t, size_t tl, const char *n, size_t nl)
       +<a href="#l784" class="line" id="l784">    784</a> {
       +<a href="#l785" class="line" id="l785">    785</a>         if (ISINCONTENT(ctx)) {
       +<a href="#l786" class="line" id="l786">    786</a>                 if (ctx.contenttype == ContentTypeHTML) {
       +<a href="#l787" class="line" id="l787">    787</a>                         /* handles transforming inline XML to data */
       +<a href="#l788" class="line" id="l788">    788</a>                         xmldata(p, &quot;\&quot;&quot;, 1);
       +<a href="#l789" class="line" id="l789">    789</a>                         ctx.attrcount = 0;
       +<a href="#l790" class="line" id="l790">    790</a>                 }
       +<a href="#l791" class="line" id="l791">    791</a>                 return;
       +<a href="#l792" class="line" id="l792">    792</a>         }
       +<a href="#l793" class="line" id="l793">    793</a> }
       +<a href="#l794" class="line" id="l794">    794</a> 
       +<a href="#l795" class="line" id="l795">    795</a> static void
       +<a href="#l796" class="line" id="l796">    796</a> xmlattrstart(XMLParser *p, const char *t, size_t tl, const char *n, size_t nl)
       +<a href="#l797" class="line" id="l797">    797</a> {
       +<a href="#l798" class="line" id="l798">    798</a>         if (ISINCONTENT(ctx)) {
       +<a href="#l799" class="line" id="l799">    799</a>                 if (ctx.contenttype == ContentTypeHTML) {
       +<a href="#l800" class="line" id="l800">    800</a>                         /* handles transforming inline XML to data */
       +<a href="#l801" class="line" id="l801">    801</a>                         if (!ctx.attrcount)
       +<a href="#l802" class="line" id="l802">    802</a>                                 xmldata(p, &quot; &quot;, 1);
       +<a href="#l803" class="line" id="l803">    803</a>                         ctx.attrcount++;
       +<a href="#l804" class="line" id="l804">    804</a>                         xmldata(p, n, nl);
       +<a href="#l805" class="line" id="l805">    805</a>                         xmldata(p, &quot;=\&quot;&quot;, 2);
       +<a href="#l806" class="line" id="l806">    806</a>                 }
       +<a href="#l807" class="line" id="l807">    807</a>                 return;
       +<a href="#l808" class="line" id="l808">    808</a>         }
       +<a href="#l809" class="line" id="l809">    809</a> 
       +<a href="#l810" class="line" id="l810">    810</a>         if (attrispermalink.len &amp;&amp; isattr(n, nl, STRP(&quot;ispermalink&quot;)))
       +<a href="#l811" class="line" id="l811">    811</a>                 string_clear(&amp;attrispermalink);
       +<a href="#l812" class="line" id="l812">    812</a>         else if (attrrel.len &amp;&amp; isattr(n, nl, STRP(&quot;rel&quot;)))
       +<a href="#l813" class="line" id="l813">    813</a>                 string_clear(&amp;attrrel);
       +<a href="#l814" class="line" id="l814">    814</a>         else if (attrtype.len &amp;&amp; isattr(n, nl, STRP(&quot;type&quot;)))
       +<a href="#l815" class="line" id="l815">    815</a>                 string_clear(&amp;attrtype);
       +<a href="#l816" class="line" id="l816">    816</a>         else if (tmpstr.len &amp;&amp;
       +<a href="#l817" class="line" id="l817">    817</a>             (isattr(n, nl, STRP(&quot;href&quot;)) ||
       +<a href="#l818" class="line" id="l818">    818</a>              isattr(n, nl, STRP(&quot;term&quot;)) ||
       +<a href="#l819" class="line" id="l819">    819</a>              isattr(n, nl, STRP(&quot;url&quot;))))
       +<a href="#l820" class="line" id="l820">    820</a>                 string_clear(&amp;tmpstr); /* use the last value for multiple attribute values */
       +<a href="#l821" class="line" id="l821">    821</a> }
       +<a href="#l822" class="line" id="l822">    822</a> 
       +<a href="#l823" class="line" id="l823">    823</a> static void
       +<a href="#l824" class="line" id="l824">    824</a> xmldata(XMLParser *p, const char *s, size_t len)
       +<a href="#l825" class="line" id="l825">    825</a> {
       +<a href="#l826" class="line" id="l826">    826</a>         if (!ctx.field)
       +<a href="#l827" class="line" id="l827">    827</a>                 return;
       +<a href="#l828" class="line" id="l828">    828</a> 
       +<a href="#l829" class="line" id="l829">    829</a>         if (ISFEEDFIELDMULTI(fieldmap[ctx.tag.id]))
       +<a href="#l830" class="line" id="l830">    830</a>                 string_append(&amp;tmpstr, s, len);
       +<a href="#l831" class="line" id="l831">    831</a>         else
       +<a href="#l832" class="line" id="l832">    832</a>                 string_append(ctx.field, s, len);
       +<a href="#l833" class="line" id="l833">    833</a> }
       +<a href="#l834" class="line" id="l834">    834</a> 
       +<a href="#l835" class="line" id="l835">    835</a> static void
       +<a href="#l836" class="line" id="l836">    836</a> xmldataentity(XMLParser *p, const char *data, size_t datalen)
       +<a href="#l837" class="line" id="l837">    837</a> {
       +<a href="#l838" class="line" id="l838">    838</a>         char buf[8];
       +<a href="#l839" class="line" id="l839">    839</a>         int len;
       +<a href="#l840" class="line" id="l840">    840</a> 
       +<a href="#l841" class="line" id="l841">    841</a>         if (!ctx.field)
       +<a href="#l842" class="line" id="l842">    842</a>                 return;
       +<a href="#l843" class="line" id="l843">    843</a> 
       +<a href="#l844" class="line" id="l844">    844</a>         /* try to translate entity, else just pass as data to
       +<a href="#l845" class="line" id="l845">    845</a>          * xmldata handler. */
       +<a href="#l846" class="line" id="l846">    846</a>         if ((len = xml_entitytostr(data, buf, sizeof(buf))) &gt; 0)
       +<a href="#l847" class="line" id="l847">    847</a>                 xmldata(p, buf, (size_t)len);
       +<a href="#l848" class="line" id="l848">    848</a>         else
       +<a href="#l849" class="line" id="l849">    849</a>                 xmldata(p, data, datalen);
       +<a href="#l850" class="line" id="l850">    850</a> }
       +<a href="#l851" class="line" id="l851">    851</a> 
       +<a href="#l852" class="line" id="l852">    852</a> static void
       +<a href="#l853" class="line" id="l853">    853</a> xmltagstart(XMLParser *p, const char *t, size_t tl)
       +<a href="#l854" class="line" id="l854">    854</a> {
       +<a href="#l855" class="line" id="l855">    855</a>         const FeedTag *f;
       +<a href="#l856" class="line" id="l856">    856</a> 
       +<a href="#l857" class="line" id="l857">    857</a>         if (ISINCONTENT(ctx)) {
       +<a href="#l858" class="line" id="l858">    858</a>                 if (ctx.contenttype == ContentTypeHTML) {
       +<a href="#l859" class="line" id="l859">    859</a>                         ctx.attrcount = 0;
       +<a href="#l860" class="line" id="l860">    860</a>                         xmldata(p, &quot;&lt;&quot;, 1);
       +<a href="#l861" class="line" id="l861">    861</a>                         xmldata(p, t, tl);
       +<a href="#l862" class="line" id="l862">    862</a>                 }
       +<a href="#l863" class="line" id="l863">    863</a>                 return;
       +<a href="#l864" class="line" id="l864">    864</a>         }
       +<a href="#l865" class="line" id="l865">    865</a> 
       +<a href="#l866" class="line" id="l866">    866</a>         /* start of RSS or Atom item / entry */
       +<a href="#l867" class="line" id="l867">    867</a>         if (ctx.feedtype == FeedTypeNone) {
       +<a href="#l868" class="line" id="l868">    868</a>                 if (istag(t, tl, STRP(&quot;entry&quot;)))
       +<a href="#l869" class="line" id="l869">    869</a>                         ctx.feedtype = FeedTypeAtom;
       +<a href="#l870" class="line" id="l870">    870</a>                 else if (istag(t, tl, STRP(&quot;item&quot;)))
       +<a href="#l871" class="line" id="l871">    871</a>                         ctx.feedtype = FeedTypeRSS;
       +<a href="#l872" class="line" id="l872">    872</a>                 return;
       +<a href="#l873" class="line" id="l873">    873</a>         }
       +<a href="#l874" class="line" id="l874">    874</a> 
       +<a href="#l875" class="line" id="l875">    875</a>         /* field tagid already set or nested tags. */
       +<a href="#l876" class="line" id="l876">    876</a>         if (ctx.tag.id) {
       +<a href="#l877" class="line" id="l877">    877</a>                 /* nested &lt;author&gt;&lt;name&gt; for Atom */
       +<a href="#l878" class="line" id="l878">    878</a>                 if (ctx.tag.id == AtomTagAuthor &amp;&amp;
       +<a href="#l879" class="line" id="l879">    879</a>                     istag(t, tl, STRP(&quot;name&quot;))) {
       +<a href="#l880" class="line" id="l880">    880</a>                         memcpy(&amp;(ctx.tag), &amp;atomtagauthorname, sizeof(ctx.tag));
       +<a href="#l881" class="line" id="l881">    881</a>                 } else {
       +<a href="#l882" class="line" id="l882">    882</a>                         return; /* other nested tags are not allowed: return */
       +<a href="#l883" class="line" id="l883">    883</a>                 }
       +<a href="#l884" class="line" id="l884">    884</a>         }
       +<a href="#l885" class="line" id="l885">    885</a> 
       +<a href="#l886" class="line" id="l886">    886</a>         /* in item */
       +<a href="#l887" class="line" id="l887">    887</a>         if (ctx.tag.id == TagUnknown) {
       +<a href="#l888" class="line" id="l888">    888</a>                 if (!(f = gettag(ctx.feedtype, t, tl)))
       +<a href="#l889" class="line" id="l889">    889</a>                         f = &amp;notag;
       +<a href="#l890" class="line" id="l890">    890</a>                 memcpy(&amp;(ctx.tag), f, sizeof(ctx.tag));
       +<a href="#l891" class="line" id="l891">    891</a>         }
       +<a href="#l892" class="line" id="l892">    892</a> 
       +<a href="#l893" class="line" id="l893">    893</a>         ctx.iscontenttag = (fieldmap[ctx.tag.id] == FeedFieldContent);
       +<a href="#l894" class="line" id="l894">    894</a>         string_clear(&amp;attrispermalink);
       +<a href="#l895" class="line" id="l895">    895</a>         string_clear(&amp;attrrel);
       +<a href="#l896" class="line" id="l896">    896</a>         string_clear(&amp;attrtype);
       +<a href="#l897" class="line" id="l897">    897</a> }
       +<a href="#l898" class="line" id="l898">    898</a> 
       +<a href="#l899" class="line" id="l899">    899</a> static void
       +<a href="#l900" class="line" id="l900">    900</a> xmltagstartparsed(XMLParser *p, const char *t, size_t tl, int isshort)
       +<a href="#l901" class="line" id="l901">    901</a> {
       +<a href="#l902" class="line" id="l902">    902</a>         enum TagId tagid;
       +<a href="#l903" class="line" id="l903">    903</a> 
       +<a href="#l904" class="line" id="l904">    904</a>         if (ISINCONTENT(ctx)) {
       +<a href="#l905" class="line" id="l905">    905</a>                 if (ctx.contenttype == ContentTypeHTML) {
       +<a href="#l906" class="line" id="l906">    906</a>                         if (isshort)
       +<a href="#l907" class="line" id="l907">    907</a>                                 xmldata(p, &quot;/&gt;&quot;, 2);
       +<a href="#l908" class="line" id="l908">    908</a>                         else
       +<a href="#l909" class="line" id="l909">    909</a>                                 xmldata(p, &quot;&gt;&quot;, 1);
       +<a href="#l910" class="line" id="l910">    910</a>                 }
       +<a href="#l911" class="line" id="l911">    911</a>                 return;
       +<a href="#l912" class="line" id="l912">    912</a>         }
       +<a href="#l913" class="line" id="l913">    913</a> 
       +<a href="#l914" class="line" id="l914">    914</a>         /* set tag type based on its attribute value */
       +<a href="#l915" class="line" id="l915">    915</a>         if (ctx.tag.id == RSSTagGuid) {
       +<a href="#l916" class="line" id="l916">    916</a>                 /* if empty the default is &quot;true&quot; */
       +<a href="#l917" class="line" id="l917">    917</a>                 if (!attrispermalink.len ||
       +<a href="#l918" class="line" id="l918">    918</a>                     isattr(attrispermalink.data, attrispermalink.len, STRP(&quot;true&quot;)))
       +<a href="#l919" class="line" id="l919">    919</a>                         ctx.tag.id = RSSTagGuidPermalinkTrue;
       +<a href="#l920" class="line" id="l920">    920</a>                 else
       +<a href="#l921" class="line" id="l921">    921</a>                         ctx.tag.id = RSSTagGuidPermalinkFalse;
       +<a href="#l922" class="line" id="l922">    922</a>         } else if (ctx.tag.id == AtomTagLink) {
       +<a href="#l923" class="line" id="l923">    923</a>                 /* empty or &quot;alternate&quot;: other types could be
       +<a href="#l924" class="line" id="l924">    924</a>                    &quot;enclosure&quot;, &quot;related&quot;, &quot;self&quot; or &quot;via&quot; */
       +<a href="#l925" class="line" id="l925">    925</a>                 if (!attrrel.len || isattr(attrrel.data, attrrel.len, STRP(&quot;alternate&quot;)))
       +<a href="#l926" class="line" id="l926">    926</a>                         ctx.tag.id = AtomTagLinkAlternate;
       +<a href="#l927" class="line" id="l927">    927</a>                 else if (isattr(attrrel.data, attrrel.len, STRP(&quot;enclosure&quot;)))
       +<a href="#l928" class="line" id="l928">    928</a>                         ctx.tag.id = AtomTagLinkEnclosure;
       +<a href="#l929" class="line" id="l929">    929</a>                 else
       +<a href="#l930" class="line" id="l930">    930</a>                         ctx.tag.id = AtomTagLink; /* unknown */
       +<a href="#l931" class="line" id="l931">    931</a>         }
       +<a href="#l932" class="line" id="l932">    932</a> 
       +<a href="#l933" class="line" id="l933">    933</a>         tagid = ctx.tag.id;
       +<a href="#l934" class="line" id="l934">    934</a> 
       +<a href="#l935" class="line" id="l935">    935</a>         /* map tag type to field: unknown or lesser priority is ignored,
       +<a href="#l936" class="line" id="l936">    936</a>            when tags of the same type are repeated only the first is used. */
       +<a href="#l937" class="line" id="l937">    937</a>         if (fieldmap[tagid] == -1 ||
       +<a href="#l938" class="line" id="l938">    938</a>             (!ISFEEDFIELDMULTI(fieldmap[tagid]) &amp;&amp;
       +<a href="#l939" class="line" id="l939">    939</a>              tagid &lt;= ctx.fields[fieldmap[tagid]].tagid)) {
       +<a href="#l940" class="line" id="l940">    940</a>                 return;
       +<a href="#l941" class="line" id="l941">    941</a>         }
       +<a href="#l942" class="line" id="l942">    942</a> 
       +<a href="#l943" class="line" id="l943">    943</a>         if (ctx.iscontenttag) {
       +<a href="#l944" class="line" id="l944">    944</a>                 ctx.iscontent = 1;
       +<a href="#l945" class="line" id="l945">    945</a>                 ctx.iscontenttag = 0;
       +<a href="#l946" class="line" id="l946">    946</a> 
       +<a href="#l947" class="line" id="l947">    947</a>                 /* detect content-type based on type attribute */
       +<a href="#l948" class="line" id="l948">    948</a>                 if (attrtype.len) {
       +<a href="#l949" class="line" id="l949">    949</a>                         if (isattr(attrtype.data, attrtype.len, STRP(&quot;html&quot;)) ||
       +<a href="#l950" class="line" id="l950">    950</a>                             isattr(attrtype.data, attrtype.len, STRP(&quot;xhtml&quot;)) ||
       +<a href="#l951" class="line" id="l951">    951</a>                             isattr(attrtype.data, attrtype.len, STRP(&quot;text/html&quot;)) ||
       +<a href="#l952" class="line" id="l952">    952</a>                             isattr(attrtype.data, attrtype.len, STRP(&quot;text/xhtml&quot;)) ||
       +<a href="#l953" class="line" id="l953">    953</a>                             isattr(attrtype.data, attrtype.len, STRP(&quot;application/xhtml+xml&quot;)))
       +<a href="#l954" class="line" id="l954">    954</a>                                 ctx.contenttype = ContentTypeHTML;
       +<a href="#l955" class="line" id="l955">    955</a>                         else /* unknown: handle as base64 text data */
       +<a href="#l956" class="line" id="l956">    956</a>                                 ctx.contenttype = ContentTypePlain;
       +<a href="#l957" class="line" id="l957">    957</a>                 } else {
       +<a href="#l958" class="line" id="l958">    958</a>                         /* default content-type */
       +<a href="#l959" class="line" id="l959">    959</a>                         if (tagid == RSSTagContentEncoded || tagid == RSSTagDescription)
       +<a href="#l960" class="line" id="l960">    960</a>                                 ctx.contenttype = ContentTypeHTML;
       +<a href="#l961" class="line" id="l961">    961</a>                         else
       +<a href="#l962" class="line" id="l962">    962</a>                                 ctx.contenttype = ContentTypePlain;
       +<a href="#l963" class="line" id="l963">    963</a>                 }
       +<a href="#l964" class="line" id="l964">    964</a>         }
       +<a href="#l965" class="line" id="l965">    965</a> 
       +<a href="#l966" class="line" id="l966">    966</a>         ctx.field = &amp;(ctx.fields[fieldmap[tagid]].str);
       +<a href="#l967" class="line" id="l967">    967</a>         ctx.fields[fieldmap[tagid]].tagid = tagid;
       +<a href="#l968" class="line" id="l968">    968</a> 
       +<a href="#l969" class="line" id="l969">    969</a>         /* clear field if it is overwritten (with a priority order) for the new
       +<a href="#l970" class="line" id="l970">    970</a>            value, if the field can have multiple values then do not clear it. */
       +<a href="#l971" class="line" id="l971">    971</a>         if (!ISFEEDFIELDMULTI(fieldmap[ctx.tag.id]))
       +<a href="#l972" class="line" id="l972">    972</a>                 string_clear(ctx.field);
       +<a href="#l973" class="line" id="l973">    973</a> }
       +<a href="#l974" class="line" id="l974">    974</a> 
       +<a href="#l975" class="line" id="l975">    975</a> static void
       +<a href="#l976" class="line" id="l976">    976</a> xmltagend(XMLParser *p, const char *t, size_t tl, int isshort)
       +<a href="#l977" class="line" id="l977">    977</a> {
       +<a href="#l978" class="line" id="l978">    978</a>         size_t i;
       +<a href="#l979" class="line" id="l979">    979</a> 
       +<a href="#l980" class="line" id="l980">    980</a>         if (ctx.feedtype == FeedTypeNone)
       +<a href="#l981" class="line" id="l981">    981</a>                 return;
       +<a href="#l982" class="line" id="l982">    982</a> 
       +<a href="#l983" class="line" id="l983">    983</a>         if (ISINCONTENT(ctx)) {
       +<a href="#l984" class="line" id="l984">    984</a>                 /* not a closed content field */
       +<a href="#l985" class="line" id="l985">    985</a>                 if (!istag(ctx.tag.name, ctx.tag.len, t, tl)) {
       +<a href="#l986" class="line" id="l986">    986</a>                         if (!isshort &amp;&amp; ctx.contenttype == ContentTypeHTML) {
       +<a href="#l987" class="line" id="l987">    987</a>                                 xmldata(p, &quot;&lt;/&quot;, 2);
       +<a href="#l988" class="line" id="l988">    988</a>                                 xmldata(p, t, tl);
       +<a href="#l989" class="line" id="l989">    989</a>                                 xmldata(p, &quot;&gt;&quot;, 1);
       +<a href="#l990" class="line" id="l990">    990</a>                         }
       +<a href="#l991" class="line" id="l991">    991</a>                         return;
       +<a href="#l992" class="line" id="l992">    992</a>                 }
       +<a href="#l993" class="line" id="l993">    993</a>         } else if (ctx.tag.id &amp;&amp; istag(ctx.tag.name, ctx.tag.len, t, tl)) {
       +<a href="#l994" class="line" id="l994">    994</a>                 /* matched tag end: close it */
       +<a href="#l995" class="line" id="l995">    995</a>                 /* copy also to the link field if the attribute isPermaLink=&quot;true&quot;
       +<a href="#l996" class="line" id="l996">    996</a>                    and it is not set by a tag with higher priority. */
       +<a href="#l997" class="line" id="l997">    997</a>                 if (ctx.tag.id == RSSTagGuidPermalinkTrue &amp;&amp; ctx.field &amp;&amp;
       +<a href="#l998" class="line" id="l998">    998</a>                     ctx.tag.id &gt; ctx.fields[FeedFieldLink].tagid) {
       +<a href="#l999" class="line" id="l999">    999</a>                         string_clear(&amp;ctx.fields[FeedFieldLink].str);
       +<a href="#l1000" class="line" id="l1000">   1000</a>                         string_append(&amp;ctx.fields[FeedFieldLink].str,
       +<a href="#l1001" class="line" id="l1001">   1001</a>                                       ctx.field-&gt;data, ctx.field-&gt;len);
       +<a href="#l1002" class="line" id="l1002">   1002</a>                         ctx.fields[FeedFieldLink].tagid = ctx.tag.id;
       +<a href="#l1003" class="line" id="l1003">   1003</a>                 }
       +<a href="#l1004" class="line" id="l1004">   1004</a>         } else if (!ctx.tag.id &amp;&amp; ((ctx.feedtype == FeedTypeAtom &amp;&amp;
       +<a href="#l1005" class="line" id="l1005">   1005</a>            istag(t, tl, STRP(&quot;entry&quot;))) || /* Atom */
       +<a href="#l1006" class="line" id="l1006">   1006</a>            (ctx.feedtype == FeedTypeRSS &amp;&amp;
       +<a href="#l1007" class="line" id="l1007">   1007</a>            istag(t, tl, STRP(&quot;item&quot;))))) /* RSS */
       +<a href="#l1008" class="line" id="l1008">   1008</a>         {
       +<a href="#l1009" class="line" id="l1009">   1009</a>                 /* end of RSS or Atom entry / item */
       +<a href="#l1010" class="line" id="l1010">   1010</a>                 printfields();
       +<a href="#l1011" class="line" id="l1011">   1011</a> 
       +<a href="#l1012" class="line" id="l1012">   1012</a>                 /* clear strings */
       +<a href="#l1013" class="line" id="l1013">   1013</a>                 for (i = 0; i &lt; FeedFieldLast; i++) {
       +<a href="#l1014" class="line" id="l1014">   1014</a>                         string_clear(&amp;ctx.fields[i].str);
       +<a href="#l1015" class="line" id="l1015">   1015</a>                         ctx.fields[i].tagid = TagUnknown;
       +<a href="#l1016" class="line" id="l1016">   1016</a>                 }
       +<a href="#l1017" class="line" id="l1017">   1017</a>                 ctx.contenttype = ContentTypeNone;
       +<a href="#l1018" class="line" id="l1018">   1018</a>                 /* allow parsing of Atom and RSS concatenated in one XML stream. */
       +<a href="#l1019" class="line" id="l1019">   1019</a>                 ctx.feedtype = FeedTypeNone;
       +<a href="#l1020" class="line" id="l1020">   1020</a>         } else {
       +<a href="#l1021" class="line" id="l1021">   1021</a>                 return; /* not end of field */
       +<a href="#l1022" class="line" id="l1022">   1022</a>         }
       +<a href="#l1023" class="line" id="l1023">   1023</a> 
       +<a href="#l1024" class="line" id="l1024">   1024</a>         /* temporary string: for fields that cannot be processed
       +<a href="#l1025" class="line" id="l1025">   1025</a>            directly and need more context, for example by its tag
       +<a href="#l1026" class="line" id="l1026">   1026</a>            attributes, like the Atom link rel=&quot;alternate|enclosure&quot;. */
       +<a href="#l1027" class="line" id="l1027">   1027</a>         if (tmpstr.len &amp;&amp; ctx.field) {
       +<a href="#l1028" class="line" id="l1028">   1028</a>                 if (ISFEEDFIELDMULTI(fieldmap[ctx.tag.id])) {
       +<a href="#l1029" class="line" id="l1029">   1029</a>                         if (ctx.field-&gt;len)
       +<a href="#l1030" class="line" id="l1030">   1030</a>                                 string_append(ctx.field, FieldMultiSeparator, 1);
       +<a href="#l1031" class="line" id="l1031">   1031</a>                         string_append(ctx.field, tmpstr.data, tmpstr.len);
       +<a href="#l1032" class="line" id="l1032">   1032</a>                 } else {
       +<a href="#l1033" class="line" id="l1033">   1033</a>                         string_clear(ctx.field);
       +<a href="#l1034" class="line" id="l1034">   1034</a>                         string_append(ctx.field, tmpstr.data, tmpstr.len);
       +<a href="#l1035" class="line" id="l1035">   1035</a>                 }
       +<a href="#l1036" class="line" id="l1036">   1036</a>         }
       +<a href="#l1037" class="line" id="l1037">   1037</a> 
       +<a href="#l1038" class="line" id="l1038">   1038</a>         /* close field */
       +<a href="#l1039" class="line" id="l1039">   1039</a>         string_clear(&amp;tmpstr); /* reuse and clear temporary string */
       +<a href="#l1040" class="line" id="l1040">   1040</a> 
       +<a href="#l1041" class="line" id="l1041">   1041</a>         if (ctx.tag.id == AtomTagAuthorName)
       +<a href="#l1042" class="line" id="l1042">   1042</a>                 memcpy(&amp;(ctx.tag), &amp;atomtagauthor, sizeof(ctx.tag)); /* outer tag */
       +<a href="#l1043" class="line" id="l1043">   1043</a>         else
       +<a href="#l1044" class="line" id="l1044">   1044</a>                 memcpy(&amp;(ctx.tag), &amp;notag, sizeof(ctx.tag));
       +<a href="#l1045" class="line" id="l1045">   1045</a> 
       +<a href="#l1046" class="line" id="l1046">   1046</a>         ctx.iscontent = 0;
       +<a href="#l1047" class="line" id="l1047">   1047</a>         ctx.field = NULL;
       +<a href="#l1048" class="line" id="l1048">   1048</a> }
       +<a href="#l1049" class="line" id="l1049">   1049</a> 
       +<a href="#l1050" class="line" id="l1050">   1050</a> int
       +<a href="#l1051" class="line" id="l1051">   1051</a> main(int argc, char *argv[])
       +<a href="#l1052" class="line" id="l1052">   1052</a> {
       +<a href="#l1053" class="line" id="l1053">   1053</a>         if (pledge(&quot;stdio&quot;, NULL) == -1)
       +<a href="#l1054" class="line" id="l1054">   1054</a>                 err(1, &quot;pledge&quot;);
       +<a href="#l1055" class="line" id="l1055">   1055</a> 
       +<a href="#l1056" class="line" id="l1056">   1056</a>         if (argc &gt; 1) {
       +<a href="#l1057" class="line" id="l1057">   1057</a>                 if (uri_parse(argv[1], &amp;baseuri) != -1 &amp;&amp; baseuri.proto[0])
       +<a href="#l1058" class="line" id="l1058">   1058</a>                         baseurl = argv[1];
       +<a href="#l1059" class="line" id="l1059">   1059</a>                 else
       +<a href="#l1060" class="line" id="l1060">   1060</a>                         errx(1, &quot;baseurl incorrect or too long&quot;);
       +<a href="#l1061" class="line" id="l1061">   1061</a>         }
       +<a href="#l1062" class="line" id="l1062">   1062</a> 
       +<a href="#l1063" class="line" id="l1063">   1063</a>         memcpy(&amp;(ctx.tag), &amp;notag, sizeof(ctx.tag));
       +<a href="#l1064" class="line" id="l1064">   1064</a> 
       +<a href="#l1065" class="line" id="l1065">   1065</a>         parser.xmlattr = xmlattr;
       +<a href="#l1066" class="line" id="l1066">   1066</a>         parser.xmlattrentity = xmlattrentity;
       +<a href="#l1067" class="line" id="l1067">   1067</a>         parser.xmlattrend = xmlattrend;
       +<a href="#l1068" class="line" id="l1068">   1068</a>         parser.xmlattrstart = xmlattrstart;
       +<a href="#l1069" class="line" id="l1069">   1069</a>         parser.xmlcdata = xmldata;
       +<a href="#l1070" class="line" id="l1070">   1070</a>         parser.xmldata = xmldata;
       +<a href="#l1071" class="line" id="l1071">   1071</a>         parser.xmldataentity = xmldataentity;
       +<a href="#l1072" class="line" id="l1072">   1072</a>         parser.xmltagend = xmltagend;
       +<a href="#l1073" class="line" id="l1073">   1073</a>         parser.xmltagstart = xmltagstart;
       +<a href="#l1074" class="line" id="l1074">   1074</a>         parser.xmltagstartparsed = xmltagstartparsed;
       +<a href="#l1075" class="line" id="l1075">   1075</a> 
       +<a href="#l1076" class="line" id="l1076">   1076</a>         /* NOTE: GETNEXT is defined in xml.h for inline optimization */
       +<a href="#l1077" class="line" id="l1077">   1077</a>         xml_parse(&amp;parser);
       +<a href="#l1078" class="line" id="l1078">   1078</a> 
       +<a href="#l1079" class="line" id="l1079">   1079</a>         checkfileerror(stdin, &quot;&lt;stdin&gt;&quot;, &#39;r&#39;);
       +<a href="#l1080" class="line" id="l1080">   1080</a>         checkfileerror(stdout, &quot;&lt;stdout&gt;&quot;, &#39;w&#39;);
       +<a href="#l1081" class="line" id="l1081">   1081</a> 
       +<a href="#l1082" class="line" id="l1082">   1082</a>         return 0;
       +<a href="#l1083" class="line" id="l1083">   1083</a> }
       +</pre>
       +</div>
       +</body>
       +</html>
 (DIR) diff --git a/tests/indent.html b/tests/indent.html
       @@ -0,0 +1,47 @@
       +<ul>
       +<li>test</li>
       +<li>test2</li>
       +<li>test3</li>
       +</ul>
       +
       +<ol>
       +<li>test</li>
       +<li>test2</li>
       +<li>test3</li>
       +<li>test</li>
       +<li>test</li>
       +<li>test</li>
       +<li>test</li>
       +<li>test</li>
       +<li>test</li>
       +<li>test</li>
       +<li>test</li>
       +<li>test</li>
       +<li>test</li>
       +</ol>
       +
       +<ul>
       +<li><div>test</div><div>another line</div></li>
       +<li><div>test</div><div>another line</div><div>and another</div></li>
       +<li><div>test</div><div>another line</div></li>
       +</ul>
       +
       +<h1>header 1</h1>
       +<p>some text</p>
       +<p>some text</p>
       +
       +<table>
       +<tr><td>text</td><td><hr/></td></tr>
       +<tr><td>text</td><td><hr/>some text</td></tr>
       +<tr><td>text</td><td><div><hr/></div></td></tr>
       +<tr><td>text</td><td><div><hr/>some text</div></td></tr>
       +</table>
       +
       +<ul>
       +<li>test<hr/></li>
       +<li>test2<hr/>text</li>
       +<li>test3</li>
       +<li><img alt="alt text" /></li>
       +</ul>
       +
       +<p><img alt="alt text" /></p>
 (DIR) diff --git a/tests/pre.html b/tests/pre.html
       @@ -1,19 +1,27 @@
       -<p>pre:</p>
       -
       -<pre>a
       -b
       -c</pre>
       -
       -
       -<p>code:</p>
       -
       -<code>a
       -b
       -c</code>
       -
       -
       -<p>code, pre:</p>
       -
       -<code><pre>a
       -b
       -c</pre></code>
       +<pre id="blob">
       +<a href="#l1" class="line" id="l1">      1</a> #include &lt;errno.h&gt;
       +<a href="#l2" class="line" id="l2">      2</a> #include &lt;stdint.h&gt;
       +<a href="#l3" class="line" id="l3">      3</a> #include &lt;stdio.h&gt;
       +<a href="#l4" class="line" id="l4">      4</a> #include &lt;stdlib.h&gt;
       +<a href="#l5" class="line" id="l5">      5</a> #include &lt;string.h&gt;
       +<a href="#l6" class="line" id="l6">      6</a> #include &lt;strings.h&gt;
       +<a href="#l7" class="line" id="l7">      7</a> 
       +<a href="#l8" class="line" id="l8">      8</a> #include &quot;util.h&quot;
       +<a href="#l9" class="line" id="l9">      9</a> #include &quot;xml.h&quot;
       +<a href="#l10" class="line" id="l10">     10</a> 
       +<a href="#l11" class="line" id="l11">     11</a> #define ISINCONTENT(ctx)  ((ctx).iscontent &amp;&amp; !((ctx).iscontenttag))
       +<a href="#l12" class="line" id="l12">     12</a> #define ISCONTENTTAG(ctx) (!((ctx).iscontent) &amp;&amp; (ctx).iscontenttag)
       +<a href="#l13" class="line" id="l13">     13</a> 
       +<a href="#l14" class="line" id="l14">     14</a> /* these feed fields support multiple separated values */
       +<a href="#l15" class="line" id="l15">     15</a> #define ISFEEDFIELDMULTI(t) ((t) == FeedFieldCategory)
       +<a href="#l16" class="line" id="l16">     16</a> 
       +<a href="#l17" class="line" id="l17">     17</a> /* string and byte-length */
       +<a href="#l18" class="line" id="l18">     18</a> #define STRP(s)           s,sizeof(s)-1
       +<a href="#l19" class="line" id="l19">     19</a> 
       +<a href="#l20" class="line" id="l20">     20</a> enum FeedType {
       +<a href="#l21" class="line" id="l21">     21</a>         FeedTypeNone = 0,
       +<a href="#l22" class="line" id="l22">     22</a>         FeedTypeRSS  = 1,
       +<a href="#l23" class="line" id="l23">     23</a>         FeedTypeAtom = 2
       +<a href="#l24" class="line" id="l24">     24</a> };
       +<a href="#l25" class="line" id="l25">     25</a> 
       +</pre>
 (DIR) diff --git a/tests/pre_code.html b/tests/pre_code.html
       @@ -0,0 +1,3 @@
       +<pre><code>test
       +test2
       +test3</code></pre>