HOME

This code opens a file and searchs for BUILD_NUMBER followed by spaces and integer. Then increments the number and saves the file.

It can be used for automated build.

#include "stream.h"

#include "osstream.h"
#include <string.h>

enum token {
    TK_NUMBER,
    TK_IDENTIFIER,
    TK_SPACES,
    TK_OTHER,

    TK_END
};


int utf8_encode(char* out, int utf)
{
    if (utf <= 0x7F) {
        // Plain ASCII
        out[0] = (char)utf;
        out[1] = 0;
        return 1;
    }
    else if (utf <= 0x07FF) {
        // 2-byte unicode
        out[0] = (char)(((utf >> 6) & 0x1F) | 0xC0);
        out[1] = (char)(((utf >> 0) & 0x3F) | 0x80);
        out[2] = 0;
        return 2;
    }
    else if (utf <= 0xFFFF) {
        // 3-byte unicode
        out[0] = (char)(((utf >> 12) & 0x0F) | 0xE0);
        out[1] = (char)(((utf >> 6) & 0x3F) | 0x80);
        out[2] = (char)(((utf >> 0) & 0x3F) | 0x80);
        out[3] = 0;
        return 3;
    }
    else if (utf <= 0x10FFFF) {
        // 4-byte unicode
        out[0] = (char)(((utf >> 18) & 0x07) | 0xF0);
        out[1] = (char)(((utf >> 12) & 0x3F) | 0x80);
        out[2] = (char)(((utf >> 6) & 0x3F) | 0x80);
        out[3] = (char)(((utf >> 0) & 0x3F) | 0x80);
        out[4] = 0;
        return 4;
    }
    else {
        // error - use replacement character
        out[0] = (char)0xEF;
        out[1] = (char)0xBF;
        out[2] = (char)0xBD;
        out[3] = 0;
        return 0;
    }
}

enum token read_token(struct stream* s, char* buffer)
{
    if (s->CurrentChar == (wchar_t)(-1))
    {
        return TK_END;
    }

    enum token tk = TK_OTHER;
    if (s->CurrentChar >= '0' && s->CurrentChar <= '9')
    {
        tk = TK_NUMBER;
        while (s->CurrentChar >= '0' && s->CurrentChar <= '9')
        {
            *buffer = (char)s->CurrentChar;
            buffer++;
            stream_match(s);
        }
    }
    else if (s->CurrentChar == ' ')
    {
        tk = TK_SPACES;
        while (s->CurrentChar == ' ')        
        {
            *buffer = (char)s->CurrentChar;
            buffer++;
            stream_match(s);
        }
    }
    else if ((s->CurrentChar >= 'a' && s->CurrentChar <= 'z') ||
             (s->CurrentChar >= 'A' && s->CurrentChar <= 'Z') ||
             s->CurrentChar == '_')
    {
        tk = TK_IDENTIFIER;
        while ((s->CurrentChar >= 'a' && s->CurrentChar <= 'z') ||
               (s->CurrentChar >= 'A' && s->CurrentChar <= 'Z') ||
               s->CurrentChar == '_') 
        {
            *buffer = (char)s->CurrentChar;
            buffer++;
            stream_match(s);
        }
    }
    else
    {
        int count = utf8_encode(buffer, s->CurrentChar);
        buffer += count;        
        stream_match(s);
    }

    *buffer = 0;
    return tk;
}

void increment_build(const char* input)
{
    struct stream s = { 0 };
    struct osstream os = { 0 };

    if (stream_fopen(&s, input))
    {
        stream_match(&s);

        char buffer[400];
        enum token tk = read_token(&s, buffer);
        if (tk != TK_END)
        {
            osstream_printf(&os, "%s", buffer);
        }
        while (tk != TK_END)
        {


            tk = read_token(&s, buffer);
            if (tk == TK_IDENTIFIER && strcmp(buffer, "BUILD_NUMBER") == 0)
            {
                osstream_printf(&os, "%s", buffer);
                tk = read_token(&s, buffer);

                osstream_printf(&os, "%s", buffer);

                tk = read_token(&s, buffer);
                int n = atoi(buffer);
                n++;
                osstream_printf(&os, "%d", n);
            }
            else if (tk != TK_END)
            {
                osstream_printf(&os, "%s", buffer);
            }
        }
    }

    stream_close(&s);

    FILE* f = fopen(input, "w");
    if (f != NULL)
    {
        fprintf(f, "%s", os.c_str);
        fclose(f);
    }
    osstream_close(&os);

}



