From c1881c179f5da9c41193ba9534c2ffb9be48b8d5 Mon Sep 17 00:00:00 2001 From: Mart Lubbers Date: Mon, 25 Jan 2016 10:16:28 +0100 Subject: [PATCH 1/1] initial commit, working readline function --- .gitignore | 3 ++ Clean System Files/Clean.h | 76 +++++++++++++++++++++++++++++++++++ Clean System Files/Makefile | 7 ++++ Clean System Files/readLine.c | 39 ++++++++++++++++++ Makefile | 11 +++++ README.md | 35 ++++++++++++++++ ReadLine.dcl | 8 ++++ ReadLine.icl | 11 +++++ test.icl | 11 +++++ 9 files changed, 201 insertions(+) create mode 100644 .gitignore create mode 100644 Clean System Files/Clean.h create mode 100644 Clean System Files/Makefile create mode 100644 Clean System Files/readLine.c create mode 100644 Makefile create mode 100644 README.md create mode 100644 ReadLine.dcl create mode 100644 ReadLine.icl create mode 100644 test.icl diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f7c3c6c --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +test +*.abc +*.o diff --git a/Clean System Files/Clean.h b/Clean System Files/Clean.h new file mode 100644 index 0000000..bf22e6e --- /dev/null +++ b/Clean System Files/Clean.h @@ -0,0 +1,76 @@ + +#define Clean(a) + +typedef struct clean_string *CleanString; + +/* a string in Clean is: + struct clean_string { + size_t clean_string_length; + char clean_string_characters[clean_string_length]; + }; + The string does not end with a '\0' ! +*/ + +#ifndef _WIN64 + +/* CleanStringLength(clean_string) returns the length of the clean_string in characters */ +#define CleanStringLength(clean_string) (*(unsigned long *)(clean_string)) + +/* CleanStringCharacters(clean_string) returns a pointer to the characters of the clean_string */ +#define CleanStringCharacters(clean_string) ((char*)(1+(unsigned long *)(clean_string))) + +/* CleanStringSizeInts(string_length) return size of *CleanString in integers */ +#define CleanStringSizeInts(string_length) (1+(((unsigned long)(string_length)+(sizeof(unsigned long)-1))>>(1+(sizeof(unsigned long)>>2)))) + +/* CleanStringVariable(clean_string,string_length) defines variable clean_string with length string_length, + before using the clean_string variable, cast to CleanString, except for the macros above */ +#define CleanStringVariable(clean_string,string_length) unsigned long clean_string[CleanStringSizeInts(string_length)] + +/* CleanStringSizeBytes(string_length) return size of *CleanString in bytes */ +#define CleanStringSizeBytes(string_length) ((sizeof(unsigned long)<<1)+(((unsigned long)(string_length)+(sizeof(unsigned long)-1)) & -(sizeof(unsigned long)))) + +typedef long *CleanIntArray; + +/* CleanIntArraySize(clean_array) returns the size (number of elements) of the clean_int_array */ +#define CleanIntArraySize(clean_int_array) (((unsigned long *)(clean_int_array))[-2]) + +/* CleanRealArraySize(clean_real_array) returns the size (number of elements) of the clean_real_array */ +#define CleanRealArraySize(clean_real_array) (((unsigned long *)(clean_real_array))[-2]) + +/* CleanCharArraySize(clean_char_array) returns the size (number of elements) of the clean_char_array */ +#define CleanCharArraySize(clean_char_array) (((unsigned long *)(clean_char_array))[-1]) + +#else + +/* CleanStringLength(clean_string) returns length of the clean_string in characters */ +#define CleanStringLength(clean_string) (*(unsigned __int64 *)(clean_string)) + +/* CleanStringCharacters(clean_string) returns a pointer to the characters of the clean_string */ +#define CleanStringCharacters(clean_string) ((char*)(1+(unsigned __int64 *)(clean_string))) + +/* CleanStringSizeInts(string_length) return size of *CleanString in integers */ +#define CleanStringSizeInts(string_length) (1+(((unsigned __int64)(string_length)+7)>>3)) + +/* CleanStringVariable(clean_string,string_length) defines variable clean_string with length string_length, + before using the clean_string variable, cast to CleanString, except for the macros above */ +#define CleanStringVariable(clean_string,string_length) unsigned __int64 clean_string[CleanStringSizeInts(string_length)] + +/* CleanStringSizeBytes(string_length) return size of *CleanString in bytes */ +#define CleanStringSizeBytes(string_length) (8+(((unsigned __int64)(string_length)+7) & -8)) + +typedef __int64 *CleanIntArray; + +/* CleanIntArraySize(clean_array) returns the size (number of elements) of the clean_int_array */ +#define CleanIntArraySize(clean_int_array) (((unsigned __int64 *)(clean_int_array))[-2]) + +/* CleanRealArraySize(clean_real_array) returns the size (number of elements) of the clean_real_array */ +#define CleanRealArraySize(clean_real_array) (((unsigned __int64 *)(clean_real_array))[-2]) + +/* CleanCharArraySize(clean_char_array) returns the size (number of elements) of the clean_char_array */ +#define CleanCharArraySize(clean_char_array) (((unsigned __int64 *)(clean_char_array))[-1]) + +#endif + +typedef double *CleanRealArray; + +typedef unsigned char *CleanCharArray; diff --git a/Clean System Files/Makefile b/Clean System Files/Makefile new file mode 100644 index 0000000..154cf00 --- /dev/null +++ b/Clean System Files/Makefile @@ -0,0 +1,7 @@ +CFLAGS=-Wall -pedantic +LDFLAGS=-lreadline + +all: readLine.o + +clean: + $(RM) -v readLine.o diff --git a/Clean System Files/readLine.c b/Clean System Files/readLine.c new file mode 100644 index 0000000..b39be2e --- /dev/null +++ b/Clean System Files/readLine.c @@ -0,0 +1,39 @@ +#include +#include + +#include +#include + +#include "Clean.h" + +static char *cs_answer = (char *)NULL; + +void cleanReadLine(CleanString prompt, int history, CleanString *result) +{ + //Initialize + unsigned long promptlen = CleanStringLength(prompt); + char *cs_prompt = (char *)malloc(promptlen+1); + if(cs_prompt == NULL){ + printf("malloc failed...\n"); + exit(1); + } + memcpy(cs_prompt, CleanStringCharacters(prompt), promptlen); + cs_prompt[promptlen] = '\0'; + + //Get the answer and add to history if not empty + if(cs_answer){ + free(cs_answer); + cs_answer = (char *)NULL; + } + cs_answer = readline(cs_prompt); + free(cs_prompt); + if(cs_answer && *cs_answer && history){ + add_history(cs_answer); + } + + //Transfor answer into cstring + CleanStringVariable(answer, strlen(cs_answer)); + *result = (CleanString) answer; + memcpy(CleanStringCharacters(answer), cs_answer, strlen(cs_answer)); + CleanStringLength(answer) = strlen(cs_answer); +} diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6dd1a70 --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +SHELL:=/bin/bash +CLM=clm +CLMFLAGS=-nt -l /usr/lib/libreadline.so + +all: test + +%: %.icl + $(CLM) $(CLMFLAGS) $(basename $<) -o $@ + +clean: + $(RM) -v test Clean\ System\ Files/test.* diff --git a/README.md b/README.md new file mode 100644 index 0000000..c50a825 --- /dev/null +++ b/README.md @@ -0,0 +1,35 @@ +Clean readline Version 0.1 +========================== + +ReadLine is a Clean library that allows interactive console programs to use the +GNU readline libraries. At the moment this is only tested on Linux. + +###Usage +To setup the library you can simply run +``` +make -C Clean\ System\ Files +``` + +To compile and test the test program you can run +``` +make +./test +``` + +When you want to use the library in your program you should compile with the +`-l /usr/lib/libreadline.so` linker flag + +###Todo + +- Test how the library reacts on non terminal stdin and EOF +- Embed the readline library in the object files in such a way that no special + compiler flag is needed. +- Control over history, right now entries are added automatically to the + history when the boolean flag is on. It would be nice to be able to add + custom entries. +- Control over tabcompletion, right now it completes on filenames. +- Check possibilities for Windows/Mac + +###Author + +Mart Lubbers (mart at martlubbers.net) diff --git a/ReadLine.dcl b/ReadLine.dcl new file mode 100644 index 0000000..da953d7 --- /dev/null +++ b/ReadLine.dcl @@ -0,0 +1,8 @@ +definition module ReadLine + +/* + Reads a line from stdin with the readline library + The value in the String argument will be used as a prompt + To enable history the Boolean variable has to be set to True +*/ +readLine :: !String !Bool !*env -> (!String, !*env) diff --git a/ReadLine.icl b/ReadLine.icl new file mode 100644 index 0000000..b8c3053 --- /dev/null +++ b/ReadLine.icl @@ -0,0 +1,11 @@ +implementation module ReadLine + +import StdEnv + +import code from "readLine.o" + +readLine :: !String !Bool !*env -> (!String, !*env) +readLine s h e = code { + ccall cleanReadLine "SI:S:A" + } + diff --git a/test.icl b/test.icl new file mode 100644 index 0000000..0919253 --- /dev/null +++ b/test.icl @@ -0,0 +1,11 @@ +module test + +import StdEnv +import ReadLine + +Start :: *World -> (String, *World) +Start w +# (f, w) = stdio w +#! (s, w) = readLine "first prompt: " True w +#! (s, w) = readLine "uparrow should word with history: " False w += (s, w) -- 2.20.1