1 /*****************************************************************************
2 * common.h (c) Copyright 2007 by inkling@users.sourceforge.net
4 * This software is part of the atscap 1.1 distribution codebase.
6 * atscap is free software; you may only redistribute it and/or modify
7 * it under the terms of the GNU General Public License, Version 2 or later,
8 * as published by the Free Software Foundation.
10 * atscap is distributed to you AS-IS, in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License Version 2
16 * along with this program; if not, write the Free Software Foundation, Inc.,
17 * at 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 #define WHO (char *) __FUNCTION__
28 #define WHERE (int) __LINE__
31 /******************************** alloc functions ***************************/
33 #define ALLOC_NAME_MAX 40
40 alloc_t allocs
[ ALLOC_MAX
];
50 memset( allocs
, 0, sizeof(allocs
));
52 for (i
= 0; i
< ALLOC_MAX
; i
++) {
53 allocs
[i
].addr
= NULL
;
54 allocs
[i
].name
= NULL
;
71 fprintf(stdout
, "\nPointers Size Name\n");
73 for (i
= 0; i
< ALLOC_MAX
; i
++) {
74 if (NULL
!= m
[i
].addr
) {
75 fprintf( stdout
, "0x%08X %8d %s\n",
77 /* broken for 64 bits? use off_t instead? */
78 (unsigned int)m
[i
].addr
,
87 fprintf(stdout
, "Pointers %9d total bytes\n\n", t
);
93 ifree ( void * p
, char *n
)
102 if (NULL
== p
) return NULL
;
104 for (i
= 0; i
< ALLOC_MAX
; i
++)
105 if (p
== m
[i
].addr
) break;
107 if (i
== ALLOC_MAX
) {
110 "ifree %p not found for %s", p
, n
);
113 "ifree %p not found for %s\n", p
, n
);
119 // fprintf( stdout, "ifreed %s %d\n", m->name, m->size);
134 imalloc ( size_t z
, char *n
)
142 for (i
= 0; i
< ALLOC_MAX
; i
++)
143 if (NULL
== m
[i
].addr
) break;
145 if (i
== ALLOC_MAX
) {
148 "ialloc full %s %d, increase ALLOC_MAX",
153 "ialloc full %s %d, increase ALLOC_MAX\n",
160 if (NULL
== p
) return NULL
;
163 m
->name
= calloc( 1, ALLOC_NAME_MAX
);
164 strncpy( m
->name
, n
, ALLOC_NAME_MAX
);
165 m
->name
[ ALLOC_NAME_MAX
- 1 ] = 0;
174 icalloc( int x
, int y
, char *n
)
181 // if (0 != arg_fmsg)
182 // fprintf( stdout, "%s %d %s\n", WHO, z, n );
186 for (i
= 0; i
< ALLOC_MAX
; i
++)
187 if (NULL
== m
[i
].addr
) break;
189 if (i
== ALLOC_MAX
) {
192 "icalloc full %s %dx%d, increase ALLOC_MAX",
197 "icalloc full %s %dx%d, increase ALLOC_MAX\n",
204 if (NULL
== p
) return NULL
;
210 m
->name
= calloc( 1, ALLOC_NAME_MAX
);
211 strncpy( m
->name
, n
, ALLOC_NAME_MAX
);
212 m
->name
[ ALLOC_NAME_MAX
- 1 ] = 0;
219 // incremental realloc, does not shrink, only grows by n bytes
222 irealloc ( void * p
, int z
, char *n
)
228 // fprintf( stdout, "%s p %p z %d\n", WHO, p, z );
233 if (NULL
== p
) return NULL
;
234 if (0 == z
) return p
;
236 for (i
= 0; i
< ALLOC_MAX
; i
++)
237 if (p
== m
[i
].addr
) break;
239 if (i
== ALLOC_MAX
) {
242 "irealloc %p not found for %s %d", p
, n
, z
);
245 "irealloc %p not found for %s %d\n", p
, n
, z
);
252 strncpy( m
->name
, n
, ALLOC_NAME_MAX
);
253 m
->name
[ ALLOC_NAME_MAX
- 1] = 0;
256 m
->addr
= realloc( m
->addr
, m
->size
);
260 /*************************** end of alloc functions *************************/
263 /********************************* text functions ***************************/
271 filebase ( char *d
, char *s
, int o
)
277 /* limit option flags to non-bogus */
281 /* limit string handling to non-bogus */
282 if (NULL
== d
) return;
283 if (NULL
== s
) return;
286 /* mutually exclusive options for how to truncate the source name */
289 /* path only, with / */
292 t
= strrchr( s
, '/' );
295 t
= strrchr( d
, '/');
301 /* path and file, without last .ext */
304 t
= strrchr( s
, '/' );
305 if (NULL
== t
) d
+= 2;
307 t
= strrchr( d
, '.');
308 if (NULL
!= t
) *t
= 0; /* truncate at last . */
311 /* truncated file only, without last .ext */
313 t
= strrchr( s
, '/' ); /* skip path */
318 /* truncate at last . */
319 t
= strrchr( d
, '.');
320 if (NULL
!= t
) *t
= 0;
322 /* no path, truncate at last . */
324 t
= strrchr( d
, '.');
325 if (NULL
!= t
) *t
= 0;
329 /* file only with .ext */
331 t
= strrchr( s
, '/' );
346 /* long long to ascii comma delimited to make big numbers easier to read.
347 Assumes dest has enough bytes for result (19 digits + 6 commas + nul).
348 Largest number is around +/- 9,000,000,000,000,000,000 (US quintillion).
352 value sl dest dl dl computation
354 1 1 1 1 (0 * 4) + 1 = 1
355 10 2 10 2 (0 * 4) + 2 = 2
356 100 3 100 3 (1 * 4) - 1 = 3
357 1000 4 1,000 5 (1 * 4) + 1 = 5
358 10000 5 10,000 6 (1 * 4) + 2 = 6
359 100000 6 100,000 7 (2 * 4) - 1 = 7
360 1000000 7 1,000,000 9 (2 * 4) + 1 = 9
361 10000000 8 10,000,000 10 (2 * 4) + 2 = 10
362 100000000 9 100,000,000 11 (3 * 4) - 1 = 11
363 1000000000 10 1,000,000,000 13 (3 * 4) + 1 = 13
365 NOTE: atoll() breaks after 2^30 on 32-bit with some older compilers.
366 Auto-verification using atoll on char c[] doesn't always work.
367 This function also depends on snprintf getting it right.
369 10000000000 11 10,000,000,000 14 (3 * 4) + 2 = 14
375 lltoasc ( char *dest
, long long value
)
377 char *s
, *b
, *d
; /* source and bottom boundary for d */
378 int i
, k
, sl
, dl
; /* loops, source len, destination len */
379 char c
[COMMA_MAX
]; /* value in ascii */
383 /* Don't want the sign confusing the comma calculation so fix it here. */
385 // value ^= -1LL; /* one */
386 // value++; /* way */
387 value
= 0LL - value
; /* or another */
388 /* if still negative, it is largest negative and will not complement. */
389 if (value
>= 0LL) *d
++ = '-';
392 snprintf( c
, COMMA_MAX
, "%lld", value
);
394 if (value
> 999LL) { /* commas needed ? */
395 b
= d
; /* save stop pointer */
396 sl
= strlen( c
); /* src len */
397 dl
= ((sl
/ 3) * 4) + (sl
% 3); /* dest len */
398 if ( 0 == ( sl
% 3)) dl
--; /* fixup for last , */
400 d
[dl
] = 0; /* NUL term */
401 dl
--; /* and back up */
403 if ( dl
< COMMA_MAX
) { /* will added commas fit? */
405 /* copy bytes from s to d in reverse order, adding , to d every 3 bytes */
407 k
= sl
- 1; /* loop limit */
408 s
= c
+ k
; /* point: 1's place end of c */
409 d
+= dl
; /* point: computed end of d */
411 for ( i
= sl
; i
> 0; ) {
412 if ( (d
< b
) || (s
< c
) ) break; /* boundary */
414 *d
-- = *s
--; /* copy & decrement */
415 if ( (d
< b
) || (s
< c
) ) break; /* boundary */
417 if (0 == ((sl
-i
) % 3)) *d
-- = ',';
418 if (d
< b
) break; /* boundary check */
421 strncpy( d
, c
, COMMA_MAX
); /* commas won't fit */
424 strncpy( d
, c
, COMMA_MAX
); /* no commas needed */
430 /* build a list of pointers up to n pointers from string s using delim c */
431 /* s is modified with NUL terms replacing each delim c */
434 build_args( char **p
, int n
, char *s
, char c
, char *caller
)
439 for (i
= 0; i
< n
; i
++) p
[i
] = NULL
;
443 for (i
= 0; i
< n
; i
++) {
447 if (NULL
== t
) break;
455 /* Similar to but different from strncpy:
456 No string greater than 16k allowed to be copied, log > 16k and NULLs.
457 Does not pad destination with 0's if length of source is shorter than n.
458 There is no valid reason to spend cpu cycles filling memory with zeros.
459 This will always null terminate at n-1 even if s is n len bytes long.
460 d result will always be n-1 characters long, at most.
464 astrncpy ( char *d
, char *s
, unsigned int n
)
469 if ( (NULL
== d
) || (NULL
== s
) ) {
471 dvrlog( LOG_INFO
, "astrncpy() %p %p NULL", d
, s
);
473 fprintf( stdout
, "\nastrncpy() %p %p NULL\n", d
, s
);
477 /* log 0 and > 65535 len */
478 if ( (0 == n
) || (n
> 16383) ) {
480 dvrlog( LOG_INFO
, "astrncpy() %d chars", n
);
482 fprintf( stdout
, "\nastrncpy() %d chars\n", n
);
487 /* count auto decrements, pointers auto increment */
488 while (c
-- > 0) if (0 == (*t
++ = *s
++)) break;
490 /* always force last byte 0 */
495 /* maximum amount to text to append with each call */
496 #define PRINTF_MAX 16384
497 /* Incremental snprintf, appends to string 'a' until size 'b' reached.
498 This keeps 'b' limited to 'a' string alloc instead of blind melon limit.
499 First call should have a strlen 0, *a = 0 or you get variable junk.
503 asnprintf ( char *a
, size_t b
, const char *fmt
, ... )
505 char *p
, t
[PRINTF_MAX
];
510 if (NULL
== a
) return;
513 memset(t
, 0, sizeof(t
));
515 /* variable arg macro start, pass fmt and ap, variable arg macro end */
516 vsnprintf( t
, sizeof(t
)-1, fmt
, ap
);
522 /* bit bucket does not overflow? */
523 if ( (la
+ lt
+ 1) < b
) {
526 astrncpy( p
, t
, lt
+ 1 );
528 /* if bit bucket does overflow, silently fail and don't exceed boundary */
530 /**************************** end of text functions *************************/
533 /******************************* librt functions ****************************/
536 char *clock_text
[ RTC_MAX
] = {
538 "PROCESS_CPUTIME_ID",
542 clockid_t clock_ids
[ RTC_MAX
] = {
544 CLOCK_PROCESS_CPUTIME_ID
,
545 CLOCK_THREAD_CPUTIME_ID
547 clockid_t clock_method
= CLOCK_PROCESS_CPUTIME_ID
;
548 long long clock_res
; /* (tv.sec<<32) | tv.nsec */
551 /* find the most accurate clock and set clock_method global */
554 test_clock_res ( void )
561 r
= 1000000000LL; /* worst case scenario is 1 clock per second */
563 for (i
= 0; i
< RTC_MAX
; i
++) {
565 /* is clock res return valid? */
566 if (0 == clock_getres( clock_ids
[i
], &res
)) {
571 /* is clock res non-zero? */
581 fprintf(stderr
, "%s has no clock method? check librt\n", NAME
);
585 /* use last lowest value in l for the syslog */
586 clock_method
= clock_ids
[j
];
589 fprintf(stdout
, "CLOCK_METHOD is %d %s\n",
590 clock_idx
, clock_text
[clock_idx
]);
594 /*************************** end of librt functions *************************/
597 /******************************* file functions *****************************/
599 /* Copy source file s to destination file d, a is 0 copy or 1 append:
600 If source contains '*', source is used for glob list.
601 If destination term with '/', [glob] source appends to dest.
602 NOTE: It could *always* glob, however glob() uses a lot of cycles.
603 Also, it tries to behave like cp -a and keep file date and mode bits.
604 TODO? alloc buf fs.blocksize or page-size? 4k is OK
609 filecopy ( char *d
, char *s
, int a
)
611 char buf
[4096], ni
[512], no
[512], fb
[256], *p
;
612 int i
, j
, k
, o
, r
, w
, z
, e
, g
, f
, rc
;
621 if (NULL
== d
) return -1;
622 if (NULL
== s
) return -1;
623 if (0 == *d
) return -1;
624 if (0 == *s
) return -1;
630 /* glob needed for * in filename? */
631 p
= strchr( s
, '*' );
632 if (NULL
== p
) p
= strchr( s
, '?' );
633 if (NULL
!= p
) g
= ~0;
636 /* WARNING: no returns until globt is freed, only continues and breaks */
637 glob( s
, 0, NULL
, &globt
);
640 advrlog( LOG_INFO
, "%s glob %s files %d", WHO
, s
, f
);
643 /* any more glob files left to do, or is single file? */
644 for (j
= 0; j
< f
; j
++) {
646 /* set name in and name out */
647 astrncpy( ni
, s
, sizeof(ni
) );
648 astrncpy( no
, d
, sizeof(no
) );
650 /* glob will change source name to glob index if found */
651 if (0 != g
) astrncpy( ni
, globt
.gl_pathv
[ j
], sizeof(ni
) );
653 /* remove any trailing / */
654 p
= no
+ strlen( no
);
656 if ('/' == *p
) *p
= 0;
658 /* destination exists? */
659 rc
= stat64( no
, &fs
);
661 if (0 != (S_IFDIR
& fs
.st_mode
)) {
662 filebase( fb
, ni
, F_FILE
);
663 asnprintf( no
, sizeof(no
), "/%s", fb
);
667 /* keep source metadata: cp -a emulation sets mtime and mode after copy */
668 rc
= stat64( ni
, &fs
);
670 /* skip bad file for whatever reason */
672 dvrlog( LOG_INFO
, "%s can't stat %s", WHO
, ni
);
676 /* clear other time stamps */
677 memset( &ut
, 0, sizeof(ut
) );
678 ut
.modtime
= fs
.st_mtime
;
679 ut
.actime
= fs
.st_atime
;
683 advrlog( LOG_INFO
, "%s %s %s", (0 == a
)?"copy":"append", ni
, no
);
685 /* peter knaggs says read only helps luser mode */
686 i
= open( ni
, FILE_ROMODE
);
688 dvrlog( LOG_INFO
, "%s can't open %s err %d", WHO
, ni
, errno
);
693 /* copy, mode is octal */
695 o
= open( no
, FILE_WMODE
, 0644 );
697 /* append. seeks end of file instead of O_APPEND flag with NFS problems */
699 o
= open( no
, O_RDWR
| O_CREAT
, 0644 );
702 dvrlog( LOG_INFO
, "%s can't open %s", WHO
, no
);
708 /* append sets file position to end, should avoid NFS problems?
709 no. append is broken. don't use it here.
711 if (0 != a
) lseek( o
, 0, SEEK_END
);
717 r
= read( i
, buf
, z
);
719 w
= write( o
, buf
, r
);
722 dvrlog( LOG_INFO
, "%s can't write %s", WHO
, no
);
728 dvrlog( LOG_INFO
, "%s wrote %d of %d to %s",
735 advrlog( LOG_INFO
, "%s EOF %s", WHO
, ni
);
741 dvrlog( LOG_INFO
, "%s can't read %s", WHO
, no
);
750 /* Change file permissions after close to match original mode then set
751 mtime after chmod. This prevents guide from reloading every time it
752 restarts with recent EPGs, and keeps auto-EPG reload on 3hr meridian.
754 NOTE: It is not expected that you will have to restart it very often.
755 This is mostly to make it easier if you're trying to add new features.
756 The wait for guide load can be very annoying after a few dozen times. :>
762 /* don't forget to free what glob allocated */
763 if (0 != g
) globfree( &globt
);
770 /**************************** end of file functions *************************/