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