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