vdr  2.2.0
tools.c
Go to the documentation of this file.
1 /*
2  * tools.c: Various tools
3  *
4  * See the main source file 'vdr.c' for copyright information and
5  * how to reach the author.
6  *
7  * $Id: tools.c 3.4 2015/02/07 15:09:17 kls Exp $
8  */
9 
10 #include "tools.h"
11 #include <ctype.h>
12 #include <dirent.h>
13 #include <errno.h>
14 extern "C" {
15 #ifdef boolean
16 #define HAVE_BOOLEAN
17 #endif
18 #include <jpeglib.h>
19 #undef boolean
20 }
21 #include <locale.h>
22 #include <stdlib.h>
23 #include <sys/time.h>
24 #include <sys/vfs.h>
25 #include <time.h>
26 #include <unistd.h>
27 #include <utime.h>
28 #include "i18n.h"
29 #include "thread.h"
30 
31 int SysLogLevel = 3;
32 
33 #define MAXSYSLOGBUF 256
34 
35 void syslog_with_tid(int priority, const char *format, ...)
36 {
37  va_list ap;
38  char fmt[MAXSYSLOGBUF];
39  snprintf(fmt, sizeof(fmt), "[%d] %s", cThread::ThreadId(), format);
40  va_start(ap, format);
41  vsyslog(priority, fmt, ap);
42  va_end(ap);
43 }
44 
45 int BCD2INT(int x)
46 {
47  return ((1000000 * BCDCHARTOINT((x >> 24) & 0xFF)) +
48  (10000 * BCDCHARTOINT((x >> 16) & 0xFF)) +
49  (100 * BCDCHARTOINT((x >> 8) & 0xFF)) +
50  BCDCHARTOINT( x & 0xFF));
51 }
52 
53 ssize_t safe_read(int filedes, void *buffer, size_t size)
54 {
55  for (;;) {
56  ssize_t p = read(filedes, buffer, size);
57  if (p < 0 && errno == EINTR) {
58  dsyslog("EINTR while reading from file handle %d - retrying", filedes);
59  continue;
60  }
61  return p;
62  }
63 }
64 
65 ssize_t safe_write(int filedes, const void *buffer, size_t size)
66 {
67  ssize_t p = 0;
68  ssize_t written = size;
69  const unsigned char *ptr = (const unsigned char *)buffer;
70  while (size > 0) {
71  p = write(filedes, ptr, size);
72  if (p < 0) {
73  if (errno == EINTR) {
74  dsyslog("EINTR while writing to file handle %d - retrying", filedes);
75  continue;
76  }
77  break;
78  }
79  ptr += p;
80  size -= p;
81  }
82  return p < 0 ? p : written;
83 }
84 
85 void writechar(int filedes, char c)
86 {
87  safe_write(filedes, &c, sizeof(c));
88 }
89 
90 int WriteAllOrNothing(int fd, const uchar *Data, int Length, int TimeoutMs, int RetryMs)
91 {
92  int written = 0;
93  while (Length > 0) {
94  int w = write(fd, Data + written, Length);
95  if (w > 0) {
96  Length -= w;
97  written += w;
98  }
99  else if (written > 0 && !FATALERRNO) {
100  // we've started writing, so we must finish it!
101  cTimeMs t;
102  cPoller Poller(fd, true);
103  Poller.Poll(RetryMs);
104  if (TimeoutMs > 0 && (TimeoutMs -= t.Elapsed()) <= 0)
105  break;
106  }
107  else
108  // nothing written yet (or fatal error), so we can just return the error code:
109  return w;
110  }
111  return written;
112 }
113 
114 char *strcpyrealloc(char *dest, const char *src)
115 {
116  if (src) {
117  int l = max(dest ? strlen(dest) : 0, strlen(src)) + 1; // don't let the block get smaller!
118  dest = (char *)realloc(dest, l);
119  if (dest)
120  strcpy(dest, src);
121  else
122  esyslog("ERROR: out of memory");
123  }
124  else {
125  free(dest);
126  dest = NULL;
127  }
128  return dest;
129 }
130 
131 char *strn0cpy(char *dest, const char *src, size_t n)
132 {
133  char *s = dest;
134  for ( ; --n && (*dest = *src) != 0; dest++, src++) ;
135  *dest = 0;
136  return s;
137 }
138 
139 char *strreplace(char *s, char c1, char c2)
140 {
141  if (s) {
142  char *p = s;
143  while (*p) {
144  if (*p == c1)
145  *p = c2;
146  p++;
147  }
148  }
149  return s;
150 }
151 
152 char *strreplace(char *s, const char *s1, const char *s2)
153 {
154  char *p = strstr(s, s1);
155  if (p) {
156  int of = p - s;
157  int l = strlen(s);
158  int l1 = strlen(s1);
159  int l2 = strlen(s2);
160  if (l2 > l1) {
161  if (char *NewBuffer = (char *)realloc(s, l + l2 - l1 + 1))
162  s = NewBuffer;
163  else {
164  esyslog("ERROR: out of memory");
165  return s;
166  }
167  }
168  char *sof = s + of;
169  if (l2 != l1)
170  memmove(sof + l2, sof + l1, l - of - l1 + 1);
171  strncpy(sof, s2, l2);
172  }
173  return s;
174 }
175 
176 const char *strchrn(const char *s, char c, size_t n)
177 {
178  if (n == 0)
179  return s;
180  if (s) {
181  for ( ; *s; s++) {
182  if (*s == c && --n == 0)
183  return s;
184  }
185  }
186  return NULL;
187 }
188 
189 int strcountchr(const char *s, char c)
190 {
191  int n = 0;
192  if (s && c) {
193  for ( ; *s; s++) {
194  if (*s == c)
195  n++;
196  }
197  }
198  return n;
199 }
200 
201 char *stripspace(char *s)
202 {
203  if (s && *s) {
204  for (char *p = s + strlen(s) - 1; p >= s; p--) {
205  if (!isspace(*p))
206  break;
207  *p = 0;
208  }
209  }
210  return s;
211 }
212 
213 char *compactspace(char *s)
214 {
215  if (s && *s) {
216  char *t = stripspace(skipspace(s));
217  char *p = t;
218  while (p && *p) {
219  char *q = skipspace(p);
220  if (q - p > 1)
221  memmove(p + 1, q, strlen(q) + 1);
222  p++;
223  }
224  if (t != s)
225  memmove(s, t, strlen(t) + 1);
226  }
227  return s;
228 }
229 
230 char *compactchars(char *s, char c)
231 {
232  if (s && *s && c) {
233  char *t = s;
234  char *p = s;
235  int n = 0;
236  while (*p) {
237  if (*p != c) {
238  *t++ = *p;
239  n = 0;
240  }
241  else if (t != s && n == 0) {
242  *t++ = *p;
243  n++;
244  }
245  p++;
246  }
247  if (n)
248  t--; // the last character was c
249  *t = 0;
250  }
251  return s;
252 }
253 
254 cString strescape(const char *s, const char *chars)
255 {
256  char *buffer;
257  const char *p = s;
258  char *t = NULL;
259  while (*p) {
260  if (strchr(chars, *p)) {
261  if (!t) {
262  buffer = MALLOC(char, 2 * strlen(s) + 1);
263  t = buffer + (p - s);
264  s = strcpy(buffer, s);
265  }
266  *t++ = '\\';
267  }
268  if (t)
269  *t++ = *p;
270  p++;
271  }
272  if (t)
273  *t = 0;
274  return cString(s, t != NULL);
275 }
276 
277 bool startswith(const char *s, const char *p)
278 {
279  while (*p) {
280  if (*p++ != *s++)
281  return false;
282  }
283  return true;
284 }
285 
286 bool endswith(const char *s, const char *p)
287 {
288  const char *se = s + strlen(s) - 1;
289  const char *pe = p + strlen(p) - 1;
290  while (pe >= p) {
291  if (*pe-- != *se-- || (se < s && pe >= p))
292  return false;
293  }
294  return true;
295 }
296 
297 bool isempty(const char *s)
298 {
299  return !(s && *skipspace(s));
300 }
301 
302 int numdigits(int n)
303 {
304  int res = 1;
305  while (n >= 10) {
306  n /= 10;
307  res++;
308  }
309  return res;
310 }
311 
312 bool isnumber(const char *s)
313 {
314  if (!s || !*s)
315  return false;
316  do {
317  if (!isdigit(*s))
318  return false;
319  } while (*++s);
320  return true;
321 }
322 
323 int64_t StrToNum(const char *s)
324 {
325  char *t = NULL;
326  int64_t n = strtoll(s, &t, 10);
327  if (t) {
328  switch (*t) {
329  case 'T': n *= 1024;
330  case 'G': n *= 1024;
331  case 'M': n *= 1024;
332  case 'K': n *= 1024;
333  }
334  }
335  return n;
336 }
337 
338 bool StrInArray(const char *a[], const char *s)
339 {
340  if (a) {
341  while (*a) {
342  if (strcmp(*a, s) == 0)
343  return true;
344  a++;
345  }
346  }
347  return false;
348 }
349 
350 cString AddDirectory(const char *DirName, const char *FileName)
351 {
352  return cString::sprintf("%s/%s", DirName && *DirName ? DirName : ".", FileName);
353 }
354 
355 #define DECIMAL_POINT_C '.'
356 
357 double atod(const char *s)
358 {
359  static lconv *loc = localeconv();
360  if (*loc->decimal_point != DECIMAL_POINT_C) {
361  char buf[strlen(s) + 1];
362  char *p = buf;
363  while (*s) {
364  if (*s == DECIMAL_POINT_C)
365  *p = *loc->decimal_point;
366  else
367  *p = *s;
368  p++;
369  s++;
370  }
371  *p = 0;
372  return atof(buf);
373  }
374  else
375  return atof(s);
376 }
377 
378 cString dtoa(double d, const char *Format)
379 {
380  static lconv *loc = localeconv();
381  char buf[16];
382  snprintf(buf, sizeof(buf), Format, d);
383  if (*loc->decimal_point != DECIMAL_POINT_C)
384  strreplace(buf, *loc->decimal_point, DECIMAL_POINT_C);
385  return buf;
386 }
387 
388 cString itoa(int n)
389 {
390  char buf[16];
391  snprintf(buf, sizeof(buf), "%d", n);
392  return buf;
393 }
394 
395 bool EntriesOnSameFileSystem(const char *File1, const char *File2)
396 {
397  struct stat st;
398  if (stat(File1, &st) == 0) {
399  dev_t dev1 = st.st_dev;
400  if (stat(File2, &st) == 0)
401  return st.st_dev == dev1;
402  else
403  LOG_ERROR_STR(File2);
404  }
405  else
406  LOG_ERROR_STR(File1);
407  return true; // we only return false if both files actually exist and are in different file systems!
408 }
409 
410 int FreeDiskSpaceMB(const char *Directory, int *UsedMB)
411 {
412  if (UsedMB)
413  *UsedMB = 0;
414  int Free = 0;
415  struct statfs statFs;
416  if (statfs(Directory, &statFs) == 0) {
417  double blocksPerMeg = 1024.0 * 1024.0 / statFs.f_bsize;
418  if (UsedMB)
419  *UsedMB = int((statFs.f_blocks - statFs.f_bfree) / blocksPerMeg);
420  Free = int(statFs.f_bavail / blocksPerMeg);
421  }
422  else
423  LOG_ERROR_STR(Directory);
424  return Free;
425 }
426 
427 bool DirectoryOk(const char *DirName, bool LogErrors)
428 {
429  struct stat ds;
430  if (stat(DirName, &ds) == 0) {
431  if (S_ISDIR(ds.st_mode)) {
432  if (access(DirName, R_OK | W_OK | X_OK) == 0)
433  return true;
434  else if (LogErrors)
435  esyslog("ERROR: can't access %s", DirName);
436  }
437  else if (LogErrors)
438  esyslog("ERROR: %s is not a directory", DirName);
439  }
440  else if (LogErrors)
441  LOG_ERROR_STR(DirName);
442  return false;
443 }
444 
445 bool MakeDirs(const char *FileName, bool IsDirectory)
446 {
447  bool result = true;
448  char *s = strdup(FileName);
449  char *p = s;
450  if (*p == '/')
451  p++;
452  while ((p = strchr(p, '/')) != NULL || IsDirectory) {
453  if (p)
454  *p = 0;
455  struct stat fs;
456  if (stat(s, &fs) != 0 || !S_ISDIR(fs.st_mode)) {
457  dsyslog("creating directory %s", s);
458  if (mkdir(s, ACCESSPERMS) == -1) {
459  LOG_ERROR_STR(s);
460  result = false;
461  break;
462  }
463  }
464  if (p)
465  *p++ = '/';
466  else
467  break;
468  }
469  free(s);
470  return result;
471 }
472 
473 bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks)
474 {
475  struct stat st;
476  if (stat(FileName, &st) == 0) {
477  if (S_ISDIR(st.st_mode)) {
478  cReadDir d(FileName);
479  if (d.Ok()) {
480  struct dirent *e;
481  while ((e = d.Next()) != NULL) {
482  cString buffer = AddDirectory(FileName, e->d_name);
483  if (FollowSymlinks) {
484  struct stat st2;
485  if (lstat(buffer, &st2) == 0) {
486  if (S_ISLNK(st2.st_mode)) {
487  int size = st2.st_size + 1;
488  char *l = MALLOC(char, size);
489  int n = readlink(buffer, l, size - 1);
490  if (n < 0) {
491  if (errno != EINVAL)
492  LOG_ERROR_STR(*buffer);
493  }
494  else {
495  l[n] = 0;
496  dsyslog("removing %s", l);
497  if (remove(l) < 0)
498  LOG_ERROR_STR(l);
499  }
500  free(l);
501  }
502  }
503  else if (errno != ENOENT) {
504  LOG_ERROR_STR(FileName);
505  return false;
506  }
507  }
508  dsyslog("removing %s", *buffer);
509  if (remove(buffer) < 0)
510  LOG_ERROR_STR(*buffer);
511  }
512  }
513  else {
514  LOG_ERROR_STR(FileName);
515  return false;
516  }
517  }
518  dsyslog("removing %s", FileName);
519  if (remove(FileName) < 0) {
520  LOG_ERROR_STR(FileName);
521  return false;
522  }
523  }
524  else if (errno != ENOENT) {
525  LOG_ERROR_STR(FileName);
526  return false;
527  }
528  return true;
529 }
530 
531 bool RemoveEmptyDirectories(const char *DirName, bool RemoveThis, const char *IgnoreFiles[])
532 {
533  bool HasIgnoredFiles = false;
534  cReadDir d(DirName);
535  if (d.Ok()) {
536  bool empty = true;
537  struct dirent *e;
538  while ((e = d.Next()) != NULL) {
539  if (strcmp(e->d_name, "lost+found")) {
540  cString buffer = AddDirectory(DirName, e->d_name);
541  struct stat st;
542  if (stat(buffer, &st) == 0) {
543  if (S_ISDIR(st.st_mode)) {
544  if (!RemoveEmptyDirectories(buffer, true, IgnoreFiles))
545  empty = false;
546  }
547  else if (RemoveThis && IgnoreFiles && StrInArray(IgnoreFiles, e->d_name))
548  HasIgnoredFiles = true;
549  else
550  empty = false;
551  }
552  else {
553  LOG_ERROR_STR(*buffer);
554  empty = false;
555  }
556  }
557  }
558  if (RemoveThis && empty) {
559  if (HasIgnoredFiles) {
560  while (*IgnoreFiles) {
561  cString buffer = AddDirectory(DirName, *IgnoreFiles);
562  if (access(buffer, F_OK) == 0) {
563  dsyslog("removing %s", *buffer);
564  if (remove(buffer) < 0) {
565  LOG_ERROR_STR(*buffer);
566  return false;
567  }
568  }
569  IgnoreFiles++;
570  }
571  }
572  dsyslog("removing %s", DirName);
573  if (remove(DirName) < 0) {
574  LOG_ERROR_STR(DirName);
575  return false;
576  }
577  }
578  return empty;
579  }
580  else
581  LOG_ERROR_STR(DirName);
582  return false;
583 }
584 
585 int DirSizeMB(const char *DirName)
586 {
587  cReadDir d(DirName);
588  if (d.Ok()) {
589  int size = 0;
590  struct dirent *e;
591  while (size >= 0 && (e = d.Next()) != NULL) {
592  cString buffer = AddDirectory(DirName, e->d_name);
593  struct stat st;
594  if (stat(buffer, &st) == 0) {
595  if (S_ISDIR(st.st_mode)) {
596  int n = DirSizeMB(buffer);
597  if (n >= 0)
598  size += n;
599  else
600  size = -1;
601  }
602  else
603  size += st.st_size / MEGABYTE(1);
604  }
605  else {
606  LOG_ERROR_STR(*buffer);
607  size = -1;
608  }
609  }
610  return size;
611  }
612  else if (errno != ENOENT)
613  LOG_ERROR_STR(DirName);
614  return -1;
615 }
616 
617 char *ReadLink(const char *FileName)
618 {
619  if (!FileName)
620  return NULL;
621  char *TargetName = canonicalize_file_name(FileName);
622  if (!TargetName) {
623  if (errno == ENOENT) // file doesn't exist
624  TargetName = strdup(FileName);
625  else // some other error occurred
626  LOG_ERROR_STR(FileName);
627  }
628  return TargetName;
629 }
630 
631 bool SpinUpDisk(const char *FileName)
632 {
633  for (int n = 0; n < 10; n++) {
634  cString buf;
635  if (DirectoryOk(FileName))
636  buf = cString::sprintf("%s/vdr-%06d", *FileName ? FileName : ".", n);
637  else
638  buf = cString::sprintf("%s.vdr-%06d", FileName, n);
639  if (access(buf, F_OK) != 0) { // the file does not exist
640  timeval tp1, tp2;
641  gettimeofday(&tp1, NULL);
642  int f = open(buf, O_WRONLY | O_CREAT, DEFFILEMODE);
643  // O_SYNC doesn't work on all file systems
644  if (f >= 0) {
645  if (fdatasync(f) < 0)
646  LOG_ERROR_STR(*buf);
647  close(f);
648  remove(buf);
649  gettimeofday(&tp2, NULL);
650  double seconds = (((long long)tp2.tv_sec * 1000000 + tp2.tv_usec) - ((long long)tp1.tv_sec * 1000000 + tp1.tv_usec)) / 1000000.0;
651  if (seconds > 0.5)
652  dsyslog("SpinUpDisk took %.2f seconds", seconds);
653  return true;
654  }
655  else
656  LOG_ERROR_STR(*buf);
657  }
658  }
659  esyslog("ERROR: SpinUpDisk failed");
660  return false;
661 }
662 
663 void TouchFile(const char *FileName)
664 {
665  if (utime(FileName, NULL) == -1 && errno != ENOENT)
666  LOG_ERROR_STR(FileName);
667 }
668 
669 time_t LastModifiedTime(const char *FileName)
670 {
671  struct stat fs;
672  if (stat(FileName, &fs) == 0)
673  return fs.st_mtime;
674  return 0;
675 }
676 
677 off_t FileSize(const char *FileName)
678 {
679  struct stat fs;
680  if (stat(FileName, &fs) == 0)
681  return fs.st_size;
682  return -1;
683 }
684 
685 // --- cTimeMs ---------------------------------------------------------------
686 
688 {
689  if (Ms >= 0)
690  Set(Ms);
691  else
692  begin = 0;
693 }
694 
695 uint64_t cTimeMs::Now(void)
696 {
697 #if _POSIX_TIMERS > 0 && defined(_POSIX_MONOTONIC_CLOCK)
698 #define MIN_RESOLUTION 5 // ms
699  static bool initialized = false;
700  static bool monotonic = false;
701  struct timespec tp;
702  if (!initialized) {
703  // check if monotonic timer is available and provides enough accurate resolution:
704  if (clock_getres(CLOCK_MONOTONIC, &tp) == 0) {
705  long Resolution = tp.tv_nsec;
706  // require a minimum resolution:
707  if (tp.tv_sec == 0 && tp.tv_nsec <= MIN_RESOLUTION * 1000000) {
708  if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) {
709  dsyslog("cTimeMs: using monotonic clock (resolution is %ld ns)", Resolution);
710  monotonic = true;
711  }
712  else
713  esyslog("cTimeMs: clock_gettime(CLOCK_MONOTONIC) failed");
714  }
715  else
716  dsyslog("cTimeMs: not using monotonic clock - resolution is too bad (%ld s %ld ns)", tp.tv_sec, tp.tv_nsec);
717  }
718  else
719  esyslog("cTimeMs: clock_getres(CLOCK_MONOTONIC) failed");
720  initialized = true;
721  }
722  if (monotonic) {
723  if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
724  return (uint64_t(tp.tv_sec)) * 1000 + tp.tv_nsec / 1000000;
725  esyslog("cTimeMs: clock_gettime(CLOCK_MONOTONIC) failed");
726  monotonic = false;
727  // fall back to gettimeofday()
728  }
729 #else
730 # warning Posix monotonic clock not available
731 #endif
732  struct timeval t;
733  if (gettimeofday(&t, NULL) == 0)
734  return (uint64_t(t.tv_sec)) * 1000 + t.tv_usec / 1000;
735  return 0;
736 }
737 
738 void cTimeMs::Set(int Ms)
739 {
740  begin = Now() + Ms;
741 }
742 
743 bool cTimeMs::TimedOut(void) const
744 {
745  return Now() >= begin;
746 }
747 
748 uint64_t cTimeMs::Elapsed(void) const
749 {
750  return Now() - begin;
751 }
752 
753 // --- UTF-8 support ---------------------------------------------------------
754 
755 static uint SystemToUtf8[128] = { 0 };
756 
757 int Utf8CharLen(const char *s)
758 {
760  return 1;
761 #define MT(s, m, v) ((*(s) & (m)) == (v)) // Mask Test
762  if (MT(s, 0xE0, 0xC0) && MT(s + 1, 0xC0, 0x80))
763  return 2;
764  if (MT(s, 0xF0, 0xE0) && MT(s + 1, 0xC0, 0x80) && MT(s + 2, 0xC0, 0x80))
765  return 3;
766  if (MT(s, 0xF8, 0xF0) && MT(s + 1, 0xC0, 0x80) && MT(s + 2, 0xC0, 0x80) && MT(s + 3, 0xC0, 0x80))
767  return 4;
768  return 1;
769 }
770 
771 uint Utf8CharGet(const char *s, int Length)
772 {
774  return (uchar)*s < 128 ? *s : SystemToUtf8[(uchar)*s - 128];
775  if (!Length)
776  Length = Utf8CharLen(s);
777  switch (Length) {
778  case 2: return ((*s & 0x1F) << 6) | (*(s + 1) & 0x3F);
779  case 3: return ((*s & 0x0F) << 12) | ((*(s + 1) & 0x3F) << 6) | (*(s + 2) & 0x3F);
780  case 4: return ((*s & 0x07) << 18) | ((*(s + 1) & 0x3F) << 12) | ((*(s + 2) & 0x3F) << 6) | (*(s + 3) & 0x3F);
781  default: ;
782  }
783  return *s;
784 }
785 
786 int Utf8CharSet(uint c, char *s)
787 {
788  if (c < 0x80 || cCharSetConv::SystemCharacterTable()) {
789  if (s)
790  *s = c;
791  return 1;
792  }
793  if (c < 0x800) {
794  if (s) {
795  *s++ = ((c >> 6) & 0x1F) | 0xC0;
796  *s = (c & 0x3F) | 0x80;
797  }
798  return 2;
799  }
800  if (c < 0x10000) {
801  if (s) {
802  *s++ = ((c >> 12) & 0x0F) | 0xE0;
803  *s++ = ((c >> 6) & 0x3F) | 0x80;
804  *s = (c & 0x3F) | 0x80;
805  }
806  return 3;
807  }
808  if (c < 0x110000) {
809  if (s) {
810  *s++ = ((c >> 18) & 0x07) | 0xF0;
811  *s++ = ((c >> 12) & 0x3F) | 0x80;
812  *s++ = ((c >> 6) & 0x3F) | 0x80;
813  *s = (c & 0x3F) | 0x80;
814  }
815  return 4;
816  }
817  return 0; // can't convert to UTF-8
818 }
819 
820 int Utf8SymChars(const char *s, int Symbols)
821 {
823  return Symbols;
824  int n = 0;
825  while (*s && Symbols--) {
826  int sl = Utf8CharLen(s);
827  s += sl;
828  n += sl;
829  }
830  return n;
831 }
832 
833 int Utf8StrLen(const char *s)
834 {
836  return strlen(s);
837  int n = 0;
838  while (*s) {
839  s += Utf8CharLen(s);
840  n++;
841  }
842  return n;
843 }
844 
845 char *Utf8Strn0Cpy(char *Dest, const char *Src, int n)
846 {
848  return strn0cpy(Dest, Src, n);
849  char *d = Dest;
850  while (*Src) {
851  int sl = Utf8CharLen(Src);
852  n -= sl;
853  if (n > 0) {
854  while (sl--)
855  *d++ = *Src++;
856  }
857  else
858  break;
859  }
860  *d = 0;
861  return Dest;
862 }
863 
864 int Utf8ToArray(const char *s, uint *a, int Size)
865 {
866  int n = 0;
867  while (*s && --Size > 0) {
869  *a++ = (uchar)(*s++);
870  else {
871  int sl = Utf8CharLen(s);
872  *a++ = Utf8CharGet(s, sl);
873  s += sl;
874  }
875  n++;
876  }
877  if (Size > 0)
878  *a = 0;
879  return n;
880 }
881 
882 int Utf8FromArray(const uint *a, char *s, int Size, int Max)
883 {
884  int NumChars = 0;
885  int NumSyms = 0;
886  while (*a && NumChars < Size) {
887  if (Max >= 0 && NumSyms++ >= Max)
888  break;
890  *s++ = *a++;
891  NumChars++;
892  }
893  else {
894  int sl = Utf8CharSet(*a);
895  if (NumChars + sl <= Size) {
896  Utf8CharSet(*a, s);
897  a++;
898  s += sl;
899  NumChars += sl;
900  }
901  else
902  break;
903  }
904  }
905  if (NumChars < Size)
906  *s = 0;
907  return NumChars;
908 }
909 
910 // --- cCharSetConv ----------------------------------------------------------
911 
913 
914 cCharSetConv::cCharSetConv(const char *FromCode, const char *ToCode)
915 {
916  if (!FromCode)
917  FromCode = systemCharacterTable ? systemCharacterTable : "UTF-8";
918  if (!ToCode)
919  ToCode = "UTF-8";
920  cd = iconv_open(ToCode, FromCode);
921  result = NULL;
922  length = 0;
923 }
924 
926 {
927  free(result);
928  if (cd != (iconv_t)-1)
929  iconv_close(cd);
930 }
931 
932 void cCharSetConv::SetSystemCharacterTable(const char *CharacterTable)
933 {
934  free(systemCharacterTable);
935  systemCharacterTable = NULL;
936  if (!strcasestr(CharacterTable, "UTF-8")) {
937  // Set up a map for the character values 128...255:
938  char buf[129];
939  for (int i = 0; i < 128; i++)
940  buf[i] = i + 128;
941  buf[128] = 0;
942  cCharSetConv csc(CharacterTable);
943  const char *s = csc.Convert(buf);
944  int i = 0;
945  while (*s) {
946  int sl = Utf8CharLen(s);
947  SystemToUtf8[i] = Utf8CharGet(s, sl);
948  s += sl;
949  i++;
950  }
951  systemCharacterTable = strdup(CharacterTable);
952  }
953 }
954 
955 const char *cCharSetConv::Convert(const char *From, char *To, size_t ToLength)
956 {
957  if (cd != (iconv_t)-1 && From && *From) {
958  char *FromPtr = (char *)From;
959  size_t FromLength = strlen(From);
960  char *ToPtr = To;
961  if (!ToPtr) {
962  int NewLength = max(length, FromLength * 2); // some reserve to avoid later reallocations
963  if (char *NewBuffer = (char *)realloc(result, NewLength)) {
964  length = NewLength;
965  result = NewBuffer;
966  }
967  else {
968  esyslog("ERROR: out of memory");
969  return From;
970  }
971  ToPtr = result;
972  ToLength = length;
973  }
974  else if (!ToLength)
975  return From; // can't convert into a zero sized buffer
976  ToLength--; // save space for terminating 0
977  char *Converted = ToPtr;
978  while (FromLength > 0) {
979  if (iconv(cd, &FromPtr, &FromLength, &ToPtr, &ToLength) == size_t(-1)) {
980  if (errno == E2BIG || errno == EILSEQ && ToLength < 1) {
981  if (To)
982  break; // caller provided a fixed size buffer, but it was too small
983  // The result buffer is too small, so increase it:
984  size_t d = ToPtr - result;
985  size_t r = length / 2;
986  int NewLength = length + r;
987  if (char *NewBuffer = (char *)realloc(result, NewLength)) {
988  length = NewLength;
989  Converted = result = NewBuffer;
990  }
991  else {
992  esyslog("ERROR: out of memory");
993  return From;
994  }
995  ToLength += r;
996  ToPtr = result + d;
997  }
998  if (errno == EILSEQ) {
999  // A character can't be converted, so mark it with '?' and proceed:
1000  FromPtr++;
1001  FromLength--;
1002  *ToPtr++ = '?';
1003  ToLength--;
1004  }
1005  else if (errno != E2BIG)
1006  return From; // unknown error, return original string
1007  }
1008  }
1009  *ToPtr = 0;
1010  return Converted;
1011  }
1012  return From;
1013 }
1014 
1015 // --- cString ---------------------------------------------------------------
1016 
1017 cString::cString(const char *S, bool TakePointer)
1018 {
1019  s = TakePointer ? (char *)S : S ? strdup(S) : NULL;
1020 }
1021 
1022 cString::cString(const char *S, const char *To)
1023 {
1024  if (!S)
1025  s = NULL;
1026  else if (!To)
1027  s = strdup(S);
1028  else {
1029  int l = To - S;
1030  s = MALLOC(char, l + 1);
1031  strncpy(s, S, l);
1032  s[l] = 0;
1033  }
1034 }
1035 
1037 {
1038  s = String.s ? strdup(String.s) : NULL;
1039 }
1040 
1042 {
1043  free(s);
1044 }
1045 
1047 {
1048  if (this == &String)
1049  return *this;
1050  free(s);
1051  s = String.s ? strdup(String.s) : NULL;
1052  return *this;
1053 }
1054 
1055 cString &cString::operator=(const char *String)
1056 {
1057  if (s == String)
1058  return *this;
1059  free(s);
1060  s = String ? strdup(String) : NULL;
1061  return *this;
1062 }
1063 
1065 {
1066  int l = strlen(s);
1067  if (Index < 0)
1068  Index = l + Index;
1069  if (Index >= 0 && Index < l)
1070  s[Index] = 0;
1071  return *this;
1072 }
1073 
1075 {
1076  compactchars(s, c);
1077  return *this;
1078 }
1079 
1080 cString cString::sprintf(const char *fmt, ...)
1081 {
1082  va_list ap;
1083  va_start(ap, fmt);
1084  char *buffer;
1085  if (!fmt || vasprintf(&buffer, fmt, ap) < 0) {
1086  esyslog("error in vasprintf('%s', ...)", fmt);
1087  buffer = strdup("???");
1088  }
1089  va_end(ap);
1090  return cString(buffer, true);
1091 }
1092 
1093 cString cString::vsprintf(const char *fmt, va_list &ap)
1094 {
1095  char *buffer;
1096  if (!fmt || vasprintf(&buffer, fmt, ap) < 0) {
1097  esyslog("error in vasprintf('%s', ...)", fmt);
1098  buffer = strdup("???");
1099  }
1100  return cString(buffer, true);
1101 }
1102 
1103 cString WeekDayName(int WeekDay)
1104 {
1105  char buffer[16];
1106  WeekDay = WeekDay == 0 ? 6 : WeekDay - 1; // we start with Monday==0!
1107  if (0 <= WeekDay && WeekDay <= 6) {
1108  // TRANSLATORS: abbreviated weekdays, beginning with monday (must all be 3 letters!)
1109  const char *day = tr("MonTueWedThuFriSatSun");
1110  day += Utf8SymChars(day, WeekDay * 3);
1111  strn0cpy(buffer, day, min(Utf8SymChars(day, 3) + 1, int(sizeof(buffer))));
1112  return buffer;
1113  }
1114  else
1115  return "???";
1116 }
1117 
1119 {
1120  struct tm tm_r;
1121  return WeekDayName(localtime_r(&t, &tm_r)->tm_wday);
1122 }
1123 
1125 {
1126  WeekDay = WeekDay == 0 ? 6 : WeekDay - 1; // we start with Monday==0!
1127  switch (WeekDay) {
1128  case 0: return tr("Monday");
1129  case 1: return tr("Tuesday");
1130  case 2: return tr("Wednesday");
1131  case 3: return tr("Thursday");
1132  case 4: return tr("Friday");
1133  case 5: return tr("Saturday");
1134  case 6: return tr("Sunday");
1135  default: return "???";
1136  }
1137 }
1138 
1140 {
1141  struct tm tm_r;
1142  return WeekDayNameFull(localtime_r(&t, &tm_r)->tm_wday);
1143 }
1144 
1146 {
1147  char buffer[32];
1148  if (t == 0)
1149  time(&t);
1150  struct tm tm_r;
1151  tm *tm = localtime_r(&t, &tm_r);
1152  snprintf(buffer, sizeof(buffer), "%s %02d.%02d. %02d:%02d", *WeekDayName(tm->tm_wday), tm->tm_mday, tm->tm_mon + 1, tm->tm_hour, tm->tm_min);
1153  return buffer;
1154 }
1155 
1157 {
1158  char buffer[32];
1159  if (ctime_r(&t, buffer)) {
1160  buffer[strlen(buffer) - 1] = 0; // strip trailing newline
1161  return buffer;
1162  }
1163  return "???";
1164 }
1165 
1167 {
1168  char buf[32];
1169  struct tm tm_r;
1170  tm *tm = localtime_r(&t, &tm_r);
1171  char *p = stpcpy(buf, WeekDayName(tm->tm_wday));
1172  *p++ = ' ';
1173  strftime(p, sizeof(buf) - (p - buf), "%d.%m.%Y", tm);
1174  return buf;
1175 }
1176 
1178 {
1179  char buf[32];
1180  struct tm tm_r;
1181  tm *tm = localtime_r(&t, &tm_r);
1182  strftime(buf, sizeof(buf), "%d.%m.%y", tm);
1183  return buf;
1184 }
1185 
1187 {
1188  char buf[25];
1189  struct tm tm_r;
1190  strftime(buf, sizeof(buf), "%R", localtime_r(&t, &tm_r));
1191  return buf;
1192 }
1193 
1194 // --- RgbToJpeg -------------------------------------------------------------
1195 
1196 #define JPEGCOMPRESSMEM 500000
1197 
1198 struct tJpegCompressData {
1199  int size;
1200  uchar *mem;
1201  };
1202 
1203 static void JpegCompressInitDestination(j_compress_ptr cinfo)
1204 {
1205  tJpegCompressData *jcd = (tJpegCompressData *)cinfo->client_data;
1206  if (jcd) {
1207  cinfo->dest->free_in_buffer = jcd->size = JPEGCOMPRESSMEM;
1208  cinfo->dest->next_output_byte = jcd->mem = MALLOC(uchar, jcd->size);
1209  }
1210 }
1211 
1212 static boolean JpegCompressEmptyOutputBuffer(j_compress_ptr cinfo)
1213 {
1214  tJpegCompressData *jcd = (tJpegCompressData *)cinfo->client_data;
1215  if (jcd) {
1216  int Used = jcd->size;
1217  int NewSize = jcd->size + JPEGCOMPRESSMEM;
1218  if (uchar *NewBuffer = (uchar *)realloc(jcd->mem, NewSize)) {
1219  jcd->size = NewSize;
1220  jcd->mem = NewBuffer;
1221  }
1222  else {
1223  esyslog("ERROR: out of memory");
1224  return false;
1225  }
1226  if (jcd->mem) {
1227  cinfo->dest->next_output_byte = jcd->mem + Used;
1228  cinfo->dest->free_in_buffer = jcd->size - Used;
1229  return true;
1230  }
1231  }
1232  return false;
1233 }
1234 
1235 static void JpegCompressTermDestination(j_compress_ptr cinfo)
1236 {
1237  tJpegCompressData *jcd = (tJpegCompressData *)cinfo->client_data;
1238  if (jcd) {
1239  int Used = cinfo->dest->next_output_byte - jcd->mem;
1240  if (Used < jcd->size) {
1241  if (uchar *NewBuffer = (uchar *)realloc(jcd->mem, Used)) {
1242  jcd->size = Used;
1243  jcd->mem = NewBuffer;
1244  }
1245  else
1246  esyslog("ERROR: out of memory");
1247  }
1248  }
1249 }
1250 
1251 uchar *RgbToJpeg(uchar *Mem, int Width, int Height, int &Size, int Quality)
1252 {
1253  if (Quality < 0)
1254  Quality = 0;
1255  else if (Quality > 100)
1256  Quality = 100;
1257 
1258  jpeg_destination_mgr jdm;
1259 
1260  jdm.init_destination = JpegCompressInitDestination;
1261  jdm.empty_output_buffer = JpegCompressEmptyOutputBuffer;
1262  jdm.term_destination = JpegCompressTermDestination;
1263 
1264  struct jpeg_compress_struct cinfo;
1265  struct jpeg_error_mgr jerr;
1266  cinfo.err = jpeg_std_error(&jerr);
1267  jpeg_create_compress(&cinfo);
1268  cinfo.dest = &jdm;
1269  tJpegCompressData jcd;
1270  cinfo.client_data = &jcd;
1271  cinfo.image_width = Width;
1272  cinfo.image_height = Height;
1273  cinfo.input_components = 3;
1274  cinfo.in_color_space = JCS_RGB;
1275 
1276  jpeg_set_defaults(&cinfo);
1277  jpeg_set_quality(&cinfo, Quality, true);
1278  jpeg_start_compress(&cinfo, true);
1279 
1280  int rs = Width * 3;
1281  JSAMPROW rp[Height];
1282  for (int k = 0; k < Height; k++)
1283  rp[k] = &Mem[rs * k];
1284  jpeg_write_scanlines(&cinfo, rp, Height);
1285  jpeg_finish_compress(&cinfo);
1286  jpeg_destroy_compress(&cinfo);
1287 
1288  Size = jcd.size;
1289  return jcd.mem;
1290 }
1291 
1292 // --- cBase64Encoder --------------------------------------------------------
1293 
1294 const char *cBase64Encoder::b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1295 
1296 cBase64Encoder::cBase64Encoder(const uchar *Data, int Length, int MaxResult)
1297 {
1298  data = Data;
1299  length = Length;
1300  maxResult = MaxResult;
1301  i = 0;
1302  result = MALLOC(char, maxResult + 1);
1303 }
1304 
1306 {
1307  free(result);
1308 }
1309 
1310 const char *cBase64Encoder::NextLine(void)
1311 {
1312  int r = 0;
1313  while (i < length && r < maxResult - 3) {
1314  result[r++] = b64[(data[i] >> 2) & 0x3F];
1315  uchar c = (data[i] << 4) & 0x3F;
1316  if (++i < length)
1317  c |= (data[i] >> 4) & 0x0F;
1318  result[r++] = b64[c];
1319  if (i < length) {
1320  c = (data[i] << 2) & 0x3F;
1321  if (++i < length)
1322  c |= (data[i] >> 6) & 0x03;
1323  result[r++] = b64[c];
1324  }
1325  else {
1326  i++;
1327  result[r++] = '=';
1328  }
1329  if (i < length) {
1330  c = data[i] & 0x3F;
1331  result[r++] = b64[c];
1332  }
1333  else
1334  result[r++] = '=';
1335  i++;
1336  }
1337  if (r > 0) {
1338  result[r] = 0;
1339  return result;
1340  }
1341  return NULL;
1342 }
1343 
1344 // --- cBitStream ------------------------------------------------------------
1345 
1347 {
1348  if (index >= length)
1349  return 1;
1350  int r = (data[index >> 3] >> (7 - (index & 7))) & 1;
1351  ++index;
1352  return r;
1353 }
1354 
1355 uint32_t cBitStream::GetBits(int n)
1356 {
1357  uint32_t r = 0;
1358  while (n--)
1359  r |= GetBit() << n;
1360  return r;
1361 }
1362 
1364 {
1365  int n = index % 8;
1366  if (n > 0)
1367  SkipBits(8 - n);
1368 }
1369 
1371 {
1372  int n = index % 16;
1373  if (n > 0)
1374  SkipBits(16 - n);
1375 }
1376 
1377 bool cBitStream::SetLength(int Length)
1378 {
1379  if (Length > length)
1380  return false;
1381  length = Length;
1382  return true;
1383 }
1384 
1385 // --- cReadLine -------------------------------------------------------------
1386 
1388 {
1389  size = 0;
1390  buffer = NULL;
1391 }
1392 
1394 {
1395  free(buffer);
1396 }
1397 
1398 char *cReadLine::Read(FILE *f)
1399 {
1400  int n = getline(&buffer, &size, f);
1401  if (n > 0) {
1402  n--;
1403  if (buffer[n] == '\n') {
1404  buffer[n] = 0;
1405  if (n > 0) {
1406  n--;
1407  if (buffer[n] == '\r')
1408  buffer[n] = 0;
1409  }
1410  }
1411  return buffer;
1412  }
1413  return NULL;
1414 }
1415 
1416 // --- cPoller ---------------------------------------------------------------
1417 
1418 cPoller::cPoller(int FileHandle, bool Out)
1419 {
1420  numFileHandles = 0;
1421  Add(FileHandle, Out);
1422 }
1423 
1424 bool cPoller::Add(int FileHandle, bool Out)
1425 {
1426  if (FileHandle >= 0) {
1427  for (int i = 0; i < numFileHandles; i++) {
1428  if (pfd[i].fd == FileHandle && pfd[i].events == (Out ? POLLOUT : POLLIN))
1429  return true;
1430  }
1431  if (numFileHandles < MaxPollFiles) {
1432  pfd[numFileHandles].fd = FileHandle;
1433  pfd[numFileHandles].events = Out ? POLLOUT : POLLIN;
1434  pfd[numFileHandles].revents = 0;
1435  numFileHandles++;
1436  return true;
1437  }
1438  esyslog("ERROR: too many file handles in cPoller");
1439  }
1440  return false;
1441 }
1442 
1443 bool cPoller::Poll(int TimeoutMs)
1444 {
1445  if (numFileHandles) {
1446  if (poll(pfd, numFileHandles, TimeoutMs) != 0)
1447  return true; // returns true even in case of an error, to let the caller
1448  // access the file and thus see the error code
1449  }
1450  return false;
1451 }
1452 
1453 // --- cReadDir --------------------------------------------------------------
1454 
1455 cReadDir::cReadDir(const char *Directory)
1456 {
1457  directory = opendir(Directory);
1458 }
1459 
1461 {
1462  if (directory)
1463  closedir(directory);
1464 }
1465 
1466 struct dirent *cReadDir::Next(void)
1467 {
1468  if (directory) {
1469  while (readdir_r(directory, &u.d, &result) == 0 && result) {
1470  if (strcmp(result->d_name, ".") && strcmp(result->d_name, ".."))
1471  return result;
1472  }
1473  }
1474  return NULL;
1475 }
1476 
1477 // --- cStringList -----------------------------------------------------------
1478 
1480 {
1481  Clear();
1482 }
1483 
1484 int cStringList::Find(const char *s) const
1485 {
1486  for (int i = 0; i < Size(); i++) {
1487  if (!strcmp(s, At(i)))
1488  return i;
1489  }
1490  return -1;
1491 }
1492 
1494 {
1495  for (int i = 0; i < Size(); i++)
1496  free(At(i));
1498 }
1499 
1500 // --- cFileNameList ---------------------------------------------------------
1501 
1502 // TODO better GetFileNames(const char *Directory, cStringList *List)?
1503 cFileNameList::cFileNameList(const char *Directory, bool DirsOnly)
1504 {
1505  Load(Directory, DirsOnly);
1506 }
1507 
1508 bool cFileNameList::Load(const char *Directory, bool DirsOnly)
1509 {
1510  Clear();
1511  if (Directory) {
1512  cReadDir d(Directory);
1513  struct dirent *e;
1514  if (d.Ok()) {
1515  while ((e = d.Next()) != NULL) {
1516  if (DirsOnly) {
1517  struct stat ds;
1518  if (stat(AddDirectory(Directory, e->d_name), &ds) == 0) {
1519  if (!S_ISDIR(ds.st_mode))
1520  continue;
1521  }
1522  }
1523  Append(strdup(e->d_name));
1524  }
1525  Sort();
1526  return true;
1527  }
1528  else
1529  LOG_ERROR_STR(Directory);
1530  }
1531  return false;
1532 }
1533 
1534 // --- cFile -----------------------------------------------------------------
1535 
1536 bool cFile::files[FD_SETSIZE] = { false };
1537 int cFile::maxFiles = 0;
1538 
1540 {
1541  f = -1;
1542 }
1543 
1545 {
1546  Close();
1547 }
1548 
1549 bool cFile::Open(const char *FileName, int Flags, mode_t Mode)
1550 {
1551  if (!IsOpen())
1552  return Open(open(FileName, Flags, Mode));
1553  esyslog("ERROR: attempt to re-open %s", FileName);
1554  return false;
1555 }
1556 
1557 bool cFile::Open(int FileDes)
1558 {
1559  if (FileDes >= 0) {
1560  if (!IsOpen()) {
1561  f = FileDes;
1562  if (f >= 0) {
1563  if (f < FD_SETSIZE) {
1564  if (f >= maxFiles)
1565  maxFiles = f + 1;
1566  if (!files[f])
1567  files[f] = true;
1568  else
1569  esyslog("ERROR: file descriptor %d already in files[]", f);
1570  return true;
1571  }
1572  else
1573  esyslog("ERROR: file descriptor %d is larger than FD_SETSIZE (%d)", f, FD_SETSIZE);
1574  }
1575  }
1576  else
1577  esyslog("ERROR: attempt to re-open file descriptor %d", FileDes);
1578  }
1579  return false;
1580 }
1581 
1582 void cFile::Close(void)
1583 {
1584  if (f >= 0) {
1585  close(f);
1586  files[f] = false;
1587  f = -1;
1588  }
1589 }
1590 
1591 bool cFile::Ready(bool Wait)
1592 {
1593  return f >= 0 && AnyFileReady(f, Wait ? 1000 : 0);
1594 }
1595 
1596 bool cFile::AnyFileReady(int FileDes, int TimeoutMs)
1597 {
1598  fd_set set;
1599  FD_ZERO(&set);
1600  for (int i = 0; i < maxFiles; i++) {
1601  if (files[i])
1602  FD_SET(i, &set);
1603  }
1604  if (0 <= FileDes && FileDes < FD_SETSIZE && !files[FileDes])
1605  FD_SET(FileDes, &set); // in case we come in with an arbitrary descriptor
1606  if (TimeoutMs == 0)
1607  TimeoutMs = 10; // load gets too heavy with 0
1608  struct timeval timeout;
1609  timeout.tv_sec = TimeoutMs / 1000;
1610  timeout.tv_usec = (TimeoutMs % 1000) * 1000;
1611  return select(FD_SETSIZE, &set, NULL, NULL, &timeout) > 0 && (FileDes < 0 || FD_ISSET(FileDes, &set));
1612 }
1613 
1614 bool cFile::FileReady(int FileDes, int TimeoutMs)
1615 {
1616  fd_set set;
1617  struct timeval timeout;
1618  FD_ZERO(&set);
1619  FD_SET(FileDes, &set);
1620  if (TimeoutMs >= 0) {
1621  if (TimeoutMs < 100)
1622  TimeoutMs = 100;
1623  timeout.tv_sec = TimeoutMs / 1000;
1624  timeout.tv_usec = (TimeoutMs % 1000) * 1000;
1625  }
1626  return select(FD_SETSIZE, &set, NULL, NULL, (TimeoutMs >= 0) ? &timeout : NULL) > 0 && FD_ISSET(FileDes, &set);
1627 }
1628 
1629 bool cFile::FileReadyForWriting(int FileDes, int TimeoutMs)
1630 {
1631  fd_set set;
1632  struct timeval timeout;
1633  FD_ZERO(&set);
1634  FD_SET(FileDes, &set);
1635  if (TimeoutMs < 100)
1636  TimeoutMs = 100;
1637  timeout.tv_sec = 0;
1638  timeout.tv_usec = TimeoutMs * 1000;
1639  return select(FD_SETSIZE, NULL, &set, NULL, &timeout) > 0 && FD_ISSET(FileDes, &set);
1640 }
1641 
1642 // --- cSafeFile -------------------------------------------------------------
1643 
1644 cSafeFile::cSafeFile(const char *FileName)
1645 {
1646  f = NULL;
1647  fileName = ReadLink(FileName);
1648  tempName = fileName ? MALLOC(char, strlen(fileName) + 5) : NULL;
1649  if (tempName)
1650  strcat(strcpy(tempName, fileName), ".$$$");
1651 }
1652 
1654 {
1655  if (f)
1656  fclose(f);
1657  unlink(tempName);
1658  free(fileName);
1659  free(tempName);
1660 }
1661 
1663 {
1664  if (!f && fileName && tempName) {
1665  f = fopen(tempName, "w");
1666  if (!f)
1667  LOG_ERROR_STR(tempName);
1668  }
1669  return f != NULL;
1670 }
1671 
1673 {
1674  bool result = true;
1675  if (f) {
1676  if (ferror(f) != 0) {
1677  LOG_ERROR_STR(tempName);
1678  result = false;
1679  }
1680  fflush(f);
1681  fsync(fileno(f));
1682  if (fclose(f) < 0) {
1683  LOG_ERROR_STR(tempName);
1684  result = false;
1685  }
1686  f = NULL;
1687  if (result && rename(tempName, fileName) < 0) {
1688  LOG_ERROR_STR(fileName);
1689  result = false;
1690  }
1691  }
1692  else
1693  result = false;
1694  return result;
1695 }
1696 
1697 // --- cUnbufferedFile -------------------------------------------------------
1698 
1699 #define USE_FADVISE
1700 
1701 #define WRITE_BUFFER KILOBYTE(800)
1702 
1704 {
1705  fd = -1;
1706 }
1707 
1709 {
1710  Close();
1711 }
1712 
1713 int cUnbufferedFile::Open(const char *FileName, int Flags, mode_t Mode)
1714 {
1715  Close();
1716  fd = open(FileName, Flags, Mode);
1717  curpos = 0;
1718 #ifdef USE_FADVISE
1719  begin = lastpos = ahead = 0;
1720  cachedstart = 0;
1721  cachedend = 0;
1722  readahead = KILOBYTE(128);
1723  written = 0;
1724  totwritten = 0;
1725  if (fd >= 0)
1726  posix_fadvise(fd, 0, 0, POSIX_FADV_RANDOM); // we could use POSIX_FADV_SEQUENTIAL, but we do our own readahead, disabling the kernel one.
1727 #endif
1728  return fd;
1729 }
1730 
1732 {
1733  if (fd >= 0) {
1734 #ifdef USE_FADVISE
1735  if (totwritten) // if we wrote anything make sure the data has hit the disk before
1736  fdatasync(fd); // calling fadvise, as this is our last chance to un-cache it.
1737  posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED);
1738 #endif
1739  int OldFd = fd;
1740  fd = -1;
1741  return close(OldFd);
1742  }
1743  errno = EBADF;
1744  return -1;
1745 }
1746 
1747 // When replaying and going e.g. FF->PLAY the position jumps back 2..8M
1748 // hence we do not want to drop recently accessed data at once.
1749 // We try to handle the common cases such as PLAY->FF->PLAY, small
1750 // jumps, moving editing marks etc.
1751 
1752 #define FADVGRAN KILOBYTE(4) // AKA fadvise-chunk-size; PAGE_SIZE or getpagesize(2) would also work.
1753 #define READCHUNK MEGABYTE(8)
1754 
1756 {
1757  readahead = ra;
1758 }
1759 
1760 int cUnbufferedFile::FadviseDrop(off_t Offset, off_t Len)
1761 {
1762  // rounding up the window to make sure that not PAGE_SIZE-aligned data gets freed.
1763  return posix_fadvise(fd, Offset - (FADVGRAN - 1), Len + (FADVGRAN - 1) * 2, POSIX_FADV_DONTNEED);
1764 }
1765 
1766 off_t cUnbufferedFile::Seek(off_t Offset, int Whence)
1767 {
1768  if (Whence == SEEK_SET && Offset == curpos)
1769  return curpos;
1770  curpos = lseek(fd, Offset, Whence);
1771  return curpos;
1772 }
1773 
1774 ssize_t cUnbufferedFile::Read(void *Data, size_t Size)
1775 {
1776  if (fd >= 0) {
1777 #ifdef USE_FADVISE
1778  off_t jumped = curpos-lastpos; // nonzero means we're not at the last offset
1779  if ((cachedstart < cachedend) && (curpos < cachedstart || curpos > cachedend)) {
1780  // current position is outside the cached window -- invalidate it.
1781  FadviseDrop(cachedstart, cachedend-cachedstart);
1782  cachedstart = curpos;
1783  cachedend = curpos;
1784  }
1785  cachedstart = min(cachedstart, curpos);
1786 #endif
1787  ssize_t bytesRead = safe_read(fd, Data, Size);
1788  if (bytesRead > 0) {
1789  curpos += bytesRead;
1790 #ifdef USE_FADVISE
1791  cachedend = max(cachedend, curpos);
1792 
1793  // Read ahead:
1794  // no jump? (allow small forward jump still inside readahead window).
1795  if (jumped >= 0 && jumped <= (off_t)readahead) {
1796  // Trigger the readahead IO, but only if we've used at least
1797  // 1/2 of the previously requested area. This avoids calling
1798  // fadvise() after every read() call.
1799  if (ahead - curpos < (off_t)(readahead / 2)) {
1800  posix_fadvise(fd, curpos, readahead, POSIX_FADV_WILLNEED);
1801  ahead = curpos + readahead;
1802  cachedend = max(cachedend, ahead);
1803  }
1804  if (readahead < Size * 32) { // automagically tune readahead size.
1805  readahead = Size * 32;
1806  }
1807  }
1808  else
1809  ahead = curpos; // jumped -> we really don't want any readahead, otherwise e.g. fast-rewind gets in trouble.
1810 #endif
1811  }
1812 #ifdef USE_FADVISE
1813  if (cachedstart < cachedend) {
1814  if (curpos - cachedstart > READCHUNK * 2) {
1815  // current position has moved forward enough, shrink tail window.
1816  FadviseDrop(cachedstart, curpos - READCHUNK - cachedstart);
1817  cachedstart = curpos - READCHUNK;
1818  }
1819  else if (cachedend > ahead && cachedend - curpos > READCHUNK * 2) {
1820  // current position has moved back enough, shrink head window.
1821  FadviseDrop(curpos + READCHUNK, cachedend - (curpos + READCHUNK));
1822  cachedend = curpos + READCHUNK;
1823  }
1824  }
1825  lastpos = curpos;
1826 #endif
1827  return bytesRead;
1828  }
1829  return -1;
1830 }
1831 
1832 ssize_t cUnbufferedFile::Write(const void *Data, size_t Size)
1833 {
1834  if (fd >=0) {
1835  ssize_t bytesWritten = safe_write(fd, Data, Size);
1836 #ifdef USE_FADVISE
1837  if (bytesWritten > 0) {
1838  begin = min(begin, curpos);
1839  curpos += bytesWritten;
1840  written += bytesWritten;
1841  lastpos = max(lastpos, curpos);
1842  if (written > WRITE_BUFFER) {
1843  if (lastpos > begin) {
1844  // Now do three things:
1845  // 1) Start writeback of begin..lastpos range
1846  // 2) Drop the already written range (by the previous fadvise call)
1847  // 3) Handle nonpagealigned data.
1848  // This is why we double the WRITE_BUFFER; the first time around the
1849  // last (partial) page might be skipped, writeback will start only after
1850  // second call; the third call will still include this page and finally
1851  // drop it from cache.
1852  off_t headdrop = min(begin, off_t(WRITE_BUFFER * 2));
1853  posix_fadvise(fd, begin - headdrop, lastpos - begin + headdrop, POSIX_FADV_DONTNEED);
1854  }
1855  begin = lastpos = curpos;
1856  totwritten += written;
1857  written = 0;
1858  // The above fadvise() works when writing slowly (recording), but could
1859  // leave cached data around when writing at a high rate, e.g. when cutting,
1860  // because by the time we try to flush the cached pages (above) the data
1861  // can still be dirty - we are faster than the disk I/O.
1862  // So we do another round of flushing, just like above, but at larger
1863  // intervals -- this should catch any pages that couldn't be released
1864  // earlier.
1865  if (totwritten > MEGABYTE(32)) {
1866  // It seems in some setups, fadvise() does not trigger any I/O and
1867  // a fdatasync() call would be required do all the work (reiserfs with some
1868  // kind of write gathering enabled), but the syncs cause (io) load..
1869  // Uncomment the next line if you think you need them.
1870  //fdatasync(fd);
1871  off_t headdrop = min(off_t(curpos - totwritten), off_t(totwritten * 2));
1872  posix_fadvise(fd, curpos - totwritten - headdrop, totwritten + headdrop, POSIX_FADV_DONTNEED);
1873  totwritten = 0;
1874  }
1875  }
1876  }
1877 #endif
1878  return bytesWritten;
1879  }
1880  return -1;
1881 }
1882 
1883 cUnbufferedFile *cUnbufferedFile::Create(const char *FileName, int Flags, mode_t Mode)
1884 {
1885  cUnbufferedFile *File = new cUnbufferedFile;
1886  if (File->Open(FileName, Flags, Mode) < 0) {
1887  delete File;
1888  File = NULL;
1889  }
1890  return File;
1891 }
1892 
1893 // --- cLockFile -------------------------------------------------------------
1894 
1895 #define LOCKFILENAME ".lock-vdr"
1896 #define LOCKFILESTALETIME 600 // seconds before considering a lock file "stale"
1897 
1898 cLockFile::cLockFile(const char *Directory)
1899 {
1900  fileName = NULL;
1901  f = -1;
1902  if (DirectoryOk(Directory))
1903  fileName = strdup(AddDirectory(Directory, LOCKFILENAME));
1904 }
1905 
1907 {
1908  Unlock();
1909  free(fileName);
1910 }
1911 
1912 bool cLockFile::Lock(int WaitSeconds)
1913 {
1914  if (f < 0 && fileName) {
1915  time_t Timeout = time(NULL) + WaitSeconds;
1916  do {
1917  f = open(fileName, O_WRONLY | O_CREAT | O_EXCL, DEFFILEMODE);
1918  if (f < 0) {
1919  if (errno == EEXIST) {
1920  struct stat fs;
1921  if (stat(fileName, &fs) == 0) {
1922  if (abs(time(NULL) - fs.st_mtime) > LOCKFILESTALETIME) {
1923  esyslog("ERROR: removing stale lock file '%s'", fileName);
1924  if (remove(fileName) < 0) {
1925  LOG_ERROR_STR(fileName);
1926  break;
1927  }
1928  continue;
1929  }
1930  }
1931  else if (errno != ENOENT) {
1932  LOG_ERROR_STR(fileName);
1933  break;
1934  }
1935  }
1936  else {
1937  LOG_ERROR_STR(fileName);
1938  break;
1939  }
1940  if (WaitSeconds)
1941  cCondWait::SleepMs(1000);
1942  }
1943  } while (f < 0 && time(NULL) < Timeout);
1944  }
1945  return f >= 0;
1946 }
1947 
1949 {
1950  if (f >= 0) {
1951  close(f);
1952  remove(fileName);
1953  f = -1;
1954  }
1955 }
1956 
1957 // --- cListObject -----------------------------------------------------------
1958 
1960 {
1961  prev = next = NULL;
1962 }
1963 
1965 {
1966 }
1967 
1969 {
1970  next = Object;
1971  Object->prev = this;
1972 }
1973 
1975 {
1976  prev = Object;
1977  Object->next = this;
1978 }
1979 
1981 {
1982  if (next)
1983  next->prev = prev;
1984  if (prev)
1985  prev->next = next;
1986  next = prev = NULL;
1987 }
1988 
1989 int cListObject::Index(void) const
1990 {
1991  cListObject *p = prev;
1992  int i = 0;
1993 
1994  while (p) {
1995  i++;
1996  p = p->prev;
1997  }
1998  return i;
1999 }
2000 
2001 // --- cListBase -------------------------------------------------------------
2002 
2004 {
2005  objects = lastObject = NULL;
2006  count = 0;
2007 }
2008 
2010 {
2011  Clear();
2012 }
2013 
2015 {
2016  if (After && After != lastObject) {
2017  After->Next()->Insert(Object);
2018  After->Append(Object);
2019  }
2020  else {
2021  if (lastObject)
2022  lastObject->Append(Object);
2023  else
2024  objects = Object;
2025  lastObject = Object;
2026  }
2027  count++;
2028 }
2029 
2031 {
2032  if (Before && Before != objects) {
2033  Before->Prev()->Append(Object);
2034  Before->Insert(Object);
2035  }
2036  else {
2037  if (objects)
2038  objects->Insert(Object);
2039  else
2040  lastObject = Object;
2041  objects = Object;
2042  }
2043  count++;
2044 }
2045 
2046 void cListBase::Del(cListObject *Object, bool DeleteObject)
2047 {
2048  if (Object == objects)
2049  objects = Object->Next();
2050  if (Object == lastObject)
2051  lastObject = Object->Prev();
2052  Object->Unlink();
2053  if (DeleteObject)
2054  delete Object;
2055  count--;
2056 }
2057 
2058 void cListBase::Move(int From, int To)
2059 {
2060  Move(Get(From), Get(To));
2061 }
2062 
2064 {
2065  if (From && To && From != To) {
2066  if (From->Index() < To->Index())
2067  To = To->Next();
2068  if (From == objects)
2069  objects = From->Next();
2070  if (From == lastObject)
2071  lastObject = From->Prev();
2072  From->Unlink();
2073  if (To) {
2074  if (To->Prev())
2075  To->Prev()->Append(From);
2076  From->Append(To);
2077  }
2078  else {
2079  lastObject->Append(From);
2080  lastObject = From;
2081  }
2082  if (!From->Prev())
2083  objects = From;
2084  }
2085 }
2086 
2088 {
2089  while (objects) {
2090  cListObject *object = objects->Next();
2091  delete objects;
2092  objects = object;
2093  }
2094  objects = lastObject = NULL;
2095  count = 0;
2096 }
2097 
2098 cListObject *cListBase::Get(int Index) const
2099 {
2100  if (Index < 0)
2101  return NULL;
2102  cListObject *object = objects;
2103  while (object && Index-- > 0)
2104  object = object->Next();
2105  return object;
2106 }
2107 
2108 static int CompareListObjects(const void *a, const void *b)
2109 {
2110  const cListObject *la = *(const cListObject **)a;
2111  const cListObject *lb = *(const cListObject **)b;
2112  return la->Compare(*lb);
2113 }
2114 
2116 {
2117  int n = Count();
2118  cListObject *a[n];
2119  cListObject *object = objects;
2120  int i = 0;
2121  while (object && i < n) {
2122  a[i++] = object;
2123  object = object->Next();
2124  }
2125  qsort(a, n, sizeof(cListObject *), CompareListObjects);
2126  objects = lastObject = NULL;
2127  for (i = 0; i < n; i++) {
2128  a[i]->Unlink();
2129  count--;
2130  Add(a[i]);
2131  }
2132 }
2133 
2134 // --- cHashBase -------------------------------------------------------------
2135 
2137 {
2138  size = Size;
2139  hashTable = (cList<cHashObject>**)calloc(size, sizeof(cList<cHashObject>*));
2140 }
2141 
2143 {
2144  Clear();
2145  free(hashTable);
2146 }
2147 
2148 void cHashBase::Add(cListObject *Object, unsigned int Id)
2149 {
2150  unsigned int hash = hashfn(Id);
2151  if (!hashTable[hash])
2152  hashTable[hash] = new cList<cHashObject>;
2153  hashTable[hash]->Add(new cHashObject(Object, Id));
2154 }
2155 
2156 void cHashBase::Del(cListObject *Object, unsigned int Id)
2157 {
2158  cList<cHashObject> *list = hashTable[hashfn(Id)];
2159  if (list) {
2160  for (cHashObject *hob = list->First(); hob; hob = list->Next(hob)) {
2161  if (hob->object == Object) {
2162  list->Del(hob);
2163  break;
2164  }
2165  }
2166  }
2167 }
2168 
2170 {
2171  for (int i = 0; i < size; i++) {
2172  delete hashTable[i];
2173  hashTable[i] = NULL;
2174  }
2175 }
2176 
2177 cListObject *cHashBase::Get(unsigned int Id) const
2178 {
2179  cList<cHashObject> *list = hashTable[hashfn(Id)];
2180  if (list) {
2181  for (cHashObject *hob = list->First(); hob; hob = list->Next(hob)) {
2182  if (hob->id == Id)
2183  return hob->object;
2184  }
2185  }
2186  return NULL;
2187 }
2188 
2190 {
2191  return hashTable[hashfn(Id)];
2192 }
int Find(const char *s) const
Definition: tools.c:1484
cString dtoa(double d, const char *Format)
Converts the given double value to a string, making sure it uses a &#39;.
Definition: tools.c:378
struct dirent * Next(void)
Definition: tools.c:1466
cListObject * next
Definition: tools.h:456
cString itoa(int n)
Definition: tools.c:388
void Append(cListObject *Object)
Definition: tools.c:1968
unsigned char uchar
Definition: tools.h:30
#define LOCKFILESTALETIME
Definition: tools.c:1896
~cFile()
Definition: tools.c:1544
ssize_t Write(const void *Data, size_t Size)
Definition: tools.c:1832
cListObject * prev
Definition: tools.h:456
virtual void Clear(void)
Definition: tools.c:1493
bool isempty(const char *s)
Definition: tools.c:297
#define dsyslog(a...)
Definition: tools.h:36
cString AddDirectory(const char *DirName, const char *FileName)
Definition: tools.c:350
int Index(void) const
Definition: tools.c:1989
int Utf8StrLen(const char *s)
Returns the number of UTF-8 symbols formed by the given string of character bytes.
Definition: tools.c:833
bool isnumber(const char *s)
Definition: tools.c:312
void Set(int Ms=0)
Definition: tools.c:738
bool Close(void)
Definition: tools.c:1672
cString(const char *S=NULL, bool TakePointer=false)
Definition: tools.c:1017
bool Ready(bool Wait=true)
Definition: tools.c:1591
cListObject * Get(unsigned int Id) const
Definition: tools.c:2177
cList< cHashObject > * GetList(unsigned int Id) const
Definition: tools.c:2189
virtual ~cStringList()
Definition: tools.c:1479
uint32_t GetBits(int n)
Definition: tools.c:1355
void Clear(void)
Definition: tools.c:2169
void Add(cListObject *Object, cListObject *After=NULL)
Definition: tools.c:2014
cTimeMs(int Ms=0)
Creates a timer with ms resolution and an initial timeout of Ms.
Definition: tools.c:687
~cReadDir()
Definition: tools.c:1460
static char * systemCharacterTable
Definition: tools.h:146
char * stripspace(char *s)
Definition: tools.c:201
bool DirectoryOk(const char *DirName, bool LogErrors)
Definition: tools.c:427
bool Open(void)
Definition: tools.c:1662
ssize_t Read(void *Data, size_t Size)
Definition: tools.c:1774
static const char * SystemCharacterTable(void)
Definition: tools.h:164
bool MakeDirs(const char *FileName, bool IsDirectory)
Definition: tools.c:445
bool endswith(const char *s, const char *p)
Definition: tools.c:286
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition: tools.c:1080
off_t Seek(off_t Offset, int Whence)
Definition: tools.c:1766
static bool FileReady(int FileDes, int TimeoutMs=1000)
Definition: tools.c:1614
void Del(cListObject *Object, unsigned int Id)
Definition: tools.c:2156
void Unlink(void)
Definition: tools.c:1980
bool Add(int FileHandle, bool Out)
Definition: tools.c:1424
#define esyslog(a...)
Definition: tools.h:34
cString & Truncate(int Index)
Truncate the string at the given Index (if Index is < 0 it is counted from the end of the string)...
Definition: tools.c:1064
char * strn0cpy(char *dest, const char *src, size_t n)
Definition: tools.c:131
cUnbufferedFile(void)
Definition: tools.c:1703
int BCD2INT(int x)
Definition: tools.c:45
void Unlock(void)
Definition: tools.c:1948
#define LOG_ERROR_STR(s)
Definition: tools.h:39
T max(T a, T b)
Definition: tools.h:55
cReadDir(const char *Directory)
Definition: tools.c:1455
void syslog_with_tid(int priority, const char *format,...)
Definition: tools.c:35
double atod(const char *s)
Converts the given string, which is a floating point number using a &#39;.
Definition: tools.c:357
int DirSizeMB(const char *DirName)
returns the total size of the files in the given directory, or -1 in case of an error ...
Definition: tools.c:585
char * ReadLink(const char *FileName)
returns a new string allocated on the heap, which the caller must delete (or NULL in case of an error...
Definition: tools.c:617
T min(T a, T b)
Definition: tools.h:54
void WordAlign(void)
Definition: tools.c:1370
cUnbufferedFile is used for large files that are mainly written or read in a streaming manner...
Definition: tools.h:418
const char * Convert(const char *From, char *To=NULL, size_t ToLength=0)
Converts the given Text from FromCode to ToCode (as set in the constructor).
Definition: tools.c:955
cCharSetConv(const char *FromCode=NULL, const char *ToCode=NULL)
Sets up a character set converter to convert from FromCode to ToCode.
Definition: tools.c:914
bool Poll(int TimeoutMs=0)
Definition: tools.c:1443
int Open(const char *FileName, int Flags, mode_t Mode=DEFFILEMODE)
Definition: tools.c:1713
int SysLogLevel
Definition: tools.c:31
char * Read(FILE *f)
Definition: tools.c:1398
#define MALLOC(type, size)
Definition: tools.h:46
virtual void Clear(void)
Definition: tools.c:2087
#define JPEGCOMPRESSMEM
Definition: tools.c:1196
#define MT(s, m, v)
~cSafeFile()
Definition: tools.c:1653
uint64_t begin
Definition: tools.h:335
#define MAXSYSLOGBUF
Definition: tools.c:33
int Utf8CharSet(uint c, char *s)
Converts the given UTF-8 symbol to a sequence of character bytes and copies them to the given string...
Definition: tools.c:786
virtual ~cListBase()
Definition: tools.c:2009
#define DECIMAL_POINT_C
Definition: tools.c:355
cString TimeToString(time_t t)
Converts the given time to a string of the form "www mmm dd hh:mm:ss yyyy".
Definition: tools.c:1156
static cString static cString vsprintf(const char *fmt, va_list &ap)
Definition: tools.c:1093
cBase64Encoder(const uchar *Data, int Length, int MaxResult=64)
Sets up a new base 64 encoder for the given Data, with the given Length.
Definition: tools.c:1296
virtual int Compare(const cListObject &ListObject) const
Must return 0 if this object is equal to ListObject, a positive value if it is "greater", and a negative value if it is "smaller".
Definition: tools.h:460
T * Next(const T *object) const
Definition: tools.h:495
ssize_t safe_write(int filedes, const void *buffer, size_t size)
Definition: tools.c:65
cString WeekDayName(int WeekDay)
Converts the given WeekDay (0=Sunday, 1=Monday, ...) to a three letter day name.
Definition: tools.c:1103
static void JpegCompressInitDestination(j_compress_ptr cinfo)
Definition: tools.c:1203
static int maxFiles
Definition: tools.h:386
cListObject * Next(void) const
Definition: tools.h:468
int Utf8CharLen(const char *s)
Returns the number of character bytes at the beginning of the given string that form a UTF-8 symbol...
Definition: tools.c:757
~cCharSetConv()
Definition: tools.c:925
static boolean JpegCompressEmptyOutputBuffer(j_compress_ptr cinfo)
Definition: tools.c:1212
#define LOCKFILENAME
Definition: tools.c:1895
bool TimedOut(void) const
Definition: tools.c:743
virtual ~cString()
Definition: tools.c:1041
cListObject(void)
Definition: tools.c:1959
static void SleepMs(int TimeoutMs)
Creates a cCondWait object and uses it to sleep for TimeoutMs milliseconds, immediately giving up the...
Definition: thread.c:57
cReadLine(void)
Definition: tools.c:1387
void Sort(void)
Definition: tools.c:2115
void Ins(cListObject *Object, cListObject *Before=NULL)
Definition: tools.c:2030
~cReadLine()
Definition: tools.c:1393
#define WRITE_BUFFER
Definition: tools.c:1701
bool Ok(void)
Definition: tools.h:379
cFileNameList(const char *Directory=NULL, bool DirsOnly=false)
Definition: tools.c:1503
int FreeDiskSpaceMB(const char *Directory, int *UsedMB)
Definition: tools.c:410
bool Open(const char *FileName, int Flags, mode_t Mode=DEFFILEMODE)
Definition: tools.c:1549
const char * NextLine(void)
Returns the next line of encoded data (terminated by &#39;\0&#39;), or NULL if there is no more encoded data...
Definition: tools.c:1310
cString DayDateTime(time_t t)
Converts the given time to a string of the form "www dd.mm. hh:mm".
Definition: tools.c:1145
static void SetSystemCharacterTable(const char *CharacterTable)
Definition: tools.c:932
int numdigits(int n)
Definition: tools.c:302
static tThreadId ThreadId(void)
Definition: thread.c:341
cFile(void)
Definition: tools.c:1539
cListBase(void)
Definition: tools.c:2003
static uint SystemToUtf8[128]
Definition: tools.c:755
cPoller(int FileHandle=-1, bool Out=false)
Definition: tools.c:1418
cString & CompactChars(char c)
Compact any sequence of characters &#39;c&#39; to a single character, and strip all of them from the beginnin...
Definition: tools.c:1074
virtual ~cListObject()
Definition: tools.c:1964
#define FADVGRAN
Definition: tools.c:1752
bool Lock(int WaitSeconds=0)
Definition: tools.c:1912
#define BCDCHARTOINT(x)
Definition: tools.h:64
cString WeekDayNameFull(int WeekDay)
Converts the given WeekDay (0=Sunday, 1=Monday, ...) to a full day name.
Definition: tools.c:1124
uchar * RgbToJpeg(uchar *Mem, int Width, int Height, int &Size, int Quality)
Converts the given Memory to a JPEG image and returns a pointer to the resulting image.
Definition: tools.c:1251
bool Load(const char *Directory, bool DirsOnly=false)
Definition: tools.c:1508
int64_t StrToNum(const char *s)
Converts the given string to a number.
Definition: tools.c:323
bool SpinUpDisk(const char *FileName)
Definition: tools.c:631
int WriteAllOrNothing(int fd, const uchar *Data, int Length, int TimeoutMs, int RetryMs)
Writes either all Data to the given file descriptor, or nothing at all.
Definition: tools.c:90
bool startswith(const char *s, const char *p)
Definition: tools.c:277
#define MEGABYTE(n)
Definition: tools.h:44
void SetReadAhead(size_t ra)
Definition: tools.c:1755
cListObject * Prev(void) const
Definition: tools.h:467
T * First(void) const
Definition: tools.h:492
void Del(cListObject *Object, bool DeleteObject=true)
Definition: tools.c:2046
int strcountchr(const char *s, char c)
returns the number of occurrences of &#39;c&#39; in &#39;s&#39;.
Definition: tools.c:189
cListObject * Get(int Index) const
Definition: tools.c:2098
cLockFile(const char *Directory)
Definition: tools.c:1898
#define FATALERRNO
Definition: tools.h:51
int Utf8ToArray(const char *s, uint *a, int Size)
Converts the given character bytes (including the terminating 0) into an array of UTF-8 symbols of th...
Definition: tools.c:864
static bool FileReadyForWriting(int FileDes, int TimeoutMs=1000)
Definition: tools.c:1629
off_t FileSize(const char *FileName)
returns the size of the given file, or -1 in case of an error (e.g. if the file doesn&#39;t exist) ...
Definition: tools.c:677
#define KILOBYTE(n)
Definition: tools.h:43
static void JpegCompressTermDestination(j_compress_ptr cinfo)
Definition: tools.c:1235
#define tr(s)
Definition: i18n.h:85
virtual void Move(int From, int To)
Definition: tools.c:2058
char * s
Definition: tools.h:170
virtual ~cHashBase()
Definition: tools.c:2142
char * skipspace(const char *s)
Definition: tools.h:200
bool EntriesOnSameFileSystem(const char *File1, const char *File2)
Checks whether the given files are on the same file system.
Definition: tools.c:395
uint Utf8CharGet(const char *s, int Length)
Returns the UTF-8 symbol at the beginning of the given string.
Definition: tools.c:771
int Utf8FromArray(const uint *a, char *s, int Size, int Max)
Converts the given array of UTF-8 symbols (including the terminating 0) into a sequence of character ...
Definition: tools.c:882
int GetBit(void)
Definition: tools.c:1346
cSafeFile(const char *FileName)
Definition: tools.c:1644
cString TimeString(time_t t)
Converts the given time to a string of the form "hh:mm".
Definition: tools.c:1186
char * strcpyrealloc(char *dest, const char *src)
Definition: tools.c:114
static bool files[]
Definition: tools.h:385
bool StrInArray(const char *a[], const char *s)
Returns true if the string s is equal to one of the strings pointed to by the (NULL terminated) array...
Definition: tools.c:338
ssize_t safe_read(int filedes, void *buffer, size_t size)
Definition: tools.c:53
bool RemoveEmptyDirectories(const char *DirName, bool RemoveThis, const char *IgnoreFiles[])
Removes all empty directories under the given directory DirName.
Definition: tools.c:531
void Add(cListObject *Object, unsigned int Id)
Definition: tools.c:2148
Definition: tools.h:333
cString ShortDateString(time_t t)
Converts the given time to a string of the form "dd.mm.yy".
Definition: tools.c:1177
static uint64_t Now(void)
Definition: tools.c:695
bool SetLength(int Length)
Definition: tools.c:1377
static int CompareListObjects(const void *a, const void *b)
Definition: tools.c:2108
static cUnbufferedFile * Create(const char *FileName, int Flags, mode_t Mode=DEFFILEMODE)
Definition: tools.c:1883
cHashBase(int Size)
Definition: tools.c:2136
bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks)
Definition: tools.c:473
void TouchFile(const char *FileName)
Definition: tools.c:663
cString & operator=(const cString &String)
Definition: tools.c:1046
#define READCHUNK
Definition: tools.c:1753
~cLockFile()
Definition: tools.c:1906
char * compactspace(char *s)
Definition: tools.c:213
cString strescape(const char *s, const char *chars)
Definition: tools.c:254
char * Utf8Strn0Cpy(char *Dest, const char *Src, int n)
Copies at most n character bytes from Src to Dest, making sure that the resulting copy ends with a co...
Definition: tools.c:845
const char * strchrn(const char *s, char c, size_t n)
returns a pointer to the n&#39;th occurrence (counting from 1) of c in s, or NULL if no such character wa...
Definition: tools.c:176
void Close(void)
Definition: tools.c:1582
virtual void Clear(void)
Definition: tools.h:602
Definition: tools.h:357
static bool AnyFileReady(int FileDes=-1, int TimeoutMs=1000)
Definition: tools.c:1596
~cUnbufferedFile()
Definition: tools.c:1708
int Utf8SymChars(const char *s, int Symbols)
Returns the number of character bytes at the beginning of the given string that form at most the give...
Definition: tools.c:820
int FadviseDrop(off_t Offset, off_t Len)
Definition: tools.c:1760
time_t LastModifiedTime(const char *FileName)
Definition: tools.c:669
char * strreplace(char *s, char c1, char c2)
Definition: tools.c:139
~cBase64Encoder()
Definition: tools.c:1305
void ByteAlign(void)
Definition: tools.c:1363
void Insert(cListObject *Object)
Definition: tools.c:1974
void writechar(int filedes, char c)
Definition: tools.c:85
Definition: tools.h:168
char * compactchars(char *s, char c)
removes all occurrences of &#39;c&#39; from the beginning an end of &#39;s&#39; and replaces sequences of multiple &#39;c...
Definition: tools.c:230
int Close(void)
Definition: tools.c:1731
static const char * b64
Definition: tools.h:294
cString DateString(time_t t)
Converts the given time to a string of the form "www dd.mm.yyyy".
Definition: tools.c:1166
uint64_t Elapsed(void) const
Definition: tools.c:748