Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Messages - sunmountain

#1
newLISP in the real world / Re: Socket Callback into Vb
December 13, 2011, 04:35:18 AM
QuoteThe form doesn't block or wait in a loop, it responds to commands.

After the web page is downloaded a webbrowser0.downloadcomplete event fires and I can write code to respond.


So the problem is solved ?

I still think it is not more complex in .NET/C#:



using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WebCrawlerWithNewLisp
{
/// <summary>
/// Description of MainForm.
/// </summary>
public partial class MainForm : Form
{
[DllImport("newlisp.dll", EntryPoint="newlispEvalStr",CharSet = CharSet.Ansi)]

public extern static string newlispEvalStr(string cmd);

public MainForm()
{
//
// The InitializeComponent() call is required for Windows Forms designer support.
//
InitializeComponent();

//
// TODO: Add constructor code after the InitializeComponent() call.
//

}

void Button1Click(object sender, EventArgs e)
{
webBrowser1.Url = new System.Uri(textBox1.Text);
webBrowser1.Update();
}

void WebBrowser1DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
// this will be called on completion !
MessageBox.Show(newlispEvalStr(@"(println ""Hello from Newlisp - embedded in C# !"")"),"Loading completed");

}
}
}


The VB.NET code would look really a lot like this.
#2
newLISP in the real world / Re: Socket Callback into Vb
December 12, 2011, 08:34:17 PM
To get you right:

you want to handle all network stuff with newlisp and have it inform the VB app an changed data ?



Anyway:

net-listen sets up a listening socket, essentially flagging the socket to be a server socket.

Then, you have to net-accept on the socket, to catch new incoming requests.

Normally, this operation blocks until new clients connect.

You then get a new client, on which you operate (net-receive, net-send).

On Unix you could use net-select et al to implement non-blocking sockets even with unblock net-accept.

That said: If you set up newlisp to wait for events, your form will do nothing - except you

do that in a thread - which complicates the thing even more.



The easiest thing for you would be to: take VB.NET (Express or SharpDevelop will do) and go with

.NET - all is solved there.

Or take  newlisp and create the form with gui server, or take newlisp and interface some UI lib like gtk or iup.
#3
newLISP in the real world / Re: Socket Callback into Vb
December 12, 2011, 12:48:25 PM
Anything is possible.

Perhaps you could just outline the idea a bit more or send some (pseudo) code ?
#4
Just to give everyone an update:



It is now possible to have arguments and return values as struct types, e.g this is possible:



Here is a small C lib, that uses structs:

#include <stdio.h>

typedef struct clock
    {
    char hour;
    int min;
    short int sec;
    } clock;

clock addClock(clock in)
    {
    in.hour += 1;
    in.min += 1;
    in.sec += 1;
    return in;
    }


Compiling as a DLL and brought to live with;

