<commit_before>/*
 * egctl - EnerGenie EM-PMS-LAN control utility
 *
 * Copyright (c) 2014 <NAME> <<EMAIL>>
 *
 * Published under the terms of the MIT License,
 * see the included COPYING file.
 */

#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>
#include <pwd.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

#define TASK_LEN            4
#define STATCRYP_LEN        4
#define CTRLCRYP_LEN        4
#define KEY_LEN             8

#define STATE_ON            0x11
#define STATE_ON_NO_VOLTAGE 0x12
#define STATE_OFF           0x22
#define STATE_OFF_VOLTAGE   0x21

#define STATE_INVALID       0xFF /* for internal use */

#define V21_STATE_ON        0x41
#define V21_STATE_OFF       0x82

#define SWITCH_ON           0x01
#define SWITCH_OFF          0x02
#define DONT_SWITCH         0x04

#define SOCKET_COUNT 4      /* AC power sockets, not network ones ;) */

#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))

typedef enum
{
    EG_PROTO_V20,
    EG_PROTO_V21
} Protocol;

typedef enum
{
    ACTION_ON,
    ACTION_OFF,
    ACTION_TOGGLE,
    ACTION_LEFT,
    ACTION_INVALID
} Action;

typedef struct
{
    Action socket[SOCKET_COUNT];
} Actions;

typedef struct
{
    uint8_t octets[KEY_LEN];
} Key;

typedef struct
{
    /* since the protocol is little-endian, low word comes first */
    uint16_t loword;
    uint16_t hiword;
} __attribute__((__packed__)) Res;

typedef struct
{
    struct sockaddr_in addr;
    Protocol           proto;
    Key                key;
} Config;

typedef struct
{
    uint8_t socket[SOCKET_COUNT];
} Status, Controls;

typedef struct
{
    uint8_t task[TASK_LEN];
    Key     key;
} Session;

const char *g_egtabs[] =
{
    NULL,           /* placeholder for ~/.egtab */
    "/etc/egtab"
};

void vfatal(const char *fmt, va_list ap)
{
    vfprintf(stderr, fmt, ap);
    fprintf(stderr, "\n");
    exit(EXIT_FAILURE);
}

void fatal(const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    vfatal(fmt, ap);
    va_end(ap);
}

void warn(const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    vfprintf(stderr, fmt, ap);
    fprintf(stderr, "\n");
    va_end(ap);
}

#ifdef DEBUG
void dbg4(const char *name, const uint8_t *buf)
{
    fprintf(stderr, "%8s: 0x%02X 0x%02X 0x%02X 0x%02X\n",
            name, buf[0], buf[1], buf[2], buf[3]);
}
#else
#define dbg4(n,b)
#endif

void xread(int fd, void *buf, size_t count)
{
    ssize_t ret = read(fd, buf, count);

    if (ret == (ssize_t)count) {
        return;
    } else if (ret == -1) {
        if (errno != EINTR)
            fatal("Unable to read from socket: %s", strerror(errno));
        else
            ret = 0;
    }

    xread(fd, (char *)buf + ret, count - ret);
}

void xwrite(int fd, const void *buf, size_t count)
{
    ssize_t ret = write(fd, buf, count);

    if (ret == (ssize_t)count) {
        return;
    } else if (ret == -1) {
        if (errno != EINTR)
            fatal("Unable to write to socket: %s", strerror(errno));
        else
            ret = 0;
    }

    xwrite(fd, (char *)buf + ret, count - ret);
}

char *get_personal_egtab_name(void)
{
    static char egtab[1024] = "/dev/null";
    struct passwd *pwd = getpwuid(getuid());

    if (pwd) {
        snprintf(egtab, sizeof(egtab), "%s/.egtab", pwd->pw_dir);
    } else {
        warn("Unable to determine user home directory");
    }

    return egtab;
}

