]> git.mxchange.org Git - flightgear.git/blob - utils/xmlgrep/xml.c
forgot one small fix
[flightgear.git] / utils / xmlgrep / xml.c
1 /* Copyright (c) 2007, 2008 by Adalin B.V.
2  * Copyright (c) 2007, 2008 by Erik Hofman
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *      * Redistributions of source code must retain the above copyright
8  *         notice, this list of conditions and the following disclaimer.
9  *      * Redistributions in binary form must reproduce the above copyright
10  *         notice, this list of conditions and the following disclaimer in the
11  *         documentation and/or other materials provided with the distribution.
12  *      * Neither the name of (any of) the copyrightholder(s) nor the
13  *         names of its contributors may be used to endorse or promote products
14  *         derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
17  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
18  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
19  * THE COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #ifdef WIN32
29 #define WIN32_LEAN_AND_MEAN
30 #include <windows.h>
31
32 typedef struct
33 {
34    HANDLE m;
35    void *p;
36 } SIMPLE_UNMMAP;
37
38 static SIMPLE_UNMMAP un;
39
40 /*
41  * map 'filename' and return a pointer to it.
42  */
43 void *simple_mmap(int, unsigned int, SIMPLE_UNMMAP *);
44 void simple_unmmap(SIMPLE_UNMMAP *);
45
46 #define mmap(a,b,c,d,e,f)       simple_mmap((e), (b), &un)
47 #define munmap(a,b)             simple_unmmap(&un)
48
49 #else   /* !WIN32 */
50 # include <sys/mman.h>
51 # include <fcntl.h>
52 #endif
53
54 #include <sys/stat.h>
55 #include <sys/types.h>
56 #include <assert.h>
57 #include <unistd.h>
58 #include <ctype.h>
59 #include <string.h>
60 #include <strings.h>    /* strncasecmp */
61 #include <stdio.h>
62 #include <stdlib.h>
63
64
65 struct _xml_id
66 {
67     char *name;
68     char *start;
69     size_t len;
70     union {
71        int fd;
72        size_t len;
73     } node;
74 };
75
76 static char *__xmlCopyNode(const char *, size_t, const char *);
77 static char *__xmlGetNodePath(const char *, size_t *, char **, size_t *);
78 static char *__xmlGetNode(const char *, size_t *, char **, size_t *, size_t *);
79 static char *__xmlSkipComment(const char *, size_t);
80 static char *__xmlSkipInfo(const char *, size_t);
81
82 static void *__xml_memmem(const char *, size_t, const char *, size_t);
83 static void *__xml_memncasecmp(const char *, size_t *, char **, size_t *);
84
85 #define PRINT(a, b, c) { \
86    if (a) { \
87       size_t q, len = c; \
88       if (b < c) len = b; \
89       if (len < 50000) { \
90          printf("(%i) '", len); \
91          for (q=0; q<len; q++) printf("%c", ((char *)(a))[q]); \
92          printf("'\n"); \
93       } else printf("Length (%u) seems too large at line %i\n",len, __LINE__); \
94    } else printf("NULL pointer at line %i\n", __LINE__); \
95 }
96
97 void *
98 xmlOpen(const char *filename)
99 {
100     struct _xml_id *id = 0;
101
102     if (filename)
103     {
104         int fd = open(filename, O_RDONLY);
105         if (fd > 0)
106         {
107             id = malloc(sizeof(struct _xml_id));
108             if (id)
109             {
110                 struct stat statbuf;
111
112                 fstat(fd, &statbuf);
113
114                 id->node.fd = fd;
115                 id->len = statbuf.st_size;
116                 id->start = mmap(0, id->len, PROT_READ, MAP_PRIVATE, fd, 0L);
117                 id->name = 0;
118             }
119         }
120     }
121
122     return (void *)id;
123 }
124
125 void
126 xmlClose(void *id)
127 {
128     if (id)
129     {
130         struct _xml_id *xid = (struct _xml_id *)id;
131         assert(xid->name == 0);
132
133         munmap(xid->start, xid->len);
134         close(xid->node.fd);
135         free(id);
136         id = 0;
137     }
138 }
139
140 void *
141 xmlGetNode(const void *id, const char *path)
142 {
143    struct _xml_id *xsid = 0;
144
145    if (id && path)
146    {
147       struct _xml_id *xid = (struct _xml_id *)id;
148       size_t len, slen;
149       char *ptr, *node;
150
151       node = (char *)path;
152       len = xid->len;
153       slen = strlen(path);
154       ptr = __xmlGetNodePath(xid->start, &len, &node, &slen);
155       if (ptr)
156       {
157          xsid = malloc(sizeof(struct _xml_id));
158          if (xsid)
159          {
160              xsid->len = len;
161              xsid->start = ptr;
162              xsid->node.len = slen;
163              xsid->name = node;
164          }
165       }
166    }
167
168    return (void *)xsid;
169 }
170
171 void *
172 xmlCopyNode(const void *id, const char *path)
173 {
174     struct _xml_id *xsid = 0;
175
176     if (id && path)
177     {
178         struct _xml_id *xid = (struct _xml_id *)id;
179         char *ptr, *node, *p;
180         size_t slen, len;
181
182         node = (char *)path;
183         len = xid->len;
184         slen = strlen(path);
185         ptr = __xmlGetNodePath(xid->start, &len, &node, &slen);
186         if (ptr)
187         {
188             xsid = malloc(sizeof(struct _xml_id) + len);
189             if (xsid)
190             {
191                 p = (char *)xsid + sizeof(struct _xml_id);
192
193                 xsid->len = len;
194                 xsid->start = p;
195                 xsid->node.len = slen;
196                 xsid->name = node;
197
198                 memcpy(xsid->start, ptr, len);
199            }
200        }
201    }
202
203    return (void *)xsid;
204 }
205
206 char *
207 xmlGetNodeName(const void *id)
208 {
209     struct _xml_id *xid = (struct _xml_id *)id;
210     size_t len;
211     char *ret;
212
213     len = xid->node.len;
214     ret = malloc(len+1);
215     if (ret)
216     {
217         memcpy(ret, xid->name, len);
218         *(ret + len) = 0;
219     }
220
221     return ret;
222 }
223
224 size_t
225 xmlCopyNodeName(const void *id, char *buf, size_t len)
226 {
227     struct _xml_id *xid = (struct _xml_id *)id;
228     size_t slen = 0;
229  
230     if (buf)
231     {
232         slen = len-1;
233         if (slen > xid->node.len) slen = xid->node.len;
234         memcpy(buf, xid->name, slen);
235         *(buf + slen) = 0;
236     }
237
238     return slen;
239 }
240
241 unsigned int
242 xmlGetNumNodes(const void *id, const char *path)
243 {
244     struct _xml_id *xid = (struct _xml_id *)id;
245     size_t num = 0;
246
247     if (xid && xid->len && path)
248     {
249         char *nodename, *pathname;
250         size_t len, slen;
251         char *p;
252
253         nodename = (char *)path;
254         if (*path == '/') nodename++;
255         slen = strlen(nodename);
256
257         pathname = strchr(nodename, '/');
258         if (pathname)
259         {
260            char *node;
261
262            len = xid->len;
263            pathname++;
264            slen -= pathname-nodename;
265            node = pathname;
266            p = __xmlGetNodePath(xid->start, &len, &node, &slen);
267         }
268         else
269         {
270             p = xid->start;
271             len = xid->len;
272         }
273
274         if (p)
275         {
276             char *node = nodename;
277             __xmlGetNode(p, &len, &node, &slen, &num);
278         }
279     }
280
281     return num;
282 }
283
284 void *
285 xmlGetNodeNum(const void *pid, void *id, const char *element, size_t num)
286 {
287     void *ret = 0;
288
289     if (pid && element)
290     {
291         struct _xml_id *xpid = (struct _xml_id *)pid;
292         struct _xml_id *xid = (struct _xml_id *)id;
293         size_t len, slen;
294         char *ptr, *node;
295
296         len = xpid->len;
297         slen = strlen(element);
298         node = (char *)element;
299         ptr = __xmlGetNode(xpid->start, &len, &node, &slen, &num);
300         if (ptr)
301         {
302              xid->len = len;
303              xid->start = ptr;
304              xid->name = node;
305              xid->node.len = slen;
306              ret = xid;
307         }
308     }
309
310     return ret;
311 }
312
313 char *
314 xmlGetString(const void *id)
315 {
316     struct _xml_id *xid = (struct _xml_id *)id;
317     char *str = 0;
318
319     if (xid && xid->len)
320     {
321         char *ps, *pe, *pend;
322         int nlen;
323
324         ps = xid->start;
325         nlen = xid->len;
326         pend = ps+nlen;
327         pe = pend;
328
329         while ((ps<pe) && isspace(*ps)) ps++;
330         while ((pe>ps) && isspace(*pe)) pe--;
331         nlen = (pe-ps);
332         if (nlen)
333         {
334             str = malloc(nlen+1);
335             if (str)
336             {
337                 memcpy(str, ps, nlen);
338                 *(str+nlen) = 0;
339             }
340         }
341     }
342
343     return str;
344 }
345
346 size_t
347 xmlCopyString(const void *id, char *buf, size_t len)
348 {
349     struct _xml_id *xid = (struct _xml_id *)id;
350     size_t nlen = 0;
351
352     if (xid && xid->len && buf && len)
353     {
354         char *ps, *pe, *pend;
355         int slen;
356
357         nlen = len-1;
358         ps = xid->start;
359         slen = xid->len;
360         pend = ps+slen;
361         pe = pend;
362
363         while ((ps<pe) && isspace(*ps)) ps++;
364         while ((pe>ps) && isspace(*pe)) pe--;
365         nlen = (pe-ps);
366         if (nlen > slen) nlen = slen;
367
368         if (nlen)
369         {
370             memcpy(buf, ps, nlen);
371             *(buf+nlen) = 0;
372         }
373     }
374
375     return nlen;
376 }
377
378 int
379 xmlCompareString(const void *id, const char *s)
380 {
381     struct _xml_id *xid = (struct _xml_id *)id;
382     int ret = -1;
383
384     if (xid && xid->len && s && (strlen(s) > 0))
385     {
386         char *ps, *pe;
387
388         ps = xid->start;
389         pe = ps + xid->len;
390         pe--;
391
392         while ((ps<pe) && isspace(*ps)) ps++;
393         while ((pe>ps) && isspace(*pe)) pe--;
394         pe++;
395
396         ret = strncasecmp(ps, s, pe-ps);
397     }
398
399     return ret;
400 }
401
402 char *
403 xmlGetNodeString(const void *id, const char *path)
404 {
405     struct _xml_id *xid = (struct _xml_id *)id;
406     char *str = 0;
407
408     if (xid && xid->len && path)
409     {
410         str = __xmlCopyNode(xid->start, xid->len, path);
411         if (str)
412         {
413             char *ps, *pe, *pend;
414             int slen;
415
416             ps = str;
417             slen = strlen(str);
418             pend = ps+slen;
419             pe = pend-1;
420
421             while ((ps<pe) && isspace(*ps)) ps++;
422             while ((pe>ps) && isspace(*pe)) pe--;
423
424             *++pe = 0;
425             slen = (pe-ps);
426             if (slen && (ps>str)) memmove(str, ps, slen);
427             else if (!slen) *str = 0;
428         }
429     }
430
431     return str;
432 }
433
434 size_t
435 xmlCopyNodeString(const void *id, const char *path, char *buffer, size_t buflen)
436 {
437     struct _xml_id *xid = (struct _xml_id *)id;
438     size_t len = 0;
439
440     if (xid && xid->len && path && buffer && buflen)
441     {
442         char *str, *node;
443         size_t slen;
444
445         *buffer = '\0';
446         len = xid->len;
447         slen = strlen(path);
448         node = (char *)path;
449         str = __xmlGetNodePath(xid->start, &len, &node, &slen);
450         if (str)
451         {
452             char *ps, *pe;
453
454             ps = str;
455             pe = ps+len-1;
456
457             while ((ps<pe) && isspace(*ps)) ps++;
458             while ((pe>ps) && isspace(*pe)) pe--;
459
460             len = (pe-ps)+1;
461             if (len >= buflen) len = buflen-1;
462
463             memcpy(buffer, ps, len);
464             str = buffer + len;
465             *str = '\0';
466         }
467     }
468
469     return len;
470 }
471
472 int
473 xmlCompareNodeString(const void *id, const char *path, const char *s)
474 {
475     struct _xml_id *xid = (struct _xml_id *)id;
476     int ret = -1;
477
478     if (xid && xid->len && path && s && (strlen(s) > 0))
479     {
480         char *node, *str, *ps, *pe;
481         size_t len, slen, i;
482
483         len = xid->len;
484         slen = strlen(path);
485         node = (char *)path;
486         str = __xmlGetNodePath(xid->start, &len, &node, &slen);
487         if (str)
488         {
489             ps = str;
490             pe = ps + len;
491             pe--;
492
493             while ((ps<pe) && isspace(*ps)) ps++;
494             while ((pe>ps) && isspace(*pe)) pe--;
495             pe++;
496
497             ret = strncasecmp(ps, s, pe-ps);
498         }
499     }
500
501     return ret;
502 }
503
504 long int
505 xmlGetInt(const void *id)
506 {
507     struct _xml_id *xid = (struct _xml_id *)id;
508     long int li = 0;
509
510     if (xid && xid->len)
511     {
512         char *end = xid->start + xid->len;
513         li = strtol(xid->start, &end, 10);
514     }
515
516     return li;
517 }
518
519 long int
520 xmlGetNodeInt(const void *id, const char *path)
521 {
522     struct _xml_id *xid = (struct _xml_id *)id;
523     long int li = 0;
524
525     if (path && xid && xid->len)
526     {
527         size_t len, slen;
528         char *str, *node;
529
530         len = xid->len;
531         slen = strlen(path);
532         node = (char *)path;
533         str = __xmlGetNodePath(xid->start, &len, &node, &slen);
534         if (str)
535         {
536             char *end = str+len;
537             li = strtol(str, &end, 10);
538         }
539     }
540
541     return li;
542 }
543
544 double
545 xmlGetDouble(const void *id)
546 {
547     struct _xml_id *xid = (struct _xml_id *)id;
548     double d = 0.0;
549
550     if (xid && xid->len)
551     {
552         char *end = xid->start + xid->len;
553         d = strtod(xid->start, &end);
554     }
555
556     return d;
557 }
558
559 double
560 xmlGetNodeDouble(const void *id, const char *path)
561 {
562     struct _xml_id *xid = (struct _xml_id *)id;
563     double d = 0.0;
564
565     if (path && xid && xid->len)
566     {
567         size_t len, slen;
568         char *str, *node;
569
570         len = xid->len;
571         slen = strlen(path);
572         node = (char *)path;
573         str = __xmlGetNodePath(xid->start, &len, &node, &slen);
574         if (str)
575         {
576             char *end = str+len;
577             d = strtod(str, &end);
578         }
579     }
580
581     return d;
582 }
583
584 void *
585 xmlMarkId(const void *id)
586 {
587    struct _xml_id *xmid = 0;
588
589    if (id)
590    {
591       xmid = malloc(sizeof(struct _xml_id));
592       if (xmid)
593       {
594           memcpy(xmid, id, sizeof(struct _xml_id));
595       }
596    }
597
598    return (void *)xmid;
599 }
600
601 /* -------------------------------------------------------------------------- */
602
603 static char *
604 __xmlCopyNode(const char *start, size_t len, const char *path)
605 {
606    char *node, *p, *ret = 0;
607    size_t rlen, slen;
608
609    rlen = len;
610    slen = strlen(path);
611    node = (char *)path;
612    p = __xmlGetNodePath(start, &rlen, &node, &slen);
613    if (p && rlen)
614    {
615       ret = calloc(1, rlen+1);
616       memcpy(ret, p, rlen);
617    }
618
619    return ret;
620 }
621
622 char *
623 __xmlGetNodePath(const char *start, size_t *len, char **name, size_t *plen)
624 {
625     char *node;
626     char *ret = 0;
627
628     assert (start != 0);
629     assert (len != 0);
630     assert (name != 0);
631     assert (*name != 0);
632     assert (plen != 0);
633
634     if ((*len == 0) || (*plen == 0) || (*plen > *len))
635         return 0;
636
637     node = *name;
638     if (*node == '/') node++;
639     if (*node != 0)
640     {
641         size_t plen, slen;
642         char *path;
643         size_t num;
644
645         slen = strlen(node);
646         path = strchr(node, '/');
647
648         if (!path) plen = slen;
649         else plen = path++ - node;
650
651         num = 0;
652         ret = __xmlGetNode(start, len, &node, &plen, &num);
653         if (ret && path)
654         {
655            plen = slen - (path - *name);
656            ret = __xmlGetNodePath(ret, len, &path, &plen);
657         }
658
659         *name = path;
660     }
661
662     return ret;
663 }
664
665 char *
666 __xmlGetNode(const char *start, size_t *len, char **name, size_t *rlen, size_t *nodenum)
667 {
668     char *new, *cur, *ne, *ret = 0;
669     size_t restlen, elementlen;
670     size_t retlen = 0;
671     int found, num;
672     char *element;
673
674     assert (start != 0);
675     assert (len != 0);
676     assert (name != 0);
677     assert (*name != 0);
678     assert (rlen != 0);
679     assert (nodenum != 0);
680
681     if ((*len == 0) || (*rlen == 0) || (*rlen > *len))
682         return 0;
683
684     found = 0;
685     num = *nodenum;
686     restlen = *len;
687     cur = (char *)start;
688     ne = cur + restlen;
689
690     while ((new = memchr(cur, '<', restlen)) != 0)
691     {
692         if (*(new+1) == '/')            /* cascading closing tag found */
693         {
694             *len -= restlen;
695              break;
696         }
697
698         new++;
699         restlen -= new-cur;
700         cur = new;
701
702         if (*cur == '!')
703         {
704             new = __xmlSkipComment(cur, restlen);
705             if (!new) return 0;
706             restlen -= new-cur;
707             cur = new;
708             continue;
709         }
710         else if (*cur == '?')
711         {
712             new = __xmlSkipInfo(cur, restlen);
713             if (!new) return 0;
714
715             restlen -= new-cur;
716             cur = new;
717             continue;
718         }
719
720         element = *name;
721         elementlen = *rlen;
722         new = __xml_memncasecmp(cur, &restlen, &element, &elementlen);
723         if (new)
724         {
725             retlen = elementlen;
726             if (found == num ) ret = new+1;
727         }
728         else
729         {
730             new = cur+elementlen;
731             if (new >= ne) return 0;
732             element = *name;
733         }
734
735         /* restlen -= new-cur; not necessary because of __xml_memncasecmp */
736         cur = new;
737         new = memchr(cur, '<', restlen);
738         if (!new) return 0;
739
740         restlen -= new-cur;
741         cur = new;
742         if (*(cur+1) != '/')                            /* new node found */
743         {
744             char *node = "*";
745             size_t slen = restlen;
746             size_t nlen = 1;
747             size_t pos = -1;
748
749             new = __xmlGetNode(cur, &slen, &node, &nlen, &pos);
750             if (!new)
751             {
752                 if (slen == restlen) return 0;
753                 else new = cur + slen;
754             }
755
756             restlen -= slen;
757             cur = new;
758
759             new = memchr(cur, '<', restlen);
760             if (!new) return 0;
761
762             restlen -= new-cur;
763             cur = new;
764         }
765
766         if (*(cur+1) == '/')                            /* closing tag found */
767         {
768             if (!strncasecmp(new+2, element, elementlen))
769             {
770                 if (found == num) *len = new-ret;
771                 *name = element;
772                 found++;
773             }
774
775             new = memchr(cur, '>', restlen);
776             if (!new) return 0;
777
778             restlen -= new-cur;
779             cur = new;
780         }
781         else return 0;
782     }
783
784     *rlen = retlen;
785     *nodenum = found;
786
787     return ret;
788 }
789
790 char *
791 __xmlSkipComment(const char *start, size_t len)
792 {
793     char *cur, *new;
794
795     cur = (char *)start;
796     new = 0;
797
798     if (memcmp(cur, "!--", 3) == 0)
799     {
800         if (len < 6) return 0;
801
802         cur += 3;
803         len -= 3;
804
805         do
806         {
807             new = memchr(cur, '-', len);
808             if (new)
809             {
810                 len -= new - cur;
811                 if ((len > 3) && (memcmp(new, "-->", 3) == 0))
812                 {
813                     new += 3;
814                     len -= 3;
815                     break;
816                 }
817                 cur = new+1;
818             }
819             else break;
820         }
821         while (new && (len > 2));
822     }
823
824     return new;
825 }
826
827 char *
828 __xmlSkipInfo(const char *start, size_t len)
829 {
830     char *cur, *new;
831
832     cur = (char *)start;
833     new = 0;
834
835     if (*cur == '?')
836     {
837         if (len < 3) return 0;
838
839         cur++;
840         len--;
841         new = memchr(cur, '?', len);
842         if (!new || *(new+1) != '>') return 0;
843
844         new += 2;
845     }
846
847     return new;
848 }
849
850
851 void *
852 __xml_memmem(const char *haystack, size_t haystacklen,
853              const char *needle, size_t needlelen)
854 {
855     void *rptr = 0;
856
857     if (haystack && needle && (needlelen > 0) && (haystacklen >= needlelen))
858     {
859         char *ns, *hs, *ptr;
860
861         hs = (char *)haystack;
862         ns = (char *)needle;
863         do
864         {
865             ptr = memchr(hs, *ns, haystacklen);
866             if (ptr)
867             {
868                 haystacklen -= (ptr - hs);
869
870                 if (haystacklen < needlelen) break;
871                 if (memcmp(ptr, needle, needlelen) == 0)
872                 {
873                    rptr = ptr;
874                    break;
875                 }
876
877                 hs = ptr+1;
878             }
879             else break;
880         }
881         while (haystacklen > needlelen);
882     }
883
884     return rptr;
885 }
886
887
888 #define NOCASECMP(a,b)  ( ((a)^(b)) & 0xdf )
889 void *
890 __xml_memncasecmp(const char *haystack, size_t *haystacklen,
891                   char **needle, size_t *needlelen)
892 {
893     void *rptr = 0;
894
895     if (haystack && needle && needlelen && (*needlelen > 0)
896         && (*haystacklen >= *needlelen))
897     {
898         char *hs = (char *)haystack;
899         char *ns;
900         size_t i;
901
902         ns = *needle;
903
904         /* search for everything */
905         if ((*ns == '*') && (*needlelen == 1))
906         {
907            char *he = hs + *haystacklen;
908
909            while ((hs < he) && (*hs != ' ') && (*hs != '>')) hs++;
910            *needle = (char *)haystack;
911            *needlelen = hs - haystack;
912            while ((hs < he) && (*hs != '>')) hs++;
913            rptr = hs;
914         }
915         else
916         {
917             size_t nlen = *needlelen;
918             char *he = hs + *haystacklen;
919
920             for (i=0; i<nlen; i++)
921             {
922                 if (NOCASECMP(*hs,*ns) && (*ns != '?')) break;
923                 if ((*hs == ' ') || (*hs == '>')) break;
924                 hs++;
925                 ns++;
926             }
927
928             if (i != nlen)
929             {
930                 while((hs < he) && (*hs != ' ') && (*hs != '>')) hs++;
931                 *needle = (char *)haystack;
932                 *needlelen = hs - haystack;
933             }
934             else
935             {
936                 *needle = (char *)haystack;
937                 *needlelen = hs - haystack;
938                 while ((hs < he) && (*hs != '>')) hs++;
939                 rptr = hs;
940             }
941         }
942
943         *haystacklen -= hs - haystack;
944     }
945
946     return rptr;
947 }
948
949 #ifdef WIN32
950 /* Source:
951  * https://mollyrocket.com/forums/viewtopic.php?p=2529
952  */
953
954 void *
955 simple_mmap(int fd, unsigned int length, SIMPLE_UNMMAP *un)
956 {
957     HANDLE f;
958     HANDLE m;
959     void *p;
960
961     f = (HANDLE)_get_osfhandle(fd);
962     if (!f) return NULL;
963
964     m = CreateFileMapping(f, NULL, PAGE_READONLY, 0, 0, NULL);
965     if (!m) return NULL;
966
967     p = MapViewOfFile(m, FILE_MAP_READ, 0,0,0);
968     if (!p)
969     {
970         CloseHandle(m);
971         return NULL;
972     }
973
974     if (n) *n = GetFileSize(f, NULL);
975
976     if (un)
977     {
978         un->m = m;
979         un->p = p;
980     }
981
982     return p;
983 }
984
985 void
986 simple_unmmap(SIMPLE_UNMMAP *un)
987 {
988    UnmapViewOfFile(un->p);
989    CloseHandle(un->m);
990 }
991 #endif