1 //  binutils.h
2 //  hosts2zones
3 //
4 //  Created by Dr. Rolf Jansen on 2016-08-13.
5 //  Copyright (c) 2016 projectworld.net. All rights reserved.
6 //
7 //  Redistribution and use in source and binary forms, with or without modification,
8 //  are permitted provided that the following conditions are met:
9 //
10 //  1. Redistributions of source code must retain the above copyright notice,
11 //     this list of conditions and the following disclaimer.
12 //
13 //  2. Redistributions in binary form must reproduce the above copyright notice,
14 //     this list of conditions and the following disclaimer in the documentation
15 //     and/or other materials provided with the distribution.
16 //
17 //  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
18 //  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
19 //  AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
20 //  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 //  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 //  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23 //  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
24 //  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 
26 
27 #define noerr 0
28 
29 typedef unsigned char uchar;
30 typedef unsigned int  uint;
31 typedef long long     llong;
32 
33 
34 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
35 
36    #define b2_0 0
37    #define b2_1 1
38 
39    #define b4_0 0
40    #define b4_1 1
41    #define b4_2 2
42    #define b4_3 3
43 
44    #define b8_0 0
45    #define b8_1 1
46    #define b8_2 2
47    #define b8_3 3
48    #define b8_4 4
49    #define b8_5 5
50    #define b8_6 6
51    #define b8_7 7
52 
53    #define swapInt16(x) _swapInt16(x)
54    #define swapInt32(x) _swapInt32(x)
55    #define swapInt64(x) _swapInt64(x)
56 
57    #if defined(__i386__) || defined(__x86_64__)
58 
_swapInt16(uint16_t x)59       static inline uint16_t _swapInt16(uint16_t x)
60       {
61          __asm__("rolw $8,%0" : "+q" (x));
62          return x;
63       }
64 
_swapInt32(uint32_t x)65       static inline uint32_t _swapInt32(uint32_t x)
66       {
67          __asm__("bswapl %0" : "+q" (x));
68          return x;
69       }
70 
71    #else
72 
_swapInt16(uint16_t x)73       static inline uint16_t _swapInt16(uint16_t x)
74       {
75          uint16_t z;
76          uint8_t *p = (uint8_t *)&x;
77          uint8_t *q = (uint8_t *)&z;
78          q[0] = p[1];
79          q[1] = p[0];
80          return z;
81       }
82 
_swapInt32(uint32_t x)83       static inline uint32_t _swapInt32(uint32_t x)
84       {
85          uint32_t z;
86          uint8_t *p = (uint8_t *)&x;
87          uint8_t *q = (uint8_t *)&z;
88          q[0] = p[3];
89          q[1] = p[2];
90          q[2] = p[1];
91          q[3] = p[0];
92          return z;
93       }
94 
95    #endif
96 
97    #if defined(__x86_64__)
98 
_swapInt64(uint64_t x)99       static inline uint64_t _swapInt64(uint64_t x)
100       {
101          __asm__("bswapq %0" : "+q" (x));
102          return x;
103       }
104 
105    #else
106 
_swapInt64(uint64_t x)107       static inline uint64_t _swapInt64(uint64_t x)
108       {
109          uint64_t z;
110          uint8_t *p = (uint8_t *)&x;
111          uint8_t *q = (uint8_t *)&z;
112          q[0] = p[7];
113          q[1] = p[6];
114          q[2] = p[5];
115          q[3] = p[4];
116          q[4] = p[3];
117          q[5] = p[2];
118          q[6] = p[1];
119          q[7] = p[0];
120          return z;
121       }
122 
123    #endif
124 
125 #else
126 
127    #define b2_0 1
128    #define b2_1 0
129 
130    #define b4_0 3
131    #define b4_1 2
132    #define b4_2 1
133    #define b4_3 0
134 
135    #define b8_0 7
136    #define b8_1 6
137    #define b8_2 5
138    #define b8_3 4
139    #define b8_4 3
140    #define b8_5 2
141    #define b8_6 1
142    #define b8_7 0
143 
144    #define swapInt16(x) (x)
145    #define swapInt32(x) (x)
146    #define swapInt64(x) (x)
147 
148 #endif
149 
150 
151 #if defined(__x86_64__)
152 
153    #include <x86intrin.h>
154 
155    static const __m128i nul16 = {0x0000000000000000ULL, 0x0000000000000000ULL};  // 16 bytes with nul
156    static const __m128i lfd16 = {0x0A0A0A0A0A0A0A0AULL, 0x0A0A0A0A0A0A0A0AULL};  // 16 bytes with line feed
157    static const __m128i col16 = {0x3A3A3A3A3A3A3A3AULL, 0x3A3A3A3A3A3A3A3AULL};  // 16 bytes with colon ':' limit
158    static const __m128i vtl16 = {0x7C7C7C7C7C7C7C7CULL, 0x7C7C7C7C7C7C7C7CULL};  // 16 bytes with vertical line '|' limit
159    static const __m128i blk16 = {0x2020202020202020ULL, 0x2020202020202020ULL};  // 16 bytes with inner blank limit
160    static const __m128i obl16 = {0x2121212121212121ULL, 0x2121212121212121ULL};  // 16 bytes with outer blank limit
161    static const __m128i dot16 = {0x2E2E2E2E2E2E2E2EULL, 0x2E2E2E2E2E2E2E2EULL};  // 16 bytes with dots '.'
162 
163    // Drop-in replacement for strlen(), utilizing some builtin SSSE3 instructions
strvlen(const char * str)164    static inline int strvlen(const char *str)
165    {
166       if (!str || !*str)
167          return 0;
168 
169       unsigned bmask;
170       if (bmask = (unsigned)_mm_movemask_epi8(_mm_cmpeq_epi8(_mm_loadu_si128((__m128i *)str), nul16)))
171          return __builtin_ctz(bmask);
172 
173       for (int len = 16 - (intptr_t)str%16;; len += 16)
174          if (bmask = (unsigned)_mm_movemask_epi8(_mm_cmpeq_epi8(_mm_load_si128((__m128i *)&str[len]), nul16)))
175             return len + __builtin_ctz(bmask);
176    }
177 
linelen(const char * line)178    static inline int linelen(const char *line)
179    {
180       if (!line || !*line)
181          return 0;
182 
183       unsigned bmask;
184       if (bmask = (unsigned)_mm_movemask_epi8(_mm_cmpeq_epi8(_mm_loadu_si128((__m128i *)line), nul16))
185                 | (unsigned)_mm_movemask_epi8(_mm_cmpeq_epi8(_mm_loadu_si128((__m128i *)line), lfd16)))
186          return __builtin_ctz(bmask);
187 
188       for (int len = 16 - (intptr_t)line%16;; len += 16)
189          if (bmask = (unsigned)_mm_movemask_epi8(_mm_cmpeq_epi8(_mm_load_si128((__m128i *)&line[len]), nul16))
190                    | (unsigned)_mm_movemask_epi8(_mm_cmpeq_epi8(_mm_load_si128((__m128i *)&line[len]), lfd16)))
191             return len + __builtin_ctz(bmask);
192    }
193 
taglen(const char * tag)194    static inline int taglen(const char *tag)
195    {
196       if (!tag || !*tag)
197          return 0;
198 
199       unsigned bmask;
200       if (bmask = (unsigned)_mm_movemask_epi8(_mm_cmpeq_epi8(_mm_loadu_si128((__m128i *)tag), nul16))
201                 | (unsigned)_mm_movemask_epi8(_mm_cmpeq_epi8(_mm_loadu_si128((__m128i *)tag), col16)))
202          return __builtin_ctz(bmask);
203 
204       for (int len = 16 - (intptr_t)tag%16;; len += 16)
205          if (bmask = (unsigned)_mm_movemask_epi8(_mm_cmpeq_epi8(_mm_load_si128((__m128i *)&tag[len]), nul16))
206                    | (unsigned)_mm_movemask_epi8(_mm_cmpeq_epi8(_mm_load_si128((__m128i *)&tag[len]), col16)))
207             return len + __builtin_ctz(bmask);
208    }
209 
fieldlen(const char * field)210    static inline int fieldlen(const char *field)
211    {
212       if (!field || !*field)
213          return 0;
214 
215       unsigned bmask;
216       if (bmask = (unsigned)_mm_movemask_epi8(_mm_cmpeq_epi8(_mm_loadu_si128((__m128i *)field), nul16))
217                 | (unsigned)_mm_movemask_epi8(_mm_cmpeq_epi8(_mm_loadu_si128((__m128i *)field), vtl16)))
218          return __builtin_ctz(bmask);
219 
220       for (int len = 16 - (intptr_t)field%16;; len += 16)
221          if (bmask = (unsigned)_mm_movemask_epi8(_mm_cmpeq_epi8(_mm_load_si128((__m128i *)&field[len]), nul16))
222                    | (unsigned)_mm_movemask_epi8(_mm_cmpeq_epi8(_mm_load_si128((__m128i *)&field[len]), vtl16)))
223             return len + __builtin_ctz(bmask);
224    }
225 
domainlen(const char * domain)226    static inline int domainlen(const char *domain)
227    {
228       if (!domain || !*domain)
229          return 0;
230 
231       unsigned bmask;
232       if (bmask = (unsigned)_mm_movemask_epi8(_mm_cmpeq_epi8(_mm_loadu_si128((__m128i *)domain), nul16))
233                 | (unsigned)_mm_movemask_epi8(_mm_cmpeq_epi8(_mm_loadu_si128((__m128i *)domain), dot16)))
234          return __builtin_ctz(bmask);
235 
236       for (int len = 16 - (intptr_t)domain%16;; len += 16)
237          if (bmask = (unsigned)_mm_movemask_epi8(_mm_cmpeq_epi8(_mm_load_si128((__m128i *)&domain[len]), nul16))
238                    | (unsigned)_mm_movemask_epi8(_mm_cmpeq_epi8(_mm_load_si128((__m128i *)&domain[len]), dot16)))
239             return len + __builtin_ctz(bmask);
240    }
241 
wordlen(const char * word)242    static inline int wordlen(const char *word)
243    {
244       if (!word || !*word)
245          return 0;
246 
247       unsigned bmask;
248       if (bmask = (unsigned)_mm_movemask_epi8(_mm_cmpeq_epi8(blk16, _mm_max_epu8(blk16, _mm_loadu_si128((__m128i *)word)))))
249          return __builtin_ctz(bmask);      // ^^^^^^^ unsigned comparison (a >= b) is identical to a == maxu(a, b) ^^^^^^^
250 
251       for (int len = 16 - (intptr_t)word%16;; len += 16)
252          if (bmask = (unsigned)_mm_movemask_epi8(_mm_cmpeq_epi8(blk16, _mm_max_epu8(blk16, _mm_load_si128((__m128i *)&word[len])))))
253             return len + __builtin_ctz(bmask);
254    }
255 
blanklen(const char * blank)256    static inline int blanklen(const char *blank)
257    {
258       if (!blank || !*blank)
259          return 0;
260 
261       unsigned bmask;
262       if (bmask = (unsigned)_mm_movemask_epi8(_mm_cmpeq_epi8(_mm_loadu_si128((__m128i *)blank), nul16))
263                 | (unsigned)_mm_movemask_epi8(_mm_cmpeq_epi8(obl16, _mm_min_epu8(obl16, _mm_loadu_si128((__m128i *)blank)))))
264          return __builtin_ctz(bmask);      // ^^^^^^^ unsigned comparison (a <= b) is identical to a == minu(a, b) ^^^^^^^
265 
266       for (int len = 16 - (intptr_t)blank%16;; len += 16)
267          if (bmask = (unsigned)_mm_movemask_epi8(_mm_cmpeq_epi8(_mm_load_si128((__m128i *)&blank[len]), nul16))
268                    | (unsigned)_mm_movemask_epi8(_mm_cmpeq_epi8(obl16, _mm_min_epu8(obl16, _mm_load_si128((__m128i *)&blank[len])))))
269             return len + __builtin_ctz(bmask);
270    }
271 
272 
273    // String copying from src to dst.
274    // m: Max. capacity of dst, including the final nul.
275    //    A value of 0 would indicate that the capacity of dst matches the size of src (including nul)
276    // l: On entry, src length or 0, on exit, the length of src, maybe NULL
277    // Returns the length of the resulting string in dst.
strmlcpy(char * dst,const char * src,int m,int * l)278    static inline int strmlcpy(char *dst, const char *src, int m, int *l)
279    {
280       int k, n;
281 
282       if (l)
283       {
284          if (!*l)
285             *l = strvlen(src);
286          k = *l;
287       }
288       else
289          k = strvlen(src);
290 
291       if (!m)
292          n = k;
293       else
294          n = (k < m) ? k : m-1;
295 
296       switch (n)
297       {
298          default:
299             if ((intptr_t)dst&0xF || (intptr_t)src&0xF)
300                for (k = 0; k  < n>>4<<1; k += 2)
301                   ((uint64_t *)dst)[k] = ((uint64_t *)src)[k], ((uint64_t *)dst)[k+1] = ((uint64_t *)src)[k+1];
302             else
303                for (k = 0; k  < n>>4; k++)
304                   _mm_store_si128(&((__m128i *)dst)[k], _mm_load_si128(&((__m128i *)src)[k]));
305          case 8 ... 15:
306             if ((k = n>>4<<1) < n>>3)
307                ((uint64_t *)dst)[k] = ((uint64_t *)src)[k];
308          case 4 ... 7:
309             if ((k = n>>3<<1) < n>>2)
310                ((uint32_t *)dst)[k] = ((uint32_t *)src)[k];
311          case 2 ... 3:
312             if ((k = n>>2<<1) < n>>1)
313                ((uint16_t *)dst)[k] = ((uint16_t *)src)[k];
314          case 1:
315             if ((k = n>>1<<1) < n)
316                dst[k] = src[k];
317          case 0:
318             ;
319       }
320 
321       dst[n] = '\0';
322       return n;
323    }
324 
325 #else
326 
327    #define strvlen(s) strlen(s)
328 
linelen(const char * line)329    static inline int linelen(const char *line)
330    {
331       if (!line || !*line)
332          return 0;
333 
334       int l;
335       for (l = 0; line[l] && line[l] != '\n'; l++)
336          ;
337       return l;
338    }
339 
taglen(const char * tag)340    static inline int taglen(const char *tag)
341    {
342       if (!tag || !*tag)
343          return 0;
344 
345       int l;
346       for (l = 0; tag[l] && tag[l] != ':'; l++)
347          ;
348       return l;
349    }
350 
fieldlen(const char * field)351    static inline int fieldlen(const char *field)
352    {
353       if (!field || !*field)
354          return 0;
355 
356       int l;
357       for (l = 0; field[l] && field[l] != '|'; l++)
358          ;
359       return l;
360    }
361 
domainlen(const char * domain)362    static inline int domainlen(const char *domain)
363    {
364       if (!domain || !*domain)
365          return 0;
366 
367       int l;
368       for (l = 0; domain[l] && domain[l] != '.'; l++)
369          ;
370       return l;
371    }
372 
wordlen(const char * word)373    static inline int wordlen(const char *word)
374    {
375       if (!word || !*word)
376          return 0;
377 
378       int l;
379       for (l = 0; (uchar)word[l] > ' '; l++)
380          ;
381       return l;
382    }
383 
blanklen(const char * blank)384    static inline int blanklen(const char *blank)
385    {
386       if (!blank || !*blank)
387          return 0;
388 
389       int l;
390       for (l = 0; blank[l] && (uchar)blank[l] <= ' '; l++)
391          ;
392       return l;
393    }
394 
395 
396    // String copying from src to dst.
397    // m: Max. capacity of dst, including the final nul.
398    //    A value of 0 would indicate that the capacity of dst matches the size of src (including nul)
399    // l: On entry, src length or 0, on exit, the length of src, maybe NULL
400    // Returns the length of the resulting string in dst.
strmlcpy(char * dst,const char * src,int m,int * l)401    static inline int strmlcpy(char *dst, const char *src, int m, int *l)
402    {
403       int k, n;
404 
405       if (l)
406       {
407          if (!*l)
408             *l = (int)strlen(src);
409          k = *l;
410       }
411       else
412          k = (int)strlen(src);
413 
414       if (!m)
415          n = k;
416       else
417          n = (k < m) ? k : m-1;
418 
419       strlcpy(dst, src, n+1);
420       return n;
421    }
422 
423 #endif
424 
425 
426 // forward skip white space  !!! s MUST NOT be NULL !!!
skip(char * s)427 static inline char *skip(char *s)
428 {
429    for (;;)
430       if ((uchar)*s <= ' ')
431          s++;
432       else
433          return s;
434 }
435 
436 // backward skip white space  !!! s MUST NOT be NULL !!!
bskip(char * s)437 static inline char *bskip(char *s)
438 {
439    for (;;)
440       if ((uchar)*--s > ' ')
441          return s+1;
442 }
443 
trim(char * s)444 static inline char *trim(char *s)
445 {
446    *bskip(s+strvlen(s)) = '\0';
447    return skip(s);
448 }
449 
450 
lowercase(char * s,int n)451 static inline char *lowercase(char *s, int n)
452 {
453    if (s)
454    {
455       char c, *p = s;
456       for (int i = 0; i < n && (c = *p); i++)
457          if ('A' <= c && c <= 'Z')
458             *p++ = c + 0x20;
459          else
460             p++;
461    }
462    return s;
463 }
464 
uppercase(char * s,int n)465 static inline char *uppercase(char *s, int n)
466 {
467    if (s)
468    {
469       char c, *p = s;
470       for (int i = 0; i < n && (c = *p); i++)
471          if ('a' <= c && c <= 'z')
472             *p++ = c - 0x20;
473          else
474             p++;
475    }
476    return s;
477 }
478 
479 
480 #pragma mark ••• Fencing Memory Allocation Wrappers •••
481 
482 // void pointer reference
483 #define VPR(p) (void **)&(p)
484 
485 typedef struct
486 {
487    ssize_t size;
488    size_t  check;
489    char    payload[16];
490 // size_t  zerowall;       // the allocation routines allocate sizeof(size_t) extra space and set this to zero
491 } allocation;
492 
493 #define allocationMetaSize (offsetof(allocation, payload) - offsetof(allocation, size))
494 
495 extern ssize_t gAllocationTotal;
496 
497 void *allocate(ssize_t size, bool cleanout);
498 void *reallocate(void *p, ssize_t size, bool cleanout, bool free_on_error);
499 void deallocate(void **p, bool cleanout);
500 void deallocate_batch(unsigned cleanout, ...);
501