Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example of adding custom C functions #187

Open
wants to merge 23 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
8aa0723
bugfix: removed warnings in WriteCellBigEndian() for 32bit builds
guberathome Dec 30, 2024
cb40ed0
Merge branch 'philburk:master' into fix-gub-241230
guberathome Dec 30, 2024
3efb3b3
feature: custom demo cf_demo1
guberathome Dec 31, 2024
70e74ae
tested and fixed cf_demo1 on MSYS2, Linux, FreeBSD, NetBSD
guberathome Dec 31, 2024
1bd41cf
feature: new custom code handling for unix build
guberathome Dec 31, 2024
09dffd0
Merge branch 'philburk:master' into docu-241230
guberathome Dec 31, 2024
6889a15
bugfix: latest merge from upstream simplifies FreeBSD handling
guberathome Dec 31, 2024
aeff369
refactored get-make-cmd to separate shell script
guberathome Dec 31, 2024
20fdba6
merge: manually resolved conflicts with upstream repo
guberathome Jan 1, 2025
f605544
Merge branch 'philburk:master' into docu-241230
guberathome Jan 2, 2025
866422e
from-codereview: moved to examples/custom/ folder
guberathome Jan 2, 2025
03a4d0a
from-codereview: replaced BE-GONE by FILE-INFO, fixed go-v1.sh
guberathome Jan 2, 2025
122ab9b
from-codereview: removed panic() and safeAlloc()
guberathome Jan 2, 2025
409cee3
from-codereview: renamed Makefile variable to CUSTOM_SOURCES
guberathome Jan 2, 2025
6daae79
from-codereview: removed go-v0.sh
guberathome Jan 2, 2025
ea826e9
fixed typo
guberathome Jan 2, 2025
e0dd86f
bugfix: removed superfluos code for MSYS
guberathome Jan 2, 2025
1d3e5e4
Merge branch 'philburk:master' into docu-241230
guberathome Jan 7, 2025
82b212b
changes from review
guberathome Jan 7, 2025
5cb19e1
free C buffer
guberathome Jan 7, 2025
b9e5235
added description for FileInfo()
guberathome Jan 7, 2025
912172e
use result of asprintf instead of calling strlen
guberathome Jan 7, 2025
128666c
Merge branch 'master' into docu-241230
guberathome Jan 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 128 additions & 0 deletions examples/custom/01-parameter-passing/cf_demo1.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#include "pf_all.h" /* lots of stuff */
#include "cf_helpers.h" /* to_C_string */
#include<errno.h> /* errno */
#include<limits.h> /* PATH_MAX */
#include<stdlib.h> /* malloc */
#include<stdio.h> /* asprintf, sprintf */
#include<string.h> /* strerror */
#include<sys/stat.h> /* struct stat, stat */

/*
* put forward declarations here if necessary
*/


/****************************************************************
** Step 1: Put your own special glue routines here
** or link them in from another file or library.
****************************************************************/

/* exported functions */

static cell_t f4711( cell_t Val )
{/* a quick way to check that custom words are available
*/
return 11 + 47*Val;
}

static cell_t file_info( cell_t path_caddr, cell_t path_len )
{
/* takes one filePath (string) as argument and returns some info on it (as a new string)
Note that you need to use FREE-C on the result buffer (FREE does not work).
*/
char* path = to_C_string( path_caddr, path_len );
struct stat info;
const char* fmtErr = "error{ id=%i, desc='%s', path='%s' }";
const char* fmtDir = "directory{ path='%s' }";
const char* fmtFile = "file{ size=%i, path='%s' }";
char* result;
cell_t res_len = -1;
/* MSYS/Cygwin may warn than asprintf() is not defined but compile and run just fine :-/ */
if( stat(path, &info) == -1 )
res_len = asprintf( &result, fmtErr, errno, strerror(errno), path );
else {
if( S_ISDIR(info.st_mode) )
res_len = asprintf( &result, fmtDir, path );
else
res_len = asprintf( &result, fmtFile, info.st_size, path );
}
PUSH_DATA_STACK( (cell_t) result );
return res_len;
}

