📄 file.c
字号:
/* * file - file I/O routines callable by users * * Copyright (C) 1999-2006 David I. Bell and Landon Curt Noll * * Primary author: David I. Bell * * Calc is open software; you can redistribute it and/or modify it under * the terms of the version 2.1 of the GNU Lesser General Public License * as published by the Free Software Foundation. * * Calc is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General * Public License for more details. * * A copy of version 2.1 of the GNU Lesser General Public License is * distributed with calc under the filename COPYING-LGPL. You should have * received a copy with calc; if not, write to Free Software Foundation, Inc. * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. * * @(#) $Revision: 29.16 $ * @(#) $Id: file.c,v 29.16 2006/08/20 15:01:30 chongo Exp $ * @(#) $Source: /usr/local/src/cmd/calc/RCS/file.c,v $ * * Under source code control: 1991/07/20 00:21:56 * File existed as early as: 1991 * * chongo <was here> /\oo/\ http://www.isthe.com/chongo/ * Share and enjoy! :-) http://www.isthe.com/chongo/tech/comp/calc/ */#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <stdlib.h>#include "have_unistd.h"#if defined(HAVE_UNISTD_H)# include <unistd.h>#endif /* HAVE_UNISTD_H */#include <ctype.h>#include "calc.h"#include "longbits.h"#include "have_fpos.h"#include "have_fpos_pos.h"#include "fposval.h"#include "file.h"#include "calcerr.h"#if defined(_WIN32)# include <io.h>#endif#define READSIZE 1024 /* buffer size for reading *//* * external STDIO functions */extern void math_setfp(FILE *fp);extern FILE *f_open(char *name, char *mode);/* * Table of opened files. * The first three entries always correspond to stdin, stdout, and stderr, * and cannot be closed. Their file ids are always 0, 1, and 2. */static FILEIO files[MAXFILES] = { {FILEID_STDIN, NULL, (dev_t)0, (ino_t)0, "(stdin)", TRUE, FALSE, FALSE, FALSE, 'r', "r"}, {FILEID_STDOUT, NULL, (dev_t)0, (ino_t)0, "(stdout)", FALSE, TRUE, FALSE, FALSE, 'w', "w"}, {FILEID_STDERR, NULL, (dev_t)0, (ino_t)0, "(stderr)", FALSE, TRUE, FALSE, FALSE, 'w', "w"}};static int ioindex[MAXFILES] = {0,1,2}; /* Indices for FILEIO table */static FILEID lastid = FILEID_STDERR; /* Last allocated file id */static int idnum = 3; /* Number of allocated file ids *//* forward static declarations */static ZVALUE filepos2z(FILEPOS pos);static FILEPOS z2filepos(ZVALUE pos);static int set_open_pos(FILE *fp, ZVALUE zpos);static int get_open_pos(FILE *fp, ZVALUE *res);static ZVALUE off_t2z(off_t siz);static ZVALUE dev2z(dev_t dev);static ZVALUE inode2z(ino_t inode);static void getscanfield(FILE *fp, BOOL skip, unsigned int width, int scannum, char *scanptr, char **strptr);static void getscanwhite(FILE *fp, BOOL skip, unsigned int width, int scannum, char **strptr);static int fscanfile(FILE *fp, char *fmt, int count, VALUE **vals);static void freadnum(FILE *fp, VALUE *valptr);static void freadsum(FILE *fp, VALUE *valptr);static void freadprod(FILE *fp, VALUE *valptr);static void fskipnum(FILE *fp);/* * file_init - perform needed initilization work * * On some systems, one cannot initialize a pointer to a FILE *. * This routine, called once at startup is a work-a-round for * systems with such bogons. * * We will also probe for any open files beyond stderr and set them up. */voidfile_init(void){ static int done = 0; /* 1 => routine already called */ struct stat sbuf; /* file status */ FILEIO *fiop; FILE *fp; int i; if (!done) { /* * setup the default set */ files[0].fp = stdin; files[1].fp = stdout; files[2].fp = stderr; for (i = 0; i < 3; ++i) { if (fstat(i, &sbuf) >= 0) { files[i].dev = sbuf.st_dev; files[i].inode = sbuf.st_ino; } } /* * note any other files that we can find */ fiop = &files[3]; for (i = 3; i < MAXFILES; fiop++, ++i) { char *tname; fiop->name = NULL; files[idnum].reading = TRUE; files[idnum].writing = TRUE; files[idnum].action = 0; /* * stat the descriptor to see what we have */ if (fstat(i, &sbuf) >= 0) { fp = (FILE *) fdopen(i,"r+"); /*guess mode*/ if (fp) { strcpy(files[idnum].mode, "r+"); } else { fp = (FILE *) fdopen(i, "r"); if (fp) { strcpy(files[idnum].mode, "r"); files[idnum].writing = FALSE; } else { fp = (FILE *) fdopen(i, "w"); if (fp) { strcpy(files[idnum].mode, "w"); files[idnum].reading = FALSE; } else continue; } } tname = (char *)malloc(sizeof("descriptor[19]")); if (tname == NULL) { math_error("Out of memory for init_file"); /*NOTREACHED*/ } sprintf(tname, "descriptor[%d]", i); files[idnum].name = tname; files[idnum].id = idnum; files[idnum].fp = fp; files[idnum].dev = sbuf.st_dev; files[idnum].inode = sbuf.st_ino; ioindex[idnum] = idnum; idnum++; lastid++; } } done = 1; }}/* * init_fileio - initialize a FILEIO structure * * This function initializes a calc FILEIO structure. It will optionally * malloc the filename string if given an non-NULL associated filename. * It will canonicalize the file open mode string. * * given: * fiop pointer to FILEIO structure to initialize * name associated filename (NULL => caller will setup filename) * mode open mode (one of {r,w,a}{,b}{,+}) * sbufp pointer to stat of open file * id calc file ID * fp open file stream */static voidinit_fileio(FILEIO *fiop, char *name, char *mode, struct stat *sbufp, FILEID id, FILE *fp){ char modestr[sizeof(fiop->mode)]; /* mode [rwa]b?\+? */ size_t namelen; /* length of name */ /* allocate filename if requested */ if (name != NULL) { namelen = strlen(name); fiop->name = (char *)malloc(namelen + 1); if (fiop->name == NULL) { math_error("No memory for filename"); /*NOTREACHED*/ } } /* initialize FILEIO structure */ if (name != NULL) { strncpy(fiop->name, name, namelen+1); } fiop->id = id; fiop->fp = fp; fiop->dev = sbufp->st_dev; fiop->inode = sbufp->st_ino; fiop->reading = FALSE; fiop->writing = FALSE; fiop->appending = FALSE; fiop->binary = FALSE; fiop->action = 0; fiop->mode[0] = '\0'; /* * determine file open mode * * While a leading 'r' is for reading and a leading 'w' is * for writing, the presense of a '+' in the string means * both reading and writing. A leading 'a' means append * which is writing. */ /* canonicalize read modes */ if (mode[0] == 'r') { /* note read mode */ strcpy(modestr, "r"); fiop->reading = TRUE; /* note binary mode even though mode is not used / ignored */ if (strchr(mode, 'b') != NULL) { strcat(modestr, "b"); } /* note if reading and writing */ if (strchr(mode, '+') != NULL) { fiop->writing = TRUE; strcat(modestr, "+"); } /* canonicalize write modes */ } else if (mode[0] == 'w') { /* note write mode */ strcpy(modestr, "w"); fiop->writing = TRUE; /* note binary mode even though mode is not used / ignored */ if (strchr(mode, 'b') != NULL) { strcat(modestr, "b"); } /* note if reading and writing */ if (strchr(mode, '+') != NULL) { fiop->reading = TRUE; strcat(modestr, "+"); } /* canonicalize append modes */ } else if (mode[0] == 'a') { /* note append mode */ strcpy(modestr, "a"); fiop->writing = TRUE; fiop->appending = TRUE; /* note binary mode even though mode is not used / ignored */ if (strchr(mode, 'b') != NULL) { strcat(modestr, "b"); } /* note if reading and writing */ if (strchr(mode, '+') != NULL) { fiop->reading = TRUE; strcat(modestr, "+"); } /* canonicalize no I/O modes */ } else { modestr[0] = '\0'; } modestr[sizeof(modestr)-1] = '\0'; /* firewall */ /* record canonical open mode string */ strncpy(fiop->mode, modestr, sizeof(fiop->mode));}/* * openid - open the specified file name for reading or writing * * given: * name file name * mode open mode (one of {r,w,a}{,b}{,+}) * * returns: * >=3 FILEID which can be used to do I/O to the file * <0 if the open failed * * NOTE: This function will not return 0, 1 or 2 since they are * reserved for stdin, stdout, stderr. In fact, it must not * return 0, 1, or 2 because it will confuse those who call * the opensearchfiile() function */FILEIDopenid(char *name, char *mode){ FILEIO *fiop; /* file structure */ FILEID id; /* new file id */ FILE *fp; struct stat sbuf; /* file status */ int i; /* find the next open slot in the files array */ if (idnum >= MAXFILES) return -E_MANYOPEN; fiop = &files[3]; for (i = 3; i < MAXFILES; fiop++,i++) { if (fiop->name == NULL) break; } if (i == MAXFILES) math_error("This should not happen in openid()!!!"); /* open the file */ fp = f_open(name, mode); if (fp == NULL) { return FILEID_NONE; } if (fstat(fileno(fp), &sbuf) < 0) { math_error("bad fstat"); /*NOTREACHED*/ } /* get a new FILEID */ id = ++lastid; ioindex[idnum++] = i; /* initialize FILEIO structure */ init_fileio(fiop, name, mode, &sbuf, id, fp); /* return calc open file ID */ return id;}/* * openpathid - open the specified abse filename, or relative filename along a search path * * given: * name file name * mode open mode (one of {r,w,a}{,b}{,+}) * pathlist list of colon separated paths (or NULL) * * returns: * >=3 FILEID which can be used to do I/O to the file * <0 if the open failed * * NOTE: This function will not return 0, 1 or 2 since they are * reserved for stdin, stdout, stderr. In fact, it must not * return 0, 1, or 2 because it will confuse those who call * the opensearchfiile() function */FILEIDopenpathid(char *name, char *mode, char *pathlist){ FILEIO *fiop; /* file structure */ FILEID id; /* new file id */ FILE *fp; struct stat sbuf; /* file status */ char *openpath; /* malloc copy of path that was opened */ int i; /* find the next open slot in the files array */ if (idnum >= MAXFILES) return -E_MANYOPEN; fiop = &files[3]; for (i = 3; i < MAXFILES; fiop++,i++) { if (fiop->name == NULL) break; } if (i == MAXFILES) math_error("This should not happen in openpathid()!!!"); /* open a file - searching along a path */ openpath = NULL; fp = f_pathopen(name, mode, pathlist, &openpath); if (fp == NULL) { if (openpath != NULL) { /* should not happen, but just in case */ free(openpath); } return FILEID_NONE; } if (fstat(fileno(fp), &sbuf) < 0) { if (openpath != NULL) { free(openpath); } math_error("bad fstat"); /*NOTREACHED*/ } if (openpath == NULL) { fclose(fp); math_error("bad openpath"); /*NOTREACHED*/ } /* get a new FILEID */ id = ++lastid; ioindex[idnum++] = i; /* initialize FILEIO structure */ init_fileio(fiop, NULL, mode, &sbuf, id, fp); fiop->name = openpath; /* already malloced by f_pathopen */ /* return calc open file ID */ return id;}/* * reopenid - reopen a FILEID * * given: * id FILEID to reopen * mode new mode to open as * mode new mode to open as (one of "r", "w", "a", "r+", "w+", "a+") * name name of new file * * returns: * FILEID which can be used to do I/O to the file * <0 if the open failed */FILEIDreopenid(FILEID id, char *mode, char *name){ FILEIO *fiop; /* file structure */ FILE *fp; struct stat sbuf; int i; /* firewall */ if ((id == FILEID_STDIN) || (id == FILEID_STDOUT) || (id == FILEID_STDERR)) { math_error("Cannot freopen stdin, stdout, or stderr"); /*NOTREACHED*/ } /* reopen the file */ fiop = NULL; for (i = 3; i < idnum; i++) { fiop = &files[ioindex[i]]; if (fiop->id == id) break; } if (i == idnum) { if (name == NULL) { fprintf(stderr, "File not open, need file name\n"); return FILEID_NONE; } if (idnum >= MAXFILES) { fprintf(stderr, "Too many open files\n"); return FILEID_NONE; } for (fiop = &files[3], i = 3; i < MAXFILES; fiop++, i++) { if (fiop->name == NULL) break; } if (i >= MAXFILES) { math_error("This should not happen in reopenid"); /*NOTREACHED*/ } fp = f_open(name, mode); if (fp == NULL) { fprintf(stderr, "Cannot open file\n"); return FILEID_NONE; } ioindex[idnum++] = i; fiop->id = id; } else { if (name == NULL) fp = freopen(fiop->name, mode, fiop->fp); else fp = freopen(name, mode, fiop->fp); if (fp == NULL) { free(fiop->name); fiop->name = NULL; idnum--; for (; i < idnum; i++) ioindex[i] = ioindex[i + 1]; return FILEID_NONE; } } if (fstat(fileno(fp), &sbuf) < 0) { math_error("bad fstat"); /*NOTREACHED*/ } /* initialize FILEIO structure */ if (name == NULL) { if (fiop->name == NULL) { math_error("old and new reopen filenames are NULL"); } } else if (fiop->name != NULL) { free(fiop->name); fiop->name = NULL; } init_fileio(fiop, name, mode, &sbuf, id, fp); /* return calc open file ID */ return id;}/* * Find the file I/O structure for the specified file id, and verifies that * it is opened in the required manner (0 for reading or 1 for writing). * If writable is -1, then no open checks are made at all and NULL is then * returned if the id represents a closed file. */FILEIO *findid(FILEID id, int writable){ FILEIO *fiop; /* file structure */ int i; fiop = NULL; if ((id < 0) || (id > lastid)) return NULL; for (i = 0; i < idnum; i++) { fiop = &files[ioindex[i]]; if (fiop->id == id) break; } if (i == idnum) return NULL; if (writable >= 0) { if ((writable && !fiop->writing) || (!writable && !fiop->reading)) { return NULL; } } return fiop;}/* * Return whether or not a file id is valid. This is used for if tests. */BOOLvalidid(FILEID id){ return (findid(id, -1) != NULL);}/* * Return the file with id = index if this is the id of a file that has been * opened (it may have since been closed). Otherwise returns FILEID_NONE. */FILEIDindexid(long index){ FILEID id; id = (FILEID) index; if ((index < 0) || (id > lastid)) return FILEID_NONE; return id;}/* * Close the specified file id. Returns TRUE if there was an error. * Closing of stdin, stdout, or stderr is illegal, but closing of already * closed files is allowed. */intcloseid(FILEID id){ FILEIO *fiop; /* file structure */ int i; int err; fiop = NULL; /* firewall */ if ((id == FILEID_STDIN) || (id == FILEID_STDOUT) || (id == FILEID_STDERR)) { math_error("Cannot close stdin, stdout, or stderr"); /*NOTREACHED*/ } /* get file structure */ for (i = 3; i < idnum; i++) { fiop = &files[ioindex[i]]; if (fiop->id == id) break; } if (i == idnum) return 1; /* File not open */ idnum--; for (; i < idnum; i++) ioindex[i] = ioindex[i + 1]; free(fiop->name); fiop->name = NULL; /* close file and note error state */ err = ferror(fiop->fp); err |= fclose(fiop->fp); fiop->fp = NULL; /* return success or failure */ return (err ? EOF : 0);}intcloseall(void){ FILEIO *fiop; int i; int err; err = 0; for (i = 3; i < idnum; i++) { fiop = &files[ioindex[i]]; if (fiop->fp) { free(fiop->name); fiop->name = NULL; err |= fclose(fiop->fp); } } idnum = 3; return err;}/* * Return whether or not an error occurred to a file. */BOOLerrorid(FILEID id){ FILEIO *fiop; /* file structure */ fiop = findid(id, -1); if (fiop == NULL) return EOF; return (ferror(fiop->fp) != 0);}/* * Return whether or not end of file occurred to a file. */BOOLeofid(FILEID id){ FILEIO *fiop; /* file structure */ fiop = findid(id, -1); if (fiop == NULL) return EOF; return (feof(fiop->fp) != 0);}/* * Flush output to an opened file. */intflushid(FILEID id){ FILEIO *fiop; /* file structure */ fiop = findid(id, -1); if (fiop == NULL) return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -