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  * @(#)read.cc 1.11 06/12/12
  27  */
  28 
  29 #pragma ident   "@(#)read.cc    1.11    06/12/12"
  30 
  31 /*
  32  *      read.c
  33  *
  34  *      This file contains the makefile reader.
  35  */
  36 
  37 /*
  38  * Included files
  39  */
  40 #include <mksh/misc.h>            /* retmem() */
  41 #include <mksh/read.h>
  42 #include <mksdmsi18n/mksdmsi18n.h>
  43 #include <sys/uio.h>              /* read() */
  44 #include <unistd.h>               /* close(), unlink(), read() */
  45 
  46 #define STRING_LEN_TO_CONVERT   (8*1024)
  47 
  48 /*
  49  *      get_next_block_fn(source)
  50  *
  51  *      Will get the next block of text to read either
  52  *      by popping one source bVSIZEOFlock of the stack of Sources
  53  *      or by reading some more from the makefile.
  54  *
  55  *      Return value:
  56  *                              The new source block to read from
  57  *
  58  *      Parameters:
  59  *              source          The old source block
  60  *
  61  *      Global variables used:
  62  *              file_being_read The name of the current file, error msg
  63  */
  64 Boolean         make_state_locked;
  65 Source
  66 get_next_block_fn(register Source source)
  67 {
  68         register off_t          to_read;
  69         register int            length;
  70         register size_t         num_wc_chars;
  71         char                    ch_save;
  72         char                    *ptr;
  73 
  74         if (source == NULL) {
  75                 return NULL;
  76         }
  77         if ((source->fd < 0) || 
  78                 ((source->bytes_left_in_file <= 0) &&
  79                         (source->inp_buf_ptr >= source->inp_buf_end))) {
  80                 /* We can't read from the makefile, so pop the source block */
  81                 if (source->fd > 2) {
  82                         (void) close(source->fd);
  83                         if (make_state_lockfile != NULL) {
  84                                 (void) unlink(make_state_lockfile);
  85                                 retmem_mb(make_state_lockfile);
  86                                 make_state_lockfile = NULL;
  87                                 make_state_locked = false;
  88                         }
  89                 }
  90                 if (source->string.free_after_use &&
  91                     (source->string.buffer.start != NULL)) {
  92                         retmem(source->string.buffer.start);
  93                         source->string.buffer.start = NULL;
  94                 }
  95                 if (source->inp_buf != NULL) {
  96                         retmem_mb(source->inp_buf);
  97                         source->inp_buf = NULL;
  98                 }
  99                 source = source->previous;
 100                 if (source != NULL) {
 101                         source->error_converting = false;
 102                 }
 103                 return source;
 104         }
 105         if (source->bytes_left_in_file > 0) {
 106         /*
 107          * Read the whole makefile.
 108          * Hopefully the kernel managed to prefetch the stuff.
 109          */
 110                 to_read = source->bytes_left_in_file;
 111                 source->inp_buf_ptr = source->inp_buf = getmem(to_read + 1);
 112                 source->inp_buf_end = source->inp_buf + to_read;
 113                 length = read(source->fd, source->inp_buf, (unsigned int) to_read);
 114                 if (length != to_read) {
 115                         WCSTOMBS(mbs_buffer, file_being_read);
 116                         if (length == 0) {
 117                                 fatal_mksh(catgets(libmksdmsi18n_catd, 1, 140, "Error reading `%s': Premature EOF"),
 118                                       mbs_buffer);
 119                         } else {
 120                                 fatal_mksh(catgets(libmksdmsi18n_catd, 1, 141, "Error reading `%s': %s"),
 121                                       mbs_buffer,
 122                                       errmsg(errno));
 123                         }
 124                 }
 125                 *source->inp_buf_end = nul_char;
 126                 source->bytes_left_in_file = 0;
 127         }
 128         /*
 129          * Try to convert the next piece.
 130          */
 131         ptr = source->inp_buf_ptr + STRING_LEN_TO_CONVERT;
 132         if (ptr > source->inp_buf_end) {
 133                 ptr = source->inp_buf_end;
 134         }
 135         for (num_wc_chars = 0; ptr > source->inp_buf_ptr; ptr--) {
 136                 ch_save = *ptr;
 137                 *ptr = nul_char;
 138                 num_wc_chars = mbstowcs(source->string.text.end,
 139                                         source->inp_buf_ptr,
 140                                         STRING_LEN_TO_CONVERT);
 141                 *ptr = ch_save;
 142                 if (num_wc_chars != (size_t)-1) {
 143                         break;
 144                 }
 145         }
 146                 
 147         if ((int) num_wc_chars == (size_t)-1) {
 148                 source->error_converting = true;
 149                 return source;
 150         }
 151 
 152         source->error_converting = false;
 153         source->inp_buf_ptr = ptr;
 154         source->string.text.end += num_wc_chars;
 155         *source->string.text.end = 0;
 156 
 157         if (source->inp_buf_ptr >= source->inp_buf_end) {
 158                 if (*(source->string.text.end - 1) != (int) newline_char) {
 159                         WCSTOMBS(mbs_buffer, file_being_read);
 160                         warning_mksh(catgets(libmksdmsi18n_catd, 1, 142, "newline is not last character in file %s"),
 161                                              mbs_buffer);
 162                         *source->string.text.end++ = (int) newline_char;
 163                         *source->string.text.end = (int) nul_char;
 164                         *source->string.buffer.end++;
 165                 }
 166                 if (source->inp_buf != NULL) {
 167                         retmem_mb(source->inp_buf);
 168                         source->inp_buf = NULL;
 169                 }
 170         }
 171         return source;
 172 }
 173 
 174