## root/clib/fio.c

/* [<][>][^][v][top][bottom][index][help] */

## DEFINITIONS

This source file includes following definitions.

1. unique
2. exist
3. numrecs
4. get_nrec
5. get_rec
6. zcreate
7. isdirectory
8. filecopy
9. qrename
10. write_dos_line
11. write_unix_line

    /* File I/O function library module,
       Rick Smereka, Copyright (C) 1995-2005.

       This program is free software; you can redistribute it and/or modify
       it under the terms of the GNU General Public License as published by
       the Free Software Foundation; either version 2 of the License, or
       (at your option) any later version.

       This program 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 General Public License for more details.

       You should have received a copy of the GNU General Public License
       along with this program; if not, get a copy via the Internet at
       http://gnu.org/copyleft/gpl.html or write to the Free Software
       Foundation, Inc., 59 Temple Place, Suite 330, Boston,
       MA 02111-1307 USA

       You can contact the author via email at rsmereka@future-lab.com

       Original DOS version Feb/95, Rick Smereka

       Port to QNX V4.23a Dec/97, Rick Smereka

       Changed the 'unique' function to create a file in the
       indicated directory. Also changed the return type to
       'int' to indicate the success or failure of the file
       name generation. Dec/97, Rick Smereka

       Added function 'qrename' specific to QNX. This function
       attempts to perform a normal rename. If that failes with
       a 'EXDEV' 'errno' (cannot move across devices), an OS
       copy is performed. Nov/98, Rick Smereka

       Ported to 32bit Windows under CodeWarrior V4.
       Ported to HP-UX under GNU C 2.8.1.
       Jan/99, Rick Smereka

       Ported to Red Hat Linux 5.2, Jul/99, Rick Smereka

       Changed function 'isdirectory' to compile on all
       platforms and use the POSIX system call 'opendir'.
       Feb/2001, Rick Smereka

       Changed function 'filecopy' to use standard stream I/O
       funtion calls ('fopen', 'fread', 'fwrite' and 'fclose').
       Mar/2001, Rick Smereka

       Corrected bug in 'zcreate' where an already existing file
       was truncated. Nov/2001, Rick Smereka

       Ported to Debian Linux. Nov/2002, Rick Smereka

       Added functions 'write_dos_line' and 'write_unix_line'.
       Dec/2002, Rick Smereka

       Changed function 'unique' to use a sequential number for the
       file name instead of a random number. Jan/2005, Rick Smereka

       Added a check for a proper directory name in function 'unique'.
       Fixed 'ifdef' in function 'qrename'. Mar/2005, Rick Smereka */

    #include "stdhead.h"

    int unique(char *dir, char *fname)
    {
       /* Create a unique file name. Uniquness will be tested in the
          directory 'dir'. Do not end 'dir' with a path separator.
          'dir' can be a null string but not a NULL pointer.
          Name of the new file is returned in 'fname' minus the
          directory name. */

       static long fcount = 0L;
       int dir_len, total_len, ex = TRUE;
       char *total_f;
       char rname[13];

       if (dir == (char *)NULL)
          return(FALSE);

       dir_len = strlen(dir);

       if (dir_len && dir[dir_len - 1] == PATH_SEP)
          return(FALSE);

       if (dir_len && !isdirectory(dir))
          return(FALSE);

       if (fname == (char *)NULL)
          return(FALSE);

       /* calculate length of total string required */

       total_len = dir_len + 14;

       /* allocate total file name string */

       if ((total_f = (char *)malloc(total_len)) == (char *)NULL)
          return(FALSE);

       while(ex)
          {
          if (fcount > 99999999L)
             fcount = 0L;

          sprintf(rname, "%08ld.tmp", fcount++);

          if (dir_len)
             sprintf(total_f, "%s%c%s", dir, PATH_SEP, rname);
          else
             strcpy(total_f, rname);

          ex = exist(total_f);
          }

       free(total_f);
       strcpy(fname, rname);
       return(TRUE);
    }

    int exist(char *file)
    {
       /* Test for file existance. Under Unix/QNX, the POSIX
          'access' function is used. Since CodeWarrior does not
          support this function and DOS directory functions are
          also not supported, we test for file existance by
          attempting to open the file. Note that the Unix/QNX
          version makes no assumption on the read/write status
          of the file whereas the Windows 32bit version specifically
          opens the file for read. Function returns 'TRUE' upon success,
          'FALSE' otherwise. */
    #ifdef OS_DOS
    struct ffblk dconst;
    struct ffblk *dta = &dconst;
    #endif

    #ifdef OS_WIN32
       FILE *in;
    #endif

       if (!strlen(file))
          return(FALSE);

    #ifdef OS_WIN32
       if ((in = fopen(file, "r")) == (FILE *)NULL)
          return(FALSE);

       fclose(in);
       return(TRUE);
    #endif

    #ifdef OS_UNIX
       if (!access(file, F_OK))
          return(TRUE);

       return(FALSE);
    #endif

    #ifdef OS_DOS
       if (!findfirst(file, dta, FA_NORMAL))
          return(TRUE);

       return(FALSE);
    #endif
    }

    int numrecs(FILE *fi)
    {
       /* Count the number of records in a file. */

       char *buf;
       int numrec = 0;

       if ((buf = (char *)malloc(BUFSIZE + 1)) == NULL)
          return(0);

       rewind(fi);
       get_rec(fi, buf);

       while(!feof(fi))
          {
          numrec++;
          get_rec(fi, buf);
          }

       rewind(fi);
       free(buf);
       return(numrec);
    }

    void get_nrec(int recno, FILE *fi, char *buf)
    {
       /* Read the 'recno' record from 'fi' into 'buf' and strip any
          line feeds. 'Buf' will contain zero bytes on failure.
          'Buf' must be statically allocated by the caller to an
          appropriate size. */

       int i;
       char *ptr;

       rewind(fi);

       for(i = 0; i < recno; i++)
          {
          fgets(buf, BUFSIZE, fi);

          if (feof(fi))
             {
             buf[0] = EOS;
             return;
             }
          }

       if ((ptr = strchr(buf, EOL)) != NULL)
          *ptr = EOS;
    }

    void get_rec(FILE *fi, char *buf)
    {
       /* Read a record from 'fi' into 'buf' and strip any
          line feeds. */

       char *ptr;

       fgets(buf, BUFSIZE, fi);

       if ((ptr = strchr(buf, EOL)) != NULL)
          *ptr = EOS;
    }

    int zcreate(char *fname)
    {
       /* Create a zero byte file called 'fname'. It is an
          error if the file already exists. Function
          returns TRUE on success, FALSE otherwise. */

       FILE *fi;

       if (fname == (char *)NULL || !strlen(fname))
          return(FALSE);

       if (exist(fname))
          return(FALSE);

       if ((fi = fopen(fname,"w")) == (FILE *)NULL)
          return(FALSE);

       fclose(fi);
       return(TRUE);
    }

    int isdirectory(char *path)
    {
       /* Check for 'path' being a directory. Function uses the
          POSIX standard 'opendir' system call. Function returns
          'TRUE' if the 'path' resolves to a directory, 'FALSE'
          otherwise. */

       DIR *dir;

       if (path == NULL || !strlen(path))
          return(FALSE);

       if ((dir = opendir(path)) == NULL)
          return(FALSE);

       closedir(dir);
       return(TRUE);
    }

    int filecopy(char *src, char *dest)
    {
       /* Copy a file from 'src' to 'dest'. If 'dest' file
          exists, it will be overwritten. A 32kb buffer is
          used to copy the data. Function returns 'TRUE'
          upon success, 'FALSE' otherwise. */

       FILE *in, *out;
       int bufsiz, ret, done = FALSE;
       char *ptr;

       if (!strlen(src) || !strlen(dest))
          return(FALSE);

       bufsiz = 32760;

       if ((ptr = (char *)malloc(bufsiz)) == (char *)NULL)
          return(FALSE);

       if ((in = fopen(src, "rb")) == NULL)
          {
          free(ptr);
          return(FALSE);
          }

       if ((out = fopen(dest, "wb")) == NULL)
          {
          fclose(in);
          free(ptr);
          return(FALSE);
          }

       /* swap until end of file or error */

       do
          {
          ret = fread(ptr, 1, bufsiz, in);

          /* trap read errors */

          if (ferror(in))
             {
             fclose(in);
             fclose(out);
             free(ptr);
             return(FALSE);
             }

          if (fwrite(ptr, 1, ret, out) != ret)
             {
             fclose(in);
             fclose(out);
             free(ptr);
             return(FALSE);
             }

          /* if we read less than a buffer size, assume done */

          if (ret < bufsiz)
             done = TRUE;
          }
       while(!done);

       fclose(in);
       fclose(out);
       free(ptr);
       return(TRUE);
    }

    int qrename(char *src, char *dest)
    {
       /* Rename a file. This version will rename a file
          anywhere (same directory, different directory on
          same volume, different directory on different
          disk/volume). Function returns 'TRUE' upon
          success, 'FALSE' otherwise. Dec/98,
          Rick Smereka */

       int lensrc, lendest;
    #ifdef OS_UNIX
       int ret;
    #endif

       // reasonableness checks

       if (src == (char *)NULL || dest == (char *)NULL)
          return(FALSE);

       lensrc = strlen(src);
       lendest = strlen(dest);

       if (!lensrc || !lendest)
          return(FALSE);

       // first, attempt a normal 'rename'

       if (!rename(src, dest))
          return(TRUE);

    #ifdef OS_UNIX
       ret = errno;

       if (ret != EXDEV)
          return(FALSE);
    #endif

       // normal rename failed, use copy

       if (!filecopy(src, dest))
          return(FALSE);

       // delete source file

       (void)unlink(src);
       return(TRUE);
    }

    int write_dos_line(FILE *out, char *buf)
    {
       /* Write a text line with DOS/Windoze line delimiters (cr/lf).
          The file 'out' must have been opened for binary output.
          Function returns 'TRUE' if the line was successfully
          written, 'FALSE' otherwise. */

       char *fbuf;
       int len;

       if (out == (FILE *)NULL || buf == (char *)NULL)
          return(FALSE);

       len = strlen(buf);

       if ((fbuf = (char *)malloc(len + 3)) == (char *)NULL)
          return(FALSE);

       sprintf(fbuf, "%s%c%c", buf, (unsigned char)EOLL,
               (unsigned char)EOL);

       if (fwrite(fbuf, 1, len + 2, out) != len + 2)
          {
          free(fbuf);
          return(FALSE);
          }

       free(fbuf);
       return(TRUE);
    }

    int write_unix_line(FILE *out, char *buf)
    {
       /* Write a text line with a Unix line delimiter (lf).
          The file 'out' must have been opened for binary output.
          Function returns 'TRUE' if the line was successfully
          written, 'FALSE' otherwise. */

       char *fbuf;
       int len;

       if (out == (FILE *)NULL || buf == (char *)NULL)
          return(FALSE);

       len = strlen(buf);

       if ((fbuf = (char *)malloc(len + 2)) == (char *)NULL)
          return(FALSE);

       sprintf(fbuf, "%s%c", buf, (unsigned char)EOL);

       if (fwrite(fbuf, 1, len + 1, out) != len + 1)
          {
          free(fbuf);
          return(FALSE);
          }

       free(fbuf);
       return(TRUE);
    }

/* [<][>][^][v][top][bottom][index][help] */