⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sflfile.c

📁 短小精悍的C语言标准函数库。提供450个以上的可移植的算法和工具代码。
💻 C
📖 第 1 页 / 共 5 页
字号:
/*  ----------------------------------------------------------------<Prolog>-
    Name:       sflfile.c
    Title:      File-access functions
    Package:    Standard Function Library (SFL)

    Written:    1992/10/28  iMatix SFL project team <sfl@imatix.com>
    Revised:    2000/01/19

    Copyright:  Copyright (c) 1996-2000 iMatix Corporation
    License:    This is free software; you can redistribute it and/or modify
                it under the terms of the SFL License Agreement as provided
                in the file LICENSE.TXT.  This software is distributed in
                the hope that it will be useful, but without any warranty.
 ------------------------------------------------------------------</Prolog>-*/

#include "prelude.h"                    /*  Universal header file            */
#include "sflstr.h"                     /*  String handling functions        */
#include "sfllist.h"                    /*  Linked-list functions            */
#include "sflmem.h"                     /*  Memory allocation functions      */
#include "sflnode.h"                    /*  Linked-list functions            */
#include "sfldir.h"                     /*  Directory access functions       */
#include "sfldate.h"                    /*  Date/time access functions       */
#include "sflsymb.h"                    /*  Symbol-table functions           */
#include "sfltok.h"                     /*  Token mashing functions          */
#include "sflcons.h"                    /*  Console output functions         */
#include "sflenv.h"                     /*  Environment access functions     */
#include "sflprint.h"                   /*  snprintf functions               */
#include "sflfile.h"                    /*  Prototypes for functions         */


/*  Ensure our buffers will be big enough for dir + name + delimiters        */
#if ((LINE_MAX - FILE_NAME_MAX) < (FILE_DIR_MAX + 10))
#   error "Cannot compile; FILE_NAME_MAX is too large."
#endif

static char
#if (PATHFOLD == TRUE || defined (MSDOS_FILESYSTEM))
    path_name [PATH_MAX + 1],           /*  Copy of path symbol              */
#endif
    work_name [LINE_MAX + 1],           /*  Name plus ext                    */
    full_name [LINE_MAX + 1],           /*  Dir plus name plus ext           */
    exec_name [LINE_MAX + 1];           /*  Executable file name             */

Bool file_crlf = FALSE;                 /*  Initial default                  */


/*  Function prototypes                                                      */

#if (defined (MSDOS_FILESYSTEM))
static Bool   system_devicename   (const char *filename);
#endif
static char  *build_next_path     (char *dest, const char *path,
                                               const char *name);
static char  *build_next_path_ext (char *dest, const char *path,
                                               const char *name,
                                               const char *ext);
static dbyte  file_mode           (const char *filename);
#if (defined (__WINDOWS__))
static Bool   is_exe_file         (const char *filename);
#endif
static DESCR *file_load_data      (const char *filename, size_t limit);
static Bool   fully_specified     (const char *filename);


/*  ---------------------------------------------------------------------[<]-
    Function: file_open

    Synopsis: opens a text file for reading or writing.  Use in combination
    with the file_read() and file_write() functions.  These functions handle
    end-of-line sequences using a heuristic that works as follows.
    ... (at this point the author went for a pint of beer and has not been
    seen since.  We're hoping that the old version - following - is ok.)

    Synopsis: Opens the specified file for input or output.  If you use
    the file_read / file_write functions you must open the file using this
    function.  This set of functions lets you read files without concern
    for the line format (CRLF or LF).  Mode should be one of 'r' 'w' 'a'.

    Returns a FILE pointer if the file is opened correctly; else NULL.
    Sets the global variable file_crlf to FALSE on all systems except MS-DOS
    (and Windows by inheritence) where it is set to TRUE by default.

    When opening a file in append mode, automatically removes any Ctrl-Z
    character under MS-DOS or OS/2.
    ---------------------------------------------------------------------[>]-*/

