1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 
  27 /*
  28  *      read.c
  29  *
  30  *      This file contains the makefile reader.
  31  */
  32 
  33 /*
  34  * Included files
  35  */
  36 #include <mksh/misc.h>            /* retmem() */
  37 #include <mksh/read.h>
  38 #include <sys/uio.h>              /* read() */
  39 #include <unistd.h>               /* close(), unlink(), read() */
  40 #include <libintl.h>
  41 
  42 #define STRING_LEN_TO_CONVERT   (8*1024)
  43 
  44 /*
  45  *      get_next_block_fn(source)
  46  *
  47  *      Will get the next block of text to read either
  48  *      by popping one source bVSIZEOFlock of the stack of Sources
  49  *      or by reading some more from the makefile.
  50  *
  51  *      Return value:
  52  *                              The new source block to read from
  53  *
  54  *      Parameters:
  55  *              source          The old source block
  56  *
  57  *      Global variables used:
  58  *              file_being_read The name of the current file, error msg
  59  */
  60 Boolean         make_state_locked;
  61 Source
  62 get_next_block_fn(register Source source)
  63 {
  64         register off_t          to_read;
  65         register int            length;
  66         register size_t         num_wc_chars;
  67         char                    ch_save;
  68         char                    *ptr;
  69 
  70         if (source == NULL) {
  71                 return NULL;
  72         }
  73         if ((source->fd < 0) || 
  74                 ((source->bytes_left_in_file <= 0) &&
  75                         (source->inp_buf_ptr >= source->inp_buf_end))) {
  76                 /* We can't read from the makefile, so pop the source block */
  77                 if (source->fd > 2) {
  78                         (void) close(source->fd);
  79                         if (make_state_lockfile != NULL) {
  80                                 (void) unlink(make_state_lockfile);
  81                                 retmem_mb(make_state_lockfile);
  82                                 make_state_lockfile = NULL;
  83                                 make_state_locked = false;
  84                         }
  85                 }
  86                 if (source->string.free_after_use &&
  87                     (source->string.buffer.start != NULL)) {
  88                         retmem(source->string.buffer.start);
  89                         source->string.buffer.start = NULL;
  90                 }
  91                 if (source->inp_buf != NULL) {
  92                         retmem_mb(source->inp_buf);
  93                         source->inp_buf = NULL;
  94                 }
  95                 source = source->previous;
  96                 if (source != NULL) {
  97                         source->error_converting = false;
  98                 }
  99                 return source;
 100         }
 101         if (source->bytes_left_in_file > 0) {
 102         /*
 103          * Read the whole makefile.
 104          * Hopefully the kernel managed to prefetch the stuff.
 105          */
 106                 to_read = source->bytes_left_in_file;
 107                 source->inp_buf_ptr = source->inp_buf = getmem(to_read + 1);
 108                 source->inp_buf_end = source->inp_buf + to_read;
 109                 length = read(source->fd, source->inp_buf, (unsigned int) to_read);
 110                 if (length != to_read) {
 111                         WCSTOMBS(mbs_buffer, file_being_read);
 112                         if (length == 0) {
 113                                 fatal_mksh(gettext("Error reading `%s': Premature EOF"),
 114                                       mbs_buffer);
 115                         } else {
 116                                 fatal_mksh(gettext("Error reading `%s': %s"),
 117                                       mbs_buffer,
 118                                       errmsg(errno));
 119                         }
 120                 }
 121                 *source->inp_buf_end = nul_char;
 122                 source->bytes_left_in_file = 0;
 123         }
 124         /*
 125          * Try to convert the next piece.
 126          */
 127         ptr = source->inp_buf_ptr + STRING_LEN_TO_CONVERT;
 128         if (ptr > source->inp_buf_end) {
 129                 ptr = source->inp_buf_end;
 130         }
 131         for (num_wc_chars = 0; ptr > source->inp_buf_ptr; ptr--) {
 132                 ch_save = *ptr;
 133                 *ptr = nul_char;
 134                 num_wc_chars = mbstowcs(source->string.text.end,
 135                                         source->inp_buf_ptr,
 136                                         STRING_LEN_TO_CONVERT);
 137                 *ptr = ch_save;
 138                 if (num_wc_chars != (size_t)-1) {
 139                         break;
 140                 }
 141         }
 142                 
 143         if ((int) num_wc_chars == (size_t)-1) {
 144                 source->error_converting = true;
 145                 return source;
 146         }
 147 
 148         source->error_converting = false;
 149         source->inp_buf_ptr = ptr;
 150         source->string.text.end += num_wc_chars;
 151         *source->string.text.end = 0;
 152 
 153         if (source->inp_buf_ptr >= source->inp_buf_end) {
 154                 if (*(source->string.text.end - 1) != (int) newline_char) {
 155                         WCSTOMBS(mbs_buffer, file_being_read);
 156                         warning_mksh(gettext("newline is not last character in file %s"),
 157                                              mbs_buffer);
 158                         *source->string.text.end++ = (int) newline_char;
 159                         *source->string.text.end = (int) nul_char;
 160                         *source->string.buffer.end++;
 161                 }
 162                 if (source->inp_buf != NULL) {
 163                         retmem_mb(source->inp_buf);
 164                         source->inp_buf = NULL;
 165                 }
 166         }
 167         return source;
 168 }
 169 
 170