1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
#include <stdint.h>
#include <unistd.h>

////////////////////////////////////////////////////////////////
//  Write bits given as strings to a buffer -- INCREMENTALLY  //
////////////////////////////////////////////////////////////////

typedef struct {
    uint8_t* buf;
    size_t pos_bytes;
    size_t pos_bit;
    size_t num_bytes;
} BitBuffer;

void print_byte(uint8_t byte) {
    for(int pos = 0; pos < 8; pos++) {
        int bit_value = (byte >> (8 - 1 - pos)) & 1;    // 001
        char ch = '0' + bit_value;
        fputc(ch, stderr);
    }
}

void print_bytes(uint8_t* buf, size_t buf_len) {
    for(int byte_idx = 0; byte_idx < buf_len; byte_idx++) {
        print_byte(buf[byte_idx]);
        fputc(byte_idx < buf_len - 1 ? ' ' : '\n', stderr);
    }
}

void set_bit(uint8_t* a_buf_byte, size_t* a_pos_bit, int bit_value) {
    assert(bit_value == 0 || bit_value == 1);
    if(bit_value == 1) {
        *a_buf_byte |= 1 << (8 - 1 - *a_pos_bit);
        // If we are writing to position 0, then 1 << (8 - 1 - *a_pos_bit) should be 10000000₂
        // If we are writing to position 1, then 1 << (8 - 1 - *a_pos_bit) should be 01000000₂
        // ...
        // If we are writing to position 7, then 1 << (8 - 1 - *a_pos_bit) should be 00000001₂
        //
        // Then, logical-or'ing that with the existing value of *a_buf_byte will set the righ bit.
    }

    // Increment the cursor (position within the byte).
    *a_pos_bit += 1;
}

void set_bits_from_string(BitBuffer* a_bitbuf, const char* s) {
    for(const char* curr = s; *curr != '\0'; curr++) {
        assert(*curr == '0' || *curr == '1' || *curr == ' ');
        if(*curr != ' ') {
            int bit_value = *curr - '0';
            assert(bit_value == 0 || bit_value == 1);
            set_bit(a_bitbuf->buf + a_bitbuf->pos_bytes, &a_bitbuf->pos_bit, bit_value);
            // &buf[*a_buf_byte] is the address of the *byte* where we will *start* writing.
        }

        if(a_bitbuf->pos_bit == 8) {
        // If we are rolling into a new byte in the buffer…
            a_bitbuf->pos_bytes += 1;  // Advance the byte position
            a_bitbuf->pos_bit    = 0;  // Reset the bit position to 0
        }
    }
}

int main(int argc, char* argv[]) {
    // Task is to write this string to a buffer (bytes).

    // INPUT
    fprintf(stderr, "Input:\n");
    const char* chunks[] = {"0100", "100", "00", "00", "110", "1011", "1110", "011", "00", "0101",
                            "100", "00", "00", "1111", "011", "110", "1011", "1110", "1010", "011",
                            "110" };
    size_t num_chunks = sizeof(chunks) / sizeof(*chunks);
    // ⚠ This only works if s was declared with «type» s[]; … i.e., as an array on the stack.
    fprintf(stderr, "num_chunks == %zd\n\n", num_chunks);

    // CREATE the bit string
    uint8_t buf[9] = {0};  // ⚠ Initialize all bytes to zero.
    BitBuffer bitbuf = { .buf = buf, .pos_bytes = 0, .pos_bit = 0, .num_bytes = sizeof(buf) / sizeof(*buf) };

    // WRITE to the bit string, one chunk at a time.
    for(int chunk_idx = 0; chunk_idx < num_chunks; chunk_idx++) {
        set_bits_from_string(&bitbuf, chunks[chunk_idx]);
    }

    // Print ACTUAL
    fprintf(stderr, "Actual:\n");
    print_bytes(bitbuf.buf, bitbuf.num_bytes); // 01001000  ←  this is correct
    fprintf(stderr, "\n");

    // Print EXPECTED (with same spacing)
    fprintf(stderr, "Expect:\n");
    fprintf(stderr, "01001000 00011010 11111001 10001011 00000011 11011110 10111110 10100111 10₀₀₀₀₀₀");
    fprintf(stderr, "\n");

    // Print the bit string to stdout, but ONLY if stdout is not a TTY (not a plain terminal.)
    // This lets us redirect to a file without making a mess of our terminal.
    if(!isatty(STDOUT_FILENO)) {
        fwrite(bitbuf.buf, sizeof(*bitbuf.buf), bitbuf.num_bytes, stdout); // print just those 9 bytes
        // fwrite(…) copies arbitary bytes from memory. ... and REMEMBER: "It's all just bytes."
    }

    return EXIT_SUCCESS;
}
/* vim: set tabstop=4 shiftwidth=4 fileencoding=utf-8 noexpandtab: */

© Copyright 2020 Alexander J. Quinn         This content is protected and may not be shared, uploaded, or distributed.