FILE *
file_open (
    const char *filename,               /*  Name of file to open             */
    char mode)                          /*  'r', 'w', or 'a'                 */
{
#if (defined (MSDOS_FILESYSTEM))
    if (system_devicename (filename))
        return (NULL);                  /*  Not allowed on device names      */

    file_crlf = TRUE;
#   if (defined (WIN32))
    SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
#   endif
#   else

    ASSERT (filename);
    file_crlf = FALSE;
#endif

    if (mode == 'r')
        return (fopen (filename, FOPEN_READ_BINARY));
    else
    if (mode == 'w')
        return (fopen (filename, FOPEN_WRITE_BINARY));
    else
    if (mode == 'a'
    &&  safe_to_extend (filename))
        return (fopen (filename, FOPEN_APPEND_BINARY));
    else
        return (NULL);                  /*  Invalid mode                     */
}


#if (defined (MSDOS_FILESYSTEM))

/*  Under MS-DOS, use of filenames containing 'aux', 'con', 'prn', or
 *  'nul' can cause problems, especially for reading.  We reject any
 *  use of these names for directories or filenames.
 */
static Bool
system_devicename (const char *supplied_filename)
{
    char
        *filename,    
        *char_ptr,
        *token,
        **tokens;
    int
        token_nbr;
    Bool
        feedback;

    filename = mem_strdup (supplied_filename);
    strconvch (filename, ' ', '_');     /*  Don't break on real spaces       */
    strconvch (filename, '/', ' ');
    strconvch (filename, '\\', ' ');
    strlwc    (filename);               /*  All comparisons in lowercase     */

    /*  Skip disk specifier if present                                       */
    if (strlen (filename) > 2 && filename [1] == ':')
        filename [0] = filename [1] = ' ';

    /*  Wipe out file extensions                                             */
    for (char_ptr = filename; *char_ptr; char_ptr++)
      {
        if (*char_ptr == '.')           /*  Wipe over file extensions        */
            while (*char_ptr && *char_ptr != ' ')
                *char_ptr++ = ' ';
            if (*char_ptr == '\0')
                break;
      }
    tokens = tok_split (filename);
    feedback = FALSE;
    for (token_nbr = 0; tokens [token_nbr]; token_nbr++)
      {
        token = tokens [token_nbr];
#if (defined (WIN32))
        /*  Ask Windows to check if it's a device                            */
        if (QueryDosDevice (token, NULL, 0) == ERROR_INSUFFICIENT_BUFFER)
#else
        if (streq (token, "aux")
        ||  streq (token, "con")
        ||  streq (token, "nul")
        ||  streq (token, "prn")
        || (strprefixed (token, "com") && isdigit (token [3]))
        || (strprefixed (token, "lpt") && isdigit (token [3])))
#endif
          {
            feedback = TRUE;
            break;
          }
      }
    tok_free (tokens);
    mem_free (filename);
    return (feedback);
}
#endif


/*  ---------------------------------------------------------------------[<]-
    Function: file_locate

    Synopsis: Combines the functions of file_where() and file_open when you
    want to read a file.  Searches for a file on a specified path, opens the
    file if found, and returns a FILE * for the open file.  Returns NULL if
    the file was not found or could not be opened for reading.
    ---------------------------------------------------------------------[>]-*/

FILE *
file_locate (
    const char *path,
    const char *name,
    const char *ext)
{
    char
        *filename;

    ASSERT (name);
    filename = file_where ('r', path, name, ext);
    if (filename)
        return (file_open (filename, 'r'));
    else
        return (NULL);
}


/*  ---------------------------------------------------------------------[<]-
    Function: file_close

    Synopsis: Closes an open file stream.  Returns 0 if okay, -1 if there
    was an error.  For now, equivalent to fclose, and supplied because it
    looks nice when you use file_open() and file_close() together.
    ---------------------------------------------------------------------[>]-*/

int
file_close (
    FILE *stream)
{
    if (stream)
        return (fclose (stream));
    else
        return (0);
}


/*  ---------------------------------------------------------------------[<]-
    Function: file_read

    Synopsis: Reads a line of text delimited by newline from the stream.
    The string must be LINE_MAX + 1 long.  Places a null byte in place of
    the newline character.  Expands tab characters to every 8th column.
    Returns TRUE when there is more input waiting; FALSE when the last line
    of the file has been read.

    Sets the global variable file_crlf to TRUE if CR was found in the file.
    This variable is by default FALSE.  It is also used by file_write.
    ---------------------------------------------------------------------[>]-*/

