/** \file * Copyright (c) 1999, 2000 Carlo Wood. All rights reserved.
* Copyright (c) 1994 Joseph Arceneaux. All rights reserved.
* Copyright (c) 1992 Free Software Foundation, Inc. All rights reserved.
* * Copyright (c) 1985 Sun Microsystems, Inc.
* * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * - 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - 2. 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. * - 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission.
* * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. * * This file is subject to the terms of the GNU General Public License as * published by the Free Software Foundation. A copy of this license is * included with this software distribution in the file COPYING. If you * do not have a copy, you may obtain a copy by writing to the Free * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * * HISTORY * - 2002-01-17 D.Ingamells Add a final newline if not present in file. */ #include "sys.h" #include #include #if defined (HAVE_UNISTD_H) #include #endif #include #ifdef VMS #include #include #include #else /* not VMS */ #include #include /* POSIX says that should exist. Some systems might need to use * or instead. */ #include #if defined (_WIN32) && !defined (__CYGWIN__) #include #endif #endif /* not VMS */ #include "indent.h" #include "code_io.h" #include "globs.h" #include "output.h" RCSTAG_CC ("$Id$"); /** * Stuff that needs to be shared with the rest of indent. Documented in * indent.h. */ char * in_prog_pos = NULL; /*!< used in output.c code_io.c indent.c */ char * buf_ptr = NULL; /*!< used in output.c lexi.c code_io.c indent.c comments.c */ char * buf_end = NULL; /*!< used in output.c lexi.c code_io.c indent.c comments.c */ BOOLEAN had_eof = false; /*!< used in output.c code_io.c comments.c parse.c */ char * cur_line = NULL; /*!< used in output.c code_io.c */ /** * */ extern char * skip_horiz_space( const char * p) { while ((*p == ' ') || (*p == TAB)) { p++; } return (char *)p; } /******************************************************************************/ extern void skip_buffered_space(void) { while ((*buf_ptr == ' ') || (*buf_ptr == TAB)) { buf_ptr++; if (buf_ptr >= buf_end) { fill_buffer(); } } } /** * */ static BOOLEAN is_comment_start(const char * p) { BOOLEAN ret; if ((*p == '/') && ((*(p + 1) == '*') || (*(p + 1) == '/'))) { ret = true; } else { ret = false; } return ret; } #ifdef VMS /** * Folks say VMS requires its own read routine. Then again, some folks * say it doesn't. Different folks have also sent me conflicting versions * of this function. Who's right? * * Anyway, this version was sent by MEHRDAD@glum.dev.cf.ac.uk and modified * slightly by me. */ static int vms_read ( int file_desc, char * buffer, int nbytes) { char * bufp; int nread; int nleft; bufp = buffer; nread = 0; nleft = nbytes; nread = read (file_desc, bufp, nleft); while (nread > 0) { bufp += nread; nleft -= nread; if (nleft < 0) { fatal (_("Internal buffering error"), 0); } nread = read (file_desc, bufp, nleft); } return nbytes - nleft; } #endif /* VMS */ /** * Return the column we are at in the input line. */ int current_column (void) { char *p; int column; /* Use save_com.size here instead of save_com.end, because save_com is * already emptied at this point. */ if ((buf_ptr >= save_com.ptr) && (buf_ptr <= save_com.ptr + save_com.len)) { p = save_com.ptr; column = save_com.start_column; } else { p = cur_line; column = 1; } while (p < buf_ptr) { switch (*p) { case EOL: case 014: /* form feed */ column = 1; break; case TAB: column += settings.tabsize - (column - 1) % settings.tabsize; break; case '\b': /* backspace */ column--; break; default: column++; break; } p++; } return column; } /** * VMS defines it's own read routine, `vms_read' */ #ifndef INDENT_SYS_READ #include #define INDENT_SYS_READ read #endif /** * Read file FILENAME into a `fileptr' structure, and return a pointer to * that structure. */ file_buffer_ty * read_file( char * filename, struct stat * file_stats) { static file_buffer_ty fileptr; /* * size is required to be unsigned for MSDOS, * in order to read files larger than 32767 * bytes in a 16-bit world... */ unsigned int size; int namelen = strlen(filename); int fd = open(filename, O_RDONLY, 0777); if (fd < 0) { fatal (_("Can't open input file %s"), filename); } if (fstat(fd, file_stats) < 0) { fatal (_("Can't stat input file %s"), filename); } if (file_stats->st_size == 0) { ERROR (_("Warning: Zero-length file %s"), filename, 0); } #if !defined(__DJGPP__) if (sizeof (int) == 2) /* Old MSDOS */ { if ((file_stats->st_size < 0) || (file_stats->st_size > (0xffff - 1))) { fatal(_("File %s is too big to read"), filename); } } else #endif { if (file_stats->st_size < 0) { fatal(_("System problem reading file %s"), filename); } } fileptr.size = file_stats->st_size; if (fileptr.data != 0) { fileptr.data = (char *) xrealloc (fileptr.data, (unsigned) file_stats->st_size + 2); /* add 1 for '\0' and 1 for * potential final added * newline. */ } else { fileptr.data = (char *) xmalloc ((unsigned) file_stats->st_size + 2); /* add 1 for '\0' and 1 for * potential final added * newline. */ } size = INDENT_SYS_READ (fd, fileptr.data, fileptr.size); if (size == (unsigned int) -1) { fatal (_("Error reading input file %s"), filename); } if (close (fd) < 0) { fatal (_("Error closeing input file %s"), filename); } /* Apparently, the DOS stores files using CR-LF for newlines, but * then the DOS `read' changes them into '\n'. Thus, the size of the * file on disc is larger than what is read into memory. Thanks, Bill. */ if (size < fileptr.size) { fileptr.size = size; } if (fileptr.name != NULL) { fileptr.name = (char *) xrealloc (fileptr.name, (unsigned) namelen + 1); } else { fileptr.name = (char *) xmalloc (namelen + 1); } (void)strncpy(fileptr.name, filename, namelen); fileptr.name[namelen] = EOS; if (fileptr.data[fileptr.size - 1] != EOL) { fileptr.data[fileptr.size] = EOL; fileptr.size++; } fileptr.data[fileptr.size] = EOS; return &fileptr; } /** * This should come from stdio.h and be some system-optimal number */ #ifndef BUFSIZ #define BUFSIZ 1024 #endif /** * Suck the standard input into a file_buffer structure, and * return a pointer to that structure. */ file_buffer_ty * read_stdin(void) { static file_buffer_ty stdinptr; unsigned int size = 15 * BUFSIZ; int ch = EOF; char * p = NULL; if (stdinptr.data != 0) { free (stdinptr.data); } stdinptr.data = (char *) xmalloc (size + 1); stdinptr.size = 0; p = stdinptr.data; do { while (stdinptr.size < size) { ch = getc (stdin); if (ch == EOF) { break; } *p++ = ch; stdinptr.size++; } if (ch != EOF) { size += (2 * BUFSIZ); stdinptr.data = xrealloc (stdinptr.data, (unsigned) size); p = stdinptr.data + stdinptr.size; } } while (ch != EOF); stdinptr.name = "Standard Input"; stdinptr.data[stdinptr.size] = EOS; return &stdinptr; } /* * Advance `buf_ptr' so that it points to the next line of input. * * If the next input line contains an indent control comment turning * off formatting (a comment, C or C++, beginning with *INDENT-OFF*), * disable indenting by calling inhibit_indenting() which will cause * `dump_line ()' to simply print out all input lines without formatting * until it finds a corresponding comment containing *INDENT-0N* which * re-enables formatting. * * Note that if this is a C comment we do not look for the closing * delimiter. Note also that older versions of this program also * skipped lines containing *INDENT** which represented errors * generated by indent in some previous formatting. This version does * not recognize such lines. */ void fill_buffer(void) { char * p = NULL; BOOLEAN finished_a_line = false; /* indent() may be saving the text between "if (...)" and the following * statement. To do so, it uses another buffer (`save_com'). Switch * back to the previous buffer here. */ if (bp_save != 0) { buf_ptr = bp_save; buf_end = be_save; bp_save = be_save = 0; /* only return if there is really something in this buffer */ if (buf_ptr < buf_end) { return; } } if (*in_prog_pos == EOS) { cur_line = buf_ptr = in_prog_pos; had_eof = true; } else { /* Here if we know there are chars to read. The file is * NULL-terminated, so we can always look one character ahead * safely. */ p = cur_line = in_prog_pos; finished_a_line = false; do { p = skip_horiz_space(p); /* If we are looking at the beginning of a comment, see * if it turns off formatting with off-on directives. */ if (is_comment_start(p)) { p += 2; p = skip_horiz_space(p); /* Skip all lines between the indent off and on directives. */ if (strncmp (p, "*INDENT-OFF*", 12) == 0) { inhibit_indenting(true); } } while ((*p != EOS) && *p != EOL) { p++; } /* Here for newline -- finish up unless formatting is off */ if (*p == EOL) { finished_a_line = true; in_prog_pos = p + 1; } /* Here for embedded NULLs */ else if ((unsigned int) (p - current_input->data) < current_input->size) { WARNING (_("Warning: File %s contains NULL-characters\n"), current_input->name, 0); p++; } /* Here for EOF with no terminating newline char. */ else { in_prog_pos = p; finished_a_line = true; } } while (!finished_a_line); buf_ptr = cur_line; buf_end = in_prog_pos; } }