char *consume_until_whitespace(char **str)
{
    char *tok = *str;

    if (tok) {
        /* strip leading whitespaces */
        tok += strspn(tok, " \t");

        if (*tok == '\0') { /* no tokens */
            *str = NULL;
            tok = NULL;
        } else {
            char *eot = tok + strcspn(tok, " \t");
            if (*eot == '\0') { /* last token */
                *str = NULL;<commit_msg>Respect HOME environment variable value<commit_after>/*
 * egctl - EnerGenie EM-PMS-LAN control utility
 *
 * Copyright (c) 2014 <NAME> <<EMAIL>>
 *
 * Published under the terms of the MIT License,
 * see the included COPYING file.
 */

#include <arpa/inet.h>
#include <errno.h>
#include <limits.h>
#include <netinet/in.h>
#include <pwd.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

#define TASK_LEN            4
#define STATCRYP_LEN        4
#define CTRLCRYP_LEN        4
#define KEY_LEN             8

#define STATE_ON            0x11
#define STATE_ON_NO_VOLTAGE 0x12
#define STATE_OFF           0x22
#define STATE_OFF_VOLTAGE   0x21

#define STATE_INVALID       0xFF /* for internal use */

#define V21_STATE_ON        0x41
#define V21_STATE_OFF       0x82

#define SWITCH_ON           0x01
#define SWITCH_OFF          0x02
#define DONT_SWITCH         0x04

#define SOCKET_COUNT 4      /* AC power sockets, not network ones ;) */

#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))

typedef enum
{
    EG_PROTO_V20,
    EG_PROTO_V21
} Protocol;

typedef enum
{
    ACTION_ON,
    ACTION_OFF,
    ACTION_TOGGLE,
    ACTION_LEFT,
    ACTION_INVALID
} Action;

typedef struct
{
    Action socket[SOCKET_COUNT];
} Actions;

typedef struct
{
    uint8_t octets[KEY_LEN];
} Key;

typedef struct
{
    /* since the protocol is little-endian, low word comes first */
    uint16_t loword;
    uint16_t hiword;
} __attribute__((__packed__)) Res;

typedef struct
{
    struct sockaddr_in addr;
    Protocol           proto;
    Key                key;
} Config;

typedef struct
{
    uint8_t socket[SOCKET_COUNT];
} Status, Controls;

typedef struct
{
    uint8_t task[TASK_LEN];
    Key     key;
} Session;

const char *g_egtabs[] =
{
    NULL,           /* placeholder for ~/.egtab */
    "/etc/egtab"
};

void vfatal(const char *fmt, va_list ap)
{
    vfprintf(stderr, fmt, ap);
    fprintf(stderr, "\n");
    exit(EXIT_FAILURE);
}

void fatal(const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    vfatal(fmt, ap);
    va_end(ap);
}

void warn(const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    vfprintf(stderr, fmt, ap);
    fprintf(stderr, "\n");
    va_end(ap);
}

#ifdef DEBUG
void dbg4(const char *name, const uint8_t *buf)
{
    fprintf(stderr, "%8s: 0x%02X 0x%02X 0x%02X 0x%02X\n",
            name, buf[0], buf[1], buf[2], buf[3]);
}
#else
#define dbg4(n,b)
#endif

void xread(int fd, void *buf, size_t count)
{
    ssize_t ret = read(fd, buf, count);

    if (ret == (ssize_t)count) {
        return;
    } else if (ret == -1) {
        if (errno != EINTR)
            fatal("Unable to read from socket: %s", strerror(errno));
        else
            ret = 0;
    }

    xread(fd, (char *)buf + ret, count - ret);
}

void xwrite(int fd, const void *buf, size_t count)
{
    ssize_t ret = write(fd, buf, count);

    if (ret == (ssize_t)count) {
        return;
    } else if (ret == -1) {
        if (errno != EINTR)
            fatal("Unable to write to socket: %s", strerror(errno));
        else
            ret = 0;
    }

    xwrite(fd, (char *)buf + ret, count - ret);
}

char *get_personal_egtab_name(void)
{
    static char egtab[PATH_MAX] = "/dev/null";
    char *home = getenv("HOME");

    if (!home) {
        struct passwd *pwd = getpwuid(getuid());
        if (pwd)
            home = pwd->pw_dir;
    }

    if (home) {
        snprintf(egtab, sizeof(egtab), "%s/.egtab", home);
    } else {
        warn("Unable to determine user home directory");
    }

    return egtab;
}

char *consume_until_whitespace(char **str)
{
    char *tok = *str;

    if (tok) {
        /* strip leading whitespaces */
        tok += strspn(tok, " \t");

        if (*tok == '\0') { /* no tokens */
            *str = NULL;
            tok = NULL;
        } else {
            char *eot = tok + strcspn(tok, " \t");
            if (*eot == '\0') { /* last token */
                *str = NULL;
{'fraction_non_alphanumeric': 0.1375, 'fraction_numerical': 0.02025, 'mean_word_length': 2.3561241610738257, 'pattern_counts': {'":': 0, '<': 36, '<?xml version=': 0, '>': 38, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4644085', 'n_tokens_mistral': 3078, 'n_tokens_neox': 2925, 'n_words': 774}