root/bin/cpdup/misc.c
/*
 * MISC.C
 */

#include "cpdup.h"

void
logstd(const char *ctl, ...)
{
    va_list va;

    va_start(va, ctl);
    vprintf(ctl, va);
    va_end(va);
}

void
logerr(const char *ctl, ...)
{
    va_list va;

    va_start(va, ctl);
    vfprintf(stderr, ctl, va);
    va_end(va);
}

char *
mprintf(const char *ctl, ...)
{
    char *ptr;
    va_list va;

    ptr = NULL;

    va_start(va, ctl);
    if (vasprintf(&ptr, ctl, va) < 0)
        fatal("malloc failed");
    va_end(va);
    assert(ptr != NULL);
    return(ptr);
}

char *
fextract(FILE *fi, int n, int *pc, int skip)
{
    int i;
    int c;
    int imax;
    char *s;

    i = 0;
    c = *pc;
    imax = (n < 0) ? 64 : n + 1;

    s = malloc(imax);
    if (s == NULL)
        fatal("out of memory");

    while (c != EOF) {
        if (n == 0 || (n < 0 && (c == ' ' || c == '\n')))
            break;

        s[i++] = c;
        if (i == imax) {
            imax += 64;
            s = realloc(s, imax);
            if (s == NULL)
                fatal("out of memory");
        }
        if (n > 0)
            --n;
        c = getc(fi);
    }
    if (c == skip && skip != EOF)
        c = getc(fi);
    *pc = c;
    s[i] = 0;
    return(s);
}

int16_t
hc_bswap16(int16_t var)
{
    return ((var & 0xff) << 8 | (var >> 8 & 0xff));
}

int32_t
hc_bswap32(int32_t var)
{
    return ((var & 0xff) << 24 | (var & 0xff00) << 8
            | (var >> 8 & 0xff00) | (var >> 24 & 0xff));
}

int64_t
hc_bswap64(int64_t var)
{
    return (hc_bswap32(var >> 32 & 0xffffffff)
            | (int64_t) hc_bswap32(var & 0xffffffff) << 32);
}

#ifdef DEBUG_MALLOC

#undef malloc
#undef free

struct malloc_info {
        struct malloc_info *next;
        struct malloc_info *prev;
        const char *file;
        int magic;
        int line;
};

struct malloc_info DummyInfo = { &DummyInfo, &DummyInfo, NULL, 0, 0 };
struct malloc_info *InfoList = &DummyInfo;

void *
debug_malloc(size_t bytes, const char *file, int line)
{
        struct malloc_info *info = malloc(sizeof(*info) + bytes);

        info->magic = 0x5513A4C2;
        info->file = file;
        info->line = line;

        info->next = InfoList;
        info->prev = InfoList->prev;
        info->next->prev = info;
        info->prev->next = info;
        return(info + 1);
}

void
debug_free(void *ptr)
{
        struct malloc_info *info = (struct malloc_info *)ptr - 1;
        struct malloc_info *scan;
        static int report;

        for (scan = DummyInfo.next; scan != &DummyInfo; scan = scan->next) {
                if (info == scan) {
                        assert(info->magic == 0x5513A4C2);
                        info->magic = 0;
                        info->next->prev = info->prev;
                        info->prev->next = info->next;
                        free(info);
                        break;
                }
        }
        if (scan == &DummyInfo)
                free(ptr);

        if ((++report & 65535) == 0) {
                printf("--- report\n");
                for (scan = DummyInfo.next; scan != &DummyInfo; scan = scan->next) {
                        printf("%-15s %d\n", scan->file, scan->line);
                }
        }
}

#endif

void
fatal(const char *ctl, ...)
{
    va_list va;

    if (ctl == NULL) {
        puts("usage: cpdup [options] src dest");
        puts("\n"
             "options:\n"
             "    -C          request compressed ssh link if remote operation\n"
             "    -d          print directories being traversed\n"
             "    -f          force update even if files look the same\n"
             "    -F<ssh_opt> add <ssh_opt> to options passed to ssh\n"
             "    -h          show this help\n"
             "    -H path     hardlink from path to target instead of copying\n"
             "    -I          display performance summary\n"
             "    -i0         do NOT confirm when removing something\n"
             "    -j0         do not try to recreate CHR or BLK devices\n"
             "    -l          force line-buffered stdout/stderr"
        );
#ifndef NOMD5
        puts("    -m          maintain/generate MD5 checkfile on source,\n"
             "                and compare with (optional) destination,\n"
             "                copying if the compare fails\n"
             "    -M file     -m+specify MD5 checkfile, else .MD5_CHECKSUMS\n"
             "                copy if md5 check fails"
        );
#endif
        puts("    -n          do not make any real changes to the target\n"
             "    -o          do not remove any files, just overwrite/add\n"
             "    -q          quiet operation\n"
             "    -R          read-only slave mode for ssh remotes\n"
             "                source to target, if source matches path.\n"
             "    -S          slave mode\n"
             "    -s0         disable safeties - allow files to overwrite directories\n"
             "    -u          use unbuffered output for -v[vv]\n"
             "    -v[vv]      verbose level (-vv is typical)\n"
             "    -V          verify file contents even if they appear\n"
             "                to be the same.\n"
             "    -VV         same as -V but ignore mtime entirely\n"
             "    -x          use .cpignore as exclusion file\n"
             "    -X file     specify exclusion file (can match full source\n"
             "                path if the exclusion file is specified via\n"
             "                an absolute path.\n"
             "\n"
             "Version " VERSION " by " AUTHORS "\n"
        );
        exit(0);
    } else {
        va_start(va, ctl);
        vfprintf(stderr, ctl, va);
        va_end(va);
        putc('\n', stderr);
        exit(EXIT_FAILURE);
    }
}