Bool
file_read (
    FILE *stream,
    char *string)
{
    int
        ch,                             /*  Character read from file         */
        cnbr;                           /*  Index into returned string       */

    ASSERT (stream);
    ASSERT (string);

    cnbr = 0;                           /*  Start at the beginning...        */
    memset (string, ' ', LINE_MAX);     /*    and prepare entire line        */
    for (;;)
      {
        ch = fgetc (stream);            /*  Get next character from file     */
        if (ch == '\t')                 /*  Jump if tab                      */
            cnbr = ((cnbr >> 3) << 3) + 8;
        else
        if (ch == '\r')                 /*  Found carriage-return            */
            file_crlf = TRUE;           /*    Set flag and ignore CR         */
        else
        if ((ch == '\n')                /*  Have end of line                 */
        ||  (ch == EOF)                 /*    or end of file                 */
        ||  (ch == 26))                 /*    or MS-DOS Ctrl-Z               */
          {
            string [cnbr] = '\0';       /*  Terminate string                 */
            return (ch == '\n' || cnbr);    /*  and return TRUE/FALSE        */
          }
        else
        if (cnbr < LINE_MAX)
            string [cnbr++] = (char) ch;    /*  Else add char to string      */

        if (cnbr >= LINE_MAX)           /*  Return in any case if line is    */
          {                             /*    too long - the line will be    */
            string [LINE_MAX] = '\0';   /*    cut into pieces                */
            return (TRUE);
          }
      }
}


/*  ---------------------------------------------------------------------[<]-
    Function: file_readn

    Synopsis: Works as file_read() but with a maximum line-length specified
    by the caller.  The supplied buffer must be at least as large as the
    specified line_max + 1.
    ---------------------------------------------------------------------[>]-*/

Bool
file_readn (
    FILE *stream,
    char *string,
    int   line_max)
{
    int
        ch,                             /*  Character read from file         */
        cnbr;                           /*  Index into returned string       */

    ASSERT (stream);
    ASSERT (string);

    cnbr = 0;                           /*  Start at the beginning...        */
    memset (string, ' ', line_max);     /*    and prepare entire line        */
    for (;;)
      {
        ch = fgetc (stream);            /*  Get next character from file     */
        if (ch == '\t')                 /*  Jump if tab                      */
            cnbr = ((cnbr >> 3) << 3) + 8;
        else
        if (ch == '\r')                 /*  Found carriage-return            */
            file_crlf = TRUE;           /*    Set flag and ignore CR         */
        else
        if ((ch == '\n')                /*  Have end of line                 */
        ||  (ch == EOF)                 /*    or end of file                 */
        ||  (ch == 26))                 /*    or MS-DOS Ctrl-Z               */
          {
            string [cnbr] = '\0';       /*  Terminate string                 */
            return (ch == '\n' || cnbr);    /*  and return TRUE/FALSE        */
          }
        else
        if (cnbr < line_max)
            string [cnbr++] = (char) ch;    /*  Else add char to string      */

        if (cnbr >= line_max)           /*  Return in any case if line is    */
          {                             /*    too long - the line will be    */
            string [line_max] = '\0';   /*    cut into pieces                */
            return (TRUE);
          }
      }
}


/*  ---------------------------------------------------------------------[<]-
    Function: file_write

    Synopsis: Writes a line of text to the specified output stream.  If the
    variable file_crlf is TRUE, adds a carriage-return to the line being
    written to the output stream.  This variable is supplied so that you can
    either ignore crlf issues (do nothing), or handle them explicitly (play
    with file_crlf).  Returns the string written, or NULL if no data could
    be written to the file.
    ---------------------------------------------------------------------[>]-*/

char *
file_write (
    FILE *stream,
    const char *string)
{
    ASSERT (stream);
    ASSERT (string);

    fputs (string, stream);
    if (file_crlf)
        fputc ('\r', stream);

    if (fputc ('\n', stream) == EOF)
        return (NULL);
    else
        return ((char *) string);
}


/*  ---------------------------------------------------------------------[<]-
    Function: file_copy

    Synopsis: Copies a file called src to one called dest.  The dest file
    may not already exist.  If mode is 'b', copies a binary file; if mode is
    't', copies a text file.  This distinction only applies to MS-DOS file
    systems; on other platforms the two modes are equivalent.  Returns 0

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -