Per prior discussion, I propose the attached patch for further
discussion. It's not quite ready. It doesn't include Sam's commits
(thanks Sam!) and doesn't address st_atim, as reported by Iain in PR
122466 (thanks Iain, I think). I will address those issues before
committing. I'm soliciting feedback meanwhile.
The patch does the following:
1. Introduces libgcobol/compat for vendor-compatibility libraries, of
which there is currently one: libgcobol/compat/lib/gnu.
2. Introduces COBOL POSIX bindings as user-defined functions, so GCC
COBOL users don't hand-craft every call to the operating system.
3. Moves C support for POSIX bindings to libgcobol/posix/shim, so named
because the functions aren't meant to be user-facing (although the
intrepid user can use them).
4. Includes some utility scripts for creating and compiling new POSIX
bindings. These are in a bin/ directory. They are not used to build or to
install libgcobol. They are not installed, and need not be included in
distributions.
5. Installs the UDFs intended for the user in a versioned directory.
On my system it shows up as
PREFIX/lib/gcc/cobol/aarch64-unknown-linux-gnu/16.0.0/
That name could use some love. Because the files are COBOL source
code meant to be included, better IMO would be
PREFIX/include/gcc/cobol/16.0.0/
or
PREFIX/include/gcc/16.0.0/cobol
or
PREFIX/share/gcc/16.0.0/cobol
Please tell me what the name should be.
It is produced in Makefile.am from:
libsubincludedir =
$(libdir)/gcc/cobol/$(target_noncanonical)/$(gcc_version)
I think I could remove the architecture with
libsubincludedir = $(libdir)/gcc/cobol/$(gcc_version)
but I don't know what to use instead of $(libdir).
Work still to come:
6. Documentation for compat/ library and posix/ binding functions. I
doubt we will need to document each function; rather some statement is
needed referring the user to the functionality being emulated, and a
discussion of how, for example, to get at errno.
7. Real tests. As of now the only use of the POSIX bindings is in
support of the compat/ library. We need tests for that library,
which we may be able to borrow from GnuCOBOL.
Patch follows. Please tell me what you would change before committing.
--jkl
[snip]
cobol: Introduce vendor-compatibility layer as user-defined functions.
Install COBOL UDFs in a target directory that includes the GCC version
in its path, to permit side-by-side installation. Support compat
library with COBOL POSIX bindings; support those binding with C
functions in libgcobol as needed.
Include developer conveniences -- Makefiles, bin/ and t/ directories --
to ensure UDFs compile and return reasonable results. These are
not installed and do not affect how libgcobol is built.
libgcobol/ChangeLog:
* Makefile.am: Move UDF-support to posix/shim, add install targets
* Makefile.in: Regenerate
* .gitignore: New file.
* compat/README.md: New file.
* compat/lib/gnu/CBL_ALLOC_MEM.cbl: New file.
* compat/lib/gnu/CBL_CHECK_FILE_EXIST.cbl: New file.
* compat/lib/gnu/CBL_DELETE_FILE.cbl: New file.
* compat/lib/gnu/CBL_FREE_MEM.cbl: New file.
* compat/t/Makefile: New file.
* compat/t/smoke.cbl: New file.
* posix/README.md: New file.
* posix/bin/Makefile: New file for UDF-developer.
* posix/bin/headers: New file.
* posix/bin/scrape.awk: New file.
* posix/bin/sizeofs.c: New file.
* posix/bin/udf-gen: New file.
* posix/cpy/posix-errno.cbl: New file.
* posix/cpy/statbuf.cpy: New file.
* posix/cpy/tm.cpy: New file.
* posix/t/Makefile: New file.
* posix/t/errno.cbl: New file.
* posix/t/exit.cbl: New file.
* posix/t/localtime.cbl: New file.
* posix/t/stat.cbl: New file.
* posix/udf/posix-exit.cbl: New file.
* posix/udf/posix-localtime.cbl: New file.
* posix/udf/posix-mkdir.cbl: New file.
* posix/udf/posix-stat.cbl: New file.
* posix/udf/posix-unlink.cbl: New file.
diff --git a/libgcobol/.gitignore b/libgcobol/.gitignore
new file mode 100644
index 00000000000..cf81477422a
--- /dev/null
+++ b/libgcobol/.gitignore
@@ -0,0 +1,8 @@
+compat/t/*
+!compat/t/Makefile
+!compat/t/*.cbl
+posix/bin/sizeofs
+posix/t/*
+!posix/t/Makefile
+!posix/t/*.cbl
+posix/udf/*.scr
diff --git a/libgcobol/Makefile.am b/libgcobol/Makefile.am
index f42bfce2380..2a04041a3c9 100644
--- a/libgcobol/Makefile.am
+++ b/libgcobol/Makefile.am
@@ -30,6 +30,8 @@ if BUILD_LIBGCOBOL
toolexeclib_LTLIBRARIES = libgcobol.la
toolexeclib_DATA = libgcobol.spec
+libsubincludedir = $(libdir)/gcc/cobol/$(target_noncanonical)/$(gcc_version)
+
##
## 2.2.12 Automatic Dependency Tracking
## Automake generates code for automatic dependency tracking by default
@@ -43,18 +45,31 @@ libgcobol_la_SOURCES = \
intrinsic.cc \
io.cc \
libgcobol.cc \
- posix/errno.cc \
- posix/localtime.cc \
- posix/stat.cc \
+ posix/shim/errno.cc \
+ posix/shim/localtime.cc \
+ posix/shim/stat.cc \
stringbin.cc \
valconv.cc \
xmlparse.cc
libgcobol_la_LIBADD = -lxml2
+nobase_libsubinclude_HEADERS = \
+ posix/cpy/posix-errno.cbl \
+ posix/cpy/statbuf.cpy \
+ posix/udf/posix-exit.cbl \
+ posix/udf/posix-localtime.cbl \
+ posix/udf/posix-mkdir.cbl \
+ posix/udf/posix-stat.cbl \
+ posix/udf/posix-unlink.cbl \
+ compat/lib/gnu/CBL_CHECK_FILE_EXIST.cbl \
+ compat/lib/gnu/CBL_ALLOC_MEM.cbl \
+ compat/lib/gnu/CBL_DELETE_FILE.cbl \
+ compat/lib/gnu/CBL_FREE_MEM.cbl
+
WARN_CFLAGS = -W -Wall -Wwrite-strings
-AM_CPPFLAGS = -I. -I$(srcdir) -I$(srcdir)/posix $(LIBQUADINCLUDE)
+AM_CPPFLAGS = -I. -I posix/shim $(LIBQUADINCLUDE)
AM_CPPFLAGS += -I /usr/include/libxml2
AM_CFLAGS = $(XCFLAGS)
diff --git a/libgcobol/Makefile.in b/libgcobol/Makefile.in
index 880fa1f40a6..e3308cbb6e6 100644
--- a/libgcobol/Makefile.in
+++ b/libgcobol/Makefile.in
@@ -36,6 +36,7 @@
# Written de novo for libgcobol.
+
VPATH = @srcdir@
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
@@ -140,7 +141,7 @@ am__aclocal_m4_deps =
$(top_srcdir)/../config/clang-plugin.m4 \
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
- $(am__configure_deps)
+ $(am__configure_deps) $(am__nobase_libsubinclude_HEADERS_DIST)
am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
configure.lineno config.status.lineno
mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
@@ -175,15 +176,16 @@ am__uninstall_files_from_dir = { \
$(am__cd) "$$dir" && rm -f $$files; }; \
}
am__installdirs = "$(DESTDIR)$(toolexeclibdir)" \
- "$(DESTDIR)$(toolexeclibdir)"
+ "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(libsubincludedir)"
LTLIBRARIES = $(toolexeclib_LTLIBRARIES)
am__dirstamp = $(am__leading_dot)dirstamp
@BUILD_LIBGCOBOL_TRUE@am_libgcobol_la_OBJECTS = charmaps.lo \
@BUILD_LIBGCOBOL_TRUE@ constants.lo gfileio.lo gmath.lo \
@BUILD_LIBGCOBOL_TRUE@ intrinsic.lo io.lo libgcobol.lo \
-@BUILD_LIBGCOBOL_TRUE@ posix/errno.lo posix/localtime.lo \
-@BUILD_LIBGCOBOL_TRUE@ posix/stat.lo stringbin.lo valconv.lo \
-@BUILD_LIBGCOBOL_TRUE@ xmlparse.lo
+@BUILD_LIBGCOBOL_TRUE@ posix/shim/errno.lo \
+@BUILD_LIBGCOBOL_TRUE@ posix/shim/localtime.lo \
+@BUILD_LIBGCOBOL_TRUE@ posix/shim/stat.lo stringbin.lo \
+@BUILD_LIBGCOBOL_TRUE@ valconv.lo xmlparse.lo
libgcobol_la_OBJECTS = $(am_libgcobol_la_OBJECTS)
@BUILD_LIBGCOBOL_TRUE@am_libgcobol_la_rpath = -rpath $(toolexeclibdir)
AM_V_P = $(am__v_P_@AM_V@)
@@ -231,6 +233,15 @@ am__can_run_installinfo = \
*) (install-info --version) >/dev/null 2>&1;; \
esac
DATA = $(toolexeclib_DATA)
+am__nobase_libsubinclude_HEADERS_DIST = posix/cpy/posix-errno.cbl \
+ posix/cpy/statbuf.cpy posix/udf/posix-exit.cbl \
+ posix/udf/posix-localtime.cbl posix/udf/posix-mkdir.cbl \
+ posix/udf/posix-stat.cbl posix/udf/posix-unlink.cbl \
+ compat/lib/gnu/CBL_CHECK_FILE_EXIST.cbl \
+ compat/lib/gnu/CBL_ALLOC_MEM.cbl \
+ compat/lib/gnu/CBL_DELETE_FILE.cbl \
+ compat/lib/gnu/CBL_FREE_MEM.cbl
+HEADERS = $(nobase_libsubinclude_HEADERS)
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \
$(LISP)config.h.in
# Read a list of newline-separated strings from the standard input,
@@ -402,6 +413,7 @@ gcc_version := $(shell @get_gcc_base_ver@
$(top_srcdir)/../gcc/BASE-VER)
# Skip the whole process if we are not building libgcobol.
@BUILD_LIBGCOBOL_TRUE@toolexeclib_LTLIBRARIES = libgcobol.la
@BUILD_LIBGCOBOL_TRUE@toolexeclib_DATA = libgcobol.spec
+@BUILD_LIBGCOBOL_TRUE@libsubincludedir =
$(libdir)/gcc/cobol/$(target_noncanonical)/$(gcc_version)
@BUILD_LIBGCOBOL_TRUE@libgcobol_la_SOURCES = \
@BUILD_LIBGCOBOL_TRUE@ charmaps.cc \
@BUILD_LIBGCOBOL_TRUE@ constants.cc \
@@ -410,16 +422,29 @@ gcc_version := $(shell @get_gcc_base_ver@
$(top_srcdir)/../gcc/BASE-VER)
@BUILD_LIBGCOBOL_TRUE@ intrinsic.cc \
@BUILD_LIBGCOBOL_TRUE@ io.cc \
@BUILD_LIBGCOBOL_TRUE@ libgcobol.cc \
-@BUILD_LIBGCOBOL_TRUE@ posix/errno.cc \
-@BUILD_LIBGCOBOL_TRUE@ posix/localtime.cc \
-@BUILD_LIBGCOBOL_TRUE@ posix/stat.cc \
+@BUILD_LIBGCOBOL_TRUE@ posix/shim/errno.cc \
+@BUILD_LIBGCOBOL_TRUE@ posix/shim/localtime.cc \
+@BUILD_LIBGCOBOL_TRUE@ posix/shim/stat.cc \
@BUILD_LIBGCOBOL_TRUE@ stringbin.cc \
@BUILD_LIBGCOBOL_TRUE@ valconv.cc \
@BUILD_LIBGCOBOL_TRUE@ xmlparse.cc
@BUILD_LIBGCOBOL_TRUE@libgcobol_la_LIBADD = -lxml2
+@BUILD_LIBGCOBOL_TRUE@nobase_libsubinclude_HEADERS = \
+@BUILD_LIBGCOBOL_TRUE@ posix/cpy/posix-errno.cbl \
+@BUILD_LIBGCOBOL_TRUE@ posix/cpy/statbuf.cpy \
+@BUILD_LIBGCOBOL_TRUE@ posix/udf/posix-exit.cbl \
+@BUILD_LIBGCOBOL_TRUE@ posix/udf/posix-localtime.cbl \
+@BUILD_LIBGCOBOL_TRUE@ posix/udf/posix-mkdir.cbl \
+@BUILD_LIBGCOBOL_TRUE@ posix/udf/posix-stat.cbl \
+@BUILD_LIBGCOBOL_TRUE@ posix/udf/posix-unlink.cbl \
+@BUILD_LIBGCOBOL_TRUE@ compat/lib/gnu/CBL_CHECK_FILE_EXIST.cbl \
+@BUILD_LIBGCOBOL_TRUE@ compat/lib/gnu/CBL_ALLOC_MEM.cbl \
+@BUILD_LIBGCOBOL_TRUE@ compat/lib/gnu/CBL_DELETE_FILE.cbl \
+@BUILD_LIBGCOBOL_TRUE@ compat/lib/gnu/CBL_FREE_MEM.cbl
+
@BUILD_LIBGCOBOL_TRUE@WARN_CFLAGS = -W -Wall -Wwrite-strings
-@BUILD_LIBGCOBOL_TRUE@AM_CPPFLAGS = -I. -I$(srcdir) -I$(srcdir)/posix \
+@BUILD_LIBGCOBOL_TRUE@AM_CPPFLAGS = -I. -I posix/shim \
@BUILD_LIBGCOBOL_TRUE@ $(LIBQUADINCLUDE) -I \
@BUILD_LIBGCOBOL_TRUE@ /usr/include/libxml2
@BUILD_LIBGCOBOL_TRUE@AM_CFLAGS = $(XCFLAGS)
@@ -523,24 +548,26 @@ clean-toolexeclibLTLIBRARIES:
echo rm -f $${locs}; \
rm -f $${locs}; \
}
-posix/$(am__dirstamp):
- @$(MKDIR_P) posix
- @: > posix/$(am__dirstamp)
-posix/$(DEPDIR)/$(am__dirstamp):
- @$(MKDIR_P) posix/$(DEPDIR)
- @: > posix/$(DEPDIR)/$(am__dirstamp)
-posix/errno.lo: posix/$(am__dirstamp) posix/$(DEPDIR)/$(am__dirstamp)
-posix/localtime.lo: posix/$(am__dirstamp) \
- posix/$(DEPDIR)/$(am__dirstamp)
-posix/stat.lo: posix/$(am__dirstamp) posix/$(DEPDIR)/$(am__dirstamp)
+posix/shim/$(am__dirstamp):
+ @$(MKDIR_P) posix/shim
+ @: > posix/shim/$(am__dirstamp)
+posix/shim/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) posix/shim/$(DEPDIR)
+ @: > posix/shim/$(DEPDIR)/$(am__dirstamp)
+posix/shim/errno.lo: posix/shim/$(am__dirstamp) \
+ posix/shim/$(DEPDIR)/$(am__dirstamp)
+posix/shim/localtime.lo: posix/shim/$(am__dirstamp) \
+ posix/shim/$(DEPDIR)/$(am__dirstamp)
+posix/shim/stat.lo: posix/shim/$(am__dirstamp) \
+ posix/shim/$(DEPDIR)/$(am__dirstamp)
libgcobol.la: $(libgcobol_la_OBJECTS) $(libgcobol_la_DEPENDENCIES)
$(EXTRA_libgcobol_la_DEPENDENCIES)
$(AM_V_GEN)$(libgcobol_la_LINK) $(am_libgcobol_la_rpath)
$(libgcobol_la_OBJECTS) $(libgcobol_la_LIBADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
- -rm -f posix/*.$(OBJEXT)
- -rm -f posix/*.lo
+ -rm -f posix/shim/*.$(OBJEXT)
+ -rm -f posix/shim/*.lo
distclean-compile:
-rm -f *.tab.c
@@ -555,9 +582,9 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stringbin.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/valconv.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xmlparse.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@posix/$(DEPDIR)/errno.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@posix/$(DEPDIR)/localtime.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@posix/$(DEPDIR)/stat.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@posix/shim/$(DEPDIR)/errno.Plo@am__quote@
+@AMDEP_TRUE@@am__include@
@am__quote@posix/shim/$(DEPDIR)/localtime.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@posix/shim/$(DEPDIR)/stat.Plo@am__quote@
.cc.o:
@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed
's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
@@ -588,7 +615,7 @@ mostlyclean-libtool:
clean-libtool:
-rm -rf .libs _libs
- -rm -rf posix/.libs posix/_libs
+ -rm -rf posix/shim/.libs posix/shim/_libs
distclean-libtool:
-rm -f libtool config.lt
@@ -613,6 +640,30 @@ uninstall-toolexeclibDATA:
@list='$(toolexeclib_DATA)'; test -n "$(toolexeclibdir)" || list=; \
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
dir='$(DESTDIR)$(toolexeclibdir)'; $(am__uninstall_files_from_dir)
+install-nobase_libsubincludeHEADERS: $(nobase_libsubinclude_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(nobase_libsubinclude_HEADERS)'; test -n "$(libsubincludedir)"
|| list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libsubincludedir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libsubincludedir)" || exit 1; \
+ fi; \
+ $(am__nobase_list) | while read dir files; do \
+ xfiles=; for file in $$files; do \
+ if test -f "$$file"; then xfiles="$$xfiles $$file"; \
+ else xfiles="$$xfiles $(srcdir)/$$file"; fi; done; \
+ test -z "$$xfiles" || { \
+ test "x$$dir" = x. || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libsubincludedir)/$$dir'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libsubincludedir)/$$dir"; }; \
+ echo " $(INSTALL_HEADER) $$xfiles
'$(DESTDIR)$(libsubincludedir)/$$dir'"; \
+ $(INSTALL_HEADER) $$xfiles "$(DESTDIR)$(libsubincludedir)/$$dir" ||
exit $$?; }; \
+ done
+
+uninstall-nobase_libsubincludeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(nobase_libsubinclude_HEADERS)'; test -n "$(libsubincludedir)"
|| list=; \
+ $(am__nobase_strip_setup); files=`$(am__nobase_strip)`; \
+ dir='$(DESTDIR)$(libsubincludedir)'; $(am__uninstall_files_from_dir)
ID: $(am__tagged_files)
$(am__define_uniq_tagged_files); mkid -fID $$unique
@@ -674,9 +725,9 @@ distclean-tags:
-rm -f cscope.out cscope.in.out cscope.po.out cscope.files
check-am: all-am
check: check-am
-all-am: Makefile $(LTLIBRARIES) $(DATA) config.h
+all-am: Makefile $(LTLIBRARIES) $(DATA) $(HEADERS) config.h
installdirs:
- for dir in "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibdir)";
do \
+ for dir in "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibdir)"
"$(DESTDIR)$(libsubincludedir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
@@ -705,8 +756,8 @@ clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f
$(CONFIG_CLEAN_VPATH_FILES)
- -rm -f posix/$(DEPDIR)/$(am__dirstamp)
- -rm -f posix/$(am__dirstamp)
+ -rm -f posix/shim/$(DEPDIR)/$(am__dirstamp)
+ -rm -f posix/shim/$(am__dirstamp)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@@ -718,7 +769,7 @@ clean-am: clean-generic clean-libtool
clean-toolexeclibLTLIBRARIES \
distclean: distclean-am
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
- -rm -rf ./$(DEPDIR) posix/$(DEPDIR)
+ -rm -rf ./$(DEPDIR) posix/shim/$(DEPDIR)
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-hdr distclean-libtool distclean-tags
@@ -735,7 +786,7 @@ info: info-am
info-am:
-install-data-am:
+install-data-am: install-nobase_libsubincludeHEADERS
install-dvi: install-dvi-am
@@ -767,7 +818,7 @@ installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
-rm -rf $(top_srcdir)/autom4te.cache
- -rm -rf ./$(DEPDIR) posix/$(DEPDIR)
+ -rm -rf ./$(DEPDIR) posix/shim/$(DEPDIR)
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
@@ -784,8 +835,8 @@ ps: ps-am
ps-am:
-uninstall-am: uninstall-toolexeclibDATA \
- uninstall-toolexeclibLTLIBRARIES
+uninstall-am: uninstall-nobase_libsubincludeHEADERS \
+ uninstall-toolexeclibDATA uninstall-toolexeclibLTLIBRARIES
.MAKE: all install-am install-strip
@@ -797,14 +848,15 @@ uninstall-am: uninstall-toolexeclibDATA \
html-am info info-am install install-am install-data \
install-data-am install-dvi install-dvi-am install-exec \
install-exec-am install-html install-html-am install-info \
- install-info-am install-man install-pdf install-pdf-am \
+ install-info-am install-man \
+ install-nobase_libsubincludeHEADERS install-pdf install-pdf-am \
install-ps install-ps-am install-strip install-toolexeclibDATA \
install-toolexeclibLTLIBRARIES installcheck installcheck-am \
installdirs maintainer-clean maintainer-clean-generic \
mostlyclean mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
- uninstall-am uninstall-toolexeclibDATA \
- uninstall-toolexeclibLTLIBRARIES
+ uninstall-am uninstall-nobase_libsubincludeHEADERS \
+ uninstall-toolexeclibDATA uninstall-toolexeclibLTLIBRARIES
.PRECIOUS: Makefile
diff --git a/libgcobol/compat/README.md b/libgcobol/compat/README.md
new file mode 100644
index 00000000000..21c22260b9b
--- /dev/null
+++ b/libgcobol/compat/README.md
@@ -0,0 +1,25 @@
+# GCC COBOL Compatibility Functions
+
+## Purpose
+
+It seems every COBOL compiler includes a library of functions intended
+to make the COBOL programer's life easier. All of them, as we
+demonstrate here, can be written in COBOL. They are supplied in COBOL
+form, not as a library. The user is free to use them via a COPY
+statement, or compile them into a utility library.
+
+Some of the functions defined here require runtime support from libgcobol.
+
+## Fri Oct 10 16:01:58 2025
+
+At the time of this writing, the functions of greatest concern are
+those that are defined by Rocket Software (formerly MicroFocus) and
+emulated by GnuCOBOL. Those are implemented in
+`gcc/cobol/compat/lib/gnu`. Any calls they would otherwise make to
+the C library are effected through COBOL POSIX bindings supplied by
+`gcc/cobol/posix/udf`.
+
+As an aid to the developer, a simple example of how these functions
+are used is found in `gcc/cobol/compat/t/smoke.cbl`. It may by
+compiled using `gcc/cobol/compat/Makefile`.
+
diff --git a/libgcobol/compat/lib/gnu/CBL_ALLOC_MEM.cbl
b/libgcobol/compat/lib/gnu/CBL_ALLOC_MEM.cbl
new file mode 100644
index 00000000000..a2a8f1a1c07
--- /dev/null
+++ b/libgcobol/compat/lib/gnu/CBL_ALLOC_MEM.cbl
@@ -0,0 +1,26 @@
+ >>PUSH SOURCE FORMAT
+ >>SOURCE FIXED
+
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * MODIFY AFTER SUCCESSFUL TESTING / IMPLEMENTATION (VPH)
+ * This function is in the public domain.
+ * Contributed by
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ IDENTIFICATION DIVISION.
+ PROGRAM-ID. CBL_ALLOC_MEM.
+
+ DATA DIVISION.
+ LINKAGE SECTION.
+ 01 MEMORY-REQUESTED PIC 9(8) COMP-4.
+ 01 MEMORY-ALLOCATED USAGE IS POINTER.
+
+ PROCEDURE DIVISION USING MEMORY-REQUESTED,
+ RETURNING MEMORY-ALLOCATED.
+
+ ALLOCATE MEMORY-REQUESTED CHARACTERS INITIALIZED,
+ RETURNING MEMORY-ALLOCATED.
+
+ END PROGRAM CBL_ALLOC_MEM.
+
+ >> POP SOURCE FORMAT
\ No newline at end of file
diff --git a/libgcobol/compat/lib/gnu/CBL_CHECK_FILE_EXIST.cbl
b/libgcobol/compat/lib/gnu/CBL_CHECK_FILE_EXIST.cbl
new file mode 100644
index 00000000000..059811cc9b2
--- /dev/null
+++ b/libgcobol/compat/lib/gnu/CBL_CHECK_FILE_EXIST.cbl
@@ -0,0 +1,46 @@
+ >>PUSH SOURCE FORMAT
+ >>SOURCE FIXED
+ * Include the posix-stat function
+ COPY posix-stat.
+ * COPY posix-errno.
+
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * MODIFY AFTER SUCCESSFUL TESTING / IMPLEMENTATION (VPH)
+ * This function is in the public domain.
+ * Contributed by James K. Lowden of Cobolworx in August 2024
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ IDENTIFICATION DIVISION.
+ PROGRAM-ID. CBL_CHECK_FILE_EXIST.
+ DATA DIVISION.
+ WORKING-STORAGE SECTION.
+ 77 FUNC-RETURN-VALUE PIC 9(8) COMP-5.
+ LINKAGE SECTION.
+ 77 RETURN-CODE PIC 9(8) COMP-5.
+ 01 STAT-BUFFER.
+ COPY statbuf.
+ 01 FILE-PATH PIC X(8192).
+ 01 FI-FILE-INFO.
+ 05 FI-FILE-SIZE-IN-BYTES PIC 9(8) COMP-4.
+ 05 FI-FILE-MOD-DATE-TIME.
+ 10 FI-FILE-DATE PIC 9(8) COMP-4.
+ 10 FI-FILE-TIME PIC 9(8) COMP-4.
+
+ PROCEDURE DIVISION USING FILE-PATH, FI-FILE-INFO,
+ RETURNING RETURN-CODE.
+ MOVE FUNCTION posix-stat(FILE-PATH, STAT-BUFFER)
+ TO FUNC-RETURN-VALUE.
+ IF FUNC-RETURN-VALUE = ZERO
+ THEN
+ MOVE ZERO TO RETURN-CODE
+ MOVE st_size TO FI-FILE-SIZE-IN-BYTES
+ MOVE st_mtim TO FI-FILE-MOD-DATE-TIME
+ ELSE
+ MOVE 1 TO RETURN-CODE
+ MOVE ZERO TO FI-FILE-SIZE-IN-BYTES
+ MOVE ZERO TO FI-FILE-DATE
+ MOVE ZERO TO FI-FILE-TIME.
+
+ END PROGRAM CBL_CHECK_FILE_EXIST.
+
+ >> POP SOURCE FORMAT
\ No newline at end of file
diff --git a/libgcobol/compat/lib/gnu/CBL_DELETE_FILE.cbl
b/libgcobol/compat/lib/gnu/CBL_DELETE_FILE.cbl
new file mode 100644
index 00000000000..1b67d997c16
--- /dev/null
+++ b/libgcobol/compat/lib/gnu/CBL_DELETE_FILE.cbl
@@ -0,0 +1,25 @@
+ >>PUSH SOURCE FORMAT
+ >>SOURCE FIXED
+ * Include the posix-unlink function
+ COPY posix-unlink.
+
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * MODIFY AFTER SUCCESSFUL TESTING / IMPLEMENTATION (VPH)
+ * This function is in the public domain.
+ * Contributed by
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ IDENTIFICATION DIVISION.
+ PROGRAM-ID. CBL_DELETE_FILE.
+ DATA DIVISION.
+ LINKAGE SECTION.
+ 77 RETURN-CODE PIC 9(8) COMP-5.
+ 01 FILE-PATH PIC X(8192).
+
+ PROCEDURE DIVISION USING FILE-PATH, RETURNING RETURN-CODE.
+
+ MOVE FUNCTION posix-unlink(FILE-PATH) TO RETURN-CODE.
+
+ END PROGRAM CBL_DELETE_FILE.
+
+ >> POP SOURCE FORMAT
\ No newline at end of file
diff --git a/libgcobol/compat/lib/gnu/CBL_FREE_MEM.cbl
b/libgcobol/compat/lib/gnu/CBL_FREE_MEM.cbl
new file mode 100644
index 00000000000..6808d140475
--- /dev/null
+++ b/libgcobol/compat/lib/gnu/CBL_FREE_MEM.cbl
@@ -0,0 +1,26 @@
+ >>PUSH SOURCE FORMAT
+ >>SOURCE FIXED
+
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * MODIFY AFTER SUCCESSFUL TESTING / IMPLEMENTATION (VPH)
+ * This function is in the public domain.
+ * Contributed by
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ IDENTIFICATION DIVISION.
+ PROGRAM-ID. CBL_FREE_MEM.
+
+ DATA DIVISION.
+ LINKAGE SECTION.
+ 77 RETURN-CODE PIC 9(8) COMP.
+ 01 MEMORY-ADDRESS USAGE IS POINTER.
+
+ PROCEDURE DIVISION USING MEMORY-ADDRESS,
+ RETURNING RETURN-CODE.
+
+ FREE MEMORY-ADDRESS.
+ MOVE ZERO TO RETURN-CODE.
+
+ END PROGRAM CBL_FREE_MEM.
+
+ >> POP SOURCE FORMAT
\ No newline at end of file
diff --git a/libgcobol/compat/t/Makefile b/libgcobol/compat/t/Makefile
new file mode 100644
index 00000000000..a1d92d391a6
--- /dev/null
+++ b/libgcobol/compat/t/Makefile
@@ -0,0 +1,16 @@
+#
+# A simple Makefile to demonstrate how the compat/lib programs are used.
+#
+
+INCLUDE = ../../posix/cpy ../../posix/udf ../lib/gnu
+
+FLAGS = -dialect mf $(addprefix -I,$(INCLUDE))
+
+test: smoke
+ ./$^
+
+% : %.cbl
+ $(ENV) $(COBC) -o $@ $(FLAGS) $(COBCFLAGS) $(LDFLAGS) $^
+
+
+
diff --git a/libgcobol/compat/t/smoke.cbl b/libgcobol/compat/t/smoke.cbl
new file mode 100644
index 00000000000..b3ba9cedd11
--- /dev/null
+++ b/libgcobol/compat/t/smoke.cbl
@@ -0,0 +1,61 @@
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * This function is in the public domain.
+ * Contributed by James K. Lowden of Cobolworx in October 2025
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ COPY posix-errno.
+
+ COPY CBL_ALLOC_MEM.
+ COPY CBL_CHECK_FILE_EXIST.
+ COPY CBL_DELETE_FILE.
+ COPY CBL_FREE_MEM.
+
+ IDENTIFICATION DIVISION.
+ PROGRAM-ID. gcobol-smoke-test.
+ DATA DIVISION.
+ WORKING-STORAGE SECTION.
+ 77 filename Pic x(80).
+ 77 status-code BINARY-LONG SIGNED.
+
+ * CBL_ALLOC_MEM
+ 01 mem-pointer usage pointer.
+ 77 mem-size pic x(8) comp-5.
+ 77 flags pic x(8) comp-5.
+
+ * CBL_CHECK_FILE_EXIST
+ 01 file-info.
+ 03 file-modification-day.
+ 05 File-Size-In-Bytes PIC 9(18) COMP.
+ 05 Mod-DD PIC 9(2) COMP. *> Modification Date
+ 05 Mod-MO PIC 9(2) COMP.
+ 05 Mod-YYYY PIC 9(4) COMP.
+ 03 file-modification-time.
+ 05 Mod-HH PIC 9(2) COMP. *> Modification Time
+ 05 Mod-MM PIC 9(2) COMP.
+ 05 Mod-SS PIC 9(2) COMP.
+ 05 FILLER PIC 9(2) COMP. *> Always 00
+
+ PROCEDURE DIVISION.
+
+ Call "CBL_ALLOC_MEM" using
+ mem-pointer
+ by value mem-size
+ by value flags
+ returning status-code.
+
+ Call "CBL_CHECK_FILE_EXIST" using filename
+ file-info
+ returning status-code.
+
+ Call "CBL_DELETE_FILE" using filename
+ returning status-code.
+
+
+ Call "CBL_FREE_MEM" using by value mem-pointer
+ returning status-code.
+
+ >>IF CBL_READ_FILE is defined
+ Call "CBL_READ_FILE"
+ using handle, offset, count, flags, buf
+ returning status-code.
+ >>END-IF
+
diff --git a/libgcobol/posix/README.md b/libgcobol/posix/README.md
new file mode 100644
index 00000000000..ee747fd0ab9
--- /dev/null
+++ b/libgcobol/posix/README.md
@@ -0,0 +1,99 @@
+# GCC COBOL Posix Functions and Adapter
+
+## Purpose
+
+GCC COBOL provides COBOL bindings for some POSIX functions. Feel free
+to contribute more. Insofar as possible, the functions take the same
+parameters and return the same values as defined by POSIX. Among
+others, they are used by the COBOL compatibility library (see
+libgcobol/compat/lib/gnu). They are installed in source form for use
+via the CDF COPY directive. The user may also decide to compile them
+to a library.
+
+ISO COBOL does not specify any relationship to any particular
+operating system, and does not reference Posix. The raw capability is
+there, of course, via the `CALL` statement. But that's not very
+convenient, and offers no parameter validation.
+
+For simple functions, e.g. **unlink**(2), the UDFs simply call the
+underlying C library. More complex functions, though,
+e.g. **stat**(2), pass or return a buffer. That buffer is normally
+defined by what members must exist, but its exact layout is left up to
+the C implementation and defined by the C header files, which are not
+parsed by GCC COBOL. Consequently we do not know, at the COBOL level,
+how to define the `struct stat` buffer required by **stat**(2). For
+such functions, we use a C "shim" function that accepts a buffer
+defined by GCC COBOL. That buffer has the members defined by POSIX
+and a layout defined by GCC COBOL. The COBOL application calls the
+COBOL POSIX binding, which uses the shim function to call the C
+library.
+
+To take **stat**(2) as an example,
+
+ COBOL program uses
+ COPY posix-stat.
+ 01 stat-buf.
+ COPY posix-statbuf. *> gcc/cobol/posix/cpy
+ FUNCTION POSIX-STAT(filename, stat-buf)
+ libgcobol/posix/udf/posix-stat.cbl
+ passes stat-buf to
+ posix_stat in libgcobol
+ posix_stat calls stat(2),
+ and copies the returned values to its input buffer
+
+## Contents
+
+The installed POSIX bindings and associated copybooks are in `cpy` and `udf`:
+
+- `cpy/` copybooks used by functions in `udf`
+- `udf/` COBOL POSIX bindings
+- `t/` simple tests demonstrating use of functions in `udf`
+
+The machine-shop tools are in `bin/`.
+
+- `bin/` developer tools to aid creation of POSIX bindings
+ - `scrape.awk` extracts function prototypes from the SYNOPSIS of a
+ man page.
+ - `udf-gen` reads function declarations and, for each one, produces
+ a COBOL User Defined Function (UDF) that calls the function.
+
+Finally,
+
+- `shim/` C support for POSIX bindings, incorporated in libgcobol
+
+## Prerequisites
+### for developers, to generate COBOL POSIX bindings
+
+To use the POSIX bindings, just use the COPY statement.
+
+To create new ones, use `udf-gen`. `udf-gen` is a Python program that
+imports the [PLY pycparser module](http://www.dabeaz.com/ply/) module,
+which must be installed.
+
+`udf-gen` is lightly documented, use `udf-gen --help`. It can be a
+little tedious to set up the first time, but if you want to use more a
+few functions, it will be faster than doing the work by hand.
+
+## Limitations
+
+`udf-gen` does not
+
+- generate a working UDF for function parameters of type `struct`,
+ such as is used by **stat**(2). This is because the information is
+ not available in a standardized way in the SYNOPSIS of a man page.
+- define helpful Level 88 values for "magic" numbers, such as
+ permission bits in **chmod**(2).
+
+None of this is particularly difficult; it's just a matter of time and
+need. The `scrape.awk` script finds 560 functions in the Ubuntu LTS
+22.04 manual. Which of those is important is for users to decide.
+
+## Other Options
+
+IBM and MicroFocus both supply intrinsic functions to interface with
+the OS, each in their own way. GnuCOBOL implements some of those functions.
+
+## Portability
+
+The UDF produced by `udf-gen` is pure ISO COBOL. The code should be
+compilable by any ISO COBOL compiler.
diff --git a/libgcobol/posix/bin/Makefile b/libgcobol/posix/bin/Makefile
new file mode 100644
index 00000000000..335f205068b
--- /dev/null
+++ b/libgcobol/posix/bin/Makefile
@@ -0,0 +1,18 @@
+#
+# Demonstrate how to generate a new COBOL binding from a man page.
+#
+
+posix-mkdir.cbl:
+ man 2 mkdir | ./scrape.awk | \
+ ../udf-gen -D mode_t=unsigned\ long > $@~
+ @mv $@~ $@
+
+# ... or
+
+posix-stat-many.scr:
+ man 2 stat | col -b | ./scrape.awk > $@~
+ @mv $@~ $@
+
+.scr.cbl:
+ ./udf-gen -D mode_t=unsigned\ long $^ > $@~
+ @mv $@~ $@
diff --git a/libgcobol/posix/bin/headers b/libgcobol/posix/bin/headers
new file mode 100644
index 00000000000..b17c0f30cb3
--- /dev/null
+++ b/libgcobol/posix/bin/headers
@@ -0,0 +1,37 @@
+#include <stddef.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <unistd.h>
+#define loff_t ssize_t
+#define socklen_t size_t
+#define fd_set struct fd_set
+#define id_t unsigned int
+// typedef int mqd_t;
+#define mqd_t int
+// typedef unsigned long int nfds_t;
+#define nfds_t unsigned long int
+
+#if 0
+typedef struct
+{
+ unsigned long int __val[(1024 / (8 * sizeof (unsigned long int)))];
+} __sigset_t;
+define struct py_sigset_t \
+{ \
+ unsigned long int __val[(1024 / (8 * sizeof (unsigned long int)))]; \
+};
+#else
+#define kernel_sigset_t sigset_t
+#define old_kernel_sigset_t sigset_t
+#endif
+
+#if 0
+typedef enum
+{
+ P_ALL,
+ P_PID,
+ P_PGID
+} idtype_t;
+#else
+#define idtype_t int
+#endif
diff --git a/libgcobol/posix/bin/scrape.awk b/libgcobol/posix/bin/scrape.awk
new file mode 100755
index 00000000000..4d244d0ee3d
--- /dev/null
+++ b/libgcobol/posix/bin/scrape.awk
@@ -0,0 +1,19 @@
+#! /usr/bin/awk -f
+
+/^UNIMPLEMENTED/ {
+ exit
+}
+
+/^DESCRIPTION/ {
+ exit
+}
+
+/struct sched_param {$/ {
+ exit
+}
+
+/SYNOPSIS/,/DESCRIPTION/ {
+ if( /([.][.]|[{},;]) *$/ ) {
+ print
+ }
+}
diff --git a/libgcobol/posix/bin/sizeofs.c b/libgcobol/posix/bin/sizeofs.c
new file mode 100644
index 00000000000..7f5f534aadb
--- /dev/null
+++ b/libgcobol/posix/bin/sizeofs.c
@@ -0,0 +1,27 @@
+#include <fcntl.h> /* Definition of AT_* constants */
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <sys/stat.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+int
+main(int argc, char *argv[])
+{
+ printf( "size of dev_t is %zu\n", sizeof(dev_t));
+ printf( "size of ino_t is %zu\n", sizeof(ino_t));
+ printf( "size of mode_t is %zu\n", sizeof(mode_t));
+ printf( "size of nlink_t is %zu\n", sizeof(nlink_t));
+ printf( "size of uid_t is %zu\n", sizeof(uid_t));
+ printf( "size of gid_t is %zu\n", sizeof(gid_t));
+ printf( "size of dev_t is %zu\n", sizeof(dev_t));
+ printf( "size of off_t is %zu\n", sizeof(off_t));
+ printf( "size of blksize_t is %zu\n", sizeof(blksize_t));
+ printf( "size of blkcnt_t is %zu\n", sizeof(blkcnt_t));
+ printf( "size of time_t is %zu\n", sizeof(time_t));
+ printf( "size of struct timespec is %zu\n", sizeof(struct timespec));
+
+ return 0;
+}
diff --git a/libgcobol/posix/bin/udf-gen b/libgcobol/posix/bin/udf-gen
new file mode 100755
index 00000000000..e6207085b1d
--- /dev/null
+++ b/libgcobol/posix/bin/udf-gen
@@ -0,0 +1,350 @@
+#! /usr/bin/python3
+
+# Copyright (c) 2024 Symas Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of the Symas Corporation nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import sys, os, getopt, re, copy
+from pycparser import c_parser, c_generator, c_ast, parse_file
+
+def starify(param):
+ stars = ""
+ while( isinstance(param, c_ast.PtrDecl) ):
+ q = ' '.join(param.quals)
+ stars = '*' + ' '.join((stars, q))
+ param = param.type
+ if( isinstance(param.type, c_ast.PtrDecl) ):
+ (stars, param) = starify(param.type)
+ if( isinstance(param, c_ast.TypeDecl) ):
+ return (stars, param)
+ return (stars, param.type)
+
+def linkage_str( i, name, param ) -> str:
+ if name == 'execve':
+ param.show()
+ if( isinstance(param, c_ast.EllipsisParam) ):
+ return (None, None, '...') # COBOL syntax error: no variadic UDF
+
+ is_array = False;
+ node = param
+
+ if( isinstance(node, c_ast.Decl) ):
+ node = node.type
+
+ if( isinstance(node, c_ast.ArrayDecl) ):
+ is_array = True;
+ node = node.type
+
+ (stars, node) = starify(node)
+
+ if( isinstance(node, c_ast.TypeDecl) ):
+ level = 1
+ item_name = ''
+ picture = ''
+ usage = ''
+ if node.declname:
+ item_name = 'Lk-' + node.declname
+
+ if is_array: # ignore level
+ if stars:
+ usage = 'Usage POINTER'
+ output = '01 FILLER.\n 02 %s %s %s OCCURS 100' \
+ % (item_name, picture, usage)
+ return (None, None, output)
+
+ if( isinstance(node.type, c_ast.Struct) ):
+ stars = None
+
+ if isinstance(node.type, c_ast.IdentifierType):
+ ctype = node.type.names[-1]
+ if ctype == 'void':
+ if not stars and not item_name:
+ return (None, None, None)
+ if ctype == 'char':
+ picture = 'X'
+ if stars[0] == '*':
+ picture = 'X ANY LENGTH'
+ if ctype == 'int' or \
+ ctype == 'long' or \
+ ctype == 'mode_t' or \
+ ctype == 'off_t' or \
+ ctype == 'size_t':
+ picture = '9(8)'
+ usage = 'Usage COMP'
+ stars = None
+
+ output = "%02d %s" % (level, ' '.join((item_name, 'PIC ' + picture,
usage)))
+ return (stars, item_name, output)
+
+ node.show()
+ return (None, None, '???')
+
+def using_str( i, name, param ) -> str:
+ item_name = ''
+ if( isinstance(param, c_ast.EllipsisParam) ):
+ return '...' # COBOL syntax error: no variadic UDF
+ node = param
+
+ if( isinstance(node, c_ast.Decl) ):
+ node = node.type
+
+ if( isinstance(node, c_ast.ArrayDecl) ):
+ node = node.type
+
+ (stars, node) = starify(node)
+
+ if( isinstance(node, c_ast.TypeDecl) ):
+ item_name = ''
+
+ if isinstance(node.type, c_ast.IdentifierType):
+ ctype = node.type.names[-1]
+ how = 'By Reference'
+ if ctype == 'int' or \
+ ctype == 'long' or \
+ ctype == 'mode_t' or \
+ ctype == 'off_t' or \
+ ctype == 'size_t':
+ how = 'By Value'
+ if node.declname:
+ item_name = '%s Lk-%s' % (how, node.declname)
+
+ return item_name
+
+def parameter_str( i, name, param ) -> str:
+ if( isinstance(param, c_ast.EllipsisParam) ):
+ return '...'
+
+ t = [0, 1, 2] # qual, type, name
+ is_array = False;
+ node = param
+
+ if( isinstance(node, c_ast.Decl) ):
+ node = node.type
+
+ if( isinstance(node, c_ast.ArrayDecl) ):
+ is_array = True;
+ node = node.type
+
+ (stars, node) = starify(node)
+
+ if( isinstance(node, c_ast.TypeDecl) ):
+ t[0] = ' '.join(node.quals)
+ item_name = ''
+ if node.declname:
+ item_name = 'Lk-' + node.declname
+ t[2] = ' '.join((stars, item_name))
+ if( node.declname == None ):
+ t[2] = ''
+ if( isinstance(node.type, c_ast.IdentifierType) ):
+ try:
+ t[1] = ' '.join(node.type.names)
+ except:
+ print("oops: node.type of %s is %s" % (name, str(node.type)))
+ return "could not parse %s arg[%d]" % (name, i)
+ if( isinstance(node.type, c_ast.Struct) ):
+ t[0] = ' '.join(node.quals)
+ t[1] = "struct " + node.type.name
+ if( isinstance(node, c_ast.ArrayDecl) ):
+ return parameter_str(i, name, node.type) + '[]'
+
+ try:
+ return ' '.join(t)
+ except:
+ print("oops: %s[%d]: {%s}" % (name, i, str(t)) )
+ param.show()
+
+class VisitPrototypes(c_ast.NodeVisitor):
+ def __init__(self):
+ self.done = set()
+
+ def type_of(self, node):
+ while( not isinstance(node.type, c_ast.TypeDecl) ):
+ node = node.type
+ return node.type.type.name
+
+ def visit_Decl(self, node):
+ name = node.name
+ if name in self.done:
+ return
+ self.done.add(name)
+
+ params = []
+ cbl_args = []
+ linkage_items = []
+ string_items = []
+ returns = '???'
+
+ if False and isinstance(node.type, c_ast.FuncDecl):
+ function_decl = node.type
+ print('Function: %s' % node.name)
+ if( node.type.args == None ):
+ print(' (no arguments)')
+ else:
+ for param_decl in node.type.args.params:
+ if( isinstance(param_decl, c_ast.EllipsisParam) ):
+ param_decl.show(offset=6)
+ continue
+ print(' Arg name: %s' % param_decl.name)
+ print(' Type:')
+ param_decl.type.show(offset=6)
+
+ if isinstance(node.type, c_ast.FuncDecl):
+ args = node.type.args
+ if isinstance(args, c_ast.ParamList):
+ #rint("params are %s (type %s)" % (str(args.params),
type(args.params)))
+ if( args == None ):
+ params.append('')
+ else:
+ for (i, param) in enumerate(args.params):
+ params.append(parameter_str(i, name, param))
+ cbl_args.append(using_str(i, name, param))
+ (stars, item, definition) = linkage_str(i, name, param)
+ if definition:
+ if stars:
+ string_items.append(item)
+ linkage_items.append(definition)
+
+ (stars, rets) = starify(node.type)
+
+ if isinstance(rets, c_ast.TypeDecl):
+ q = ' '.join(rets.quals)
+ if( isinstance(rets.type, c_ast.Struct) ):
+ t = "struct " + rets.type.name
+ else:
+ t = ' '.join(rets.type.names)
+ returns = ' '.join((q, t, stars))
+
+ if name == None:
+ return
+
+ # print the C version as a comment
+ cparams = [ x.replace('Lk-', '') for x in params ]
+ print( " * %s %s(%s)"
+ % (returns, name, ', '.join(cparams)) )
+
+ # print the UDF
+ print( ' Identification Division.')
+ sname = name
+ if( sname[0] == '_' ):
+ sname = sname[1:]
+ print( ' Function-ID. posix-%s.' % sname)
+
+ print( ' Data Division.')
+ print( ' Linkage Section.')
+ print( ' 77 Return-Value Binary-Long.')
+ for item in linkage_items:
+ print( ' %s.' % item.strip())
+ args = ',\n '.join(cbl_args)
+ args = 'using\n %s\n ' % args
+ print( ' Procedure Division %s Returning Return-Value.'
+ % args )
+ for item in string_items:
+ print( ' Inspect Backward %s ' % item +
+ 'Replacing Leading Space By Low-Value' )
+ using_args = ''
+ if args:
+ using_args = '%s' % args
+ print( ' Call "%s" %s Returning Return-Value.'
+ % (name, using_args) )
+ print( ' Goback.')
+ print( ' End Function posix-%s.' % sname)
+
+# Hard code a path to the fake includes
+# if not using cpp(1) environment variables.
+cpp_args = ['-I/home/jklowden/projects/3rd/pycparser/utils/fake_libc_include']
+
+for var in ('CPATH', 'C_INCLUDE_PATH'):
+ dir = os.getenv(var)
+ if dir:
+ cpp_args = ''
+
+def process(srcfile):
+ ast = parse_file(srcfile, use_cpp=True, cpp_args=cpp_args)
+ # print(c_generator.CGenerator().visit(ast))
+ v = VisitPrototypes()
+ v.visit(ast)
+
+__doc__ = """
+SYNOPSIS
+ udf-gen [-I include-path] [header-file ...]
+
+DESCRIPTION
+ For each C function declared in header-file,
+produce an ISO COBOL user-defined function definition to call it.
+If no filename is supplied, declarations are read from standard input.
+All output is written to standard output.
+
+ This Python script uses the PLY pycparser module,
+(http://www.dabeaz.com/ply/), which supplies a set of simplified "fake
+header files" to avoid parsing the (very complex) standard C header
+files. These alost suffice for parsing the Posix function
+declarations in Section 2 of the manual.
+
+ Use the -I option or the cpp(1) environment variables to direct
+the preprocessor to use the fake header files instead of the system
+header files.
+
+LIMITATIONS
+ udf-gen does not recognize C struct parameters, such as used by stat(2).
+
+ No attempt has been made to define "magic" values, such as would
+be needed for example by chmod(2).
+"""
+
+def main( argv=None ):
+ global cpp_args
+ if argv is None:
+ argv = sys.argv
+ # parse command line options
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], "D:hI:m:", ["help"])
+ except getopt.error as msg:
+ print(msg)
+ print("for help use --help")
+ sys.exit(2)
+
+ # process options
+ astfile = None
+
+ for opt, arg in opts:
+ if opt in ("-h", "--help"):
+ print(__doc__)
+ sys.exit(0)
+ if opt == '-D':
+ cpp_args.append('-D%s ' % arg)
+ if opt == '-I':
+ cpp_args[0] = '-I' + arg
+
+ # process arguments
+ if not args:
+ args = ('/dev/stdin',)
+
+ for arg in args:
+ process(arg)
+
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/libgcobol/posix/cpy/posix-errno.cbl
b/libgcobol/posix/cpy/posix-errno.cbl
new file mode 100644
index 00000000000..9670637b3ba
--- /dev/null
+++ b/libgcobol/posix/cpy/posix-errno.cbl
@@ -0,0 +1,18 @@
+ Identification Division.
+ Function-ID. posix-errno.
+
+ Data Division.
+ Linkage Section.
+ 77 Return-Value Binary-Long.
+ 01 Error-Msg PIC X ANY LENGTH.
+
+ Procedure Division
+ using Error-Msg
+ Returning Return-Value.
+ CALL "posix_errno"
+ returning Return-Value.
+ CALL "strerror"
+ using by value Return-Value
+ returning error-msg.
+ Goback.
+ END FUNCTION posix-errno.
diff --git a/libgcobol/posix/cpy/statbuf.cpy b/libgcobol/posix/cpy/statbuf.cpy
new file mode 100644
index 00000000000..36f8a76c47f
--- /dev/null
+++ b/libgcobol/posix/cpy/statbuf.cpy
@@ -0,0 +1,14 @@
+ 05 st_dev Usage is Binary-Double Unsigned.
+ 05 st_ino Usage is Binary-Double Unsigned.
+ 05 st_mode Usage is Binary-Long Unsigned.
+ 05 st_nlink Usage is Binary-Long Unsigned.
+ 05 st_uid Usage is Binary-Long Unsigned.
+ 05 st_gid Usage is Binary-Long Unsigned.
+ 05 st_rdev Usage is Binary-Double Unsigned.
+ 05 st_size Usage is Binary-Double Unsigned.
+ 05 st_blksize Usage is Binary-Long Unsigned.
+ 05 filler Pic x(4).
+ 05 st_blocks Usage is Binary-Double Unsigned.
+ 05 st_atim Usage is Binary-Double Unsigned.
+ 05 st_mtim Usage is Binary-Double Unsigned.
+ 05 st_ctim Usage is Binary-Double Unsigned.
diff --git a/libgcobol/posix/cpy/tm.cpy b/libgcobol/posix/cpy/tm.cpy
new file mode 100644
index 00000000000..3e374f75e88
--- /dev/null
+++ b/libgcobol/posix/cpy/tm.cpy
@@ -0,0 +1,19 @@
+ 02 tm_sec Usage is Binary-Long.
+ 02 tm_min Usage is Binary-Long.
+ 02 tm_hour Usage is Binary-Long.
+ 02 tm_mday Usage is Binary-Long.
+ 02 tm_mon Usage is Binary-Long.
+ 02 tm_year Usage is Binary-Long.
+ 02 tm_wday Usage is Binary-Long.
+ 02 tm_yday Usage is Binary-Long.
+ 02 tm_isdst Usage is Binary-Long.
+
+
+
+
+
+
+
+
+
+
diff --git a/libgcobol/posix/errno.cc b/libgcobol/posix/shim/errno.cc
similarity index 100%
rename from libgcobol/posix/errno.cc
rename to libgcobol/posix/shim/errno.cc
diff --git a/libgcobol/posix/localtime.cc b/libgcobol/posix/shim/localtime.cc
similarity index 100%
rename from libgcobol/posix/localtime.cc
rename to libgcobol/posix/shim/localtime.cc
diff --git a/libgcobol/posix/stat.cc b/libgcobol/posix/shim/stat.cc
similarity index 100%
rename from libgcobol/posix/stat.cc
rename to libgcobol/posix/shim/stat.cc
diff --git a/libgcobol/posix/stat.h b/libgcobol/posix/shim/stat.h
similarity index 100%
rename from libgcobol/posix/stat.h
rename to libgcobol/posix/shim/stat.h
diff --git a/libgcobol/posix/tm.h b/libgcobol/posix/shim/tm.h
similarity index 100%
rename from libgcobol/posix/tm.h
rename to libgcobol/posix/shim/tm.h
diff --git a/libgcobol/posix/t/Makefile b/libgcobol/posix/t/Makefile
new file mode 100644
index 00000000000..2da74a7aee8
--- /dev/null
+++ b/libgcobol/posix/t/Makefile
@@ -0,0 +1,36 @@
+.SUFFIXES: .scr .cbl
+
+#
+# Ensure UDFs compile and run without crashing.
+#
+
+# COBCFLAGS is defined by the user
+
+COBC = gcobol
+LDFLAGS = -L $$(pwd) -Wl,-rpath -Wl,$$(pwd)
+
+TESTS = errno exit localtime stat
+
+# Default target builds the tests
+all: $(TESTS)
+
+% : %.cbl
+ $(COBC) -o $@ $(COBCFLAGS) -I. -I../cpy -I../udf $(LDFLAGS) $<
+
+
+exit: ../udf/posix-exit.cbl
+
+errno: ../udf/posix-mkdir.cbl
+
+stat: ../udf/posix-stat.cbl
+
+localtime: ../udf/posix-stat.cbl
+
+# Run the tests
+test: $(TESTS)
+ @$(foreach P,$(TESTS),echo $(P):; ./$(P);)
+
+clean:
+ rm -f *.o $(basename $(wildcard *.cbl))
+
+
diff --git a/libgcobol/posix/t/errno.cbl b/libgcobol/posix/t/errno.cbl
new file mode 100644
index 00000000000..22078ae3c31
--- /dev/null
+++ b/libgcobol/posix/t/errno.cbl
@@ -0,0 +1,26 @@
+ COPY posix-mkdir.
+ COPY posix-errno.
+
+ Identification Division.
+ Program-ID. test-errno.
+ Data Division.
+ Working-Storage Section.
+ 77 Return-Value Binary-Long.
+ 77 Exit-Status Binary-Long Value 1.
+ 77 error-msg PIC X(100).
+ 77 errnum Binary-Long.
+ 77 Filename PIC X(100) Value '/'.
+
+ Procedure Division.
+ Display 'calling posix-mkdir with a foolish name ...'
+ Move Function posix-mkdir(Filename, 0) to Return-Value.
+ If Return-Value <> 0
+ Display 'calling posix-errno ...'
+ Move Function posix-errno(error-msg) to errnum
+ Display 'error: "' Filename '": ' error-msg ' (' errnum ')'
+ Goback with Error Status errnum
+ Else
+ Display 'Return-Value is ' Return-Value
+ End-If.
+
+ Goback.
diff --git a/libgcobol/posix/t/exit.cbl b/libgcobol/posix/t/exit.cbl
new file mode 100644
index 00000000000..4aed400b17a
--- /dev/null
+++ b/libgcobol/posix/t/exit.cbl
@@ -0,0 +1,15 @@
+ COPY posix-exit.
+
+ Identification Division.
+ Program-ID. test-exit.
+ Data Division.
+ Working-Storage Section.
+ 77 Return-Value Binary-Long.
+ 77 Exit-Status Binary-Long Value 1.
+
+ Procedure Division.
+ Display 'calling posix-exit ...'
+ Move Function posix-exit(Exit-Status) to Return-Value.
+ * Does not return, Does not print
+ Display 'How did we get here?'
+ Goback.
diff --git a/libgcobol/posix/t/localtime.cbl b/libgcobol/posix/t/localtime.cbl
new file mode 100644
index 00000000000..1a6dc2229eb
--- /dev/null
+++ b/libgcobol/posix/t/localtime.cbl
@@ -0,0 +1,47 @@
+ * Include the posix-stat and posix-localtime functions.
+ COPY posix-stat.
+ COPY posix-localtime.
+ COPY posix-errno.
+
+ Identification Division.
+ Program-ID. test-localtime.
+ Data Division.
+ Working-Storage Section.
+ 77 Return-Value Usage Binary-Long.
+ 77 Stat-Status Usage Binary-Long Value 1.
+ 77 Filename Pic x(80) Value 'Makefile'.
+ 77 Msg Pic x(100).
+ 01 Lk-statbuf.
+ COPY statbuf.
+ 01 Lk-tm.
+ COPY tm.
+ 01 Today.
+ 02 tm_year PIC 9999.
+ 02 tm_mon PIC 99.
+ 02 tm_wday PIC 99.
+
+ Procedure Division.
+ Display 'calling posix-stat for ' Function Trim(Filename) ' ...'
+ Move Function posix-stat(Filename, lk-statbuf) to Return-Value.
+ Display 'posix-stat returned: ' Return-Value.
+ If Return-Value < 0 then
+ Display Function Trim(Filename) ': '
+ 'errno ', Function posix-errno(Msg), ': ' Msg
+ Goback.
+
+ Display 'calling posix-localtime ...'
+ Move Function posix-localtime(st_mtim, lk-tm) to Return-Value.
+ Display 'posix-localtime returned: ' Return-Value.
+ If Return-Value < 0 then
+ Display 'posix-localtime: ', Function Trim(Filename) ': '
+ 'errno ', Function posix-errno(Msg), ': ' Msg
+ ' (st_mtim ' st_mtim ')'
+ Goback.
+ Move Corresponding Lk-tm to Today.
+ Add 1900 to tm_year of Today.
+ Display "'" Function trim(Filename) "'"
+ ' (st_mtim ' st_mtim ') modified '
+ tm_year of Today '-'
+ tm_mon of Today '-'
+ tm_wday of Today.
+ Goback.
diff --git a/libgcobol/posix/t/stat.cbl b/libgcobol/posix/t/stat.cbl
new file mode 100644
index 00000000000..4aa64a49b6d
--- /dev/null
+++ b/libgcobol/posix/t/stat.cbl
@@ -0,0 +1,24 @@
+ * Include the posix-stat function
+ COPY posix-stat.
+ COPY posix-errno.
+
+ Identification Division.
+ Program-ID. test-stat.
+ Data Division.
+ Working-Storage Section.
+ 77 Return-Value Usage Binary-Long.
+ 77 Stat-Status Usage Binary-Long Value 1.
+ 77 Filename Pic x(80) Value 'Makefile'.
+ 77 Msg Pic x(100).
+ 01 Lk-statbuf.
+ COPY statbuf.
+
+ Procedure Division.
+ Display 'calling posix-stat ...'
+ Move Function posix-stat(Filename, lk-statbuf) to Return-Value.
+ Display 'posix-stat return value:' Return-Value.
+ If Return-Value < 0 then
+ Display Function Trim(Filename) ': '
+ 'errno ', Function posix-errno(Msg), ': ' Msg.
+
+ Goback.
diff --git a/libgcobol/posix/udf/posix-exit.cbl
b/libgcobol/posix/udf/posix-exit.cbl
new file mode 100644
index 00000000000..cd2ac1857e9
--- /dev/null
+++ b/libgcobol/posix/udf/posix-exit.cbl
@@ -0,0 +1,12 @@
+ Identification Division.
+ Function-ID. posix-exit.
+
+ Data Division.
+ Linkage Section.
+ 77 Return-Value Binary-Long.
+ 77 Exit-Status Binary-Long.
+
+ Procedure Division using Exit-Status Returning Return-Value.
+ CALL "_exit" using by value Exit-Status.
+ Goback.
+ END FUNCTION posix-exit.
\ No newline at end of file
diff --git a/libgcobol/posix/udf/posix-localtime.cbl
b/libgcobol/posix/udf/posix-localtime.cbl
new file mode 100644
index 00000000000..3c5ab48a2d5
--- /dev/null
+++ b/libgcobol/posix/udf/posix-localtime.cbl
@@ -0,0 +1,35 @@
+ * int stat(const char * pathname, struct stat * statbuf)
+ Identification Division.
+ Function-ID. posix-localtime.
+ Data Division.
+ Working-Storage Section.
+ 77 bufsize Usage Binary-Long.
+ 77 Tm-pointer Usage Pointer.
+ 01 Lk-tm-posix Based.
+ COPY tm.
+ Linkage Section.
+ 77 Return-Value Usage Binary-Long.
+ 01 Lk-timep Usage Binary-Long.
+ 01 Lk-tm.
+ COPY tm.
+
+ Procedure Division using
+ By Reference Lk-timep,
+ By Reference Lk-tm,
+ Returning Return-Value.
+
+ Move Function Length(Lk-tm-posix) to bufsize.
+ Call "posix_localtime" using
+ By Reference Lk-timep,
+ By Value bufsize,
+ Returning tm-pointer.
+
+ If tm-pointer = NULL
+ move -1 to Return-Value
+ Else
+ move 0 to Return-Value
+ set address of lk-tm-posix to tm-pointer
+ move lk-tm-posix to lk-tm.
+
+ Goback.
+ End Function posix-localtime.
diff --git a/libgcobol/posix/udf/posix-mkdir.cbl
b/libgcobol/posix/udf/posix-mkdir.cbl
new file mode 100644
index 00000000000..6de543ea957
--- /dev/null
+++ b/libgcobol/posix/udf/posix-mkdir.cbl
@@ -0,0 +1,21 @@
+ Identification Division.
+ Function-ID. posix-mkdir.
+ Data Division.
+ Working-Storage Section.
+ 77 bufsize Usage Binary-Long.
+ Linkage Section.
+ 77 Return-Value Binary-Long.
+ 01 Lk-pathname PIC X ANY LENGTH.
+ 01 Lk-Mode Binary-Long.
+
+ Procedure Division using
+ By Reference Lk-pathname,
+ By Value Lk-Mode,
+ Returning Return-Value.
+ Inspect Backward Lk-pathname Replacing Leading Space By Low-Value
+ Call "mkdir" using
+ By Reference Lk-pathname,
+ By Value Lk-Mode,
+ Returning Return-Value.
+ Goback.
+ End Function posix-mkdir.
diff --git a/libgcobol/posix/udf/posix-stat.cbl
b/libgcobol/posix/udf/posix-stat.cbl
new file mode 100644
index 00000000000..a9a69886032
--- /dev/null
+++ b/libgcobol/posix/udf/posix-stat.cbl
@@ -0,0 +1,45 @@
+ * int stat(const char * pathname, struct stat * statbuf)
+ Identification Division.
+ Function-ID. posix-stat.
+ Data Division.
+ Working-Storage Section.
+ 77 bufsize Usage Binary-Long.
+ Linkage Section.
+ 77 Return-Value Binary-Long.
+ 01 Lk-pathname PIC X ANY LENGTH.
+ 01 Lk-statbuf.
+ COPY statbuf.
+
+ Procedure Division using
+ By Reference Lk-pathname,
+ By Reference Lk-statbuf,
+ Returning Return-Value.
+ Inspect Backward Lk-pathname
+ Replacing Leading Space By Low-Value
+ Move Function Byte-Length(Lk-statbuf) to bufsize.
+ D Display 'posix-stat: using bufsize ', bufsize.
+ Call "posix_stat" using
+ By Reference Lk-pathname,
+ By Reference Lk-statbuf
+ By Value bufsize
+ Returning Return-Value.
+ D Perform Show-Statbuf.
+ Goback.
+
+ Show-Statbuf Section.
+
+ Display 'st_dev: ', st_dev.
+ Display 'st_ino: ', st_ino.
+ Display 'st_mode: ', st_mode.
+ Display 'st_nlink: ', st_nlink.
+ Display 'st_uid: ', st_uid.
+ Display 'st_gid: ', st_gid.
+ Display 'st_rdev: ', st_rdev.
+ Display 'st_size: ', st_size.
+ Display 'st_blksize: ', st_blksize.
+ Display 'st_blocks: ', st_blocks.
+ Display 'st_atim: ', st_atim.
+ Display 'st_mtim: ', st_mtim.
+ Display 'st_ctim: ', st_ctim.
+
+ End Function posix-stat.
diff --git a/libgcobol/posix/udf/posix-unlink.cbl
b/libgcobol/posix/udf/posix-unlink.cbl
new file mode 100644
index 00000000000..852b58c3580
--- /dev/null
+++ b/libgcobol/posix/udf/posix-unlink.cbl
@@ -0,0 +1,26 @@
+ >>PUSH SOURCE FORMAT
+ >>SOURCE FIXED
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * This function is in the public domain.
+ * Contributed by
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ Identification Division.
+ Function-ID. posix-unlink.
+ Data Division.
+ Working-Storage Section.
+ 77 bufsize Usage Binary-Long.
+ Linkage Section.
+ 77 Return-Value Binary-Long.
+ 01 Lk-pathname PIC X ANY LENGTH.
+
+ Procedure Division using
+ By Reference Lk-pathname,
+ Returning Return-Value.
+ Inspect Backward Lk-pathname Replacing Leading Space,
+ - By Low-Value.
+ Call "unlink" using
+ By Reference Lk-pathname,
+ Returning Return-Value.
+ Goback.
+ End Function posix-unlink.
+ >> POP SOURCE FORMAT
[pins]