root/src/simh/sim_fio.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sim_finit
  2. sim_buf_swap_data
  3. sim_fread
  4. sim_buf_copy_swapped
  5. sim_fwrite
  6. sim_fsize_ex
  7. sim_fsize_name_ex
  8. sim_fsize_name
  9. sim_fsize
  10. sim_fopen
  11. sim_fseeko
  12. sim_ftell
  13. sim_fseeko
  14. sim_ftell
  15. sim_fseeko
  16. sim_ftell
  17. sim_fseeko
  18. sim_ftell
  19. sim_fseeko
  20. sim_ftell
  21. sim_fseek
  22. sim_set_fsize
  23. sim_set_fifo_nonblock
  24. sim_set_fsize
  25. sim_set_fifo_nonblock

   1 /*
   2  * sim_fio.c: simulator file I/O library
   3  *
   4  * vim: filetype=c:tabstop=4:ai:expandtab
   5  * SPDX-License-Identifier: MIT
   6  * scspell-id: bc8c09f8-f62a-11ec-9723-80ee73e9b8e7
   7  *
   8  * ---------------------------------------------------------------------------
   9  *
  10  * Copyright (c) 1993-2008 Robert M. Supnik
  11  * Copyright (c) 2021-2023 The DPS8M Development Team
  12  *
  13  * Permission is hereby granted, free of charge, to any person obtaining a
  14  * copy of this software and associated documentation files (the "Software"),
  15  * to deal in the Software without restriction, including without limitation
  16  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  17  * and/or sell copies of the Software, and to permit persons to whom the
  18  * Software is furnished to do so, subject to the following conditions:
  19  *
  20  * The above copyright notice and this permission notice shall be included
  21  * in all copies or substantial portions of the Software.
  22  *
  23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  24  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  25  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  26  * ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  27  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
  28  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  29  * SOFTWARE.
  30  *
  31  * Except as contained in this notice, the name of Robert M. Supnik shall not
  32  * be used in advertising or otherwise to promote the sale, use or other
  33  * dealings in this Software without prior written authorization from
  34  * Robert M. Supnik.
  35  *
  36  * ---------------------------------------------------------------------------
  37  */
  38 
  39 /*
  40  * This library includes:
  41  *
  42  * sim_finit            -       initialize package
  43  * sim_fopen            -       open file
  44  * sim_fread            -       endian independent read (formerly fxread)
  45  * sim_write            -       endian independent write (formerly fxwrite)
  46  * sim_fseek            -       conditionally extended (>32b) seek (
  47  * sim_fseeko           -       extended seek (>32b if available)
  48  * sim_fsize            -       get file size
  49  * sim_fsize_name       -       get file size of named file
  50  * sim_fsize_ex         -       get file size as a t_offset
  51  * sim_fsize_name_ex    -       get file size as a t_offset of named file
  52  * sim_buf_copy_swapped -       copy data swapping elements along the way
  53  * sim_buf_swap_data    -       swap data elements inplace in buffer
  54  */
  55 
  56 #include <fcntl.h>
  57 #include <sys/file.h>
  58 #include <sys/types.h>
  59 #include <sys/stat.h>
  60 
  61 #include "sim_defs.h"
  62 
  63 #include "../decNumber/decContext.h"
  64 #include "../decNumber/decNumberLocal.h"
  65 
  66 #ifndef DECLITEND
  67 # error Unknown platform endianness
  68 #endif /* ifndef DECLITEND */
  69 
  70 #ifdef TESTING
  71 # undef FREE
  72 # define FREE(p) free(p)
  73 #endif /* ifdef TESTING */
  74 
  75 t_bool sim_end;                     /* TRUE = little endian, FALSE = big endian */
  76 t_bool sim_taddr_64;                /* t_addr is > 32b and Large File Support available */
  77 t_bool sim_toffset_64;              /* Large File (>2GB) file I/O Support available */
  78 
  79 /*
  80  * OS-independent, endian independent binary I/O package
  81  *
  82  * For consistency, all binary data read and written by the simulator
  83  * is stored in little endian data order.  That is, in a multi-byte
  84  * data item, the bytes are written out right to left, low order byte
  85  * to high order byte.  On a big endian host, data is read and written
  86  * from high byte to low byte.  Consequently, data written on a little
  87  * endian system must be byte reversed to be usable on a big endian
  88  * system, and vice versa.
  89  *
  90  * These routines are analogs of the standard C runtime routines
  91  * fread and fwrite.  If the host is little endian, or the data items
  92  * are size char, then the calls are passed directly to fread or
  93  * fwrite.  Otherwise, these routines perform the necessary byte swaps.
  94  * Sim_fread swaps in place, sim_fwrite uses an intermediate buffer.
  95  */
  96 
  97 int32 sim_finit (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  98 {
  99 sim_end = DECLITEND;
 100 sim_toffset_64 = (sizeof(t_offset) > sizeof(int32));    /* Large File (>2GB) support */
 101 /*CONSTCOND*/
 102 sim_taddr_64 = sim_toffset_64 && (sizeof(t_addr) > sizeof(int32));
 103 return sim_end;
 104 }
 105 
 106 void sim_buf_swap_data (void *bptr, size_t size, size_t count)
     /* [previous][next][first][last][top][bottom][index][help] */
 107 {
 108 uint32 j;
 109 int32 k;
 110 unsigned char by, *sptr, *dptr;
 111 
 112 if (sim_end || (count == 0) || (size == sizeof (char)))
 113     return;
 114 for (j = 0, dptr = sptr = (unsigned char *) bptr;       /* loop on items */
 115      j < count; j++) {
 116     for (k = (int32)(size - 1); k >= (((int32) size + 1) / 2); k--) {
 117         by = *sptr;                                     /* swap end-for-end */
 118         *sptr++ = *(dptr + k);
 119         *(dptr + k) = by;
 120         }
 121     sptr = dptr = dptr + size;                          /* next item */
 122     }
 123 }
 124 
 125 size_t sim_fread (void *bptr, size_t size, size_t count, FILE *fptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 126 {
 127 size_t c;
 128 
 129 if ((size == 0) || (count == 0))                        /* check arguments */
 130     return 0;
 131 c = fread (bptr, size, count, fptr);                    /* read buffer */
 132 if (sim_end || (size == sizeof (char)) || (c == 0))     /* le, byte, or err? */
 133     return c;                                           /* done */
 134 sim_buf_swap_data (bptr, size, count);
 135 return c;
 136 }
 137 
 138 void sim_buf_copy_swapped (void *dbuf, const void *sbuf, size_t size, size_t count)
     /* [previous][next][first][last][top][bottom][index][help] */
 139 {
 140 size_t j;
 141 int32 k;
 142 const unsigned char *sptr = (const unsigned char *)sbuf;
 143 unsigned char *dptr = (unsigned char *)dbuf;
 144 
 145 if (sim_end || (size == sizeof (char))) {
 146     memcpy (dptr, sptr, size * count);
 147     return;
 148     }
 149 for (j = 0; j < count; j++) {                           /* loop on items */
 150     for (k = (int32)(size - 1); k >= 0; k--)
 151         *(dptr + k) = *sptr++;
 152     dptr = dptr + size;
 153     }
 154 }
 155 
 156 size_t sim_fwrite (const void *bptr, size_t size, size_t count, FILE *fptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 157 {
 158 size_t c, nelem, nbuf, lcnt, total;
 159 int32 i;
 160 const unsigned char *sptr;
 161 unsigned char *sim_flip;
 162 
 163 if ((size == 0) || (count == 0))                        /* check arguments */
 164     return 0;
 165 if (sim_end || (size == sizeof (char)))                 /* le or byte? */
 166     return fwrite (bptr, size, count, fptr);            /* done */
 167 sim_flip = (unsigned char *)malloc(FLIP_SIZE);
 168 if (!sim_flip)
 169     return 0;
 170 nelem = FLIP_SIZE / size;                               /* elements in buffer */
 171 nbuf = count / nelem;                                   /* number buffers */
 172 lcnt = count % nelem;                                   /* count in last buf */
 173 if (lcnt) nbuf = nbuf + 1;
 174 else lcnt = nelem;
 175 total = 0;
 176 sptr = (const unsigned char *) bptr;                    /* init input ptr */
 177 for (i = (int32)nbuf; i > 0; i--) {                     /* loop on buffers */
 178     c = (i == 1)? lcnt: nelem;
 179     sim_buf_copy_swapped (sim_flip, sptr, size, c);
 180     sptr = sptr + size * count;
 181     c = fwrite (sim_flip, size, c, fptr);
 182     if (c == 0) {
 183         FREE(sim_flip);
 184         return total;
 185         }
 186     total = total + c;
 187     }
 188 FREE(sim_flip);
 189 return total;
 190 }
 191 
 192 /* Forward Declaration */
 193 
 194 t_offset sim_ftell (FILE *st);
 195 
 196 /* Get file size */
 197 
 198 t_offset sim_fsize_ex (FILE *fp)
     /* [previous][next][first][last][top][bottom][index][help] */
 199 {
 200 t_offset pos, sz;
 201 
 202 if (fp == NULL)
 203     return 0;
 204 pos = sim_ftell (fp);
 205 if (sim_fseek (fp, 0, SEEK_END))
 206   return 0;
 207 sz = sim_ftell (fp);
 208 if (sim_fseeko (fp, pos, SEEK_SET))
 209   return 0;
 210 return sz;
 211 }
 212 
 213 t_offset sim_fsize_name_ex (const char *fname)
     /* [previous][next][first][last][top][bottom][index][help] */
 214 {
 215 FILE *fp;
 216 t_offset sz;
 217 
 218 if ((fp = sim_fopen (fname, "rb")) == NULL)
 219     return 0;
 220 sz = sim_fsize_ex (fp);
 221 fclose (fp);
 222 return sz;
 223 }
 224 
 225 uint32 sim_fsize_name (const char *fname)
     /* [previous][next][first][last][top][bottom][index][help] */
 226 {
 227 return (uint32)(sim_fsize_name_ex (fname));
 228 }
 229 
 230 uint32 sim_fsize (FILE *fp)
     /* [previous][next][first][last][top][bottom][index][help] */
 231 {
 232 return (uint32)(sim_fsize_ex (fp));
 233 }
 234 
 235 /* OS-dependent routines */
 236 
 237 /* Optimized file open */
 238 
 239 FILE *sim_fopen (const char *file, const char *mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 240 {
 241 FILE *fsc = NULL;
 242 #if defined(USE_FCNTL) || defined(USE_FLOCK)
 243 # include <fcntl.h>
 244 # include <sys/stat.h>
 245 # include <sys/types.h>
 246 int writable = 0;
 247 int rc = 0;
 248 if (strstr(mode, "+") != NULL)
 249   writable = 1;
 250 if (strstr(mode, "w") != NULL)
 251   writable = 1;
 252 if (strstr(mode, "a") != NULL)
 253   writable = 1;
 254 #endif /* if defined(USE_FCNTL) || defined(USE_FLOCK) */
 255 #if (defined (__linux) || defined (__linux__) || defined (_AIX)) && !defined (DONT_DO_LARGEFILE)
 256 fsc = fopen64 (file, mode);
 257 #else
 258 fsc = fopen (file, mode);
 259 #endif
 260 #if defined(USE_FCNTL)
 261 struct flock lock;
 262 memset (&lock, 0, sizeof(lock));
 263 lock.l_type = F_WRLCK;
 264 if (writable && !sim_nolock) {
 265   if (fsc != NULL)
 266     rc = fcntl (fileno(fsc), F_SETLK, &lock);
 267   if (rc < 0) {
 268     if (!sim_quiet) {
 269       sim_printf ("%s(%s): %s",
 270                   __func__, mode, strerror(errno));
 271       if (fcntl(fileno(fsc), F_GETLK, &lock) == 0 && lock.l_pid > 0)
 272         sim_printf (" (locked by PID %lu)",
 273                    (unsigned long)lock.l_pid);
 274       sim_printf ("\r\n");
 275     }
 276     if (!sim_iglock) return NULL;
 277   }
 278 }
 279 #elif defined(USE_FLOCK) /* if defined(USE_FCNTL) */
 280 if (writable && !sim_nolock) {
 281   if (fsc != NULL)
 282     rc = flock (fileno(fsc), LOCK_EX | LOCK_NB);
 283   if (rc < 0) {
 284     if (!sim_quiet)
 285       sim_printf ("%s(%s): %s (locked?)\r\n",
 286                   __func__, mode, strerror(errno));
 287     if (!sim_iglock) return NULL;
 288   }
 289 }
 290 #endif /* elif defined(USE_FLOCK) */
 291 return fsc;
 292 }
 293 
 294 #if !defined (DONT_DO_LARGEFILE)
 295 
 296 # if ((defined(__sun) || defined(__sun__)) && defined(_LARGEFILE_SOURCE))
 297 #  define S_SIM_IO_FSEEK_EXT_ 1
 298 int sim_fseeko (FILE *st, t_offset offset, int whence)
     /* [previous][next][first][last][top][bottom][index][help] */
 299 {
 300 return fseeko (st, (off_t)offset, whence);
 301 }
 302 
 303 t_offset sim_ftell (FILE *st)
     /* [previous][next][first][last][top][bottom][index][help] */
 304 {
 305 return (t_offset)(ftello (st));
 306 }
 307 
 308 # endif
 309 
 310 /* Windows */
 311 
 312 # if defined (_WIN32)
 313 #  define S_SIM_IO_FSEEK_EXT_ 1
 314 #  include <sys/stat.h>
 315 
 316 int sim_fseeko (FILE *st, t_offset offset, int whence)
     /* [previous][next][first][last][top][bottom][index][help] */
 317 {
 318 fpos_t fileaddr;
 319 struct _stati64 statb;
 320 
 321 switch (whence) {
 322 
 323     case SEEK_SET:
 324         fileaddr = (fpos_t)offset;
 325         break;
 326 
 327     case SEEK_END:
 328         if (_fstati64 (_fileno (st), &statb))
 329             return (-1);
 330         fileaddr = statb.st_size + offset;
 331         break;
 332     case SEEK_CUR:
 333         if (fgetpos (st, &fileaddr))
 334             return (-1);
 335         fileaddr = fileaddr + offset;
 336         break;
 337 
 338     default:
 339         errno = EINVAL;
 340         return (-1);
 341         }
 342 
 343 return fsetpos (st, &fileaddr);
 344 }
 345 
 346 t_offset sim_ftell (FILE *st)
     /* [previous][next][first][last][top][bottom][index][help] */
 347 {
 348 fpos_t fileaddr;
 349 if (fgetpos (st, &fileaddr))
 350     return (-1);
 351 return (t_offset)fileaddr;
 352 }
 353 
 354 # endif                                                  /* end Windows */
 355 
 356 /* Linux */
 357 
 358 # if defined (__linux) || defined (__linux__) || defined (_AIX)
 359 #  define S_SIM_IO_FSEEK_EXT_ 1
 360 int sim_fseeko (FILE *st, t_offset xpos, int origin)
     /* [previous][next][first][last][top][bottom][index][help] */
 361 {
 362 return fseeko64 (st, (off64_t)xpos, origin);
 363 }
 364 
 365 t_offset sim_ftell (FILE *st)
     /* [previous][next][first][last][top][bottom][index][help] */
 366 {
 367 return (t_offset)(ftello64 (st));
 368 }
 369 
 370 # endif                                                  /* end Linux with LFS */
 371 
 372 /* Apple */
 373 
 374 # if defined (__APPLE__)          || \
 375     defined (__FreeBSD__)         || \
 376     defined (__NetBSD__)          || \
 377     defined (__OpenBSD__)         || \
 378     defined (__CYGWIN__)
 379 #  define S_SIM_IO_FSEEK_EXT_ 1
 380 int sim_fseeko (FILE *st, t_offset xpos, int origin)
     /* [previous][next][first][last][top][bottom][index][help] */
 381 {
 382 return fseeko (st, (off_t)xpos, origin);
 383 }
 384 
 385 t_offset sim_ftell (FILE *st)
     /* [previous][next][first][last][top][bottom][index][help] */
 386 {
 387 return (t_offset)(ftello (st));
 388 }
 389 
 390 # endif  /* end Apple */
 391 #endif /* !DONT_DO_LARGEFILE */
 392 
 393 /* Default: no OS-specific routine has been defined */
 394 
 395 #if !defined (S_SIM_IO_FSEEK_EXT_)
 396 int sim_fseeko (FILE *st, t_offset xpos, int origin)
     /* [previous][next][first][last][top][bottom][index][help] */
 397 {
 398 return fseek (st, (long) xpos, origin);
 399 }
 400 
 401 t_offset sim_ftell (FILE *st)
     /* [previous][next][first][last][top][bottom][index][help] */
 402 {
 403 return (t_offset)(ftell (st));
 404 }
 405 #endif
 406 
 407 int sim_fseek (FILE *st, t_addr offset, int whence)
     /* [previous][next][first][last][top][bottom][index][help] */
 408 {
 409 return sim_fseeko (st, (t_offset)offset, whence);
 410 }
 411 
 412 #if defined(_WIN32)
 413 # include <io.h>
 414 int sim_set_fsize (FILE *fptr, t_addr size)
     /* [previous][next][first][last][top][bottom][index][help] */
 415 {
 416 return _chsize(_fileno(fptr), (long)size);
 417 }
 418 
 419 int sim_set_fifo_nonblock (FILE *fptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 420 {
 421 return -1;
 422 }
 423 
 424 #else /* !defined(_WIN32) */
 425 # include <unistd.h>
 426 int sim_set_fsize (FILE *fptr, t_addr size)
     /* [previous][next][first][last][top][bottom][index][help] */
 427 {
 428 return ftruncate(fileno(fptr), (off_t)size);
 429 }
 430 
 431 # include <sys/types.h>
 432 # include <sys/stat.h>
 433 # include <fcntl.h>
 434 
 435 int sim_set_fifo_nonblock (FILE *fptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 436 {
 437 struct stat stbuf;
 438 
 439 if (!fptr || fstat (fileno(fptr), &stbuf))
 440     return -1;
 441 # if defined(S_IFIFO) && defined(O_NONBLOCK)
 442 if ((stbuf.st_mode & S_IFIFO)) {
 443     int flags = fcntl(fileno(fptr), F_GETFL, 0);
 444     return fcntl(fileno(fptr), F_SETFL, flags | O_NONBLOCK);
 445     }
 446 # endif
 447 return -1;
 448 }
 449 
 450 #endif

/* [previous][next][first][last][top][bottom][index][help] */