#include <stdio.h>
#include <stdlib.h>
//#include <sys/types.h>
//#include <sys/stat.h>
#include <assert.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>
#include <stdbool.h>
#include <stddef.h>

struct stream
{
    const char* data; //utf8 encoded

    wchar_t CurrentChar;
    int CurrentLine;
    int CurrentCol;
    int CurrentBytePos;
    int NextBytePos;
};


#define STREAM_INIT {0}


wchar_t stream_match(struct stream* stream);


void stream_close(struct stream* stream);

void stream_attach(struct stream* stream, const char* text);
bool stream_set(struct stream* stream, const char* text);
bool stream_fopen(struct stream* stream, const char* path);
wchar_t stream_look_ahead(const struct stream* stream);
wchar_t stream_look_ahead_twice(const struct stream* stream, wchar_t* ch2);


#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <assert.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>

#include "stream.h"


#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(__WINDOWS__)
#define stat _stat
#define strdup _strdup
#endif


void stream_attach(struct stream* stream, const char* text)
{
    stream_close(stream);
    stream->data = text;
}

bool stream_set(struct stream* stream, const char* text)
{
    char* data = strdup(text);
    if (data)
    {
        stream_attach(stream, data);
    }
    return data != NULL;
}

bool stream_fopen(struct stream* stream, const char* path)
{
    bool result = false;
    struct stat info;
    int r = stat(
        path,
        &info);
    if (r == 0)
    {
        char* data = (char*)malloc(sizeof(char) * info.st_size + 1);
        if (data != NULL)
        {
            FILE* file = fopen(path, "r");
            if (file != NULL)
            {
                //SKIP BOM
                if (info.st_size >= 3)
                {
                    fread(data, 1, 3, file);
                    if (data[0] == (char)0xEF &&
                        data[1] == (char)0xBB &&
                        data[2] == (char)0xBF)
                    {
                        size_t n = fread(data, 1, info.st_size - 3, file);
                        data[n] = 0;
                    }
                    else
                    {
                        size_t n = fread(data + 3, 1, info.st_size - 3, file);
                        data[3 + n] = 0;
                    }
                }
                else
                {
                    size_t n = fread(data, 1, info.st_size, file);
                    data[n] = 0;
                }

                fclose(file);
                result = true;
                stream_attach(stream, data);
            }
        }
    }
    return result;
}

static wchar_t ReadNextChar(const char* data, int currentPos, int* bytes)
{
    //https://www.ietf.org/rfc/rfc3629.txt
    //https://www.fileformat.info/info/unicode/utf8.htm

    int pos = currentPos;

    unsigned u = EOF;

    if (data != NULL)
    {
        int c = data[pos];

        if (c == '\0' /*EOF*/)
        {
            u = EOF;
        }
        else if ((c & 0x80) == 0)
        {
            pos++;
            u = c;
        }
        else if ((c & 0xC0) == 0x80)
        {
            u = EOF;
        }
        else
        {
            pos++;
            u = (c & 0xE0) == 0xC0 ? (c & 0x1F)
                : (c & 0xF0) == 0xE0 ? (c & 0x0F)
                : (c & 0xF8) == 0xF0 ? (c & 0x07)
                : 0;

            if (u == 0)
            {
                u = EOF;
            }
            else
            {
                for (;;)
                {
                    c = data[pos];
                    pos++;

                    if (c == EOF)
                    {
                        break;
                    }
                    else if ((c & 0xC0) == 0x80)
                    {
                        u = (u << 6) | (c & 0x3F);
                    }
                    else
                    {
                        pos--;
                        break;
                    }
                }
            }
        }
    }

    *bytes = pos - currentPos;
    return u;
}

