diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..fe3b4e7 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Pdos-PdAndro \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..b589d56 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml new file mode 100644 index 0000000..d8426fd --- /dev/null +++ b/.idea/deploymentTargetDropDown.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..66ff961 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,20 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..d651ee7 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/NOCOPYRIGHT.txt b/NOCOPYRIGHT.txt new file mode 100644 index 0000000..2425884 --- /dev/null +++ b/NOCOPYRIGHT.txt @@ -0,0 +1,22 @@ +====================================================================== + + Worldwide PUBLIC DOMAIN dedication + + The authors disclaim copyright to this software. + + Anyone is free to copy, modify, publish, use, compile, sell, or + distribute this software, either in source code form or as a + compiled binary, for any purpose, commercial or non-commercial, + and by any means. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT OF ANY PATENT, COPYRIGHT, TRADE SECRET OR OTHER + PROPRIETARY RIGHT. + IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES + OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +====================================================================== diff --git a/README.md b/README.md new file mode 100644 index 0000000..5219688 --- /dev/null +++ b/README.md @@ -0,0 +1,35 @@ + +# Android armeabi-v7a (32bit ARM) apk for [PDOS](https://pdos.org) + +The source code is Public Domain except the gradle directory and gradlew.* + +## The application requires a hardware keyboard attached to your smartphone. + +This app will create 2 files in your "Download/" folder (hi.txt and pcomm.arm) + +## How to use it + +After message "please enter a command" enter: ``pcomm.exe`` + + +![screen](doc/screen.jpg) + + +## Developement + +If you want to make change to the APK, you need to sign it before install it : +``` +zip -r app.zip ./app/ + +mv app.zip app.apk + +keytool -genkey -keyalg RSA -alias mykeystore -keystore mykeystore.jks -storepass 12345678 -validity 360 + +apksigner sign --ks release.jks app.apk + +``` + +https://docs.oracle.com/en/java/javase/12/tools/keytool.html + +https://developer.android.com/studio/command-line/apksigner + diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..cabc34d --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,57 @@ +plugins { + id 'com.android.application' + id 'org.jetbrains.kotlin.android' +} + +android { + namespace 'com.cod5.pdos_pdandro' + compileSdk 33 + + defaultConfig { + applicationId "com.cod5.pdos_pdandro" + minSdk 21 + targetSdk 33 + versionCode 1 + versionName "1.0" + ndk.abiFilters 'armeabi-v7a', 'x86' + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + debug { + jniDebuggable true + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.18.1' + } + } + buildFeatures { + viewBinding true + } + ndkVersion '23.1.7779620' +} + +dependencies { + + implementation 'androidx.core:core-ktx:1.9.0' + implementation 'androidx.appcompat:appcompat:1.6.1' + implementation 'com.google.android.material:material:1.8.0' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.5' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..d71d978 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/assets/arm64-v8a b/app/src/main/assets/arm64-v8a new file mode 120000 index 0000000..6a6a4c9 --- /dev/null +++ b/app/src/main/assets/arm64-v8a @@ -0,0 +1 @@ +armeabi-v7a \ No newline at end of file diff --git a/app/src/main/assets/armeabi-v7a/pcomm.exe b/app/src/main/assets/armeabi-v7a/pcomm.exe new file mode 100644 index 0000000..a4eaaa0 Binary files /dev/null and b/app/src/main/assets/armeabi-v7a/pcomm.exe differ diff --git a/app/src/main/assets/x86/pcomm.exe b/app/src/main/assets/x86/pcomm.exe new file mode 100644 index 0000000..714777b Binary files /dev/null and b/app/src/main/assets/x86/pcomm.exe differ diff --git a/app/src/main/assets/x86_64 b/app/src/main/assets/x86_64 new file mode 120000 index 0000000..f4bad79 --- /dev/null +++ b/app/src/main/assets/x86_64 @@ -0,0 +1 @@ +x86 \ No newline at end of file diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt new file mode 100644 index 0000000..f4a3cf1 --- /dev/null +++ b/app/src/main/cpp/CMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required(VERSION 3.18.1) + +project("pdos_pdandro") + +if (${ANDROID_ABI} STREQUAL "armeabi-v7a" OR ${ANDROID_ABI} STREQUAL "x86") +#if (${ANDROID_ABI} STREQUAL "x86") +add_subdirectory(${CMAKE_SOURCE_DIR}/pdpclib/${ANDROID_ABI}) +add_subdirectory(${CMAKE_SOURCE_DIR}/bios/${ANDROID_ABI}) +#add_subdirectory(${CMAKE_SOURCE_DIR}/pcomm/${ANDROID_ABI}) +endif() + +add_executable( + libpdos.so + + pdos.c) + +add_executable( + libls.so + + ls.c) + +add_executable(libtest.so + IMPORTED + ) + diff --git a/app/src/main/cpp/bios/armeabi-v7a/CMakeLists.txt b/app/src/main/cpp/bios/armeabi-v7a/CMakeLists.txt new file mode 100644 index 0000000..094d582 --- /dev/null +++ b/app/src/main/cpp/bios/armeabi-v7a/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.18.1) + +project("pdos_pdandro") +enable_language(C) + +add_executable( + libbios.so + + ${CMAKE_SOURCE_DIR}/pdpclib/${ANDROID_ABI}/linstart.c + bios.c + exeload.c +) + +target_compile_options(libbios.so PRIVATE + $<$:-ffreestanding -fno-builtin -fno-stack-protector -nostdinc -nostdlib -O0 -D__UNOPT__ -D__ARM__ -DNEED_AOUT -DNEED_MPROTECT -I${CMAKE_SOURCE_DIR}/pdpclib/${ANDROID_ABI} -I${CMAKE_CURRENT_SOURCE_DIR}> +) + +target_link_options(libbios.so PRIVATE "-Wl,-nostdlib") +target_link_options(libbios.so PRIVATE "-nostdlib") + +target_link_libraries(libbios.so PRIVATE pdpclib) + diff --git a/app/src/main/cpp/bios/armeabi-v7a/__os.h b/app/src/main/cpp/bios/armeabi-v7a/__os.h new file mode 100644 index 0000000..a504a15 --- /dev/null +++ b/app/src/main/cpp/bios/armeabi-v7a/__os.h @@ -0,0 +1,156 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* os.h - C library exported by OS */ +/* */ +/*********************************************************************/ + +/* Note that a BIOS that uses this interface is unlikely to populate + all of these things, especially if running on hardware of the + 1980s era. You can expect restrictions such as only fopen (of a + filename such as "0x80"), fread, fwrite, fseek actually working, + and only working if you give them offsets and lengths that are + multiples of 512 and/or the sector size. Also the buffer that + data is read into/written from may have alignment requirements + such as 16 bytes or 512 bytes. It depends on what is out there. */ + +#ifndef __OS_INCLUDED +#define __OS_INCLUDED + +#include +#include +#include +#include + +typedef struct { + /* a BIOS may not have this, as it implies the existence of a + complete C library, not typical for a real BIOS. Even an OS + won't necessarily have this. */ + int (*__start)(char *p); + /* a BIOS will typically have a block of memory it expects you + to malloc. This is the size. A BIOS may or may not allow + arbitrary mallocs that differ from this size. */ + size_t mem_amt; + /* if this is true, it means that mem_amt is adjusted every + time you call malloc, so that you can get multiple chunks + of memory instead of requiring only contiguous memory. + Only applicable to a BIOS. */ + int mem_rpt; + /* the name of the program being executed. Could be an empty + string */ + char *prog_name; + /* The single parameter passed to this program. E.g. a suggested + disk name to be opened. Will at least be an empty string */ + char *prog_parm; + int (*Xprintf)(const char *format, ...); + int (**main)(int argc, char **argv); + void *(*malloc)(size_t size); + FILE *Xstdin; + FILE *Xstdout; +#ifdef __SUBC__ + void * (*Xfopen)(const char *filename, const char *mode); +#else + FILE *(*Xfopen)(const char *filename, const char *mode); +#endif + int (*Xfseek)(FILE *stream, long offset, int whence); + size_t (*Xfread)(void *ptr, size_t size, size_t nmemb, FILE *stream); + int (*Xfclose)(FILE *stream); + size_t (*Xfwrite)(const void *ptr, size_t size, size_t nmemb, FILE *stream); + char *(*Xfgets)(char *s, int n, FILE *stream); + char *(*strchr)(const char *s, int c); + int (*strcmp)(const char *s1, const char *s2); + int (*strncmp)(const char *s1, const char *s2, size_t n); + char *(*strcpy)(char *s1, const char *s2); + size_t (*strlen)(const char *s); + int (*Xfgetc)(FILE *stream); + int (*Xfputc)(int c, FILE *stream); + int (*Xfflush)(FILE *stream); + int (*Xsetvbuf)(FILE *stream, char *buf, int mode, size_t size); + void *(*PosGetDTA)(void); + int (*PosFindFirst)(char *pat, int attrib); + int (*PosFindNext)(void); + int (*PosGetDeviceInformation)(int handle, unsigned int *devinfo); + int (*PosSetDeviceInformation)(int handle, unsigned int devinfo); + char *(*Xctime)(const time_t *timer); + time_t (*Xtime)(time_t *timer); + int (*PosChangeDir)(const char *to); + int (*PosMakeDir)(const char *dname); + int (*PosRemoveDir)(const char *dname); + int (*Xremove)(const char *filename); + void *(*memcpy)(void *s1, const void *s2, size_t n); + char *(*strncpy)(char *s1, const char *s2, size_t n); + char *(*strcat)(char *s1, const char *s2); + FILE *Xstderr; + void (*free)(void *ptr); + void (*abort)(void); + void *(*memset)(void *s, int c, size_t n); + int (*Xfputs)(const char *s, FILE *stream); + int (*Xfprintf)(FILE *stream, const char *format, ...); + char *(*Xgetenv)(const char *name); + void *(*memmove)(void *s1, const void *s2, size_t n); + void (*Xexit)(int status); + int (*memcmp)(const void *s1, const void *s2, size_t n); + int *(*_errno)(void); /* internal use */ + char *(*Xtmpnam)(char *s); + int (*Xvfprintf)(FILE *stream, const char *format, va_list arg); + int (*Xungetc)(int c, FILE *stream); + int (*Xvsprintf)(char *s, const char *format, va_list arg); + int (*Xsprintf)(char *s, const char *format, ...); +#ifdef __SUBC__ + int (*signal)(int sig, int (*handler)()); +#else + void (*(*signal)(int sig, void (*func)(int)))(int); +#endif + int (*raise)(int sig); + void *(*Xcalloc)(size_t nmemb, size_t size); + void *(*Xrealloc)(void *ptr, size_t size); + int (*Xatoi)(const char *nptr); + long (*Xstrtol)(const char *nptr, char **endptr, int base); + unsigned long (*Xstrtoul)(const char *nptr, char **endptr, int base); + void (*Xqsort)(void *a, size_t b, size_t c, + int (*f)(const void *d, const void *e)); +#ifdef __SUBC__ + void *(*Xbsearch)(const void *key, const void *base, + size_t nmemb, size_t size, + int (*compar)()); +#else + void *(*Xbsearch)(const void *key, const void *base, + size_t nmemb, size_t size, + int (*compar)(const void *, const void *)); +#endif +#ifdef __SUBC__ + void *(*Xlocaltime)(); +#else + struct tm *(*Xlocaltime)(const time_t *timer); +#endif + clock_t (*Xclock)(void); + char *(*strerror)(int errnum); + char *(*strrchr)(const char *s, int c); + char *(*strstr)(const char *s1, const char *s2); + char *(*strpbrk)(const char *s1, const char *s2); + size_t (*strspn)(const char *s1, const char *s2); + size_t (*strcspn)(const char *s1, const char *s2); + void *(*memchr)(const void *s, int c, size_t n); + long (*Xftell)(FILE *stream); + int (*Xabs)(int j); + char *(*setlocale)(int category, const char *locale); + void (*Xperror)(const char *s); + void (*Xrewind)(FILE *stream); + char *(*strncat)(char *s1, const char *s2, size_t n); + int (*Xsscanf)(const char *s, const char *format, ...); + int (*isalnum)(int c); + int (*isxdigit)(int c); + int (*Xrename)(const char *old, const char *newnam); + void (*Xclearerr)(FILE *stream); + int (*_assert)(char *x, char *y, int z); /* internal use */ + double (*Xatof)(const char *nptr); +} OS; + +extern OS *__os; + +#endif diff --git a/app/src/main/cpp/bios/armeabi-v7a/a_out.h b/app/src/main/cpp/bios/armeabi-v7a/a_out.h new file mode 100644 index 0000000..b454011 --- /dev/null +++ b/app/src/main/cpp/bios/armeabi-v7a/a_out.h @@ -0,0 +1,34 @@ +/* written by Paul Edwards */ +/* released to the public domain */ +/* poor man's version of a.out.h - contains everything required by + pdos at time of writing */ +/* Documentation for the a.out format can be found here: + http://man.cat-v.org/unix_8th/5/a.out */ + +#define SEGMENT_SIZE 0x10000UL + +struct exec { + unsigned long a_info; + unsigned long a_text; + unsigned long a_data; + unsigned long a_bss; + unsigned long a_syms; + unsigned long a_entry; + unsigned long a_trsize; + unsigned long a_drsize; +}; + +/* First 2 bytes of a_info are magic number identifying the format. + * Mask 0xffff can be used on the a_info for checking the numbers. + * Top word should be 0x0064. */ +#define OMAGIC 0407 +#define NMAGIC 0410 +#define ZMAGIC 0413 +#define QMAGIC 0314 + +#define N_TXTOFF(e) (0x400) +#define N_TXTADDR(e) (SEGMENT_SIZE) +/* this formula doesn't work when the text size is exactly 64k */ +#define N_DATADDR(e) \ + (N_TXTADDR(e) + SEGMENT_SIZE + ((e).a_text & 0xffff0000UL)) +#define N_BSSADDR(e) (N_DATADDR(e) + (e).a_data) diff --git a/app/src/main/cpp/bios/armeabi-v7a/bios.c b/app/src/main/cpp/bios/armeabi-v7a/bios.c new file mode 100644 index 0000000..8bd97dc --- /dev/null +++ b/app/src/main/cpp/bios/armeabi-v7a/bios.c @@ -0,0 +1,454 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* bios - generic BIOS that exports the C library */ +/* */ +/*********************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "__os.h" +#include "exeload.h" + +extern int __genstart; +extern int (*__genmain)(int argc, char **argv); + +/* A BIOS is meant to be machine-specific, so this is not a big deal */ +#if 1 +#define PATH "" +/* #define PATH "./" */ +#else +#define PATH "/storage/emulated/0/Download/" +#endif + +#define MEMAMT 24*1000*1000 + +#if defined(__gnu_linux__) || defined(__ARM__) +extern int __start(int argc, char **argv); +#else +extern int __start(char *p); +#endif + +int their_start(char *parm); + +#ifndef __SUBC__ +static int getmainargs(int *_Argc, + char ***_Argv); +#endif + +void *PosGetDTA(void); + +#if defined(__gnu_linux__) || defined(__ARM__) +#include + +static int dirfile; + +static DTA origdta; + +int PosFindFirst(char *pat, int attrib); +int PosFindNext(void); +#endif + +static OS bios = { their_start, 0, 0, NULL, NULL, printf, 0, malloc, NULL, NULL, + fopen, fseek, fread, fclose, fwrite, fgets, strchr, + strcmp, strncmp, strcpy, strlen, fgetc, fputc, + fflush, setvbuf, + PosGetDTA, +#if defined(__gnu_linux__) || defined(__ARM__) + PosFindFirst, PosFindNext, +#else + 0, 0, +#endif + 0, 0, + ctime, time, +#if defined(__gnu_linux__) || defined(__ARM__) + PosChangeDir, PosMakeDir, PosRemoveDir, +#else + 0, 0, 0, +#endif + remove, + memcpy, strncpy, strcat, 0 /* stderr */, free, abort, memset, fputs, fprintf, + getenv, memmove, exit, memcmp, _errno, tmpnam, vfprintf, ungetc, vsprintf, + sprintf, signal, raise, calloc, realloc, atoi, strtol, strtoul, qsort, + bsearch, localtime, clock, strerror, strrchr, strstr, strpbrk, strspn, + strcspn, memchr, ftell, abs, setlocale, perror, rewind, strncat, sscanf, + isalnum, isxdigit, rename, clearerr, _assert, atof, +}; + +static char buf[400]; +static char cmd[300]; + +static int (*genstart)(OS *bios); + +int main(int argc, char **argv) +{ + unsigned char *p; + unsigned char *entry_point; + int rc; + char *prog_name; + int need_usage = 0; + int valid = 0; + int shell = 0; + FILE *scr = NULL; + int quiet = 0; + + bios.mem_amt = MEMAMT; + bios.Xstdin = stdin; + bios.Xstdout = stdout; + bios.Xstderr = stderr; + __genstart = 1; + bios.main = &__genmain; + + /* parameters override everything */ + if (argc > 1) + { + if (strcmp(argv[1], "-quiet") == 0) + { + quiet = 1; + argc--; + argv++; + } + if (argc > 1) + { + if (strcmp(argv[1], "-shell") == 0) + { + shell = 1; + argc--; + argv++; + } + } + if (argc > 1) + { + if (strcmp(argv[1], "-quiet") == 0) + { + quiet = 1; + argc--; + argv++; + } + } + /* if they've typed in --help or anything, give them usage */ + if (argv[1][0] == '-') + { + need_usage = 1; + } + else if (argc == 2) + { + bios.prog_name = argv[1]; + bios.prog_parm = ""; + valid = 1; + } + else if (argc == 3) + { + bios.prog_name = argv[1]; + bios.prog_parm = argv[2]; + valid = 1; + } + else + { + need_usage = 1; + } + } + if (!quiet && !need_usage) + { + printf("bios starting\n"); + } + if (!valid && !need_usage) + { + /* an individual command(s) overrides a shell */ + scr = fopen("biosauto.cmd", "r"); + if (scr != NULL) + { + valid = 1; + } + else + { + scr = fopen("biosauto.shl", "r"); + if (scr != NULL) + { + valid = 1; + shell = 1; + } + } + } + if (!valid && !need_usage) + { + scr = stdin; + printf("enter commands, press enter to exit\n"); + } + do + { + if (need_usage) break; /* should put this before do */ + if (scr != NULL) + { + if (fgets(buf, sizeof buf, scr) == NULL) + { + break; + } + p = strchr(buf, '\n'); + if (p != NULL) + { + *p = '\0'; + } + if (buf[0] == '\0') + { + if (scr == stdin) + { + break; + } + continue; + } + if (buf[0] == '#') + { + continue; + } + bios.prog_name = buf; + p = strchr(buf, ' '); + if (p != NULL) + { + *p = '\0'; + bios.prog_parm = p + 1; + } + else + { + bios.prog_parm = ""; + } + } + + p = calloc(1, 5000000); + if (p == NULL) + { + printf("insufficient memory\n"); + return (EXIT_FAILURE); + } + if (exeloadDoload(&entry_point, bios.prog_name, &p) != 0) + { + printf("failed to load executable\n"); + return (EXIT_FAILURE); + } + genstart = (void *)entry_point; + /* printf("first byte of code is %02X\n", *(unsigned char *)entry_point); */ + +#ifdef NEED_DELAY + for (rc = 0; rc < 3; rc++) + { + printf("please accept a delay before we execute program " + "in BSS memory\n"); + } +#endif + +#if 1 + rc = genstart(&bios); +#else + rc = 0; +#endif + if (!quiet) + { + printf("return from called program is %d\n", rc); + } + free(p); + + if (scr == NULL) + { + break; + } + } while (1); + + if (need_usage) + { + printf("usage: bios [options] [single parm]\n"); + printf("allows execution of non-standard executables\n"); + printf("if no parameters are given and biosauto.cmd is given,\n"); + printf("commands are read, executed and there will be a pause\n"); + printf("otherwise, biosauto.shl is looked for, and there will be\n"); + printf("no pause, because it is assumed to be a shell\n"); + printf("valid options are -quiet and -shell\n"); + printf("e.g. bios -shell pdos.exe uc8086.vhd\n"); + printf("e.g. bios pcomm.exe\n"); + return (EXIT_FAILURE); + } + if (scr == stdin) + { + /* pause has already been done, effectively */ + } + else if (!shell) + { + printf("press enter to exit\n"); + fgets(buf, sizeof buf, stdin); + } + if ((scr != NULL) && (scr != stdin)) + { + fclose(scr); + } + if (!quiet) + { + printf("bios exiting\n"); + } + return (0); +} + +int their_start(char *parm) +{ +#if defined(__gnu_linux__) || defined(__ARM__) + int argc; + char **argv; + getmainargs(&argc, &argv); + __start(argc, argv); +#else + __start(parm); +#endif +} + + +#define MAXPARMS 50 + +#ifndef __SUBC__ +static int getmainargs(int *_Argc, + char ***_Argv) +{ + char *p; + int x; + int argc; + static char *argv[MAXPARMS + 1]; + static char *env[] = {NULL}; + + p = cmd; + + argv[0] = p; + p = strchr(p, ' '); + if (p == NULL) + { + p = ""; + } + else + { + *p = '\0'; + p++; + } + + while (*p == ' ') + { + p++; + } + if (*p == '\0') + { + argv[1] = NULL; + argc = 1; + } + else + { + for (x = 1; x < MAXPARMS; ) + { + char srch = ' '; + + if (*p == '"') + { + p++; + srch = '"'; + } + argv[x] = p; + x++; + p = strchr(p, srch); + if (p == NULL) + { + break; + } + else + { + *p = '\0'; + p++; + while (*p == ' ') p++; + if (*p == '\0') break; /* strip trailing blanks */ + } + } + argv[x] = NULL; + argc = x; + } + + *_Argc = argc; + *_Argv = argv; + return (0); +} +#endif + +#if defined(__gnu_linux__) || defined(__ARM__) + +void *PosGetDTA(void) +{ + return (&origdta); +} + +static int ff_search(void) +{ + static unsigned char buf[500]; + static size_t upto = 0; + static size_t avail = 0; + + if (avail <= 0) + { + avail = __getdents(dirfile, buf, 500); + if (avail <= 0) + { + __close(dirfile); + return (1); + } + } + strncpy(origdta.file_name, buf + upto + 10, sizeof origdta.file_name); + origdta.file_name[sizeof origdta.file_name - 1] = '\0'; + strncpy(origdta.lfn, buf + upto + 10, sizeof origdta.lfn); + origdta.lfn[sizeof origdta.lfn - 1] = '\0'; + upto += *(short *)(buf + upto + 8); + if (upto >= avail) + { + upto = avail = 0; + } + return (0); +} + +int PosFindFirst(char *pat, int attrib) +{ + dirfile = __open(".", 0, 0); + if (dirfile < 0) return (1); + return (ff_search()); +} + +int PosFindNext(void) +{ + return (ff_search()); +} + +int PosChangeDir(const char *to) +{ + return (__chdir(to)); +} + +int PosMakeDir(const char *dname) +{ + return (__mkdir(dname, 0777)); +} + +int PosRemoveDir(const char *dname) +{ + return (__rmdir(dname)); +} + +#else + +void *PosGetDTA(void) +{ + return (NULL); +} + +#endif diff --git a/app/src/main/cpp/bios/armeabi-v7a/exeload.c b/app/src/main/cpp/bios/armeabi-v7a/exeload.c new file mode 100644 index 0000000..dbeec25 --- /dev/null +++ b/app/src/main/cpp/bios/armeabi-v7a/exeload.c @@ -0,0 +1,2529 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Alica Okano. */ +/* Released to the Public Domain as discussed here: */ +/* http://creativecommons.org/publicdomain/zero/1.0/ */ +/* */ +/* Reworked and AmigaOS and MVS added by Paul Edwards */ +/* All changes remain public domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* exeload.c - functions for loading executables */ +/* */ +/*********************************************************************/ + +#include +#include +#include +#include + +#include "exeload.h" + +/* Headers for executable support. */ +#if NEED_AOUT +#include "a_out.h" +#endif +#if NEED_MZ +#include "mz.h" +#include "pecoff.h" +char msvcrt[FILENAME_MAX] = "\\MSVCRT.DLL"; +char kernel32[FILENAME_MAX] = "\\KERNEL32.DLL"; +#endif +#if NEED_ELF +#include "elf.h" +#endif + +/* For reading files Pos API must be used directly + * as PDPCLIB allocates memory from the process address space. */ + +#if NEED_AOUT +static int exeloadLoadAOUT(unsigned char **entry_point, + FILE *fp, + unsigned char **loadloc); + +#endif +#if NEED_MZ +static int exeloadLoadMZ(unsigned char **entry_point, + FILE *fp, + unsigned char **loadloc); +/* Subfunctions of exeloadLoadMZ() for loading extensions to MZ. */ +static int exeloadLoadPE(unsigned char **entry_point, + FILE *fp, + unsigned char **loadloc, + unsigned long e_lfanew); + +static int exeloadLoadLX(unsigned char **entry_point, + FILE *fp, + unsigned long e_lfanew); +static int exeloadLoadNE(unsigned char **entry_point, + FILE *fp, + unsigned long e_lfanew); + +/* Support function for loading DLLs. */ +static int exeloadLoadPEDLL(unsigned char *exeStart, + IMAGE_IMPORT_DESCRIPTOR *import_desc); +#endif + +#if NEED_ELF +static int exeloadLoadELF(unsigned char **entry_point, + FILE *fp, + unsigned char **loadloc); +#endif +#if NEED_MVS +static int exeloadLoadMVS(unsigned char **entry_point, + FILE *fp, + unsigned char **loadloc); +static int fixPE(unsigned char *buf, + size_t *len, + unsigned char **entry, + unsigned long rlad); +static int processRLD(unsigned char *buf, + unsigned long rlad, + unsigned char *rld, + int len); +#endif +#if NEED_AMIGA +static int exeloadLoadAmiga(unsigned char **entry_point, + FILE *fp, + unsigned char **loadloc); + +#endif +int exeloadDoload(unsigned char **entry_point, + char *progname, + unsigned char **loadloc) +{ + FILE *fp; + int ret = 1; + + fp = fopen(progname, "rb"); + if (fp == NULL) + { + printf("Failed to open %s for loading\n", progname); + return (1); + } + /* Tries to load the executable as different formats. + * Returned 0 means the executable was loaded successfully. + * 1 means it is not the format the function loads. + * 2 means correct format, but error occured. */ +#if NEED_AOUT + if (ret == 1) ret = exeloadLoadAOUT(entry_point, fp, loadloc); +#endif +#if NEED_MZ + if (ret == 1) ret = exeloadLoadMZ(entry_point, fp, loadloc); +#endif +#if NEED_AMIGA + if (ret == 1) ret = exeloadLoadAmiga(entry_point, fp, loadloc); +#endif +#if NEED_MVS + if (ret == 1) ret = exeloadLoadMVS((unsigned char **)entry_point, + fp, + (unsigned char **)loadloc); +#endif +#if NEED_ELF + if (ret == 1) ret = exeloadLoadELF(entry_point, fp, loadloc); +#endif + + fclose(fp); + if (ret != 0) + { + return (1); + } + + return (0); +} + +#if NEED_AOUT +static int exeloadLoadAOUT(unsigned char **entry_point, + FILE *fp, + unsigned char **loadloc) +{ + struct exec firstbit; + unsigned long exeLen; + unsigned char *exeStart; + unsigned char *bss; + unsigned int *corrections; + unsigned int i; + unsigned int offs; + unsigned int type; + unsigned int zapdata; + unsigned char *zap; + + + if (/*(fseek(fp, 0, SEEK_SET) != 0) || */(fread(&firstbit, sizeof(firstbit), 1, fp) != 1)) + { + return (1); + } + /* ZMAGIC and NMAGIC are currently not supported + * as they should be loaded at 0x10000, + * but the kernel reserves the first 4 MiB. */ + if ((firstbit.a_info & 0xffff) == ZMAGIC) + { + printf("a.out ZMAGIC is not supported\n"); + return (2); + } + else if ((firstbit.a_info & 0xffff) == NMAGIC) + { + printf("a.out NMAGIC is not supported\n"); + return (2); + } + else if ((firstbit.a_info & 0xffff) == QMAGIC) + { + printf("a.out QMAGIC is not supported\n"); + return (2); + } + else if ((firstbit.a_info & 0xffff) != OMAGIC) + { + /* The file is not A.OUT. */ + return (1); + } + exeLen = firstbit.a_text + firstbit.a_data + firstbit.a_bss; + if (*loadloc != NULL) + { + exeStart = *loadloc; + } + else + { + exeStart = malloc(exeLen); + if (exeStart == NULL) + { + printf("Insufficient memory to load A.OUT program\n"); + return (2); + } + } + + /* printf("loading %lu bytes of text\n", firstbit.a_text); */ + if (fread(exeStart, firstbit.a_text, 1, fp) != 1) + { + printf("Error occured while reading A.OUT text\n"); + return (2); + } + if (firstbit.a_data != 0) + { + /* printf("loading %lu bytes of data\n", firstbit.a_data); */ + if (fread(exeStart + firstbit.a_text, + firstbit.a_data, + 1, + fp) != 1) + { + printf("Error occured while reading A.OUT data\n"); + return (2); + } + } + + /* initialise BSS */ + bss = exeStart + firstbit.a_text + firstbit.a_data; + memset(bss, '\0', firstbit.a_bss); + /* Relocations. */ + { + zap = exeStart; + zapdata = (unsigned int)zap; + if (firstbit.a_trsize != 0) + { + corrections = malloc(firstbit.a_trsize); + if (corrections == NULL) + { + printf("insufficient memory %lu\n", firstbit.a_trsize); + return (2); + } + if (fread(corrections, firstbit.a_trsize, 1, fp) != 1) + { + printf("Error occured while reading A.OUT text relocations\n"); + free(corrections); + return (2); + } + for (i = 0; i < firstbit.a_trsize / 4; i += 2) + { + offs = corrections[i]; + type = corrections[i + 1]; + if (((type >> 24) & 0xff) != 0x04) + { + continue; + } + *(unsigned int *)(zap + offs) += zapdata; + } + free(corrections); + } + if (firstbit.a_drsize != 0) + { + corrections = malloc(firstbit.a_drsize); + if (corrections == NULL) + { + printf("insufficient memory %lu\n", firstbit.a_drsize); + return (2); + } + if (fread(corrections, firstbit.a_drsize, 1, fp) != 1) + { + printf("Error occured while reading A.OUT data relocations\n"); + free(corrections); + return (2); + } + zap = exeStart + firstbit.a_text; + for (i = 0; i < firstbit.a_drsize / 4; i += 2) + { + offs = corrections[i]; + type = corrections[i + 1]; + if (((type >> 24) & 0xff) != 0x04) + { + continue; + } + *(unsigned int *)(zap + offs) += zapdata; + } + free(corrections); + } + } + + *entry_point = exeStart + firstbit.a_entry; + if (*loadloc == NULL) + { + *loadloc = exeStart; + } + + return (0); +} +#endif + +#if NEED_MVS +static int exeloadLoadMVS(unsigned char **entry_point, + FILE *fp, + unsigned char **loadloc) +{ + size_t readbytes; + unsigned char *entry; + int didalloc = 0; + + /* printf("in LoadMVS\n"); */ + if (*loadloc == NULL) + { + *loadloc = malloc(1000000); + if (*loadloc == NULL) + { + return (1); + } + didalloc = 1; + } + rewind(fp); + readbytes = fread(*loadloc, 1, 1000000, fp); + /* printf("read %d bytes\n", (int)readbytes); */ + + /* the last parameter is an unsigned long because the code allows + relocations to be done for a theoretical load point rather than + requiring the actual load point. In case we wanted to do the + calculations to later store the executable in ROM or something + like that. */ + + if (fixPE(*loadloc, &readbytes, &entry, (unsigned long)*loadloc) != 0) + { + if (didalloc) + { + free(*loadloc); + *loadloc = NULL; + } + return (1); + } + *entry_point = entry; + + return (0); +} +#endif + +#if NEED_AMIGA +#define getword(p) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]) +#define putword(p, val) (p[0] = (unsigned char)((val >> 24) & 0xff), \ + p[1] = (unsigned char)((val >> 16) & 0xff), \ + p[2] = (unsigned char)((val >> 8) & 0xff), \ + p[3] = (unsigned char)(val & 0xff)) + +#define HUNK_HEADER 0x3F3 +#define HUNK_CODE 0x3E9 +#define HUNK_DATA 0x3EA +#define HUNK_BSS 0x3EB +#define HUNK_RELOC32 0x3EC +#define HUNK_SYMBOL 0x3F0 +#define HUNK_END 0x3F2 + +static int exeloadLoadAmiga(unsigned char **entry_point, + FILE *fp, + unsigned char **loadloc) +{ + size_t readbytes; + unsigned char *p; + unsigned long temp; + int datahunk = 1; + int codehunk = 0; + int bsshunk; + unsigned char *beg; + unsigned char *codestart; + unsigned char *datastart = NULL; + unsigned char *bssstart; + unsigned char *genstart; /* generic start location when doing relocations */ + unsigned char *codereloc = NULL; + unsigned char *datareloc = NULL; + int iter; + int didalloc = 0; + + /* printf("in LoadAmiga\n"); */ + if (*loadloc == NULL) + { + *loadloc = malloc(1000000); + if (*loadloc == NULL) + { + return (1); + } + didalloc = 1; + } + p = beg = *loadloc; + rewind(fp); + readbytes = fread(p, 1, 1000000, fp); + /* printf("read %d bytes\n", (int)readbytes); */ + if (readbytes < 4) + { + if (didalloc) + { + free(*loadloc); + *loadloc = NULL; + } + return (1); + } + bssstart = p + readbytes; + temp = getword(p); + if (temp != HUNK_HEADER) + { + if (didalloc) + { + free(*loadloc); + *loadloc = NULL; + } + return (1); + } + p += 4; + temp = getword(p); + if (temp != 0) + { + printf("can't handle Amiga Hunk 1\n"); + if (didalloc) + { + free(*loadloc); + *loadloc = NULL; + } + return (1); + } + p += 4; + temp = getword(p); + if (temp == 2) + { + /* printf("no data section\n"); */ + bsshunk = 1; + datahunk = -1; + /* printf("bsshunk determined to be %d\n", bsshunk); */ + p += 8; + } + else if (temp == 3) + { + /* looks like this: + 000000 000003F3 00000000 00000003 00000000 ................ + 000010 00000002 0000002A 00000001 00000002 .......*........ + + So that 3 is the number of hunks, or highest hunk number + plus 1. Then comes 0, the first hunk number. Then comes + 2, the last hunk number, then comes x'2A', the length of + hunk number 0 (CODE), then comes 1, the length of + hunk number 1 (DATA), then comes 2, the length of hunk + number 2 (BSS since we have a data section, otherwise + it would have been 1). Lengths are the number of 4-byte + words. + */ + /* printf("we have a data section\n"); */ + bsshunk = 2; + /* printf("bsshunk determined to be %d\n", bsshunk); */ + p += 12; + } + else + { + printf("can't handle Amiga Hunk 2\n"); + if (didalloc) + { + free(*loadloc); + *loadloc = NULL; + } + return (1); + } + p += 12; + + temp = getword(p); + if (temp != HUNK_CODE) + { + printf("Amiga Hunk expecting code at hex %lx\n", + (unsigned long)(p - beg)); + if (didalloc) + { + free(*loadloc); + *loadloc = NULL; + } + return (1); + } + p += 4; + temp = getword(p); + /* printf("length of code is hex %lx\n", temp); */ + p += 4; + codestart = p; + /* printf("at codestart is %02X\n", *(unsigned char *)codestart); */ + p += temp * 4; + + while (1) + { + if (p >= bssstart) + { + /* printf("reached end of executable\n"); */ + break; + } + temp = getword(p); + if (temp == HUNK_RELOC32) + { + p += 4; + /* if we haven't yet encountered a HUNK_DATA, then this + must be a code relocation */ + if (datastart == NULL) + { + codereloc = p; + } + else + { + datareloc = p; + } + /* skip relocations for now, come back later */ + temp = getword(p); + while (temp != 0) + { + p += 4; /* skip count of relocations */ + p += 4; /* skip hunk number */ + p += temp * 4; /* skip relocations */ + temp = getword(p); + } + /* printf("skipped relocations\n"); */ + p += 4; + } + else if (temp == HUNK_DATA) + { + p += 4; /* skip hunk id */ + temp = getword(p); + p += 4; /* skip number of words */ + datastart = p; + /* printf("got data start for real\n"); */ + p += temp * 4; + } + else if (temp == HUNK_SYMBOL) + { + /* printf("got symbol\n"); */ + p += 4; /* skip hunk id */ + temp = getword(p); + while (temp != 0) /* until hunk number is 0 */ + { + long len; + long rem; + + p += 4; /* skip hunk number */ + /* printf("symbol %s found\n", p); */ + len = strlen((char *)p); + len++; + rem = len % 4; + if (rem != 0) + { + len = len - rem + 4; /* move up to 4-byte boundary */ + } + p += len; + p += 4; /* skip offset */ + temp = getword(p); + } + p += 4; /* skip hunk number */ + } + else if (temp == HUNK_END) + { + /* printf("got hunk end\n"); */ + p += 4; + } + else if (temp == HUNK_BSS) + { + /* printf("got BSS hunk\n"); */ + p += 8; + } + else + { + printf("unexpected Amiga Hunk id hex %lx\n", temp); + if (didalloc) + { + free(*loadloc); + *loadloc = NULL; + } + return (1); + } + } + + /* apply relocations */ + /* printf("applying relocations\n"); */ + for (iter = 0; iter < 2; iter++) + { + if ((iter == 0) && (codereloc == NULL)) continue; + if ((iter == 1) && (datareloc == NULL)) continue; + if (iter == 0) + { + /* printf("applying code relocations\n"); */ + genstart = codestart; + p = codereloc; + } + else if (iter == 1) + { + /* printf("applying data relocations\n"); */ + genstart = datastart; + p = datareloc; + } + temp = getword(p); + while (temp != 0) + { + unsigned long count; + int hunk_nbr; + unsigned char *correction; + unsigned long x; + + count = temp; + p += 4; /* skip count of relocations */ + hunk_nbr = getword(p); + p += 4; /* skip hunk number */ + if (hunk_nbr == codehunk) + { + correction = codestart; + /* printf("got %lu CODE relocations\n", count); */ + } + else if (hunk_nbr == datahunk) + { + correction = datastart; + /* printf("got %lu DATA relocations\n", count); */ + } + else if (hunk_nbr == bsshunk) + { + correction = bssstart; + /* printf("got %lu BSS relocations\n", count); */ + } + else + { + printf("got unexpected Amiga Hunk number hex %x\n", hunk_nbr); + printf("code hunk is %d\n", codehunk); + printf("data hunk is %d\n", datahunk); + printf("bss hunk is %d\n", bsshunk); + if (didalloc) + { + free(*loadloc); + *loadloc = NULL; + } + return (1); + } + /* WARNING - the following is not entirely accurate. There + ARE data relocations, and the above code caters for that, + and that's why there are two iterations of the loop. But + pogi points for trying. */ + + /* Note that all relocations are applied to the code + section, but the code needs different corrections + depending on whether it is referencing another location + in code, a data reference, e.g. a global variable with a + value of 5, or a BSS reference, e.g. an uninitialized + global variable. */ + /* At the various offsets in the code there will be values, + such as 48, which are the correct offsets if the module + was loaded at location 0 in memory, and also the data + section started at location 0 in memory, and also the + bss section (variables that need to be set to 0 before + the executable runs) is set to location 0 in memory. + Note that the BSS takes up no space in the executable + because it would just be a whole lot of zeros serving + no purpose. So the onus is on the program loading the + executable to initialize that area. That area is + normally placed at the end of the executable, but you + can do a separate malloc and put it anywhere if you + want. You can also put the data section anywhere you + want to, with a separate malloc, so long as you actually + copy all that data across to the new location. This is + what needs to happen with reentrant modules. There needs + to be a register (such as ds: in 8086) pointing to where + the global variables are. And normally the BSS comes + after that, so you can use a single register to point to + both data and BSS. The code corrections only need to be + done once for the code section itself, and the data + offsets are all given in reference to some dedicated + register (such as ds) so that no more corrections are + required to the code to reference the correct offsets. + In fact, you don't need to correct them at all, they are + all set to the correct offsets for the dedicated + register. But if you're not using a dedicated register, + or you are using the huge, large or compact memory models + of the 8086, you can't use a dedicated register, as there + is too much data (more than 64k) for ds to reference, so + ds keeps on being reloaded, and thus the code corrections + need to be made to point to the full address + (segment:offset) of where the variable can be found. + For the 68000 you also need the full address (as the + compiler is not using a dedicated register and dynamically + providing the offsets), but it is a flat 32-bit pointer. + If you are using a compiler that DOES use a dedicated + register, then there will simply be no "data corrections" + found in the relocation table, ie the relocation table + will only have references to locations in the code where + somewhere else in the code needs to be referenced (e.g. + to call a function) but because the code is not loaded + at location 0 (or effectively done so via virtual memory, + or some other fixed location like Windows used to use), + so it needs to know where exactly in memory it has been + loaded. */ + + for (x = 0; x < count; x++) + { + unsigned char *zaploc; + unsigned char *xxx; + unsigned long value; + unsigned long oldref; + unsigned char *properref; + unsigned long properref_val; + + xxx = &p[x * 4]; /* point to a value, such as 12, + which is where in the code section will need + to be adjusted */ + value = getword(xxx); /* now we have that value 12 */ + zaploc = genstart + value; /* now we point to the + exact location in the code section that needs + to have a correction applied. Note that the + corrected value to be applied depends on whether + it is a code, data or BSS reference, but we have + already determined that, and are already pointing + to the relevant memory address. */ + oldref = getword(zaploc); /* now we have the old + value of the function or whatever, e.g. if the + called function is at offset 40 in the code + section, then it will have the value 40. */ + properref = correction + oldref; /* This is where we + want the code to start looking for this code, data + or BSS reference. Even if we are on a 64-bit system + and we are loading this 32-bit module, someone + else will have made sure that we are effectively + on a 4 GiB boundary so that this pointer will be + valid, even though we're just about to truncate + it to 4 bytes. ie on a 64-bit system, properref + could be 0x1 0000 0000 - but that's OK so long + as the high 32 bits of all registers have been + set to 0x1 0000 0000. None of this 68000 code + knows about the high 32-bits of 64-bit registers + so will not disturb any data stored there. */ + properref_val = (unsigned long)properref; /* this + probably won't truncate the pointer, but we are + putting it in integer form, ready for manipulation. + Note that if this program is running on a 8086, + and you are trying to load this 68000 executable + (prior to switching to the 68000 coprocessor), + using far data pointers, you will need to use a + compiler that converts far pointers into flat + references when converting from pointer to long, + because + the 68000 program will require a flat reference. + ie the compiler needs to do the equivalent of + ((properref >> 4) << 16) | (properref & 0xffff) + in order to create properref_val. Or you need + to provide your own routine to do that. In my + opinion this is the job of the compiler, it + should know that you are wanting a flat reference. + So too when you go: + char *p = (char *)0xb8000UL; + it should convert that into b800:0000 itself. + Speak to your compiler vendor! + If we were doing things the other way around, ie + you have a 68000 loading an 8086 large memory model + program, then this is a "known quantity" (the same + as loading a small memory model program) and it is + this loader code (perhaps compiled with a 68000) + that would need to convert a flat memory pointer (ie + where it loaded the 8086 program into 68000 memory) + that would need to convert a flat pointer into a + segmented pointer suitable for the 8086 prior to + switching to the 8086 coprocessor. So it is reasonable + for you to do the bit shifting in your own code. After + first of all converting into an unsigned long, because + maybe the loader is not 68000 either, but another + segmented architecture with different segmentation rules, + and it too needs to convert to a flat address (as + represented by unsigned long) prior to being manually + converted into an address suitable for the 8086. */ + + putword(zaploc, properref_val); + } + p += temp * 4; /* skip relocations */ + temp = getword(p); + } + } + /* printf("finished relocations\n"); */ + + *entry_point = codestart; + /* printf("just set entry point, first byte %02X\n", + *(unsigned char *)codestart); */ + + return (0); +} +#endif + +#if NEED_ELF +static int exeloadLoadELF(unsigned char **entry_point, + FILE *fp, + unsigned char **loadloc) +{ + int doing_elf_rel = 0; + int doing_elf_exec = 0; + Elf32_Ehdr *elfHdr; + Elf32_Phdr *program_table = NULL; + Elf32_Phdr *segment; + Elf32_Shdr *section_table = NULL; + Elf32_Shdr *section; + unsigned char *elf_other_sections = NULL; + Elf32_Addr lowest_p_vaddr = 0; + Elf32_Word lowest_segment_align = 0; + unsigned char *exeStart = NULL; + unsigned char *bss; + unsigned long exeLen; + unsigned char firstbit[4]; + long newpos; + size_t readbytes; + + if ((fseek(fp, 0, SEEK_SET) != 0) + || (fread(&firstbit, sizeof firstbit, 1, fp) != 1) + || (memcmp(&firstbit, "\x7f" "ELF", 4) != 0)) + { + return (1); + } + { + int elf_invalid = 0; + + /* Loads entire ELF header into memory. */ + elfHdr = malloc(sizeof(Elf32_Ehdr)); + if (elfHdr == NULL) + { + printf("Insufficient memory for ELF header\n"); + return (2); + } + if ((fseek(fp, 0, SEEK_SET) != 0) + || (fread(elfHdr, sizeof(Elf32_Ehdr), 1, fp) != 1)) + { + printf("Error occured while reading ELF header\n"); + free(elfHdr); + return (2); + } + + /* Checks e_ident if the program can be used on PDOS-32. */ + if (elfHdr->e_ident[EI_CLASS] != ELFCLASS32) + { + if (elfHdr->e_ident[EI_CLASS] == ELFCLASS64) + { + printf("64-bit ELF is not supported\n"); + } + else if (elfHdr->e_ident[EI_CLASS] == ELFCLASSNONE) + { + printf("Invalid ELF class\n"); + } + else + { + printf("Unknown ELF class: %u\n", elfHdr->e_ident[EI_CLASS]); + } + elf_invalid = 1; + } + if (elfHdr->e_ident[EI_DATA] != ELFDATA2LSB) + { + if (elfHdr->e_ident[EI_DATA] == ELFDATA2MSB) + { + printf("Big-endian ELF encoding is not supported\n"); + } + else if (elfHdr->e_ident[EI_DATA] == ELFDATANONE) + { + printf("Invalid ELF data encoding\n"); + } + else + { + printf("Unknown ELF data encoding: %u\n", + elfHdr->e_ident[EI_DATA]); + } + elf_invalid = 1; + } + if (elfHdr->e_ident[EI_OSABI] != ELFOSABI_NONE) + { + printf("No OS or ABI specific extensions for ELF supported\n"); + elf_invalid = 1; + } + /* Checks other parts of the header if the file can be loaded. */ + if (elfHdr->e_type == ET_REL) + { + doing_elf_rel = 1; + } + else if (elfHdr->e_type == ET_EXEC) + { + doing_elf_exec = 1; + } + else + { + printf("Only ELF relocatable " + "and executable " + "files are supported\n"); + elf_invalid = 1; + } + if (elfHdr->e_machine != EM_386) + { + printf("Only Intel 386 architecture is supported\n"); + elf_invalid = 1; + } + if (doing_elf_exec) + { + if (elfHdr->e_phoff == 0 || elfHdr->e_phnum == 0) + { + printf("Executable file is missing Program Header Table\n"); + elf_invalid = 1; + } + if (elfHdr->e_phnum >= SHN_LORESERVE) + { + printf("Reserved indexes for e_phnum are not supported\n"); + printf("e_phnum is %04x\n", elfHdr->e_phnum); + elf_invalid = 1; + } + if (elfHdr->e_phentsize != sizeof(Elf32_Phdr)) + { + printf("Program Header Table entries have unsupported size\n"); + printf("e_phentsize: %u supported size: %lu\n", + elfHdr->e_phentsize, sizeof(Elf32_Phdr)); + elf_invalid = 1; + } + } + else if (doing_elf_rel) + { + if (elfHdr->e_shoff == 0 || elfHdr->e_shnum == 0) + { + printf("Relocatable file is missing Section Header Table\n"); + elf_invalid = 1; + } + if (elfHdr->e_shnum >= SHN_LORESERVE) + { + printf("Reserved indexes for e_shnum are not supported\n"); + printf("e_shnum is %04x\n", elfHdr->e_shnum); + elf_invalid = 1; + } + if (elfHdr->e_shentsize != sizeof(Elf32_Shdr)) + { + printf("Section Header Table entries have unsupported size\n"); + printf("e_shentsize: %u supported size: %lu\n", + elfHdr->e_shentsize, sizeof(Elf32_Shdr)); + elf_invalid = 1; + } + } + if (elf_invalid) + { + /* All problems with ELF header are reported + * and loading is stopped. */ + printf("This ELF file cannot be loaded\n"); + free(elfHdr); + return (2); + } + /* Loads Program Header Table if it is present. */ + if (!(elfHdr->e_phoff == 0 || elfHdr->e_phnum == 0)) + { + program_table = malloc(elfHdr->e_phnum * elfHdr->e_phentsize); + if (program_table == NULL) + { + printf("Insufficient memory for ELF Program Header Table\n"); + free(elfHdr); + return (2); + } + if ((fseek(fp, elfHdr->e_phoff, SEEK_SET) != 0) + || (fread(program_table, + elfHdr->e_phnum * elfHdr->e_phentsize, + 1, + fp) != 1)) + { + printf("Error occured while reading " + "ELF Program Header Table\n"); + free(elfHdr); + free(program_table); + return (2); + } + } + /* Loads Section Header Table if it is present. */ + if (!(elfHdr->e_shoff == 0 || elfHdr->e_shnum == 0)) + { + section_table = malloc(elfHdr->e_shnum * elfHdr->e_shentsize); + if (section_table == NULL) + { + printf("Insufficient memory for ELF Section Header Table\n"); + free(elfHdr); + free(program_table); + return (2); + } + if ((fseek(fp, elfHdr->e_shoff, SEEK_SET) != 0) + || (fread(section_table, + elfHdr->e_shnum * elfHdr->e_shentsize, + 1, + fp) != 1)) + { + printf("Error occured while reading " + "ELF Section Header Table\n"); + free(elfHdr); + free(program_table); + free(section_table); + return (2); + } + } + } + + if (1) + { + /* Calculates how much memory is needed + * and allocates memory for sections used only for loading. */ + unsigned long otherLen = 0; + + exeLen = 0; + if (doing_elf_exec) + { + Elf32_Addr highest_p_vaddr = 0; + Elf32_Word highest_segment_memsz = 0; + + for (segment = program_table; + segment < program_table + elfHdr->e_phnum; + segment++) + { + if (segment->p_type == PT_LOAD) + { + if (!lowest_p_vaddr || lowest_p_vaddr > segment->p_vaddr) + { + lowest_p_vaddr = segment->p_vaddr; + lowest_segment_align = segment->p_align; + } + if (highest_p_vaddr < segment->p_vaddr) + { + highest_p_vaddr = segment->p_vaddr; + highest_segment_memsz = segment->p_memsz; + } + } + } + exeLen = highest_p_vaddr - lowest_p_vaddr + highest_segment_memsz; + if (lowest_segment_align > 1) + { + /* Ensures alignment of the lowest segment. + * 0 and 1 mean no alignment restrictions. */ + exeLen += lowest_segment_align; + } + } + if (section_table) + { + for (section = section_table; + section < section_table + elfHdr->e_shnum; + section++) + { + unsigned long section_size = section->sh_size; + if (section->sh_addralign > 1) + { + /* Some sections must be aligned + * on sh_addralign byte boundaries. + * 0 and 1 mean no alignment restrictions. */ + section_size += section->sh_addralign; + } + if ((section->sh_flags & SHF_ALLOC) + && (section->sh_type != SHT_RELA)) + { + /* Section is needed while the program is running, + * but if we are loading an executable file, + * the memory is already counted + * using Program Header Table. */ + if (doing_elf_exec) continue; + exeLen += section_size; + } + else + { + /* Section is used only for loading. */ + otherLen += section_size; + } + } + elf_other_sections = malloc(otherLen); + if (elf_other_sections == NULL) + { + printf("Insufficient memory to load ELF sections\n"); + free(elfHdr); + free(program_table); + free(section_table); + return (2); + } + } + } + /* Allocates memory for the process. */ + if (*loadloc != NULL) + { + exeStart = *loadloc; + } + else + { + exeStart = malloc(exeLen); + } + if (exeStart == NULL) + { + printf("Insufficient memory to load ELF program\n"); + free(elfHdr); + free(program_table); + free(section_table); + free(elf_other_sections); + return (2); + } + + if (1) + { + /* Loads all sections of ELF file with proper alignment, + * clears all SHT_NOBITS sections and stores the addresses + * in sh_addr of each section. + * bss is set now too. */ + unsigned char *exe_addr = exeStart; + unsigned char *other_addr = elf_other_sections; + + bss = NULL; + if (doing_elf_exec) + { + /* Aligns the exeStart on lowest segment alignment boundary. */ + /*exeStart = (unsigned char *)((((unsigned long)exeStart + / lowest_segment_align) + 1) + * lowest_segment_align);*/ + /* +++Enable aligning. */ + for (segment = program_table; + segment < program_table + elfHdr->e_phnum; + segment++) + { + if (segment->p_type == PT_LOAD) + { + exe_addr = exeStart + (segment->p_vaddr - lowest_p_vaddr); + + if ((fseek(fp, segment->p_offset, SEEK_SET) != 0) + || (fread(exe_addr, + segment->p_filesz, + 1, + fp) != 1)) + { + printf("Error occured while reading ELF segment\n"); + free(elfHdr); + free(program_table); + free(section_table); + free(elf_other_sections); + return (2); + } + + /* Bytes that are not present in file, + * but must be present in memory must be set to 0. */ + if (segment->p_filesz < segment->p_memsz) + { + bss = exe_addr + (segment->p_filesz); + memset(bss, '\0', + segment->p_memsz - segment->p_filesz); + } + } + } + } + + for (section = section_table; + section < section_table + elfHdr->e_shnum; + section++) + { + if ((section->sh_flags & SHF_ALLOC) + && (section->sh_type != SHT_RELA)) + { + /* If we are loading executable file, + * SHF_ALLOC sections are already loaded in segments. */ + if (doing_elf_exec) continue; + if (section->sh_addralign > 1) + { + exe_addr = (void *)((((unsigned long)exe_addr + / (section->sh_addralign)) + 1) + * (section->sh_addralign)); + } + if (section->sh_type != SHT_NOBITS) + { + if ((fseek(fp, section->sh_offset, SEEK_SET) != 0) + || (fread(exe_addr, + section->sh_size, + 1, + fp) != 1)) + { + printf("Error occured while reading ELF section\n"); + free(elfHdr); + free(program_table); + free(section_table); + free(elf_other_sections); + return (2); + } + } + else + { + /* The section is probably BSS. */ + if (bss != 0) + { + printf("Multiple SHT_NOBITS with SHF_ALLOC " + "present in ELF file\n"); + } + bss = exe_addr; + /* All SHT_NOBITS should be cleared to 0. */ + memset(bss, '\0', section->sh_size); + } + /* sh_addr is 0 in relocatable files, + * so we can use it to store the real address. */ + section->sh_addr = (Elf32_Addr)exe_addr; + exe_addr += section->sh_size; + } + else + { + if (section->sh_addralign > 1) + { + other_addr = (void *)((((unsigned long)other_addr + / (section->sh_addralign)) + 1) + * (section->sh_addralign)); + } + if (section->sh_type != SHT_NOBITS) + { + if (section->sh_size != 0) + { + if ((fseek(fp, section->sh_offset, SEEK_SET) != 0) + || (fread(other_addr, + section->sh_size, + 1, + fp) != 1)) + { + printf("Error occured while reading ELF section\n"); + free(elfHdr); + free(program_table); + free(section_table); + free(elf_other_sections); + return (2); + } + } + } + else + { + /* All SHT_NOBITS should be cleared to 0. */ + memset(other_addr, '\0', section->sh_size); + } + /* sh_addr is 0 in relocatable files, + * so we can use it to store the real address. */ + section->sh_addr = (Elf32_Addr)other_addr; + other_addr += section->sh_size; + } + } + } + /* Program was successfully loaded from the file, + * no more errors can occur. */ + + /* Relocations. */ + if (1) + { + for (section = section_table; + section < section_table + elfHdr->e_shnum; + section++) + { + if (section->sh_type == SHT_RELA) + { + /* sh_link specifies the symbol table + * and sh_info section being modified. */ + Elf32_Sym *sym_table = (Elf32_Sym *)(section_table + + (section->sh_link))->sh_addr; + unsigned char *target_base = exeStart + + (((unsigned char *)(section_table + + (section->sh_info))->sh_addr) + - (unsigned char *)lowest_p_vaddr); + Elf32_Rela *startrel = (Elf32_Rela *)section->sh_addr; + Elf32_Rela *currel; + + if (section->sh_entsize != sizeof(Elf32_Rela)) + { + printf("Invalid size of relocation entries in ELF file\n"); + continue; + } + + for (currel = startrel; + currel < (startrel + + ((section->sh_size) / (section->sh_entsize))); + currel++) + { + long *target = (long *)(target_base + currel->r_offset); + Elf32_Sym *symbol = (sym_table + + ELF32_R_SYM(currel->r_info)); + Elf32_Addr sym_value = 0; + + if (ELF32_R_SYM(currel->r_info) != STN_UNDEF) + { + if (symbol->st_shndx == SHN_ABS) + { + /* Absolute symbol, stores absolute value. */ + sym_value = symbol->st_value; + } + else if (symbol->st_shndx == SHN_UNDEF) + { + /* Dynamic linker should fill this symbol. */ + printf("Undefined symbol in ELF file\n"); + continue; + } + else if (symbol->st_shndx == SHN_XINDEX) + { + printf("Unsupported value in ELF symbol\n"); + printf("symbol->st_shndx: %x\n", symbol->st_shndx); + continue; + } + else + { + /* Internal symbol. Must be converted + * to absolute symbol.*/ + sym_value = symbol->st_value; + /* Adds the address of the related section + * so the symbol stores absolute address. */ + sym_value += ((section_table + + symbol->st_shndx)->sh_addr); + } + } + switch (ELF32_R_TYPE(currel->r_info)) + { + case R_386_NONE: + break; + case R_386_32: + /* Symbol value + offset. */ + *target = *target - lowest_p_vaddr + (long)exeStart; + break; + case R_386_PC32: + /* Symbol value + offset - absolute address + * of the modified field. */ + *target = (sym_value + (*target) + - (unsigned long)target); + break; + default: + printf("Unknown relocation type in ELF file\n"); + } + } + } + else if (section->sh_type == SHT_REL) + { + /* sh_link specifies the symbol table + * and sh_info section being modified. */ + Elf32_Sym *sym_table = (Elf32_Sym *)(section_table + + (section->sh_link))->sh_addr; + unsigned char *target_base = (unsigned char *)(section_table + + (section->sh_info))->sh_addr; + Elf32_Rel *startrel = (Elf32_Rel *)section->sh_addr; + Elf32_Rel *currel; + + if (section->sh_entsize != sizeof(Elf32_Rel)) + { + printf("Invalid size of relocation entries in ELF file\n"); + continue; + } + + for (currel = startrel; + currel < (startrel + + ((section->sh_size) / (section->sh_entsize))); + currel++) + { + long *target = (long *)(target_base + currel->r_offset); + Elf32_Sym *symbol = (sym_table + + ELF32_R_SYM(currel->r_info)); + Elf32_Addr sym_value = 0; + + if (ELF32_R_SYM(currel->r_info) != STN_UNDEF) + { + if (symbol->st_shndx == SHN_ABS) + { + /* Absolute symbol, stores absolute value. */ + sym_value = symbol->st_value; + } + else if (symbol->st_shndx == SHN_UNDEF) + { + /* Dynamic linker should fill this symbol. */ + printf("Undefined symbol in ELF file\n"); + continue; + } + else if (symbol->st_shndx == SHN_XINDEX) + { + printf("Unsupported value in ELF symbol\n"); + printf("symbol->st_shndx: %x\n", symbol->st_shndx); + continue; + } + else + { + /* Internal symbol. Must be converted + * to absolute symbol.*/ + sym_value = symbol->st_value; + /* Adds the address of the related section + * so the symbol stores absolute address. */ + sym_value += ((section_table + + symbol->st_shndx)->sh_addr); + } + } + switch (ELF32_R_TYPE(currel->r_info)) + { + case R_386_NONE: + break; + case R_386_32: + /* Symbol value + offset. */ + *target = sym_value + *target; + break; + case R_386_PC32: + /* Symbol value + offset - absolute address + * of the modified field. */ + *target = (sym_value + (*target) + - (unsigned long)target); + break; + default: + printf("Unknown relocation type in ELF file\n"); + } + } + } + } + } + + *entry_point = exeStart + (elfHdr->e_entry - lowest_p_vaddr); + + /* Frees memory not needed by the process. */ + free(elfHdr); + free(program_table); + free(section_table); + free(elf_other_sections); + + if (*loadloc == NULL) + { + *loadloc = exeStart; + } + return (0); +} +#endif + +#if NEED_MZ +static int exeloadLoadMZ(unsigned char **entry_point, + FILE *fp, + unsigned char **loadloc) +{ + Mz_hdr firstbit; + + /* The header size is in paragraphs, + * so the smallest possible header is 16 bytes (paragraph) long. + * Next is the magic number checked. */ + if ((fseek(fp, 0, SEEK_SET) != 0) + || (fread(&firstbit, 16, 1, fp) != 1) + || (memcmp(firstbit.magic, "MZ", 2) != 0 + && memcmp(&firstbit.magic, "ZM", 2) != 0)) + { + return (1); + } + if (firstbit.header_size == 0) + { + printf("MZ Header has 0 size\n"); + return (2); + } + if (firstbit.header_size * 16 > sizeof(firstbit)) + { + printf("MZ Header is too large, size: %u\n", + (unsigned int)firstbit.header_size * 16); + return (2); + } + /* Loads the rest of the header. */ + if (fread(((char *)&firstbit) + 16, + (firstbit.header_size - 1) * 16, + 1, + fp) != 1) + { + printf("Error occured while reading MZ header\n"); + return (2); + } + /* Determines whether the executable has extensions or is a pure MZ. + * Extensions are at offset in e_lfanew, + * so the header must have at least 4 paragraphs. */ + if ((firstbit.header_size >= 4) + && (firstbit.e_lfanew != 0)) + { + int ret; + + /* Same logic as in exeloadDoload(). */ + ret = exeloadLoadPE(entry_point, fp, loadloc, firstbit.e_lfanew); + if (ret == 1) + ret = exeloadLoadLX(entry_point, fp, firstbit.e_lfanew); + if (ret == 1) + ret = exeloadLoadNE(entry_point, fp, firstbit.e_lfanew); + if (ret == 1) + printf("Unknown MZ extension\n"); + return (ret); + } + /* Pure MZ executables are for 16-bit DOS, so we cannot run them. */ + printf("Pure MZ executables are not supported\n"); + + return (2); +} + +static int exeloadLoadPE(unsigned char **entry_point, + FILE *fp, + unsigned char **loadloc, + unsigned long e_lfanew) +{ + Coff_hdr coff_hdr; + Pe32_optional_hdr *optional_hdr; + Coff_section *section_table, *section; + unsigned char *exeStart; + int ret; + + { + unsigned char firstbit[4]; + + if ((fseek(fp, e_lfanew, SEEK_SET) != 0) + || (fread(firstbit, 4, 1, fp) != 1) + || (memcmp(firstbit, "PE\0\0", 4) != 0)) + { + return (1); + } + } + if (fread(&coff_hdr, sizeof(coff_hdr), 1, fp) != 1) + { + printf("Error occured while reading COFF header\n"); + return (2); + } +#if TARGET_64BIT + if (coff_hdr.Machine != IMAGE_FILE_MACHINE_AMD64) + { + printf("only 64-bit PE programs are supported\n"); + return (2); + } +#else + if ((coff_hdr.Machine != IMAGE_FILE_MACHINE_UNKNOWN) + && (coff_hdr.Machine != IMAGE_FILE_MACHINE_I386)) + { + if (coff_hdr.Machine == IMAGE_FILE_MACHINE_AMD64) + { + printf("64-bit PE programs are not supported\n"); + } + else + { + printf("Unknown PE machine type: %04x\n", coff_hdr.Machine); + } + return (2); + } +#endif + + if ((coff_hdr.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) != 0) + { + printf("only relocatable executables supported\n"); + return (2); + } + + optional_hdr = malloc(coff_hdr.SizeOfOptionalHeader); + if (optional_hdr == NULL) + { + printf("Insufficient memory to load PE optional header\n"); + return (2); + } + if (fread(optional_hdr, coff_hdr.SizeOfOptionalHeader, 1, fp) != 1) + { + printf("Error occured while reading PE optional header\n"); + free(optional_hdr); + return (2); + } +#if TARGET_64BIT + if (optional_hdr->Magic != MAGIC_PE32PLUS) + { + printf("Unknown PE optional header magic: %04x\n", + optional_hdr->Magic); + free(optional_hdr); + return (2); + } +#else + if (optional_hdr->Magic != MAGIC_PE32) + { + printf("Unknown PE optional header magic: %04x\n", + optional_hdr->Magic); + free(optional_hdr); + return (2); + } +#endif + + section_table = malloc(coff_hdr.NumberOfSections * sizeof(Coff_section)); + if (section_table == NULL) + { + printf("Insufficient memory to load PE section headers\n"); + free(optional_hdr); + return (2); + } + if (fread(section_table, + coff_hdr.NumberOfSections * sizeof(Coff_section), + 1, + fp) != 1) + { + printf("Error occured while reading PE optional header\n"); + free(section_table); + free(optional_hdr); + return (2); + } + + /* Allocates memory for the process. + * Size of image is obtained from the optional header. */ + if (*loadloc != NULL) + { + exeStart = *loadloc; + } + else + { + exeStart = malloc(optional_hdr->SizeOfImage); + } + if (exeStart == NULL) + { + printf("Insufficient memory to load PE program\n"); + free(section_table); + free(optional_hdr); + return (2); + } + + /* Loads all sections at their addresses. */ + for (section = section_table; + section < section_table + coff_hdr.NumberOfSections; + section++) + { + unsigned long size_in_file; + + /* Virtual size of a section is larger than in file, + * so the difference is filled with 0. */ + if (section->VirtualSize > section->SizeOfRawData) + { + memset(exeStart + + section->VirtualAddress + + section->SizeOfRawData, + 0, + section->VirtualSize - section->SizeOfRawData); + size_in_file = section->SizeOfRawData; + } + /* SizeOfRawData is rounded up, + * so it can be larger than VirtualSize. */ + else + { + size_in_file = section->VirtualSize; + } + if (size_in_file != 0) + { + if ((fseek(fp, section->PointerToRawData, SEEK_SET) != 0) + || (fread(exeStart + section->VirtualAddress, + size_in_file, + 1, + fp) != 1)) + { + printf("Error occured while reading PE section\n"); + free(section_table); + free(optional_hdr); + return (2); + } + } + } + + if (exeStart != optional_hdr->ImageBase) + { + /* Relocations are not stripped, so the executable can be relocated. */ + if (optional_hdr->NumberOfRvaAndSizes > DATA_DIRECTORY_REL) + { + IMAGE_DATA_DIRECTORY *data_dir = (((IMAGE_DATA_DIRECTORY *) + (optional_hdr + 1)) + + DATA_DIRECTORY_REL); + /* Difference between preferred address and real address. */ + ptrdiff_t image_diff; + int lower_exeStart; + Base_relocation_block *rel_block = ((Base_relocation_block *) + (exeStart + + (data_dir + ->VirtualAddress))); + Base_relocation_block *end_rel_block; + + if (optional_hdr->ImageBase > exeStart) + { + /* Image is loaded at lower address than preferred. */ + image_diff = optional_hdr->ImageBase - exeStart; + lower_exeStart = 1; + } + else + { + image_diff = exeStart - optional_hdr->ImageBase; + lower_exeStart = 0; + } + + end_rel_block = rel_block + ((data_dir->Size) + / sizeof(Base_relocation_block)); + + for (; rel_block < end_rel_block;) + { + unsigned short *cur_rel = (unsigned short *)rel_block; + unsigned short *end_rel; + + end_rel = (cur_rel + + ((rel_block->BlockSize) + / sizeof(unsigned short))); + cur_rel = (unsigned short *)(rel_block + 1); + + for (; cur_rel < end_rel; cur_rel++) + { + /* Top 4 bits indicate the type of relocation. */ + unsigned char rel_type = (unsigned char)((*cur_rel) >> 12); + unsigned char *rel_target = (exeStart + (rel_block->PageRva) + + ((*cur_rel) & 0x0fff)); + + if (rel_type == IMAGE_REL_BASED_ABSOLUTE) continue; + if (rel_type == IMAGE_REL_BASED_HIGHLOW) + { + if (lower_exeStart) + *(unsigned char **)rel_target -= image_diff; + else *(unsigned char **)rel_target += image_diff; + } + else + { + printf("Unknown PE relocation type: %u\n", + rel_type); + } + } + + rel_block = (Base_relocation_block *)cur_rel; + } + } + } + + if (optional_hdr->NumberOfRvaAndSizes > DATA_DIRECTORY_IMPORT_TABLE) + { + IMAGE_DATA_DIRECTORY *data_dir = (((IMAGE_DATA_DIRECTORY *) + (optional_hdr + 1)) + + DATA_DIRECTORY_IMPORT_TABLE); + if (data_dir->Size != 0) + { + IMAGE_IMPORT_DESCRIPTOR *import_desc = ((void *) + (exeStart + + (data_dir + ->VirtualAddress))); + + /* Each descriptor is for one DLL + * and the array has a null terminator. */ + for (; import_desc->OriginalFirstThunk; import_desc++) + { + ret = exeloadLoadPEDLL(exeStart, import_desc); + if (ret != 0) + { + printf("Cannot load DLL %s, ret %d\n", + exeStart + import_desc->Name, ret); + return (2); + } + } + } + } + + *entry_point = exeStart + optional_hdr->AddressOfEntryPoint; + /* Frees memory not needed by the process. */ + free(section_table); + free(optional_hdr); + if (*loadloc == NULL) + { + *loadloc = exeStart; + } + return (0); +} + + +static int exeloadLoadPEDLL(unsigned char *exeStart, + IMAGE_IMPORT_DESCRIPTOR *import_desc) +{ + Mz_hdr mzFirstbit; + FILE *fp; + Coff_hdr coff_hdr; + Pe32_optional_hdr *optional_hdr; + Coff_section *section_table, *section; + unsigned char *dllStart; + long newpos; + size_t readbytes; + char *name1; + char *name2; + + /* PE DLL is being loaded, + * so it is loaded in the same way as PE executable, + * but the MZ stage is integrated. */ + name1 = exeStart + import_desc->Name; + if ((strcmp(name1, "kernel32.dll") == 0) + || (strcmp(name1, "KERNEL32.dll") == 0)) + { + name2 = kernel32; + } + else if (strcmp(name1, "msvcrt.dll") == 0) + { + name2 = msvcrt; + } + else + { + name2 = name1; + } + fp = fopen(name2, "rb"); + if (fp == NULL) + { + printf("Failed to open %s for loading\n", + exeStart + (import_desc->Name)); + return (1); + } + + /* The header size is in paragraphs, + * so the smallest possible header is 16 bytes (paragraph) long. + * Next is the magic number checked. */ + if ((fseek(fp, 0, SEEK_SET) != 0) + || (fread(&mzFirstbit, 16, 1, fp) != 1) + || (memcmp(mzFirstbit.magic, "MZ", 2) != 0) + && (memcmp(&mzFirstbit.magic, "ZM", 2) != 0)) + { + fclose(fp); + return (2); + } + if (mzFirstbit.header_size == 0) + { + printf("MZ Header has 0 size\n"); + fclose(fp); + return (3); + } + if (mzFirstbit.header_size * 16 > sizeof(mzFirstbit)) + { + printf("MZ Header is too large, size: %u\n", + mzFirstbit.header_size * 16); + fclose(fp); + return (4); + } + /* Loads the rest of the header. */ + if (fread(((char *)&mzFirstbit) + 16, + (mzFirstbit.header_size - 1) * 16, + 1, + fp) != 1) + { + printf("Error occured while reading MZ header\n"); + return (5); + } + /* Determines whether the executable has extensions or is a pure MZ. + * Extensions are at offset in e_lfanew, + * so the header must have at least 4 paragraphs. */ + if ((mzFirstbit.header_size < 4) + || (mzFirstbit.e_lfanew == 0)) + { + fclose(fp); + return (6); + } + + /* PE stage begins. */ + { + unsigned char firstbit[4]; + + if ((fseek(fp, mzFirstbit.e_lfanew, SEEK_SET) != 0) + || (fread(firstbit, 4, 1, fp) != 1) + || (memcmp(firstbit, "PE\0\0", 4) != 0)) + { + fclose(fp); + return (7); + } + } + if (fread(&coff_hdr, sizeof(coff_hdr), 1, fp) != 1) + { + printf("Error occured while reading COFF header\n"); + fclose(fp); + return (8); + } + if ((coff_hdr.Machine != IMAGE_FILE_MACHINE_UNKNOWN) + && (coff_hdr.Machine != IMAGE_FILE_MACHINE_I386)) + { + if (coff_hdr.Machine == IMAGE_FILE_MACHINE_AMD64) + { + printf("64-bit PE programs are not supported\n"); + } + else + { + printf("Unknown PE machine type: %04x\n", coff_hdr.Machine); + } + fclose(fp); + return (9); + } + + if (coff_hdr.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) + { + printf("only relocatable DLLs are supported\n"); + fclose(fp); + return (10); + } + + optional_hdr = malloc(coff_hdr.SizeOfOptionalHeader); + if (optional_hdr == NULL) + { + printf("Insufficient memory to load PE optional header\n"); + fclose(fp); + return (11); + } + if (fread(optional_hdr, coff_hdr.SizeOfOptionalHeader, 1, fp) != 1) + { + printf("Error occured while reading PE optional header\n"); + free(optional_hdr); + fclose(fp); + return (12); + } + if (optional_hdr->Magic != MAGIC_PE32) + { + printf("Unknown PE optional header magic: %04x\n", + optional_hdr->Magic); + free(optional_hdr); + fclose(fp); + return (13); + } + + section_table = malloc(coff_hdr.NumberOfSections * sizeof(Coff_section)); + if (section_table == NULL) + { + printf("Insufficient memory to load PE section headers\n"); + free(optional_hdr); + fclose(fp); + return (14); + } + if (fread(section_table, + coff_hdr.NumberOfSections * sizeof(Coff_section), + 1, + fp) != 1) + { + printf("Error occured while reading PE optional header\n"); + free(section_table); + free(optional_hdr); + fclose(fp); + return (15); + } + + /* Allocates memory for the process. + * Size of image is obtained from the optional header. */ + dllStart = malloc(optional_hdr->SizeOfImage); + if (dllStart == NULL) + { + printf("Insufficient memory to load PE program\n"); + free(section_table); + free(optional_hdr); + fclose(fp); + return (16); + } + + /* Loads all sections at their addresses. */ + for (section = section_table; + section < section_table + (coff_hdr.NumberOfSections); + section++) + { + unsigned long size_in_file; + + /* Virtual size of a section is larger than in file, + * so the difference is filled with 0. */ + if ((section->VirtualSize) > (section->SizeOfRawData)) + { + memset((dllStart + + (section->VirtualAddress) + + (section->SizeOfRawData)), + 0, + (section->VirtualSize) - (section->SizeOfRawData)); + size_in_file = section->SizeOfRawData; + } + /* SizeOfRawData is rounded up, + * so it can be larger than VirtualSize. */ + else + { + size_in_file = section->VirtualSize; + } + if ((fseek(fp, section->PointerToRawData, SEEK_SET) != 0) + || fread(dllStart + (section->VirtualAddress), + size_in_file, + 1, + fp) != 1) + { + printf("Error occured while reading PE section\n"); + free(section_table); + free(optional_hdr); + fclose(fp); + return (17); + } + } + fclose(fp); + + if (dllStart != optional_hdr->ImageBase) + { + /* Relocations are not stripped, so the executable can be relocated. */ + if (optional_hdr->NumberOfRvaAndSizes > DATA_DIRECTORY_REL) + { + IMAGE_DATA_DIRECTORY *data_dir = (((IMAGE_DATA_DIRECTORY *) + (optional_hdr + 1)) + + DATA_DIRECTORY_REL); + /* Difference between preferred address and real address. */ + unsigned long image_diff; + int lower_dllStart; + Base_relocation_block *rel_block = ((Base_relocation_block *) + (dllStart + + (data_dir + ->VirtualAddress))); + Base_relocation_block *end_rel_block; + + if (optional_hdr->ImageBase > dllStart) + { + /* Image is loaded at lower address than preferred. */ + image_diff = optional_hdr->ImageBase + - dllStart; + lower_dllStart = 1; + } + else + { + image_diff = dllStart + - optional_hdr->ImageBase; + lower_dllStart = 0; + } + end_rel_block = rel_block + ((data_dir->Size) + / sizeof(Base_relocation_block)); + + for (; rel_block < end_rel_block;) + { + unsigned short *cur_rel = (unsigned short *)rel_block; + unsigned short *end_rel; + + end_rel = (cur_rel + + ((rel_block->BlockSize) + / sizeof(unsigned short))); + cur_rel = (unsigned short *)(rel_block + 1); + + for (; cur_rel < end_rel; cur_rel++) + { + /* Top 4 bits indicate the type of relocation. */ + unsigned char rel_type = (*cur_rel) >> 12; + void *rel_target = (dllStart + (rel_block->PageRva) + + ((*cur_rel) & 0x0fff)); + + if (rel_type == IMAGE_REL_BASED_ABSOLUTE) continue; + if (rel_type == IMAGE_REL_BASED_HIGHLOW) + { + if (lower_dllStart) + (*((unsigned long *)rel_target)) -= image_diff; + else (*((unsigned long *)rel_target)) += image_diff; + } + else + { + printf("Unknown PE relocation type: %u\n", + rel_type); + } + } + + rel_block = (Base_relocation_block *)cur_rel; + } + } + } + + if (optional_hdr->NumberOfRvaAndSizes > DATA_DIRECTORY_EXPORT_TABLE) + { + IMAGE_DATA_DIRECTORY *data_dir = (((IMAGE_DATA_DIRECTORY *) + (optional_hdr + 1)) + + DATA_DIRECTORY_EXPORT_TABLE); + IMAGE_EXPORT_DIRECTORY *export_dir; + unsigned long *functionTable; + unsigned long *nameTable; + unsigned short *ordinalTable; + unsigned long *thunk; + + if (data_dir->Size == 0) + { + printf("DLL has no export tables\n"); + free(section_table); + free(optional_hdr); + return (18); + } + + export_dir = ((void *)(dllStart + (data_dir->VirtualAddress))); + functionTable = (void *)(dllStart + (export_dir->AddressOfFunctions)); + nameTable = (void *)(dllStart + (export_dir->AddressOfNames)); + ordinalTable = (void *)(dllStart + + (export_dir->AddressOfNameOrdinals)); + + /* The importing itself. + * Import Address Table of the executable is parsed + * and function addresses are written + * when they are found. */ + for (thunk = (void *)(exeStart + (import_desc->FirstThunk)); + *thunk != 0; + thunk++) + { + if ((*thunk) & 0x80000000) + { + /* Bit 31 set, import by ordinal. */ + *thunk = ((unsigned long) + (dllStart + + (functionTable[((*thunk) & 0x7fffffff) + - (export_dir->Base)]))); + } + else + { + /* Import by name. */ + unsigned char *hintname = exeStart + ((*thunk) & 0x7fffffff); + int i; + + /* The first 2 bytes are hint index, + * so they are skipped to get the name. */ + hintname += 2; + for (i = 0; i < (export_dir->NumberOfNames); i++) + { + if (strcmp(hintname, dllStart + (nameTable[i]))) continue; + break; + } + if (i == (export_dir->NumberOfNames)) + { + printf("Function %s not found in DLL\n", hintname); + free(section_table); + free(optional_hdr); + return (1); + } + /* PE specification says that the ordinals in ordinal table + * are biased by Ordinal Base, + * but it does not seem to be correct. */ + *thunk = (unsigned long)(dllStart + + (functionTable[ordinalTable[i]])); + } + } + /* After the DLL is bound, time/date stamp is copied. */ + import_desc->TimeDateStamp = export_dir->TimeDateStamp; + } + if (optional_hdr->NumberOfRvaAndSizes > DATA_DIRECTORY_IMPORT_TABLE) + { + IMAGE_DATA_DIRECTORY *data_dir = (((IMAGE_DATA_DIRECTORY *) + (optional_hdr + 1)) + + DATA_DIRECTORY_IMPORT_TABLE); + if (data_dir->Size != 0) + { + IMAGE_IMPORT_DESCRIPTOR *import_desc = ((void *) + (dllStart + + (data_dir + ->VirtualAddress))); + + /* Each descriptor is for one DLL + * and the array has a null terminator. */ + for (; import_desc->OriginalFirstThunk; import_desc++) + { + if (exeloadLoadPEDLL(dllStart, import_desc)) + { + printf("Failed to load DLL %s\n", + dllStart + (import_desc->Name)); + free(section_table); + free(optional_hdr); + return (19); + } + } + } + } + + /* Entry point is optional for DLLs. */ + if (optional_hdr->AddressOfEntryPoint) + { + int ret = callDllEntry(dllStart + (optional_hdr->AddressOfEntryPoint), + dllStart, + 1, /* fdwReason = DLL_PROCESS_ATTACH */ + (void *)1); /* lpvReserved = non-NULL */ + + if (ret == 0) + { + printf("Initialization of DLL %s failed\n", + exeStart + (import_desc->Name)); + free(section_table); + free(optional_hdr); + return (20); + } + } + + /* Frees memory not needed by the DLL. */ + free(section_table); + free(optional_hdr); + + return (0); +} + +static int exeloadLoadLX(unsigned char **entry_point, + FILE *fp, + unsigned long e_lfanew) +{ + unsigned char firstbit[2]; + long newpos; + size_t readbytes; + + if ((fseek(fp, e_lfanew, SEEK_SET) != 0) + || (fread(firstbit, sizeof(firstbit), 1, fp) != 1) + || (memcmp(firstbit, "LX", 2) != 0)) + { + return (1); + } + /* LX seems to be called LE sometimes. */ + printf("LX (other name LE) is not supported\n"); + + return (2); +} + +static int exeloadLoadNE(unsigned char **entry_point, + FILE *fp, + unsigned long e_lfanew) +{ + unsigned char firstbit[2]; + long newpos; + size_t readbytes; + + if ((fseek(fp, e_lfanew, SEEK_SET) != 0) + || (fread(firstbit, sizeof(firstbit), 1, fp) != 1) + || (memcmp(firstbit, "NE", 2) != 0)) + { + return (1); + } + printf("NE is not supported\n"); + + return (2); +} + +#endif /* NEED_MZ */ + +#if NEED_MVS +/* Structures here are documented in Appendix B and E of + MVS Program Management: Advanced Facilities SA22-7644-14: + http://publibfp.dhe.ibm.com/cgi-bin/bookmgr/BOOKS/iea2b2b1/CCONTENTS + and the IEBCOPY component is documented here: + Appendix B of OS/390 DFSMSdfp Utilities SC26-7343-00 + or Appendix B of the z/OS equivalent SC26-7414-05 available here at + http://publibz.boulder.ibm.com/epubs/pdf/dgt2u140.pdf +*/ + +#define PE_DEBUG 1 + +static int fixPE(unsigned char *buf, + size_t *len, + unsigned char **entry, + unsigned long rlad) +{ + unsigned char *p; + unsigned char *q; + /* int z; */ + typedef struct { + unsigned char pds2name[8]; + unsigned char unused1[19]; + unsigned char pds2epa[3]; + unsigned char pds2ftb1; + unsigned char pds2ftb2; + unsigned char pds2ftb3; + } IHAPDS; + IHAPDS *ihapds; + int rmode; + int amode; + int ent; + int rec = 0; + int corrupt = 1; + int rem = *len; + int l; + int l2; + int lastt = -1; + unsigned char *upto = buf; + + if ((*len <= 8) || (*((int *)buf + 1) != 0xca6d0f)) + { + /* printf("Not an MVS PE executable\n"); */ + return (-1); + } +#if PE_DEBUG + printf("MVS PE total length is %lu\n", (unsigned long)*len); +#endif + p = buf; + while (1) + { + rec++; + l = *(short *)p; + /* keep track of remaining bytes, and ensure they really exist */ + if (l > rem) + { + break; + } + rem -= l; +#if PE_DEBUG + printf("rec %d, offset %d is len %d\n", rec, p - buf, l); +#endif +#if 0 + if (1) + { + for (z = 0; z < l; z++) + { + printf("z %d %x %c\n", z, p[z], + isprint((unsigned char)p[z]) ? p[z] : ' '); + } + } +#endif + if (rec == 3) /* directory record */ + { + /* there should only be one directory entry, + which is 4 + 276 + 12 */ + if (l < 292) + { + break; + } + q = p + 24; + l2 = *(short *)q; + if (l2 < 32) break; + ihapds = (IHAPDS *)(q + 2); + rmode = ihapds->pds2ftb2 & 0x10; +/* do we care about alias entry point amode? */ +#if 0 + amode = (ihapds->pds2ftb2 & 0x0c) >> 2; +#else + amode = ihapds->pds2ftb2 & 0x03; +#endif + ent = ((unsigned long)ihapds->pds2epa[0] << 16) + | ((unsigned long)ihapds->pds2epa[1] << 8) + | ihapds->pds2epa[2]; + *entry = buf + ent; +#if PE_DEBUG + printf("module name is %.8s\n", ihapds->pds2name); + printf("rmode is %s\n", rmode ? "ANY" : "24"); + printf("amode is "); + if (amode == 0) + { + printf("24"); + } + else if (amode == 2) + { + printf("31"); + } + else if (amode == 1) + { + printf("64"); + } + else if (amode == 3) + { + printf("ANY"); + } + printf("\n"); + printf("entry point is %x\n", ent); +#endif + } + else if (rec > 3) + { + int t; + int r2; + int l2; + int term = 0; + + if (l < (4 + 12)) + { + break; + } + q = p + 4 + 10; + r2 = l - 4 - 10; + while (1) + { + l2 = *(short *)q; + r2 -= sizeof(short); + if (l2 > r2) + { + term = 1; + break; + } + r2 -= l2; + + if (l2 == 0) break; + q += sizeof(short); +#if PE_DEBUG + printf("load module record is of type %2x (len %5d)" + " offset %d\n", + *q, l2, q - p); +#endif + + t = *q; + if ((lastt == 1) || (lastt == 3) || (lastt == 0x0d)) + { +#if PE_DEBUG + printf("rectype: program text\n"); +#endif + memmove(upto, q, l2); + upto += l2; + t = -1; + if (lastt == 0x0d) + { + term = 1; + corrupt = 0; + break; + } + } + else if (t == 0x20) + { + /* printf("rectype: CESD\n"); */ + } + else if (t == 1) + { + /* printf("rectype: Control\n"); */ + } + else if (t == 0x0d) + { + /* printf("rectype: Control, about to end\n"); */ + } + else if (t == 2) + { + /* printf("rectype: RLD\n"); */ + if (processRLD(buf, rlad, q, l2) != 0) + { + term = 1; + break; + } + } + else if (t == 3) + { + int l3; + + /* printf("rectype: Dicionary = Control + RLD\n"); */ + l3 = *(short *)(q + 6) + 16; +#if 0 + printf("l3 is %d\n", l3); +#endif + if (processRLD(buf, rlad, q, l3) != 0) + { + term = 1; + break; + } + } + else if (t == 0x0e) + { + /* printf("rectype: Last record of module\n"); */ + if (processRLD(buf, rlad, q, l2) != 0) + { + term = 1; + break; + } + term = 1; + corrupt = 0; + break; + } + else if (t == 0x80) + { + /* printf("rectype: CSECT\n"); */ + } + else + { + /* printf("rectype: unknown %x\n", t); */ + } +#if 0 + if ((t == 0x20) || (t == 2)) + { + for (z = 0; z < l; z++) + { + printf("z %d %x %c\n", z, q[z], + isprint(q[z]) ? q[z] : ' '); + } + } +#endif + lastt = t; + + q += l2; + if (r2 == 0) + { +#if PE_DEBUG + printf("another clean exit\n"); +#endif + break; + } + else if (r2 < (10 + sizeof(short))) + { + /* printf("another unclean exit\n"); */ + term = 1; + break; + } + r2 -= 10; + q += 10; + } + if (term) break; + } + p = p + l; + if (rem == 0) + { +#if PE_DEBUG + printf("breaking cleanly\n"); +#endif + } + else if (rem < 2) + { + break; + } + } + if (corrupt) + { + printf("corrupt module\n"); + return (-1); + } +#if 0 + printf("dumping new module\n"); +#endif + *len = upto - buf; /* return new module length */ + return (0); +} + + +static int processRLD(unsigned char *buf, + unsigned long rlad, + unsigned char *rld, + int len) +{ + unsigned char *r; + int cont = 0; + unsigned char *fin; + int negative; + int ll; + int a; + long newval; + unsigned int *zaploc; + + r = (unsigned char *)rld + 16; + fin = rld + len; + while (r != fin) + { + if (!cont) + { + r += 4; /* skip R & P */ + if (r >= fin) + { + printf("corrupt1 at position %x\n", r - rld - 4); + return (-1); + } + } + negative = *r & 0x02; + if (negative) + { + printf("got a negative adjustment - unsupported\n"); + return (-1); + } + ll = (*r & 0x0c) >> 2; + ll++; + if ((ll != 4) && (ll != 3)) + { + printf("untested and unsupported relocation %d\n", ll); + return (-1); + } + if (ll == 3) + { + if (rlad > 0xffffff) + { + printf("AL3 prevents relocating this module to %lx\n", rlad); + return (-1); + } + } + cont = *r & 0x01; /* do we have A & F continous? */ + r++; + if ((r + 3) > fin) + { + printf("corrupt2 at position %x\n", r - rld); + return (-1); + } + a = ((unsigned long)r[0] << 16) + || ((unsigned long)r[1] << 8) + || r[2]; + /* +++ need bounds checking on this OS code */ + /* printf("need to zap %d bytes at offset %6x\n", ll, a); */ + zaploc = (unsigned int *)(buf + a); + + /* This old code doesn't look right. The integer is misaligned */ + /* zaploc = (unsigned int *)(buf + a - ((ll == 3) ? 1 : 0)); */ + + newval = *zaploc; + /* printf("which means that %8x ", newval); */ + newval += rlad; + /* printf("becomes %8x\n", newval); */ + *zaploc = newval; + r += 3; + } + return (0); +} +#endif diff --git a/app/src/main/cpp/bios/armeabi-v7a/exeload.h b/app/src/main/cpp/bios/armeabi-v7a/exeload.h new file mode 100644 index 0000000..1537920 --- /dev/null +++ b/app/src/main/cpp/bios/armeabi-v7a/exeload.h @@ -0,0 +1,16 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Alica Okano. */ +/* Released to the Public Domain as discussed here: */ +/* http://creativecommons.org/publicdomain/zero/1.0/ */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* exeload.h - header for exeload.c */ +/* */ +/*********************************************************************/ + +int exeloadDoload(unsigned char **entry_point, + char *progname, + unsigned char **loadloc); diff --git a/app/src/main/cpp/bios/armeabi-v7a/pos.h b/app/src/main/cpp/bios/armeabi-v7a/pos.h new file mode 100644 index 0000000..5e43956 --- /dev/null +++ b/app/src/main/cpp/bios/armeabi-v7a/pos.h @@ -0,0 +1,524 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* pos - some low-level dos functions */ +/* */ +/* In my opinion, all the MSDOS functions should have had both a */ +/* low-level assember interrupt definition, and a functional */ +/* interface for higher level languages such as C. It is important */ +/* to have both interfaces as it allows anyone creating a new */ +/* language to implement the functions themselves. It is also a */ +/* good idea to make the API start with a specific mneumonic like */ +/* the Dos* and Win* etc functions you see in the OS/2 API. It is */ +/* not a good idea to pretend to be performing data abstraction by */ +/* typedefing long as LONG etc. Hence, the following is what I */ +/* think should have been done to formalise the HLL Dos API. */ +/* */ +/* Obviously it's a bit late to be standardizing this now, and not */ +/* only that, but it's not much of a standard when I'm the only */ +/* user of it either! However, this interface is first and */ +/* foremost to provide myself with a clearcut API so that I can */ +/* make it 32-bit at the drop of a hat. */ +/* */ +/*********************************************************************/ + +#ifndef POS_INCLUDED +#define POS_INCLUDED + +#include + +/*Standard Error Codes for PDOS*/ +/*When adding a new error code here, also add it to PosGetErrorMessageString() + *in pdos.c + */ +#define POS_ERR_NO_ERROR 0x00 +#define POS_ERR_FUNCTION_NUMBER_INVALID 0x01 +#define POS_ERR_FILE_NOT_FOUND 0x02 +#define POS_ERR_PATH_NOT_FOUND 0x03 +#define POS_ERR_MANY_OPEN_FILES 0x04 +#define POS_ERR_ACCESS_DENIED 0x05 +#define POS_ERR_INVALID_HANDLE 0x06 +#define POS_ERR_MEM_CONTROL_BLOCK_DESTROYED 0x07 +#define POS_ERR_INSUFFICIENT_MEMORY 0x08 +#define POS_ERR_MEMORY_BLOCK_ADDRESS_INVALID 0x09 +#define POS_ERR_ENVIRONMENT_INVALID 0x0A +#define POS_ERR_FORMAT_INVALID 0x0B +#define POS_ERR_ACCESS_CODE_INVALID 0x0C +#define POS_ERR_DATA_INVALID 0x0D +#define POS_ERR_RESERVED 0x0E +#define POS_ERR_FIXUP_OVERFLOW 0x0E +#define POS_ERR_INVALID_DRIVE 0x0F +#define POS_ERR_ATTEMPTED_TO_REMOVE_CURRENT_DIRECTORY 0x10 +#define POS_ERR_NOT_SAME_DEVICE 0x11 +#define POS_ERR_NO_MORE_FILES 0x12 +/**/ + +#define POS_ERR_FILE_EXISTS 0x50 + +/* for use by PosAllocMem callers */ +#define POS_LOC_MASK 0x300 +#define POS_LOC20 0x100 +#define POS_LOC32 0x200 +#define POS_LOC64 0x300 + +/* File attribute bits */ +#define FILE_ATTR_READONLY 0x01 +#define FILE_ATTR_HIDDEN 0x02 +#define FILE_ATTR_SYSTEM 0x04 +#define FILE_ATTR_LABEL 0x08 +#define FILE_ATTR_DIRECTORY 0x10 +#define FILE_ATTR_ARCHIVE 0x20 + +/* Video subsystem information */ +typedef struct pos_video_info { + unsigned int mode; + unsigned int page; + unsigned int rows; + unsigned int cols; + unsigned int cursorStart; + unsigned int cursorEnd; + unsigned int row; + unsigned int col; + unsigned int currentAttrib; +} pos_video_info; + +/* Input buffer used for INT 21,A */ +typedef struct pos_input_buffer { + unsigned char maxChars; /* Maximum number of chars buffer can hold */ + unsigned char actualChars; /* Number of chars actually read + (not including final CR) */ + char data[1]; /* 1 is arbitrary, for C compilers that don't accept + incomplete arrays */ +} pos_input_buffer; + +/* ===== BEGINS PROCESS MANAGEMENT DATA STRUCTURES ===== */ + +/* Process status enumeration. */ +typedef enum { + /* Process has been loaded but not yet executed. */ + PDOS_PROCSTATUS_LOADED, + /* Process is the current foreground process. */ + PDOS_PROCSTATUS_ACTIVE, + /* Process is waiting for child process to finish. */ + PDOS_PROCSTATUS_CHILDWAIT, + /* Process is a TSR */ + PDOS_PROCSTATUS_TSR, + /* Process has voluntarily suspended itself. */ + PDOS_PROCSTATUS_SUSPENDED, + /* Process has terminated */ + PDOS_PROCSTATUS_TERMINATED +} PDOS_PROCSTATUS; + +#define PDOS_PROCESS_EXENAMESZ 13 + +/* PDOS_PROCINFO: data structure with info about a process */ +typedef struct _PDOS_PROCINFO { + char exeName[PDOS_PROCESS_EXENAMESZ]; /* ASCIIZ short name of executable */ + unsigned long pid; /* Process ID */ + unsigned long ppid; /* Parent Process ID; 0 if none */ + unsigned long prevPid; /* Prev PID in chain; 0 if start of chain */ + unsigned long nextPid; /* Next PID in chain; 0 if end of chain */ + PDOS_PROCSTATUS status; /* Process status */ +} PDOS_PROCINFO; + +/* ===== ENDING PROCESS MANAGEMENT DATA STRUCTURES ===== */ + +typedef struct { +#ifdef __32BIT__ + char *env; +#else + short env; +#endif + unsigned char *cmdtail; + char *fcb1; + char *fcb2; +} POSEXEC_PARMBLOCK; + +/* API functions */ + +void PosTermNoRC(void); /* int 20h */ + +/* int 21h */ +unsigned int PosDisplayOutput(unsigned int ch); /* func 2 */ + +unsigned int PosDirectConsoleOutput(unsigned int ch); /* func 6 */ + +unsigned int PosDirectCharInputNoEcho(void); /* func 7 */ + +unsigned int PosGetCharInputNoEcho(void); /* func 8 */ + +unsigned int PosDisplayString(const char *buf); /* func 9 */ + +void PosReadBufferedInput(pos_input_buffer *buf); /* func A */ + +unsigned int PosSelectDisk(unsigned int drive); /* func e */ + +unsigned int PosGetDefaultDrive(void); /* func 19 */ + +void PosSetDTA(void *dta); /* func 1a */ + +void PosSetInterruptVector(unsigned int intnum, void *handler); /* func 25 */ + +void PosGetSystemDate(unsigned int *year, /* func 2a */ + unsigned int *month, + unsigned int *day, + unsigned int *dw); + +unsigned int PosSetSystemDate(unsigned int year, /* func 2b */ + unsigned int month, + unsigned int day); + +void PosGetSystemTime(unsigned int *hour, /* func 2c */ + unsigned int *min, + unsigned int *sec, + unsigned int *hundredths); + +void PosSetVerifyFlag(int flag); /* func 2e + - set read-after-write verification flag */ + +void *PosGetDTA(void); /* func 2f */ + +unsigned int PosGetDosVersion(void); /* func 30 */ + +void PosTerminateAndStayResident(int exitCode, int paragraphs); /* func 31 */ + +int PosGetBreakFlag(void); /* func 33, subfunc 00 + - get Ctrl+Break checking flag status */ + +void PosSetBreakFlag(int flag); /* func 33, subfunc 01 + - set Ctrl+Break checking flag status */ + +int PosGetBootDrive(void); /* func 33, subfunc 05 + - get boot drive (1=A,2=B,etc.) */ + +void *PosGetInterruptVector(int intnum); /* func 35 */ + +void PosGetFreeSpace(int drive, + unsigned int *secperclu, + unsigned int *numfreeclu, + unsigned int *bytpersec, + unsigned int *totclus); /* func 36 */ + +int PosMakeDir(const char *dname); /* func 39 */ + +int PosRemoveDir(const char *dname); /* func 3a */ + +int PosChangeDir(const char *to); /* func 3b */ + +int PosCreatFile(const char *name, /* func 3c */ + int attrib, + int *handle); + +int PosOpenFile(const char *name, /* func 3d */ + int mode, + int *handle); + +int PosCloseFile(int handle); /* func 3e */ + +int PosReadFile(int fh, /* func 3f */ + void *data, + unsigned int bytes, + unsigned int *readbytes); + +int PosWriteFile(int handle, /* func 40 */ + const void *data, + unsigned int len, + unsigned int *writtenbytes); + +int PosDeleteFile(const char *fname); /* func 41 */ + +int PosMoveFilePointer(int handle, /* func 42 */ + long offset, + int whence, + long *newpos); + +int PosGetFileAttributes(const char *fnm,int *attr);/*func 43*/ + +int PosSetFileAttributes(const char *fnm,int attr);/*func 43 subfunc 01*/ + +int PosGetDeviceInformation(int handle, unsigned int *devinfo); + /* func 44 subfunc 0 */ + +int PosSetDeviceInformation(int handle, unsigned int devinfo); + /* func 44 subfunc 1 */ + +int PosBlockDeviceRemovable(int drive); /* func 44 subfunc 8 */ + +int PosBlockDeviceRemote(int drive,int *da); /* func 44 subfunc 9 */ + +int PosGenericBlockDeviceRequest(int drive, + int catcode, + int function, + void *parmblock); /*func 44 subfunc 0D*/ + + +int PosDuplicateFileHandle(int fh); /* func 45 */ + +int PosForceDuplicateFileHandle(int fh, int newfh); /* func 46 */ + +int PosGetCurDir(int drive, char *dir); /* func 47 */ + +/* func 48 alternate entry really for 16-bit */ +void *PosAllocMemPages(unsigned int pages, unsigned int *maxpages); + +int PosFreeMem(void *ptr); /* func 49 */ + +/* func 4a */ +int PosReallocPages(void *ptr, unsigned int newpages, unsigned int *maxp); + +int PosExec(char *prog, POSEXEC_PARMBLOCK *parmblock); /* func 4b */ + +void PosTerminate(int rc); /* func 4c */ + +int PosGetReturnCode(void); /* func 4d */ + +int PosFindFirst(char *pat, int attrib); /* func 4e */ + +int PosFindNext(void); /* func 4f */ + +int PosGetCurrentProcessId(void); /* func 51 */ + +/* func 54 - get read-after-write verification flag */ +int PosGetVerifyFlag(void); + +int PosRenameFile(const char *old, const char *new); /* func 56 */ + +int PosGetFileLastWrittenDateAndTime(int handle, + unsigned int *fdate, + unsigned int *ftime); /*func 57*/ + +int PosSetFileLastWrittenDateAndTime(int handle, + unsigned int fdate, + unsigned int ftime);/*func 57 subfunc 1*/ + +int PosCreatNewFile(const char *name, int attrib, int *handle); /*func 5b*/ + +int PosTruename(char *prename,char *postname); /*func 60*/ + +void PosAExec(char *prog, POSEXEC_PARMBLOCK *parmblock); /* func 80 */ + +/* The following functions are extensions... */ + +void PosDisplayInteger(int x); /* func f6.00 */ + +void PosReboot(void); /* func f6.01 */ + +void PosSetDosVersion(unsigned int version); /* func f6.03 */ + +int PosGetLogUnimplemented(void); /* func f6.04 */ + +void PosSetLogUnimplemented(int flag); /* func f6.05 */ + +/* So programs can reliably determine if they are running under PDOS-16 or + * some other implementation of PDOS API, such as FreeDOS, MS-DOS, PC-DOS, + * DR-DOS, DOSBox, etc. INT 21,AX=F606 will return AX=1234 under PDOS, but not + * under these other operating systems. + */ +#define PDOS_MAGIC 0x1234 + +int PosGetMagic(void); /* func f6.06 */ + +void PosGetMemoryManagementStats(void *stats); /* func f6.07 */ + +void *PosAllocMem(unsigned int size, unsigned int flags); /* func f6.08 */ + +/* Given an error code return corresponding message */ +char *PosGetErrorMessageString(unsigned int errorCode); /* func f6.09 */ + +void PosPowerOff(void); /* func f6.0a */ + +/* Func F6.0C - Get info about a process. + * pid = PID to get info on (0=get info on init process) + * infoSz should be sizeof(PDOS_PROCINFO). It is passed for future-proofing + * (future versions might make the structure bigger, we know whether client + * wants old or new version based on the passed size) + */ +int PosProcessGetInfo(unsigned long pid, + PDOS_PROCINFO *info, + unsigned int infoSz); + +/* Func F6.0D - Get memory usage stats for given process + * pid=0 for current process + */ +void PosProcessGetMemoryStats(unsigned long pid, void *stats); + +void PosClearScreen(void); /* func f6.30 */ + +void PosMoveCursor(int row, int col); /* func f6.31 */ + +int PosGetVideoInfo(pos_video_info *info, unsigned int size); /* func f6.32 */ + +int PosKeyboardHit(void); /* func f6.33 */ + +/* F6,34 - Yield the CPU. Currently calls APM BIOS to reduce CPU usage. + * One day it might be used for multi-tasking. + */ +void PosYield(void); + +/* F6,35 - Sleep for given number of seconds */ +void PosSleep(unsigned long seconds); + +/* F6,36 - Get tick count */ +unsigned long PosGetClockTickCount(void); + +/* F6,37 - Set Video Attribute */ +void PosSetVideoAttribute(unsigned int attribute); + +/* F6,38 - Set Video Mode */ +int PosSetVideoMode(unsigned int mode); + +/* F6,39 - Set Video Page */ +int PosSetVideoPage(unsigned int page); + +/* F6,3A - Set Environment Variable + * To unset a variable, pass NULL for the value. The name and value string + * will be copied into the environment block, so are not required after + * this call. + */ +int PosSetEnv(char *name, char *value); + +/* F6,3B - Get Environment Block + * Returns the environment block for the current process. + */ +void * PosGetEnvBlock(void); + +/* F6,3C - Set Named Font */ +int PosSetNamedFont(char *fontName); + +/* F6,3D - Allocate Virtual Memory */ +void *PosVirtualAlloc(void *addr, size_t size); + +/* F6,3E - Free Virtual Memory */ +void PosVirtualFree(void *addr, size_t size); + +/* F6,3F - Get Command Line String For The Current Process */ +char *PosGetCommandLine(void); + +/* F6,40 - Read Byte From Port */ +unsigned char PosInp(unsigned int port); + +/* F6,41 - Write Byte To Port */ +void PosOutp(unsigned int port, unsigned char data); + +/* F6,42 - Absolute Drive Read */ +unsigned int PosAbsoluteDriveRead(int drive,unsigned long start_sector, + unsigned int sectors,void *buf); +/* F6,43 - Absolute Drive Write */ +unsigned int PosAbsoluteDriveWrite(int drive,unsigned long start_sector, + unsigned int sectors,void *buf); + +/* F6,44 - Boot a Disk */ +unsigned int PosDoBoot(int disknum); + +/* F6,45 - start or stop screen capture */ +unsigned int PosScrncap(int disknum); + +/* F6,46 - GetStdHandle */ +void *PosGetStdHandle(unsigned int nStdHandle); + +/* F6,47 - SetStdHandle */ +unsigned int PosSetStdHandle(unsigned int nStdHandle, void *hHandle); + +/* F6,48 - start system monitor */ +unsigned int PosMonitor(void); + +/* F6,49 - show return codes */ +unsigned int PosShowret(int flag); + +unsigned int PosAbsoluteDiskRead(int drive, unsigned long start_sector, + unsigned int sectors,void *buf); /*INT25 */ + +unsigned int PosAbsoluteDiskWrite(int drive, unsigned long start_sector, + unsigned int sectors,void *buf); /*INT26 */ + + +/*Structure for BPB*/ +typedef struct { + unsigned char BytesPerSector[2]; + unsigned char SectorsPerClustor; + unsigned char ReservedSectors[2]; + unsigned char FatCount; + unsigned char RootEntries[2]; + unsigned char TotalSectors16[2]; + unsigned char MediaType; + unsigned char FatSize16[2]; + unsigned char SectorsPerTrack[2]; + unsigned char Heads[2]; + unsigned char HiddenSectors_Low[2]; + unsigned char HiddenSectors_High[2]; + unsigned char TotalSectors32[4]; +} BPB; +/**/ + +/*Structure for function call 440D*/ +typedef struct { + unsigned char special_function; + unsigned char reservedspace[6]; + BPB bpb; + unsigned char reserve2[100]; /* for OSes with bigger BPBs */ +}PB_1560; +/**/ + +/*Structure for int25/26*/ +typedef struct{ + unsigned long sectornumber; + unsigned int numberofsectors; + void *transferaddress; +}DP; +/**/ + +/*Structure for tempDTA in case of multiple PosFindFirst Calls*/ +typedef struct { + int handle; + char pat[20]; +}FFBLK; +/**/ + +/*Structure to define variables used in DTA*/ +typedef struct { + char attr; /*attribute of the search(0x00)*/ + char drive; /*drive used in search(0x01)*/ + char search[11]; /*search name used(0x02)*/ + int direntno; /*directory entry number(0x0D)*/ + int startcluster; /*starting cluster number for + current directory zero for + root directory(0x0F)*/ + int reserved; /*reserved(0x11)*/ + int startcluster2; /*starting cluster number for + current directory zero for + root directory(0x13)*/ + unsigned char attrib; /*attribute of the matching file + (0x15)*/ + int file_time; /*file time(0x16)*/ + int file_date; /*file date(0x18)*/ + long file_size; /*file size(0x1A)*/ + char file_name[13]; /*ASCIIZ file name and extension in + form NAME.EXT with blanks stripped + 0x1E)*/ + unsigned char lfn[256]; /*Stores LFN (255 characters max.) and + *null terminator.*/ + /*+++Add support for UCS-2 and find + *better place for LFN provided to DIR.*/ + +}DTA; +/**/ + + +#if defined(__PDOSGEN__) +#include <__os.h> + +#define PosGetDTA __os->PosGetDTA +#define PosFindFirst __os->PosFindFirst +#define PosFindNext __os->PosFindNext +#define PosChangeDir __os->PosChangeDir +#define PosMakeDir __os->PosMakeDir +#define PosRemoveDir __os->PosRemoveDir +#endif + + +#endif /* POS_INCLUDED */ diff --git a/app/src/main/cpp/bios/x86/CMakeLists.txt b/app/src/main/cpp/bios/x86/CMakeLists.txt new file mode 100644 index 0000000..9e44685 --- /dev/null +++ b/app/src/main/cpp/bios/x86/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.18.1) + +project("pdos_pdandro") +enable_language(C) + +add_executable( + libbios.so + + ${CMAKE_SOURCE_DIR}/pdpclib/${ANDROID_ABI}/linstart.c + bios.c + exeload.c +) + +target_compile_options(libbios.so PRIVATE + $<$:-ffreestanding -fno-builtin -fno-stack-protector -nostdinc -nostdlib -D__gnu_linux__ -O2 -DNEED_AOUT -DNEED_MPROTECT -I${CMAKE_SOURCE_DIR}/pdpclib/${ANDROID_ABI} -I${CMAKE_CURRENT_SOURCE_DIR}> +) + +target_link_options(libbios.so PRIVATE "-Wl,-nostdlib") +target_link_options(libbios.so PRIVATE "-nostdlib") + +target_link_libraries(libbios.so PRIVATE pdpclib) + diff --git a/app/src/main/cpp/bios/x86/__os.h b/app/src/main/cpp/bios/x86/__os.h new file mode 100644 index 0000000..a504a15 --- /dev/null +++ b/app/src/main/cpp/bios/x86/__os.h @@ -0,0 +1,156 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* os.h - C library exported by OS */ +/* */ +/*********************************************************************/ + +/* Note that a BIOS that uses this interface is unlikely to populate + all of these things, especially if running on hardware of the + 1980s era. You can expect restrictions such as only fopen (of a + filename such as "0x80"), fread, fwrite, fseek actually working, + and only working if you give them offsets and lengths that are + multiples of 512 and/or the sector size. Also the buffer that + data is read into/written from may have alignment requirements + such as 16 bytes or 512 bytes. It depends on what is out there. */ + +#ifndef __OS_INCLUDED +#define __OS_INCLUDED + +#include +#include +#include +#include + +typedef struct { + /* a BIOS may not have this, as it implies the existence of a + complete C library, not typical for a real BIOS. Even an OS + won't necessarily have this. */ + int (*__start)(char *p); + /* a BIOS will typically have a block of memory it expects you + to malloc. This is the size. A BIOS may or may not allow + arbitrary mallocs that differ from this size. */ + size_t mem_amt; + /* if this is true, it means that mem_amt is adjusted every + time you call malloc, so that you can get multiple chunks + of memory instead of requiring only contiguous memory. + Only applicable to a BIOS. */ + int mem_rpt; + /* the name of the program being executed. Could be an empty + string */ + char *prog_name; + /* The single parameter passed to this program. E.g. a suggested + disk name to be opened. Will at least be an empty string */ + char *prog_parm; + int (*Xprintf)(const char *format, ...); + int (**main)(int argc, char **argv); + void *(*malloc)(size_t size); + FILE *Xstdin; + FILE *Xstdout; +#ifdef __SUBC__ + void * (*Xfopen)(const char *filename, const char *mode); +#else + FILE *(*Xfopen)(const char *filename, const char *mode); +#endif + int (*Xfseek)(FILE *stream, long offset, int whence); + size_t (*Xfread)(void *ptr, size_t size, size_t nmemb, FILE *stream); + int (*Xfclose)(FILE *stream); + size_t (*Xfwrite)(const void *ptr, size_t size, size_t nmemb, FILE *stream); + char *(*Xfgets)(char *s, int n, FILE *stream); + char *(*strchr)(const char *s, int c); + int (*strcmp)(const char *s1, const char *s2); + int (*strncmp)(const char *s1, const char *s2, size_t n); + char *(*strcpy)(char *s1, const char *s2); + size_t (*strlen)(const char *s); + int (*Xfgetc)(FILE *stream); + int (*Xfputc)(int c, FILE *stream); + int (*Xfflush)(FILE *stream); + int (*Xsetvbuf)(FILE *stream, char *buf, int mode, size_t size); + void *(*PosGetDTA)(void); + int (*PosFindFirst)(char *pat, int attrib); + int (*PosFindNext)(void); + int (*PosGetDeviceInformation)(int handle, unsigned int *devinfo); + int (*PosSetDeviceInformation)(int handle, unsigned int devinfo); + char *(*Xctime)(const time_t *timer); + time_t (*Xtime)(time_t *timer); + int (*PosChangeDir)(const char *to); + int (*PosMakeDir)(const char *dname); + int (*PosRemoveDir)(const char *dname); + int (*Xremove)(const char *filename); + void *(*memcpy)(void *s1, const void *s2, size_t n); + char *(*strncpy)(char *s1, const char *s2, size_t n); + char *(*strcat)(char *s1, const char *s2); + FILE *Xstderr; + void (*free)(void *ptr); + void (*abort)(void); + void *(*memset)(void *s, int c, size_t n); + int (*Xfputs)(const char *s, FILE *stream); + int (*Xfprintf)(FILE *stream, const char *format, ...); + char *(*Xgetenv)(const char *name); + void *(*memmove)(void *s1, const void *s2, size_t n); + void (*Xexit)(int status); + int (*memcmp)(const void *s1, const void *s2, size_t n); + int *(*_errno)(void); /* internal use */ + char *(*Xtmpnam)(char *s); + int (*Xvfprintf)(FILE *stream, const char *format, va_list arg); + int (*Xungetc)(int c, FILE *stream); + int (*Xvsprintf)(char *s, const char *format, va_list arg); + int (*Xsprintf)(char *s, const char *format, ...); +#ifdef __SUBC__ + int (*signal)(int sig, int (*handler)()); +#else + void (*(*signal)(int sig, void (*func)(int)))(int); +#endif + int (*raise)(int sig); + void *(*Xcalloc)(size_t nmemb, size_t size); + void *(*Xrealloc)(void *ptr, size_t size); + int (*Xatoi)(const char *nptr); + long (*Xstrtol)(const char *nptr, char **endptr, int base); + unsigned long (*Xstrtoul)(const char *nptr, char **endptr, int base); + void (*Xqsort)(void *a, size_t b, size_t c, + int (*f)(const void *d, const void *e)); +#ifdef __SUBC__ + void *(*Xbsearch)(const void *key, const void *base, + size_t nmemb, size_t size, + int (*compar)()); +#else + void *(*Xbsearch)(const void *key, const void *base, + size_t nmemb, size_t size, + int (*compar)(const void *, const void *)); +#endif +#ifdef __SUBC__ + void *(*Xlocaltime)(); +#else + struct tm *(*Xlocaltime)(const time_t *timer); +#endif + clock_t (*Xclock)(void); + char *(*strerror)(int errnum); + char *(*strrchr)(const char *s, int c); + char *(*strstr)(const char *s1, const char *s2); + char *(*strpbrk)(const char *s1, const char *s2); + size_t (*strspn)(const char *s1, const char *s2); + size_t (*strcspn)(const char *s1, const char *s2); + void *(*memchr)(const void *s, int c, size_t n); + long (*Xftell)(FILE *stream); + int (*Xabs)(int j); + char *(*setlocale)(int category, const char *locale); + void (*Xperror)(const char *s); + void (*Xrewind)(FILE *stream); + char *(*strncat)(char *s1, const char *s2, size_t n); + int (*Xsscanf)(const char *s, const char *format, ...); + int (*isalnum)(int c); + int (*isxdigit)(int c); + int (*Xrename)(const char *old, const char *newnam); + void (*Xclearerr)(FILE *stream); + int (*_assert)(char *x, char *y, int z); /* internal use */ + double (*Xatof)(const char *nptr); +} OS; + +extern OS *__os; + +#endif diff --git a/app/src/main/cpp/bios/x86/a_out.h b/app/src/main/cpp/bios/x86/a_out.h new file mode 100644 index 0000000..b454011 --- /dev/null +++ b/app/src/main/cpp/bios/x86/a_out.h @@ -0,0 +1,34 @@ +/* written by Paul Edwards */ +/* released to the public domain */ +/* poor man's version of a.out.h - contains everything required by + pdos at time of writing */ +/* Documentation for the a.out format can be found here: + http://man.cat-v.org/unix_8th/5/a.out */ + +#define SEGMENT_SIZE 0x10000UL + +struct exec { + unsigned long a_info; + unsigned long a_text; + unsigned long a_data; + unsigned long a_bss; + unsigned long a_syms; + unsigned long a_entry; + unsigned long a_trsize; + unsigned long a_drsize; +}; + +/* First 2 bytes of a_info are magic number identifying the format. + * Mask 0xffff can be used on the a_info for checking the numbers. + * Top word should be 0x0064. */ +#define OMAGIC 0407 +#define NMAGIC 0410 +#define ZMAGIC 0413 +#define QMAGIC 0314 + +#define N_TXTOFF(e) (0x400) +#define N_TXTADDR(e) (SEGMENT_SIZE) +/* this formula doesn't work when the text size is exactly 64k */ +#define N_DATADDR(e) \ + (N_TXTADDR(e) + SEGMENT_SIZE + ((e).a_text & 0xffff0000UL)) +#define N_BSSADDR(e) (N_DATADDR(e) + (e).a_data) diff --git a/app/src/main/cpp/bios/x86/bios.c b/app/src/main/cpp/bios/x86/bios.c new file mode 100644 index 0000000..8bd97dc --- /dev/null +++ b/app/src/main/cpp/bios/x86/bios.c @@ -0,0 +1,454 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* bios - generic BIOS that exports the C library */ +/* */ +/*********************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "__os.h" +#include "exeload.h" + +extern int __genstart; +extern int (*__genmain)(int argc, char **argv); + +/* A BIOS is meant to be machine-specific, so this is not a big deal */ +#if 1 +#define PATH "" +/* #define PATH "./" */ +#else +#define PATH "/storage/emulated/0/Download/" +#endif + +#define MEMAMT 24*1000*1000 + +#if defined(__gnu_linux__) || defined(__ARM__) +extern int __start(int argc, char **argv); +#else +extern int __start(char *p); +#endif + +int their_start(char *parm); + +#ifndef __SUBC__ +static int getmainargs(int *_Argc, + char ***_Argv); +#endif + +void *PosGetDTA(void); + +#if defined(__gnu_linux__) || defined(__ARM__) +#include + +static int dirfile; + +static DTA origdta; + +int PosFindFirst(char *pat, int attrib); +int PosFindNext(void); +#endif + +static OS bios = { their_start, 0, 0, NULL, NULL, printf, 0, malloc, NULL, NULL, + fopen, fseek, fread, fclose, fwrite, fgets, strchr, + strcmp, strncmp, strcpy, strlen, fgetc, fputc, + fflush, setvbuf, + PosGetDTA, +#if defined(__gnu_linux__) || defined(__ARM__) + PosFindFirst, PosFindNext, +#else + 0, 0, +#endif + 0, 0, + ctime, time, +#if defined(__gnu_linux__) || defined(__ARM__) + PosChangeDir, PosMakeDir, PosRemoveDir, +#else + 0, 0, 0, +#endif + remove, + memcpy, strncpy, strcat, 0 /* stderr */, free, abort, memset, fputs, fprintf, + getenv, memmove, exit, memcmp, _errno, tmpnam, vfprintf, ungetc, vsprintf, + sprintf, signal, raise, calloc, realloc, atoi, strtol, strtoul, qsort, + bsearch, localtime, clock, strerror, strrchr, strstr, strpbrk, strspn, + strcspn, memchr, ftell, abs, setlocale, perror, rewind, strncat, sscanf, + isalnum, isxdigit, rename, clearerr, _assert, atof, +}; + +static char buf[400]; +static char cmd[300]; + +static int (*genstart)(OS *bios); + +int main(int argc, char **argv) +{ + unsigned char *p; + unsigned char *entry_point; + int rc; + char *prog_name; + int need_usage = 0; + int valid = 0; + int shell = 0; + FILE *scr = NULL; + int quiet = 0; + + bios.mem_amt = MEMAMT; + bios.Xstdin = stdin; + bios.Xstdout = stdout; + bios.Xstderr = stderr; + __genstart = 1; + bios.main = &__genmain; + + /* parameters override everything */ + if (argc > 1) + { + if (strcmp(argv[1], "-quiet") == 0) + { + quiet = 1; + argc--; + argv++; + } + if (argc > 1) + { + if (strcmp(argv[1], "-shell") == 0) + { + shell = 1; + argc--; + argv++; + } + } + if (argc > 1) + { + if (strcmp(argv[1], "-quiet") == 0) + { + quiet = 1; + argc--; + argv++; + } + } + /* if they've typed in --help or anything, give them usage */ + if (argv[1][0] == '-') + { + need_usage = 1; + } + else if (argc == 2) + { + bios.prog_name = argv[1]; + bios.prog_parm = ""; + valid = 1; + } + else if (argc == 3) + { + bios.prog_name = argv[1]; + bios.prog_parm = argv[2]; + valid = 1; + } + else + { + need_usage = 1; + } + } + if (!quiet && !need_usage) + { + printf("bios starting\n"); + } + if (!valid && !need_usage) + { + /* an individual command(s) overrides a shell */ + scr = fopen("biosauto.cmd", "r"); + if (scr != NULL) + { + valid = 1; + } + else + { + scr = fopen("biosauto.shl", "r"); + if (scr != NULL) + { + valid = 1; + shell = 1; + } + } + } + if (!valid && !need_usage) + { + scr = stdin; + printf("enter commands, press enter to exit\n"); + } + do + { + if (need_usage) break; /* should put this before do */ + if (scr != NULL) + { + if (fgets(buf, sizeof buf, scr) == NULL) + { + break; + } + p = strchr(buf, '\n'); + if (p != NULL) + { + *p = '\0'; + } + if (buf[0] == '\0') + { + if (scr == stdin) + { + break; + } + continue; + } + if (buf[0] == '#') + { + continue; + } + bios.prog_name = buf; + p = strchr(buf, ' '); + if (p != NULL) + { + *p = '\0'; + bios.prog_parm = p + 1; + } + else + { + bios.prog_parm = ""; + } + } + + p = calloc(1, 5000000); + if (p == NULL) + { + printf("insufficient memory\n"); + return (EXIT_FAILURE); + } + if (exeloadDoload(&entry_point, bios.prog_name, &p) != 0) + { + printf("failed to load executable\n"); + return (EXIT_FAILURE); + } + genstart = (void *)entry_point; + /* printf("first byte of code is %02X\n", *(unsigned char *)entry_point); */ + +#ifdef NEED_DELAY + for (rc = 0; rc < 3; rc++) + { + printf("please accept a delay before we execute program " + "in BSS memory\n"); + } +#endif + +#if 1 + rc = genstart(&bios); +#else + rc = 0; +#endif + if (!quiet) + { + printf("return from called program is %d\n", rc); + } + free(p); + + if (scr == NULL) + { + break; + } + } while (1); + + if (need_usage) + { + printf("usage: bios [options] [single parm]\n"); + printf("allows execution of non-standard executables\n"); + printf("if no parameters are given and biosauto.cmd is given,\n"); + printf("commands are read, executed and there will be a pause\n"); + printf("otherwise, biosauto.shl is looked for, and there will be\n"); + printf("no pause, because it is assumed to be a shell\n"); + printf("valid options are -quiet and -shell\n"); + printf("e.g. bios -shell pdos.exe uc8086.vhd\n"); + printf("e.g. bios pcomm.exe\n"); + return (EXIT_FAILURE); + } + if (scr == stdin) + { + /* pause has already been done, effectively */ + } + else if (!shell) + { + printf("press enter to exit\n"); + fgets(buf, sizeof buf, stdin); + } + if ((scr != NULL) && (scr != stdin)) + { + fclose(scr); + } + if (!quiet) + { + printf("bios exiting\n"); + } + return (0); +} + +int their_start(char *parm) +{ +#if defined(__gnu_linux__) || defined(__ARM__) + int argc; + char **argv; + getmainargs(&argc, &argv); + __start(argc, argv); +#else + __start(parm); +#endif +} + + +#define MAXPARMS 50 + +#ifndef __SUBC__ +static int getmainargs(int *_Argc, + char ***_Argv) +{ + char *p; + int x; + int argc; + static char *argv[MAXPARMS + 1]; + static char *env[] = {NULL}; + + p = cmd; + + argv[0] = p; + p = strchr(p, ' '); + if (p == NULL) + { + p = ""; + } + else + { + *p = '\0'; + p++; + } + + while (*p == ' ') + { + p++; + } + if (*p == '\0') + { + argv[1] = NULL; + argc = 1; + } + else + { + for (x = 1; x < MAXPARMS; ) + { + char srch = ' '; + + if (*p == '"') + { + p++; + srch = '"'; + } + argv[x] = p; + x++; + p = strchr(p, srch); + if (p == NULL) + { + break; + } + else + { + *p = '\0'; + p++; + while (*p == ' ') p++; + if (*p == '\0') break; /* strip trailing blanks */ + } + } + argv[x] = NULL; + argc = x; + } + + *_Argc = argc; + *_Argv = argv; + return (0); +} +#endif + +#if defined(__gnu_linux__) || defined(__ARM__) + +void *PosGetDTA(void) +{ + return (&origdta); +} + +static int ff_search(void) +{ + static unsigned char buf[500]; + static size_t upto = 0; + static size_t avail = 0; + + if (avail <= 0) + { + avail = __getdents(dirfile, buf, 500); + if (avail <= 0) + { + __close(dirfile); + return (1); + } + } + strncpy(origdta.file_name, buf + upto + 10, sizeof origdta.file_name); + origdta.file_name[sizeof origdta.file_name - 1] = '\0'; + strncpy(origdta.lfn, buf + upto + 10, sizeof origdta.lfn); + origdta.lfn[sizeof origdta.lfn - 1] = '\0'; + upto += *(short *)(buf + upto + 8); + if (upto >= avail) + { + upto = avail = 0; + } + return (0); +} + +int PosFindFirst(char *pat, int attrib) +{ + dirfile = __open(".", 0, 0); + if (dirfile < 0) return (1); + return (ff_search()); +} + +int PosFindNext(void) +{ + return (ff_search()); +} + +int PosChangeDir(const char *to) +{ + return (__chdir(to)); +} + +int PosMakeDir(const char *dname) +{ + return (__mkdir(dname, 0777)); +} + +int PosRemoveDir(const char *dname) +{ + return (__rmdir(dname)); +} + +#else + +void *PosGetDTA(void) +{ + return (NULL); +} + +#endif diff --git a/app/src/main/cpp/bios/x86/exeload.c b/app/src/main/cpp/bios/x86/exeload.c new file mode 100644 index 0000000..b836742 --- /dev/null +++ b/app/src/main/cpp/bios/x86/exeload.c @@ -0,0 +1,2528 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Alica Okano. */ +/* Released to the Public Domain as discussed here: */ +/* http://creativecommons.org/publicdomain/zero/1.0/ */ +/* */ +/* Reworked and AmigaOS and MVS added by Paul Edwards */ +/* All changes remain public domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* exeload.c - functions for loading executables */ +/* */ +/*********************************************************************/ + +#include +#include +#include +#include + +#include "exeload.h" + +/* Headers for executable support. */ +#if NEED_AOUT +#include "a_out.h" +#endif +#if NEED_MZ +#include "mz.h" +#include "pecoff.h" +char msvcrt[FILENAME_MAX] = "\\MSVCRT.DLL"; +char kernel32[FILENAME_MAX] = "\\KERNEL32.DLL"; +#endif +#if NEED_ELF +#include "elf.h" +#endif + +/* For reading files Pos API must be used directly + * as PDPCLIB allocates memory from the process address space. */ + +#if NEED_AOUT +static int exeloadLoadAOUT(unsigned char **entry_point, + FILE *fp, + unsigned char **loadloc); + +#endif +#if NEED_MZ +static int exeloadLoadMZ(unsigned char **entry_point, + FILE *fp, + unsigned char **loadloc); +/* Subfunctions of exeloadLoadMZ() for loading extensions to MZ. */ +static int exeloadLoadPE(unsigned char **entry_point, + FILE *fp, + unsigned char **loadloc, + unsigned long e_lfanew); + +static int exeloadLoadLX(unsigned char **entry_point, + FILE *fp, + unsigned long e_lfanew); +static int exeloadLoadNE(unsigned char **entry_point, + FILE *fp, + unsigned long e_lfanew); + +/* Support function for loading DLLs. */ +static int exeloadLoadPEDLL(unsigned char *exeStart, + IMAGE_IMPORT_DESCRIPTOR *import_desc); +#endif + +#if NEED_ELF +static int exeloadLoadELF(unsigned char **entry_point, + FILE *fp, + unsigned char **loadloc); +#endif +#if NEED_MVS +static int exeloadLoadMVS(unsigned char **entry_point, + FILE *fp, + unsigned char **loadloc); +static int fixPE(unsigned char *buf, + size_t *len, + unsigned char **entry, + unsigned long rlad); +static int processRLD(unsigned char *buf, + unsigned long rlad, + unsigned char *rld, + int len); +#endif +#if NEED_AMIGA +static int exeloadLoadAmiga(unsigned char **entry_point, + FILE *fp, + unsigned char **loadloc); + +#endif +int exeloadDoload(unsigned char **entry_point, + char *progname, + unsigned char **loadloc) +{ + FILE *fp; + int ret = 1; + + fp = fopen(progname, "rb"); + if (fp == NULL) + { + printf("Failed to open %s for loading\n", progname); + return (1); + } + /* Tries to load the executable as different formats. + * Returned 0 means the executable was loaded successfully. + * 1 means it is not the format the function loads. + * 2 means correct format, but error occured. */ +#if NEED_AOUT + if (ret == 1) ret = exeloadLoadAOUT(entry_point, fp, loadloc); +#endif +#if NEED_MZ + if (ret == 1) ret = exeloadLoadMZ(entry_point, fp, loadloc); +#endif +#if NEED_AMIGA + if (ret == 1) ret = exeloadLoadAmiga(entry_point, fp, loadloc); +#endif +#if NEED_MVS + if (ret == 1) ret = exeloadLoadMVS((unsigned char **)entry_point, + fp, + (unsigned char **)loadloc); +#endif +#if NEED_ELF + if (ret == 1) ret = exeloadLoadELF(entry_point, fp, loadloc); +#endif + + fclose(fp); + if (ret != 0) + { + return (1); + } + + return (0); +} + +#if NEED_AOUT +static int exeloadLoadAOUT(unsigned char **entry_point, + FILE *fp, + unsigned char **loadloc) +{ + struct exec firstbit; + unsigned long exeLen; + unsigned char *exeStart; + unsigned char *bss; + unsigned int *corrections; + unsigned int i; + unsigned int offs; + unsigned int type; + unsigned int zapdata; + unsigned char *zap; + + + if (/*(fseek(fp, 0, SEEK_SET) != 0) || */(fread(&firstbit, sizeof(firstbit), 1, fp) != 1)) + { + return (1); + } + /* ZMAGIC and NMAGIC are currently not supported + * as they should be loaded at 0x10000, + * but the kernel reserves the first 4 MiB. */ + if ((firstbit.a_info & 0xffff) == ZMAGIC) + { + printf("a.out ZMAGIC is not supported\n"); + return (2); + } + else if ((firstbit.a_info & 0xffff) == NMAGIC) + { + printf("a.out NMAGIC is not supported\n"); + return (2); + } + else if ((firstbit.a_info & 0xffff) == QMAGIC) + { + printf("a.out QMAGIC is not supported\n"); + return (2); + } + else if ((firstbit.a_info & 0xffff) != OMAGIC) + { + /* The file is not A.OUT. */ + return (1); + } + exeLen = firstbit.a_text + firstbit.a_data + firstbit.a_bss; + if (*loadloc != NULL) + { + exeStart = *loadloc; + } + else + { + exeStart = malloc(exeLen); + if (exeStart == NULL) + { + printf("Insufficient memory to load A.OUT program\n"); + return (2); + } + } + + /* printf("loading %lu bytes of text\n", firstbit.a_text); */ + if (fread(exeStart, firstbit.a_text, 1, fp) != 1) + { + printf("Error occured while reading A.OUT text\n"); + return (2); + } + if (firstbit.a_data != 0) + { + /* printf("loading %lu bytes of data\n", firstbit.a_data); */ + if (fread(exeStart + firstbit.a_text, + firstbit.a_data, + 1, + fp) != 1) + { + printf("Error occured while reading A.OUT data\n"); + return (2); + } + } + + /* initialise BSS */ + bss = exeStart + firstbit.a_text + firstbit.a_data; + memset(bss, '\0', firstbit.a_bss); + /* Relocations. */ + { + zap = exeStart; + zapdata = (unsigned int)zap; + if (firstbit.a_trsize != 0) + { + corrections = malloc(firstbit.a_trsize); + if (corrections == NULL) + { + printf("insufficient memory %lu\n", firstbit.a_trsize); + return (2); + } + if (fread(corrections, firstbit.a_trsize, 1, fp) != 1) + { + printf("Error occured while reading A.OUT text relocations\n"); + free(corrections); + return (2); + } + for (i = 0; i < firstbit.a_trsize / 4; i += 2) + { + offs = corrections[i]; + type = corrections[i + 1]; + if (((type >> 24) & 0xff) != 0x04) + { + continue; + } + *(unsigned int *)(zap + offs) += zapdata; + } + free(corrections); + } + if (firstbit.a_drsize != 0) + { + corrections = malloc(firstbit.a_drsize); + if (corrections == NULL) + { + printf("insufficient memory %lu\n", firstbit.a_drsize); + return (2); + } + if (fread(corrections, firstbit.a_drsize, 1, fp) != 1) + { + printf("Error occured while reading A.OUT data relocations\n"); + free(corrections); + return (2); + } + zap = exeStart + firstbit.a_text; + for (i = 0; i < firstbit.a_drsize / 4; i += 2) + { + offs = corrections[i]; + type = corrections[i + 1]; + if (((type >> 24) & 0xff) != 0x04) + { + continue; + } + *(unsigned int *)(zap + offs) += zapdata; + } + free(corrections); + } + } + + *entry_point = exeStart + firstbit.a_entry; + if (*loadloc == NULL) + { + *loadloc = exeStart; + } + + return (0); +} +#endif + +#if NEED_MVS +static int exeloadLoadMVS(unsigned char **entry_point, + FILE *fp, + unsigned char **loadloc) +{ + size_t readbytes; + unsigned char *entry; + int didalloc = 0; + + /* printf("in LoadMVS\n"); */ + if (*loadloc == NULL) + { + *loadloc = malloc(1000000); + if (*loadloc == NULL) + { + return (1); + } + didalloc = 1; + } + rewind(fp); + readbytes = fread(*loadloc, 1, 1000000, fp); + /* printf("read %d bytes\n", (int)readbytes); */ + + /* the last parameter is an unsigned long because the code allows + relocations to be done for a theoretical load point rather than + requiring the actual load point. In case we wanted to do the + calculations to later store the executable in ROM or something + like that. */ + + if (fixPE(*loadloc, &readbytes, &entry, (unsigned long)*loadloc) != 0) + { + if (didalloc) + { + free(*loadloc); + *loadloc = NULL; + } + return (1); + } + *entry_point = entry; + + return (0); +} +#endif + +#if NEED_AMIGA +#define getword(p) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]) +#define putword(p, val) (p[0] = (unsigned char)((val >> 24) & 0xff), \ + p[1] = (unsigned char)((val >> 16) & 0xff), \ + p[2] = (unsigned char)((val >> 8) & 0xff), \ + p[3] = (unsigned char)(val & 0xff)) + +#define HUNK_HEADER 0x3F3 +#define HUNK_CODE 0x3E9 +#define HUNK_DATA 0x3EA +#define HUNK_BSS 0x3EB +#define HUNK_RELOC32 0x3EC +#define HUNK_SYMBOL 0x3F0 +#define HUNK_END 0x3F2 + +static int exeloadLoadAmiga(unsigned char **entry_point, + FILE *fp, + unsigned char **loadloc) +{ + size_t readbytes; + unsigned char *p; + unsigned long temp; + int datahunk = 1; + int codehunk = 0; + int bsshunk; + unsigned char *beg; + unsigned char *codestart; + unsigned char *datastart = NULL; + unsigned char *bssstart; + unsigned char *genstart; /* generic start location when doing relocations */ + unsigned char *codereloc = NULL; + unsigned char *datareloc = NULL; + int iter; + int didalloc = 0; + + /* printf("in LoadAmiga\n"); */ + if (*loadloc == NULL) + { + *loadloc = malloc(1000000); + if (*loadloc == NULL) + { + return (1); + } + didalloc = 1; + } + p = beg = *loadloc; + rewind(fp); + readbytes = fread(p, 1, 1000000, fp); + /* printf("read %d bytes\n", (int)readbytes); */ + if (readbytes < 4) + { + if (didalloc) + { + free(*loadloc); + *loadloc = NULL; + } + return (1); + } + bssstart = p + readbytes; + temp = getword(p); + if (temp != HUNK_HEADER) + { + if (didalloc) + { + free(*loadloc); + *loadloc = NULL; + } + return (1); + } + p += 4; + temp = getword(p); + if (temp != 0) + { + printf("can't handle Amiga Hunk 1\n"); + if (didalloc) + { + free(*loadloc); + *loadloc = NULL; + } + return (1); + } + p += 4; + temp = getword(p); + if (temp == 2) + { + /* printf("no data section\n"); */ + bsshunk = 1; + datahunk = -1; + /* printf("bsshunk determined to be %d\n", bsshunk); */ + p += 8; + } + else if (temp == 3) + { + /* looks like this: + 000000 000003F3 00000000 00000003 00000000 ................ + 000010 00000002 0000002A 00000001 00000002 .......*........ + + So that 3 is the number of hunks, or highest hunk number + plus 1. Then comes 0, the first hunk number. Then comes + 2, the last hunk number, then comes x'2A', the length of + hunk number 0 (CODE), then comes 1, the length of + hunk number 1 (DATA), then comes 2, the length of hunk + number 2 (BSS since we have a data section, otherwise + it would have been 1). Lengths are the number of 4-byte + words. + */ + /* printf("we have a data section\n"); */ + bsshunk = 2; + /* printf("bsshunk determined to be %d\n", bsshunk); */ + p += 12; + } + else + { + printf("can't handle Amiga Hunk 2\n"); + if (didalloc) + { + free(*loadloc); + *loadloc = NULL; + } + return (1); + } + p += 12; + + temp = getword(p); + if (temp != HUNK_CODE) + { + printf("Amiga Hunk expecting code at hex %lx\n", + (unsigned long)(p - beg)); + if (didalloc) + { + free(*loadloc); + *loadloc = NULL; + } + return (1); + } + p += 4; + temp = getword(p); + /* printf("length of code is hex %lx\n", temp); */ + p += 4; + codestart = p; + /* printf("at codestart is %02X\n", *(unsigned char *)codestart); */ + p += temp * 4; + + while (1) + { + if (p >= bssstart) + { + /* printf("reached end of executable\n"); */ + break; + } + temp = getword(p); + if (temp == HUNK_RELOC32) + { + p += 4; + /* if we haven't yet encountered a HUNK_DATA, then this + must be a code relocation */ + if (datastart == NULL) + { + codereloc = p; + } + else + { + datareloc = p; + } + /* skip relocations for now, come back later */ + temp = getword(p); + while (temp != 0) + { + p += 4; /* skip count of relocations */ + p += 4; /* skip hunk number */ + p += temp * 4; /* skip relocations */ + temp = getword(p); + } + /* printf("skipped relocations\n"); */ + p += 4; + } + else if (temp == HUNK_DATA) + { + p += 4; /* skip hunk id */ + temp = getword(p); + p += 4; /* skip number of words */ + datastart = p; + /* printf("got data start for real\n"); */ + p += temp * 4; + } + else if (temp == HUNK_SYMBOL) + { + /* printf("got symbol\n"); */ + p += 4; /* skip hunk id */ + temp = getword(p); + while (temp != 0) /* until hunk number is 0 */ + { + long len; + long rem; + + p += 4; /* skip hunk number */ + /* printf("symbol %s found\n", p); */ + len = strlen((char *)p); + len++; + rem = len % 4; + if (rem != 0) + { + len = len - rem + 4; /* move up to 4-byte boundary */ + } + p += len; + p += 4; /* skip offset */ + temp = getword(p); + } + p += 4; /* skip hunk number */ + } + else if (temp == HUNK_END) + { + /* printf("got hunk end\n"); */ + p += 4; + } + else if (temp == HUNK_BSS) + { + /* printf("got BSS hunk\n"); */ + p += 8; + } + else + { + printf("unexpected Amiga Hunk id hex %lx\n", temp); + if (didalloc) + { + free(*loadloc); + *loadloc = NULL; + } + return (1); + } + } + + /* apply relocations */ + /* printf("applying relocations\n"); */ + for (iter = 0; iter < 2; iter++) + { + if ((iter == 0) && (codereloc == NULL)) continue; + if ((iter == 1) && (datareloc == NULL)) continue; + if (iter == 0) + { + /* printf("applying code relocations\n"); */ + genstart = codestart; + p = codereloc; + } + else if (iter == 1) + { + /* printf("applying data relocations\n"); */ + genstart = datastart; + p = datareloc; + } + temp = getword(p); + while (temp != 0) + { + unsigned long count; + int hunk_nbr; + unsigned char *correction; + unsigned long x; + + count = temp; + p += 4; /* skip count of relocations */ + hunk_nbr = getword(p); + p += 4; /* skip hunk number */ + if (hunk_nbr == codehunk) + { + correction = codestart; + /* printf("got %lu CODE relocations\n", count); */ + } + else if (hunk_nbr == datahunk) + { + correction = datastart; + /* printf("got %lu DATA relocations\n", count); */ + } + else if (hunk_nbr == bsshunk) + { + correction = bssstart; + /* printf("got %lu BSS relocations\n", count); */ + } + else + { + printf("got unexpected Amiga Hunk number hex %x\n", hunk_nbr); + printf("code hunk is %d\n", codehunk); + printf("data hunk is %d\n", datahunk); + printf("bss hunk is %d\n", bsshunk); + if (didalloc) + { + free(*loadloc); + *loadloc = NULL; + } + return (1); + } + /* WARNING - the following is not entirely accurate. There + ARE data relocations, and the above code caters for that, + and that's why there are two iterations of the loop. But + pogi points for trying. */ + + /* Note that all relocations are applied to the code + section, but the code needs different corrections + depending on whether it is referencing another location + in code, a data reference, e.g. a global variable with a + value of 5, or a BSS reference, e.g. an uninitialized + global variable. */ + /* At the various offsets in the code there will be values, + such as 48, which are the correct offsets if the module + was loaded at location 0 in memory, and also the data + section started at location 0 in memory, and also the + bss section (variables that need to be set to 0 before + the executable runs) is set to location 0 in memory. + Note that the BSS takes up no space in the executable + because it would just be a whole lot of zeros serving + no purpose. So the onus is on the program loading the + executable to initialize that area. That area is + normally placed at the end of the executable, but you + can do a separate malloc and put it anywhere if you + want. You can also put the data section anywhere you + want to, with a separate malloc, so long as you actually + copy all that data across to the new location. This is + what needs to happen with reentrant modules. There needs + to be a register (such as ds: in 8086) pointing to where + the global variables are. And normally the BSS comes + after that, so you can use a single register to point to + both data and BSS. The code corrections only need to be + done once for the code section itself, and the data + offsets are all given in reference to some dedicated + register (such as ds) so that no more corrections are + required to the code to reference the correct offsets. + In fact, you don't need to correct them at all, they are + all set to the correct offsets for the dedicated + register. But if you're not using a dedicated register, + or you are using the huge, large or compact memory models + of the 8086, you can't use a dedicated register, as there + is too much data (more than 64k) for ds to reference, so + ds keeps on being reloaded, and thus the code corrections + need to be made to point to the full address + (segment:offset) of where the variable can be found. + For the 68000 you also need the full address (as the + compiler is not using a dedicated register and dynamically + providing the offsets), but it is a flat 32-bit pointer. + If you are using a compiler that DOES use a dedicated + register, then there will simply be no "data corrections" + found in the relocation table, ie the relocation table + will only have references to locations in the code where + somewhere else in the code needs to be referenced (e.g. + to call a function) but because the code is not loaded + at location 0 (or effectively done so via virtual memory, + or some other fixed location like Windows used to use), + so it needs to know where exactly in memory it has been + loaded. */ + + for (x = 0; x < count; x++) + { + unsigned char *zaploc; + unsigned char *xxx; + unsigned long value; + unsigned long oldref; + unsigned char *properref; + unsigned long properref_val; + + xxx = &p[x * 4]; /* point to a value, such as 12, + which is where in the code section will need + to be adjusted */ + value = getword(xxx); /* now we have that value 12 */ + zaploc = genstart + value; /* now we point to the + exact location in the code section that needs + to have a correction applied. Note that the + corrected value to be applied depends on whether + it is a code, data or BSS reference, but we have + already determined that, and are already pointing + to the relevant memory address. */ + oldref = getword(zaploc); /* now we have the old + value of the function or whatever, e.g. if the + called function is at offset 40 in the code + section, then it will have the value 40. */ + properref = correction + oldref; /* This is where we + want the code to start looking for this code, data + or BSS reference. Even if we are on a 64-bit system + and we are loading this 32-bit module, someone + else will have made sure that we are effectively + on a 4 GiB boundary so that this pointer will be + valid, even though we're just about to truncate + it to 4 bytes. ie on a 64-bit system, properref + could be 0x1 0000 0000 - but that's OK so long + as the high 32 bits of all registers have been + set to 0x1 0000 0000. None of this 68000 code + knows about the high 32-bits of 64-bit registers + so will not disturb any data stored there. */ + properref_val = (unsigned long)properref; /* this + probably won't truncate the pointer, but we are + putting it in integer form, ready for manipulation. + Note that if this program is running on a 8086, + and you are trying to load this 68000 executable + (prior to switching to the 68000 coprocessor), + using far data pointers, you will need to use a + compiler that converts far pointers into flat + references when converting from pointer to long, + because + the 68000 program will require a flat reference. + ie the compiler needs to do the equivalent of + ((properref >> 4) << 16) | (properref & 0xffff) + in order to create properref_val. Or you need + to provide your own routine to do that. In my + opinion this is the job of the compiler, it + should know that you are wanting a flat reference. + So too when you go: + char *p = (char *)0xb8000UL; + it should convert that into b800:0000 itself. + Speak to your compiler vendor! + If we were doing things the other way around, ie + you have a 68000 loading an 8086 large memory model + program, then this is a "known quantity" (the same + as loading a small memory model program) and it is + this loader code (perhaps compiled with a 68000) + that would need to convert a flat memory pointer (ie + where it loaded the 8086 program into 68000 memory) + that would need to convert a flat pointer into a + segmented pointer suitable for the 8086 prior to + switching to the 8086 coprocessor. So it is reasonable + for you to do the bit shifting in your own code. After + first of all converting into an unsigned long, because + maybe the loader is not 68000 either, but another + segmented architecture with different segmentation rules, + and it too needs to convert to a flat address (as + represented by unsigned long) prior to being manually + converted into an address suitable for the 8086. */ + + putword(zaploc, properref_val); + } + p += temp * 4; /* skip relocations */ + temp = getword(p); + } + } + /* printf("finished relocations\n"); */ + + *entry_point = codestart; + /* printf("just set entry point, first byte %02X\n", + *(unsigned char *)codestart); */ + + return (0); +} +#endif + +#if NEED_ELF +static int exeloadLoadELF(unsigned char **entry_point, + FILE *fp, + unsigned char **loadloc) +{ + int doing_elf_rel = 0; + int doing_elf_exec = 0; + Elf32_Ehdr *elfHdr; + Elf32_Phdr *program_table = NULL; + Elf32_Phdr *segment; + Elf32_Shdr *section_table = NULL; + Elf32_Shdr *section; + unsigned char *elf_other_sections = NULL; + Elf32_Addr lowest_p_vaddr = 0; + Elf32_Word lowest_segment_align = 0; + unsigned char *exeStart = NULL; + unsigned char *bss; + unsigned long exeLen; + unsigned char firstbit[4]; + long newpos; + size_t readbytes; + + if (/*(fseek(fp, 0, SEEK_SET) != 0) || */(fread(&firstbit, sizeof firstbit, 1, fp) != 1) + || (memcmp(&firstbit, "\x7f" "ELF", 4) != 0)) + { + return (1); + } + { + int elf_invalid = 0; + + /* Loads entire ELF header into memory. */ + elfHdr = malloc(sizeof(Elf32_Ehdr)); + if (elfHdr == NULL) + { + printf("Insufficient memory for ELF header\n"); + return (2); + } + if ((fseek(fp, 0, SEEK_SET) != 0) + || (fread(elfHdr, sizeof(Elf32_Ehdr), 1, fp) != 1)) + { + printf("Error occured while reading ELF header\n"); + free(elfHdr); + return (2); + } + + /* Checks e_ident if the program can be used on PDOS-32. */ + if (elfHdr->e_ident[EI_CLASS] != ELFCLASS32) + { + if (elfHdr->e_ident[EI_CLASS] == ELFCLASS64) + { + printf("64-bit ELF is not supported\n"); + } + else if (elfHdr->e_ident[EI_CLASS] == ELFCLASSNONE) + { + printf("Invalid ELF class\n"); + } + else + { + printf("Unknown ELF class: %u\n", elfHdr->e_ident[EI_CLASS]); + } + elf_invalid = 1; + } + if (elfHdr->e_ident[EI_DATA] != ELFDATA2LSB) + { + if (elfHdr->e_ident[EI_DATA] == ELFDATA2MSB) + { + printf("Big-endian ELF encoding is not supported\n"); + } + else if (elfHdr->e_ident[EI_DATA] == ELFDATANONE) + { + printf("Invalid ELF data encoding\n"); + } + else + { + printf("Unknown ELF data encoding: %u\n", + elfHdr->e_ident[EI_DATA]); + } + elf_invalid = 1; + } + if (elfHdr->e_ident[EI_OSABI] != ELFOSABI_NONE) + { + printf("No OS or ABI specific extensions for ELF supported\n"); + elf_invalid = 1; + } + /* Checks other parts of the header if the file can be loaded. */ + if (elfHdr->e_type == ET_REL) + { + doing_elf_rel = 1; + } + else if (elfHdr->e_type == ET_EXEC) + { + doing_elf_exec = 1; + } + else + { + printf("Only ELF relocatable " + "and executable " + "files are supported\n"); + elf_invalid = 1; + } + if (elfHdr->e_machine != EM_386) + { + printf("Only Intel 386 architecture is supported\n"); + elf_invalid = 1; + } + if (doing_elf_exec) + { + if (elfHdr->e_phoff == 0 || elfHdr->e_phnum == 0) + { + printf("Executable file is missing Program Header Table\n"); + elf_invalid = 1; + } + if (elfHdr->e_phnum >= SHN_LORESERVE) + { + printf("Reserved indexes for e_phnum are not supported\n"); + printf("e_phnum is %04x\n", elfHdr->e_phnum); + elf_invalid = 1; + } + if (elfHdr->e_phentsize != sizeof(Elf32_Phdr)) + { + printf("Program Header Table entries have unsupported size\n"); + printf("e_phentsize: %u supported size: %lu\n", + elfHdr->e_phentsize, sizeof(Elf32_Phdr)); + elf_invalid = 1; + } + } + else if (doing_elf_rel) + { + if (elfHdr->e_shoff == 0 || elfHdr->e_shnum == 0) + { + printf("Relocatable file is missing Section Header Table\n"); + elf_invalid = 1; + } + if (elfHdr->e_shnum >= SHN_LORESERVE) + { + printf("Reserved indexes for e_shnum are not supported\n"); + printf("e_shnum is %04x\n", elfHdr->e_shnum); + elf_invalid = 1; + } + if (elfHdr->e_shentsize != sizeof(Elf32_Shdr)) + { + printf("Section Header Table entries have unsupported size\n"); + printf("e_shentsize: %u supported size: %lu\n", + elfHdr->e_shentsize, sizeof(Elf32_Shdr)); + elf_invalid = 1; + } + } + if (elf_invalid) + { + /* All problems with ELF header are reported + * and loading is stopped. */ + printf("This ELF file cannot be loaded\n"); + free(elfHdr); + return (2); + } + /* Loads Program Header Table if it is present. */ + if (!(elfHdr->e_phoff == 0 || elfHdr->e_phnum == 0)) + { + program_table = malloc(elfHdr->e_phnum * elfHdr->e_phentsize); + if (program_table == NULL) + { + printf("Insufficient memory for ELF Program Header Table\n"); + free(elfHdr); + return (2); + } + if ((fseek(fp, elfHdr->e_phoff, SEEK_SET) != 0) + || (fread(program_table, + elfHdr->e_phnum * elfHdr->e_phentsize, + 1, + fp) != 1)) + { + printf("Error occured while reading " + "ELF Program Header Table\n"); + free(elfHdr); + free(program_table); + return (2); + } + } + /* Loads Section Header Table if it is present. */ + if (!(elfHdr->e_shoff == 0 || elfHdr->e_shnum == 0)) + { + section_table = malloc(elfHdr->e_shnum * elfHdr->e_shentsize); + if (section_table == NULL) + { + printf("Insufficient memory for ELF Section Header Table\n"); + free(elfHdr); + free(program_table); + return (2); + } + if ((fseek(fp, elfHdr->e_shoff, SEEK_SET) != 0) + || (fread(section_table, + elfHdr->e_shnum * elfHdr->e_shentsize, + 1, + fp) != 1)) + { + printf("Error occured while reading " + "ELF Section Header Table\n"); + free(elfHdr); + free(program_table); + free(section_table); + return (2); + } + } + } + + if (1) + { + /* Calculates how much memory is needed + * and allocates memory for sections used only for loading. */ + unsigned long otherLen = 0; + + exeLen = 0; + if (doing_elf_exec) + { + Elf32_Addr highest_p_vaddr = 0; + Elf32_Word highest_segment_memsz = 0; + + for (segment = program_table; + segment < program_table + elfHdr->e_phnum; + segment++) + { + if (segment->p_type == PT_LOAD) + { + if (!lowest_p_vaddr || lowest_p_vaddr > segment->p_vaddr) + { + lowest_p_vaddr = segment->p_vaddr; + lowest_segment_align = segment->p_align; + } + if (highest_p_vaddr < segment->p_vaddr) + { + highest_p_vaddr = segment->p_vaddr; + highest_segment_memsz = segment->p_memsz; + } + } + } + exeLen = highest_p_vaddr - lowest_p_vaddr + highest_segment_memsz; + if (lowest_segment_align > 1) + { + /* Ensures alignment of the lowest segment. + * 0 and 1 mean no alignment restrictions. */ + exeLen += lowest_segment_align; + } + } + if (section_table) + { + for (section = section_table; + section < section_table + elfHdr->e_shnum; + section++) + { + unsigned long section_size = section->sh_size; + if (section->sh_addralign > 1) + { + /* Some sections must be aligned + * on sh_addralign byte boundaries. + * 0 and 1 mean no alignment restrictions. */ + section_size += section->sh_addralign; + } + if ((section->sh_flags & SHF_ALLOC) + && (section->sh_type != SHT_RELA)) + { + /* Section is needed while the program is running, + * but if we are loading an executable file, + * the memory is already counted + * using Program Header Table. */ + if (doing_elf_exec) continue; + exeLen += section_size; + } + else + { + /* Section is used only for loading. */ + otherLen += section_size; + } + } + elf_other_sections = malloc(otherLen); + if (elf_other_sections == NULL) + { + printf("Insufficient memory to load ELF sections\n"); + free(elfHdr); + free(program_table); + free(section_table); + return (2); + } + } + } + /* Allocates memory for the process. */ + if (*loadloc != NULL) + { + exeStart = *loadloc; + } + else + { + exeStart = malloc(exeLen); + } + if (exeStart == NULL) + { + printf("Insufficient memory to load ELF program\n"); + free(elfHdr); + free(program_table); + free(section_table); + free(elf_other_sections); + return (2); + } + + if (1) + { + /* Loads all sections of ELF file with proper alignment, + * clears all SHT_NOBITS sections and stores the addresses + * in sh_addr of each section. + * bss is set now too. */ + unsigned char *exe_addr = exeStart; + unsigned char *other_addr = elf_other_sections; + + bss = NULL; + if (doing_elf_exec) + { + /* Aligns the exeStart on lowest segment alignment boundary. */ + /*exeStart = (unsigned char *)((((unsigned long)exeStart + / lowest_segment_align) + 1) + * lowest_segment_align);*/ + /* +++Enable aligning. */ + for (segment = program_table; + segment < program_table + elfHdr->e_phnum; + segment++) + { + if (segment->p_type == PT_LOAD) + { + exe_addr = exeStart + (segment->p_vaddr - lowest_p_vaddr); + + if ((fseek(fp, segment->p_offset, SEEK_SET) != 0) + || (fread(exe_addr, + segment->p_filesz, + 1, + fp) != 1)) + { + printf("Error occured while reading ELF segment\n"); + free(elfHdr); + free(program_table); + free(section_table); + free(elf_other_sections); + return (2); + } + + /* Bytes that are not present in file, + * but must be present in memory must be set to 0. */ + if (segment->p_filesz < segment->p_memsz) + { + bss = exe_addr + (segment->p_filesz); + memset(bss, '\0', + segment->p_memsz - segment->p_filesz); + } + } + } + } + + for (section = section_table; + section < section_table + elfHdr->e_shnum; + section++) + { + if ((section->sh_flags & SHF_ALLOC) + && (section->sh_type != SHT_RELA)) + { + /* If we are loading executable file, + * SHF_ALLOC sections are already loaded in segments. */ + if (doing_elf_exec) continue; + if (section->sh_addralign > 1) + { + exe_addr = (void *)((((unsigned long)exe_addr + / (section->sh_addralign)) + 1) + * (section->sh_addralign)); + } + if (section->sh_type != SHT_NOBITS) + { + if ((fseek(fp, section->sh_offset, SEEK_SET) != 0) + || (fread(exe_addr, + section->sh_size, + 1, + fp) != 1)) + { + printf("Error occured while reading ELF section\n"); + free(elfHdr); + free(program_table); + free(section_table); + free(elf_other_sections); + return (2); + } + } + else + { + /* The section is probably BSS. */ + if (bss != 0) + { + printf("Multiple SHT_NOBITS with SHF_ALLOC " + "present in ELF file\n"); + } + bss = exe_addr; + /* All SHT_NOBITS should be cleared to 0. */ + memset(bss, '\0', section->sh_size); + } + /* sh_addr is 0 in relocatable files, + * so we can use it to store the real address. */ + section->sh_addr = (Elf32_Addr)exe_addr; + exe_addr += section->sh_size; + } + else + { + if (section->sh_addralign > 1) + { + other_addr = (void *)((((unsigned long)other_addr + / (section->sh_addralign)) + 1) + * (section->sh_addralign)); + } + if (section->sh_type != SHT_NOBITS) + { + if (section->sh_size != 0) + { + if ((fseek(fp, section->sh_offset, SEEK_SET) != 0) + || (fread(other_addr, + section->sh_size, + 1, + fp) != 1)) + { + printf("Error occured while reading ELF section\n"); + free(elfHdr); + free(program_table); + free(section_table); + free(elf_other_sections); + return (2); + } + } + } + else + { + /* All SHT_NOBITS should be cleared to 0. */ + memset(other_addr, '\0', section->sh_size); + } + /* sh_addr is 0 in relocatable files, + * so we can use it to store the real address. */ + section->sh_addr = (Elf32_Addr)other_addr; + other_addr += section->sh_size; + } + } + } + /* Program was successfully loaded from the file, + * no more errors can occur. */ + + /* Relocations. */ + if (1) + { + for (section = section_table; + section < section_table + elfHdr->e_shnum; + section++) + { + if (section->sh_type == SHT_RELA) + { + /* sh_link specifies the symbol table + * and sh_info section being modified. */ + Elf32_Sym *sym_table = (Elf32_Sym *)(section_table + + (section->sh_link))->sh_addr; + unsigned char *target_base = exeStart + + (((unsigned char *)(section_table + + (section->sh_info))->sh_addr) + - (unsigned char *)lowest_p_vaddr); + Elf32_Rela *startrel = (Elf32_Rela *)section->sh_addr; + Elf32_Rela *currel; + + if (section->sh_entsize != sizeof(Elf32_Rela)) + { + printf("Invalid size of relocation entries in ELF file\n"); + continue; + } + + for (currel = startrel; + currel < (startrel + + ((section->sh_size) / (section->sh_entsize))); + currel++) + { + long *target = (long *)(target_base + currel->r_offset); + Elf32_Sym *symbol = (sym_table + + ELF32_R_SYM(currel->r_info)); + Elf32_Addr sym_value = 0; + + if (ELF32_R_SYM(currel->r_info) != STN_UNDEF) + { + if (symbol->st_shndx == SHN_ABS) + { + /* Absolute symbol, stores absolute value. */ + sym_value = symbol->st_value; + } + else if (symbol->st_shndx == SHN_UNDEF) + { + /* Dynamic linker should fill this symbol. */ + printf("Undefined symbol in ELF file\n"); + continue; + } + else if (symbol->st_shndx == SHN_XINDEX) + { + printf("Unsupported value in ELF symbol\n"); + printf("symbol->st_shndx: %x\n", symbol->st_shndx); + continue; + } + else + { + /* Internal symbol. Must be converted + * to absolute symbol.*/ + sym_value = symbol->st_value; + /* Adds the address of the related section + * so the symbol stores absolute address. */ + sym_value += ((section_table + + symbol->st_shndx)->sh_addr); + } + } + switch (ELF32_R_TYPE(currel->r_info)) + { + case R_386_NONE: + break; + case R_386_32: + /* Symbol value + offset. */ + *target = *target - lowest_p_vaddr + (long)exeStart; + break; + case R_386_PC32: + /* Symbol value + offset - absolute address + * of the modified field. */ + *target = (sym_value + (*target) + - (unsigned long)target); + break; + default: + printf("Unknown relocation type in ELF file\n"); + } + } + } + else if (section->sh_type == SHT_REL) + { + /* sh_link specifies the symbol table + * and sh_info section being modified. */ + Elf32_Sym *sym_table = (Elf32_Sym *)(section_table + + (section->sh_link))->sh_addr; + unsigned char *target_base = (unsigned char *)(section_table + + (section->sh_info))->sh_addr; + Elf32_Rel *startrel = (Elf32_Rel *)section->sh_addr; + Elf32_Rel *currel; + + if (section->sh_entsize != sizeof(Elf32_Rel)) + { + printf("Invalid size of relocation entries in ELF file\n"); + continue; + } + + for (currel = startrel; + currel < (startrel + + ((section->sh_size) / (section->sh_entsize))); + currel++) + { + long *target = (long *)(target_base + currel->r_offset); + Elf32_Sym *symbol = (sym_table + + ELF32_R_SYM(currel->r_info)); + Elf32_Addr sym_value = 0; + + if (ELF32_R_SYM(currel->r_info) != STN_UNDEF) + { + if (symbol->st_shndx == SHN_ABS) + { + /* Absolute symbol, stores absolute value. */ + sym_value = symbol->st_value; + } + else if (symbol->st_shndx == SHN_UNDEF) + { + /* Dynamic linker should fill this symbol. */ + printf("Undefined symbol in ELF file\n"); + continue; + } + else if (symbol->st_shndx == SHN_XINDEX) + { + printf("Unsupported value in ELF symbol\n"); + printf("symbol->st_shndx: %x\n", symbol->st_shndx); + continue; + } + else + { + /* Internal symbol. Must be converted + * to absolute symbol.*/ + sym_value = symbol->st_value; + /* Adds the address of the related section + * so the symbol stores absolute address. */ + sym_value += ((section_table + + symbol->st_shndx)->sh_addr); + } + } + switch (ELF32_R_TYPE(currel->r_info)) + { + case R_386_NONE: + break; + case R_386_32: + /* Symbol value + offset. */ + *target = sym_value + *target; + break; + case R_386_PC32: + /* Symbol value + offset - absolute address + * of the modified field. */ + *target = (sym_value + (*target) + - (unsigned long)target); + break; + default: + printf("Unknown relocation type in ELF file\n"); + } + } + } + } + } + + *entry_point = exeStart + (elfHdr->e_entry - lowest_p_vaddr); + + /* Frees memory not needed by the process. */ + free(elfHdr); + free(program_table); + free(section_table); + free(elf_other_sections); + + if (*loadloc == NULL) + { + *loadloc = exeStart; + } + return (0); +} +#endif + +#if NEED_MZ +static int exeloadLoadMZ(unsigned char **entry_point, + FILE *fp, + unsigned char **loadloc) +{ + Mz_hdr firstbit; + + /* The header size is in paragraphs, + * so the smallest possible header is 16 bytes (paragraph) long. + * Next is the magic number checked. */ + if ((fseek(fp, 0, SEEK_SET) != 0) + || (fread(&firstbit, 16, 1, fp) != 1) + || (memcmp(firstbit.magic, "MZ", 2) != 0 + && memcmp(&firstbit.magic, "ZM", 2) != 0)) + { + return (1); + } + if (firstbit.header_size == 0) + { + printf("MZ Header has 0 size\n"); + return (2); + } + if (firstbit.header_size * 16 > sizeof(firstbit)) + { + printf("MZ Header is too large, size: %u\n", + (unsigned int)firstbit.header_size * 16); + return (2); + } + /* Loads the rest of the header. */ + if (fread(((char *)&firstbit) + 16, + (firstbit.header_size - 1) * 16, + 1, + fp) != 1) + { + printf("Error occured while reading MZ header\n"); + return (2); + } + /* Determines whether the executable has extensions or is a pure MZ. + * Extensions are at offset in e_lfanew, + * so the header must have at least 4 paragraphs. */ + if ((firstbit.header_size >= 4) + && (firstbit.e_lfanew != 0)) + { + int ret; + + /* Same logic as in exeloadDoload(). */ + ret = exeloadLoadPE(entry_point, fp, loadloc, firstbit.e_lfanew); + if (ret == 1) + ret = exeloadLoadLX(entry_point, fp, firstbit.e_lfanew); + if (ret == 1) + ret = exeloadLoadNE(entry_point, fp, firstbit.e_lfanew); + if (ret == 1) + printf("Unknown MZ extension\n"); + return (ret); + } + /* Pure MZ executables are for 16-bit DOS, so we cannot run them. */ + printf("Pure MZ executables are not supported\n"); + + return (2); +} + +static int exeloadLoadPE(unsigned char **entry_point, + FILE *fp, + unsigned char **loadloc, + unsigned long e_lfanew) +{ + Coff_hdr coff_hdr; + Pe32_optional_hdr *optional_hdr; + Coff_section *section_table, *section; + unsigned char *exeStart; + int ret; + + { + unsigned char firstbit[4]; + + if ((fseek(fp, e_lfanew, SEEK_SET) != 0) + || (fread(firstbit, 4, 1, fp) != 1) + || (memcmp(firstbit, "PE\0\0", 4) != 0)) + { + return (1); + } + } + if (fread(&coff_hdr, sizeof(coff_hdr), 1, fp) != 1) + { + printf("Error occured while reading COFF header\n"); + return (2); + } +#if TARGET_64BIT + if (coff_hdr.Machine != IMAGE_FILE_MACHINE_AMD64) + { + printf("only 64-bit PE programs are supported\n"); + return (2); + } +#else + if ((coff_hdr.Machine != IMAGE_FILE_MACHINE_UNKNOWN) + && (coff_hdr.Machine != IMAGE_FILE_MACHINE_I386)) + { + if (coff_hdr.Machine == IMAGE_FILE_MACHINE_AMD64) + { + printf("64-bit PE programs are not supported\n"); + } + else + { + printf("Unknown PE machine type: %04x\n", coff_hdr.Machine); + } + return (2); + } +#endif + + if ((coff_hdr.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) != 0) + { + printf("only relocatable executables supported\n"); + return (2); + } + + optional_hdr = malloc(coff_hdr.SizeOfOptionalHeader); + if (optional_hdr == NULL) + { + printf("Insufficient memory to load PE optional header\n"); + return (2); + } + if (fread(optional_hdr, coff_hdr.SizeOfOptionalHeader, 1, fp) != 1) + { + printf("Error occured while reading PE optional header\n"); + free(optional_hdr); + return (2); + } +#if TARGET_64BIT + if (optional_hdr->Magic != MAGIC_PE32PLUS) + { + printf("Unknown PE optional header magic: %04x\n", + optional_hdr->Magic); + free(optional_hdr); + return (2); + } +#else + if (optional_hdr->Magic != MAGIC_PE32) + { + printf("Unknown PE optional header magic: %04x\n", + optional_hdr->Magic); + free(optional_hdr); + return (2); + } +#endif + + section_table = malloc(coff_hdr.NumberOfSections * sizeof(Coff_section)); + if (section_table == NULL) + { + printf("Insufficient memory to load PE section headers\n"); + free(optional_hdr); + return (2); + } + if (fread(section_table, + coff_hdr.NumberOfSections * sizeof(Coff_section), + 1, + fp) != 1) + { + printf("Error occured while reading PE optional header\n"); + free(section_table); + free(optional_hdr); + return (2); + } + + /* Allocates memory for the process. + * Size of image is obtained from the optional header. */ + if (*loadloc != NULL) + { + exeStart = *loadloc; + } + else + { + exeStart = malloc(optional_hdr->SizeOfImage); + } + if (exeStart == NULL) + { + printf("Insufficient memory to load PE program\n"); + free(section_table); + free(optional_hdr); + return (2); + } + + /* Loads all sections at their addresses. */ + for (section = section_table; + section < section_table + coff_hdr.NumberOfSections; + section++) + { + unsigned long size_in_file; + + /* Virtual size of a section is larger than in file, + * so the difference is filled with 0. */ + if (section->VirtualSize > section->SizeOfRawData) + { + memset(exeStart + + section->VirtualAddress + + section->SizeOfRawData, + 0, + section->VirtualSize - section->SizeOfRawData); + size_in_file = section->SizeOfRawData; + } + /* SizeOfRawData is rounded up, + * so it can be larger than VirtualSize. */ + else + { + size_in_file = section->VirtualSize; + } + if (size_in_file != 0) + { + if ((fseek(fp, section->PointerToRawData, SEEK_SET) != 0) + || (fread(exeStart + section->VirtualAddress, + size_in_file, + 1, + fp) != 1)) + { + printf("Error occured while reading PE section\n"); + free(section_table); + free(optional_hdr); + return (2); + } + } + } + + if (exeStart != optional_hdr->ImageBase) + { + /* Relocations are not stripped, so the executable can be relocated. */ + if (optional_hdr->NumberOfRvaAndSizes > DATA_DIRECTORY_REL) + { + IMAGE_DATA_DIRECTORY *data_dir = (((IMAGE_DATA_DIRECTORY *) + (optional_hdr + 1)) + + DATA_DIRECTORY_REL); + /* Difference between preferred address and real address. */ + ptrdiff_t image_diff; + int lower_exeStart; + Base_relocation_block *rel_block = ((Base_relocation_block *) + (exeStart + + (data_dir + ->VirtualAddress))); + Base_relocation_block *end_rel_block; + + if (optional_hdr->ImageBase > exeStart) + { + /* Image is loaded at lower address than preferred. */ + image_diff = optional_hdr->ImageBase - exeStart; + lower_exeStart = 1; + } + else + { + image_diff = exeStart - optional_hdr->ImageBase; + lower_exeStart = 0; + } + + end_rel_block = rel_block + ((data_dir->Size) + / sizeof(Base_relocation_block)); + + for (; rel_block < end_rel_block;) + { + unsigned short *cur_rel = (unsigned short *)rel_block; + unsigned short *end_rel; + + end_rel = (cur_rel + + ((rel_block->BlockSize) + / sizeof(unsigned short))); + cur_rel = (unsigned short *)(rel_block + 1); + + for (; cur_rel < end_rel; cur_rel++) + { + /* Top 4 bits indicate the type of relocation. */ + unsigned char rel_type = (unsigned char)((*cur_rel) >> 12); + unsigned char *rel_target = (exeStart + (rel_block->PageRva) + + ((*cur_rel) & 0x0fff)); + + if (rel_type == IMAGE_REL_BASED_ABSOLUTE) continue; + if (rel_type == IMAGE_REL_BASED_HIGHLOW) + { + if (lower_exeStart) + *(unsigned char **)rel_target -= image_diff; + else *(unsigned char **)rel_target += image_diff; + } + else + { + printf("Unknown PE relocation type: %u\n", + rel_type); + } + } + + rel_block = (Base_relocation_block *)cur_rel; + } + } + } + + if (optional_hdr->NumberOfRvaAndSizes > DATA_DIRECTORY_IMPORT_TABLE) + { + IMAGE_DATA_DIRECTORY *data_dir = (((IMAGE_DATA_DIRECTORY *) + (optional_hdr + 1)) + + DATA_DIRECTORY_IMPORT_TABLE); + if (data_dir->Size != 0) + { + IMAGE_IMPORT_DESCRIPTOR *import_desc = ((void *) + (exeStart + + (data_dir + ->VirtualAddress))); + + /* Each descriptor is for one DLL + * and the array has a null terminator. */ + for (; import_desc->OriginalFirstThunk; import_desc++) + { + ret = exeloadLoadPEDLL(exeStart, import_desc); + if (ret != 0) + { + printf("Cannot load DLL %s, ret %d\n", + exeStart + import_desc->Name, ret); + return (2); + } + } + } + } + + *entry_point = exeStart + optional_hdr->AddressOfEntryPoint; + /* Frees memory not needed by the process. */ + free(section_table); + free(optional_hdr); + if (*loadloc == NULL) + { + *loadloc = exeStart; + } + return (0); +} + + +static int exeloadLoadPEDLL(unsigned char *exeStart, + IMAGE_IMPORT_DESCRIPTOR *import_desc) +{ + Mz_hdr mzFirstbit; + FILE *fp; + Coff_hdr coff_hdr; + Pe32_optional_hdr *optional_hdr; + Coff_section *section_table, *section; + unsigned char *dllStart; + long newpos; + size_t readbytes; + char *name1; + char *name2; + + /* PE DLL is being loaded, + * so it is loaded in the same way as PE executable, + * but the MZ stage is integrated. */ + name1 = exeStart + import_desc->Name; + if ((strcmp(name1, "kernel32.dll") == 0) + || (strcmp(name1, "KERNEL32.dll") == 0)) + { + name2 = kernel32; + } + else if (strcmp(name1, "msvcrt.dll") == 0) + { + name2 = msvcrt; + } + else + { + name2 = name1; + } + fp = fopen(name2, "rb"); + if (fp == NULL) + { + printf("Failed to open %s for loading\n", + exeStart + (import_desc->Name)); + return (1); + } + + /* The header size is in paragraphs, + * so the smallest possible header is 16 bytes (paragraph) long. + * Next is the magic number checked. */ + if ((fseek(fp, 0, SEEK_SET) != 0) + || (fread(&mzFirstbit, 16, 1, fp) != 1) + || (memcmp(mzFirstbit.magic, "MZ", 2) != 0) + && (memcmp(&mzFirstbit.magic, "ZM", 2) != 0)) + { + fclose(fp); + return (2); + } + if (mzFirstbit.header_size == 0) + { + printf("MZ Header has 0 size\n"); + fclose(fp); + return (3); + } + if (mzFirstbit.header_size * 16 > sizeof(mzFirstbit)) + { + printf("MZ Header is too large, size: %u\n", + mzFirstbit.header_size * 16); + fclose(fp); + return (4); + } + /* Loads the rest of the header. */ + if (fread(((char *)&mzFirstbit) + 16, + (mzFirstbit.header_size - 1) * 16, + 1, + fp) != 1) + { + printf("Error occured while reading MZ header\n"); + return (5); + } + /* Determines whether the executable has extensions or is a pure MZ. + * Extensions are at offset in e_lfanew, + * so the header must have at least 4 paragraphs. */ + if ((mzFirstbit.header_size < 4) + || (mzFirstbit.e_lfanew == 0)) + { + fclose(fp); + return (6); + } + + /* PE stage begins. */ + { + unsigned char firstbit[4]; + + if ((fseek(fp, mzFirstbit.e_lfanew, SEEK_SET) != 0) + || (fread(firstbit, 4, 1, fp) != 1) + || (memcmp(firstbit, "PE\0\0", 4) != 0)) + { + fclose(fp); + return (7); + } + } + if (fread(&coff_hdr, sizeof(coff_hdr), 1, fp) != 1) + { + printf("Error occured while reading COFF header\n"); + fclose(fp); + return (8); + } + if ((coff_hdr.Machine != IMAGE_FILE_MACHINE_UNKNOWN) + && (coff_hdr.Machine != IMAGE_FILE_MACHINE_I386)) + { + if (coff_hdr.Machine == IMAGE_FILE_MACHINE_AMD64) + { + printf("64-bit PE programs are not supported\n"); + } + else + { + printf("Unknown PE machine type: %04x\n", coff_hdr.Machine); + } + fclose(fp); + return (9); + } + + if (coff_hdr.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) + { + printf("only relocatable DLLs are supported\n"); + fclose(fp); + return (10); + } + + optional_hdr = malloc(coff_hdr.SizeOfOptionalHeader); + if (optional_hdr == NULL) + { + printf("Insufficient memory to load PE optional header\n"); + fclose(fp); + return (11); + } + if (fread(optional_hdr, coff_hdr.SizeOfOptionalHeader, 1, fp) != 1) + { + printf("Error occured while reading PE optional header\n"); + free(optional_hdr); + fclose(fp); + return (12); + } + if (optional_hdr->Magic != MAGIC_PE32) + { + printf("Unknown PE optional header magic: %04x\n", + optional_hdr->Magic); + free(optional_hdr); + fclose(fp); + return (13); + } + + section_table = malloc(coff_hdr.NumberOfSections * sizeof(Coff_section)); + if (section_table == NULL) + { + printf("Insufficient memory to load PE section headers\n"); + free(optional_hdr); + fclose(fp); + return (14); + } + if (fread(section_table, + coff_hdr.NumberOfSections * sizeof(Coff_section), + 1, + fp) != 1) + { + printf("Error occured while reading PE optional header\n"); + free(section_table); + free(optional_hdr); + fclose(fp); + return (15); + } + + /* Allocates memory for the process. + * Size of image is obtained from the optional header. */ + dllStart = malloc(optional_hdr->SizeOfImage); + if (dllStart == NULL) + { + printf("Insufficient memory to load PE program\n"); + free(section_table); + free(optional_hdr); + fclose(fp); + return (16); + } + + /* Loads all sections at their addresses. */ + for (section = section_table; + section < section_table + (coff_hdr.NumberOfSections); + section++) + { + unsigned long size_in_file; + + /* Virtual size of a section is larger than in file, + * so the difference is filled with 0. */ + if ((section->VirtualSize) > (section->SizeOfRawData)) + { + memset((dllStart + + (section->VirtualAddress) + + (section->SizeOfRawData)), + 0, + (section->VirtualSize) - (section->SizeOfRawData)); + size_in_file = section->SizeOfRawData; + } + /* SizeOfRawData is rounded up, + * so it can be larger than VirtualSize. */ + else + { + size_in_file = section->VirtualSize; + } + if ((fseek(fp, section->PointerToRawData, SEEK_SET) != 0) + || fread(dllStart + (section->VirtualAddress), + size_in_file, + 1, + fp) != 1) + { + printf("Error occured while reading PE section\n"); + free(section_table); + free(optional_hdr); + fclose(fp); + return (17); + } + } + fclose(fp); + + if (dllStart != optional_hdr->ImageBase) + { + /* Relocations are not stripped, so the executable can be relocated. */ + if (optional_hdr->NumberOfRvaAndSizes > DATA_DIRECTORY_REL) + { + IMAGE_DATA_DIRECTORY *data_dir = (((IMAGE_DATA_DIRECTORY *) + (optional_hdr + 1)) + + DATA_DIRECTORY_REL); + /* Difference between preferred address and real address. */ + unsigned long image_diff; + int lower_dllStart; + Base_relocation_block *rel_block = ((Base_relocation_block *) + (dllStart + + (data_dir + ->VirtualAddress))); + Base_relocation_block *end_rel_block; + + if (optional_hdr->ImageBase > dllStart) + { + /* Image is loaded at lower address than preferred. */ + image_diff = optional_hdr->ImageBase + - dllStart; + lower_dllStart = 1; + } + else + { + image_diff = dllStart + - optional_hdr->ImageBase; + lower_dllStart = 0; + } + end_rel_block = rel_block + ((data_dir->Size) + / sizeof(Base_relocation_block)); + + for (; rel_block < end_rel_block;) + { + unsigned short *cur_rel = (unsigned short *)rel_block; + unsigned short *end_rel; + + end_rel = (cur_rel + + ((rel_block->BlockSize) + / sizeof(unsigned short))); + cur_rel = (unsigned short *)(rel_block + 1); + + for (; cur_rel < end_rel; cur_rel++) + { + /* Top 4 bits indicate the type of relocation. */ + unsigned char rel_type = (*cur_rel) >> 12; + void *rel_target = (dllStart + (rel_block->PageRva) + + ((*cur_rel) & 0x0fff)); + + if (rel_type == IMAGE_REL_BASED_ABSOLUTE) continue; + if (rel_type == IMAGE_REL_BASED_HIGHLOW) + { + if (lower_dllStart) + (*((unsigned long *)rel_target)) -= image_diff; + else (*((unsigned long *)rel_target)) += image_diff; + } + else + { + printf("Unknown PE relocation type: %u\n", + rel_type); + } + } + + rel_block = (Base_relocation_block *)cur_rel; + } + } + } + + if (optional_hdr->NumberOfRvaAndSizes > DATA_DIRECTORY_EXPORT_TABLE) + { + IMAGE_DATA_DIRECTORY *data_dir = (((IMAGE_DATA_DIRECTORY *) + (optional_hdr + 1)) + + DATA_DIRECTORY_EXPORT_TABLE); + IMAGE_EXPORT_DIRECTORY *export_dir; + unsigned long *functionTable; + unsigned long *nameTable; + unsigned short *ordinalTable; + unsigned long *thunk; + + if (data_dir->Size == 0) + { + printf("DLL has no export tables\n"); + free(section_table); + free(optional_hdr); + return (18); + } + + export_dir = ((void *)(dllStart + (data_dir->VirtualAddress))); + functionTable = (void *)(dllStart + (export_dir->AddressOfFunctions)); + nameTable = (void *)(dllStart + (export_dir->AddressOfNames)); + ordinalTable = (void *)(dllStart + + (export_dir->AddressOfNameOrdinals)); + + /* The importing itself. + * Import Address Table of the executable is parsed + * and function addresses are written + * when they are found. */ + for (thunk = (void *)(exeStart + (import_desc->FirstThunk)); + *thunk != 0; + thunk++) + { + if ((*thunk) & 0x80000000) + { + /* Bit 31 set, import by ordinal. */ + *thunk = ((unsigned long) + (dllStart + + (functionTable[((*thunk) & 0x7fffffff) + - (export_dir->Base)]))); + } + else + { + /* Import by name. */ + unsigned char *hintname = exeStart + ((*thunk) & 0x7fffffff); + int i; + + /* The first 2 bytes are hint index, + * so they are skipped to get the name. */ + hintname += 2; + for (i = 0; i < (export_dir->NumberOfNames); i++) + { + if (strcmp(hintname, dllStart + (nameTable[i]))) continue; + break; + } + if (i == (export_dir->NumberOfNames)) + { + printf("Function %s not found in DLL\n", hintname); + free(section_table); + free(optional_hdr); + return (1); + } + /* PE specification says that the ordinals in ordinal table + * are biased by Ordinal Base, + * but it does not seem to be correct. */ + *thunk = (unsigned long)(dllStart + + (functionTable[ordinalTable[i]])); + } + } + /* After the DLL is bound, time/date stamp is copied. */ + import_desc->TimeDateStamp = export_dir->TimeDateStamp; + } + if (optional_hdr->NumberOfRvaAndSizes > DATA_DIRECTORY_IMPORT_TABLE) + { + IMAGE_DATA_DIRECTORY *data_dir = (((IMAGE_DATA_DIRECTORY *) + (optional_hdr + 1)) + + DATA_DIRECTORY_IMPORT_TABLE); + if (data_dir->Size != 0) + { + IMAGE_IMPORT_DESCRIPTOR *import_desc = ((void *) + (dllStart + + (data_dir + ->VirtualAddress))); + + /* Each descriptor is for one DLL + * and the array has a null terminator. */ + for (; import_desc->OriginalFirstThunk; import_desc++) + { + if (exeloadLoadPEDLL(dllStart, import_desc)) + { + printf("Failed to load DLL %s\n", + dllStart + (import_desc->Name)); + free(section_table); + free(optional_hdr); + return (19); + } + } + } + } + + /* Entry point is optional for DLLs. */ + if (optional_hdr->AddressOfEntryPoint) + { + int ret = callDllEntry(dllStart + (optional_hdr->AddressOfEntryPoint), + dllStart, + 1, /* fdwReason = DLL_PROCESS_ATTACH */ + (void *)1); /* lpvReserved = non-NULL */ + + if (ret == 0) + { + printf("Initialization of DLL %s failed\n", + exeStart + (import_desc->Name)); + free(section_table); + free(optional_hdr); + return (20); + } + } + + /* Frees memory not needed by the DLL. */ + free(section_table); + free(optional_hdr); + + return (0); +} + +static int exeloadLoadLX(unsigned char **entry_point, + FILE *fp, + unsigned long e_lfanew) +{ + unsigned char firstbit[2]; + long newpos; + size_t readbytes; + + if ((fseek(fp, e_lfanew, SEEK_SET) != 0) + || (fread(firstbit, sizeof(firstbit), 1, fp) != 1) + || (memcmp(firstbit, "LX", 2) != 0)) + { + return (1); + } + /* LX seems to be called LE sometimes. */ + printf("LX (other name LE) is not supported\n"); + + return (2); +} + +static int exeloadLoadNE(unsigned char **entry_point, + FILE *fp, + unsigned long e_lfanew) +{ + unsigned char firstbit[2]; + long newpos; + size_t readbytes; + + if ((fseek(fp, e_lfanew, SEEK_SET) != 0) + || (fread(firstbit, sizeof(firstbit), 1, fp) != 1) + || (memcmp(firstbit, "NE", 2) != 0)) + { + return (1); + } + printf("NE is not supported\n"); + + return (2); +} + +#endif /* NEED_MZ */ + +#if NEED_MVS +/* Structures here are documented in Appendix B and E of + MVS Program Management: Advanced Facilities SA22-7644-14: + http://publibfp.dhe.ibm.com/cgi-bin/bookmgr/BOOKS/iea2b2b1/CCONTENTS + and the IEBCOPY component is documented here: + Appendix B of OS/390 DFSMSdfp Utilities SC26-7343-00 + or Appendix B of the z/OS equivalent SC26-7414-05 available here at + http://publibz.boulder.ibm.com/epubs/pdf/dgt2u140.pdf +*/ + +#define PE_DEBUG 1 + +static int fixPE(unsigned char *buf, + size_t *len, + unsigned char **entry, + unsigned long rlad) +{ + unsigned char *p; + unsigned char *q; + /* int z; */ + typedef struct { + unsigned char pds2name[8]; + unsigned char unused1[19]; + unsigned char pds2epa[3]; + unsigned char pds2ftb1; + unsigned char pds2ftb2; + unsigned char pds2ftb3; + } IHAPDS; + IHAPDS *ihapds; + int rmode; + int amode; + int ent; + int rec = 0; + int corrupt = 1; + int rem = *len; + int l; + int l2; + int lastt = -1; + unsigned char *upto = buf; + + if ((*len <= 8) || (*((int *)buf + 1) != 0xca6d0f)) + { + /* printf("Not an MVS PE executable\n"); */ + return (-1); + } +#if PE_DEBUG + printf("MVS PE total length is %lu\n", (unsigned long)*len); +#endif + p = buf; + while (1) + { + rec++; + l = *(short *)p; + /* keep track of remaining bytes, and ensure they really exist */ + if (l > rem) + { + break; + } + rem -= l; +#if PE_DEBUG + printf("rec %d, offset %d is len %d\n", rec, p - buf, l); +#endif +#if 0 + if (1) + { + for (z = 0; z < l; z++) + { + printf("z %d %x %c\n", z, p[z], + isprint((unsigned char)p[z]) ? p[z] : ' '); + } + } +#endif + if (rec == 3) /* directory record */ + { + /* there should only be one directory entry, + which is 4 + 276 + 12 */ + if (l < 292) + { + break; + } + q = p + 24; + l2 = *(short *)q; + if (l2 < 32) break; + ihapds = (IHAPDS *)(q + 2); + rmode = ihapds->pds2ftb2 & 0x10; +/* do we care about alias entry point amode? */ +#if 0 + amode = (ihapds->pds2ftb2 & 0x0c) >> 2; +#else + amode = ihapds->pds2ftb2 & 0x03; +#endif + ent = ((unsigned long)ihapds->pds2epa[0] << 16) + | ((unsigned long)ihapds->pds2epa[1] << 8) + | ihapds->pds2epa[2]; + *entry = buf + ent; +#if PE_DEBUG + printf("module name is %.8s\n", ihapds->pds2name); + printf("rmode is %s\n", rmode ? "ANY" : "24"); + printf("amode is "); + if (amode == 0) + { + printf("24"); + } + else if (amode == 2) + { + printf("31"); + } + else if (amode == 1) + { + printf("64"); + } + else if (amode == 3) + { + printf("ANY"); + } + printf("\n"); + printf("entry point is %x\n", ent); +#endif + } + else if (rec > 3) + { + int t; + int r2; + int l2; + int term = 0; + + if (l < (4 + 12)) + { + break; + } + q = p + 4 + 10; + r2 = l - 4 - 10; + while (1) + { + l2 = *(short *)q; + r2 -= sizeof(short); + if (l2 > r2) + { + term = 1; + break; + } + r2 -= l2; + + if (l2 == 0) break; + q += sizeof(short); +#if PE_DEBUG + printf("load module record is of type %2x (len %5d)" + " offset %d\n", + *q, l2, q - p); +#endif + + t = *q; + if ((lastt == 1) || (lastt == 3) || (lastt == 0x0d)) + { +#if PE_DEBUG + printf("rectype: program text\n"); +#endif + memmove(upto, q, l2); + upto += l2; + t = -1; + if (lastt == 0x0d) + { + term = 1; + corrupt = 0; + break; + } + } + else if (t == 0x20) + { + /* printf("rectype: CESD\n"); */ + } + else if (t == 1) + { + /* printf("rectype: Control\n"); */ + } + else if (t == 0x0d) + { + /* printf("rectype: Control, about to end\n"); */ + } + else if (t == 2) + { + /* printf("rectype: RLD\n"); */ + if (processRLD(buf, rlad, q, l2) != 0) + { + term = 1; + break; + } + } + else if (t == 3) + { + int l3; + + /* printf("rectype: Dicionary = Control + RLD\n"); */ + l3 = *(short *)(q + 6) + 16; +#if 0 + printf("l3 is %d\n", l3); +#endif + if (processRLD(buf, rlad, q, l3) != 0) + { + term = 1; + break; + } + } + else if (t == 0x0e) + { + /* printf("rectype: Last record of module\n"); */ + if (processRLD(buf, rlad, q, l2) != 0) + { + term = 1; + break; + } + term = 1; + corrupt = 0; + break; + } + else if (t == 0x80) + { + /* printf("rectype: CSECT\n"); */ + } + else + { + /* printf("rectype: unknown %x\n", t); */ + } +#if 0 + if ((t == 0x20) || (t == 2)) + { + for (z = 0; z < l; z++) + { + printf("z %d %x %c\n", z, q[z], + isprint(q[z]) ? q[z] : ' '); + } + } +#endif + lastt = t; + + q += l2; + if (r2 == 0) + { +#if PE_DEBUG + printf("another clean exit\n"); +#endif + break; + } + else if (r2 < (10 + sizeof(short))) + { + /* printf("another unclean exit\n"); */ + term = 1; + break; + } + r2 -= 10; + q += 10; + } + if (term) break; + } + p = p + l; + if (rem == 0) + { +#if PE_DEBUG + printf("breaking cleanly\n"); +#endif + } + else if (rem < 2) + { + break; + } + } + if (corrupt) + { + printf("corrupt module\n"); + return (-1); + } +#if 0 + printf("dumping new module\n"); +#endif + *len = upto - buf; /* return new module length */ + return (0); +} + + +static int processRLD(unsigned char *buf, + unsigned long rlad, + unsigned char *rld, + int len) +{ + unsigned char *r; + int cont = 0; + unsigned char *fin; + int negative; + int ll; + int a; + long newval; + unsigned int *zaploc; + + r = (unsigned char *)rld + 16; + fin = rld + len; + while (r != fin) + { + if (!cont) + { + r += 4; /* skip R & P */ + if (r >= fin) + { + printf("corrupt1 at position %x\n", r - rld - 4); + return (-1); + } + } + negative = *r & 0x02; + if (negative) + { + printf("got a negative adjustment - unsupported\n"); + return (-1); + } + ll = (*r & 0x0c) >> 2; + ll++; + if ((ll != 4) && (ll != 3)) + { + printf("untested and unsupported relocation %d\n", ll); + return (-1); + } + if (ll == 3) + { + if (rlad > 0xffffff) + { + printf("AL3 prevents relocating this module to %lx\n", rlad); + return (-1); + } + } + cont = *r & 0x01; /* do we have A & F continous? */ + r++; + if ((r + 3) > fin) + { + printf("corrupt2 at position %x\n", r - rld); + return (-1); + } + a = ((unsigned long)r[0] << 16) + || ((unsigned long)r[1] << 8) + || r[2]; + /* +++ need bounds checking on this OS code */ + /* printf("need to zap %d bytes at offset %6x\n", ll, a); */ + zaploc = (unsigned int *)(buf + a); + + /* This old code doesn't look right. The integer is misaligned */ + /* zaploc = (unsigned int *)(buf + a - ((ll == 3) ? 1 : 0)); */ + + newval = *zaploc; + /* printf("which means that %8x ", newval); */ + newval += rlad; + /* printf("becomes %8x\n", newval); */ + *zaploc = newval; + r += 3; + } + return (0); +} +#endif diff --git a/app/src/main/cpp/bios/x86/exeload.h b/app/src/main/cpp/bios/x86/exeload.h new file mode 100644 index 0000000..1537920 --- /dev/null +++ b/app/src/main/cpp/bios/x86/exeload.h @@ -0,0 +1,16 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Alica Okano. */ +/* Released to the Public Domain as discussed here: */ +/* http://creativecommons.org/publicdomain/zero/1.0/ */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* exeload.h - header for exeload.c */ +/* */ +/*********************************************************************/ + +int exeloadDoload(unsigned char **entry_point, + char *progname, + unsigned char **loadloc); diff --git a/app/src/main/cpp/bios/x86/pos.h b/app/src/main/cpp/bios/x86/pos.h new file mode 100644 index 0000000..5e43956 --- /dev/null +++ b/app/src/main/cpp/bios/x86/pos.h @@ -0,0 +1,524 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* pos - some low-level dos functions */ +/* */ +/* In my opinion, all the MSDOS functions should have had both a */ +/* low-level assember interrupt definition, and a functional */ +/* interface for higher level languages such as C. It is important */ +/* to have both interfaces as it allows anyone creating a new */ +/* language to implement the functions themselves. It is also a */ +/* good idea to make the API start with a specific mneumonic like */ +/* the Dos* and Win* etc functions you see in the OS/2 API. It is */ +/* not a good idea to pretend to be performing data abstraction by */ +/* typedefing long as LONG etc. Hence, the following is what I */ +/* think should have been done to formalise the HLL Dos API. */ +/* */ +/* Obviously it's a bit late to be standardizing this now, and not */ +/* only that, but it's not much of a standard when I'm the only */ +/* user of it either! However, this interface is first and */ +/* foremost to provide myself with a clearcut API so that I can */ +/* make it 32-bit at the drop of a hat. */ +/* */ +/*********************************************************************/ + +#ifndef POS_INCLUDED +#define POS_INCLUDED + +#include + +/*Standard Error Codes for PDOS*/ +/*When adding a new error code here, also add it to PosGetErrorMessageString() + *in pdos.c + */ +#define POS_ERR_NO_ERROR 0x00 +#define POS_ERR_FUNCTION_NUMBER_INVALID 0x01 +#define POS_ERR_FILE_NOT_FOUND 0x02 +#define POS_ERR_PATH_NOT_FOUND 0x03 +#define POS_ERR_MANY_OPEN_FILES 0x04 +#define POS_ERR_ACCESS_DENIED 0x05 +#define POS_ERR_INVALID_HANDLE 0x06 +#define POS_ERR_MEM_CONTROL_BLOCK_DESTROYED 0x07 +#define POS_ERR_INSUFFICIENT_MEMORY 0x08 +#define POS_ERR_MEMORY_BLOCK_ADDRESS_INVALID 0x09 +#define POS_ERR_ENVIRONMENT_INVALID 0x0A +#define POS_ERR_FORMAT_INVALID 0x0B +#define POS_ERR_ACCESS_CODE_INVALID 0x0C +#define POS_ERR_DATA_INVALID 0x0D +#define POS_ERR_RESERVED 0x0E +#define POS_ERR_FIXUP_OVERFLOW 0x0E +#define POS_ERR_INVALID_DRIVE 0x0F +#define POS_ERR_ATTEMPTED_TO_REMOVE_CURRENT_DIRECTORY 0x10 +#define POS_ERR_NOT_SAME_DEVICE 0x11 +#define POS_ERR_NO_MORE_FILES 0x12 +/**/ + +#define POS_ERR_FILE_EXISTS 0x50 + +/* for use by PosAllocMem callers */ +#define POS_LOC_MASK 0x300 +#define POS_LOC20 0x100 +#define POS_LOC32 0x200 +#define POS_LOC64 0x300 + +/* File attribute bits */ +#define FILE_ATTR_READONLY 0x01 +#define FILE_ATTR_HIDDEN 0x02 +#define FILE_ATTR_SYSTEM 0x04 +#define FILE_ATTR_LABEL 0x08 +#define FILE_ATTR_DIRECTORY 0x10 +#define FILE_ATTR_ARCHIVE 0x20 + +/* Video subsystem information */ +typedef struct pos_video_info { + unsigned int mode; + unsigned int page; + unsigned int rows; + unsigned int cols; + unsigned int cursorStart; + unsigned int cursorEnd; + unsigned int row; + unsigned int col; + unsigned int currentAttrib; +} pos_video_info; + +/* Input buffer used for INT 21,A */ +typedef struct pos_input_buffer { + unsigned char maxChars; /* Maximum number of chars buffer can hold */ + unsigned char actualChars; /* Number of chars actually read + (not including final CR) */ + char data[1]; /* 1 is arbitrary, for C compilers that don't accept + incomplete arrays */ +} pos_input_buffer; + +/* ===== BEGINS PROCESS MANAGEMENT DATA STRUCTURES ===== */ + +/* Process status enumeration. */ +typedef enum { + /* Process has been loaded but not yet executed. */ + PDOS_PROCSTATUS_LOADED, + /* Process is the current foreground process. */ + PDOS_PROCSTATUS_ACTIVE, + /* Process is waiting for child process to finish. */ + PDOS_PROCSTATUS_CHILDWAIT, + /* Process is a TSR */ + PDOS_PROCSTATUS_TSR, + /* Process has voluntarily suspended itself. */ + PDOS_PROCSTATUS_SUSPENDED, + /* Process has terminated */ + PDOS_PROCSTATUS_TERMINATED +} PDOS_PROCSTATUS; + +#define PDOS_PROCESS_EXENAMESZ 13 + +/* PDOS_PROCINFO: data structure with info about a process */ +typedef struct _PDOS_PROCINFO { + char exeName[PDOS_PROCESS_EXENAMESZ]; /* ASCIIZ short name of executable */ + unsigned long pid; /* Process ID */ + unsigned long ppid; /* Parent Process ID; 0 if none */ + unsigned long prevPid; /* Prev PID in chain; 0 if start of chain */ + unsigned long nextPid; /* Next PID in chain; 0 if end of chain */ + PDOS_PROCSTATUS status; /* Process status */ +} PDOS_PROCINFO; + +/* ===== ENDING PROCESS MANAGEMENT DATA STRUCTURES ===== */ + +typedef struct { +#ifdef __32BIT__ + char *env; +#else + short env; +#endif + unsigned char *cmdtail; + char *fcb1; + char *fcb2; +} POSEXEC_PARMBLOCK; + +/* API functions */ + +void PosTermNoRC(void); /* int 20h */ + +/* int 21h */ +unsigned int PosDisplayOutput(unsigned int ch); /* func 2 */ + +unsigned int PosDirectConsoleOutput(unsigned int ch); /* func 6 */ + +unsigned int PosDirectCharInputNoEcho(void); /* func 7 */ + +unsigned int PosGetCharInputNoEcho(void); /* func 8 */ + +unsigned int PosDisplayString(const char *buf); /* func 9 */ + +void PosReadBufferedInput(pos_input_buffer *buf); /* func A */ + +unsigned int PosSelectDisk(unsigned int drive); /* func e */ + +unsigned int PosGetDefaultDrive(void); /* func 19 */ + +void PosSetDTA(void *dta); /* func 1a */ + +void PosSetInterruptVector(unsigned int intnum, void *handler); /* func 25 */ + +void PosGetSystemDate(unsigned int *year, /* func 2a */ + unsigned int *month, + unsigned int *day, + unsigned int *dw); + +unsigned int PosSetSystemDate(unsigned int year, /* func 2b */ + unsigned int month, + unsigned int day); + +void PosGetSystemTime(unsigned int *hour, /* func 2c */ + unsigned int *min, + unsigned int *sec, + unsigned int *hundredths); + +void PosSetVerifyFlag(int flag); /* func 2e + - set read-after-write verification flag */ + +void *PosGetDTA(void); /* func 2f */ + +unsigned int PosGetDosVersion(void); /* func 30 */ + +void PosTerminateAndStayResident(int exitCode, int paragraphs); /* func 31 */ + +int PosGetBreakFlag(void); /* func 33, subfunc 00 + - get Ctrl+Break checking flag status */ + +void PosSetBreakFlag(int flag); /* func 33, subfunc 01 + - set Ctrl+Break checking flag status */ + +int PosGetBootDrive(void); /* func 33, subfunc 05 + - get boot drive (1=A,2=B,etc.) */ + +void *PosGetInterruptVector(int intnum); /* func 35 */ + +void PosGetFreeSpace(int drive, + unsigned int *secperclu, + unsigned int *numfreeclu, + unsigned int *bytpersec, + unsigned int *totclus); /* func 36 */ + +int PosMakeDir(const char *dname); /* func 39 */ + +int PosRemoveDir(const char *dname); /* func 3a */ + +int PosChangeDir(const char *to); /* func 3b */ + +int PosCreatFile(const char *name, /* func 3c */ + int attrib, + int *handle); + +int PosOpenFile(const char *name, /* func 3d */ + int mode, + int *handle); + +int PosCloseFile(int handle); /* func 3e */ + +int PosReadFile(int fh, /* func 3f */ + void *data, + unsigned int bytes, + unsigned int *readbytes); + +int PosWriteFile(int handle, /* func 40 */ + const void *data, + unsigned int len, + unsigned int *writtenbytes); + +int PosDeleteFile(const char *fname); /* func 41 */ + +int PosMoveFilePointer(int handle, /* func 42 */ + long offset, + int whence, + long *newpos); + +int PosGetFileAttributes(const char *fnm,int *attr);/*func 43*/ + +int PosSetFileAttributes(const char *fnm,int attr);/*func 43 subfunc 01*/ + +int PosGetDeviceInformation(int handle, unsigned int *devinfo); + /* func 44 subfunc 0 */ + +int PosSetDeviceInformation(int handle, unsigned int devinfo); + /* func 44 subfunc 1 */ + +int PosBlockDeviceRemovable(int drive); /* func 44 subfunc 8 */ + +int PosBlockDeviceRemote(int drive,int *da); /* func 44 subfunc 9 */ + +int PosGenericBlockDeviceRequest(int drive, + int catcode, + int function, + void *parmblock); /*func 44 subfunc 0D*/ + + +int PosDuplicateFileHandle(int fh); /* func 45 */ + +int PosForceDuplicateFileHandle(int fh, int newfh); /* func 46 */ + +int PosGetCurDir(int drive, char *dir); /* func 47 */ + +/* func 48 alternate entry really for 16-bit */ +void *PosAllocMemPages(unsigned int pages, unsigned int *maxpages); + +int PosFreeMem(void *ptr); /* func 49 */ + +/* func 4a */ +int PosReallocPages(void *ptr, unsigned int newpages, unsigned int *maxp); + +int PosExec(char *prog, POSEXEC_PARMBLOCK *parmblock); /* func 4b */ + +void PosTerminate(int rc); /* func 4c */ + +int PosGetReturnCode(void); /* func 4d */ + +int PosFindFirst(char *pat, int attrib); /* func 4e */ + +int PosFindNext(void); /* func 4f */ + +int PosGetCurrentProcessId(void); /* func 51 */ + +/* func 54 - get read-after-write verification flag */ +int PosGetVerifyFlag(void); + +int PosRenameFile(const char *old, const char *new); /* func 56 */ + +int PosGetFileLastWrittenDateAndTime(int handle, + unsigned int *fdate, + unsigned int *ftime); /*func 57*/ + +int PosSetFileLastWrittenDateAndTime(int handle, + unsigned int fdate, + unsigned int ftime);/*func 57 subfunc 1*/ + +int PosCreatNewFile(const char *name, int attrib, int *handle); /*func 5b*/ + +int PosTruename(char *prename,char *postname); /*func 60*/ + +void PosAExec(char *prog, POSEXEC_PARMBLOCK *parmblock); /* func 80 */ + +/* The following functions are extensions... */ + +void PosDisplayInteger(int x); /* func f6.00 */ + +void PosReboot(void); /* func f6.01 */ + +void PosSetDosVersion(unsigned int version); /* func f6.03 */ + +int PosGetLogUnimplemented(void); /* func f6.04 */ + +void PosSetLogUnimplemented(int flag); /* func f6.05 */ + +/* So programs can reliably determine if they are running under PDOS-16 or + * some other implementation of PDOS API, such as FreeDOS, MS-DOS, PC-DOS, + * DR-DOS, DOSBox, etc. INT 21,AX=F606 will return AX=1234 under PDOS, but not + * under these other operating systems. + */ +#define PDOS_MAGIC 0x1234 + +int PosGetMagic(void); /* func f6.06 */ + +void PosGetMemoryManagementStats(void *stats); /* func f6.07 */ + +void *PosAllocMem(unsigned int size, unsigned int flags); /* func f6.08 */ + +/* Given an error code return corresponding message */ +char *PosGetErrorMessageString(unsigned int errorCode); /* func f6.09 */ + +void PosPowerOff(void); /* func f6.0a */ + +/* Func F6.0C - Get info about a process. + * pid = PID to get info on (0=get info on init process) + * infoSz should be sizeof(PDOS_PROCINFO). It is passed for future-proofing + * (future versions might make the structure bigger, we know whether client + * wants old or new version based on the passed size) + */ +int PosProcessGetInfo(unsigned long pid, + PDOS_PROCINFO *info, + unsigned int infoSz); + +/* Func F6.0D - Get memory usage stats for given process + * pid=0 for current process + */ +void PosProcessGetMemoryStats(unsigned long pid, void *stats); + +void PosClearScreen(void); /* func f6.30 */ + +void PosMoveCursor(int row, int col); /* func f6.31 */ + +int PosGetVideoInfo(pos_video_info *info, unsigned int size); /* func f6.32 */ + +int PosKeyboardHit(void); /* func f6.33 */ + +/* F6,34 - Yield the CPU. Currently calls APM BIOS to reduce CPU usage. + * One day it might be used for multi-tasking. + */ +void PosYield(void); + +/* F6,35 - Sleep for given number of seconds */ +void PosSleep(unsigned long seconds); + +/* F6,36 - Get tick count */ +unsigned long PosGetClockTickCount(void); + +/* F6,37 - Set Video Attribute */ +void PosSetVideoAttribute(unsigned int attribute); + +/* F6,38 - Set Video Mode */ +int PosSetVideoMode(unsigned int mode); + +/* F6,39 - Set Video Page */ +int PosSetVideoPage(unsigned int page); + +/* F6,3A - Set Environment Variable + * To unset a variable, pass NULL for the value. The name and value string + * will be copied into the environment block, so are not required after + * this call. + */ +int PosSetEnv(char *name, char *value); + +/* F6,3B - Get Environment Block + * Returns the environment block for the current process. + */ +void * PosGetEnvBlock(void); + +/* F6,3C - Set Named Font */ +int PosSetNamedFont(char *fontName); + +/* F6,3D - Allocate Virtual Memory */ +void *PosVirtualAlloc(void *addr, size_t size); + +/* F6,3E - Free Virtual Memory */ +void PosVirtualFree(void *addr, size_t size); + +/* F6,3F - Get Command Line String For The Current Process */ +char *PosGetCommandLine(void); + +/* F6,40 - Read Byte From Port */ +unsigned char PosInp(unsigned int port); + +/* F6,41 - Write Byte To Port */ +void PosOutp(unsigned int port, unsigned char data); + +/* F6,42 - Absolute Drive Read */ +unsigned int PosAbsoluteDriveRead(int drive,unsigned long start_sector, + unsigned int sectors,void *buf); +/* F6,43 - Absolute Drive Write */ +unsigned int PosAbsoluteDriveWrite(int drive,unsigned long start_sector, + unsigned int sectors,void *buf); + +/* F6,44 - Boot a Disk */ +unsigned int PosDoBoot(int disknum); + +/* F6,45 - start or stop screen capture */ +unsigned int PosScrncap(int disknum); + +/* F6,46 - GetStdHandle */ +void *PosGetStdHandle(unsigned int nStdHandle); + +/* F6,47 - SetStdHandle */ +unsigned int PosSetStdHandle(unsigned int nStdHandle, void *hHandle); + +/* F6,48 - start system monitor */ +unsigned int PosMonitor(void); + +/* F6,49 - show return codes */ +unsigned int PosShowret(int flag); + +unsigned int PosAbsoluteDiskRead(int drive, unsigned long start_sector, + unsigned int sectors,void *buf); /*INT25 */ + +unsigned int PosAbsoluteDiskWrite(int drive, unsigned long start_sector, + unsigned int sectors,void *buf); /*INT26 */ + + +/*Structure for BPB*/ +typedef struct { + unsigned char BytesPerSector[2]; + unsigned char SectorsPerClustor; + unsigned char ReservedSectors[2]; + unsigned char FatCount; + unsigned char RootEntries[2]; + unsigned char TotalSectors16[2]; + unsigned char MediaType; + unsigned char FatSize16[2]; + unsigned char SectorsPerTrack[2]; + unsigned char Heads[2]; + unsigned char HiddenSectors_Low[2]; + unsigned char HiddenSectors_High[2]; + unsigned char TotalSectors32[4]; +} BPB; +/**/ + +/*Structure for function call 440D*/ +typedef struct { + unsigned char special_function; + unsigned char reservedspace[6]; + BPB bpb; + unsigned char reserve2[100]; /* for OSes with bigger BPBs */ +}PB_1560; +/**/ + +/*Structure for int25/26*/ +typedef struct{ + unsigned long sectornumber; + unsigned int numberofsectors; + void *transferaddress; +}DP; +/**/ + +/*Structure for tempDTA in case of multiple PosFindFirst Calls*/ +typedef struct { + int handle; + char pat[20]; +}FFBLK; +/**/ + +/*Structure to define variables used in DTA*/ +typedef struct { + char attr; /*attribute of the search(0x00)*/ + char drive; /*drive used in search(0x01)*/ + char search[11]; /*search name used(0x02)*/ + int direntno; /*directory entry number(0x0D)*/ + int startcluster; /*starting cluster number for + current directory zero for + root directory(0x0F)*/ + int reserved; /*reserved(0x11)*/ + int startcluster2; /*starting cluster number for + current directory zero for + root directory(0x13)*/ + unsigned char attrib; /*attribute of the matching file + (0x15)*/ + int file_time; /*file time(0x16)*/ + int file_date; /*file date(0x18)*/ + long file_size; /*file size(0x1A)*/ + char file_name[13]; /*ASCIIZ file name and extension in + form NAME.EXT with blanks stripped + 0x1E)*/ + unsigned char lfn[256]; /*Stores LFN (255 characters max.) and + *null terminator.*/ + /*+++Add support for UCS-2 and find + *better place for LFN provided to DIR.*/ + +}DTA; +/**/ + + +#if defined(__PDOSGEN__) +#include <__os.h> + +#define PosGetDTA __os->PosGetDTA +#define PosFindFirst __os->PosFindFirst +#define PosFindNext __os->PosFindNext +#define PosChangeDir __os->PosChangeDir +#define PosMakeDir __os->PosMakeDir +#define PosRemoveDir __os->PosRemoveDir +#endif + + +#endif /* POS_INCLUDED */ diff --git a/app/src/main/cpp/ls.c b/app/src/main/cpp/ls.c new file mode 100644 index 0000000..7cce4a8 --- /dev/null +++ b/app/src/main/cpp/ls.c @@ -0,0 +1,47 @@ +#include +#include +#include +#include + +void printenv(const char *dir) +{ + char **env; + env = environ; + while (env[0]) { + printf("%s\n", env[0]); + env++; + } + //unlink(""); +} + +void ls(const char *dir) +{ + struct dirent** list; + int n; + n = scandir(dir, &list,NULL, alphasort); + if (n < 0) { + printf("%s : not found or empty\n", dir); + } else { + printf("Directory : %s\n", dir); + while (n) { + n--; + printf("%s\n", list[n]->d_name); + free(list[n]); + } + free(list); + } +} +int main(int argc, char *argv[]) +{ + int c; + + if (argc > 1) { + ls(argv[1]); + } else { + ls("./"); + } + //c = getchar(); + //printf("You typed: '%c'\n", c); + return 0; +} + diff --git a/app/src/main/cpp/pdos.c b/app/src/main/cpp/pdos.c new file mode 100644 index 0000000..83a1108 --- /dev/null +++ b/app/src/main/cpp/pdos.c @@ -0,0 +1,173 @@ + +// The authors disclam copyright to this source code + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int new_mode; +static int old_mode; +void printenv() +{ + char **env; + env = environ; + while (env[0]) { + if (strstr(env[0], "PATH=")) { + write(1, env[0], strlen(env[0])); + write(1, "\n", 1); + } + env++; + } +} + +int run(char *cmd, char *arg1) +{ + pid_t pid; + int in; + int out; + int status = -1; + char *args[10]; + args[0] = cmd; + args[1] = arg1; + args[2] = NULL; + + fcntl(STDIN_FILENO, F_SETFL, old_mode); + pid = fork(); + in = dup(0); + out = dup(1); + if (pid == 0) {; + execv(args[0], args); + write(STDOUT_FILENO, "!exe\n", 5); + exit(-1); + } else { + waitpid(pid, &status, 0); + dup2(in, 0); + dup2(out, 1); + fcntl(STDIN_FILENO, F_SETFL, new_mode); + } + + return status; +} + +#define BIN_SIZE 32 * 1024 * 1024 +int main(int argc, char *argv[]) { + int n = 0; + FILE *fp = stdin; + int fd = STDIN_FILENO; + char cmd[1024]; + char b[1024]; + char *prompt = NULL; +#if 0 // amd64 in RAM execution test + /* char assembly[] = {0x48, 0xc7, 0xc0, 0x10, 0x00, 0x00, 0x00, // movq $16, %rax + 0xc3}; // retq + */ // Arm32 + char assembly[] = {0x11, 0x00, 0xa0, 0xe3, // mov r0, #17 + 0x1e, 0xff, 0x2f, 0xe1}; // bx lr + + char *bin; + int ret; + char *err; + long pagesize = sysconf(_SC_PAGESIZE); + long memsize = (BIN_SIZE + pagesize -1) / pagesize * pagesize; + bin = (long)malloc(BIN_SIZE + pagesize - 1) / pagesize * pagesize; + //bin = malloc(pagesize); + memcpy(bin, assembly, sizeof(assembly)); + ret = mprotect(bin, memsize, PROT_EXEC|PROT_READ|PROT_WRITE); + if (ret != 0) { + err = strerror(errno); + write(STDOUT_FILENO, err, strlen(err)); + + } + ret = ((int(*)())bin)(); + snprintf(cmd, 10, "R%ld", ret); + sleep(1); + write(STDOUT_FILENO, cmd, strlen(cmd)); +#endif + + sleep(1); + + if (argc > 1) { + write(STDOUT_FILENO, argv[1], strlen(argv[1])); + } + if (argc > 2) { + write(STDOUT_FILENO, "\n", 1); + write(STDOUT_FILENO, argv[2], strlen(argv[2])); + } + write(STDOUT_FILENO, "\n", 1); + //sleep(2); + + snprintf(b, sizeof(b), argv[1], "bios"); + snprintf(cmd, sizeof(cmd), "%s", b); + if (system(cmd) >= 0) { + sleep(3); + // return 0; + } + + + prompt = "\n*** DEBUG SHELL ****.\nprompt>"; + write(STDOUT_FILENO, prompt, strlen(prompt)); + prompt = NULL; + old_mode = fcntl(STDIN_FILENO, F_GETFL); + new_mode = old_mode | O_NONBLOCK; + fcntl(STDIN_FILENO, F_SETFL, new_mode); + + //printenv(); + + while (1) { + char buf[1024]; + ssize_t l; + int i; + l = read(fd, buf, sizeof(buf)); + if (l > 0) { + write(STDOUT_FILENO, buf, l); + i = 0; + while (i < l) { + if (buf[i] == '\n') { + cmd[n] = '\0'; + if (n > 0) { + if (!strcmp(cmd, "exit")) { + exit(0); + } else if (!strcmp(cmd, "test1")) { + prompt = "\x1b[A\r\x1b[K\x1b[1;32mopened \x1b[1;4;34m%s\x1b[0;1;32m in your browser.\x1b[0m\n\x1b[1;1H"; + write(STDOUT_FILENO, prompt, strlen(prompt)); + } else if (!strcmp(cmd, "bios.exe")) { + snprintf(cmd, sizeof(cmd), argv[1], "bios"); + run(cmd, NULL); + } else if (!strcmp(cmd, "pcomm.exe")) { + snprintf(cmd, sizeof(cmd), argv[1], "pcomm"); + run(cmd, NULL); + } else { + system(cmd); + } + } + + prompt ="prompt>"; + n = 0; + } else if (buf[i] == 0x08) { + buf[n--] = '\0'; + } else { + if (n < (sizeof(cmd) - 2)) { + cmd[n] = buf[i]; + n++; + } else { + n = 0; + } + } + i++; + } + } else { + if (prompt != NULL) { + write(STDOUT_FILENO, prompt, strlen(prompt)); + prompt = NULL; + } + usleep(20000); + } + } + return 0; +} diff --git a/app/src/main/cpp/pdpclib/armeabi-v7a/CMakeLists.txt b/app/src/main/cpp/pdpclib/armeabi-v7a/CMakeLists.txt new file mode 100644 index 0000000..f68b927 --- /dev/null +++ b/app/src/main/cpp/pdpclib/armeabi-v7a/CMakeLists.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.18.1) + +project("pdos_pdandro") +enable_language(C ASM) + +add_library( + pdpclib + STATIC + + stdio.c + string.c + stdlib.c + start.c + time.c + errno.c + assert.c + signal.c + locale.c + ctype.c + math.c + armsupa.asm + __memmgr.c +) + +target_compile_options(pdpclib PRIVATE + $<$:-ffreestanding -fno-builtin -fno-stack-protector -nostdinc -nostdlib -O0 -fno-common -D__UNOPT__ -D__ARM__ -DUSE_MEMMGR -I${CMAKE_CURRENT_SOURCE_DIR}> + $<$:-x assembler-with-cpp -DLINUX=1> +) + diff --git a/app/src/main/cpp/pdpclib/armeabi-v7a/__memmgr.c b/app/src/main/cpp/pdpclib/armeabi-v7a/__memmgr.c new file mode 100644 index 0000000..3a691eb --- /dev/null +++ b/app/src/main/cpp/pdpclib/armeabi-v7a/__memmgr.c @@ -0,0 +1,878 @@ +/*********************************************************************/ +/* */ +/* This Program Written By Paul Edwards. */ +/* Released to the public domain. */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* memmgr - manage memory */ +/* */ +/*********************************************************************/ + +#include "__memmgr.h" + +#include + +MEMMGR __memmgr; + +void memmgrDefaults(MEMMGR *memmgr) +{ + return; +} + +void memmgrInit(MEMMGR *memmgr) +{ + memmgr->start = NULL; + memmgr->startf = NULL; + return; +} + +void memmgrTerm(MEMMGR *memmgr) +{ + return; +} + +/* Supply a block of memory. We make sure this is inserted in + the right spot logically in memory, and since it will be a + free block, we stick it at the front of the list */ +void memmgrSupply(MEMMGR *memmgr, void *buffer, size_t szbuf) +{ + MEMMGRN *p, *l, *b; + + if (((int)buffer % MEMMGR_ALIGN) != 0) + { + szbuf -= (MEMMGR_ALIGN - (int)buffer % MEMMGR_ALIGN); + buffer = (char *)buffer + (MEMMGR_ALIGN - (int)buffer % MEMMGR_ALIGN); + } + + if ((szbuf % MEMMGR_ALIGN) != 0) + { + szbuf -= szbuf % MEMMGR_ALIGN; + } + + p = memmgr->start; + l = NULL; + while ((p != NULL) && ((MEMMGRN *)buffer >= p)) + { + l = p; + p = p->next; + } + + b = (MEMMGRN *)buffer; + + b->prev = l; + b->next = p; + + if (l != NULL) + { + l->next = b; + } + else + { + memmgr->start = b; + } + + if (p != NULL) + { + p->prev = b; + } + + b->fixed = 1; + b->size = szbuf; + b->allocated = 0; + + /* add this to the front of the list */ + b->nextf = memmgr->startf; + if (b->nextf != NULL) + { + b->nextf->prevf = b; + } + b->prevf = NULL; + memmgr->startf = b; +#ifdef __MEMMGR_INTEGRITY + b->eyecheck1 = b->eyecheck2 = 0xa5a5a5a5; + memmgrIntegrity(memmgr); +#endif + return; +} + +void *memmgrAllocate(MEMMGR *memmgr, size_t bytes, int id) +{ + MEMMGRN *p, *n; + size_t oldbytes = bytes; + +#ifdef __MEMMGR_DEBUG + if (memmgrDebug) + { + printf("***allocating size %d\n\n", bytes); + } +#endif +#ifdef __MEMMGR_INTEGRITY + memmgrIntegrity(memmgr); +#endif + /* technically they could have specified a strange free + memory size, like 101, which would disrupt the alignment. + MEMMGR_MINFREE should have compensated for this by ensuring + that it is a multiple of the MEMMGRN alignment */ + bytes += MEMMGRN_SZ; + if ((bytes % MEMMGR_MINFRTOT) != 0) + { + bytes = ((bytes / MEMMGR_MINFRTOT) + 1) + * MEMMGR_MINFRTOT; + } + +#ifdef __MEMMGR_DEBUG + if (memmgrDebug) + { + printf("***converted to %d\n\n", bytes); + } +#endif + /* if they have exceeded the limits of the data type, + bail out now. */ + if (bytes < oldbytes) + { + return (NULL); + } + + p = memmgr->startf; + + while (p != NULL) + { + if (p->size >= bytes) + { + /* The free chain should never have something allocated. + If it does, let's just crash so the user can get a + call stack rather than have their data randomly + corrupted. */ + if (p->allocated) + { +#if MEMMGR_CRASH + *(char *)0 = 0; +#endif + exit(EXIT_FAILURE); + } + /* we don't need the whole block, so construct a new + free node */ + if ((p->size - bytes) >= MEMMGR_MINFRTOT) + { + n = (MEMMGRN *)((char *)p + bytes); + n->next = p->next; + if (n->next != NULL) + { + n->next->prev = n; + } + n->prev = p; + p->next = n; + n->fixed = 0; + n->size = p->size - bytes; + n->allocated = 0; +#ifdef __MEMMGR_INTEGRITY + n->eyecheck1 = n->eyecheck2 = 0xa5a5a5a5; +#endif + p->size = bytes; + + /* remove p this from the free chain and + replace with n */ + n->nextf = p->nextf; + n->prevf = p->prevf; + if (n->nextf != NULL) + { + n->nextf->prevf = n; + } + if (n->prevf != NULL) + { + n->prevf->nextf = n; + } + /* if the previous entry is NULL, then we must be + the first in the queue. If we're not, crash */ + else if (memmgr->startf != p) + { +#if MEMMGR_CRASH + *(char *)0 = 0; +#endif + exit(EXIT_FAILURE); + } + else + { + memmgr->startf = n; + } + } + /* otherwise we're not creating a new node, so just + remove this entry from the free chain */ + else + { + if (p->nextf != NULL) + { + p->nextf->prevf = p->prevf; + } + if (p->prevf != NULL) + { + p->prevf->nextf = p->nextf; + } + /* if the previous entry is NULL, then we must be + the first in the queue. If we're not, crash */ + else if (memmgr->startf != p) + { +#if MEMMGR_CRASH + *(char *)0 = 0; +#endif + exit(EXIT_FAILURE); + } + else + { + memmgr->startf = p->nextf; + } + } + /* for safety, don't keep the old free pointer chain + hanging around */ + p->nextf = NULL; + p->prevf = NULL; + + p->allocated = 0x5a5a; + p->id = id; + break; + } + p = p->nextf; + } + if (p == NULL) + { +#ifdef __MEMMGR_DEBUG + if (memmgrDebug) + { + printf("***alloc returning NULL!\n\n"); + } +#endif + return (p); + } + else + { + size_t *q; + + q = (size_t *)((char *)p + MEMMGRN_SZ); + *(q - 1) = oldbytes; +#ifdef __MEMMGR_DEBUG + if (memmgrDebug) + { + printf("***alloc returning %p\n\n", p); + } +#endif +#ifdef __MEMMGR_INTEGRITY + memmgrIntegrity(memmgr); +#endif + return ((char *)p + MEMMGRN_SZ); + } +} + +void memmgrFree(MEMMGR *memmgr, void *ptr) +{ + MEMMGRN *p, *n, *l; + int combprev = 0; /* did we combine with the previous? */ + int combnext = 0; /* are we combining with the next node? */ + + p = (MEMMGRN *)((char *)ptr - MEMMGRN_SZ); + +#ifdef __MEMMGR_DEBUG + if (memmgrDebug) + { + printf("***freeing size %d block %p\n\n", p->size, p); + } +#endif +#ifdef __MEMMGR_INTEGRITY + memmgrIntegrity(memmgr); +#endif + /* If they try to free a bit of memory that isn't remotely + what it's meant to be, just crash so that they get a + call stack */ + if (p->allocated != 0x5a5a) + { +#if MEMMGR_CRASH + *(char *)0 = 0; +#endif + exit(EXIT_FAILURE); + } + + p->allocated = 0; + /* let's hope we're in the middle of a valid chain */ + l = p->prev; + n = p->next; + + /* If the previous block is also free, just expand it's size + without any further fuss */ + if (!p->fixed && (l != NULL) && !l->allocated) + { + l->size += p->size; + l->next = p->next; + if (l->next != NULL) + { + l->next->prev = l; + } + combprev = 1; + } + /* is the next one up combinable? */ + if ((n != NULL) && !n->allocated && !n->fixed) + { + combnext = 1; + } + + /* We can have a fuss-free combination if the previous node + was not combined */ + if (combnext && !combprev) + { + p->size += n->size; + p->next = n->next; + if (p->next != NULL) + { + p->next->prev = p; + } + p->nextf = n->nextf; + if (p->nextf != NULL) + { + p->nextf->prevf = p; + } + p->prevf = n->prevf; + if (p->prevf != NULL) + { + p->prevf->nextf = p; + } + else if (memmgr->startf != n) + { +#if MEMMGR_CRASH + *(char *)0 = 0; +#endif + exit(EXIT_FAILURE); + } + else + { + memmgr->startf = p; + } + } + + /* this is the hairy situation. We're combining two existing + free blocks into one. While the blocks themselves are + contiguous, the two components are at random spots in the + free memory chain, e.g. they might be B and E in + A <-> B <-> C <-> D <-> E <-> F + So what's the obvious thing to do? Give it up and become a + Buddhist monk! The less obvious thing is to keep B in its + spot, just with an enhanced size, then get D and F to link + together. The special case of the two nodes actually already + being linked together by happy coincidence doesn't need + special handling. If it does, that monastery looks more + and more appealing every day. Do you reckon Buddhist monks + talk about giving it all up and doing C programming? Once + the node E is eliminated, B can be expanded. */ + + else if (combnext && combprev) + { + if (n->nextf != NULL) + { + n->nextf->prevf = n->prevf; + } + if (n->prevf != NULL) + { + n->prevf->nextf = n->nextf; + } + else if (memmgr->startf != n) + { +#if MEMMGR_CRASH + *(char *)0 = 0; +#endif + exit(EXIT_FAILURE); + } + else + { + memmgr->startf = n->nextf; + n->nextf->prevf = NULL; + } + + /* Ok, the free memory has been taken care of, now we go + back to the newly combined node and combine it with + this one. */ + l->size += n->size; + l->next = n->next; + if (l->next != NULL) + { + l->next->prev = l; + } + + /* That wasn't so hairy after all */ + /* Actually it was */ + } + + if (combnext) + { +#ifdef __MEMMGR_INTEGRITY + n->eyecheck1 = n->eyecheck2 = 0; +#endif + /* for safety */ + n->nextf = NULL; + n->prevf = NULL; + } + if (combprev) + { +#ifdef __MEMMGR_INTEGRITY + p->eyecheck1 = p->eyecheck2 = 0; +#endif + /* for safety */ + p->nextf = NULL; + p->prevf = NULL; + } + + /* If we didn't do any combination, then add this new node to + the front of the free chain */ + if (!combprev && !combnext) + { + p->nextf = memmgr->startf; + memmgr->startf = p; + p->prevf = NULL; + if (p->nextf != NULL) + { + p->nextf->prevf = p; + } + } + +#ifdef __MEMMGR_DEBUG + if (memmgrDebug) + { + printf("***free returning\n\n"); + } +#endif +#ifdef __MEMMGR_INTEGRITY + memmgrIntegrity(memmgr); +#endif + return; +} + +void memmgrFreeId(MEMMGR *memmgr, int id) +{ + MEMMGRN *p, *l; + + p = memmgr->start; + l = NULL; + +#ifdef __MEMMGR_INTEGRITY + memmgrIntegrity(memmgr); +#endif + while (p != NULL) + { + if ((p->id == id) && p->allocated) + { + /* skip past the MEMMGRN */ + memmgrFree(memmgr, (char *)p + MEMMGRN_SZ); + + /* It is possible that the p node has been invalidated + now, because of combination with the previous node. + So we go back to the previous pointer and try again. + This time it shouldn't find the node allocated. */ + if (l != NULL) + { + p = l; + } + } + l = p; + p = p->next; + } +#ifdef __MEMMGR_INTEGRITY + memmgrIntegrity(memmgr); +#endif + return; +} + +/* find the largest block of memory available */ +size_t memmgrMaxSize(MEMMGR *memmgr) +{ + MEMMGRN *p; + size_t max = 0; + + p = memmgr->startf; + + while (p != NULL) + { + if (p->size > max) + { + max = p->size; + } + p = p->nextf; + } + if (max != 0) + { + max -= MEMMGRN_SZ; + } + return (max); +} + +/* find total amount of memory available */ +size_t memmgrTotSize(MEMMGR *memmgr) +{ + MEMMGRN *p; + size_t tot = 0; + + p = memmgr->startf; + + while (p != NULL) + { + if (p->size != 0) + { + tot += (p->size - MEMMGRN_SZ); + } + p = p->next; + } + return (tot); +} + +int memmgrDebug = 0; +int memmgrDebug2 = 0; + + +#ifdef __MEMMGR_INTEGRITY +/* do an integrity check */ +void memmgrIntegrity(MEMMGR *memmgr) +{ + MEMMGRN *p; + size_t max = 0; + +#ifdef __MEMMGR_DEBUG +#if 0 + if (memmgrDebug2 != 0) + { + memmgrDebug2++; + if (memmgrDebug2 == 22362000) + { + memmgrDebug = 1; + } + } +#endif + if (memmgrDebug) + { + printf("%d integrity checking all nodes\n\n", memmgrDebug2); + } +#endif + p = memmgr->start; + + while (p != NULL) + { +#ifdef __MEMMGR_DEBUG + if (memmgrDebug) + { + printf("p is %p\n\n", p); + printf("ec1 %x, ec2 %x\n\n", + p->eyecheck1, p->eyecheck2); + printf("size %d, alloc %x\n\n", + p->size, p->allocated); + printf("forward is %p, back is %p\n\n", + p->next, p->prev); + printf("forwardf is %p, backf is %p\n\n", + p->nextf, p->prevf); + } +#endif + if ((p->eyecheck1 != 0xa5a5a5a5) || (p->eyecheck2 != 0xa5a5a5a5)) + { + *(char *)0 = '\0'; /* try to invoke crash */ + exit(EXIT_FAILURE); + } + if ((p->next != NULL) && (p->next->prev != p)) + { + *(char *)0 = '\0'; /* try to invoke crash */ + exit(EXIT_FAILURE); + } + p = p->next; + } +#ifdef __MEMMGR_DEBUG + if (memmgrDebug) + { + printf("integrity checking free chain\n\n"); + } +#endif + p = memmgr->startf; + if ((p != NULL) && (p->prevf != NULL)) + { + *(char *)0 = '\0'; /* try to invoke crash */ + exit(EXIT_FAILURE); + } + + while (p != NULL) + { +#ifdef __MEMMGR_DEBUG + if (memmgrDebug) + { + printf("p is %p\n\n", p); + printf("ec1 %x, ec2 %x\n\n", + p->eyecheck1, p->eyecheck2); + printf("size %d, alloc %x\n\n", + p->size, p->allocated); + printf("forwardf is %p, backf is %p\n\n", + p->nextf, p->prevf); + } +#endif + if ((p->eyecheck1 != 0xa5a5a5a5) || (p->eyecheck2 != 0xa5a5a5a5) + || p->allocated) + { + *(char *)0 = '\0'; /* try to invoke crash */ + exit(EXIT_FAILURE); + } + if ((p->nextf != NULL) && (p->nextf->prevf != p)) + { + *(char *)0 = '\0'; /* try to invoke crash */ + exit(EXIT_FAILURE); + } + p = p->nextf; + } +#ifdef __MEMMGR_DEBUG + if (memmgrDebug) + { + printf("finished integrity checking\n\n"); + } +#endif + return; +} +#endif + +/* resize a memory block */ +/* note that the size in the control block is the + size of available data plus the control block */ +int memmgrRealloc(MEMMGR *memmgr, void *ptr, size_t newsize) +{ + MEMMGRN *p, *n, *z; + size_t oldbytes = newsize; + +#ifdef __MEMMGR_DEBUG + if (memmgrDebug) + { + printf("***reallocating %p\n\n", ptr); + } +#endif +#ifdef __MEMMGR_INTEGRITY + memmgrIntegrity(memmgr); +#endif + newsize += MEMMGRN_SZ; + if ((newsize % MEMMGR_MINFRTOT) != 0) + { + newsize = ((newsize / MEMMGR_MINFRTOT) + 1) + * MEMMGR_MINFRTOT; + } + + /* if they have exceeded the limits of the data type, + bail out now. */ + if (newsize < oldbytes) + { + return (-1); + } + + /* if they are passing a NULL pointer, bail out also */ + if (ptr == NULL) + { + return (-1); + } + + + p = (MEMMGRN *)((char *)ptr - MEMMGRN_SZ); + + /* If they try to manipulate a bit of memory that isn't remotely + what it's meant to be, just crash so that they get a + call stack */ + if (p->allocated != 0x5a5a) + { +#if MEMMGR_CRASH + *(char *)0 = 0; +#endif + exit(EXIT_FAILURE); + } + + /* let's hope we're in the middle of a valid chain */ + + /* Now we have 3 distinct scenarios. + 1. They are asking for a reduction in size, and there's room + to create a new (free) block of memory. + so newsize + minfree + cb <= p->size + 2. They're asking for a reduction in size, but there's not + enough room for a new control block. + so newsize < p->size but newsize + minfree + cb > p->size + 3. They're asking for an expansion of memory, and the next + block of memory up is able to satisfy that request. + so newsize > p->size + */ + + /* are they asking for an expansion? */ + if (p->size < newsize) + { + n = p->next; + if ((n != NULL) + && !n->allocated + && !n->fixed + && ((n->size + p->size) >= newsize)) + { + /* ok, we can satisfy this request. Let's see if we + have enough room to insert a new node. */ + if ((p->size + n->size) < (newsize + MEMMGR_MINFRTOT)) + { + /* not enough room for a new node - just combine + and be done */ + if (n->nextf != NULL) + { + n->nextf->prevf = n->prevf; + } + if (n->prevf != NULL) + { + n->prevf->nextf = n->nextf; + } + else if (memmgr->startf != n) + { +#if MEMMGR_CRASH + *(char *)0 = 0; +#endif + exit(EXIT_FAILURE); + } + else + { + memmgr->startf = n->nextf; + } + /* Ok, free chain has been taken care of, now let's get + rid of that next node by combining */ + p->size += n->size; + p->next = n->next; + if (p->next != NULL) + { + p->next->prev = p; + } + } + else + { + /* we have room for a new node - so, construct the new + node first */ + z = (MEMMGRN *)((char *)p + newsize); + z->allocated = 0; + z->fixed = 0; +#ifdef __MEMMGR_INTEGRITY + z->eyecheck1 = z->eyecheck2 = 0xa5a5a5a5; +#endif + z->size = p->size + n->size - newsize; + z->prev = p; + p->next = z; + z->next = n->next; + if (z->next != NULL) + { + z->next->prev = z; + } + z->nextf = n->nextf; + if (z->nextf != NULL) + { + z->nextf->prevf = z; + } + z->prevf = n->prevf; + if (z->prevf != NULL) + { + z->prevf->nextf = z; + } + else if (memmgr->startf != n) + { +#if MEMMGR_CRASH + *(char *)0 = 0; +#endif + exit(EXIT_FAILURE); + } + else + { + memmgr->startf = z; + } + /* n node is now irrelevant. adjust p's size */ + p->size = newsize; + } + } + /* we don't have enough room to satisfy this expansion request */ + else + { + return (-1); + } + } + /* It's not an expansion, but is there enough room to insert a + new node? */ + else if ((newsize + MEMMGR_MINFRTOT) <= p->size) + { + /* yep, let's insert new node */ + n = (MEMMGRN *)((char *)p + newsize); + n->next = p->next; + if (n->next != NULL) + { + n->next->prev = n; + } + n->prev = p; + p->next = n; + n->fixed = 0; + n->size = p->size - newsize; + n->allocated = 0; +#ifdef __MEMMGR_INTEGRITY + n->eyecheck1 = n->eyecheck2 = 0xa5a5a5a5; +#endif + p->size = newsize; + + /* combine with next block if possible */ + z = n->next; + if ((z != NULL) && !z->allocated && !z->fixed) + { +#ifdef __MEMMGR_INTEGRITY + z->eyecheck1 = z->eyecheck2 = 0; +#endif + n->size += z->size; + n->next = z->next; + if (n->next != NULL) + { + n->next->prev = n; + } + n->nextf = z->nextf; + if (n->nextf != NULL) + { + n->nextf->prevf = n; + } + n->prevf = z->prevf; + if (n->prevf != NULL) + { + n->prevf->nextf = n; + } + else if (memmgr->startf != z) + { +#if MEMMGR_CRASH + *(char *)0 = 0; +#endif + exit(EXIT_FAILURE); + } + else + { + memmgr->startf = n; + } + } + /* otherwise add it to the start of the free chain */ + else + { + n->nextf = memmgr->startf; + if (n->nextf != NULL) + { + n->nextf->prevf = n; + } + n->prevf = NULL; + memmgr->startf = n; + } + } + /* Otherwise they are requesting a minor resize downwards, + and we just need to acknowledge it, not actually do + anything. */ + +#ifdef __MEMMGR_DEBUG + if (memmgrDebug) + { + printf("***returning from realloc\n\n"); + } +#endif +#ifdef __MEMMGR_INTEGRITY + memmgrIntegrity(memmgr); +#endif + + /* Keep track of the new size */ + { + size_t *q; + + q = (size_t *)((char *)p + MEMMGRN_SZ); + *(q - 1) = oldbytes; + } + return (0); +} diff --git a/app/src/main/cpp/pdpclib/armeabi-v7a/__memmgr.h b/app/src/main/cpp/pdpclib/armeabi-v7a/__memmgr.h new file mode 100644 index 0000000..d0da86d --- /dev/null +++ b/app/src/main/cpp/pdpclib/armeabi-v7a/__memmgr.h @@ -0,0 +1,155 @@ +/*********************************************************************/ +/* */ +/* This Program Written By Paul Edwards. */ +/* Released to the public domain. */ +/* */ +/*********************************************************************/ + +#if 0 + +Example usage: + +MEMMGR memmgr; /* define an instance of the object */ +char *ptr; /* scratch pointer */ + + +memmgrDefaults(&memmgr); /* always called to set up object defaults */ +memmgrInit(&memmgr); /* Initialize object */ +memmgrSupply(&memmmgr, (void *)0x04100000, 32 * 1024 * 1024); + /* Supply the object with a buffer that starts at the 65 MB location + and is 32 MB in size. This can be called multiple times to give + memmgr multiple blocks of memory to manage */ +ptr = memmgrAllocate(&memmgr, 500, 0); + /* allocate 500 bytes of memory. 0 is an "optional" ID if you want + to group memory blocks. ptr will be NULL if memory couldn't be + obtained */ +memmgrFree(&memmgr, ptr); /* free memory associated with this + pointer */ +memmgrTerm(&memmgr); /* Terminate object */ + + +Other functions: + +memmgrFreeID(&memmgr, 5); /* free all memory with an ID of 5 */ +printf("largest block of memory available is %d\n", + memmgrMaxSize(&memmgr)); +printf("total amount of available memory is %d\n", + memmgrTotSize(&memmgr)); +memmgrIntegrity(&memmgr); /* check any memory chain corruption */ +memmgrRealloc(&memmgr, ptr, 1000); /* resize the object to be 1000 + bytes. Returns 0 if successful, negative if the request failed for + any reason. */ + +#endif + + +#ifndef MEMMGR_INCLUDED +#define MEMMGR_INCLUDED + +#include + +/* Do you want memmgr to perform lots of integrity checks? */ +/* Note that this will slow down the system, but it doesn't + print out anything or change the functionality of your + application. */ +/* #define __MEMMGR_INTEGRITY 1 */ + +/* Do you want lots of debugging output? */ +/* Note that you still need to set the memmgrDebug variable to 1 + before it is actually activated */ +/* #define __MEMMGR_DEBUG 1 */ + +typedef struct memmgrn { +#ifdef __MEMMGR_INTEGRITY + int eyecheck1; +#endif + struct memmgrn *next; + struct memmgrn *prev; + struct memmgrn *nextf; + struct memmgrn *prevf; + int fixed; + size_t size; /* size of memory available to user */ + int allocated; + int id; +#ifdef __MEMMGR_INTEGRITY + int eyecheck2; +#endif + size_t filler; /* we add this so that *(p - size_t) is writable */ +} MEMMGRN; + +typedef struct { + MEMMGRN *start; + MEMMGRN *startf; +} MEMMGR; + +/* What boundary we want the memmgr control block to be a multiple of */ +#define MEMMGR_ALIGN 8 + +#define MEMMGRN_SZ \ + ((sizeof(MEMMGRN) % MEMMGR_ALIGN == 0) ? \ + sizeof(MEMMGRN) : \ + ((sizeof(MEMMGRN) / MEMMGR_ALIGN + 1) * MEMMGR_ALIGN)) + +/* Let's make sure that the minimum free data area is at least + as big as the node itself, so that we don't have more than + 50% of the available memory used up by control blocks due + to fragmentation */ +#define MEMMGR_MINFREE MEMMGRN_SZ + +/* total size of the minimum free area, including room for the + control block */ +#define MEMMGR_MINFRTOT (MEMMGRN_SZ + MEMMGR_MINFREE) + +/* do you want to crash whenever an integrity problem arises? */ +#ifndef MEMMGR_CRASH +#define MEMMGR_CRASH 1 +#endif + +#ifdef NICEASM +#define memmgrDefaults mmDef +#define memmgrInit mmInit +#define memmgrTerm mmTerm +#define memmgrSupply mmSupply +#define memmgrAllocate mmAlloc +#define memmgrFree mmFree +#define memmgrFreeId mmFreeId +#define memmgrMaxSize mmMaxSiz +#define memmgrTotSize mmTotSiz +#define memmgrIntegrity mmInteg +#define memmgrRealloc mmRealoc +#define memmgrDebug mmDebug +#define memmgrDebug2 mmDbg2 +#else +#define memmgrDefaults __mmDef +#define memmgrInit __mmInit +#define memmgrTerm __mmTerm +#define memmgrSupply __mmSupply +#define memmgrAllocate __mmAlloc +#define memmgrFree __mmFree +#define memmgrFreeId __mmFId +#define memmgrMaxSize __mmMaxSize +#define memmgrTotSize __mmTotSize +#define memmgrIntegrity __mmIntegrity +#define memmgrRealloc __mmRealloc +#define memmgrDebug __mmDebug +#define memmgrDebug2 __mmDbg2 +#endif + +void memmgrDefaults(MEMMGR *memmgr); +void memmgrInit(MEMMGR *memmgr); +void memmgrTerm(MEMMGR *memmgr); +void memmgrSupply(MEMMGR *memmgr, void *buffer, size_t szbuf); +void *memmgrAllocate(MEMMGR *memmgr, size_t bytes, int id); +void memmgrFree(MEMMGR *memmgr, void *ptr); +void memmgrFreeId(MEMMGR *memmgr, int id); +size_t memmgrMaxSize(MEMMGR *memmgr); +size_t memmgrTotSize(MEMMGR *memmgr); +void memmgrIntegrity(MEMMGR *memmgr); +int memmgrRealloc(MEMMGR *memmgr, void *ptr, size_t newsize); + +extern int memmgrDebug; +extern int memmgrDebug2; + +extern MEMMGR __memmgr; + +#endif diff --git a/app/src/main/cpp/pdpclib/armeabi-v7a/armsupa.asm b/app/src/main/cpp/pdpclib/armeabi-v7a/armsupa.asm new file mode 100644 index 0000000..09ba5d6 --- /dev/null +++ b/app/src/main/cpp/pdpclib/armeabi-v7a/armsupa.asm @@ -0,0 +1,451 @@ +# This code was taken from the public domain SubC +# Modified by Paul Edwards +# All changes remain public domain + +# Calling conventions: r0,r1,r2,stack, return in r0 +# 64-bit values in r0/r1, r2/r3, never in r1/r2 +# (observe register alignment!) +# System call: r7=call#, arguments r0,r1,r2,r3,r4,r5 +# carry indicates error, +# return/error value in r0 + +# https://github.com/aligrudi/neatlibc/blob/master/arm/syscall.s +# https://gist.github.com/yamnikov-oleg/454f48c3c45b735631f2 +# https://syscalls.w3challs.com/?arch=arm_strong + + .text + .align 2 +# int setjmp(jmp_buf env); + + .globl __Ysetjmp + .globl ___Ysetjmp + .type __Ysetjmp, %function + .align 2 +__Ysetjmp: +___Ysetjmp: +# ldr r1,[sp] @ env + mov r1,r0 + mov r2,sp +# add r2,r2,#4 +# str sp,[r1] + str r2,[r1] + str r11,[r1,#4] @ fp + str lr,[r1,#8] @ r14 + str r4,[r1,#12] + str r5,[r1,#16] + str r6,[r1,#20] + str r7,[r1,#24] + str r8,[r1,#28] + str r9,[r1,#32] @ rfp + str r10,[r1,#36] @ sl + mov r0,#0 + mov pc,lr + +# void longjmp(jmp_buf env, int v); + + .globl longjmp + .globl _longjmp + .type longjmp, %function + .align 2 +longjmp: +_longjmp: +# ldr r0,[sp,#4] @ v + mov r2,r0 + mov r0,r1 + + cmp r0,#0 + moveq r0,#1 + +# ldr r1,[sp] @ env + mov r1,r2 + + ldr sp,[r1] + ldr r11,[r1,#4] @ fp + ldr lr,[r1,#8] + ldr r4,[r1,#12] + ldr r5,[r1,#16] + ldr r6,[r1,#20] + ldr r7,[r1,#24] + ldr r8,[r1,#28] + ldr r9,[r1,#32] + ldr r10,[r1,#36] + mov pc,lr + +.if LINUX +# void _exita(int rc); + + .globl __exita + .globl ___exita + .type __exita, %function + .align 2 +__exita: +___exita: + stmfd sp!,{lr} +# ldr r0,[sp,#4] @ rc + mov r7,#1 @ SYS_exit + swi 0 + ldmia sp!,{pc} + +# int ___write(int fd, void *buf, int len); + + .globl __write + .globl ___write + .type __write, %function + .align 2 +__write: +___write: + stmfd sp!,{lr} +# ldr r2,[sp,#12] @ len +# ldr r1,[sp,#8] @ buf +# ldr r0,[sp,#4] @ fd + mov r7,#4 @ SYS_write + swi 0 +wrtok: ldmia sp!,{pc} + +# int ___read(int fd, void *buf, int len); + + .globl __read + .globl ___read + .type __read, %function + .align 2 +__read: +___read: + stmfd sp!,{lr} +# ldr r2,[sp,#12] @ len +# ldr r1,[sp,#8] @ buf +# ldr r0,[sp,#4] @ fd + mov r7,#3 @ SYS_read + swi 0 +redok: ldmia sp!,{pc} + +# int ___seek(int fd, int pos, int how); + + .globl __seek + .globl ___seek + .type __seek, %function + .align 2 +__seek: +___seek: + stmfd sp!,{lr} +# ldr r2,[sp,#12] @ how +# ldr r1,[sp,#8] @ off_t +# ldr r0,[sp,#4] @ fd + mov r7,#19 + swi 0 +lskok: + ldmia sp!,{pc} + +# int __creat(char *path, int mode); + + .globl __creat + .globl ___creat + .type __creat, %function + .align 2 +__creat: +___creat: + stmfd sp!,{lr} +# ldr r1,[sp,#8] @ mode + mov r1,#0x1A4 @ 0644 +# ldr r0,[sp,#4] @ path + mov r7,#8 @ SYS_creat + swi 0 +crtok: ldmia sp!,{pc} + +# int _open(char *path, int flags); + + .globl __open + .globl ___open + .type __open, %function + .align 2 +__open: +___open: + stmfd sp!,{lr} +# mov r2,#0x1A4 @ 0644 +# ldr r1,[sp,#8] @ flags +# ldr r0,[sp,#4] @ path + mov r7,#5 @ SYS_open + swi 0 +opnok: ldmia sp!,{pc} + +# int _close(int fd); + + .globl __close + .globl ___close + .type __close, %function + .align 2 +__close: +___close: + stmfd sp!,{lr} +# ldr r0,[sp,#4] @ fd + mov r7,#6 @ SYS_close + swi 0 +clsok: ldmia sp!,{pc} + +# int ___remove(char *path); + + .globl __remove + .globl ___remove + .type __remove, %function + .align 2 +__remove: +___remove: + stmfd sp!,{lr} +# ldr r0,[sp,#4] @ path + mov r7,#10 @ SYS_unlink + swi 0 +unlok: ldmia sp!,{pc} + +# int ___rename(char *old, char *new); + + .globl __rename + .globl ___rename + .type __rename, %function + .align 2 +__rename: +___rename: + stmfd sp!,{lr} +# ldr r1,[sp,#8] @ new +# ldr r0,[sp,#4] @ old + mov r7,#0x26 @ SYS_rename + swi 0 +renok: ldmia sp!,{pc} + +# int __time(void); + + .globl __time + .globl ___time + .type __time, %function + .align 2 +__time: +___time: + stmfd sp!,{lr} + sub sp,sp,#16 @ struct timespec + mov r1,sp + mov r0,#0 @ CLOCK_REALTIME + ldr r7,=0x107 @ SYS_clock_gettime + swi 0 +timok: ldr r0,[sp] + add sp,sp,#16 + ldmia sp!,{pc} + +# int ___mprotect(const void *buf, size_t len, int prot); + + .globl __mprotect + .globl ___mprotect + .type __mprotect, %function + .align 2 +__mprotect: +___mprotect: + stmfd sp!,{lr} +# ldr r2,[sp,#12] @ prot +# ldr r1,[sp,#8] @ len +# ldr r0,[sp,#4] @ buf + mov r7,#125 @ SYS_mprotect + swi 0 +mpok: ldmia sp!,{pc} + +# int ___getdents(unsigned int fd, struct linux_dirent *dirent, int count); + + .globl __getdents + .globl ___getdents + .type __getdents, %function + .align 2 +__getdents: +___getdents: + stmfd sp!,{lr} +# ldr r2,[sp,#12] @ count +# ldr r1,[sp,#8] @ dirent +# ldr r0,[sp,#4] @ fd + mov r7,#141 @ SYS_getdents + swi 0 +gdok: ldmia sp!,{pc} + +# int ___ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); + + .globl __ioctl + .globl ___ioctl + .type __ioctl, %function + .align 2 +__ioctl: +___ioctl: + stmfd sp!,{lr} +# ldr r2,[sp,#12] @ arg +# ldr r1,[sp,#8] @ cmd +# ldr r0,[sp,#4] @ fd + mov r7,#54 @ SYS_ioctl + swi 0 +iocok: ldmia sp!,{pc} + +# int ___chdir(const char *filename); + + .globl __chdir + .globl ___chdir + .type __chdir, %function + .align 2 +__chdir: +___chdir: + stmfd sp!,{lr} +# ldr r0,[sp,#4] @ filename + mov r7,#12 @ SYS_chdir + swi 0 +cdok: ldmia sp!,{pc} + +# int ___mkdir(const char *pathname, unsigned int mode); + + .globl __mkdir + .globl ___mkdir + .type __mkdir, %function + .align 2 +__mkdir: +___mkdir: + stmfd sp!,{lr} +# ldr r1,[sp,#8] @ mode +# ldr r0,[sp,#4] @ pathname + mov r7,#39 @ SYS_mkdir + swi 0 +mdok: ldmia sp!,{pc} + +# int ___rmdir(const char *pathname); + + .globl __rmdir + .globl ___rmdir + .type __rmdir, %function + .align 2 +__rmdir: +___rmdir: + stmfd sp!,{lr} +# ldr r0,[sp,#4] @ pathname + mov r7,#40 @ SYS_rmdir + swi 0 +rdok: ldmia sp!,{pc} + +.endif + + +# This function is required by GCC but isn't used for anything + .globl __main + .globl ___main +__main: +___main: + mov pc, lr + + +# unsigned integer divide +# inner loop code taken from http://me.henri.net/fp-div.html +# in: r0 = num, r1 = den +# out: r0 = quot, r1 = rem + + .globl __udivsi3 + .globl ___udivsi3 + .type __udivsi3, %function + .globl __aeabi_uidiv + .type __aeabi_uidiv, %function + .align 2 +__udivsi3: +___udivsi3: +__aeabi_uidiv: + rsb r2,r1,#0 + mov r1,#0 + adds r0,r0,r0 + .rept 32 + adcs r1,r2,r1,lsl #1 + subcc r1,r1,r2 + adcs r0,r0,r0 + .endr + mov pc,lr + +# signed integer divide +# in: r0 = num, r1 = den +# out: r0 = quot + + .globl __divsi3 + .globl ___divsi3 + .type __divsi3, %function + .globl __aeabi_idiv + .type __aeabi_idiv, %function + .align 2 +__divsi3: +___divsi3: +__aeabi_idiv: + stmfd sp!,{lr} + eor r3,r0,r1 @ r3 = sign +# asr r3,r3,#31 + mov r3,r3,asr#31 + cmp r1,#0 + beq divz + rsbmi r1,r1,#0 + cmp r0,#0 + rsbmi r0,r0,#0 + bl ___udivsi3 + cmp r3,#0 + rsbne r0,r0,#0 + ldmia sp!,{pc} +divz: mov r0,#8 @ SIGFPE + stmfd sp!,{r0} + mov r0,#1 + stmfd sp!,{r0} +# bl Craise + mov r0,#0 @ if raise(SIGFPE) failed, return 0 + ldmia sp!,{pc} + +# signed integer modulo +# in: r0 = num, r1 = den +# out: r0 = rem + + .globl __modsi3 + .globl ___modsi3 + .type __modsi3, %function + .globl __aeabi_idivmod + .type __aeabi_idivmod, %function + .align 2 +__modsi3: +___modsi3: +__aeabi_idivmod: + stmfd sp!,{r4,lr} +# asr r4,r0,#31 @ r4 = sign + mov r4,r0,asr#31 + bl ___divsi3 + mov r0,r1 + cmp r4,#0 + rsbne r0,r0,#0 + ldmia sp!,{r4,pc} + +# unsigned integer modulo +# in: r0 = num, r1 = den +# out: r0 = rem + + .globl __umodsi3 + .globl ___umodsi3 + .type __umodsi3, %function + .globl __aeabi_uidivmod + .type __aeabi_uidivmod, %function + .align 2 +__umodsi3: +___umodsi3: +__aeabi_uidivmod: + stmfd sp!,{lr} + bl ___udivsi3 + mov r0,r1 + ldmia sp!,{pc} + + + .globl __aeabi_memcpy8 + .type __aeabi_memcpy8, %function + .globl __aeabi_memcpy4 + .type __aeabi_memcpy4, %function + .globl __aeabi_memcpy + .type __aeabi_memcpy, %function + .align 2 +__aeabi_memcpy8: +__aeabi_memcpy4: +__aeabi_memcpy: +3: cmp r2, #0 + beq 2f + adds r2, r1, r2 +1: ldrb r3, [r1] + adds r1, r1, #1 + strb r3, [r0] + adds r0, r0, #1 + cmp r1, r2 + bne 1b +2: bx lr diff --git a/app/src/main/cpp/pdpclib/armeabi-v7a/assert.c b/app/src/main/cpp/pdpclib/armeabi-v7a/assert.c new file mode 100644 index 0000000..6d60c15 --- /dev/null +++ b/app/src/main/cpp/pdpclib/armeabi-v7a/assert.c @@ -0,0 +1,24 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* assert.c - implementation of stuff in assert.h */ +/* */ +/*********************************************************************/ + +#include "assert.h" +#include "stdio.h" +#include "stdlib.h" +#include "stddef.h" + +__PDPCLIB_API__ int _assert(char *x, char *y, int z) +{ + fprintf(__stderr, "assertion failed for statement %s in " + "file %s on line %d\n", x, y, z); + abort(); + return (0); +} diff --git a/app/src/main/cpp/pdpclib/armeabi-v7a/assert.h b/app/src/main/cpp/pdpclib/armeabi-v7a/assert.h new file mode 100644 index 0000000..ae3495b --- /dev/null +++ b/app/src/main/cpp/pdpclib/armeabi-v7a/assert.h @@ -0,0 +1,33 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* assert.h - assert header file. */ +/* */ +/*********************************************************************/ + +#ifndef __ASSERT_INCLUDED +#define __ASSERT_INCLUDED + +int _assert(char *x, char *y, int z); + +#ifdef NDEBUG +#define assert(ignore) (0) +#else +#define assert(x) (x) ? (0) : \ + _assert(#x, __FILE__, __LINE__) +#endif + +#if defined(__PDOSGEN__) +#include <__os.h> + +#define _assert __os->_assert + +#endif + + +#endif diff --git a/app/src/main/cpp/pdpclib/armeabi-v7a/ctype.c b/app/src/main/cpp/pdpclib/armeabi-v7a/ctype.c new file mode 100644 index 0000000..442edc4 --- /dev/null +++ b/app/src/main/cpp/pdpclib/armeabi-v7a/ctype.c @@ -0,0 +1,1641 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* ctype.c - implementation of stuff in ctype.h */ +/* */ +/*********************************************************************/ + +#include "stddef.h" + +#if !defined(__MVS__) && !defined(__CMS__) && !defined(__VSE__) +static unsigned short __isbufR[257] = { + 0x0000U, /* EOF */ + 0x0004U, /* NUL */ + 0x0004U, /* 01 */ + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0104U, + 0x0104U, + 0x0104U, + 0x0104U, + 0x0104U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0140U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x0459U, + 0x0459U, + 0x0459U, + 0x0459U, + 0x0459U, + 0x0459U, + 0x0459U, + 0x0459U, + 0x0459U, + 0x0459U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x0653U, + 0x0653U, + 0x0653U, + 0x0653U, + 0x0653U, + 0x0653U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x0473U, + 0x0473U, + 0x0473U, + 0x0473U, + 0x0473U, + 0x0473U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x0004U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U }; + +static short __tolowR[257] = { + -1, + 0x00, + 0x01, + 0x02, + 0x03, + 0x04, + 0x05, + 0x06, + 0x07, + 0x08, + 0x09, + 0x0A, + 0x0B, + 0x0C, + 0x0D, + 0x0E, + 0x0F, + 0x10, + 0x11, + 0x12, + 0x13, + 0x14, + 0x15, + 0x16, + 0x17, + 0x18, + 0x19, + 0x1A, + 0x1B, + 0x1C, + 0x1D, + 0x1E, + 0x1F, + 0x20, + 0x21, + 0x22, + 0x23, + 0x24, + 0x25, + 0x26, + 0x27, + 0x28, + 0x29, + 0x2A, + 0x2B, + 0x2C, + 0x2D, + 0x2E, + 0x2F, + 0x30, + 0x31, + 0x32, + 0x33, + 0x34, + 0x35, + 0x36, + 0x37, + 0x38, + 0x39, + 0x3A, + 0x3B, + 0x3C, + 0x3D, + 0x3E, + 0x3F, + 0x40, + 0x61, + 0x62, + 0x63, + 0x64, + 0x65, + 0x66, + 0x67, + 0x68, + 0x69, + 0x6A, + 0x6B, + 0x6C, + 0x6D, + 0x6E, + 0x6F, + 0x70, + 0x71, + 0x72, + 0x73, + 0x74, + 0x75, + 0x76, + 0x77, + 0x78, + 0x79, + 0x7A, + 0x5B, + 0x5C, + 0x5D, + 0x5E, + 0x5F, + 0x60, + 0x61, + 0x62, + 0x63, + 0x64, + 0x65, + 0x66, + 0x67, + 0x68, + 0x69, + 0x6A, + 0x6B, + 0x6C, + 0x6D, + 0x6E, + 0x6F, + 0x70, + 0x71, + 0x72, + 0x73, + 0x74, + 0x75, + 0x76, + 0x77, + 0x78, + 0x79, + 0x7A, + 0x7B, + 0x7C, + 0x7D, + 0x7E, + 0x7F, + 0x80, + 0x81, + 0x82, + 0x83, + 0x84, + 0x85, + 0x86, + 0x87, + 0x88, + 0x89, + 0x8A, + 0x8B, + 0x8C, + 0x8D, + 0x8E, + 0x8F, + 0x90, + 0x91, + 0x92, + 0x93, + 0x94, + 0x95, + 0x96, + 0x97, + 0x98, + 0x99, + 0x9A, + 0x9B, + 0x9C, + 0x9D, + 0x9E, + 0x9F, + 0xA0, + 0xA1, + 0xA2, + 0xA3, + 0xA4, + 0xA5, + 0xA6, + 0xA7, + 0xA8, + 0xA9, + 0xAA, + 0xAB, + 0xAC, + 0xAD, + 0xAE, + 0xAF, + 0xB0, + 0xB1, + 0xB2, + 0xB3, + 0xB4, + 0xB5, + 0xB6, + 0xB7, + 0xB8, + 0xB9, + 0xBA, + 0xBB, + 0xBC, + 0xBD, + 0xBE, + 0xBF, + 0xC0, + 0xC1, + 0xC2, + 0xC3, + 0xC4, + 0xC5, + 0xC6, + 0xC7, + 0xC8, + 0xC9, + 0xCA, + 0xCB, + 0xCC, + 0xCD, + 0xCE, + 0xCF, + 0xD0, + 0xD1, + 0xD2, + 0xD3, + 0xD4, + 0xD5, + 0xD6, + 0xD7, + 0xD8, + 0xD9, + 0xDA, + 0xDB, + 0xDC, + 0xDD, + 0xDE, + 0xDF, + 0xE0, + 0xE1, + 0xE2, + 0xE3, + 0xE4, + 0xE5, + 0xE6, + 0xE7, + 0xE8, + 0xE9, + 0xEA, + 0xEB, + 0xEC, + 0xED, + 0xEE, + 0xEF, + 0xF0, + 0xF1, + 0xF2, + 0xF3, + 0xF4, + 0xF5, + 0xF6, + 0xF7, + 0xF8, + 0xF9, + 0xFA, + 0xFB, + 0xFC, + 0xFD, + 0xFE, + 0xFF }; + +static short __toupR[257] = { + -1, + 0x00, + 0x01, + 0x02, + 0x03, + 0x04, + 0x05, + 0x06, + 0x07, + 0x08, + 0x09, + 0x0A, + 0x0B, + 0x0C, + 0x0D, + 0x0E, + 0x0F, + 0x10, + 0x11, + 0x12, + 0x13, + 0x14, + 0x15, + 0x16, + 0x17, + 0x18, + 0x19, + 0x1A, + 0x1B, + 0x1C, + 0x1D, + 0x1E, + 0x1F, + 0x20, + 0x21, + 0x22, + 0x23, + 0x24, + 0x25, + 0x26, + 0x27, + 0x28, + 0x29, + 0x2A, + 0x2B, + 0x2C, + 0x2D, + 0x2E, + 0x2F, + 0x30, + 0x31, + 0x32, + 0x33, + 0x34, + 0x35, + 0x36, + 0x37, + 0x38, + 0x39, + 0x3A, + 0x3B, + 0x3C, + 0x3D, + 0x3E, + 0x3F, + 0x40, + 0x41, + 0x42, + 0x43, + 0x44, + 0x45, + 0x46, + 0x47, + 0x48, + 0x49, + 0x4A, + 0x4B, + 0x4C, + 0x4D, + 0x4E, + 0x4F, + 0x50, + 0x51, + 0x52, + 0x53, + 0x54, + 0x55, + 0x56, + 0x57, + 0x58, + 0x59, + 0x5A, + 0x5B, + 0x5C, + 0x5D, + 0x5E, + 0x5F, + 0x60, + 0x41, + 0x42, + 0x43, + 0x44, + 0x45, + 0x46, + 0x47, + 0x48, + 0x49, + 0x4A, + 0x4B, + 0x4C, + 0x4D, + 0x4E, + 0x4F, + 0x50, + 0x51, + 0x52, + 0x53, + 0x54, + 0x55, + 0x56, + 0x57, + 0x58, + 0x59, + 0x5A, + 0x7B, + 0x7C, + 0x7D, + 0x7E, + 0x7F, + 0x80, + 0x81, + 0x82, + 0x83, + 0x84, + 0x85, + 0x86, + 0x87, + 0x88, + 0x89, + 0x8A, + 0x8B, + 0x8C, + 0x8D, + 0x8E, + 0x8F, + 0x90, + 0x91, + 0x92, + 0x93, + 0x94, + 0x95, + 0x96, + 0x97, + 0x98, + 0x99, + 0x9A, + 0x9B, + 0x9C, + 0x9D, + 0x9E, + 0x9F, + 0xA0, + 0xA1, + 0xA2, + 0xA3, + 0xA4, + 0xA5, + 0xA6, + 0xA7, + 0xA8, + 0xA9, + 0xAA, + 0xAB, + 0xAC, + 0xAD, + 0xAE, + 0xAF, + 0xB0, + 0xB1, + 0xB2, + 0xB3, + 0xB4, + 0xB5, + 0xB6, + 0xB7, + 0xB8, + 0xB9, + 0xBA, + 0xBB, + 0xBC, + 0xBD, + 0xBE, + 0xBF, + 0xC0, + 0xC1, + 0xC2, + 0xC3, + 0xC4, + 0xC5, + 0xC6, + 0xC7, + 0xC8, + 0xC9, + 0xCA, + 0xCB, + 0xCC, + 0xCD, + 0xCE, + 0xCF, + 0xD0, + 0xD1, + 0xD2, + 0xD3, + 0xD4, + 0xD5, + 0xD6, + 0xD7, + 0xD8, + 0xD9, + 0xDA, + 0xDB, + 0xDC, + 0xDD, + 0xDE, + 0xDF, + 0xE0, + 0xE1, + 0xE2, + 0xE3, + 0xE4, + 0xE5, + 0xE6, + 0xE7, + 0xE8, + 0xE9, + 0xEA, + 0xEB, + 0xEC, + 0xED, + 0xEE, + 0xEF, + 0xF0, + 0xF1, + 0xF2, + 0xF3, + 0xF4, + 0xF5, + 0xF6, + 0xF7, + 0xF8, + 0xF9, + 0xFA, + 0xFB, + 0xFC, + 0xFD, + 0xFE, + 0xFF }; + +#else + +static unsigned short __isbufR[257] = { + 0x0000U, /* EOF */ + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0104U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0104U, + 0x0104U, + 0x0104U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0104U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0000U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0000U, + 0x0000U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0000U, + 0x0004U, + 0x0140U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0090U, /* x'4a' is cent, not printable after conversion to ASCII */ + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0090U, /* x'6a' is secondary vertical bar, doesn't exist in ASCII */ + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x0000U, + 0x0473U, + 0x0473U, + 0x0473U, + 0x0473U, + 0x0473U, + 0x0473U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x00D0U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x00D0U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x00D0U, + 0x0000U, + 0x0000U, + 0x00D0U, + 0x0653U, + 0x0653U, + 0x0653U, + 0x0653U, + 0x0653U, + 0x0653U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x00D0U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x00D0U, + 0x0000U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0459U, + 0x0459U, + 0x0459U, + 0x0459U, + 0x0459U, + 0x0459U, + 0x0459U, + 0x0459U, + 0x0459U, + 0x0459U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U }; + +static short __tolowR[257] = { + -1, + 0x00, + 0x01, + 0x02, + 0x03, + 0x04, + 0x05, + 0x06, + 0x07, + 0x08, + 0x09, + 0x0A, + 0x0B, + 0x0C, + 0x0D, + 0x0E, + 0x0F, + 0x10, + 0x11, + 0x12, + 0x13, + 0x14, + 0x15, + 0x16, + 0x17, + 0x18, + 0x19, + 0x1A, + 0x1B, + 0x1C, + 0x1D, + 0x1E, + 0x1F, + 0x20, + 0x21, + 0x22, + 0x23, + 0x24, + 0x25, + 0x26, + 0x27, + 0x28, + 0x29, + 0x2A, + 0x2B, + 0x2C, + 0x2D, + 0x2E, + 0x2F, + 0x30, + 0x31, + 0x32, + 0x33, + 0x34, + 0x35, + 0x36, + 0x37, + 0x38, + 0x39, + 0x3A, + 0x3B, + 0x3C, + 0x3D, + 0x3E, + 0x3F, + 0x40, + 0x41, + 0x42, + 0x43, + 0x44, + 0x45, + 0x46, + 0x47, + 0x48, + 0x49, + 0x4A, + 0x4B, + 0x4C, + 0x4D, + 0x4E, + 0x4F, + 0x50, + 0x51, + 0x52, + 0x53, + 0x54, + 0x55, + 0x56, + 0x57, + 0x58, + 0x59, + 0x5A, + 0x5B, + 0x5C, + 0x5D, + 0x5E, + 0x5F, + 0x60, + 0x61, + 0x62, + 0x63, + 0x64, + 0x65, + 0x66, + 0x67, + 0x68, + 0x69, + 0x6A, + 0x6B, + 0x6C, + 0x6D, + 0x6E, + 0x6F, + 0x70, + 0x71, + 0x72, + 0x73, + 0x74, + 0x75, + 0x76, + 0x77, + 0x78, + 0x79, + 0x7A, + 0x7B, + 0x7C, + 0x7D, + 0x7E, + 0x7F, + 0x80, + 0x81, + 0x82, + 0x83, + 0x84, + 0x85, + 0x86, + 0x87, + 0x88, + 0x89, + 0x8A, + 0x8B, + 0x8C, + 0x8D, + 0x8E, + 0x8F, + 0x90, + 0x91, + 0x92, + 0x93, + 0x94, + 0x95, + 0x96, + 0x97, + 0x98, + 0x99, + 0x9A, + 0x9B, + 0x9C, + 0x9D, + 0x9E, + 0x9F, + 0xA0, + 0xA1, + 0xA2, + 0xA3, + 0xA4, + 0xA5, + 0xA6, + 0xA7, + 0xA8, + 0xA9, + 0xAA, + 0xAB, + 0xAC, + 0xAD, + 0xAE, + 0xAF, + 0xB0, + 0xB1, + 0xB2, + 0xB3, + 0xB4, + 0xB5, + 0xB6, + 0xB7, + 0xB8, + 0xB9, + 0xBA, + 0xBB, + 0xBC, + 0xBD, + 0xBE, + 0xBF, + 0xC0, + 0x81, + 0x82, + 0x83, + 0x84, + 0x85, + 0x86, + 0x87, + 0x88, + 0x89, + 0xCA, + 0xCB, + 0xCC, + 0xCD, + 0xCE, + 0xCF, + 0xD0, + 0x91, + 0x92, + 0x93, + 0x94, + 0x95, + 0x96, + 0x97, + 0x98, + 0x99, + 0xDA, + 0xDB, + 0xDC, + 0xDD, + 0xDE, + 0xDF, + 0xE0, + 0xE1, + 0xA2, + 0xA3, + 0xA4, + 0xA5, + 0xA6, + 0xA7, + 0xA8, + 0xA9, + 0xEA, + 0xEB, + 0xEC, + 0xED, + 0xEE, + 0xEF, + 0xF0, + 0xF1, + 0xF2, + 0xF3, + 0xF4, + 0xF5, + 0xF6, + 0xF7, + 0xF8, + 0xF9, + 0xFA, + 0xFB, + 0xFC, + 0xFD, + 0xFE, + 0xFF }; + +static short __toupR[257] = { + -1, + 0x00, + 0x01, + 0x02, + 0x03, + 0x04, + 0x05, + 0x06, + 0x07, + 0x08, + 0x09, + 0x0A, + 0x0B, + 0x0C, + 0x0D, + 0x0E, + 0x0F, + 0x10, + 0x11, + 0x12, + 0x13, + 0x14, + 0x15, + 0x16, + 0x17, + 0x18, + 0x19, + 0x1A, + 0x1B, + 0x1C, + 0x1D, + 0x1E, + 0x1F, + 0x20, + 0x21, + 0x22, + 0x23, + 0x24, + 0x25, + 0x26, + 0x27, + 0x28, + 0x29, + 0x2A, + 0x2B, + 0x2C, + 0x2D, + 0x2E, + 0x2F, + 0x30, + 0x31, + 0x32, + 0x33, + 0x34, + 0x35, + 0x36, + 0x37, + 0x38, + 0x39, + 0x3A, + 0x3B, + 0x3C, + 0x3D, + 0x3E, + 0x3F, + 0x40, + 0x41, + 0x42, + 0x43, + 0x44, + 0x45, + 0x46, + 0x47, + 0x48, + 0x49, + 0x4A, + 0x4B, + 0x4C, + 0x4D, + 0x4E, + 0x4F, + 0x50, + 0x51, + 0x52, + 0x53, + 0x54, + 0x55, + 0x56, + 0x57, + 0x58, + 0x59, + 0x5A, + 0x5B, + 0x5C, + 0x5D, + 0x5E, + 0x5F, + 0x60, + 0x61, + 0x62, + 0x63, + 0x64, + 0x65, + 0x66, + 0x67, + 0x68, + 0x69, + 0x6A, + 0x6B, + 0x6C, + 0x6D, + 0x6E, + 0x6F, + 0x70, + 0x71, + 0x72, + 0x73, + 0x74, + 0x75, + 0x76, + 0x77, + 0x78, + 0x79, + 0x7A, + 0x7B, + 0x7C, + 0x7D, + 0x7E, + 0x7F, + 0x80, + 0xC1, + 0xC2, + 0xC3, + 0xC4, + 0xC5, + 0xC6, + 0xC7, + 0xC8, + 0xC9, + 0x8A, + 0x8B, + 0x8C, + 0x8D, + 0x8E, + 0x8F, + 0x90, + 0xD1, + 0xD2, + 0xD3, + 0xD4, + 0xD5, + 0xD6, + 0xD7, + 0xD8, + 0xD9, + 0x9A, + 0x9B, + 0x9C, + 0x9D, + 0x9E, + 0x9F, + 0xA0, + 0xA1, + 0xE2, + 0xE3, + 0xE4, + 0xE5, + 0xE6, + 0xE7, + 0xE8, + 0xE9, + 0xAA, + 0xAB, + 0xAC, + 0xAD, + 0xAE, + 0xAF, + 0xB0, + 0xB1, + 0xB2, + 0xB3, + 0xB4, + 0xB5, + 0xB6, + 0xB7, + 0xB8, + 0xB9, + 0xBA, + 0xBB, + 0xBC, + 0xBD, + 0xBE, + 0xBF, + 0xC0, + 0xC1, + 0xC2, + 0xC3, + 0xC4, + 0xC5, + 0xC6, + 0xC7, + 0xC8, + 0xC9, + 0xCA, + 0xCB, + 0xCC, + 0xCD, + 0xCE, + 0xCF, + 0xD0, + 0xD1, + 0xD2, + 0xD3, + 0xD4, + 0xD5, + 0xD6, + 0xD7, + 0xD8, + 0xD9, + 0xDA, + 0xDB, + 0xDC, + 0xDD, + 0xDE, + 0xDF, + 0xE0, + 0xE1, + 0xE2, + 0xE3, + 0xE4, + 0xE5, + 0xE6, + 0xE7, + 0xE8, + 0xE9, + 0xEA, + 0xEB, + 0xEC, + 0xED, + 0xEE, + 0xEF, + 0xF0, + 0xF1, + 0xF2, + 0xF3, + 0xF4, + 0xF5, + 0xF6, + 0xF7, + 0xF8, + 0xF9, + 0xFA, + 0xFB, + 0xFC, + 0xFD, + 0xFE, + 0xFF }; + +#endif + +unsigned short *__isbuf = &__isbufR[1]; +short *__tolow = &__tolowR[1]; +short *__toup = &__toupR[1]; + +__PDPCLIB_API__ int isalnum(int c) +{ + return (__isbuf[(c)] & 0x0001U); +} + +__PDPCLIB_API__ int isalpha(int c) +{ + return (__isbuf[(c)] & 0x0002U); +} + +__PDPCLIB_API__ int iscntrl(int c) +{ + return (__isbuf[(c)] & 0x0004U); +} + +__PDPCLIB_API__ int isdigit(int c) +{ + return (__isbuf[(c)] & 0x0008U); +} + +__PDPCLIB_API__ int isgraph(int c) +{ + return (__isbuf[(c)] & 0x0010U); +} + +__PDPCLIB_API__ int islower(int c) +{ + return (__isbuf[(c)] & 0x0020U); +} + +__PDPCLIB_API__ int isprint(int c) +{ + return (__isbuf[(c)] & 0x0040U); +} + +__PDPCLIB_API__ int ispunct(int c) +{ + return (__isbuf[(c)] & 0x0080U); +} + +__PDPCLIB_API__ int isspace(int c) +{ + return (__isbuf[(c)] & 0x0100U); +} + +__PDPCLIB_API__ int isupper(int c) +{ + return (__isbuf[(c)] & 0x0200U); +} + +__PDPCLIB_API__ int isxdigit(int c) +{ + return (__isbuf[(c)] & 0x0400U); +} + +__PDPCLIB_API__ int tolower(int c) +{ + return (__tolow[(c)]); +} + +__PDPCLIB_API__ int toupper(int c) +{ + return (__toup[(c)]); +} diff --git a/app/src/main/cpp/pdpclib/armeabi-v7a/ctype.h b/app/src/main/cpp/pdpclib/armeabi-v7a/ctype.h new file mode 100644 index 0000000..b368324 --- /dev/null +++ b/app/src/main/cpp/pdpclib/armeabi-v7a/ctype.h @@ -0,0 +1,60 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* ctype.h - ctype header file. */ +/* */ +/*********************************************************************/ + +#ifndef __CTYPE_INCLUDED +#define __CTYPE_INCLUDED + +int isalnum(int c); +int isalpha(int c); +int iscntrl(int c); +int isdigit(int c); +int isgraph(int c); +int islower(int c); +int isprint(int c); +int ispunct(int c); +int isspace(int c); +int isupper(int c); +int isxdigit(int c); +int tolower(int c); +int toupper(int c); + +#if defined(__WIN32__) && !defined(__STATIC__) || defined(__SUBC__) + +/* don't use macros on these environments */ + +#elif defined(__PDOSGEN__) +#include <__os.h> + +#define isalnum __os->isalnum +#define isxdigit __os->isxdigit + +#else +extern unsigned short *__isbuf; +extern short *__tolow; +extern short *__toup; + +#define isalnum(c) (__isbuf[(c)] & 0x0001U) +#define isalpha(c) (__isbuf[(c)] & 0x0002U) +#define iscntrl(c) (__isbuf[(c)] & 0x0004U) +#define isdigit(c) (__isbuf[(c)] & 0x0008U) +#define isgraph(c) (__isbuf[(c)] & 0x0010U) +#define islower(c) (__isbuf[(c)] & 0x0020U) +#define isprint(c) (__isbuf[(c)] & 0x0040U) +#define ispunct(c) (__isbuf[(c)] & 0x0080U) +#define isspace(c) (__isbuf[(c)] & 0x0100U) +#define isupper(c) (__isbuf[(c)] & 0x0200U) +#define isxdigit(c) (__isbuf[(c)] & 0x0400U) +#define tolower(c) (__tolow[(c)]) +#define toupper(c) (__toup[(c)]) +#endif + +#endif diff --git a/app/src/main/cpp/pdpclib/armeabi-v7a/errno.c b/app/src/main/cpp/pdpclib/armeabi-v7a/errno.c new file mode 100644 index 0000000..fc780bc --- /dev/null +++ b/app/src/main/cpp/pdpclib/armeabi-v7a/errno.c @@ -0,0 +1,18 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* errno.c - implementation of stuff in errno.h */ +/* */ +/*********************************************************************/ + +#include "stddef.h" + +int __errno = 0; + +__PDPCLIB_API__ int *_errno() + { return(&__errno); } diff --git a/app/src/main/cpp/pdpclib/armeabi-v7a/errno.h b/app/src/main/cpp/pdpclib/armeabi-v7a/errno.h new file mode 100644 index 0000000..6483ff7 --- /dev/null +++ b/app/src/main/cpp/pdpclib/armeabi-v7a/errno.h @@ -0,0 +1,29 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* errno.h - errno header file. */ +/* */ +/*********************************************************************/ + +#ifndef __ERRNO_INCLUDED +#define __ERRNO_INCLUDED + +#define EDOM 1 +#define ERANGE 2 + +#define errno (*(_errno())) + +int *_errno(void); + +#if defined(__PDOSGEN__) +#include <__os.h> +#undef errno +#define errno (*(__os->_errno())) +#endif + +#endif diff --git a/app/src/main/cpp/pdpclib/armeabi-v7a/float.h b/app/src/main/cpp/pdpclib/armeabi-v7a/float.h new file mode 100644 index 0000000..311762d --- /dev/null +++ b/app/src/main/cpp/pdpclib/armeabi-v7a/float.h @@ -0,0 +1,128 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* float.h - float header file. */ +/* */ +/*********************************************************************/ + +#ifndef __FLOAT_INCLUDED +#define __FLOAT_INCLUDED + +#if defined(__CMS__) || defined(__MVS__) || defined(__VSE__) +/* + IBM 360 & 370 use "HEX" floating point + float is 32 bits, double & long double are 64 bit. + Although some models can do 128 bit (actually 120 bit) + GCC does not implement this and "long double" is same as "double" +*/ + +/* rounding direction is unpredictable */ +#define FLT_ROUNDS 0 + +/* Floating point is HEX so RADIX is base 16 */ +#define FLT_RADIX 16 + +/* Note FLT_RADIX is 16 these are smaller than normal*/ +#define FLT_MANT_DIG 6 +#define DBL_MANT_DIG 14 +/* don't use 128 bit floats so this is still 14 */ +#define LDBL_MANT_DIG 14 + + +/* As IBM uses hex float with "wobbling precision" these are approximate */ +#define FLT_DIG 7 +#define DBL_DIG 15 +#define LDBL_DIG 15 + + +#define FLT_MIN_EXP (-64) +#define DBL_MIN_EXP (-64) +#define LDBL_MIN_EXP (-64) + +#define FLT_MIN_10_EXP (-78) +#define DBL_MIN_10_EXP (-78) +#define LDBL_MIN_10_EXP (-78) + +#define FLT_MAX_EXP 63 +#define DBL_MAX_EXP 63 +#define LDBL_MAX_EXP 63 + +#define FLT_MAX_10_EXP 75 +#define DBL_MAX_10_EXP 75 +#define LDBL_MAX_10_EXP 75 + +/* + This is a temporary fiddle to get round bug in GCC + scanning of ASCII to Floats. +*/ +typedef union { + unsigned short _HexVal[4]; + double _Dval; + float _Fval; + long _Lval; +} _HexFloat; + +static _HexFloat _FltMax = {{0x7fff, 0xffff ,0xffff ,0xffff}}; +static _HexFloat _FltMin = {{0x0010, 0x0000 ,0x0000 ,0x0000}}; +static _HexFloat _DblMax = {{0x7fff ,0xffff ,0xffff ,0xffff}}; +static _HexFloat _DblMin = {{0x0010 ,0x0000 ,0x0000 ,0x0000}}; +static _HexFloat _FltEps = {{0x3C10 ,0x0000 ,0x0000 ,0x0000}}; +static _HexFloat _DblEps = {{0x3410 ,0x0000 ,0x0000 ,0x0000}}; + +#define FLT_MAX _FltMax._Fval +#define DBL_MAX _DblMax._Dval +#define LDBL_MAX _DblMax._Lval + +#define FLT_MIN _FltMin._Fval +#define DBL_MIN _DblMin._Fval +#define LDBL_MIN _DblMin._Fval + +#define FLT_EPSILON _FltEps._Fval +#define DBL_EPSILON _DblEps._Fval +#define LDBL_EPSILON _DblEps._Fval + + + +#else +/* + original stuff from Paul for IEEE maths +*/ + +#define FLT_ROUNDS 1 +#define FLT_RADIX 2 +#define FLT_MANT_DIG 24 +#define DBL_MANT_DIG 53 +#define LDBL_MANT_DIG 53 +#define FLT_DIG 6 +#define DBL_DIG 10 +#define LDBL_DIG 10 +#define FLT_MIN_EXP -125 +#define DBL_MIN_EXP -1021 +#define LDBL_MIN_EXP -1021 +#define FLT_MIN_10_EXP -37 +#define DBL_MIN_10_EXP -37 +#define LDBL_MIN_10_EXP -37 +#define FLT_MAX_EXP +128 +#define DBL_MAX_EXP +1024 +#define LDBL_MAX_EXP +1024 +#define FLT_MAX_10_EXP +37 +#define DBL_MAX_10_EXP +37 +#define LDBL_MAX_10_EXP +37 +#define FLT_MAX 1E+37 +#define DBL_MAX 1E+37 +#define LDBL_MAX 1E+37 +#define FLT_EPSILON 1E-5 +#define DBL_EPSILON 1E-9 +#define LDBL_EPSILON 1E-9 +#define FLT_MIN 1E-37 +#define DBL_MIN 1E-37 +#define LDBL_MIN 1E-37 +#endif + +#endif + diff --git a/app/src/main/cpp/pdpclib/armeabi-v7a/limits.h b/app/src/main/cpp/pdpclib/armeabi-v7a/limits.h new file mode 100644 index 0000000..e6f61f8 --- /dev/null +++ b/app/src/main/cpp/pdpclib/armeabi-v7a/limits.h @@ -0,0 +1,52 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* limits.h - limits header file. */ +/* */ +/*********************************************************************/ + +#ifndef __LIMITS_INCLUDED +#define __LIMITS_INCLUDED + +#define CHAR_BIT 8 +#define SCHAR_MIN -128 +#define SCHAR_MAX 127 +#define UCHAR_MAX 255 +#if ('\x80' < 0) +#define CHAR_MIN -128 +#define CHAR_MAX 127 +#else +#define CHAR_MIN 0 +#define CHAR_MAX 255 +#endif +#define MB_LEN_MAX 1 +#define SHRT_MIN (-SHRT_MAX-1) +#define SHRT_MAX 32767 +#define USHRT_MAX ((unsigned short)65535U) + +#if (defined(__OS2__) || defined(__32BIT__) || defined(__MVS__) \ + || defined(__VSE__) || defined(__PDOS386__) \ + || defined(__CMS__) || defined(__WIN32__) || defined(__gnu_linux__) \ + || defined(__AMIGA__) ||defined(__SMALLERC__) || defined(__ARM__) \ + || defined(__EFI__)) +#define INT_MIN (-INT_MAX-1) +#define INT_MAX 2147483647 +#define UINT_MAX 4294967295U +#endif + +#if (defined(__MSDOS__) || defined(__DOS__) || defined(__POWERC)) +#define INT_MIN (-INT_MAX-1) +#define INT_MAX 32767 +#define UINT_MAX 65535U +#endif + +#define LONG_MIN (-LONG_MAX-1) +#define LONG_MAX 2147483647L +#define ULONG_MAX 4294967295UL + +#endif diff --git a/app/src/main/cpp/pdpclib/armeabi-v7a/linstart.c b/app/src/main/cpp/pdpclib/armeabi-v7a/linstart.c new file mode 100644 index 0000000..ea3d2ba --- /dev/null +++ b/app/src/main/cpp/pdpclib/armeabi-v7a/linstart.c @@ -0,0 +1,96 @@ +/* Startup code for Linux */ +/* written by Paul Edwards */ +/* released to the public domain */ + +#include "errno.h" +#include "stddef.h" + +/* malloc calls get this */ +static char membuf[31000000]; +static char *newmembuf = membuf; + +extern int __start(int argc, char **argv); +extern int __exita(int rc); + +#ifdef NEED_MPROTECT +extern int __mprotect(void *buf, size_t len, int prot); + +#define PROT_READ 1 +#define PROT_WRITE 2 +#define PROT_EXEC 4 +#endif + +/* We can get away with a minimal startup code, plus make it + a C program. There is no return address. Instead, on the + stack is a count, followed by all the parameters as pointers */ + +int _start(char *p) +{ + int rc; + +#ifdef NEED_MPROTECT + /* make malloced memory executable */ + /* most environments already make the memory executable */ + /* but some certainly don't */ + /* there doesn't appear to be a syscall to get the page size to + ensure page alignment (as required), and I read that some + environments have 4k page sizes but mprotect requires 16k + alignment. So for now we'll just go with 16k */ + size_t blksize = 16 * 1024; + size_t numblks; + + newmembuf = membuf + blksize; /* could waste memory here */ + newmembuf = newmembuf - (unsigned int)newmembuf % blksize; + numblks = sizeof membuf / blksize; + numblks -= 2; /* if already aligned, we wasted an extra block */ + rc = __mprotect(newmembuf, + numblks * blksize, + PROT_READ | PROT_WRITE | PROT_EXEC); + if (rc != 0) return (rc); +#endif + + /* I don't know what the official rules for ARM are, but + looking at the stack on entry showed that this code + would work */ +#ifdef __ARM__ + +#if defined(__UNOPT__) + rc = __start(*(int *)(&p + 5), &p + 6); +#else + rc = __start(*(int *)(&p + 6), &p + 7); +#endif + +#else + rc = __start(*(int *)(&p - 1), &p); +#endif + __exita(rc); + return (rc); +} + + +void *__allocmem(size_t size) +{ + return (newmembuf); +} + + +#if defined(__WATCOMC__) + +#define CTYP __cdecl + +/* this is invoked by long double manipulations + in stdio.c and needs to be done properly */ + +int CTYP _CHP(void) +{ + return (0); +} + +/* don't know what these are */ + +void CTYP cstart_(void) { return; } +void CTYP _argc(void) { return; } +void CTYP argc(void) { return; } +void CTYP _8087(void) { return; } + +#endif diff --git a/app/src/main/cpp/pdpclib/armeabi-v7a/locale.c b/app/src/main/cpp/pdpclib/armeabi-v7a/locale.c new file mode 100644 index 0000000..b322830 --- /dev/null +++ b/app/src/main/cpp/pdpclib/armeabi-v7a/locale.c @@ -0,0 +1,60 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* locale.c - implementation of stuff in locale.h */ +/* */ +/*********************************************************************/ + +#include "locale.h" +#include "limits.h" +#include "string.h" +#include "stddef.h" + +static struct lconv thislocale = { + ".", + "", + "", + "", + "", + "", + "", + "", + "", + "", + CHAR_MAX, + CHAR_MAX, + CHAR_MAX, + CHAR_MAX, + CHAR_MAX, + CHAR_MAX, + CHAR_MAX, + CHAR_MAX +}; + +__PDPCLIB_API__ char *setlocale(int category, const char *locale) +{ + (void)category; + if (locale == NULL) + { + return ("C"); + } + else if ((strcmp(locale, "C") == 0) + || (strcmp(locale, "") == 0)) + { + return ("C"); + } + else + { + return (NULL); + } +} + +__PDPCLIB_API__ struct lconv *localeconv(void) +{ + return (&thislocale); +} diff --git a/app/src/main/cpp/pdpclib/armeabi-v7a/locale.h b/app/src/main/cpp/pdpclib/armeabi-v7a/locale.h new file mode 100644 index 0000000..7027700 --- /dev/null +++ b/app/src/main/cpp/pdpclib/armeabi-v7a/locale.h @@ -0,0 +1,56 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* locale.h - locale header file. */ +/* */ +/*********************************************************************/ + +#ifndef __LOCALE_INCLUDED +#define __LOCALE_INCLUDED + +struct lconv { + char *decimal_point; + char *thousands_sep; + char *grouping; + char *int_curr_symbol; + char *currency_symbol; + char *mon_decimal_point; + char *mon_thousands_sep; + char *mon_grouping; + char *positive_sign; + char *negative_sign; + char int_frac_digits; + char frac_digits; + char p_cs_precedes; + char p_sep_by_space; + char n_cs_precedes; + char n_sep_by_space; + char p_sign_posn; + char n_sign_posn; +}; + +#define NULL ((void *)0) +#define LC_ALL 1 +#define LC_COLLATE 2 +#define LC_CTYPE 3 +#define LC_MONETARY 4 +#define LC_NUMERIC 5 +#define LC_TIME 6 + +char *setlocale(int category, const char *locale); +struct lconv *localeconv(void); + +#if defined(__PDOSGEN__) +#include <__os.h> + +#define setlocale __os->setlocale + +#endif + + +#endif diff --git a/app/src/main/cpp/pdpclib/armeabi-v7a/math.c b/app/src/main/cpp/pdpclib/armeabi-v7a/math.c new file mode 100644 index 0000000..3f66818 --- /dev/null +++ b/app/src/main/cpp/pdpclib/armeabi-v7a/math.c @@ -0,0 +1,723 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/* 9-April-2006 D.Wade */ +/* Moved definitions for HUGE_VAL to math.h */ +/* Inserted argument rang checks in :- */ +/* acos */ +/* */ +/* */ +/* */ +/* 2-April-2006 D.Wade added code for the :- */ +/* */ +/* acos(double x); */ +/* asin(double x); */ +/* atan(double x); */ +/* cos(double x); */ +/* sin(double x); */ +/* tan(double x); */ +/* cosh(double x); */ +/* sinh(double x); */ +/* tanh(double x); */ +/* exp(double x); */ +/* frexp(double value, int *exp); */ +/* ldexp(double x, int exp); */ +/* log(double x); */ +/* log10(double x); */ +/* modf(double value, double *iptr); */ +/* pow(double x, double y); */ +/* sqrt(double x); */ +/* */ +/* Note:- */ +/* In order to avoide Copyright these functions are generally */ +/* implemented using Taylor Series. As a result they are a little */ +/* slower that the equivalents in many maths packages. */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* math.c - implementation of stuff in math.h */ +/* */ +/*********************************************************************/ + +#include "math.h" +#include "float.h" +#include "errno.h" +#include "stddef.h" + +/* + + Some constants to make life easier elsewhere + (These should I guess be in math.h) + +*/ +static const double pi = 3.1415926535897932384626433832795; +static const double ln10 = 2.3025850929940456840179914546844; +static const double ln2 = 0.69314718055994530941723212145818 ; + + +__PDPCLIB_API__ double ceil(double x) +{ + int y; + + y = (int)x; + if ((double)y < x) + { + y++; + } + return ((double)y); +} + +#ifdef fabs +#undef fabs +#endif +__PDPCLIB_API__ double fabs(double x) +{ + if (x < 0.0) + { + x = -x; + } + return (x); +} + +__PDPCLIB_API__ double floor(double x) +{ + int y; + + if (x < 0.0) + { + y = (int)x; + if ((double)y != x) + { + y--; + } + } + else + { + y = (int)x; + } + return ((double)y); +} + +__PDPCLIB_API__ double fmod(double x, double y) +{ + int imod; + if(y == 0.0) return (0.0); + imod = x / y; + return ((double)x-((double)imod*y)); +} + +#ifdef acos +#undef acos +#endif +/* + + For cos just use (sin(x)**2 + cos(x)**2)=1 + Note:- asin(x) decides which taylor series + to use to ensure quickest convergence. + +*/ +__PDPCLIB_API__ double acos(double x) +{ + +/* +*/ + + if ( fabs(x) > 1.0 ) /* is argument out of range */ + { + errno=EDOM; + return (HUGE_VAL); + } + if ( x < 0.0 ) return ( pi - acos(-x) ) ; + + return ( asin ( sqrt(1.0 - x*x) ) ); + +} + +#ifdef asin +#undef asin +#endif +/* + + This routines Calculate arcsin(x) & arccos(x). + + Note if "x" is close to "1" the series converges slowly. + To avoid this we use (sin(x)**2 + cos(x)**2)=1 + and fact cos(x)=sin(x+pi/2) + +*/ + +__PDPCLIB_API__ double asin (double y) +{ + int i; + double term,answer,work,x,powx,coef; + + x = y; + +/* + if arg is -ve then we want "-asin(-x)" +*/ + + if (x <0.0 ) return ( -asin(-x) ); + +/* + If arg is > 1.0 we can't calculate + (note also < -1.0 but previous statement removes this case) +*/ + if ( x > 1.0 ) + { + errno=EDOM; + return(HUGE_VAL); + } + +/* + now check for large(ish) x > 0.6 +*/ + + if( x > 0.75 ) + { + x = ( sqrt(1.0 - (x*x) ) ); + return((pi/2.0)-asin(x)); + } + +/* + arcsin(x) = x + 1/2 (x^3/3) + (1/2)(3/4)(x^5/5) + + (1/2)(3/4)(5/6)(x^7/7) + ... +*/ + i=1; + answer=x; + term = 1; + coef = 1; + powx = x; + + while (1) + { + work = i; + coef = (coef * work)/(work+1); + powx = powx * x * x; + term = coef * powx / (work + 2.0); + if ( answer == (answer + term) )break; + answer = answer + (term); + i+=2; + } + + return(answer); +} + + +#ifdef atan +#undef atan +#endif +/* + + Because atan(x) is valid for large values of "x" & + the taylor series converges more slowly for large "X" + we use the following + + 1. Reduce to the first octant by using :- + + atan(-x)=-atan(x), + atan(1/x)=PI/2-atan(x) + + 2. Reduce further so that |x| less than tan(PI/12) + + atan(x)=pi/6+atan((X*sqrt(3)-1)/(x+sqrt(3))) + + 3. Then use the taylor series + + atan(x) = x - x**3 + x**5 - x**7 + ---- ---- ---- + 3 5 7 + +*/ + +__PDPCLIB_API__ double atan (double x) +{ + int i; + double term,answer,work,powx; + +/* + if arg is -ve then we want "-atan(-x)" +*/ + + if ( x<0.0 ) return ( -atan(-x) ); + +/* + If arg is large we can't calculate + use atan(1/x)=PI/2-atan(x) +*/ + + if ( x > 1.0 ) return ((pi/2) - atan(1.0/x)); + +/* + now check for large(ish) x > tan(15) (0.26794919243112) + if so use atan(x)=pi/6+atan((X*SQRT3-1)/(X+SQRT3)) +*/ + + if( x > (2.0 - sqrt(3.0))) + return( (pi/6.0) + atan( ( x * sqrt(3.0)-1.0 ) / (x + sqrt(3.0) ) ) ); + +/* +* atan(x) = x - x**3 + x**5 - x**7 +* ---- ---- ---- +* 3 5 7 +*/ + + i=1; + answer=x; + term = x; + powx = x; + + while (1) + { + work = i; + powx = 0.0 - powx * x * x; + term = powx / (work + 2.0); + if ( answer == (answer + term) )break; + answer = answer + (term); + i+=2; + } + + return(answer); + +} + + +/* atan2 was taken from libnix and modified slightly */ + +__PDPCLIB_API__ double atan2(double y,double x) +{ + return (x >= y) ? + (x >= -y ? atan(y/x) : -pi/2 - atan(x/y)) + : + (x >= -y ? pi/2 - atan(x/y) + : (y >= 0) ? pi + atan(y/x) + : -pi + atan(y/x)); +} + + +#ifdef cos +#undef cos +#endif +__PDPCLIB_API__ double cos(double x) +{ +/* + + Calculate COS using Taylor series. + + sin(x) = 1 - x**2 + x**4 - x**6 + x**8 + ==== ==== ==== ==== ......... + 2! 4! 6! 8! + + Note whilst this is accurate it can be slow for large + values of "X" so we scale + +*/ + + int i; + double term,answer,work,x1; + +/* + Scale arguments to be in range 1 => pi +*/ + + i = x/(2*pi); + x1 = x - (i * (2.0 * pi)); + + i=1; + term=answer=1; + + + while (1) + { + work = i; + term = -(term * x1 * x1)/(work * (work + 1.0)); + if ( answer == (answer + term) )break; + answer = answer + term; + i += 2; + } + + return(answer); + +} + +#ifdef sin +#undef sin +#endif +__PDPCLIB_API__ double sin(double x) +{ +/* + + Calculate SIN using Taylor series. + + sin(x) = x - x**3 + x**5 - x**7 + x**9 + ==== ==== ==== ==== + 3! 5! 7! 9! + + Note whilst this is accurate it can be slow for large values + of "X" so we scale + +*/ + + int i; + double term,answer,work,x1; + +/* + scale so series converges pretty quickly +*/ + i = x/(2.0*pi); + x1 = x - (i * (2.0 * pi)); + +/* + set up initial term +*/ + i=1; + term=answer=x1; +/* + loop until no more changes +*/ + while (1) + { + work = i+1; + term = -(term * x1 * x1)/(work * (work + 1.0)); + if ( answer == (answer + term) )break; + answer = answer + term; + i = i+2; + } + + return(answer); +} + +#ifdef tan +#undef tan +#endif +__PDPCLIB_API__ double tan (double x) +{ +/* + + use tan = sin(x)/cos(x) + if cos(x) is 0 then return HUGE_VAL else return sin/cos + + *** need to set ERROR for overflow *** + +*/ + double temp; + + temp=cos(x); + if (temp == 0.0 ) + { + /* errno=EDOM; don't seem to return an error here */ + return (HUGE_VAL); /* need to set error here */ + } + return ( sin(x)/cos(x) ); +} + +/* + + Hyperbolic functions + + SINH(X) = (E**X-E**(-1))/2 + COSH(X) = (E**X+E**(-1))/2 + +*/ +__PDPCLIB_API__ double cosh(double x) +{ + double dexpx; + + dexpx = exp(x); + + return( 0.5 * (dexpx + (1.0/dexpx) ) ); + +} + +__PDPCLIB_API__ double sinh(double x) +{ + double dexpx; + + dexpx = exp(x); + + return( 0.5 * (dexpx - (1.0/dexpx) ) ); +} + +/* + tanh returns the hyperbolic area tangent of floating point argument x. +*/ + +__PDPCLIB_API__ double tanh(double x) +{ + double dexp2; + + dexp2 = exp( -2.0 * x); + return ( (1.0 - dexp2) / (1.0 + dexp2) ); +} + +/* + +exp(x) = 1 + x + x2/2 + x3/6 + x4/24 + x5/120 + ... + xn/n! + ... + +*/ +__PDPCLIB_API__ double exp (double x) +{ + int i; + double term,answer,work; + + i=2; + term=x; + answer=x; + + while (1) + { + work = i; + term = (term * x)/work; + if ( answer == (answer + term) )break; + answer = answer + (term); + i++; + } + + answer=answer+1.0; + return(answer); +} + +/* + + Calculate LOG using Taylor series. + + log(1+ x) = x - x**2 + x**3 - x**4 + x**5 + ==== ==== ==== ==== ......... + 2 3 4 8 + + Note this only works for small x so we scale.... + +*/ +__PDPCLIB_API__ double log (double x) +{ + int i,scale; + double term,answer,work,xs; + + if (x <= 0 ) + { + /* need to set signal */ + errno=EDOM; + return (HUGE_VAL); + } + if( x == 1.0)return(0.0); + +/* + Scale arguments to be in range 1 < x <= 10 +*/ + +/* + scale = 0; + xs = x; + while ( xs > 10.0 ) { scale ++; xs=xs/10.0;} + while ( xs < 1.0 ) { scale --; xs=xs*10.0;} +*/ + xs = frexp(x,&scale); + xs = (1.0 * xs) - 1.0; + scale = scale - 0; + + i=2; + term=answer=xs; + + while (1) + { + work = i; + term = - (term * xs); + if ( answer == (answer + (term/work)) )break; + answer = answer + (term/work); + i++; + } + + answer = answer + (double)scale * ln2; + return(answer); +} + + +__PDPCLIB_API__ double log10(double x) +{ + return ( log(x) / ln10 ); +} + + +/* + + This code uses log and exp to calculate x to the power y. + If + +*/ + +__PDPCLIB_API__ double pow(double x,double y) +{ + int j,neg; + double yy,xx; + neg=0; + j=y; + yy=j; + if( yy == y) { + xx = x; + if ( y < 0 ){neg = 1; j = -j;} + if ( y == 0) return (1.0); + --j; + while(j>0){ xx=xx * x; j--;} + if(neg)xx=1.0/xx; + return (xx); + } + if (x < 0.0) + { + errno=EDOM; + return(0.0); + } + if (y == 0.0) return (1.0); + + return (exp(y*log(x))); +} + +#ifdef sqrt +#undef sqrt +#endif +/* + + pretty tivial code here. + + 1) Scale x such that 1 <= x <= 4.0 + + 2) Use newton Raphson to calculate root. + + 4) multiply back up. + + Because we only scale by "4" this is pretty slow.... + +*/ + +__PDPCLIB_API__ double sqrt(double x) +{ + double xs,yn,ynn; + double pow1; + int i; + + if (x < 0.0) + { + errno=EDOM; + return(0.0); + } + if (x == 0.0) return (0.0); + +/* + + Scale argument 1 <= x <= 4 + +*/ + + xs=x; + pow1=1; + + while(xs<1.0){xs=xs*4.0;pow1=pow1/2.0;} + while(xs>=4.0){xs=xs/4.0;pow1=pow1*2.0;} + +/* + calculate using Newton raphson + use x0 = x/2.0 +*/ + + i=0; + yn = xs/2.0; + ynn = 0; + while(1) + { + ynn = (yn + xs/yn)*0.5; + if ( fabs(ynn-yn) <= 10.0 * DBL_MIN ) break; else yn=ynn; + if ( i > 10 ) break; else i++ ; + } + return (ynn*pow1); +} + + +__PDPCLIB_API__ double frexp(double x, int *exp) +{ +/* + split float into fraction and mantissa + note this is not so easy for IBM as it uses HEX float +*/ + union dblhex + { + double d; + unsigned short s[4]; + }; + union dblhex split; + + if ( x == 0.0) + { + exp=0; + return (0.0); + } + + split.d = x; + *exp = (((split.s[0] >> 8) & 0x007f)-64) * 4; + split.s[0] = split.s[0] & 0x80ff; + split.s[0] = split.s[0] | 0x4000; + /* following code adjust for fact IBM has hex float */ + while ( (fabs(split.d) < 0.5) && (split.d != 0) ) + { + split.d = split.d * 2; + *exp =( *exp ) - 1; + } + /* */ + return(split.d); +} + +__PDPCLIB_API__ double ldexp(double x, int exp) +{ +/* + note this is not so easy for IBM as it uses HEX float +*/ + int bin_exp,hex_exp,adj_exp; + union dblhex + { + double d; + unsigned short s[4]; + }; + union dblhex split; +/* + note "X" mauy already have an exponent => extract it +*/ + split.d = frexp(x,&bin_exp); + bin_exp = bin_exp + exp; /* add in from caller */ +/* need to test for sensible value here */ + hex_exp = (bin_exp / 4); /* convert back to HEX */ + adj_exp = bin_exp - (hex_exp * 4); + if (adj_exp < 0){ hex_exp=hex_exp -1; adj_exp = 4 + adj_exp;} + split.s[0] = split.s[0] & 0x80ff; + split.s[0] = split.s[0] | (((hex_exp+64) << 8) & 0x7f00); + /* following code adjust for fact IBM has hex float */ + /* well it will I have done */ + while ( adj_exp > 0 ) + { + split.d = split.d * 2; + --adj_exp; + } + /**/ + return(split.d); +} + +__PDPCLIB_API__ double modf(double value, double *iptr) +{ + int neg = 0; + long i; + + if (value < 0) + { + neg = 1; + value = -value; + } + i = (long)value; + value = value - i; + if (neg) + { + value = -value; + i = -i; + } + *iptr = i; + return (value); +} diff --git a/app/src/main/cpp/pdpclib/armeabi-v7a/math.h b/app/src/main/cpp/pdpclib/armeabi-v7a/math.h new file mode 100644 index 0000000..7e41535 --- /dev/null +++ b/app/src/main/cpp/pdpclib/armeabi-v7a/math.h @@ -0,0 +1,95 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* math.h - math header file. */ +/* */ +/*********************************************************************/ + +#ifndef __MATH_INCLUDED +#define __MATH_INCLUDED + +/* + Some constants - at present these are only defined for IBM +*/ +#if defined(__MVS__) || defined (__CMS__) || defined(__VSE__) +/* + This is about the nearest thing we can get to inf wthout +*/ +#define HUGE_VAL 9.999999999999999999999E72 + +#else + +#define HUGE_VAL 9.999999999999999999999E72 + +#endif + +double ceil(double x); +double fabs(double x); +double floor(double x); +double fmod(double x, double y); + +/* unimplemented: */ + + +double atan2(double y, double x); +double frexp(double value, int *exp); +double ldexp(double x, int exp); +double modf(double value, double *iptr); + +/* + Implemented by d.wade - April 2006 +*/ + +double pow(double x, double y); +double sqrt(double x); +double acos(double x); +double asin(double x); +double atan(double x); +double cos(double x); +double sin(double x); +double tan(double x); +double cosh(double x); +double sinh(double x); +double tanh(double x); +double exp(double x); +double log(double x); +double log10(double x); + + +#if 0 /* def __WATCOMC__ */ +#pragma intrinsic(cos, sin, tan, exp, log, log10, sqrt) +#endif + +#if defined(__IBMC__) && defined(__OS2__) +double _Builtin __fabs(double x); +#define fabs(x) (__fabs((x))) +double _Builtin __fsin(double x); +#define sin(x) (__fsin((x))) +double _Builtin __fcos(double x); +#define cos(x) (__fcos((x))) +double _Builtin __fptan(double x); +#define tan(x) (__fptan((x))) +double _Builtin __fpatan(double x); +#define atan(x) (__fpatan((x))) +double _Builtin __facos(double x); +#define acos(x) (__facos((x))) +double _Builtin __fasin(double x); +#define asin(x) (__fasin((x))) +double _Builtin __fsqrt(double x); +#define sqrt(x) (__fsqrt((x))) +#endif + +#ifdef __BORLANDC__ +double __sin__(double x); +#define sin(x) (__sin__((x))) +double __cos__(double x); +#define cos(x) (__cos__((x))) +#endif + +#endif + diff --git a/app/src/main/cpp/pdpclib/armeabi-v7a/pgastart.c b/app/src/main/cpp/pdpclib/armeabi-v7a/pgastart.c new file mode 100644 index 0000000..5c89581 --- /dev/null +++ b/app/src/main/cpp/pdpclib/armeabi-v7a/pgastart.c @@ -0,0 +1,36 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* pgastart - startup routine for PDOS generic applications */ +/* */ +/*********************************************************************/ + +#include <__os.h> + +OS *__os; + +int main(int argc, char **argv); + +/* This name is known to certain versions of "ld" as the entry +point of an application and there is no particular reason to not +use it. */ + +int __crt0(OS *os) +{ + __os = os; + *__os->main = main; + return (__os->__start(0)); +} + +#ifdef __AMIGA__ +/* needed for Amiga (gccami) */ +void __main(void) +{ + return; +} +#endif diff --git a/app/src/main/cpp/pdpclib/armeabi-v7a/setjmp.h b/app/src/main/cpp/pdpclib/armeabi-v7a/setjmp.h new file mode 100644 index 0000000..d9313bf --- /dev/null +++ b/app/src/main/cpp/pdpclib/armeabi-v7a/setjmp.h @@ -0,0 +1,101 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* setjmp.h - setjmp header file. */ +/* */ +/*********************************************************************/ + +#ifndef __SETJMP_INCLUDED +#define __SETJMP_INCLUDED + +typedef struct { +#if defined(__MVS__) || defined(__CMS__) || defined(__VSE__) + int regs[15]; +#elif defined(__AMIGA__) + long a0; + long a1; + long a2; + long a3; + long a4; + long a5; + long a6; + long a7; + long d0; + long d1; + long d2; + long d3; + long d4; + long d5; + long d6; + long d7; + long retaddr; +#elif defined(__ARM__) || defined(__ARMGEN__) + void *sp; + void *fp; + void *ip; + int r4; + int r5; + int r6; + int r7; + int r8; + int r9; + int r10; +#elif defined(__WIN32__) || defined(__32BIT__) || defined(__OS2__) \ + || defined(__PDOS386__) || defined(__gnu_linux__) || defined(__EFI__) + int ebx; + int ecx; + int edx; + int edi; + int esi; + int esp; + int ebp; + int retaddr; + int extra[7]; /* for compatibility with MSVCRT */ +#elif defined(__MSDOS__) || defined(__DOS__) || defined(__POWERC) + int bx; + int cx; + int dx; + int di; + int si; + int sp; + int bp; + int retoff; + int retseg; + int ds; + int es; +#else +#error unknown system in setjmp.h +#endif + int retval; +} jmp_buf[1]; + +void longjmp(jmp_buf env, int val); + +#ifdef __MSC__ +int setjmp(jmp_buf env); + +#elif defined(__ARM__) || defined(__ARMGEN__) +/* it appears that gcc has _setjmp as a known keyword which + is causing issues on ARM, so we change the name */ +#define setjmp(x) __Ysetjmp(x) +int __Ysetjmp(jmp_buf env); + +#elif defined(__MSDOS__) +#define setjmp(x) __setj(x) +#if defined(__WATCOMC__) +int __cdecl __setj(jmp_buf env); +#else +int __setj(jmp_buf env); +#endif + +#else +#define setjmp(x) _setjmp(x) +int _setjmp(jmp_buf env); +#endif + +#endif diff --git a/app/src/main/cpp/pdpclib/armeabi-v7a/signal.c b/app/src/main/cpp/pdpclib/armeabi-v7a/signal.c new file mode 100644 index 0000000..8162efc --- /dev/null +++ b/app/src/main/cpp/pdpclib/armeabi-v7a/signal.c @@ -0,0 +1,87 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* signal.c - implementation of stuff in signal.h */ +/* */ +/*********************************************************************/ + +#include "signal.h" +#include "stdlib.h" +#include "stddef.h" + +static void (*handlers[])(int) = { + __sigdfl, + __sigdfl, + __sigdfl, + __sigdfl, + __sigdfl, + __sigdfl, + __sigdfl }; + +void __sigdfl(int sig); +void __sigerr(int sig); +void __sigign(int sig); + +#if 0 +#define SIG_DFL __sigdfl +#define SIG_ERR __sigerr +#define SIG_IGN __sigign +#endif + +__PDPCLIB_API__ void (*signal(int sig, void (*func)(int)))(int) +{ +#if defined(__WIN32__) && !defined(__STATIC__) + if ((int)func == SIG_DFL) + { + handlers[sig] = __sigdfl; + } + else if ((int)func == SIG_ERR) + { + handlers[sig] = __sigerr; + } + else if ((int)func == SIG_IGN) + { + handlers[sig] = __sigign; + } +#else + handlers[sig] = func; +#endif + return (func); +} + + +__PDPCLIB_API__ int raise(int sig) +{ + (handlers[sig])(sig); + return (0); +} + +__PDPCLIB_API__ void __sigdfl(int sig) +{ +#ifndef SEGHACK + handlers[sig] = SIG_DFL; +#endif + if (sig == SIGABRT) + { + exit(EXIT_FAILURE); + } + return; +} + +__PDPCLIB_API__ void __sigerr(int sig) +{ + (void)sig; + return; +} + +__PDPCLIB_API__ void __sigign(int sig) +{ + (void)sig; + return; +} + diff --git a/app/src/main/cpp/pdpclib/armeabi-v7a/signal.h b/app/src/main/cpp/pdpclib/armeabi-v7a/signal.h new file mode 100644 index 0000000..29ea68a --- /dev/null +++ b/app/src/main/cpp/pdpclib/armeabi-v7a/signal.h @@ -0,0 +1,56 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* signal.h - signal header file. */ +/* */ +/*********************************************************************/ + +#ifndef __SIGNAL_INCLUDED +#define __SIGNAL_INCLUDED + +typedef int sig_atomic_t; + +void __sigdfl(int sig); +void __sigerr(int sig); +void __sigign(int sig); + +#if (defined(__WIN32__) && !defined(__STATIC__)) || defined (__PDOSGEN__) +#define SIG_DFL 0 +#define SIG_ERR -1 +#define SIG_IGN 1 +#else +#define SIG_DFL __sigdfl +#define SIG_ERR __sigerr +#define SIG_IGN __sigign +#endif + +#define SIGABRT 1 +#define SIGFPE 2 +#define SIGILL 3 +#define SIGINT 4 +#define SIGSEGV 5 +#define SIGTERM 6 + +#ifdef __SUBC__ +int signal(int sig, int (*handler)()); +#else +void (*signal(int sig, void (*func)(int)))(int); +#endif + +int raise(int sig); + + +#if defined(__PDOSGEN__) +#include <__os.h> + +#define signal __os->signal +#define raise __os->raise +#endif + + +#endif diff --git a/app/src/main/cpp/pdpclib/armeabi-v7a/start.c b/app/src/main/cpp/pdpclib/armeabi-v7a/start.c new file mode 100644 index 0000000..45b0256 --- /dev/null +++ b/app/src/main/cpp/pdpclib/armeabi-v7a/start.c @@ -0,0 +1,1428 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* start.c - startup/termination code */ +/* */ +/*********************************************************************/ + +/* We have the following independent concepts: + +1. What processor is used, e.g. __ARM__ or __386__ or __8086__ +This is important to setjmp as it needs an appropriate sized +buffer for the registers that need to be saved. Note that the +8086 has different memory models, and in e.g. tiny and small +memory models, the segment registers shouldn't be saved/ +restored, as the OS could theoretically use this knowledge to +move the application to some other location. Although the +executable would need to be specially marked that it can be +dynamically relocated, as otherwise it could directly obtain +memory from the OS at runtime and change the segment registers +(via far pointers). The important thing is that the concept exists. + +2. What compiler is used, e.g. __GCC__ (and version number within that, +and forks within that, and targets within that - not just processor +as the target but also the calling convention). + +3. Whether the OS exports the C library (PDOS-generic does, PDOS/386 doesn't) + +4. What API is used, e.g. Pos* vs Win32 vs Posix. Note that it is +possible to get one API to be implemented via translation into another +API. + +5. The size of ints, e.g. __32BIT__ vs __16BIT__ + +6. The API (e.g. Pos) versus any operating system that actually +implements that API (e.g. PDOS/386). Or Win32 API implemented by +PDOS/386. + +7. Whether the OS itself relies on a generic pseudo-BIOS/HAL + +8. Whether the OS/BIOS provides data in blocks (e.g. MVS or a PC BIOS) or +whether you can read/write an arbitrary number of bytes. + +9. The fact that the C library, including PDPCLIB, reconciles block +versus character mode if necessary, and the application always gets +a character mode interface. + +10. Whether the OS does the conversion of blocks (ie blocks on a +mainframe CKD disk, or sectors on a PC) into characters within the +OS itself, or outsources that job to the C library that it relies on. +Currently PDOS/386 does Bos* calls in the OS itself to read disk +sectors, but PDPCLIB could have done those Bos* calls itself, in the +same flavor of code that MVS/CMS/VSE use, which would likely have +been neater, and a better abstraction. PDOS/386 may be restructured +to do this in the future, but it may simply become PDOS-generic if +that is done. That's still unclear to me. Something like pcomm +calling PosMonitor() to implement the "monitor" command is something +beyond what can be considered generic, ie dealing with 80386 registers, +and might possibly need to be shifted up to a higher layer (the HAL/ +pseudo-BIOS) - but that HAL needs to do printfs which are back in +the OS to do, I think. You can't expect a BIOS to provide a full C +library, even though that is the case when running under some +other OS. + +Historically these concepts have all been jumbled up in PDOS/PDPCLIB +and never been reconciled. Which is why there are anomalies such as +a PDOS-generic application for ARM is built needing PDOS386 defined, +when it has nothing whatsoever to do with an 80386. It works, but is +confusing and not properly abstracted/defined. + +So let's try to reconcile at least some of them now. + +And apologies for Pos* being a bit confusing since the name is similar +to POSIX, but they are completely unrelated. Pos* was actually inspired +by Dos* from OS/2 which I thought was a neat naming convention for +the MSDOS INT 21H functions, even though I hated the actual parameter types. + +__POSGEN__ - this define means that both the C library and the Pos* +interface have been exported by the operating system (not necessarily +PDOS-generic) via the well-defined, set in stone (ha ha) __os structure. +Applications can define this. It's not for use when compiling the +actual OS. Or should this be split up into __POS__ and __GENERIC__? +Or __POS__ to specify the API and __CEXPORT__ to say the C library has +been exported (which could be done independently of exporting the +rest of the Pos* API). Note that there is a difference between using +the C library and building the C library. + +__POSGENOS__ - I give up. + +*/ + +#include "stdio.h" +#include "stdlib.h" +#include "string.h" +#include "stddef.h" +#include "setjmp.h" + +#if USE_MEMMGR +#include "__memmgr.h" +#endif + +#ifdef __ARM__ +#define __gnu_linux__ +#endif + +extern FILE *__userFiles[__NFILE]; + +extern void (*__userExit[__NATEXIT])(void); + +#define MAXPARMS 50 /* maximum number of arguments we can handle */ + +#ifdef __OS2__ +#define INCL_DOS +#include +#endif + +#ifdef __WIN32__ +#include +#endif + +static int runnum = 0; + +int __G_live = 0; +void *__G_ptr = NULL; +int __G_one = 1; +int __G_zero = 0; + +#ifdef __gnu_linux__ + +struct termios { + unsigned int c_iflag; + unsigned int c_oflag; + unsigned int c_cflag; + unsigned int c_lflag; + unsigned int whoknows[50]; +}; + +static struct termios tios_save; +static struct termios tios_new; + +int __ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); + +#define TCGETS 0x00005401U +#define TCSETS 0x00005402U + +#define ISIG 0x1 +#define ICANON 0x2 +#define ECHO 0x8 +#define ECHONL 0x40 + +#define IXON 0x400 + +#endif + + +#if defined(__WATCOMC__) && !defined(WATLIN) +#define CTYP __cdecl +#else +#define CTYP +#endif + +#ifdef __SMALLERC__ +#define __MSDOS__ +#endif + +#if defined(__PDOS386__) +/* Used for PDOS itself to avoid API calls when starting. */ +int __minstart = 0; +#endif + +/* will be set by __exit */ +static int globrc = 0; + +static jmp_buf jb; + +#ifndef __PDPCLIB_DLL + +/* Unfortunately Watcom requires us to make main() a watcall, + even if everything else is compiled with -ecc */ +#if defined(__WATCOMC__) +#define MAINTYP __watcall +#else +#define MAINTYP +#endif + +int MAINTYP main(int argc, char **argv); + +int __genstart = 0; +int MAINTYP (*__genmain)(int argc, char **argv) = main; + +#endif + +#ifdef __MSDOS__ +/* Must be unsigned as it is used for array index */ +#ifndef __SMALLERC__ +extern +#endif +unsigned char *__envptr; +#ifndef __SMALLERC__ +extern +#endif +unsigned short __osver; +static unsigned char *newcmdline = NULL; +#endif + +#ifdef __VSE__ +#undef __CMS__ +#undef __MVS__ +#endif + +#if defined(__MVS__) || defined(__CMS__) || defined(__VSE__) +int __tso = 0; /* is this a TSO environment? */ +extern int __doperm; /* are we doing the permanent datasets? */ +int __upsi = 0; /* UPSI switches for VSE */ +#endif + +void __exit(int status); +void CTYP __exita(int status); + +#if !defined(__MVS__) && !defined(__CMS__) && !defined(__VSE__) +static char buffer1[BUFSIZ + 8]; +static char buffer2[BUFSIZ + 8]; +static char buffer3[BUFSIZ + 8]; +#endif + +#if defined(__AMIGA__) + +#include + +struct Node { + struct Node *ln_Succ; + char filler[6]; + char *ln_Name; +}; + +struct Library { + struct Node lib_Node; + /* other junk */ +}; + +struct List { + struct Node *lh_Head; + char filler[10]; +}; + +struct ExecBase { + char filler[378]; + struct List LibList; +}; + +struct ExecBase *SysBase; +void *DOSBase; +#endif + +#if defined(__EFI__) +#include "efi.h" +#endif + +#if defined(__PDOS386__) +#include +#include +unsigned char *__envptr; +static unsigned int stdin_dw; +#endif + +#if USE_MEMMGR +extern void *__lastsup; /* last thing supplied to memmgr */ +#endif + +char **__eplist; +char *__plist; + +#ifdef __WIN32__ +static DWORD stdin_dw; +static DWORD stdout_dw; + +/* Not sure what _startupinfo is. */ +typedef int _startupinfo; + +__PDPCLIB_API__ int __getmainargs(int *_Argc, + char ***_Argv, + char ***_Env, + int _DoWildCard, + _startupinfo *_StartInfo) +{ + char *p; + int x; + int argc; + static char *argv[MAXPARMS + 1]; + static char *env[] = {NULL}; + + p = GetCommandLine(); + + /* kludge for presumed HX bug */ + if (strncmp(p, "C:\\COMMAND.COM /c", 17) == 0) + { + p += 17; + p += strspn(p, " "); + } + + argv[0] = p; + p = strchr(p, ' '); + if (p == NULL) + { + p = ""; + } + else + { + *p = '\0'; + p++; + } + + while (*p == ' ') + { + p++; + } + if (*p == '\0') + { + argv[1] = NULL; + argc = 1; + } + else + { + for (x = 1; x < MAXPARMS; ) + { + char srch = ' '; + + if (*p == '"') + { + p++; + srch = '"'; + } + argv[x] = p; + x++; + p = strchr(p, srch); + if (p == NULL) + { + break; + } + else + { + *p = '\0'; + p++; + while (*p == ' ') p++; + if (*p == '\0') break; /* strip trailing blanks */ + } + } + argv[x] = NULL; + argc = x; + } + + *_Argc = argc; + *_Argv = argv; + *_Env = env; + return (0); +} +#endif + +#if defined(__CMS__) +int __start(char *plist, char *pgmname, char **eplist) +#elif defined(__VSE__) +int __start(char *p, char *pgmname, char *ep) +#elif defined(__MVS__) +int __start(char *p, char *pgmname, int tso) +#elif defined(__gnu_linux__) +int __start(int argc, char **argv) +#elif defined(__AMIGA__) +int __start(unsigned long cmdlen, char *p, void *pdosbase) +#elif defined(__EFI__) +int __start(void) +#elif defined(__SMALLERC__) +__PDPCLIB_API__ int CTYP __start(char *p, unsigned short osver) +#else +__PDPCLIB_API__ int CTYP __start(char *p) +#endif +{ +#ifdef __CMS__ + char *p; +#endif +#ifdef __EFI__ + char *p = ""; +#endif + int x; + int oldglobrc = globrc; + jmp_buf oldjb; +#if !defined(__gnu_linux__) + int argc; + static char *argv[MAXPARMS + 1]; +#endif + int rc; +#ifdef __AMIGA__ + struct Library *library; +#endif +#ifdef __OS2__ + ULONG maxFH; + LONG reqFH; +#endif +#ifdef __MSDOS__ + unsigned char *env; + unsigned char *nclsave; +#endif +#if defined(__MVS__) || defined(__CMS__) || defined(__VSE__) + int parmLen; + int progLen; + char parmbuf[310]; /* z/VSE can have a PARM up to 300 characters */ +#endif + +#if !defined(__MVS__) && !defined(__CMS__) && !defined(__VSE__) + + runnum++; + memcpy(&oldjb, &jb, sizeof oldjb); +#ifdef __AMIGA__ + if (cmdlen >= 0x80000000UL) + { + cmdlen -= 0x80000000UL; + SysBase = (struct ExecBase *)pdosbase; + } + else + { + SysBase = *(struct ExecBase **)4; + } + if (cmdlen > 0) + { + cmdlen--; + } + p[(size_t)cmdlen] = '\0'; + argv[0] = "UNKNOWN"; + DOSBase = NULL; + library = (struct Library *)SysBase->LibList.lh_Head; + while (library != NULL) + { + if (strcmp(library->lib_Node.ln_Name, "dos.library") == 0) + { + DOSBase = library; + break; + } + library = (struct Library *)library->lib_Node.ln_Succ; + } + if (DOSBase == NULL) + { + return (-1); + } +#endif + +#ifdef __WIN32__ + if (runnum == 1) + { + __stdin->hfile = GetStdHandle(STD_INPUT_HANDLE); + { + DWORD dw; + +#ifndef ENABLE_VIRTUAL_TERMINAL_INPUT +#define ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200 +#endif + if (GetConsoleMode(__stdin->hfile, &stdin_dw)) + { + dw = stdin_dw; + dw |= ENABLE_VIRTUAL_TERMINAL_INPUT; + SetConsoleMode(__stdin->hfile, dw); + } + } + __stdout->hfile = GetStdHandle(STD_OUTPUT_HANDLE); + { + DWORD dw; + +#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING +#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 +#endif + if (GetConsoleMode(__stdout->hfile, &stdout_dw)) + { + dw = stdout_dw; + dw |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + dw |= ENABLE_PROCESSED_OUTPUT; + SetConsoleMode(__stdout->hfile, dw); + } + } + __stderr->hfile = GetStdHandle(STD_ERROR_HANDLE); + } +#elif defined(__AMIGA__) + __stdin->hfile = Input(); + __stdout->hfile = Output(); + __stderr->hfile = Output(); +#else + __stdin->hfile = 0; + __stdout->hfile = 1; + __stderr->hfile = 2; +#endif + +#if defined(__PDOS386__) + PosGetDeviceInformation(0, &stdin_dw); + stdin_dw &= 0xff; +#endif + +#if defined(__gnu_linux__) + if (runnum == 1) + { + __ioctl(0, TCGETS, (unsigned long)&tios_save); + tios_new = tios_save; + tios_new.c_iflag &= ~IXON; + tios_new.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG); + __ioctl(0, TCSETS, (unsigned long)&tios_new); + } +#endif + + if (runnum == 1) + { + __stdin->quickBin = 0; + __stdin->quickText = 0; + __stdin->textMode = 1; + __stdin->intFno = 0; + __stdin->bufStartR = 0; + __stdin->justseeked = 0; + __stdin->bufTech = _IOLBF; + __stdin->intBuffer = buffer1; + __stdin->fbuf = __stdin->intBuffer + 2; + *__stdin->fbuf++ = '\0'; + *__stdin->fbuf++ = '\0'; + __stdin->szfbuf = BUFSIZ; + __stdin->endbuf = __stdin->fbuf + __stdin->szfbuf; + *__stdin->endbuf = '\n'; + __stdin->noNl = 0; + __stdin->upto = __stdin->endbuf; + __stdin->bufStartR = -__stdin->szfbuf; + __stdin->mode = __READ_MODE; + __stdin->ungetCh = -1; + __stdin->update = 0; + __stdin->theirBuffer = 0; + __stdin->permfile = 1; + __stdin->isopen = 1; + + __stdout->quickBin = 0; + __stdout->quickText = 0; + __stdout->textMode = 1; + __stdout->bufTech = _IOLBF; + __stdout->intBuffer = buffer2; + __stdout->fbuf = __stdout->intBuffer; + *__stdout->fbuf++ = '\0'; + *__stdout->fbuf++ = '\0'; + __stdout->szfbuf = BUFSIZ; + __stdout->endbuf = __stdout->fbuf + __stdout->szfbuf; + *__stdout->endbuf = '\n'; + __stdout->noNl = 0; + __stdout->upto = __stdout->fbuf; + __stdout->bufStartR = 0; + __stdout->justseeked = 0; + __stdout->mode = __WRITE_MODE; + __stdout->update = 0; + __stdout->theirBuffer = 0; + __stdout->permfile = 1; + __stdout->isopen = 1; + + __stderr->quickBin = 0; + __stderr->quickText = 0; + __stderr->textMode = 1; + __stderr->bufTech = _IOLBF; + __stderr->intBuffer = buffer3; + __stderr->fbuf = __stderr->intBuffer; + *__stderr->fbuf++ = '\0'; + *__stderr->fbuf++ = '\0'; + __stderr->szfbuf = BUFSIZ; + __stderr->endbuf = __stderr->fbuf + __stderr->szfbuf; + *__stderr->endbuf = '\n'; + __stderr->noNl = 0; + __stderr->upto = __stderr->fbuf; + __stderr->bufStartR = 0; + __stderr->justseeked = 0; + __stderr->mode = __WRITE_MODE; + __stderr->update = 0; + __stderr->theirBuffer = 0; + __stderr->permfile = 1; + __stderr->isopen = 1; + +#if USE_MEMMGR + memmgrDefaults(&__memmgr); + memmgrInit(&__memmgr); +#endif + } + +#else + int dyna_sysprint = 0; + int dyna_systerm = 0; + int dyna_sysin = 0; +#if defined(__CMS__) +/* + This code checks to see if DDs exist for SYSIN, SYSPRINT & SYSTERM + if not it issues FD to the terminal +*/ + char s202parm [800]; /* svc 202 buffer */ + int code; + int parm; + int ret; + int have_sysparm; + + runnum++; + memcpy(&oldjb, &jb, sizeof oldjb); +/* + Now build the SVC 202 string for sysprint +*/ + memcpy ( &s202parm[0] , "FILEDEF ", 8); + memcpy ( &s202parm[8] , "SYSPRINT", 8); + memcpy ( &s202parm[16] , "( ", 8); + memcpy ( &s202parm[24] , "NOCHANGE", 8); + s202parm[32]=s202parm[33]=s202parm[34]=s202parm[35]= + s202parm[36]=s202parm[37]=s202parm[38]=s202parm[39]=0xff; +/* + and issue the SVC +*/ + ret = __SVC202 ( s202parm, &code, &parm ); + if (ret == 24) + { /* we need to issue filedef */ + memcpy ( &s202parm[16] , "TERM ", 8); + memcpy ( &s202parm[24] , "( ", 8); + memcpy ( &s202parm[32] , "LRECL ", 8); + memcpy ( &s202parm[40] , "80 ", 8); + memcpy ( &s202parm[48] , "RECFM ", 8); + memcpy ( &s202parm[56] , "F ", 8); + s202parm[64]=s202parm[65]=s202parm[66]=s202parm[67]= + s202parm[68]=s202parm[69]=s202parm[70]=s202parm[71]=0xff; + + ret = __SVC202 ( s202parm, &code, &parm ); + dyna_sysprint = 1; + } + +/* + Now build the SVC 202 string for systerm +*/ + memcpy ( &s202parm[0] , "FILEDEF ", 8); + memcpy ( &s202parm[8] , "SYSTERM ", 8); + memcpy ( &s202parm[16] , "( ", 8); + memcpy ( &s202parm[24] , "NOCHANGE", 8); + s202parm[32]=s202parm[33]=s202parm[34]=s202parm[35]= + s202parm[36]=s202parm[37]=s202parm[38]=s202parm[39]=0xff; +/* + and issue the SVC +*/ + ret = __SVC202 ( s202parm, &code, &parm ); + if (ret == 24) + { /* we need to issue filedef */ + memcpy ( &s202parm[16] , "TERM ", 8); + memcpy ( &s202parm[24] , "( ", 8); + memcpy ( &s202parm[32] , "LRECL ", 8); + memcpy ( &s202parm[40] , "80 ", 8); + memcpy ( &s202parm[48] , "RECFM ", 8); + memcpy ( &s202parm[56] , "F ", 8); + s202parm[64]=s202parm[65]=s202parm[66]=s202parm[67]= + s202parm[68]=s202parm[69]=s202parm[70]=s202parm[71]=0xff; + + ret = __SVC202 ( s202parm, &code, &parm ); + dyna_systerm = 1; + } + +/* + Now build the SVC 202 string for sysin +*/ + memcpy ( &s202parm[0] , "FILEDEF ", 8); + memcpy ( &s202parm[8] , "SYSIN ", 8); + memcpy ( &s202parm[16] , "( ", 8); + memcpy ( &s202parm[24] , "NOCHANGE", 8); + s202parm[32]=s202parm[33]=s202parm[34]=s202parm[35]= + s202parm[36]=s202parm[37]=s202parm[38]=s202parm[39]=0xff; +/* + and issue the SVC +*/ + ret = __SVC202 ( s202parm, &code, &parm ); + + if (ret == 24) + { /* we need to issue filedef */ + memcpy ( &s202parm[16] , "TERM ", 8); + memcpy ( &s202parm[24] , "( ", 8); + memcpy ( &s202parm[32] , "LRECL ", 8); + memcpy ( &s202parm[40] , "80 ", 8); + memcpy ( &s202parm[48] , "RECFM ", 8); + memcpy ( &s202parm[56] , "F ", 8); + s202parm[64]=s202parm[65]=s202parm[66]=s202parm[67]= + s202parm[68]=s202parm[69]=s202parm[70]=s202parm[71]=0xff; + + ret = __SVC202 ( s202parm, &code, &parm ); + dyna_sysin = 1; + } + +#else /* not CMS */ + runnum++; + memcpy(&oldjb, &jb, sizeof oldjb); +#endif + +#if USE_MEMMGR + memmgrDefaults(&__memmgr); + memmgrInit(&__memmgr); +#endif +#if 0 /* MUSIC */ + /* switch on lowercasing of input */ + /* normal MUSIC default is to uppercase, and it's probably + better to let the user control that with the /TEXT LC + command instead */ + __textlc(); +#endif +#if defined(__MVS__) + /* need to know if this is a TSO environment straight away + because it determines how the permanent files will be + opened */ + parmLen = ((unsigned int)p[0] << 8) | (unsigned int)p[1]; +#if 1 /* traditional way of checking to see if it is TSO */ + if ((parmLen > 0) && (p[2] == 0)) /* assume TSO */ + { + __tso = 1; + } +#else + __tso = (tso != 0); /* even "CALL" is considered to be TSO */ +#endif + +#endif /* MVS */ + __doperm = 1; + __stdout = fopen("dd:SYSPRINT", "w"); + if (__stdout == NULL) + { + __exita(EXIT_FAILURE); + } + __stdout->dynal = dyna_sysprint; + + __stderr = fopen("dd:SYSTERM", "w"); + if (__stderr == NULL) + { + printf("SYSTERM DD not defined\n"); + fclose(__stdout); + __exita(EXIT_FAILURE); + } + __stderr->dynal = dyna_systerm; + + __stdin = fopen("dd:SYSIN", "r"); + if (__stdin == NULL) + { + fprintf(__stderr, "SYSIN DD not defined\n"); + fclose(__stdout); + fclose(__stderr); + __exita(EXIT_FAILURE); + } + __stdin->dynal = dyna_sysin; + __doperm = 0; +#if defined(__CMS__) + __eplist = eplist; + __plist = plist; + + if (plist[0] == '\xff') /* are we at the fence already? */ + { + p = plist; /* yes, this is also the start of the plist */ + } + else + { + p = plist + 8; /* no, so jump past the command name */ + } + + /* Now build the SVC 202 string for sysparm */ + memcpy ( &s202parm[0] , "FILEDEF ", 8); + memcpy ( &s202parm[8] , "SYSPARM ", 8); + memcpy ( &s202parm[16] , "( ", 8); + memcpy ( &s202parm[24] , "NOCHANGE", 8); + s202parm[32]=s202parm[33]=s202parm[34]=s202parm[35]= + s202parm[36]=s202parm[37]=s202parm[38]=s202parm[39]=0xff; + /* and issue the SVC */ + ret = __SVC202 ( s202parm, &code, &parm ); + + have_sysparm = (ret != 24); + + + /* if no parameters are provided, the tokenized + plist will start with x'ff'. However, if they + have provided a SYSPARM, then we'll use that + as the parameter. But only if they haven't + provided any parameters! If they have provided + parameters then we instead lowercase everything + and go to special processing (useful when in + an EXEC with CONTROL MSG etc). */ + + /* No parameters */ + if (p[0] == 0xff) + { + parmLen = 0; + + if (have_sysparm) + { + FILE *pf; + + /* have a parameter file - let's use it */ + pf = fopen("dd:SYSPARM", "r"); + if (pf != NULL) + { + fgets(parmbuf + 2, sizeof parmbuf - 2, pf); + fclose(pf); + p = strchr(parmbuf + 2, '\n'); + if (p != NULL) + { + *p = '\0'; + } + parmLen = strlen(parmbuf + 2); + } + } + } + /* If there is no EPLIST, or there is a SYSPARM so + they are invoking special processing, then we + will be using the PLIST only. */ + else if ((eplist == NULL) || have_sysparm) + { + /* copy across the tokenized plist, which + consists of 8 character chunks, space-padded, + and terminated by x'ff'. Note that the first + 2 characters of parmbuf are reserved for an + (unused) length, so we must skip them */ + for (x = 0; x < sizeof parmbuf / 9 - 1; x++) + { + if (p[x * 8] == 0xff) break; + memcpy(parmbuf + 2 + x * 9, p + x * 8, 8); + parmbuf[2 + x * 9 + 8] = ' '; + } + parmbuf[2 + x * 9] = '\0'; + parmLen = strlen(parmbuf + 2); + + /* even though we have a SYSPARM, we don't use it, + we just use it as a signal to do some serious + underscore searching! */ + if (have_sysparm) + { + char *q; + char *r; + char *lock; + int cnt = 0; + int c; + int shift = 0; + int rev = 0; /* reverse logic */ + + q = parmbuf + 2; + r = q; + lock = q; + + /* reverse the case switching when _+ is specified + as the first parameter */ + if (memcmp(r, "_+", 2) == 0) + { + rev = 1; + cnt += 2; + r += 2; + } + while (*r != '\0') + { + cnt++; + if (rev) + { + c = toupper((unsigned char)*r); + } + else + { + c = tolower((unsigned char)*r); + } + if (shift && (c != ' ')) + { + if (rev) + { + c = tolower((unsigned char)*r); + } + else + { + c = toupper((unsigned char)*r); + } + shift = 0; + } + if (c == '_') + { + shift = 1; + } + /* if we've reached the inter-parameter space, then + collapse it - a space requires a shift */ + else if (cnt == 9) + { + while (q > lock) + { + q--; + if (*q != ' ') + { + q++; + lock = q; + break; + } + } + cnt = 0; + if (shift) + { + *q++ = ' '; + shift = 0; + } + } + else if (c != ' ') + { + *q++ = c; + } + r++; + } + *q = '\0'; + parmLen = strlen(parmbuf + 2); + } + } + /* else, we have an eplist, and no sysparm, so use that */ + else + { + parmLen = eplist[2] - eplist[1]; + /* 2 bytes reserved for an unused length, 1 byte for NUL */ + if (parmLen >= sizeof parmbuf - 2) + { + parmLen = sizeof parmbuf - 1 - 2; + } + memcpy(parmbuf + 2, eplist[1], parmLen); + } +#elif defined(__VSE__) + __upsi = pgmname[9]; /* we shouldn't really clump this */ + + if (ep != NULL) + { + ep = *(char **)ep; + } + /* The ep only has a genuine value if the top bit is set */ + if (((unsigned int)ep & 0x80000000) != 0) + { + /* it is a 24-bit address */ + ep = (char *)((unsigned int)ep & 0x00ffffff); + parmLen = *(short *)ep; + memcpy(parmbuf + 2, ep + 2, parmLen); + } + /* if no parm, use SYSPARM instead */ + else if (p[0] != 0) + { + /* in the special case of a "?", inspect the UPSI switches */ + if ((p[0] == 1) && (p[1] == '?')) + { + /* user is required to set all switches to 0. All + are reserved, except for the first one, which + says that the parameter will be read from SYSINPT */ + if (__upsi & 0x80) + { + fgets(parmbuf + 2, sizeof parmbuf - 2, __stdin); + p = strchr(parmbuf + 2, '\n'); + if (p != NULL) + { + *p = '\0'; + } + parmLen = strlen(parmbuf + 2); + } + else + { + parmLen = 0; + } + } + /* for all other parameter values, just use as-is */ + else + { + parmLen = p[0]; + memcpy(parmbuf + 2, p + 1, parmLen); + } + + } + /* otherwise there is no parm */ + else + { + parmLen = 0; + } +#else /* MVS etc */ + parmLen = ((unsigned int)p[0] << 8) | (unsigned int)p[1]; + if (parmLen >= sizeof parmbuf - 2) + { + parmLen = sizeof parmbuf - 1 - 2; + } + /* We copy the parameter into our own area because + the caller hasn't necessarily allocated room for + a terminating NUL, nor is it necessarily correct + to clobber the caller's area with NULs. */ + memcpy(parmbuf, p, parmLen + 2); +#endif + p = parmbuf; +#ifdef __MVS__ + if (__tso) +#else + if (0) +#endif + { + progLen = ((unsigned int)p[2] << 8) | (unsigned int)p[3]; + parmLen -= (progLen + 4); + argv[0] = p + 4; + p += (progLen + 4); + if (parmLen > 0) + { + *(p - 1) = '\0'; + } + else + { + *p = '\0'; + } + p[parmLen] = '\0'; + } + else /* batch or tso "call" */ + { + progLen = 0; + p += 2; + argv[0] = pgmname; + pgmname[8] = '\0'; + pgmname = strchr(pgmname, ' '); + if (pgmname != NULL) + { + *pgmname = '\0'; + } + if (parmLen > 0) + { + p[parmLen] = '\0'; + } + else + { + p = ""; + } + } +#endif /* defined(__MVS__) || defined(__CMS__) || defined(__VSE__) */ + + for (x=0; x < __NFILE; x++) + { + __userFiles[x] = NULL; + } + +#ifdef __PDPCLIB_DLL + return (0); +#endif + +#if defined(__PDOS386__) + /* PDOS-32 uses an API call returning the full command line string. */ + if (!__minstart) + { + p = PosGetCommandLine(); + __envptr = PosGetEnvBlock(); + } + else + { + /* PDOS itself is starting so no API calls should be used. */ + p = ""; + __envptr = NULL; + } +#endif + +#ifdef __WIN32__ + p = GetCommandLine(); + + /* kludge for presumed HX bug */ + if (strncmp(p, "C:\\COMMAND.COM /c", 17) == 0) + { + p += 17; + p += strspn(p, " "); + } +#endif + +#ifdef __OS2__ + reqFH = 0; + DosSetRelMaxFH(&reqFH, &maxFH); + if (maxFH < (FOPEN_MAX + 10)) + { + reqFH = FOPEN_MAX - maxFH + 10; + DosSetRelMaxFH(&reqFH, &maxFH); + } +#endif +#ifdef __OS2__ + argv[0] = p; + p += strlen(p) + 1; +#endif +#if defined(__WIN32__) || defined(__PDOS386__) + /* Windows and PDOS-32 get the full command line string. */ + argv[0] = p; + p = strchr(p, ' '); + if (p == NULL) + { + p = ""; + } + else + { + *p = '\0'; + p++; + } +#elif defined(__MSDOS__) + argv[0] = ""; + +#ifdef __SMALLERC__ + __envptr = (unsigned char *) + ((unsigned long)(*(unsigned short *)(p + 0x2c)) << 4); + __osver = osver; +#endif + + + if(__osver > 0x300) + { + env=__envptr; + if (env != NULL) + { + while (1) + { + if (*env++ == '\0' && *env++ == '\0') + { + if (*(unsigned short *)env != 0) + { + argv[0] = (char *)env + 2; + } + break; + } + } + } + } + + nclsave = newcmdline; + newcmdline = NULL; + if (p == NULL) + { + p = ""; + } + else + { + p = p + 0x80; + if (*p == 0x7f) + { + unsigned char *q; + + /* this is above the limits of the PSP, so CMDLINE + potentially has the whole command line, including + the command */ + q = getenv("CMDLINE"); + if (q != NULL) + { + q = strchr(q, ' '); + if (q != NULL) + { + q++; + newcmdline = malloc(strlen(q) + 1); + if (newcmdline != NULL) + { + strcpy(newcmdline, q); + p = newcmdline; + } + } + } + if (newcmdline == NULL) + { + fprintf(stderr, "command line too long to handle\n"); + newcmdline = nclsave; + if (runnum == 1) + { + __exit(EXIT_FAILURE); + } + runnum--; + return(EXIT_FAILURE); + } + } + else + { + p[*p + 1] = '\0'; + p++; + } + } +#endif +#if !defined(__gnu_linux__) + while (*p == ' ') + { + p++; + } + if (*p == '\0') + { + argv[1] = NULL; + argc = 1; + } + else + { + for (x = 1; x < MAXPARMS; ) + { + char srch = ' '; + + if (*p == '"') + { + p++; + srch = '"'; + } + argv[x] = p; + x++; + p = strchr(p, srch); + if (p == NULL) + { + break; + } + else + { + *p = '\0'; + p++; + while (*p == ' ') p++; + if (*p == '\0') break; /* strip trailing blanks */ + } + } + argv[x] = NULL; + argc = x; + } +#endif +#ifdef PDOS_MAIN_ENTRY + *i1 = argc; + *i2 = (int)argv; + return (0); +#elif defined(__PDPCLIB_DLL) + return (0); +#else + /* note that any executable (mainly one being used as a + pseudo-BIOS/HAL) can choose to export it's C library, + and in that case, the called program should not directly + call the OS's exit function, but should return here so + that this executable regains control. But exit() can be + called from anywhere. So we need to use setjmp and longjmp. + Note that the runnum increments for every invocation */ + + if (!__genstart) + { + rc = setjmp(jb); + if (rc != 0) + { + /* we're here because of longjmp */ + /* the invoker needs to set globrc first, otherwise + we can't distinguish a genuine return code */ + rc = globrc; + } + else + { + /* I'm not sure if we can eliminate this call to main + and always use genmain instead */ + rc = main(argc, argv); + } + } + else + { + rc = setjmp(jb); + if (rc != 0) + { + rc = globrc; + } + else + { + rc = __genmain(argc, argv); + } + } + globrc = oldglobrc; + memcpy(&jb, &oldjb, sizeof jb); + +#ifdef __MSDOS__ + if (newcmdline != NULL) + { + free(newcmdline); + } + newcmdline = nclsave; +#endif + if (runnum == 1) + { + __exit(rc); + } + runnum--; + return (rc); +#endif +} + +void _exit(int status); +void _cexit(void); +void _c_exit(void); + +void __exit(int status) +{ + /* Complete C library termination and exit with error code. */ + if (runnum == 1) + { + _cexit(); + } + +#ifdef __WIN32__ + ExitProcess(status); +#else + if (runnum == 1) + { + __exita(status); + /* in case exita returns here, which is the case for PDOS-generic + running under the pseudo-BIOS currently, decrement the run number + so that we don't get called again */ + runnum--; + /* and we can't go through another longjmp either */ + return; + } + globrc = status; + + longjmp(jb, status); + +#endif +} + +__PDPCLIB_API__ void _exit(int status) +{ + /* Quick C library termination and exit with error code.. */ + _c_exit(); + +#ifdef __WIN32__ + ExitProcess(status); +#else + __exita(status); +#endif +} + +__PDPCLIB_API__ void _cexit(void) +{ + /* Complete C library termination. */ + _c_exit(); +} + +__PDPCLIB_API__ void _c_exit(void) +{ + /* Quick C library termination. */ + int x; + +#if 0 + for (x = __NATEXIT - 1; x >= 0; x--) + { + if (__userExit[x] != 0) + { + (__userExit[x])(); + } + } +#endif + + for (x = 0; x < __NFILE; x++) + { + if (__userFiles[x] != NULL) + { +#if defined(__VSE__) + /* this should be closed after the rest of the user files */ + if (__userFiles[x] != __stdpch) +#endif + fclose(__userFiles[x]); + } + } + +#if defined(__VSE__) + if (__stdpch != NULL) fclose(__stdpch); +#endif + + if (__stdout != NULL) fflush(__stdout); + if (__stderr != NULL) fflush(__stderr); +#if defined(__WIN32__) + SetConsoleMode(__stdin->hfile, stdin_dw); + SetConsoleMode(__stdout->hfile, stdout_dw); +#endif + +#if defined(__PDOS386__) + PosSetDeviceInformation(0, stdin_dw); +#endif + +#if defined(__gnu_linux__) + if (runnum == 1) + { + __ioctl(0, TCSETS, (unsigned long)&tios_save); + } +#endif + +#if defined(__MVS__) || defined(__CMS__) || defined(__VSE__) + if (__stdin != NULL) fclose(__stdin); + if (__stdout != NULL) fclose(__stdout); + if (__stderr != NULL) fclose(__stderr); +#endif + + + if (runnum == 1) + { +#if USE_MEMMGR + memmgrTerm(&__memmgr); + +/* release memory for most circumstances, although a + better solution will be required eventually */ +#if defined(__MVS__) || defined(__CMS__) || defined(__VSE__) + if (__lastsup != NULL) + { + __freem(__lastsup); + } +#endif +#endif /* USE_MEMMGR */ + } +} + +#ifdef __WIN32__ +/* Windows extensions. */ +static int _fmode; +__PDPCLIB_API__ int *__p__fmode(void) +{ + /* Not sure what should this function do. */ + return (&_fmode); +} + +static char *_environ[] = {NULL}; +static char **_environ_ptr = _environ; +__PDPCLIB_API__ char ***__p__environ(void) +{ + /* Not sure what should this function do. */ + return (&_environ_ptr); +} + +__PDPCLIB_API__ void __set_app_type(int at) +{ + /* Not sure what should this function do. */ + ; +} + +__PDPCLIB_API__ int _setmode(int fd, int mode) +{ + /* Should change mode of file descriptor (fd) + * to mode (binary, text, Unicode...) + * and return the previous mode. + * We do not have _fileno() to convert FILE * + * to int and _fileno() can be implemented + * as macro accesing FILE internals..., + * so this function is just a dummy. */ + return (0); +} + +__PDPCLIB_API__ void (*_onexit(void (*func)(void)))(void) +{ + if (atexit(func)) return (NULL); + return (func); +} +#endif diff --git a/app/src/main/cpp/pdpclib/armeabi-v7a/stdarg.h b/app/src/main/cpp/pdpclib/armeabi-v7a/stdarg.h new file mode 100644 index 0000000..342ea40 --- /dev/null +++ b/app/src/main/cpp/pdpclib/armeabi-v7a/stdarg.h @@ -0,0 +1,60 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* stdarg.h - stdarg header file. */ +/* */ +/*********************************************************************/ + +#ifndef __STDARG_INCLUDED +#define __STDARG_INCLUDED + +/* don't use builtins on MVS until they have been implemented */ +/* don't use on EMX either */ +/* and they haven't been implemented in PDOS/386 either */ +#if 0 +if defined(__GNUC__) && !defined(__MVS__) && !defined(__CMS__) \ + && !defined(__VSE__) && !defined(__EMX__) && !defined(__PDOS386__) \ + && !defined(__gnu_linux__) && !defined(__NOBIVA__) \ + && !defined(__ARM__) +#endif + +/* Try only using builtins for GCC 4.x and above, which + appears to cover clang too */ +#if defined (__GNUC__) && __GNUC__ > 3 + +#ifndef __GNUC_VA_LIST +#define __GNUC_VA_LIST +typedef __builtin_va_list __gnuc_va_list; +#endif + +typedef __gnuc_va_list va_list; + +#define va_start(v,l) __builtin_va_start(v,l) +#define va_end(v) __builtin_va_end(v) +#define va_arg(v,l) __builtin_va_arg(v,l) +#if !defined(__STRICT_ANSI__) || __STDC_VERSION__ + 0 >= 199900L +#define va_copy(d,s) __builtin_va_copy(d,s) +#endif +#define __va_copy(d,s) __builtin_va_copy(d,s) + +#else /* __GNUC__ */ + +typedef char * va_list; + +#ifdef __XWATCOMC__ +#define va_start(ap, parmN) ap = (char far *)&parmN + sizeof(parmN) +#define va_arg(ap, type) *(type far *)(ap += sizeof(type), ap - sizeof(type)) +#else +#define va_start(ap, parmN) ap = (char *)&parmN + sizeof(parmN) +#define va_arg(ap, type) *(type *)(ap += sizeof(type), ap - sizeof(type)) +#endif +#define va_end(ap) ap = (char *)0 + +#endif + +#endif diff --git a/app/src/main/cpp/pdpclib/armeabi-v7a/stddef.h b/app/src/main/cpp/pdpclib/armeabi-v7a/stddef.h new file mode 100644 index 0000000..7a534ab --- /dev/null +++ b/app/src/main/cpp/pdpclib/armeabi-v7a/stddef.h @@ -0,0 +1,46 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* stddef.h - assert header file. */ +/* */ +/*********************************************************************/ + +#ifndef __STDDEF_INCLUDED +#define __STDDEF_INCLUDED + +typedef int ptrdiff_t; +#ifndef __SIZE_T_DEFINED +#define __SIZE_T_DEFINED +#if (defined(__OS2__) || defined(__32BIT__) || defined(__MVS__) \ + || defined(__CMS__) || defined(__VSE__) || defined(__SMALLERC__) \ + || defined(__ARM__) || defined(__gnu_linux__) || defined(__PDOS386__) \ + || defined(__SZ4__)) +typedef unsigned long size_t; +#elif (defined(__MSDOS__) || defined(__DOS__) || defined(__POWERC) \ + || defined(__WIN32__) || defined(__AMIGA__) || defined(__EFI__)) +typedef unsigned int size_t; +#endif +#endif +#ifndef __WCHAR_T_DEFINED +#define __WCHAR_T_DEFINED +#ifndef _WCHAR_T_DEFINED +#define _WCHAR_T_DEFINED +#endif +typedef char wchar_t; +#endif + +#define NULL ((void *)0) +#define offsetof(x, y) (size_t)&(((x *)0)->y) + +#ifdef __PDPCLIB_DLL +#define __PDPCLIB_API__ __declspec(dllexport) +#else +#define __PDPCLIB_API__ +#endif + +#endif diff --git a/app/src/main/cpp/pdpclib/armeabi-v7a/stdio.c b/app/src/main/cpp/pdpclib/armeabi-v7a/stdio.c new file mode 100644 index 0000000..65853f0 --- /dev/null +++ b/app/src/main/cpp/pdpclib/armeabi-v7a/stdio.c @@ -0,0 +1,6546 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/* Modifications by Dave Edwards, released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* stdio.c - implementation of stuff in stdio.h */ +/* */ +/* The philosophy of the PC/Unix/ASCII implementation is explained */ +/* here. For the MVS/CMS/EBCDIC implementation, see halfway down */ +/* this source file (or search for "design of MVS"). */ +/* */ +/* There is a static array containing pointers to file objects. */ +/* This is required in order to close all the files on program */ +/* termination. */ +/* */ +/* In order to give speed absolute priority, so that people don't */ +/* resort to calling DosRead themselves, there is a special flag */ +/* in the FILE object called "quickbin". If this flag is set to 1 */ +/* it means that it is a binary file and there is nothing in the */ +/* buffer and there are no errors, so don't stuff around, just call */ +/* DosRead. */ +/* */ +/* When a buffer exists, which is most of the time, fbuf will point */ +/* to it. The size of the buffer is given by szfbuf. upto will */ +/* point to the next character to be read. endbuf will point PAST */ +/* the last valid character in the buffer. bufStartR represents */ +/* the position in the file that the first character in the buffer */ +/* is at. This is only updated when a new buffer is read in. */ +/* */ +/* After file open, for a file being read, bufStartR will actually */ +/* be a negative number, which if added to the position of upto */ +/* will get to 0. On a file being written, bufStartR will be set */ +/* to 0, and upto will point to the start of the buffer. The */ +/* reason for the difference on the read is in order to tell the */ +/* difference between an empty buffer and a buffer with data in it, */ +/* but which hasn't been used yet. The alternative would be to */ +/* either keep track of a flag, or make fopen read in an initial */ +/* buffer. But we want to avoid reading in data that no-one has */ +/* yet requested. */ +/* */ +/* The buffer is organized as follows... */ +/* What we have is an internal buffer, which is 8 characters */ +/* longer than the actually used buffer. E.g. say BUFSIZ is */ +/* 512 bytes, then we actually allocate 520 bytes. The first */ +/* 2 characters will be junk, the next 2 characters set to NUL, */ +/* for protection against some backward-compares. The fourth-last */ +/* character is set to '\n', to protect against overscan. The */ +/* last 3 characters will be junk, to protect against memory */ +/* violation. intBuffer is the internal buffer, but everyone */ +/* refers to fbuf, which is actually set to the &intBuffer[4]. */ +/* Also, szfbuf is the size of the "visible" buffer, not the */ +/* internal buffer. The reason for the 2 junk characters at the */ +/* beginning is to align the buffer on a 4-byte boundary. */ +/* */ +/* On MVS/CMS/VSE/MUSIC, bufStartR is done differently. It starts */ +/* as 0, and fbuf, endbuf and upto are all set to the same */ +/* location - the start of the buffer. With no more data */ +/* available, a read is done, and endbuf changes according to the */ +/* size of the data read. If the application does an fread for */ +/* say 60 bytes when reading an F80 dataset, then 60 characters */ +/* will go directly into the user buffer, then the remaining */ +/* 20 bytes will go into the beginning of the internal buffer, so */ +/* the bufStartR will be adjusted to that fact, and upto and */ +/* fbuf will both point to the beginning, and endbuf will be an */ +/* additional 20 bytes ahead. */ +/* */ +/*********************************************************************/ + +#include "stdio.h" +#include "string.h" +#include "stdlib.h" +#include "stdarg.h" +#include "ctype.h" +#include "errno.h" +#include "float.h" +#include "limits.h" +#include "stddef.h" + +/* VSE is similar to MVS at the moment */ +#if defined(__VSE__) +#define __MVS__ 1 +#endif + +/* PDOS/386 and MSDOS use the same interface most of the time */ +/* Note that PDOS is for the 32-bit version, since the 16-bit + version uses the MSDOS version since it is compatible with it */ +/* linux is pretty similar too */ +#if defined(__PDOS386__) || defined(__gnu_linux__) || defined(__SMALLERC__) \ + || defined(__ARM__) +#define __MSDOS__ +#endif + +#if defined(__MSDOS__) && !defined(__gnu_linux__) && !defined(__ARM__) +#if defined(__WATCOMC__) && !defined(__32BIT__) +#define CTYP __cdecl +#else +#define CTYP +#endif +extern int CTYP __creat(const char *filename, int mode, int *errind); +extern int CTYP __open(const char *filename, int mode, int *errind); +extern int CTYP __read(int handle, void *buf, unsigned int len, int *errind); +extern int CTYP __write(int handle, const void *buf, unsigned int len, + int *errind); +extern int CTYP __seek(int handle, long offset, int whence); +extern void CTYP __close(int handle); +extern void CTYP __remove(const char *filename); +extern void CTYP __rename(const char *old, const char *newnam); +#endif + +#ifdef __AMIGA__ +#include +#endif + +#ifdef __EFI__ +#include "efi.h" +#endif + +#ifdef __OS2__ +#include +#endif + +#ifdef __WIN32__ +#include +#endif + +#if defined(__MVS__) || defined(__CMS__) +#include "mvssupa.h" +#define FIXED_BINARY 0 +#define VARIABLE_BINARY 1 +#define FIXED_TEXT 2 +#define VARIABLE_TEXT 3 +#endif + +#if defined(__gnu_linux__) || defined(__ARM__) + +extern int __open(const char *a, int b, int c); +extern int __write(int a, const void *b, int c); +extern int __read(int a, void *b, int c); +extern int __seek(int handle, long offset, int whence); +extern void __close(int handle); +extern void __remove(const char *filename); +extern void __rename(const char *old, const char *newnam); + +#define O_RDONLY 0x0 +#define O_WRONLY 0x1 +#define O_RDWR 0x2 +#define O_CREAT 0x40 +#define O_TRUNC 0x200 + +static int open(const char *a, int b, int *c) +{ + int ret = -1; + + *c = 0; + if (b == 2) + { + ret = __open(a, O_RDWR, 0); + } + else if (b == 1) + { + ret = __open(a, O_WRONLY | O_CREAT | O_TRUNC, 0664); + } + else if (b == 0) + { + ret = __open(a, O_RDONLY, 0); + } + if (ret < 0) + { + *c = 1; + } + return (ret); +} + +#define __open(a,b,c) (open((a),(b),(c))) +#define __write(a,b,c,d) (*(d) = 0, (__write)((a),(b),(c))) +#define __read(a,b,c,d) (*(d) = 0, (__read)((a),(b),(c))) + +#endif + +static FILE permFiles[3]; + +#define unused(x) ((void)(x)) +#define outch(ch) ((fq == NULL) ? *s++ = (char)ch : putc(ch, fq)) +#define inch() ((fp == NULL) ? \ + (ch = (unsigned char)*s++) : (ch = getc(fp))) + +/* We need to choose whether we are doing move mode or + locate mode */ +#if !LOCMODE /* move mode */ + + +#if defined(__VSE__) + +/* for VSE, library files are actually written to memory + during processing */ + +#define lbegwrite(stream, len) \ + ( \ + ((stream)->vselupto + (len) > (stream->vselend)) ? \ + (lenwrite = 0, dptr = NULL) : \ + (lenwrite = (len), dptr = (unsigned char *)(stream)->vselupto) \ + ) +#define lfinwrite(stream) (((stream)->vselupto += lenwrite), lenwrite) + +#define vbegwrite(stream, len) (lenwrite = (len), dptr = (stream)->asmbuf) +#define vfinwrite(stream) (__awrite((stream)->hfile, &dptr, &lenwrite)) + +#define begwrite(stream, len) ((stream)->vse_punch ? \ + lbegwrite((stream), (len)) : vbegwrite((stream), (len))) +#define finwrite(stream) ((stream)->vse_punch ? \ + lfinwrite(stream) : vfinwrite(stream)) + +#else +#define begwrite(stream, len) (lenwrite = (len), dptr = (stream)->asmbuf) +#define finwrite(stream) (__awrite((stream)->hfile, &dptr, &lenwrite)) +#endif + +#else /* locate mode */ +#define begwrite(stream, len) (lenwrite = (len), \ + __awrite((stream)->hfile, &dptr, &lenwrite)) +#define finwrite(stream) +#endif + +#if defined(__MVS__) || defined(__CMS__) +int __doperm = 0; /* are we doing the permanent datasets? */ +extern int __tso; /* are we in a TSO environment? */ +static unsigned char *dptr; +static size_t lenwrite; +static int inseek = 0; +static size_t lenread; +#define __aread(a,b) ((__aread)((a),(b),&lenread)) +#endif + + +FILE *__stdin_ptr = &permFiles[0]; +FILE *__stdout_ptr = &permFiles[1]; +FILE *__stderr_ptr = &permFiles[2]; + +FILE *__userFiles[__NFILE]; +static FILE *myfile; +static int spareSpot; +static int err; +static int inreopen = 0; + +#if defined(__VSE__) +/* for VSE library files being punched */ +#define VSE_LIB_LIM 1000000 +static char *__vsepb = NULL; +FILE *__stdpch = NULL; +#endif + +static const char *fnm; +static const char *modus; +static int modeType; + +__PDPCLIB_API__ FILE **__gtin() + { return(&__stdin_ptr); } +__PDPCLIB_API__ FILE **__gtout() + { return(&__stdout_ptr); } +__PDPCLIB_API__ FILE **__gterr() + { return(&__stderr_ptr); } + +#if defined(__WIN32__) && !defined(__STATIC__) +__PDPCLIB_API__ __DUMMYFILE _iob[3]; +#endif + +static void dblcvt(double num, char cnvtype, size_t nwidth, + int nprecision, char *result); +static int vvprintf(const char *format, va_list arg, FILE *fq, char *s); +static int vvscanf(const char *format, va_list arg, FILE *fp, const char *s); +static void fopen2(void); +static void fopen3(void); +static void findSpareSpot(void); +static void checkMode(void); +static void osfopen(void); + +#if !defined(__MVS__) && !defined(__CMS__) +static void fwriteSlow(const void *ptr, + size_t size, + size_t nmemb, + FILE *stream, + size_t towrite, + size_t *elemWritten); +static void fwriteSlowT(const void *ptr, + FILE *stream, + size_t towrite, + size_t *actualWritten); +static void fwriteSlowB(const void *ptr, + FILE *stream, + size_t towrite, + size_t *actualWritten); +static void freadSlowT(void *ptr, + FILE *stream, + size_t toread, + size_t *actualRead); +static void freadSlowB(void *ptr, + FILE *stream, + size_t toread, + size_t *actualRead); +#endif + +static int examine(const char **formt, FILE *fq, char *s, va_list *arg, + int chcount); + +#if defined(__CMS__) || defined(__MVS__) +static void filedef(char *fdddname, char *fnm, int mymode); +static void fdclr(char *ddname); +#endif +#ifdef __CMS__ +extern void __SVC202 ( char *s202parm, int *code, int *parm ); +static int cmsrename(const char *old, const char *newnam); +static int cmsremove(const char *filename); +static char *int_strtok(char *s1, const char *s2); +#define strtok int_strtok +#endif + + +__PDPCLIB_API__ int printf(const char *format, ...) +{ + va_list arg; + int ret; + + va_start(arg, format); + ret = vfprintf(__stdout, format, arg); + va_end(arg); + return (ret); +} + +__PDPCLIB_API__ int fprintf(FILE *stream, const char *format, ...) +{ + va_list arg; + int ret; + + stream = __INTFILE(stream); + + va_start(arg, format); + ret = vfprintf(stream, format, arg); + va_end(arg); + return (ret); +} + +__PDPCLIB_API__ int vfprintf(FILE *stream, const char *format, va_list arg) +{ + int ret; + + stream = __INTFILE(stream); + + stream->quickText = 0; + ret = vvprintf(format, arg, stream, NULL); + return (ret); +} + +__PDPCLIB_API__ int vprintf(const char *format, va_list arg) +{ + int ret; + + ret = vfprintf(stdout, format, arg); + return (ret); +} + +__PDPCLIB_API__ FILE *fopen(const char *filename, const char *mode) +{ +#if defined(__VSE__) + char *p; + char *q; + char memname[9]; + int memlen; + char phase[80]; + + /* for VSE, we cannot write directly to a library, we + instead need to punch appropriate controls */ + /* note that both w and wb are treated the same */ + if ((*mode == 'w') && ((p = strchr(filename, '(')) != NULL)) + { + q = strchr(filename, ')'); + if (q <= p) return (NULL); + memlen = q - p - 1; + if (memlen > (sizeof memname - 1)) + { + memlen = (sizeof memname - 1); + } + memcpy(memname, p + 1, memlen); + memname[memlen] = '\0'; + for (p = memname; *p != '\0'; p++) + { + *p = toupper((unsigned char)*p); + } + if (__stdpch == NULL) + { + __vsepb = malloc(VSE_LIB_LIM + 4); + if (__vsepb == NULL) return (NULL); + __stdpch = fopen("dd:syspunch", "wb"); + if (__stdpch != NULL) + { + __stdpch->vse_punch = 2; + __stdpch->vselupto = __vsepb; + __stdpch->vselend = __vsepb + VSE_LIB_LIM; + __stdpch->reallyu = 1; + } + } + if (__stdpch != NULL) + { + __stdpch->vse_punch = 0; + memset(phase, ' ', sizeof phase); + sprintf(phase, " PHASE %s,*", memname); + phase[strlen(phase)] = ' '; + fwrite(phase, 1, sizeof phase, __stdpch); + __stdpch->vse_punch = 2; /* in an active file */ + } + return (__stdpch); + } +#endif + + fnm = filename; + modus = mode; + err = 0; + if (!inreopen) + { + myfile = malloc(sizeof(FILE)); + } + if (myfile == NULL) + { + err = 1; + } + else + { + if (!inreopen) + { + myfile->permfile = 0; + } +#if defined(__MVS__) || defined(__CMS__) + if (__doperm) + { + myfile->permfile = 1; + } +#endif + if (inreopen) + { + spareSpot = myfile->intFno; + } + else if (!myfile->permfile) + { + findSpareSpot(); + } + if (!err) + { + fopen2(); + } + if (err && !inreopen) + { + free(myfile); + } + } + if (err && !inreopen) + { + myfile = NULL; + } +#if defined(__VSE__) + else + { + myfile->vse_punch = 0; + } +#endif + return (myfile); +} + +static void fopen2(void) +{ + checkMode(); + if (!err) + { + strcpy(myfile->modeStr, modus); + osfopen(); + if (!err) + { + if (myfile->permfile) + { + myfile->intFno = 0; + } + else + { + __userFiles[spareSpot] = myfile; + myfile->intFno = spareSpot; + } + fopen3(); + } + } + return; +} + +static void fopen3(void) +{ + myfile->intBuffer = malloc(BUFSIZ + 8); + if (myfile->intBuffer == NULL) + { + err = 1; + } + else + { + myfile->theirBuffer = 0; + myfile->fbuf = myfile->intBuffer + 2; + *myfile->fbuf++ = '\0'; + *myfile->fbuf++ = '\0'; + myfile->szfbuf = BUFSIZ; +#if !defined(__MVS__) && !defined(__CMS__) + myfile->quickText = 0; +#endif + myfile->noNl = 0; + myfile->endbuf = myfile->fbuf + myfile->szfbuf; + *myfile->endbuf = '\n'; +#if defined(__MVS__) || defined(__CMS__) + myfile->upto = myfile->fbuf; + myfile->szfbuf = myfile->lrecl; + myfile->endbuf = myfile->fbuf; /* for read only */ +#else + myfile->upto = myfile->endbuf; +#endif +#if defined(__MVS__) || defined(__CMS__) + myfile->bufStartR = 0; +#else + myfile->bufStartR = -(long)myfile->szfbuf; +#endif + myfile->justseeked = 0; + if (myfile->permfile) + { + myfile->bufTech = _IOLBF; + } + else + { + myfile->bufTech = _IOFBF; + } + myfile->errorInd = 0; + myfile->eofInd = 0; + myfile->istemp = 0; + myfile->ungetCh = -1; + myfile->update = 0; + myfile->isopen = 1; +#if !defined(__MVS__) && !defined(__CMS__) + if (!myfile->textMode) + { + myfile->quickBin = 1; + } + else + { + myfile->quickBin = 0; + } +#endif + myfile->mode = __READ_MODE; + /* gccerm, but not gccarm, seems to have a problem with this + switch */ + switch (modeType) + { + case 2: + case 5: + case 8: + case 11: + myfile->bufStartR = 0; + myfile->upto = myfile->fbuf; + myfile->mode = __WRITE_MODE; +#if defined(__MVS__) || defined(__CMS__) + myfile->endbuf = myfile->fbuf + myfile->szfbuf; +#endif + break; + } + switch (modeType) + { + case 3: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + myfile->update = 1; + myfile->quickBin = 0; + myfile->justseeked = 1; + break; + } + switch (modeType) + { + case 3: + case 6: + case 9: + case 12: + myfile->quickBin = 0; + fseek(myfile, 0, SEEK_END); + break; + } + } + return; +} + +static void findSpareSpot(void) +{ + int x; + + for (x = 0; x < __NFILE; x++) + { + if (__userFiles[x] == NULL) + { + break; + } + } + if (x == __NFILE) + { + err = 1; + } + else + { + spareSpot = x; + } + return; +} + +/* checkMode - interpret mode string */ +/* r = 1 */ +/* w = 2 */ +/* a = 3 */ +/* rb = 4 */ +/* wb = 5 */ +/* ab = 6 */ +/* r+ = 7 */ +/* w+ = 8 */ +/* a+ = 9 */ +/* r+b or rb+ = 10 */ +/* w+b or wb+ = 11 */ +/* a+b or ab+ = 12 */ + +static void checkMode(void) +{ + if (strncmp(modus, "r+b", 3) == 0) + { + modeType = 10; + } + else if (strncmp(modus, "rb+", 3) == 0) + { + modeType = 10; + } + else if (strncmp(modus, "w+b", 3) == 0) + { + modeType = 11; + } + else if (strncmp(modus, "wb+", 3) == 0) + { + modeType = 11; + } + else if (strncmp(modus, "a+b", 3) == 0) + { + modeType = 12; + } + else if (strncmp(modus, "ab+", 3) == 0) + { + modeType = 12; + } + else if (strncmp(modus, "r+", 2) == 0) + { + modeType = 7; + } + else if (strncmp(modus, "w+", 2) == 0) + { + modeType = 8; + } + else if (strncmp(modus, "a+", 2) == 0) + { + modeType = 9; + } + else if (strncmp(modus, "rb", 2) == 0) + { + modeType = 4; + } + else if (strncmp(modus, "wb", 2) == 0) + { + modeType = 5; + } + else if (strncmp(modus, "ab", 2) == 0) + { + modeType = 6; + } + else if (strncmp(modus, "r", 1) == 0) + { + modeType = 1; + } + else if (strncmp(modus, "w", 1) == 0) + { + modeType = 2; + } + else if (strncmp(modus, "a", 1) == 0) + { + modeType = 3; + } + else + { + err = 1; + return; + } + if ((modeType == 4) + || (modeType == 5) + || (modeType == 6) + || (modeType == 10) + || (modeType == 11) + || (modeType == 12)) + { + myfile->textMode = 0; + } + else + { + myfile->textMode = 1; + } + return; +} + +static void osfopen(void) +{ +#ifdef __AMIGA__ + int mode; + + if ((modeType == 1) || (modeType == 4) + || (modeType == 7) || (modeType == 10)) + { + mode = 0; /* read */ + } + else if ((modeType == 2) || (modeType == 5) + || (modeType == 8) || (modeType == 11)) + { + mode = 1; /* write */ + } + else + { + mode = 2; /* append or otherwise unsupported */ + /* because we don't have append mode implemented + at the moment on AMIGA, just return with an + error immediately */ + err = 1; + errno = 2; + return; + } + if (mode) + { + myfile->hfile = Open(fnm, MODE_NEWFILE); + } + else + { + myfile->hfile = Open(fnm, MODE_OLDFILE); + } + if (myfile->hfile == NULL) + { + err = 1; + errno = 1; + } +#endif +#ifdef __OS2__ + APIRET rc; + ULONG action; + ULONG newsize = 0; + ULONG fileAttr = 0; + ULONG openAction = 0; + ULONG openMode = 0; + + if ((modeType == 1) || (modeType == 4) || (modeType == 7) + || (modeType == 10)) + { + openAction |= OPEN_ACTION_FAIL_IF_NEW; + openAction |= OPEN_ACTION_OPEN_IF_EXISTS; + } + else if ((modeType == 2) || (modeType == 5) || (modeType == 8) + || (modeType == 11)) + { + openAction |= OPEN_ACTION_CREATE_IF_NEW; + openAction |= OPEN_ACTION_REPLACE_IF_EXISTS; + } + else if ((modeType == 3) || (modeType == 6) || (modeType == 9) + || (modeType == 12)) + { + openAction |= OPEN_ACTION_CREATE_IF_NEW; + openAction |= OPEN_ACTION_OPEN_IF_EXISTS; + } + openMode |= OPEN_SHARE_DENYWRITE; + if ((modeType == 1) || (modeType == 4)) + { + openMode |= OPEN_ACCESS_READONLY; + } + else if ((modeType == 2) || (modeType == 3) || (modeType == 5) + || (modeType == 6)) + { + openMode |= OPEN_ACCESS_WRITEONLY; + } + else + { + openMode |= OPEN_ACCESS_READWRITE; + } + if ((strlen(fnm) == 2) + && (fnm[1] == ':') + && (openMode == OPEN_ACCESS_READONLY)) + { + openMode |= OPEN_FLAGS_DASD; + } + rc = DosOpen((PSZ)fnm, + &myfile->hfile, + &action, + newsize, + fileAttr, + openAction, + openMode, + NULL); + if (rc != 0) + { + err = 1; + errno = rc; + } +#endif +#ifdef __WIN32__ + DWORD dwDesiredAccess = 0; + DWORD dwShareMode = FILE_SHARE_READ; + DWORD dwCreationDisposition = 0; + DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL; + + if ((modeType == 1) || (modeType == 4) || (modeType == 7) + || (modeType == 10)) + { + dwCreationDisposition = OPEN_EXISTING; + } + else if ((modeType == 2) || (modeType == 5) || (modeType == 8) + || (modeType == 11)) + { + dwCreationDisposition = CREATE_ALWAYS; + } + else if ((modeType == 3) || (modeType == 6) || (modeType == 9) + || (modeType == 12)) + { + dwCreationDisposition = OPEN_EXISTING; + } + if ((modeType == 1) || (modeType == 4)) + { + dwDesiredAccess = GENERIC_READ; + } + else if ((modeType == 2) || (modeType == 5)) + { + dwDesiredAccess = GENERIC_WRITE; + } + else + { + dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; + } + myfile->hfile = CreateFile(fnm, + dwDesiredAccess, + dwShareMode, + NULL, + dwCreationDisposition, + dwFlagsAndAttributes, + NULL); + if ((myfile->hfile == INVALID_HANDLE_VALUE) + && ((modeType == 3) || (modeType == 6) + || (modeType == 9) || (modeType == 12))) + { + dwCreationDisposition = CREATE_ALWAYS; + myfile->hfile = CreateFile(fnm, + dwDesiredAccess, + dwShareMode, + NULL, + dwCreationDisposition, + dwFlagsAndAttributes, + NULL); + } + if (myfile->hfile == INVALID_HANDLE_VALUE) + { + err = 1; + errno = GetLastError(); + } +#endif +#ifdef __MSDOS__ + int mode; + int errind; + + if ((modeType == 1) || (modeType == 4) + || (modeType == 7) || (modeType == 10) + || (modeType == 3) || (modeType == 6) + || (modeType == 9) || (modeType == 12)) + { + mode = 0; /* read */ + } + else if ((modeType == 2) || (modeType == 5) + || (modeType == 8) || (modeType == 11)) + { + mode = 1; /* write */ + } + else + { + err = 1; + errno = 2; + return; + } + if (mode) + { +#if defined(__gnu_linux__) || defined(__ARM__) + myfile->hfile = __open(fnm, 1, &errind); +#else + myfile->hfile = __creat(fnm, 0, &errind); +#endif + } + else + { + myfile->hfile = __open(fnm, 2, &errind); + if (errind) + { + if ((modeType == 3) || (modeType == 6) + || (modeType == 9) || (modeType == 12)) + { +#if defined(__gnu_linux__) || defined(__ARM__) + myfile->hfile = __open(fnm, 1, &errind); +#else + myfile->hfile = __creat(fnm, 0, &errind); +#endif + } + } + } + if (errind) + { + err = 1; + errno = myfile->hfile; + } +#endif +#if defined(__MVS__) || defined(__CMS__) + int mode; + char *p; + char *q; + int len; + char newfnm[FILENAME_MAX]; + char tmpdd[9]; + + if ((modeType == 1) || (modeType == 4)) + { + mode = 0; /* reading */ + } + else if ((modeType == 2) || (modeType == 5)) + { + mode = 1; /* writing */ + } + else if (modeType == 11) + { + fprintf(stderr, "we don't have the ability to do update, " + "but switching to write mode as a kludge\n"); + mode = 1; + } + else + { + mode = 2; /* update */ + + /* because we don't have the ability to update files + at the moment on MVS or CMS, just return with an + error immediately */ + err = 1; + errno = 2; + return; + } + + myfile->pdsmem[0] = '\0'; /* seek needs to know if member provided */ + + if (!inseek) + { + myfile->dynal = 0; + } +/* dw */ +/* This code needs changing for VM */ + p = strchr(fnm, ':'); + if ((p != NULL) + && ((strncmp(fnm, "dd", 2) == 0) + || (strncmp(fnm, "DD", 2) == 0))) + { + p++; + /* support a filename of dd:include/stdio.h */ + q = strchr(p, '/'); + if (q != NULL) + { + strcpy(newfnm, p); + q = strchr(newfnm, '/'); + *q = '('; + q = strchr(newfnm, '.'); + if (q != NULL) + { + strcpy(q, ")"); + } + p = newfnm; + } + } + else +/* if we are in here then there is no "dd:" on front of file */ +/* if its CMS generate a ddname and issue a filedef for the file */ +#if defined(__CMS__) + { +/* create a DD from the handle number */ + strcpy(newfnm, fnm); + p = newfnm; + while (*p != '\0') + { + *p = toupper((unsigned char)*p); + p++; + } + if (!myfile->permfile) + { + sprintf(tmpdd, "PDP%03dHD", spareSpot); + } + else + { + if (myfile == __stdout) + { + strcpy(tmpdd, "PDPOUTHD"); + } + else if (myfile == __stdin) + { + strcpy(tmpdd, "PDPINXHD"); + } + else if (myfile == __stderr) + { + strcpy(tmpdd, "PDPERRHD"); + } + } + filedef(tmpdd, newfnm, mode); + myfile->dynal = 1; + p = tmpdd; + } +#elif defined(__MVS__) + +#if !defined(MUSIC) /* for MUSIC, send everything through to SVC99 */ + if ((strchr(fnm, '\'') == NULL) && (strchr(fnm, '(') == NULL) +#if defined(__MVS__) + && !__tso +#endif + ) +#endif + { + strcpy(newfnm, fnm); + p = newfnm; + + /* The SVC 99 interface on MVS requires an uppercase + filename in order to be found via a catalog search */ + while (*p != '\0') + { + *p = toupper((unsigned char)*p); + p++; + } + /* create a DD from the handle number */ + if (!myfile->permfile) + { + sprintf(tmpdd, "PDP%03dHD", spareSpot); + } + else + { + if (myfile == __stdout) + { + strcpy(tmpdd, "PDPOUTHD"); + } + else if (myfile == __stdin) + { + strcpy(tmpdd, "PDPINXHD"); + } + else if (myfile == __stderr) + { + strcpy(tmpdd, "PDPERRHD"); + } + } + fdclr(tmpdd); /* unconditionally clear */ + filedef(tmpdd, newfnm, mode); + if (err) return; + myfile->dynal = 1; + p = tmpdd; + } + +#if !defined(MUSIC) + /* This is our traditional function for MVS. Keep it for now, + for the complex strings. For the simple strings, which + are always used on environments such as PDOS and MUSIC, + use the code above instead. */ + else + { + char rawf[FILENAME_MAX]; /* file name without member, + suitable for dynamic allocation */ + + if (!myfile->permfile) + { + sprintf(newfnm, "PDP%03dHD", spareSpot); + } + else + { + if (myfile == __stdout) + { + strcpy(newfnm, "PDPOUTHD"); + } + else if (myfile == __stdin) + { + strcpy(newfnm, "PDPINXHD"); + } + else if (myfile == __stderr) + { + strcpy(newfnm, "PDPERRHD"); + } + } + strcpy(tmpdd, newfnm); + + strcpy(rawf, ""); + /* strip any single quote */ + if ((fnm[0] == '\'') || (fnm[0] == '/')) + { + fnm++; + } +#if defined(__MVS__) && !defined(__VSE__) + else + { + /* Call IKJPARS to get a prefix */ + if (__tso) + { + char *z = "@@@@@@@Z"; /* dummy DSN */ + int len; + char *gp; + + gp = __getepf(z); + len = strlen(gp); + if (len > strlen(z)) + { + if (strcmp(gp + strlen(gp) - strlen(z), z) == 0) + { + len -= strlen(z); + } + if (len + 1 < sizeof rawf) + { + strncpy(rawf, gp, len); + rawf[len] = '\0'; + } + } + } + } +#endif + strcat(rawf, fnm); + + /* If we have a file such as "'FRED.C(MARY)'" we need to + convert this into PDP001HD(MARY) and do a dynamic + allocation of PDP001HD to "FRED.C". This involves + extracting the member name and then eliminating the member + name and any single quotes */ + p = strchr(rawf, '('); + if (p != NULL) + { + *p = '\0'; + p++; + strcat(newfnm, "("); + strcat(newfnm, p); + + p = strchr(newfnm, ')'); + if (p != NULL) + { + *(p + 1) = '\0'; + } + } + else + { + char *last; + + /* If we have a file such as "test/paul.asm" we need to convert + it into PDP001HD(PAUL) and do a dynamic allocation of + PDP001HD to "TEST.ASM" */ + while ((p = strchr(rawf, '/')) != NULL) + { + *p = '.'; + } + last = strrchr(rawf, '.'); + if (last != NULL) + { + *last++ = '\0'; + p = strrchr(rawf, '.'); + if (p == NULL) + { + p = rawf; + } + else + { + p++; + } + strcat(newfnm, "("); + if (strlen(p) > 8) + { + p[8] = '\0'; + } + strcat(newfnm, p); + strcat(newfnm, ")"); + memmove(p, last, strlen(last) + 1); + } + + /* strip any single quote */ + p = strchr(rawf, '\''); + if (p != NULL) + { + *p = '\0'; + } + } + + /* MVS requires uppercase filenames */ + p = rawf; + while (*p != '\0') + { + *p = toupper((unsigned char)*p); + p++; + } + + /* dynamically allocate file */ + errno = __dynal(strlen(tmpdd), tmpdd, strlen(rawf), rawf); + if (errno != 0) + { + err = 1; + return; + } + myfile->dynal = 1; + + p = newfnm; + } +#endif /* MUSIC */ + +#else + { + p = (char *)fnm; + } +#endif + q = p; + strcpy(myfile->ddname, " "); + len = strcspn(p, "("); + if (len > 8) + { + len = 8; + } + memcpy(myfile->ddname, p, len); + p = myfile->ddname; + while (*p != '\0') + { + *p = toupper((unsigned char)*p); + p++; + } + + p = strchr(q, '('); + if (p != NULL) + { + p++; + strcpy(myfile->pdsmem, " "); + len = strcspn(p, ")"); + if (len > 8) + { + len = 8; + } + memcpy(myfile->pdsmem, p, len); + p = myfile->pdsmem; + while (*p != '\0') + { + *p = toupper((unsigned char)*p); + p++; + } + p = myfile->pdsmem; + } + myfile->reallyu = 0; + myfile->reallyt = 0; + myfile->asmbuf = 0; + + /* Set some default DCB info. Stress - this will not interfere + in any way with DCB information the user provides in JCL, + or on an existing dataset. It is only used when all else + fails */ + if (myfile->textMode) + { + myfile->recfm = __RECFM_V; + myfile->lrecl = 255; + if (myfile->permfile) + { + /* don't block __stdout/__stderr so that output is not + delayed if the program crashes */ + myfile->blksize = 259; + } + else + { + myfile->blksize = 6233; + } + } + else + { + myfile->recfm = __RECFM_U; + myfile->lrecl = 0; + myfile->blksize = 6233; + } +#if defined(__MVS__) + /* If we are dealing with SYSIN/SYSPRINT/SYSTERM and we are + in a TSO environment, then we should use GETLINE/PUTLINE + by default, as you would expect for any other TSO + command, like LISTCAT. If people don't want that, they + should do a "CALL" to invoke the program as a + non-TSO-command-processor */ + if (__tso && myfile->permfile) + { + mode |= 0x80; /* use PUTLINE/GETLINE if available */ + } +#endif + + myfile->hfile = + __aopen(myfile->ddname, &mode, &myfile->recfm, &myfile->lrecl, + &myfile->blksize, &myfile->asmbuf, p); + + /* The true RECFM is not the "recfm" variable. True + RECFM is as follows: + + x'C0' U, x'80' F, x'40' V + x'20' T with F, V, or U; + with top two bits off, x'20' is D (ANSI variable) + T is obsolete except MVS 3.8 - track overflow + x'10' B + x'08' S (standard with F; spanned with V) + x'04' A + x'02' M (never both A and M) + */ + + myfile->true_recfm = (mode >> 16) & 0xff; + + mode &= 0x03; /* only interested in the simple mode now */ + + /* errors from MVS __aopen are negative numbers */ + if ((int)myfile->hfile <= 0) + { + err = 1; + errno = -(int)myfile->hfile; + return; + } + + /* recfm=f and v are effecively always line-buffered + because we currently do not support blocking. as + such, there is no need to switch this flag on at + the moment, as it is only relevant to recfm=u */ + myfile->line_buf = 0; + /* if we have a RECFM=U, do special processing */ + if (myfile->recfm == __RECFM_U) + { + /* sysprint etc are expected to be line-buffered, + although we allow full buffering for RECFM=UB */ + if (myfile->permfile + && ((myfile->true_recfm & 0x10) == 0) + ) + { + myfile->line_buf = 1; + } + + myfile->reallyu = 1; + myfile->quickBin = 0; /* switch off to be on the safe side */ + + /* if open for writing, kludge to switch to fixed */ + if (mode == 1) + { + myfile->recfm = __RECFM_F; + } + /* if open for reading, kludge to switch to variable */ + else if (mode == 0) + { + myfile->recfm = __RECFM_V; + } + /* we need to work with a decent lrecl in case the + assembler routine set the real thing */ + if (myfile->lrecl == 0) + { + myfile->lrecl = myfile->blksize; + if (myfile->lrecl == 0) + { + __aclose(myfile); + err = 1; + errno = 1; + return; + } + } + } + /* if we have RECFM=V, the usable lrecl is 4 bytes shorter + than we are told, so just adjust that here */ + else if (myfile->recfm == __RECFM_V) + { + if (myfile->lrecl > 4) + { + myfile->lrecl -= 4; + } + } + + if ((modeType == 4) || (modeType == 5) || (modeType == 11)) + { + myfile->style = 0; /* binary */ + } + else + { + myfile->style = 2; /* text */ + /* for RECFM=U we use binary mode when reading or writing + text files as we don't want any translation done. But + record the fact that it was really text mode */ + if (myfile->reallyu) + { + myfile->reallyt = 1; + myfile->style = 0; + } + } + + /* by the time we reach here, there is no RECFM=U, so + we only have 2 forms of binary (starting at 0) and + two forms of text (starting at 2), so we just need + to add the recfm (0 or 1) to the above. It should + probably be done in a less complicated manner! */ + myfile->style += myfile->recfm; + + if (myfile->style == VARIABLE_TEXT) + { + myfile->quickText = 1; + } + else + { + myfile->quickText = 0; + } + if (myfile->style == FIXED_BINARY) + { + myfile->quickBin = 1; + } + else + { + myfile->quickBin = 0; + } +#endif + return; +} + + +#if defined(__VSE__) + +#define CARDLEN 80 +#define MAXCDATA 56 /* maximum data bytes on TXT record */ +#define MAXRLEN (MAXCDATA * 10 - 4) /* maximum length of a single record */ + /* the 4 is to ensure the length is never on a card by itself */ + +static int vseCloseLib(FILE *stream) +{ + char card[CARDLEN]; + size_t cnt; + size_t tot; + size_t rem; + size_t upto; + size_t x; + size_t r; + size_t subtot; + + stream->vse_punch = 0; + + tot = stream->vselupto - __vsepb; + /* The file needs an EOF marker */ + memset(__vsepb + tot, 0x00, 4); + tot += 4; + + memset(card, ' ', sizeof card); + memcpy(card, "\x02" "ESD", 4); + *(short *)(card + 10) = 0x20; /* length of this ESD is the minimal 0x20 */ + *(short *)(card + 14) = 1; /* CSECT 1 */ + memset(card + 16, ' ', 8); /* name is blank */ + + *(int *)(card + 24) = 0; /* assembled origin = 0 */ + *(card + 24) = 0x04; /* PC for some reason */ + *(int *)(card + 28) = 0; /* AMODE + length - for some reason we + don't need to set the length properly. */ + +#if 0 + /* is this required? */ + *(int *)(card + 28) = tot + + (tot/MAXRLEN + ((tot % MAXRLEN) != 0)) * sizeof(int); +#endif + + memcpy(card + 32, "TOTO ", 8); /* total? */ + + /* is this required? */ + *(int *)(card + 44) = tot + + (tot/MAXRLEN + ((tot % MAXRLEN) != 0)) * sizeof(int); + fwrite(card, 1, sizeof card, stream); + + subtot = 0; + for (upto = 0; upto < tot; upto += rem) + { + rem = tot - upto; + if (rem > MAXRLEN) + { + rem = MAXRLEN; + } + for (x = 0; x < rem; x += r) + { + r = rem - x; + if (r > MAXCDATA) + { + r = MAXCDATA; + } + if ((x == 0) && (r > (MAXCDATA - sizeof(int)))) + { + r -= sizeof(int); + } + memset(card, ' ', sizeof card); + memcpy(card, "\x02" "TXT", 4); + *(int *)(card + 4) = subtot; /* origin */ + card[4] = ' '; + *(short *)(card + 10) = r + ((x == 0) ? sizeof(int) : 0); + /* byte count */ + *(int *)(card + 12) = 1; /* CSECT 1 */ + if (x == 0) + { + *(int *)(card + 16) = rem; + if ((upto + rem) >= tot) + { + *(int *)(card + 16) -= 4; + } + memcpy(card + 16 + sizeof(int), __vsepb + upto, r); + subtot += (r + sizeof(int)); + } + else + { + memcpy(card + 16, __vsepb + upto + x, r); + subtot += r; + } + fwrite(card, 1, sizeof card, stream); + } + } + memset(card, ' ', sizeof card); + memcpy(card, "\x02" "END", 4); +#if 0 + /* is this required? */ + *(int *)(card + 24) = tot + + (tot/MAXRLEN + ((tot % MAXRLEN) != 0)) * sizeof(int); +#endif + fwrite(card, 1, sizeof card, stream); + + stream->vselupto = __vsepb; + stream->vse_punch = 1; /* still the punch, but not active */ + + return (0); +} +#endif + + +__PDPCLIB_API__ int fclose(FILE *stream) +{ +#ifdef __OS2__ + APIRET rc; +#endif +#ifdef __WIN32__ + BOOL rc; +#endif + + stream = __INTFILE(stream); + + if (!stream->isopen) + { + return (EOF); + } + fflush(stream); +#ifdef __VSE__ + /* only take action if in an active file */ + if (stream->vse_punch == 2) + { + stream->upto = stream->fbuf; + stream->bufStartR = 0; + return (vseCloseLib(stream)); + } + /* closing an inactive punch must be the real thing, so free + the buffer and go through the rest of the close logic. */ + else if (stream->vse_punch == 1) + { + free(__vsepb); + __vsepb = NULL; + } +#endif +#ifdef __AMIGA__ + Close(stream->hfile); +#endif +#ifdef __OS2__ + rc = DosClose(stream->hfile); +#endif +#ifdef __WIN32__ + rc = CloseHandle(stream->hfile); +#endif +#ifdef __MSDOS__ + __close(stream->hfile); +#endif +#if defined(__MVS__) || defined(__CMS__) + if ((stream->mode == __WRITE_MODE) && (stream->upto != stream->fbuf)) + { + if (stream->reallyu) + { + /* we should not get to here, because the flush would + have taken care of it. perhaps we can generate an + internal error */ + } + else if (stream->textMode) + { + putc('\n', stream); + } + else + { + size_t remain; + size_t x; + + remain = stream->endbuf - stream->upto; + for (x = 0; x < remain; x++) + { + putc(0x00, stream); + } + } + } + __aclose(stream->hfile); +#ifdef __CMS__ + if (stream->dynal && !inseek) + { + fdclr(stream->ddname); + } +#endif +#endif + if (!stream->theirBuffer) + { +#if !defined(__MVS__) && !defined(__CMS__) && !defined(__VSE__) + /* on the PC, permanent files have a static buffer */ + if (!stream->permfile) +#endif + free(stream->intBuffer); + } + if (!stream->permfile && !inreopen) + { +#if !defined(__MVS__) && !defined(__CMS__) + if (stream->istemp) + { + remove("ZZZZZZZA.$$$"); + } +#endif + __userFiles[stream->intFno] = NULL; + free(stream); + } + else + { +#if defined(__MVS__) || defined(__CMS__) + /* if we're not in the middle of freopen ... */ + if (!stream->permfile) + { + __userFiles[stream->intFno] = NULL; + } + if (!inreopen) + { + free(stream); + /* need to protect against the app closing the file + which it is allowed to */ + if (stream == __stdin) + { + __stdin = NULL; + } + else if (stream == __stdout) + { + __stdout = NULL; + } + else if (stream == __stderr) + { + __stderr = NULL; + } + } +#else + stream->isopen = 0; +#endif + } +#ifdef __OS2__ + if (rc != 0) + { + errno = rc; + return (EOF); + } +#endif +#ifdef __WIN32__ + if (!rc) + { + errno = GetLastError(); + return (EOF); + } +#endif + return (0); +} + + +#if !defined(__MVS__) && !defined(__CMS__) +static void iread(FILE *stream, void *ptr, size_t toread, size_t *actualRead) +{ +#ifdef __AMIGA__ + long tempRead; +#endif +#ifdef __OS2__ + APIRET rc; + ULONG tempRead; +#endif +#ifdef __WIN32__ + BOOL rc; + DWORD tempRead; +#endif +#ifdef __MSDOS__ + int errind; + size_t tempRead; +#endif + +#ifdef __AMIGA__ + tempRead = Read(stream->hfile, ptr, toread); + if (tempRead == -1) + { + *actualRead = 0; + stream->errorInd = 1; + } + else + { + *actualRead = tempRead; + } +#endif +#ifdef __OS2__ + rc = DosRead(stream->hfile, ptr, toread, &tempRead); + if (rc != 0) + { + *actualRead = 0; + stream->errorInd = 1; + errno = rc; + } + else + { + *actualRead = tempRead; + } +#endif +#ifdef __WIN32__ + rc = ReadFile(stream->hfile, + ptr, + toread, + &tempRead, + NULL); + if (!rc) + { + *actualRead = 0; + stream->errorInd = 1; + errno = GetLastError(); + } + else + { + size_t x; + char *p; + + *actualRead = tempRead; + /* Windows returns DEL for backspace instead of ^H so we + convert to ^H now */ + if (stream == stdin) + { + p = ptr; + for (x = 0; x < *actualRead; x++) + { + if (p[x] == 0x7f) + { + p[x] = 0x08; + } + } + } + } +#endif +#ifdef __MSDOS__ + tempRead = __read(stream->hfile, ptr, toread, &errind); + if (errind) + { + errno = tempRead; + *actualRead = 0; + stream->errorInd = 1; + } + else + { + *actualRead = tempRead; + } +#endif + return; +} + + +__PDPCLIB_API__ size_t fread(void *ptr, + size_t size, + size_t nmemb, + FILE *stream) +{ + size_t toread; + size_t elemRead; + size_t actualRead; + + stream = __INTFILE(stream); + + if (nmemb == 1) + { + toread = size; + } + else if (size == 1) + { + toread = nmemb; + } + else + { + toread = size * nmemb; + } + if (toread < stream->szfbuf) + { + stream->quickBin = 0; + } + if (stream->ungetCh != -1) + { + *--stream->upto = (char)stream->ungetCh; + stream->ungetCh = -1; + } + if (!stream->quickBin) + { + /* if we were previously writing and then + we seeked, and now we're reading, we need to + correct things */ + if (stream->justseeked) + { + stream->justseeked = 0; + if (stream->mode == __WRITE_MODE) + { + stream->bufStartR -= (stream->endbuf - stream->fbuf); + stream->upto = stream->endbuf; + stream->mode = __READ_MODE; + } + } + if (stream->textMode) + { + freadSlowT(ptr, stream, toread, &actualRead); + } + else + { + if (toread <= (stream->endbuf - stream->upto)) + { + memcpy(ptr, stream->upto, toread); + actualRead = toread; + stream->upto += toread; + } + else + { + freadSlowB(ptr, stream, toread, &actualRead); + } + } + if (nmemb == 1) + { + if (actualRead == size) + { + elemRead = 1; + } + else + { + elemRead = 0; + } + } + else if (size == 1) + { + elemRead = actualRead; + } + else + { + if (size == 0) + { + elemRead = 0; + } + else + { + elemRead = actualRead / size; + } + } + return (elemRead); + } + else + { + iread(stream, ptr, toread, &actualRead); + if (nmemb == 1) + { + if (actualRead == size) + { + elemRead = 1; + } + else + { + elemRead = 0; + stream->eofInd = 1; + } + } + else if (size == 1) + { + elemRead = actualRead; + if (nmemb != actualRead) + { + stream->eofInd = 1; + } + } + else + { + if (size == 0) + { + elemRead = 0; + } + else + { + elemRead = actualRead / size; + } + if (toread != actualRead) + { + stream->eofInd = 1; + } + } + stream->bufStartR += actualRead; + return (elemRead); + } +} + + +/* +while toread has not been satisfied +{ + scan stuff out of buffer, replenishing buffer as required +} +*/ + +static void freadSlowT(void *ptr, + FILE *stream, + size_t toread, + size_t *actualRead) +{ + int finReading = 0; + size_t avail; + size_t need; + char *p; + size_t got; + size_t tempRead; + + *actualRead = 0; + while (!finReading) + { + if (stream->upto == stream->endbuf) + { + iread(stream, stream->fbuf, stream->szfbuf, &tempRead); + if (tempRead == 0) + { + stream->eofInd = 1; + break; + } + stream->bufStartR += (stream->upto - stream->fbuf); + stream->endbuf = stream->fbuf + tempRead; + *stream->endbuf = '\n'; + stream->upto = stream->fbuf; + } + avail = (size_t)(stream->endbuf - stream->upto) + 1; + need = toread - *actualRead; + p = memchr(stream->upto, '\n', avail); + got = (size_t)(p - stream->upto); + if (need < got) + { + memcpy((char *)ptr + *actualRead, stream->upto, need); + stream->upto += need; + *actualRead += need; + } + else + { + memcpy((char *)ptr + *actualRead, stream->upto, got); + stream->upto += got; + *actualRead += got; + if (p != stream->endbuf) + { + if (*(stream->upto - 1) == '\r') + { + *((char *)ptr + *actualRead - 1) = '\n'; + stream->upto++; + } + else if (need != got) + { + *((char *)ptr + *actualRead) = '\n'; + *actualRead += 1; + stream->upto++; + } + } + else + { + if (*(stream->upto - 1) == '\r') + { +#ifdef __WIN32__ + if ((stream == stdin) + && (stream->bufTech == _IONBF)) + { + *((char *)ptr + *actualRead - 1) = '\n'; + } + else +#endif + *actualRead -= 1; + } + } + } + if (*actualRead == toread) + { + finReading = 1; + } + } + return; +} + +static void freadSlowB(void *ptr, + FILE *stream, + size_t toread, + size_t *actualRead) +{ + size_t avail; + size_t left; + size_t tempRead; + + avail = (size_t)(stream->endbuf - stream->upto); + memcpy(ptr, stream->upto, avail); + left = toread - avail; + *actualRead = avail; + stream->bufStartR += (stream->endbuf - stream->fbuf); + if (stream->eofInd) + { + return; + } + if (left >= stream->szfbuf) + { + iread(stream, (char *)ptr + *actualRead, left, &tempRead); + if (stream->errorInd) + { + } + else if (tempRead != left) + { + stream->eofInd = 1; + } + *actualRead += tempRead; + stream->quickBin = 1; + if (tempRead >= stream->szfbuf) + { + stream->bufStartR += (tempRead - stream->szfbuf); + stream->endbuf = stream->fbuf + stream->szfbuf; + } + else + { + stream->endbuf = stream->fbuf + tempRead; + *stream->endbuf = '\n'; + } + stream->upto = stream->endbuf; + } + else + { + stream->upto = stream->fbuf; + iread(stream, stream->fbuf, stream->szfbuf, &tempRead); + if (stream->errorInd) + { + } + else if (tempRead < left) + { + stream->eofInd = 1; + } + stream->endbuf = stream->fbuf + tempRead; + *stream->endbuf = '\n'; + avail = (size_t)(stream->endbuf - stream->upto); + if (avail > left) + { + avail = left; + } + memcpy((char *)ptr + *actualRead, + stream->upto, + avail); + stream->upto += avail; + *actualRead += avail; + } + return; +} +#endif + + +#if !defined(__MVS__) && !defined(__CMS__) +static void iwrite(FILE *stream, + const void *ptr, + size_t towrite, + size_t *actualWritten) +{ +#ifdef __AMIGA__ + long tempWritten; +#endif +#ifdef __OS2__ + ULONG tempWritten; + APIRET rc; +#endif +#ifdef __WIN32__ + DWORD tempWritten; + BOOL rc; +#endif +#ifdef __MSDOS__ + size_t tempWritten; + int errind; +#endif +#ifdef __EFI__ + size_t tempWritten; + static CHAR16 onechar[2] = {0, '\0'}; +#endif + +#ifdef __AMIGA__ + tempWritten = Write(stream->hfile, ptr, towrite); + if (tempWritten == -1) + { + stream->errorInd = 1; + tempWritten = 0; + errno = 1; + } +#endif +#ifdef __OS2__ + rc = DosWrite(stream->hfile, (VOID *)ptr, towrite, &tempWritten); + if (rc != 0) + { + stream->errorInd = 1; + tempWritten = 0; + errno = rc; + } +#endif +#ifdef __WIN32__ + rc = WriteFile(stream->hfile, ptr, towrite, &tempWritten, NULL); + if (!rc) + { + stream->errorInd = 1; + tempWritten = 0; + errno = GetLastError(); + } +#endif +#ifdef __MSDOS__ + tempWritten = __write(stream->hfile, + ptr, + towrite, + &errind); + if (errind) + { + stream->errorInd = 1; + tempWritten = 0; + errno = 1; + } +#endif +#ifdef __EFI__ + for (tempWritten = 0; tempWritten < towrite; tempWritten++) + { + onechar[0] = *((unsigned char *)ptr + tempWritten); + if (onechar[0] == '\n') + { + onechar[0] = '\r'; + __gST->ConOut->OutputString(__gST->ConOut, onechar); + onechar[0] = '\n'; + } + __gST->ConOut->OutputString(__gST->ConOut, onechar); + } +#endif + *actualWritten = tempWritten; + return; +} + + +__PDPCLIB_API__ size_t fwrite(const void *ptr, + size_t size, + size_t nmemb, + FILE *stream) +{ + size_t towrite; + size_t elemWritten; + size_t actualWritten; + + stream = __INTFILE(stream); + + if (nmemb == 1) + { + towrite = size; + } + else if (size == 1) + { + towrite = nmemb; + } + else + { + towrite = size * nmemb; + } + if (towrite < stream->szfbuf) + { + stream->quickBin = 0; + if ((stream->bufTech == _IONBF) && !stream->textMode) + { + stream->quickBin = 1; + } + } + if (!stream->quickBin) + { + fwriteSlow(ptr, size, nmemb, stream, towrite, &elemWritten); + return (elemWritten); + } + else + { + iwrite(stream, ptr, towrite, &actualWritten); + if (nmemb == 1) + { + if (actualWritten == size) + { + elemWritten = 1; + } + else + { + elemWritten = 0; + } + } + else if (size == 1) + { + elemWritten = actualWritten; + } + else + { + elemWritten = actualWritten / size; + } + stream->bufStartR += actualWritten; + return (elemWritten); + } +} + +static void fwriteSlow(const void *ptr, + size_t size, + size_t nmemb, + FILE *stream, + size_t towrite, + size_t *elemWritten) +{ + size_t actualWritten; + + if (stream->justseeked) + { + stream->justseeked = 0; + if (stream->mode == __READ_MODE) + { + stream->bufStartR += (stream->endbuf - stream->fbuf); + stream->upto = stream->fbuf; + stream->mode = __WRITE_MODE; + } + } + if ((stream->textMode) || (stream->bufTech == _IOLBF)) + { + fwriteSlowT(ptr, stream, towrite, &actualWritten); + } + else + { + fwriteSlowB(ptr, stream, towrite, &actualWritten); + } + if (nmemb == 1) + { + if (actualWritten == size) + { + *elemWritten = 1; + } + else + { + *elemWritten = 0; + } + } + else if (size == 1) + { + *elemWritten = actualWritten; + } + else + { + *elemWritten = actualWritten / size; + } + return; +} + + +/* can still be called on binary files, if the binary file is + line buffered */ + +static void fwriteSlowT(const void *ptr, + FILE *stream, + size_t towrite, + size_t *actualWritten) +{ + char *p; + char *tptr; + char *oldp; + size_t diffp; + size_t rem; + int fin; + size_t tempWritten; + + *actualWritten = 0; + tptr = (char *)ptr; + p = tptr; + oldp = p; + p = (char *)memchr(oldp, '\n', towrite - (size_t)(oldp - tptr)); + while (p != NULL) + { + diffp = (size_t)(p - oldp); + fin = 0; + while (!fin) + { + rem = (size_t)(stream->endbuf - stream->upto); + if (diffp < rem) + { + memcpy(stream->upto, oldp, diffp); + stream->upto += diffp; + *actualWritten += diffp; + fin = 1; + } + else + { + memcpy(stream->upto, oldp, rem); + oldp += rem; + diffp -= rem; + iwrite(stream, stream->fbuf, stream->szfbuf, &tempWritten); + if (stream->errorInd) return; + + *actualWritten += rem; + stream->upto = stream->fbuf; + stream->bufStartR += tempWritten; + } + } + rem = (size_t)(stream->endbuf - stream->upto); + if (rem < 3) + { + iwrite(stream, + stream->fbuf, + stream->upto - stream->fbuf, + &tempWritten); + if (stream->errorInd) return; + stream->upto = stream->fbuf; + stream->bufStartR += tempWritten; + } +#if !defined(__gnu_linux__) && !defined(__ARM__) + if (stream->textMode) + { + memcpy(stream->upto, "\r\n", 2); + stream->upto += 2; + } + else +#endif + { + memcpy(stream->upto, "\n", 1); + stream->upto += 1; + } + *actualWritten += 1; + oldp = p + 1; + p = (char *)memchr(oldp, '\n', towrite - (size_t)(oldp - tptr)); + } + + if ((stream->bufTech == _IOLBF) + && (stream->upto != stream->fbuf) + && (oldp != tptr)) + { + iwrite(stream, + stream->fbuf, + stream->upto - stream->fbuf, + &tempWritten); + if (stream->errorInd) return; + stream->upto = stream->fbuf; + stream->bufStartR += tempWritten; + } + + diffp = towrite - *actualWritten; + while (diffp != 0) + { + rem = (size_t)(stream->endbuf - stream->upto); + if (diffp < rem) + { + memcpy(stream->upto, oldp, diffp); + stream->upto += diffp; + *actualWritten += diffp; + } + else + { + memcpy(stream->upto, oldp, rem); + iwrite(stream, stream->fbuf, stream->szfbuf, &tempWritten); + if (stream->errorInd) return; + else + { + *actualWritten += rem; + stream->upto = stream->fbuf; + } + stream->bufStartR += tempWritten; + oldp += rem; + } + diffp = towrite - *actualWritten; + } + if ((stream->bufTech == _IONBF) + && (stream->upto != stream->fbuf)) + { + iwrite(stream, + stream->fbuf, + stream->upto - stream->fbuf, + &tempWritten); + if (stream->errorInd) return; + stream->upto = stream->fbuf; + stream->bufStartR += tempWritten; + } + return; +} + +/* whilst write requests are smaller than a buffer, we do not turn + on quickbin */ + +static void fwriteSlowB(const void *ptr, + FILE *stream, + size_t towrite, + size_t *actualWritten) +{ + size_t spare; + size_t tempWritten; + size_t left; + spare = (size_t)(stream->endbuf - stream->upto); + if (towrite < spare) + { + memcpy(stream->upto, ptr, towrite); + *actualWritten = towrite; + stream->upto += towrite; + return; + } + memcpy(stream->upto, ptr, spare); + iwrite(stream, stream->fbuf, stream->szfbuf, &tempWritten); + if (stream->errorInd) return; + *actualWritten = spare; + stream->upto = stream->fbuf; + stream->bufStartR += tempWritten; + left = towrite - *actualWritten; + if (left > stream->szfbuf) + { + stream->quickBin = 1; + iwrite(stream, (const char *)ptr + *actualWritten, left, &tempWritten); + if (stream->errorInd) return; + *actualWritten += tempWritten; + stream->bufStartR += *actualWritten; + } + else + { + memcpy(stream->fbuf, + (char *)ptr + *actualWritten, + left); + stream->upto += left; + *actualWritten += left; + } + return; +} +#endif + +static int vvprintf(const char *format, va_list arg, FILE *fq, char *s) +{ + int fin = 0; + int vint; + double vdbl; + unsigned int uvint; + const char *vcptr; + int chcount = 0; + size_t len; + char numbuf[50]; + char *nptr; + int *viptr; + + while (!fin) + { + if (*format == '\0') + { + fin = 1; + } + else if (*format == '%') + { + format++; + if (*format == 'd') + { + vint = va_arg(arg, int); + if (vint < 0) + { + uvint = -vint; + } + else + { + uvint = vint; + } + nptr = numbuf; + do + { + *nptr++ = (char)('0' + uvint % 10); + uvint /= 10; + } while (uvint > 0); + if (vint < 0) + { + *nptr++ = '-'; + } + do + { + nptr--; + outch(*nptr); + chcount++; + } while (nptr != numbuf); + } + else if (strchr("eEgGfF", *format) != NULL && *format != 0) + { + vdbl = va_arg(arg, double); + dblcvt(vdbl, *format, 0, 6, numbuf); /* 'e','f' etc. */ + len = strlen(numbuf); + if (fq == NULL) + { + memcpy(s, numbuf, len); + s += len; + } + else + { + fputs(numbuf, fq); + } + chcount += len; + } + else if (*format == 's') + { + vcptr = va_arg(arg, const char *); + if (vcptr == NULL) + { + vcptr = "(null)"; + } + if (fq == NULL) + { + len = strlen(vcptr); + memcpy(s, vcptr, len); + s += len; + chcount += len; + } + else + { + fputs(vcptr, fq); + chcount += strlen(vcptr); + } + } + else if (*format == 'c') + { + vint = va_arg(arg, int); + outch(vint); + chcount++; + } + else if (*format == 'n') + { + viptr = va_arg(arg, int *); + *viptr = chcount; + } + else if (*format == '%') + { + outch('%'); + chcount++; + } + else + { + int extraCh; + + extraCh = examine(&format, fq, s, &arg, chcount); + chcount += extraCh; + if (s != NULL) + { + s += extraCh; + } + } + } + else + { + outch(*format); + chcount++; + } + format++; + } + return (chcount); +} + +static int examine(const char **formt, FILE *fq, char *s, va_list *arg, + int chcount) +{ + int extraCh = 0; + int flagMinus = 0; + int flagPlus = 0; + int flagSpace = 0; + int flagHash = 0; + int flagZero = 0; + int width = 0; + int precision = -1; + int half = 0; + int lng = 0; + int specifier = 0; + int fin; + long lvalue; + short int hvalue; + int ivalue; + unsigned long ulvalue; + double vdbl; + char *svalue; + char work[50]; + int x; + int y; + int rem; + const char *format; + int base; + int fillCh; + int neg; + int length; + size_t slen; + + unused(chcount); + format = *formt; + /* processing flags */ + fin = 0; + while (!fin) + { + switch (*format) + { + case '-': flagMinus = 1; + break; + case '+': flagPlus = 1; + break; + case ' ': flagSpace = 1; + break; + case '#': flagHash = 1; + break; + case '0': flagZero = 1; + break; + case '*': width = va_arg(*arg, int); + if (width < 0) + { + flagMinus = 1; + width = -width; + } + break; + default: fin = 1; + break; + } + if (!fin) + { + format++; + } + else + { + if (flagSpace && flagPlus) + { + flagSpace = 0; + } + if (flagMinus) + { + flagZero = 0; + } + } + } + + /* processing width */ + if (isdigit((unsigned char)*format)) + { + while (isdigit((unsigned char)*format)) + { + width = width * 10 + (*format - '0'); + format++; + } + } + + /* processing precision */ + if (*format == '.') + { + format++; + if (*format == '*') + { + precision = va_arg(*arg, int); + format++; + } + else + { + precision = 0; + while (isdigit((unsigned char)*format)) + { + precision = precision * 10 + (*format - '0'); + format++; + } + } + } + + /* processing h/l/L */ + if (*format == 'h') + { + /* all environments should promote shorts to ints, + so we should be able to ignore the 'h' specifier. + It will create problems otherwise. */ + /* half = 1; */ + } + else if (*format == 'l') + { + lng = 1; + } + else if (*format == 'L') + { + lng = 1; + } + else + { + format--; + } + format++; + + /* processing specifier */ + specifier = *format; + + if (strchr("dxXuiop", specifier) != NULL && specifier != 0) + { + if (precision < 0) + { + precision = 1; + } +#if defined(__MSDOS__) && \ + !defined(__PDOS386__) && \ + !defined(__SMALLERC__) && \ + !defined(__gnu_linux__) && \ + !defined(__ARM__) + if (specifier == 'p') + { + lng = 1; + lvalue = (long)va_arg(*arg, void *); + } + else +#endif + if (lng) + { + lvalue = va_arg(*arg, long); + } + else if (half) + { + /* short is promoted to int, so use int */ + hvalue = va_arg(*arg, int); + if (specifier == 'u') lvalue = (unsigned short)hvalue; + else lvalue = hvalue; + } + else + { + ivalue = va_arg(*arg, int); + if (specifier == 'u') lvalue = (unsigned int)ivalue; + else lvalue = ivalue; + } + ulvalue = (unsigned long)lvalue; + if ((lvalue < 0) && ((specifier == 'd') || (specifier == 'i'))) + { + neg = 1; + ulvalue = -lvalue; + } + else + { + neg = 0; + } +#if defined(__MSDOS__) && \ + !defined(__PDOS386__) && \ + !defined(__SMALLERC__) && \ + !defined(__gnu_linux__) && \ + !defined(__ARM__) + if (!lng) + { + ulvalue &= 0xffff; + } +#endif + if ((specifier == 'X') || (specifier == 'x') || (specifier == 'p')) + { + base = 16; + } + else if (specifier == 'o') + { + base = 8; + } + else + { + base = 10; + } + if (specifier == 'p') + { +#if defined(__MSDOS__) && \ + !defined(__PDOS386__) && \ + !defined(__SMALLERC__) && \ + !defined(__gnu_linux__) && \ + !defined(__ARM__) + precision = 9; +#else + precision = 8; +#endif + } + x = 0; + while (ulvalue > 0) + { + rem = (int)(ulvalue % base); + if (rem < 10) + { + work[x] = (char)('0' + rem); + } + else + { + if ((specifier == 'X') || (specifier == 'p')) + { + work[x] = (char)('A' + (rem - 10)); + } + else + { + work[x] = (char)('a' + (rem - 10)); + } + } + x++; +#if defined(__MSDOS__) && \ + !defined(__PDOS386__) && \ + !defined(__SMALLERC__) && \ + !defined(__gnu_linux__) && \ + !defined(__ARM__) + if ((x == 4) && (specifier == 'p')) + { + work[x] = ':'; + x++; + } +#endif + ulvalue = ulvalue / base; + } +#if defined(__MSDOS__) && \ + !defined(__PDOS386__) && \ + !defined(__SMALLERC__) && \ + !defined(__gnu_linux__) && \ + !defined(__ARM__) + if (specifier == 'p') + { + while (x < 5) + { + work[x] = (x == 4) ? ':' : '0'; + x++; + } + } +#endif + while (x < precision) + { + work[x] = '0'; + x++; + } + if (neg) + { + work[x++] = '-'; + } + else if (flagPlus) + { + work[x++] = '+'; + } + else if (flagSpace) + { + work[x++] = ' '; + } + if (flagZero) + { + fillCh = '0'; + } + else + { + fillCh = ' '; + } + y = x; + if (!flagMinus) + { + while (y < width) + { + outch(fillCh); + extraCh++; + y++; + } + } + if (flagHash && (toupper((unsigned char)specifier) == 'X')) + { + outch('0'); + outch('x'); + extraCh += 2; + } + x--; + while (x >= 0) + { + outch(work[x]); + extraCh++; + x--; + } + if (flagMinus) + { + while (y < width) + { + outch(fillCh); + extraCh++; + y++; + } + } + } + else if (strchr("eEgGfF", specifier) != NULL && specifier != 0) + { + if (precision < 0) + { + precision = 6; + } + vdbl = va_arg(*arg, double); + dblcvt(vdbl, specifier, width, precision, work); /* 'e','f' etc. */ + slen = strlen(work); + if ((flagSpace || flagPlus) && (work[0] != '-')) + { + slen++; + memmove(work + 1, work, slen); + if (flagSpace) + { + work[0] = ' '; + } + else if (flagPlus) + { + work[0] = '+'; + } + } + if (fq == NULL) + { + memcpy(s, work, slen); + s += slen; + } + else + { + fputs(work, fq); + } + extraCh += slen; + } + else if (specifier == 's') + { + svalue = va_arg(*arg, char *); + fillCh = ' '; + if (precision > 0) + { + char *p; + + p = memchr(svalue, '\0', precision); + if (p != NULL) + { + length = (int)(p - svalue); + } + else + { + length = precision; + } + } + else if (precision < 0) + { + length = strlen(svalue); + } + else + { + length = 0; + } + if (!flagMinus) + { + if (length < width) + { + extraCh += (width - length); + for (x = 0; x < (width - length); x++) + { + outch(fillCh); + } + } + } + for (x = 0; x < length; x++) + { + outch(svalue[x]); + } + extraCh += length; + if (flagMinus) + { + if (length < width) + { + extraCh += (width - length); + for (x = 0; x < (width - length); x++) + { + outch(fillCh); + } + } + } + } + *formt = format; + return (extraCh); +} + +__PDPCLIB_API__ int fputc(int c, FILE *stream) +{ + char buf[1]; + + stream = __INTFILE(stream); + +#if !defined(__MVS__) && !defined(__CMS__) + stream->quickBin = 0; + if ((stream->upto < (stream->endbuf - 2)) + && (stream->bufTech != _IONBF)) + { + if (stream->textMode) + { + if (c == '\n') + { + if (stream->bufTech == _IOFBF) + { + *stream->upto++ = '\r'; + *stream->upto++ = '\n'; + } + else + { + buf[0] = (char)c; + if (fwrite(buf, 1, 1, stream) != 1) + { + return (EOF); + } + } + } + else + { + *stream->upto++ = (char)c; + } + } + else + { + *stream->upto++ = (char)c; + } + } + else +#endif + { + buf[0] = (char)c; + if (fwrite(buf, 1, 1, stream) != 1) + { + return (EOF); + } + } + return (c); +} + +#if !defined(__MVS__) && !defined(__CMS__) +__PDPCLIB_API__ int fputs(const char *s, FILE *stream) +{ + size_t len; + size_t ret; + + stream = __INTFILE(stream); + + len = strlen(s); + ret = fwrite(s, len, 1, stream); + if (ret != 1) return (EOF); + else return (0); +} +#endif + +__PDPCLIB_API__ int remove(const char *filename) +{ + int ret; +#ifdef __OS2__ + APIRET rc; +#endif +#ifdef __WIN32__ + BOOL rc; +#endif + +#ifdef __AMIGA__ + DeleteFile(filename); + ret = 0; +#endif +#ifdef __OS2__ + rc = DosDelete((PSZ)filename); + if (rc != 0) + { + ret = 1; + errno = rc; + } + else + { + ret = 0; + } +#endif +#ifdef __WIN32__ + rc = DeleteFile(filename); + if (!rc) + { + ret = 1; + errno = GetLastError(); + } + else + { + ret = 0; + } +#endif +#ifdef __MSDOS__ + __remove(filename); + ret = 0; +#endif +#ifdef __MVS__ + char buf[FILENAME_MAX + 50]; + char *p; + + sprintf(buf, " DELETE %s", filename); + p = buf; + while (*p != '\0') + { + *p = toupper((unsigned char)*p); + p++; + } + ret = __idcams(strlen(buf), buf); +#endif +#ifdef __CMS__ + ret = cmsremove(filename); +#endif + return (ret); +} + +__PDPCLIB_API__ int rename(const char *old, const char *newnam) +{ + int ret; +#ifdef __OS2__ + APIRET rc; +#endif +#ifdef __WIN32__ + BOOL rc; +#endif + +#ifdef __AMIGA__ + Rename(old, newnam); + ret = 0; +#endif +#ifdef __OS2__ + rc = DosMove((PSZ)old, (PSZ)newnam); + if (rc != 0) + { + ret = 1; + errno = rc; + } + else + { + ret = 0; + } +#endif +#ifdef __WIN32__ + rc = MoveFile(old, newnam); + if (!rc) + { + ret = 1; + errno = GetLastError(); + } + else + { + ret = 0; + } +#endif +#ifdef __MSDOS__ + __rename(old, newnam); + ret = 0; +#endif +#ifdef __MVS__ + char buf[FILENAME_MAX + FILENAME_MAX + 50]; + char *p; + + sprintf(buf, " ALTER %s NEWNAME(%s)", old, newnam); + p = buf; + while (*p != '\0') + { + *p = toupper((unsigned char)*p); + p++; + } + ret = __idcams(strlen(buf), buf); +#endif +#ifdef __CMS__ + ret = cmsrename(old, newnam); +#endif + return (ret); +} + +__PDPCLIB_API__ int sprintf(char *s, const char *format, ...) +{ + va_list arg; + int ret; + + va_start(arg, format); + ret = vsprintf(s, format, arg); + va_end(arg); + return (ret); +} + +__PDPCLIB_API__ int vsprintf(char *s, const char *format, va_list arg) +{ + int ret; + + ret = vvprintf(format, arg, NULL, s); + if (ret >= 0) + { + *(s + ret) = '\0'; + } + return (ret); +} + +/* + +In fgets, we have the following possibilites... + +1. we found a genuine '\n' that terminated the search. +2. we hit the '\n' at the endbuf. +3. we hit the '\n' sentinel. + +*/ +#if !defined(__MVS__) && !defined(__CMS__) +__PDPCLIB_API__ char *fgets(char *s, int n, FILE *stream) +{ + char *p; + register char *t; + register char *u = s; + int c; + int processed; + size_t actualRead; + + stream = __INTFILE(stream); + + if (stream->quickText) + { + p = stream->upto + n - 1; + t = stream->upto; + if (p < stream->endbuf) + { + c = *p; + *p = '\n'; +#if defined(__OS2__) || defined(__WIN32__) + if (n < 8) + { +#endif + while ((*u++ = *t++) != '\n') ; /* tight inner loop */ +#if defined(__OS2__) || defined(__WIN32__) + } + else + { + register unsigned int *i1; + register unsigned int *i2; + register unsigned int z; + + i1 = (unsigned int *)t; + i2 = (unsigned int *)u; + while (1) + { + z = *i1; + if ((z & 0xffU) == '\n') break; + z >>= 8; + if ((z & 0xffU) == '\n') break; + z >>= 8; + if ((z & 0xffU) == '\n') break; + z >>= 8; + if ((z & 0xffU) == '\n') break; + *i2++ = *i1++; + } + t = (char *)i1; + u = (char *)i2; + while ((*u++ = *t++) != '\n') ; + } +#endif + *p = (char)c; + if (t <= p) + { + if (*(t - 2) == '\r') /* t is protected, u isn't */ + { + *(u - 2) = '\n'; + *(u - 1) = '\0'; + } + else + { + *u = '\0'; + } + stream->upto = t; + return (s); + } + else + { + processed = (int)(t - stream->upto) - 1; + stream->upto = t - 1; + u--; + } + } + else + { + while ((*u++ = *t++) != '\n') ; /* tight inner loop */ + if (t <= stream->endbuf) + { + if (*(t - 2) == '\r') /* t is protected, u isn't */ + { + *(u - 2) = '\n'; + *(u - 1) = '\0'; + } + else + { + *u = '\0'; + } + stream->upto = t; + return (s); + } + else + { + processed = (int)(t - stream->upto) - 1; + stream->upto = t - 1; + u--; + } + } + } + else + { + processed = 0; + } + + if (n < 1) + { + return (NULL); + } + if (n < 2) + { + *u = '\0'; + return (s); + } + if (stream->ungetCh != -1) + { + processed++; + *u++ = (char)stream->ungetCh; + stream->ungetCh = -1; + } + +#if defined(__gnu_linux__) || defined(__ARM__) + if (stream == stdin) + { + n--; + while (processed < n) + { + c = getc(stream); + if (c == EOF) break; + s[processed] = c; + if ((c == '\b') || (c == 0x7f)) + { + if (processed > 0) + { + putc('\b', stdout); + putc(' ', stdout); + putc('\b', stdout); + fflush(stdout); + processed--; + } + continue; + } + else + { + putc(c, stdout); + fflush(stdout); + } + if (c == '\n') break; + processed++; + } + if ((processed == 0) && (c == EOF)) return (NULL); + if ((processed < n) && !stream->noNl) + { + s[processed++] = '\n'; + } + s[processed] = '\0'; + return (s); + } +#endif + + while (1) + { + t = stream->upto; + p = stream->upto + (n - processed) - 1; + if (p < stream->endbuf) + { + c = *p; + *p = '\n'; + } + if (stream->noNl) + { + while (((*u++ = *t) != '\n') && (*t++ != '\r')) ; + if (*(u - 1) == '\n') + { + t++; + } + else + { + u--; + while ((*u++ = *t++) != '\n') ; + } + } + else + { + while ((*u++ = *t++) != '\n') ; /* tight inner loop */ + } + if (p < stream->endbuf) + { + *p = (char)c; + } + if (((t <= p) && (p < stream->endbuf)) + || ((t <= stream->endbuf) && (p >= stream->endbuf))) + { + if (stream->textMode) + { + if (stream->noNl) + { + if ((*(t - 1) == '\r') || (*(t - 1) == '\n')) + { + *(u - 1) = '\0'; + } + else + { + *u = '\0'; + } + } + /* can't inspect t because the \r may have been in + previous buffer */ + else if (((u - s) >= 2) && (*(u - 2) == '\r')) + { + *(u - 2) = '\n'; + *(u - 1) = '\0'; + } + else + { + *u = '\0'; + } + } + stream->upto = t; + if (stream->textMode) + { + stream->quickText = 1; + } + return (s); + } + else if (((t > p) && (p < stream->endbuf)) + || ((t > stream->endbuf) && (p >= stream->endbuf))) + { + int leave = 1; + + if (stream->textMode) + { + if (t > stream->endbuf) + { + if ((t - stream->upto) > 1) + { + if (*(t - 2) == '\r') /* t is protected, u isn't */ + { + processed -= 1; /* preparation for add */ + } + } + leave = 0; + } + else + { +#if defined(__ARM__) && !defined(__UNOPT__) +/* there is a bug where it seems to reach here, but I can't use + printf to debug it, because adding a printf makes the problem + disappear. So we'll just live with this for now */ +/* Note that the bug only occurs if optimization is switched on */ + printf(""); +#endif + if ((*(t - 2) == '\r') && (*(t - 1) == '\n')) + { + *(u - 2) = '\n'; + *(u - 1) = '\0'; + } + else + { + t--; + *(u - 1) = '\0'; + } + } + } + else if (t > stream->endbuf) + { + leave = 0; + } + else + { + *u = '\0'; + } + if (leave) + { + stream->upto = t; + if (stream->textMode) + { + stream->quickText = 1; + } + return (s); + } + } + processed += (int)(t - stream->upto) - 1; + u--; + stream->bufStartR += (stream->endbuf - stream->fbuf); + iread(stream, stream->fbuf, stream->szfbuf, &actualRead); + stream->endbuf = stream->fbuf + actualRead; + *stream->endbuf = '\n'; + if (actualRead == 0) + { + *u = '\0'; + if ((u - s) <= 1) + { + stream->eofInd = 1; + return (NULL); + } + else + { + return (s); + } + } + stream->upto = stream->fbuf; + } +} +#endif + +__PDPCLIB_API__ int ungetc(int c, FILE *stream) +{ + stream = __INTFILE(stream); + + if ((stream->ungetCh != -1) || (c == EOF)) + { + return (EOF); + } + stream->ungetCh = (unsigned char)c; + stream->quickText = 0; + stream->quickBin = 0; + return ((unsigned char)c); +} + +__PDPCLIB_API__ int fgetc(FILE *stream) +{ + unsigned char x[1]; + size_t ret; + + stream = __INTFILE(stream); + + ret = fread(x, 1, 1, stream); + if (ret == 0) + { + return (EOF); + } + return ((int)x[0]); +} + +__PDPCLIB_API__ int fseek(FILE *stream, long int offset, int whence) +{ + long oldpos; + long newpos; +#ifdef __AMIGA__ + long retpos; +#endif +#ifdef __OS2__ + ULONG retpos; + APIRET rc; +#endif +#ifdef __WIN32__ + DWORD retpos; +#endif +#ifdef __MSDOS__ + int ret; +#endif + + stream = __INTFILE(stream); + + oldpos = stream->bufStartR + (stream->upto - stream->fbuf); + if (stream->mode == __WRITE_MODE) + { + fflush(stream); + } + if (whence == SEEK_SET) + { + newpos = offset; + } + else if (whence == SEEK_CUR) + { + newpos = oldpos + offset; + } + + /*printf ("newpos: %ld\n", newpos); + printf ("bufStartR: %ld\n", stream->bufStartR); + printf ("endbuf: %ld\n", stream->endbuf); + printf ("fbuf: %ld\n", stream->fbuf);*/ + + if (whence == SEEK_END) + { + char buf[1000]; + + if (stream->mode == __WRITE_MODE) + { + fseek(stream, oldpos, SEEK_SET); + } + while (fread(buf, sizeof buf, 1, stream) == 1) + { + /* do nothing */ + } + newpos = ftell(stream); + fseek(stream, newpos, SEEK_SET); + } + else if ((newpos >= stream->bufStartR) + /* when seeking repeatedly to the same location, the new position + will be pointing to the end of the buffer, so we want <= not < */ + && (newpos <= (stream->bufStartR + (stream->endbuf - stream->fbuf))) + && !stream->update + && !stream->quickBin + /* when we have just seeked, we will be at the end of the buffer, + but the data in the buffer is not actually valid, so we can't + adjust the pointer to make it valid. An exception is if they + are seeking to the same location. */ + && ((stream->upto != stream->endbuf) || (oldpos == newpos)) + && (stream->mode == __READ_MODE)) + { + stream->upto = stream->fbuf + (size_t)(newpos - stream->bufStartR); + } + else + { +#ifdef __AMIGA__ + retpos = Seek(stream->hfile, newpos, OFFSET_BEGINNING); + if (retpos == -1) + { + return (-1); + } + stream->endbuf = stream->fbuf + stream->szfbuf; + if (stream->mode == __READ_MODE) + { + stream->upto = stream->endbuf; + stream->bufStartR = newpos - stream->szfbuf; + } + else + { + stream->upto = stream->fbuf; + stream->bufStartR = newpos; + } +#endif +#ifdef __OS2__ + rc = DosSetFilePtr(stream->hfile, newpos, FILE_BEGIN, &retpos); + if ((rc != 0) || (retpos != newpos)) + { + errno = rc; + return (-1); + } + stream->endbuf = stream->fbuf + stream->szfbuf; + if (stream->mode == __READ_MODE) + { + stream->upto = stream->endbuf; + stream->bufStartR = newpos - stream->szfbuf; + } + else + { + stream->upto = stream->fbuf; + stream->bufStartR = newpos; + } +#endif +#ifdef __WIN32__ + retpos = SetFilePointer(stream->hfile, newpos, NULL, FILE_BEGIN); + if (retpos != newpos) + { + errno = GetLastError(); + return (-1); + } + stream->endbuf = stream->fbuf + stream->szfbuf; + if (stream->mode == __READ_MODE) + { + stream->upto = stream->endbuf; + stream->bufStartR = newpos - stream->szfbuf; + } + else + { + stream->upto = stream->fbuf; + stream->bufStartR = newpos; + } +#endif +#ifdef __MSDOS__ + ret = __seek(stream->hfile, newpos, SEEK_SET); +#if defined(__gnu_linux__) || defined(__ARM__) + if (ret == -1) return (ret); +#else + if (ret) return (ret); +#endif + stream->endbuf = stream->fbuf + stream->szfbuf; + if (stream->mode == __READ_MODE) + { + stream->upto = stream->endbuf; + stream->bufStartR = newpos - stream->szfbuf; + } + else + { + stream->upto = stream->fbuf; + stream->bufStartR = newpos; + } +#endif +#if defined(__MVS__) || defined(__CMS__) + char fnm[FILENAME_MAX]; + long int x; + size_t y; + char buf[1000]; + + oldpos = ftell(stream); + if (newpos < oldpos) + { + strcpy(fnm, "dd:"); + strcat(fnm, stream->ddname); + if (stream->pdsmem[0] != '\0') + { + sprintf(fnm + strlen(fnm), "(%s)", stream->pdsmem); + } + inseek = 1; + if (freopen(fnm, stream->modeStr, stream) == NULL) + { + stream->errorInd = 1; + return (-1); + } + inseek = 0; + oldpos = 0; + } + y = (newpos - oldpos) % sizeof buf; + fread(buf, y, 1, stream); + for (x = oldpos + y; x < newpos; x += sizeof buf) + { + fread(buf, sizeof buf, 1, stream); + } + if (stream->errorInd) + { + return (-1); + } +#endif + } + stream->justseeked = 1; + stream->quickBin = 0; + stream->quickText = 0; + stream->ungetCh = -1; + stream->eofInd = 0; + return (0); +} + +__PDPCLIB_API__ long int ftell(FILE *stream) +{ + stream = __INTFILE(stream); + + return (stream->bufStartR + (stream->upto - stream->fbuf)); +} + +__PDPCLIB_API__ int fsetpos(FILE *stream, const fpos_t *pos) +{ + stream = __INTFILE(stream); + + fseek(stream, *pos, SEEK_SET); + return (0); +} + +__PDPCLIB_API__ int fgetpos(FILE *stream, fpos_t *pos) +{ + stream = __INTFILE(stream); + + *pos = ftell(stream); + return (0); +} + +__PDPCLIB_API__ void rewind(FILE *stream) +{ + stream = __INTFILE(stream); + + fseek(stream, 0L, SEEK_SET); + return; +} + +__PDPCLIB_API__ void clearerr(FILE *stream) +{ + stream = __INTFILE(stream); + + stream->errorInd = 0; + stream->eofInd = 0; + return; +} + +__PDPCLIB_API__ void perror(const char *s) +{ + if ((s != NULL) && (*s != '\0')) + { + printf("%s: ", s); + } + if (errno == 0) + { + printf("No error has occurred\n"); + } + else + { + printf("An error has occurred\n"); + } + return; +} + +/* +NULL + F = allocate, setup +NULL + L = allocate, setup +NULL + N = ignore, return success +buf + F = setup +buf + L = setup +buf + N = ignore, return success +*/ + +__PDPCLIB_API__ int setvbuf(FILE *stream, char *buf, int mode, size_t size) +{ + char *mybuf; + + stream = __INTFILE(stream); + +#if defined(__MVS__) || defined(__CMS__) + /* don't allow mucking around with buffers on MVS or CMS */ + return (0); +#endif + + if (mode == _IONBF) + { + stream->bufTech = mode; +#ifdef __WIN32__ + if (stream == stdin) + { + DWORD dw; + + if (GetConsoleMode(stream->hfile, &dw)) + { + dw &= ~ENABLE_LINE_INPUT; + dw &= ~ENABLE_PROCESSED_INPUT; + SetConsoleMode(stream->hfile, dw); + } + } +#endif +#if defined(__PDOS386__) + if (stream == stdin) + { + unsigned int dw; + + PosGetDeviceInformation(0, &dw); + dw &= 0xff; + dw |= (1 << 5); + PosSetDeviceInformation(0, dw); + } +#endif + return (0); + } + if (buf == NULL) + { + if (size < 2) + { + return (-1); + } + mybuf = malloc(size + 8); + if (mybuf == NULL) + { + return (-1); + } + } + else + { + if (size < 10) + { + return (-1); + } + mybuf = buf; + stream->theirBuffer = 1; + size -= 8; + } + if (!stream->permfile) + { + free(stream->intBuffer); + } + stream->intBuffer = mybuf; + stream->fbuf = stream->intBuffer; + stream->szfbuf = size; + stream->endbuf = stream->fbuf + stream->szfbuf; + *stream->endbuf = '\n'; + stream->bufStartR = -(long)stream->szfbuf; + if (stream->mode == __WRITE_MODE) + { + stream->upto = stream->fbuf; + } + else + { + stream->upto = stream->endbuf; + } + stream->bufTech = mode; + if (!stream->textMode && (stream->bufTech == _IOLBF)) + { + stream->quickBin = 0; + } + return (0); +} + +__PDPCLIB_API__ int setbuf(FILE *stream, char *buf) +{ + int ret; + + stream = __INTFILE(stream); + + if (buf == NULL) + { + ret = setvbuf(stream, NULL, _IONBF, 0); + } + else + { + ret = setvbuf(stream, buf, _IOFBF, BUFSIZ); + } + return (ret); +} + +__PDPCLIB_API__ FILE *freopen(const char *filename, + const char *mode, + FILE *stream) +{ + stream = __INTFILE(stream); + + inreopen = 1; + fclose(stream); + + myfile = stream; + fopen(filename, mode); + if (err && !stream->permfile) + { + __userFiles[stream->intFno] = NULL; + free(stream); + } +#if defined(__MVS__) || defined(__CMS__) + else if (err) + { + free(stream); + /* need to protect against the app closing the file + which it is allowed to */ + if (stream == __stdin) + { + __stdin = NULL; + } + else if (stream == __stdout) + { + __stdout = NULL; + } + else if (stream == __stderr) + { + __stderr = NULL; + } + } +#endif + inreopen = 0; + if (err) + { + return (NULL); + } + return (stream); +} + +__PDPCLIB_API__ int fflush(FILE *stream) +{ +#if defined(__MVS__) || defined(__CMS__) + if ((stream->mode == __WRITE_MODE) && (stream->upto != stream->fbuf)) + { + if (stream->reallyu) + { + size_t last; + + last = stream->upto - stream->fbuf; + begwrite(stream, last); + memcpy(dptr, stream->fbuf, last); + finwrite(stream); + stream->upto = stream->fbuf; + } + else if ((stream == __stdout) || (stream == __stderr)) + { + fputc('\n', stream); + } + } +#else + size_t actualWritten; + + stream = __INTFILE(stream); + + if ((stream->upto != stream->fbuf) && (stream->mode == __WRITE_MODE)) + { + iwrite(stream, + stream->fbuf, + stream->upto - stream->fbuf, + &actualWritten); + if (stream->errorInd) return (EOF); + stream->bufStartR += actualWritten; + stream->upto = stream->fbuf; + } +#endif + return (0); +} + +__PDPCLIB_API__ char *tmpnam(char *s) +{ +#if defined(__MVS__) || defined(__CMS__) + static char buf[] = "dd:ZZZZZZZA"; +#else + static char buf[] = "ZZZZZZZA.$$$"; +#endif + +#if defined(__MVS__) || defined(__CMS__) + buf[10]++; +#else + buf[7]++; +#endif + if (s == NULL) + { + return (buf); + } + strcpy(s, buf); + return (s); +} + +__PDPCLIB_API__ FILE *tmpfile(void) +{ +#if defined(__MVS__) || defined(__CMS__) + return (fopen("dd:ZZZZZZZA", "wb+")); +#else + FILE *fu; + fu = fopen("ZZZZZZZA.$$$", "wb+"); + if (fu != NULL) + { + fu->istemp = 1; + } + return (fu); +#endif +} + +__PDPCLIB_API__ int fscanf(FILE *stream, const char *format, ...) +{ + va_list arg; + int ret; + + stream = __INTFILE(stream); + + va_start(arg, format); + ret = vvscanf(format, arg, stream, NULL); + va_end(arg); + return (ret); +} + +__PDPCLIB_API__ int scanf(const char *format, ...) +{ + va_list arg; + int ret; + + va_start(arg, format); + ret = vvscanf(format, arg, __stdin, NULL); + va_end(arg); + return (ret); +} + +__PDPCLIB_API__ int sscanf(const char *s, const char *format, ...) +{ + va_list arg; + int ret; + + va_start(arg, format); + ret = vvscanf(format, arg, NULL, s); + va_end(arg); + return (ret); +} + +/* vvscanf - the guts of the input scanning */ +/* several mods by Dave Edwards */ +static int vvscanf(const char *format, va_list arg, FILE *fp, const char *s) +{ + int ch; + int fin = 0; + int cnt = 0; + char *cptr; + int *iptr; + void **vptr; + unsigned int *uptr; + long *lptr; + unsigned long *luptr; + short *hptr; + unsigned short *huptr; + double *dptr; + float *fptr; + long startpos; + const char *startp; + int skipvar; /* nonzero if we are skipping this variable */ + int modlong; /* nonzero if "l" modifier found */ + int modshort; /* nonzero if "h" modifier found */ + int width; /* maximum chars to read */ + int informatitem; /* nonzero if % format item started */ + /* informatitem is 1 if we have processed "%l" but not the + type letter (s,d,e,f,g,...) yet. */ + + if (fp != NULL) + { + startpos = ftell(fp); + } + else + { + startp = s; + } + inch(); + informatitem = 0; /* init */ + /* don't bail out at end of data as there may be a %n */ + /*if ((fp != NULL && ch == EOF) || (fp == NULL && ch == 0)) return EOF; */ + /* initially at EOF or end of string */ + while (!fin) + { + if (*format == '\0') + { + fin = 1; + } + else if (*format == '%' || informatitem) + { + if(*format=='%') /* starting a format item */ + { + format++; + modlong=0; /* init */ + modshort=0; + skipvar = 0; + width = 0; + if (*format == '*') + { + skipvar = 1; + format++; + } + } + if (*format == '%') /* %% */ + { + if (ch != '%') return (cnt); + inch(); + informatitem=0; + } + else if (*format == 'l') + { + /* Type modifier: l (e.g. %ld) */ + modlong=1; + informatitem=1; + } + else if (*format == 'h') + { + /* Type modifier: h (short int) */ + modshort=1; + informatitem=1; + } + else if (isdigit((unsigned char)*format)) + { + width = width * 10 + (*format - '0'); + informatitem = 1; + } + else /* process a type character: */ + { + informatitem=0; /* end of format item */ + if (*format == 's') + { + if (!skipvar) + { + cptr = va_arg(arg, char *); + } + /* Skip leading whitespace: */ + while (ch>=0 && isspace(ch)) inch(); + if ((fp != NULL && ch == EOF) || (fp == NULL && ch == 0)) + /* at EOF or end of string */ + { + if (!skipvar) + { + *cptr = 0; /* give a null string */ + } + continue; + } + else + { + for(;;) + { + if (isspace(ch)) break; + if ((fp != NULL && ch == EOF) + || (fp == NULL && ch == 0)) + { + break; + } + if (!skipvar) + { + *cptr++ = (char)ch; + } + inch(); + } + if (!skipvar) + { + *cptr = '\0'; + } + cnt++; + } + } + else if (*format == '[') + { + int reverse = 0; + int found; + const char *first; + const char *last; + size_t size; + size_t mcnt = 0; + + if (!skipvar) + { + cptr = va_arg(arg, char *); + } + format++; + if (*format == '^') + { + reverse = 1; + format++; + } + if (*format == '\0') break; + first = format; + format++; + last = strchr(format, ']'); + if (last == NULL) return (cnt); + size = (size_t)(last - first); + while (1) + { + /* note that C90 doesn't require special + processing for '-' so it hasn't been + added */ + found = (memchr(first, ch, size) != NULL); + if (found && reverse) break; + if (!found && !reverse) break; + if (!skipvar) + { + *cptr++ = (char)ch; + } + mcnt++; + inch(); + /* if at EOF or end of string, bug out */ + if ((fp != NULL && ch == EOF) + || (fp == NULL && ch == 0)) + { + break; + } + } + if (mcnt > 0) + { + if (!skipvar) + { + *cptr++ = '\0'; + } + cnt++; + } + else + { + break; + } + format = last + 1; + } + else if (*format == 'c') + { + if (!skipvar) + { + cptr = va_arg(arg, char *); + } + if ((fp != NULL && ch == EOF) + || (fp == NULL && ch == 0)) + { + /* do nothing */ + } + else + { + if (!skipvar) + { + *cptr = ch; + } + cnt++; + inch(); + } + } + else if (*format == 'n') + { + uptr = va_arg(arg, unsigned int *); + if (fp != NULL) + { + *uptr = (unsigned int)(ftell(fp) - startpos); + } + else + { + /* we need a -1 because s will point to + the character after the NUL */ + *uptr = (unsigned int)(s - startp - 1); + } + } + else if (*format == 'd' || *format == 'u' + || *format == 'x' || *format == 'o' + || *format == 'p' + || *format == 'i') + { + int neg = 0; + unsigned long x = 0; + int undecided = 0; + int base = 10; + int mcnt = 0; + + if (*format == 'x') base = 16; + else if (*format == 'p') base = 16; + else if (*format == 'o') base = 8; + else if (*format == 'i') base = 0; + if (!skipvar) + { + if ((*format == 'd') || (*format == 'i')) + { + if (modlong) lptr = va_arg(arg, long *); + else if (modshort) hptr = va_arg(arg, short *); + else iptr = va_arg(arg, int *); + } + else if (*format == 'p') + { + vptr = va_arg(arg, void **); + } + else + { + if (modlong) luptr = va_arg(arg, unsigned long *); + else if (modshort) huptr = + va_arg(arg, unsigned short *); + else uptr = va_arg(arg, unsigned int *); + } + } + /* Skip leading whitespace: */ + while (ch>=0 && isspace(ch)) inch(); + if (ch == '-') + { + neg = 1; + inch(); + } + else if(ch == '+') inch(); + + /* this logic is the same as strtoul so if you + change this, change that one too */ + + if (base == 0) + { + undecided = 1; + } + while (!((fp != NULL && ch == EOF) + || (fp == NULL && ch == 0))) + { + if (isdigit((unsigned char)ch)) + { + if (base == 0) + { + if (ch == '0') + { + base = 8; + } + else + { + base = 10; + undecided = 0; + } + } + x = x * base + (ch - '0'); + inch(); + } +/* DOS has a ':' in the pointer - skip that */ +#if defined(__MSDOS__) && \ + !defined(__PDOS386__) && \ + !defined(__gnu_linux__) && \ + !defined(__ARM__) + else if ((*format == 'p') && (ch == ':')) + { + inch(); + } +#endif + else if (isalpha((unsigned char)ch)) + { + if ((ch == 'X') || (ch == 'x')) + { + if ((base == 0) || ((base == 8) && undecided)) + { + base = 16; + undecided = 0; + inch(); + } + else if (base == 16) + { + /* hex values are allowed to have an + optional 0x */ + inch(); + } + else + { + break; + } + } + else if (base <= 10) + { + break; + } + else + { + x = x * base + + (toupper((unsigned char)ch) - 'A') + 10; + inch(); + } + } + else + { + break; + } + mcnt++; + } + + /* end of strtoul logic */ + + /* If we didn't get any characters, don't go any + further */ + if (mcnt == 0) + { + break; + } + + + if (!skipvar) + { + if ((*format == 'd') || (*format == 'i')) + { + long lval; + + if (neg) + { + lval = (long)-x; + } + else + { + lval = (long)x; + } + if (modlong) *lptr=lval; + /* l modifier: assign to long */ + else if (modshort) *hptr = (short)lval; + /* h modifier */ + else *iptr=(int)lval; + } + else if (*format == 'p') + { + *vptr = (void *)x; + } + else + { + if (modlong) *luptr = (unsigned long)x; + else if (modshort) *huptr = (unsigned short)x; + else *uptr = (unsigned int)x; + } + } + cnt++; + } + else if (*format=='e' || *format=='f' || *format=='g' || + *format=='E' || *format=='G') + { + /* Floating-point (double or float) input item */ + int negsw1,negsw2,dotsw,expsw,ndigs1,ndigs2,nfdigs; + int ntrailzer,expnum,expsignsw; + double fpval,pow10; + + if (!skipvar) + { + if (modlong) dptr = va_arg(arg, double *); + else fptr = va_arg(arg, float *); + } + negsw1=0; /* init */ + negsw2=0; + dotsw=0; + expsw=0; + ndigs1=0; + ndigs2=0; + nfdigs=0; + ntrailzer=0; /* # of trailing 0's unaccounted for */ + expnum=0; + expsignsw=0; /* nonzero means done +/- on exponent */ + fpval=0.0; + /* Skip leading whitespace: */ + while (ch>=0 && isspace(ch)) inch(); + if (ch=='-') + { + negsw1=1; + inch(); + } + else if (ch=='+') inch(); + while (ch>0) + { + if (ch=='.' && dotsw==0 && expsw==0) dotsw=1; + else if (isdigit(ch)) + { + if(expsw) + { + ndigs2++; + expnum=expnum*10+(ch-'0'); + } + else + { + /* To avoid overflow or loss of precision, + skip leading and trailing zeros unless + really needed. (Automatic for leading + 0's, since 0.0*10.0 is 0.0) */ + ndigs1++; + if (dotsw) nfdigs++; + if (ch=='0' && fpval!=0.) + { + /* Possible trailing 0 */ + ntrailzer++; + } + else + { + /* Account for any preceding zeros */ + while (ntrailzer>0) + { + fpval = fpval * 10; + ntrailzer--; + } + fpval=fpval*10.0+(ch-'0'); + } + } + } + else if ((ch=='e' || ch=='E') && expsw==0) expsw=1; + else if ((ch=='+' || ch=='-') && expsw==1 + && ndigs2==0 && expsignsw==0) + { + expsignsw=1; + if (ch=='-') negsw2=1; + } + else break; /* bad char: end of input item */ + inch(); + } + /* don't finish at end of input there may be a %n */ + /*if ((fp != NULL && ch == EOF) + || (fp == NULL && ch == 0)) fin=1;*/ + /* Check for a valid fl-pt value: */ + if (ndigs1==0 || (expsw && ndigs2==0)) return(cnt); + /* Complete the fl-pt value: */ + if (negsw2) expnum=-expnum; + expnum+=ntrailzer-nfdigs; + if (expnum!=0 && fpval!=0.0) + { + negsw2=0; + if (expnum<0) + { + expnum=-expnum; + negsw2=1; + } + /* Multiply or divide by 10.0**expnum, using + bits of expnum (fast method) */ + pow10=10.0; + for (;;) + { + if (expnum & 1) /* low-order bit */ + { + if (negsw2) fpval = fpval / pow10; + else fpval = fpval * pow10; + } + expnum>>=1; /* shift right 1 bit */ + if (expnum==0) break; + pow10 = pow10 * pow10; + /* 10.**n where n is power of 2 */ + } + } + if (negsw1) fpval=-fpval; + if (!skipvar) + { + /* l modifier: assign to double */ + if (modlong) *dptr=fpval; + else *fptr=(float)fpval; + } + cnt++; + } + } + } + else if (isspace((unsigned char)(*format))) + { + /* Whitespace char in format string: skip next whitespace + chars in input data. This supports input of multiple + data items. */ + while (ch>=0 && isspace(ch)) + { + inch(); + } + } + else /* some other character in the format string */ + { + if (ch != *format) return (cnt); + inch(); + } + format++; + /* don't bail out at end of string as there may be a %n */ + /*if ((fp != NULL && ch == EOF) || (fp == NULL && ch == 0)) fin = 1;*/ + /* EOF */ + } + if (fp != NULL) ungetc(ch, fp); + return (cnt); +} + +__PDPCLIB_API__ char *gets(char *s) +{ + char *ret; + + __stdin->quickText = 0; + __stdin->noNl = 1; + ret = fgets(s, INT_MAX, __stdin); + __stdin->noNl = 0; + __stdin->quickText = 1; + return (ret); +} + +__PDPCLIB_API__ int puts(const char *s) +{ + int ret; + + ret = fputs(s, __stdout); + if (ret == EOF) + { + return (ret); + } + return (putc('\n', __stdout)); +} + +/* The following functions are implemented as macros */ + +#undef getchar +#undef putchar +#undef getc +#undef putc +#undef feof +#undef ferror + +__PDPCLIB_API__ int getc(FILE *stream) +{ + stream = __INTFILE(stream); + + return (fgetc(stream)); +} + +__PDPCLIB_API__ int putc(int c, FILE *stream) +{ + stream = __INTFILE(stream); + + return (fputc(c, stream)); +} + +__PDPCLIB_API__ int getchar(void) +{ + return (getc(__stdin)); +} + +__PDPCLIB_API__ int putchar(int c) +{ + return (putc(c, __stdout)); +} + +__PDPCLIB_API__ int feof(FILE *stream) +{ + stream = __INTFILE(stream); + + return (stream->eofInd); +} + +__PDPCLIB_API__ int ferror(FILE *stream) +{ + stream = __INTFILE(stream); + + return (stream->errorInd); +} + +#if 0 +Design of MVS i/o routines + +The broad objectives of the MVS implementation are as follows: + +1. An application doing a binary fread equal to LRECL should +get speed equivalent to doing the GET macro. + +2. An application doing a text fgets equal to or greater than +LRECL should get speed equivalent to the GET macro. + +3. Variable-block files are encapsulated in terms of RDW files. +RDW files are what is produced by certain implementations of +ftp when the "rdw" option is chosen. Data is stored on the PC +or whatever as a 2-byte big-endian length, then 2 NUL bytes, +then the data. See the S/380 documentation that comes with +MVS/380 for more information on this format. So a binary read +of a V or VB file will produce a RDW stream (basically, BDWs +are stripped, but not RDWs). + +4. If a binary copy is done from a V dataset to a U dataset, +the RDW data stream will be preserved exactly. If the U data +set is subsequently copied to an F dataset, there will +necessarily be NUL-padding. If this dataset is then copied +to a V dataset, the extraneous NULs (which comprise an +invalid RDW) will be silently ignored/stripped. + +5. If a text copy is done from a V dataset to a U dataset, +the U dataset will get x'15' (EBCDIC newline) characters +added. The RDW will be stripped. Trailing spaces will be +preserved. With one exception - a single blank character +on a line will be removed. If this dataset is then copied +to a F dataset, there will be trailing spaces added to fit +the LRECL. If this dataset is then copied to a V dataset, +the trailing spaces will all be truncated. If a line is +empty, a single blank character will be inserted. + +6. If a long line is being written in text mode, it will +be silently truncated regardless of whether the output file +is RECFM=V or F. In binary mode, when writing to a RECFM=F, +the data simply gets wrapped to the next record. For a binary +write to a RECFM=V where the RDW signals a length greater +than the LRECL, the record will be silently truncated. If +writing to a RECFM=V in binary mode with insufficient data +to match the RDW, it is considered an error. Similarly, +more data than the RDW will cause a new record to be +started. An invalid RDW in the data stream is considered +a write error. + +7. In RECFM=U datasets, the block boundary is always ignored. +When the application writes a newline character to the data +stream, it is treated as just another character and dutifully +written out. Newlines are never added or stripped by the +C library when a block boundary is encountered - not even in +text mode. This marks a break from IBMs behaviour and is +required in order to be able to read a RECFM=U in binary +mode (e.g. the way zip would) and still preserve newline +characters if the file being read happens to be a text file +(as opposed to e.g. another zip file - something zip has +no way of knowing). NULs encountered when reading +a RECFM=U in text mode may be stripped. Similarly, trailing +NULs in the application data stream are stripped. This way, +someone doing a binary copy of a file, and who has stored +it in a RECFM=F dataset (where NUL padding is necessary), +and then has copied it into a RECFM=U (where NULs must +necessarily be preserved if doing binary copies) will be +stripped by the first person who does a text read or +write. + +8. DCB information provided by the user in JCL, or on a +dataset, always has priority and the C library will adjust +around that. Only if there is no existing DCB information +available anywhere will the C library provide a default, +which is RECFM=VB,LRECL=255,BLKSIZE=6233 for text, and +RECFM=U,LRECL=0,BLKSIZE=6233 for binary. This blocksize +is traditionally considered to be the universal blocksize. + +9. An open of a PDS with no member given will read the +directory. Any attempt to open a PDS directory for writing +will fail. + +10. RECFM=U allows you to preserve the exact length of +data. RECFM=FB with a LRECL of 1 also achieves this, but +is much more overhead. A special exception may be made in +the future for binary reading of FB datasets to provide +the same performance as RECFM=U. + +11. Data is processed by the C library one record at a time. +There is an intention to change to block reading in the +future now that the assembler (for MVS at least) has that +flexibility. + + +The implementation has been based around 4 different processing +concepts: + +1. Fixed text. +2. Fixed binary. +3. Variable text. +4. Variable binary. + +RECFM=U was grafted on in terms of a faked variable binary +for reading and a faked fixed binary for writing. There is +a "reallyu" to record the fact that it was really U, and +at various points the processing changes slightly to cope +with that. There is also a "reallyt" variable that notes +the fact that it was originally a text mode request, but +that has been switched (to avoid translation of newlines +into spaces or RDW etc). + +The code has been designed to work in both locate mode +and in move mode, although it would be rare for anyone to +want to use locate mode, and support for that may drop at +some point. + + +The main assembler functions are as follows (note that +__aopen in C becomes @@AOPEN in assembler): + +void *__aopen(const char *ddname, + int *mode, + int *recfm, + int *lrecl, + int *blksize, + void **asmbuf, + const char *member); + +This function opens an 8-character (right-padded with spaces) +DDNAME. For dynamically-allocated datasets, a previous call +to __dynal would have been done to a generated ddname of the +form PDP001HD where 001 corresponds to a spare slot. The +mode is passed by address. It is typically simply set to +read or write, but if it is set to read, blocked, then the +assembler routines have the option of setting this to just +read, e.g. if the device is a terminal and block mode is +inappropriate. + +Mode values are as follows: +0 = input (read) +1 = output (write) +2 = update (read and write, initally read) +3 = append +4 = inout = read and write, initially read (same as update) +5 = outin = write, then reread + +Additional mode flags: +0x08 = Use EXCP if input file is tape. +0x10 = Use block mode. +0x80 = Use GETLINE/PUTLINE if TSO terminal detected + +recfm values are: +0 = fixed +1 = variable +2 = undefined +And again, the C program provides defaults but the assembler +function has the final say. + +lrecl = default record/line length set by caller, with +assembler deciding what to really do. + +blksize - default block size set by caller, assembler deciding +what to really use. + +asmbuf - if file is opened in write mode, in the normal move +mode, then this will be set to point to a buffer large enough +to store the lrecl. Storage will be below the line so it is +suitable for doing I/O from. Buffer will be freed when the +dataset is closed. + +member - pointer to a PDS member to be opened. Member should +be 8 characters, padded with spaces. If member is set to NULL, +then this open is not for a member of a PDS (so this parameter +is probably normally NULL). + +__aopen returns a "handle" on success, or a negative value +(when cast to int) on failure. These values will probably +be unclumped in the future. + + +int __aread(void *handle, void *buf, size_t *len); + +This function takes the handle previously returned from __aopen +and reads into the provided buffer a single record. It is +assumed that the buffer is big enough to hold the LRECL +previously returned by __aopen. *len will contain the length +of the actual record returned, e.g. if RECFM=U, then while +reading each record (block), the length might change. +In the case of RECFM=V, the record includes a RDW. + +__aread returns 0 on success, non-zero on failure. + + +int __awrite(void *handle, unsigned char **buf, size_t *sz); + +This function takes the handle previously returned from __aopen +and writes the buffer pointed to by *buf. If operating in locate +mode, it actually sets the *buf to where to write to, so the +application can subsequently write there. *sz provides the +length of the data to write, which is particularly necessary +for RECFM=U where there is no other way to know the length. +In the future, the assembler may update the size to reflect +actual written in the case of a partial write. + +__awrite returns 0 on success, non-zero for failure. + + +void __aclose(void *handle); + +This function takes the handle previously returned from __aopen +and closes the file and releases any buffers that were allocated +in the open. + + + +Here is some old documentation that might be worth updating +one day: + +in/out function rec-type mode method +in fread fixed bin loop reading, remember remainder +in fread fixed text loop reading + truncing, remember rem +in fread var bin loop reading (+ len), remember remainder +in fread var text loop reading (+ len), remember remainder +in fgets fixed bin read, scan, remember remainder +in fgets fixed text read, trunc, remember remainder +in fgets var bin read, scan, rr +in fgets var text read, rr +in fgetc fixed bin read, rr +in fgetc fixed text read, trunc, rr +in fgetc var bin read, rr +in fgetc var text read, rr + +out fwrite fixed bin loop doing put, rr +out fwrite fixed text search newline, copy + pad, put, rr +out fwrite var bin if nelem != 1 copy to max lrecl +out fwrite var text loop search nl, put, rr +out fputs fixed bin loop doing put, rr +out fputs fixed text search newline, copy + pad, put, rr +out fputs var bin put +out fputs var text search newline, put, copy rem +out fputc fixed bin copy to rr until rr == lrecl +out fputc fixed text copy to rr until newline, then pad +out fputc var bin copy to rr until rr == lrecl +out fputc var text copy to rr until newline + + +fread: if quickbin, if read elem size == lrecl, doit +fgets: if variable record + no remainder + if buffer > record size, copy + add newline +#endif + +#if defined(__MVS__) || defined(__CMS__) +__PDPCLIB_API__ char *fgets(char *s, int n, FILE *stream) +{ + unsigned char *eptr; + size_t len; + int cnt; + int c; + + if (stream->quickText) + { + if (__aread(stream->hfile, &dptr) != 0) + { + stream->eofInd = 1; + stream->quickText = 0; + return (NULL); + } + len = ((dptr[0] << 8) | dptr[1]) - 4; + if ((len == 1) && (dptr[4] == ' ')) + { + len = 0; + } + if (n > (len + 1)) + { + memcpy(s, dptr + 4, len); + memcpy(s + len, "\n", 2); + stream->bufStartR += len + 1; + return (s); + } + else + { + memcpy(stream->fbuf, dptr + 4, len); + stream->upto = stream->fbuf; + stream->endbuf = stream->fbuf + len; + *(stream->endbuf++) = '\n'; + stream->quickText = 0; + } + } + + if (stream->eofInd) + { + return (NULL); + } + + switch (stream->style) + { + case FIXED_TEXT: + if ((stream->endbuf == stream->fbuf) + && (n > (stream->lrecl + 2))) + { + if (__aread(stream->hfile, &dptr) != 0) + { + stream->eofInd = 1; + return (NULL); + } + eptr = dptr + stream->lrecl - 1; + while ((*eptr == ' ') && (eptr >= dptr)) + { + eptr--; + } + eptr++; + memcpy(s, dptr, eptr - dptr); + if (stream->noNl) + { + s[eptr - dptr] = '\0'; + } + else + { + memcpy(s + (eptr - dptr), "\n", 2); + } + stream->bufStartR += (eptr - dptr) + 1; + return (s); + } + break; + + default: + break; + + } + + /* Ok, the obvious optimizations have been done, + so now we switch to the slow generic version */ + + n--; + cnt = 0; + while (cnt < n) + { + c = getc(stream); + if (c == EOF) break; + s[cnt] = c; + if ((stream == stdin) && stream->reallyu) + { + if (c == '\b') + { + if (cnt > 0) + { + putc('\b', stdout); + putc(' ', stdout); + putc('\b', stdout); + fflush(stdout); + cnt--; + } + continue; + } + else + { + putc(c, stdout); + fflush(stdout); + } + } + if (c == '\n') break; + cnt++; + } + if ((cnt == 0) && (c == EOF)) return (NULL); + if ((cnt < n) && !stream->noNl) + { + s[cnt++] = '\n'; + } + s[cnt] = '\0'; + return (s); +} + +__PDPCLIB_API__ int fputs(const char *s, FILE *stream) +{ + const char *p; + size_t len; + + if (stream->quickText) + { + p = strchr(s, '\n'); + if (p != NULL) + { + len = p - s; + if (len > stream->lrecl) + { + len = stream->lrecl; + } + begwrite(stream, len + 4); + memcpy(dptr + 4, s, len); + dptr[0] = (len + 4) >> 8; + dptr[1] = (len + 4) & 0xff; + dptr[2] = 0; + dptr[3] = 0; + finwrite(stream); + stream->bufStartR += (len + 1); + if (*(p + 1) == '\0') + { + return (len + 1); + } + s = p + 1; + stream->quickText = 0; + } + } + switch (stream->style) + { + case FIXED_TEXT: + len = strlen(s); + if (len > 0) + { + len--; + if (((strchr(s, '\n') - s) == len) + && (stream->upto == stream->fbuf) + && (len <= stream->lrecl)) + { + begwrite(stream, stream->lrecl); + memcpy(dptr, s, len); + memset(dptr + len, ' ', stream->szfbuf - len); + finwrite(stream); + stream->bufStartR += len; + } + else + { + fwrite(s, len + 1, 1, stream); + } + } + break; + + default: + len = strlen(s); + fwrite(s, len, 1, stream); + break; + } + return (0); +} + +__PDPCLIB_API__ size_t fwrite(const void *ptr, + size_t size, + size_t nmemb, + FILE *stream) +{ + size_t bytes; + size_t sz; + char *p; + int x; + + if (stream->quickBin) + { + if ((nmemb == 1) && (size == stream->lrecl)) + { + begwrite(stream, stream->lrecl); + memcpy(dptr, ptr, size); + finwrite(stream); + stream->bufStartR += size; + return (1); + } + else + { + stream->quickBin = 0; + } + } + switch (stream->style) + { + case FIXED_BINARY: + bytes = nmemb * size; + /* if we've exceed our buffer we need to write out + a record - but if we haven't written any data to + our internal buffer yet, don't bother going through + this code, it'll be handled later. */ + if (((stream->endbuf - stream->upto) <= bytes) + && (stream->upto != stream->fbuf)) + { + /* ready to write a record - request some space + from MVS */ + begwrite(stream, stream->lrecl); + sz = stream->endbuf - stream->upto; + memcpy(dptr, stream->fbuf, stream->szfbuf - sz); + memcpy(dptr + stream->szfbuf - sz, ptr, sz); + finwrite(stream); + ptr = (char *)ptr + sz; + bytes -= sz; + stream->upto = stream->fbuf; + stream->bufStartR += stream->szfbuf; + } + /* At this point, the internal buffer is empty if the + number of bytes to write is still greater than the + internal buffer. In which case, start writing directly + to an MVS-provided area. */ + while (bytes >= stream->szfbuf) + { + begwrite(stream, stream->lrecl); + memcpy(dptr, ptr, stream->szfbuf); + finwrite(stream); + ptr = (char *)ptr + stream->szfbuf; + bytes -= stream->szfbuf; + stream->bufStartR += stream->szfbuf; + } + + /* RECFM=U to a text file should write up to the most + recent newline */ + if (stream->line_buf && stream->reallyu && stream->reallyt) + { + p = (char *)ptr + bytes - 1; + /* look for a newline somewhere in this new data */ + /* since we write on both buffer full and newline + found conditions */ + while (p >= (char *)ptr) + { + if (*p == '\n') break; + p--; + } + /* found a newline, write up to this point, including + any data that may be in our internal buffer */ + if (p >= (char *)ptr) + { + p++; /* get past the newline */ + sz = stream->upto - stream->fbuf; + stream->upto = stream->fbuf; + begwrite(stream, sz + (p - (char *)ptr)); + memcpy(dptr, stream->fbuf, sz); + memcpy(dptr + sz, ptr, (p - (char *)ptr)); + finwrite(stream); + bytes -= (p - (char *)ptr); + stream->bufStartR += (p - (char *)ptr); + ptr = p; + stream->upto = stream->fbuf; + } + } + + /* any remainder needs to go into the internal buffer */ + memcpy(stream->upto, ptr, bytes); + stream->upto += bytes; + break; + + case VARIABLE_BINARY: + bytes = nmemb * size; + while (bytes > 0) + { + int fulllen; + + if (stream->errorInd) + { + nmemb = 0; + break; + } + sz = stream->upto - stream->fbuf; + if (sz < 4) + { + if ((bytes + sz) < 4) + { + memcpy(stream->upto, ptr, bytes); + stream->upto += bytes; + bytes = 0; + break; + } + else + { + memcpy(stream->upto, ptr, 4 - sz); + ptr = (char *)ptr + (4 - sz); + bytes -= (4 - sz); + stream->upto += (4 - sz); + sz = 4; + if (memcmp(stream->fbuf + 2, "\0\0", 2) != 0) + { + stream->errorInd = 1; + nmemb = 0; + break; + } + fulllen = (stream->fbuf[0] << 8) | stream->fbuf[1]; + if (fulllen == 0) + { + /* here we allow for the possibility that + they are copying a data source that has + terminating NULs added - so long as all + remaining charactes are NUL, it will be + allowed. Otherwise we rely on the above + validation to catch a problem - checking + 2 bytes at a time, which shouldn't be a + problem since this is only at the end of + the file */ + stream->upto = stream->fbuf + 2; + continue; + } + else if (fulllen < 4) + { + stream->errorInd = 1; + nmemb = 0; + break; + } + } + } + + /* we have 4 bytes, validated */ + fulllen = (stream->fbuf[0] << 8) | stream->fbuf[1]; + + /* If we have enough data, write it out */ + if ((sz + bytes) >= fulllen) + { + /* silently truncate long records to give + user more flexibility */ + if (fulllen > (stream->lrecl + 4)) + { + stream->fbuf[0] = (stream->lrecl + 4) >> 8; + stream->fbuf[1] = (stream->lrecl + 4) & 0xff; + begwrite(stream, stream->lrecl + 4); + if (sz >= (stream->lrecl + 4)) + { + memcpy(dptr, stream->fbuf, stream->lrecl + 4); + } + else + { + memcpy(dptr, stream->fbuf, sz); + memcpy(dptr + sz, ptr, stream->lrecl + 4 - sz); + } + } + else if (fulllen != 0) + { + begwrite(stream, fulllen); + memcpy(dptr, stream->fbuf, sz); + memcpy(dptr + sz, ptr, fulllen - sz); + } + if (fulllen != 0) + { + finwrite(stream); + } + stream->bufStartR += fulllen; + stream->upto = stream->fbuf; + bytes -= (fulllen - sz); + ptr = (char *)ptr + (fulllen - sz); + } + + /* less data than required, store it, without + overflowing our buffer */ + else if ((sz + bytes) > stream->lrecl) + { + memcpy(stream->upto, + ptr, + stream->lrecl - sz); + /* here we allow upto to exceed our buffer. + shouldn't be a problem as we never write + to that memory. alternative is to make + BUFSIZ 64k. */ + stream->upto += bytes; + ptr = (char *)ptr + bytes; + bytes = 0; + } + + /* enough room to fit data */ + else + { + memcpy(stream->upto, ptr, bytes); + stream->upto += bytes; + ptr = (char *)ptr + bytes; + bytes = 0; + } + } + break; + + case FIXED_TEXT: + bytes = nmemb * size; + p = memchr(ptr, '\n', bytes); + if (p != NULL) + { + sz = p - (char *)ptr; + bytes -= sz + 1; + if (stream->upto == stream->fbuf) + { + if (sz > stream->lrecl) + { + sz = stream->lrecl; + } + begwrite(stream, stream->lrecl); + memcpy(dptr, ptr, sz); + memset(dptr + sz, ' ', stream->szfbuf - sz); + finwrite(stream); + stream->bufStartR += sz; + } + else + { + if (((stream->upto - stream->fbuf) + sz) > stream->lrecl) + { + sz = stream->lrecl - (stream->upto - stream->fbuf); + } + memcpy(stream->upto, ptr, sz); + sz += (stream->upto - stream->fbuf); + begwrite(stream, stream->lrecl); + memcpy(dptr, stream->fbuf, sz); + memset(dptr + sz, ' ', stream->lrecl - sz); + finwrite(stream); + stream->bufStartR += sz; + stream->upto = stream->fbuf; + } + ptr = (char *)p + 1; + if (bytes > 0) + { + p = memchr(ptr, '\n', bytes); + while (p != NULL) + { + sz = p - (char *)ptr; + bytes -= sz + 1; + if (sz > stream->lrecl) + { + sz = stream->lrecl; + } + begwrite(stream, stream->lrecl); + memcpy(dptr, ptr, sz); + memset(dptr + sz, ' ', stream->szfbuf - sz); + finwrite(stream); + stream->bufStartR += sz; + ptr = p + 1; + p = memchr(ptr, '\n', bytes); + } + if (bytes > 0) + { + sz = bytes; + if (sz > stream->lrecl) + { + sz = stream->lrecl; + } + memcpy(stream->upto, ptr, sz); + stream->upto += sz; + bytes = 0; + } + } + } + else /* p == NULL */ + { + if (((stream->upto - stream->fbuf) + bytes) > stream->lrecl) + { + bytes = stream->lrecl - (stream->upto - stream->fbuf); + } + memcpy(stream->upto, ptr, bytes); + stream->upto += bytes; + } + break; + + case VARIABLE_TEXT: + stream->quickText = 0; + bytes = nmemb * size; + p = memchr(ptr, '\n', bytes); + if (p != NULL) + { + sz = p - (char *)ptr; + bytes -= sz + 1; + if (stream->upto == stream->fbuf) + { + if (sz > stream->lrecl) + { + sz = stream->lrecl; + } + begwrite(stream, (sz == 0) ? 5 : sz + 4); + if(sz == 0) + { + dptr[0] = 0; + dptr[1] = 5; + dptr[2] = 0; + dptr[3] = 0; + dptr[4] = ' '; + finwrite(stream); + /* note that the bufStartR needs to reflect + just the newline, and not the dummy space + we added */ + stream->bufStartR += 1; + } + else + { + dptr[0] = (sz + 4) >> 8; + dptr[1] = (sz + 4) & 0xff; + dptr[2] = 0; + dptr[3] = 0; + memcpy(dptr + 4, ptr, sz); + finwrite(stream); + stream->bufStartR += (sz + 1); + } + } + else + { + if (((stream->upto - stream->fbuf) + sz) > stream->lrecl) + { + sz = stream->lrecl - (stream->upto - stream->fbuf); + } + memcpy(stream->upto, ptr, sz); + sz += (stream->upto - stream->fbuf); + begwrite(stream, (sz == 0) ? 5 : sz + 4); + if(sz == 0) + { + dptr[0] = 0; + dptr[1] = 5; + dptr[2] = 0; + dptr[3] = 0; + dptr[4] = ' '; + finwrite(stream); + stream->bufStartR += 1; + } + else + { + dptr[0] = (sz + 4) >> 8; + dptr[1] = (sz + 4) & 0xff; + dptr[2] = 0; + dptr[3] = 0; + memcpy(dptr + 4, stream->fbuf, sz); + finwrite(stream); + stream->bufStartR += (sz + 1); + } + stream->upto = stream->fbuf; + } + ptr = (char *)p + 1; + if (bytes > 0) + { + p = memchr(ptr, '\n', bytes); + while (p != NULL) + { + sz = p - (char *)ptr; + bytes -= sz + 1; + if (sz > stream->lrecl) + { + sz = stream->lrecl; + } + begwrite(stream, (sz == 0) ? 5 : sz + 4); + if(sz == 0) + { + dptr[0] = 0; + dptr[1] = 5; + dptr[2] = 0; + dptr[3] = 0; + dptr[4] = ' '; + finwrite(stream); + stream->bufStartR += 1; + } + else + { + dptr[0] = (sz + 4) >> 8; + dptr[1] = (sz + 4) & 0xff; + dptr[2] = 0; + dptr[3] = 0; + memcpy(dptr + 4, ptr, sz); + finwrite(stream); + stream->bufStartR += (sz + 1); + } + ptr = p + 1; + p = memchr(ptr, '\n', bytes); + } + if (bytes > 0) + { + sz = bytes; + if (sz > stream->lrecl) + { + sz = stream->lrecl; + } + memcpy(stream->upto, ptr, sz); + stream->upto += sz; + bytes = 0; + } + } + } + else /* p == NULL */ + { + if (((stream->upto - stream->fbuf) + bytes) > stream->lrecl) + { + bytes = stream->lrecl - (stream->upto - stream->fbuf); + } + memcpy(stream->upto, ptr, bytes); + stream->upto += bytes; + } + break; + } + return (nmemb); +} + +__PDPCLIB_API__ size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) +{ + size_t bytes; + size_t read; + size_t totalread; + size_t extra; + unsigned char *eptr; + + if (stream->quickBin) + { + if ((nmemb == 1) && (size == stream->lrecl)) + { + if (__aread(stream->hfile, &dptr) != 0) + { + stream->eofInd = 1; + stream->quickBin = 0; + return (0); + } + memcpy(ptr, dptr, size); + stream->bufStartR += size; + return (1); + } + else + { + stream->quickBin = 0; + } + } + if (stream->eofInd) + { + return (0); + } + + /* If we have an unget character, then write it into + the buffer in advance */ + if (stream->ungetCh != -1) + { + stream->upto--; + *stream->upto = stream->ungetCh; + stream->ungetCh = -1; + } + + switch (stream->style) + { + case FIXED_TEXT: + bytes = nmemb * size; + read = stream->endbuf - stream->upto; + if (read > bytes) + { + memcpy(ptr, stream->upto, bytes); + stream->upto += bytes; + totalread = bytes; + } + else + { + memcpy(ptr, stream->upto, read); + stream->bufStartR += (stream->endbuf - stream->fbuf); + stream->upto = stream->endbuf = stream->fbuf; + totalread = read; + } + + while (totalread < bytes) + { + if (__aread(stream->hfile, &dptr) != 0) + { + stream->eofInd = 1; + break; + } + + eptr = dptr + stream->lrecl - 1; + while ((*eptr == ' ') && (eptr >= dptr)) + { + eptr--; + } + + read = eptr + 1 - dptr; + + if ((totalread + read) >= bytes) + { + extra = (totalread + read) - bytes; + read -= extra; + memcpy(stream->fbuf, dptr + read, extra); + stream->endbuf = stream->fbuf + extra; + *stream->endbuf++ = '\n'; + } + + memcpy((char *)ptr + totalread, dptr, read); + totalread += read; + stream->bufStartR += read; + if (totalread < bytes) + { + *((char *)ptr + totalread) = '\n'; + totalread++; + stream->bufStartR++; + } + } + return ((size == 0) ? 0 : (totalread / size)); + break; + + case FIXED_BINARY: + bytes = nmemb * size; + read = stream->endbuf - stream->upto; + if (read > bytes) + { + memcpy(ptr, stream->upto, bytes); + stream->upto += bytes; + totalread = bytes; + } + else + { + memcpy(ptr, stream->upto, read); + stream->bufStartR += (stream->endbuf - stream->fbuf); + stream->upto = stream->endbuf = stream->fbuf; + totalread = read; + } + + while (totalread < bytes) + { + if (__aread(stream->hfile, &dptr) != 0) + { + stream->eofInd = 1; + break; + } + + read = stream->lrecl; + + if ((totalread + read) > bytes) + { + extra = (totalread + read) - bytes; + read -= extra; + memcpy(stream->fbuf, dptr + read, extra); + stream->endbuf = stream->fbuf + extra; + } + + memcpy((char *)ptr + totalread, dptr, read); + totalread += read; + stream->bufStartR += read; + } + return ((size == 0) ? 0 : (totalread / size)); + break; + + case VARIABLE_TEXT: + bytes = nmemb * size; + read = stream->endbuf - stream->upto; + if (read > bytes) + { + memcpy(ptr, stream->upto, bytes); + stream->upto += bytes; + totalread = bytes; + } + else + { + memcpy(ptr, stream->upto, read); + stream->bufStartR += (stream->endbuf - stream->fbuf); + stream->upto = stream->endbuf = stream->fbuf; + totalread = read; + } + + while (totalread < bytes) + { + if (__aread(stream->hfile, &dptr) != 0) + { + stream->eofInd = 1; + break; + } + + read = (dptr[0] << 8) | dptr[1]; + read -= 4; + dptr += 4; + if ((read == 1) && (dptr[0] == ' ')) + { + read = 0; + } + + if ((totalread + read) >= bytes) + { + extra = (totalread + read) - bytes; + read -= extra; + memcpy(stream->fbuf, dptr + read, extra); + stream->endbuf = stream->fbuf + extra; + *stream->endbuf++ = '\n'; + } + + memcpy((char *)ptr + totalread, dptr, read); + totalread += read; + stream->bufStartR += read; + if (totalread < bytes) + { + *((char *)ptr + totalread) = '\n'; + totalread++; + stream->bufStartR++; + } + } + return ((size == 0) ? 0 : (totalread / size)); + break; + + case VARIABLE_BINARY: + bytes = nmemb * size; + read = stream->endbuf - stream->upto; + if (read > bytes) + { + memcpy(ptr, stream->upto, bytes); + stream->upto += bytes; + totalread = bytes; + } + else + { + memcpy(ptr, stream->upto, read); + stream->bufStartR += (stream->endbuf - stream->fbuf); + stream->upto = stream->endbuf = stream->fbuf; + totalread = read; + } + + while (totalread < bytes) + { + if (__aread(stream->hfile, &dptr) != 0) + { + stream->eofInd = 1; + break; + } + + if (!stream->reallyu) + { + read = (dptr[0] << 8) | dptr[1]; + } + else + { + read = lenread; + if (stream->reallyt) + { + unsigned char *p; + + /* get rid of any trailing NULs in text mode */ + p = memchr(dptr, '\0', read); + if (p != NULL) + { + read = p - dptr; + } + } + } + + if ((totalread + read) > bytes) + { + extra = (totalread + read) - bytes; + read -= extra; + memcpy(stream->fbuf, dptr + read, extra); + stream->endbuf = stream->fbuf + extra; + } + + memcpy((char *)ptr + totalread, dptr, read); + totalread += read; + stream->bufStartR += read; + } + return ((size == 0) ? 0 : (totalread / size)); + break; + + default: + break; + } + return (0); +} + +#endif + +/* + filedef dynamically allocates a file (via SVC 99) on MVS-like + environments. +*/ + +#if defined(__MVS__) + +static struct { + char len; /* length of request block, always 20 */ + char verb; /* dynamic allocation function requested */ + char flag1; + char flag2; + short error_reason; /* returned */ + short info_reason; /* returned */ + void *tu_list; /* list of pointers to text units */ + int reserved; + char moreflags[4]; /* extraflags */ +} rb; + +static void *tu_list[10]; /* pointers to text units */ + +static struct { + short key; /* key defining what this text unit is */ + short numparms; /* number of parms that follow */ + short parm1_len; + char parm1[98]; + /* parm2_len etc would theoretically follow, but we + can't define them, because the length of 98 is probably + not correct in the first place */ +} tu[10]; + +static void filedef(char *fdddname, char *fnm, int mymode) +{ + memset(&rb, 0x00, sizeof rb); + rb.len = 20; + rb.verb = 0x01; /* allocate */ + rb.tu_list = tu_list; + + tu_list[0] = &tu[0]; + tu[0].key = 0x0001; /* ddname */ + tu[0].numparms = 1; + tu[0].parm1_len = strlen(fdddname); + strcpy(tu[0].parm1, fdddname); + + tu_list[1] = &tu[1]; + tu[1].key = 0x0002; /* dsname */ + tu[1].numparms = 1; + tu[1].parm1_len = strlen(fnm); + strcpy(tu[1].parm1, fnm); + + tu_list[2] = &tu[2]; + tu[2].key = 0x0004; /* disp */ + tu[2].numparms = 1; + tu[2].parm1_len = 1; + tu[2].parm1[0] = 0x08; /* SHR */ + + tu_list[3] = 0; + tu_list[4] = 0; + tu_list[5] = (void *)0x80000000; + + errno = __svc99(&rb); + + /* if we had an error, then for datasets open for write, + try allocating a new dataset (this will be the normal + situation - it is abnormal is to find the dataset already + pre-allocated */ + if (errno) + { + /* if open for write */ + if ( mymode ) + { + tu[2].parm1[0] = 0x04; /* NEW */ + /* Note that the operating system, e.g. PDOS, + may override the RECFM, e.g. to make everything + RECFM=U + */ + + /* if binary */ + if (modeType == 5) + { + /* F80, which is default */ + /* That seems like a strange default. Regardless, + we should be using RECFM=U, BLKSIZE=6233 for + output binary files */ + } + else + { + /* V255 */ + tu_list[3] = &tu[3]; + tu[3].key = 0x49; /* RECFM */ + tu[3].numparms = 1; + tu[3].parm1_len = 1; + tu[3].parm1[0] = 0x40; /* V */ + + tu_list[4] = &tu[4]; + tu[4].key = 0x42; /* LRECL */ + tu[4].numparms = 1; + tu[4].parm1_len = 2; + tu[4].parm1[0] = 0; /* LRECL = 255 */ + tu[4].parm1[1] = 255; + } + } + errno = __svc99(&rb); + } + if (errno != 0) + { + if (rb.error_reason != 0) + { + errno = rb.error_reason; + } + err = 1; + } + return; +} + +static void fdclr(char *ddname) +{ + memset(&rb, 0x00, sizeof rb); + rb.len = 20; + rb.verb = 0x02; /* unallocate */ + rb.tu_list = tu_list; + + tu_list[0] = &tu[0]; + tu[0].key = 0x0001; /* ddname */ + tu[0].numparms = 1; + tu[0].parm1_len = strlen(ddname); + strcpy(tu[0].parm1, ddname); + + tu_list[1] = (void *)0x80000000; + + __svc99(&rb); + return; +} +#endif + + +/* + Following code issues a FILEDEF for CMS +*/ + +#ifdef __CMS__ +static void filedef(char *fdddname, char *fnm, int mymode) +{ + char s202parm [800]; + + int code; + int parm; + char *fname; + char *ftype; + char *fmode; + char *member; + char *p; + int console; + +/* + Skip leading blanks because sometimes people do that in CMS +*/ + while (fnm[0] == ' ') fnm++; + +/* + first parse the file name +*/ + console = 0; + if( fnm[0] == '*') console = 1; + while ( NULL != (p = strchr(fnm, '.')) )*p=' '; /* replace . with */ +/* + check for a member +*/ + p = strtok(fnm, "(" ); /* member name starts with a ( */ + member = strtok (NULL, ")" ); + fname = strtok(p, " "); + ftype = strtok(NULL, " "); + if (ftype == NULL) ftype = ""; + fmode = strtok(NULL, " "); + if (fmode == NULL) fmode = ""; + + +/* + Now build the SVC 202 string +*/ + memcpy ( &s202parm[0] , "FILEDEF ", 8); + memcpy ( &s202parm[8] , fdddname, 8); + if(console) + { + memcpy ( &s202parm[16] , "TERMINAL", 8); + memcpy ( &s202parm[24] , "( " , 8 ); + memcpy ( &s202parm[32] , "RECFM " , 8 ); + memcpy ( &s202parm[40] , "V " , 8 ); + memcpy ( &s202parm[48] , "LRECL " , 8 ); + memcpy ( &s202parm[56] , "80 " , 8 ); + s202parm[64]=s202parm[65]=s202parm[66]=s202parm[67]= + s202parm[68]=s202parm[69]=s202parm[70]=s202parm[71]=0xff; + } + else + { + memcpy ( &s202parm[16] , "DISK ", 8); +/* + Clear PARMS area +*/ + memcpy ( &s202parm[24] , " " , 8); + memcpy ( &s202parm[32] , " " , 8); + if (mymode) + { + memcpy ( &s202parm[40] , "A1 " , 8); + if (fmode[0] != '\0') + { + memcpy ( &s202parm[40] , fmode, strlen(fmode)); + } + } + else + { + memcpy ( &s202parm[40] , "* " , 8); + memcpy ( &s202parm[40] , fmode , strlen(fmode) ); + } + + memcpy ( &s202parm[24] , fname , + ( strlen(fname) > 8 ) ? 8 : strlen(fname) ); + memcpy ( &s202parm[32] , ftype , + ( strlen(ftype) >8 ) ? 8 : strlen(ftype) ); + if ( mymode ) + { + memcpy ( &s202parm[48] , "( " , 8 ); + memcpy ( &s202parm[56] , "RECFM " , 8 ); + memcpy ( &s202parm[64] , "V " , 8 ); + memcpy ( &s202parm[72] , "LRECL " , 8 ); + memcpy ( &s202parm[80] , "2000 " , 8 ); + if (modeType == 5) + { + memcpy ( &s202parm[64] , "F " , 8 ); + memcpy ( &s202parm[80] , "800 " , 8 ); + } + s202parm[88]=s202parm[89]=s202parm[90]=s202parm[91]= + s202parm[92]=s202parm[93]=s202parm[94]=s202parm[95]=0xff; + } + else + { + if(member == NULL) + { + s202parm[48]=s202parm[49]=s202parm[50]=s202parm[51]= + s202parm[52]=s202parm[53]=s202parm[54]=s202parm[55]=0xff; + } + else + { + memcpy ( &s202parm[48] , "( " , 8 ); + memcpy ( &s202parm[64] , " " , 8 ); + memcpy ( &s202parm[56] , "MEMBER " , 8 ); + memcpy ( &s202parm[64] , member , + ( strlen(member) >8 ) ? 8 : strlen(member) ); + s202parm[72]=s202parm[73]=s202parm[74]=s202parm[75]= + s202parm[76]=s202parm[77]=s202parm[78]=s202parm[79]=0xff; + } + } + } + __SVC202 ( s202parm, &code, &parm ); +} + +static void fdclr(char *ddname) +{ + char s202parm [800]; + int code; + int parm; + + /* build the SVC 202 string */ + memcpy( &s202parm[0] , "FILEDEF ", 8); + memcpy( &s202parm[8] , ddname, 8); + memcpy( &s202parm[16] , "CLEAR ", 8); + memset( &s202parm[24], 0xff, 8); + + __SVC202 ( s202parm, &code, &parm ); + return; +} + +/* + Following code does a rename for CMS +*/ + +static int cmsrename(const char *old, const char *newnam) +{ + char s202parm[8*8]; + int code; + int parm; + char fnm[FILENAME_MAX]; + char *p; + char *q; + + memset(s202parm, ' ', sizeof s202parm); + + memcpy(&s202parm[0], "RENAME ", 8); + + strncpy(fnm, old, sizeof fnm); + fnm[sizeof fnm - 1] = '\0'; + p = fnm; + while (*p != '\0') + { + *p = toupper((unsigned)*p); + p++; + } + p = strchr(fnm, ' '); + if (p == NULL) p = strchr(fnm, '.'); + if (p == NULL) return (-1); + *p++ = '\0'; + q = strchr(p, ' '); + if (q == NULL) q = strchr(p, '.'); + if (q == NULL) q = "A"; + else *q++ = '\0'; + + memcpy(&s202parm[8], fnm, (strlen(fnm) > 8 ? 8 : strlen(fnm))); + memcpy(&s202parm[16], p, (strlen(p) > 8 ? 8 : strlen(p))); + memcpy(&s202parm[24], q, (strlen(q) > 8 ? 8 : strlen(q))); + + strncpy(fnm, newnam, sizeof fnm); + fnm[sizeof fnm - 1] = '\0'; + p = fnm; + while (*p != '\0') + { + *p = toupper((unsigned)*p); + p++; + } + p = strchr(fnm, ' '); + if (p == NULL) p = strchr(fnm, '.'); + if (p == NULL) return (-1); + *p++ = '\0'; + q = strchr(p, ' '); + if (q == NULL) q = strchr(p, '.'); + if (q == NULL) q = "A"; + else *q++ = '\0'; + + memcpy(&s202parm[32], fnm, (strlen(fnm) > 8 ? 8 : strlen(fnm))); + memcpy(&s202parm[40], p, (strlen(p) > 8 ? 8 : strlen(p))); + memcpy(&s202parm[48], q, (strlen(q) > 8 ? 8 : strlen(q))); + + memset(&s202parm[56], 0xff, 8); + + __SVC202(s202parm, &code, &parm); + return (parm); +} + +/* + Following code does a remove for CMS +*/ + +static int cmsremove(const char *filename) +{ + char s202parm[5*8]; + int code; + int parm; + const char *p; + const char *q; + char *f; + char fnm[FILENAME_MAX]; + + strncpy(fnm, filename, sizeof fnm); + fnm[sizeof fnm - 1] = '\0'; + f = fnm; + while (*f != '\0') + { + *f = toupper((unsigned)*f); + f++; + } + filename = fnm; + + memset(s202parm, ' ', sizeof s202parm); + + /* build the SVC 202 string */ + memcpy( &s202parm[0] , "ERASE ", 8); + + p = strchr(filename, ' '); + if (p == NULL) + { + p = strchr(filename, '.'); + } + if (p == NULL) + { + memcpy( &s202parm[8] , filename, strlen(filename)); + memset( &s202parm[16], 0xff, 8); + } + else + { + memcpy( &s202parm[8] , filename, p - filename); + q = strchr(p + 1, ' '); + if (q == NULL) + { + q = strchr(p + 1, '.'); + } + if (q == NULL) + { + memcpy( &s202parm[16] , p + 1, strlen(p + 1)); + memset( &s202parm[24], 0xff, 8); + } + else + { + memcpy( &s202parm[16] , p + 1, q - p - 1); + memcpy( &s202parm[24] , q + 1, strlen(q + 1)); + memset( &s202parm[32], 0xff, 8); + } + } + + __SVC202 ( s202parm, &code, &parm ); + return (parm); +} + +static char *int_strtok(char *s1, const char *s2) +{ + static char *old = NULL; + char *p; + size_t len; + size_t remain; + + if (s1 != NULL) old = s1; + if (old == NULL) return (NULL); + p = old; + len = strspn(p, s2); + remain = strlen(p); + if (remain <= len) { old = NULL; return (NULL); } + p += len; + len = strcspn(p, s2); + remain = strlen(p); + if (remain <= len) { old = NULL; return (p); } + *(p + len) = '\0'; + old = p + len + 1; + return (p); +} + +#endif + + +/* + + The truely cludged piece of code was concocted by Dave Wade + + His erstwhile tutors are probably turning in their graves. + + It is however placed in the Public Domain so that any one + who wishes to improve is free to do so + +*/ + +static void dblcvt(double num, char cnvtype, size_t nwidth, + int nprecision, char *result) +{ + double b,round; + int i,j,exp,pdigits,format; + char sign, work[125]; + + /* save original data & set sign */ + + if ( num < 0 ) + { + b = -num; + sign = '-'; + } + else + { + b = num; + sign = ' '; + } + + /* + Now scale to get exponent + */ + + exp = 0; + if( b > 1.0 ) + { + while ((b >= 10.0) && (exp < 120)) + { + ++exp; + b=b / 10.0; + } + } + else if ( b == 0.0 ) + { + exp=0; + } + /* 1.0 will get exp = 0 */ + else if ( b < 1.0 ) + { + while ((b < 1.0) && (exp > -120)) + { + --exp; + b=b*10.0; + } + } + if ((exp <= -120) || (exp >= 120)) + { + exp = 0; + b = 0.0; + } + + /* + now decide how to print and save in FORMAT. + -1 => we need leading digits + 0 => print in exp + +1 => we have digits before dp. + */ + + switch (cnvtype) + { + case 'E': + case 'e': + format = 0; + break; + case 'f': + case 'F': + if ( exp >= 0 ) + { + format = 1; + } + else + { + format = -1; + } + break; + default: + /* Style e is used if the exponent from its + conversion is less than -4 or greater than + or equal to the precision. + */ + if ( exp >= 0 ) + { + if ( nprecision > exp ) + { + format=1; + } + else + { + format=0; + } + } + else + { + /* if ( nprecision > (-(exp+1) ) ) { */ + if ( exp >= -4) + { + format=-1; + } + else + { + format=0; + } + } + break; + } + /* + Now round + */ + switch (format) + { + case 0: /* we are printing in standard form */ + if (nprecision < DBL_MANT_DIG) /* we need to round */ + { + j = nprecision; + } + else + { + j=DBL_MANT_DIG; + } + round = 1.0/2.0; + i = 0; + while (++i <= j) + { + round = round/10.0; + } + b = b + round; + if (b >= 10.0) + { + b = b/10.0; + exp = exp + 1; + } + break; + + case 1: /* we have a number > 1 */ + /* need to round at the exp + nprecisionth digit */ + if (exp + nprecision < DBL_MANT_DIG) /* we need to round */ + { + j = exp + nprecision; + } + else + { + j = DBL_MANT_DIG; + } + round = 0.5; + i = 0; + while (i++ < j) + { + round = round/10; + } + b = b + round; + if (b >= 10.0) + { + b = b/10.0; + exp = exp + 1; + } + break; + + case -1: /* we have a number that starts 0.xxxx */ + if (nprecision < DBL_MANT_DIG) /* we need to round */ + { + j = nprecision + exp + 1; + } + else + { + j = DBL_MANT_DIG; + } + round = 5.0; + i = 0; + while (i++ < j) + { + round = round/10; + } + if (j >= 0) + { + b = b + round; + } + if (b >= 10.0) + { + b = b/10.0; + exp = exp + 1; + } + if (exp >= 0) + { + format = 1; + } + break; + } + /* + Now extract the requisite number of digits + */ + + if (format==-1) + { + /* + Number < 1.0 so we need to print the "0." + and the leading zeros... + */ + result[0]=sign; + result[1]='0'; + result[2]='.'; + result[3]=0x00; + while (++exp) + { + --nprecision; + strcat(result,"0"); + } + i=b; + --nprecision; + work[0] = (char)('0' + i % 10); + work[1] = 0x00; + strcat(result,work); + + pdigits = nprecision; + + while (pdigits-- > 0) + { + b = b - i; + b = b * 10.0; + i = b; + work[0] = (char)('0' + i % 10); + work[1] = 0x00; + strcat(result,work); + } + } + /* + Number >= 1.0 just print the first digit + */ + else if (format==+1) + { + i = b; + result[0] = sign; + result[1] = '\0'; + work[0] = (char)('0' + i % 10); + work[1] = 0x00; + strcat(result,work); + nprecision = nprecision + exp; + pdigits = nprecision ; + + while (pdigits-- > 0) + { + if ( ((nprecision-pdigits-1)==exp) ) + { + strcat(result,"."); + } + b = b - i; + b = b * 10.0; + i = b; + work[0] = (char)('0' + i % 10); + work[1] = 0x00; + strcat(result,work); + } + } + /* + printing in standard form + */ + else + { + i = b; + result[0] = sign; + result[1] = '\0'; + work[0] = (char)('0' + i % 10); + work[1] = 0x00; + strcat(result,work); + strcat(result,"."); + + pdigits = nprecision; + + while (pdigits-- > 0) + { + b = b - i; + b = b * 10.0; + i = b; + work[0] = (char)('0' + i % 10); + work[1] = 0x00; + strcat(result,work); + } + } + + if (format==0) + { /* exp format - put exp on end */ + work[0] = 'E'; + if ( exp < 0 ) + { + exp = -exp; + work[1]= '-'; + } + else + { + work[1]= '+'; + } + work[2] = (char)('0' + (exp/10) % 10); + work[3] = (char)('0' + exp % 10); + work[4] = 0x00; + strcat(result, work); + } + else + { + /* get rid of trailing zeros for g specifier */ + if (cnvtype == 'G' || cnvtype == 'g') + { + char *p; + + p = strchr(result, '.'); + if (p != NULL) + { + p++; + p = p + strlen(p) - 1; + while (*p != '.' && *p == '0') + { + *p = '\0'; + p--; + } + if (*p == '.') + { + *p = '\0'; + } + } + } + } + /* printf(" Final Answer = <%s> fprintf gives=%g\n", + result,num); */ + /* + do we need to pad + */ + if(result[0] == ' ')strcpy(work,result+1); else strcpy(work,result); + pdigits=nwidth-strlen(work); + result[0]= 0x00; + while(pdigits>0) + { + strcat(result," "); + pdigits--; + } + strcat(result,work); + return; +} diff --git a/app/src/main/cpp/pdpclib/armeabi-v7a/stdio.h b/app/src/main/cpp/pdpclib/armeabi-v7a/stdio.h new file mode 100644 index 0000000..085bc00 --- /dev/null +++ b/app/src/main/cpp/pdpclib/armeabi-v7a/stdio.h @@ -0,0 +1,330 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* stdio.h - stdio header file */ +/* */ +/*********************************************************************/ + +#ifndef __STDIO_INCLUDED +#define __STDIO_INCLUDED + +/* Perhaps should copy these definitions in instead */ +#include + +#ifndef __SIZE_T_DEFINED +#define __SIZE_T_DEFINED +#if (defined(__OS2__) || defined(__32BIT__) || defined(__MVS__) \ + || defined(__CMS__) || defined(__VSE__) || defined(__SMALLERC__) \ + || defined(__ARM__) || defined(__gnu_linux__) || defined(__PDOS386__) \ + || defined(__SZ4__)) +typedef unsigned long size_t; +#elif (defined(__MSDOS__) || defined(__DOS__) || defined(__POWERC) \ + || defined(__WIN32__) || defined(__AMIGA__) || defined(__EFI__)) +typedef unsigned int size_t; +#endif +#endif + +/* + What we have is an internal buffer, which is 8 characters + longer than the actually used buffer. E.g. say BUFSIZ is + 512 bytes, then we actually allocate 520 bytes. The first + 2 characters will be junk, the next 2 characters set to NUL, + for protection against some backward-compares. The fourth-last + character is set to '\n', to protect against overscan. The + last 3 characters will be junk, to protect against memory + violation. intBuffer is the internal buffer, but everyone refers + to fbuf, which is actually set to the &intBuffer[4]. Also, + szfbuf is the size of the "visible" buffer, not the internal + buffer. The reason for the 2 junk characters at the beginning + is to align the buffer on a 4-byte boundary. + + Here is what memory would look like after an fwrite of "ABC" + to an MVS LRECL=80, RECFM=F dataset: + + intbuffer: x'50000' + fbuf: x'50004' + upto: x'50007' + endbuf: x'58004' + + x'50004' = x'C1' + x'50005' = x'C2' + x'50006' = x'C3' +*/ + +typedef struct +{ +#if (defined(__OS2__) || defined(__32BIT__) || defined(__PDOS386__)) + unsigned long hfile; /* OS/2 file handle */ +#elif (defined(__MSDOS__) || defined(__DOS__) || defined(__POWERC) \ + || defined(__SMALLERC__)) + int hfile; /* dos file handle */ +#elif defined(__WIN32__) || defined(__AMIGA__) + void *hfile; +#elif defined(__gnu_linux__) || defined(__ARM__) || defined(__EFI__) + int hfile; +#endif +#if (defined(__MVS__) || defined(__CMS__) || defined(__VSE__)) + void *hfile; + void *asmbuf; + int recfm; + int true_recfm; + int style; + int lrecl; + int blksize; + char ddname[9]; + char pdsmem[9]; + int reallyu; /* 1 = this is really a RECFM=U file */ + int reallyt; /* 1 = this is really a text file */ + int dynal; /* 1 = this file was dynamically allocated */ + int line_buf; /* 1 = we are forcing line buffering */ +#endif +#if defined(__VSE__) + int vse_punch; /* 1 = this is writing to a VSE library */ + char *vselupto; /* where we are up to in the internal buffer */ + char *vselend; /* end of the internal buffer */ +#endif + int quickBin; /* 1 = do DosRead NOW!!!! */ + int quickText; /* 1 = quick text mode */ + int textMode; /* 1 = text mode, 0 = binary mode */ + int intFno; /* internal file number */ + unsigned long bufStartR; /* buffer start represents, e.g. if we + have read in 3 buffers, each of 512 bytes, and we are + currently reading from the 3rd buffer, then the first + character in the buffer would be 1024, so that is what is + put in bufStartR. */ + int justseeked; /* 1 = last operation was a seek */ + char *fbuf; /* file buffer - this is what all the routines + look at. */ + size_t szfbuf; /* size of file buffer (the one that the routines + see, and the user allocates, and what is actually + read in from disk) */ + char *upto; /* what character is next to read from buffer */ + char *endbuf; /* pointer PAST last character in buffer, ie it + points to the '\n' in the internal buffer */ + int errorInd; /* whether an error has occurred on this file */ + int eofInd; /* whether EOF has been reached on this file */ + int ungetCh; /* character pushed back, -1 if none */ + int bufTech; /* buffering technique, _IOFBF etc */ + char *intBuffer; /* internal buffer */ + int noNl; /* When doing gets, we don't copy NL */ + int mode; /* __READ_MODE or __WRITE_MODE */ + int update; /* Is file update (read + write)? */ + int theirBuffer; /* Is the buffer supplied by them? */ + int permfile; /* Is this stdin/stdout/stderr? */ + int isopen; /* Is this file open? */ + char modeStr[4]; /* 2nd parameter to fopen */ + int tempch; /* work variable for putc */ + int istemp; /* opened by tmpfile? */ +} FILE; + +typedef unsigned long fpos_t; + +#define NULL ((void *)0) +#define FILENAME_MAX 260 +#define FOPEN_MAX 256 +#define _IOFBF 1 +#define _IOLBF 2 +#define _IONBF 3 + + +#ifndef BUFSIZ + +/*#define BUFSIZ 409600*/ +/* #define BUFSIZ 8192 */ +/*#define BUFSIZ 5120*/ + +#if defined(__MVS__) || defined(__VSE__) +/* set it to maximum possible LRECL to simplify processing */ +/* also add in room for a RDW and dword align it just to be + on the safe side */ +#define BUFSIZ 32768 +#elif defined(__CMS__) +/* similar considerations for CMS as MVS */ +#define BUFSIZ 65544 +#else +#define BUFSIZ 6144 +#endif +/* #define BUFSIZ 10 */ +/* #define BUFSIZ 512 */ + +#endif + + +#define EOF -1 +#define L_tmpnam FILENAME_MAX +#define TMP_MAX 25 +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 +#define __NFILE (FOPEN_MAX - 3) +#define __READ_MODE 0 +#define __WRITE_MODE 1 + +#define __RECFM_F 0 +#define __RECFM_V 1 +#define __RECFM_U 2 + +#if 0 +extern FILE *stdin; +extern FILE *stdout; +extern FILE *stderr; + +extern FILE *__userFiles[__NFILE]; +#endif + +FILE **__gtin(void); +FILE **__gtout(void); +FILE **__gterr(void); + +#define __stdin (*(__gtin())) +#define __stdout (*(__gtout())) +#define __stderr (*(__gterr())) + +#if defined(__WIN32__) && !defined(__STATIC__) +/* For Windows stdin, stdout and stderr macros + * are implemented using an array FILE _iob[] + * where the first three members + * are stdin, stdout and stderr. + * In this array each member has size 32 bytes, + * so __DUMMYFILE is used instead + * and the pointers are converted + * using __INTFILE macro. */ +#define __DUMMYFILE_SIZE 32 + +typedef struct +{ + char filler[__DUMMYFILE_SIZE]; +} __DUMMYFILE; + +#ifndef __PDPCLIB_DLL +__declspec(dllimport) __DUMMYFILE _iob[3]; +#endif + +#define stdin ((FILE *) &(_iob[0])) +#define stdout ((FILE *) &(_iob[1])) +#define stderr ((FILE *) &(_iob[2])) + +#define __INTFILE(f) (((f) == stdin) ? __stdin : \ + ((f) == stdout) ? __stdout : \ + ((f) == stderr) ? __stderr : \ + f) +#else +#define stdin (*(__gtin())) +#define stdout (*(__gtout())) +#define stderr (*(__gterr())) + +#define __INTFILE(f) (f) +#endif + +#if defined(__VSE__) +extern FILE *__stdpch; +#endif + +int printf(const char *format, ...); +FILE *fopen(const char *filename, const char *mode); +int fclose(FILE *stream); +size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); +size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); +int fputc(int c, FILE *stream); +int fputs(const char *s, FILE *stream); +int fprintf(FILE *stream, const char *format, ...); +int vfprintf(FILE *stream, const char *format, va_list arg); +int vprintf(const char *format, va_list arg); +int remove(const char *filename); +int rename(const char *old, const char *newnam); +int sprintf(char *s, const char *format, ...); +int vsprintf(char *s, const char *format, va_list arg); +char *fgets(char *s, int n, FILE *stream); +int ungetc(int c, FILE *stream); +int fgetc(FILE *stream); +int fseek(FILE *stream, long offset, int whence); +long ftell(FILE *stream); +int fsetpos(FILE *stream, const fpos_t *pos); +int fgetpos(FILE *stream, fpos_t *pos); +void rewind(FILE *stream); +void clearerr(FILE *stream); +void perror(const char *s); +int setvbuf(FILE *stream, char *buf, int mode, size_t size); +int setbuf(FILE *stream, char *buf); +FILE *freopen(const char *filename, const char *mode, FILE *stream); +int fflush(FILE *stream); +char *tmpnam(char *s); +FILE *tmpfile(void); +int fscanf(FILE *stream, const char *format, ...); +int scanf(const char *format, ...); +int sscanf(const char *s, const char *format, ...); +char *gets(char *s); +int puts(const char *s); + +#ifndef __POWERC +int getchar(void); +int putchar(int c); +int getc(FILE *stream); +int putc(int c, FILE *stream); +int feof(FILE *stream); +int ferror(FILE *stream); +#endif + +#if !defined(__WIN32__) || defined(__STATIC__) +#define getchar() (getc(stdin)) +#define putchar(c) (putc((c), stdout)) +#define getc(stream) (fgetc((stream))) +#define putc(c, stream) \ + ( \ + ((stream)->tempch = (c)), \ + ((stream)->quickBin = 0), \ + ((stream)->quickText = 0), \ + (((stream)->tempch == '\n') \ + || (stream)->justseeked \ + || (((stream)->upto + 1) >= (stream)->endbuf)) ? \ + (fputc((stream)->tempch, (stream))) : \ + (*(stream)->upto++ = (stream)->tempch) \ + ) + +#define feof(stream) ((stream)->eofInd) +#define ferror(stream) ((stream)->errorInd) +#endif + +#if defined(__PDOSGEN__) +#include <__os.h> + +#define printf __os->Xprintf +#undef stdin +#define stdin __os->Xstdin +#undef stdout +#define stdout __os->Xstdout +#undef stderr +#define stderr __os->Xstderr +#define fopen __os->Xfopen +#define fseek __os->Xfseek +#define fread __os->Xfread +#define fclose __os->Xfclose +#define fwrite __os->Xfwrite +#define fgets __os->Xfgets +#define fgetc __os->Xfgetc +#define fputc __os->Xfputc +#define fflush __os->Xfflush +#define remove __os->Xremove +#define fputs __os->Xfputs +#define fprintf __os->Xfprintf +#define tmpnam __os->Xtmpnam +#define vfprintf __os->Xvfprintf +#define ungetc __os->Xungetc +#define vsprintf __os->Xvsprintf +#define sprintf __os->Xsprintf +#define ftell __os->Xftell +#define perror __os->Xperror +#define rewind __os->Xrewind +#define sscanf __os->Xsscanf +#define rename __os->Xrename +#define clearerr __os->Xclearerr +#endif + +#endif /* __STDIO_INCLUDED */ + + diff --git a/app/src/main/cpp/pdpclib/armeabi-v7a/stdlib.c b/app/src/main/cpp/pdpclib/armeabi-v7a/stdlib.c new file mode 100644 index 0000000..a7ba1cd --- /dev/null +++ b/app/src/main/cpp/pdpclib/armeabi-v7a/stdlib.c @@ -0,0 +1,1123 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* stdlib.c - implementation of stuff in stdlib.h */ +/* */ +/*********************************************************************/ + +#include "stdlib.h" +#include "signal.h" +#include "string.h" +#include "ctype.h" +#include "stddef.h" + +/* VSE is similar to MVS */ +#if defined(__VSE__) +#define __MVS__ 1 +#endif + +/* PDOS and MSDOS use the same interface most of the time */ +#if defined(__PDOS386__) || defined(__SMALLERC__) +#define __MSDOS__ +#endif + +#ifdef __PDOS386__ +#include +#endif + +#ifdef __AMIGA__ +#include +#endif + +#ifdef __EFI__ +#include "efi.h" +#endif + +#ifdef __OS2__ +#define INCL_DOSMISC +#define INCL_DOSPROCESS +#include +#endif + +#ifdef __WIN32__ +#include +#endif + +#if defined(__MVS__) || defined(__CMS__) +#include "mvssupa.h" +#endif + +#ifdef __MVS__ +extern int __tso; +#endif + +#if USE_MEMMGR +#include "__memmgr.h" +/* GCCMVS 3.4.6 requires 49 MB minimum for full optimization */ +/* so we give it 60. GCCMVS 3.2.3 only requires 20 MB */ +/* Note that you can set MAX_CHUNK to less than REQ_CHUNK */ +/* But don't do this until MVS/380 etc have been changed to */ +/* allow multiple memory requests. */ +/* But bump it up to almost 64 MiB so that if CMS is misconfigured */ +/* it tries to get almost 16 MiB (and from subpool 3) so should fail */ + +#if defined(MULMEM) +#define MAX_CHUNK 67100672 +#define REQ_CHUNK 67100672 +#elif defined(__gnu_linux__) || defined(__ARM__) +#define MAX_CHUNK 30000000 /* maximum size we will store in memmgr */ +#define REQ_CHUNK 30000000 /* size that we request from OS */ +#else +#define MAX_CHUNK 67100672 /* maximum size we will store in memmgr */ +#define REQ_CHUNK 67100672 /* size that we request from OS */ +#endif +void *__lastsup = NULL; /* last thing supplied to memmgr */ +#endif + +#ifdef __MSDOS__ +#if defined(__WATCOMC__) && !defined(__32BIT__) +#define CTYP __cdecl +#else +#define CTYP +#endif +#if defined(__32BIT__) && !defined(NOLIBALLOC) +/* For PDOS-32 liballoc is used for memory management. */ +#include "liballoc.h" +#else +void CTYP __allocmem(size_t size, void **ptr); +void CTYP __freemem(void *ptr); +#endif +extern unsigned char *__envptr; +int CTYP __exec(char *cmd, void *env); +int CTYP __getrc(void); +#endif + +#if defined(__gnu_linux__) || defined(__ARM__) +void *__allocmem(size_t size); +#endif + +void (*__userExit[__NATEXIT])(void); + +__PDPCLIB_API__ void *malloc(size_t size) +{ +#ifdef __AMIGA__ + size_t *x; + + x = AllocMem(size + sizeof(size_t), 0); + if (x == NULL) return (NULL); + *x = size; + return (x + 1); +#endif +#ifdef __EFI__ + size_t *x = NULL; + + __gBS->AllocPool(EfiLoaderData, size + sizeof(size_t), (void *)&x); + if (x == NULL) return (NULL); + *x = size; + return (x + 1); +#endif +#ifdef __OS2__ + PVOID BaseAddress; + ULONG ulObjectSize; + ULONG ulAllocationFlags; + APIRET rc; + + ulObjectSize = size + sizeof(size_t); + ulAllocationFlags = PAG_COMMIT | PAG_WRITE | PAG_READ; + rc = DosAllocMem(&BaseAddress, ulObjectSize, ulAllocationFlags); + if (rc != 0) return (NULL); + *(size_t *)BaseAddress = size; + BaseAddress = (char *)BaseAddress + sizeof(size_t); + return ((void *)BaseAddress); +#endif +#ifdef __MSDOS__ +#if defined(__32BIT__) && !defined(NOLIBALLOC) + return (__malloc(size)); +#else + size_t *ptr; + + __allocmem(size + sizeof(size_t), (void **)&ptr); + if (ptr == NULL) return (NULL); + *ptr = size; + return (ptr + 1); +#endif +#endif +#if USE_MEMMGR + void *ptr; + + if (size > MAX_CHUNK) + { +#if defined(__MVS__) || defined(__CMS__) || defined(__gnu_linux__) \ + || defined(__ARM__) +#if defined(MULMEM) + /* If we support multiple memory requests */ + ptr = __getm(size); +#else + ptr = NULL; +#endif +#elif defined(__WIN32__) + ptr = GlobalAlloc(0, size + sizeof(size_t)); + if (ptr != NULL) + { + *(size_t *)ptr = size; + ptr = (char *)ptr + sizeof(size_t); + } +#elif defined(__gnu_linux__) || defined(__ARM__) + ptr = __allocmem(size + sizeof(size_t)); + if (ptr != NULL) + { + *(size_t *)ptr = size; + ptr = (char *)ptr + sizeof(size_t); + } +#endif + } + else + { + ptr = memmgrAllocate(&__memmgr, size, 0); + if (ptr == NULL) + { + void *ptr2; + +#if defined(__MVS__) || defined(__CMS__) + /* until MVS/380 is fixed, don't do an additional request, + unless MULMEM is defined */ +#if defined(MULMEM) + if (1) +#else + if (__memmgr.start == NULL) +#endif + { + ptr2 = __getm(REQ_CHUNK); + } + else + { + ptr2 = NULL; + } +#elif defined(__WIN32__) + ptr2 = GlobalAlloc(0, REQ_CHUNK); + if (ptr2 != NULL) + { + *(size_t *)ptr2 = size; + ptr2 = (char *)ptr2 + sizeof(size_t); + } +#elif defined(__gnu_linux__) || defined(__ARM__) + if (__memmgr.start == NULL) + { + ptr2 = __allocmem(REQ_CHUNK); + } + else + { + ptr2 = NULL; + } + if (ptr2 != NULL) + { + *(size_t *)ptr2 = size; + ptr2 = (char *)ptr2 + sizeof(size_t); + } +#endif + if (ptr2 == NULL) + { + return (NULL); + } + __lastsup = ptr2; + memmgrSupply(&__memmgr, ptr2, REQ_CHUNK); + ptr = memmgrAllocate(&__memmgr, size, 0); + } + } + return (ptr); +#else /* not MEMMGR */ +#if defined(__MVS__) || defined(__CMS__) + return (__getm(size)); +#elif defined(__WIN32__) + void *ptr; + + ptr = GlobalAlloc(0, size + sizeof(size_t)); + if (ptr != NULL) + { + *(size_t *)ptr = size; + ptr = (char *)ptr + sizeof(size_t); + } + return (ptr); +#elif defined(__gnu_linux__) || defined(__ARM__) + void *ptr; + + ptr = __allocmem(size + sizeof(size_t)); + if (ptr != NULL) + { + *(size_t *)ptr = size; + ptr = (char *)ptr + sizeof(size_t); + } + return (ptr); +#endif +#endif /* not MEMMGR */ +} + +__PDPCLIB_API__ void *calloc(size_t nmemb, size_t size) +{ + void *ptr; + size_t total; + + if (nmemb == 1) + { + total = size; + } + else if (size == 1) + { + total = nmemb; + } + else + { + total = nmemb * size; + } + ptr = malloc(total); + if (ptr != NULL) + { + memset(ptr, '\0', total); + } + return (ptr); +} + +__PDPCLIB_API__ void *realloc(void *ptr, size_t size) +{ +#if defined(__PDOS386__) && !defined(NOLIBALLOC) + return (__realloc(ptr, size)); +#else + char *newptr; + size_t oldsize; + + if (size == 0) + { + free(ptr); + return (NULL); + } +#if USE_MEMMGR + if (memmgrRealloc(&__memmgr, ptr, size) == 0) + { + return (ptr); + } +#endif + newptr = malloc(size); + if (newptr == NULL) + { + return (NULL); + } + if (ptr != NULL) + { + oldsize = *((size_t *)ptr - 1); + if (oldsize < size) + { + size = oldsize; + } + memcpy(newptr, ptr, size); + free(ptr); + } + return (newptr); +#endif +} + +__PDPCLIB_API__ void free(void *ptr) +{ +#ifdef __AMIGA__ + if (ptr != NULL) + { + ptr = (char *)ptr - sizeof(size_t); + FreeMem(ptr, *(size_t *)ptr + sizeof(size_t)); + } +#endif +#ifdef __EFI__ + if (ptr != NULL) + { + ptr = (char *)ptr - sizeof(size_t); + __gBS->FreePool(ptr); + } +#endif +#ifdef __OS2__ + if (ptr != NULL) + { + ptr = (char *)ptr - sizeof(size_t); + DosFreeMem((PVOID)ptr); + } +#endif +#ifdef __MSDOS__ +#if defined(__32BIT__) && !defined(NOLIBALLOC) + __free(ptr); +#else + if (ptr != NULL) + { + ptr = (char *)ptr - sizeof(size_t); + __freemem(ptr); + } +#endif +#endif +#if USE_MEMMGR + if (ptr != NULL) + { + size_t size; + + size = *((size_t *)ptr - 1); + if (size > MAX_CHUNK) + { +#if defined(__MVS__) || defined(__CMS__) +#if defined(MULMEM) + /* Ignore, unless MULMEM is defined, until MVS/380 is fixed */ + __freem(ptr); +#endif +#elif defined(__WIN32__) + GlobalFree(((size_t *)ptr) - 1); +#endif + } + else + { + memmgrFree(&__memmgr, ptr); + } + } +#else /* not using MEMMGR */ +#if defined(__MVS__) || defined(__CMS__) + if (ptr != NULL) + { + __freem(ptr); + } +#endif +#ifdef __WIN32__ + if (ptr != NULL) + { + GlobalFree(((size_t *)ptr) - 1); + } +#endif +#endif /* not USE_MEMMGR */ + return; +} + +__PDPCLIB_API__ void abort(void) +{ + raise(SIGABRT); + exit(EXIT_FAILURE); +#if !defined(__EMX__) && !defined(__GNUC__) && !defined(__WIN32__) \ + && !defined(__gnu_linux__) && !defined(__ARM__) + return; +#endif +} + +#if !defined(__EMX__) && !defined(__GNUC__) && !defined(__gnu_linux__) \ + && !defined(__ARM__) \ + || defined(WATLIN) +void __exit(int status); +#else +void __exit(int status) __attribute__((noreturn)); +#endif + +__PDPCLIB_API__ void exit(int status) +{ + __exit(status); +#if !defined(__EMX__) && !defined(__GNUC__) && !defined(__WIN32__) \ + && !defined(__gnu_linux__) && !defined(__ARM__) + return; +#endif +} + +/* This qsort routine was obtained from libnix (also public domain), + * and then reformatted. + * + * This qsort function does a little trick: + * To reduce stackspace it iterates the larger interval instead of doing + * the recursion on both intervals. + * So stackspace is limited to 32*stack_for_1_iteration = + * 32*4*(4 arguments+1 returnaddress+11 stored registers) = 2048 Bytes, + * which is small enough for everybodys use. + * (And this is the worst case if you own 4GB and sort an array of chars.) + * Sparing the function calling overhead does improve performance, too. + */ + +__PDPCLIB_API__ void qsort(void *base, + size_t nmemb, + size_t size, + int (*compar)(const void *, const void *)) +{ + char *base2 = (char *)base; + size_t i,a,b,c; + + while (nmemb > 1) + { + a = 0; + b = nmemb-1; + c = (a+b)/2; /* Middle element */ + for (;;) + { + while ((*compar)(&base2[size*c],&base2[size*a]) > 0) + { + a++; /* Look for one >= middle */ + } + while ((*compar)(&base2[size*c],&base2[size*b]) < 0) + { + b--; /* Look for one <= middle */ + } + if (a >= b) + { + break; /* We found no pair */ + } + for (i=0; i> 16) & 0x7fff); + myseed = myseed * 1103515245UL + 12345; + ret = (ret << 16) | (int)((myseed >> 16) & 0xffff); +#else + ret = (int)((myseed >> 16) & 0x7fff); +#endif + return (ret); +} + +__PDPCLIB_API__ double atof(const char *nptr) +{ + return (strtod(nptr, (char **)NULL)); +} + +__PDPCLIB_API__ double strtod(const char *nptr, char **endptr) +{ + double x = 0.0; + double xs= 1.0; + double es = 1.0; + double xf = 0.0; + double xd = 1.0; + + while( isspace( (unsigned char)*nptr ) ) ++nptr; + if(*nptr == '-') + { + xs = -1; + nptr++; + } + else if(*nptr == '+') + { + nptr++; + } + + + while (1) + { + if (isdigit((unsigned char)*nptr)) + { + x = x * 10 + (*nptr - '0'); + nptr++; + } + else + { + x = x * xs; + break; + } + } + if (*nptr == '.') + { + nptr++; + while (1) + { + if (isdigit((unsigned char)*nptr)) + { + xf = xf * 10 + (*nptr - '0'); + xd = xd * 10; + } + else + { + x = x + xs * (xf / xd); + break; + } + nptr++; + } + } + if ((*nptr == 'e') || (*nptr == 'E')) + { + nptr++; + if (*nptr == '-') + { + es = -1; + nptr++; + } + xd = 1; + xf = 0; + while (1) + { + if (isdigit((unsigned char)*nptr)) + { + xf = xf * 10 + (*nptr - '0'); + nptr++; + } + else + { + while (xf > 0) + { + xd = xd * 10; + xf = xf - 1; + } + if (es < 0.0) + { + x = x / xd; + } + else + { + x = x * xd; + } + break; + } + } + } + if (endptr != NULL) + { + *endptr = (char *)nptr; + } + return (x); +} + +__PDPCLIB_API__ int atoi(const char *nptr) +{ + return ((int)strtol(nptr, (char **)NULL, 10)); +} + +__PDPCLIB_API__ long int atol(const char *nptr) +{ + return (strtol(nptr, (char **)NULL, 10)); +} + +/* this logic is also in vvscanf - if you update this, update + that one too */ + +__PDPCLIB_API__ unsigned long int strtoul( + const char *nptr, char **endptr, int base) +{ + unsigned long x = 0; + int undecided = 0; + + if (base == 0) + { + undecided = 1; + } + while (isspace((unsigned char)*nptr)) + { + nptr++; + } + while (1) + { + if (isdigit((unsigned char)*nptr)) + { + if (base == 0) + { + if (*nptr == '0') + { + base = 8; + } + else + { + base = 10; + undecided = 0; + } + } + x = x * base + (*nptr - '0'); + nptr++; + } + else if (isalpha((unsigned char)*nptr)) + { + if ((*nptr == 'X') || (*nptr == 'x')) + { + if ((base == 0) || ((base == 8) && undecided)) + { + base = 16; + undecided = 0; + nptr++; + } + else if (base == 16) + { + /* hex values are allowed to have an optional 0x */ + nptr++; + } + else + { + break; + } + } + else if (base <= 10) + { + break; + } + else + { + x = x * base + (toupper((unsigned char)*nptr) - 'A') + 10; + nptr++; + } + } + else + { + break; + } + } + if (endptr != NULL) + { + *endptr = (char *)nptr; + } + return (x); +} + +__PDPCLIB_API__ long int strtol(const char *nptr, char **endptr, int base) +{ + unsigned long y; + long x; + int neg = 0; + + while (isspace((unsigned char)*nptr)) + { + nptr++; + } + if (*nptr == '-') + { + neg = 1; + nptr++; + } + else if (*nptr == '+') + { + nptr++; + } + y = strtoul(nptr, endptr, base); + if (neg) + { + x = (long)-y; + } + else + { + x = (long)y; + } + return (x); +} + +__PDPCLIB_API__ int mblen(const char *s, size_t n) +{ + if (s == NULL) + { + return (0); + } + if (n == 1) + { + return (1); + } + else + { + return (-1); + } +} + +__PDPCLIB_API__ int mbtowc(wchar_t *pwc, const char *s, size_t n) +{ + if (s == NULL) + { + return (0); + } + if (n == 1) + { + if (pwc != NULL) + { + *pwc = *s; + } + return (1); + } + else + { + return (-1); + } +} + +__PDPCLIB_API__ int wctomb(char *s, wchar_t wchar) +{ + if (s != NULL) + { + *s = wchar; + return (1); + } + else + { + return (0); + } +} + +__PDPCLIB_API__ size_t mbstowcs(wchar_t *pwcs, const char *s, size_t n) +{ + strncpy((char *)pwcs, s, n); + if (strlen(s) >= n) + { + return (n); + } + return (strlen((char *)pwcs)); +} + +__PDPCLIB_API__ size_t wcstombs(char *s, const wchar_t *pwcs, size_t n) +{ + strncpy(s, (const char *)pwcs, n); + if (strlen((const char *)pwcs) >= n) + { + return (n); + } + return (strlen(s)); +} + +#ifdef abs +#undef abs +#endif +__PDPCLIB_API__ int abs(int j) +{ + if (j < 0) + { + j = -j; + } + return (j); +} + +__PDPCLIB_API__ div_t div(int numer, int denom) +{ + div_t x; + + x.quot = numer / denom; + x.rem = numer % denom; + return (x); +} + +#ifdef labs +#undef labs +#endif +__PDPCLIB_API__ long int labs(long int j) +{ + if (j < 0) + { + j = -j; + } + return (j); +} + +__PDPCLIB_API__ ldiv_t ldiv(long int numer, long int denom) +{ + ldiv_t x; + + x.quot = numer / denom; + x.rem = numer % denom; + return (x); +} + +__PDPCLIB_API__ int atexit(void (*func)(void)) +{ + int x; + + for (x = 0; x < __NATEXIT; x++) + { + if (__userExit[x] == 0) + { + __userExit[x] = func; + return (0); + } + } + return (-1); +} + +static int ins_strncmp(const char *one, const char *two, size_t len) +{ + size_t x = 0; + + if (len == 0) return (0); + while ((x < len) + && (toupper((unsigned char)*one) == toupper((unsigned char)*two))) + { + if (*one == '\0') + { + return (0); + } + one++; + two++; + x++; + } + if (x == len) return (0); + return (toupper((unsigned char)*one) - toupper((unsigned char)*two)); +} + +__PDPCLIB_API__ char *getenv(const char *name) +{ +#ifdef __OS2__ + PSZ result; + + if (DosScanEnv((void *)name, (void *)&result) == 0) + { + return ((char *)result); + } +#endif +#if defined(__MSDOS__) || defined(__WIN32__) + char *env; + size_t lenn; + +#ifdef __WIN32__ + env = GetEnvironmentStrings(); +#else + env = (char *)__envptr; +#endif + lenn = strlen(name); + while (*env != '\0') + { + if (ins_strncmp(env, name, lenn) == 0) + { + if (env[lenn] == '=') + { + return (&env[lenn + 1]); + } + } + env = env + strlen(env) + 1; + } +#endif + return (NULL); +} + +/* The following code was taken from Paul Markham's "EXEC" program, + and adapted to create a system() function. The code is all + public domain */ + +__PDPCLIB_API__ int system(const char *string) +{ +#ifdef __OS2__ + char err_obj[100]; + APIRET rc; + RESULTCODES results; + + if (string == NULL) + { + return (1); + } + rc = DosExecPgm(err_obj, sizeof err_obj, EXEC_SYNC, + (PSZ)string, NULL, &results, (PSZ)string); + if (rc != 0) + { + return (rc); + } + return ((int)results.codeResult); +#endif +#ifdef __WIN32__ + BOOL rc; + PROCESS_INFORMATION pi; + STARTUPINFO si; + DWORD ExitCode; + char *cmdproc; + char cmdbuf[300]; + + cmdproc = getenv("COMSPEC"); + if (cmdproc == NULL) + { + return (-1); + } + if (strlen(string) + strlen(cmdproc) > sizeof cmdbuf - 10) + { + return (-2); + } + strcpy(cmdbuf, cmdproc); + strcat(cmdbuf, " /c "); + strcat(cmdbuf, string); + + memset(&si, 0, sizeof si); + si.cb = sizeof si; + memset(&pi, 0, sizeof pi); + + rc = CreateProcess(cmdproc, + cmdbuf, + NULL, + NULL, + FALSE, + 0, + NULL, + NULL, + &si, + &pi); + if (!rc) + { + int ret; + + ret = GetLastError(); + if (ret == 0) + { + ret = -1; /* force an error */ + } + return (ret); + } + WaitForSingleObject(pi.hProcess, INFINITE); + GetExitCodeProcess(pi.hProcess, &ExitCode); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return (ExitCode); +#endif +#ifdef __MSDOS__ + int rc; +#ifdef __PDOS386__ + static unsigned char cmdt[300]; +#else + static unsigned char cmdt[140]; +#endif + static +#ifdef __PDOS386__ + POSEXEC_PARMBLOCK +#else + struct { + unsigned short env; + unsigned char *cmdtail; + char *fcb1; + char *fcb2; + } +#endif + parmblock = { 0, cmdt, NULL, NULL }; + size_t len; + char *cmd; + + if (string == NULL) + { + return (1); + } + cmd = getenv("COMSPEC"); + if (cmd == NULL) + { + cmd = "\\command.com"; + } +#ifdef __PDOS386__ + if ((strlen(cmd) + strlen(string) + 5) > sizeof cmdt) + { + return (-1); + } + strcpy(cmdt, cmd); + strcat(cmdt, " /c "); + strcat(cmdt, string); +#else + len = strlen(string); + cmdt[0] = (unsigned char)(len + 3); + memcpy(&cmdt[1], "/c ", 3); + memcpy(&cmdt[4], string, len); + memcpy(&cmdt[len + 4], "\r", 2); +#endif + rc = __exec(cmd, &parmblock); + if (rc != 0) return (-rc); + return (__getrc()); +#endif +#if defined(MUSIC) + return (__system(strlen(string), string)); +#elif defined(__MVS__) + char pgm[9]; + size_t pgm_len; + size_t cnt; + char *p; + + p = strchr(string, ' '); + if (p == NULL) + { + p = strchr(string, '\0'); + } + + pgm_len = p - string; + /* don't allow a program name greater than 8 */ + + if (pgm_len > 8) + { + return (-1); + } + memcpy(pgm, string, pgm_len); + pgm[pgm_len] = '\0'; + + /* uppercase the program name */ + for (cnt = 0; cnt < pgm_len; cnt++) + { + pgm[cnt] = toupper((unsigned char)pgm[cnt]); + } + + /* point to parms */ + if (*p != '\0') + { + p++; + } + + /* all parms now available */ + /* we use 1 = batch or 2 = tso */ + return (__system(__tso ? 2: 1, pgm_len, pgm, strlen(p), p)); +#endif +#if defined(__CMS__) + /* not implemented yet */ + return (0); +#endif +} + +__PDPCLIB_API__ void *bsearch(const void *key, const void *base, + size_t nmemb, size_t size, + int (*compar)(const void *, const void *)) +{ + size_t try; + int res; + const void *ptr; + + while (nmemb > 0) + { + try = nmemb / 2; + ptr = (void *)((char *)base + try * size); + res = compar(ptr, key); + if (res == 0) + { + return ((void *)ptr); + } + else if (res < 0) + { + nmemb = nmemb - try - 1; + base = (const void *)((const char *)ptr + size); + } + else + { + nmemb = try; + } + } + return (NULL); +} diff --git a/app/src/main/cpp/pdpclib/armeabi-v7a/stdlib.h b/app/src/main/cpp/pdpclib/armeabi-v7a/stdlib.h new file mode 100644 index 0000000..7161bc2 --- /dev/null +++ b/app/src/main/cpp/pdpclib/armeabi-v7a/stdlib.h @@ -0,0 +1,143 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* stdlib.h - stdlib header file */ +/* */ +/*********************************************************************/ + +#ifndef __STDLIB_INCLUDED +#define __STDLIB_INCLUDED + +#ifndef __SIZE_T_DEFINED +#define __SIZE_T_DEFINED +#if (defined(__OS2__) || defined(__32BIT__) || defined(__MVS__) \ + || defined(__CMS__) || defined(__VSE__) || defined(__SMALLERC__) \ + || defined(__ARM__)|| defined(__gnu_linux__) || defined(__PDOS386__) \ + || defined(__SZ4__)) +typedef unsigned long size_t; +#elif (defined(__MSDOS__) || defined(__DOS__) || defined(__POWERC) \ + || defined(__WIN32__) || defined(__AMIGA__) || defined(__EFI__)) +typedef unsigned int size_t; +#endif +#endif +#ifndef __WCHAR_T_DEFINED +#define __WCHAR_T_DEFINED +#ifndef _WCHAR_T_DEFINED +#define _WCHAR_T_DEFINED +#endif +typedef char wchar_t; +#endif +typedef struct { int quot; int rem; } div_t; +typedef struct { long quot; long rem; } ldiv_t; + +#define NULL ((void *)0) +#define EXIT_SUCCESS 0 +#if defined(__MVS__) || defined(__CMS__) || defined(__VSE__) +#define EXIT_FAILURE 12 +#else +#define EXIT_FAILURE 1 +#endif +#if defined(__32BIT__) || defined(__WIN32__) +#define RAND_MAX 2147483647 +#else +#define RAND_MAX 32767 +#endif +#define MB_CUR_MAX 1 +#define __NATEXIT 32 + +void *malloc(size_t size); +void *calloc(size_t nmemb, size_t size); +void *realloc(void *ptr, size_t size); +void free(void *ptr); +#if (defined(__MVS__) || defined(__CMS__) || defined(__VSE__)) \ + && defined(__GNUC__) +void abort(void) __attribute__((noreturn)); +void exit(int status) __attribute__((noreturn)); +#else +void abort(void); +void exit(int status); +#endif + +#ifdef __SUBC__ +void qsort(void *a, size_t b, size_t c, + int (*f)()); +#else +void qsort(void *a, size_t b, size_t c, + int (*f)(const void *d, const void *e)); +#endif + +void srand(unsigned int seed); +int rand(void); +double atof(const char *nptr); +double strtod(const char *nptr, char **endptr); +int atoi(const char *nptr); +long atol(const char *nptr); +long strtol(const char *nptr, char **endptr, int base); +unsigned long strtoul(const char *nptr, char **endptr, int base); +int mblen(const char *s, size_t n); +int mbtowc(wchar_t *pwc, const char *s, size_t n); +int wctomb(char *s, wchar_t wchar); +size_t mbstowcs(wchar_t *pwcs, const char *s, size_t n); +size_t wcstombs(char *s, const wchar_t *pwcs, size_t n); +int abs(int j); +div_t div(int numer, int denom); +long labs(long j); +ldiv_t ldiv(long numer, long denom); + +#ifdef __SUBC__ +int atexit(int (*func)()); +#else +int atexit(void (*func)(void)); +#endif + +char *getenv(const char *name); +int system(const char *string); + +#ifdef __SUBC__ +void *bsearch(const void *key, const void *base, + size_t nmemb, size_t size, + int (*compar)()); +#else +void *bsearch(const void *key, const void *base, + size_t nmemb, size_t size, + int (*compar)(const void *, const void *)); +#endif + +#ifdef __WATCOMC__ +#pragma intrinsic (abs,labs,div,ldiv) +#endif + +#if defined(__IBMC__) && defined(__OS2__) +int _Builtin __abs(int j); +#define abs(j) (__abs((j))) +long _Builtin __labs(long j); +#define labs(j) (__labs((j))) +#endif + +#if defined(__PDOSGEN__) +#include <__os.h> + +#define malloc __os->malloc +#define free __os->free +#undef abort +#define abort __os->abort +#define getenv __os->Xgetenv +#define exit __os->Xexit +#define calloc __os->Xcalloc +#define realloc __os->Xrealloc +#define atoi __os->Xatoi +#define strtol __os->Xstrtol +#define strtoul __os->Xstrtoul +#define qsort __os->Xqsort +#define bsearch __os->Xbsearch +#define abs __os->Xabs +#define atof __os->Xatof + +#endif + +#endif diff --git a/app/src/main/cpp/pdpclib/armeabi-v7a/string.c b/app/src/main/cpp/pdpclib/armeabi-v7a/string.c new file mode 100644 index 0000000..5b02bb8 --- /dev/null +++ b/app/src/main/cpp/pdpclib/armeabi-v7a/string.c @@ -0,0 +1,491 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* string.c - implementation of routines in string.h */ +/* */ +/*********************************************************************/ + +#include "stdio.h" +#include "string.h" +#include "stddef.h" + +#if defined(__PDOSGEN__) + +/* Because the compiler sometimes generates a deliberate call to + memcpy, the memcpy function needs to exist. We could instead make + the compiler generate code that honors the memcpy macro, but for + now, this will do */ + +#undef memcpy +__PDPCLIB_API__ void *memcpy(void *s1, const void *s2, size_t n) +{ + return (__os->memcpy(s1, s2, n)); +} + +#undef memset +__PDPCLIB_API__ void *memset(void *s, int c, size_t n) +{ + return (__os->memset(s, c, n)); +} + +#else + +#ifdef memmove +#undef memmove +#endif +__PDPCLIB_API__ void *memmove(void *s1, const void *s2, size_t n) +{ + char *p = s1; + const char *cs2 = s2; + size_t x; + + if (p <= cs2) + { + for (x=0; x < n; x++) + { + *p = *cs2; + p++; + cs2++; + } + } + else + { + if (n != 0) + { + for (x=n-1; x > 0; x--) + { + *(p+x) = *(cs2+x); + } + *(p+x) = *(cs2+x); + } + } + return (s1); +} + +#ifdef strcpy +#undef strcpy +#endif +__PDPCLIB_API__ char *strcpy(char *s1, const char *s2) +{ + char *p = s1; + + while ((*p++ = *s2++) != '\0') ; + return (s1); +} + +#ifdef strncpy +#undef strncpy +#endif +__PDPCLIB_API__ char *strncpy(char *s1, const char *s2, size_t n) +{ + char *p = s1; + size_t x; + + for (x=0; x < n; x++) + { + *p = *s2; + if (*s2 == '\0') break; + p++; + s2++; + } + for (; x < n; x++) + { + *p++ = '\0'; + } + return (s1); +} + +#ifdef strcat +#undef strcat +#endif +__PDPCLIB_API__ char *strcat(char *s1, const char *s2) +{ + char *p = s1; + + while (*p != '\0') p++; + while ((*p = *s2) != '\0') + { + p++; + s2++; + } + return (s1); +} + +#ifdef strncat +#undef strncat +#endif +__PDPCLIB_API__ char *strncat(char *s1, const char *s2, size_t n) +{ + char *p = s1; + size_t x = 0; + + while (*p != '\0') p++; + while ((*s2 != '\0') && (x < n)) + { + *p = *s2; + p++; + s2++; + x++; + } + *p = '\0'; + return (s1); +} + +#ifdef memcmp +#undef memcmp +#endif +__PDPCLIB_API__ int memcmp(const void *s1, const void *s2, size_t n) +{ + const unsigned char *p1; + const unsigned char *p2; + size_t x = 0; + + p1 = (const unsigned char *)s1; + p2 = (const unsigned char *)s2; + while (x < n) + { + if (p1[x] < p2[x]) return (-1); + else if (p1[x] > p2[x]) return (1); + x++; + } + return (0); +} + +#ifdef strcmp +#undef strcmp +#endif +__PDPCLIB_API__ int strcmp(const char *s1, const char *s2) +{ + const unsigned char *p1; + const unsigned char *p2; + + p1 = (const unsigned char *)s1; + p2 = (const unsigned char *)s2; + while (*p1 != '\0') + { + if (*p1 < *p2) return (-1); + else if (*p1 > *p2) return (1); + p1++; + p2++; + } + if (*p2 == '\0') return (0); + else return (-1); +} + +#ifdef strcoll +#undef strcoll +#endif +__PDPCLIB_API__ int strcoll(const char *s1, const char *s2) +{ + return (strcmp(s1, s2)); +} + +#ifdef strncmp +#undef strncmp +#endif +__PDPCLIB_API__ int strncmp(const char *s1, const char *s2, size_t n) +{ + const unsigned char *p1; + const unsigned char *p2; + size_t x = 0; + + p1 = (const unsigned char *)s1; + p2 = (const unsigned char *)s2; + while (x < n) + { + if (p1[x] < p2[x]) return (-1); + else if (p1[x] > p2[x]) return (1); + else if (p1[x] == '\0') return (0); + x++; + } + return (0); +} + +#ifdef strxfrm +#undef strxfrm +#endif +__PDPCLIB_API__ size_t strxfrm(char *s1, const char *s2, size_t n) +{ + size_t oldlen; + + oldlen = strlen(s2); + if (oldlen < n) + { + memcpy(s1, s2, oldlen); + s1[oldlen] = '\0'; + } + return (oldlen); +} + +#ifdef memchr +#undef memchr +#endif +__PDPCLIB_API__ void *memchr(const void *s, int c, size_t n) +{ + const unsigned char *p; + size_t x = 0; + + p = (const unsigned char *)s; + while (x < n) + { + if (*p == (unsigned char)c) return ((void *)p); + p++; + x++; + } + return (NULL); +} + +#ifdef strchr +#undef strchr +#endif +__PDPCLIB_API__ char *strchr(const char *s, int c) +{ + while (*s != '\0') + { + if (*s == (char)c) return ((char *)s); + s++; + } + if (c == '\0') return ((char *)s); + return (NULL); +} + +#ifdef strcspn +#undef strcspn +#endif +__PDPCLIB_API__ size_t strcspn(const char *s1, const char *s2) +{ + const char *p1; + const char *p2; + + p1 = s1; + while (*p1 != '\0') + { + p2 = s2; + while (*p2 != '\0') + { + if (*p1 == *p2) return ((size_t)(p1 - s1)); + p2++; + } + p1++; + } + return ((size_t)(p1 - s1)); +} + +#ifdef strpbrk +#undef strpbrk +#endif +__PDPCLIB_API__ char *strpbrk(const char *s1, const char *s2) +{ + const char *p1; + const char *p2; + + p1 = s1; + while (*p1 != '\0') + { + p2 = s2; + while (*p2 != '\0') + { + if (*p1 == *p2) return ((char *)p1); + p2++; + } + p1++; + } + return (NULL); +} + +#ifdef strrchr +#undef strrchr +#endif +__PDPCLIB_API__ char *strrchr(const char *s, int c) +{ + const char *p; + + p = s + strlen(s); + while (1) + { + if (*p == (char)c) return ((char *)p); + if (p == s) break; + p--; + } + return (NULL); +} + +#ifdef strspn +#undef strspn +#endif +__PDPCLIB_API__ size_t strspn(const char *s1, const char *s2) +{ + const char *p1; + const char *p2; + + p1 = s1; + while (*p1 != '\0') + { + p2 = s2; + while (*p2 != '\0') + { + if (*p1 == *p2) break; + p2++; + } + if (*p2 == '\0') return ((size_t)(p1 - s1)); + p1++; + } + return ((size_t)(p1 - s1)); +} + + +/* strstr by Frank Adam */ +/* modified by Paul Edwards */ + +#ifdef strstr +#undef strstr +#endif +__PDPCLIB_API__ char *strstr(const char *s1, const char *s2) +{ + const char *p = s1, *p1, *p2 = s2; + + while (*p) + { + if (*p == *s2) + { + p1 = p; + p2 = s2; + while ((*p2 != '\0') && (*p1 == *p2)) + { + p1++; + p2++; + } + if (*p2 == '\0') + { + return (char *)p; + } + } + p++; + } + return NULL; +} + +#ifdef strtok +#undef strtok +#endif +__PDPCLIB_API__ char *strtok(char *s1, const char *s2) +{ + static char *old = NULL; + char *p; + size_t len; + size_t remain; + + if (s1 != NULL) old = s1; + if (old == NULL) return (NULL); + p = old; + len = strspn(p, s2); + remain = strlen(p); + if (remain <= len) { old = NULL; return (NULL); } + p += len; + len = strcspn(p, s2); + remain = strlen(p); + if (remain <= len) { old = NULL; return (p); } + *(p + len) = '\0'; + old = p + len + 1; + return (p); +} + +#ifdef memset +#undef memset +#endif +__PDPCLIB_API__ void *memset(void *s, int c, size_t n) +{ + size_t x = 0; + + for (x = 0; x < n; x++) + { + *((char *)s + x) = (unsigned char)c; + } + return (s); +} + +#ifdef strerror +#undef strerror +#endif +__PDPCLIB_API__ char *strerror(int errnum) +{ + if (errnum == 0) return ("No error has occurred\n"); + else return ("An error has occurred\n"); +} + +#ifdef strlen +#undef strlen +#endif +__PDPCLIB_API__ size_t strlen(const char *s) +{ + const char *p; + + p = s; + while (*p != '\0') p++; + return ((size_t)(p - s)); +} + +#ifndef USE_ASSEMBLER +#ifdef memcpy +#undef memcpy +#endif +#ifndef __32BIT__ +__PDPCLIB_API__ void *memcpy(void *s1, const void *s2, size_t n) +{ + register const unsigned char *f = s2; + register const unsigned char *fe; + register unsigned char *t = s1; + + fe = f + n; + while (f != fe) + { + *t++ = *f++; + } + return (s1); +} +#else +__PDPCLIB_API__ void *memcpy(void *s1, const void *s2, size_t n) +{ + register unsigned int *p = (unsigned int *)s1; + register unsigned int *cs2 = (unsigned int *)s2; + register unsigned int *endi; + + endi = (unsigned int *)((char *)p + (n & ~0x03)); + while (p != endi) + { + *p++ = *cs2++; + } + switch (n & 0x03) + { + case 0: + break; + case 1: + *(char *)p = *(char *)cs2; + break; + case 2: + *(char *)p = *(char *)cs2; + p = (unsigned int *)((char *)p + 1); + cs2 = (unsigned int *)((char *)cs2 + 1); + *(char *)p = *(char *)cs2; + break; + case 3: + *(char *)p = *(char *)cs2; + p = (unsigned int *)((char *)p + 1); + cs2 = (unsigned int *)((char *)cs2 + 1); + *(char *)p = *(char *)cs2; + p = (unsigned int *)((char *)p + 1); + cs2 = (unsigned int *)((char *)cs2 + 1); + *(char *)p = *(char *)cs2; + break; + } + return (s1); +} +#endif /* 32BIT */ +#endif /* USE_ASSEMBLER */ + +#endif /* __PDOSGEN__ */ diff --git a/app/src/main/cpp/pdpclib/armeabi-v7a/string.h b/app/src/main/cpp/pdpclib/armeabi-v7a/string.h new file mode 100644 index 0000000..da60dce --- /dev/null +++ b/app/src/main/cpp/pdpclib/armeabi-v7a/string.h @@ -0,0 +1,180 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* string.h - string header file. */ +/* */ +/*********************************************************************/ + +#ifndef __STRING_INCLUDED +#define __STRING_INCLUDED + +#ifndef __SIZE_T_DEFINED +#define __SIZE_T_DEFINED +#if (defined(__OS2__) || defined(__32BIT__) || defined(__MVS__) \ + || defined(__CMS__) || defined(__VSE__) || defined(__SMALLERC__) \ + || defined(__ARM__) || defined(__gnu_linux__) || defined(__PDOS386__) \ + || defined(__SZ4__)) +typedef unsigned long size_t; +#elif (defined(__MSDOS__) || defined(__DOS__) || defined(__POWERC) \ + || defined(__WIN32__) || defined(__AMIGA__) || defined(__EFI__)) +typedef unsigned int size_t; +#endif +#endif + +#define NULL ((void *)0) +void *memcpy(void *s1, const void *s2, size_t n); +void *memmove(void *s1, const void *s2, size_t n); +char *strcpy(char *s1, const char *s2); +char *strncpy(char *s1, const char *s2, size_t n); +char *strcat(char *s1, const char *s2); +char *strncat(char *s1, const char *s2, size_t n); +int memcmp(const void *s1, const void *s2, size_t n); +int strcmp(const char *s1, const char *s2); +int strcoll(const char *s1, const char *s2); +int strncmp(const char *s1, const char *s2, size_t n); +size_t strxfrm(char *s1, const char *s2, size_t n); +void *memchr(const void *s, int c, size_t n); +char *strchr(const char *s, int c); +size_t strcspn(const char *s1, const char *s2); +char *strpbrk(const char *s1, const char *s2); +char *strrchr(const char *s, int c); +size_t strspn(const char *s1, const char *s2); +char *strstr(const char *s1, const char *s2); +char *strtok(char *s1, const char *s2); +void *memset(void *s, int c, size_t n); +char *strerror(int errnum); +size_t strlen(const char *s); + +#if defined(__WATCOMC__) && !defined(__SZ4__) +#ifdef __INLINE_FUNCTIONS__ +#pragma intrinsic(memchr, memcmp, memcpy, strcat, strcpy, strlen, strchr) +#endif +#endif + +#if defined(__IBMC__) && defined(__OS2__) +char * _Builtin __strcat(char *s1, const char *s2); +#define strcat(s1,s2) (__strcat((s1),(s2))) +char * _Builtin __strchr(const char *s, int c); +#define strchr(s,c) (__strchr((s),(c))) +int _Builtin __strcmp(const char *s1, const char *s2); +#define strcmp(s1,s2) (__strcmp((s1),(s2))) +int _Builtin __strcpy(char *s1, const char *s2); +#define strcpy(s1,s2) (__strcpy((s1),(s2))) +size_t _Builtin __strlen(const char *s); +#define strlen(s) (__strlen((s))) +char * _Builtin __strncat(char *s1, const char *s2, size_t n); +#define strncat(s1,s2,n) (__strncat((s1),(s2),(n))) +int _Builtin __strncmp(const char *s1, const char *s2, size_t n); +#define strncmp(s1,s2,n) (__strncmp((s1),(s2),(n))) +char * _Builtin __strncpy(char *s1, const char *s2, size_t n); +#define strncpy(s1,s2,n) (__strncpy((s1),(s2),(n))) +char * _Builtin __strrchr(const char *s, int c); +#define strrchr(s,c) (__strrchr((s),(c))) +void * _Builtin __memcpy(void *s1, const void *s2, size_t n); +#define memcpy(s1,s2,n) (__memcpy((s1),(s2),(n))) +void * _Builtin __memchr(const void *s, int c, size_t n); +#define memchr(s,c,n) (__memchr((s),(c),(n))) +int _Builtin __memcmp(const void *s1, const void *s2, size_t n); +#define memcmp(s1,s2,n) (__memcmp((s1),(s2),(n))) +void * _Builtin __memset(void *s, int c, size_t n); +#define memset(s,c,n) (__memset((s),(c),(n))) +void * _Builtin __memmove(void *s1, const void *s2, size_t n); +#define memmove(s1,s2,n) (__memmove((s1),(s2),(n))) +#endif + +#ifdef __WATMUS__ +#define __GNUC__ 0 +#endif + +#if defined (__GNUC__) && __GNUC__ >= 3 && !defined(__ARM__) +#define memcpy(s1,s2,n) (__builtin_memcpy((s1),(s2),(n))) +#define memcmp(s1,s2,n) (__builtin_memcmp((s1),(s2),(n))) +#endif + +/* We don't activate these GCC builtins, because they + normally resort to a call to the normal function, + and when they do, they generate slightly worse + code! Also, they appear to be buggy on MVS. */ + +#if 0 +#define strcat(s1,s2) (__builtin_strcat((s1),(s2))) +#define strchr(s,c) (__builtin_strchr((s),(c))) +#define strcmp(s1,s2) (__builtin_strcmp((s1),(s2))) +#define strcpy(s1,s2) (__builtin_strcpy((s1),(s2))) +#define strlen(s) (__builtin_strlen((s))) +#define strncat(s1,s2,n) (__builtin_strncat((s1),(s2),(n))) +#define strncmp(s1,s2,n) (__builtin_strncmp((s1),(s2),(n))) +#define strncpy(s1,s2,n) (__builtin_strncpy((s1),(s2),(n))) +#define strrchr(s,c) (__builtin_strrchr((s),(c))) +#define memset(s,c,n) (__builtin_memset((s),(c),(n))) +#define strstr(s1,s2) (__builtin_strstr((s1),(s2))) +#define strpbrk(s1,s2) (__builtin_strpbrk((s1),(s2))) +#define strspn(s1,s2) (__builtin_strspn((s1),(s2))) +#define strcspn(s1,s2) (__builtin_strcspn((s1),(s2))) +#endif + +#ifdef __BORLANDC__ +#ifdef __INLINE_FUNCTIONS__ +void *__memcpy__(void *s1, const void *s2, size_t n); +#define memcpy(s1,s2,n) (__memcpy__((s1),(s2),(n))) +void *__memchr__(const void *s, int c, size_t n); +#define memchr(s,c,n) (__memchr__((s),(c),(n))) +int __memcmp__(const void *s1, const void *s2, size_t n); +#define memcmp(s1,s2,n) (__memcmp__((s1),(s2),(n))) +void *__memset__(void *s, int c, size_t n); +#define memset(s,c,n) (__memset__((s),(c),(n))) +char *__strcat__(char *s1, const char *s2); +#define strcat(s1,s2) (__strcat__((s1),(s2))) +char *__strchr__(const char *s, int c); +#define strchr(s,c) (__strchr__((s),(c))) +int __strcmp__(const char *s1, const char *s2); +#define strcmp(s1,s2) (__strcmp__((s1),(s2))) +char *__strcpy__(char *s1, const char *s2); +#define strcpy(s1,s2) (__strcpy__((s1),(s2))) +size_t __strlen__(const char *s); +#define strlen(s) (__strlen__((s))) +char *__strncat__(char *s1, const char *s2, size_t n); +#define strncat(s1,s2,n) (__strncat__((s1),(s2),(n))) +int __strncmp__(const char *s1, const char *s2, size_t n); +#define strncmp(s1,s2,n) (__strncmp__((s1),(s2),(n))) +char *__strncpy__(char *s1, const char *s2, size_t n); +#define strncpy(s1,s2,n) (__strncpy__((s1),(s2),(n))) +char *__strrchr__(const char *s, int c); +#define strrchr(s,c) (__strrchr__((s),(c))) +#endif +#endif + + +#if defined(__PDOSGEN__) +#include <__os.h> + +#define strchr __os->strchr +#define strcmp __os->strcmp +#define strncmp __os->strncmp +#define strcpy __os->strcpy +#define strlen __os->strlen +#undef memcpy +#define memcpy __os->memcpy +#define strncpy __os->strncpy +#define strcat __os->strcat +#define memset __os->memset +#define memmove __os->memmove +#undef memcmp +#define memcmp __os->memcmp +#define strerror __os->strerror +#define strrchr __os->strrchr +#define strstr __os->strstr +#define strpbrk __os->strpbrk +#define strspn __os->strspn +#define strcspn __os->strcspn +#define memchr __os->memchr +#define strncat __os->strncat +#endif + + +#endif diff --git a/app/src/main/cpp/pdpclib/armeabi-v7a/time.c b/app/src/main/cpp/pdpclib/armeabi-v7a/time.c new file mode 100644 index 0000000..4aa2177 --- /dev/null +++ b/app/src/main/cpp/pdpclib/armeabi-v7a/time.c @@ -0,0 +1,635 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* time.c - implementation of stuff in time.h */ +/* */ +/*********************************************************************/ + +#include "time.h" +#include "stdarg.h" +#include "stdio.h" +#include "stddef.h" + +/* just get VSE to use MVS for now */ +#if defined(__VSE__) +#define __MVS__ 1 +#endif + +/* pdos and msdos use the same interface most of the time) */ +#if defined(__PDOS386__) || defined(__SMALLERC__) +#define __MSDOS__ +#endif + +#if defined(__MVS__) || defined(__CMS__) +#include "mvssupa.h" +#endif +#ifdef __AMIGA__ +#include +#endif +#ifdef __OS2__ +#include +#endif +#ifdef __WIN32__ +#include +#endif +#ifdef __MSDOS__ +#ifdef __WATCOMC__ +#define CTYP __cdecl +#else +#define CTYP +#endif +void CTYP __datetime(void *ptr); +#endif + +#if defined(__ARM__) +unsigned long __time(void); +#endif + +#if defined(__gnu_linux__) +unsigned long __time(unsigned long *); +#endif + +/* scalar date routines -- public domain by Ray Gardner +** These will work over the range 1-01-01 thru 14699-12-31 +** The functions written by Ray are isleap, months_to_days, +** years_to_days, ymd_to_scalar, scalar_to_ymd. +** modified slightly by Paul Edwards +*/ + +static int isleap(unsigned yr) +{ + return yr % 400 == 0 || (yr % 4 == 0 && yr % 100 != 0); +} + +static unsigned months_to_days(unsigned month) +{ + return (month * 3057 - 3007) / 100; +} + +static long years_to_days (unsigned yr) +{ + return yr * 365L + yr / 4 - yr / 100 + yr / 400; +} + +static long ymd_to_scalar(unsigned yr, unsigned mo, unsigned day) +{ + long scalar; + + scalar = day + months_to_days(mo); + if ( mo > 2 ) /* adjust if past February */ + scalar -= isleap(yr) ? 1 : 2; + yr--; + scalar += years_to_days(yr); + return (scalar); +} + +static void scalar_to_ymd(long scalar, + unsigned *pyr, + unsigned *pmo, + unsigned *pday) +{ + unsigned n; /* compute inverse of years_to_days() */ + + n = (unsigned)((scalar * 400L) / 146097L); + while (years_to_days(n) < scalar) + { + n++; + } + for ( n = (unsigned)((scalar * 400L) / 146097L); years_to_days(n) < scalar; ) + n++; /* 146097 == years_to_days(400) */ + *pyr = n; + n = (unsigned)(scalar - years_to_days(n-1)); + if ( n > 59 ) { /* adjust if past February */ + n += 2; + if ( isleap(*pyr) ) + n -= n > 62 ? 1 : 2; + } + *pmo = (n * 100 + 3007) / 3057; /* inverse of months_to_days() */ + *pday = n - months_to_days(*pmo); + return; +} + +__PDPCLIB_API__ time_t time(time_t *timer) +{ + time_t tt; +#ifdef __AMIGA__ + struct DateStamp ds; +#endif +#ifdef __OS2__ + DATETIME dt; + APIRET rc; +#endif +#ifdef __WIN32__ + SYSTEMTIME dt; +#endif +#if defined(__MSDOS__) || defined(__AMIGA__) || defined(__EFI__) + struct { + int year; + int month; + int day; + int hours; + int minutes; + int seconds; + int hundredths; + } dt; +#endif +#if defined(__MVS__) || defined(__CMS__) + unsigned int clk[2]; +#endif + +#ifdef __AMIGA__ + DateStamp(&ds); + tt = ymd_to_scalar(1978, 1, 1) - ymd_to_scalar(1970, 1, 1); + tt += ds.ds_Days; + tt = tt * 24 * 60 + ds.ds_Minute; + tt = tt * 60 + ds.ds_Tick / 50; +#endif +#ifdef __OS2__ + rc = DosGetDateTime(&dt); + if (rc != 0) + { + tt = (time_t)-1; + } + else +#endif +#ifdef __WIN32__ + GetSystemTime(&dt); + tt = ymd_to_scalar(dt.wYear, dt.wMonth, dt.wDay) + - ymd_to_scalar(1970, 1, 1); + tt = tt * 24 + dt.wHour; + tt = tt * 60 + dt.wMinute; + tt = tt * 60 + dt.wSecond; +#endif +#if defined(__MSDOS__) + __datetime(&dt); +#endif +#if defined(__MVS__) || defined(__CMS__) + tt = __getclk(clk); +#elif defined(__ARM__) + tt = __time(); +#elif defined(__gnu_linux__) + tt = __time(NULL); +#elif !defined(__WIN32__) && !defined(__AMIGA__) + + { + tt = ymd_to_scalar(dt.year, dt.month, dt.day) + - ymd_to_scalar(1970, 1, 1); + tt = tt * 24 + dt.hours; + tt = tt * 60 + dt.minutes; + tt = tt * 60 + dt.seconds; + } +#endif + if (timer != NULL) + { + *timer = tt; + } + return (tt); +} + +__PDPCLIB_API__ clock_t clock(void) +{ + return ((clock_t)-1); +} + +__PDPCLIB_API__ double difftime(time_t time1, time_t time0) +{ + return ((double)(time1 - time0)); +} + +__PDPCLIB_API__ time_t mktime(struct tm *timeptr) +{ + time_t tt; + + if (timeptr->tm_year < 70) + { + tt = (time_t)-1; + } + else + { + tt = ymd_to_scalar(timeptr->tm_year + 1900, + timeptr->tm_mon + 1, + timeptr->tm_mday) + - ymd_to_scalar(1970, 1, 1); + tt = tt * 24 + timeptr->tm_hour; + tt = tt * 60 + timeptr->tm_min; + tt = tt * 60 + timeptr->tm_sec; + } + *timeptr = *gmtime(&tt); + return (tt); +} + +__PDPCLIB_API__ char *asctime(const struct tm *timeptr) +{ + static const char wday_name[7][3] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" + }; + static const char mon_name[12][3] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; + static char result[26]; + + sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n", + wday_name[timeptr->tm_wday], + mon_name[timeptr->tm_mon], + timeptr->tm_mday, timeptr->tm_hour, + timeptr->tm_min, timeptr->tm_sec, + 1900 + timeptr->tm_year); + return result; +} + +__PDPCLIB_API__ char *ctime(const time_t *timer) +{ + return (asctime(localtime(timer))); +} + +__PDPCLIB_API__ struct tm *localtime(const time_t *timer) +{ +#ifdef __MVS__ + time_t t; + int o; + int r; + + t = *timer; + o = __gettz(); /* this function returns the local timezone + offset in 1.048576 second increments. The + maximum offset people have managed to define + is 14 hours (Kirribati) and when mulplied + by 16384, this doesn't exceed a 32-bit + signed integer, so we're safe. + + However, the TZ offset value is actually + truncated, e.g. -27465.8 is stored as -27465, + which combined with the 1.048576 granularity + means that we don't have 1-second accuracy. + So we round to the nearest minute. */ + o = o * 16384; + o /= 15625; + /* now we have an inaccurate seconds */ + r = o % 60; + o /= 60; /* convert to minutes */ + if ((o >= 0) && (r >= 30)) + { + o++; + } + else if ((o <= 0) && (r <= -30)) + { + o--; + } + o *= 60; /* convert to seconds */ + t += o; + return (gmtime(&t)); +#else + return (gmtime(timer)); +#endif +} + +/* dow - written by Paul Edwards, 1993-01-31 */ +/* Released to the Public Domain */ +/* This routine will work over the range 1-01-01 to 32767-12-31. + It assumes the current calendar system has always been in + place in that time. If you pass 0 or negative years, then + it produces results on the assumption that there is a year + 0. It should always produce a value in the range of 0..6 + if a valid month and day have been passed, no matter what + the year is. However, it has not been tested for negative + years, because the results are meaningless anyway. It is + mainly to stop people playing silly buggers and causing + the macro to crash on negative years. */ + +#define dow(y,m,d) \ + ((((((m)+9)%12+1)<<4)%27 + (d) + 1 + \ + ((y)%400+400) + ((y)%400+400)/4 - ((y)%400+400)/100 + \ + (((m)<=2) ? ( \ + (((((y)%4)==0) && (((y)%100)!=0)) || (((y)%400)==0)) \ + ? 5 : 6) : 0)) % 7) + +static struct tm tms; + +__PDPCLIB_API__ struct tm *gmtime(const time_t *timer) +{ + unsigned yr, mo, da; + unsigned long secs; + unsigned long days; + + days = *timer / (60L*60*24); + secs = *timer % (60L*60*24); + scalar_to_ymd(days + ymd_to_scalar(1970, 1, 1), &yr, &mo, &da); + tms.tm_year = yr - 1900; + tms.tm_mon = mo - 1; + tms.tm_mday = da; + tms.tm_yday = (int)(ymd_to_scalar(tms.tm_year + 1900, mo, da) + - ymd_to_scalar(tms.tm_year + 1900, 1, 1)); + tms.tm_wday = dow(tms.tm_year + 1900, mo, da); + tms.tm_isdst = -1; + tms.tm_sec = (int)(secs % 60); + secs /= 60; + tms.tm_min = (int)(secs % 60); + secs /= 60; + tms.tm_hour = (int)secs; + return (&tms); +} + +/* + * strftime.c + * + * implements the iso c function strftime() + * + * written 1989-09-06 by jim nutt + * released into the public domain by jim nutt + * + * modified 1989-10-21 by Rob Duff + * + * modified 1994-08-26 by Paul Edwards + */ + +static char *aday[] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" +}; + +static char *day[] = { + "Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday" +}; + +static char *amonth[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + +static char *month[] = { + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" +}; + +static char *__tzname[2] = { "" "" }; +static char buf[26]; + +static void strfmt(char *str, const char *fmt, ...); + +/** + * + * size_t strftime(char *str, + * size_t maxs, + * const char *fmt, + * const struct tm *t) + * + * this functions acts much like a sprintf for time/date output. + * given a pointer to an output buffer, a format string and a + * time, it copies the time to the output buffer formatted in + * accordance with the format string. the parameters are used + * as follows: + * + * str is a pointer to the output buffer, there should + * be at least maxs characters available at the address + * pointed to by str. + * + * maxs is the maximum number of characters to be copied + * into the output buffer, included the '\0' terminator + * + * fmt is the format string. a percent sign (%) is used + * to indicate that the following character is a special + * format character. the following are valid format + * characters: + * + * %A full weekday name (Monday) + * %a abbreviated weekday name (Mon) + * %B full month name (January) + * %b abbreviated month name (Jan) + * %c standard date and time representation + * %d day-of-month (01-31) + * %H hour (24 hour clock) (00-23) + * %I hour (12 hour clock) (01-12) + * %j day-of-year (001-366) + * %M minute (00-59) + * %m month (01-12) + * %p local equivalent of AM or PM + * %S second (00-59) + * %U week-of-year, first day sunday (00-53) + * %W week-of-year, first day monday (00-53) + * %w weekday (0-6, sunday is 0) + * %X standard time representation + * %x standard date representation + * %Y year with century + * %y year without century (00-99) + * %Z timezone name + * %% percent sign + * + * the standard date string is equivalent to: + * + * %a %b %d %Y + * + * the standard time string is equivalent to: + * + * %H:%M:%S + * + * the standard date and time string is equivalent to: + * + * %a %b %d %H:%M:%S %Y + * + * strftime returns the number of characters placed in the + * buffer, not including the terminating \0, or zero if more + * than maxs characters were produced. + * +**/ + +__PDPCLIB_API__ size_t strftime(char *s, + size_t maxs, + const char *f, + const struct tm *t) +{ + int w; + char *p, *q, *r; + + p = s; + q = s + maxs - 1; + while ((*f != '\0')) + { + if (*f++ == '%') + { + r = buf; + switch (*f++) + { + case '%' : + r = "%"; + break; + + case 'a' : + r = aday[t->tm_wday]; + break; + + case 'A' : + r = day[t->tm_wday]; + break; + + case 'b' : + r = amonth[t->tm_mon]; + break; + + case 'B' : + r = month[t->tm_mon]; + break; + + case 'c' : + strfmt(r, "%0 %0 %2 %2:%2:%2 %4", + aday[t->tm_wday], amonth[t->tm_mon], + t->tm_mday,t->tm_hour, t->tm_min, + t->tm_sec, t->tm_year+1900); + break; + + case 'd' : + strfmt(r,"%2",t->tm_mday); + break; + + case 'H' : + strfmt(r,"%2",t->tm_hour); + break; + + case 'I' : + strfmt(r,"%2",(t->tm_hour%12)?t->tm_hour%12:12); + break; + + case 'j' : + strfmt(r,"%3",t->tm_yday+1); + break; + + case 'm' : + strfmt(r,"%2",t->tm_mon+1); + break; + + case 'M' : + strfmt(r,"%2",t->tm_min); + break; + + case 'p' : + r = (t->tm_hour>11)?"PM":"AM"; + break; + + case 'S' : + strfmt(r,"%2",t->tm_sec); + break; + + case 'U' : + w = t->tm_yday/7; + if (t->tm_yday%7 > t->tm_wday) + w++; + strfmt(r, "%2", w); + break; + + case 'W' : + w = t->tm_yday/7; + if (t->tm_yday%7 > (t->tm_wday+6)%7) + w++; + strfmt(r, "%2", w); + break; + + case 'w' : + strfmt(r,"%1",t->tm_wday); + break; + + case 'x' : + strfmt(r, "%3s %3s %2 %4", aday[t->tm_wday], + amonth[t->tm_mon], t->tm_mday, t->tm_year+1900); + break; + + case 'X' : + strfmt(r, "%2:%2:%2", t->tm_hour, + t->tm_min, t->tm_sec); + break; + + case 'y' : + strfmt(r,"%2",t->tm_year%100); + break; + + case 'Y' : + strfmt(r,"%4",t->tm_year+1900); + break; + + case 'Z' : + r = (t->tm_isdst) ? __tzname[1] : __tzname[0]; + break; + + default: + buf[0] = '%'; /* reconstruct the format */ + buf[1] = f[-1]; + buf[2] = '\0'; + if (buf[1] == 0) + f--; /* back up if at end of string */ + } + while (*r) + { + if (p == q) + { + *q = '\0'; + return 0; + } + *p++ = *r++; + } + } + else + { + if (p == q) + { + *q = '\0'; + return 0; + } + *p++ = f[-1]; + } + } + *p = '\0'; + return (size_t)(p - s); +} + +static int pow[5] = { 1, 10, 100, 1000, 10000 }; + +/** + * static void strfmt(char *str, char *fmt); + * + * simple sprintf for strftime + * + * each format descriptor is of the form %n + * where n goes from zero to four + * + * 0 -- string %s + * 1..4 -- int %?.?d + * +**/ + +static void strfmt(char *str, const char *fmt, ...) +{ + int ival, ilen; + char *sval; + va_list vp; + + va_start(vp, fmt); + while (*fmt) + { + if (*fmt++ == '%') + { + ilen = *fmt++ - '0'; + if (ilen == 0) /* zero means string arg */ + { + sval = va_arg(vp, char*); + while (*sval) + *str++ = *sval++; + } + else /* always leading zeros */ + { + ival = va_arg(vp, int); + while (ilen) + { + ival %= pow[ilen--]; + *str++ = (char)('0' + ival / pow[ilen]); + } + } + } + else *str++ = fmt[-1]; + } + *str = '\0'; + va_end(vp); +} diff --git a/app/src/main/cpp/pdpclib/armeabi-v7a/time.h b/app/src/main/cpp/pdpclib/armeabi-v7a/time.h new file mode 100644 index 0000000..782c38d --- /dev/null +++ b/app/src/main/cpp/pdpclib/armeabi-v7a/time.h @@ -0,0 +1,72 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* time.h - time header file. */ +/* */ +/*********************************************************************/ + +#ifndef __TIME_INCLUDED +#define __TIME_INCLUDED + +#define CLOCKS_PER_SEC 1000 +#define NULL ((void *)0) + +typedef unsigned int clock_t; + +#ifndef __SIZE_T_DEFINED +#define __SIZE_T_DEFINED +#if (defined(__OS2__) || defined(__32BIT__) || defined(__MVS__) \ + || defined(__CMS__) || defined(__VSE__) || defined(__SMALLERC__) \ + || defined(__ARM__) || defined(__gnu_linux__) || defined(__PDOS386__) \ + || defined(__SZ4__)) +typedef unsigned long size_t; +#elif (defined(__MSDOS__) || defined(__DOS__) || defined(__POWERC) \ + || defined(__WIN32__) || defined(__AMIGA__) || defined(__EFI__)) +typedef unsigned int size_t; +#endif +#endif + +typedef unsigned long time_t; + +struct tm +{ + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; +}; + +time_t time(time_t *timer); +clock_t clock(void); +double difftime(time_t time1, time_t time0); +time_t mktime(struct tm *timeptr); +char *asctime(const struct tm *timeptr); +char *ctime(const time_t *timer); +struct tm *gmtime(const time_t *timer); +struct tm *localtime(const time_t *timer); +size_t strftime(char *s, size_t maxsize, + const char *format, const struct tm *timeptr); + + +#if defined(__PDOSGEN__) +#include <__os.h> + +#define ctime __os->Xctime +#define localtime __os->Xlocaltime +#define time __os->Xtime +#define clock __os->Xclock + +#endif + + +#endif diff --git a/app/src/main/cpp/pdpclib/x86/CMakeLists.txt b/app/src/main/cpp/pdpclib/x86/CMakeLists.txt new file mode 100644 index 0000000..f110cda --- /dev/null +++ b/app/src/main/cpp/pdpclib/x86/CMakeLists.txt @@ -0,0 +1,30 @@ +cmake_minimum_required(VERSION 3.18.1) + +project("pdos_pdandro") +enable_language(C ASM) + +add_library( + pdpclib + STATIC + + linsupa.asm + stdio.c + string.c + stdlib.c + start.c + time.c + errno.c + assert.c + signal.c + locale.c + ctype.c + setjmp.c + math.c + __memmgr.c +) + +target_compile_options(pdpclib PRIVATE + $<$:-ffreestanding -fno-builtin -fno-stack-protector -nostdinc -nostdlib -D__gnu_linux__ -O2 -fno-builtin -DUSE_MEMMGR -I${CMAKE_CURRENT_SOURCE_DIR}> + $<$:-x assembler-with-cpp> +) + diff --git a/app/src/main/cpp/pdpclib/x86/__memmgr.c b/app/src/main/cpp/pdpclib/x86/__memmgr.c new file mode 100644 index 0000000..3a691eb --- /dev/null +++ b/app/src/main/cpp/pdpclib/x86/__memmgr.c @@ -0,0 +1,878 @@ +/*********************************************************************/ +/* */ +/* This Program Written By Paul Edwards. */ +/* Released to the public domain. */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* memmgr - manage memory */ +/* */ +/*********************************************************************/ + +#include "__memmgr.h" + +#include + +MEMMGR __memmgr; + +void memmgrDefaults(MEMMGR *memmgr) +{ + return; +} + +void memmgrInit(MEMMGR *memmgr) +{ + memmgr->start = NULL; + memmgr->startf = NULL; + return; +} + +void memmgrTerm(MEMMGR *memmgr) +{ + return; +} + +/* Supply a block of memory. We make sure this is inserted in + the right spot logically in memory, and since it will be a + free block, we stick it at the front of the list */ +void memmgrSupply(MEMMGR *memmgr, void *buffer, size_t szbuf) +{ + MEMMGRN *p, *l, *b; + + if (((int)buffer % MEMMGR_ALIGN) != 0) + { + szbuf -= (MEMMGR_ALIGN - (int)buffer % MEMMGR_ALIGN); + buffer = (char *)buffer + (MEMMGR_ALIGN - (int)buffer % MEMMGR_ALIGN); + } + + if ((szbuf % MEMMGR_ALIGN) != 0) + { + szbuf -= szbuf % MEMMGR_ALIGN; + } + + p = memmgr->start; + l = NULL; + while ((p != NULL) && ((MEMMGRN *)buffer >= p)) + { + l = p; + p = p->next; + } + + b = (MEMMGRN *)buffer; + + b->prev = l; + b->next = p; + + if (l != NULL) + { + l->next = b; + } + else + { + memmgr->start = b; + } + + if (p != NULL) + { + p->prev = b; + } + + b->fixed = 1; + b->size = szbuf; + b->allocated = 0; + + /* add this to the front of the list */ + b->nextf = memmgr->startf; + if (b->nextf != NULL) + { + b->nextf->prevf = b; + } + b->prevf = NULL; + memmgr->startf = b; +#ifdef __MEMMGR_INTEGRITY + b->eyecheck1 = b->eyecheck2 = 0xa5a5a5a5; + memmgrIntegrity(memmgr); +#endif + return; +} + +void *memmgrAllocate(MEMMGR *memmgr, size_t bytes, int id) +{ + MEMMGRN *p, *n; + size_t oldbytes = bytes; + +#ifdef __MEMMGR_DEBUG + if (memmgrDebug) + { + printf("***allocating size %d\n\n", bytes); + } +#endif +#ifdef __MEMMGR_INTEGRITY + memmgrIntegrity(memmgr); +#endif + /* technically they could have specified a strange free + memory size, like 101, which would disrupt the alignment. + MEMMGR_MINFREE should have compensated for this by ensuring + that it is a multiple of the MEMMGRN alignment */ + bytes += MEMMGRN_SZ; + if ((bytes % MEMMGR_MINFRTOT) != 0) + { + bytes = ((bytes / MEMMGR_MINFRTOT) + 1) + * MEMMGR_MINFRTOT; + } + +#ifdef __MEMMGR_DEBUG + if (memmgrDebug) + { + printf("***converted to %d\n\n", bytes); + } +#endif + /* if they have exceeded the limits of the data type, + bail out now. */ + if (bytes < oldbytes) + { + return (NULL); + } + + p = memmgr->startf; + + while (p != NULL) + { + if (p->size >= bytes) + { + /* The free chain should never have something allocated. + If it does, let's just crash so the user can get a + call stack rather than have their data randomly + corrupted. */ + if (p->allocated) + { +#if MEMMGR_CRASH + *(char *)0 = 0; +#endif + exit(EXIT_FAILURE); + } + /* we don't need the whole block, so construct a new + free node */ + if ((p->size - bytes) >= MEMMGR_MINFRTOT) + { + n = (MEMMGRN *)((char *)p + bytes); + n->next = p->next; + if (n->next != NULL) + { + n->next->prev = n; + } + n->prev = p; + p->next = n; + n->fixed = 0; + n->size = p->size - bytes; + n->allocated = 0; +#ifdef __MEMMGR_INTEGRITY + n->eyecheck1 = n->eyecheck2 = 0xa5a5a5a5; +#endif + p->size = bytes; + + /* remove p this from the free chain and + replace with n */ + n->nextf = p->nextf; + n->prevf = p->prevf; + if (n->nextf != NULL) + { + n->nextf->prevf = n; + } + if (n->prevf != NULL) + { + n->prevf->nextf = n; + } + /* if the previous entry is NULL, then we must be + the first in the queue. If we're not, crash */ + else if (memmgr->startf != p) + { +#if MEMMGR_CRASH + *(char *)0 = 0; +#endif + exit(EXIT_FAILURE); + } + else + { + memmgr->startf = n; + } + } + /* otherwise we're not creating a new node, so just + remove this entry from the free chain */ + else + { + if (p->nextf != NULL) + { + p->nextf->prevf = p->prevf; + } + if (p->prevf != NULL) + { + p->prevf->nextf = p->nextf; + } + /* if the previous entry is NULL, then we must be + the first in the queue. If we're not, crash */ + else if (memmgr->startf != p) + { +#if MEMMGR_CRASH + *(char *)0 = 0; +#endif + exit(EXIT_FAILURE); + } + else + { + memmgr->startf = p->nextf; + } + } + /* for safety, don't keep the old free pointer chain + hanging around */ + p->nextf = NULL; + p->prevf = NULL; + + p->allocated = 0x5a5a; + p->id = id; + break; + } + p = p->nextf; + } + if (p == NULL) + { +#ifdef __MEMMGR_DEBUG + if (memmgrDebug) + { + printf("***alloc returning NULL!\n\n"); + } +#endif + return (p); + } + else + { + size_t *q; + + q = (size_t *)((char *)p + MEMMGRN_SZ); + *(q - 1) = oldbytes; +#ifdef __MEMMGR_DEBUG + if (memmgrDebug) + { + printf("***alloc returning %p\n\n", p); + } +#endif +#ifdef __MEMMGR_INTEGRITY + memmgrIntegrity(memmgr); +#endif + return ((char *)p + MEMMGRN_SZ); + } +} + +void memmgrFree(MEMMGR *memmgr, void *ptr) +{ + MEMMGRN *p, *n, *l; + int combprev = 0; /* did we combine with the previous? */ + int combnext = 0; /* are we combining with the next node? */ + + p = (MEMMGRN *)((char *)ptr - MEMMGRN_SZ); + +#ifdef __MEMMGR_DEBUG + if (memmgrDebug) + { + printf("***freeing size %d block %p\n\n", p->size, p); + } +#endif +#ifdef __MEMMGR_INTEGRITY + memmgrIntegrity(memmgr); +#endif + /* If they try to free a bit of memory that isn't remotely + what it's meant to be, just crash so that they get a + call stack */ + if (p->allocated != 0x5a5a) + { +#if MEMMGR_CRASH + *(char *)0 = 0; +#endif + exit(EXIT_FAILURE); + } + + p->allocated = 0; + /* let's hope we're in the middle of a valid chain */ + l = p->prev; + n = p->next; + + /* If the previous block is also free, just expand it's size + without any further fuss */ + if (!p->fixed && (l != NULL) && !l->allocated) + { + l->size += p->size; + l->next = p->next; + if (l->next != NULL) + { + l->next->prev = l; + } + combprev = 1; + } + /* is the next one up combinable? */ + if ((n != NULL) && !n->allocated && !n->fixed) + { + combnext = 1; + } + + /* We can have a fuss-free combination if the previous node + was not combined */ + if (combnext && !combprev) + { + p->size += n->size; + p->next = n->next; + if (p->next != NULL) + { + p->next->prev = p; + } + p->nextf = n->nextf; + if (p->nextf != NULL) + { + p->nextf->prevf = p; + } + p->prevf = n->prevf; + if (p->prevf != NULL) + { + p->prevf->nextf = p; + } + else if (memmgr->startf != n) + { +#if MEMMGR_CRASH + *(char *)0 = 0; +#endif + exit(EXIT_FAILURE); + } + else + { + memmgr->startf = p; + } + } + + /* this is the hairy situation. We're combining two existing + free blocks into one. While the blocks themselves are + contiguous, the two components are at random spots in the + free memory chain, e.g. they might be B and E in + A <-> B <-> C <-> D <-> E <-> F + So what's the obvious thing to do? Give it up and become a + Buddhist monk! The less obvious thing is to keep B in its + spot, just with an enhanced size, then get D and F to link + together. The special case of the two nodes actually already + being linked together by happy coincidence doesn't need + special handling. If it does, that monastery looks more + and more appealing every day. Do you reckon Buddhist monks + talk about giving it all up and doing C programming? Once + the node E is eliminated, B can be expanded. */ + + else if (combnext && combprev) + { + if (n->nextf != NULL) + { + n->nextf->prevf = n->prevf; + } + if (n->prevf != NULL) + { + n->prevf->nextf = n->nextf; + } + else if (memmgr->startf != n) + { +#if MEMMGR_CRASH + *(char *)0 = 0; +#endif + exit(EXIT_FAILURE); + } + else + { + memmgr->startf = n->nextf; + n->nextf->prevf = NULL; + } + + /* Ok, the free memory has been taken care of, now we go + back to the newly combined node and combine it with + this one. */ + l->size += n->size; + l->next = n->next; + if (l->next != NULL) + { + l->next->prev = l; + } + + /* That wasn't so hairy after all */ + /* Actually it was */ + } + + if (combnext) + { +#ifdef __MEMMGR_INTEGRITY + n->eyecheck1 = n->eyecheck2 = 0; +#endif + /* for safety */ + n->nextf = NULL; + n->prevf = NULL; + } + if (combprev) + { +#ifdef __MEMMGR_INTEGRITY + p->eyecheck1 = p->eyecheck2 = 0; +#endif + /* for safety */ + p->nextf = NULL; + p->prevf = NULL; + } + + /* If we didn't do any combination, then add this new node to + the front of the free chain */ + if (!combprev && !combnext) + { + p->nextf = memmgr->startf; + memmgr->startf = p; + p->prevf = NULL; + if (p->nextf != NULL) + { + p->nextf->prevf = p; + } + } + +#ifdef __MEMMGR_DEBUG + if (memmgrDebug) + { + printf("***free returning\n\n"); + } +#endif +#ifdef __MEMMGR_INTEGRITY + memmgrIntegrity(memmgr); +#endif + return; +} + +void memmgrFreeId(MEMMGR *memmgr, int id) +{ + MEMMGRN *p, *l; + + p = memmgr->start; + l = NULL; + +#ifdef __MEMMGR_INTEGRITY + memmgrIntegrity(memmgr); +#endif + while (p != NULL) + { + if ((p->id == id) && p->allocated) + { + /* skip past the MEMMGRN */ + memmgrFree(memmgr, (char *)p + MEMMGRN_SZ); + + /* It is possible that the p node has been invalidated + now, because of combination with the previous node. + So we go back to the previous pointer and try again. + This time it shouldn't find the node allocated. */ + if (l != NULL) + { + p = l; + } + } + l = p; + p = p->next; + } +#ifdef __MEMMGR_INTEGRITY + memmgrIntegrity(memmgr); +#endif + return; +} + +/* find the largest block of memory available */ +size_t memmgrMaxSize(MEMMGR *memmgr) +{ + MEMMGRN *p; + size_t max = 0; + + p = memmgr->startf; + + while (p != NULL) + { + if (p->size > max) + { + max = p->size; + } + p = p->nextf; + } + if (max != 0) + { + max -= MEMMGRN_SZ; + } + return (max); +} + +/* find total amount of memory available */ +size_t memmgrTotSize(MEMMGR *memmgr) +{ + MEMMGRN *p; + size_t tot = 0; + + p = memmgr->startf; + + while (p != NULL) + { + if (p->size != 0) + { + tot += (p->size - MEMMGRN_SZ); + } + p = p->next; + } + return (tot); +} + +int memmgrDebug = 0; +int memmgrDebug2 = 0; + + +#ifdef __MEMMGR_INTEGRITY +/* do an integrity check */ +void memmgrIntegrity(MEMMGR *memmgr) +{ + MEMMGRN *p; + size_t max = 0; + +#ifdef __MEMMGR_DEBUG +#if 0 + if (memmgrDebug2 != 0) + { + memmgrDebug2++; + if (memmgrDebug2 == 22362000) + { + memmgrDebug = 1; + } + } +#endif + if (memmgrDebug) + { + printf("%d integrity checking all nodes\n\n", memmgrDebug2); + } +#endif + p = memmgr->start; + + while (p != NULL) + { +#ifdef __MEMMGR_DEBUG + if (memmgrDebug) + { + printf("p is %p\n\n", p); + printf("ec1 %x, ec2 %x\n\n", + p->eyecheck1, p->eyecheck2); + printf("size %d, alloc %x\n\n", + p->size, p->allocated); + printf("forward is %p, back is %p\n\n", + p->next, p->prev); + printf("forwardf is %p, backf is %p\n\n", + p->nextf, p->prevf); + } +#endif + if ((p->eyecheck1 != 0xa5a5a5a5) || (p->eyecheck2 != 0xa5a5a5a5)) + { + *(char *)0 = '\0'; /* try to invoke crash */ + exit(EXIT_FAILURE); + } + if ((p->next != NULL) && (p->next->prev != p)) + { + *(char *)0 = '\0'; /* try to invoke crash */ + exit(EXIT_FAILURE); + } + p = p->next; + } +#ifdef __MEMMGR_DEBUG + if (memmgrDebug) + { + printf("integrity checking free chain\n\n"); + } +#endif + p = memmgr->startf; + if ((p != NULL) && (p->prevf != NULL)) + { + *(char *)0 = '\0'; /* try to invoke crash */ + exit(EXIT_FAILURE); + } + + while (p != NULL) + { +#ifdef __MEMMGR_DEBUG + if (memmgrDebug) + { + printf("p is %p\n\n", p); + printf("ec1 %x, ec2 %x\n\n", + p->eyecheck1, p->eyecheck2); + printf("size %d, alloc %x\n\n", + p->size, p->allocated); + printf("forwardf is %p, backf is %p\n\n", + p->nextf, p->prevf); + } +#endif + if ((p->eyecheck1 != 0xa5a5a5a5) || (p->eyecheck2 != 0xa5a5a5a5) + || p->allocated) + { + *(char *)0 = '\0'; /* try to invoke crash */ + exit(EXIT_FAILURE); + } + if ((p->nextf != NULL) && (p->nextf->prevf != p)) + { + *(char *)0 = '\0'; /* try to invoke crash */ + exit(EXIT_FAILURE); + } + p = p->nextf; + } +#ifdef __MEMMGR_DEBUG + if (memmgrDebug) + { + printf("finished integrity checking\n\n"); + } +#endif + return; +} +#endif + +/* resize a memory block */ +/* note that the size in the control block is the + size of available data plus the control block */ +int memmgrRealloc(MEMMGR *memmgr, void *ptr, size_t newsize) +{ + MEMMGRN *p, *n, *z; + size_t oldbytes = newsize; + +#ifdef __MEMMGR_DEBUG + if (memmgrDebug) + { + printf("***reallocating %p\n\n", ptr); + } +#endif +#ifdef __MEMMGR_INTEGRITY + memmgrIntegrity(memmgr); +#endif + newsize += MEMMGRN_SZ; + if ((newsize % MEMMGR_MINFRTOT) != 0) + { + newsize = ((newsize / MEMMGR_MINFRTOT) + 1) + * MEMMGR_MINFRTOT; + } + + /* if they have exceeded the limits of the data type, + bail out now. */ + if (newsize < oldbytes) + { + return (-1); + } + + /* if they are passing a NULL pointer, bail out also */ + if (ptr == NULL) + { + return (-1); + } + + + p = (MEMMGRN *)((char *)ptr - MEMMGRN_SZ); + + /* If they try to manipulate a bit of memory that isn't remotely + what it's meant to be, just crash so that they get a + call stack */ + if (p->allocated != 0x5a5a) + { +#if MEMMGR_CRASH + *(char *)0 = 0; +#endif + exit(EXIT_FAILURE); + } + + /* let's hope we're in the middle of a valid chain */ + + /* Now we have 3 distinct scenarios. + 1. They are asking for a reduction in size, and there's room + to create a new (free) block of memory. + so newsize + minfree + cb <= p->size + 2. They're asking for a reduction in size, but there's not + enough room for a new control block. + so newsize < p->size but newsize + minfree + cb > p->size + 3. They're asking for an expansion of memory, and the next + block of memory up is able to satisfy that request. + so newsize > p->size + */ + + /* are they asking for an expansion? */ + if (p->size < newsize) + { + n = p->next; + if ((n != NULL) + && !n->allocated + && !n->fixed + && ((n->size + p->size) >= newsize)) + { + /* ok, we can satisfy this request. Let's see if we + have enough room to insert a new node. */ + if ((p->size + n->size) < (newsize + MEMMGR_MINFRTOT)) + { + /* not enough room for a new node - just combine + and be done */ + if (n->nextf != NULL) + { + n->nextf->prevf = n->prevf; + } + if (n->prevf != NULL) + { + n->prevf->nextf = n->nextf; + } + else if (memmgr->startf != n) + { +#if MEMMGR_CRASH + *(char *)0 = 0; +#endif + exit(EXIT_FAILURE); + } + else + { + memmgr->startf = n->nextf; + } + /* Ok, free chain has been taken care of, now let's get + rid of that next node by combining */ + p->size += n->size; + p->next = n->next; + if (p->next != NULL) + { + p->next->prev = p; + } + } + else + { + /* we have room for a new node - so, construct the new + node first */ + z = (MEMMGRN *)((char *)p + newsize); + z->allocated = 0; + z->fixed = 0; +#ifdef __MEMMGR_INTEGRITY + z->eyecheck1 = z->eyecheck2 = 0xa5a5a5a5; +#endif + z->size = p->size + n->size - newsize; + z->prev = p; + p->next = z; + z->next = n->next; + if (z->next != NULL) + { + z->next->prev = z; + } + z->nextf = n->nextf; + if (z->nextf != NULL) + { + z->nextf->prevf = z; + } + z->prevf = n->prevf; + if (z->prevf != NULL) + { + z->prevf->nextf = z; + } + else if (memmgr->startf != n) + { +#if MEMMGR_CRASH + *(char *)0 = 0; +#endif + exit(EXIT_FAILURE); + } + else + { + memmgr->startf = z; + } + /* n node is now irrelevant. adjust p's size */ + p->size = newsize; + } + } + /* we don't have enough room to satisfy this expansion request */ + else + { + return (-1); + } + } + /* It's not an expansion, but is there enough room to insert a + new node? */ + else if ((newsize + MEMMGR_MINFRTOT) <= p->size) + { + /* yep, let's insert new node */ + n = (MEMMGRN *)((char *)p + newsize); + n->next = p->next; + if (n->next != NULL) + { + n->next->prev = n; + } + n->prev = p; + p->next = n; + n->fixed = 0; + n->size = p->size - newsize; + n->allocated = 0; +#ifdef __MEMMGR_INTEGRITY + n->eyecheck1 = n->eyecheck2 = 0xa5a5a5a5; +#endif + p->size = newsize; + + /* combine with next block if possible */ + z = n->next; + if ((z != NULL) && !z->allocated && !z->fixed) + { +#ifdef __MEMMGR_INTEGRITY + z->eyecheck1 = z->eyecheck2 = 0; +#endif + n->size += z->size; + n->next = z->next; + if (n->next != NULL) + { + n->next->prev = n; + } + n->nextf = z->nextf; + if (n->nextf != NULL) + { + n->nextf->prevf = n; + } + n->prevf = z->prevf; + if (n->prevf != NULL) + { + n->prevf->nextf = n; + } + else if (memmgr->startf != z) + { +#if MEMMGR_CRASH + *(char *)0 = 0; +#endif + exit(EXIT_FAILURE); + } + else + { + memmgr->startf = n; + } + } + /* otherwise add it to the start of the free chain */ + else + { + n->nextf = memmgr->startf; + if (n->nextf != NULL) + { + n->nextf->prevf = n; + } + n->prevf = NULL; + memmgr->startf = n; + } + } + /* Otherwise they are requesting a minor resize downwards, + and we just need to acknowledge it, not actually do + anything. */ + +#ifdef __MEMMGR_DEBUG + if (memmgrDebug) + { + printf("***returning from realloc\n\n"); + } +#endif +#ifdef __MEMMGR_INTEGRITY + memmgrIntegrity(memmgr); +#endif + + /* Keep track of the new size */ + { + size_t *q; + + q = (size_t *)((char *)p + MEMMGRN_SZ); + *(q - 1) = oldbytes; + } + return (0); +} diff --git a/app/src/main/cpp/pdpclib/x86/__memmgr.h b/app/src/main/cpp/pdpclib/x86/__memmgr.h new file mode 100644 index 0000000..d0da86d --- /dev/null +++ b/app/src/main/cpp/pdpclib/x86/__memmgr.h @@ -0,0 +1,155 @@ +/*********************************************************************/ +/* */ +/* This Program Written By Paul Edwards. */ +/* Released to the public domain. */ +/* */ +/*********************************************************************/ + +#if 0 + +Example usage: + +MEMMGR memmgr; /* define an instance of the object */ +char *ptr; /* scratch pointer */ + + +memmgrDefaults(&memmgr); /* always called to set up object defaults */ +memmgrInit(&memmgr); /* Initialize object */ +memmgrSupply(&memmmgr, (void *)0x04100000, 32 * 1024 * 1024); + /* Supply the object with a buffer that starts at the 65 MB location + and is 32 MB in size. This can be called multiple times to give + memmgr multiple blocks of memory to manage */ +ptr = memmgrAllocate(&memmgr, 500, 0); + /* allocate 500 bytes of memory. 0 is an "optional" ID if you want + to group memory blocks. ptr will be NULL if memory couldn't be + obtained */ +memmgrFree(&memmgr, ptr); /* free memory associated with this + pointer */ +memmgrTerm(&memmgr); /* Terminate object */ + + +Other functions: + +memmgrFreeID(&memmgr, 5); /* free all memory with an ID of 5 */ +printf("largest block of memory available is %d\n", + memmgrMaxSize(&memmgr)); +printf("total amount of available memory is %d\n", + memmgrTotSize(&memmgr)); +memmgrIntegrity(&memmgr); /* check any memory chain corruption */ +memmgrRealloc(&memmgr, ptr, 1000); /* resize the object to be 1000 + bytes. Returns 0 if successful, negative if the request failed for + any reason. */ + +#endif + + +#ifndef MEMMGR_INCLUDED +#define MEMMGR_INCLUDED + +#include + +/* Do you want memmgr to perform lots of integrity checks? */ +/* Note that this will slow down the system, but it doesn't + print out anything or change the functionality of your + application. */ +/* #define __MEMMGR_INTEGRITY 1 */ + +/* Do you want lots of debugging output? */ +/* Note that you still need to set the memmgrDebug variable to 1 + before it is actually activated */ +/* #define __MEMMGR_DEBUG 1 */ + +typedef struct memmgrn { +#ifdef __MEMMGR_INTEGRITY + int eyecheck1; +#endif + struct memmgrn *next; + struct memmgrn *prev; + struct memmgrn *nextf; + struct memmgrn *prevf; + int fixed; + size_t size; /* size of memory available to user */ + int allocated; + int id; +#ifdef __MEMMGR_INTEGRITY + int eyecheck2; +#endif + size_t filler; /* we add this so that *(p - size_t) is writable */ +} MEMMGRN; + +typedef struct { + MEMMGRN *start; + MEMMGRN *startf; +} MEMMGR; + +/* What boundary we want the memmgr control block to be a multiple of */ +#define MEMMGR_ALIGN 8 + +#define MEMMGRN_SZ \ + ((sizeof(MEMMGRN) % MEMMGR_ALIGN == 0) ? \ + sizeof(MEMMGRN) : \ + ((sizeof(MEMMGRN) / MEMMGR_ALIGN + 1) * MEMMGR_ALIGN)) + +/* Let's make sure that the minimum free data area is at least + as big as the node itself, so that we don't have more than + 50% of the available memory used up by control blocks due + to fragmentation */ +#define MEMMGR_MINFREE MEMMGRN_SZ + +/* total size of the minimum free area, including room for the + control block */ +#define MEMMGR_MINFRTOT (MEMMGRN_SZ + MEMMGR_MINFREE) + +/* do you want to crash whenever an integrity problem arises? */ +#ifndef MEMMGR_CRASH +#define MEMMGR_CRASH 1 +#endif + +#ifdef NICEASM +#define memmgrDefaults mmDef +#define memmgrInit mmInit +#define memmgrTerm mmTerm +#define memmgrSupply mmSupply +#define memmgrAllocate mmAlloc +#define memmgrFree mmFree +#define memmgrFreeId mmFreeId +#define memmgrMaxSize mmMaxSiz +#define memmgrTotSize mmTotSiz +#define memmgrIntegrity mmInteg +#define memmgrRealloc mmRealoc +#define memmgrDebug mmDebug +#define memmgrDebug2 mmDbg2 +#else +#define memmgrDefaults __mmDef +#define memmgrInit __mmInit +#define memmgrTerm __mmTerm +#define memmgrSupply __mmSupply +#define memmgrAllocate __mmAlloc +#define memmgrFree __mmFree +#define memmgrFreeId __mmFId +#define memmgrMaxSize __mmMaxSize +#define memmgrTotSize __mmTotSize +#define memmgrIntegrity __mmIntegrity +#define memmgrRealloc __mmRealloc +#define memmgrDebug __mmDebug +#define memmgrDebug2 __mmDbg2 +#endif + +void memmgrDefaults(MEMMGR *memmgr); +void memmgrInit(MEMMGR *memmgr); +void memmgrTerm(MEMMGR *memmgr); +void memmgrSupply(MEMMGR *memmgr, void *buffer, size_t szbuf); +void *memmgrAllocate(MEMMGR *memmgr, size_t bytes, int id); +void memmgrFree(MEMMGR *memmgr, void *ptr); +void memmgrFreeId(MEMMGR *memmgr, int id); +size_t memmgrMaxSize(MEMMGR *memmgr); +size_t memmgrTotSize(MEMMGR *memmgr); +void memmgrIntegrity(MEMMGR *memmgr); +int memmgrRealloc(MEMMGR *memmgr, void *ptr, size_t newsize); + +extern int memmgrDebug; +extern int memmgrDebug2; + +extern MEMMGR __memmgr; + +#endif diff --git a/app/src/main/cpp/pdpclib/x86/assert.c b/app/src/main/cpp/pdpclib/x86/assert.c new file mode 100644 index 0000000..6d60c15 --- /dev/null +++ b/app/src/main/cpp/pdpclib/x86/assert.c @@ -0,0 +1,24 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* assert.c - implementation of stuff in assert.h */ +/* */ +/*********************************************************************/ + +#include "assert.h" +#include "stdio.h" +#include "stdlib.h" +#include "stddef.h" + +__PDPCLIB_API__ int _assert(char *x, char *y, int z) +{ + fprintf(__stderr, "assertion failed for statement %s in " + "file %s on line %d\n", x, y, z); + abort(); + return (0); +} diff --git a/app/src/main/cpp/pdpclib/x86/assert.h b/app/src/main/cpp/pdpclib/x86/assert.h new file mode 100644 index 0000000..ae3495b --- /dev/null +++ b/app/src/main/cpp/pdpclib/x86/assert.h @@ -0,0 +1,33 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* assert.h - assert header file. */ +/* */ +/*********************************************************************/ + +#ifndef __ASSERT_INCLUDED +#define __ASSERT_INCLUDED + +int _assert(char *x, char *y, int z); + +#ifdef NDEBUG +#define assert(ignore) (0) +#else +#define assert(x) (x) ? (0) : \ + _assert(#x, __FILE__, __LINE__) +#endif + +#if defined(__PDOSGEN__) +#include <__os.h> + +#define _assert __os->_assert + +#endif + + +#endif diff --git a/app/src/main/cpp/pdpclib/x86/ctype.c b/app/src/main/cpp/pdpclib/x86/ctype.c new file mode 100644 index 0000000..442edc4 --- /dev/null +++ b/app/src/main/cpp/pdpclib/x86/ctype.c @@ -0,0 +1,1641 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* ctype.c - implementation of stuff in ctype.h */ +/* */ +/*********************************************************************/ + +#include "stddef.h" + +#if !defined(__MVS__) && !defined(__CMS__) && !defined(__VSE__) +static unsigned short __isbufR[257] = { + 0x0000U, /* EOF */ + 0x0004U, /* NUL */ + 0x0004U, /* 01 */ + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0104U, + 0x0104U, + 0x0104U, + 0x0104U, + 0x0104U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0140U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x0459U, + 0x0459U, + 0x0459U, + 0x0459U, + 0x0459U, + 0x0459U, + 0x0459U, + 0x0459U, + 0x0459U, + 0x0459U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x0653U, + 0x0653U, + 0x0653U, + 0x0653U, + 0x0653U, + 0x0653U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x0473U, + 0x0473U, + 0x0473U, + 0x0473U, + 0x0473U, + 0x0473U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x0004U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U }; + +static short __tolowR[257] = { + -1, + 0x00, + 0x01, + 0x02, + 0x03, + 0x04, + 0x05, + 0x06, + 0x07, + 0x08, + 0x09, + 0x0A, + 0x0B, + 0x0C, + 0x0D, + 0x0E, + 0x0F, + 0x10, + 0x11, + 0x12, + 0x13, + 0x14, + 0x15, + 0x16, + 0x17, + 0x18, + 0x19, + 0x1A, + 0x1B, + 0x1C, + 0x1D, + 0x1E, + 0x1F, + 0x20, + 0x21, + 0x22, + 0x23, + 0x24, + 0x25, + 0x26, + 0x27, + 0x28, + 0x29, + 0x2A, + 0x2B, + 0x2C, + 0x2D, + 0x2E, + 0x2F, + 0x30, + 0x31, + 0x32, + 0x33, + 0x34, + 0x35, + 0x36, + 0x37, + 0x38, + 0x39, + 0x3A, + 0x3B, + 0x3C, + 0x3D, + 0x3E, + 0x3F, + 0x40, + 0x61, + 0x62, + 0x63, + 0x64, + 0x65, + 0x66, + 0x67, + 0x68, + 0x69, + 0x6A, + 0x6B, + 0x6C, + 0x6D, + 0x6E, + 0x6F, + 0x70, + 0x71, + 0x72, + 0x73, + 0x74, + 0x75, + 0x76, + 0x77, + 0x78, + 0x79, + 0x7A, + 0x5B, + 0x5C, + 0x5D, + 0x5E, + 0x5F, + 0x60, + 0x61, + 0x62, + 0x63, + 0x64, + 0x65, + 0x66, + 0x67, + 0x68, + 0x69, + 0x6A, + 0x6B, + 0x6C, + 0x6D, + 0x6E, + 0x6F, + 0x70, + 0x71, + 0x72, + 0x73, + 0x74, + 0x75, + 0x76, + 0x77, + 0x78, + 0x79, + 0x7A, + 0x7B, + 0x7C, + 0x7D, + 0x7E, + 0x7F, + 0x80, + 0x81, + 0x82, + 0x83, + 0x84, + 0x85, + 0x86, + 0x87, + 0x88, + 0x89, + 0x8A, + 0x8B, + 0x8C, + 0x8D, + 0x8E, + 0x8F, + 0x90, + 0x91, + 0x92, + 0x93, + 0x94, + 0x95, + 0x96, + 0x97, + 0x98, + 0x99, + 0x9A, + 0x9B, + 0x9C, + 0x9D, + 0x9E, + 0x9F, + 0xA0, + 0xA1, + 0xA2, + 0xA3, + 0xA4, + 0xA5, + 0xA6, + 0xA7, + 0xA8, + 0xA9, + 0xAA, + 0xAB, + 0xAC, + 0xAD, + 0xAE, + 0xAF, + 0xB0, + 0xB1, + 0xB2, + 0xB3, + 0xB4, + 0xB5, + 0xB6, + 0xB7, + 0xB8, + 0xB9, + 0xBA, + 0xBB, + 0xBC, + 0xBD, + 0xBE, + 0xBF, + 0xC0, + 0xC1, + 0xC2, + 0xC3, + 0xC4, + 0xC5, + 0xC6, + 0xC7, + 0xC8, + 0xC9, + 0xCA, + 0xCB, + 0xCC, + 0xCD, + 0xCE, + 0xCF, + 0xD0, + 0xD1, + 0xD2, + 0xD3, + 0xD4, + 0xD5, + 0xD6, + 0xD7, + 0xD8, + 0xD9, + 0xDA, + 0xDB, + 0xDC, + 0xDD, + 0xDE, + 0xDF, + 0xE0, + 0xE1, + 0xE2, + 0xE3, + 0xE4, + 0xE5, + 0xE6, + 0xE7, + 0xE8, + 0xE9, + 0xEA, + 0xEB, + 0xEC, + 0xED, + 0xEE, + 0xEF, + 0xF0, + 0xF1, + 0xF2, + 0xF3, + 0xF4, + 0xF5, + 0xF6, + 0xF7, + 0xF8, + 0xF9, + 0xFA, + 0xFB, + 0xFC, + 0xFD, + 0xFE, + 0xFF }; + +static short __toupR[257] = { + -1, + 0x00, + 0x01, + 0x02, + 0x03, + 0x04, + 0x05, + 0x06, + 0x07, + 0x08, + 0x09, + 0x0A, + 0x0B, + 0x0C, + 0x0D, + 0x0E, + 0x0F, + 0x10, + 0x11, + 0x12, + 0x13, + 0x14, + 0x15, + 0x16, + 0x17, + 0x18, + 0x19, + 0x1A, + 0x1B, + 0x1C, + 0x1D, + 0x1E, + 0x1F, + 0x20, + 0x21, + 0x22, + 0x23, + 0x24, + 0x25, + 0x26, + 0x27, + 0x28, + 0x29, + 0x2A, + 0x2B, + 0x2C, + 0x2D, + 0x2E, + 0x2F, + 0x30, + 0x31, + 0x32, + 0x33, + 0x34, + 0x35, + 0x36, + 0x37, + 0x38, + 0x39, + 0x3A, + 0x3B, + 0x3C, + 0x3D, + 0x3E, + 0x3F, + 0x40, + 0x41, + 0x42, + 0x43, + 0x44, + 0x45, + 0x46, + 0x47, + 0x48, + 0x49, + 0x4A, + 0x4B, + 0x4C, + 0x4D, + 0x4E, + 0x4F, + 0x50, + 0x51, + 0x52, + 0x53, + 0x54, + 0x55, + 0x56, + 0x57, + 0x58, + 0x59, + 0x5A, + 0x5B, + 0x5C, + 0x5D, + 0x5E, + 0x5F, + 0x60, + 0x41, + 0x42, + 0x43, + 0x44, + 0x45, + 0x46, + 0x47, + 0x48, + 0x49, + 0x4A, + 0x4B, + 0x4C, + 0x4D, + 0x4E, + 0x4F, + 0x50, + 0x51, + 0x52, + 0x53, + 0x54, + 0x55, + 0x56, + 0x57, + 0x58, + 0x59, + 0x5A, + 0x7B, + 0x7C, + 0x7D, + 0x7E, + 0x7F, + 0x80, + 0x81, + 0x82, + 0x83, + 0x84, + 0x85, + 0x86, + 0x87, + 0x88, + 0x89, + 0x8A, + 0x8B, + 0x8C, + 0x8D, + 0x8E, + 0x8F, + 0x90, + 0x91, + 0x92, + 0x93, + 0x94, + 0x95, + 0x96, + 0x97, + 0x98, + 0x99, + 0x9A, + 0x9B, + 0x9C, + 0x9D, + 0x9E, + 0x9F, + 0xA0, + 0xA1, + 0xA2, + 0xA3, + 0xA4, + 0xA5, + 0xA6, + 0xA7, + 0xA8, + 0xA9, + 0xAA, + 0xAB, + 0xAC, + 0xAD, + 0xAE, + 0xAF, + 0xB0, + 0xB1, + 0xB2, + 0xB3, + 0xB4, + 0xB5, + 0xB6, + 0xB7, + 0xB8, + 0xB9, + 0xBA, + 0xBB, + 0xBC, + 0xBD, + 0xBE, + 0xBF, + 0xC0, + 0xC1, + 0xC2, + 0xC3, + 0xC4, + 0xC5, + 0xC6, + 0xC7, + 0xC8, + 0xC9, + 0xCA, + 0xCB, + 0xCC, + 0xCD, + 0xCE, + 0xCF, + 0xD0, + 0xD1, + 0xD2, + 0xD3, + 0xD4, + 0xD5, + 0xD6, + 0xD7, + 0xD8, + 0xD9, + 0xDA, + 0xDB, + 0xDC, + 0xDD, + 0xDE, + 0xDF, + 0xE0, + 0xE1, + 0xE2, + 0xE3, + 0xE4, + 0xE5, + 0xE6, + 0xE7, + 0xE8, + 0xE9, + 0xEA, + 0xEB, + 0xEC, + 0xED, + 0xEE, + 0xEF, + 0xF0, + 0xF1, + 0xF2, + 0xF3, + 0xF4, + 0xF5, + 0xF6, + 0xF7, + 0xF8, + 0xF9, + 0xFA, + 0xFB, + 0xFC, + 0xFD, + 0xFE, + 0xFF }; + +#else + +static unsigned short __isbufR[257] = { + 0x0000U, /* EOF */ + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0104U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0104U, + 0x0104U, + 0x0104U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0104U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0000U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0000U, + 0x0000U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0004U, + 0x0000U, + 0x0004U, + 0x0140U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0090U, /* x'4a' is cent, not printable after conversion to ASCII */ + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0090U, /* x'6a' is secondary vertical bar, doesn't exist in ASCII */ + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x00D0U, + 0x0000U, + 0x0473U, + 0x0473U, + 0x0473U, + 0x0473U, + 0x0473U, + 0x0473U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x00D0U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0073U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x00D0U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x00D0U, + 0x0000U, + 0x0000U, + 0x00D0U, + 0x0653U, + 0x0653U, + 0x0653U, + 0x0653U, + 0x0653U, + 0x0653U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x00D0U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x00D0U, + 0x0000U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0253U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0459U, + 0x0459U, + 0x0459U, + 0x0459U, + 0x0459U, + 0x0459U, + 0x0459U, + 0x0459U, + 0x0459U, + 0x0459U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U, + 0x0000U }; + +static short __tolowR[257] = { + -1, + 0x00, + 0x01, + 0x02, + 0x03, + 0x04, + 0x05, + 0x06, + 0x07, + 0x08, + 0x09, + 0x0A, + 0x0B, + 0x0C, + 0x0D, + 0x0E, + 0x0F, + 0x10, + 0x11, + 0x12, + 0x13, + 0x14, + 0x15, + 0x16, + 0x17, + 0x18, + 0x19, + 0x1A, + 0x1B, + 0x1C, + 0x1D, + 0x1E, + 0x1F, + 0x20, + 0x21, + 0x22, + 0x23, + 0x24, + 0x25, + 0x26, + 0x27, + 0x28, + 0x29, + 0x2A, + 0x2B, + 0x2C, + 0x2D, + 0x2E, + 0x2F, + 0x30, + 0x31, + 0x32, + 0x33, + 0x34, + 0x35, + 0x36, + 0x37, + 0x38, + 0x39, + 0x3A, + 0x3B, + 0x3C, + 0x3D, + 0x3E, + 0x3F, + 0x40, + 0x41, + 0x42, + 0x43, + 0x44, + 0x45, + 0x46, + 0x47, + 0x48, + 0x49, + 0x4A, + 0x4B, + 0x4C, + 0x4D, + 0x4E, + 0x4F, + 0x50, + 0x51, + 0x52, + 0x53, + 0x54, + 0x55, + 0x56, + 0x57, + 0x58, + 0x59, + 0x5A, + 0x5B, + 0x5C, + 0x5D, + 0x5E, + 0x5F, + 0x60, + 0x61, + 0x62, + 0x63, + 0x64, + 0x65, + 0x66, + 0x67, + 0x68, + 0x69, + 0x6A, + 0x6B, + 0x6C, + 0x6D, + 0x6E, + 0x6F, + 0x70, + 0x71, + 0x72, + 0x73, + 0x74, + 0x75, + 0x76, + 0x77, + 0x78, + 0x79, + 0x7A, + 0x7B, + 0x7C, + 0x7D, + 0x7E, + 0x7F, + 0x80, + 0x81, + 0x82, + 0x83, + 0x84, + 0x85, + 0x86, + 0x87, + 0x88, + 0x89, + 0x8A, + 0x8B, + 0x8C, + 0x8D, + 0x8E, + 0x8F, + 0x90, + 0x91, + 0x92, + 0x93, + 0x94, + 0x95, + 0x96, + 0x97, + 0x98, + 0x99, + 0x9A, + 0x9B, + 0x9C, + 0x9D, + 0x9E, + 0x9F, + 0xA0, + 0xA1, + 0xA2, + 0xA3, + 0xA4, + 0xA5, + 0xA6, + 0xA7, + 0xA8, + 0xA9, + 0xAA, + 0xAB, + 0xAC, + 0xAD, + 0xAE, + 0xAF, + 0xB0, + 0xB1, + 0xB2, + 0xB3, + 0xB4, + 0xB5, + 0xB6, + 0xB7, + 0xB8, + 0xB9, + 0xBA, + 0xBB, + 0xBC, + 0xBD, + 0xBE, + 0xBF, + 0xC0, + 0x81, + 0x82, + 0x83, + 0x84, + 0x85, + 0x86, + 0x87, + 0x88, + 0x89, + 0xCA, + 0xCB, + 0xCC, + 0xCD, + 0xCE, + 0xCF, + 0xD0, + 0x91, + 0x92, + 0x93, + 0x94, + 0x95, + 0x96, + 0x97, + 0x98, + 0x99, + 0xDA, + 0xDB, + 0xDC, + 0xDD, + 0xDE, + 0xDF, + 0xE0, + 0xE1, + 0xA2, + 0xA3, + 0xA4, + 0xA5, + 0xA6, + 0xA7, + 0xA8, + 0xA9, + 0xEA, + 0xEB, + 0xEC, + 0xED, + 0xEE, + 0xEF, + 0xF0, + 0xF1, + 0xF2, + 0xF3, + 0xF4, + 0xF5, + 0xF6, + 0xF7, + 0xF8, + 0xF9, + 0xFA, + 0xFB, + 0xFC, + 0xFD, + 0xFE, + 0xFF }; + +static short __toupR[257] = { + -1, + 0x00, + 0x01, + 0x02, + 0x03, + 0x04, + 0x05, + 0x06, + 0x07, + 0x08, + 0x09, + 0x0A, + 0x0B, + 0x0C, + 0x0D, + 0x0E, + 0x0F, + 0x10, + 0x11, + 0x12, + 0x13, + 0x14, + 0x15, + 0x16, + 0x17, + 0x18, + 0x19, + 0x1A, + 0x1B, + 0x1C, + 0x1D, + 0x1E, + 0x1F, + 0x20, + 0x21, + 0x22, + 0x23, + 0x24, + 0x25, + 0x26, + 0x27, + 0x28, + 0x29, + 0x2A, + 0x2B, + 0x2C, + 0x2D, + 0x2E, + 0x2F, + 0x30, + 0x31, + 0x32, + 0x33, + 0x34, + 0x35, + 0x36, + 0x37, + 0x38, + 0x39, + 0x3A, + 0x3B, + 0x3C, + 0x3D, + 0x3E, + 0x3F, + 0x40, + 0x41, + 0x42, + 0x43, + 0x44, + 0x45, + 0x46, + 0x47, + 0x48, + 0x49, + 0x4A, + 0x4B, + 0x4C, + 0x4D, + 0x4E, + 0x4F, + 0x50, + 0x51, + 0x52, + 0x53, + 0x54, + 0x55, + 0x56, + 0x57, + 0x58, + 0x59, + 0x5A, + 0x5B, + 0x5C, + 0x5D, + 0x5E, + 0x5F, + 0x60, + 0x61, + 0x62, + 0x63, + 0x64, + 0x65, + 0x66, + 0x67, + 0x68, + 0x69, + 0x6A, + 0x6B, + 0x6C, + 0x6D, + 0x6E, + 0x6F, + 0x70, + 0x71, + 0x72, + 0x73, + 0x74, + 0x75, + 0x76, + 0x77, + 0x78, + 0x79, + 0x7A, + 0x7B, + 0x7C, + 0x7D, + 0x7E, + 0x7F, + 0x80, + 0xC1, + 0xC2, + 0xC3, + 0xC4, + 0xC5, + 0xC6, + 0xC7, + 0xC8, + 0xC9, + 0x8A, + 0x8B, + 0x8C, + 0x8D, + 0x8E, + 0x8F, + 0x90, + 0xD1, + 0xD2, + 0xD3, + 0xD4, + 0xD5, + 0xD6, + 0xD7, + 0xD8, + 0xD9, + 0x9A, + 0x9B, + 0x9C, + 0x9D, + 0x9E, + 0x9F, + 0xA0, + 0xA1, + 0xE2, + 0xE3, + 0xE4, + 0xE5, + 0xE6, + 0xE7, + 0xE8, + 0xE9, + 0xAA, + 0xAB, + 0xAC, + 0xAD, + 0xAE, + 0xAF, + 0xB0, + 0xB1, + 0xB2, + 0xB3, + 0xB4, + 0xB5, + 0xB6, + 0xB7, + 0xB8, + 0xB9, + 0xBA, + 0xBB, + 0xBC, + 0xBD, + 0xBE, + 0xBF, + 0xC0, + 0xC1, + 0xC2, + 0xC3, + 0xC4, + 0xC5, + 0xC6, + 0xC7, + 0xC8, + 0xC9, + 0xCA, + 0xCB, + 0xCC, + 0xCD, + 0xCE, + 0xCF, + 0xD0, + 0xD1, + 0xD2, + 0xD3, + 0xD4, + 0xD5, + 0xD6, + 0xD7, + 0xD8, + 0xD9, + 0xDA, + 0xDB, + 0xDC, + 0xDD, + 0xDE, + 0xDF, + 0xE0, + 0xE1, + 0xE2, + 0xE3, + 0xE4, + 0xE5, + 0xE6, + 0xE7, + 0xE8, + 0xE9, + 0xEA, + 0xEB, + 0xEC, + 0xED, + 0xEE, + 0xEF, + 0xF0, + 0xF1, + 0xF2, + 0xF3, + 0xF4, + 0xF5, + 0xF6, + 0xF7, + 0xF8, + 0xF9, + 0xFA, + 0xFB, + 0xFC, + 0xFD, + 0xFE, + 0xFF }; + +#endif + +unsigned short *__isbuf = &__isbufR[1]; +short *__tolow = &__tolowR[1]; +short *__toup = &__toupR[1]; + +__PDPCLIB_API__ int isalnum(int c) +{ + return (__isbuf[(c)] & 0x0001U); +} + +__PDPCLIB_API__ int isalpha(int c) +{ + return (__isbuf[(c)] & 0x0002U); +} + +__PDPCLIB_API__ int iscntrl(int c) +{ + return (__isbuf[(c)] & 0x0004U); +} + +__PDPCLIB_API__ int isdigit(int c) +{ + return (__isbuf[(c)] & 0x0008U); +} + +__PDPCLIB_API__ int isgraph(int c) +{ + return (__isbuf[(c)] & 0x0010U); +} + +__PDPCLIB_API__ int islower(int c) +{ + return (__isbuf[(c)] & 0x0020U); +} + +__PDPCLIB_API__ int isprint(int c) +{ + return (__isbuf[(c)] & 0x0040U); +} + +__PDPCLIB_API__ int ispunct(int c) +{ + return (__isbuf[(c)] & 0x0080U); +} + +__PDPCLIB_API__ int isspace(int c) +{ + return (__isbuf[(c)] & 0x0100U); +} + +__PDPCLIB_API__ int isupper(int c) +{ + return (__isbuf[(c)] & 0x0200U); +} + +__PDPCLIB_API__ int isxdigit(int c) +{ + return (__isbuf[(c)] & 0x0400U); +} + +__PDPCLIB_API__ int tolower(int c) +{ + return (__tolow[(c)]); +} + +__PDPCLIB_API__ int toupper(int c) +{ + return (__toup[(c)]); +} diff --git a/app/src/main/cpp/pdpclib/x86/ctype.h b/app/src/main/cpp/pdpclib/x86/ctype.h new file mode 100644 index 0000000..b368324 --- /dev/null +++ b/app/src/main/cpp/pdpclib/x86/ctype.h @@ -0,0 +1,60 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* ctype.h - ctype header file. */ +/* */ +/*********************************************************************/ + +#ifndef __CTYPE_INCLUDED +#define __CTYPE_INCLUDED + +int isalnum(int c); +int isalpha(int c); +int iscntrl(int c); +int isdigit(int c); +int isgraph(int c); +int islower(int c); +int isprint(int c); +int ispunct(int c); +int isspace(int c); +int isupper(int c); +int isxdigit(int c); +int tolower(int c); +int toupper(int c); + +#if defined(__WIN32__) && !defined(__STATIC__) || defined(__SUBC__) + +/* don't use macros on these environments */ + +#elif defined(__PDOSGEN__) +#include <__os.h> + +#define isalnum __os->isalnum +#define isxdigit __os->isxdigit + +#else +extern unsigned short *__isbuf; +extern short *__tolow; +extern short *__toup; + +#define isalnum(c) (__isbuf[(c)] & 0x0001U) +#define isalpha(c) (__isbuf[(c)] & 0x0002U) +#define iscntrl(c) (__isbuf[(c)] & 0x0004U) +#define isdigit(c) (__isbuf[(c)] & 0x0008U) +#define isgraph(c) (__isbuf[(c)] & 0x0010U) +#define islower(c) (__isbuf[(c)] & 0x0020U) +#define isprint(c) (__isbuf[(c)] & 0x0040U) +#define ispunct(c) (__isbuf[(c)] & 0x0080U) +#define isspace(c) (__isbuf[(c)] & 0x0100U) +#define isupper(c) (__isbuf[(c)] & 0x0200U) +#define isxdigit(c) (__isbuf[(c)] & 0x0400U) +#define tolower(c) (__tolow[(c)]) +#define toupper(c) (__toup[(c)]) +#endif + +#endif diff --git a/app/src/main/cpp/pdpclib/x86/errno.c b/app/src/main/cpp/pdpclib/x86/errno.c new file mode 100644 index 0000000..fc780bc --- /dev/null +++ b/app/src/main/cpp/pdpclib/x86/errno.c @@ -0,0 +1,18 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* errno.c - implementation of stuff in errno.h */ +/* */ +/*********************************************************************/ + +#include "stddef.h" + +int __errno = 0; + +__PDPCLIB_API__ int *_errno() + { return(&__errno); } diff --git a/app/src/main/cpp/pdpclib/x86/errno.h b/app/src/main/cpp/pdpclib/x86/errno.h new file mode 100644 index 0000000..6483ff7 --- /dev/null +++ b/app/src/main/cpp/pdpclib/x86/errno.h @@ -0,0 +1,29 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* errno.h - errno header file. */ +/* */ +/*********************************************************************/ + +#ifndef __ERRNO_INCLUDED +#define __ERRNO_INCLUDED + +#define EDOM 1 +#define ERANGE 2 + +#define errno (*(_errno())) + +int *_errno(void); + +#if defined(__PDOSGEN__) +#include <__os.h> +#undef errno +#define errno (*(__os->_errno())) +#endif + +#endif diff --git a/app/src/main/cpp/pdpclib/x86/float.h b/app/src/main/cpp/pdpclib/x86/float.h new file mode 100644 index 0000000..311762d --- /dev/null +++ b/app/src/main/cpp/pdpclib/x86/float.h @@ -0,0 +1,128 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* float.h - float header file. */ +/* */ +/*********************************************************************/ + +#ifndef __FLOAT_INCLUDED +#define __FLOAT_INCLUDED + +#if defined(__CMS__) || defined(__MVS__) || defined(__VSE__) +/* + IBM 360 & 370 use "HEX" floating point + float is 32 bits, double & long double are 64 bit. + Although some models can do 128 bit (actually 120 bit) + GCC does not implement this and "long double" is same as "double" +*/ + +/* rounding direction is unpredictable */ +#define FLT_ROUNDS 0 + +/* Floating point is HEX so RADIX is base 16 */ +#define FLT_RADIX 16 + +/* Note FLT_RADIX is 16 these are smaller than normal*/ +#define FLT_MANT_DIG 6 +#define DBL_MANT_DIG 14 +/* don't use 128 bit floats so this is still 14 */ +#define LDBL_MANT_DIG 14 + + +/* As IBM uses hex float with "wobbling precision" these are approximate */ +#define FLT_DIG 7 +#define DBL_DIG 15 +#define LDBL_DIG 15 + + +#define FLT_MIN_EXP (-64) +#define DBL_MIN_EXP (-64) +#define LDBL_MIN_EXP (-64) + +#define FLT_MIN_10_EXP (-78) +#define DBL_MIN_10_EXP (-78) +#define LDBL_MIN_10_EXP (-78) + +#define FLT_MAX_EXP 63 +#define DBL_MAX_EXP 63 +#define LDBL_MAX_EXP 63 + +#define FLT_MAX_10_EXP 75 +#define DBL_MAX_10_EXP 75 +#define LDBL_MAX_10_EXP 75 + +/* + This is a temporary fiddle to get round bug in GCC + scanning of ASCII to Floats. +*/ +typedef union { + unsigned short _HexVal[4]; + double _Dval; + float _Fval; + long _Lval; +} _HexFloat; + +static _HexFloat _FltMax = {{0x7fff, 0xffff ,0xffff ,0xffff}}; +static _HexFloat _FltMin = {{0x0010, 0x0000 ,0x0000 ,0x0000}}; +static _HexFloat _DblMax = {{0x7fff ,0xffff ,0xffff ,0xffff}}; +static _HexFloat _DblMin = {{0x0010 ,0x0000 ,0x0000 ,0x0000}}; +static _HexFloat _FltEps = {{0x3C10 ,0x0000 ,0x0000 ,0x0000}}; +static _HexFloat _DblEps = {{0x3410 ,0x0000 ,0x0000 ,0x0000}}; + +#define FLT_MAX _FltMax._Fval +#define DBL_MAX _DblMax._Dval +#define LDBL_MAX _DblMax._Lval + +#define FLT_MIN _FltMin._Fval +#define DBL_MIN _DblMin._Fval +#define LDBL_MIN _DblMin._Fval + +#define FLT_EPSILON _FltEps._Fval +#define DBL_EPSILON _DblEps._Fval +#define LDBL_EPSILON _DblEps._Fval + + + +#else +/* + original stuff from Paul for IEEE maths +*/ + +#define FLT_ROUNDS 1 +#define FLT_RADIX 2 +#define FLT_MANT_DIG 24 +#define DBL_MANT_DIG 53 +#define LDBL_MANT_DIG 53 +#define FLT_DIG 6 +#define DBL_DIG 10 +#define LDBL_DIG 10 +#define FLT_MIN_EXP -125 +#define DBL_MIN_EXP -1021 +#define LDBL_MIN_EXP -1021 +#define FLT_MIN_10_EXP -37 +#define DBL_MIN_10_EXP -37 +#define LDBL_MIN_10_EXP -37 +#define FLT_MAX_EXP +128 +#define DBL_MAX_EXP +1024 +#define LDBL_MAX_EXP +1024 +#define FLT_MAX_10_EXP +37 +#define DBL_MAX_10_EXP +37 +#define LDBL_MAX_10_EXP +37 +#define FLT_MAX 1E+37 +#define DBL_MAX 1E+37 +#define LDBL_MAX 1E+37 +#define FLT_EPSILON 1E-5 +#define DBL_EPSILON 1E-9 +#define LDBL_EPSILON 1E-9 +#define FLT_MIN 1E-37 +#define DBL_MIN 1E-37 +#define LDBL_MIN 1E-37 +#endif + +#endif + diff --git a/app/src/main/cpp/pdpclib/x86/limits.h b/app/src/main/cpp/pdpclib/x86/limits.h new file mode 100644 index 0000000..e6f61f8 --- /dev/null +++ b/app/src/main/cpp/pdpclib/x86/limits.h @@ -0,0 +1,52 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* limits.h - limits header file. */ +/* */ +/*********************************************************************/ + +#ifndef __LIMITS_INCLUDED +#define __LIMITS_INCLUDED + +#define CHAR_BIT 8 +#define SCHAR_MIN -128 +#define SCHAR_MAX 127 +#define UCHAR_MAX 255 +#if ('\x80' < 0) +#define CHAR_MIN -128 +#define CHAR_MAX 127 +#else +#define CHAR_MIN 0 +#define CHAR_MAX 255 +#endif +#define MB_LEN_MAX 1 +#define SHRT_MIN (-SHRT_MAX-1) +#define SHRT_MAX 32767 +#define USHRT_MAX ((unsigned short)65535U) + +#if (defined(__OS2__) || defined(__32BIT__) || defined(__MVS__) \ + || defined(__VSE__) || defined(__PDOS386__) \ + || defined(__CMS__) || defined(__WIN32__) || defined(__gnu_linux__) \ + || defined(__AMIGA__) ||defined(__SMALLERC__) || defined(__ARM__) \ + || defined(__EFI__)) +#define INT_MIN (-INT_MAX-1) +#define INT_MAX 2147483647 +#define UINT_MAX 4294967295U +#endif + +#if (defined(__MSDOS__) || defined(__DOS__) || defined(__POWERC)) +#define INT_MIN (-INT_MAX-1) +#define INT_MAX 32767 +#define UINT_MAX 65535U +#endif + +#define LONG_MIN (-LONG_MAX-1) +#define LONG_MAX 2147483647L +#define ULONG_MAX 4294967295UL + +#endif diff --git a/app/src/main/cpp/pdpclib/x86/linstart.c b/app/src/main/cpp/pdpclib/x86/linstart.c new file mode 100644 index 0000000..ea3d2ba --- /dev/null +++ b/app/src/main/cpp/pdpclib/x86/linstart.c @@ -0,0 +1,96 @@ +/* Startup code for Linux */ +/* written by Paul Edwards */ +/* released to the public domain */ + +#include "errno.h" +#include "stddef.h" + +/* malloc calls get this */ +static char membuf[31000000]; +static char *newmembuf = membuf; + +extern int __start(int argc, char **argv); +extern int __exita(int rc); + +#ifdef NEED_MPROTECT +extern int __mprotect(void *buf, size_t len, int prot); + +#define PROT_READ 1 +#define PROT_WRITE 2 +#define PROT_EXEC 4 +#endif + +/* We can get away with a minimal startup code, plus make it + a C program. There is no return address. Instead, on the + stack is a count, followed by all the parameters as pointers */ + +int _start(char *p) +{ + int rc; + +#ifdef NEED_MPROTECT + /* make malloced memory executable */ + /* most environments already make the memory executable */ + /* but some certainly don't */ + /* there doesn't appear to be a syscall to get the page size to + ensure page alignment (as required), and I read that some + environments have 4k page sizes but mprotect requires 16k + alignment. So for now we'll just go with 16k */ + size_t blksize = 16 * 1024; + size_t numblks; + + newmembuf = membuf + blksize; /* could waste memory here */ + newmembuf = newmembuf - (unsigned int)newmembuf % blksize; + numblks = sizeof membuf / blksize; + numblks -= 2; /* if already aligned, we wasted an extra block */ + rc = __mprotect(newmembuf, + numblks * blksize, + PROT_READ | PROT_WRITE | PROT_EXEC); + if (rc != 0) return (rc); +#endif + + /* I don't know what the official rules for ARM are, but + looking at the stack on entry showed that this code + would work */ +#ifdef __ARM__ + +#if defined(__UNOPT__) + rc = __start(*(int *)(&p + 5), &p + 6); +#else + rc = __start(*(int *)(&p + 6), &p + 7); +#endif + +#else + rc = __start(*(int *)(&p - 1), &p); +#endif + __exita(rc); + return (rc); +} + + +void *__allocmem(size_t size) +{ + return (newmembuf); +} + + +#if defined(__WATCOMC__) + +#define CTYP __cdecl + +/* this is invoked by long double manipulations + in stdio.c and needs to be done properly */ + +int CTYP _CHP(void) +{ + return (0); +} + +/* don't know what these are */ + +void CTYP cstart_(void) { return; } +void CTYP _argc(void) { return; } +void CTYP argc(void) { return; } +void CTYP _8087(void) { return; } + +#endif diff --git a/app/src/main/cpp/pdpclib/x86/linsupa.asm b/app/src/main/cpp/pdpclib/x86/linsupa.asm new file mode 100755 index 0000000..9e69ede --- /dev/null +++ b/app/src/main/cpp/pdpclib/x86/linsupa.asm @@ -0,0 +1,385 @@ +# linsupa.asm - support code for C programs for Linux +# +# This program written by Paul Edwards +# Released to the public domain + + +.globl ___setj +___setj: +.globl __setj +__setj: +mov 4(%esp), %eax +push %ebx +mov %esp, %ebx +mov %ebx, 20(%eax) #esp + +mov %ebp, %ebx +mov %ebx, 24(%eax) + +mov %ecx, 4(%eax) +mov %edx, 8(%eax) +mov %edi, 12(%eax) +mov %esi, 16(%eax) + +mov 4(%esp), %ebx # return address +mov %ebx, 28(%eax) # return address + +pop %ebx +mov %ebx,0(%eax) +mov $0, %eax + +ret + + + +.globl ___longj +___longj: +.globl __longj +__longj: +mov 4(%esp), %eax +mov 20(%eax), %ebp +mov %ebp, %esp + +pop %ebx # position of old ebx +pop %ebx # position of old return address + +mov 28(%eax), %ebx # return address +push %ebx + +mov 24(%eax), %ebx +mov %ebx, %ebp + +mov 0(%eax), %ebx +mov 4(%eax), %ecx +mov 8(%eax), %edx +mov 12(%eax), %edi +mov 16(%eax), %esi + +mov 60(%eax), %eax # return value + +ret + + +.globl ___write +___write: +.globl __write +__write: +push %ebp +mov %esp, %ebp +push %ebx +push %ecx +push %edx + +# function code 4 = write +movl $4, %eax +# handle +movl 8(%ebp), %ebx +# data pointer +movl 12(%ebp), %ecx +# length +movl 16(%ebp), %edx +int $0x80 +pop %edx +pop %ecx +pop %ebx +pop %ebp +ret + + +.globl ___read +___read: +.globl __read +__read: +push %ebp +mov %esp, %ebp +push %ebx +push %ecx +push %edx + +# function code 3 = read +movl $3, %eax +# handle +movl 8(%ebp), %ebx +# data pointer +movl 12(%ebp), %ecx +# length +movl 16(%ebp), %edx +int $0x80 +pop %edx +pop %ecx +pop %ebx +pop %ebp +ret + + + +.globl ___open +___open: +.globl __open +__open: +push %ebp +mov %esp, %ebp +push %ebx +push %ecx +push %edx + +# function code 5 = open +movl $5, %eax +# filename +movl 8(%ebp), %ebx +# flag +movl 12(%ebp), %ecx +# mode +movl 16(%ebp), %edx +int $0x80 +pop %edx +pop %ecx +pop %ebx +pop %ebp +ret + + + +.globl __seek +__seek: +.globl ___seek +___seek: +push %ebp +mov %esp, %ebp +push %ebx +push %ecx +push %edx + +# function code 19 = lseek +movl $19, %eax +# handle +movl 8(%ebp), %ebx +# offset +movl 12(%ebp), %ecx +# whence +movl 16(%ebp), %edx +int $0x80 +pop %edx +pop %ecx +pop %ebx +pop %ebp +ret + + + +.globl ___rename +___rename: +.globl __rename +__rename: +push %ebp +mov %esp, %ebp +push %ebx +push %ecx + +# function code 38 = rename +movl $38, %eax +# old file +movl 8(%ebp), %ebx +# new file +movl 12(%ebp), %ecx +int $0x80 +pop %ecx +pop %ebx +pop %ebp + + +.globl ___remove +___remove: +.globl __remove +__remove: +push %ebp +mov %esp, %ebp +push %ebx +# function code 10 = unlink +movl $10, %eax +# filename +movl 8(%ebp), %ebx +int $0x80 +pop %ebx +pop %ebp +ret + + +.globl ___close +___close: +.globl __close +__close: +push %ebp +mov %esp, %ebp +push %ebx +# function code 6 = close +movl $6, %eax +# handle +movl 8(%ebp), %ebx +int $0x80 +pop %ebx +pop %ebp +ret + + +.globl ___exita +___exita: +.globl __exita +__exita: +# exit/terminate +push %ebp +mov %esp, %ebp +push %ebx +movl 8(%ebp), %ebx +movl $1, %eax +int $0x80 +pop %ebx +pop %ebp +ret + + +.globl ___time +___time: +.globl __time +__time: +push %ebp +mov %esp, %ebp +push %ebx +# function code 13 = retrieve current time +movl $13, %eax +# pointer to time_t +movl 8(%ebp), %ebx +int $0x80 +pop %ebx +pop %ebp +ret + + +.globl ___ioctl +___ioctl: +.globl __ioctl +__ioctl: +push %ebp +mov %esp, %ebp +push %ebx +push %ecx +push %edx +# function code 54 = ioctl +movl $54, %eax +# file descriptor +movl 8(%ebp), %ebx +# command +movl 12(%ebp), %ecx +# parameter +movl 16(%ebp), %edx +int $0x80 +pop %edx +pop %ecx +pop %ebx +pop %ebp +ret + + +.globl ___chdir +___chdir: +.globl __chdir +__chdir: +push %ebp +mov %esp, %ebp +push %ebx +# function code 12 = chdir +movl $12, %eax +# filename (directory name) +movl 8(%ebp), %ebx +int $0x80 +pop %ebx +pop %ebp +ret + + +.globl ___rmdir +___rmdir: +.globl __rmdir +__rmdir: +push %ebp +mov %esp, %ebp +push %ebx +# function code 40 = rmdir +movl $40, %eax +# pathname +movl 8(%ebp), %ebx +int $0x80 +pop %ebx +pop %ebp +ret + + +.globl ___mkdir +___mkdir: +.globl __mkdir +__mkdir: +push %ebp +mov %esp, %ebp +push %ebx +push %ecx +# function code 39 = mkdir +movl $39, %eax +# pathname +movl 8(%ebp), %ebx +# mode +movl 12(%ebp), %ecx +int $0x80 +pop %ecx +pop %ebx +pop %ebp +ret + + +.globl ___getdents +___getdents: +.globl __getdents +__getdents: +push %ebp +mov %esp, %ebp +push %ebx +push %ecx +push %edx +# function code 141 = getdents +movl $141, %eax +# file descriptor +movl 8(%ebp), %ebx +# dirent +movl 12(%ebp), %ecx +# count +movl 16(%ebp), %edx +int $0x80 +pop %edx +pop %ecx +pop %ebx +pop %ebp +ret + + +.globl ___mprotect +___mprotect: +.globl __mprotect +__mprotect: +push %ebp +mov %esp, %ebp +push %ebx +push %ecx +push %edx +# function code 125 = mprotet +movl $125, %eax +# start +movl 8(%ebp), %ebx +# len +movl 12(%ebp), %ecx +# prot +movl 16(%ebp), %edx +int $0x80 +pop %edx +pop %ecx +pop %ebx +pop %ebp +ret diff --git a/app/src/main/cpp/pdpclib/x86/locale.c b/app/src/main/cpp/pdpclib/x86/locale.c new file mode 100644 index 0000000..b322830 --- /dev/null +++ b/app/src/main/cpp/pdpclib/x86/locale.c @@ -0,0 +1,60 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* locale.c - implementation of stuff in locale.h */ +/* */ +/*********************************************************************/ + +#include "locale.h" +#include "limits.h" +#include "string.h" +#include "stddef.h" + +static struct lconv thislocale = { + ".", + "", + "", + "", + "", + "", + "", + "", + "", + "", + CHAR_MAX, + CHAR_MAX, + CHAR_MAX, + CHAR_MAX, + CHAR_MAX, + CHAR_MAX, + CHAR_MAX, + CHAR_MAX +}; + +__PDPCLIB_API__ char *setlocale(int category, const char *locale) +{ + (void)category; + if (locale == NULL) + { + return ("C"); + } + else if ((strcmp(locale, "C") == 0) + || (strcmp(locale, "") == 0)) + { + return ("C"); + } + else + { + return (NULL); + } +} + +__PDPCLIB_API__ struct lconv *localeconv(void) +{ + return (&thislocale); +} diff --git a/app/src/main/cpp/pdpclib/x86/locale.h b/app/src/main/cpp/pdpclib/x86/locale.h new file mode 100644 index 0000000..7027700 --- /dev/null +++ b/app/src/main/cpp/pdpclib/x86/locale.h @@ -0,0 +1,56 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* locale.h - locale header file. */ +/* */ +/*********************************************************************/ + +#ifndef __LOCALE_INCLUDED +#define __LOCALE_INCLUDED + +struct lconv { + char *decimal_point; + char *thousands_sep; + char *grouping; + char *int_curr_symbol; + char *currency_symbol; + char *mon_decimal_point; + char *mon_thousands_sep; + char *mon_grouping; + char *positive_sign; + char *negative_sign; + char int_frac_digits; + char frac_digits; + char p_cs_precedes; + char p_sep_by_space; + char n_cs_precedes; + char n_sep_by_space; + char p_sign_posn; + char n_sign_posn; +}; + +#define NULL ((void *)0) +#define LC_ALL 1 +#define LC_COLLATE 2 +#define LC_CTYPE 3 +#define LC_MONETARY 4 +#define LC_NUMERIC 5 +#define LC_TIME 6 + +char *setlocale(int category, const char *locale); +struct lconv *localeconv(void); + +#if defined(__PDOSGEN__) +#include <__os.h> + +#define setlocale __os->setlocale + +#endif + + +#endif diff --git a/app/src/main/cpp/pdpclib/x86/math.c b/app/src/main/cpp/pdpclib/x86/math.c new file mode 100644 index 0000000..3f66818 --- /dev/null +++ b/app/src/main/cpp/pdpclib/x86/math.c @@ -0,0 +1,723 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/* 9-April-2006 D.Wade */ +/* Moved definitions for HUGE_VAL to math.h */ +/* Inserted argument rang checks in :- */ +/* acos */ +/* */ +/* */ +/* */ +/* 2-April-2006 D.Wade added code for the :- */ +/* */ +/* acos(double x); */ +/* asin(double x); */ +/* atan(double x); */ +/* cos(double x); */ +/* sin(double x); */ +/* tan(double x); */ +/* cosh(double x); */ +/* sinh(double x); */ +/* tanh(double x); */ +/* exp(double x); */ +/* frexp(double value, int *exp); */ +/* ldexp(double x, int exp); */ +/* log(double x); */ +/* log10(double x); */ +/* modf(double value, double *iptr); */ +/* pow(double x, double y); */ +/* sqrt(double x); */ +/* */ +/* Note:- */ +/* In order to avoide Copyright these functions are generally */ +/* implemented using Taylor Series. As a result they are a little */ +/* slower that the equivalents in many maths packages. */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* math.c - implementation of stuff in math.h */ +/* */ +/*********************************************************************/ + +#include "math.h" +#include "float.h" +#include "errno.h" +#include "stddef.h" + +/* + + Some constants to make life easier elsewhere + (These should I guess be in math.h) + +*/ +static const double pi = 3.1415926535897932384626433832795; +static const double ln10 = 2.3025850929940456840179914546844; +static const double ln2 = 0.69314718055994530941723212145818 ; + + +__PDPCLIB_API__ double ceil(double x) +{ + int y; + + y = (int)x; + if ((double)y < x) + { + y++; + } + return ((double)y); +} + +#ifdef fabs +#undef fabs +#endif +__PDPCLIB_API__ double fabs(double x) +{ + if (x < 0.0) + { + x = -x; + } + return (x); +} + +__PDPCLIB_API__ double floor(double x) +{ + int y; + + if (x < 0.0) + { + y = (int)x; + if ((double)y != x) + { + y--; + } + } + else + { + y = (int)x; + } + return ((double)y); +} + +__PDPCLIB_API__ double fmod(double x, double y) +{ + int imod; + if(y == 0.0) return (0.0); + imod = x / y; + return ((double)x-((double)imod*y)); +} + +#ifdef acos +#undef acos +#endif +/* + + For cos just use (sin(x)**2 + cos(x)**2)=1 + Note:- asin(x) decides which taylor series + to use to ensure quickest convergence. + +*/ +__PDPCLIB_API__ double acos(double x) +{ + +/* +*/ + + if ( fabs(x) > 1.0 ) /* is argument out of range */ + { + errno=EDOM; + return (HUGE_VAL); + } + if ( x < 0.0 ) return ( pi - acos(-x) ) ; + + return ( asin ( sqrt(1.0 - x*x) ) ); + +} + +#ifdef asin +#undef asin +#endif +/* + + This routines Calculate arcsin(x) & arccos(x). + + Note if "x" is close to "1" the series converges slowly. + To avoid this we use (sin(x)**2 + cos(x)**2)=1 + and fact cos(x)=sin(x+pi/2) + +*/ + +__PDPCLIB_API__ double asin (double y) +{ + int i; + double term,answer,work,x,powx,coef; + + x = y; + +/* + if arg is -ve then we want "-asin(-x)" +*/ + + if (x <0.0 ) return ( -asin(-x) ); + +/* + If arg is > 1.0 we can't calculate + (note also < -1.0 but previous statement removes this case) +*/ + if ( x > 1.0 ) + { + errno=EDOM; + return(HUGE_VAL); + } + +/* + now check for large(ish) x > 0.6 +*/ + + if( x > 0.75 ) + { + x = ( sqrt(1.0 - (x*x) ) ); + return((pi/2.0)-asin(x)); + } + +/* + arcsin(x) = x + 1/2 (x^3/3) + (1/2)(3/4)(x^5/5) + + (1/2)(3/4)(5/6)(x^7/7) + ... +*/ + i=1; + answer=x; + term = 1; + coef = 1; + powx = x; + + while (1) + { + work = i; + coef = (coef * work)/(work+1); + powx = powx * x * x; + term = coef * powx / (work + 2.0); + if ( answer == (answer + term) )break; + answer = answer + (term); + i+=2; + } + + return(answer); +} + + +#ifdef atan +#undef atan +#endif +/* + + Because atan(x) is valid for large values of "x" & + the taylor series converges more slowly for large "X" + we use the following + + 1. Reduce to the first octant by using :- + + atan(-x)=-atan(x), + atan(1/x)=PI/2-atan(x) + + 2. Reduce further so that |x| less than tan(PI/12) + + atan(x)=pi/6+atan((X*sqrt(3)-1)/(x+sqrt(3))) + + 3. Then use the taylor series + + atan(x) = x - x**3 + x**5 - x**7 + ---- ---- ---- + 3 5 7 + +*/ + +__PDPCLIB_API__ double atan (double x) +{ + int i; + double term,answer,work,powx; + +/* + if arg is -ve then we want "-atan(-x)" +*/ + + if ( x<0.0 ) return ( -atan(-x) ); + +/* + If arg is large we can't calculate + use atan(1/x)=PI/2-atan(x) +*/ + + if ( x > 1.0 ) return ((pi/2) - atan(1.0/x)); + +/* + now check for large(ish) x > tan(15) (0.26794919243112) + if so use atan(x)=pi/6+atan((X*SQRT3-1)/(X+SQRT3)) +*/ + + if( x > (2.0 - sqrt(3.0))) + return( (pi/6.0) + atan( ( x * sqrt(3.0)-1.0 ) / (x + sqrt(3.0) ) ) ); + +/* +* atan(x) = x - x**3 + x**5 - x**7 +* ---- ---- ---- +* 3 5 7 +*/ + + i=1; + answer=x; + term = x; + powx = x; + + while (1) + { + work = i; + powx = 0.0 - powx * x * x; + term = powx / (work + 2.0); + if ( answer == (answer + term) )break; + answer = answer + (term); + i+=2; + } + + return(answer); + +} + + +/* atan2 was taken from libnix and modified slightly */ + +__PDPCLIB_API__ double atan2(double y,double x) +{ + return (x >= y) ? + (x >= -y ? atan(y/x) : -pi/2 - atan(x/y)) + : + (x >= -y ? pi/2 - atan(x/y) + : (y >= 0) ? pi + atan(y/x) + : -pi + atan(y/x)); +} + + +#ifdef cos +#undef cos +#endif +__PDPCLIB_API__ double cos(double x) +{ +/* + + Calculate COS using Taylor series. + + sin(x) = 1 - x**2 + x**4 - x**6 + x**8 + ==== ==== ==== ==== ......... + 2! 4! 6! 8! + + Note whilst this is accurate it can be slow for large + values of "X" so we scale + +*/ + + int i; + double term,answer,work,x1; + +/* + Scale arguments to be in range 1 => pi +*/ + + i = x/(2*pi); + x1 = x - (i * (2.0 * pi)); + + i=1; + term=answer=1; + + + while (1) + { + work = i; + term = -(term * x1 * x1)/(work * (work + 1.0)); + if ( answer == (answer + term) )break; + answer = answer + term; + i += 2; + } + + return(answer); + +} + +#ifdef sin +#undef sin +#endif +__PDPCLIB_API__ double sin(double x) +{ +/* + + Calculate SIN using Taylor series. + + sin(x) = x - x**3 + x**5 - x**7 + x**9 + ==== ==== ==== ==== + 3! 5! 7! 9! + + Note whilst this is accurate it can be slow for large values + of "X" so we scale + +*/ + + int i; + double term,answer,work,x1; + +/* + scale so series converges pretty quickly +*/ + i = x/(2.0*pi); + x1 = x - (i * (2.0 * pi)); + +/* + set up initial term +*/ + i=1; + term=answer=x1; +/* + loop until no more changes +*/ + while (1) + { + work = i+1; + term = -(term * x1 * x1)/(work * (work + 1.0)); + if ( answer == (answer + term) )break; + answer = answer + term; + i = i+2; + } + + return(answer); +} + +#ifdef tan +#undef tan +#endif +__PDPCLIB_API__ double tan (double x) +{ +/* + + use tan = sin(x)/cos(x) + if cos(x) is 0 then return HUGE_VAL else return sin/cos + + *** need to set ERROR for overflow *** + +*/ + double temp; + + temp=cos(x); + if (temp == 0.0 ) + { + /* errno=EDOM; don't seem to return an error here */ + return (HUGE_VAL); /* need to set error here */ + } + return ( sin(x)/cos(x) ); +} + +/* + + Hyperbolic functions + + SINH(X) = (E**X-E**(-1))/2 + COSH(X) = (E**X+E**(-1))/2 + +*/ +__PDPCLIB_API__ double cosh(double x) +{ + double dexpx; + + dexpx = exp(x); + + return( 0.5 * (dexpx + (1.0/dexpx) ) ); + +} + +__PDPCLIB_API__ double sinh(double x) +{ + double dexpx; + + dexpx = exp(x); + + return( 0.5 * (dexpx - (1.0/dexpx) ) ); +} + +/* + tanh returns the hyperbolic area tangent of floating point argument x. +*/ + +__PDPCLIB_API__ double tanh(double x) +{ + double dexp2; + + dexp2 = exp( -2.0 * x); + return ( (1.0 - dexp2) / (1.0 + dexp2) ); +} + +/* + +exp(x) = 1 + x + x2/2 + x3/6 + x4/24 + x5/120 + ... + xn/n! + ... + +*/ +__PDPCLIB_API__ double exp (double x) +{ + int i; + double term,answer,work; + + i=2; + term=x; + answer=x; + + while (1) + { + work = i; + term = (term * x)/work; + if ( answer == (answer + term) )break; + answer = answer + (term); + i++; + } + + answer=answer+1.0; + return(answer); +} + +/* + + Calculate LOG using Taylor series. + + log(1+ x) = x - x**2 + x**3 - x**4 + x**5 + ==== ==== ==== ==== ......... + 2 3 4 8 + + Note this only works for small x so we scale.... + +*/ +__PDPCLIB_API__ double log (double x) +{ + int i,scale; + double term,answer,work,xs; + + if (x <= 0 ) + { + /* need to set signal */ + errno=EDOM; + return (HUGE_VAL); + } + if( x == 1.0)return(0.0); + +/* + Scale arguments to be in range 1 < x <= 10 +*/ + +/* + scale = 0; + xs = x; + while ( xs > 10.0 ) { scale ++; xs=xs/10.0;} + while ( xs < 1.0 ) { scale --; xs=xs*10.0;} +*/ + xs = frexp(x,&scale); + xs = (1.0 * xs) - 1.0; + scale = scale - 0; + + i=2; + term=answer=xs; + + while (1) + { + work = i; + term = - (term * xs); + if ( answer == (answer + (term/work)) )break; + answer = answer + (term/work); + i++; + } + + answer = answer + (double)scale * ln2; + return(answer); +} + + +__PDPCLIB_API__ double log10(double x) +{ + return ( log(x) / ln10 ); +} + + +/* + + This code uses log and exp to calculate x to the power y. + If + +*/ + +__PDPCLIB_API__ double pow(double x,double y) +{ + int j,neg; + double yy,xx; + neg=0; + j=y; + yy=j; + if( yy == y) { + xx = x; + if ( y < 0 ){neg = 1; j = -j;} + if ( y == 0) return (1.0); + --j; + while(j>0){ xx=xx * x; j--;} + if(neg)xx=1.0/xx; + return (xx); + } + if (x < 0.0) + { + errno=EDOM; + return(0.0); + } + if (y == 0.0) return (1.0); + + return (exp(y*log(x))); +} + +#ifdef sqrt +#undef sqrt +#endif +/* + + pretty tivial code here. + + 1) Scale x such that 1 <= x <= 4.0 + + 2) Use newton Raphson to calculate root. + + 4) multiply back up. + + Because we only scale by "4" this is pretty slow.... + +*/ + +__PDPCLIB_API__ double sqrt(double x) +{ + double xs,yn,ynn; + double pow1; + int i; + + if (x < 0.0) + { + errno=EDOM; + return(0.0); + } + if (x == 0.0) return (0.0); + +/* + + Scale argument 1 <= x <= 4 + +*/ + + xs=x; + pow1=1; + + while(xs<1.0){xs=xs*4.0;pow1=pow1/2.0;} + while(xs>=4.0){xs=xs/4.0;pow1=pow1*2.0;} + +/* + calculate using Newton raphson + use x0 = x/2.0 +*/ + + i=0; + yn = xs/2.0; + ynn = 0; + while(1) + { + ynn = (yn + xs/yn)*0.5; + if ( fabs(ynn-yn) <= 10.0 * DBL_MIN ) break; else yn=ynn; + if ( i > 10 ) break; else i++ ; + } + return (ynn*pow1); +} + + +__PDPCLIB_API__ double frexp(double x, int *exp) +{ +/* + split float into fraction and mantissa + note this is not so easy for IBM as it uses HEX float +*/ + union dblhex + { + double d; + unsigned short s[4]; + }; + union dblhex split; + + if ( x == 0.0) + { + exp=0; + return (0.0); + } + + split.d = x; + *exp = (((split.s[0] >> 8) & 0x007f)-64) * 4; + split.s[0] = split.s[0] & 0x80ff; + split.s[0] = split.s[0] | 0x4000; + /* following code adjust for fact IBM has hex float */ + while ( (fabs(split.d) < 0.5) && (split.d != 0) ) + { + split.d = split.d * 2; + *exp =( *exp ) - 1; + } + /* */ + return(split.d); +} + +__PDPCLIB_API__ double ldexp(double x, int exp) +{ +/* + note this is not so easy for IBM as it uses HEX float +*/ + int bin_exp,hex_exp,adj_exp; + union dblhex + { + double d; + unsigned short s[4]; + }; + union dblhex split; +/* + note "X" mauy already have an exponent => extract it +*/ + split.d = frexp(x,&bin_exp); + bin_exp = bin_exp + exp; /* add in from caller */ +/* need to test for sensible value here */ + hex_exp = (bin_exp / 4); /* convert back to HEX */ + adj_exp = bin_exp - (hex_exp * 4); + if (adj_exp < 0){ hex_exp=hex_exp -1; adj_exp = 4 + adj_exp;} + split.s[0] = split.s[0] & 0x80ff; + split.s[0] = split.s[0] | (((hex_exp+64) << 8) & 0x7f00); + /* following code adjust for fact IBM has hex float */ + /* well it will I have done */ + while ( adj_exp > 0 ) + { + split.d = split.d * 2; + --adj_exp; + } + /**/ + return(split.d); +} + +__PDPCLIB_API__ double modf(double value, double *iptr) +{ + int neg = 0; + long i; + + if (value < 0) + { + neg = 1; + value = -value; + } + i = (long)value; + value = value - i; + if (neg) + { + value = -value; + i = -i; + } + *iptr = i; + return (value); +} diff --git a/app/src/main/cpp/pdpclib/x86/math.h b/app/src/main/cpp/pdpclib/x86/math.h new file mode 100644 index 0000000..7e41535 --- /dev/null +++ b/app/src/main/cpp/pdpclib/x86/math.h @@ -0,0 +1,95 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* math.h - math header file. */ +/* */ +/*********************************************************************/ + +#ifndef __MATH_INCLUDED +#define __MATH_INCLUDED + +/* + Some constants - at present these are only defined for IBM +*/ +#if defined(__MVS__) || defined (__CMS__) || defined(__VSE__) +/* + This is about the nearest thing we can get to inf wthout +*/ +#define HUGE_VAL 9.999999999999999999999E72 + +#else + +#define HUGE_VAL 9.999999999999999999999E72 + +#endif + +double ceil(double x); +double fabs(double x); +double floor(double x); +double fmod(double x, double y); + +/* unimplemented: */ + + +double atan2(double y, double x); +double frexp(double value, int *exp); +double ldexp(double x, int exp); +double modf(double value, double *iptr); + +/* + Implemented by d.wade - April 2006 +*/ + +double pow(double x, double y); +double sqrt(double x); +double acos(double x); +double asin(double x); +double atan(double x); +double cos(double x); +double sin(double x); +double tan(double x); +double cosh(double x); +double sinh(double x); +double tanh(double x); +double exp(double x); +double log(double x); +double log10(double x); + + +#if 0 /* def __WATCOMC__ */ +#pragma intrinsic(cos, sin, tan, exp, log, log10, sqrt) +#endif + +#if defined(__IBMC__) && defined(__OS2__) +double _Builtin __fabs(double x); +#define fabs(x) (__fabs((x))) +double _Builtin __fsin(double x); +#define sin(x) (__fsin((x))) +double _Builtin __fcos(double x); +#define cos(x) (__fcos((x))) +double _Builtin __fptan(double x); +#define tan(x) (__fptan((x))) +double _Builtin __fpatan(double x); +#define atan(x) (__fpatan((x))) +double _Builtin __facos(double x); +#define acos(x) (__facos((x))) +double _Builtin __fasin(double x); +#define asin(x) (__fasin((x))) +double _Builtin __fsqrt(double x); +#define sqrt(x) (__fsqrt((x))) +#endif + +#ifdef __BORLANDC__ +double __sin__(double x); +#define sin(x) (__sin__((x))) +double __cos__(double x); +#define cos(x) (__cos__((x))) +#endif + +#endif + diff --git a/app/src/main/cpp/pdpclib/x86/setjmp.c b/app/src/main/cpp/pdpclib/x86/setjmp.c new file mode 100644 index 0000000..cdd321e --- /dev/null +++ b/app/src/main/cpp/pdpclib/x86/setjmp.c @@ -0,0 +1,44 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* setjmp.c - implementation of stuff in setjmp.h */ +/* */ +/*********************************************************************/ + +#include "setjmp.h" +#include "stddef.h" + +#if defined(__WATCOMC__) && !defined(__32BIT__) +#define CTYP __cdecl +#else +#define CTYP +#endif + +extern int CTYP __setj(jmp_buf env); +extern int CTYP __longj(void *); + +#ifdef __MSC__ +__PDPCLIB_API__ int setjmp(jmp_buf env) +#else +__PDPCLIB_API__ int _setjmp(jmp_buf env) +#endif +{ + return (__setj(env)); +} + +__PDPCLIB_API__ void longjmp(jmp_buf env, int val) +{ + if (val == 0) + { + val = 1; + } + env[0].retval = val; + /* load regs */ + __longj(env); + return; +} diff --git a/app/src/main/cpp/pdpclib/x86/setjmp.h b/app/src/main/cpp/pdpclib/x86/setjmp.h new file mode 100644 index 0000000..d9313bf --- /dev/null +++ b/app/src/main/cpp/pdpclib/x86/setjmp.h @@ -0,0 +1,101 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* setjmp.h - setjmp header file. */ +/* */ +/*********************************************************************/ + +#ifndef __SETJMP_INCLUDED +#define __SETJMP_INCLUDED + +typedef struct { +#if defined(__MVS__) || defined(__CMS__) || defined(__VSE__) + int regs[15]; +#elif defined(__AMIGA__) + long a0; + long a1; + long a2; + long a3; + long a4; + long a5; + long a6; + long a7; + long d0; + long d1; + long d2; + long d3; + long d4; + long d5; + long d6; + long d7; + long retaddr; +#elif defined(__ARM__) || defined(__ARMGEN__) + void *sp; + void *fp; + void *ip; + int r4; + int r5; + int r6; + int r7; + int r8; + int r9; + int r10; +#elif defined(__WIN32__) || defined(__32BIT__) || defined(__OS2__) \ + || defined(__PDOS386__) || defined(__gnu_linux__) || defined(__EFI__) + int ebx; + int ecx; + int edx; + int edi; + int esi; + int esp; + int ebp; + int retaddr; + int extra[7]; /* for compatibility with MSVCRT */ +#elif defined(__MSDOS__) || defined(__DOS__) || defined(__POWERC) + int bx; + int cx; + int dx; + int di; + int si; + int sp; + int bp; + int retoff; + int retseg; + int ds; + int es; +#else +#error unknown system in setjmp.h +#endif + int retval; +} jmp_buf[1]; + +void longjmp(jmp_buf env, int val); + +#ifdef __MSC__ +int setjmp(jmp_buf env); + +#elif defined(__ARM__) || defined(__ARMGEN__) +/* it appears that gcc has _setjmp as a known keyword which + is causing issues on ARM, so we change the name */ +#define setjmp(x) __Ysetjmp(x) +int __Ysetjmp(jmp_buf env); + +#elif defined(__MSDOS__) +#define setjmp(x) __setj(x) +#if defined(__WATCOMC__) +int __cdecl __setj(jmp_buf env); +#else +int __setj(jmp_buf env); +#endif + +#else +#define setjmp(x) _setjmp(x) +int _setjmp(jmp_buf env); +#endif + +#endif diff --git a/app/src/main/cpp/pdpclib/x86/signal.c b/app/src/main/cpp/pdpclib/x86/signal.c new file mode 100644 index 0000000..8162efc --- /dev/null +++ b/app/src/main/cpp/pdpclib/x86/signal.c @@ -0,0 +1,87 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* signal.c - implementation of stuff in signal.h */ +/* */ +/*********************************************************************/ + +#include "signal.h" +#include "stdlib.h" +#include "stddef.h" + +static void (*handlers[])(int) = { + __sigdfl, + __sigdfl, + __sigdfl, + __sigdfl, + __sigdfl, + __sigdfl, + __sigdfl }; + +void __sigdfl(int sig); +void __sigerr(int sig); +void __sigign(int sig); + +#if 0 +#define SIG_DFL __sigdfl +#define SIG_ERR __sigerr +#define SIG_IGN __sigign +#endif + +__PDPCLIB_API__ void (*signal(int sig, void (*func)(int)))(int) +{ +#if defined(__WIN32__) && !defined(__STATIC__) + if ((int)func == SIG_DFL) + { + handlers[sig] = __sigdfl; + } + else if ((int)func == SIG_ERR) + { + handlers[sig] = __sigerr; + } + else if ((int)func == SIG_IGN) + { + handlers[sig] = __sigign; + } +#else + handlers[sig] = func; +#endif + return (func); +} + + +__PDPCLIB_API__ int raise(int sig) +{ + (handlers[sig])(sig); + return (0); +} + +__PDPCLIB_API__ void __sigdfl(int sig) +{ +#ifndef SEGHACK + handlers[sig] = SIG_DFL; +#endif + if (sig == SIGABRT) + { + exit(EXIT_FAILURE); + } + return; +} + +__PDPCLIB_API__ void __sigerr(int sig) +{ + (void)sig; + return; +} + +__PDPCLIB_API__ void __sigign(int sig) +{ + (void)sig; + return; +} + diff --git a/app/src/main/cpp/pdpclib/x86/signal.h b/app/src/main/cpp/pdpclib/x86/signal.h new file mode 100644 index 0000000..29ea68a --- /dev/null +++ b/app/src/main/cpp/pdpclib/x86/signal.h @@ -0,0 +1,56 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* signal.h - signal header file. */ +/* */ +/*********************************************************************/ + +#ifndef __SIGNAL_INCLUDED +#define __SIGNAL_INCLUDED + +typedef int sig_atomic_t; + +void __sigdfl(int sig); +void __sigerr(int sig); +void __sigign(int sig); + +#if (defined(__WIN32__) && !defined(__STATIC__)) || defined (__PDOSGEN__) +#define SIG_DFL 0 +#define SIG_ERR -1 +#define SIG_IGN 1 +#else +#define SIG_DFL __sigdfl +#define SIG_ERR __sigerr +#define SIG_IGN __sigign +#endif + +#define SIGABRT 1 +#define SIGFPE 2 +#define SIGILL 3 +#define SIGINT 4 +#define SIGSEGV 5 +#define SIGTERM 6 + +#ifdef __SUBC__ +int signal(int sig, int (*handler)()); +#else +void (*signal(int sig, void (*func)(int)))(int); +#endif + +int raise(int sig); + + +#if defined(__PDOSGEN__) +#include <__os.h> + +#define signal __os->signal +#define raise __os->raise +#endif + + +#endif diff --git a/app/src/main/cpp/pdpclib/x86/start.c b/app/src/main/cpp/pdpclib/x86/start.c new file mode 100644 index 0000000..45b0256 --- /dev/null +++ b/app/src/main/cpp/pdpclib/x86/start.c @@ -0,0 +1,1428 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* start.c - startup/termination code */ +/* */ +/*********************************************************************/ + +/* We have the following independent concepts: + +1. What processor is used, e.g. __ARM__ or __386__ or __8086__ +This is important to setjmp as it needs an appropriate sized +buffer for the registers that need to be saved. Note that the +8086 has different memory models, and in e.g. tiny and small +memory models, the segment registers shouldn't be saved/ +restored, as the OS could theoretically use this knowledge to +move the application to some other location. Although the +executable would need to be specially marked that it can be +dynamically relocated, as otherwise it could directly obtain +memory from the OS at runtime and change the segment registers +(via far pointers). The important thing is that the concept exists. + +2. What compiler is used, e.g. __GCC__ (and version number within that, +and forks within that, and targets within that - not just processor +as the target but also the calling convention). + +3. Whether the OS exports the C library (PDOS-generic does, PDOS/386 doesn't) + +4. What API is used, e.g. Pos* vs Win32 vs Posix. Note that it is +possible to get one API to be implemented via translation into another +API. + +5. The size of ints, e.g. __32BIT__ vs __16BIT__ + +6. The API (e.g. Pos) versus any operating system that actually +implements that API (e.g. PDOS/386). Or Win32 API implemented by +PDOS/386. + +7. Whether the OS itself relies on a generic pseudo-BIOS/HAL + +8. Whether the OS/BIOS provides data in blocks (e.g. MVS or a PC BIOS) or +whether you can read/write an arbitrary number of bytes. + +9. The fact that the C library, including PDPCLIB, reconciles block +versus character mode if necessary, and the application always gets +a character mode interface. + +10. Whether the OS does the conversion of blocks (ie blocks on a +mainframe CKD disk, or sectors on a PC) into characters within the +OS itself, or outsources that job to the C library that it relies on. +Currently PDOS/386 does Bos* calls in the OS itself to read disk +sectors, but PDPCLIB could have done those Bos* calls itself, in the +same flavor of code that MVS/CMS/VSE use, which would likely have +been neater, and a better abstraction. PDOS/386 may be restructured +to do this in the future, but it may simply become PDOS-generic if +that is done. That's still unclear to me. Something like pcomm +calling PosMonitor() to implement the "monitor" command is something +beyond what can be considered generic, ie dealing with 80386 registers, +and might possibly need to be shifted up to a higher layer (the HAL/ +pseudo-BIOS) - but that HAL needs to do printfs which are back in +the OS to do, I think. You can't expect a BIOS to provide a full C +library, even though that is the case when running under some +other OS. + +Historically these concepts have all been jumbled up in PDOS/PDPCLIB +and never been reconciled. Which is why there are anomalies such as +a PDOS-generic application for ARM is built needing PDOS386 defined, +when it has nothing whatsoever to do with an 80386. It works, but is +confusing and not properly abstracted/defined. + +So let's try to reconcile at least some of them now. + +And apologies for Pos* being a bit confusing since the name is similar +to POSIX, but they are completely unrelated. Pos* was actually inspired +by Dos* from OS/2 which I thought was a neat naming convention for +the MSDOS INT 21H functions, even though I hated the actual parameter types. + +__POSGEN__ - this define means that both the C library and the Pos* +interface have been exported by the operating system (not necessarily +PDOS-generic) via the well-defined, set in stone (ha ha) __os structure. +Applications can define this. It's not for use when compiling the +actual OS. Or should this be split up into __POS__ and __GENERIC__? +Or __POS__ to specify the API and __CEXPORT__ to say the C library has +been exported (which could be done independently of exporting the +rest of the Pos* API). Note that there is a difference between using +the C library and building the C library. + +__POSGENOS__ - I give up. + +*/ + +#include "stdio.h" +#include "stdlib.h" +#include "string.h" +#include "stddef.h" +#include "setjmp.h" + +#if USE_MEMMGR +#include "__memmgr.h" +#endif + +#ifdef __ARM__ +#define __gnu_linux__ +#endif + +extern FILE *__userFiles[__NFILE]; + +extern void (*__userExit[__NATEXIT])(void); + +#define MAXPARMS 50 /* maximum number of arguments we can handle */ + +#ifdef __OS2__ +#define INCL_DOS +#include +#endif + +#ifdef __WIN32__ +#include +#endif + +static int runnum = 0; + +int __G_live = 0; +void *__G_ptr = NULL; +int __G_one = 1; +int __G_zero = 0; + +#ifdef __gnu_linux__ + +struct termios { + unsigned int c_iflag; + unsigned int c_oflag; + unsigned int c_cflag; + unsigned int c_lflag; + unsigned int whoknows[50]; +}; + +static struct termios tios_save; +static struct termios tios_new; + +int __ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); + +#define TCGETS 0x00005401U +#define TCSETS 0x00005402U + +#define ISIG 0x1 +#define ICANON 0x2 +#define ECHO 0x8 +#define ECHONL 0x40 + +#define IXON 0x400 + +#endif + + +#if defined(__WATCOMC__) && !defined(WATLIN) +#define CTYP __cdecl +#else +#define CTYP +#endif + +#ifdef __SMALLERC__ +#define __MSDOS__ +#endif + +#if defined(__PDOS386__) +/* Used for PDOS itself to avoid API calls when starting. */ +int __minstart = 0; +#endif + +/* will be set by __exit */ +static int globrc = 0; + +static jmp_buf jb; + +#ifndef __PDPCLIB_DLL + +/* Unfortunately Watcom requires us to make main() a watcall, + even if everything else is compiled with -ecc */ +#if defined(__WATCOMC__) +#define MAINTYP __watcall +#else +#define MAINTYP +#endif + +int MAINTYP main(int argc, char **argv); + +int __genstart = 0; +int MAINTYP (*__genmain)(int argc, char **argv) = main; + +#endif + +#ifdef __MSDOS__ +/* Must be unsigned as it is used for array index */ +#ifndef __SMALLERC__ +extern +#endif +unsigned char *__envptr; +#ifndef __SMALLERC__ +extern +#endif +unsigned short __osver; +static unsigned char *newcmdline = NULL; +#endif + +#ifdef __VSE__ +#undef __CMS__ +#undef __MVS__ +#endif + +#if defined(__MVS__) || defined(__CMS__) || defined(__VSE__) +int __tso = 0; /* is this a TSO environment? */ +extern int __doperm; /* are we doing the permanent datasets? */ +int __upsi = 0; /* UPSI switches for VSE */ +#endif + +void __exit(int status); +void CTYP __exita(int status); + +#if !defined(__MVS__) && !defined(__CMS__) && !defined(__VSE__) +static char buffer1[BUFSIZ + 8]; +static char buffer2[BUFSIZ + 8]; +static char buffer3[BUFSIZ + 8]; +#endif + +#if defined(__AMIGA__) + +#include + +struct Node { + struct Node *ln_Succ; + char filler[6]; + char *ln_Name; +}; + +struct Library { + struct Node lib_Node; + /* other junk */ +}; + +struct List { + struct Node *lh_Head; + char filler[10]; +}; + +struct ExecBase { + char filler[378]; + struct List LibList; +}; + +struct ExecBase *SysBase; +void *DOSBase; +#endif + +#if defined(__EFI__) +#include "efi.h" +#endif + +#if defined(__PDOS386__) +#include +#include +unsigned char *__envptr; +static unsigned int stdin_dw; +#endif + +#if USE_MEMMGR +extern void *__lastsup; /* last thing supplied to memmgr */ +#endif + +char **__eplist; +char *__plist; + +#ifdef __WIN32__ +static DWORD stdin_dw; +static DWORD stdout_dw; + +/* Not sure what _startupinfo is. */ +typedef int _startupinfo; + +__PDPCLIB_API__ int __getmainargs(int *_Argc, + char ***_Argv, + char ***_Env, + int _DoWildCard, + _startupinfo *_StartInfo) +{ + char *p; + int x; + int argc; + static char *argv[MAXPARMS + 1]; + static char *env[] = {NULL}; + + p = GetCommandLine(); + + /* kludge for presumed HX bug */ + if (strncmp(p, "C:\\COMMAND.COM /c", 17) == 0) + { + p += 17; + p += strspn(p, " "); + } + + argv[0] = p; + p = strchr(p, ' '); + if (p == NULL) + { + p = ""; + } + else + { + *p = '\0'; + p++; + } + + while (*p == ' ') + { + p++; + } + if (*p == '\0') + { + argv[1] = NULL; + argc = 1; + } + else + { + for (x = 1; x < MAXPARMS; ) + { + char srch = ' '; + + if (*p == '"') + { + p++; + srch = '"'; + } + argv[x] = p; + x++; + p = strchr(p, srch); + if (p == NULL) + { + break; + } + else + { + *p = '\0'; + p++; + while (*p == ' ') p++; + if (*p == '\0') break; /* strip trailing blanks */ + } + } + argv[x] = NULL; + argc = x; + } + + *_Argc = argc; + *_Argv = argv; + *_Env = env; + return (0); +} +#endif + +#if defined(__CMS__) +int __start(char *plist, char *pgmname, char **eplist) +#elif defined(__VSE__) +int __start(char *p, char *pgmname, char *ep) +#elif defined(__MVS__) +int __start(char *p, char *pgmname, int tso) +#elif defined(__gnu_linux__) +int __start(int argc, char **argv) +#elif defined(__AMIGA__) +int __start(unsigned long cmdlen, char *p, void *pdosbase) +#elif defined(__EFI__) +int __start(void) +#elif defined(__SMALLERC__) +__PDPCLIB_API__ int CTYP __start(char *p, unsigned short osver) +#else +__PDPCLIB_API__ int CTYP __start(char *p) +#endif +{ +#ifdef __CMS__ + char *p; +#endif +#ifdef __EFI__ + char *p = ""; +#endif + int x; + int oldglobrc = globrc; + jmp_buf oldjb; +#if !defined(__gnu_linux__) + int argc; + static char *argv[MAXPARMS + 1]; +#endif + int rc; +#ifdef __AMIGA__ + struct Library *library; +#endif +#ifdef __OS2__ + ULONG maxFH; + LONG reqFH; +#endif +#ifdef __MSDOS__ + unsigned char *env; + unsigned char *nclsave; +#endif +#if defined(__MVS__) || defined(__CMS__) || defined(__VSE__) + int parmLen; + int progLen; + char parmbuf[310]; /* z/VSE can have a PARM up to 300 characters */ +#endif + +#if !defined(__MVS__) && !defined(__CMS__) && !defined(__VSE__) + + runnum++; + memcpy(&oldjb, &jb, sizeof oldjb); +#ifdef __AMIGA__ + if (cmdlen >= 0x80000000UL) + { + cmdlen -= 0x80000000UL; + SysBase = (struct ExecBase *)pdosbase; + } + else + { + SysBase = *(struct ExecBase **)4; + } + if (cmdlen > 0) + { + cmdlen--; + } + p[(size_t)cmdlen] = '\0'; + argv[0] = "UNKNOWN"; + DOSBase = NULL; + library = (struct Library *)SysBase->LibList.lh_Head; + while (library != NULL) + { + if (strcmp(library->lib_Node.ln_Name, "dos.library") == 0) + { + DOSBase = library; + break; + } + library = (struct Library *)library->lib_Node.ln_Succ; + } + if (DOSBase == NULL) + { + return (-1); + } +#endif + +#ifdef __WIN32__ + if (runnum == 1) + { + __stdin->hfile = GetStdHandle(STD_INPUT_HANDLE); + { + DWORD dw; + +#ifndef ENABLE_VIRTUAL_TERMINAL_INPUT +#define ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200 +#endif + if (GetConsoleMode(__stdin->hfile, &stdin_dw)) + { + dw = stdin_dw; + dw |= ENABLE_VIRTUAL_TERMINAL_INPUT; + SetConsoleMode(__stdin->hfile, dw); + } + } + __stdout->hfile = GetStdHandle(STD_OUTPUT_HANDLE); + { + DWORD dw; + +#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING +#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 +#endif + if (GetConsoleMode(__stdout->hfile, &stdout_dw)) + { + dw = stdout_dw; + dw |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + dw |= ENABLE_PROCESSED_OUTPUT; + SetConsoleMode(__stdout->hfile, dw); + } + } + __stderr->hfile = GetStdHandle(STD_ERROR_HANDLE); + } +#elif defined(__AMIGA__) + __stdin->hfile = Input(); + __stdout->hfile = Output(); + __stderr->hfile = Output(); +#else + __stdin->hfile = 0; + __stdout->hfile = 1; + __stderr->hfile = 2; +#endif + +#if defined(__PDOS386__) + PosGetDeviceInformation(0, &stdin_dw); + stdin_dw &= 0xff; +#endif + +#if defined(__gnu_linux__) + if (runnum == 1) + { + __ioctl(0, TCGETS, (unsigned long)&tios_save); + tios_new = tios_save; + tios_new.c_iflag &= ~IXON; + tios_new.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG); + __ioctl(0, TCSETS, (unsigned long)&tios_new); + } +#endif + + if (runnum == 1) + { + __stdin->quickBin = 0; + __stdin->quickText = 0; + __stdin->textMode = 1; + __stdin->intFno = 0; + __stdin->bufStartR = 0; + __stdin->justseeked = 0; + __stdin->bufTech = _IOLBF; + __stdin->intBuffer = buffer1; + __stdin->fbuf = __stdin->intBuffer + 2; + *__stdin->fbuf++ = '\0'; + *__stdin->fbuf++ = '\0'; + __stdin->szfbuf = BUFSIZ; + __stdin->endbuf = __stdin->fbuf + __stdin->szfbuf; + *__stdin->endbuf = '\n'; + __stdin->noNl = 0; + __stdin->upto = __stdin->endbuf; + __stdin->bufStartR = -__stdin->szfbuf; + __stdin->mode = __READ_MODE; + __stdin->ungetCh = -1; + __stdin->update = 0; + __stdin->theirBuffer = 0; + __stdin->permfile = 1; + __stdin->isopen = 1; + + __stdout->quickBin = 0; + __stdout->quickText = 0; + __stdout->textMode = 1; + __stdout->bufTech = _IOLBF; + __stdout->intBuffer = buffer2; + __stdout->fbuf = __stdout->intBuffer; + *__stdout->fbuf++ = '\0'; + *__stdout->fbuf++ = '\0'; + __stdout->szfbuf = BUFSIZ; + __stdout->endbuf = __stdout->fbuf + __stdout->szfbuf; + *__stdout->endbuf = '\n'; + __stdout->noNl = 0; + __stdout->upto = __stdout->fbuf; + __stdout->bufStartR = 0; + __stdout->justseeked = 0; + __stdout->mode = __WRITE_MODE; + __stdout->update = 0; + __stdout->theirBuffer = 0; + __stdout->permfile = 1; + __stdout->isopen = 1; + + __stderr->quickBin = 0; + __stderr->quickText = 0; + __stderr->textMode = 1; + __stderr->bufTech = _IOLBF; + __stderr->intBuffer = buffer3; + __stderr->fbuf = __stderr->intBuffer; + *__stderr->fbuf++ = '\0'; + *__stderr->fbuf++ = '\0'; + __stderr->szfbuf = BUFSIZ; + __stderr->endbuf = __stderr->fbuf + __stderr->szfbuf; + *__stderr->endbuf = '\n'; + __stderr->noNl = 0; + __stderr->upto = __stderr->fbuf; + __stderr->bufStartR = 0; + __stderr->justseeked = 0; + __stderr->mode = __WRITE_MODE; + __stderr->update = 0; + __stderr->theirBuffer = 0; + __stderr->permfile = 1; + __stderr->isopen = 1; + +#if USE_MEMMGR + memmgrDefaults(&__memmgr); + memmgrInit(&__memmgr); +#endif + } + +#else + int dyna_sysprint = 0; + int dyna_systerm = 0; + int dyna_sysin = 0; +#if defined(__CMS__) +/* + This code checks to see if DDs exist for SYSIN, SYSPRINT & SYSTERM + if not it issues FD to the terminal +*/ + char s202parm [800]; /* svc 202 buffer */ + int code; + int parm; + int ret; + int have_sysparm; + + runnum++; + memcpy(&oldjb, &jb, sizeof oldjb); +/* + Now build the SVC 202 string for sysprint +*/ + memcpy ( &s202parm[0] , "FILEDEF ", 8); + memcpy ( &s202parm[8] , "SYSPRINT", 8); + memcpy ( &s202parm[16] , "( ", 8); + memcpy ( &s202parm[24] , "NOCHANGE", 8); + s202parm[32]=s202parm[33]=s202parm[34]=s202parm[35]= + s202parm[36]=s202parm[37]=s202parm[38]=s202parm[39]=0xff; +/* + and issue the SVC +*/ + ret = __SVC202 ( s202parm, &code, &parm ); + if (ret == 24) + { /* we need to issue filedef */ + memcpy ( &s202parm[16] , "TERM ", 8); + memcpy ( &s202parm[24] , "( ", 8); + memcpy ( &s202parm[32] , "LRECL ", 8); + memcpy ( &s202parm[40] , "80 ", 8); + memcpy ( &s202parm[48] , "RECFM ", 8); + memcpy ( &s202parm[56] , "F ", 8); + s202parm[64]=s202parm[65]=s202parm[66]=s202parm[67]= + s202parm[68]=s202parm[69]=s202parm[70]=s202parm[71]=0xff; + + ret = __SVC202 ( s202parm, &code, &parm ); + dyna_sysprint = 1; + } + +/* + Now build the SVC 202 string for systerm +*/ + memcpy ( &s202parm[0] , "FILEDEF ", 8); + memcpy ( &s202parm[8] , "SYSTERM ", 8); + memcpy ( &s202parm[16] , "( ", 8); + memcpy ( &s202parm[24] , "NOCHANGE", 8); + s202parm[32]=s202parm[33]=s202parm[34]=s202parm[35]= + s202parm[36]=s202parm[37]=s202parm[38]=s202parm[39]=0xff; +/* + and issue the SVC +*/ + ret = __SVC202 ( s202parm, &code, &parm ); + if (ret == 24) + { /* we need to issue filedef */ + memcpy ( &s202parm[16] , "TERM ", 8); + memcpy ( &s202parm[24] , "( ", 8); + memcpy ( &s202parm[32] , "LRECL ", 8); + memcpy ( &s202parm[40] , "80 ", 8); + memcpy ( &s202parm[48] , "RECFM ", 8); + memcpy ( &s202parm[56] , "F ", 8); + s202parm[64]=s202parm[65]=s202parm[66]=s202parm[67]= + s202parm[68]=s202parm[69]=s202parm[70]=s202parm[71]=0xff; + + ret = __SVC202 ( s202parm, &code, &parm ); + dyna_systerm = 1; + } + +/* + Now build the SVC 202 string for sysin +*/ + memcpy ( &s202parm[0] , "FILEDEF ", 8); + memcpy ( &s202parm[8] , "SYSIN ", 8); + memcpy ( &s202parm[16] , "( ", 8); + memcpy ( &s202parm[24] , "NOCHANGE", 8); + s202parm[32]=s202parm[33]=s202parm[34]=s202parm[35]= + s202parm[36]=s202parm[37]=s202parm[38]=s202parm[39]=0xff; +/* + and issue the SVC +*/ + ret = __SVC202 ( s202parm, &code, &parm ); + + if (ret == 24) + { /* we need to issue filedef */ + memcpy ( &s202parm[16] , "TERM ", 8); + memcpy ( &s202parm[24] , "( ", 8); + memcpy ( &s202parm[32] , "LRECL ", 8); + memcpy ( &s202parm[40] , "80 ", 8); + memcpy ( &s202parm[48] , "RECFM ", 8); + memcpy ( &s202parm[56] , "F ", 8); + s202parm[64]=s202parm[65]=s202parm[66]=s202parm[67]= + s202parm[68]=s202parm[69]=s202parm[70]=s202parm[71]=0xff; + + ret = __SVC202 ( s202parm, &code, &parm ); + dyna_sysin = 1; + } + +#else /* not CMS */ + runnum++; + memcpy(&oldjb, &jb, sizeof oldjb); +#endif + +#if USE_MEMMGR + memmgrDefaults(&__memmgr); + memmgrInit(&__memmgr); +#endif +#if 0 /* MUSIC */ + /* switch on lowercasing of input */ + /* normal MUSIC default is to uppercase, and it's probably + better to let the user control that with the /TEXT LC + command instead */ + __textlc(); +#endif +#if defined(__MVS__) + /* need to know if this is a TSO environment straight away + because it determines how the permanent files will be + opened */ + parmLen = ((unsigned int)p[0] << 8) | (unsigned int)p[1]; +#if 1 /* traditional way of checking to see if it is TSO */ + if ((parmLen > 0) && (p[2] == 0)) /* assume TSO */ + { + __tso = 1; + } +#else + __tso = (tso != 0); /* even "CALL" is considered to be TSO */ +#endif + +#endif /* MVS */ + __doperm = 1; + __stdout = fopen("dd:SYSPRINT", "w"); + if (__stdout == NULL) + { + __exita(EXIT_FAILURE); + } + __stdout->dynal = dyna_sysprint; + + __stderr = fopen("dd:SYSTERM", "w"); + if (__stderr == NULL) + { + printf("SYSTERM DD not defined\n"); + fclose(__stdout); + __exita(EXIT_FAILURE); + } + __stderr->dynal = dyna_systerm; + + __stdin = fopen("dd:SYSIN", "r"); + if (__stdin == NULL) + { + fprintf(__stderr, "SYSIN DD not defined\n"); + fclose(__stdout); + fclose(__stderr); + __exita(EXIT_FAILURE); + } + __stdin->dynal = dyna_sysin; + __doperm = 0; +#if defined(__CMS__) + __eplist = eplist; + __plist = plist; + + if (plist[0] == '\xff') /* are we at the fence already? */ + { + p = plist; /* yes, this is also the start of the plist */ + } + else + { + p = plist + 8; /* no, so jump past the command name */ + } + + /* Now build the SVC 202 string for sysparm */ + memcpy ( &s202parm[0] , "FILEDEF ", 8); + memcpy ( &s202parm[8] , "SYSPARM ", 8); + memcpy ( &s202parm[16] , "( ", 8); + memcpy ( &s202parm[24] , "NOCHANGE", 8); + s202parm[32]=s202parm[33]=s202parm[34]=s202parm[35]= + s202parm[36]=s202parm[37]=s202parm[38]=s202parm[39]=0xff; + /* and issue the SVC */ + ret = __SVC202 ( s202parm, &code, &parm ); + + have_sysparm = (ret != 24); + + + /* if no parameters are provided, the tokenized + plist will start with x'ff'. However, if they + have provided a SYSPARM, then we'll use that + as the parameter. But only if they haven't + provided any parameters! If they have provided + parameters then we instead lowercase everything + and go to special processing (useful when in + an EXEC with CONTROL MSG etc). */ + + /* No parameters */ + if (p[0] == 0xff) + { + parmLen = 0; + + if (have_sysparm) + { + FILE *pf; + + /* have a parameter file - let's use it */ + pf = fopen("dd:SYSPARM", "r"); + if (pf != NULL) + { + fgets(parmbuf + 2, sizeof parmbuf - 2, pf); + fclose(pf); + p = strchr(parmbuf + 2, '\n'); + if (p != NULL) + { + *p = '\0'; + } + parmLen = strlen(parmbuf + 2); + } + } + } + /* If there is no EPLIST, or there is a SYSPARM so + they are invoking special processing, then we + will be using the PLIST only. */ + else if ((eplist == NULL) || have_sysparm) + { + /* copy across the tokenized plist, which + consists of 8 character chunks, space-padded, + and terminated by x'ff'. Note that the first + 2 characters of parmbuf are reserved for an + (unused) length, so we must skip them */ + for (x = 0; x < sizeof parmbuf / 9 - 1; x++) + { + if (p[x * 8] == 0xff) break; + memcpy(parmbuf + 2 + x * 9, p + x * 8, 8); + parmbuf[2 + x * 9 + 8] = ' '; + } + parmbuf[2 + x * 9] = '\0'; + parmLen = strlen(parmbuf + 2); + + /* even though we have a SYSPARM, we don't use it, + we just use it as a signal to do some serious + underscore searching! */ + if (have_sysparm) + { + char *q; + char *r; + char *lock; + int cnt = 0; + int c; + int shift = 0; + int rev = 0; /* reverse logic */ + + q = parmbuf + 2; + r = q; + lock = q; + + /* reverse the case switching when _+ is specified + as the first parameter */ + if (memcmp(r, "_+", 2) == 0) + { + rev = 1; + cnt += 2; + r += 2; + } + while (*r != '\0') + { + cnt++; + if (rev) + { + c = toupper((unsigned char)*r); + } + else + { + c = tolower((unsigned char)*r); + } + if (shift && (c != ' ')) + { + if (rev) + { + c = tolower((unsigned char)*r); + } + else + { + c = toupper((unsigned char)*r); + } + shift = 0; + } + if (c == '_') + { + shift = 1; + } + /* if we've reached the inter-parameter space, then + collapse it - a space requires a shift */ + else if (cnt == 9) + { + while (q > lock) + { + q--; + if (*q != ' ') + { + q++; + lock = q; + break; + } + } + cnt = 0; + if (shift) + { + *q++ = ' '; + shift = 0; + } + } + else if (c != ' ') + { + *q++ = c; + } + r++; + } + *q = '\0'; + parmLen = strlen(parmbuf + 2); + } + } + /* else, we have an eplist, and no sysparm, so use that */ + else + { + parmLen = eplist[2] - eplist[1]; + /* 2 bytes reserved for an unused length, 1 byte for NUL */ + if (parmLen >= sizeof parmbuf - 2) + { + parmLen = sizeof parmbuf - 1 - 2; + } + memcpy(parmbuf + 2, eplist[1], parmLen); + } +#elif defined(__VSE__) + __upsi = pgmname[9]; /* we shouldn't really clump this */ + + if (ep != NULL) + { + ep = *(char **)ep; + } + /* The ep only has a genuine value if the top bit is set */ + if (((unsigned int)ep & 0x80000000) != 0) + { + /* it is a 24-bit address */ + ep = (char *)((unsigned int)ep & 0x00ffffff); + parmLen = *(short *)ep; + memcpy(parmbuf + 2, ep + 2, parmLen); + } + /* if no parm, use SYSPARM instead */ + else if (p[0] != 0) + { + /* in the special case of a "?", inspect the UPSI switches */ + if ((p[0] == 1) && (p[1] == '?')) + { + /* user is required to set all switches to 0. All + are reserved, except for the first one, which + says that the parameter will be read from SYSINPT */ + if (__upsi & 0x80) + { + fgets(parmbuf + 2, sizeof parmbuf - 2, __stdin); + p = strchr(parmbuf + 2, '\n'); + if (p != NULL) + { + *p = '\0'; + } + parmLen = strlen(parmbuf + 2); + } + else + { + parmLen = 0; + } + } + /* for all other parameter values, just use as-is */ + else + { + parmLen = p[0]; + memcpy(parmbuf + 2, p + 1, parmLen); + } + + } + /* otherwise there is no parm */ + else + { + parmLen = 0; + } +#else /* MVS etc */ + parmLen = ((unsigned int)p[0] << 8) | (unsigned int)p[1]; + if (parmLen >= sizeof parmbuf - 2) + { + parmLen = sizeof parmbuf - 1 - 2; + } + /* We copy the parameter into our own area because + the caller hasn't necessarily allocated room for + a terminating NUL, nor is it necessarily correct + to clobber the caller's area with NULs. */ + memcpy(parmbuf, p, parmLen + 2); +#endif + p = parmbuf; +#ifdef __MVS__ + if (__tso) +#else + if (0) +#endif + { + progLen = ((unsigned int)p[2] << 8) | (unsigned int)p[3]; + parmLen -= (progLen + 4); + argv[0] = p + 4; + p += (progLen + 4); + if (parmLen > 0) + { + *(p - 1) = '\0'; + } + else + { + *p = '\0'; + } + p[parmLen] = '\0'; + } + else /* batch or tso "call" */ + { + progLen = 0; + p += 2; + argv[0] = pgmname; + pgmname[8] = '\0'; + pgmname = strchr(pgmname, ' '); + if (pgmname != NULL) + { + *pgmname = '\0'; + } + if (parmLen > 0) + { + p[parmLen] = '\0'; + } + else + { + p = ""; + } + } +#endif /* defined(__MVS__) || defined(__CMS__) || defined(__VSE__) */ + + for (x=0; x < __NFILE; x++) + { + __userFiles[x] = NULL; + } + +#ifdef __PDPCLIB_DLL + return (0); +#endif + +#if defined(__PDOS386__) + /* PDOS-32 uses an API call returning the full command line string. */ + if (!__minstart) + { + p = PosGetCommandLine(); + __envptr = PosGetEnvBlock(); + } + else + { + /* PDOS itself is starting so no API calls should be used. */ + p = ""; + __envptr = NULL; + } +#endif + +#ifdef __WIN32__ + p = GetCommandLine(); + + /* kludge for presumed HX bug */ + if (strncmp(p, "C:\\COMMAND.COM /c", 17) == 0) + { + p += 17; + p += strspn(p, " "); + } +#endif + +#ifdef __OS2__ + reqFH = 0; + DosSetRelMaxFH(&reqFH, &maxFH); + if (maxFH < (FOPEN_MAX + 10)) + { + reqFH = FOPEN_MAX - maxFH + 10; + DosSetRelMaxFH(&reqFH, &maxFH); + } +#endif +#ifdef __OS2__ + argv[0] = p; + p += strlen(p) + 1; +#endif +#if defined(__WIN32__) || defined(__PDOS386__) + /* Windows and PDOS-32 get the full command line string. */ + argv[0] = p; + p = strchr(p, ' '); + if (p == NULL) + { + p = ""; + } + else + { + *p = '\0'; + p++; + } +#elif defined(__MSDOS__) + argv[0] = ""; + +#ifdef __SMALLERC__ + __envptr = (unsigned char *) + ((unsigned long)(*(unsigned short *)(p + 0x2c)) << 4); + __osver = osver; +#endif + + + if(__osver > 0x300) + { + env=__envptr; + if (env != NULL) + { + while (1) + { + if (*env++ == '\0' && *env++ == '\0') + { + if (*(unsigned short *)env != 0) + { + argv[0] = (char *)env + 2; + } + break; + } + } + } + } + + nclsave = newcmdline; + newcmdline = NULL; + if (p == NULL) + { + p = ""; + } + else + { + p = p + 0x80; + if (*p == 0x7f) + { + unsigned char *q; + + /* this is above the limits of the PSP, so CMDLINE + potentially has the whole command line, including + the command */ + q = getenv("CMDLINE"); + if (q != NULL) + { + q = strchr(q, ' '); + if (q != NULL) + { + q++; + newcmdline = malloc(strlen(q) + 1); + if (newcmdline != NULL) + { + strcpy(newcmdline, q); + p = newcmdline; + } + } + } + if (newcmdline == NULL) + { + fprintf(stderr, "command line too long to handle\n"); + newcmdline = nclsave; + if (runnum == 1) + { + __exit(EXIT_FAILURE); + } + runnum--; + return(EXIT_FAILURE); + } + } + else + { + p[*p + 1] = '\0'; + p++; + } + } +#endif +#if !defined(__gnu_linux__) + while (*p == ' ') + { + p++; + } + if (*p == '\0') + { + argv[1] = NULL; + argc = 1; + } + else + { + for (x = 1; x < MAXPARMS; ) + { + char srch = ' '; + + if (*p == '"') + { + p++; + srch = '"'; + } + argv[x] = p; + x++; + p = strchr(p, srch); + if (p == NULL) + { + break; + } + else + { + *p = '\0'; + p++; + while (*p == ' ') p++; + if (*p == '\0') break; /* strip trailing blanks */ + } + } + argv[x] = NULL; + argc = x; + } +#endif +#ifdef PDOS_MAIN_ENTRY + *i1 = argc; + *i2 = (int)argv; + return (0); +#elif defined(__PDPCLIB_DLL) + return (0); +#else + /* note that any executable (mainly one being used as a + pseudo-BIOS/HAL) can choose to export it's C library, + and in that case, the called program should not directly + call the OS's exit function, but should return here so + that this executable regains control. But exit() can be + called from anywhere. So we need to use setjmp and longjmp. + Note that the runnum increments for every invocation */ + + if (!__genstart) + { + rc = setjmp(jb); + if (rc != 0) + { + /* we're here because of longjmp */ + /* the invoker needs to set globrc first, otherwise + we can't distinguish a genuine return code */ + rc = globrc; + } + else + { + /* I'm not sure if we can eliminate this call to main + and always use genmain instead */ + rc = main(argc, argv); + } + } + else + { + rc = setjmp(jb); + if (rc != 0) + { + rc = globrc; + } + else + { + rc = __genmain(argc, argv); + } + } + globrc = oldglobrc; + memcpy(&jb, &oldjb, sizeof jb); + +#ifdef __MSDOS__ + if (newcmdline != NULL) + { + free(newcmdline); + } + newcmdline = nclsave; +#endif + if (runnum == 1) + { + __exit(rc); + } + runnum--; + return (rc); +#endif +} + +void _exit(int status); +void _cexit(void); +void _c_exit(void); + +void __exit(int status) +{ + /* Complete C library termination and exit with error code. */ + if (runnum == 1) + { + _cexit(); + } + +#ifdef __WIN32__ + ExitProcess(status); +#else + if (runnum == 1) + { + __exita(status); + /* in case exita returns here, which is the case for PDOS-generic + running under the pseudo-BIOS currently, decrement the run number + so that we don't get called again */ + runnum--; + /* and we can't go through another longjmp either */ + return; + } + globrc = status; + + longjmp(jb, status); + +#endif +} + +__PDPCLIB_API__ void _exit(int status) +{ + /* Quick C library termination and exit with error code.. */ + _c_exit(); + +#ifdef __WIN32__ + ExitProcess(status); +#else + __exita(status); +#endif +} + +__PDPCLIB_API__ void _cexit(void) +{ + /* Complete C library termination. */ + _c_exit(); +} + +__PDPCLIB_API__ void _c_exit(void) +{ + /* Quick C library termination. */ + int x; + +#if 0 + for (x = __NATEXIT - 1; x >= 0; x--) + { + if (__userExit[x] != 0) + { + (__userExit[x])(); + } + } +#endif + + for (x = 0; x < __NFILE; x++) + { + if (__userFiles[x] != NULL) + { +#if defined(__VSE__) + /* this should be closed after the rest of the user files */ + if (__userFiles[x] != __stdpch) +#endif + fclose(__userFiles[x]); + } + } + +#if defined(__VSE__) + if (__stdpch != NULL) fclose(__stdpch); +#endif + + if (__stdout != NULL) fflush(__stdout); + if (__stderr != NULL) fflush(__stderr); +#if defined(__WIN32__) + SetConsoleMode(__stdin->hfile, stdin_dw); + SetConsoleMode(__stdout->hfile, stdout_dw); +#endif + +#if defined(__PDOS386__) + PosSetDeviceInformation(0, stdin_dw); +#endif + +#if defined(__gnu_linux__) + if (runnum == 1) + { + __ioctl(0, TCSETS, (unsigned long)&tios_save); + } +#endif + +#if defined(__MVS__) || defined(__CMS__) || defined(__VSE__) + if (__stdin != NULL) fclose(__stdin); + if (__stdout != NULL) fclose(__stdout); + if (__stderr != NULL) fclose(__stderr); +#endif + + + if (runnum == 1) + { +#if USE_MEMMGR + memmgrTerm(&__memmgr); + +/* release memory for most circumstances, although a + better solution will be required eventually */ +#if defined(__MVS__) || defined(__CMS__) || defined(__VSE__) + if (__lastsup != NULL) + { + __freem(__lastsup); + } +#endif +#endif /* USE_MEMMGR */ + } +} + +#ifdef __WIN32__ +/* Windows extensions. */ +static int _fmode; +__PDPCLIB_API__ int *__p__fmode(void) +{ + /* Not sure what should this function do. */ + return (&_fmode); +} + +static char *_environ[] = {NULL}; +static char **_environ_ptr = _environ; +__PDPCLIB_API__ char ***__p__environ(void) +{ + /* Not sure what should this function do. */ + return (&_environ_ptr); +} + +__PDPCLIB_API__ void __set_app_type(int at) +{ + /* Not sure what should this function do. */ + ; +} + +__PDPCLIB_API__ int _setmode(int fd, int mode) +{ + /* Should change mode of file descriptor (fd) + * to mode (binary, text, Unicode...) + * and return the previous mode. + * We do not have _fileno() to convert FILE * + * to int and _fileno() can be implemented + * as macro accesing FILE internals..., + * so this function is just a dummy. */ + return (0); +} + +__PDPCLIB_API__ void (*_onexit(void (*func)(void)))(void) +{ + if (atexit(func)) return (NULL); + return (func); +} +#endif diff --git a/app/src/main/cpp/pdpclib/x86/stdarg.h b/app/src/main/cpp/pdpclib/x86/stdarg.h new file mode 100644 index 0000000..342ea40 --- /dev/null +++ b/app/src/main/cpp/pdpclib/x86/stdarg.h @@ -0,0 +1,60 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* stdarg.h - stdarg header file. */ +/* */ +/*********************************************************************/ + +#ifndef __STDARG_INCLUDED +#define __STDARG_INCLUDED + +/* don't use builtins on MVS until they have been implemented */ +/* don't use on EMX either */ +/* and they haven't been implemented in PDOS/386 either */ +#if 0 +if defined(__GNUC__) && !defined(__MVS__) && !defined(__CMS__) \ + && !defined(__VSE__) && !defined(__EMX__) && !defined(__PDOS386__) \ + && !defined(__gnu_linux__) && !defined(__NOBIVA__) \ + && !defined(__ARM__) +#endif + +/* Try only using builtins for GCC 4.x and above, which + appears to cover clang too */ +#if defined (__GNUC__) && __GNUC__ > 3 + +#ifndef __GNUC_VA_LIST +#define __GNUC_VA_LIST +typedef __builtin_va_list __gnuc_va_list; +#endif + +typedef __gnuc_va_list va_list; + +#define va_start(v,l) __builtin_va_start(v,l) +#define va_end(v) __builtin_va_end(v) +#define va_arg(v,l) __builtin_va_arg(v,l) +#if !defined(__STRICT_ANSI__) || __STDC_VERSION__ + 0 >= 199900L +#define va_copy(d,s) __builtin_va_copy(d,s) +#endif +#define __va_copy(d,s) __builtin_va_copy(d,s) + +#else /* __GNUC__ */ + +typedef char * va_list; + +#ifdef __XWATCOMC__ +#define va_start(ap, parmN) ap = (char far *)&parmN + sizeof(parmN) +#define va_arg(ap, type) *(type far *)(ap += sizeof(type), ap - sizeof(type)) +#else +#define va_start(ap, parmN) ap = (char *)&parmN + sizeof(parmN) +#define va_arg(ap, type) *(type *)(ap += sizeof(type), ap - sizeof(type)) +#endif +#define va_end(ap) ap = (char *)0 + +#endif + +#endif diff --git a/app/src/main/cpp/pdpclib/x86/stddef.h b/app/src/main/cpp/pdpclib/x86/stddef.h new file mode 100644 index 0000000..7a534ab --- /dev/null +++ b/app/src/main/cpp/pdpclib/x86/stddef.h @@ -0,0 +1,46 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* stddef.h - assert header file. */ +/* */ +/*********************************************************************/ + +#ifndef __STDDEF_INCLUDED +#define __STDDEF_INCLUDED + +typedef int ptrdiff_t; +#ifndef __SIZE_T_DEFINED +#define __SIZE_T_DEFINED +#if (defined(__OS2__) || defined(__32BIT__) || defined(__MVS__) \ + || defined(__CMS__) || defined(__VSE__) || defined(__SMALLERC__) \ + || defined(__ARM__) || defined(__gnu_linux__) || defined(__PDOS386__) \ + || defined(__SZ4__)) +typedef unsigned long size_t; +#elif (defined(__MSDOS__) || defined(__DOS__) || defined(__POWERC) \ + || defined(__WIN32__) || defined(__AMIGA__) || defined(__EFI__)) +typedef unsigned int size_t; +#endif +#endif +#ifndef __WCHAR_T_DEFINED +#define __WCHAR_T_DEFINED +#ifndef _WCHAR_T_DEFINED +#define _WCHAR_T_DEFINED +#endif +typedef char wchar_t; +#endif + +#define NULL ((void *)0) +#define offsetof(x, y) (size_t)&(((x *)0)->y) + +#ifdef __PDPCLIB_DLL +#define __PDPCLIB_API__ __declspec(dllexport) +#else +#define __PDPCLIB_API__ +#endif + +#endif diff --git a/app/src/main/cpp/pdpclib/x86/stdio.c b/app/src/main/cpp/pdpclib/x86/stdio.c new file mode 100644 index 0000000..f880d07 --- /dev/null +++ b/app/src/main/cpp/pdpclib/x86/stdio.c @@ -0,0 +1,6541 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/* Modifications by Dave Edwards, released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* stdio.c - implementation of stuff in stdio.h */ +/* */ +/* The philosophy of the PC/Unix/ASCII implementation is explained */ +/* here. For the MVS/CMS/EBCDIC implementation, see halfway down */ +/* this source file (or search for "design of MVS"). */ +/* */ +/* There is a static array containing pointers to file objects. */ +/* This is required in order to close all the files on program */ +/* termination. */ +/* */ +/* In order to give speed absolute priority, so that people don't */ +/* resort to calling DosRead themselves, there is a special flag */ +/* in the FILE object called "quickbin". If this flag is set to 1 */ +/* it means that it is a binary file and there is nothing in the */ +/* buffer and there are no errors, so don't stuff around, just call */ +/* DosRead. */ +/* */ +/* When a buffer exists, which is most of the time, fbuf will point */ +/* to it. The size of the buffer is given by szfbuf. upto will */ +/* point to the next character to be read. endbuf will point PAST */ +/* the last valid character in the buffer. bufStartR represents */ +/* the position in the file that the first character in the buffer */ +/* is at. This is only updated when a new buffer is read in. */ +/* */ +/* After file open, for a file being read, bufStartR will actually */ +/* be a negative number, which if added to the position of upto */ +/* will get to 0. On a file being written, bufStartR will be set */ +/* to 0, and upto will point to the start of the buffer. The */ +/* reason for the difference on the read is in order to tell the */ +/* difference between an empty buffer and a buffer with data in it, */ +/* but which hasn't been used yet. The alternative would be to */ +/* either keep track of a flag, or make fopen read in an initial */ +/* buffer. But we want to avoid reading in data that no-one has */ +/* yet requested. */ +/* */ +/* The buffer is organized as follows... */ +/* What we have is an internal buffer, which is 8 characters */ +/* longer than the actually used buffer. E.g. say BUFSIZ is */ +/* 512 bytes, then we actually allocate 520 bytes. The first */ +/* 2 characters will be junk, the next 2 characters set to NUL, */ +/* for protection against some backward-compares. The fourth-last */ +/* character is set to '\n', to protect against overscan. The */ +/* last 3 characters will be junk, to protect against memory */ +/* violation. intBuffer is the internal buffer, but everyone */ +/* refers to fbuf, which is actually set to the &intBuffer[4]. */ +/* Also, szfbuf is the size of the "visible" buffer, not the */ +/* internal buffer. The reason for the 2 junk characters at the */ +/* beginning is to align the buffer on a 4-byte boundary. */ +/* */ +/* On MVS/CMS/VSE/MUSIC, bufStartR is done differently. It starts */ +/* as 0, and fbuf, endbuf and upto are all set to the same */ +/* location - the start of the buffer. With no more data */ +/* available, a read is done, and endbuf changes according to the */ +/* size of the data read. If the application does an fread for */ +/* say 60 bytes when reading an F80 dataset, then 60 characters */ +/* will go directly into the user buffer, then the remaining */ +/* 20 bytes will go into the beginning of the internal buffer, so */ +/* the bufStartR will be adjusted to that fact, and upto and */ +/* fbuf will both point to the beginning, and endbuf will be an */ +/* additional 20 bytes ahead. */ +/* */ +/*********************************************************************/ + +#include "stdio.h" +#include "string.h" +#include "stdlib.h" +#include "stdarg.h" +#include "ctype.h" +#include "errno.h" +#include "float.h" +#include "limits.h" +#include "stddef.h" + +/* VSE is similar to MVS at the moment */ +#if defined(__VSE__) +#define __MVS__ 1 +#endif + +/* PDOS/386 and MSDOS use the same interface most of the time */ +/* Note that PDOS is for the 32-bit version, since the 16-bit + version uses the MSDOS version since it is compatible with it */ +/* linux is pretty similar too */ +#if defined(__PDOS386__) || defined(__gnu_linux__) || defined(__SMALLERC__) \ + || defined(__ARM__) +#define __MSDOS__ +#endif + +#if defined(__MSDOS__) && !defined(__gnu_linux__) && !defined(__ARM__) +#if defined(__WATCOMC__) && !defined(__32BIT__) +#define CTYP __cdecl +#else +#define CTYP +#endif +extern int CTYP __creat(const char *filename, int mode, int *errind); +extern int CTYP __open(const char *filename, int mode, int *errind); +extern int CTYP __read(int handle, void *buf, unsigned int len, int *errind); +extern int CTYP __write(int handle, const void *buf, unsigned int len, + int *errind); +extern int CTYP __seek(int handle, long offset, int whence); +extern void CTYP __close(int handle); +extern void CTYP __remove(const char *filename); +extern void CTYP __rename(const char *old, const char *newnam); +#endif + +#ifdef __AMIGA__ +#include +#endif + +#ifdef __EFI__ +#include "efi.h" +#endif + +#ifdef __OS2__ +#include +#endif + +#ifdef __WIN32__ +#include +#endif + +#if defined(__MVS__) || defined(__CMS__) +#include "mvssupa.h" +#define FIXED_BINARY 0 +#define VARIABLE_BINARY 1 +#define FIXED_TEXT 2 +#define VARIABLE_TEXT 3 +#endif + +#if defined(__gnu_linux__) || defined(__ARM__) + +extern int __open(const char *a, int b, int c); +extern int __write(int a, const void *b, int c); +extern int __read(int a, void *b, int c); +extern int __seek(int handle, long offset, int whence); +extern void __close(int handle); +extern void __remove(const char *filename); +extern void __rename(const char *old, const char *newnam); + +#define O_RDONLY 0x0 +#define O_WRONLY 0x1 +#define O_RDWR 0x2 +#define O_CREAT 0x40 +#define O_TRUNC 0x200 + +static int open(const char *a, int b, int *c) +{ + int ret = -1; + + *c = 0; + if (b == 2) + { + ret = __open(a, O_RDWR, 0); + } + else if (b == 1) + { + ret = __open(a, O_WRONLY | O_CREAT | O_TRUNC, 0664); + } + else if (b == 0) + { + ret = __open(a, O_RDONLY, 0); + } + if (ret < 0) + { + *c = 1; + } + return (ret); +} + +#define __open(a,b,c) (open((a),(b),(c))) +#define __write(a,b,c,d) (*(d) = 0, (__write)((a),(b),(c))) +#define __read(a,b,c,d) (*(d) = 0, (__read)((a),(b),(c))) + +#endif + +static FILE permFiles[3]; + +#define unused(x) ((void)(x)) +#define outch(ch) ((fq == NULL) ? *s++ = (char)ch : putc(ch, fq)) +#define inch() ((fp == NULL) ? \ + (ch = (unsigned char)*s++) : (ch = getc(fp))) + +/* We need to choose whether we are doing move mode or + locate mode */ +#if !LOCMODE /* move mode */ + + +#if defined(__VSE__) + +/* for VSE, library files are actually written to memory + during processing */ + +#define lbegwrite(stream, len) \ + ( \ + ((stream)->vselupto + (len) > (stream->vselend)) ? \ + (lenwrite = 0, dptr = NULL) : \ + (lenwrite = (len), dptr = (unsigned char *)(stream)->vselupto) \ + ) +#define lfinwrite(stream) (((stream)->vselupto += lenwrite), lenwrite) + +#define vbegwrite(stream, len) (lenwrite = (len), dptr = (stream)->asmbuf) +#define vfinwrite(stream) (__awrite((stream)->hfile, &dptr, &lenwrite)) + +#define begwrite(stream, len) ((stream)->vse_punch ? \ + lbegwrite((stream), (len)) : vbegwrite((stream), (len))) +#define finwrite(stream) ((stream)->vse_punch ? \ + lfinwrite(stream) : vfinwrite(stream)) + +#else +#define begwrite(stream, len) (lenwrite = (len), dptr = (stream)->asmbuf) +#define finwrite(stream) (__awrite((stream)->hfile, &dptr, &lenwrite)) +#endif + +#else /* locate mode */ +#define begwrite(stream, len) (lenwrite = (len), \ + __awrite((stream)->hfile, &dptr, &lenwrite)) +#define finwrite(stream) +#endif + +#if defined(__MVS__) || defined(__CMS__) +int __doperm = 0; /* are we doing the permanent datasets? */ +extern int __tso; /* are we in a TSO environment? */ +static unsigned char *dptr; +static size_t lenwrite; +static int inseek = 0; +static size_t lenread; +#define __aread(a,b) ((__aread)((a),(b),&lenread)) +#endif + + +FILE *__stdin_ptr = &permFiles[0]; +FILE *__stdout_ptr = &permFiles[1]; +FILE *__stderr_ptr = &permFiles[2]; + +FILE *__userFiles[__NFILE]; +static FILE *myfile; +static int spareSpot; +static int err; +static int inreopen = 0; + +#if defined(__VSE__) +/* for VSE library files being punched */ +#define VSE_LIB_LIM 1000000 +static char *__vsepb = NULL; +FILE *__stdpch = NULL; +#endif + +static const char *fnm; +static const char *modus; +static int modeType; + +__PDPCLIB_API__ FILE **__gtin() + { return(&__stdin_ptr); } +__PDPCLIB_API__ FILE **__gtout() + { return(&__stdout_ptr); } +__PDPCLIB_API__ FILE **__gterr() + { return(&__stderr_ptr); } + +#if defined(__WIN32__) && !defined(__STATIC__) +__PDPCLIB_API__ __DUMMYFILE _iob[3]; +#endif + +static void dblcvt(double num, char cnvtype, size_t nwidth, + int nprecision, char *result); +static int vvprintf(const char *format, va_list arg, FILE *fq, char *s); +static int vvscanf(const char *format, va_list arg, FILE *fp, const char *s); +static void fopen2(void); +static void fopen3(void); +static void findSpareSpot(void); +static void checkMode(void); +static void osfopen(void); + +#if !defined(__MVS__) && !defined(__CMS__) +static void fwriteSlow(const void *ptr, + size_t size, + size_t nmemb, + FILE *stream, + size_t towrite, + size_t *elemWritten); +static void fwriteSlowT(const void *ptr, + FILE *stream, + size_t towrite, + size_t *actualWritten); +static void fwriteSlowB(const void *ptr, + FILE *stream, + size_t towrite, + size_t *actualWritten); +static void freadSlowT(void *ptr, + FILE *stream, + size_t toread, + size_t *actualRead); +static void freadSlowB(void *ptr, + FILE *stream, + size_t toread, + size_t *actualRead); +#endif + +static int examine(const char **formt, FILE *fq, char *s, va_list *arg, + int chcount); + +#if defined(__CMS__) || defined(__MVS__) +static void filedef(char *fdddname, char *fnm, int mymode); +static void fdclr(char *ddname); +#endif +#ifdef __CMS__ +extern void __SVC202 ( char *s202parm, int *code, int *parm ); +static int cmsrename(const char *old, const char *newnam); +static int cmsremove(const char *filename); +static char *int_strtok(char *s1, const char *s2); +#define strtok int_strtok +#endif + + +__PDPCLIB_API__ int printf(const char *format, ...) +{ + va_list arg; + int ret; + + va_start(arg, format); + ret = vfprintf(__stdout, format, arg); + va_end(arg); + return (ret); +} + +__PDPCLIB_API__ int fprintf(FILE *stream, const char *format, ...) +{ + va_list arg; + int ret; + + stream = __INTFILE(stream); + + va_start(arg, format); + ret = vfprintf(stream, format, arg); + va_end(arg); + return (ret); +} + +__PDPCLIB_API__ int vfprintf(FILE *stream, const char *format, va_list arg) +{ + int ret; + + stream = __INTFILE(stream); + + stream->quickText = 0; + ret = vvprintf(format, arg, stream, NULL); + return (ret); +} + +__PDPCLIB_API__ int vprintf(const char *format, va_list arg) +{ + int ret; + + ret = vfprintf(stdout, format, arg); + return (ret); +} + +__PDPCLIB_API__ FILE *fopen(const char *filename, const char *mode) +{ +#if defined(__VSE__) + char *p; + char *q; + char memname[9]; + int memlen; + char phase[80]; + + /* for VSE, we cannot write directly to a library, we + instead need to punch appropriate controls */ + /* note that both w and wb are treated the same */ + if ((*mode == 'w') && ((p = strchr(filename, '(')) != NULL)) + { + q = strchr(filename, ')'); + if (q <= p) return (NULL); + memlen = q - p - 1; + if (memlen > (sizeof memname - 1)) + { + memlen = (sizeof memname - 1); + } + memcpy(memname, p + 1, memlen); + memname[memlen] = '\0'; + for (p = memname; *p != '\0'; p++) + { + *p = toupper((unsigned char)*p); + } + if (__stdpch == NULL) + { + __vsepb = malloc(VSE_LIB_LIM + 4); + if (__vsepb == NULL) return (NULL); + __stdpch = fopen("dd:syspunch", "wb"); + if (__stdpch != NULL) + { + __stdpch->vse_punch = 2; + __stdpch->vselupto = __vsepb; + __stdpch->vselend = __vsepb + VSE_LIB_LIM; + __stdpch->reallyu = 1; + } + } + if (__stdpch != NULL) + { + __stdpch->vse_punch = 0; + memset(phase, ' ', sizeof phase); + sprintf(phase, " PHASE %s,*", memname); + phase[strlen(phase)] = ' '; + fwrite(phase, 1, sizeof phase, __stdpch); + __stdpch->vse_punch = 2; /* in an active file */ + } + return (__stdpch); + } +#endif + + fnm = filename; + modus = mode; + err = 0; + if (!inreopen) + { + myfile = malloc(sizeof(FILE)); + } + if (myfile == NULL) + { + err = 1; + } + else + { + if (!inreopen) + { + myfile->permfile = 0; + } +#if defined(__MVS__) || defined(__CMS__) + if (__doperm) + { + myfile->permfile = 1; + } +#endif + if (inreopen) + { + spareSpot = myfile->intFno; + } + else if (!myfile->permfile) + { + findSpareSpot(); + } + if (!err) + { + fopen2(); + } + if (err && !inreopen) + { + free(myfile); + } + } + if (err && !inreopen) + { + myfile = NULL; + } +#if defined(__VSE__) + else + { + myfile->vse_punch = 0; + } +#endif + return (myfile); +} + +static void fopen2(void) +{ + checkMode(); + if (!err) + { + strcpy(myfile->modeStr, modus); + osfopen(); + if (!err) + { + if (myfile->permfile) + { + myfile->intFno = 0; + } + else + { + __userFiles[spareSpot] = myfile; + myfile->intFno = spareSpot; + } + fopen3(); + } + } + return; +} + +static void fopen3(void) +{ + myfile->intBuffer = malloc(BUFSIZ + 8); + if (myfile->intBuffer == NULL) + { + err = 1; + } + else + { + myfile->theirBuffer = 0; + myfile->fbuf = myfile->intBuffer + 2; + *myfile->fbuf++ = '\0'; + *myfile->fbuf++ = '\0'; + myfile->szfbuf = BUFSIZ; +#if !defined(__MVS__) && !defined(__CMS__) + myfile->quickText = 0; +#endif + myfile->noNl = 0; + myfile->endbuf = myfile->fbuf + myfile->szfbuf; + *myfile->endbuf = '\n'; +#if defined(__MVS__) || defined(__CMS__) + myfile->upto = myfile->fbuf; + myfile->szfbuf = myfile->lrecl; + myfile->endbuf = myfile->fbuf; /* for read only */ +#else + myfile->upto = myfile->endbuf; +#endif +#if defined(__MVS__) || defined(__CMS__) + myfile->bufStartR = 0; +#else + myfile->bufStartR = -(long)myfile->szfbuf; +#endif + myfile->justseeked = 0; + if (myfile->permfile) + { + myfile->bufTech = _IOLBF; + } + else + { + myfile->bufTech = _IOFBF; + } + myfile->errorInd = 0; + myfile->eofInd = 0; + myfile->istemp = 0; + myfile->ungetCh = -1; + myfile->update = 0; + myfile->isopen = 1; +#if !defined(__MVS__) && !defined(__CMS__) + if (!myfile->textMode) + { + myfile->quickBin = 1; + } + else + { + myfile->quickBin = 0; + } +#endif + myfile->mode = __READ_MODE; + /* gccerm, but not gccarm, seems to have a problem with this + switch */ + switch (modeType) + { + case 2: + case 5: + case 8: + case 11: + myfile->bufStartR = 0; + myfile->upto = myfile->fbuf; + myfile->mode = __WRITE_MODE; +#if defined(__MVS__) || defined(__CMS__) + myfile->endbuf = myfile->fbuf + myfile->szfbuf; +#endif + break; + } + switch (modeType) + { + case 3: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + myfile->update = 1; + myfile->quickBin = 0; + myfile->justseeked = 1; + break; + } + switch (modeType) + { + case 3: + case 6: + case 9: + case 12: + myfile->quickBin = 0; + fseek(myfile, 0, SEEK_END); + break; + } + } + return; +} + +static void findSpareSpot(void) +{ + int x; + + for (x = 0; x < __NFILE; x++) + { + if (__userFiles[x] == NULL) + { + break; + } + } + if (x == __NFILE) + { + err = 1; + } + else + { + spareSpot = x; + } + return; +} + +/* checkMode - interpret mode string */ +/* r = 1 */ +/* w = 2 */ +/* a = 3 */ +/* rb = 4 */ +/* wb = 5 */ +/* ab = 6 */ +/* r+ = 7 */ +/* w+ = 8 */ +/* a+ = 9 */ +/* r+b or rb+ = 10 */ +/* w+b or wb+ = 11 */ +/* a+b or ab+ = 12 */ + +static void checkMode(void) +{ + if (strncmp(modus, "r+b", 3) == 0) + { + modeType = 10; + } + else if (strncmp(modus, "rb+", 3) == 0) + { + modeType = 10; + } + else if (strncmp(modus, "w+b", 3) == 0) + { + modeType = 11; + } + else if (strncmp(modus, "wb+", 3) == 0) + { + modeType = 11; + } + else if (strncmp(modus, "a+b", 3) == 0) + { + modeType = 12; + } + else if (strncmp(modus, "ab+", 3) == 0) + { + modeType = 12; + } + else if (strncmp(modus, "r+", 2) == 0) + { + modeType = 7; + } + else if (strncmp(modus, "w+", 2) == 0) + { + modeType = 8; + } + else if (strncmp(modus, "a+", 2) == 0) + { + modeType = 9; + } + else if (strncmp(modus, "rb", 2) == 0) + { + modeType = 4; + } + else if (strncmp(modus, "wb", 2) == 0) + { + modeType = 5; + } + else if (strncmp(modus, "ab", 2) == 0) + { + modeType = 6; + } + else if (strncmp(modus, "r", 1) == 0) + { + modeType = 1; + } + else if (strncmp(modus, "w", 1) == 0) + { + modeType = 2; + } + else if (strncmp(modus, "a", 1) == 0) + { + modeType = 3; + } + else + { + err = 1; + return; + } + if ((modeType == 4) + || (modeType == 5) + || (modeType == 6) + || (modeType == 10) + || (modeType == 11) + || (modeType == 12)) + { + myfile->textMode = 0; + } + else + { + myfile->textMode = 1; + } + return; +} + +static void osfopen(void) +{ +#ifdef __AMIGA__ + int mode; + + if ((modeType == 1) || (modeType == 4) + || (modeType == 7) || (modeType == 10)) + { + mode = 0; /* read */ + } + else if ((modeType == 2) || (modeType == 5) + || (modeType == 8) || (modeType == 11)) + { + mode = 1; /* write */ + } + else + { + mode = 2; /* append or otherwise unsupported */ + /* because we don't have append mode implemented + at the moment on AMIGA, just return with an + error immediately */ + err = 1; + errno = 2; + return; + } + if (mode) + { + myfile->hfile = Open(fnm, MODE_NEWFILE); + } + else + { + myfile->hfile = Open(fnm, MODE_OLDFILE); + } + if (myfile->hfile == NULL) + { + err = 1; + errno = 1; + } +#endif +#ifdef __OS2__ + APIRET rc; + ULONG action; + ULONG newsize = 0; + ULONG fileAttr = 0; + ULONG openAction = 0; + ULONG openMode = 0; + + if ((modeType == 1) || (modeType == 4) || (modeType == 7) + || (modeType == 10)) + { + openAction |= OPEN_ACTION_FAIL_IF_NEW; + openAction |= OPEN_ACTION_OPEN_IF_EXISTS; + } + else if ((modeType == 2) || (modeType == 5) || (modeType == 8) + || (modeType == 11)) + { + openAction |= OPEN_ACTION_CREATE_IF_NEW; + openAction |= OPEN_ACTION_REPLACE_IF_EXISTS; + } + else if ((modeType == 3) || (modeType == 6) || (modeType == 9) + || (modeType == 12)) + { + openAction |= OPEN_ACTION_CREATE_IF_NEW; + openAction |= OPEN_ACTION_OPEN_IF_EXISTS; + } + openMode |= OPEN_SHARE_DENYWRITE; + if ((modeType == 1) || (modeType == 4)) + { + openMode |= OPEN_ACCESS_READONLY; + } + else if ((modeType == 2) || (modeType == 3) || (modeType == 5) + || (modeType == 6)) + { + openMode |= OPEN_ACCESS_WRITEONLY; + } + else + { + openMode |= OPEN_ACCESS_READWRITE; + } + if ((strlen(fnm) == 2) + && (fnm[1] == ':') + && (openMode == OPEN_ACCESS_READONLY)) + { + openMode |= OPEN_FLAGS_DASD; + } + rc = DosOpen((PSZ)fnm, + &myfile->hfile, + &action, + newsize, + fileAttr, + openAction, + openMode, + NULL); + if (rc != 0) + { + err = 1; + errno = rc; + } +#endif +#ifdef __WIN32__ + DWORD dwDesiredAccess = 0; + DWORD dwShareMode = FILE_SHARE_READ; + DWORD dwCreationDisposition = 0; + DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL; + + if ((modeType == 1) || (modeType == 4) || (modeType == 7) + || (modeType == 10)) + { + dwCreationDisposition = OPEN_EXISTING; + } + else if ((modeType == 2) || (modeType == 5) || (modeType == 8) + || (modeType == 11)) + { + dwCreationDisposition = CREATE_ALWAYS; + } + else if ((modeType == 3) || (modeType == 6) || (modeType == 9) + || (modeType == 12)) + { + dwCreationDisposition = OPEN_EXISTING; + } + if ((modeType == 1) || (modeType == 4)) + { + dwDesiredAccess = GENERIC_READ; + } + else if ((modeType == 2) || (modeType == 5)) + { + dwDesiredAccess = GENERIC_WRITE; + } + else + { + dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; + } + myfile->hfile = CreateFile(fnm, + dwDesiredAccess, + dwShareMode, + NULL, + dwCreationDisposition, + dwFlagsAndAttributes, + NULL); + if ((myfile->hfile == INVALID_HANDLE_VALUE) + && ((modeType == 3) || (modeType == 6) + || (modeType == 9) || (modeType == 12))) + { + dwCreationDisposition = CREATE_ALWAYS; + myfile->hfile = CreateFile(fnm, + dwDesiredAccess, + dwShareMode, + NULL, + dwCreationDisposition, + dwFlagsAndAttributes, + NULL); + } + if (myfile->hfile == INVALID_HANDLE_VALUE) + { + err = 1; + errno = GetLastError(); + } +#endif +#ifdef __MSDOS__ + int mode; + int errind; + + if ((modeType == 1) || (modeType == 4) + || (modeType == 7) || (modeType == 10) + || (modeType == 3) || (modeType == 6) + || (modeType == 9) || (modeType == 12)) + { + mode = 0; /* read */ + } + else if ((modeType == 2) || (modeType == 5) + || (modeType == 8) || (modeType == 11)) + { + mode = 1; /* write */ + } + else + { + err = 1; + errno = 2; + return; + } + if (mode) + { +#if defined(__gnu_linux__) || defined(__ARM__) + myfile->hfile = __open(fnm, 1, &errind); +#else + myfile->hfile = __creat(fnm, 0, &errind); +#endif + } + else + { + myfile->hfile = __open(fnm, 2, &errind); + if (errind) + { + if ((modeType == 3) || (modeType == 6) + || (modeType == 9) || (modeType == 12)) + { +#if defined(__gnu_linux__) || defined(__ARM__) + myfile->hfile = __open(fnm, 1, &errind); +#else + myfile->hfile = __creat(fnm, 0, &errind); +#endif + } + } + } + if (errind) + { + err = 1; + errno = myfile->hfile; + } +#endif +#if defined(__MVS__) || defined(__CMS__) + int mode; + char *p; + char *q; + int len; + char newfnm[FILENAME_MAX]; + char tmpdd[9]; + + if ((modeType == 1) || (modeType == 4)) + { + mode = 0; /* reading */ + } + else if ((modeType == 2) || (modeType == 5)) + { + mode = 1; /* writing */ + } + else if (modeType == 11) + { + fprintf(stderr, "we don't have the ability to do update, " + "but switching to write mode as a kludge\n"); + mode = 1; + } + else + { + mode = 2; /* update */ + + /* because we don't have the ability to update files + at the moment on MVS or CMS, just return with an + error immediately */ + err = 1; + errno = 2; + return; + } + + myfile->pdsmem[0] = '\0'; /* seek needs to know if member provided */ + + if (!inseek) + { + myfile->dynal = 0; + } +/* dw */ +/* This code needs changing for VM */ + p = strchr(fnm, ':'); + if ((p != NULL) + && ((strncmp(fnm, "dd", 2) == 0) + || (strncmp(fnm, "DD", 2) == 0))) + { + p++; + /* support a filename of dd:include/stdio.h */ + q = strchr(p, '/'); + if (q != NULL) + { + strcpy(newfnm, p); + q = strchr(newfnm, '/'); + *q = '('; + q = strchr(newfnm, '.'); + if (q != NULL) + { + strcpy(q, ")"); + } + p = newfnm; + } + } + else +/* if we are in here then there is no "dd:" on front of file */ +/* if its CMS generate a ddname and issue a filedef for the file */ +#if defined(__CMS__) + { +/* create a DD from the handle number */ + strcpy(newfnm, fnm); + p = newfnm; + while (*p != '\0') + { + *p = toupper((unsigned char)*p); + p++; + } + if (!myfile->permfile) + { + sprintf(tmpdd, "PDP%03dHD", spareSpot); + } + else + { + if (myfile == __stdout) + { + strcpy(tmpdd, "PDPOUTHD"); + } + else if (myfile == __stdin) + { + strcpy(tmpdd, "PDPINXHD"); + } + else if (myfile == __stderr) + { + strcpy(tmpdd, "PDPERRHD"); + } + } + filedef(tmpdd, newfnm, mode); + myfile->dynal = 1; + p = tmpdd; + } +#elif defined(__MVS__) + +#if !defined(MUSIC) /* for MUSIC, send everything through to SVC99 */ + if ((strchr(fnm, '\'') == NULL) && (strchr(fnm, '(') == NULL) +#if defined(__MVS__) + && !__tso +#endif + ) +#endif + { + strcpy(newfnm, fnm); + p = newfnm; + + /* The SVC 99 interface on MVS requires an uppercase + filename in order to be found via a catalog search */ + while (*p != '\0') + { + *p = toupper((unsigned char)*p); + p++; + } + /* create a DD from the handle number */ + if (!myfile->permfile) + { + sprintf(tmpdd, "PDP%03dHD", spareSpot); + } + else + { + if (myfile == __stdout) + { + strcpy(tmpdd, "PDPOUTHD"); + } + else if (myfile == __stdin) + { + strcpy(tmpdd, "PDPINXHD"); + } + else if (myfile == __stderr) + { + strcpy(tmpdd, "PDPERRHD"); + } + } + fdclr(tmpdd); /* unconditionally clear */ + filedef(tmpdd, newfnm, mode); + if (err) return; + myfile->dynal = 1; + p = tmpdd; + } + +#if !defined(MUSIC) + /* This is our traditional function for MVS. Keep it for now, + for the complex strings. For the simple strings, which + are always used on environments such as PDOS and MUSIC, + use the code above instead. */ + else + { + char rawf[FILENAME_MAX]; /* file name without member, + suitable for dynamic allocation */ + + if (!myfile->permfile) + { + sprintf(newfnm, "PDP%03dHD", spareSpot); + } + else + { + if (myfile == __stdout) + { + strcpy(newfnm, "PDPOUTHD"); + } + else if (myfile == __stdin) + { + strcpy(newfnm, "PDPINXHD"); + } + else if (myfile == __stderr) + { + strcpy(newfnm, "PDPERRHD"); + } + } + strcpy(tmpdd, newfnm); + + strcpy(rawf, ""); + /* strip any single quote */ + if ((fnm[0] == '\'') || (fnm[0] == '/')) + { + fnm++; + } +#if defined(__MVS__) && !defined(__VSE__) + else + { + /* Call IKJPARS to get a prefix */ + if (__tso) + { + char *z = "@@@@@@@Z"; /* dummy DSN */ + int len; + char *gp; + + gp = __getepf(z); + len = strlen(gp); + if (len > strlen(z)) + { + if (strcmp(gp + strlen(gp) - strlen(z), z) == 0) + { + len -= strlen(z); + } + if (len + 1 < sizeof rawf) + { + strncpy(rawf, gp, len); + rawf[len] = '\0'; + } + } + } + } +#endif + strcat(rawf, fnm); + + /* If we have a file such as "'FRED.C(MARY)'" we need to + convert this into PDP001HD(MARY) and do a dynamic + allocation of PDP001HD to "FRED.C". This involves + extracting the member name and then eliminating the member + name and any single quotes */ + p = strchr(rawf, '('); + if (p != NULL) + { + *p = '\0'; + p++; + strcat(newfnm, "("); + strcat(newfnm, p); + + p = strchr(newfnm, ')'); + if (p != NULL) + { + *(p + 1) = '\0'; + } + } + else + { + char *last; + + /* If we have a file such as "test/paul.asm" we need to convert + it into PDP001HD(PAUL) and do a dynamic allocation of + PDP001HD to "TEST.ASM" */ + while ((p = strchr(rawf, '/')) != NULL) + { + *p = '.'; + } + last = strrchr(rawf, '.'); + if (last != NULL) + { + *last++ = '\0'; + p = strrchr(rawf, '.'); + if (p == NULL) + { + p = rawf; + } + else + { + p++; + } + strcat(newfnm, "("); + if (strlen(p) > 8) + { + p[8] = '\0'; + } + strcat(newfnm, p); + strcat(newfnm, ")"); + memmove(p, last, strlen(last) + 1); + } + + /* strip any single quote */ + p = strchr(rawf, '\''); + if (p != NULL) + { + *p = '\0'; + } + } + + /* MVS requires uppercase filenames */ + p = rawf; + while (*p != '\0') + { + *p = toupper((unsigned char)*p); + p++; + } + + /* dynamically allocate file */ + errno = __dynal(strlen(tmpdd), tmpdd, strlen(rawf), rawf); + if (errno != 0) + { + err = 1; + return; + } + myfile->dynal = 1; + + p = newfnm; + } +#endif /* MUSIC */ + +#else + { + p = (char *)fnm; + } +#endif + q = p; + strcpy(myfile->ddname, " "); + len = strcspn(p, "("); + if (len > 8) + { + len = 8; + } + memcpy(myfile->ddname, p, len); + p = myfile->ddname; + while (*p != '\0') + { + *p = toupper((unsigned char)*p); + p++; + } + + p = strchr(q, '('); + if (p != NULL) + { + p++; + strcpy(myfile->pdsmem, " "); + len = strcspn(p, ")"); + if (len > 8) + { + len = 8; + } + memcpy(myfile->pdsmem, p, len); + p = myfile->pdsmem; + while (*p != '\0') + { + *p = toupper((unsigned char)*p); + p++; + } + p = myfile->pdsmem; + } + myfile->reallyu = 0; + myfile->reallyt = 0; + myfile->asmbuf = 0; + + /* Set some default DCB info. Stress - this will not interfere + in any way with DCB information the user provides in JCL, + or on an existing dataset. It is only used when all else + fails */ + if (myfile->textMode) + { + myfile->recfm = __RECFM_V; + myfile->lrecl = 255; + if (myfile->permfile) + { + /* don't block __stdout/__stderr so that output is not + delayed if the program crashes */ + myfile->blksize = 259; + } + else + { + myfile->blksize = 6233; + } + } + else + { + myfile->recfm = __RECFM_U; + myfile->lrecl = 0; + myfile->blksize = 6233; + } +#if defined(__MVS__) + /* If we are dealing with SYSIN/SYSPRINT/SYSTERM and we are + in a TSO environment, then we should use GETLINE/PUTLINE + by default, as you would expect for any other TSO + command, like LISTCAT. If people don't want that, they + should do a "CALL" to invoke the program as a + non-TSO-command-processor */ + if (__tso && myfile->permfile) + { + mode |= 0x80; /* use PUTLINE/GETLINE if available */ + } +#endif + + myfile->hfile = + __aopen(myfile->ddname, &mode, &myfile->recfm, &myfile->lrecl, + &myfile->blksize, &myfile->asmbuf, p); + + /* The true RECFM is not the "recfm" variable. True + RECFM is as follows: + + x'C0' U, x'80' F, x'40' V + x'20' T with F, V, or U; + with top two bits off, x'20' is D (ANSI variable) + T is obsolete except MVS 3.8 - track overflow + x'10' B + x'08' S (standard with F; spanned with V) + x'04' A + x'02' M (never both A and M) + */ + + myfile->true_recfm = (mode >> 16) & 0xff; + + mode &= 0x03; /* only interested in the simple mode now */ + + /* errors from MVS __aopen are negative numbers */ + if ((int)myfile->hfile <= 0) + { + err = 1; + errno = -(int)myfile->hfile; + return; + } + + /* recfm=f and v are effecively always line-buffered + because we currently do not support blocking. as + such, there is no need to switch this flag on at + the moment, as it is only relevant to recfm=u */ + myfile->line_buf = 0; + /* if we have a RECFM=U, do special processing */ + if (myfile->recfm == __RECFM_U) + { + /* sysprint etc are expected to be line-buffered, + although we allow full buffering for RECFM=UB */ + if (myfile->permfile + && ((myfile->true_recfm & 0x10) == 0) + ) + { + myfile->line_buf = 1; + } + + myfile->reallyu = 1; + myfile->quickBin = 0; /* switch off to be on the safe side */ + + /* if open for writing, kludge to switch to fixed */ + if (mode == 1) + { + myfile->recfm = __RECFM_F; + } + /* if open for reading, kludge to switch to variable */ + else if (mode == 0) + { + myfile->recfm = __RECFM_V; + } + /* we need to work with a decent lrecl in case the + assembler routine set the real thing */ + if (myfile->lrecl == 0) + { + myfile->lrecl = myfile->blksize; + if (myfile->lrecl == 0) + { + __aclose(myfile); + err = 1; + errno = 1; + return; + } + } + } + /* if we have RECFM=V, the usable lrecl is 4 bytes shorter + than we are told, so just adjust that here */ + else if (myfile->recfm == __RECFM_V) + { + if (myfile->lrecl > 4) + { + myfile->lrecl -= 4; + } + } + + if ((modeType == 4) || (modeType == 5) || (modeType == 11)) + { + myfile->style = 0; /* binary */ + } + else + { + myfile->style = 2; /* text */ + /* for RECFM=U we use binary mode when reading or writing + text files as we don't want any translation done. But + record the fact that it was really text mode */ + if (myfile->reallyu) + { + myfile->reallyt = 1; + myfile->style = 0; + } + } + + /* by the time we reach here, there is no RECFM=U, so + we only have 2 forms of binary (starting at 0) and + two forms of text (starting at 2), so we just need + to add the recfm (0 or 1) to the above. It should + probably be done in a less complicated manner! */ + myfile->style += myfile->recfm; + + if (myfile->style == VARIABLE_TEXT) + { + myfile->quickText = 1; + } + else + { + myfile->quickText = 0; + } + if (myfile->style == FIXED_BINARY) + { + myfile->quickBin = 1; + } + else + { + myfile->quickBin = 0; + } +#endif + return; +} + + +#if defined(__VSE__) + +#define CARDLEN 80 +#define MAXCDATA 56 /* maximum data bytes on TXT record */ +#define MAXRLEN (MAXCDATA * 10 - 4) /* maximum length of a single record */ + /* the 4 is to ensure the length is never on a card by itself */ + +static int vseCloseLib(FILE *stream) +{ + char card[CARDLEN]; + size_t cnt; + size_t tot; + size_t rem; + size_t upto; + size_t x; + size_t r; + size_t subtot; + + stream->vse_punch = 0; + + tot = stream->vselupto - __vsepb; + /* The file needs an EOF marker */ + memset(__vsepb + tot, 0x00, 4); + tot += 4; + + memset(card, ' ', sizeof card); + memcpy(card, "\x02" "ESD", 4); + *(short *)(card + 10) = 0x20; /* length of this ESD is the minimal 0x20 */ + *(short *)(card + 14) = 1; /* CSECT 1 */ + memset(card + 16, ' ', 8); /* name is blank */ + + *(int *)(card + 24) = 0; /* assembled origin = 0 */ + *(card + 24) = 0x04; /* PC for some reason */ + *(int *)(card + 28) = 0; /* AMODE + length - for some reason we + don't need to set the length properly. */ + +#if 0 + /* is this required? */ + *(int *)(card + 28) = tot + + (tot/MAXRLEN + ((tot % MAXRLEN) != 0)) * sizeof(int); +#endif + + memcpy(card + 32, "TOTO ", 8); /* total? */ + + /* is this required? */ + *(int *)(card + 44) = tot + + (tot/MAXRLEN + ((tot % MAXRLEN) != 0)) * sizeof(int); + fwrite(card, 1, sizeof card, stream); + + subtot = 0; + for (upto = 0; upto < tot; upto += rem) + { + rem = tot - upto; + if (rem > MAXRLEN) + { + rem = MAXRLEN; + } + for (x = 0; x < rem; x += r) + { + r = rem - x; + if (r > MAXCDATA) + { + r = MAXCDATA; + } + if ((x == 0) && (r > (MAXCDATA - sizeof(int)))) + { + r -= sizeof(int); + } + memset(card, ' ', sizeof card); + memcpy(card, "\x02" "TXT", 4); + *(int *)(card + 4) = subtot; /* origin */ + card[4] = ' '; + *(short *)(card + 10) = r + ((x == 0) ? sizeof(int) : 0); + /* byte count */ + *(int *)(card + 12) = 1; /* CSECT 1 */ + if (x == 0) + { + *(int *)(card + 16) = rem; + if ((upto + rem) >= tot) + { + *(int *)(card + 16) -= 4; + } + memcpy(card + 16 + sizeof(int), __vsepb + upto, r); + subtot += (r + sizeof(int)); + } + else + { + memcpy(card + 16, __vsepb + upto + x, r); + subtot += r; + } + fwrite(card, 1, sizeof card, stream); + } + } + memset(card, ' ', sizeof card); + memcpy(card, "\x02" "END", 4); +#if 0 + /* is this required? */ + *(int *)(card + 24) = tot + + (tot/MAXRLEN + ((tot % MAXRLEN) != 0)) * sizeof(int); +#endif + fwrite(card, 1, sizeof card, stream); + + stream->vselupto = __vsepb; + stream->vse_punch = 1; /* still the punch, but not active */ + + return (0); +} +#endif + + +__PDPCLIB_API__ int fclose(FILE *stream) +{ +#ifdef __OS2__ + APIRET rc; +#endif +#ifdef __WIN32__ + BOOL rc; +#endif + + stream = __INTFILE(stream); + + if (!stream->isopen) + { + return (EOF); + } + fflush(stream); +#ifdef __VSE__ + /* only take action if in an active file */ + if (stream->vse_punch == 2) + { + stream->upto = stream->fbuf; + stream->bufStartR = 0; + return (vseCloseLib(stream)); + } + /* closing an inactive punch must be the real thing, so free + the buffer and go through the rest of the close logic. */ + else if (stream->vse_punch == 1) + { + free(__vsepb); + __vsepb = NULL; + } +#endif +#ifdef __AMIGA__ + Close(stream->hfile); +#endif +#ifdef __OS2__ + rc = DosClose(stream->hfile); +#endif +#ifdef __WIN32__ + rc = CloseHandle(stream->hfile); +#endif +#ifdef __MSDOS__ + __close(stream->hfile); +#endif +#if defined(__MVS__) || defined(__CMS__) + if ((stream->mode == __WRITE_MODE) && (stream->upto != stream->fbuf)) + { + if (stream->reallyu) + { + /* we should not get to here, because the flush would + have taken care of it. perhaps we can generate an + internal error */ + } + else if (stream->textMode) + { + putc('\n', stream); + } + else + { + size_t remain; + size_t x; + + remain = stream->endbuf - stream->upto; + for (x = 0; x < remain; x++) + { + putc(0x00, stream); + } + } + } + __aclose(stream->hfile); +#ifdef __CMS__ + if (stream->dynal && !inseek) + { + fdclr(stream->ddname); + } +#endif +#endif + if (!stream->theirBuffer) + { +#if !defined(__MVS__) && !defined(__CMS__) && !defined(__VSE__) + /* on the PC, permanent files have a static buffer */ + if (!stream->permfile) +#endif + free(stream->intBuffer); + } + if (!stream->permfile && !inreopen) + { +#if !defined(__MVS__) && !defined(__CMS__) + if (stream->istemp) + { + remove("ZZZZZZZA.$$$"); + } +#endif + __userFiles[stream->intFno] = NULL; + free(stream); + } + else + { +#if defined(__MVS__) || defined(__CMS__) + /* if we're not in the middle of freopen ... */ + if (!stream->permfile) + { + __userFiles[stream->intFno] = NULL; + } + if (!inreopen) + { + free(stream); + /* need to protect against the app closing the file + which it is allowed to */ + if (stream == __stdin) + { + __stdin = NULL; + } + else if (stream == __stdout) + { + __stdout = NULL; + } + else if (stream == __stderr) + { + __stderr = NULL; + } + } +#else + stream->isopen = 0; +#endif + } +#ifdef __OS2__ + if (rc != 0) + { + errno = rc; + return (EOF); + } +#endif +#ifdef __WIN32__ + if (!rc) + { + errno = GetLastError(); + return (EOF); + } +#endif + return (0); +} + + +#if !defined(__MVS__) && !defined(__CMS__) +static void iread(FILE *stream, void *ptr, size_t toread, size_t *actualRead) +{ +#ifdef __AMIGA__ + long tempRead; +#endif +#ifdef __OS2__ + APIRET rc; + ULONG tempRead; +#endif +#ifdef __WIN32__ + BOOL rc; + DWORD tempRead; +#endif +#ifdef __MSDOS__ + int errind; + size_t tempRead; +#endif + +#ifdef __AMIGA__ + tempRead = Read(stream->hfile, ptr, toread); + if (tempRead == -1) + { + *actualRead = 0; + stream->errorInd = 1; + } + else + { + *actualRead = tempRead; + } +#endif +#ifdef __OS2__ + rc = DosRead(stream->hfile, ptr, toread, &tempRead); + if (rc != 0) + { + *actualRead = 0; + stream->errorInd = 1; + errno = rc; + } + else + { + *actualRead = tempRead; + } +#endif +#ifdef __WIN32__ + rc = ReadFile(stream->hfile, + ptr, + toread, + &tempRead, + NULL); + if (!rc) + { + *actualRead = 0; + stream->errorInd = 1; + errno = GetLastError(); + } + else + { + size_t x; + char *p; + + *actualRead = tempRead; + /* Windows returns DEL for backspace instead of ^H so we + convert to ^H now */ + if (stream == stdin) + { + p = ptr; + for (x = 0; x < *actualRead; x++) + { + if (p[x] == 0x7f) + { + p[x] = 0x08; + } + } + } + } +#endif +#ifdef __MSDOS__ + tempRead = __read(stream->hfile, ptr, toread, &errind); + if (errind) + { + errno = tempRead; + *actualRead = 0; + stream->errorInd = 1; + } + else + { + *actualRead = tempRead; + } +#endif + return; +} + + +__PDPCLIB_API__ size_t fread(void *ptr, + size_t size, + size_t nmemb, + FILE *stream) +{ + size_t toread; + size_t elemRead; + size_t actualRead; + + stream = __INTFILE(stream); + + if (nmemb == 1) + { + toread = size; + } + else if (size == 1) + { + toread = nmemb; + } + else + { + toread = size * nmemb; + } + if (toread < stream->szfbuf) + { + stream->quickBin = 0; + } + if (stream->ungetCh != -1) + { + *--stream->upto = (char)stream->ungetCh; + stream->ungetCh = -1; + } + if (!stream->quickBin) + { + /* if we were previously writing and then + we seeked, and now we're reading, we need to + correct things */ + if (stream->justseeked) + { + stream->justseeked = 0; + if (stream->mode == __WRITE_MODE) + { + stream->bufStartR -= (stream->endbuf - stream->fbuf); + stream->upto = stream->endbuf; + stream->mode = __READ_MODE; + } + } + if (stream->textMode) + { + freadSlowT(ptr, stream, toread, &actualRead); + } + else + { + if (toread <= (stream->endbuf - stream->upto)) + { + memcpy(ptr, stream->upto, toread); + actualRead = toread; + stream->upto += toread; + } + else + { + freadSlowB(ptr, stream, toread, &actualRead); + } + } + if (nmemb == 1) + { + if (actualRead == size) + { + elemRead = 1; + } + else + { + elemRead = 0; + } + } + else if (size == 1) + { + elemRead = actualRead; + } + else + { + if (size == 0) + { + elemRead = 0; + } + else + { + elemRead = actualRead / size; + } + } + return (elemRead); + } + else + { + iread(stream, ptr, toread, &actualRead); + if (nmemb == 1) + { + if (actualRead == size) + { + elemRead = 1; + } + else + { + elemRead = 0; + stream->eofInd = 1; + } + } + else if (size == 1) + { + elemRead = actualRead; + if (nmemb != actualRead) + { + stream->eofInd = 1; + } + } + else + { + if (size == 0) + { + elemRead = 0; + } + else + { + elemRead = actualRead / size; + } + if (toread != actualRead) + { + stream->eofInd = 1; + } + } + stream->bufStartR += actualRead; + return (elemRead); + } +} + + +/* +while toread has not been satisfied +{ + scan stuff out of buffer, replenishing buffer as required +} +*/ + +static void freadSlowT(void *ptr, + FILE *stream, + size_t toread, + size_t *actualRead) +{ + int finReading = 0; + size_t avail; + size_t need; + char *p; + size_t got; + size_t tempRead; + + *actualRead = 0; + while (!finReading) + { + if (stream->upto == stream->endbuf) + { + iread(stream, stream->fbuf, stream->szfbuf, &tempRead); + if (tempRead == 0) + { + stream->eofInd = 1; + break; + } + stream->bufStartR += (stream->upto - stream->fbuf); + stream->endbuf = stream->fbuf + tempRead; + *stream->endbuf = '\n'; + stream->upto = stream->fbuf; + } + avail = (size_t)(stream->endbuf - stream->upto) + 1; + need = toread - *actualRead; + p = memchr(stream->upto, '\n', avail); + got = (size_t)(p - stream->upto); + if (need < got) + { + memcpy((char *)ptr + *actualRead, stream->upto, need); + stream->upto += need; + *actualRead += need; + } + else + { + memcpy((char *)ptr + *actualRead, stream->upto, got); + stream->upto += got; + *actualRead += got; + if (p != stream->endbuf) + { + if (*(stream->upto - 1) == '\r') + { + *((char *)ptr + *actualRead - 1) = '\n'; + stream->upto++; + } + else if (need != got) + { + *((char *)ptr + *actualRead) = '\n'; + *actualRead += 1; + stream->upto++; + } + } + else + { + if (*(stream->upto - 1) == '\r') + { +#ifdef __WIN32__ + if ((stream == stdin) + && (stream->bufTech == _IONBF)) + { + *((char *)ptr + *actualRead - 1) = '\n'; + } + else +#endif + *actualRead -= 1; + } + } + } + if (*actualRead == toread) + { + finReading = 1; + } + } + return; +} + +static void freadSlowB(void *ptr, + FILE *stream, + size_t toread, + size_t *actualRead) +{ + size_t avail; + size_t left; + size_t tempRead; + + avail = (size_t)(stream->endbuf - stream->upto); + memcpy(ptr, stream->upto, avail); + left = toread - avail; + *actualRead = avail; + stream->bufStartR += (stream->endbuf - stream->fbuf); + if (stream->eofInd) + { + return; + } + if (left >= stream->szfbuf) + { + iread(stream, (char *)ptr + *actualRead, left, &tempRead); + if (stream->errorInd) + { + } + else if (tempRead != left) + { + stream->eofInd = 1; + } + *actualRead += tempRead; + stream->quickBin = 1; + if (tempRead >= stream->szfbuf) + { + stream->bufStartR += (tempRead - stream->szfbuf); + stream->endbuf = stream->fbuf + stream->szfbuf; + } + else + { + stream->endbuf = stream->fbuf + tempRead; + *stream->endbuf = '\n'; + } + stream->upto = stream->endbuf; + } + else + { + stream->upto = stream->fbuf; + iread(stream, stream->fbuf, stream->szfbuf, &tempRead); + if (stream->errorInd) + { + } + else if (tempRead < left) + { + stream->eofInd = 1; + } + stream->endbuf = stream->fbuf + tempRead; + *stream->endbuf = '\n'; + avail = (size_t)(stream->endbuf - stream->upto); + if (avail > left) + { + avail = left; + } + memcpy((char *)ptr + *actualRead, + stream->upto, + avail); + stream->upto += avail; + *actualRead += avail; + } + return; +} +#endif + + +#if !defined(__MVS__) && !defined(__CMS__) +static void iwrite(FILE *stream, + const void *ptr, + size_t towrite, + size_t *actualWritten) +{ +#ifdef __AMIGA__ + long tempWritten; +#endif +#ifdef __OS2__ + ULONG tempWritten; + APIRET rc; +#endif +#ifdef __WIN32__ + DWORD tempWritten; + BOOL rc; +#endif +#ifdef __MSDOS__ + size_t tempWritten; + int errind; +#endif +#ifdef __EFI__ + size_t tempWritten; + static CHAR16 onechar[2] = {0, '\0'}; +#endif + +#ifdef __AMIGA__ + tempWritten = Write(stream->hfile, ptr, towrite); + if (tempWritten == -1) + { + stream->errorInd = 1; + tempWritten = 0; + errno = 1; + } +#endif +#ifdef __OS2__ + rc = DosWrite(stream->hfile, (VOID *)ptr, towrite, &tempWritten); + if (rc != 0) + { + stream->errorInd = 1; + tempWritten = 0; + errno = rc; + } +#endif +#ifdef __WIN32__ + rc = WriteFile(stream->hfile, ptr, towrite, &tempWritten, NULL); + if (!rc) + { + stream->errorInd = 1; + tempWritten = 0; + errno = GetLastError(); + } +#endif +#ifdef __MSDOS__ + tempWritten = __write(stream->hfile, + ptr, + towrite, + &errind); + if (errind) + { + stream->errorInd = 1; + tempWritten = 0; + errno = 1; + } +#endif +#ifdef __EFI__ + for (tempWritten = 0; tempWritten < towrite; tempWritten++) + { + onechar[0] = *((unsigned char *)ptr + tempWritten); + if (onechar[0] == '\n') + { + onechar[0] = '\r'; + __gST->ConOut->OutputString(__gST->ConOut, onechar); + onechar[0] = '\n'; + } + __gST->ConOut->OutputString(__gST->ConOut, onechar); + } +#endif + *actualWritten = tempWritten; + return; +} + + +__PDPCLIB_API__ size_t fwrite(const void *ptr, + size_t size, + size_t nmemb, + FILE *stream) +{ + size_t towrite; + size_t elemWritten; + size_t actualWritten; + + stream = __INTFILE(stream); + + if (nmemb == 1) + { + towrite = size; + } + else if (size == 1) + { + towrite = nmemb; + } + else + { + towrite = size * nmemb; + } + if (towrite < stream->szfbuf) + { + stream->quickBin = 0; + if ((stream->bufTech == _IONBF) && !stream->textMode) + { + stream->quickBin = 1; + } + } + if (!stream->quickBin) + { + fwriteSlow(ptr, size, nmemb, stream, towrite, &elemWritten); + return (elemWritten); + } + else + { + iwrite(stream, ptr, towrite, &actualWritten); + if (nmemb == 1) + { + if (actualWritten == size) + { + elemWritten = 1; + } + else + { + elemWritten = 0; + } + } + else if (size == 1) + { + elemWritten = actualWritten; + } + else + { + elemWritten = actualWritten / size; + } + stream->bufStartR += actualWritten; + return (elemWritten); + } +} + +static void fwriteSlow(const void *ptr, + size_t size, + size_t nmemb, + FILE *stream, + size_t towrite, + size_t *elemWritten) +{ + size_t actualWritten; + + if (stream->justseeked) + { + stream->justseeked = 0; + if (stream->mode == __READ_MODE) + { + stream->bufStartR += (stream->endbuf - stream->fbuf); + stream->upto = stream->fbuf; + stream->mode = __WRITE_MODE; + } + } + if ((stream->textMode) || (stream->bufTech == _IOLBF)) + { + fwriteSlowT(ptr, stream, towrite, &actualWritten); + } + else + { + fwriteSlowB(ptr, stream, towrite, &actualWritten); + } + if (nmemb == 1) + { + if (actualWritten == size) + { + *elemWritten = 1; + } + else + { + *elemWritten = 0; + } + } + else if (size == 1) + { + *elemWritten = actualWritten; + } + else + { + *elemWritten = actualWritten / size; + } + return; +} + + +/* can still be called on binary files, if the binary file is + line buffered */ + +static void fwriteSlowT(const void *ptr, + FILE *stream, + size_t towrite, + size_t *actualWritten) +{ + char *p; + char *tptr; + char *oldp; + size_t diffp; + size_t rem; + int fin; + size_t tempWritten; + + *actualWritten = 0; + tptr = (char *)ptr; + p = tptr; + oldp = p; + p = (char *)memchr(oldp, '\n', towrite - (size_t)(oldp - tptr)); + while (p != NULL) + { + diffp = (size_t)(p - oldp); + fin = 0; + while (!fin) + { + rem = (size_t)(stream->endbuf - stream->upto); + if (diffp < rem) + { + memcpy(stream->upto, oldp, diffp); + stream->upto += diffp; + *actualWritten += diffp; + fin = 1; + } + else + { + memcpy(stream->upto, oldp, rem); + oldp += rem; + diffp -= rem; + iwrite(stream, stream->fbuf, stream->szfbuf, &tempWritten); + if (stream->errorInd) return; + + *actualWritten += rem; + stream->upto = stream->fbuf; + stream->bufStartR += tempWritten; + } + } + rem = (size_t)(stream->endbuf - stream->upto); + if (rem < 3) + { + iwrite(stream, + stream->fbuf, + stream->upto - stream->fbuf, + &tempWritten); + if (stream->errorInd) return; + stream->upto = stream->fbuf; + stream->bufStartR += tempWritten; + } +#if !defined(__gnu_linux__) && !defined(__ARM__) + if (stream->textMode) + { + memcpy(stream->upto, "\r\n", 2); + stream->upto += 2; + } + else +#endif + { + memcpy(stream->upto, "\n", 1); + stream->upto += 1; + } + *actualWritten += 1; + oldp = p + 1; + p = (char *)memchr(oldp, '\n', towrite - (size_t)(oldp - tptr)); + } + + if ((stream->bufTech == _IOLBF) + && (stream->upto != stream->fbuf) + && (oldp != tptr)) + { + iwrite(stream, + stream->fbuf, + stream->upto - stream->fbuf, + &tempWritten); + if (stream->errorInd) return; + stream->upto = stream->fbuf; + stream->bufStartR += tempWritten; + } + + diffp = towrite - *actualWritten; + while (diffp != 0) + { + rem = (size_t)(stream->endbuf - stream->upto); + if (diffp < rem) + { + memcpy(stream->upto, oldp, diffp); + stream->upto += diffp; + *actualWritten += diffp; + } + else + { + memcpy(stream->upto, oldp, rem); + iwrite(stream, stream->fbuf, stream->szfbuf, &tempWritten); + if (stream->errorInd) return; + else + { + *actualWritten += rem; + stream->upto = stream->fbuf; + } + stream->bufStartR += tempWritten; + oldp += rem; + } + diffp = towrite - *actualWritten; + } + if ((stream->bufTech == _IONBF) + && (stream->upto != stream->fbuf)) + { + iwrite(stream, + stream->fbuf, + stream->upto - stream->fbuf, + &tempWritten); + if (stream->errorInd) return; + stream->upto = stream->fbuf; + stream->bufStartR += tempWritten; + } + return; +} + +/* whilst write requests are smaller than a buffer, we do not turn + on quickbin */ + +static void fwriteSlowB(const void *ptr, + FILE *stream, + size_t towrite, + size_t *actualWritten) +{ + size_t spare; + size_t tempWritten; + size_t left; + spare = (size_t)(stream->endbuf - stream->upto); + if (towrite < spare) + { + memcpy(stream->upto, ptr, towrite); + *actualWritten = towrite; + stream->upto += towrite; + return; + } + memcpy(stream->upto, ptr, spare); + iwrite(stream, stream->fbuf, stream->szfbuf, &tempWritten); + if (stream->errorInd) return; + *actualWritten = spare; + stream->upto = stream->fbuf; + stream->bufStartR += tempWritten; + left = towrite - *actualWritten; + if (left > stream->szfbuf) + { + stream->quickBin = 1; + iwrite(stream, (const char *)ptr + *actualWritten, left, &tempWritten); + if (stream->errorInd) return; + *actualWritten += tempWritten; + stream->bufStartR += *actualWritten; + } + else + { + memcpy(stream->fbuf, + (char *)ptr + *actualWritten, + left); + stream->upto += left; + *actualWritten += left; + } + return; +} +#endif + +static int vvprintf(const char *format, va_list arg, FILE *fq, char *s) +{ + int fin = 0; + int vint; + double vdbl; + unsigned int uvint; + const char *vcptr; + int chcount = 0; + size_t len; + char numbuf[50]; + char *nptr; + int *viptr; + + while (!fin) + { + if (*format == '\0') + { + fin = 1; + } + else if (*format == '%') + { + format++; + if (*format == 'd') + { + vint = va_arg(arg, int); + if (vint < 0) + { + uvint = -vint; + } + else + { + uvint = vint; + } + nptr = numbuf; + do + { + *nptr++ = (char)('0' + uvint % 10); + uvint /= 10; + } while (uvint > 0); + if (vint < 0) + { + *nptr++ = '-'; + } + do + { + nptr--; + outch(*nptr); + chcount++; + } while (nptr != numbuf); + } + else if (strchr("eEgGfF", *format) != NULL && *format != 0) + { + vdbl = va_arg(arg, double); + dblcvt(vdbl, *format, 0, 6, numbuf); /* 'e','f' etc. */ + len = strlen(numbuf); + if (fq == NULL) + { + memcpy(s, numbuf, len); + s += len; + } + else + { + fputs(numbuf, fq); + } + chcount += len; + } + else if (*format == 's') + { + vcptr = va_arg(arg, const char *); + if (vcptr == NULL) + { + vcptr = "(null)"; + } + if (fq == NULL) + { + len = strlen(vcptr); + memcpy(s, vcptr, len); + s += len; + chcount += len; + } + else + { + fputs(vcptr, fq); + chcount += strlen(vcptr); + } + } + else if (*format == 'c') + { + vint = va_arg(arg, int); + outch(vint); + chcount++; + } + else if (*format == 'n') + { + viptr = va_arg(arg, int *); + *viptr = chcount; + } + else if (*format == '%') + { + outch('%'); + chcount++; + } + else + { + int extraCh; + + extraCh = examine(&format, fq, s, &arg, chcount); + chcount += extraCh; + if (s != NULL) + { + s += extraCh; + } + } + } + else + { + outch(*format); + chcount++; + } + format++; + } + return (chcount); +} + +static int examine(const char **formt, FILE *fq, char *s, va_list *arg, + int chcount) +{ + int extraCh = 0; + int flagMinus = 0; + int flagPlus = 0; + int flagSpace = 0; + int flagHash = 0; + int flagZero = 0; + int width = 0; + int precision = -1; + int half = 0; + int lng = 0; + int specifier = 0; + int fin; + long lvalue; + short int hvalue; + int ivalue; + unsigned long ulvalue; + double vdbl; + char *svalue; + char work[50]; + int x; + int y; + int rem; + const char *format; + int base; + int fillCh; + int neg; + int length; + size_t slen; + + unused(chcount); + format = *formt; + /* processing flags */ + fin = 0; + while (!fin) + { + switch (*format) + { + case '-': flagMinus = 1; + break; + case '+': flagPlus = 1; + break; + case ' ': flagSpace = 1; + break; + case '#': flagHash = 1; + break; + case '0': flagZero = 1; + break; + case '*': width = va_arg(*arg, int); + if (width < 0) + { + flagMinus = 1; + width = -width; + } + break; + default: fin = 1; + break; + } + if (!fin) + { + format++; + } + else + { + if (flagSpace && flagPlus) + { + flagSpace = 0; + } + if (flagMinus) + { + flagZero = 0; + } + } + } + + /* processing width */ + if (isdigit((unsigned char)*format)) + { + while (isdigit((unsigned char)*format)) + { + width = width * 10 + (*format - '0'); + format++; + } + } + + /* processing precision */ + if (*format == '.') + { + format++; + if (*format == '*') + { + precision = va_arg(*arg, int); + format++; + } + else + { + precision = 0; + while (isdigit((unsigned char)*format)) + { + precision = precision * 10 + (*format - '0'); + format++; + } + } + } + + /* processing h/l/L */ + if (*format == 'h') + { + /* all environments should promote shorts to ints, + so we should be able to ignore the 'h' specifier. + It will create problems otherwise. */ + /* half = 1; */ + } + else if (*format == 'l') + { + lng = 1; + } + else if (*format == 'L') + { + lng = 1; + } + else + { + format--; + } + format++; + + /* processing specifier */ + specifier = *format; + + if (strchr("dxXuiop", specifier) != NULL && specifier != 0) + { + if (precision < 0) + { + precision = 1; + } +#if defined(__MSDOS__) && \ + !defined(__PDOS386__) && \ + !defined(__SMALLERC__) && \ + !defined(__gnu_linux__) && \ + !defined(__ARM__) + if (specifier == 'p') + { + lng = 1; + lvalue = (long)va_arg(*arg, void *); + } + else +#endif + if (lng) + { + lvalue = va_arg(*arg, long); + } + else if (half) + { + /* short is promoted to int, so use int */ + hvalue = va_arg(*arg, int); + if (specifier == 'u') lvalue = (unsigned short)hvalue; + else lvalue = hvalue; + } + else + { + ivalue = va_arg(*arg, int); + if (specifier == 'u') lvalue = (unsigned int)ivalue; + else lvalue = ivalue; + } + ulvalue = (unsigned long)lvalue; + if ((lvalue < 0) && ((specifier == 'd') || (specifier == 'i'))) + { + neg = 1; + ulvalue = -lvalue; + } + else + { + neg = 0; + } +#if defined(__MSDOS__) && \ + !defined(__PDOS386__) && \ + !defined(__SMALLERC__) && \ + !defined(__gnu_linux__) && \ + !defined(__ARM__) + if (!lng) + { + ulvalue &= 0xffff; + } +#endif + if ((specifier == 'X') || (specifier == 'x') || (specifier == 'p')) + { + base = 16; + } + else if (specifier == 'o') + { + base = 8; + } + else + { + base = 10; + } + if (specifier == 'p') + { +#if defined(__MSDOS__) && \ + !defined(__PDOS386__) && \ + !defined(__SMALLERC__) && \ + !defined(__gnu_linux__) && \ + !defined(__ARM__) + precision = 9; +#else + precision = 8; +#endif + } + x = 0; + while (ulvalue > 0) + { + rem = (int)(ulvalue % base); + if (rem < 10) + { + work[x] = (char)('0' + rem); + } + else + { + if ((specifier == 'X') || (specifier == 'p')) + { + work[x] = (char)('A' + (rem - 10)); + } + else + { + work[x] = (char)('a' + (rem - 10)); + } + } + x++; +#if defined(__MSDOS__) && \ + !defined(__PDOS386__) && \ + !defined(__SMALLERC__) && \ + !defined(__gnu_linux__) && \ + !defined(__ARM__) + if ((x == 4) && (specifier == 'p')) + { + work[x] = ':'; + x++; + } +#endif + ulvalue = ulvalue / base; + } +#if defined(__MSDOS__) && \ + !defined(__PDOS386__) && \ + !defined(__SMALLERC__) && \ + !defined(__gnu_linux__) && \ + !defined(__ARM__) + if (specifier == 'p') + { + while (x < 5) + { + work[x] = (x == 4) ? ':' : '0'; + x++; + } + } +#endif + while (x < precision) + { + work[x] = '0'; + x++; + } + if (neg) + { + work[x++] = '-'; + } + else if (flagPlus) + { + work[x++] = '+'; + } + else if (flagSpace) + { + work[x++] = ' '; + } + if (flagZero) + { + fillCh = '0'; + } + else + { + fillCh = ' '; + } + y = x; + if (!flagMinus) + { + while (y < width) + { + outch(fillCh); + extraCh++; + y++; + } + } + if (flagHash && (toupper((unsigned char)specifier) == 'X')) + { + outch('0'); + outch('x'); + extraCh += 2; + } + x--; + while (x >= 0) + { + outch(work[x]); + extraCh++; + x--; + } + if (flagMinus) + { + while (y < width) + { + outch(fillCh); + extraCh++; + y++; + } + } + } + else if (strchr("eEgGfF", specifier) != NULL && specifier != 0) + { + if (precision < 0) + { + precision = 6; + } + vdbl = va_arg(*arg, double); + dblcvt(vdbl, specifier, width, precision, work); /* 'e','f' etc. */ + slen = strlen(work); + if ((flagSpace || flagPlus) && (work[0] != '-')) + { + slen++; + memmove(work + 1, work, slen); + if (flagSpace) + { + work[0] = ' '; + } + else if (flagPlus) + { + work[0] = '+'; + } + } + if (fq == NULL) + { + memcpy(s, work, slen); + s += slen; + } + else + { + fputs(work, fq); + } + extraCh += slen; + } + else if (specifier == 's') + { + svalue = va_arg(*arg, char *); + fillCh = ' '; + if (precision > 0) + { + char *p; + + p = memchr(svalue, '\0', precision); + if (p != NULL) + { + length = (int)(p - svalue); + } + else + { + length = precision; + } + } + else if (precision < 0) + { + length = strlen(svalue); + } + else + { + length = 0; + } + if (!flagMinus) + { + if (length < width) + { + extraCh += (width - length); + for (x = 0; x < (width - length); x++) + { + outch(fillCh); + } + } + } + for (x = 0; x < length; x++) + { + outch(svalue[x]); + } + extraCh += length; + if (flagMinus) + { + if (length < width) + { + extraCh += (width - length); + for (x = 0; x < (width - length); x++) + { + outch(fillCh); + } + } + } + } + *formt = format; + return (extraCh); +} + +__PDPCLIB_API__ int fputc(int c, FILE *stream) +{ + char buf[1]; + + stream = __INTFILE(stream); + +#if !defined(__MVS__) && !defined(__CMS__) + stream->quickBin = 0; + if ((stream->upto < (stream->endbuf - 2)) + && (stream->bufTech != _IONBF)) + { + if (stream->textMode) + { + if (c == '\n') + { + if (stream->bufTech == _IOFBF) + { + *stream->upto++ = '\r'; + *stream->upto++ = '\n'; + } + else + { + buf[0] = (char)c; + if (fwrite(buf, 1, 1, stream) != 1) + { + return (EOF); + } + } + } + else + { + *stream->upto++ = (char)c; + } + } + else + { + *stream->upto++ = (char)c; + } + } + else +#endif + { + buf[0] = (char)c; + if (fwrite(buf, 1, 1, stream) != 1) + { + return (EOF); + } + } + return (c); +} + +#if !defined(__MVS__) && !defined(__CMS__) +__PDPCLIB_API__ int fputs(const char *s, FILE *stream) +{ + size_t len; + size_t ret; + + stream = __INTFILE(stream); + + len = strlen(s); + ret = fwrite(s, len, 1, stream); + if (ret != 1) return (EOF); + else return (0); +} +#endif + +__PDPCLIB_API__ int remove(const char *filename) +{ + int ret; +#ifdef __OS2__ + APIRET rc; +#endif +#ifdef __WIN32__ + BOOL rc; +#endif + +#ifdef __AMIGA__ + DeleteFile(filename); + ret = 0; +#endif +#ifdef __OS2__ + rc = DosDelete((PSZ)filename); + if (rc != 0) + { + ret = 1; + errno = rc; + } + else + { + ret = 0; + } +#endif +#ifdef __WIN32__ + rc = DeleteFile(filename); + if (!rc) + { + ret = 1; + errno = GetLastError(); + } + else + { + ret = 0; + } +#endif +#ifdef __MSDOS__ + __remove(filename); + ret = 0; +#endif +#ifdef __MVS__ + char buf[FILENAME_MAX + 50]; + char *p; + + sprintf(buf, " DELETE %s", filename); + p = buf; + while (*p != '\0') + { + *p = toupper((unsigned char)*p); + p++; + } + ret = __idcams(strlen(buf), buf); +#endif +#ifdef __CMS__ + ret = cmsremove(filename); +#endif + return (ret); +} + +__PDPCLIB_API__ int rename(const char *old, const char *newnam) +{ + int ret; +#ifdef __OS2__ + APIRET rc; +#endif +#ifdef __WIN32__ + BOOL rc; +#endif + +#ifdef __AMIGA__ + Rename(old, newnam); + ret = 0; +#endif +#ifdef __OS2__ + rc = DosMove((PSZ)old, (PSZ)newnam); + if (rc != 0) + { + ret = 1; + errno = rc; + } + else + { + ret = 0; + } +#endif +#ifdef __WIN32__ + rc = MoveFile(old, newnam); + if (!rc) + { + ret = 1; + errno = GetLastError(); + } + else + { + ret = 0; + } +#endif +#ifdef __MSDOS__ + __rename(old, newnam); + ret = 0; +#endif +#ifdef __MVS__ + char buf[FILENAME_MAX + FILENAME_MAX + 50]; + char *p; + + sprintf(buf, " ALTER %s NEWNAME(%s)", old, newnam); + p = buf; + while (*p != '\0') + { + *p = toupper((unsigned char)*p); + p++; + } + ret = __idcams(strlen(buf), buf); +#endif +#ifdef __CMS__ + ret = cmsrename(old, newnam); +#endif + return (ret); +} + +__PDPCLIB_API__ int sprintf(char *s, const char *format, ...) +{ + va_list arg; + int ret; + + va_start(arg, format); + ret = vsprintf(s, format, arg); + va_end(arg); + return (ret); +} + +__PDPCLIB_API__ int vsprintf(char *s, const char *format, va_list arg) +{ + int ret; + + ret = vvprintf(format, arg, NULL, s); + if (ret >= 0) + { + *(s + ret) = '\0'; + } + return (ret); +} + +/* + +In fgets, we have the following possibilites... + +1. we found a genuine '\n' that terminated the search. +2. we hit the '\n' at the endbuf. +3. we hit the '\n' sentinel. + +*/ +#if !defined(__MVS__) && !defined(__CMS__) +__PDPCLIB_API__ char *fgets(char *s, int n, FILE *stream) +{ + char *p; + register char *t; + register char *u = s; + int c; + int processed; + size_t actualRead; + + stream = __INTFILE(stream); + + if (stream->quickText) + { + p = stream->upto + n - 1; + t = stream->upto; + if (p < stream->endbuf) + { + c = *p; + *p = '\n'; +#if defined(__OS2__) || defined(__WIN32__) + if (n < 8) + { +#endif + while ((*u++ = *t++) != '\n') ; /* tight inner loop */ +#if defined(__OS2__) || defined(__WIN32__) + } + else + { + register unsigned int *i1; + register unsigned int *i2; + register unsigned int z; + + i1 = (unsigned int *)t; + i2 = (unsigned int *)u; + while (1) + { + z = *i1; + if ((z & 0xffU) == '\n') break; + z >>= 8; + if ((z & 0xffU) == '\n') break; + z >>= 8; + if ((z & 0xffU) == '\n') break; + z >>= 8; + if ((z & 0xffU) == '\n') break; + *i2++ = *i1++; + } + t = (char *)i1; + u = (char *)i2; + while ((*u++ = *t++) != '\n') ; + } +#endif + *p = (char)c; + if (t <= p) + { + if (*(t - 2) == '\r') /* t is protected, u isn't */ + { + *(u - 2) = '\n'; + *(u - 1) = '\0'; + } + else + { + *u = '\0'; + } + stream->upto = t; + return (s); + } + else + { + processed = (int)(t - stream->upto) - 1; + stream->upto = t - 1; + u--; + } + } + else + { + while ((*u++ = *t++) != '\n') ; /* tight inner loop */ + if (t <= stream->endbuf) + { + if (*(t - 2) == '\r') /* t is protected, u isn't */ + { + *(u - 2) = '\n'; + *(u - 1) = '\0'; + } + else + { + *u = '\0'; + } + stream->upto = t; + return (s); + } + else + { + processed = (int)(t - stream->upto) - 1; + stream->upto = t - 1; + u--; + } + } + } + else + { + processed = 0; + } + + if (n < 1) + { + return (NULL); + } + if (n < 2) + { + *u = '\0'; + return (s); + } + if (stream->ungetCh != -1) + { + processed++; + *u++ = (char)stream->ungetCh; + stream->ungetCh = -1; + } + +#if defined(__gnu_linux__) || defined(__ARM__) + if (stream == stdin) + { + n--; + while (processed < n) + { + c = getc(stream); + if (c == EOF) break; + s[processed] = c; + if ((c == '\b') || (c == 0x7f)) + { + if (processed > 0) + { + putc('\b', stdout); + putc(' ', stdout); + putc('\b', stdout); + fflush(stdout); + processed--; + } + continue; + } + else + { + putc(c, stdout); + fflush(stdout); + } + if (c == '\n') break; + processed++; + } + if ((processed == 0) && (c == EOF)) return (NULL); + if ((processed < n) && !stream->noNl) + { + s[processed++] = '\n'; + } + s[processed] = '\0'; + return (s); + } +#endif + + while (1) + { + t = stream->upto; + p = stream->upto + (n - processed) - 1; + if (p < stream->endbuf) + { + c = *p; + *p = '\n'; + } + if (stream->noNl) + { + while (((*u++ = *t) != '\n') && (*t++ != '\r')) ; + if (*(u - 1) == '\n') + { + t++; + } + else + { + u--; + while ((*u++ = *t++) != '\n') ; + } + } + else + { + while ((*u++ = *t++) != '\n') ; /* tight inner loop */ + } + if (p < stream->endbuf) + { + *p = (char)c; + } + if (((t <= p) && (p < stream->endbuf)) + || ((t <= stream->endbuf) && (p >= stream->endbuf))) + { + if (stream->textMode) + { + if (stream->noNl) + { + if ((*(t - 1) == '\r') || (*(t - 1) == '\n')) + { + *(u - 1) = '\0'; + } + else + { + *u = '\0'; + } + } + /* can't inspect t because the \r may have been in + previous buffer */ + else if (((u - s) >= 2) && (*(u - 2) == '\r')) + { + *(u - 2) = '\n'; + *(u - 1) = '\0'; + } + else + { + *u = '\0'; + } + } + stream->upto = t; + if (stream->textMode) + { + stream->quickText = 1; + } + return (s); + } + else if (((t > p) && (p < stream->endbuf)) + || ((t > stream->endbuf) && (p >= stream->endbuf))) + { + int leave = 1; + + if (stream->textMode) + { + if (t > stream->endbuf) + { + if ((t - stream->upto) > 1) + { + if (*(t - 2) == '\r') /* t is protected, u isn't */ + { + processed -= 1; /* preparation for add */ + } + } + leave = 0; + } + else + { +#if defined(__ARM__) && !defined(__UNOPT__) +/* there is a bug where it seems to reach here, but I can't use + printf to debug it, because adding a printf makes the problem + disappear. So we'll just live with this for now */ +/* Note that the bug only occurs if optimization is switched on */ + printf(""); +#endif + if ((*(t - 2) == '\r') && (*(t - 1) == '\n')) + { + *(u - 2) = '\n'; + *(u - 1) = '\0'; + } + else + { + t--; + *(u - 1) = '\0'; + } + } + } + else if (t > stream->endbuf) + { + leave = 0; + } + else + { + *u = '\0'; + } + if (leave) + { + stream->upto = t; + if (stream->textMode) + { + stream->quickText = 1; + } + return (s); + } + } + processed += (int)(t - stream->upto) - 1; + u--; + stream->bufStartR += (stream->endbuf - stream->fbuf); + iread(stream, stream->fbuf, stream->szfbuf, &actualRead); + stream->endbuf = stream->fbuf + actualRead; + *stream->endbuf = '\n'; + if (actualRead == 0) + { + *u = '\0'; + if ((u - s) <= 1) + { + stream->eofInd = 1; + return (NULL); + } + else + { + return (s); + } + } + stream->upto = stream->fbuf; + } +} +#endif + +__PDPCLIB_API__ int ungetc(int c, FILE *stream) +{ + stream = __INTFILE(stream); + + if ((stream->ungetCh != -1) || (c == EOF)) + { + return (EOF); + } + stream->ungetCh = (unsigned char)c; + stream->quickText = 0; + stream->quickBin = 0; + return ((unsigned char)c); +} + +__PDPCLIB_API__ int fgetc(FILE *stream) +{ + unsigned char x[1]; + size_t ret; + + stream = __INTFILE(stream); + + ret = fread(x, 1, 1, stream); + if (ret == 0) + { + return (EOF); + } + return ((int)x[0]); +} + +__PDPCLIB_API__ int fseek(FILE *stream, long int offset, int whence) +{ + long oldpos; + long newpos; +#ifdef __AMIGA__ + long retpos; +#endif +#ifdef __OS2__ + ULONG retpos; + APIRET rc; +#endif +#ifdef __WIN32__ + DWORD retpos; +#endif +#ifdef __MSDOS__ + int ret; +#endif + + stream = __INTFILE(stream); + + oldpos = stream->bufStartR + (stream->upto - stream->fbuf); + if (stream->mode == __WRITE_MODE) + { + fflush(stream); + } + if (whence == SEEK_SET) + { + newpos = offset; + } + else if (whence == SEEK_CUR) + { + newpos = oldpos + offset; + } + + if (whence == SEEK_END) + { + char buf[1000]; + + if (stream->mode == __WRITE_MODE) + { + fseek(stream, oldpos, SEEK_SET); + } + while (fread(buf, sizeof buf, 1, stream) == 1) + { + /* do nothing */ + } + newpos = ftell(stream); + fseek(stream, newpos, SEEK_SET); + } + else if ((newpos >= stream->bufStartR) + /* when seeking repeatedly to the same location, the new position + will be pointing to the end of the buffer, so we want <= not < */ + && (newpos <= (stream->bufStartR + (stream->endbuf - stream->fbuf))) + && !stream->update + && !stream->quickBin + /* when we have just seeked, we will be at the end of the buffer, + but the data in the buffer is not actually valid, so we can't + adjust the pointer to make it valid. An exception is if they + are seeking to the same location. */ + && ((stream->upto != stream->endbuf) || (oldpos == newpos)) + && (stream->mode == __READ_MODE)) + { + stream->upto = stream->fbuf + (size_t)(newpos - stream->bufStartR); + } + else + { +#ifdef __AMIGA__ + retpos = Seek(stream->hfile, newpos, OFFSET_BEGINNING); + if (retpos == -1) + { + return (-1); + } + stream->endbuf = stream->fbuf + stream->szfbuf; + if (stream->mode == __READ_MODE) + { + stream->upto = stream->endbuf; + stream->bufStartR = newpos - stream->szfbuf; + } + else + { + stream->upto = stream->fbuf; + stream->bufStartR = newpos; + } +#endif +#ifdef __OS2__ + rc = DosSetFilePtr(stream->hfile, newpos, FILE_BEGIN, &retpos); + if ((rc != 0) || (retpos != newpos)) + { + errno = rc; + return (-1); + } + stream->endbuf = stream->fbuf + stream->szfbuf; + if (stream->mode == __READ_MODE) + { + stream->upto = stream->endbuf; + stream->bufStartR = newpos - stream->szfbuf; + } + else + { + stream->upto = stream->fbuf; + stream->bufStartR = newpos; + } +#endif +#ifdef __WIN32__ + retpos = SetFilePointer(stream->hfile, newpos, NULL, FILE_BEGIN); + if (retpos != newpos) + { + errno = GetLastError(); + return (-1); + } + stream->endbuf = stream->fbuf + stream->szfbuf; + if (stream->mode == __READ_MODE) + { + stream->upto = stream->endbuf; + stream->bufStartR = newpos - stream->szfbuf; + } + else + { + stream->upto = stream->fbuf; + stream->bufStartR = newpos; + } +#endif +#ifdef __MSDOS__ + ret = __seek(stream->hfile, newpos, SEEK_SET); +#if defined(__gnu_linux__) || defined(__ARM__) + if (ret == -1) return (ret); +#else + if (ret) return (ret); +#endif + stream->endbuf = stream->fbuf + stream->szfbuf; + if (stream->mode == __READ_MODE) + { + stream->upto = stream->endbuf; + stream->bufStartR = newpos - stream->szfbuf; + } + else + { + stream->upto = stream->fbuf; + stream->bufStartR = newpos; + } +#endif +#if defined(__MVS__) || defined(__CMS__) + char fnm[FILENAME_MAX]; + long int x; + size_t y; + char buf[1000]; + + oldpos = ftell(stream); + if (newpos < oldpos) + { + strcpy(fnm, "dd:"); + strcat(fnm, stream->ddname); + if (stream->pdsmem[0] != '\0') + { + sprintf(fnm + strlen(fnm), "(%s)", stream->pdsmem); + } + inseek = 1; + if (freopen(fnm, stream->modeStr, stream) == NULL) + { + stream->errorInd = 1; + return (-1); + } + inseek = 0; + oldpos = 0; + } + y = (newpos - oldpos) % sizeof buf; + fread(buf, y, 1, stream); + for (x = oldpos + y; x < newpos; x += sizeof buf) + { + fread(buf, sizeof buf, 1, stream); + } + if (stream->errorInd) + { + return (-1); + } +#endif + } + stream->justseeked = 1; + stream->quickBin = 0; + stream->quickText = 0; + stream->ungetCh = -1; + stream->eofInd = 0; + return (0); +} + +__PDPCLIB_API__ long int ftell(FILE *stream) +{ + stream = __INTFILE(stream); + + return (stream->bufStartR + (stream->upto - stream->fbuf)); +} + +__PDPCLIB_API__ int fsetpos(FILE *stream, const fpos_t *pos) +{ + stream = __INTFILE(stream); + + fseek(stream, *pos, SEEK_SET); + return (0); +} + +__PDPCLIB_API__ int fgetpos(FILE *stream, fpos_t *pos) +{ + stream = __INTFILE(stream); + + *pos = ftell(stream); + return (0); +} + +__PDPCLIB_API__ void rewind(FILE *stream) +{ + stream = __INTFILE(stream); + + fseek(stream, 0L, SEEK_SET); + return; +} + +__PDPCLIB_API__ void clearerr(FILE *stream) +{ + stream = __INTFILE(stream); + + stream->errorInd = 0; + stream->eofInd = 0; + return; +} + +__PDPCLIB_API__ void perror(const char *s) +{ + if ((s != NULL) && (*s != '\0')) + { + printf("%s: ", s); + } + if (errno == 0) + { + printf("No error has occurred\n"); + } + else + { + printf("An error has occurred\n"); + } + return; +} + +/* +NULL + F = allocate, setup +NULL + L = allocate, setup +NULL + N = ignore, return success +buf + F = setup +buf + L = setup +buf + N = ignore, return success +*/ + +__PDPCLIB_API__ int setvbuf(FILE *stream, char *buf, int mode, size_t size) +{ + char *mybuf; + + stream = __INTFILE(stream); + +#if defined(__MVS__) || defined(__CMS__) + /* don't allow mucking around with buffers on MVS or CMS */ + return (0); +#endif + + if (mode == _IONBF) + { + stream->bufTech = mode; +#ifdef __WIN32__ + if (stream == stdin) + { + DWORD dw; + + if (GetConsoleMode(stream->hfile, &dw)) + { + dw &= ~ENABLE_LINE_INPUT; + dw &= ~ENABLE_PROCESSED_INPUT; + SetConsoleMode(stream->hfile, dw); + } + } +#endif +#if defined(__PDOS386__) + if (stream == stdin) + { + unsigned int dw; + + PosGetDeviceInformation(0, &dw); + dw &= 0xff; + dw |= (1 << 5); + PosSetDeviceInformation(0, dw); + } +#endif + return (0); + } + if (buf == NULL) + { + if (size < 2) + { + return (-1); + } + mybuf = malloc(size + 8); + if (mybuf == NULL) + { + return (-1); + } + } + else + { + if (size < 10) + { + return (-1); + } + mybuf = buf; + stream->theirBuffer = 1; + size -= 8; + } + if (!stream->permfile) + { + free(stream->intBuffer); + } + stream->intBuffer = mybuf; + stream->fbuf = stream->intBuffer; + stream->szfbuf = size; + stream->endbuf = stream->fbuf + stream->szfbuf; + *stream->endbuf = '\n'; + stream->bufStartR = -(long)stream->szfbuf; + if (stream->mode == __WRITE_MODE) + { + stream->upto = stream->fbuf; + } + else + { + stream->upto = stream->endbuf; + } + stream->bufTech = mode; + if (!stream->textMode && (stream->bufTech == _IOLBF)) + { + stream->quickBin = 0; + } + return (0); +} + +__PDPCLIB_API__ int setbuf(FILE *stream, char *buf) +{ + int ret; + + stream = __INTFILE(stream); + + if (buf == NULL) + { + ret = setvbuf(stream, NULL, _IONBF, 0); + } + else + { + ret = setvbuf(stream, buf, _IOFBF, BUFSIZ); + } + return (ret); +} + +__PDPCLIB_API__ FILE *freopen(const char *filename, + const char *mode, + FILE *stream) +{ + stream = __INTFILE(stream); + + inreopen = 1; + fclose(stream); + + myfile = stream; + fopen(filename, mode); + if (err && !stream->permfile) + { + __userFiles[stream->intFno] = NULL; + free(stream); + } +#if defined(__MVS__) || defined(__CMS__) + else if (err) + { + free(stream); + /* need to protect against the app closing the file + which it is allowed to */ + if (stream == __stdin) + { + __stdin = NULL; + } + else if (stream == __stdout) + { + __stdout = NULL; + } + else if (stream == __stderr) + { + __stderr = NULL; + } + } +#endif + inreopen = 0; + if (err) + { + return (NULL); + } + return (stream); +} + +__PDPCLIB_API__ int fflush(FILE *stream) +{ +#if defined(__MVS__) || defined(__CMS__) + if ((stream->mode == __WRITE_MODE) && (stream->upto != stream->fbuf)) + { + if (stream->reallyu) + { + size_t last; + + last = stream->upto - stream->fbuf; + begwrite(stream, last); + memcpy(dptr, stream->fbuf, last); + finwrite(stream); + stream->upto = stream->fbuf; + } + else if ((stream == __stdout) || (stream == __stderr)) + { + fputc('\n', stream); + } + } +#else + size_t actualWritten; + + stream = __INTFILE(stream); + + if ((stream->upto != stream->fbuf) && (stream->mode == __WRITE_MODE)) + { + iwrite(stream, + stream->fbuf, + stream->upto - stream->fbuf, + &actualWritten); + if (stream->errorInd) return (EOF); + stream->bufStartR += actualWritten; + stream->upto = stream->fbuf; + } +#endif + return (0); +} + +__PDPCLIB_API__ char *tmpnam(char *s) +{ +#if defined(__MVS__) || defined(__CMS__) + static char buf[] = "dd:ZZZZZZZA"; +#else + static char buf[] = "ZZZZZZZA.$$$"; +#endif + +#if defined(__MVS__) || defined(__CMS__) + buf[10]++; +#else + buf[7]++; +#endif + if (s == NULL) + { + return (buf); + } + strcpy(s, buf); + return (s); +} + +__PDPCLIB_API__ FILE *tmpfile(void) +{ +#if defined(__MVS__) || defined(__CMS__) + return (fopen("dd:ZZZZZZZA", "wb+")); +#else + FILE *fu; + fu = fopen("ZZZZZZZA.$$$", "wb+"); + if (fu != NULL) + { + fu->istemp = 1; + } + return (fu); +#endif +} + +__PDPCLIB_API__ int fscanf(FILE *stream, const char *format, ...) +{ + va_list arg; + int ret; + + stream = __INTFILE(stream); + + va_start(arg, format); + ret = vvscanf(format, arg, stream, NULL); + va_end(arg); + return (ret); +} + +__PDPCLIB_API__ int scanf(const char *format, ...) +{ + va_list arg; + int ret; + + va_start(arg, format); + ret = vvscanf(format, arg, __stdin, NULL); + va_end(arg); + return (ret); +} + +__PDPCLIB_API__ int sscanf(const char *s, const char *format, ...) +{ + va_list arg; + int ret; + + va_start(arg, format); + ret = vvscanf(format, arg, NULL, s); + va_end(arg); + return (ret); +} + +/* vvscanf - the guts of the input scanning */ +/* several mods by Dave Edwards */ +static int vvscanf(const char *format, va_list arg, FILE *fp, const char *s) +{ + int ch; + int fin = 0; + int cnt = 0; + char *cptr; + int *iptr; + void **vptr; + unsigned int *uptr; + long *lptr; + unsigned long *luptr; + short *hptr; + unsigned short *huptr; + double *dptr; + float *fptr; + long startpos; + const char *startp; + int skipvar; /* nonzero if we are skipping this variable */ + int modlong; /* nonzero if "l" modifier found */ + int modshort; /* nonzero if "h" modifier found */ + int width; /* maximum chars to read */ + int informatitem; /* nonzero if % format item started */ + /* informatitem is 1 if we have processed "%l" but not the + type letter (s,d,e,f,g,...) yet. */ + + if (fp != NULL) + { + startpos = ftell(fp); + } + else + { + startp = s; + } + inch(); + informatitem = 0; /* init */ + /* don't bail out at end of data as there may be a %n */ + /*if ((fp != NULL && ch == EOF) || (fp == NULL && ch == 0)) return EOF; */ + /* initially at EOF or end of string */ + while (!fin) + { + if (*format == '\0') + { + fin = 1; + } + else if (*format == '%' || informatitem) + { + if(*format=='%') /* starting a format item */ + { + format++; + modlong=0; /* init */ + modshort=0; + skipvar = 0; + width = 0; + if (*format == '*') + { + skipvar = 1; + format++; + } + } + if (*format == '%') /* %% */ + { + if (ch != '%') return (cnt); + inch(); + informatitem=0; + } + else if (*format == 'l') + { + /* Type modifier: l (e.g. %ld) */ + modlong=1; + informatitem=1; + } + else if (*format == 'h') + { + /* Type modifier: h (short int) */ + modshort=1; + informatitem=1; + } + else if (isdigit((unsigned char)*format)) + { + width = width * 10 + (*format - '0'); + informatitem = 1; + } + else /* process a type character: */ + { + informatitem=0; /* end of format item */ + if (*format == 's') + { + if (!skipvar) + { + cptr = va_arg(arg, char *); + } + /* Skip leading whitespace: */ + while (ch>=0 && isspace(ch)) inch(); + if ((fp != NULL && ch == EOF) || (fp == NULL && ch == 0)) + /* at EOF or end of string */ + { + if (!skipvar) + { + *cptr = 0; /* give a null string */ + } + continue; + } + else + { + for(;;) + { + if (isspace(ch)) break; + if ((fp != NULL && ch == EOF) + || (fp == NULL && ch == 0)) + { + break; + } + if (!skipvar) + { + *cptr++ = (char)ch; + } + inch(); + } + if (!skipvar) + { + *cptr = '\0'; + } + cnt++; + } + } + else if (*format == '[') + { + int reverse = 0; + int found; + const char *first; + const char *last; + size_t size; + size_t mcnt = 0; + + if (!skipvar) + { + cptr = va_arg(arg, char *); + } + format++; + if (*format == '^') + { + reverse = 1; + format++; + } + if (*format == '\0') break; + first = format; + format++; + last = strchr(format, ']'); + if (last == NULL) return (cnt); + size = (size_t)(last - first); + while (1) + { + /* note that C90 doesn't require special + processing for '-' so it hasn't been + added */ + found = (memchr(first, ch, size) != NULL); + if (found && reverse) break; + if (!found && !reverse) break; + if (!skipvar) + { + *cptr++ = (char)ch; + } + mcnt++; + inch(); + /* if at EOF or end of string, bug out */ + if ((fp != NULL && ch == EOF) + || (fp == NULL && ch == 0)) + { + break; + } + } + if (mcnt > 0) + { + if (!skipvar) + { + *cptr++ = '\0'; + } + cnt++; + } + else + { + break; + } + format = last + 1; + } + else if (*format == 'c') + { + if (!skipvar) + { + cptr = va_arg(arg, char *); + } + if ((fp != NULL && ch == EOF) + || (fp == NULL && ch == 0)) + { + /* do nothing */ + } + else + { + if (!skipvar) + { + *cptr = ch; + } + cnt++; + inch(); + } + } + else if (*format == 'n') + { + uptr = va_arg(arg, unsigned int *); + if (fp != NULL) + { + *uptr = (unsigned int)(ftell(fp) - startpos); + } + else + { + /* we need a -1 because s will point to + the character after the NUL */ + *uptr = (unsigned int)(s - startp - 1); + } + } + else if (*format == 'd' || *format == 'u' + || *format == 'x' || *format == 'o' + || *format == 'p' + || *format == 'i') + { + int neg = 0; + unsigned long x = 0; + int undecided = 0; + int base = 10; + int mcnt = 0; + + if (*format == 'x') base = 16; + else if (*format == 'p') base = 16; + else if (*format == 'o') base = 8; + else if (*format == 'i') base = 0; + if (!skipvar) + { + if ((*format == 'd') || (*format == 'i')) + { + if (modlong) lptr = va_arg(arg, long *); + else if (modshort) hptr = va_arg(arg, short *); + else iptr = va_arg(arg, int *); + } + else if (*format == 'p') + { + vptr = va_arg(arg, void **); + } + else + { + if (modlong) luptr = va_arg(arg, unsigned long *); + else if (modshort) huptr = + va_arg(arg, unsigned short *); + else uptr = va_arg(arg, unsigned int *); + } + } + /* Skip leading whitespace: */ + while (ch>=0 && isspace(ch)) inch(); + if (ch == '-') + { + neg = 1; + inch(); + } + else if(ch == '+') inch(); + + /* this logic is the same as strtoul so if you + change this, change that one too */ + + if (base == 0) + { + undecided = 1; + } + while (!((fp != NULL && ch == EOF) + || (fp == NULL && ch == 0))) + { + if (isdigit((unsigned char)ch)) + { + if (base == 0) + { + if (ch == '0') + { + base = 8; + } + else + { + base = 10; + undecided = 0; + } + } + x = x * base + (ch - '0'); + inch(); + } +/* DOS has a ':' in the pointer - skip that */ +#if defined(__MSDOS__) && \ + !defined(__PDOS386__) && \ + !defined(__gnu_linux__) && \ + !defined(__ARM__) + else if ((*format == 'p') && (ch == ':')) + { + inch(); + } +#endif + else if (isalpha((unsigned char)ch)) + { + if ((ch == 'X') || (ch == 'x')) + { + if ((base == 0) || ((base == 8) && undecided)) + { + base = 16; + undecided = 0; + inch(); + } + else if (base == 16) + { + /* hex values are allowed to have an + optional 0x */ + inch(); + } + else + { + break; + } + } + else if (base <= 10) + { + break; + } + else + { + x = x * base + + (toupper((unsigned char)ch) - 'A') + 10; + inch(); + } + } + else + { + break; + } + mcnt++; + } + + /* end of strtoul logic */ + + /* If we didn't get any characters, don't go any + further */ + if (mcnt == 0) + { + break; + } + + + if (!skipvar) + { + if ((*format == 'd') || (*format == 'i')) + { + long lval; + + if (neg) + { + lval = (long)-x; + } + else + { + lval = (long)x; + } + if (modlong) *lptr=lval; + /* l modifier: assign to long */ + else if (modshort) *hptr = (short)lval; + /* h modifier */ + else *iptr=(int)lval; + } + else if (*format == 'p') + { + *vptr = (void *)x; + } + else + { + if (modlong) *luptr = (unsigned long)x; + else if (modshort) *huptr = (unsigned short)x; + else *uptr = (unsigned int)x; + } + } + cnt++; + } + else if (*format=='e' || *format=='f' || *format=='g' || + *format=='E' || *format=='G') + { + /* Floating-point (double or float) input item */ + int negsw1,negsw2,dotsw,expsw,ndigs1,ndigs2,nfdigs; + int ntrailzer,expnum,expsignsw; + double fpval,pow10; + + if (!skipvar) + { + if (modlong) dptr = va_arg(arg, double *); + else fptr = va_arg(arg, float *); + } + negsw1=0; /* init */ + negsw2=0; + dotsw=0; + expsw=0; + ndigs1=0; + ndigs2=0; + nfdigs=0; + ntrailzer=0; /* # of trailing 0's unaccounted for */ + expnum=0; + expsignsw=0; /* nonzero means done +/- on exponent */ + fpval=0.0; + /* Skip leading whitespace: */ + while (ch>=0 && isspace(ch)) inch(); + if (ch=='-') + { + negsw1=1; + inch(); + } + else if (ch=='+') inch(); + while (ch>0) + { + if (ch=='.' && dotsw==0 && expsw==0) dotsw=1; + else if (isdigit(ch)) + { + if(expsw) + { + ndigs2++; + expnum=expnum*10+(ch-'0'); + } + else + { + /* To avoid overflow or loss of precision, + skip leading and trailing zeros unless + really needed. (Automatic for leading + 0's, since 0.0*10.0 is 0.0) */ + ndigs1++; + if (dotsw) nfdigs++; + if (ch=='0' && fpval!=0.) + { + /* Possible trailing 0 */ + ntrailzer++; + } + else + { + /* Account for any preceding zeros */ + while (ntrailzer>0) + { + fpval = fpval * 10; + ntrailzer--; + } + fpval=fpval*10.0+(ch-'0'); + } + } + } + else if ((ch=='e' || ch=='E') && expsw==0) expsw=1; + else if ((ch=='+' || ch=='-') && expsw==1 + && ndigs2==0 && expsignsw==0) + { + expsignsw=1; + if (ch=='-') negsw2=1; + } + else break; /* bad char: end of input item */ + inch(); + } + /* don't finish at end of input there may be a %n */ + /*if ((fp != NULL && ch == EOF) + || (fp == NULL && ch == 0)) fin=1;*/ + /* Check for a valid fl-pt value: */ + if (ndigs1==0 || (expsw && ndigs2==0)) return(cnt); + /* Complete the fl-pt value: */ + if (negsw2) expnum=-expnum; + expnum+=ntrailzer-nfdigs; + if (expnum!=0 && fpval!=0.0) + { + negsw2=0; + if (expnum<0) + { + expnum=-expnum; + negsw2=1; + } + /* Multiply or divide by 10.0**expnum, using + bits of expnum (fast method) */ + pow10=10.0; + for (;;) + { + if (expnum & 1) /* low-order bit */ + { + if (negsw2) fpval = fpval / pow10; + else fpval = fpval * pow10; + } + expnum>>=1; /* shift right 1 bit */ + if (expnum==0) break; + pow10 = pow10 * pow10; + /* 10.**n where n is power of 2 */ + } + } + if (negsw1) fpval=-fpval; + if (!skipvar) + { + /* l modifier: assign to double */ + if (modlong) *dptr=fpval; + else *fptr=(float)fpval; + } + cnt++; + } + } + } + else if (isspace((unsigned char)(*format))) + { + /* Whitespace char in format string: skip next whitespace + chars in input data. This supports input of multiple + data items. */ + while (ch>=0 && isspace(ch)) + { + inch(); + } + } + else /* some other character in the format string */ + { + if (ch != *format) return (cnt); + inch(); + } + format++; + /* don't bail out at end of string as there may be a %n */ + /*if ((fp != NULL && ch == EOF) || (fp == NULL && ch == 0)) fin = 1;*/ + /* EOF */ + } + if (fp != NULL) ungetc(ch, fp); + return (cnt); +} + +__PDPCLIB_API__ char *gets(char *s) +{ + char *ret; + + __stdin->quickText = 0; + __stdin->noNl = 1; + ret = fgets(s, INT_MAX, __stdin); + __stdin->noNl = 0; + __stdin->quickText = 1; + return (ret); +} + +__PDPCLIB_API__ int puts(const char *s) +{ + int ret; + + ret = fputs(s, __stdout); + if (ret == EOF) + { + return (ret); + } + return (putc('\n', __stdout)); +} + +/* The following functions are implemented as macros */ + +#undef getchar +#undef putchar +#undef getc +#undef putc +#undef feof +#undef ferror + +__PDPCLIB_API__ int getc(FILE *stream) +{ + stream = __INTFILE(stream); + + return (fgetc(stream)); +} + +__PDPCLIB_API__ int putc(int c, FILE *stream) +{ + stream = __INTFILE(stream); + + return (fputc(c, stream)); +} + +__PDPCLIB_API__ int getchar(void) +{ + return (getc(__stdin)); +} + +__PDPCLIB_API__ int putchar(int c) +{ + return (putc(c, __stdout)); +} + +__PDPCLIB_API__ int feof(FILE *stream) +{ + stream = __INTFILE(stream); + + return (stream->eofInd); +} + +__PDPCLIB_API__ int ferror(FILE *stream) +{ + stream = __INTFILE(stream); + + return (stream->errorInd); +} + +#if 0 +Design of MVS i/o routines + +The broad objectives of the MVS implementation are as follows: + +1. An application doing a binary fread equal to LRECL should +get speed equivalent to doing the GET macro. + +2. An application doing a text fgets equal to or greater than +LRECL should get speed equivalent to the GET macro. + +3. Variable-block files are encapsulated in terms of RDW files. +RDW files are what is produced by certain implementations of +ftp when the "rdw" option is chosen. Data is stored on the PC +or whatever as a 2-byte big-endian length, then 2 NUL bytes, +then the data. See the S/380 documentation that comes with +MVS/380 for more information on this format. So a binary read +of a V or VB file will produce a RDW stream (basically, BDWs +are stripped, but not RDWs). + +4. If a binary copy is done from a V dataset to a U dataset, +the RDW data stream will be preserved exactly. If the U data +set is subsequently copied to an F dataset, there will +necessarily be NUL-padding. If this dataset is then copied +to a V dataset, the extraneous NULs (which comprise an +invalid RDW) will be silently ignored/stripped. + +5. If a text copy is done from a V dataset to a U dataset, +the U dataset will get x'15' (EBCDIC newline) characters +added. The RDW will be stripped. Trailing spaces will be +preserved. With one exception - a single blank character +on a line will be removed. If this dataset is then copied +to a F dataset, there will be trailing spaces added to fit +the LRECL. If this dataset is then copied to a V dataset, +the trailing spaces will all be truncated. If a line is +empty, a single blank character will be inserted. + +6. If a long line is being written in text mode, it will +be silently truncated regardless of whether the output file +is RECFM=V or F. In binary mode, when writing to a RECFM=F, +the data simply gets wrapped to the next record. For a binary +write to a RECFM=V where the RDW signals a length greater +than the LRECL, the record will be silently truncated. If +writing to a RECFM=V in binary mode with insufficient data +to match the RDW, it is considered an error. Similarly, +more data than the RDW will cause a new record to be +started. An invalid RDW in the data stream is considered +a write error. + +7. In RECFM=U datasets, the block boundary is always ignored. +When the application writes a newline character to the data +stream, it is treated as just another character and dutifully +written out. Newlines are never added or stripped by the +C library when a block boundary is encountered - not even in +text mode. This marks a break from IBMs behaviour and is +required in order to be able to read a RECFM=U in binary +mode (e.g. the way zip would) and still preserve newline +characters if the file being read happens to be a text file +(as opposed to e.g. another zip file - something zip has +no way of knowing). NULs encountered when reading +a RECFM=U in text mode may be stripped. Similarly, trailing +NULs in the application data stream are stripped. This way, +someone doing a binary copy of a file, and who has stored +it in a RECFM=F dataset (where NUL padding is necessary), +and then has copied it into a RECFM=U (where NULs must +necessarily be preserved if doing binary copies) will be +stripped by the first person who does a text read or +write. + +8. DCB information provided by the user in JCL, or on a +dataset, always has priority and the C library will adjust +around that. Only if there is no existing DCB information +available anywhere will the C library provide a default, +which is RECFM=VB,LRECL=255,BLKSIZE=6233 for text, and +RECFM=U,LRECL=0,BLKSIZE=6233 for binary. This blocksize +is traditionally considered to be the universal blocksize. + +9. An open of a PDS with no member given will read the +directory. Any attempt to open a PDS directory for writing +will fail. + +10. RECFM=U allows you to preserve the exact length of +data. RECFM=FB with a LRECL of 1 also achieves this, but +is much more overhead. A special exception may be made in +the future for binary reading of FB datasets to provide +the same performance as RECFM=U. + +11. Data is processed by the C library one record at a time. +There is an intention to change to block reading in the +future now that the assembler (for MVS at least) has that +flexibility. + + +The implementation has been based around 4 different processing +concepts: + +1. Fixed text. +2. Fixed binary. +3. Variable text. +4. Variable binary. + +RECFM=U was grafted on in terms of a faked variable binary +for reading and a faked fixed binary for writing. There is +a "reallyu" to record the fact that it was really U, and +at various points the processing changes slightly to cope +with that. There is also a "reallyt" variable that notes +the fact that it was originally a text mode request, but +that has been switched (to avoid translation of newlines +into spaces or RDW etc). + +The code has been designed to work in both locate mode +and in move mode, although it would be rare for anyone to +want to use locate mode, and support for that may drop at +some point. + + +The main assembler functions are as follows (note that +__aopen in C becomes @@AOPEN in assembler): + +void *__aopen(const char *ddname, + int *mode, + int *recfm, + int *lrecl, + int *blksize, + void **asmbuf, + const char *member); + +This function opens an 8-character (right-padded with spaces) +DDNAME. For dynamically-allocated datasets, a previous call +to __dynal would have been done to a generated ddname of the +form PDP001HD where 001 corresponds to a spare slot. The +mode is passed by address. It is typically simply set to +read or write, but if it is set to read, blocked, then the +assembler routines have the option of setting this to just +read, e.g. if the device is a terminal and block mode is +inappropriate. + +Mode values are as follows: +0 = input (read) +1 = output (write) +2 = update (read and write, initally read) +3 = append +4 = inout = read and write, initially read (same as update) +5 = outin = write, then reread + +Additional mode flags: +0x08 = Use EXCP if input file is tape. +0x10 = Use block mode. +0x80 = Use GETLINE/PUTLINE if TSO terminal detected + +recfm values are: +0 = fixed +1 = variable +2 = undefined +And again, the C program provides defaults but the assembler +function has the final say. + +lrecl = default record/line length set by caller, with +assembler deciding what to really do. + +blksize - default block size set by caller, assembler deciding +what to really use. + +asmbuf - if file is opened in write mode, in the normal move +mode, then this will be set to point to a buffer large enough +to store the lrecl. Storage will be below the line so it is +suitable for doing I/O from. Buffer will be freed when the +dataset is closed. + +member - pointer to a PDS member to be opened. Member should +be 8 characters, padded with spaces. If member is set to NULL, +then this open is not for a member of a PDS (so this parameter +is probably normally NULL). + +__aopen returns a "handle" on success, or a negative value +(when cast to int) on failure. These values will probably +be unclumped in the future. + + +int __aread(void *handle, void *buf, size_t *len); + +This function takes the handle previously returned from __aopen +and reads into the provided buffer a single record. It is +assumed that the buffer is big enough to hold the LRECL +previously returned by __aopen. *len will contain the length +of the actual record returned, e.g. if RECFM=U, then while +reading each record (block), the length might change. +In the case of RECFM=V, the record includes a RDW. + +__aread returns 0 on success, non-zero on failure. + + +int __awrite(void *handle, unsigned char **buf, size_t *sz); + +This function takes the handle previously returned from __aopen +and writes the buffer pointed to by *buf. If operating in locate +mode, it actually sets the *buf to where to write to, so the +application can subsequently write there. *sz provides the +length of the data to write, which is particularly necessary +for RECFM=U where there is no other way to know the length. +In the future, the assembler may update the size to reflect +actual written in the case of a partial write. + +__awrite returns 0 on success, non-zero for failure. + + +void __aclose(void *handle); + +This function takes the handle previously returned from __aopen +and closes the file and releases any buffers that were allocated +in the open. + + + +Here is some old documentation that might be worth updating +one day: + +in/out function rec-type mode method +in fread fixed bin loop reading, remember remainder +in fread fixed text loop reading + truncing, remember rem +in fread var bin loop reading (+ len), remember remainder +in fread var text loop reading (+ len), remember remainder +in fgets fixed bin read, scan, remember remainder +in fgets fixed text read, trunc, remember remainder +in fgets var bin read, scan, rr +in fgets var text read, rr +in fgetc fixed bin read, rr +in fgetc fixed text read, trunc, rr +in fgetc var bin read, rr +in fgetc var text read, rr + +out fwrite fixed bin loop doing put, rr +out fwrite fixed text search newline, copy + pad, put, rr +out fwrite var bin if nelem != 1 copy to max lrecl +out fwrite var text loop search nl, put, rr +out fputs fixed bin loop doing put, rr +out fputs fixed text search newline, copy + pad, put, rr +out fputs var bin put +out fputs var text search newline, put, copy rem +out fputc fixed bin copy to rr until rr == lrecl +out fputc fixed text copy to rr until newline, then pad +out fputc var bin copy to rr until rr == lrecl +out fputc var text copy to rr until newline + + +fread: if quickbin, if read elem size == lrecl, doit +fgets: if variable record + no remainder + if buffer > record size, copy + add newline +#endif + +#if defined(__MVS__) || defined(__CMS__) +__PDPCLIB_API__ char *fgets(char *s, int n, FILE *stream) +{ + unsigned char *eptr; + size_t len; + int cnt; + int c; + + if (stream->quickText) + { + if (__aread(stream->hfile, &dptr) != 0) + { + stream->eofInd = 1; + stream->quickText = 0; + return (NULL); + } + len = ((dptr[0] << 8) | dptr[1]) - 4; + if ((len == 1) && (dptr[4] == ' ')) + { + len = 0; + } + if (n > (len + 1)) + { + memcpy(s, dptr + 4, len); + memcpy(s + len, "\n", 2); + stream->bufStartR += len + 1; + return (s); + } + else + { + memcpy(stream->fbuf, dptr + 4, len); + stream->upto = stream->fbuf; + stream->endbuf = stream->fbuf + len; + *(stream->endbuf++) = '\n'; + stream->quickText = 0; + } + } + + if (stream->eofInd) + { + return (NULL); + } + + switch (stream->style) + { + case FIXED_TEXT: + if ((stream->endbuf == stream->fbuf) + && (n > (stream->lrecl + 2))) + { + if (__aread(stream->hfile, &dptr) != 0) + { + stream->eofInd = 1; + return (NULL); + } + eptr = dptr + stream->lrecl - 1; + while ((*eptr == ' ') && (eptr >= dptr)) + { + eptr--; + } + eptr++; + memcpy(s, dptr, eptr - dptr); + if (stream->noNl) + { + s[eptr - dptr] = '\0'; + } + else + { + memcpy(s + (eptr - dptr), "\n", 2); + } + stream->bufStartR += (eptr - dptr) + 1; + return (s); + } + break; + + default: + break; + + } + + /* Ok, the obvious optimizations have been done, + so now we switch to the slow generic version */ + + n--; + cnt = 0; + while (cnt < n) + { + c = getc(stream); + if (c == EOF) break; + s[cnt] = c; + if ((stream == stdin) && stream->reallyu) + { + if (c == '\b') + { + if (cnt > 0) + { + putc('\b', stdout); + putc(' ', stdout); + putc('\b', stdout); + fflush(stdout); + cnt--; + } + continue; + } + else + { + putc(c, stdout); + fflush(stdout); + } + } + if (c == '\n') break; + cnt++; + } + if ((cnt == 0) && (c == EOF)) return (NULL); + if ((cnt < n) && !stream->noNl) + { + s[cnt++] = '\n'; + } + s[cnt] = '\0'; + return (s); +} + +__PDPCLIB_API__ int fputs(const char *s, FILE *stream) +{ + const char *p; + size_t len; + + if (stream->quickText) + { + p = strchr(s, '\n'); + if (p != NULL) + { + len = p - s; + if (len > stream->lrecl) + { + len = stream->lrecl; + } + begwrite(stream, len + 4); + memcpy(dptr + 4, s, len); + dptr[0] = (len + 4) >> 8; + dptr[1] = (len + 4) & 0xff; + dptr[2] = 0; + dptr[3] = 0; + finwrite(stream); + stream->bufStartR += (len + 1); + if (*(p + 1) == '\0') + { + return (len + 1); + } + s = p + 1; + stream->quickText = 0; + } + } + switch (stream->style) + { + case FIXED_TEXT: + len = strlen(s); + if (len > 0) + { + len--; + if (((strchr(s, '\n') - s) == len) + && (stream->upto == stream->fbuf) + && (len <= stream->lrecl)) + { + begwrite(stream, stream->lrecl); + memcpy(dptr, s, len); + memset(dptr + len, ' ', stream->szfbuf - len); + finwrite(stream); + stream->bufStartR += len; + } + else + { + fwrite(s, len + 1, 1, stream); + } + } + break; + + default: + len = strlen(s); + fwrite(s, len, 1, stream); + break; + } + return (0); +} + +__PDPCLIB_API__ size_t fwrite(const void *ptr, + size_t size, + size_t nmemb, + FILE *stream) +{ + size_t bytes; + size_t sz; + char *p; + int x; + + if (stream->quickBin) + { + if ((nmemb == 1) && (size == stream->lrecl)) + { + begwrite(stream, stream->lrecl); + memcpy(dptr, ptr, size); + finwrite(stream); + stream->bufStartR += size; + return (1); + } + else + { + stream->quickBin = 0; + } + } + switch (stream->style) + { + case FIXED_BINARY: + bytes = nmemb * size; + /* if we've exceed our buffer we need to write out + a record - but if we haven't written any data to + our internal buffer yet, don't bother going through + this code, it'll be handled later. */ + if (((stream->endbuf - stream->upto) <= bytes) + && (stream->upto != stream->fbuf)) + { + /* ready to write a record - request some space + from MVS */ + begwrite(stream, stream->lrecl); + sz = stream->endbuf - stream->upto; + memcpy(dptr, stream->fbuf, stream->szfbuf - sz); + memcpy(dptr + stream->szfbuf - sz, ptr, sz); + finwrite(stream); + ptr = (char *)ptr + sz; + bytes -= sz; + stream->upto = stream->fbuf; + stream->bufStartR += stream->szfbuf; + } + /* At this point, the internal buffer is empty if the + number of bytes to write is still greater than the + internal buffer. In which case, start writing directly + to an MVS-provided area. */ + while (bytes >= stream->szfbuf) + { + begwrite(stream, stream->lrecl); + memcpy(dptr, ptr, stream->szfbuf); + finwrite(stream); + ptr = (char *)ptr + stream->szfbuf; + bytes -= stream->szfbuf; + stream->bufStartR += stream->szfbuf; + } + + /* RECFM=U to a text file should write up to the most + recent newline */ + if (stream->line_buf && stream->reallyu && stream->reallyt) + { + p = (char *)ptr + bytes - 1; + /* look for a newline somewhere in this new data */ + /* since we write on both buffer full and newline + found conditions */ + while (p >= (char *)ptr) + { + if (*p == '\n') break; + p--; + } + /* found a newline, write up to this point, including + any data that may be in our internal buffer */ + if (p >= (char *)ptr) + { + p++; /* get past the newline */ + sz = stream->upto - stream->fbuf; + stream->upto = stream->fbuf; + begwrite(stream, sz + (p - (char *)ptr)); + memcpy(dptr, stream->fbuf, sz); + memcpy(dptr + sz, ptr, (p - (char *)ptr)); + finwrite(stream); + bytes -= (p - (char *)ptr); + stream->bufStartR += (p - (char *)ptr); + ptr = p; + stream->upto = stream->fbuf; + } + } + + /* any remainder needs to go into the internal buffer */ + memcpy(stream->upto, ptr, bytes); + stream->upto += bytes; + break; + + case VARIABLE_BINARY: + bytes = nmemb * size; + while (bytes > 0) + { + int fulllen; + + if (stream->errorInd) + { + nmemb = 0; + break; + } + sz = stream->upto - stream->fbuf; + if (sz < 4) + { + if ((bytes + sz) < 4) + { + memcpy(stream->upto, ptr, bytes); + stream->upto += bytes; + bytes = 0; + break; + } + else + { + memcpy(stream->upto, ptr, 4 - sz); + ptr = (char *)ptr + (4 - sz); + bytes -= (4 - sz); + stream->upto += (4 - sz); + sz = 4; + if (memcmp(stream->fbuf + 2, "\0\0", 2) != 0) + { + stream->errorInd = 1; + nmemb = 0; + break; + } + fulllen = (stream->fbuf[0] << 8) | stream->fbuf[1]; + if (fulllen == 0) + { + /* here we allow for the possibility that + they are copying a data source that has + terminating NULs added - so long as all + remaining charactes are NUL, it will be + allowed. Otherwise we rely on the above + validation to catch a problem - checking + 2 bytes at a time, which shouldn't be a + problem since this is only at the end of + the file */ + stream->upto = stream->fbuf + 2; + continue; + } + else if (fulllen < 4) + { + stream->errorInd = 1; + nmemb = 0; + break; + } + } + } + + /* we have 4 bytes, validated */ + fulllen = (stream->fbuf[0] << 8) | stream->fbuf[1]; + + /* If we have enough data, write it out */ + if ((sz + bytes) >= fulllen) + { + /* silently truncate long records to give + user more flexibility */ + if (fulllen > (stream->lrecl + 4)) + { + stream->fbuf[0] = (stream->lrecl + 4) >> 8; + stream->fbuf[1] = (stream->lrecl + 4) & 0xff; + begwrite(stream, stream->lrecl + 4); + if (sz >= (stream->lrecl + 4)) + { + memcpy(dptr, stream->fbuf, stream->lrecl + 4); + } + else + { + memcpy(dptr, stream->fbuf, sz); + memcpy(dptr + sz, ptr, stream->lrecl + 4 - sz); + } + } + else if (fulllen != 0) + { + begwrite(stream, fulllen); + memcpy(dptr, stream->fbuf, sz); + memcpy(dptr + sz, ptr, fulllen - sz); + } + if (fulllen != 0) + { + finwrite(stream); + } + stream->bufStartR += fulllen; + stream->upto = stream->fbuf; + bytes -= (fulllen - sz); + ptr = (char *)ptr + (fulllen - sz); + } + + /* less data than required, store it, without + overflowing our buffer */ + else if ((sz + bytes) > stream->lrecl) + { + memcpy(stream->upto, + ptr, + stream->lrecl - sz); + /* here we allow upto to exceed our buffer. + shouldn't be a problem as we never write + to that memory. alternative is to make + BUFSIZ 64k. */ + stream->upto += bytes; + ptr = (char *)ptr + bytes; + bytes = 0; + } + + /* enough room to fit data */ + else + { + memcpy(stream->upto, ptr, bytes); + stream->upto += bytes; + ptr = (char *)ptr + bytes; + bytes = 0; + } + } + break; + + case FIXED_TEXT: + bytes = nmemb * size; + p = memchr(ptr, '\n', bytes); + if (p != NULL) + { + sz = p - (char *)ptr; + bytes -= sz + 1; + if (stream->upto == stream->fbuf) + { + if (sz > stream->lrecl) + { + sz = stream->lrecl; + } + begwrite(stream, stream->lrecl); + memcpy(dptr, ptr, sz); + memset(dptr + sz, ' ', stream->szfbuf - sz); + finwrite(stream); + stream->bufStartR += sz; + } + else + { + if (((stream->upto - stream->fbuf) + sz) > stream->lrecl) + { + sz = stream->lrecl - (stream->upto - stream->fbuf); + } + memcpy(stream->upto, ptr, sz); + sz += (stream->upto - stream->fbuf); + begwrite(stream, stream->lrecl); + memcpy(dptr, stream->fbuf, sz); + memset(dptr + sz, ' ', stream->lrecl - sz); + finwrite(stream); + stream->bufStartR += sz; + stream->upto = stream->fbuf; + } + ptr = (char *)p + 1; + if (bytes > 0) + { + p = memchr(ptr, '\n', bytes); + while (p != NULL) + { + sz = p - (char *)ptr; + bytes -= sz + 1; + if (sz > stream->lrecl) + { + sz = stream->lrecl; + } + begwrite(stream, stream->lrecl); + memcpy(dptr, ptr, sz); + memset(dptr + sz, ' ', stream->szfbuf - sz); + finwrite(stream); + stream->bufStartR += sz; + ptr = p + 1; + p = memchr(ptr, '\n', bytes); + } + if (bytes > 0) + { + sz = bytes; + if (sz > stream->lrecl) + { + sz = stream->lrecl; + } + memcpy(stream->upto, ptr, sz); + stream->upto += sz; + bytes = 0; + } + } + } + else /* p == NULL */ + { + if (((stream->upto - stream->fbuf) + bytes) > stream->lrecl) + { + bytes = stream->lrecl - (stream->upto - stream->fbuf); + } + memcpy(stream->upto, ptr, bytes); + stream->upto += bytes; + } + break; + + case VARIABLE_TEXT: + stream->quickText = 0; + bytes = nmemb * size; + p = memchr(ptr, '\n', bytes); + if (p != NULL) + { + sz = p - (char *)ptr; + bytes -= sz + 1; + if (stream->upto == stream->fbuf) + { + if (sz > stream->lrecl) + { + sz = stream->lrecl; + } + begwrite(stream, (sz == 0) ? 5 : sz + 4); + if(sz == 0) + { + dptr[0] = 0; + dptr[1] = 5; + dptr[2] = 0; + dptr[3] = 0; + dptr[4] = ' '; + finwrite(stream); + /* note that the bufStartR needs to reflect + just the newline, and not the dummy space + we added */ + stream->bufStartR += 1; + } + else + { + dptr[0] = (sz + 4) >> 8; + dptr[1] = (sz + 4) & 0xff; + dptr[2] = 0; + dptr[3] = 0; + memcpy(dptr + 4, ptr, sz); + finwrite(stream); + stream->bufStartR += (sz + 1); + } + } + else + { + if (((stream->upto - stream->fbuf) + sz) > stream->lrecl) + { + sz = stream->lrecl - (stream->upto - stream->fbuf); + } + memcpy(stream->upto, ptr, sz); + sz += (stream->upto - stream->fbuf); + begwrite(stream, (sz == 0) ? 5 : sz + 4); + if(sz == 0) + { + dptr[0] = 0; + dptr[1] = 5; + dptr[2] = 0; + dptr[3] = 0; + dptr[4] = ' '; + finwrite(stream); + stream->bufStartR += 1; + } + else + { + dptr[0] = (sz + 4) >> 8; + dptr[1] = (sz + 4) & 0xff; + dptr[2] = 0; + dptr[3] = 0; + memcpy(dptr + 4, stream->fbuf, sz); + finwrite(stream); + stream->bufStartR += (sz + 1); + } + stream->upto = stream->fbuf; + } + ptr = (char *)p + 1; + if (bytes > 0) + { + p = memchr(ptr, '\n', bytes); + while (p != NULL) + { + sz = p - (char *)ptr; + bytes -= sz + 1; + if (sz > stream->lrecl) + { + sz = stream->lrecl; + } + begwrite(stream, (sz == 0) ? 5 : sz + 4); + if(sz == 0) + { + dptr[0] = 0; + dptr[1] = 5; + dptr[2] = 0; + dptr[3] = 0; + dptr[4] = ' '; + finwrite(stream); + stream->bufStartR += 1; + } + else + { + dptr[0] = (sz + 4) >> 8; + dptr[1] = (sz + 4) & 0xff; + dptr[2] = 0; + dptr[3] = 0; + memcpy(dptr + 4, ptr, sz); + finwrite(stream); + stream->bufStartR += (sz + 1); + } + ptr = p + 1; + p = memchr(ptr, '\n', bytes); + } + if (bytes > 0) + { + sz = bytes; + if (sz > stream->lrecl) + { + sz = stream->lrecl; + } + memcpy(stream->upto, ptr, sz); + stream->upto += sz; + bytes = 0; + } + } + } + else /* p == NULL */ + { + if (((stream->upto - stream->fbuf) + bytes) > stream->lrecl) + { + bytes = stream->lrecl - (stream->upto - stream->fbuf); + } + memcpy(stream->upto, ptr, bytes); + stream->upto += bytes; + } + break; + } + return (nmemb); +} + +__PDPCLIB_API__ size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) +{ + size_t bytes; + size_t read; + size_t totalread; + size_t extra; + unsigned char *eptr; + + if (stream->quickBin) + { + if ((nmemb == 1) && (size == stream->lrecl)) + { + if (__aread(stream->hfile, &dptr) != 0) + { + stream->eofInd = 1; + stream->quickBin = 0; + return (0); + } + memcpy(ptr, dptr, size); + stream->bufStartR += size; + return (1); + } + else + { + stream->quickBin = 0; + } + } + if (stream->eofInd) + { + return (0); + } + + /* If we have an unget character, then write it into + the buffer in advance */ + if (stream->ungetCh != -1) + { + stream->upto--; + *stream->upto = stream->ungetCh; + stream->ungetCh = -1; + } + + switch (stream->style) + { + case FIXED_TEXT: + bytes = nmemb * size; + read = stream->endbuf - stream->upto; + if (read > bytes) + { + memcpy(ptr, stream->upto, bytes); + stream->upto += bytes; + totalread = bytes; + } + else + { + memcpy(ptr, stream->upto, read); + stream->bufStartR += (stream->endbuf - stream->fbuf); + stream->upto = stream->endbuf = stream->fbuf; + totalread = read; + } + + while (totalread < bytes) + { + if (__aread(stream->hfile, &dptr) != 0) + { + stream->eofInd = 1; + break; + } + + eptr = dptr + stream->lrecl - 1; + while ((*eptr == ' ') && (eptr >= dptr)) + { + eptr--; + } + + read = eptr + 1 - dptr; + + if ((totalread + read) >= bytes) + { + extra = (totalread + read) - bytes; + read -= extra; + memcpy(stream->fbuf, dptr + read, extra); + stream->endbuf = stream->fbuf + extra; + *stream->endbuf++ = '\n'; + } + + memcpy((char *)ptr + totalread, dptr, read); + totalread += read; + stream->bufStartR += read; + if (totalread < bytes) + { + *((char *)ptr + totalread) = '\n'; + totalread++; + stream->bufStartR++; + } + } + return ((size == 0) ? 0 : (totalread / size)); + break; + + case FIXED_BINARY: + bytes = nmemb * size; + read = stream->endbuf - stream->upto; + if (read > bytes) + { + memcpy(ptr, stream->upto, bytes); + stream->upto += bytes; + totalread = bytes; + } + else + { + memcpy(ptr, stream->upto, read); + stream->bufStartR += (stream->endbuf - stream->fbuf); + stream->upto = stream->endbuf = stream->fbuf; + totalread = read; + } + + while (totalread < bytes) + { + if (__aread(stream->hfile, &dptr) != 0) + { + stream->eofInd = 1; + break; + } + + read = stream->lrecl; + + if ((totalread + read) > bytes) + { + extra = (totalread + read) - bytes; + read -= extra; + memcpy(stream->fbuf, dptr + read, extra); + stream->endbuf = stream->fbuf + extra; + } + + memcpy((char *)ptr + totalread, dptr, read); + totalread += read; + stream->bufStartR += read; + } + return ((size == 0) ? 0 : (totalread / size)); + break; + + case VARIABLE_TEXT: + bytes = nmemb * size; + read = stream->endbuf - stream->upto; + if (read > bytes) + { + memcpy(ptr, stream->upto, bytes); + stream->upto += bytes; + totalread = bytes; + } + else + { + memcpy(ptr, stream->upto, read); + stream->bufStartR += (stream->endbuf - stream->fbuf); + stream->upto = stream->endbuf = stream->fbuf; + totalread = read; + } + + while (totalread < bytes) + { + if (__aread(stream->hfile, &dptr) != 0) + { + stream->eofInd = 1; + break; + } + + read = (dptr[0] << 8) | dptr[1]; + read -= 4; + dptr += 4; + if ((read == 1) && (dptr[0] == ' ')) + { + read = 0; + } + + if ((totalread + read) >= bytes) + { + extra = (totalread + read) - bytes; + read -= extra; + memcpy(stream->fbuf, dptr + read, extra); + stream->endbuf = stream->fbuf + extra; + *stream->endbuf++ = '\n'; + } + + memcpy((char *)ptr + totalread, dptr, read); + totalread += read; + stream->bufStartR += read; + if (totalread < bytes) + { + *((char *)ptr + totalread) = '\n'; + totalread++; + stream->bufStartR++; + } + } + return ((size == 0) ? 0 : (totalread / size)); + break; + + case VARIABLE_BINARY: + bytes = nmemb * size; + read = stream->endbuf - stream->upto; + if (read > bytes) + { + memcpy(ptr, stream->upto, bytes); + stream->upto += bytes; + totalread = bytes; + } + else + { + memcpy(ptr, stream->upto, read); + stream->bufStartR += (stream->endbuf - stream->fbuf); + stream->upto = stream->endbuf = stream->fbuf; + totalread = read; + } + + while (totalread < bytes) + { + if (__aread(stream->hfile, &dptr) != 0) + { + stream->eofInd = 1; + break; + } + + if (!stream->reallyu) + { + read = (dptr[0] << 8) | dptr[1]; + } + else + { + read = lenread; + if (stream->reallyt) + { + unsigned char *p; + + /* get rid of any trailing NULs in text mode */ + p = memchr(dptr, '\0', read); + if (p != NULL) + { + read = p - dptr; + } + } + } + + if ((totalread + read) > bytes) + { + extra = (totalread + read) - bytes; + read -= extra; + memcpy(stream->fbuf, dptr + read, extra); + stream->endbuf = stream->fbuf + extra; + } + + memcpy((char *)ptr + totalread, dptr, read); + totalread += read; + stream->bufStartR += read; + } + return ((size == 0) ? 0 : (totalread / size)); + break; + + default: + break; + } + return (0); +} + +#endif + +/* + filedef dynamically allocates a file (via SVC 99) on MVS-like + environments. +*/ + +#if defined(__MVS__) + +static struct { + char len; /* length of request block, always 20 */ + char verb; /* dynamic allocation function requested */ + char flag1; + char flag2; + short error_reason; /* returned */ + short info_reason; /* returned */ + void *tu_list; /* list of pointers to text units */ + int reserved; + char moreflags[4]; /* extraflags */ +} rb; + +static void *tu_list[10]; /* pointers to text units */ + +static struct { + short key; /* key defining what this text unit is */ + short numparms; /* number of parms that follow */ + short parm1_len; + char parm1[98]; + /* parm2_len etc would theoretically follow, but we + can't define them, because the length of 98 is probably + not correct in the first place */ +} tu[10]; + +static void filedef(char *fdddname, char *fnm, int mymode) +{ + memset(&rb, 0x00, sizeof rb); + rb.len = 20; + rb.verb = 0x01; /* allocate */ + rb.tu_list = tu_list; + + tu_list[0] = &tu[0]; + tu[0].key = 0x0001; /* ddname */ + tu[0].numparms = 1; + tu[0].parm1_len = strlen(fdddname); + strcpy(tu[0].parm1, fdddname); + + tu_list[1] = &tu[1]; + tu[1].key = 0x0002; /* dsname */ + tu[1].numparms = 1; + tu[1].parm1_len = strlen(fnm); + strcpy(tu[1].parm1, fnm); + + tu_list[2] = &tu[2]; + tu[2].key = 0x0004; /* disp */ + tu[2].numparms = 1; + tu[2].parm1_len = 1; + tu[2].parm1[0] = 0x08; /* SHR */ + + tu_list[3] = 0; + tu_list[4] = 0; + tu_list[5] = (void *)0x80000000; + + errno = __svc99(&rb); + + /* if we had an error, then for datasets open for write, + try allocating a new dataset (this will be the normal + situation - it is abnormal is to find the dataset already + pre-allocated */ + if (errno) + { + /* if open for write */ + if ( mymode ) + { + tu[2].parm1[0] = 0x04; /* NEW */ + /* Note that the operating system, e.g. PDOS, + may override the RECFM, e.g. to make everything + RECFM=U + */ + + /* if binary */ + if (modeType == 5) + { + /* F80, which is default */ + /* That seems like a strange default. Regardless, + we should be using RECFM=U, BLKSIZE=6233 for + output binary files */ + } + else + { + /* V255 */ + tu_list[3] = &tu[3]; + tu[3].key = 0x49; /* RECFM */ + tu[3].numparms = 1; + tu[3].parm1_len = 1; + tu[3].parm1[0] = 0x40; /* V */ + + tu_list[4] = &tu[4]; + tu[4].key = 0x42; /* LRECL */ + tu[4].numparms = 1; + tu[4].parm1_len = 2; + tu[4].parm1[0] = 0; /* LRECL = 255 */ + tu[4].parm1[1] = 255; + } + } + errno = __svc99(&rb); + } + if (errno != 0) + { + if (rb.error_reason != 0) + { + errno = rb.error_reason; + } + err = 1; + } + return; +} + +static void fdclr(char *ddname) +{ + memset(&rb, 0x00, sizeof rb); + rb.len = 20; + rb.verb = 0x02; /* unallocate */ + rb.tu_list = tu_list; + + tu_list[0] = &tu[0]; + tu[0].key = 0x0001; /* ddname */ + tu[0].numparms = 1; + tu[0].parm1_len = strlen(ddname); + strcpy(tu[0].parm1, ddname); + + tu_list[1] = (void *)0x80000000; + + __svc99(&rb); + return; +} +#endif + + +/* + Following code issues a FILEDEF for CMS +*/ + +#ifdef __CMS__ +static void filedef(char *fdddname, char *fnm, int mymode) +{ + char s202parm [800]; + + int code; + int parm; + char *fname; + char *ftype; + char *fmode; + char *member; + char *p; + int console; + +/* + Skip leading blanks because sometimes people do that in CMS +*/ + while (fnm[0] == ' ') fnm++; + +/* + first parse the file name +*/ + console = 0; + if( fnm[0] == '*') console = 1; + while ( NULL != (p = strchr(fnm, '.')) )*p=' '; /* replace . with */ +/* + check for a member +*/ + p = strtok(fnm, "(" ); /* member name starts with a ( */ + member = strtok (NULL, ")" ); + fname = strtok(p, " "); + ftype = strtok(NULL, " "); + if (ftype == NULL) ftype = ""; + fmode = strtok(NULL, " "); + if (fmode == NULL) fmode = ""; + + +/* + Now build the SVC 202 string +*/ + memcpy ( &s202parm[0] , "FILEDEF ", 8); + memcpy ( &s202parm[8] , fdddname, 8); + if(console) + { + memcpy ( &s202parm[16] , "TERMINAL", 8); + memcpy ( &s202parm[24] , "( " , 8 ); + memcpy ( &s202parm[32] , "RECFM " , 8 ); + memcpy ( &s202parm[40] , "V " , 8 ); + memcpy ( &s202parm[48] , "LRECL " , 8 ); + memcpy ( &s202parm[56] , "80 " , 8 ); + s202parm[64]=s202parm[65]=s202parm[66]=s202parm[67]= + s202parm[68]=s202parm[69]=s202parm[70]=s202parm[71]=0xff; + } + else + { + memcpy ( &s202parm[16] , "DISK ", 8); +/* + Clear PARMS area +*/ + memcpy ( &s202parm[24] , " " , 8); + memcpy ( &s202parm[32] , " " , 8); + if (mymode) + { + memcpy ( &s202parm[40] , "A1 " , 8); + if (fmode[0] != '\0') + { + memcpy ( &s202parm[40] , fmode, strlen(fmode)); + } + } + else + { + memcpy ( &s202parm[40] , "* " , 8); + memcpy ( &s202parm[40] , fmode , strlen(fmode) ); + } + + memcpy ( &s202parm[24] , fname , + ( strlen(fname) > 8 ) ? 8 : strlen(fname) ); + memcpy ( &s202parm[32] , ftype , + ( strlen(ftype) >8 ) ? 8 : strlen(ftype) ); + if ( mymode ) + { + memcpy ( &s202parm[48] , "( " , 8 ); + memcpy ( &s202parm[56] , "RECFM " , 8 ); + memcpy ( &s202parm[64] , "V " , 8 ); + memcpy ( &s202parm[72] , "LRECL " , 8 ); + memcpy ( &s202parm[80] , "2000 " , 8 ); + if (modeType == 5) + { + memcpy ( &s202parm[64] , "F " , 8 ); + memcpy ( &s202parm[80] , "800 " , 8 ); + } + s202parm[88]=s202parm[89]=s202parm[90]=s202parm[91]= + s202parm[92]=s202parm[93]=s202parm[94]=s202parm[95]=0xff; + } + else + { + if(member == NULL) + { + s202parm[48]=s202parm[49]=s202parm[50]=s202parm[51]= + s202parm[52]=s202parm[53]=s202parm[54]=s202parm[55]=0xff; + } + else + { + memcpy ( &s202parm[48] , "( " , 8 ); + memcpy ( &s202parm[64] , " " , 8 ); + memcpy ( &s202parm[56] , "MEMBER " , 8 ); + memcpy ( &s202parm[64] , member , + ( strlen(member) >8 ) ? 8 : strlen(member) ); + s202parm[72]=s202parm[73]=s202parm[74]=s202parm[75]= + s202parm[76]=s202parm[77]=s202parm[78]=s202parm[79]=0xff; + } + } + } + __SVC202 ( s202parm, &code, &parm ); +} + +static void fdclr(char *ddname) +{ + char s202parm [800]; + int code; + int parm; + + /* build the SVC 202 string */ + memcpy( &s202parm[0] , "FILEDEF ", 8); + memcpy( &s202parm[8] , ddname, 8); + memcpy( &s202parm[16] , "CLEAR ", 8); + memset( &s202parm[24], 0xff, 8); + + __SVC202 ( s202parm, &code, &parm ); + return; +} + +/* + Following code does a rename for CMS +*/ + +static int cmsrename(const char *old, const char *newnam) +{ + char s202parm[8*8]; + int code; + int parm; + char fnm[FILENAME_MAX]; + char *p; + char *q; + + memset(s202parm, ' ', sizeof s202parm); + + memcpy(&s202parm[0], "RENAME ", 8); + + strncpy(fnm, old, sizeof fnm); + fnm[sizeof fnm - 1] = '\0'; + p = fnm; + while (*p != '\0') + { + *p = toupper((unsigned)*p); + p++; + } + p = strchr(fnm, ' '); + if (p == NULL) p = strchr(fnm, '.'); + if (p == NULL) return (-1); + *p++ = '\0'; + q = strchr(p, ' '); + if (q == NULL) q = strchr(p, '.'); + if (q == NULL) q = "A"; + else *q++ = '\0'; + + memcpy(&s202parm[8], fnm, (strlen(fnm) > 8 ? 8 : strlen(fnm))); + memcpy(&s202parm[16], p, (strlen(p) > 8 ? 8 : strlen(p))); + memcpy(&s202parm[24], q, (strlen(q) > 8 ? 8 : strlen(q))); + + strncpy(fnm, newnam, sizeof fnm); + fnm[sizeof fnm - 1] = '\0'; + p = fnm; + while (*p != '\0') + { + *p = toupper((unsigned)*p); + p++; + } + p = strchr(fnm, ' '); + if (p == NULL) p = strchr(fnm, '.'); + if (p == NULL) return (-1); + *p++ = '\0'; + q = strchr(p, ' '); + if (q == NULL) q = strchr(p, '.'); + if (q == NULL) q = "A"; + else *q++ = '\0'; + + memcpy(&s202parm[32], fnm, (strlen(fnm) > 8 ? 8 : strlen(fnm))); + memcpy(&s202parm[40], p, (strlen(p) > 8 ? 8 : strlen(p))); + memcpy(&s202parm[48], q, (strlen(q) > 8 ? 8 : strlen(q))); + + memset(&s202parm[56], 0xff, 8); + + __SVC202(s202parm, &code, &parm); + return (parm); +} + +/* + Following code does a remove for CMS +*/ + +static int cmsremove(const char *filename) +{ + char s202parm[5*8]; + int code; + int parm; + const char *p; + const char *q; + char *f; + char fnm[FILENAME_MAX]; + + strncpy(fnm, filename, sizeof fnm); + fnm[sizeof fnm - 1] = '\0'; + f = fnm; + while (*f != '\0') + { + *f = toupper((unsigned)*f); + f++; + } + filename = fnm; + + memset(s202parm, ' ', sizeof s202parm); + + /* build the SVC 202 string */ + memcpy( &s202parm[0] , "ERASE ", 8); + + p = strchr(filename, ' '); + if (p == NULL) + { + p = strchr(filename, '.'); + } + if (p == NULL) + { + memcpy( &s202parm[8] , filename, strlen(filename)); + memset( &s202parm[16], 0xff, 8); + } + else + { + memcpy( &s202parm[8] , filename, p - filename); + q = strchr(p + 1, ' '); + if (q == NULL) + { + q = strchr(p + 1, '.'); + } + if (q == NULL) + { + memcpy( &s202parm[16] , p + 1, strlen(p + 1)); + memset( &s202parm[24], 0xff, 8); + } + else + { + memcpy( &s202parm[16] , p + 1, q - p - 1); + memcpy( &s202parm[24] , q + 1, strlen(q + 1)); + memset( &s202parm[32], 0xff, 8); + } + } + + __SVC202 ( s202parm, &code, &parm ); + return (parm); +} + +static char *int_strtok(char *s1, const char *s2) +{ + static char *old = NULL; + char *p; + size_t len; + size_t remain; + + if (s1 != NULL) old = s1; + if (old == NULL) return (NULL); + p = old; + len = strspn(p, s2); + remain = strlen(p); + if (remain <= len) { old = NULL; return (NULL); } + p += len; + len = strcspn(p, s2); + remain = strlen(p); + if (remain <= len) { old = NULL; return (p); } + *(p + len) = '\0'; + old = p + len + 1; + return (p); +} + +#endif + + +/* + + The truely cludged piece of code was concocted by Dave Wade + + His erstwhile tutors are probably turning in their graves. + + It is however placed in the Public Domain so that any one + who wishes to improve is free to do so + +*/ + +static void dblcvt(double num, char cnvtype, size_t nwidth, + int nprecision, char *result) +{ + double b,round; + int i,j,exp,pdigits,format; + char sign, work[125]; + + /* save original data & set sign */ + + if ( num < 0 ) + { + b = -num; + sign = '-'; + } + else + { + b = num; + sign = ' '; + } + + /* + Now scale to get exponent + */ + + exp = 0; + if( b > 1.0 ) + { + while ((b >= 10.0) && (exp < 120)) + { + ++exp; + b=b / 10.0; + } + } + else if ( b == 0.0 ) + { + exp=0; + } + /* 1.0 will get exp = 0 */ + else if ( b < 1.0 ) + { + while ((b < 1.0) && (exp > -120)) + { + --exp; + b=b*10.0; + } + } + if ((exp <= -120) || (exp >= 120)) + { + exp = 0; + b = 0.0; + } + + /* + now decide how to print and save in FORMAT. + -1 => we need leading digits + 0 => print in exp + +1 => we have digits before dp. + */ + + switch (cnvtype) + { + case 'E': + case 'e': + format = 0; + break; + case 'f': + case 'F': + if ( exp >= 0 ) + { + format = 1; + } + else + { + format = -1; + } + break; + default: + /* Style e is used if the exponent from its + conversion is less than -4 or greater than + or equal to the precision. + */ + if ( exp >= 0 ) + { + if ( nprecision > exp ) + { + format=1; + } + else + { + format=0; + } + } + else + { + /* if ( nprecision > (-(exp+1) ) ) { */ + if ( exp >= -4) + { + format=-1; + } + else + { + format=0; + } + } + break; + } + /* + Now round + */ + switch (format) + { + case 0: /* we are printing in standard form */ + if (nprecision < DBL_MANT_DIG) /* we need to round */ + { + j = nprecision; + } + else + { + j=DBL_MANT_DIG; + } + round = 1.0/2.0; + i = 0; + while (++i <= j) + { + round = round/10.0; + } + b = b + round; + if (b >= 10.0) + { + b = b/10.0; + exp = exp + 1; + } + break; + + case 1: /* we have a number > 1 */ + /* need to round at the exp + nprecisionth digit */ + if (exp + nprecision < DBL_MANT_DIG) /* we need to round */ + { + j = exp + nprecision; + } + else + { + j = DBL_MANT_DIG; + } + round = 0.5; + i = 0; + while (i++ < j) + { + round = round/10; + } + b = b + round; + if (b >= 10.0) + { + b = b/10.0; + exp = exp + 1; + } + break; + + case -1: /* we have a number that starts 0.xxxx */ + if (nprecision < DBL_MANT_DIG) /* we need to round */ + { + j = nprecision + exp + 1; + } + else + { + j = DBL_MANT_DIG; + } + round = 5.0; + i = 0; + while (i++ < j) + { + round = round/10; + } + if (j >= 0) + { + b = b + round; + } + if (b >= 10.0) + { + b = b/10.0; + exp = exp + 1; + } + if (exp >= 0) + { + format = 1; + } + break; + } + /* + Now extract the requisite number of digits + */ + + if (format==-1) + { + /* + Number < 1.0 so we need to print the "0." + and the leading zeros... + */ + result[0]=sign; + result[1]='0'; + result[2]='.'; + result[3]=0x00; + while (++exp) + { + --nprecision; + strcat(result,"0"); + } + i=b; + --nprecision; + work[0] = (char)('0' + i % 10); + work[1] = 0x00; + strcat(result,work); + + pdigits = nprecision; + + while (pdigits-- > 0) + { + b = b - i; + b = b * 10.0; + i = b; + work[0] = (char)('0' + i % 10); + work[1] = 0x00; + strcat(result,work); + } + } + /* + Number >= 1.0 just print the first digit + */ + else if (format==+1) + { + i = b; + result[0] = sign; + result[1] = '\0'; + work[0] = (char)('0' + i % 10); + work[1] = 0x00; + strcat(result,work); + nprecision = nprecision + exp; + pdigits = nprecision ; + + while (pdigits-- > 0) + { + if ( ((nprecision-pdigits-1)==exp) ) + { + strcat(result,"."); + } + b = b - i; + b = b * 10.0; + i = b; + work[0] = (char)('0' + i % 10); + work[1] = 0x00; + strcat(result,work); + } + } + /* + printing in standard form + */ + else + { + i = b; + result[0] = sign; + result[1] = '\0'; + work[0] = (char)('0' + i % 10); + work[1] = 0x00; + strcat(result,work); + strcat(result,"."); + + pdigits = nprecision; + + while (pdigits-- > 0) + { + b = b - i; + b = b * 10.0; + i = b; + work[0] = (char)('0' + i % 10); + work[1] = 0x00; + strcat(result,work); + } + } + + if (format==0) + { /* exp format - put exp on end */ + work[0] = 'E'; + if ( exp < 0 ) + { + exp = -exp; + work[1]= '-'; + } + else + { + work[1]= '+'; + } + work[2] = (char)('0' + (exp/10) % 10); + work[3] = (char)('0' + exp % 10); + work[4] = 0x00; + strcat(result, work); + } + else + { + /* get rid of trailing zeros for g specifier */ + if (cnvtype == 'G' || cnvtype == 'g') + { + char *p; + + p = strchr(result, '.'); + if (p != NULL) + { + p++; + p = p + strlen(p) - 1; + while (*p != '.' && *p == '0') + { + *p = '\0'; + p--; + } + if (*p == '.') + { + *p = '\0'; + } + } + } + } + /* printf(" Final Answer = <%s> fprintf gives=%g\n", + result,num); */ + /* + do we need to pad + */ + if(result[0] == ' ')strcpy(work,result+1); else strcpy(work,result); + pdigits=nwidth-strlen(work); + result[0]= 0x00; + while(pdigits>0) + { + strcat(result," "); + pdigits--; + } + strcat(result,work); + return; +} diff --git a/app/src/main/cpp/pdpclib/x86/stdio.h b/app/src/main/cpp/pdpclib/x86/stdio.h new file mode 100644 index 0000000..085bc00 --- /dev/null +++ b/app/src/main/cpp/pdpclib/x86/stdio.h @@ -0,0 +1,330 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* stdio.h - stdio header file */ +/* */ +/*********************************************************************/ + +#ifndef __STDIO_INCLUDED +#define __STDIO_INCLUDED + +/* Perhaps should copy these definitions in instead */ +#include + +#ifndef __SIZE_T_DEFINED +#define __SIZE_T_DEFINED +#if (defined(__OS2__) || defined(__32BIT__) || defined(__MVS__) \ + || defined(__CMS__) || defined(__VSE__) || defined(__SMALLERC__) \ + || defined(__ARM__) || defined(__gnu_linux__) || defined(__PDOS386__) \ + || defined(__SZ4__)) +typedef unsigned long size_t; +#elif (defined(__MSDOS__) || defined(__DOS__) || defined(__POWERC) \ + || defined(__WIN32__) || defined(__AMIGA__) || defined(__EFI__)) +typedef unsigned int size_t; +#endif +#endif + +/* + What we have is an internal buffer, which is 8 characters + longer than the actually used buffer. E.g. say BUFSIZ is + 512 bytes, then we actually allocate 520 bytes. The first + 2 characters will be junk, the next 2 characters set to NUL, + for protection against some backward-compares. The fourth-last + character is set to '\n', to protect against overscan. The + last 3 characters will be junk, to protect against memory + violation. intBuffer is the internal buffer, but everyone refers + to fbuf, which is actually set to the &intBuffer[4]. Also, + szfbuf is the size of the "visible" buffer, not the internal + buffer. The reason for the 2 junk characters at the beginning + is to align the buffer on a 4-byte boundary. + + Here is what memory would look like after an fwrite of "ABC" + to an MVS LRECL=80, RECFM=F dataset: + + intbuffer: x'50000' + fbuf: x'50004' + upto: x'50007' + endbuf: x'58004' + + x'50004' = x'C1' + x'50005' = x'C2' + x'50006' = x'C3' +*/ + +typedef struct +{ +#if (defined(__OS2__) || defined(__32BIT__) || defined(__PDOS386__)) + unsigned long hfile; /* OS/2 file handle */ +#elif (defined(__MSDOS__) || defined(__DOS__) || defined(__POWERC) \ + || defined(__SMALLERC__)) + int hfile; /* dos file handle */ +#elif defined(__WIN32__) || defined(__AMIGA__) + void *hfile; +#elif defined(__gnu_linux__) || defined(__ARM__) || defined(__EFI__) + int hfile; +#endif +#if (defined(__MVS__) || defined(__CMS__) || defined(__VSE__)) + void *hfile; + void *asmbuf; + int recfm; + int true_recfm; + int style; + int lrecl; + int blksize; + char ddname[9]; + char pdsmem[9]; + int reallyu; /* 1 = this is really a RECFM=U file */ + int reallyt; /* 1 = this is really a text file */ + int dynal; /* 1 = this file was dynamically allocated */ + int line_buf; /* 1 = we are forcing line buffering */ +#endif +#if defined(__VSE__) + int vse_punch; /* 1 = this is writing to a VSE library */ + char *vselupto; /* where we are up to in the internal buffer */ + char *vselend; /* end of the internal buffer */ +#endif + int quickBin; /* 1 = do DosRead NOW!!!! */ + int quickText; /* 1 = quick text mode */ + int textMode; /* 1 = text mode, 0 = binary mode */ + int intFno; /* internal file number */ + unsigned long bufStartR; /* buffer start represents, e.g. if we + have read in 3 buffers, each of 512 bytes, and we are + currently reading from the 3rd buffer, then the first + character in the buffer would be 1024, so that is what is + put in bufStartR. */ + int justseeked; /* 1 = last operation was a seek */ + char *fbuf; /* file buffer - this is what all the routines + look at. */ + size_t szfbuf; /* size of file buffer (the one that the routines + see, and the user allocates, and what is actually + read in from disk) */ + char *upto; /* what character is next to read from buffer */ + char *endbuf; /* pointer PAST last character in buffer, ie it + points to the '\n' in the internal buffer */ + int errorInd; /* whether an error has occurred on this file */ + int eofInd; /* whether EOF has been reached on this file */ + int ungetCh; /* character pushed back, -1 if none */ + int bufTech; /* buffering technique, _IOFBF etc */ + char *intBuffer; /* internal buffer */ + int noNl; /* When doing gets, we don't copy NL */ + int mode; /* __READ_MODE or __WRITE_MODE */ + int update; /* Is file update (read + write)? */ + int theirBuffer; /* Is the buffer supplied by them? */ + int permfile; /* Is this stdin/stdout/stderr? */ + int isopen; /* Is this file open? */ + char modeStr[4]; /* 2nd parameter to fopen */ + int tempch; /* work variable for putc */ + int istemp; /* opened by tmpfile? */ +} FILE; + +typedef unsigned long fpos_t; + +#define NULL ((void *)0) +#define FILENAME_MAX 260 +#define FOPEN_MAX 256 +#define _IOFBF 1 +#define _IOLBF 2 +#define _IONBF 3 + + +#ifndef BUFSIZ + +/*#define BUFSIZ 409600*/ +/* #define BUFSIZ 8192 */ +/*#define BUFSIZ 5120*/ + +#if defined(__MVS__) || defined(__VSE__) +/* set it to maximum possible LRECL to simplify processing */ +/* also add in room for a RDW and dword align it just to be + on the safe side */ +#define BUFSIZ 32768 +#elif defined(__CMS__) +/* similar considerations for CMS as MVS */ +#define BUFSIZ 65544 +#else +#define BUFSIZ 6144 +#endif +/* #define BUFSIZ 10 */ +/* #define BUFSIZ 512 */ + +#endif + + +#define EOF -1 +#define L_tmpnam FILENAME_MAX +#define TMP_MAX 25 +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 +#define __NFILE (FOPEN_MAX - 3) +#define __READ_MODE 0 +#define __WRITE_MODE 1 + +#define __RECFM_F 0 +#define __RECFM_V 1 +#define __RECFM_U 2 + +#if 0 +extern FILE *stdin; +extern FILE *stdout; +extern FILE *stderr; + +extern FILE *__userFiles[__NFILE]; +#endif + +FILE **__gtin(void); +FILE **__gtout(void); +FILE **__gterr(void); + +#define __stdin (*(__gtin())) +#define __stdout (*(__gtout())) +#define __stderr (*(__gterr())) + +#if defined(__WIN32__) && !defined(__STATIC__) +/* For Windows stdin, stdout and stderr macros + * are implemented using an array FILE _iob[] + * where the first three members + * are stdin, stdout and stderr. + * In this array each member has size 32 bytes, + * so __DUMMYFILE is used instead + * and the pointers are converted + * using __INTFILE macro. */ +#define __DUMMYFILE_SIZE 32 + +typedef struct +{ + char filler[__DUMMYFILE_SIZE]; +} __DUMMYFILE; + +#ifndef __PDPCLIB_DLL +__declspec(dllimport) __DUMMYFILE _iob[3]; +#endif + +#define stdin ((FILE *) &(_iob[0])) +#define stdout ((FILE *) &(_iob[1])) +#define stderr ((FILE *) &(_iob[2])) + +#define __INTFILE(f) (((f) == stdin) ? __stdin : \ + ((f) == stdout) ? __stdout : \ + ((f) == stderr) ? __stderr : \ + f) +#else +#define stdin (*(__gtin())) +#define stdout (*(__gtout())) +#define stderr (*(__gterr())) + +#define __INTFILE(f) (f) +#endif + +#if defined(__VSE__) +extern FILE *__stdpch; +#endif + +int printf(const char *format, ...); +FILE *fopen(const char *filename, const char *mode); +int fclose(FILE *stream); +size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); +size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); +int fputc(int c, FILE *stream); +int fputs(const char *s, FILE *stream); +int fprintf(FILE *stream, const char *format, ...); +int vfprintf(FILE *stream, const char *format, va_list arg); +int vprintf(const char *format, va_list arg); +int remove(const char *filename); +int rename(const char *old, const char *newnam); +int sprintf(char *s, const char *format, ...); +int vsprintf(char *s, const char *format, va_list arg); +char *fgets(char *s, int n, FILE *stream); +int ungetc(int c, FILE *stream); +int fgetc(FILE *stream); +int fseek(FILE *stream, long offset, int whence); +long ftell(FILE *stream); +int fsetpos(FILE *stream, const fpos_t *pos); +int fgetpos(FILE *stream, fpos_t *pos); +void rewind(FILE *stream); +void clearerr(FILE *stream); +void perror(const char *s); +int setvbuf(FILE *stream, char *buf, int mode, size_t size); +int setbuf(FILE *stream, char *buf); +FILE *freopen(const char *filename, const char *mode, FILE *stream); +int fflush(FILE *stream); +char *tmpnam(char *s); +FILE *tmpfile(void); +int fscanf(FILE *stream, const char *format, ...); +int scanf(const char *format, ...); +int sscanf(const char *s, const char *format, ...); +char *gets(char *s); +int puts(const char *s); + +#ifndef __POWERC +int getchar(void); +int putchar(int c); +int getc(FILE *stream); +int putc(int c, FILE *stream); +int feof(FILE *stream); +int ferror(FILE *stream); +#endif + +#if !defined(__WIN32__) || defined(__STATIC__) +#define getchar() (getc(stdin)) +#define putchar(c) (putc((c), stdout)) +#define getc(stream) (fgetc((stream))) +#define putc(c, stream) \ + ( \ + ((stream)->tempch = (c)), \ + ((stream)->quickBin = 0), \ + ((stream)->quickText = 0), \ + (((stream)->tempch == '\n') \ + || (stream)->justseeked \ + || (((stream)->upto + 1) >= (stream)->endbuf)) ? \ + (fputc((stream)->tempch, (stream))) : \ + (*(stream)->upto++ = (stream)->tempch) \ + ) + +#define feof(stream) ((stream)->eofInd) +#define ferror(stream) ((stream)->errorInd) +#endif + +#if defined(__PDOSGEN__) +#include <__os.h> + +#define printf __os->Xprintf +#undef stdin +#define stdin __os->Xstdin +#undef stdout +#define stdout __os->Xstdout +#undef stderr +#define stderr __os->Xstderr +#define fopen __os->Xfopen +#define fseek __os->Xfseek +#define fread __os->Xfread +#define fclose __os->Xfclose +#define fwrite __os->Xfwrite +#define fgets __os->Xfgets +#define fgetc __os->Xfgetc +#define fputc __os->Xfputc +#define fflush __os->Xfflush +#define remove __os->Xremove +#define fputs __os->Xfputs +#define fprintf __os->Xfprintf +#define tmpnam __os->Xtmpnam +#define vfprintf __os->Xvfprintf +#define ungetc __os->Xungetc +#define vsprintf __os->Xvsprintf +#define sprintf __os->Xsprintf +#define ftell __os->Xftell +#define perror __os->Xperror +#define rewind __os->Xrewind +#define sscanf __os->Xsscanf +#define rename __os->Xrename +#define clearerr __os->Xclearerr +#endif + +#endif /* __STDIO_INCLUDED */ + + diff --git a/app/src/main/cpp/pdpclib/x86/stdlib.c b/app/src/main/cpp/pdpclib/x86/stdlib.c new file mode 100644 index 0000000..a7ba1cd --- /dev/null +++ b/app/src/main/cpp/pdpclib/x86/stdlib.c @@ -0,0 +1,1123 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* stdlib.c - implementation of stuff in stdlib.h */ +/* */ +/*********************************************************************/ + +#include "stdlib.h" +#include "signal.h" +#include "string.h" +#include "ctype.h" +#include "stddef.h" + +/* VSE is similar to MVS */ +#if defined(__VSE__) +#define __MVS__ 1 +#endif + +/* PDOS and MSDOS use the same interface most of the time */ +#if defined(__PDOS386__) || defined(__SMALLERC__) +#define __MSDOS__ +#endif + +#ifdef __PDOS386__ +#include +#endif + +#ifdef __AMIGA__ +#include +#endif + +#ifdef __EFI__ +#include "efi.h" +#endif + +#ifdef __OS2__ +#define INCL_DOSMISC +#define INCL_DOSPROCESS +#include +#endif + +#ifdef __WIN32__ +#include +#endif + +#if defined(__MVS__) || defined(__CMS__) +#include "mvssupa.h" +#endif + +#ifdef __MVS__ +extern int __tso; +#endif + +#if USE_MEMMGR +#include "__memmgr.h" +/* GCCMVS 3.4.6 requires 49 MB minimum for full optimization */ +/* so we give it 60. GCCMVS 3.2.3 only requires 20 MB */ +/* Note that you can set MAX_CHUNK to less than REQ_CHUNK */ +/* But don't do this until MVS/380 etc have been changed to */ +/* allow multiple memory requests. */ +/* But bump it up to almost 64 MiB so that if CMS is misconfigured */ +/* it tries to get almost 16 MiB (and from subpool 3) so should fail */ + +#if defined(MULMEM) +#define MAX_CHUNK 67100672 +#define REQ_CHUNK 67100672 +#elif defined(__gnu_linux__) || defined(__ARM__) +#define MAX_CHUNK 30000000 /* maximum size we will store in memmgr */ +#define REQ_CHUNK 30000000 /* size that we request from OS */ +#else +#define MAX_CHUNK 67100672 /* maximum size we will store in memmgr */ +#define REQ_CHUNK 67100672 /* size that we request from OS */ +#endif +void *__lastsup = NULL; /* last thing supplied to memmgr */ +#endif + +#ifdef __MSDOS__ +#if defined(__WATCOMC__) && !defined(__32BIT__) +#define CTYP __cdecl +#else +#define CTYP +#endif +#if defined(__32BIT__) && !defined(NOLIBALLOC) +/* For PDOS-32 liballoc is used for memory management. */ +#include "liballoc.h" +#else +void CTYP __allocmem(size_t size, void **ptr); +void CTYP __freemem(void *ptr); +#endif +extern unsigned char *__envptr; +int CTYP __exec(char *cmd, void *env); +int CTYP __getrc(void); +#endif + +#if defined(__gnu_linux__) || defined(__ARM__) +void *__allocmem(size_t size); +#endif + +void (*__userExit[__NATEXIT])(void); + +__PDPCLIB_API__ void *malloc(size_t size) +{ +#ifdef __AMIGA__ + size_t *x; + + x = AllocMem(size + sizeof(size_t), 0); + if (x == NULL) return (NULL); + *x = size; + return (x + 1); +#endif +#ifdef __EFI__ + size_t *x = NULL; + + __gBS->AllocPool(EfiLoaderData, size + sizeof(size_t), (void *)&x); + if (x == NULL) return (NULL); + *x = size; + return (x + 1); +#endif +#ifdef __OS2__ + PVOID BaseAddress; + ULONG ulObjectSize; + ULONG ulAllocationFlags; + APIRET rc; + + ulObjectSize = size + sizeof(size_t); + ulAllocationFlags = PAG_COMMIT | PAG_WRITE | PAG_READ; + rc = DosAllocMem(&BaseAddress, ulObjectSize, ulAllocationFlags); + if (rc != 0) return (NULL); + *(size_t *)BaseAddress = size; + BaseAddress = (char *)BaseAddress + sizeof(size_t); + return ((void *)BaseAddress); +#endif +#ifdef __MSDOS__ +#if defined(__32BIT__) && !defined(NOLIBALLOC) + return (__malloc(size)); +#else + size_t *ptr; + + __allocmem(size + sizeof(size_t), (void **)&ptr); + if (ptr == NULL) return (NULL); + *ptr = size; + return (ptr + 1); +#endif +#endif +#if USE_MEMMGR + void *ptr; + + if (size > MAX_CHUNK) + { +#if defined(__MVS__) || defined(__CMS__) || defined(__gnu_linux__) \ + || defined(__ARM__) +#if defined(MULMEM) + /* If we support multiple memory requests */ + ptr = __getm(size); +#else + ptr = NULL; +#endif +#elif defined(__WIN32__) + ptr = GlobalAlloc(0, size + sizeof(size_t)); + if (ptr != NULL) + { + *(size_t *)ptr = size; + ptr = (char *)ptr + sizeof(size_t); + } +#elif defined(__gnu_linux__) || defined(__ARM__) + ptr = __allocmem(size + sizeof(size_t)); + if (ptr != NULL) + { + *(size_t *)ptr = size; + ptr = (char *)ptr + sizeof(size_t); + } +#endif + } + else + { + ptr = memmgrAllocate(&__memmgr, size, 0); + if (ptr == NULL) + { + void *ptr2; + +#if defined(__MVS__) || defined(__CMS__) + /* until MVS/380 is fixed, don't do an additional request, + unless MULMEM is defined */ +#if defined(MULMEM) + if (1) +#else + if (__memmgr.start == NULL) +#endif + { + ptr2 = __getm(REQ_CHUNK); + } + else + { + ptr2 = NULL; + } +#elif defined(__WIN32__) + ptr2 = GlobalAlloc(0, REQ_CHUNK); + if (ptr2 != NULL) + { + *(size_t *)ptr2 = size; + ptr2 = (char *)ptr2 + sizeof(size_t); + } +#elif defined(__gnu_linux__) || defined(__ARM__) + if (__memmgr.start == NULL) + { + ptr2 = __allocmem(REQ_CHUNK); + } + else + { + ptr2 = NULL; + } + if (ptr2 != NULL) + { + *(size_t *)ptr2 = size; + ptr2 = (char *)ptr2 + sizeof(size_t); + } +#endif + if (ptr2 == NULL) + { + return (NULL); + } + __lastsup = ptr2; + memmgrSupply(&__memmgr, ptr2, REQ_CHUNK); + ptr = memmgrAllocate(&__memmgr, size, 0); + } + } + return (ptr); +#else /* not MEMMGR */ +#if defined(__MVS__) || defined(__CMS__) + return (__getm(size)); +#elif defined(__WIN32__) + void *ptr; + + ptr = GlobalAlloc(0, size + sizeof(size_t)); + if (ptr != NULL) + { + *(size_t *)ptr = size; + ptr = (char *)ptr + sizeof(size_t); + } + return (ptr); +#elif defined(__gnu_linux__) || defined(__ARM__) + void *ptr; + + ptr = __allocmem(size + sizeof(size_t)); + if (ptr != NULL) + { + *(size_t *)ptr = size; + ptr = (char *)ptr + sizeof(size_t); + } + return (ptr); +#endif +#endif /* not MEMMGR */ +} + +__PDPCLIB_API__ void *calloc(size_t nmemb, size_t size) +{ + void *ptr; + size_t total; + + if (nmemb == 1) + { + total = size; + } + else if (size == 1) + { + total = nmemb; + } + else + { + total = nmemb * size; + } + ptr = malloc(total); + if (ptr != NULL) + { + memset(ptr, '\0', total); + } + return (ptr); +} + +__PDPCLIB_API__ void *realloc(void *ptr, size_t size) +{ +#if defined(__PDOS386__) && !defined(NOLIBALLOC) + return (__realloc(ptr, size)); +#else + char *newptr; + size_t oldsize; + + if (size == 0) + { + free(ptr); + return (NULL); + } +#if USE_MEMMGR + if (memmgrRealloc(&__memmgr, ptr, size) == 0) + { + return (ptr); + } +#endif + newptr = malloc(size); + if (newptr == NULL) + { + return (NULL); + } + if (ptr != NULL) + { + oldsize = *((size_t *)ptr - 1); + if (oldsize < size) + { + size = oldsize; + } + memcpy(newptr, ptr, size); + free(ptr); + } + return (newptr); +#endif +} + +__PDPCLIB_API__ void free(void *ptr) +{ +#ifdef __AMIGA__ + if (ptr != NULL) + { + ptr = (char *)ptr - sizeof(size_t); + FreeMem(ptr, *(size_t *)ptr + sizeof(size_t)); + } +#endif +#ifdef __EFI__ + if (ptr != NULL) + { + ptr = (char *)ptr - sizeof(size_t); + __gBS->FreePool(ptr); + } +#endif +#ifdef __OS2__ + if (ptr != NULL) + { + ptr = (char *)ptr - sizeof(size_t); + DosFreeMem((PVOID)ptr); + } +#endif +#ifdef __MSDOS__ +#if defined(__32BIT__) && !defined(NOLIBALLOC) + __free(ptr); +#else + if (ptr != NULL) + { + ptr = (char *)ptr - sizeof(size_t); + __freemem(ptr); + } +#endif +#endif +#if USE_MEMMGR + if (ptr != NULL) + { + size_t size; + + size = *((size_t *)ptr - 1); + if (size > MAX_CHUNK) + { +#if defined(__MVS__) || defined(__CMS__) +#if defined(MULMEM) + /* Ignore, unless MULMEM is defined, until MVS/380 is fixed */ + __freem(ptr); +#endif +#elif defined(__WIN32__) + GlobalFree(((size_t *)ptr) - 1); +#endif + } + else + { + memmgrFree(&__memmgr, ptr); + } + } +#else /* not using MEMMGR */ +#if defined(__MVS__) || defined(__CMS__) + if (ptr != NULL) + { + __freem(ptr); + } +#endif +#ifdef __WIN32__ + if (ptr != NULL) + { + GlobalFree(((size_t *)ptr) - 1); + } +#endif +#endif /* not USE_MEMMGR */ + return; +} + +__PDPCLIB_API__ void abort(void) +{ + raise(SIGABRT); + exit(EXIT_FAILURE); +#if !defined(__EMX__) && !defined(__GNUC__) && !defined(__WIN32__) \ + && !defined(__gnu_linux__) && !defined(__ARM__) + return; +#endif +} + +#if !defined(__EMX__) && !defined(__GNUC__) && !defined(__gnu_linux__) \ + && !defined(__ARM__) \ + || defined(WATLIN) +void __exit(int status); +#else +void __exit(int status) __attribute__((noreturn)); +#endif + +__PDPCLIB_API__ void exit(int status) +{ + __exit(status); +#if !defined(__EMX__) && !defined(__GNUC__) && !defined(__WIN32__) \ + && !defined(__gnu_linux__) && !defined(__ARM__) + return; +#endif +} + +/* This qsort routine was obtained from libnix (also public domain), + * and then reformatted. + * + * This qsort function does a little trick: + * To reduce stackspace it iterates the larger interval instead of doing + * the recursion on both intervals. + * So stackspace is limited to 32*stack_for_1_iteration = + * 32*4*(4 arguments+1 returnaddress+11 stored registers) = 2048 Bytes, + * which is small enough for everybodys use. + * (And this is the worst case if you own 4GB and sort an array of chars.) + * Sparing the function calling overhead does improve performance, too. + */ + +__PDPCLIB_API__ void qsort(void *base, + size_t nmemb, + size_t size, + int (*compar)(const void *, const void *)) +{ + char *base2 = (char *)base; + size_t i,a,b,c; + + while (nmemb > 1) + { + a = 0; + b = nmemb-1; + c = (a+b)/2; /* Middle element */ + for (;;) + { + while ((*compar)(&base2[size*c],&base2[size*a]) > 0) + { + a++; /* Look for one >= middle */ + } + while ((*compar)(&base2[size*c],&base2[size*b]) < 0) + { + b--; /* Look for one <= middle */ + } + if (a >= b) + { + break; /* We found no pair */ + } + for (i=0; i> 16) & 0x7fff); + myseed = myseed * 1103515245UL + 12345; + ret = (ret << 16) | (int)((myseed >> 16) & 0xffff); +#else + ret = (int)((myseed >> 16) & 0x7fff); +#endif + return (ret); +} + +__PDPCLIB_API__ double atof(const char *nptr) +{ + return (strtod(nptr, (char **)NULL)); +} + +__PDPCLIB_API__ double strtod(const char *nptr, char **endptr) +{ + double x = 0.0; + double xs= 1.0; + double es = 1.0; + double xf = 0.0; + double xd = 1.0; + + while( isspace( (unsigned char)*nptr ) ) ++nptr; + if(*nptr == '-') + { + xs = -1; + nptr++; + } + else if(*nptr == '+') + { + nptr++; + } + + + while (1) + { + if (isdigit((unsigned char)*nptr)) + { + x = x * 10 + (*nptr - '0'); + nptr++; + } + else + { + x = x * xs; + break; + } + } + if (*nptr == '.') + { + nptr++; + while (1) + { + if (isdigit((unsigned char)*nptr)) + { + xf = xf * 10 + (*nptr - '0'); + xd = xd * 10; + } + else + { + x = x + xs * (xf / xd); + break; + } + nptr++; + } + } + if ((*nptr == 'e') || (*nptr == 'E')) + { + nptr++; + if (*nptr == '-') + { + es = -1; + nptr++; + } + xd = 1; + xf = 0; + while (1) + { + if (isdigit((unsigned char)*nptr)) + { + xf = xf * 10 + (*nptr - '0'); + nptr++; + } + else + { + while (xf > 0) + { + xd = xd * 10; + xf = xf - 1; + } + if (es < 0.0) + { + x = x / xd; + } + else + { + x = x * xd; + } + break; + } + } + } + if (endptr != NULL) + { + *endptr = (char *)nptr; + } + return (x); +} + +__PDPCLIB_API__ int atoi(const char *nptr) +{ + return ((int)strtol(nptr, (char **)NULL, 10)); +} + +__PDPCLIB_API__ long int atol(const char *nptr) +{ + return (strtol(nptr, (char **)NULL, 10)); +} + +/* this logic is also in vvscanf - if you update this, update + that one too */ + +__PDPCLIB_API__ unsigned long int strtoul( + const char *nptr, char **endptr, int base) +{ + unsigned long x = 0; + int undecided = 0; + + if (base == 0) + { + undecided = 1; + } + while (isspace((unsigned char)*nptr)) + { + nptr++; + } + while (1) + { + if (isdigit((unsigned char)*nptr)) + { + if (base == 0) + { + if (*nptr == '0') + { + base = 8; + } + else + { + base = 10; + undecided = 0; + } + } + x = x * base + (*nptr - '0'); + nptr++; + } + else if (isalpha((unsigned char)*nptr)) + { + if ((*nptr == 'X') || (*nptr == 'x')) + { + if ((base == 0) || ((base == 8) && undecided)) + { + base = 16; + undecided = 0; + nptr++; + } + else if (base == 16) + { + /* hex values are allowed to have an optional 0x */ + nptr++; + } + else + { + break; + } + } + else if (base <= 10) + { + break; + } + else + { + x = x * base + (toupper((unsigned char)*nptr) - 'A') + 10; + nptr++; + } + } + else + { + break; + } + } + if (endptr != NULL) + { + *endptr = (char *)nptr; + } + return (x); +} + +__PDPCLIB_API__ long int strtol(const char *nptr, char **endptr, int base) +{ + unsigned long y; + long x; + int neg = 0; + + while (isspace((unsigned char)*nptr)) + { + nptr++; + } + if (*nptr == '-') + { + neg = 1; + nptr++; + } + else if (*nptr == '+') + { + nptr++; + } + y = strtoul(nptr, endptr, base); + if (neg) + { + x = (long)-y; + } + else + { + x = (long)y; + } + return (x); +} + +__PDPCLIB_API__ int mblen(const char *s, size_t n) +{ + if (s == NULL) + { + return (0); + } + if (n == 1) + { + return (1); + } + else + { + return (-1); + } +} + +__PDPCLIB_API__ int mbtowc(wchar_t *pwc, const char *s, size_t n) +{ + if (s == NULL) + { + return (0); + } + if (n == 1) + { + if (pwc != NULL) + { + *pwc = *s; + } + return (1); + } + else + { + return (-1); + } +} + +__PDPCLIB_API__ int wctomb(char *s, wchar_t wchar) +{ + if (s != NULL) + { + *s = wchar; + return (1); + } + else + { + return (0); + } +} + +__PDPCLIB_API__ size_t mbstowcs(wchar_t *pwcs, const char *s, size_t n) +{ + strncpy((char *)pwcs, s, n); + if (strlen(s) >= n) + { + return (n); + } + return (strlen((char *)pwcs)); +} + +__PDPCLIB_API__ size_t wcstombs(char *s, const wchar_t *pwcs, size_t n) +{ + strncpy(s, (const char *)pwcs, n); + if (strlen((const char *)pwcs) >= n) + { + return (n); + } + return (strlen(s)); +} + +#ifdef abs +#undef abs +#endif +__PDPCLIB_API__ int abs(int j) +{ + if (j < 0) + { + j = -j; + } + return (j); +} + +__PDPCLIB_API__ div_t div(int numer, int denom) +{ + div_t x; + + x.quot = numer / denom; + x.rem = numer % denom; + return (x); +} + +#ifdef labs +#undef labs +#endif +__PDPCLIB_API__ long int labs(long int j) +{ + if (j < 0) + { + j = -j; + } + return (j); +} + +__PDPCLIB_API__ ldiv_t ldiv(long int numer, long int denom) +{ + ldiv_t x; + + x.quot = numer / denom; + x.rem = numer % denom; + return (x); +} + +__PDPCLIB_API__ int atexit(void (*func)(void)) +{ + int x; + + for (x = 0; x < __NATEXIT; x++) + { + if (__userExit[x] == 0) + { + __userExit[x] = func; + return (0); + } + } + return (-1); +} + +static int ins_strncmp(const char *one, const char *two, size_t len) +{ + size_t x = 0; + + if (len == 0) return (0); + while ((x < len) + && (toupper((unsigned char)*one) == toupper((unsigned char)*two))) + { + if (*one == '\0') + { + return (0); + } + one++; + two++; + x++; + } + if (x == len) return (0); + return (toupper((unsigned char)*one) - toupper((unsigned char)*two)); +} + +__PDPCLIB_API__ char *getenv(const char *name) +{ +#ifdef __OS2__ + PSZ result; + + if (DosScanEnv((void *)name, (void *)&result) == 0) + { + return ((char *)result); + } +#endif +#if defined(__MSDOS__) || defined(__WIN32__) + char *env; + size_t lenn; + +#ifdef __WIN32__ + env = GetEnvironmentStrings(); +#else + env = (char *)__envptr; +#endif + lenn = strlen(name); + while (*env != '\0') + { + if (ins_strncmp(env, name, lenn) == 0) + { + if (env[lenn] == '=') + { + return (&env[lenn + 1]); + } + } + env = env + strlen(env) + 1; + } +#endif + return (NULL); +} + +/* The following code was taken from Paul Markham's "EXEC" program, + and adapted to create a system() function. The code is all + public domain */ + +__PDPCLIB_API__ int system(const char *string) +{ +#ifdef __OS2__ + char err_obj[100]; + APIRET rc; + RESULTCODES results; + + if (string == NULL) + { + return (1); + } + rc = DosExecPgm(err_obj, sizeof err_obj, EXEC_SYNC, + (PSZ)string, NULL, &results, (PSZ)string); + if (rc != 0) + { + return (rc); + } + return ((int)results.codeResult); +#endif +#ifdef __WIN32__ + BOOL rc; + PROCESS_INFORMATION pi; + STARTUPINFO si; + DWORD ExitCode; + char *cmdproc; + char cmdbuf[300]; + + cmdproc = getenv("COMSPEC"); + if (cmdproc == NULL) + { + return (-1); + } + if (strlen(string) + strlen(cmdproc) > sizeof cmdbuf - 10) + { + return (-2); + } + strcpy(cmdbuf, cmdproc); + strcat(cmdbuf, " /c "); + strcat(cmdbuf, string); + + memset(&si, 0, sizeof si); + si.cb = sizeof si; + memset(&pi, 0, sizeof pi); + + rc = CreateProcess(cmdproc, + cmdbuf, + NULL, + NULL, + FALSE, + 0, + NULL, + NULL, + &si, + &pi); + if (!rc) + { + int ret; + + ret = GetLastError(); + if (ret == 0) + { + ret = -1; /* force an error */ + } + return (ret); + } + WaitForSingleObject(pi.hProcess, INFINITE); + GetExitCodeProcess(pi.hProcess, &ExitCode); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return (ExitCode); +#endif +#ifdef __MSDOS__ + int rc; +#ifdef __PDOS386__ + static unsigned char cmdt[300]; +#else + static unsigned char cmdt[140]; +#endif + static +#ifdef __PDOS386__ + POSEXEC_PARMBLOCK +#else + struct { + unsigned short env; + unsigned char *cmdtail; + char *fcb1; + char *fcb2; + } +#endif + parmblock = { 0, cmdt, NULL, NULL }; + size_t len; + char *cmd; + + if (string == NULL) + { + return (1); + } + cmd = getenv("COMSPEC"); + if (cmd == NULL) + { + cmd = "\\command.com"; + } +#ifdef __PDOS386__ + if ((strlen(cmd) + strlen(string) + 5) > sizeof cmdt) + { + return (-1); + } + strcpy(cmdt, cmd); + strcat(cmdt, " /c "); + strcat(cmdt, string); +#else + len = strlen(string); + cmdt[0] = (unsigned char)(len + 3); + memcpy(&cmdt[1], "/c ", 3); + memcpy(&cmdt[4], string, len); + memcpy(&cmdt[len + 4], "\r", 2); +#endif + rc = __exec(cmd, &parmblock); + if (rc != 0) return (-rc); + return (__getrc()); +#endif +#if defined(MUSIC) + return (__system(strlen(string), string)); +#elif defined(__MVS__) + char pgm[9]; + size_t pgm_len; + size_t cnt; + char *p; + + p = strchr(string, ' '); + if (p == NULL) + { + p = strchr(string, '\0'); + } + + pgm_len = p - string; + /* don't allow a program name greater than 8 */ + + if (pgm_len > 8) + { + return (-1); + } + memcpy(pgm, string, pgm_len); + pgm[pgm_len] = '\0'; + + /* uppercase the program name */ + for (cnt = 0; cnt < pgm_len; cnt++) + { + pgm[cnt] = toupper((unsigned char)pgm[cnt]); + } + + /* point to parms */ + if (*p != '\0') + { + p++; + } + + /* all parms now available */ + /* we use 1 = batch or 2 = tso */ + return (__system(__tso ? 2: 1, pgm_len, pgm, strlen(p), p)); +#endif +#if defined(__CMS__) + /* not implemented yet */ + return (0); +#endif +} + +__PDPCLIB_API__ void *bsearch(const void *key, const void *base, + size_t nmemb, size_t size, + int (*compar)(const void *, const void *)) +{ + size_t try; + int res; + const void *ptr; + + while (nmemb > 0) + { + try = nmemb / 2; + ptr = (void *)((char *)base + try * size); + res = compar(ptr, key); + if (res == 0) + { + return ((void *)ptr); + } + else if (res < 0) + { + nmemb = nmemb - try - 1; + base = (const void *)((const char *)ptr + size); + } + else + { + nmemb = try; + } + } + return (NULL); +} diff --git a/app/src/main/cpp/pdpclib/x86/stdlib.h b/app/src/main/cpp/pdpclib/x86/stdlib.h new file mode 100644 index 0000000..7161bc2 --- /dev/null +++ b/app/src/main/cpp/pdpclib/x86/stdlib.h @@ -0,0 +1,143 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* stdlib.h - stdlib header file */ +/* */ +/*********************************************************************/ + +#ifndef __STDLIB_INCLUDED +#define __STDLIB_INCLUDED + +#ifndef __SIZE_T_DEFINED +#define __SIZE_T_DEFINED +#if (defined(__OS2__) || defined(__32BIT__) || defined(__MVS__) \ + || defined(__CMS__) || defined(__VSE__) || defined(__SMALLERC__) \ + || defined(__ARM__)|| defined(__gnu_linux__) || defined(__PDOS386__) \ + || defined(__SZ4__)) +typedef unsigned long size_t; +#elif (defined(__MSDOS__) || defined(__DOS__) || defined(__POWERC) \ + || defined(__WIN32__) || defined(__AMIGA__) || defined(__EFI__)) +typedef unsigned int size_t; +#endif +#endif +#ifndef __WCHAR_T_DEFINED +#define __WCHAR_T_DEFINED +#ifndef _WCHAR_T_DEFINED +#define _WCHAR_T_DEFINED +#endif +typedef char wchar_t; +#endif +typedef struct { int quot; int rem; } div_t; +typedef struct { long quot; long rem; } ldiv_t; + +#define NULL ((void *)0) +#define EXIT_SUCCESS 0 +#if defined(__MVS__) || defined(__CMS__) || defined(__VSE__) +#define EXIT_FAILURE 12 +#else +#define EXIT_FAILURE 1 +#endif +#if defined(__32BIT__) || defined(__WIN32__) +#define RAND_MAX 2147483647 +#else +#define RAND_MAX 32767 +#endif +#define MB_CUR_MAX 1 +#define __NATEXIT 32 + +void *malloc(size_t size); +void *calloc(size_t nmemb, size_t size); +void *realloc(void *ptr, size_t size); +void free(void *ptr); +#if (defined(__MVS__) || defined(__CMS__) || defined(__VSE__)) \ + && defined(__GNUC__) +void abort(void) __attribute__((noreturn)); +void exit(int status) __attribute__((noreturn)); +#else +void abort(void); +void exit(int status); +#endif + +#ifdef __SUBC__ +void qsort(void *a, size_t b, size_t c, + int (*f)()); +#else +void qsort(void *a, size_t b, size_t c, + int (*f)(const void *d, const void *e)); +#endif + +void srand(unsigned int seed); +int rand(void); +double atof(const char *nptr); +double strtod(const char *nptr, char **endptr); +int atoi(const char *nptr); +long atol(const char *nptr); +long strtol(const char *nptr, char **endptr, int base); +unsigned long strtoul(const char *nptr, char **endptr, int base); +int mblen(const char *s, size_t n); +int mbtowc(wchar_t *pwc, const char *s, size_t n); +int wctomb(char *s, wchar_t wchar); +size_t mbstowcs(wchar_t *pwcs, const char *s, size_t n); +size_t wcstombs(char *s, const wchar_t *pwcs, size_t n); +int abs(int j); +div_t div(int numer, int denom); +long labs(long j); +ldiv_t ldiv(long numer, long denom); + +#ifdef __SUBC__ +int atexit(int (*func)()); +#else +int atexit(void (*func)(void)); +#endif + +char *getenv(const char *name); +int system(const char *string); + +#ifdef __SUBC__ +void *bsearch(const void *key, const void *base, + size_t nmemb, size_t size, + int (*compar)()); +#else +void *bsearch(const void *key, const void *base, + size_t nmemb, size_t size, + int (*compar)(const void *, const void *)); +#endif + +#ifdef __WATCOMC__ +#pragma intrinsic (abs,labs,div,ldiv) +#endif + +#if defined(__IBMC__) && defined(__OS2__) +int _Builtin __abs(int j); +#define abs(j) (__abs((j))) +long _Builtin __labs(long j); +#define labs(j) (__labs((j))) +#endif + +#if defined(__PDOSGEN__) +#include <__os.h> + +#define malloc __os->malloc +#define free __os->free +#undef abort +#define abort __os->abort +#define getenv __os->Xgetenv +#define exit __os->Xexit +#define calloc __os->Xcalloc +#define realloc __os->Xrealloc +#define atoi __os->Xatoi +#define strtol __os->Xstrtol +#define strtoul __os->Xstrtoul +#define qsort __os->Xqsort +#define bsearch __os->Xbsearch +#define abs __os->Xabs +#define atof __os->Xatof + +#endif + +#endif diff --git a/app/src/main/cpp/pdpclib/x86/string.c b/app/src/main/cpp/pdpclib/x86/string.c new file mode 100644 index 0000000..5b02bb8 --- /dev/null +++ b/app/src/main/cpp/pdpclib/x86/string.c @@ -0,0 +1,491 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* string.c - implementation of routines in string.h */ +/* */ +/*********************************************************************/ + +#include "stdio.h" +#include "string.h" +#include "stddef.h" + +#if defined(__PDOSGEN__) + +/* Because the compiler sometimes generates a deliberate call to + memcpy, the memcpy function needs to exist. We could instead make + the compiler generate code that honors the memcpy macro, but for + now, this will do */ + +#undef memcpy +__PDPCLIB_API__ void *memcpy(void *s1, const void *s2, size_t n) +{ + return (__os->memcpy(s1, s2, n)); +} + +#undef memset +__PDPCLIB_API__ void *memset(void *s, int c, size_t n) +{ + return (__os->memset(s, c, n)); +} + +#else + +#ifdef memmove +#undef memmove +#endif +__PDPCLIB_API__ void *memmove(void *s1, const void *s2, size_t n) +{ + char *p = s1; + const char *cs2 = s2; + size_t x; + + if (p <= cs2) + { + for (x=0; x < n; x++) + { + *p = *cs2; + p++; + cs2++; + } + } + else + { + if (n != 0) + { + for (x=n-1; x > 0; x--) + { + *(p+x) = *(cs2+x); + } + *(p+x) = *(cs2+x); + } + } + return (s1); +} + +#ifdef strcpy +#undef strcpy +#endif +__PDPCLIB_API__ char *strcpy(char *s1, const char *s2) +{ + char *p = s1; + + while ((*p++ = *s2++) != '\0') ; + return (s1); +} + +#ifdef strncpy +#undef strncpy +#endif +__PDPCLIB_API__ char *strncpy(char *s1, const char *s2, size_t n) +{ + char *p = s1; + size_t x; + + for (x=0; x < n; x++) + { + *p = *s2; + if (*s2 == '\0') break; + p++; + s2++; + } + for (; x < n; x++) + { + *p++ = '\0'; + } + return (s1); +} + +#ifdef strcat +#undef strcat +#endif +__PDPCLIB_API__ char *strcat(char *s1, const char *s2) +{ + char *p = s1; + + while (*p != '\0') p++; + while ((*p = *s2) != '\0') + { + p++; + s2++; + } + return (s1); +} + +#ifdef strncat +#undef strncat +#endif +__PDPCLIB_API__ char *strncat(char *s1, const char *s2, size_t n) +{ + char *p = s1; + size_t x = 0; + + while (*p != '\0') p++; + while ((*s2 != '\0') && (x < n)) + { + *p = *s2; + p++; + s2++; + x++; + } + *p = '\0'; + return (s1); +} + +#ifdef memcmp +#undef memcmp +#endif +__PDPCLIB_API__ int memcmp(const void *s1, const void *s2, size_t n) +{ + const unsigned char *p1; + const unsigned char *p2; + size_t x = 0; + + p1 = (const unsigned char *)s1; + p2 = (const unsigned char *)s2; + while (x < n) + { + if (p1[x] < p2[x]) return (-1); + else if (p1[x] > p2[x]) return (1); + x++; + } + return (0); +} + +#ifdef strcmp +#undef strcmp +#endif +__PDPCLIB_API__ int strcmp(const char *s1, const char *s2) +{ + const unsigned char *p1; + const unsigned char *p2; + + p1 = (const unsigned char *)s1; + p2 = (const unsigned char *)s2; + while (*p1 != '\0') + { + if (*p1 < *p2) return (-1); + else if (*p1 > *p2) return (1); + p1++; + p2++; + } + if (*p2 == '\0') return (0); + else return (-1); +} + +#ifdef strcoll +#undef strcoll +#endif +__PDPCLIB_API__ int strcoll(const char *s1, const char *s2) +{ + return (strcmp(s1, s2)); +} + +#ifdef strncmp +#undef strncmp +#endif +__PDPCLIB_API__ int strncmp(const char *s1, const char *s2, size_t n) +{ + const unsigned char *p1; + const unsigned char *p2; + size_t x = 0; + + p1 = (const unsigned char *)s1; + p2 = (const unsigned char *)s2; + while (x < n) + { + if (p1[x] < p2[x]) return (-1); + else if (p1[x] > p2[x]) return (1); + else if (p1[x] == '\0') return (0); + x++; + } + return (0); +} + +#ifdef strxfrm +#undef strxfrm +#endif +__PDPCLIB_API__ size_t strxfrm(char *s1, const char *s2, size_t n) +{ + size_t oldlen; + + oldlen = strlen(s2); + if (oldlen < n) + { + memcpy(s1, s2, oldlen); + s1[oldlen] = '\0'; + } + return (oldlen); +} + +#ifdef memchr +#undef memchr +#endif +__PDPCLIB_API__ void *memchr(const void *s, int c, size_t n) +{ + const unsigned char *p; + size_t x = 0; + + p = (const unsigned char *)s; + while (x < n) + { + if (*p == (unsigned char)c) return ((void *)p); + p++; + x++; + } + return (NULL); +} + +#ifdef strchr +#undef strchr +#endif +__PDPCLIB_API__ char *strchr(const char *s, int c) +{ + while (*s != '\0') + { + if (*s == (char)c) return ((char *)s); + s++; + } + if (c == '\0') return ((char *)s); + return (NULL); +} + +#ifdef strcspn +#undef strcspn +#endif +__PDPCLIB_API__ size_t strcspn(const char *s1, const char *s2) +{ + const char *p1; + const char *p2; + + p1 = s1; + while (*p1 != '\0') + { + p2 = s2; + while (*p2 != '\0') + { + if (*p1 == *p2) return ((size_t)(p1 - s1)); + p2++; + } + p1++; + } + return ((size_t)(p1 - s1)); +} + +#ifdef strpbrk +#undef strpbrk +#endif +__PDPCLIB_API__ char *strpbrk(const char *s1, const char *s2) +{ + const char *p1; + const char *p2; + + p1 = s1; + while (*p1 != '\0') + { + p2 = s2; + while (*p2 != '\0') + { + if (*p1 == *p2) return ((char *)p1); + p2++; + } + p1++; + } + return (NULL); +} + +#ifdef strrchr +#undef strrchr +#endif +__PDPCLIB_API__ char *strrchr(const char *s, int c) +{ + const char *p; + + p = s + strlen(s); + while (1) + { + if (*p == (char)c) return ((char *)p); + if (p == s) break; + p--; + } + return (NULL); +} + +#ifdef strspn +#undef strspn +#endif +__PDPCLIB_API__ size_t strspn(const char *s1, const char *s2) +{ + const char *p1; + const char *p2; + + p1 = s1; + while (*p1 != '\0') + { + p2 = s2; + while (*p2 != '\0') + { + if (*p1 == *p2) break; + p2++; + } + if (*p2 == '\0') return ((size_t)(p1 - s1)); + p1++; + } + return ((size_t)(p1 - s1)); +} + + +/* strstr by Frank Adam */ +/* modified by Paul Edwards */ + +#ifdef strstr +#undef strstr +#endif +__PDPCLIB_API__ char *strstr(const char *s1, const char *s2) +{ + const char *p = s1, *p1, *p2 = s2; + + while (*p) + { + if (*p == *s2) + { + p1 = p; + p2 = s2; + while ((*p2 != '\0') && (*p1 == *p2)) + { + p1++; + p2++; + } + if (*p2 == '\0') + { + return (char *)p; + } + } + p++; + } + return NULL; +} + +#ifdef strtok +#undef strtok +#endif +__PDPCLIB_API__ char *strtok(char *s1, const char *s2) +{ + static char *old = NULL; + char *p; + size_t len; + size_t remain; + + if (s1 != NULL) old = s1; + if (old == NULL) return (NULL); + p = old; + len = strspn(p, s2); + remain = strlen(p); + if (remain <= len) { old = NULL; return (NULL); } + p += len; + len = strcspn(p, s2); + remain = strlen(p); + if (remain <= len) { old = NULL; return (p); } + *(p + len) = '\0'; + old = p + len + 1; + return (p); +} + +#ifdef memset +#undef memset +#endif +__PDPCLIB_API__ void *memset(void *s, int c, size_t n) +{ + size_t x = 0; + + for (x = 0; x < n; x++) + { + *((char *)s + x) = (unsigned char)c; + } + return (s); +} + +#ifdef strerror +#undef strerror +#endif +__PDPCLIB_API__ char *strerror(int errnum) +{ + if (errnum == 0) return ("No error has occurred\n"); + else return ("An error has occurred\n"); +} + +#ifdef strlen +#undef strlen +#endif +__PDPCLIB_API__ size_t strlen(const char *s) +{ + const char *p; + + p = s; + while (*p != '\0') p++; + return ((size_t)(p - s)); +} + +#ifndef USE_ASSEMBLER +#ifdef memcpy +#undef memcpy +#endif +#ifndef __32BIT__ +__PDPCLIB_API__ void *memcpy(void *s1, const void *s2, size_t n) +{ + register const unsigned char *f = s2; + register const unsigned char *fe; + register unsigned char *t = s1; + + fe = f + n; + while (f != fe) + { + *t++ = *f++; + } + return (s1); +} +#else +__PDPCLIB_API__ void *memcpy(void *s1, const void *s2, size_t n) +{ + register unsigned int *p = (unsigned int *)s1; + register unsigned int *cs2 = (unsigned int *)s2; + register unsigned int *endi; + + endi = (unsigned int *)((char *)p + (n & ~0x03)); + while (p != endi) + { + *p++ = *cs2++; + } + switch (n & 0x03) + { + case 0: + break; + case 1: + *(char *)p = *(char *)cs2; + break; + case 2: + *(char *)p = *(char *)cs2; + p = (unsigned int *)((char *)p + 1); + cs2 = (unsigned int *)((char *)cs2 + 1); + *(char *)p = *(char *)cs2; + break; + case 3: + *(char *)p = *(char *)cs2; + p = (unsigned int *)((char *)p + 1); + cs2 = (unsigned int *)((char *)cs2 + 1); + *(char *)p = *(char *)cs2; + p = (unsigned int *)((char *)p + 1); + cs2 = (unsigned int *)((char *)cs2 + 1); + *(char *)p = *(char *)cs2; + break; + } + return (s1); +} +#endif /* 32BIT */ +#endif /* USE_ASSEMBLER */ + +#endif /* __PDOSGEN__ */ diff --git a/app/src/main/cpp/pdpclib/x86/string.h b/app/src/main/cpp/pdpclib/x86/string.h new file mode 100644 index 0000000..da60dce --- /dev/null +++ b/app/src/main/cpp/pdpclib/x86/string.h @@ -0,0 +1,180 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* string.h - string header file. */ +/* */ +/*********************************************************************/ + +#ifndef __STRING_INCLUDED +#define __STRING_INCLUDED + +#ifndef __SIZE_T_DEFINED +#define __SIZE_T_DEFINED +#if (defined(__OS2__) || defined(__32BIT__) || defined(__MVS__) \ + || defined(__CMS__) || defined(__VSE__) || defined(__SMALLERC__) \ + || defined(__ARM__) || defined(__gnu_linux__) || defined(__PDOS386__) \ + || defined(__SZ4__)) +typedef unsigned long size_t; +#elif (defined(__MSDOS__) || defined(__DOS__) || defined(__POWERC) \ + || defined(__WIN32__) || defined(__AMIGA__) || defined(__EFI__)) +typedef unsigned int size_t; +#endif +#endif + +#define NULL ((void *)0) +void *memcpy(void *s1, const void *s2, size_t n); +void *memmove(void *s1, const void *s2, size_t n); +char *strcpy(char *s1, const char *s2); +char *strncpy(char *s1, const char *s2, size_t n); +char *strcat(char *s1, const char *s2); +char *strncat(char *s1, const char *s2, size_t n); +int memcmp(const void *s1, const void *s2, size_t n); +int strcmp(const char *s1, const char *s2); +int strcoll(const char *s1, const char *s2); +int strncmp(const char *s1, const char *s2, size_t n); +size_t strxfrm(char *s1, const char *s2, size_t n); +void *memchr(const void *s, int c, size_t n); +char *strchr(const char *s, int c); +size_t strcspn(const char *s1, const char *s2); +char *strpbrk(const char *s1, const char *s2); +char *strrchr(const char *s, int c); +size_t strspn(const char *s1, const char *s2); +char *strstr(const char *s1, const char *s2); +char *strtok(char *s1, const char *s2); +void *memset(void *s, int c, size_t n); +char *strerror(int errnum); +size_t strlen(const char *s); + +#if defined(__WATCOMC__) && !defined(__SZ4__) +#ifdef __INLINE_FUNCTIONS__ +#pragma intrinsic(memchr, memcmp, memcpy, strcat, strcpy, strlen, strchr) +#endif +#endif + +#if defined(__IBMC__) && defined(__OS2__) +char * _Builtin __strcat(char *s1, const char *s2); +#define strcat(s1,s2) (__strcat((s1),(s2))) +char * _Builtin __strchr(const char *s, int c); +#define strchr(s,c) (__strchr((s),(c))) +int _Builtin __strcmp(const char *s1, const char *s2); +#define strcmp(s1,s2) (__strcmp((s1),(s2))) +int _Builtin __strcpy(char *s1, const char *s2); +#define strcpy(s1,s2) (__strcpy((s1),(s2))) +size_t _Builtin __strlen(const char *s); +#define strlen(s) (__strlen((s))) +char * _Builtin __strncat(char *s1, const char *s2, size_t n); +#define strncat(s1,s2,n) (__strncat((s1),(s2),(n))) +int _Builtin __strncmp(const char *s1, const char *s2, size_t n); +#define strncmp(s1,s2,n) (__strncmp((s1),(s2),(n))) +char * _Builtin __strncpy(char *s1, const char *s2, size_t n); +#define strncpy(s1,s2,n) (__strncpy((s1),(s2),(n))) +char * _Builtin __strrchr(const char *s, int c); +#define strrchr(s,c) (__strrchr((s),(c))) +void * _Builtin __memcpy(void *s1, const void *s2, size_t n); +#define memcpy(s1,s2,n) (__memcpy((s1),(s2),(n))) +void * _Builtin __memchr(const void *s, int c, size_t n); +#define memchr(s,c,n) (__memchr((s),(c),(n))) +int _Builtin __memcmp(const void *s1, const void *s2, size_t n); +#define memcmp(s1,s2,n) (__memcmp((s1),(s2),(n))) +void * _Builtin __memset(void *s, int c, size_t n); +#define memset(s,c,n) (__memset((s),(c),(n))) +void * _Builtin __memmove(void *s1, const void *s2, size_t n); +#define memmove(s1,s2,n) (__memmove((s1),(s2),(n))) +#endif + +#ifdef __WATMUS__ +#define __GNUC__ 0 +#endif + +#if defined (__GNUC__) && __GNUC__ >= 3 && !defined(__ARM__) +#define memcpy(s1,s2,n) (__builtin_memcpy((s1),(s2),(n))) +#define memcmp(s1,s2,n) (__builtin_memcmp((s1),(s2),(n))) +#endif + +/* We don't activate these GCC builtins, because they + normally resort to a call to the normal function, + and when they do, they generate slightly worse + code! Also, they appear to be buggy on MVS. */ + +#if 0 +#define strcat(s1,s2) (__builtin_strcat((s1),(s2))) +#define strchr(s,c) (__builtin_strchr((s),(c))) +#define strcmp(s1,s2) (__builtin_strcmp((s1),(s2))) +#define strcpy(s1,s2) (__builtin_strcpy((s1),(s2))) +#define strlen(s) (__builtin_strlen((s))) +#define strncat(s1,s2,n) (__builtin_strncat((s1),(s2),(n))) +#define strncmp(s1,s2,n) (__builtin_strncmp((s1),(s2),(n))) +#define strncpy(s1,s2,n) (__builtin_strncpy((s1),(s2),(n))) +#define strrchr(s,c) (__builtin_strrchr((s),(c))) +#define memset(s,c,n) (__builtin_memset((s),(c),(n))) +#define strstr(s1,s2) (__builtin_strstr((s1),(s2))) +#define strpbrk(s1,s2) (__builtin_strpbrk((s1),(s2))) +#define strspn(s1,s2) (__builtin_strspn((s1),(s2))) +#define strcspn(s1,s2) (__builtin_strcspn((s1),(s2))) +#endif + +#ifdef __BORLANDC__ +#ifdef __INLINE_FUNCTIONS__ +void *__memcpy__(void *s1, const void *s2, size_t n); +#define memcpy(s1,s2,n) (__memcpy__((s1),(s2),(n))) +void *__memchr__(const void *s, int c, size_t n); +#define memchr(s,c,n) (__memchr__((s),(c),(n))) +int __memcmp__(const void *s1, const void *s2, size_t n); +#define memcmp(s1,s2,n) (__memcmp__((s1),(s2),(n))) +void *__memset__(void *s, int c, size_t n); +#define memset(s,c,n) (__memset__((s),(c),(n))) +char *__strcat__(char *s1, const char *s2); +#define strcat(s1,s2) (__strcat__((s1),(s2))) +char *__strchr__(const char *s, int c); +#define strchr(s,c) (__strchr__((s),(c))) +int __strcmp__(const char *s1, const char *s2); +#define strcmp(s1,s2) (__strcmp__((s1),(s2))) +char *__strcpy__(char *s1, const char *s2); +#define strcpy(s1,s2) (__strcpy__((s1),(s2))) +size_t __strlen__(const char *s); +#define strlen(s) (__strlen__((s))) +char *__strncat__(char *s1, const char *s2, size_t n); +#define strncat(s1,s2,n) (__strncat__((s1),(s2),(n))) +int __strncmp__(const char *s1, const char *s2, size_t n); +#define strncmp(s1,s2,n) (__strncmp__((s1),(s2),(n))) +char *__strncpy__(char *s1, const char *s2, size_t n); +#define strncpy(s1,s2,n) (__strncpy__((s1),(s2),(n))) +char *__strrchr__(const char *s, int c); +#define strrchr(s,c) (__strrchr__((s),(c))) +#endif +#endif + + +#if defined(__PDOSGEN__) +#include <__os.h> + +#define strchr __os->strchr +#define strcmp __os->strcmp +#define strncmp __os->strncmp +#define strcpy __os->strcpy +#define strlen __os->strlen +#undef memcpy +#define memcpy __os->memcpy +#define strncpy __os->strncpy +#define strcat __os->strcat +#define memset __os->memset +#define memmove __os->memmove +#undef memcmp +#define memcmp __os->memcmp +#define strerror __os->strerror +#define strrchr __os->strrchr +#define strstr __os->strstr +#define strpbrk __os->strpbrk +#define strspn __os->strspn +#define strcspn __os->strcspn +#define memchr __os->memchr +#define strncat __os->strncat +#endif + + +#endif diff --git a/app/src/main/cpp/pdpclib/x86/time.c b/app/src/main/cpp/pdpclib/x86/time.c new file mode 100644 index 0000000..4aa2177 --- /dev/null +++ b/app/src/main/cpp/pdpclib/x86/time.c @@ -0,0 +1,635 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* time.c - implementation of stuff in time.h */ +/* */ +/*********************************************************************/ + +#include "time.h" +#include "stdarg.h" +#include "stdio.h" +#include "stddef.h" + +/* just get VSE to use MVS for now */ +#if defined(__VSE__) +#define __MVS__ 1 +#endif + +/* pdos and msdos use the same interface most of the time) */ +#if defined(__PDOS386__) || defined(__SMALLERC__) +#define __MSDOS__ +#endif + +#if defined(__MVS__) || defined(__CMS__) +#include "mvssupa.h" +#endif +#ifdef __AMIGA__ +#include +#endif +#ifdef __OS2__ +#include +#endif +#ifdef __WIN32__ +#include +#endif +#ifdef __MSDOS__ +#ifdef __WATCOMC__ +#define CTYP __cdecl +#else +#define CTYP +#endif +void CTYP __datetime(void *ptr); +#endif + +#if defined(__ARM__) +unsigned long __time(void); +#endif + +#if defined(__gnu_linux__) +unsigned long __time(unsigned long *); +#endif + +/* scalar date routines -- public domain by Ray Gardner +** These will work over the range 1-01-01 thru 14699-12-31 +** The functions written by Ray are isleap, months_to_days, +** years_to_days, ymd_to_scalar, scalar_to_ymd. +** modified slightly by Paul Edwards +*/ + +static int isleap(unsigned yr) +{ + return yr % 400 == 0 || (yr % 4 == 0 && yr % 100 != 0); +} + +static unsigned months_to_days(unsigned month) +{ + return (month * 3057 - 3007) / 100; +} + +static long years_to_days (unsigned yr) +{ + return yr * 365L + yr / 4 - yr / 100 + yr / 400; +} + +static long ymd_to_scalar(unsigned yr, unsigned mo, unsigned day) +{ + long scalar; + + scalar = day + months_to_days(mo); + if ( mo > 2 ) /* adjust if past February */ + scalar -= isleap(yr) ? 1 : 2; + yr--; + scalar += years_to_days(yr); + return (scalar); +} + +static void scalar_to_ymd(long scalar, + unsigned *pyr, + unsigned *pmo, + unsigned *pday) +{ + unsigned n; /* compute inverse of years_to_days() */ + + n = (unsigned)((scalar * 400L) / 146097L); + while (years_to_days(n) < scalar) + { + n++; + } + for ( n = (unsigned)((scalar * 400L) / 146097L); years_to_days(n) < scalar; ) + n++; /* 146097 == years_to_days(400) */ + *pyr = n; + n = (unsigned)(scalar - years_to_days(n-1)); + if ( n > 59 ) { /* adjust if past February */ + n += 2; + if ( isleap(*pyr) ) + n -= n > 62 ? 1 : 2; + } + *pmo = (n * 100 + 3007) / 3057; /* inverse of months_to_days() */ + *pday = n - months_to_days(*pmo); + return; +} + +__PDPCLIB_API__ time_t time(time_t *timer) +{ + time_t tt; +#ifdef __AMIGA__ + struct DateStamp ds; +#endif +#ifdef __OS2__ + DATETIME dt; + APIRET rc; +#endif +#ifdef __WIN32__ + SYSTEMTIME dt; +#endif +#if defined(__MSDOS__) || defined(__AMIGA__) || defined(__EFI__) + struct { + int year; + int month; + int day; + int hours; + int minutes; + int seconds; + int hundredths; + } dt; +#endif +#if defined(__MVS__) || defined(__CMS__) + unsigned int clk[2]; +#endif + +#ifdef __AMIGA__ + DateStamp(&ds); + tt = ymd_to_scalar(1978, 1, 1) - ymd_to_scalar(1970, 1, 1); + tt += ds.ds_Days; + tt = tt * 24 * 60 + ds.ds_Minute; + tt = tt * 60 + ds.ds_Tick / 50; +#endif +#ifdef __OS2__ + rc = DosGetDateTime(&dt); + if (rc != 0) + { + tt = (time_t)-1; + } + else +#endif +#ifdef __WIN32__ + GetSystemTime(&dt); + tt = ymd_to_scalar(dt.wYear, dt.wMonth, dt.wDay) + - ymd_to_scalar(1970, 1, 1); + tt = tt * 24 + dt.wHour; + tt = tt * 60 + dt.wMinute; + tt = tt * 60 + dt.wSecond; +#endif +#if defined(__MSDOS__) + __datetime(&dt); +#endif +#if defined(__MVS__) || defined(__CMS__) + tt = __getclk(clk); +#elif defined(__ARM__) + tt = __time(); +#elif defined(__gnu_linux__) + tt = __time(NULL); +#elif !defined(__WIN32__) && !defined(__AMIGA__) + + { + tt = ymd_to_scalar(dt.year, dt.month, dt.day) + - ymd_to_scalar(1970, 1, 1); + tt = tt * 24 + dt.hours; + tt = tt * 60 + dt.minutes; + tt = tt * 60 + dt.seconds; + } +#endif + if (timer != NULL) + { + *timer = tt; + } + return (tt); +} + +__PDPCLIB_API__ clock_t clock(void) +{ + return ((clock_t)-1); +} + +__PDPCLIB_API__ double difftime(time_t time1, time_t time0) +{ + return ((double)(time1 - time0)); +} + +__PDPCLIB_API__ time_t mktime(struct tm *timeptr) +{ + time_t tt; + + if (timeptr->tm_year < 70) + { + tt = (time_t)-1; + } + else + { + tt = ymd_to_scalar(timeptr->tm_year + 1900, + timeptr->tm_mon + 1, + timeptr->tm_mday) + - ymd_to_scalar(1970, 1, 1); + tt = tt * 24 + timeptr->tm_hour; + tt = tt * 60 + timeptr->tm_min; + tt = tt * 60 + timeptr->tm_sec; + } + *timeptr = *gmtime(&tt); + return (tt); +} + +__PDPCLIB_API__ char *asctime(const struct tm *timeptr) +{ + static const char wday_name[7][3] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" + }; + static const char mon_name[12][3] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; + static char result[26]; + + sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n", + wday_name[timeptr->tm_wday], + mon_name[timeptr->tm_mon], + timeptr->tm_mday, timeptr->tm_hour, + timeptr->tm_min, timeptr->tm_sec, + 1900 + timeptr->tm_year); + return result; +} + +__PDPCLIB_API__ char *ctime(const time_t *timer) +{ + return (asctime(localtime(timer))); +} + +__PDPCLIB_API__ struct tm *localtime(const time_t *timer) +{ +#ifdef __MVS__ + time_t t; + int o; + int r; + + t = *timer; + o = __gettz(); /* this function returns the local timezone + offset in 1.048576 second increments. The + maximum offset people have managed to define + is 14 hours (Kirribati) and when mulplied + by 16384, this doesn't exceed a 32-bit + signed integer, so we're safe. + + However, the TZ offset value is actually + truncated, e.g. -27465.8 is stored as -27465, + which combined with the 1.048576 granularity + means that we don't have 1-second accuracy. + So we round to the nearest minute. */ + o = o * 16384; + o /= 15625; + /* now we have an inaccurate seconds */ + r = o % 60; + o /= 60; /* convert to minutes */ + if ((o >= 0) && (r >= 30)) + { + o++; + } + else if ((o <= 0) && (r <= -30)) + { + o--; + } + o *= 60; /* convert to seconds */ + t += o; + return (gmtime(&t)); +#else + return (gmtime(timer)); +#endif +} + +/* dow - written by Paul Edwards, 1993-01-31 */ +/* Released to the Public Domain */ +/* This routine will work over the range 1-01-01 to 32767-12-31. + It assumes the current calendar system has always been in + place in that time. If you pass 0 or negative years, then + it produces results on the assumption that there is a year + 0. It should always produce a value in the range of 0..6 + if a valid month and day have been passed, no matter what + the year is. However, it has not been tested for negative + years, because the results are meaningless anyway. It is + mainly to stop people playing silly buggers and causing + the macro to crash on negative years. */ + +#define dow(y,m,d) \ + ((((((m)+9)%12+1)<<4)%27 + (d) + 1 + \ + ((y)%400+400) + ((y)%400+400)/4 - ((y)%400+400)/100 + \ + (((m)<=2) ? ( \ + (((((y)%4)==0) && (((y)%100)!=0)) || (((y)%400)==0)) \ + ? 5 : 6) : 0)) % 7) + +static struct tm tms; + +__PDPCLIB_API__ struct tm *gmtime(const time_t *timer) +{ + unsigned yr, mo, da; + unsigned long secs; + unsigned long days; + + days = *timer / (60L*60*24); + secs = *timer % (60L*60*24); + scalar_to_ymd(days + ymd_to_scalar(1970, 1, 1), &yr, &mo, &da); + tms.tm_year = yr - 1900; + tms.tm_mon = mo - 1; + tms.tm_mday = da; + tms.tm_yday = (int)(ymd_to_scalar(tms.tm_year + 1900, mo, da) + - ymd_to_scalar(tms.tm_year + 1900, 1, 1)); + tms.tm_wday = dow(tms.tm_year + 1900, mo, da); + tms.tm_isdst = -1; + tms.tm_sec = (int)(secs % 60); + secs /= 60; + tms.tm_min = (int)(secs % 60); + secs /= 60; + tms.tm_hour = (int)secs; + return (&tms); +} + +/* + * strftime.c + * + * implements the iso c function strftime() + * + * written 1989-09-06 by jim nutt + * released into the public domain by jim nutt + * + * modified 1989-10-21 by Rob Duff + * + * modified 1994-08-26 by Paul Edwards + */ + +static char *aday[] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" +}; + +static char *day[] = { + "Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday" +}; + +static char *amonth[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + +static char *month[] = { + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" +}; + +static char *__tzname[2] = { "" "" }; +static char buf[26]; + +static void strfmt(char *str, const char *fmt, ...); + +/** + * + * size_t strftime(char *str, + * size_t maxs, + * const char *fmt, + * const struct tm *t) + * + * this functions acts much like a sprintf for time/date output. + * given a pointer to an output buffer, a format string and a + * time, it copies the time to the output buffer formatted in + * accordance with the format string. the parameters are used + * as follows: + * + * str is a pointer to the output buffer, there should + * be at least maxs characters available at the address + * pointed to by str. + * + * maxs is the maximum number of characters to be copied + * into the output buffer, included the '\0' terminator + * + * fmt is the format string. a percent sign (%) is used + * to indicate that the following character is a special + * format character. the following are valid format + * characters: + * + * %A full weekday name (Monday) + * %a abbreviated weekday name (Mon) + * %B full month name (January) + * %b abbreviated month name (Jan) + * %c standard date and time representation + * %d day-of-month (01-31) + * %H hour (24 hour clock) (00-23) + * %I hour (12 hour clock) (01-12) + * %j day-of-year (001-366) + * %M minute (00-59) + * %m month (01-12) + * %p local equivalent of AM or PM + * %S second (00-59) + * %U week-of-year, first day sunday (00-53) + * %W week-of-year, first day monday (00-53) + * %w weekday (0-6, sunday is 0) + * %X standard time representation + * %x standard date representation + * %Y year with century + * %y year without century (00-99) + * %Z timezone name + * %% percent sign + * + * the standard date string is equivalent to: + * + * %a %b %d %Y + * + * the standard time string is equivalent to: + * + * %H:%M:%S + * + * the standard date and time string is equivalent to: + * + * %a %b %d %H:%M:%S %Y + * + * strftime returns the number of characters placed in the + * buffer, not including the terminating \0, or zero if more + * than maxs characters were produced. + * +**/ + +__PDPCLIB_API__ size_t strftime(char *s, + size_t maxs, + const char *f, + const struct tm *t) +{ + int w; + char *p, *q, *r; + + p = s; + q = s + maxs - 1; + while ((*f != '\0')) + { + if (*f++ == '%') + { + r = buf; + switch (*f++) + { + case '%' : + r = "%"; + break; + + case 'a' : + r = aday[t->tm_wday]; + break; + + case 'A' : + r = day[t->tm_wday]; + break; + + case 'b' : + r = amonth[t->tm_mon]; + break; + + case 'B' : + r = month[t->tm_mon]; + break; + + case 'c' : + strfmt(r, "%0 %0 %2 %2:%2:%2 %4", + aday[t->tm_wday], amonth[t->tm_mon], + t->tm_mday,t->tm_hour, t->tm_min, + t->tm_sec, t->tm_year+1900); + break; + + case 'd' : + strfmt(r,"%2",t->tm_mday); + break; + + case 'H' : + strfmt(r,"%2",t->tm_hour); + break; + + case 'I' : + strfmt(r,"%2",(t->tm_hour%12)?t->tm_hour%12:12); + break; + + case 'j' : + strfmt(r,"%3",t->tm_yday+1); + break; + + case 'm' : + strfmt(r,"%2",t->tm_mon+1); + break; + + case 'M' : + strfmt(r,"%2",t->tm_min); + break; + + case 'p' : + r = (t->tm_hour>11)?"PM":"AM"; + break; + + case 'S' : + strfmt(r,"%2",t->tm_sec); + break; + + case 'U' : + w = t->tm_yday/7; + if (t->tm_yday%7 > t->tm_wday) + w++; + strfmt(r, "%2", w); + break; + + case 'W' : + w = t->tm_yday/7; + if (t->tm_yday%7 > (t->tm_wday+6)%7) + w++; + strfmt(r, "%2", w); + break; + + case 'w' : + strfmt(r,"%1",t->tm_wday); + break; + + case 'x' : + strfmt(r, "%3s %3s %2 %4", aday[t->tm_wday], + amonth[t->tm_mon], t->tm_mday, t->tm_year+1900); + break; + + case 'X' : + strfmt(r, "%2:%2:%2", t->tm_hour, + t->tm_min, t->tm_sec); + break; + + case 'y' : + strfmt(r,"%2",t->tm_year%100); + break; + + case 'Y' : + strfmt(r,"%4",t->tm_year+1900); + break; + + case 'Z' : + r = (t->tm_isdst) ? __tzname[1] : __tzname[0]; + break; + + default: + buf[0] = '%'; /* reconstruct the format */ + buf[1] = f[-1]; + buf[2] = '\0'; + if (buf[1] == 0) + f--; /* back up if at end of string */ + } + while (*r) + { + if (p == q) + { + *q = '\0'; + return 0; + } + *p++ = *r++; + } + } + else + { + if (p == q) + { + *q = '\0'; + return 0; + } + *p++ = f[-1]; + } + } + *p = '\0'; + return (size_t)(p - s); +} + +static int pow[5] = { 1, 10, 100, 1000, 10000 }; + +/** + * static void strfmt(char *str, char *fmt); + * + * simple sprintf for strftime + * + * each format descriptor is of the form %n + * where n goes from zero to four + * + * 0 -- string %s + * 1..4 -- int %?.?d + * +**/ + +static void strfmt(char *str, const char *fmt, ...) +{ + int ival, ilen; + char *sval; + va_list vp; + + va_start(vp, fmt); + while (*fmt) + { + if (*fmt++ == '%') + { + ilen = *fmt++ - '0'; + if (ilen == 0) /* zero means string arg */ + { + sval = va_arg(vp, char*); + while (*sval) + *str++ = *sval++; + } + else /* always leading zeros */ + { + ival = va_arg(vp, int); + while (ilen) + { + ival %= pow[ilen--]; + *str++ = (char)('0' + ival / pow[ilen]); + } + } + } + else *str++ = fmt[-1]; + } + *str = '\0'; + va_end(vp); +} diff --git a/app/src/main/cpp/pdpclib/x86/time.h b/app/src/main/cpp/pdpclib/x86/time.h new file mode 100644 index 0000000..782c38d --- /dev/null +++ b/app/src/main/cpp/pdpclib/x86/time.h @@ -0,0 +1,72 @@ +/*********************************************************************/ +/* */ +/* This Program Written by Paul Edwards. */ +/* Released to the Public Domain */ +/* */ +/*********************************************************************/ +/*********************************************************************/ +/* */ +/* time.h - time header file. */ +/* */ +/*********************************************************************/ + +#ifndef __TIME_INCLUDED +#define __TIME_INCLUDED + +#define CLOCKS_PER_SEC 1000 +#define NULL ((void *)0) + +typedef unsigned int clock_t; + +#ifndef __SIZE_T_DEFINED +#define __SIZE_T_DEFINED +#if (defined(__OS2__) || defined(__32BIT__) || defined(__MVS__) \ + || defined(__CMS__) || defined(__VSE__) || defined(__SMALLERC__) \ + || defined(__ARM__) || defined(__gnu_linux__) || defined(__PDOS386__) \ + || defined(__SZ4__)) +typedef unsigned long size_t; +#elif (defined(__MSDOS__) || defined(__DOS__) || defined(__POWERC) \ + || defined(__WIN32__) || defined(__AMIGA__) || defined(__EFI__)) +typedef unsigned int size_t; +#endif +#endif + +typedef unsigned long time_t; + +struct tm +{ + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; +}; + +time_t time(time_t *timer); +clock_t clock(void); +double difftime(time_t time1, time_t time0); +time_t mktime(struct tm *timeptr); +char *asctime(const struct tm *timeptr); +char *ctime(const time_t *timer); +struct tm *gmtime(const time_t *timer); +struct tm *localtime(const time_t *timer); +size_t strftime(char *s, size_t maxsize, + const char *format, const struct tm *timeptr); + + +#if defined(__PDOSGEN__) +#include <__os.h> + +#define ctime __os->Xctime +#define localtime __os->Xlocaltime +#define time __os->Xtime +#define clock __os->Xclock + +#endif + + +#endif diff --git a/app/src/main/java/com/cod5/pdos_pdandro/MainActivity.kt b/app/src/main/java/com/cod5/pdos_pdandro/MainActivity.kt new file mode 100644 index 0000000..29d0dcf --- /dev/null +++ b/app/src/main/java/com/cod5/pdos_pdandro/MainActivity.kt @@ -0,0 +1,835 @@ +/* + * 2022-10-25 PUBLIC DOMAIN by Jean-Marc Lienher + * + * The authors disclam copyright to this source code + */ +package com.cod5.pdos_pdandro + +import android.Manifest +import android.content.Context +import android.content.pm.PackageManager +import android.graphics.* +import android.os.Build +import android.os.Bundle +import android.os.Environment +import android.os.Handler +import android.system.Os +import android.util.DisplayMetrics +import android.view.KeyEvent +import android.view.View +import android.view.View.OnClickListener +import android.view.WindowManager +import android.view.inputmethod.InputMethodManager +import android.widget.Toast +import androidx.appcompat.app.AppCompatActivity +import androidx.core.app.ActivityCompat +import com.cod5.pdos_pdandro.databinding.ActivityMainBinding +import java.io.BufferedInputStream +import java.io.BufferedReader +import java.io.File +import java.io.FileInputStream +import java.io.FileOutputStream +import java.io.IOException +import java.io.InputStream +import java.io.OutputStreamWriter +import java.nio.file.Files +import java.nio.file.OpenOption +import java.util.* +import kotlin.math.ceil +import kotlin.system.exitProcess + + +class MainActivity : AppCompatActivity(), OnClickListener { + + private lateinit var binding: ActivityMainBinding + private lateinit var bitmap: Bitmap + private lateinit var canvas: Canvas + private lateinit var paint: Paint + private var margin = 10 + private var line_height = 1F + private var glyph_width = 1F + private var rows = arrayListOf() + private var cur_col = 0 + private var cur_row = 0 + private var cur_show = true + private var cur_timer = 0 + private var escape_state = 0 + private var escape_val = 0 + private var escape_args = arrayListOf() + private var escape_save = arrayListOf() + private var escape_gfx = ScreenChar("") + private lateinit var proc: Process + private lateinit var wri: OutputStreamWriter + private var input_buf = "" + private lateinit var imm: InputMethodManager + + companion object { + private const val STORAGE_PERMISSION_CODE = 101 + var normal = Typeface.create("monospace", Typeface.NORMAL) + var bold = Typeface.create("monospace", Typeface.BOLD) + var italic = Typeface.create("monospace", Typeface.ITALIC) + var bolditalic = Typeface.create("monospace", Typeface.BOLD_ITALIC) + } + + /* a single charcater in our ANSI console */ + class ScreenChar(str: String) { + var txt = str + var decoration = "" + var color = Color.WHITE + var bgcolor = Color.BLACK + var typeface = normal + + fun set(model: ScreenChar) + { + typeface = model.typeface + color = model.color + bgcolor = model.bgcolor + decoration = model.decoration + } + fun reset() { + color = Color.BLACK + bgcolor = Color.WHITE + typeface = normal + decoration = "" + } + } + + /* a row in our ANSI console */ + class ScreenRow (nbcol: Int) { + var col = arrayListOf() + init { + var i = 0 + while (i < nbcol) { + col.add(ScreenChar(" ")) + i++ + } + } + fun set(model: ScreenChar) { + var i = 0 + while (i < col.size) { + col[i].set(model) + i++ + } + } + operator fun get(j: Int): ScreenChar { + return col[j] + } + } + + /* write data to the input of our native executable */ + fun write_buf() { + try { + if (input_buf.length > 0) { + wri.append(input_buf) + input_buf = "" + wri.flush() + } + } catch (e: Exception) { + e.printStackTrace() + } + } + + /* read data from our native executable and quit if it has exit */ + fun read_data() { + try { + val x = proc.exitValue() + finishAffinity() + exitProcess(x) + //System.exit(x) + } catch (e: Exception) { + // nothing + } + try { + val b = ByteArray(proc.inputStream.available()) + val t = proc.inputStream.read(b) + if (t < 1) { + draw_cursor() + return + } + addtxt(String(b)) + } catch (e: Exception) { + // e.printStackTrace() + } + } + + /* physical keyboard input */ + override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { + var s = when (keyCode) { + KeyEvent.KEYCODE_ENTER -> "\n" + KeyEvent.KEYCODE_NUMPAD_ENTER -> "\n" + KeyEvent.KEYCODE_ESCAPE -> "\u001b\u001b" + KeyEvent.KEYCODE_DEL -> "\b" + // https://sourceforge.net/p/pdos/gitcode/ci/master/tree/src/pdos.c#l1764 + KeyEvent.KEYCODE_DPAD_UP -> "\u001b[A" + KeyEvent.KEYCODE_DPAD_DOWN -> "\u001b[B" + KeyEvent.KEYCODE_DPAD_RIGHT -> "\u001b[C" + KeyEvent.KEYCODE_DPAD_LEFT -> "\u001b[D" + KeyEvent.KEYCODE_CTRL_LEFT -> "\u001b[1;5;D" + KeyEvent.KEYCODE_CTRL_RIGHT -> "\u001b[1;5;C" + KeyEvent.KEYCODE_INSERT -> "\u001b[2~" + KeyEvent.KEYCODE_FORWARD_DEL -> "\u001b[3~" + KeyEvent.KEYCODE_MOVE_HOME -> "\u001b[1~" + KeyEvent.KEYCODE_MOVE_END -> "\u001b[4~" + KeyEvent.KEYCODE_PAGE_DOWN -> { + if (event.isCtrlPressed) { + "\u001b[6;5~" + } else { + "\u001b[6~" + } + } + KeyEvent.KEYCODE_PAGE_UP -> { + if (event.isCtrlPressed) { + "\u001b[5;5~" + } else { + "\u001b[5~" + } + } + else -> "" + } + if (event.isAltPressed) { + if (keyCode >= KeyEvent.KEYCODE_A && keyCode <= KeyEvent.KEYCODE_Z) { + s = (keyCode - KeyEvent.KEYCODE_A + 'a'.code).toChar().toString() + s = "\u001b$s" + } + } + if (s.length == 0) { + val c = event.unicodeChar + if (c >= ' '.code) { + s = c.toChar().toString() + } + } + if (s.length > 0) { + val sb = StringBuilder() + sb.append(input_buf).append(s) + input_buf = sb.toString() + write_buf() + return true + } else { + return super.onKeyDown(keyCode, event) + } + } + + /* timer to read data from our native executable */ + fun run_timer() { + Timer().scheduleAtFixedRate(object : TimerTask() { + override fun run() { + Handler(mainLooper).postDelayed( + { read_data() }, 0.toLong()) + } + }, 1000, 20) + } + + override fun onClick(p0: View?) { + if (getCurrentFocus() == null && !imm.isAcceptingText) { + imm.toggleSoftInputFromWindow(p0?.windowToken, WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN, 0) + } + } + + /* called when the activity starts */ + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + binding = ActivityMainBinding.inflate(layoutInflater) + setContentView(binding.root) + supportActionBar?.hide() + + imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + binding.imageView?.setOnClickListener(this) + + binding.imageView?.setOnKeyListener { view, i, keyEvent -> + if (keyEvent.action == KeyEvent.ACTION_DOWN) { + onKeyDown(keyEvent.keyCode, keyEvent) + } + return@setOnKeyListener true + } + + run() + run_timer() + init_display() + } + + /* initilise the console widget area */ + fun init_display() + { + val dm = DisplayMetrics() + @Suppress("DEPRECATION") + windowManager.defaultDisplay.getMetrics(dm) + val dw = dm.widthPixels - 2 * margin + val dh = dm.heightPixels - 2 * margin + + bitmap = Bitmap.createBitmap(dw, dh, Bitmap.Config.ARGB_8888) + canvas = Canvas(bitmap) + + paint = Paint() + paint.color = Color.WHITE + paint.strokeWidth = 0F + paint.typeface = normal + + // find the optimal text size for the screen + var h = 0F + paint.textSize = 8F + var add = 1.0F + while (h < dh) { + h = (paint.fontMetrics.descent - paint.fontMetrics.ascent) * 25F + if (h < dh) { + paint.textSize += add + } else { + paint.textSize -= add + if (add == 1.0F) { + add = 0.5F + } else if (add == 0.5F) { + add = 0.125F + } else { + h = dh.toFloat() + 1.0F + } + } + } + binding.imageView?.setImageBitmap(bitmap) + line_height = paint.fontMetrics.descent - paint.fontMetrics.ascent + glyph_width = paint.measureText("_") + + var i = 0 + while (i < 25) { + rows.add(ScreenRow(80)) + i++ + } + } + + /* draw the console characters */ + fun draw(draw_all: Boolean) { + var i = 0 + var y = margin.toFloat() - paint.fontMetrics.ascent + val ascent = paint.fontMetrics.ascent + + while (i < 25) { + var j = 0 + val r = rows[i] + var x = margin.toFloat() + if (draw_all || i == cur_row) { + while (j < 80) { + val col = r[j] + paint.color = col.bgcolor + canvas.drawRect(RectF(x, y + ascent, x + glyph_width, ceil(y + ascent + line_height)), paint) + x += glyph_width + j++ + } + } + y += line_height + i++ + } + i = 0 + y = margin.toFloat() - paint.fontMetrics.ascent + while (i < 25) { + var j = 0 + val r = rows[i] + var x = margin.toFloat() + if (draw_all || i == cur_row) { + while (j < 80) { + val col = r[j] + paint.color = col.color + paint.typeface = col.typeface + canvas.drawText(col.txt, x, y, paint) + if (col.decoration.length > 0) { + canvas.drawText(col.decoration, x, y, paint) + } + x += glyph_width + j++ + } + } + y += line_height + i++ + } + binding.imageView?.invalidate() + } + + /* scroll the console rows */ + fun scroll(amount: Int) { + var i = 0 + + if (amount < 0) { + while (i > amount) { + rows.removeLast() + i-- + } + i = 0 + while (i > amount) { + rows.add(0, ScreenRow(80)) + rows[0].set(escape_gfx) + i-- + } + } else { + while (i < amount) { + rows.removeAt(0) + i++ + } + i = 0 + while (i < amount) { + rows.add(ScreenRow(80)) + rows[rows.size-1].set(escape_gfx) + i++ + } + } + } + + /* blank the character in the range */ + fun earse(start_col : Int, start_row :Int, end_col: Int, end_row:Int) { + var r = start_row + while (r <= end_row) { + val row = rows[r] + var c = 0 + val ec = 79 + if (r == start_row ) { + c = start_col + } + if (r == end_row) { + c = end_col + } + while (c <= ec) { + row[c].txt = "" // TODO + c++ + } + r++ + } + } + + /* 8 colors for the ANSI console */ + fun get_ansi_color(index: Int) : Int { + return when(index) { + 0 -> Color.BLACK + 1 -> Color.RED + 2 -> Color.GREEN + 3 -> Color.YELLOW + 4 -> Color.BLUE + 5 -> Color.MAGENTA + 6 -> Color.CYAN + 7 -> Color.WHITE + else -> Color.GRAY + } + } + + // Select Graphics Rendition + // https://en.wikipedia.org/wiki/ANSI_escape_code + fun sgr() { + var f = 0 + if (escape_args.size > 1) { + f = escape_args[0] + } + if (f == 0) { + escape_gfx.reset() + } else if (f == 1) { + if (escape_gfx.typeface == italic) { + escape_gfx.typeface = bolditalic + } else { + escape_gfx.typeface = bold + } + } else if (f == 2) { + // do nothing + } else if (f == 3) { + if (escape_gfx.typeface == bold) { + escape_gfx.typeface = bolditalic + } else { + escape_gfx.typeface = italic + } + } else if (f == 4) { + escape_gfx.decoration = "_" + } else if (f >= 30 && f <= 37) { + escape_gfx.color = get_ansi_color(f - 30) + } else if (f >= 40 && f <= 47) { + escape_gfx.bgcolor = get_ansi_color(f - 40) + } else if (f >= 90 && f <= 97) { + escape_gfx.color = get_ansi_color(f - 90) // FIXME brighter + } else if (f >= 100 && f <= 107) { + escape_gfx.bgcolor = get_ansi_color(f - 100) // FIXME brighter + } + } + + /* blink the cursor */ + fun draw_cursor() { + if (!cur_show) { + return + } + cur_timer++ + if (cur_timer == 25) { + val bg = rows[cur_row][cur_col].bgcolor + val fg = rows[cur_row][cur_col].color + rows[cur_row][cur_col].bgcolor = fg + rows[cur_row][cur_col].color = bg + draw(false) + rows[cur_row][cur_col].bgcolor = bg + rows[cur_row][cur_col].color = fg + } else if (cur_timer == 50) { + draw(false) + cur_timer = 0 + } + } + + /* private escape sequence */ + fun ansi_private(c : Int) { + if (c == 'h'.code) { // show caret + if (escape_args.size > 1) { + val cmd = escape_args[1] + if (cmd == 25) { + cur_show = true + } + } + } else if (c == 'l'.code) { // hide caret + if (escape_args.size > 1) { + val cmd = escape_args[1] + if (cmd == 25) { + cur_show = false + } + } + } + } + + /* parse escape sequences */ + fun ansi_term(c: Int) { + // https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797 + // https://sourceforge.net/p/pdos/gitcode/ci/master/tree/src/pdos.c#l5493 + var n = 1 + if (escape_args.size > 0) { + if (escape_args[0] == -'?'.code) { + ansi_private(c) + return + } + n = escape_args[0] + } + if (c == 'A'.code) { + cur_row -= n + } else if (c == 'B'.code) { + cur_row += n + } else if (c == 'C'.code) { + cur_col += n + } else if (c == 'D'.code) { + cur_col -= n + } else if (c == 'E'.code) { + cur_row += n + cur_col = 0 + } else if (c == 'F'.code) { + cur_row -= n + cur_col = 0 + } else if (c == 'G'.code || c == 'f'.code) { + if (escape_args.size > 0) { + cur_col = escape_args[0] - 1 + } + } else if (c == 'H'.code) { // set cursor position + if (escape_args.size > 0) { + cur_row = escape_args[0] - 1 + if (escape_args.size > 1) { + cur_col = escape_args[1] - 1 + } else { + cur_col = 0 + } + } + } else if (c == 'J'.code) { // clear screen + if (escape_args.size == 0) { + n = 0 + } + if (n == 0) { + earse(cur_col, cur_row, 79, 24) + } else if (n == 1) { + earse(0, 0, cur_col, cur_row) + } else if (n == 2) { + earse(0, 0, 79, 24) + } + } else if (c == 'K'.code) { // clear line + if (escape_args.size == 0) { + n = 0 + } + if (n == 0) { + earse(cur_col, cur_row, 79, cur_row) + } else if (n == 1) { + earse(0, cur_row, cur_col, cur_row) + } else if (n == 2) { + earse(0, cur_row, 79, cur_row) + } + } else if (c == 'S'.code) { + scroll(n) + } else if (c == 'T'.code) { + scroll(-n) + } else if (c == 's'.code) { + escape_save.add(cur_row) + escape_save.add(cur_col) + } else if (c == 'u'.code) { + if (escape_save.size > 1) { + cur_col = escape_save.removeLast() + cur_row = escape_save.removeLast() + } + } else if (c == 'm'.code) { + sgr() + } + } + + /* append text to our ANSI console */ + fun addtxt(txt: String) { + var i = 0 + var all = false + val nbcp = txt.codePointCount(0, txt.length) + var row = rows[cur_row] + var col = row[cur_col] + var last_row = cur_row + var last_col = cur_col + while (i < nbcp) { + val c = txt.codePointAt(i) + if (escape_state == 3) { + escape_state = 0 + } + if (escape_state == 1) { + // https://notes.burke.libbey.me/ansi-escape-codes/ + if (c == '['.code) { + escape_state = 2 + escape_val = -1 + escape_args.clear() + } else { + escape_state = 0 + i-- // rescan the current character + } + } else if (escape_state == 2) { + if (c >= '0'.code && c <= '9'.code) { + if (escape_val == -1) { + escape_val = 0 + } + escape_val *= 10 + escape_val += c - '0'.code + } else if (c == ';'.code) { + escape_args.add(escape_val) + escape_val = -1 + } else if (c == '='.code) { + escape_args.add(-'='.code) + escape_val = -1 + } else if (c == '?'.code) { + escape_args.add(-'?'.code) + escape_val = -1 + } else if (c >= 0x40 && c <= 0x7E){ + if (escape_val >= 0) { + escape_args.add(escape_val) + } + ansi_term(c) + all = true + escape_state = 3 + } + } else if (c == 10) { // \n + cur_row++ + cur_col = 0 + } else if (c == 13) { // \r + } else if (c == 8) { + if (cur_col > 0) { + cur_col-- + col = row[cur_col] + col.txt = " " + } + } else if (c == 0x1B) { // ESC + escape_state = 1 + } else { + val sb = StringBuilder() + sb.appendCodePoint(c) + col.set(escape_gfx) + col.txt = sb.toString() + cur_col++ + } + if (cur_col < 0) { + cur_col = 0 + } + if (cur_row < 0) { + cur_row = 0 + } + if (cur_col >= 80) { + if (escape_state == 0) { + cur_row++ + cur_col = 0 + } else { + cur_col = 79 + } + } + if (cur_row >= 25) { + if (escape_state == 0) { + scroll(cur_row - 24) + last_row = -1 + } + cur_row = 24 + } + if (last_row != cur_row) { + all = true + row = rows[cur_row] + col = row[cur_col] + last_row = cur_row + last_col = cur_col + } else if (last_col != cur_col) { + col = row[cur_col] + last_col = cur_col + } + i++ + } + draw(all) + } + + /* print result of permission request */ + override fun onRequestPermissionsResult(requestCode: Int, + permissions: Array, + grantResults: IntArray) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) + if (requestCode == STORAGE_PERMISSION_CODE) { + if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + Toast.makeText(this@MainActivity, "Storage Permission Granted", Toast.LENGTH_SHORT).show() + } else { + Toast.makeText(this@MainActivity, "Storage Permission Denied", Toast.LENGTH_SHORT).show() + } + } + } + + /* asks for read/write permission on Download directory */ + private fun hasWriteStoragePermission(): Boolean { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + return true + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + requestPermissions( + arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), + STORAGE_PERMISSION_CODE + ) + return false + } + } + return true + } + + /* try to rune exec */ + fun run() { + hasWriteStoragePermission() + val tim = Timer() + tim.scheduleAtFixedRate(object : TimerTask() { + override fun run() { + Handler(mainLooper).postDelayed( + { + val ex = Environment.getExternalStorageDirectory().absolutePath + val dir = File("$ex/Download") + try { + if (!dir.exists()) { + dir.mkdir() + } + } catch (e: Exception) { + // + } + if (dir.isDirectory && dir.canWrite()) { + addtxt("running in $dir\n") + tim.cancel() + init_app(dir) + } else { + addtxt("$dir missing permission!\n") + } + }, 0.toLong()) + } + }, 1000, 1000) + } + + private fun isEqual(is1: InputStream, is2: InputStream) : Boolean { + is1.use { src -> + is2.use { dest -> + var ch : Int + while (src.read().also { ch = it } != -1) { + if (ch != dest.read()) { + return false; + } + } + } + } + return true; + } + + /* copy files and run native executable */ + fun init_app(dir: File) { + val s = applicationContext.applicationInfo.nativeLibraryDir + val c = "$s/libpdos.so" + + try { + val file = File(dir, "pdos.exe") + if (!file.exists()) { + val input = resources.openRawResource(R.raw.pdos) + val output = FileOutputStream(file) + val buffer = ByteArray(4096) + var rd = input.read(buffer) + while (rd > 0) { + output.write(buffer, 0, rd) + rd = input.read(buffer) + } + input.close() + output.close() + } + } catch (e: Exception) { + // + } + + try { + val file = File(dir, "pcomm.exe") + + if (file.exists()) { + val abi = Build.SUPPORTED_ABIS[0] + val temp1 = resources.assets.open("$abi/pcomm.exe") + val temp2 = FileInputStream(file) + + if (!isEqual(temp1, temp2)) { + android.util.Log.i(javaClass.name, "Resource file has changed") + file.delete(); + } + + temp1.close() + temp2.close() + } + + if (!file.exists()) { + val abi = Build.SUPPORTED_ABIS[0] + val input = resources.assets.open("$abi/pcomm.exe") + val output = FileOutputStream(file) + val buffer = ByteArray(4096) + var rd = input.read(buffer) + while (rd > 0) { + output.write(buffer, 0, rd) + rd = input.read(buffer) + } + input.close() + output.close() + } + } catch (e: Exception) { + // + } + + try { + val file = File(dir, "uc8086.vhd") + if (!file.exists()) { + val input = resources.openRawResource(R.raw.uc8086) + val output = FileOutputStream(file) + val buffer = ByteArray(4096) + var rd = input.read(buffer) + while (rd > 0) { + output.write(buffer, 0, rd) + rd = input.read(buffer) + } + input.close() + output.close() + } + } catch (e: Exception) { + // + } + + if (dir.canWrite()) { + c.runCommand(dir) + } + } + + + /* execute system command */ + fun String.runCommand(workingDir: File): String { + try { + val own = applicationContext.applicationInfo.nativeLibraryDir + + proc = Runtime.getRuntime().exec( + arrayOf (this, "$own/lib%s.so", workingDir.absolutePath), + Os.environ(), workingDir) + wri = proc.outputStream.writer() + return "" + } catch(e: IOException) { + e.printStackTrace() + return "ERROR" + } + } +} diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..27c5134 --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..f4a6589 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,16 @@ + + + + + + diff --git a/app/src/main/res/layout-land/activity_main.xml b/app/src/main/res/layout-land/activity_main.xml new file mode 100644 index 0000000..7dd4671 --- /dev/null +++ b/app/src/main/res/layout-land/activity_main.xml @@ -0,0 +1,20 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..2cc030a --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..eca70cf --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..eca70cf --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000..6037ff4 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 0000000..23bdb9a Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 0000000..c56c682 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 0000000..6fc46b9 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000..e3fd16a Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..df3a9d2 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 0000000..3ea0fe5 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..849fbdb Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 0000000..3d1efe4 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..225b2c5 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/raw/pdos.exe b/app/src/main/res/raw/pdos.exe new file mode 100644 index 0000000..5a03302 Binary files /dev/null and b/app/src/main/res/raw/pdos.exe differ diff --git a/app/src/main/res/raw/uc8086.vhd b/app/src/main/res/raw/uc8086.vhd new file mode 100644 index 0000000..da7cdf7 Binary files /dev/null and b/app/src/main/res/raw/uc8086.vhd differ diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml new file mode 100644 index 0000000..3f1cca3 --- /dev/null +++ b/app/src/main/res/values-night/themes.xml @@ -0,0 +1,17 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..f8c6127 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..4daad1c --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + Pdos-PdAndro + \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..1e78db7 --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,17 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/backup_rules.xml b/app/src/main/res/xml/backup_rules.xml new file mode 100644 index 0000000..fa0f996 --- /dev/null +++ b/app/src/main/res/xml/backup_rules.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/data_extraction_rules.xml b/app/src/main/res/xml/data_extraction_rules.xml new file mode 100644 index 0000000..9ee9997 --- /dev/null +++ b/app/src/main/res/xml/data_extraction_rules.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..eaceefd --- /dev/null +++ b/build.gradle @@ -0,0 +1,6 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +plugins { + id 'com.android.application' version '7.4.1' apply false + id 'com.android.library' version '7.4.1' apply false + id 'org.jetbrains.kotlin.android' version '1.7.10' apply false +} \ No newline at end of file diff --git a/doc/screen.jpg b/doc/screen.jpg new file mode 100644 index 0000000..d0aaa98 Binary files /dev/null and b/doc/screen.jpg differ diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..3c5031e --- /dev/null +++ b/gradle.properties @@ -0,0 +1,23 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Kotlin code style for this project: "official" or "obsolete": +kotlin.code.style=official +# Enables namespacing of each library's R class so that its R class includes only the +# resources declared in the library itself and none from the library's dependencies, +# thereby reducing the size of the R class for that library +android.nonTransitiveRClass=true \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..e708b1c Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..e2b7165 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Mon Oct 10 22:20:41 CEST 2022 +distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..4f906e0 --- /dev/null +++ b/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..107acd3 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..c968195 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,16 @@ +pluginManagement { + repositories { + gradlePluginPortal() + google() + mavenCentral() + } +} +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} +rootProject.name = "Pdos-PdAndro" +include ':app'