static void free_c( cell_t c_allocate_buffer )
{
/* Using FREE on a c_allocate_buffer is not possible (due to extra information stored),
using pfAllocMem() / pfFreeMem() does not help either.
So we need a separate word to free C-allocated buffers.
*/
free( (void*) c_allocate_buffer );
}


/****************************************************************
** Step 2: Create CustomFunctionTable.
** Do not change the name of CustomFunctionTable!
** It is used by the pForth kernel.
****************************************************************/

#ifdef PF_NO_GLOBAL_INIT
/******************
** If your loader does not support global initialization, then you
** must define PF_NO_GLOBAL_INIT and provide a function to fill
** the table. Some embedded system loaders require this!
** Do not change the name of LoadCustomFunctionTable()!
** It is called by the pForth kernel.
*/
#define NUM_CUSTOM_FUNCTIONS (3)
CFunc0 CustomFunctionTable[NUM_CUSTOM_FUNCTIONS];

Err LoadCustomFunctionTable( void )
{
CustomFunctionTable[0] = f4711;
CustomFunctionTable[1] = file_info;
CustomFunctionTable[1] = free_c;
return 0;
}

#else
/******************
** If your loader supports global initialization (most do.) then just
** create the table like this.
*/
CFunc0 CustomFunctionTable[] =
{
(CFunc0) f4711,
(CFunc0) file_info,
(CFunc0) free_c
};
#endif


/****************************************************************
** Step 3: Add custom functions to the dictionary.
** Do not change the name of CompileCustomFunctions!
** It is called by the pForth kernel.
****************************************************************/

#if (!defined(PF_NO_INIT)) && (!defined(PF_NO_SHELL))
Err CompileCustomFunctions( void )
{
Err err;
int i = 0;
/* Compile Forth words that call your custom functions.
** Make sure order of functions matches that in LoadCustomFunctionTable().
** Parameters are: Name in UPPER CASE, Function, Index, Mode, NumParams
*/
err = CreateGlueToC( "F4711" , i++, C_RETURNS_VALUE, 1 );
if( err < 0 ) return err;
err = CreateGlueToC( "FILE-INFO", i++, C_RETURNS_VALUE, 2 );
if( err < 0 ) return err;
err = CreateGlueToC( "FREE-C" , i++, C_RETURNS_VOID , 1 );
if( err < 0 ) return err;

return 0;
}
#else
Err CompileCustomFunctions( void ) { return 0; }
#endif
19 changes: 19 additions & 0 deletions examples/custom/01-parameter-passing/demo.fth
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
\ f4711 is a clear indicator that compilation of custom functions was successful
." f4711( 0, 1, 10, 100, 1000 ) = ( "
0 f4711 . ." , "
1 f4711 . ." , "
10 f4711 . ." , "
100 f4711 . ." , "
1000 f4711 . ." )"
CR

\ example of passing strings from PForth to custom C code
: SHOW-FILE-INFO
FILE-INFO over -rot
." " type cr
free-c
;
." FILE-INFO: " cr
s" Makefile" SHOW-FILE-INFO
s" ../../examples" SHOW-FILE-INFO
s" fileNotHere" SHOW-FILE-INFO
42 changes: 42 additions & 0 deletions examples/custom/01-parameter-passing/go.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/bin/sh

# Compile pForth with custom code and show that this works.
# We assume a posix shell and system (but adaption should be easy to others).
# This improved version only compiles the custom code defined in CF_SOURCES.
# Warning: This patches the existing source tree and might create confusion when not used on separate Git branch in case an error occurs.
# Tested on MSYS2-Cygwin, Linux, FreeBSD (X86_64 architecture each), NetBSD (i386 architecture)

