Skip to content
Open
Show file tree
Hide file tree
Changes from 17 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
110 changes: 110 additions & 0 deletions examples/custom/01-parameter-passing/cf_demo1.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#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 FileInfo( cell_t path_caddr, cell_t path_len ) {
char* path = to_C_string( path_caddr, path_len );
Comment thread
guberathome marked this conversation as resolved.
Outdated
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;
/* MSYS/Cygwin may warn than asprintf() is not defined but compile and run just fine :-/ */
if( stat(path, &info) == -1 )
asprintf( &result, fmtErr, errno, strerror(errno), path );

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not go through the Forth output path so it will not work over a serial port.

Demonstrating custom C calling does not require calling complex host functions.
It could just be a function that modifies a string.
The user will just replace these custom functions so the simpler the better.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not go through the Forth output path so it will not work over a serial port.

Just to clarify: asprintf() allocates a buffer of correct size into which it sprintf's the formatted output.
Which then gets returned.
I'm not aware of bypassing any PForth functionality here.

Demonstrating custom C calling does not require calling complex host functions. It could just be a function that modifies a string. The user will just replace these custom functions so the simpler the better.

That's what is done here.
Creating a new string (of previously unknown length) requires either hairy assumptions about maximal length or allocating a new buffer. All the fun of programming C.

else {
if( S_ISDIR(info.st_mode) )
asprintf( &result, fmtDir, path );
else
asprintf( &result, fmtFile, info.st_size, path );
}
PUSH_DATA_STACK( (cell_t) result );
return (cell_t)strlen(result);

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

path is not getting freed.
Can you avoid doing the dangerous memory allocation for the C string? Maybe allocate on the stack.

@guberathome guberathome Jan 7, 2025

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added FREE-C word.
Thus deallocation is done in demo.fth.

}


/****************************************************************
** 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 (2)
CFunc0 CustomFunctionTable[NUM_CUSTOM_FUNCTIONS];

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

#else
/******************
** If your loader supports global initialization (most do.) then just
** create the table like this.
*/
CFunc0 CustomFunctionTable[] =
{
(CFunc0) f4711,
(CFunc0) FileInfo
};
#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;

return 0;
}
#else
Err CompileCustomFunctions( void ) { return 0; }
#endif
17 changes: 17 additions & 0 deletions examples/custom/01-parameter-passing/demo.fth
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
\ 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 passing strings from PForth to custom C code
Comment thread
guberathome marked this conversation as resolved.
Outdated
: SHOW-FILE-INFO
." " FILE-INFO type cr
;
." 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 */
Comment thread
guberathome marked this conversation as resolved.
Outdated
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 @@ -39,6 +39,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 Down Expand Up @@ -74,7 +81,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