blob: 40f780e3453603e22a7585ab01f59f6973d63f29 [file]
/*
* Copyright (c) 2021-2026 Symas Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the Symas Corporation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "io.h"
#include "cobol-endian.h"
#include <cassert>
#include <cerrno>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
/*
* The Cobol runtime support is responsible to set the file status
* word appropriately to the application's expectations. This function
* sets the defined file status register for the file to value of the
* status parameter, except for FhErrno. For FhErrno, it sets the
* file status register to a value derived from the current value of
* errno. If the errno value is not accounted for, the high bit is
* set to 1, and the rest to errno.
*/
extern "C"
file_status_t
__gg__file_status_word( enum file_status_t status,
int error_number) {
file_status_t file_status_register;
if( status != FsErrno ) {
return status;
}
switch( error_number ) {
case 0: file_status_register = FsSuccess; break;
case EACCES: file_status_register = FsNoAccess; break;
case EDQUOT: file_status_register = FsBoundary; break;
case EEXIST: file_status_register = FsNoAccess; break;
case EFAULT: file_status_register = FsNoFile; break;
case EFBIG: file_status_register = FsBoundary; break;
case EINTR: file_status_register = FsOsError; break;
case EINVAL: file_status_register = FsWrongType; break;
case EISDIR: file_status_register = FsWrongType; break;
case ELOOP: file_status_register = FsOsError; break;
case EMFILE: file_status_register = FsOsError; break;
case ENAMETOOLONG:
file_status_register = FsWrongType; break;
case ENFILE: file_status_register = FsOsError; break;
case ENODEV: file_status_register = FsNoFile; break;
case ENOENT: file_status_register = FsNoFile; break;
case ENOMEM: file_status_register = FsOsError; break;
case ENOSPC: file_status_register = FsBoundary; break;
case ENOTDIR: file_status_register = FsNoFile; break;
case ENXIO: file_status_register = FsNoFile; break;
case EOPNOTSUPP:
file_status_register = FsOsError; break;
case EOVERFLOW: file_status_register = FsBoundary; break;
case EPERM: file_status_register = FsNoAccess; break;
case EROFS: file_status_register = FsNoAccess; break;
case ETXTBSY: file_status_register= FsWrongType; break;
case EWOULDBLOCK:
file_status_register = FsOsError; break;
default:
file_status_register = FsOsError;
break;
}
return file_status_register;
}
/*
* This function is used by libgcobol_compat_gnu.
* If status parameter is FsErrno, return the file_status_t for errno.
* If status paramter is FsSuccess, return the file_status_t for errnum parameter.
* The output is byte-swapped per MF specification.
*/
#include <cstring>
extern "C"
uint16_t
__compat_file_status_word( enum file_status_t status, int errnum) {
/* In July of 2026, I had to make this routine work on a big-endian machine.
By my recent standards, this routine is something of a mess. It was
returning a four-byte native binary file_status_t. The only place this
routine is called, however, is in cobrt-file-status.cbl, where
the function call to __compat_file_status_word expects a return value
of "01 FILE-STATUS PIC X(2) COMP-5.", which is a two-byte native binary
value. On a little-endian machine, this works because the return value is
actually just sixteen bits in the low part half of the int, and the top
two x00 bytes are discarded.
That doesn't work on a big-endian architecture, where the actual return
information is the top two bytes that are being discarded.
So, I changed this routine to return a two-byte binary value, and adjusted
the mangling accordingly. Dubner, 2026-07-04 */
switch( status ) {
case FsErrno:
errnum = errno;
break;
case FsSuccess:
break;
default:
fprintf(stderr, "status is 0x%x, (%d)\n", status, status);
assert( status == FsErrno || status == FsSuccess );
break;
}
switch( errnum ) {
case EACCES:
case EPERM:
status = FsCobRt037; // File access denied
break;
case EBADF:
status = FsCobRt034; // Incorrect mode or file descriptor
break;
case EDQUOT:
case ENOSPC:
status = FsCobRt028; // No space on device
break;
case EFBIG:
case EOVERFLOW:
status = FsCobRt194; // File size too large
break;
case EINVAL:
status = FsCobRt181; // Invalid parameter error
break;
case EIO:
status = FsCobRt033; // Physical I-O error
break;
case EISDIR:
status = FsCobRt021; // File is a directory
break;
case EMFILE:
status = FsCobRt014; // Too many files open simultaneously
break;
case ENAMETOOLONG:
status = FsCobRt188; // Filename too large
break;
case ENOENT:
status = FsCobRt013; // File not found
break;
case ENOMEM:
status = FsCobRt105; // Memory allocation error
break;
case EPIPE:
status = FsCobRt042; // Attempt to write on broken pipe
break;
case EROFS:
status = FsCobRt030; // File system is read-only
break;
default:
status = FsCobRt000; // No defined mapping for errno value
}
// This function returns 9x status in the FsCobRt range.
assert( FsCobRt000 <= status && status <= 0x09FF );
static_assert(sizeof(status) == 4);
uint16_t retval;
if( !cobol_target_big_endian() ) // cppcheck-suppress knownConditionTrueFalse
{
// Arrange little-endian output per MF definition.
retval = ((status & 0xF)<<8) + '9';
}
else
{
retval = (('9')<<8) + (status & 0xF);
}
return retval;
}