# copy demo sources. Thus we do not need to change the make file.

cp ../cf_helpers.h ../../../csrc/
cp cf_demo1.c ../../../csrc/
CUSTOM_SOURCES="cf_demo1.c"
export CUSTOM_SOURCES

echo
echo "----------------------------------------"
echo "make pforth (skip standalone executable)"
echo "----------------------------------------"
MAKE_CMD=`../get-make-cmd.sh`
cd ../../../platforms/unix/

$MAKE_CMD pforth.dic # we just need a PForth executable+dictionary

echo
echo "---------------------------"
echo "show that custom code works"
echo "---------------------------"
./pforth -q ../../examples/custom/01-parameter-passing/demo.fth

echo
echo "----------------------------"
echo "restore original source tree"
echo "----------------------------"
rm ../../csrc/cf_helpers.h
rm ../../csrc/cf_demo1.c
$MAKE_CMD clean

echo
echo "-----------------"
echo "That's all folks!"
echo "-----------------"
26 changes: 26 additions & 0 deletions examples/custom/cf_helpers.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/* custom code for pforth (hence Custom Forth = cf)
This is a hack and for demonstration purposes only.
It simplifies a few things (like patching of Makefile)
but violates rules for production C code (e.g placing definitions in header files and terminating at the 1st sign of trouble).
Defines helper functions for several examples.
*/

#ifndef CF_HELPERS_H
#define CF_HELPERS_H

#include <stdlib.h> /* malloc */
#include <string.h> /* memcpy */

static char* to_C_string( cell_t strData, cell_t iStrLen )
{/* copy PForth string to C-string (zero terminated)
Don't forget to free() the result!
*/
char* buf = malloc(iStrLen+1);
if( buf != NULL ) {
memcpy( buf, (void*)strData, iStrLen );
buf[iStrLen] = 0;
}
return buf;
}

#endif /* CF_HELPERS_H */
16 changes: 16 additions & 0 deletions examples/custom/get-make-cmd.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/bin/sh

os=`uname -o 2>/dev/null`
if test -z "$os" ; then
# NetBSD-uname does not implement '-o' option
os=`uname -s`
fi

case "$os" in
"FreeBSD" | "NetBSD")
echo "gmake"
;;
*) # e.g. "Msys" | "GNU/Linux"
echo "make"
;;
esac
9 changes: 8 additions & 1 deletion platforms/unix/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,13 @@ FULL_WARNINGS = \
-Wmissing-prototypes \
-Wmissing-declarations

# custom code options
ifndef CUSTOM_SOURCES
# note: setting CF_PARAM does not help: It only deactivates all definitions in pfcustom.c, which we only include when no custom code is compiled!
# We do not remove CF_PARAM from code and documentation until we can verify that Makefiles continue to work.
CUSTOM_SOURCES=pfcustom.c
endif

DEBUGOPTS = -g
CCOPTS = $(WIDTHOPT) -x c -O2 $(FULL_WARNINGS) $(EXTRA_CCOPTS) $(DEBUGOPTS)

Expand All @@ -82,7 +89,7 @@ PFINCLUDES = pf_all.h pf_cglue.h pf_clib.h pf_core.h pf_float.h \
pfcompil.h pfinnrfp.h pforth.h
PFBASESOURCE = pf_cglue.c pf_clib.c pf_core.c pf_inner.c \
pf_io.c pf_io_none.c pf_main.c pf_mem.c pf_save.c \
pf_text.c pf_words.c pfcompil.c pfcustom.c
pf_text.c pf_words.c pfcompil.c $(CUSTOM_SOURCES)
PFSOURCE = $(PFBASESOURCE) $(IO_SOURCE)

VPATH = .:$(CSRCDIR):$(CSRCDIR)/posix:$(CSRCDIR)/stdio:$(CSRCDIR)/win32_console:$(CSRCDIR)/win32
Expand Down
Loading