root/usr/src/cmd/make/lib/mksh/read.cc
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
 * Use is subject to license terms.
 */


/*
 *      read.c
 *
 *      This file contains the makefile reader.
 */

/*
 * Included files
 */
#include <mksh/misc.h>          /* retmem() */
#include <mksh/read.h>
#include <sys/uio.h>            /* read() */
#include <unistd.h>             /* close(), unlink(), read() */
#include <libintl.h>

#define STRING_LEN_TO_CONVERT   (8*1024)

/*
 *      get_next_block_fn(source)
 *
 *      Will get the next block of text to read either
 *      by popping one source bVSIZEOFlock of the stack of Sources
 *      or by reading some more from the makefile.
 *
 *      Return value:
 *                              The new source block to read from
 *
 *      Parameters:
 *              source          The old source block
 *
 *      Global variables used:
 *              file_being_read The name of the current file, error msg
 */
Boolean         make_state_locked;
Source
get_next_block_fn(Source source)
{
        off_t           to_read;
        int             length;
        size_t          num_wc_chars;
        char                    ch_save;
        char                    *ptr;

        if (source == NULL) {
                return NULL;
        }
        if ((source->fd < 0) ||
                ((source->bytes_left_in_file <= 0) &&
                        (source->inp_buf_ptr >= source->inp_buf_end))) {
                /* We can't read from the makefile, so pop the source block */
                if (source->fd > 2) {
                        (void) close(source->fd);
                        if (make_state_lockfile != NULL) {
                                (void) unlink(make_state_lockfile);
                                retmem_mb(make_state_lockfile);
                                make_state_lockfile = NULL;
                                make_state_locked = false;
                        }
                }
                if (source->string.free_after_use &&
                    (source->string.buffer.start != NULL)) {
                        retmem(source->string.buffer.start);
                        source->string.buffer.start = NULL;
                }
                if (source->inp_buf != NULL) {
                        retmem_mb(source->inp_buf);
                        source->inp_buf = NULL;
                }
                source = source->previous;
                if (source != NULL) {
                        source->error_converting = false;
                }
                return source;
        }
        if (source->bytes_left_in_file > 0) {
        /*
         * Read the whole makefile.
         * Hopefully the kernel managed to prefetch the stuff.
         */
                to_read = source->bytes_left_in_file;
                source->inp_buf_ptr = source->inp_buf = getmem(to_read + 1);
                source->inp_buf_end = source->inp_buf + to_read;
                length = read(source->fd, source->inp_buf, (unsigned int) to_read);
                if (length != to_read) {
                        WCSTOMBS(mbs_buffer, file_being_read);
                        if (length == 0) {
                                fatal_mksh(gettext("Error reading `%s': Premature EOF"),
                                      mbs_buffer);
                        } else {
                                fatal_mksh(gettext("Error reading `%s': %s"),
                                      mbs_buffer,
                                      errmsg(errno));
                        }
                }
                *source->inp_buf_end = nul_char;
                source->bytes_left_in_file = 0;
        }
        /*
         * Try to convert the next piece.
         */
        ptr = source->inp_buf_ptr + STRING_LEN_TO_CONVERT;
        if (ptr > source->inp_buf_end) {
                ptr = source->inp_buf_end;
        }
        for (num_wc_chars = 0; ptr > source->inp_buf_ptr; ptr--) {
                ch_save = *ptr;
                *ptr = nul_char;
                num_wc_chars = mbstowcs(source->string.text.end,
                                        source->inp_buf_ptr,
                                        STRING_LEN_TO_CONVERT);
                *ptr = ch_save;
                if (num_wc_chars != (size_t)-1) {
                        break;
                }
        }

        if ((int) num_wc_chars == (size_t)-1) {
                source->error_converting = true;
                return source;
        }

        source->error_converting = false;
        source->inp_buf_ptr = ptr;
        source->string.text.end += num_wc_chars;
        *source->string.text.end = 0;

        if (source->inp_buf_ptr >= source->inp_buf_end) {
                if (*(source->string.text.end - 1) != (int) newline_char) {
                        WCSTOMBS(mbs_buffer, file_being_read);
                        warning_mksh(gettext("newline is not last character in file %s"),
                                             mbs_buffer);
                        *source->string.text.end++ = (int) newline_char;
                        *source->string.text.end = (int) nul_char;
                        *source->string.buffer.end++;
                }
                if (source->inp_buf != NULL) {
                        retmem_mb(source->inp_buf);
                        source->inp_buf = NULL;
                }
        }
        return source;
}