tools.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:20k
- /*
- * $Id: tools.c,v 1.173 1999/01/11 21:55:44 wessels Exp $
- *
- * DEBUG: section 21 Misc Functions
- * AUTHOR: Harvest Derived
- *
- * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
- * ----------------------------------------------------------
- *
- * Squid is the result of efforts by numerous individuals from the
- * Internet community. Development is led by Duane Wessels of the
- * National Laboratory for Applied Network Research and funded by the
- * National Science Foundation. Squid is Copyrighted (C) 1998 by
- * Duane Wessels and the University of California San Diego. Please
- * see the COPYRIGHT file for full details. Squid incorporates
- * software developed and/or copyrighted by other sources. Please see
- * the CREDITS file for full details.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
- */
- #include "squid.h"
- #define DEAD_MSG "
- The Squid Cache (version %s) died.n
- n
- You've encountered a fatal error in the Squid Cache version %s.n
- If a core file was created (possibly in the swap directory),n
- please execute 'gdb squid core' or 'dbx squid core', then type 'where',n
- and report the trace back to squid-bugs@ircache.net.n
- n
- Thanks!n"
- static void fatal_common(const char *);
- static void fatalvf(const char *fmt, va_list args);
- static void mail_warranty(void);
- #if USE_ASYNC_IO
- static AIOCB safeunlinkComplete;
- #endif
- #if MEM_GEN_TRACE
- extern void log_trace_done();
- extern void log_trace_init(char *);
- #endif
- void
- releaseServerSockets(void)
- {
- int i;
- /* Release the main ports as early as possible */
- for (i = 0; i < NHttpSockets; i++) {
- if (HttpSockets[i] >= 0)
- close(HttpSockets[i]);
- }
- if (theInIcpConnection >= 0)
- close(theInIcpConnection);
- if (theOutIcpConnection >= 0 && theOutIcpConnection != theInIcpConnection)
- close(theOutIcpConnection);
- }
- static char *
- dead_msg(void)
- {
- LOCAL_ARRAY(char, msg, 1024);
- snprintf(msg, 1024, DEAD_MSG, version_string, version_string);
- return msg;
- }
- static void
- mail_warranty(void)
- {
- FILE *fp = NULL;
- char *filename;
- static char command[256];
- if ((filename = tempnam(NULL, appname)) == NULL)
- return;
- if ((fp = fopen(filename, "w")) == NULL)
- return;
- fprintf(fp, "From: %sn", appname);
- fprintf(fp, "To: %sn", Config.adminEmail);
- fprintf(fp, "Subject: %sn", dead_msg());
- fclose(fp);
- snprintf(command, 256, "mail %s < %s", Config.adminEmail, filename);
- system(command); /* XXX should avoid system(3) */
- unlink(filename);
- }
- void
- dumpMallocStats(void)
- {
- #if HAVE_MSTATS && HAVE_GNUMALLOC_H
- struct mstats ms = mstats();
- fprintf(debug_log, "ttotal space in arena: %6d KBn",
- (int) (ms.bytes_total >> 10));
- fprintf(debug_log, "tTotal free: %6d KB %d%%n",
- (int) (ms.bytes_free >> 10),
- percent(ms.bytes_free, ms.bytes_total));
- #elif HAVE_MALLINFO
- struct mallinfo mp;
- int t;
- if (!do_mallinfo)
- return;
- mp = mallinfo();
- fprintf(debug_log, "Memory usage for %s via mallinfo():n", appname);
- fprintf(debug_log, "ttotal space in arena: %6d KBn",
- mp.arena >> 10);
- fprintf(debug_log, "tOrdinary blocks: %6d KB %6d blksn",
- mp.uordblks >> 10, mp.ordblks);
- fprintf(debug_log, "tSmall blocks: %6d KB %6d blksn",
- mp.usmblks >> 10, mp.smblks);
- fprintf(debug_log, "tHolding blocks: %6d KB %6d blksn",
- mp.hblkhd >> 10, mp.hblks);
- fprintf(debug_log, "tFree Small blocks: %6d KBn",
- mp.fsmblks >> 10);
- fprintf(debug_log, "tFree Ordinary blocks: %6d KBn",
- mp.fordblks >> 10);
- t = mp.uordblks + mp.usmblks + mp.hblkhd;
- fprintf(debug_log, "tTotal in use: %6d KB %d%%n",
- t >> 10, percent(t, mp.arena));
- t = mp.fsmblks + mp.fordblks;
- fprintf(debug_log, "tTotal free: %6d KB %d%%n",
- t >> 10, percent(t, mp.arena));
- #if HAVE_EXT_MALLINFO
- fprintf(debug_log, "tmax size of small blocks:t%dn",
- mp.mxfast);
- fprintf(debug_log, "tnumber of small blocks in a holding block:t%dn",
- mp.nlblks);
- fprintf(debug_log, "tsmall block rounding factor:t%dn",
- mp.grain);
- fprintf(debug_log, "tspace (including overhead) allocated in ord. blks:t%dn",
- mp.uordbytes);
- fprintf(debug_log, "tnumber of ordinary blocks allocated:t%dn",
- mp.allocated);
- fprintf(debug_log, "tbytes used in maintaining the free tree:t%dn",
- mp.treeoverhead);
- #endif /* HAVE_EXT_MALLINFO */
- #endif /* HAVE_MALLINFO */
- }
- void
- squid_getrusage(struct rusage *r)
- {
- memset(r, ' ', sizeof(struct rusage));
- #if HAVE_GETRUSAGE && defined(RUSAGE_SELF)
- #ifdef _SQUID_SOLARIS_
- /* Solaris 2.5 has getrusage() permission bug -- Arjan de Vet */
- enter_suid();
- #endif
- getrusage(RUSAGE_SELF, r);
- #ifdef _SQUID_SOLARIS_
- leave_suid();
- #endif
- #endif
- }
- double
- rusage_cputime(struct rusage *r)
- {
- return (double) r->ru_stime.tv_sec +
- (double) r->ru_utime.tv_sec +
- (double) r->ru_stime.tv_usec / 1000000.0 +
- (double) r->ru_utime.tv_usec / 1000000.0;
- }
- int
- rusage_maxrss(struct rusage *r)
- {
- #if defined(_SQUID_SGI_) && _ABIAPI
- return r->ru_pad[0];
- #elif defined(_SQUID_SGI_)
- return r->ru_maxrss;
- #elif defined(_SQUID_OSF_)
- return r->ru_maxrss;
- #elif defined(BSD4_4)
- return r->ru_maxrss;
- #elif HAVE_GETPAGESIZE
- return (r->ru_maxrss * getpagesize()) >> 10;
- #elif defined(PAGESIZE)
- return (r->ru_maxrss * PAGESIZE) >> 10;
- #else
- return r->ru_maxrss;
- #endif
- }
- int
- rusage_pagefaults(struct rusage *r)
- {
- #if defined(_SQUID_SGI_) && _ABIAPI
- return r->ru_pad[5];
- #else
- return r->ru_majflt;
- #endif
- }
- void
- PrintRusage(void)
- {
- struct rusage rusage;
- squid_getrusage(&rusage);
- fprintf(debug_log, "CPU Usage: %.3f secondsn", rusage_cputime(&rusage));
- fprintf(debug_log, "Maximum Resident Size: %d KBn",
- rusage_maxrss(&rusage));
- fprintf(debug_log, "Page faults with physical i/o: %dn",
- rusage_pagefaults(&rusage));
- }
- void
- death(int sig)
- {
- if (sig == SIGSEGV)
- fprintf(debug_log, "FATAL: Received Segment Violation...dying.n");
- else if (sig == SIGBUS)
- fprintf(debug_log, "FATAL: Received Bus Error...dying.n");
- else
- fprintf(debug_log, "FATAL: Received signal %d...dying.n", sig);
- #ifdef PRINT_STACK_TRACE
- #ifdef _SQUID_HPUX_
- {
- extern void U_STACK_TRACE(void); /* link with -lcl */
- fflush(debug_log);
- dup2(fileno(debug_log), 2);
- U_STACK_TRACE();
- }
- #endif /* _SQUID_HPUX_ */
- #ifdef _SQUID_SOLARIS_
- { /* get ftp://opcom.sun.ca/pub/tars/opcom_stack.tar.gz and */
- extern void opcom_stack_trace(void); /* link with -lopcom_stack */
- fflush(debug_log);
- dup2(fileno(debug_log), fileno(stdout));
- opcom_stack_trace();
- fflush(stdout);
- }
- #endif /* _SQUID_SOLARIS_ */
- #endif /* PRINT_STACK_TRACE */
- #if SA_RESETHAND == 0
- signal(SIGSEGV, SIG_DFL);
- signal(SIGBUS, SIG_DFL);
- signal(sig, SIG_DFL);
- #endif
- releaseServerSockets();
- storeDirWriteCleanLogs(0);
- PrintRusage();
- dumpMallocStats();
- if (squid_curtime - SQUID_RELEASE_TIME < 864000) {
- /* skip if more than 10 days old */
- if (Config.adminEmail)
- mail_warranty();
- else
- puts(dead_msg());
- }
- abort();
- }
- void
- sigusr2_handle(int sig)
- {
- static int state = 0;
- /* no debug() here; bad things happen if the signal is delivered during _db_print() */
- if (state == 0) {
- #ifndef MEM_GEN_TRACE
- _db_init(Config.Log.log, "ALL,10");
- #else
- log_trace_done();
- #endif
- state = 1;
- } else {
- #ifndef MEM_GEN_TRACE
- _db_init(Config.Log.log, Config.debugOptions);
- #else
- log_trace_init("/tmp/squid.alloc");
- #endif
- state = 0;
- }
- #if !HAVE_SIGACTION
- signal(sig, sigusr2_handle); /* reinstall */
- #endif
- }
- static void
- fatal_common(const char *message)
- {
- #if HAVE_SYSLOG
- if (opt_syslog_enable)
- syslog(LOG_ALERT, "%s", message);
- #endif
- fprintf(debug_log, "FATAL: %sn", message);
- if (opt_debug_stderr && debug_log != stderr)
- fprintf(stderr, "FATAL: %sn", message);
- fprintf(debug_log, "Squid Cache (Version %s): Terminated abnormally.n",
- version_string);
- fflush(debug_log);
- PrintRusage();
- dumpMallocStats();
- }
- /* fatal */
- void
- fatal(const char *message)
- {
- releaseServerSockets();
- /* check for store_rebuilding flag because fatal() is often
- * used in early initialization phases, long before we ever
- * get to the store log. */
- if (!store_rebuilding)
- storeDirWriteCleanLogs(0);
- fatal_common(message);
- exit(shutting_down ? 0 : 1);
- }
- /* printf-style interface for fatal */
- #if STDC_HEADERS
- void
- fatalf(const char *fmt,...)
- {
- va_list args;
- va_start(args, fmt);
- #else
- void
- fatalf(va_alist)
- va_dcl
- {
- va_list args;
- const char *fmt = NULL;
- va_start(args);
- fmt = va_arg(args, char *);
- #endif
- fatalvf(fmt, args);
- va_end(args);
- }
- /* used by fatalf */
- static void
- fatalvf(const char *fmt, va_list args)
- {
- static char fatal_str[BUFSIZ];
- vsnprintf(fatal_str, sizeof(fatal_str), fmt, args);
- fatal(fatal_str);
- }
- /* fatal with dumping core */
- void
- fatal_dump(const char *message)
- {
- releaseServerSockets();
- if (message)
- fatal_common(message);
- if (opt_catch_signals)
- storeDirWriteCleanLogs(0);
- abort();
- }
- void
- debug_trap(const char *message)
- {
- if (!opt_catch_signals)
- fatal_dump(message);
- _db_print("WARNING: %sn", message);
- }
- void
- sig_child(int sig)
- {
- #ifdef _SQUID_NEXT_
- union wait status;
- #else
- int status;
- #endif
- pid_t pid;
- do {
- #ifdef _SQUID_NEXT_
- pid = wait3(&status, WNOHANG, NULL);
- #else
- pid = waitpid(-1, &status, WNOHANG);
- #endif
- /* no debug() here; bad things happen if the signal is delivered during _db_print() */
- #if HAVE_SIGACTION
- } while (pid > 0);
- #else
- } while (pid > 0 || (pid < 0 && errno == EINTR));
- signal(sig, sig_child);
- #endif
- }
- const char *
- getMyHostname(void)
- {
- LOCAL_ARRAY(char, host, SQUIDHOSTNAMELEN + 1);
- static int present = 0;
- const struct hostent *h = NULL;
- char *t = NULL;
- if ((t = Config.visibleHostname) != NULL)
- return t;
- /* Get the host name and store it in host to return */
- if (!present) {
- host[0] = ' ';
- if (gethostname(host, SQUIDHOSTNAMELEN) == -1) {
- debug(50, 1) ("getMyHostname: gethostname failed: %sn",
- xstrerror());
- return NULL;
- } else {
- if ((h = gethostbyname(host)) != NULL) {
- /* DNS lookup successful */
- /* use the official name from DNS lookup */
- strcpy(host, h->h_name);
- }
- present = 1;
- }
- }
- return host;
- }
- const char *
- uniqueHostname(void)
- {
- return Config.uniqueHostname ? Config.uniqueHostname : getMyHostname();
- }
- void
- safeunlink(const char *s, int quiet)
- {
- #if USE_ASYNC_IO
- aioUnlink(s,
- quiet ? NULL : safeunlinkComplete,
- quiet ? NULL : xstrdup(s));
- #else
- Counter.syscalls.disk.unlinks++;
- if (unlink(s) < 0 && !quiet)
- debug(50, 1) ("safeunlink: Couldn't delete %s: %sn", s, xstrerror());
- #endif
- }
- #if USE_ASYNC_IO
- static void
- safeunlinkComplete(int fd, void *data, int retcode, int errcode)
- {
- char *s = data;
- if (retcode < 0) {
- errno = errcode;
- debug(50, 1) ("safeunlink: Couldn't delete %s. %sn", s, xstrerror());
- errno = 0;
- }
- xfree(s);
- }
- #endif
- /* leave a privilegied section. (Give up any privilegies)
- * Routines that need privilegies can rap themselves in enter_suid()
- * and leave_suid()
- * To give upp all posibilites to gain privilegies use no_suid()
- */
- void
- leave_suid(void)
- {
- struct passwd *pwd = NULL;
- struct group *grp = NULL;
- debug(21, 3) ("leave_suid: PID %d calledn", getpid());
- if (geteuid() != 0)
- return;
- /* Started as a root, check suid option */
- if (Config.effectiveUser == NULL)
- return;
- if ((pwd = getpwnam(Config.effectiveUser)) == NULL)
- return;
- if (Config.effectiveGroup && (grp = getgrnam(Config.effectiveGroup))) {
- if (setgid(grp->gr_gid) < 0)
- debug(50, 1) ("leave_suid: setgid: %sn", xstrerror());
- } else {
- if (setgid(pwd->pw_gid) < 0)
- debug(50, 1) ("leave_suid: setgid: %sn", xstrerror());
- }
- debug(21, 3) ("leave_suid: PID %d giving up root, becoming '%s'n",
- getpid(), pwd->pw_name);
- #if HAVE_SETRESUID
- if (setresuid(pwd->pw_uid, pwd->pw_uid, 0) < 0)
- debug(50, 1) ("leave_suid: setresuid: %sn", xstrerror());
- #elif HAVE_SETEUID
- if (seteuid(pwd->pw_uid) < 0)
- debug(50, 1) ("leave_suid: seteuid: %sn", xstrerror());
- #else
- if (setuid(pwd->pw_uid) < 0)
- debug(50, 1) ("leave_suid: setuid: %sn", xstrerror());
- #endif
- }
- /* Enter a privilegied section */
- void
- enter_suid(void)
- {
- debug(21, 3) ("enter_suid: PID %d taking root privelegesn", getpid());
- #if HAVE_SETRESUID
- setresuid(-1, 0, -1);
- #else
- setuid(0);
- #endif
- }
- /* Give up the posibility to gain privilegies.
- * this should be used before starting a sub process
- */
- void
- no_suid(void)
- {
- uid_t uid;
- leave_suid();
- uid = geteuid();
- debug(21, 3) ("leave_suid: PID %d giving up root priveleges forevern", getpid());
- #if HAVE_SETRESUID
- if (setresuid(uid, uid, uid) < 0)
- debug(50, 1) ("no_suid: setresuid: %sn", xstrerror());
- #else
- setuid(0);
- if (setuid(uid) < 0)
- debug(50, 1) ("no_suid: setuid: %sn", xstrerror());
- #endif
- }
- void
- writePidFile(void)
- {
- int fd;
- const char *f = NULL;
- mode_t old_umask;
- char buf[32];
- if ((f = Config.pidFilename) == NULL)
- return;
- if (!strcmp(Config.pidFilename, "none"))
- return;
- enter_suid();
- old_umask = umask(022);
- fd = file_open(f, O_WRONLY | O_CREAT | O_TRUNC, NULL, NULL, NULL);
- umask(old_umask);
- leave_suid();
- if (fd < 0) {
- debug(50, 0) ("%s: %sn", f, xstrerror());
- debug_trap("Could not write pid file");
- return;
- }
- snprintf(buf, 32, "%dn", (int) getpid());
- write(fd, buf, strlen(buf));
- file_close(fd);
- }
- pid_t
- readPidFile(void)
- {
- FILE *pid_fp = NULL;
- const char *f = Config.pidFilename;
- pid_t pid = -1;
- int i;
- if (f == NULL || !strcmp(Config.pidFilename, "none")) {
- fprintf(stderr, "%s: ERROR: No pid file name definedn", appname);
- exit(1);
- }
- pid_fp = fopen(f, "r");
- if (pid_fp != NULL) {
- pid = 0;
- if (fscanf(pid_fp, "%d", &i) == 1)
- pid = (pid_t) i;
- fclose(pid_fp);
- } else {
- if (errno != ENOENT) {
- fprintf(stderr, "%s: ERROR: Could not read pid filen", appname);
- fprintf(stderr, "t%s: %sn", f, xstrerror());
- exit(1);
- }
- }
- return pid;
- }
- void
- setMaxFD(void)
- {
- #if HAVE_SETRLIMIT
- /* try to use as many file descriptors as possible */
- /* System V uses RLIMIT_NOFILE and BSD uses RLIMIT_OFILE */
- struct rlimit rl;
- #if defined(RLIMIT_NOFILE)
- if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
- debug(50, 0) ("setrlimit: RLIMIT_NOFILE: %sn", xstrerror());
- } else {
- rl.rlim_cur = Squid_MaxFD;
- if (rl.rlim_cur > rl.rlim_max)
- Squid_MaxFD = rl.rlim_cur = rl.rlim_max;
- if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
- snprintf(tmp_error_buf, ERROR_BUF_SZ,
- "setrlimit: RLIMIT_NOFILE: %s", xstrerror());
- fatal_dump(tmp_error_buf);
- }
- }
- #elif defined(RLIMIT_OFILE)
- if (getrlimit(RLIMIT_OFILE, &rl) < 0) {
- debug(50, 0) ("setrlimit: RLIMIT_NOFILE: %sn", xstrerror());
- } else {
- rl.rlim_cur = Squid_MaxFD;
- if (rl.rlim_cur > rl.rlim_max)
- Squid_MaxFD = rl.rlim_cur = rl.rlim_max;
- if (setrlimit(RLIMIT_OFILE, &rl) < 0) {
- snprintf(tmp_error_buf, ERROR_BUF_SZ,
- "setrlimit: RLIMIT_OFILE: %s", xstrerror());
- fatal_dump(tmp_error_buf);
- }
- }
- #endif
- #else /* HAVE_SETRLIMIT */
- debug(21, 1) ("setMaxFD: Cannot increase: setrlimit() not supported on this systemn");
- #endif /* HAVE_SETRLIMIT */
- #if HAVE_SETRLIMIT && defined(RLIMIT_DATA)
- if (getrlimit(RLIMIT_DATA, &rl) < 0) {
- debug(50, 0) ("getrlimit: RLIMIT_DATA: %sn", xstrerror());
- } else if (rl.rlim_max > rl.rlim_cur) {
- rl.rlim_cur = rl.rlim_max; /* set it to the max */
- if (setrlimit(RLIMIT_DATA, &rl) < 0) {
- snprintf(tmp_error_buf, ERROR_BUF_SZ,
- "setrlimit: RLIMIT_DATA: %s", xstrerror());
- fatal_dump(tmp_error_buf);
- }
- }
- #endif /* RLIMIT_DATA */
- #if HAVE_SETRLIMIT && defined(RLIMIT_VMEM)
- if (getrlimit(RLIMIT_VMEM, &rl) < 0) {
- debug(50, 0) ("getrlimit: RLIMIT_VMEM: %sn", xstrerror());
- } else if (rl.rlim_max > rl.rlim_cur) {
- rl.rlim_cur = rl.rlim_max; /* set it to the max */
- if (setrlimit(RLIMIT_VMEM, &rl) < 0) {
- snprintf(tmp_error_buf, ERROR_BUF_SZ,
- "setrlimit: RLIMIT_VMEM: %s", xstrerror());
- fatal_dump(tmp_error_buf);
- }
- }
- #endif /* RLIMIT_VMEM */
- }
- time_t
- getCurrentTime(void)
- {
- #if GETTIMEOFDAY_NO_TZP
- gettimeofday(¤t_time);
- #else
- gettimeofday(¤t_time, NULL);
- #endif
- current_dtime = (double) current_time.tv_sec +
- (double) current_time.tv_usec / 1000000.0;
- return squid_curtime = current_time.tv_sec;
- }
- int
- percent(int a, int b)
- {
- return b ? ((int) (100.0 * a / b + 0.5)) : 0;
- }
- double
- dpercent(double a, double b)
- {
- return b ? (100.0 * a / b) : 0.0;
- }
- void
- squid_signal(int sig, SIGHDLR * func, int flags)
- {
- #if HAVE_SIGACTION
- struct sigaction sa;
- sa.sa_handler = func;
- sa.sa_flags = flags;
- sigemptyset(&sa.sa_mask);
- if (sigaction(sig, &sa, NULL) < 0)
- debug(50, 0) ("sigaction: sig=%d func=%p: %sn", sig, func, xstrerror());
- #else
- signal(sig, func);
- #endif
- }
- struct in_addr
- inaddrFromHostent(const struct hostent *hp)
- {
- struct in_addr s;
- xmemcpy(&s.s_addr, hp->h_addr, sizeof(s.s_addr));
- return s;
- }
- double
- doubleAverage(double cur, double new, int N, int max)
- {
- if (N > max)
- N = max;
- return (cur * (N - 1.0) + new) / N;
- }
- int
- intAverage(int cur, int new, int n, int max)
- {
- if (n > max)
- n = max;
- return (cur * (n - 1) + new) / n;
- }
- void
- logsFlush(void)
- {
- if (debug_log)
- fflush(debug_log);
- if (cache_useragent_log)
- fflush(cache_useragent_log);
- }
- char *
- checkNullString(char *p)
- {
- return p ? p : "(NULL)";
- }
- void
- dlinkAdd(void *data, dlink_node * m, dlink_list * list)
- {
- m->data = data;
- m->prev = NULL;
- m->next = list->head;
- if (list->head)
- list->head->prev = m;
- list->head = m;
- if (list->tail == NULL)
- list->tail = m;
- }
- void
- dlinkAddTail(void *data, dlink_node * m, dlink_list * list)
- {
- m->data = data;
- m->next = NULL;
- m->prev = list->tail;
- if (list->tail)
- list->tail->next = m;
- list->tail = m;
- if (list->head == NULL)
- list->head = m;
- }
- void
- dlinkDelete(dlink_node * m, dlink_list * list)
- {
- if (m->next)
- m->next->prev = m->prev;
- if (m->prev)
- m->prev->next = m->next;
- if (m == list->head)
- list->head = m->next;
- if (m == list->tail)
- list->tail = m->prev;
- }
- void
- kb_incr(kb_t * k, size_t v)
- {
- k->bytes += v;
- k->kb += (k->bytes >> 10);
- k->bytes &= 0x3FF;
- }
- void
- gb_flush(gb_t * g)
- {
- g->gb += (g->bytes >> 30);
- g->bytes &= (1 << 30) - 1;
- }
- double
- gb_to_double(const gb_t * g)
- {
- return ((double) g->gb) * ((double) (1 << 30)) + ((double) g->bytes);
- }
- const char *
- gb_to_str(const gb_t * g)
- {
- /*
- * it is often convenient to call gb_to_str several times for _one_ printf
- */
- #define max_cc_calls 5
- typedef char GbBuf[32];
- static GbBuf bufs[max_cc_calls];
- static int call_id = 0;
- double value = gb_to_double(g);
- char *buf = bufs[call_id++];
- /* select format */
- if (value < 1e9)
- snprintf(buf, sizeof(GbBuf), "%.2f MB", value / 1e6);
- else if (value < 1e12)
- snprintf(buf, sizeof(GbBuf), "%.2f GB", value / 1e9);
- else
- snprintf(buf, sizeof(GbBuf), "%.2f TB", value / 1e12);
- return buf;
- }
- void
- debugObj(int section, int level, const char *label, void *obj, ObjPackMethod pm)
- {
- MemBuf mb;
- Packer p;
- assert(label && obj && pm);
- memBufDefInit(&mb);
- packerToMemInit(&p, &mb);
- (*pm) (obj, &p);
- debug(section, level) ("%s%s", label, mb.buf);
- packerClean(&p);
- memBufClean(&mb);
- }
- int
- stringHasWhitespace(const char *s)
- {
- return (strcspn(s, w_space) != strlen(s));
- }