wchar_t stream_look_ahead(const struct stream* stream)
{
    int bytes = 0;
    wchar_t ch =
        ReadNextChar(stream->data, stream->NextBytePos, &bytes);

    return ch;
}

wchar_t stream_look_ahead_twice(const struct stream* stream, wchar_t* ch2)
{
    *ch2 = WEOF;

    int bytes = 0;
    wchar_t ch =
        ReadNextChar(stream->data, stream->NextBytePos, &bytes);

    if (bytes > 0)
    {
        *ch2 = ReadNextChar(stream->data, stream->NextBytePos + bytes, &bytes);
    }

    return ch;
}

wchar_t stream_match(struct stream* stream)
{

    int bytes = 0;
    wchar_t ch =
        ReadNextChar(stream->data, stream->NextBytePos, &bytes);


    if (bytes > 0)
    {
        if (stream->CurrentLine == 0)
        {
            stream->CurrentLine = 1;
        }

        stream->CurrentBytePos = stream->NextBytePos;
        stream->NextBytePos += bytes;
        stream->CurrentCol++;

        if (ch == '\n') //fopen on windows automatically removes \r
        {
            stream->CurrentLine++;
            stream->CurrentCol = 0;
        }
        stream->CurrentChar = ch;
    }
    else if (ch == (wchar_t)EOF)
    {
        if (stream->CurrentBytePos != stream->NextBytePos)
        {
            stream->CurrentBytePos = stream->NextBytePos;
            stream->CurrentCol++;
            stream->CurrentChar = ch;
        }
    }

    return ch;
}

void stream_close(struct stream* stream)
{
    free((void*)stream->data);
    stream->CurrentCol = 0;
    stream->CurrentLine = 0;
    stream->NextBytePos = 0;
    stream->CurrentBytePos = 0;
    stream->CurrentChar = 0;
}

#include <errno.h>
#include <varargs.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>

struct osstream
{
    char* c_str;
    int size;
    int capacity;
};


int osstream_putc(int ch, struct osstream* sb);

int osstream_close(struct osstream* stream);


int osstream_vafprintf(struct osstream* stream, const char* fmt, va_list args);

int osstream_printf(struct osstream* stream, const char* fmt, ...);

#include "osstream.h"


int osstream_putc(int ch, struct osstream* sb)
{
    if (sb->size + 1 > sb->capacity)
    {
        int n = sb->capacity + sb->capacity / 2;
        if (n < sb->size + 1)
        {
            n = sb->size + 1;
        }

        char* pnew = sb->c_str;
        pnew = (char*)realloc(pnew, (n + 1) * sizeof(char));
        if (pnew)
        {
            sb->c_str = pnew;
            sb->capacity = n;
        }
        else
        {
            errno = ENOMEM;
            ch = EOF;
        }
    }

    if (ch != EOF)
    {
        sb->c_str[sb->size] = ch;
        sb->c_str[sb->size + 1] = 0;
        sb->size++;
    }

    return ch;
}

int osstream_close(struct osstream* stream)
{
    free(stream->c_str);
    return 0;
}


int osstream_vafprintf(struct osstream* stream, const char* fmt, va_list args)
{
    int size = 0;
    va_list tmpa;

    va_copy(tmpa, args);

    size = vsnprintf(stream->c_str + stream->size, stream->capacity - stream->size, fmt, tmpa);

    va_end(tmpa);

    if (size < 0)
    {
        return -1;
    }

    if (stream->size + size > stream->capacity)
    {
        char* pnew = stream->c_str;
        pnew = (char*)realloc(pnew, (stream->size + size + 1) * sizeof(char));
        if (pnew)
        {
            stream->c_str = pnew;
            stream->capacity = stream->size + size;
        }
        else
        {
            errno = ENOMEM;
            size = -1;
        }
    }

    size = vsprintf(stream->c_str + stream->size, fmt, args);
    if (size > 0)
    {
        stream->size += size;
    }
    return size;
}

int osstream_printf(struct osstream* stream, const char* fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    int size = osstream_vafprintf(stream, fmt, args);
    va_end(args);
    return size;
}