HelenOS sources

root/uspace/app/sbi/src/input.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. input_new_file
  2. input_new_interactive
  3. input_new_string
  4. input_init_file
  5. input_init_interactive
  6. input_init_string
  7. input_get_line
  8. input_get_line_no

/*
 * Copyright (c) 2010 Jiri Svoboda
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 * - The name of the author may not be used to endorse or promote products
 *   derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/** @file Input module
 *
 * Reads source code. Currently input can be read from a file (standard
 * case), from a string literal (when parsing builtin code) or interactively
 * from the user.
 */

#include <stdio.h>
#include <stdlib.h>
#include "mytypes.h"
#include "os/os.h"
#include "strtab.h"

#include "input.h"

/** Size of input buffer. XXX This limits the maximum line length. */
#define INPUT_BUFFER_SIZE 256

static errno_t input_init_file(input_t *input, const char *fname);
static void input_init_interactive(input_t *input);
static void input_init_string(input_t *input, const char *str);

/** Create new input object for reading from file.
 *
 * @param input         Place to store pointer to new input object.
 * @param fname         Name of file to read from.
 *
 * @return              EOK on success, ENOMEM when allocation fails,
 *                      ENOENT when opening file fails.
 */
errno_t input_new_file(input_t **input, const char *fname)
{
        *input = malloc(sizeof(input_t));
        if (*input == NULL)
                return ENOMEM;

        return input_init_file(*input, fname);
}

/** Create new input object for reading from interactive input.
 *
 * @param input         Place to store pointer to new input object.
 * @return              EOK on success, ENOMEM when allocation fails.
 */
errno_t input_new_interactive(input_t **input)
{
        *input = malloc(sizeof(input_t));
        if (*input == NULL)
                return ENOMEM;

        input_init_interactive(*input);
        return EOK;
}

/** Create new input object for reading from string.
 *
 * @param input         Place to store pointer to new input object.
 * @param str           String literal from which to read input.
 * @return              EOK on success, ENOMEM when allocation fails.
 */
errno_t input_new_string(input_t **input, const char *str)
{
        *input = malloc(sizeof(input_t));
        if (*input == NULL)
                return ENOMEM;

        input_init_string(*input, str);
        return EOK;
}

/** Initialize input object for reading from file.
 *
 * @param input         Input object.
 * @param fname         Name of file to read from.
 *
 * @return              EOK on success, ENOENT when opening file fails.
 */
static errno_t input_init_file(input_t *input, const char *fname)
{
        FILE *f;

        f = fopen(fname, "rt");
        if (f == NULL)
                return ENOENT;

        input->buffer = malloc(INPUT_BUFFER_SIZE);
        if (input->buffer == NULL) {
                printf("Memory allocation failed.\n");
                exit(1);
        }

        input->name = os_str_dup(fname);
        input->str = NULL;
        input->line_no = 0;
        input->fin = f;
        return EOK;
}

/** Initialize input object for reading from interactive input.
 *
 * @param input         Input object.
 */
static void input_init_interactive(input_t *input)
{
        input->buffer = malloc(INPUT_BUFFER_SIZE);
        if (input->buffer == NULL) {
                printf("Memory allocation failed.\n");
                exit(1);
        }

        input->name = "<user-input>";
        input->str = NULL;
        input->line_no = 0;
        input->fin = NULL;
}

/** Initialize input object for reading from string.
 *
 * @param input         Input object.
 * @param str           String literal from which to read input.
 */
static void input_init_string(input_t *input, const char *str)
{
        input->buffer = malloc(INPUT_BUFFER_SIZE);
        if (input->buffer == NULL) {
                printf("Memory allocation failed.\n");
                exit(1);
        }

        input->name = "<builtin>";
        input->str = str;
        input->line_no = 0;
        input->fin = NULL;
}

/** Get next line of input.
 *
 * The pointer stored in @a line is owned by @a input and is valid until the
 * next call to input_get_line(). The caller is not to free it. The returned
 * line is terminated with '\n' if another line is coming (potentially empty).
 * An empty line ("") signals end of input.
 *
 * @param input         Input object.
 * @param line          Place to store pointer to next line.
 *
 * @return              EOK on success, EIO on failure.
 */
errno_t input_get_line(input_t *input, char **line)
{
        const char *prompt;
        const char *sp;
        char *dp;
        char *line_p;
        size_t cnt;

        if (input->fin != NULL) {
                /* Reading from file. */
                if (fgets(input->buffer, INPUT_BUFFER_SIZE, input->fin) == NULL)
                        input->buffer[0] = '\0';

                if (ferror(input->fin))
                        return EIO;

                *line = input->buffer;
        } else if (input->str != NULL) {
                /* Reading from a string constant. */

                /* Copy one line. */
                sp = input->str;
                dp = input->buffer;
                cnt = 0;
                while (*sp != '\n' && *sp != '\0' &&
                    cnt < INPUT_BUFFER_SIZE - 2) {
                        *dp++ = *sp++;
                }

                /* Advance to start of next line. */
                if (*sp == '\n')
                        *dp++ = *sp++;

                *dp = '\0';
                input->str = sp;
                *line = input->buffer;
        } else {
                /* Interactive mode */
                if (input->line_no == 0)
                        prompt = "sbi> ";
                else
                        prompt = "...  ";

                fflush(stdout);
                if (os_input_line(prompt, &line_p) != EOK)
                        return EIO;

                *line = line_p;
        }

        ++input->line_no;
        return EOK;
}

/** Get number of the last provided line of input.
 *
 * @param input         Input object.
 * @return              Line number of the last provided input line (counting
 *                      from 1 up).
 */
int input_get_line_no(input_t *input)
{
        return input->line_no;
}

/* [<][>][^][v][top][bottom][index][help] */
HelenOS homepage, sources at GitHub