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``
+
+
+
+
+
+## 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'