(struct 'clock "char" "int" "short int")
; struct definition must exist !

(import "struct.dll" "addClock" "clock" "clock")
(set 'fmt "cnnn ld dn")
(set 'in (pack fmt 1 1 1))
(println (unpack fmt in))
(set 'out (addClock in))

; give as string object
(println (unpack fmt out))

; only give address to string
(set 'out (addClock (address out)))
(println (unpack fmt out))
(set 'out (pack fmt 0 0 0))

; repeat
(dotimes (i 100)
    (set 'out (addClock (address out)))
)
(println (unpack fmt out))

; repeat
(dotimes (i 100)
    (set 'out (addClock out))
)
(println (unpack fmt out))

; even fully anonymous calls work !
(println (unpack fmt (addClock (pack fmt 254 (- (pow 2 32) 2) 65534))))

gives this:

(1 1 1)
(2 2 2)
(3 3 3)
(100 100 100)
(-56 200 200)
(-1 -1 -1)


As you can see, right now it is neccessary to pad the struct members manually (n),

here you see the padding on 32 Bit platform (compiled with gcc).



Next step is to extent pack/unpack so that you can do this:



(struct 'clock "char" "int" "short int") ; corresponding to C struct
(import "struct.dll" "addClock" "clock" "clock")
(set 'in (pack clock 1 1 1)) ; auto-boxing
(println (unpack clock in)) ; auto-unboxing -> (1 1 1)
(set 'out (addClock in))
(println (unpack clock out)) ; auto-unboxing -> (2 2 2)


This should be ready before the weekend, I guess.
#5
newLISP newS / Re: newLISP development release v.10.3.8
December 07, 2011, 11:15:10 AM
Good news !



Could you please explain the numbering scheme used for the versions ?
#6
newLISP newS / Re: extended import and callback API
December 06, 2011, 02:48:34 AM
Hi lutz,

I made a small fix, sent you the code.



Under Windows (mingw, gcc 4.6.1, Win XP Pro SP 2 32 But) it adds

280590-274958 = 5632 Bytes, so the addition is neglectable I think.



But to be fair: it is compute intensive, as it creates call information on the fly using assembler

ninja technics.



Now I can put python to rest :-)

At least, as soon I implemented proper struct handling.
#7
newLISP newS / Re: extended import and callback API
December 03, 2011, 01:54:25 PM
Hi,

Yes I'm done with implementing the closure callback extention.

Now you can write code like this:

(import "msvcrt" "qsort" "void" "void*" "int" "int" "void*")
(import "msvcrt" "atexit" "void" "void*")
(define (bye) (println "See you ..."))
(atexit (callback 'bye "void" "void"))
(set 'l '())
(dotimes (i 30)
    (set 'l (append l (list (int (mul 30 (random)))))))
(set 'base (pack (dup "ld " 30) l))
(println "Unsorted:")
(println (unpack (dup "ld " 30) base))
(define (cmp a b)
    (- (get-int a) (get-int b)))
(qsort (address base) 30 4 (callback 'cmp "int" "void*" "void*"))
(println "Sorted by qsort:")
(println (unpack (dup "ld " 30) base))
(exit)


which gives (your rng may create alternate numbers, though):



Unsorted:
(0 16 5 24 17 14 10 26 24 22 5 25 21 15 9 0 2 10 4 4 29 13 3 0 0 11 15 17 18 18)
Sorted by qsort:
(0 0 0 0 2 3 4 4 5 5 9 10 10 11 13 14 15 15 16 17 17 18 18 21 22 24 24 25 26 29)
See you ...


And you can (for instance) interact in more "natural" way with ui libraries.

For example I use http://www.tecgraf.puc-rio.br/iup/">IUP very often.

To use it, I place a iup.dll in the same directory as newlisp.exe and then do this:



(import "iup.dll" "IupOpen" "void" "void")
(import "iup.dll" "IupClose" "void" "void")
(import "iup.dll" "IupButton" "int" "char*" "int")
(import "iup.dll" "IupSetAttribute" "int" "int" "char*" "char*")
(import "iup.dll" "IupSetAttributeHandle" "int" "int" "char*" "void*")
(import "iup.dll" "IupSetCallback" "int" "int" "char*" "void*")
(import "iup.dll" "IupShowXY" "int" "int" "int" "int")
(import "iup.dll" "IupDialog" "int" "int")
(import "iup.dll" "IupMainLoop" "int" "void")
(import "iup.dll" "IupLabel" "int" "char*")
(import "iup.dll" "IupVbox" "int" "int" "int" "int" "int")
(import "msvcrt.dll" "atexit" "void" "void*")

(IupOpen)
(set 'quit_bt (IupButton "Quit" 0))
(set 'quit_bt2 (IupButton "More Quit" 0))

(define (quit_cb handle button pressed x y status)
(begin
    (println "handle id " handle)
    (if (= handle quit_bt) (println "quit_bt pressed "))
    (if (= handle quit_bt2) (println "quit_bt2 pressed "))
    (println "pressed? " (if (= 1 pressed) "Yes" "No"))
    (println "x " x)
    (println "y " y)
    (println "status " (get-string status))
    -2) ; IUP_DEFAULT = -2
)

(define (end) (println "Quit !"))

(IupSetCallback quit_bt "BUTTON_CB" (callback 'quit_cb "int" "int" "int" "int" "int" "int" "char*"))
(IupSetCallback quit_bt2 "BUTTON_CB" (callback 'quit_cb "int" "int" "int" "int" "int" "int" "char*"))
(set 'label (IupLabel "Very long label"))
(IupSetAttribute label "EXPAND" "YES")
(IupSetAttribute label "ALIGNMENT" "ACENTER")
(set 'vbox (IupVbox label quit_bt quit_bt2 0))
(IupSetAttribute vbox "MARGIN" "10x10")
(IupSetAttribute vbox "GAP" "5")
(IupSetAttribute vbox "ALIGNMENT" "ACENTER")
(set 'dialog (IupDialog vbox) )
(IupSetAttribute dialog "EXPAND" "YES")
(IupSetAttribute dialog "SIZE" "QUARTER")
(IupSetAttributeHandle dialog "DEFAULTESC" quit_bt)
(IupShowXY dialog 100 100)
(IupSetAttribute dialog "TITLE" "IUP from newLisp 10.3.8_DEVEL")
(atexit (callback 'end "void" "void"))
(IupMainLoop)
(IupClose)
(exit)


If run and clicking on the first or second button gives something like this:



$ newlisp.exe iup_button.lsp
handle id 23449624
quit_bt pressed
pressed? Yes
x 22
y 9
status   1
handle id 23449624
quit_bt pressed
pressed? No
x 22
y 9
status   1
handle id 23449624
quit_bt pressed
pressed? Yes
x 22
y 9
status     3
handle id 23449624
quit_bt pressed
pressed? No
x 22
y 9
status     3
handle id 23451248
quit_bt2 pressed
pressed? Yes
x 24
y 17
status   1
handle id 23451248
quit_bt2 pressed
pressed? No
x 24
y 17
status   1
handle id 23451248
quit_bt2 pressed
pressed? Yes
x 24
y 17
status     3
handle id 23451248
quit_bt2 pressed
pressed? No
x 24
y 17
status     3
Quit !


As a sideeffect of this extension the number of callbacks is virtually unlimited.



What is missing is support for varargs (which is really hard to implement in ffi context,

and support for structs/unions, which is not so hard to implement.



By now the extension adds ca. 40 kB (Windows XP SP2, gcc 4.6.1 (mingw)).



I'm looking forward to see this in 10.3.8 :-)



And again: a big thank you to lutz for this opportunity.
#8
newLISP in the real world / FFI closures are on the way
November 25, 2011, 12:57:27 AM
This morning, while commuting, I did finish the foundation for ffi closures.

That said, now I can create real ffi closures and get their addresses for later use,

and more important, call them.



Hopefully on my way back home I finish the marshalling code and can show some demo.



To give you a clue on how it is used:

(set 'a (callback (lambda (a b c) (mul a b c)) "int" "int" "int" "int"))
(println (a 1 2 3))
(println a)
(exit)


Which gives

OK <0x7b0008>
Me was called ...
with 3 arguments
6
<closure><6D0090>


The most interesting part here is Me was called ..., which is a real C call (the (println (a 1 2 3)) should not confuse you) to a ffi closure,

which then calls a trampoline function which executes the lambda in the callback definition.



The missing pieces are stuffing the lamba with arguments and returning the result cell(s) back

to the caller.

This explanation might get clearer if you see the code, though.
#9
I'm asking myself what was the best verb in newLisp for the ffi closures.

Many people have some anticipation when they read closure, and

would probably confuse or disappoint them.



It could even be made  a special case of the standard callback symbol,

I think that would be natural, after fcall has been merged into import.



Anyway Lutz - I'm into #2 of my list :-)
#10
I see ...

Cool :-)



I did only make small progress today, but this now works as expected:



(import "msvcrt" "sprintf")
(set 'res (dup " " 50))
(set 'csprintf (fcall sprintf c_int c_string c_string c_int c_double))
(set 'PI 3.1415926)
(println (csprintf res "the answer is always %i, or %.8f" 42 PI))
(println res)
(exit 0)


which gives:



newlisp.exe fsprintf.lsp
38
the answer is always 42, or 3.14159260


This honours the fact that a pointer is just that: a pointer.

I will make this more general (for where newLisp has primitives like integer), so when you

declare a parameter as pointer (c_string, c_pointer), and later feed it with an integer symbol, the content changes respectivly - so there is no more need for unpack here.



And I did more clean up, as I think that the (old now) fcall thing is almost done.



Next on my list are these:



* finish ffi_call execution

* make closures work (aka callbacks)

* create and manage structures at runtime

* wash the dishes :-)



But first I need to merge again ...

...



I hope to have this all done before holiday season :-)

(then I'd like to create a Android port)



Thank you Lutz for the support !
#11
That seems reasonable:

http://www.opensource.apple.com/source/libffi/libffi-18/include/ffi.h">//http://www.opensource.apple.com/source/libffi/libffi-18/include/ffi.h



The problem to me seems to be, that this file may be present at several locations in an OSX install,

for example the ruby cocoa bridge brings its own (newer) version.



DLL hell reincarnated on Macintosh ...



As Apple ships this version, it might be good enough, though.

Alternatively we could document the process of building a newer one.
#12
Perhaps just run ldd on the newlisp binary on OSX to see which dylibs it requires.



Under Windows Dependcy Walker just lists libffi-5.dll (the internal) name, which is not present.

I'll take a look into this, now I don't know why it works.



BTW, which version of libffi is present in OSX ?
#13
I just incoporated the files, thanks.

I've cleaned the code a bit, and patched another file (nl-filesys.c):



CELL * p_makeDir(CELL * params)
{
char * dirString;
UINT mode;

mode = 0777; /* drwxrwxrwx  gets user masked to drwxr-xr-x on most UNIX */

/* consume param regardless of OS */
params = getString(params, &dirString);

if(params != nilCell)
    {
    getInteger(params, &mode);
    }

#ifdef WIN_32
return(mkdir(dirString) == 0 ? trueCell : nilCell);
#else
return(mkdir(dirString, (mode_t)mode) == 0 ? trueCell : nilCell);
#endif
}


Here's the corresponding patch, which remedies compiler warnings:

--- ../newlisp-10.3.6/nl-filesys.c      2011-11-18 20:05:00 +0100
+++ nl-filesys.c        2011-11-22 21:15:50 +0100
@@ -771,17 +771,17 @@
 CELL * p_makeDir(CELL * params)
 {
 char * dirString;
-mode_t mode;
-UINT inMode;
+UINT mode;

+mode = 0777; /* drwxrwxrwx  gets user masked to drwxr-xr-x on most UNIX */
+
+/* consume param regardless of OS */
 params = getString(params, &dirString);
+
 if(params != nilCell)
     {
-    getInteger(params, &inMode);
-    mode = inMode;
+    getInteger(params, &mode);
     }
-else
-    mode = 0777; /* drwxrwxrwx  gets user masked to drwxr-xr-x on most UNIX */

 #ifdef WIN_32
 return(mkdir(dirString) == 0 ? trueCell : nilCell);


The only weakness here is the cast of UINT to mode_t, the maximum value for mode_t (for which mode_t makes any sense) is 7777

in octal notation, which is 4095 in decimal notation - which can be expressed in 11 bits (0xfff in hex).

On some platforms mode_t is unsigned short, on some unsigned int - so either 16 or 32 bits.



One should be aware of such things, perhaps by putting a note in the docs ?

Or by fencing the maximum value (and having a note):



...
getInteger(params, &mode);
mode = mode > 0xfff ? 0xfff : mode;
...


Then it should be safe.



EDIT:

I just compared the size of the striped newlisp.exe binaries with and without FFI.

FFI makes ist exactly 4096 Bytes larger - which is hex 0x1000 :-)
#14
Now it is possible to return float values directly (which does not work with imported functions):



(import "msvcrt.dll" "log10")
log10<77C4D060>
; define a fcall object return type is double, takes one double as parameter
(set 'clog10 (fcall log10 c_double c_double))
log10<77C4D060>
(clog10 1000)
3
(number? (clog10 1000))
true
(format "%.2f" (clog10 1000))
"3.00"
(format "%.8f" (clog10 3.1415926))
"0.49714987"


Right now, not nearly all types are supported, and type checking and error detection are rather weak.

But I'm progressing.
#15
I can't wait for the answer - this can get philosophical.



The key question is: what is value and when is it nil (as I remember there is no false in lisp, though) ?

If you look over to python, "", empty lists, tuples and numeric 0 are false.

That seems natural, but in lisp you work on lists, an (0) is in list - so true.

Even an empty string is a cell, with no value, it is in list - so true.

An empty list says: there is nothing in list, nil - so false.



So for me the question goes down to: is there an element in list or not ?



If you would take e.g. Python's approach you ask: does to value of an element evaluate to true ?



But: how can you then distinguish between () and ("") ?

Then both would give nil, but 1. case has no element where 2. has one (an empty string).

So for at least some cases you would need a hasElement* or such.



I think the lisp approach is consistent.



Just my thoughts.



*JAVA TM public final static synchronized unvoid function