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_fseek
  16. sim_set_fsize
  17. sim_set_fifo_nonblock
  18. sim_set_fsize
  19. 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-2025 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 #if !defined(DECLITEND)
  67 # error Unknown platform endianness
  68 #endif /* if !defined(DECLITEND) */
  69 
  70 #if defined(NO_LOCALE)
  71 # define xstrerror_l strerror
  72 #endif
  73 
  74 #if defined(FREE)
  75 # undef FREE
  76 #endif /* if defined(FREE) */
  77 #define FREE(p) do  \
  78   {                 \
  79     free((p));      \
  80     (p) = NULL;     \
  81   } while(0)
  82 
  83 t_bool sim_end;                     /* TRUE = little endian, FALSE = big endian */
  84 
  85 /*
  86  * OS-independent, endian independent binary I/O package
  87  *
  88  * For consistency, all binary data read and written by the simulator
  89  * is stored in little endian data order.  That is, in a multi-byte
  90  * data item, the bytes are written out right to left, low order byte
  91  * to high order byte.  On a big endian host, data is read and written
  92  * from high byte to low byte.  Consequently, data written on a little
  93  * endian system must be byte reversed to be usable on a big endian
  94  * system, and vice versa.
  95  *
  96  * These routines are analogs of the standard C runtime routines
  97  * fread and fwrite.  If the host is little endian, or the data items
  98  * are size char, then the calls are passed directly to fread or
  99  * fwrite.  Otherwise, these routines perform the necessary byte swaps.
 100  * Sim_fread swaps in place, sim_fwrite uses an intermediate buffer.
 101  */
 102 
 103 int32 sim_finit (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 104 {
 105 sim_end = DECLITEND;
 106 return sim_end;
 107 }
 108 
 109 void sim_buf_swap_data (void *bptr, size_t size, size_t count)
     /* [previous][next][first][last][top][bottom][index][help] */
 110 {
 111 size_t j;
 112 size_t k;
 113 unsigned char by, *sptr, *dptr;
 114 
 115 if (sim_end || (count == 0) || (size == sizeof (char)))
 116     return;
 117 for (j = 0, dptr = sptr = (unsigned char *) bptr;       /* loop on items */
 118      j < count; j++) {
 119     for (k = (int32)(size - 1); k >= (((int32) size + 1) / 2); k--) {
 120         by = *sptr;                                     /* swap end-for-end */
 121         *sptr++ = *(dptr + k);
 122         *(dptr + k) = by;
 123         }
 124     sptr = dptr = dptr + size;                          /* next item */
 125     }
 126 }
 127 
 128 size_t sim_fread (void *bptr, size_t size, size_t count, FILE *fptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 129 {
 130 size_t c;
 131 
 132 if ((size == 0) || (count == 0))                        /* check arguments */
 133     return 0;
 134 c = fread (bptr, size, count, fptr);                    /* read buffer */
 135 if (sim_end || (size == sizeof (char)) || (c == 0))     /* le, byte, or err? */
 136     return c;                                           /* done */
 137 sim_buf_swap_data (bptr, size, count);
 138 return c;
 139 }
 140 
 141 void sim_buf_copy_swapped (void *dbuf, const void *sbuf, size_t size, size_t count)
     /* [previous][next][first][last][top][bottom][index][help] */
 142 {
 143 size_t j;
 144 size_t k;
 145 const unsigned char *sptr = (const unsigned char *)sbuf;
 146 unsigned char *dptr = (unsigned char *)dbuf;
 147 
 148 if (sim_end || (size == sizeof (char))) {
 149     memcpy (dptr, sptr, size * count);
 150     return;
 151     }
 152 for (j = 0; j < count; j++) {                           /* loop on items */
 153     /* Unsigned countdown loop. Pre-decrement k before it's used inside the
 154        loop so that k == 0 in the loop body to process the last item, then
 155        terminate. Initialize k to size for the same reason: the pre-decrement
 156        gives us size - 1 in the loop body. */
 157     for (k = size; k > 0; /* empty */)
 158         *(dptr + --k) = *sptr++;
 159     dptr = dptr + size;
 160     }
 161 }
 162 
 163 size_t sim_fwrite (const void *bptr, size_t size, size_t count, FILE *fptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 164 {
 165 size_t c, nelem, nbuf, lcnt, total;
 166 int32 i;
 167 const unsigned char *sptr;
 168 unsigned char *sim_flip;
 169 
 170 if ((size == 0) || (count == 0))                        /* check arguments */
 171     return 0;
 172 if (sim_end || (size == sizeof (char)))                 /* le or byte? */
 173     return fwrite (bptr, size, count, fptr);            /* done */
 174 sim_flip = (unsigned char *)malloc(FLIP_SIZE);
 175 if (!sim_flip)
 176     return 0;
 177 nelem = FLIP_SIZE / size;                               /* elements in buffer */
 178 nbuf = count / nelem;                                   /* number buffers */
 179 lcnt = count % nelem;                                   /* count in last buf */
 180 if (lcnt) nbuf = nbuf + 1;
 181 else lcnt = nelem;
 182 total = 0;
 183 sptr = (const unsigned char *) bptr;                    /* init input ptr */
 184 for (i = (int32)nbuf; i > 0; i--) {                     /* loop on buffers */
 185     c = (i == 1)? lcnt: nelem;
 186     sim_buf_copy_swapped (sim_flip, sptr, size, c);
 187     sptr = sptr + size * count;
 188     c = fwrite (sim_flip, size, c, fptr);
 189     if (c == 0) {
 190         FREE(sim_flip);
 191         return total;
 192         }
 193     total = total + c;
 194     }
 195 FREE(sim_flip);
 196 return total;
 197 }
 198 
 199 /* Forward Declaration */
 200 
 201 t_offset sim_ftell (FILE *st);
 202 
 203 /* Get file size */
 204 
 205 t_offset sim_fsize_ex (FILE *fp)
     /* [previous][next][first][last][top][bottom][index][help] */
 206 {
 207 t_offset pos, sz;
 208 
 209 if (fp == NULL)
 210     return 0;
 211 pos = sim_ftell (fp);
 212 if (sim_fseek (fp, 0, SEEK_END))
 213   return 0;
 214 sz = sim_ftell (fp);
 215 if (sim_fseeko (fp, pos, SEEK_SET))
 216   return 0;
 217 return sz;
 218 }
 219 
 220 t_offset sim_fsize_name_ex (const char *fname)
     /* [previous][next][first][last][top][bottom][index][help] */
 221 {
 222 FILE *fp;
 223 t_offset sz;
 224 
 225 if ((fp = sim_fopen (fname, "rb")) == NULL)
 226     return 0;
 227 sz = sim_fsize_ex (fp);
 228 fclose (fp);
 229 return sz;
 230 }
 231 
 232 uint32 sim_fsize_name (const char *fname)
     /* [previous][next][first][last][top][bottom][index][help] */
 233 {
 234 return (uint32)(sim_fsize_name_ex (fname));
 235 }
 236 
 237 uint32 sim_fsize (FILE *fp)
     /* [previous][next][first][last][top][bottom][index][help] */
 238 {
 239 return (uint32)(sim_fsize_ex (fp));
 240 }
 241 
 242 /* OS-dependent routines */
 243 
 244 /* Optimized file open */
 245 
 246 FILE *sim_fopen (const char *file, const char *mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 247 {
 248 FILE *fsc = NULL;
 249 #if defined(USE_FCNTL) || defined(USE_FLOCK)
 250 # include <fcntl.h>
 251 # include <sys/stat.h>
 252 # include <sys/types.h>
 253 int writable = 0;
 254 int rc = 0;
 255 if (strstr(mode, "+") != NULL)
 256   writable = 1;
 257 if (strstr(mode, "w") != NULL)
 258   writable = 1;
 259 if (strstr(mode, "a") != NULL)
 260   writable = 1;
 261 #endif /* if defined(USE_FCNTL) || defined(USE_FLOCK) */
 262 fsc = fopen (file, mode);
 263 #if defined(USE_FCNTL)
 264 struct flock lock;
 265 (void)memset (&lock, 0, sizeof(lock));
 266 lock.l_type = F_WRLCK;
 267 if (writable && !sim_nolock) {
 268   if (fsc != NULL)
 269     rc = fcntl (fileno(fsc), F_SETLK, &lock);
 270   if (rc < 0) {
 271     if (!sim_quiet) {
 272       sim_printf ("%s(%s): %s [Error %d]",
 273                   __func__, mode, xstrerror_l(errno), errno);
 274       if (fcntl(fileno(fsc), F_GETLK, &lock) == 0 && lock.l_pid > 0)
 275         sim_printf (" (locked by PID %lu)",
 276                    (unsigned long)lock.l_pid);
 277       sim_printf ("\r\n");
 278     }
 279     if (!sim_iglock) {
 280       fclose(fsc);
 281       return NULL;
 282     }
 283   }
 284 }
 285 #elif defined(USE_FLOCK) /* if defined(USE_FCNTL) */
 286 if (writable && !sim_nolock) {
 287   if (fsc != NULL)
 288     rc = flock (fileno(fsc), LOCK_EX | LOCK_NB);
 289   if (rc < 0) {
 290     if (!sim_quiet)
 291       sim_printf ("%s(%s): %s [Error %d] (locked?)\r\n",
 292                   __func__, mode, xstrerror_l(errno), errno);
 293     if (!sim_iglock) return NULL;
 294   }
 295 }
 296 #endif /* elif defined(USE_FLOCK) */
 297 return fsc;
 298 }
 299 
 300 #if defined (_WIN32)
 301 # include <sys/stat.h>
 302 
 303 int sim_fseeko (FILE *st, t_offset offset, int whence)
     /* [previous][next][first][last][top][bottom][index][help] */
 304 {
 305 fpos_t fileaddr;
 306 struct _stati64 statb;
 307 
 308 switch (whence) {
 309     case SEEK_SET:
 310         fileaddr = (fpos_t)offset;
 311         break;
 312 
 313     case SEEK_END:
 314         if (_fstati64 (_fileno (st), &statb))
 315             return (-1);
 316         fileaddr = statb.st_size + offset;
 317         break;
 318     case SEEK_CUR:
 319         if (fgetpos (st, &fileaddr))
 320             return (-1);
 321         fileaddr = fileaddr + offset;
 322         break;
 323 
 324     default:
 325         errno = EINVAL;
 326         return (-1);
 327         }
 328 
 329 return fsetpos (st, &fileaddr);
 330 }
 331 
 332 t_offset sim_ftell (FILE *st)
     /* [previous][next][first][last][top][bottom][index][help] */
 333 {
 334 fpos_t fileaddr;
 335 if (fgetpos (st, &fileaddr))
 336     return (-1);
 337 return (t_offset)fileaddr;
 338 }
 339 
 340 #else
 341 
 342 int sim_fseeko (FILE *st, t_offset xpos, int origin)
     /* [previous][next][first][last][top][bottom][index][help] */
 343 {
 344 return fseeko (st, (off_t)xpos, origin);
 345 }
 346 
 347 t_offset sim_ftell (FILE *st)
     /* [previous][next][first][last][top][bottom][index][help] */
 348 {
 349 return (t_offset)(ftello (st));
 350 }
 351 
 352 #endif
 353 
 354 int sim_fseek (FILE *st, t_addr offset, int whence)
     /* [previous][next][first][last][top][bottom][index][help] */
 355 {
 356 return sim_fseeko (st, (t_offset)offset, whence);
 357 }
 358 
 359 #if defined(_WIN32)
 360 # include <io.h>
 361 int sim_set_fsize (FILE *fptr, t_addr size)
     /* [previous][next][first][last][top][bottom][index][help] */
 362 {
 363 return _chsize(_fileno(fptr), (long)size);
 364 }
 365 
 366 int sim_set_fifo_nonblock (FILE *fptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 367 {
 368 return -1;
 369 }
 370 
 371 #else /* !defined(_WIN32) */
 372 # include <unistd.h>
 373 int sim_set_fsize (FILE *fptr, t_addr size)
     /* [previous][next][first][last][top][bottom][index][help] */
 374 {
 375 return ftruncate(fileno(fptr), (off_t)size);
 376 }
 377 
 378 # include <sys/types.h>
 379 # include <sys/stat.h>
 380 # include <fcntl.h>
 381 
 382 int sim_set_fifo_nonblock (FILE *fptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 383 {
 384 struct stat stbuf;
 385 
 386 if (!fptr || fstat (fileno(fptr), &stbuf))
 387     return -1;
 388 # if defined(S_IFIFO) && defined(O_NONBLOCK)
 389 if ((stbuf.st_mode & S_IFIFO)) {
 390     int flags = fcntl(fileno(fptr), F_GETFL, 0);
 391     return fcntl(fileno(fptr), F_SETFL, flags | O_NONBLOCK);
 392     }
 393 # endif
 394 return -1;
 395 }
 396 
 397 #endif

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