]> Git Repo - binutils.git/blob - gprofng/src/util.cc
Automatic date update in version.in
[binutils.git] / gprofng / src / util.cc
1 /* Copyright (C) 2021 Free Software Foundation, Inc.
2    Contributed by Oracle.
3
4    This file is part of GNU Binutils.
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3, or (at your option)
9    any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, 51 Franklin Street - Fifth Floor, Boston,
19    MA 02110-1301, USA.  */
20
21 #include "config.h"
22 #include <sys/param.h>
23 #include <stdarg.h>
24 #include <unistd.h>
25 #include <dirent.h>    // readdir()
26 #include <sys/param.h> // MAXPATHLEN
27 #include <pthread.h>   // mutex
28 #include <libgen.h>    // dirname
29 #include <sys/types.h> // open
30 #include <sys/stat.h>  // open
31 #include <errno.h>     // errno
32 #include <fcntl.h>     // open
33
34 #include "util.h"
35 #include "dbe_structs.h"
36 #include "StringBuilder.h"
37 #include "StringMap.h"      // For directory names
38 #include "Application.h"    // Only for get_prog_name
39 #include "vec.h"
40
41 void
42 tsadd (timestruc_t *result, timestruc_t *time)
43 {
44   // This routine will add "time" to "result".
45   result->tv_sec += time->tv_sec;
46   result->tv_nsec += time->tv_nsec;
47   if (result->tv_nsec >= NANOSEC)
48     {
49       result->tv_nsec -= NANOSEC;
50       result->tv_sec++;
51     }
52 }
53
54 void
55 tssub (timestruc_t *result, timestruc_t *time1, timestruc_t *time2)
56 {
57   // This routine will store "time1" - "time2" in "result".
58
59   if (time1->tv_nsec >= time2->tv_nsec)
60     {
61       result->tv_nsec = time1->tv_nsec - time2->tv_nsec;
62       if (time1->tv_sec >= time2->tv_sec)
63         result->tv_sec = time1->tv_sec - time2->tv_sec;
64       else
65         {
66           result->tv_sec = -1;
67           result->tv_nsec = 0;
68         }
69     }
70   else
71     {
72       result->tv_nsec = time1->tv_nsec + NANOSEC - time2->tv_nsec;
73       if (time1->tv_sec - 1 >= time2->tv_sec)
74         result->tv_sec = time1->tv_sec - 1 - time2->tv_sec;
75       else
76         {
77           result->tv_sec = -1;
78           result->tv_nsec = 0;
79         }
80     }
81 }
82
83 int
84 tscmp (timestruc_t *time1, timestruc_t *time2)
85 {
86   // This routine will return 1 if "time1" is greater than "time2"
87   // and 0 if "time1" is equal to "time2" and -1 otherwise.
88   if (time1->tv_sec == time2->tv_sec)
89     return time1->tv_nsec > time2->tv_nsec ? 1 :
90           time1->tv_nsec == time2->tv_nsec ? 0 : -1;
91   else
92     return time1->tv_sec > time2->tv_sec ? 1 : -1;
93 }
94
95 void
96 int_max (int *maximum, int count)
97 {
98   if (count > *maximum)
99     *maximum = count;
100 }
101
102 double
103 TValue::to_double ()
104 {
105   switch (tag)
106     {
107     case VT_DOUBLE:
108       return (double) d;
109     case VT_INT:
110       return (double) i;
111     case VT_ULLONG:
112       return (double) ull;
113     case VT_LLONG:
114     case VT_ADDRESS:
115       return (double) ll;
116     case VT_FLOAT:
117       return (double) f;
118     case VT_SHORT:
119       return (double) s;
120     default:
121       return 0.0;
122     }
123 }
124
125 int
126 TValue::to_int ()
127 {
128   switch (tag)
129     {
130     case VT_DOUBLE:
131       return (int) d;
132     case VT_INT:
133       return (int) i;
134     case VT_ULLONG:
135       return (int) ull;
136     case VT_LLONG:
137     case VT_ADDRESS:
138       return (int) ll;
139     case VT_FLOAT:
140       return (int) f;
141     case VT_SHORT:
142       return (int) s;
143     default:
144       return 0;
145     }
146 }
147
148 size_t
149 TValue::get_len ()
150 {
151   char buf[256];
152   return strlen (to_str (buf, sizeof (buf)));
153 }
154
155 char *
156 TValue::to_str (char *str, size_t strsz)
157 {
158   switch (tag)
159     {
160     case VT_DOUBLE:
161       if (d == 0.)
162         {
163           if (sign)
164             snprintf (str, strsz, NTXT ("+0.   "));
165           else
166             snprintf (str, strsz, NTXT ("0.   "));
167         }
168       else if (sign)
169         snprintf (str, strsz, NTXT ("%+.3lf"), d);
170       else
171         snprintf (str, strsz, NTXT ("%.3lf"), d);
172       break;
173     case VT_INT:
174       snprintf (str, strsz, NTXT ("%u"), i);
175       break;
176     case VT_LLONG:
177       if (sign)
178         snprintf (str, strsz, NTXT ("%+lld"), ll);
179       else
180         snprintf (str, strsz, NTXT ("%lld"), ll);
181       break;
182     case VT_ULLONG:
183       snprintf (str, strsz, NTXT ("%llu"), ll);
184       break;
185     case VT_ADDRESS:
186       snprintf (str, strsz, NTXT ("%u:0x%08x"), ADDRESS_SEG (ll), ADDRESS_OFF (ll));
187       break;
188     case VT_FLOAT:
189       snprintf (str, strsz, NTXT ("%.3f"), f);
190       break;
191     case VT_SHORT:
192       snprintf (str, strsz, NTXT ("%hu"), s);
193       break;
194     case VT_LABEL:
195       return l; // 'str' is not used !!!
196     default:
197       *str = '\0';
198       break;
199     }
200
201   return str;
202 }
203
204 void
205 TValue::make_delta (TValue *v1, TValue *v2)
206 {
207   assert (v1->tag == v2->tag);
208   tag = v1->tag;
209   sign = true;
210   switch (v1->tag)
211     {
212     case VT_INT:
213       i = v1->i - v2->i;
214       break;
215     case VT_LLONG:
216       ll = v1->ll - v2->ll;
217       break;
218     case VT_ULLONG:
219     case VT_ADDRESS:
220       tag = VT_LLONG;
221       ll = (long long) (v1->ull - v2->ull);
222       break;
223     case VT_FLOAT:
224       f = v1->f - v2->f;
225       break;
226     case VT_DOUBLE:
227       d = v1->d - v2->d;
228       break;
229     default:
230       assert (0);
231       break;
232     }
233 }
234
235 void
236 TValue::make_ratio (TValue *v1, TValue *v2)
237 {
238   assert (v1->tag == v2->tag);
239   double x1 = v1->to_double ();
240   double x2 = v2->to_double ();
241   sign = false;
242   if (x1 == 0.)
243     {
244       // if the numerator is 0, the ratio is 1. or 0. only
245       d = (x2 == 0.) ? 1. : 0.;
246       tag = VT_DOUBLE;
247     }
248   else
249     {
250       // EUGENE replace 99.999 with a variable that is known by both DBE and GUI
251       if (x1 > 99.999 * x2)
252         {
253           l = dbe_strdup (">99.999");
254           tag = VT_LABEL;
255         }
256       else if (x1 < -99.999 * x2)
257         {
258           l = dbe_strdup ("<-99.999");
259           tag = VT_LABEL;
260         }
261       else
262         {
263           d = x1 / x2;
264           tag = VT_DOUBLE;
265         }
266     }
267 }
268
269 int
270 TValue::compare (TValue *v)
271 {
272   if (tag != v->tag)
273     { // Only for comparison (Ratio)
274       if (tag == VT_LABEL)
275         {
276           if (v->tag == VT_LABEL)
277             return strcoll (l, v->l);
278           return 1;
279         }
280       if (v->tag == VT_LABEL)
281         return -1;
282       return ll < v->ll ? -1 : (ll == v->ll ? 0 : 1);
283     }
284   switch (tag)
285     {
286     case VT_SHORT:
287       return s < v->s ? -1 : (s == v->s ? 0 : 1);
288     case VT_INT:
289       return i < v->i ? -1 : (i == v->i ? 0 : 1);
290     case VT_FLOAT:
291       return f < v->f ? -1 : (f == v->f ? 0 : 1);
292     case VT_DOUBLE:
293       return d < v->d ? -1 : (d == v->d ? 0 : 1);
294     case VT_LABEL:
295       return strcoll (l, v->l);
296     case VT_LLONG:
297     case VT_ULLONG:
298     case VT_ADDRESS:
299     case VT_HRTIME:
300     default:
301       return (ll < v->ll) ? -1 : ((ll == v->ll) ? 0 : 1);
302     }
303 }
304
305 char *
306 strstr_r (char *s1, const char *s2)
307 {
308   char *str = NULL;
309   for (char *s = s1; s;)
310     {
311       s = strstr (s, s2);
312       if (s)
313         {
314           str = s;
315           s++;
316         }
317     }
318   return str;
319 }
320
321 // reversal order of strpbrk
322
323 char *
324 strrpbrk (const char *string, const char *brkset)
325 {
326   const char *p;
327   const char *s;
328   for (s = string + strlen (string) - 1; s >= string; s--)
329     {
330       for (p = brkset; *p != '\0' && *p != *s; ++p)
331         ;
332       if (*p != '\0')
333         return ((char *) s);
334     }
335   return NULL;
336 }
337
338 char *
339 read_line (FILE *fptr)
340 {
341   // get an input line, no size limit
342   int line_sz = 128; // starting size
343   char *line = (char *) malloc (line_sz);
344
345   // read as much of the line as will fit in memory
346   line[0] = 0;
347   int len = 0;
348   for (;;)
349     {
350       while (fgets (line + len, line_sz - len, fptr) != NULL)
351         {
352           len = (int) strlen (line);
353           if (len == 0 || line[len - 1] == '\n')
354             break;
355           // increase the buffer
356           char *lineNew = (char *) malloc (2 * line_sz);
357           strncpy (lineNew, line, line_sz);
358           lineNew[line_sz] = '\0';
359           free (line);
360           line = lineNew;
361           line_sz *= 2;
362           if (line == NULL)
363             {
364               fprintf (stderr, GTXT ("   Line too long -- out of memory; exiting\n"));
365               exit (1);
366             }
367         }
368       if (len == 0)
369         {
370           free (line);
371           return NULL;
372         }
373       // see if there's a continuation line
374       if ((len >= 2) && (line[len - 1] == '\n') && (line[len - 2] == '\\'))
375         {
376           // remove the trailing \ and the \n, and keep going
377           line[len - 2] = 0;
378           len -= 2;
379         }
380       else
381         break;
382     }
383   return line; // expecting the caller to free it
384 }
385
386 Vector<char *> *
387 split_str (char *str, char delimiter)
388 {
389   Vector<char *> *v = new Vector<char *>;
390   for (char *s = str; s;)
391     {
392       if (*s == '"')
393         {
394           char *next_s = NULL;
395           char *tok = parse_qstring (s, &next_s);
396           if (tok && *tok != '\0')
397             v->append (tok);
398           if (*next_s)
399             s = next_s + 1;
400           else
401             s = NULL;
402         }
403       else
404         {
405           char *next_s = strchr (s, delimiter);
406           if (next_s)
407             {
408               if (next_s != s)
409                 v->append (dbe_strndup (s, next_s - s));
410               s = next_s + 1;
411             }
412           else
413             {
414               if (*s != '\0')
415                 v->append (dbe_strdup (s));
416               s = NULL;
417             }
418         }
419     }
420   return v;
421 }
422
423 // get quoted string
424 char *
425 parse_qstring (char *in_str, char **endptr)
426 {
427   int i;
428   char c, c2;
429   char term;
430   char csnum[2 * MAXPATHLEN];
431
432   // Skip any leading blanks or tabs
433   while (*in_str == '\t' || *in_str == ' ')
434     in_str++;
435
436   int gtxt = 0;
437   if (*in_str == 'G' && *(in_str + 1) == 'T' && *(in_str + 2) == 'X'
438       && *(in_str + 3) == 'T' && *(in_str + 4) == '(')
439     {
440       gtxt = 1;
441       in_str += 5;
442     }
443   // non-quoted string
444   if (*in_str == '"')
445     term = '"';
446   else if (*in_str == '\'')
447     term = '\'';
448   else
449     return strtok_r (in_str, NTXT (" "), endptr);
450
451   StringBuilder sb;
452   while ((c = *(++in_str)) != '\0')
453     {
454       if (c == term) // the closing quote
455         break;
456       if (c == '\\')
457         { // handle any escaped characters
458           c2 = *(++in_str);
459           switch (c2)
460             {
461             case '\"':
462               sb.append ('\"');
463               break;
464             case '\'':
465               sb.append ('\'');
466               break;
467             case '\\':
468               sb.append ('\\');
469               break;
470             case 't':
471               sb.append ('\t');
472               break;
473             case 'r':
474               sb.append ('\r');
475               break;
476             case 'b':
477               sb.append ('\b');
478               break;
479             case 'f':
480               sb.append ('\f');
481               break;
482             case 'n':
483               sb.append ('\n');
484               break;
485             default:
486               if ((c2 >= '0') && (c2 <= '9'))
487                 {
488                   for (i = 0; i < MAXPATHLEN; i++)
489                     {
490                       if (((c2 < '0') || (c2 > '9')) && (c2 != 'x') &&
491                           ((c2 < 'a') || (c2 > 'f')) &&
492                           ((c2 < 'A') || (c2 > 'F')))
493                         {
494                           csnum[i] = '\0';
495                           --in_str;
496                           break;
497                         }
498                       else
499                         {
500                           csnum[i] = c2;
501                           c2 = *(++in_str);
502                         }
503                     }
504                   sb.append ((char) strtoul (csnum, endptr, 0));
505                 }
506               else
507                 sb.append (c2);
508               break;
509             }
510         }
511       else
512         sb.append (c);
513     }
514   if (c == term && gtxt && *in_str == ')')
515     in_str++;
516   if (*in_str == '\0')
517     *endptr = in_str;
518   else
519     *endptr = in_str + 1;
520   return sb.toString ();
521 }
522
523 // parse a file name of the form name`name2`
524 // returns name
525 // stores the pointer to named in fcontext
526 // returns NULL if the string is not properly formatted
527 char *
528 parse_fname (char *in_str, char **fcontext)
529 {
530   *fcontext = NULL;
531   int ch = '`';
532   if (in_str == NULL)
533     return NULL;
534   char *copy = strdup (in_str);
535   char *p = strchr (copy, ch);
536   if (p != NULL)
537     {
538       // yes, there's an embedded file name
539       *p = '\0';
540       p++;
541       // now find the terminating single quote
542       char *p1 = strchr (p, ch);
543       if (p1 == NULL)
544         {
545           // if we don't have the closing `, the format is incorrect
546           free (copy);
547           return NULL;
548         }
549       //remove the closing quote
550       *p1 = '\0';
551       // see if there's anything following it
552       if (*(p1 + 1) != 0)
553         {
554           // error in format
555           free (copy);
556           return NULL;
557         }
558       free (*fcontext);
559       *fcontext = strdup (p);
560     }
561   return copy;
562 }
563
564 int
565 get_paren (const char *name)
566 {
567   char buf[8192];
568   char *ptr;
569   int temp_level1, temp_level2;
570
571   temp_level1 = temp_level2 = 0;
572   snprintf (buf, sizeof (buf), NTXT ("%s"), name);
573   while ((ptr = strrpbrk (buf, "><)(")) != NULL)
574     {
575       if (*ptr == '>')
576         temp_level1++;
577       else if (*ptr == '<')
578         temp_level1--;
579       else if (*ptr == ')')
580         temp_level2++;
581       else
582         {
583           temp_level2--;
584           if (temp_level1 <= 0 && temp_level2 <= 0)
585             return (int) (ptr - buf);
586         }
587       *ptr = '\0';
588     }
589   return -1;
590 }
591
592 // CRC-64 based on x^64 + x^11 + x^2 + x + 1 polynomial.
593 // This algorithm doesn't perform well but is short and
594 // readable. We currently use it for a small amount of
595 // short strings. Should this change, another algorithm
596 // with better performance is to be used instead.
597 static uint64_t masks[256] = {
598   /*   0 */ 0x000000, 0x000807, 0x00100e, 0x001809, 0x00201c, 0x00281b,
599   /*   6 */ 0x003012, 0x003815, 0x004038, 0x00483f, 0x005036, 0x005831,
600   /*  12 */ 0x006024, 0x006823, 0x00702a, 0x00782d, 0x008070, 0x008877,
601   /*  18 */ 0x00907e, 0x009879, 0x00a06c, 0x00a86b, 0x00b062, 0x00b865,
602   /*  24 */ 0x00c048, 0x00c84f, 0x00d046, 0x00d841, 0x00e054, 0x00e853,
603   /*  30 */ 0x00f05a, 0x00f85d, 0x0100e0, 0x0108e7, 0x0110ee, 0x0118e9,
604   /*  36 */ 0x0120fc, 0x0128fb, 0x0130f2, 0x0138f5, 0x0140d8, 0x0148df,
605   /*  42 */ 0x0150d6, 0x0158d1, 0x0160c4, 0x0168c3, 0x0170ca, 0x0178cd,
606   /*  48 */ 0x018090, 0x018897, 0x01909e, 0x019899, 0x01a08c, 0x01a88b,
607   /*  54 */ 0x01b082, 0x01b885, 0x01c0a8, 0x01c8af, 0x01d0a6, 0x01d8a1,
608   /*  60 */ 0x01e0b4, 0x01e8b3, 0x01f0ba, 0x01f8bd, 0x0201c0, 0x0209c7,
609   /*  66 */ 0x0211ce, 0x0219c9, 0x0221dc, 0x0229db, 0x0231d2, 0x0239d5,
610   /*  72 */ 0x0241f8, 0x0249ff, 0x0251f6, 0x0259f1, 0x0261e4, 0x0269e3,
611   /*  78 */ 0x0271ea, 0x0279ed, 0x0281b0, 0x0289b7, 0x0291be, 0x0299b9,
612   /*  84 */ 0x02a1ac, 0x02a9ab, 0x02b1a2, 0x02b9a5, 0x02c188, 0x02c98f,
613   /*  90 */ 0x02d186, 0x02d981, 0x02e194, 0x02e993, 0x02f19a, 0x02f99d,
614   /*  96 */ 0x030120, 0x030927, 0x03112e, 0x031929, 0x03213c, 0x03293b,
615   /* 102 */ 0x033132, 0x033935, 0x034118, 0x03491f, 0x035116, 0x035911,
616   /* 108 */ 0x036104, 0x036903, 0x03710a, 0x03790d, 0x038150, 0x038957,
617   /* 114 */ 0x03915e, 0x039959, 0x03a14c, 0x03a94b, 0x03b142, 0x03b945,
618   /* 120 */ 0x03c168, 0x03c96f, 0x03d166, 0x03d961, 0x03e174, 0x03e973,
619   /* 126 */ 0x03f17a, 0x03f97d, 0x040380, 0x040b87, 0x04138e, 0x041b89,
620   /* 132 */ 0x04239c, 0x042b9b, 0x043392, 0x043b95, 0x0443b8, 0x044bbf,
621   /* 138 */ 0x0453b6, 0x045bb1, 0x0463a4, 0x046ba3, 0x0473aa, 0x047bad,
622   /* 144 */ 0x0483f0, 0x048bf7, 0x0493fe, 0x049bf9, 0x04a3ec, 0x04abeb,
623   /* 150 */ 0x04b3e2, 0x04bbe5, 0x04c3c8, 0x04cbcf, 0x04d3c6, 0x04dbc1,
624   /* 156 */ 0x04e3d4, 0x04ebd3, 0x04f3da, 0x04fbdd, 0x050360, 0x050b67,
625   /* 162 */ 0x05136e, 0x051b69, 0x05237c, 0x052b7b, 0x053372, 0x053b75,
626   /* 168 */ 0x054358, 0x054b5f, 0x055356, 0x055b51, 0x056344, 0x056b43,
627   /* 174 */ 0x05734a, 0x057b4d, 0x058310, 0x058b17, 0x05931e, 0x059b19,
628   /* 180 */ 0x05a30c, 0x05ab0b, 0x05b302, 0x05bb05, 0x05c328, 0x05cb2f,
629   /* 186 */ 0x05d326, 0x05db21, 0x05e334, 0x05eb33, 0x05f33a, 0x05fb3d,
630   /* 192 */ 0x060240, 0x060a47, 0x06124e, 0x061a49, 0x06225c, 0x062a5b,
631   /* 198 */ 0x063252, 0x063a55, 0x064278, 0x064a7f, 0x065276, 0x065a71,
632   /* 204 */ 0x066264, 0x066a63, 0x06726a, 0x067a6d, 0x068230, 0x068a37,
633   /* 210 */ 0x06923e, 0x069a39, 0x06a22c, 0x06aa2b, 0x06b222, 0x06ba25,
634   /* 216 */ 0x06c208, 0x06ca0f, 0x06d206, 0x06da01, 0x06e214, 0x06ea13,
635   /* 222 */ 0x06f21a, 0x06fa1d, 0x0702a0, 0x070aa7, 0x0712ae, 0x071aa9,
636   /* 228 */ 0x0722bc, 0x072abb, 0x0732b2, 0x073ab5, 0x074298, 0x074a9f,
637   /* 234 */ 0x075296, 0x075a91, 0x076284, 0x076a83, 0x07728a, 0x077a8d,
638   /* 240 */ 0x0782d0, 0x078ad7, 0x0792de, 0x079ad9, 0x07a2cc, 0x07aacb,
639   /* 246 */ 0x07b2c2, 0x07bac5, 0x07c2e8, 0x07caef, 0x07d2e6, 0x07dae1,
640   /* 252 */ 0x07e2f4, 0x07eaf3, 0x07f2fa, 0x07fafd
641 };
642
643 uint64_t
644 crc64 (const char *str, size_t len)
645 {
646   uint64_t res = 0LL;
647   for (size_t i = 0; i < len; i++)
648     {
649       unsigned char b = (unsigned char) ((res >> 56) ^ *str++);
650       res = res << 8;
651       res ^= masks [b];
652     }
653   return res;
654 }
655
656 /**
657  * Canonize path inside the string provided by the argument
658  * @param path
659  * @return path
660  */
661 char *
662 canonical_path (char *path)
663 {
664   char *s1, *s2;
665   if (!path)
666     return path;
667   s1 = path;
668   s2 = path;
669   while (*s1)
670     {
671       if (*s1 == '.' && s1[1] == '/')
672         { // remove .///
673           for (s1++; *s1; s1++)
674             if (*s1 != '/')
675               break;
676         }
677       else if (*s1 == '/')
678         { // replace /// with /
679           *(s2++) = *s1;
680           for (s1++; *s1; s1++)
681             if (*s1 != '/')
682               break;
683         }
684       else
685         {
686           while (*s1)
687             { // copy file or directory name
688               if (*s1 == '/')
689                 break;
690               *(s2++) = *(s1++);
691             }
692         }
693     }
694   *s2 = 0;
695   if (s2 != path && (s2 - 1) != path && s2[-1] == '/')  // remove last /
696     *(s2 - 1) = 0;
697   return path;
698 }
699
700 char *
701 get_relative_path (char *name)
702 {
703   if (*name == '/' && theApplication)
704     {
705       char *cwd = theApplication->get_cur_dir ();
706       if (cwd)
707         {
708           size_t len = strlen (cwd);
709           if (len > 0 && len < strlen (name) && name[len] == '/'
710               && strncmp (cwd, name, len) == 0)
711             {
712               for (name += len + 1; *name == '/'; name++)
713                 ;
714               return name;
715             }
716         }
717     }
718   return name;
719 }
720
721 /**
722  * Generate a relative link name from path_from to path_to
723  * Example:
724  * path_from=a/b/c/d
725  * path_to=a/b/e/f/g
726  * lname=../../e/f/g
727  * @param path_to
728  * @param path_from
729  * @return lname - relative link
730  */
731 char *
732 get_relative_link (const char *path_from, const char *path_to)
733 {
734   if (!path_to)
735     path_to = ".";
736   if (!path_from)
737     path_from = ".";
738   char *s1 = dbe_strdup (path_to);
739   s1 = canonical_path (s1);
740   char *s2 = dbe_strdup (path_from);
741   s2 = canonical_path (s2);
742   long l = dbe_sstrlen (s1);
743   // try to find common directories
744   int common_slashes = 0;
745   int last_common_slash = -1;
746   for (int i = 0; i < l; i++)
747     {
748       if (s1[i] != s2[i]) break;
749       if (s1[i] == 0) break;
750       if (s1[i] == '/')
751         {
752           common_slashes++;
753           last_common_slash = i;
754         }
755     }
756   // find slashes in remaining path_to
757   int slashes = 0;
758   for (int i = last_common_slash + 1; i < l; i++)
759     {
760       if (s1[i] == '/')
761         {
762           // Exclude "/./" case
763           if (i > last_common_slash + 2)
764             {
765               if (s1[i - 1] == '.' && s1[i - 2] == '/')
766                 continue;
767             }
768           else if (i > 0 && s1[i - 1] == '.')
769             continue;
770           slashes++;
771         }
772     }
773   // generate relative path
774   StringBuilder sb;
775   for (int i = 0; i < slashes; i++)
776     sb.append ("../");
777   sb.append (s2 + last_common_slash + 1);
778   char *lname = sb.toString ();
779   free (s1);
780   free (s2);
781   return lname;
782 }
783
784 char *
785 get_prog_name (int basename)
786 {
787   char *nm = NULL;
788   if (theApplication)
789     {
790       nm = theApplication->get_name ();
791       if (nm && basename)
792         nm = get_basename (nm);
793     }
794   return nm;
795 }
796
797 char *
798 dbe_strndup (const char *str, size_t len)
799 {
800   if (str == NULL)
801     return NULL;
802   char *s = (char *) malloc (len + 1);
803   strncpy (s, str, len);
804   s[len] = '\0';
805   return s;
806 }
807
808 char *
809 dbe_sprintf (const char *fmt, ...)
810 {
811   char buffer[256];
812   int buf_size;
813   va_list vp;
814
815   va_start (vp, fmt);
816   buf_size = vsnprintf (buffer, sizeof (buffer), fmt, vp) + 1;
817   va_end (vp);
818   if (buf_size < (int) sizeof (buffer))
819     {
820       if (buf_size <= 1)
821         buffer[0] = 0;
822       return strdup (buffer);
823     }
824
825   va_start (vp, fmt);
826   char *buf = (char *) malloc (buf_size);
827   vsnprintf (buf, buf_size, fmt, vp);
828   va_end (vp);
829   return buf;
830 }
831
832 ssize_t
833 dbe_write (int f, const char *fmt, ...)
834 {
835   char buffer[256];
836   int buf_size;
837   va_list vp;
838
839   va_start (vp, fmt);
840   buf_size = vsnprintf (buffer, sizeof (buffer), fmt, vp) + 1;
841   va_end (vp);
842   if (buf_size < (int) sizeof (buffer))
843     {
844       if (buf_size <= 1)
845         buffer[0] = 0;
846       return write (f, buffer, strlen (buffer));
847     }
848
849   va_start (vp, fmt);
850   char *buf = (char *) malloc (buf_size);
851   vsnprintf (buf, buf_size, fmt, vp);
852   va_end (vp);
853   ssize_t val = write (f, buf, strlen (buf));
854   free (buf);
855   return val;
856 }
857
858 /* Worker Threads to avoid hanging on file servers */
859
860 /*
861  * Thread states
862  */
863 enum
864 {
865   THREAD_START,
866   THREAD_STARTED,
867   THREAD_CANCEL,
868   THREAD_CANCELED,
869   THREAD_CREATE,
870   THREAD_NOT_CREATED,
871   THREAD_FINISHED
872 };
873
874 /*
875  * Communication structure
876  */
877 struct worker_thread_info
878 {
879   pthread_t thread_id;      /* ID returned by pthread_create() */
880   int thread_num;           /* Application-defined thread # */
881   volatile int control;     /* Thread state */
882   volatile int result;      /* Return status */
883   struct stat64 statbuf;    /* File info from stat64() */
884   const char *path;         /* File */
885 };
886
887 static pthread_mutex_t worker_thread_lock = PTHREAD_MUTEX_INITIALIZER;
888 static int worker_thread_number = 0;
889 /**
890  * Call stat64() on current worker thread
891  * Check if control is not THREAD_CANCEL
892  * If control is THREAD_CANCEL return (exit thread)
893  * @param *wt_info
894  */
895 static void *
896 dbe_stat_on_thread (void *arg)
897 {
898   struct worker_thread_info *wt_info = (struct worker_thread_info *) arg;
899   pthread_mutex_lock (&worker_thread_lock);
900   {
901     if (wt_info->control != THREAD_START)
902       {
903         // Already too late
904         pthread_mutex_unlock (&worker_thread_lock);
905         return 0;
906       }
907     wt_info->control = THREAD_STARTED;
908   }
909   pthread_mutex_unlock (&worker_thread_lock);
910   const char * path = wt_info->path;
911   int st = stat64 (path, &(wt_info->statbuf));
912   pthread_mutex_lock (&worker_thread_lock);
913   {
914     if (wt_info->control == THREAD_CANCEL)
915       {
916         // Too late.
917         pthread_mutex_unlock (&worker_thread_lock);
918         free (wt_info);
919         return 0;
920       }
921     wt_info->result = st;
922     wt_info->control = THREAD_FINISHED;
923   }
924   pthread_mutex_unlock (&worker_thread_lock);
925   return 0;
926 }
927
928 /**
929  * Create a worker thread to call specified function
930  * Wait for its result, but not longer than 5 seconds
931  * If the timeout happens, tell the thread to cancel
932  * @param path
933  * @param wt_info
934  * @return thread state
935  */
936 static int
937 dbe_dispatch_on_thread (const char *path, struct worker_thread_info *wt_info)
938 {
939   wt_info->result = 0;
940   wt_info->control = THREAD_START;
941   pthread_attr_t attr;
942   /* Initialize thread creation attributes */
943   int res = pthread_attr_init (&attr);
944   if (res != 0)
945     {
946       wt_info->control = THREAD_NOT_CREATED;
947       return THREAD_NOT_CREATED;
948     }
949   wt_info->thread_id = 0;
950   wt_info->path = path;
951   // Lock
952   pthread_mutex_lock (&worker_thread_lock);
953   worker_thread_number++;
954   wt_info->thread_num = worker_thread_number;
955   // Unlock
956   pthread_mutex_unlock (&worker_thread_lock);
957   // Create thread
958   res = pthread_create (&wt_info->thread_id, &attr, &dbe_stat_on_thread, wt_info);
959   if (res != 0)
960     {
961       wt_info->control = THREAD_NOT_CREATED;
962       pthread_attr_destroy (&attr);
963       return THREAD_NOT_CREATED;
964     }
965   // Wait for the thread to finish
966   res = 0;
967   useconds_t maxusec = 5000000; // 5 seconds
968   useconds_t deltausec = 1000; // 1 millisecond
969   int max = maxusec / deltausec;
970   for (int i = 0; i < max; i++)
971     {
972       if (THREAD_FINISHED == wt_info->control)
973         break; // We are done
974       usleep (deltausec);
975     }
976   // Lock
977   pthread_mutex_lock (&worker_thread_lock);
978   if (THREAD_FINISHED != wt_info->control)
979     {
980       // Cancel thread
981       wt_info->control = THREAD_CANCEL; // Cannot use wt_info after that!
982       res = THREAD_CANCEL;
983     }
984   // Unlock
985   pthread_mutex_unlock (&worker_thread_lock);
986   // Destroy the thread attributes object, since it is no longer needed
987   pthread_attr_destroy (&attr);
988   // Report that thread was canceled
989   if (THREAD_CANCEL == res)
990     return res; /* Cannot free memory allocated by thread */
991   // Free all thread resources
992   void *resources = 0;
993   res = pthread_join (wt_info->thread_id, &resources);
994   free (resources); /* Free memory allocated by thread */
995   return THREAD_FINISHED;
996 }
997
998 static pthread_mutex_t dirnames_lock = PTHREAD_MUTEX_INITIALIZER;
999 static Map<const char*, int> *dirnamesMap = NULL;
1000
1001 #define DIR_STATUS_EXISTS 0
1002 #define DIR_STATUS_UNKNOWN 2
1003
1004 /**
1005  * Check if this directory name is known
1006  * Return:
1007  * @param path
1008  *  0 - known, exists
1009  *  1 - known, does not exist
1010  *  2 - not known
1011  */
1012 static int
1013 check_dirname (const char *path)
1014 {
1015   pthread_mutex_lock (&dirnames_lock);
1016   if (NULL == dirnamesMap)
1017     dirnamesMap = new StringMap<int>(128, 128);
1018   pthread_mutex_unlock (&dirnames_lock);
1019   int res = DIR_STATUS_UNKNOWN;
1020   if (path && *path)
1021     {
1022       char *fn = dbe_strdup (path);
1023       char *dn = dirname (fn);
1024       if (dn && *dn)
1025         res = dirnamesMap->get (dn);
1026       free (fn);
1027     }
1028   return res;
1029 }
1030
1031 /**
1032  * Save directory name and its status
1033  * @param path
1034  * @param status
1035  * @return
1036  */
1037 static void
1038 extract_and_save_dirname (const char *path, int status)
1039 {
1040   pthread_mutex_lock (&dirnames_lock);
1041   if (NULL == dirnamesMap)
1042     dirnamesMap = new StringMap<int>(128, 128);
1043   pthread_mutex_unlock (&dirnames_lock);
1044   char *fn = dbe_strdup (path);
1045   if (fn && *fn != 0)
1046     {
1047       char *dn = dirname (fn);
1048       if (dn && (*dn != 0))
1049         {
1050           int st = 0; // exists
1051           if (0 != status)
1052             st = 1; // does not exist
1053           dirnamesMap->put (dn, st);
1054         }
1055     }
1056   free (fn);
1057 }
1058
1059 // get status for specified file
1060 static int
1061 dbe_stat_internal (const char *path, struct stat64 *sbuf, bool file_only)
1062 {
1063   struct stat64 statbuf;
1064   int dir_status = check_dirname (path);
1065   if (dir_status == DIR_STATUS_UNKNOWN)
1066     {
1067       // Try to use a worker thread
1068       if (theApplication->get_number_of_worker_threads () > 0)
1069         {
1070           struct worker_thread_info *wt_info;
1071           wt_info = (worker_thread_info *) calloc (1, sizeof (worker_thread_info));
1072           if (wt_info != NULL)
1073             {
1074               int res = dbe_dispatch_on_thread (path, wt_info);
1075               if (THREAD_FINISHED == res)
1076                 {
1077                   int st = wt_info->result;
1078                   extract_and_save_dirname (path, st);
1079                   if (st == 0 && file_only)
1080                     if (S_ISREG ((wt_info->statbuf).st_mode) == 0)
1081                       st = -1; // It is not a regular file
1082                   if (sbuf != NULL)
1083                     *sbuf = wt_info->statbuf;
1084                   free (wt_info);
1085                   return st;
1086                 }
1087               else
1088                 {
1089                   if (THREAD_CANCEL == res)
1090                     {
1091                       // Worker thread hung. Cannot free wt_info.
1092                       // Allocated memory will be freed by worker thread.
1093                       // save directory
1094                       extract_and_save_dirname (path, 1);
1095                       return 1; // stat64 failed
1096                     }
1097                   else  // THREAD_NOT_CREATED - continue on current thread
1098                     free (wt_info);
1099                 }
1100             }
1101         }
1102     }
1103   else if (dir_status != DIR_STATUS_EXISTS)
1104     return -1; // does not exist
1105   if (sbuf == NULL)
1106     sbuf = &statbuf;
1107   int st = stat64 (path, sbuf);
1108   Dprintf (DEBUG_DBE_FILE, NTXT ("dbe_stat %d '%s'\n"), st, path);
1109   if (st == -1)
1110     return -1;
1111   else if (file_only && S_ISREG (sbuf->st_mode) == 0)
1112     return -1; // It is not ordinary file
1113   return st;
1114 }
1115
1116 // get status for the regular file
1117
1118 int
1119 dbe_stat_file (const char *path, struct stat64 *sbuf)
1120 {
1121   int res = dbe_stat_internal (path, sbuf, true);
1122   return res;
1123 }
1124
1125 // get status for specified file
1126
1127 int
1128 dbe_stat (const char *path, struct stat64 *sbuf)
1129 {
1130   int res = dbe_stat_internal (path, sbuf, false);
1131   return res;
1132 }
1133
1134 /**
1135  * Reads directory and prepares list of files according to the specified format
1136  * Supported formats:
1137  * "/bin/ls -a" - see 'man ls' for details
1138  * "/bin/ls -aF" - see 'man ls' for details
1139  * @param path
1140  * @param format
1141  * @return char * files
1142  */
1143 char *
1144 dbe_read_dir (const char *path, const char *format)
1145 {
1146   StringBuilder sb;
1147   DIR *dir = opendir (path);
1148   if (dir == NULL)
1149     return sb.toString ();
1150   int format_aF = 0;
1151   if (!strcmp (format, NTXT ("/bin/ls -aF")))
1152     format_aF = 1;
1153   struct dirent *entry = NULL;
1154   if (format != NULL)
1155     {
1156       while ((entry = readdir (dir)) != NULL)
1157         {
1158           sb.append (entry->d_name);
1159           if (format_aF)
1160             {
1161               const char *attr = NTXT ("@"); // Link
1162               struct stat64 sbuf;
1163               sbuf.st_mode = 0;
1164               char filename[MAXPATHLEN + 1];
1165               snprintf (filename, sizeof (filename), NTXT ("%s/%s"), path, entry->d_name);
1166               dbe_stat (filename, &sbuf);
1167               if (S_IREAD & sbuf.st_mode)
1168                 { // Readable
1169                   if (S_ISDIR (sbuf.st_mode) != 0)  // Directory
1170                     attr = NTXT ("/");
1171                   else if (S_ISREG (sbuf.st_mode) != 0) // Regular file
1172                     attr = NTXT ("");
1173                 }
1174               sb.append (attr);
1175             }
1176           sb.append (NTXT ("\n"));
1177         }
1178     }
1179   closedir (dir);
1180   return sb.toString ();
1181 }
1182
1183 /**
1184  * Gets list of processes according to the specified format
1185  * Supported formats:
1186  * "/bin/ps -ef" - see 'man ps' for details
1187  * @param format
1188  * @return char * processes
1189  */
1190 char *
1191 dbe_get_processes (const char *format)
1192 {
1193   StringBuilder sb;
1194   if (!strcmp (format, NTXT ("/bin/ps -ef")))
1195     {
1196       char buf[BUFSIZ];
1197       FILE *ptr = popen (format, "r");
1198       if (ptr != NULL)
1199         {
1200           while (fgets (buf, BUFSIZ, ptr) != NULL)
1201             sb.append (buf);
1202           pclose (ptr);
1203         }
1204     }
1205   return sb.toString ();
1206 }
1207
1208 /**
1209  * Creates the directory named by the specified path name, including any
1210  * necessary but nonexistent parent directories.
1211  * Uses system utility "/bin/mkdir -p"
1212  * Temporary limitation: path name should not contain spaces.
1213  * Returns message from "/bin/mkdir -p"
1214  * @param pathname
1215  * @return result
1216  */
1217 char *
1218 dbe_create_directories (const char *pathname)
1219 {
1220   StringBuilder sb;
1221   char *makedir = dbe_sprintf (NTXT ("/bin/mkdir -p %s 2>&1"), pathname);
1222   char out[BUFSIZ];
1223   FILE *ptr = popen (makedir, "r");
1224   if (ptr != NULL)
1225     {
1226       while (fgets (out, BUFSIZ, ptr) != NULL)
1227         sb.append (out);
1228       pclose (ptr);
1229     }
1230   free (makedir);
1231   DIR *dir = opendir (pathname);
1232   if (dir != NULL)
1233     {
1234       closedir (dir);
1235       return NULL; // success
1236     }
1237   else
1238     sb.append (NTXT ("\nError: Cannot open directory\n")); // DEBUG
1239   return sb.toString (); // error
1240 }
1241
1242 /**
1243  * Deletes the file or the directory named by the specified path name.
1244  * If this pathname denotes a directory, then the directory must be empty in order to be deleted.
1245  * Uses system utility "/bin/rm" or "/bin/rmdir"
1246  * Temporary limitation: path name should not contain spaces.
1247  * Returns error message from system utility
1248  * @param pathname
1249  * @return result
1250  */
1251 char *
1252 dbe_delete_file (const char *pathname)
1253 {
1254   StringBuilder sb;
1255   char *cmd = NULL;
1256   struct stat64 sbuf;
1257   sbuf.st_mode = 0;
1258   int st = dbe_stat (pathname, &sbuf);
1259   if (st == 0)
1260     { // Exists
1261       if (S_ISDIR (sbuf.st_mode) != 0)      // Directory
1262         cmd = dbe_sprintf (NTXT ("/bin/rmdir %s 2>&1"), pathname);
1263       else if (S_ISREG (sbuf.st_mode) != 0)     // Regular file
1264         cmd = dbe_sprintf (NTXT ("/bin/rm %s 2>&1"), pathname);
1265     }
1266   else
1267     return NULL; // Nothing to remove
1268   if (cmd != NULL)
1269     {
1270       char out[BUFSIZ];
1271       FILE *ptr = popen (cmd, "r");
1272       if (ptr != NULL)
1273         {
1274           while (fgets (out, BUFSIZ, ptr) != NULL)
1275             sb.append (out);
1276           pclose (ptr);
1277         }
1278       free (cmd);
1279     }
1280   else
1281     sb.sprintf (NTXT ("Error: cannot remove %s - not a regular file and not a directory\n"), pathname);
1282   return sb.toString ();
1283 }
1284
1285 char *
1286 dbe_xml2str (const char *s)
1287 {
1288   if (s == NULL)
1289     return NULL;
1290   StringBuilder sb;
1291   while (*s)
1292     {
1293       if (*s == '&')
1294         {
1295           if (strncmp (s, NTXT ("&nbsp;"), 6) == 0)
1296             {
1297               sb.append (' ');
1298               s += 6;
1299               continue;
1300             }
1301           else if (strncmp (s, NTXT ("&quot;"), 6) == 0)
1302             {
1303               sb.append ('"');
1304               s += 6;
1305               continue;
1306             }
1307           else if (strncmp (s, NTXT ("&amp;"), 5) == 0)
1308             {
1309               sb.append ('&');
1310               s += 5;
1311               continue;
1312             }
1313           else if (strncmp (s, NTXT ("&lt;"), 4) == 0)
1314             {
1315               sb.append ('<');
1316               s += 4;
1317               continue;
1318             }
1319           else if (strncmp (s, NTXT ("&gt;"), 4) == 0)
1320             {
1321               sb.append ('>');
1322               s += 4;
1323               continue;
1324             }
1325         }
1326       sb.append (*s);
1327       s++;
1328     }
1329   return sb.toString ();
1330 }
1331
1332 void
1333 swapByteOrder (void *p, size_t sz)
1334 {
1335   if (sz == 8)
1336     {
1337       uint64_t *pv = (uint64_t *) p;
1338       uint64_t v = *pv;
1339       v = ((v & 0x00000000FF000000) << 8) | ((v >> 8) & 0x00000000FF000000) |
1340               ((v & 0x0000000000FF0000) << 24) | ((v >> 24) & 0x0000000000FF0000) |
1341               ((v & 0x000000000000FF00) << 40) | ((v >> 40) & 0x000000000000FF00) |
1342               (v >> 56) | (v << 56);
1343       *pv = v;
1344     }
1345   else if (sz == 4)
1346     {
1347       uint32_t *pv = (uint32_t *) p;
1348       uint32_t v = *pv;
1349       v = (v >> 24) | (v << 24) | ((v & 0x0000FF00) << 8) | ((v >> 8) & 0x0000FF00);
1350       *pv = v;
1351     }
1352   else if (sz == 2)
1353     {
1354       uint16_t *pv = (uint16_t *) p;
1355       uint16_t v = *pv;
1356       v = (v >> 8) | (v << 8);
1357       *pv = v;
1358     }
1359 }
1360
1361 void
1362 destroy (void *vec)
1363 {
1364   if (vec == NULL)
1365     return;
1366   Vector<void*> *array = (Vector<void*>*)vec;
1367   switch (array->type ())
1368     {
1369     case VEC_STRING:
1370       ((Vector<char *>*)array)->destroy ();
1371       break;
1372     case VEC_VOIDARR:
1373     case VEC_STRINGARR:
1374     case VEC_INTARR:
1375     case VEC_BOOLARR:
1376     case VEC_LLONGARR:
1377     case VEC_DOUBLEARR:
1378       for (long i = 0; i < array->size (); i++)
1379         destroy (array->fetch (i));
1380       break;
1381     case VEC_INTEGER:
1382     case VEC_CHAR:
1383     case VEC_BOOL:
1384     case VEC_DOUBLE:
1385     case VEC_LLONG:
1386     default:
1387       break;
1388     }
1389   delete array;
1390 }
1391
1392 int64_t
1393 read_from_file (int fd, void *buffer, int64_t nbyte)
1394 {
1395   int64_t cnt = 0;
1396   char *buf = (char *) buffer;
1397   while (nbyte > 0)
1398     { // Sometimes system cannot read 'nbyte'
1399       ssize_t n = read (fd, (void *) (buf + cnt), (size_t) nbyte);
1400       if (n <= 0)
1401         break;
1402       nbyte -= n;
1403       cnt += n;
1404     }
1405   return cnt;
1406 }
1407
1408 /**
1409  * Create symbolic link to the path
1410  * @param  path - path with spaces
1411  * @param  dir  - directory where the link should be created
1412  * @return symbolic link
1413  */
1414 char *
1415 dbe_create_symlink_to_path (const char *path, const char *dir)
1416 {
1417   char *symbolic_link = NULL;
1418   if (NULL == path || NULL == dir)
1419     return NULL;
1420   int res = mkdir (dir, 0777);
1421   if (res != 0 && dbe_stat (dir, NULL) != 0)
1422     return NULL; // Cannot create directory
1423   long len = dbe_sstrlen (path);
1424   if (len <= 4)
1425     return NULL; // Unknown situation
1426   if (strcmp ((path + len - 4), "/bin") != 0)   // Unknown situation
1427     return NULL;
1428   int max = 99; // Just an arbitrary number
1429   for (int i = 1; i <= max; i++)
1430     {
1431       // Try to create symbolic link
1432       char *d = dbe_sprintf ("%s/%d", dir, i);
1433       if (NULL == d)
1434         return NULL;
1435       res = mkdir (d, 0777);
1436       symbolic_link = dbe_sprintf ("%s/%s", d, "bin");
1437       free (d);
1438       if (NULL == symbolic_link) // Not enough memory
1439         return NULL;
1440       res = symlink (path, symbolic_link);
1441       if (res == 0)     // Link is created - use it.
1442         break;
1443       // Check if such link already exists
1444       int e = errno;
1445       char buf[MAXPATHLEN + 1];
1446       memset (buf, 0, MAXPATHLEN + 1);
1447       ssize_t n = readlink (symbolic_link, buf, MAXPATHLEN);
1448       if (n == len && strcmp (path, buf) == 0) // Link is correct - use it.
1449         break;
1450       if (i == max)
1451         { // report the error
1452           fprintf (stderr, GTXT ("Error: symlink(%s, %s) returned error: %d\n"), path, symbolic_link, res);
1453           fprintf (stderr, GTXT ("Error: errno=%d (%s)\n"), e, strerror (e));
1454           fflush (stderr);
1455         }
1456       free (symbolic_link);
1457       symbolic_link = NULL;
1458     }
1459   return symbolic_link;
1460 }
1461
1462 // Compute checksum for specified file.
1463 // This code is from usr/src/cmd/cksum.c, adapted for us
1464 // crcposix -- compute posix.2 compatable 32 bit CRC
1465 //
1466 // The POSIX.2 (draft 10) CRC algorithm.
1467 // This is a 32 bit CRC with polynomial
1468 //      x**32 + x**26 + x**23 + x**22 + x**16 + x**12 + x**11 + x**10 +
1469 //      x**8  + x**7  + x**5  + x**4  + x**2  + x**1  + x**0
1470 //
1471 // layout is from the POSIX.2 Rationale
1472
1473 static uint32_t crctab_posix[256] = {
1474   0x00000000L,
1475   0x04C11DB7L, 0x09823B6EL, 0x0D4326D9L, 0x130476DCL, 0x17C56B6BL,
1476   0x1A864DB2L, 0x1E475005L, 0x2608EDB8L, 0x22C9F00FL, 0x2F8AD6D6L,
1477   0x2B4BCB61L, 0x350C9B64L, 0x31CD86D3L, 0x3C8EA00AL, 0x384FBDBDL,
1478   0x4C11DB70L, 0x48D0C6C7L, 0x4593E01EL, 0x4152FDA9L, 0x5F15ADACL,
1479   0x5BD4B01BL, 0x569796C2L, 0x52568B75L, 0x6A1936C8L, 0x6ED82B7FL,
1480   0x639B0DA6L, 0x675A1011L, 0x791D4014L, 0x7DDC5DA3L, 0x709F7B7AL,
1481   0x745E66CDL, 0x9823B6E0L, 0x9CE2AB57L, 0x91A18D8EL, 0x95609039L,
1482   0x8B27C03CL, 0x8FE6DD8BL, 0x82A5FB52L, 0x8664E6E5L, 0xBE2B5B58L,
1483   0xBAEA46EFL, 0xB7A96036L, 0xB3687D81L, 0xAD2F2D84L, 0xA9EE3033L,
1484   0xA4AD16EAL, 0xA06C0B5DL, 0xD4326D90L, 0xD0F37027L, 0xDDB056FEL,
1485   0xD9714B49L, 0xC7361B4CL, 0xC3F706FBL, 0xCEB42022L, 0xCA753D95L,
1486   0xF23A8028L, 0xF6FB9D9FL, 0xFBB8BB46L, 0xFF79A6F1L, 0xE13EF6F4L,
1487   0xE5FFEB43L, 0xE8BCCD9AL, 0xEC7DD02DL, 0x34867077L, 0x30476DC0L,
1488   0x3D044B19L, 0x39C556AEL, 0x278206ABL, 0x23431B1CL, 0x2E003DC5L,
1489   0x2AC12072L, 0x128E9DCFL, 0x164F8078L, 0x1B0CA6A1L, 0x1FCDBB16L,
1490   0x018AEB13L, 0x054BF6A4L, 0x0808D07DL, 0x0CC9CDCAL, 0x7897AB07L,
1491   0x7C56B6B0L, 0x71159069L, 0x75D48DDEL, 0x6B93DDDBL, 0x6F52C06CL,
1492   0x6211E6B5L, 0x66D0FB02L, 0x5E9F46BFL, 0x5A5E5B08L, 0x571D7DD1L,
1493   0x53DC6066L, 0x4D9B3063L, 0x495A2DD4L, 0x44190B0DL, 0x40D816BAL,
1494   0xACA5C697L, 0xA864DB20L, 0xA527FDF9L, 0xA1E6E04EL, 0xBFA1B04BL,
1495   0xBB60ADFCL, 0xB6238B25L, 0xB2E29692L, 0x8AAD2B2FL, 0x8E6C3698L,
1496   0x832F1041L, 0x87EE0DF6L, 0x99A95DF3L, 0x9D684044L, 0x902B669DL,
1497   0x94EA7B2AL, 0xE0B41DE7L, 0xE4750050L, 0xE9362689L, 0xEDF73B3EL,
1498   0xF3B06B3BL, 0xF771768CL, 0xFA325055L, 0xFEF34DE2L, 0xC6BCF05FL,
1499   0xC27DEDE8L, 0xCF3ECB31L, 0xCBFFD686L, 0xD5B88683L, 0xD1799B34L,
1500   0xDC3ABDEDL, 0xD8FBA05AL, 0x690CE0EEL, 0x6DCDFD59L, 0x608EDB80L,
1501   0x644FC637L, 0x7A089632L, 0x7EC98B85L, 0x738AAD5CL, 0x774BB0EBL,
1502   0x4F040D56L, 0x4BC510E1L, 0x46863638L, 0x42472B8FL, 0x5C007B8AL,
1503   0x58C1663DL, 0x558240E4L, 0x51435D53L, 0x251D3B9EL, 0x21DC2629L,
1504   0x2C9F00F0L, 0x285E1D47L, 0x36194D42L, 0x32D850F5L, 0x3F9B762CL,
1505   0x3B5A6B9BL, 0x0315D626L, 0x07D4CB91L, 0x0A97ED48L, 0x0E56F0FFL,
1506   0x1011A0FAL, 0x14D0BD4DL, 0x19939B94L, 0x1D528623L, 0xF12F560EL,
1507   0xF5EE4BB9L, 0xF8AD6D60L, 0xFC6C70D7L, 0xE22B20D2L, 0xE6EA3D65L,
1508   0xEBA91BBCL, 0xEF68060BL, 0xD727BBB6L, 0xD3E6A601L, 0xDEA580D8L,
1509   0xDA649D6FL, 0xC423CD6AL, 0xC0E2D0DDL, 0xCDA1F604L, 0xC960EBB3L,
1510   0xBD3E8D7EL, 0xB9FF90C9L, 0xB4BCB610L, 0xB07DABA7L, 0xAE3AFBA2L,
1511   0xAAFBE615L, 0xA7B8C0CCL, 0xA379DD7BL, 0x9B3660C6L, 0x9FF77D71L,
1512   0x92B45BA8L, 0x9675461FL, 0x8832161AL, 0x8CF30BADL, 0x81B02D74L,
1513   0x857130C3L, 0x5D8A9099L, 0x594B8D2EL, 0x5408ABF7L, 0x50C9B640L,
1514   0x4E8EE645L, 0x4A4FFBF2L, 0x470CDD2BL, 0x43CDC09CL, 0x7B827D21L,
1515   0x7F436096L, 0x7200464FL, 0x76C15BF8L, 0x68860BFDL, 0x6C47164AL,
1516   0x61043093L, 0x65C52D24L, 0x119B4BE9L, 0x155A565EL, 0x18197087L,
1517   0x1CD86D30L, 0x029F3D35L, 0x065E2082L, 0x0B1D065BL, 0x0FDC1BECL,
1518   0x3793A651L, 0x3352BBE6L, 0x3E119D3FL, 0x3AD08088L, 0x2497D08DL,
1519   0x2056CD3AL, 0x2D15EBE3L, 0x29D4F654L, 0xC5A92679L, 0xC1683BCEL,
1520   0xCC2B1D17L, 0xC8EA00A0L, 0xD6AD50A5L, 0xD26C4D12L, 0xDF2F6BCBL,
1521   0xDBEE767CL, 0xE3A1CBC1L, 0xE760D676L, 0xEA23F0AFL, 0xEEE2ED18L,
1522   0xF0A5BD1DL, 0xF464A0AAL, 0xF9278673L, 0xFDE69BC4L, 0x89B8FD09L,
1523   0x8D79E0BEL, 0x803AC667L, 0x84FBDBD0L, 0x9ABC8BD5L, 0x9E7D9662L,
1524   0x933EB0BBL, 0x97FFAD0CL, 0xAFB010B1L, 0xAB710D06L, 0xA6322BDFL,
1525   0xA2F33668L, 0xBCB4666DL, 0xB8757BDAL, 0xB5365D03L, 0xB1F740B4L
1526 };
1527
1528 static void
1529 m_crcposix (uint32_t *crcp, unsigned char *bp, uint32_t n)
1530 {
1531   while (n-- > 0)
1532     *crcp = (*crcp << 8) ^ crctab_posix[(unsigned char) ((*crcp >> 24)^*bp++)];
1533 }
1534
1535 // Do CRC-POSIX function by calling a library entry point that has a
1536 // slightly different calling sequence.
1537 static uint32_t
1538 docrcposix (uint32_t crcval, unsigned char *bp, uint32_t n)
1539 {
1540   m_crcposix (&crcval, bp, n);
1541   return (crcval);
1542 }
1543
1544 // Sum algorithms require various kinds of post-processing.
1545 // The 'S' and 'R' variables are from the POSIX.2 (Draft 8?) description
1546 // of the "sum" utility.
1547 static uint32_t
1548 postprocess (uint32_t S, long long n)
1549 {
1550   // POSIX tacks on significant bytes of the length so that
1551   // different length sequences of '\0' have different sums;
1552   // then it complements sum.
1553   unsigned char char_n[sizeof (n)];
1554   uint32_t i;
1555   for (i = 0; n != 0; n >>= 8, ++i)
1556     char_n[i] = (unsigned char) (n & 0xFF);
1557   return (~docrcposix (S, char_n, i));
1558 }
1559
1560 uint32_t
1561 get_cksum (const char * pathname, char ** errmsg)
1562 {
1563   int fd = open (pathname, O_RDONLY);
1564   if (fd < 0)
1565     {
1566       if (errmsg)
1567         *errmsg = dbe_sprintf (GTXT ("*** Warning: Error opening file for reading: %s"), pathname);
1568       return 0; // error
1569     }
1570   uint32_t crcval = 0;
1571   long long bytes = 0;
1572   int64_t n;
1573   unsigned char buf[4096];
1574   while ((n = read_from_file (fd, (char *) buf, sizeof (buf))) > 0)
1575     {
1576       bytes += n;
1577       crcval = docrcposix (crcval, buf, n);
1578     }
1579   close (fd);
1580   crcval = postprocess (crcval, bytes);
1581   return crcval;
1582 }
This page took 0.108832 seconds and 4 git commands to generate.