cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_syspower.c (11469B)


      1/*
      2  Simple DirectMedia Layer
      3  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
      4
      5  This software is provided 'as-is', without any express or implied
      6  warranty.  In no event will the authors be held liable for any damages
      7  arising from the use of this software.
      8
      9  Permission is granted to anyone to use this software for any purpose,
     10  including commercial applications, and to alter it and redistribute it
     11  freely, subject to the following restrictions:
     12
     13  1. The origin of this software must not be misrepresented; you must not
     14     claim that you wrote the original software. If you use this software
     15     in a product, an acknowledgment in the product documentation would be
     16     appreciated but is not required.
     17  2. Altered source versions must be plainly marked as such, and must not be
     18     misrepresented as being the original software.
     19  3. This notice may not be removed or altered from any source distribution.
     20*/
     21#include "../../SDL_internal.h"
     22
     23#ifndef SDL_POWER_DISABLED
     24#if SDL_POWER_LINUX
     25
     26#include <stdio.h>
     27#include <unistd.h>
     28
     29#include <sys/types.h>
     30#include <sys/stat.h>
     31#include <dirent.h>
     32#include <fcntl.h>
     33
     34#include "SDL_power.h"
     35
     36static const char *proc_apm_path = "/proc/apm";
     37static const char *proc_acpi_battery_path = "/proc/acpi/battery";
     38static const char *proc_acpi_ac_adapter_path = "/proc/acpi/ac_adapter";
     39
     40static int open_acpi_file(const char *base, const char *node, const char *key)
     41{
     42    const size_t pathlen = strlen(base) + strlen(node) + strlen(key) + 3;
     43    char *path = (char *) alloca(pathlen);
     44    if (path == NULL) {
     45        return -1;  /* oh well. */
     46    }
     47
     48    snprintf(path, pathlen, "%s/%s/%s", base, node, key);
     49    return open(path, O_RDONLY);
     50}
     51
     52
     53static SDL_bool
     54load_acpi_file(const char *base, const char *node, const char *key,
     55               char *buf, size_t buflen)
     56{
     57    ssize_t br = 0;
     58    const int fd = open_acpi_file(base, node, key);
     59    if (fd == -1) {
     60        return SDL_FALSE;
     61    }
     62    br = read(fd, buf, buflen-1);
     63    close(fd);
     64    if (br < 0) {
     65        return SDL_FALSE;
     66    }
     67    buf[br] = '\0';             /* null-terminate the string. */
     68    return SDL_TRUE;
     69}
     70
     71
     72static SDL_bool
     73make_proc_acpi_key_val(char **_ptr, char **_key, char **_val)
     74{
     75    char *ptr = *_ptr;
     76
     77    while (*ptr == ' ') {
     78        ptr++;  /* skip whitespace. */
     79    }
     80
     81    if (*ptr == '\0') {
     82        return SDL_FALSE;  /* EOF. */
     83    }
     84
     85    *_key = ptr;
     86
     87    while ((*ptr != ':') && (*ptr != '\0')) {
     88        ptr++;
     89    }
     90
     91    if (*ptr == '\0') {
     92        return SDL_FALSE;  /* (unexpected) EOF. */
     93    }
     94
     95    *(ptr++) = '\0';  /* terminate the key. */
     96
     97    while ((*ptr == ' ') && (*ptr != '\0')) {
     98        ptr++;  /* skip whitespace. */
     99    }
    100
    101    if (*ptr == '\0') {
    102        return SDL_FALSE;  /* (unexpected) EOF. */
    103    }
    104
    105    *_val = ptr;
    106
    107    while ((*ptr != '\n') && (*ptr != '\0')) {
    108        ptr++;
    109    }
    110
    111    if (*ptr != '\0') {
    112        *(ptr++) = '\0';  /* terminate the value. */
    113    }
    114
    115    *_ptr = ptr;  /* store for next time. */
    116    return SDL_TRUE;
    117}
    118
    119static void
    120check_proc_acpi_battery(const char * node, SDL_bool * have_battery,
    121                        SDL_bool * charging, int *seconds, int *percent)
    122{
    123    const char *base = proc_acpi_battery_path;
    124    char info[1024];
    125    char state[1024];
    126    char *ptr = NULL;
    127    char *key = NULL;
    128    char *val = NULL;
    129    SDL_bool charge = SDL_FALSE;
    130    SDL_bool choose = SDL_FALSE;
    131    int maximum = -1;
    132    int remaining = -1;
    133    int secs = -1;
    134    int pct = -1;
    135
    136    if (!load_acpi_file(base, node, "state", state, sizeof (state))) {
    137        return;
    138    } else if (!load_acpi_file(base, node, "info", info, sizeof (info))) {
    139        return;
    140    }
    141
    142    ptr = &state[0];
    143    while (make_proc_acpi_key_val(&ptr, &key, &val)) {
    144        if (strcmp(key, "present") == 0) {
    145            if (strcmp(val, "yes") == 0) {
    146                *have_battery = SDL_TRUE;
    147            }
    148        } else if (strcmp(key, "charging state") == 0) {
    149            /* !!! FIXME: what exactly _does_ charging/discharging mean? */
    150            if (strcmp(val, "charging/discharging") == 0) {
    151                charge = SDL_TRUE;
    152            } else if (strcmp(val, "charging") == 0) {
    153                charge = SDL_TRUE;
    154            }
    155        } else if (strcmp(key, "remaining capacity") == 0) {
    156            char *endptr = NULL;
    157            const int cvt = (int) strtol(val, &endptr, 10);
    158            if (*endptr == ' ') {
    159                remaining = cvt;
    160            }
    161        }
    162    }
    163
    164    ptr = &info[0];
    165    while (make_proc_acpi_key_val(&ptr, &key, &val)) {
    166        if (strcmp(key, "design capacity") == 0) {
    167            char *endptr = NULL;
    168            const int cvt = (int) strtol(val, &endptr, 10);
    169            if (*endptr == ' ') {
    170                maximum = cvt;
    171            }
    172        }
    173    }
    174
    175    if ((maximum >= 0) && (remaining >= 0)) {
    176        pct = (int) ((((float) remaining) / ((float) maximum)) * 100.0f);
    177        if (pct < 0) {
    178            pct = 0;
    179        } else if (pct > 100) {
    180            pct = 100;
    181        }
    182    }
    183
    184    /* !!! FIXME: calculate (secs). */
    185
    186    /*
    187     * We pick the battery that claims to have the most minutes left.
    188     *  (failing a report of minutes, we'll take the highest percent.)
    189     */
    190    if ((secs < 0) && (*seconds < 0)) {
    191        if ((pct < 0) && (*percent < 0)) {
    192            choose = SDL_TRUE;  /* at least we know there's a battery. */
    193        }
    194        if (pct > *percent) {
    195            choose = SDL_TRUE;
    196        }
    197    } else if (secs > *seconds) {
    198        choose = SDL_TRUE;
    199    }
    200
    201    if (choose) {
    202        *seconds = secs;
    203        *percent = pct;
    204        *charging = charge;
    205    }
    206}
    207
    208static void
    209check_proc_acpi_ac_adapter(const char * node, SDL_bool * have_ac)
    210{
    211    const char *base = proc_acpi_ac_adapter_path;
    212    char state[256];
    213    char *ptr = NULL;
    214    char *key = NULL;
    215    char *val = NULL;
    216
    217    if (!load_acpi_file(base, node, "state", state, sizeof (state))) {
    218        return;
    219    }
    220
    221    ptr = &state[0];
    222    while (make_proc_acpi_key_val(&ptr, &key, &val)) {
    223        if (strcmp(key, "state") == 0) {
    224            if (strcmp(val, "on-line") == 0) {
    225                *have_ac = SDL_TRUE;
    226            }
    227        }
    228    }
    229}
    230
    231
    232SDL_bool
    233SDL_GetPowerInfo_Linux_proc_acpi(SDL_PowerState * state,
    234                                 int *seconds, int *percent)
    235{
    236    struct dirent *dent = NULL;
    237    DIR *dirp = NULL;
    238    SDL_bool have_battery = SDL_FALSE;
    239    SDL_bool have_ac = SDL_FALSE;
    240    SDL_bool charging = SDL_FALSE;
    241
    242    *seconds = -1;
    243    *percent = -1;
    244    *state = SDL_POWERSTATE_UNKNOWN;
    245
    246    dirp = opendir(proc_acpi_battery_path);
    247    if (dirp == NULL) {
    248        return SDL_FALSE;  /* can't use this interface. */
    249    } else {
    250        while ((dent = readdir(dirp)) != NULL) {
    251            const char *node = dent->d_name;
    252            check_proc_acpi_battery(node, &have_battery, &charging,
    253                                    seconds, percent);
    254        }
    255        closedir(dirp);
    256    }
    257
    258    dirp = opendir(proc_acpi_ac_adapter_path);
    259    if (dirp == NULL) {
    260        return SDL_FALSE;  /* can't use this interface. */
    261    } else {
    262        while ((dent = readdir(dirp)) != NULL) {
    263            const char *node = dent->d_name;
    264            check_proc_acpi_ac_adapter(node, &have_ac);
    265        }
    266        closedir(dirp);
    267    }
    268
    269    if (!have_battery) {
    270        *state = SDL_POWERSTATE_NO_BATTERY;
    271    } else if (charging) {
    272        *state = SDL_POWERSTATE_CHARGING;
    273    } else if (have_ac) {
    274        *state = SDL_POWERSTATE_CHARGED;
    275    } else {
    276        *state = SDL_POWERSTATE_ON_BATTERY;
    277    }
    278
    279    return SDL_TRUE;   /* definitive answer. */
    280}
    281
    282
    283static SDL_bool
    284next_string(char **_ptr, char **_str)
    285{
    286    char *ptr = *_ptr;
    287    char *str = *_str;
    288
    289    while (*ptr == ' ') {       /* skip any spaces... */
    290        ptr++;
    291    }
    292
    293    if (*ptr == '\0') {
    294        return SDL_FALSE;
    295    }
    296
    297    str = ptr;
    298    while ((*ptr != ' ') && (*ptr != '\n') && (*ptr != '\0'))
    299        ptr++;
    300
    301    if (*ptr != '\0')
    302        *(ptr++) = '\0';
    303
    304    *_str = str;
    305    *_ptr = ptr;
    306    return SDL_TRUE;
    307}
    308
    309static SDL_bool
    310int_string(char *str, int *val)
    311{
    312    char *endptr = NULL;
    313    *val = (int) strtol(str, &endptr, 0);
    314    return ((*str != '\0') && (*endptr == '\0'));
    315}
    316
    317/* http://lxr.linux.no/linux+v2.6.29/drivers/char/apm-emulation.c */
    318SDL_bool
    319SDL_GetPowerInfo_Linux_proc_apm(SDL_PowerState * state,
    320                                int *seconds, int *percent)
    321{
    322    SDL_bool need_details = SDL_FALSE;
    323    int ac_status = 0;
    324    int battery_status = 0;
    325    int battery_flag = 0;
    326    int battery_percent = 0;
    327    int battery_time = 0;
    328    const int fd = open(proc_apm_path, O_RDONLY);
    329    char buf[128];
    330    char *ptr = &buf[0];
    331    char *str = NULL;
    332    ssize_t br;
    333
    334    if (fd == -1) {
    335        return SDL_FALSE;       /* can't use this interface. */
    336    }
    337
    338    br = read(fd, buf, sizeof (buf) - 1);
    339    close(fd);
    340
    341    if (br < 0) {
    342        return SDL_FALSE;
    343    }
    344
    345    buf[br] = '\0';             /* null-terminate the string. */
    346    if (!next_string(&ptr, &str)) {     /* driver version */
    347        return SDL_FALSE;
    348    }
    349    if (!next_string(&ptr, &str)) {     /* BIOS version */
    350        return SDL_FALSE;
    351    }
    352    if (!next_string(&ptr, &str)) {     /* APM flags */
    353        return SDL_FALSE;
    354    }
    355
    356    if (!next_string(&ptr, &str)) {     /* AC line status */
    357        return SDL_FALSE;
    358    } else if (!int_string(str, &ac_status)) {
    359        return SDL_FALSE;
    360    }
    361
    362    if (!next_string(&ptr, &str)) {     /* battery status */
    363        return SDL_FALSE;
    364    } else if (!int_string(str, &battery_status)) {
    365        return SDL_FALSE;
    366    }
    367    if (!next_string(&ptr, &str)) {     /* battery flag */
    368        return SDL_FALSE;
    369    } else if (!int_string(str, &battery_flag)) {
    370        return SDL_FALSE;
    371    }
    372    if (!next_string(&ptr, &str)) {     /* remaining battery life percent */
    373        return SDL_FALSE;
    374    }
    375    if (str[strlen(str) - 1] == '%') {
    376        str[strlen(str) - 1] = '\0';
    377    }
    378    if (!int_string(str, &battery_percent)) {
    379        return SDL_FALSE;
    380    }
    381
    382    if (!next_string(&ptr, &str)) {     /* remaining battery life time */
    383        return SDL_FALSE;
    384    } else if (!int_string(str, &battery_time)) {
    385        return SDL_FALSE;
    386    }
    387
    388    if (!next_string(&ptr, &str)) {     /* remaining battery life time units */
    389        return SDL_FALSE;
    390    } else if (strcmp(str, "min") == 0) {
    391        battery_time *= 60;
    392    }
    393
    394    if (battery_flag == 0xFF) { /* unknown state */
    395        *state = SDL_POWERSTATE_UNKNOWN;
    396    } else if (battery_flag & (1 << 7)) {       /* no battery */
    397        *state = SDL_POWERSTATE_NO_BATTERY;
    398    } else if (battery_flag & (1 << 3)) {       /* charging */
    399        *state = SDL_POWERSTATE_CHARGING;
    400        need_details = SDL_TRUE;
    401    } else if (ac_status == 1) {
    402        *state = SDL_POWERSTATE_CHARGED;        /* on AC, not charging. */
    403        need_details = SDL_TRUE;
    404    } else {
    405        *state = SDL_POWERSTATE_ON_BATTERY;
    406        need_details = SDL_TRUE;
    407    }
    408
    409    *percent = -1;
    410    *seconds = -1;
    411    if (need_details) {
    412        const int pct = battery_percent;
    413        const int secs = battery_time;
    414
    415        if (pct >= 0) {         /* -1 == unknown */
    416            *percent = (pct > 100) ? 100 : pct; /* clamp between 0%, 100% */
    417        }
    418        if (secs >= 0) {        /* -1 == unknown */
    419            *seconds = secs;
    420        }
    421    }
    422
    423    return SDL_TRUE;
    424}
    425
    426#endif /* SDL_POWER_LINUX */
    427#endif /* SDL_POWER_DISABLED */
    428
    429/* vi: set ts=4 sw=4 expandtab: */