Login

Subversion Repositories NedoOS

Rev

Blame | Last modification | View Log | Download | RSS feed

/* asmfile.c - assembler file structure.

   This is free and unencumbered software released into the public domain.
   For more information, please refer to <http://unlicense.org>. */


#include "defs.h"

#include <stdbool.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "debug.h"
#include "l_list.h"
#include "asmfile.h"

void _asm_file_reset_pos (struct asm_file_t *self)
{
    self->pos = -1;             // invalid
    self->line = 0;             // invalid
    self->line_start = -1;      // invalid
    self->line_end = -1;        // invalid
}

void asm_file_clear (struct asm_file_t *self)
{
    if (!self)
        return; // Fail
    self->data = NULL;
    self->size = 0;
    _asm_file_reset_pos (self);
}

// Returns "false" on success.
bool asm_file_load (struct asm_file_t *self, const char *name)
{
    bool ok;
    FILE *f;
    long s;
    char *p;

    if (!self)
    {
        // Fail
        errno = EINVAL;
        return false;
    }

    ok = false;
    f = NULL;
    s = 0;
    p = NULL;

    _DBG_ ("File name = '%s'", name);

#if defined (_WIN32) || defined (_WIN64)
    f = fopen (name, "rb");
#else
    f = fopen (name, "r");
#endif
    if (!f)
    {
        // Fail
        _perror ("fopen");
        goto _local_exit;
    }

    errno = 0;

    fseek (f, 0, SEEK_END);
    if (errno)
    {
        // Fail
        _perror ("fseek");
        goto _local_exit;
    }

    s = ftell (f);
    if (s < 0)
    {
        // Fail
        _perror ("ftell");
        goto _local_exit;
    }

    fseek (f, 0, SEEK_SET);
    if (errno)
    {
        // Fail
        _perror ("fseek");
        goto _local_exit;
    }

    _DBG_ ("File size = %li", (long) s);

    if (s)
    {
        p = malloc (s);
        if (!p)
        {
            // Fail
            _perror ("malloc");
            goto _local_exit;
        }
        errno = 0;
        if (fread (p, s, 1, f) != 1)
        {
            // Fail
            _perror ("fread");
            goto _local_exit;
        }
        // Success
        ok = true;
    }

_local_exit:
    if (f)
        fclose (f);
    if (!ok)
    {
        if (p)
            free (p);
        p = NULL;
        s = 0;
    }
    self->data = p;
    self->size = s;
    _asm_file_reset_pos (self);
    return ok;
}

bool asm_file_eof (struct asm_file_t *self)
{
    if (!self)
    {
        // Fail
        errno = EINVAL;
        return true;
    }
    if (self->size)
    {
        // Success
        if (0         <= self->pos
        &&  self->pos <  self->size)
            return false;
        else
            return true;
    }
    else
    {
        // Fail
        errno = ENOENT;
        return true;
    }
}

bool asm_file_eol (struct asm_file_t *self)
{
    if (!self)
    {
        // Fail
        errno = EINVAL;
        return true;
    }
    if (!asm_file_eof (self))
    {
        // Success
        if (self->line_start <= self->pos
        &&  self->pos        <= self->line_end)
            return false;
        else
            return true;
    }
    else
        return true;    // Fail
}

const char *_find_line_end (const char *s, unsigned len)
{
    if (!s)
        return (char *) NULL;   // Fail
    while (len)
    {
        if (len && (*s == '\r' || *s == '\n'))
            break;
        s++;
        len--;
    }
    return s;   // Success
}

const char *_skip_line_end (const char *s, unsigned len)
{
    if (!s)
        return (char *) NULL;   // Fail
    if (len)
    {
        if (*s == '\r')
        {
            // found
            len--;
            s++;
            if (len && *s == '\n')
                s++;
        }
        else if (*s == '\n')
        {
            // found
            len--;
            s++;
            if (len && *s == '\r')
                s++;
        }
        else
            s += len;   // not found, skip to the end
    }
    return s;
}

bool asm_file_next_line (struct asm_file_t *self, const char **s, unsigned *len)
{
    const char *startp, *endp;
    unsigned sz;

    if (!self || !s || !len)
    {
        // Fail
        errno = EINVAL;
        return false;
    }
    if (self->pos < 0 || (self->pos >= 0 && !asm_file_eof (self)))
    {
        if (self->pos < 0)
        {
            // Start reading
            sz = self->size;
            startp = self->data;
        }
        else
        {
            // Continue reading
            sz = self->size - self->line_end;
            startp = _skip_line_end (self->data + self->line_end, sz);
            self->pos = startp - self->data;
            sz = self->size - self->pos;
        }
        endp = _find_line_end (startp, sz);
        self->pos = startp - self->data;
        if (!asm_file_eof (self))
        {
            // Success
            self->line++;
            self->line_start = self->pos;
            self->line_end = endp - self->data;
            *s = self->data + self->line_start;
            *len = self->line_end - self->line_start;
            return true;
        }
    }
    // Fail
    self->line_start = self->pos;
    self->line_end = self->pos;
    *s = (char *) NULL;
    *len = 0;
    return false;
}

void asm_file_free (struct asm_file_t *self)
{
    if (!self)
    {
        // Fail
        errno = EINVAL;
        return;
    }
    if (self->data)
        free (self->data);
    asm_file_clear (self);
}