static char *cs_answer = (char *)NULL;
HISTORY_STATE *history_state = NULL;
-char *cleanStringToCString(CleanString s){
+//Helper functions
+char *cleanStringToCString(CleanString s)
+{
unsigned long len = CleanStringLength(s);
char *cs = (char *)malloc(len+1);
if(cs == NULL){
return cs;
}
-void cleanReadLine(CleanString prompt, int history, CleanString *result)
+void cleanSetReadLineName(CleanString name)
+{
+ rl_readline_name = cleanStringToCString(name);
+}
+
+//Readline functions
+void cleanReadLine(CleanString prompt, int history, CleanString *result, int *eof)
{
char *cs_prompt = cleanStringToCString(prompt);
if(cs_answer && *cs_answer && history){
add_history(cs_answer);
}
-
+
+ *eof = 0;
if(!cs_answer){ //In case of an EOF
- CleanStringVariable(answer, 1);
- *result = (CleanString) answer;
- memcpy(CleanStringCharacters(answer), "", 1);
- CleanStringLength(answer) = 1;
- } else { //In case of a proper response
- CleanStringVariable(answer, strlen(cs_answer));
- *result = (CleanString) answer;
- memcpy(CleanStringCharacters(answer), cs_answer, strlen(cs_answer));
- CleanStringLength(answer) = strlen(cs_answer);
+ cs_answer = (char *)malloc(1);
+ cs_answer[0] = '\0';
+ *eof = 1;
}
+ CleanStringVariable(answer, strlen(cs_answer));
+ *result = (CleanString) answer;
+ memcpy(CleanStringCharacters(answer), cs_answer, strlen(cs_answer));
+ CleanStringLength(answer) = strlen(cs_answer);
}
-void cleanSetReadLineName(CleanString name){
- rl_readline_name = cleanStringToCString(name);
-}
-
-void cleanUsingHistory(){
+//History Functions
+//Initializing History and State Management
+void cleanUsingHistory()
+{
using_history();
}
-void cleanGetState(int *offset, int *num, int *flags){
+void cleanGetState(int *offset, int *num, int *flags)
+{
*offset = history_get_history_state()->offset;
*num = history_get_history_state()->length;
*flags = history_get_history_state()->flags;
}
-void cleanGetHistoryItem(int num, CleanString *line, CleanString *timestamp){
+void cleanGetHistoryItem(int num, CleanString *line, CleanString *timestamp)
+{
char *cs_line = history_get_history_state()->entries[num]->line;
char *cs_stamp = history_get_history_state()->entries[num]->timestamp;
CleanStringLength(cleanTimestamp) = strlen(cs_stamp);
}
-void cleanInitNewHistoryState(int offset, int flags, int num){
+void cleanInitNewHistoryState(int offset, int flags, int num)
+{
if(history_state != NULL){
//we should test if we can recursively free the object
free(history_state);
history_state->flags = 0;
}
-void cleanSetNewHistoryEntry(int i, CleanString line, CleanString timestamp){
+void cleanSetNewHistoryEntry(int i, CleanString line, CleanString timestamp)
+{
char *cs_line = cleanStringToCString(line);
char *cs_timestamp = cleanStringToCString(timestamp);
history_state->entries[i]->line = cs_line;
history_state->entries[i]->timestamp = cs_timestamp;
}
-void cleanCommitSetHistory(void){
+void cleanCommitSetHistory(void)
+{
history_set_history_state(history_state);
}
-void cleanAddHistory(CleanString entry){
+//History List Management
+void cleanAddHistoryTime(CleanString timestamp)
+{
+ char *cs_timestamp = cleanStringToCString(timestamp);
+ add_history_time(cs_timestamp);
+ free(cs_timestamp);
+}
+
+void cleanAddHistory(CleanString entry)
+{
char *cs_entry = cleanStringToCString(entry);
add_history(cs_entry);
free(cs_entry);
}
-void cleanClearHistory(){
+void cleanRemoveHistory(int which, CleanString *line, CleanString *timestamp)
+{
+ HIST_ENTRY *entry = remove_history(which);
+ char *cs_line = entry->line;
+ char *cs_stamp = entry->timestamp;
+
+ CleanStringVariable(cleanLine, strlen(cs_line));
+ *line = (CleanString) cleanLine;
+ memcpy(CleanStringCharacters(cleanLine), cs_line, strlen(cs_line));
+ CleanStringLength(cleanLine) = strlen(cs_line);
+
+ CleanStringVariable(cleanTimestamp, strlen(cs_stamp));
+ *timestamp = (CleanString) cleanTimestamp;
+ memcpy(CleanStringCharacters(cleanTimestamp), cs_stamp, strlen(cs_stamp));
+ CleanStringLength(cleanTimestamp) = strlen(cs_stamp);
+
+ histdata_t tofree = free_history_entry(entry);
+ free(tofree);
+}
+
+void cleanReplaceHistoryEntry(
+ int which, CleanString l, CleanString *line, CleanString *timestamp)
+{
+ char *cs_l = cleanStringToCString(l);
+ HIST_ENTRY *entry = replace_history_entry(which, cs_l, NULL);
+ free(cs_l);
+ if(entry == NULL){
+ printf("invalid which\n");
+ }
+
+ char *cs_line = entry->line;
+ char *cs_stamp = entry->timestamp;
+
+ CleanStringVariable(cleanLine, strlen(cs_line));
+ *line = (CleanString) cleanLine;
+ memcpy(CleanStringCharacters(cleanLine), cs_line, strlen(cs_line));
+ CleanStringLength(cleanLine) = strlen(cs_line);
+
+ CleanStringVariable(cleanTimestamp, strlen(cs_stamp));
+ *timestamp = (CleanString) cleanTimestamp;
+ memcpy(CleanStringCharacters(cleanTimestamp), cs_stamp, strlen(cs_stamp));
+ CleanStringLength(cleanTimestamp) = strlen(cs_stamp);
+
+ histdata_t tofree = free_history_entry(entry);
+ free(tofree);
+}
+
+
+void cleanClearHistory()
+{
clear_history();
}
-int cleanHistorySearch(CleanString s, int dir){
+void cleanStifleHistory(int max)
+{
+ stifle_history(max);
+}
+
+int cleanUnstifleHistory()
+{
+ return unstifle_history();
+}
+
+int cleanHistoryIsStifled()
+{
+ return history_is_stifled();
+}
+
+//Information About the History List
+int cleanHistoryTotalBytes()
+{
+ return history_total_bytes();
+}
+
+//Moving Around the History List
+
+//Searching the History List
+int cleanHistorySearch(CleanString s, int dir)
+{
char *cs_s = cleanStringToCString(s);
int ret = history_search(cs_s, dir);
free(cs_s);
return ret;
}
-int cleanHistorySearchPrefix(CleanString s, int dir){
+int cleanHistorySearchPrefix(CleanString s, int dir)
+{
char *cs_s = cleanStringToCString(s);
int ret = history_search_prefix(cs_s, dir);
free(cs_s);
return ret;
}
-int cleanHistorySearchPos(CleanString s, int dir, int pos){
+int cleanHistorySearchPos(CleanString s, int dir, int pos)
+{
char *cs_s = cleanStringToCString(s);
int ret = history_search_pos(cs_s, dir, pos);
free(cs_s);
return ret;
}
+//Managing the History File
int cleanReadHistory(CleanString path)
{
char *cs_path = cleanStringToCString(path);
SHELL:=/bin/bash
-CLM=clm
-CLMFLAGS=-nt -l /usr/lib/libreadline.so
+CLM:=clm
+CLMFLAGS:=-nt -l /usr/lib/libreadline.so
+LIBRARYDIR:=Clean\ System\ Files
+BINARIES:=test testscripts/issue1
-all: test
+.PHONY: readline clean
+
+all: readline $(BINARIES)
+
+readline:
+ $(MAKE) -C $(LIBRARYDIR)
%: %.icl
$(CLM) $(CLMFLAGS) $(basename $<) -o $@
clean:
- $(RM) -v test Clean\ System\ Files/{ReadLine,test}.*
+ $(MAKE) -C $(LIBRARYDIR) clean
+ $(RM) -v $(BINARIES)
+ $(RM) -v $(addprefix $(LIBRARYDIR)/,$(addsuffix .*,$(BINARIES)))
definition module ReadLine
+import StdEnv
+
+:: Maybe a = Nothing | Just a
:: HistoryItem = {line :: String, timestamp :: String}
:: HistoryState = {entries :: [HistoryItem], offset :: Int, flags :: Int}
+instance toString HistoryItem
+instance toString HistoryState
+
//Non-library functions
setReadLineName :: !String !*env -> !*env
//Readline
-readLine :: !String !Bool !*env -> (!String, !*env)
+readLine :: !String !Bool !*env -> (!Maybe String, !*env)
//Initializing History and State Management
//Note that this HAS to be executed when you want to add entries when the
//History List Management
addHistory :: !String !*env -> !*env
+addHistoryTime :: !String !*env -> !*env
+removeHistory :: !Int !*env -> (!HistoryItem, !*env)
+replaceHistoryEntry :: !Int !String !*env -> (!HistoryItem, !*env)
clearHistory :: !*env -> !*env
-//TODO some more functions
+stifleHistory :: !Int !*env -> !*env
+unstifleHistory :: !*env -> !*env
+historyIsStifled :: !*env -> (!Int, !*env)
//Information About the History List
-//TODO
+historyList :: !*env -> (![HistoryItem], !*env)
+whereHistory :: !*env -> (!Int, !*env)
+currentHistory :: !*env -> (!Maybe HistoryItem, !*env)
+historyGet :: !Int !*env -> (!Maybe HistoryItem, !*env)
+historyGetTime :: HistoryItem -> String
+historyTotalBytes :: !*env -> (!Int, !*env)
//Moving Around the History List
//TODO
import code from "readLine.o"
+instance toString HistoryItem where
+ toString {line,timestamp} = line +++ " (" +++ timestamp +++ ")"
+instance toString HistoryState where
+ toString {entries,offset,flags} = "[" +++ toS entries +++ "]\n" +++
+ "offset: " +++ toString offset +++ "\nflags: " +++ toString flags
+ where
+ toS :: [HistoryItem] -> String
+ toS [] = "--empty--"
+ toS [x] = toString x
+ toS [x:xs] = toString x +++ ","
+
//Readline
-readLine :: !String !Bool !*env -> (!String, !*env)
-readLine s h e = code {
- ccall cleanReadLine "SI:S:A"
- }
+readLine :: !String !Bool !*env -> (!Maybe String, !*env)
+readLine s h e
+# (s, eof, e) = readLineEof s h e
+= (if eof Nothing (Just s), e)
+ where
+ readLineEof :: !String !Bool !*env -> (!String, !Bool, !*env)
+ readLineEof s h e = code {
+ ccall cleanReadLine "SI:VSI:A"
+ }
setReadLineName :: !String !*env -> !*env
setReadLineName s e = code {
- ccall cleanSetReadLineName "S:V:A"
+ ccall cleanSetReadLineName "S:V:A"
}
//Initializing History and State Management
usingHistory :: !*env -> !*env
usingHistory e = code {
- ccall cleanUsingHistory ":V:A"
+ ccall cleanUsingHistory ":V:A"
}
historyGetHistoryState :: !*env -> (!HistoryState, !*env)
where
getState :: !*env -> (!Int, !Int, !Int, !*env)
getState e= code {
- ccall cleanGetState ":VIII:A"
- }
+ ccall cleanGetState ":VIII:A"
+ }
getItems :: !Int !*env -> (![HistoryItem], !*env)
getItems 0 e = ([], e)
getItems i e
getItem :: !Int !*env -> (!String, !String, !*env)
getItem i e = code {
- ccall cleanGetHistoryItem "I:VSS:A"
- }
+ ccall cleanGetHistoryItem "I:VSS:A"
+ }
historySetHistoryState :: !HistoryState !*env -> !*env
//History List Management
addHistory :: !String !*env -> !*env
addHistory s e = code {
- ccall cleanAddHistory "S:V:A"
+ ccall cleanAddHistory "S:V:A"
}
+addHistoryTime :: !String !*env -> !*env
+addHistoryTime s e = code {
+ ccall cleanAddHistoryTime "S:V:A"
+ }
+
+removeHistory :: !Int !*env -> (!HistoryItem, !*env)
+removeHistory i e
+# (line, timestamp, e) = removeHistoryItem i e
+= ({HistoryItem | line=line, timestamp=timestamp}, e)
+ where
+ removeHistoryItem :: !Int !*env -> (!String, !String, !*env)
+ removeHistoryItem i e = code {
+ ccall cleanRemoveHistory "I:VSS:A"
+ }
+
+replaceHistoryEntry :: !Int !String !*env -> (!HistoryItem, !*env)
+replaceHistoryEntry i s e
+# (line, timestamp, e) = replaceItem i s e
+= ({HistoryItem | line=line, timestamp=timestamp}, e)
+ where
+ replaceItem :: !Int !String !*env -> (!String, !String, !*env)
+ replaceItem i s e = code {
+ ccall cleanReplaceHistoryEntry "IS:VSS:A"
+ }
+
clearHistory :: !*env -> !*env
clearHistory e = code {
- ccall cleanClearHistory ":V:A"
+ ccall cleanClearHistory ":V:A"
+ }
+
+stifleHistory :: !Int !*env -> !*env
+stifleHistory i e = code {
+ ccall cleanStifleHistory "I:V:A"
+ }
+
+unstifleHistory :: !*env -> !*env
+unstifleHistory e = code {
+ ccall cleanUnstifleHistory ":V:A"
+ }
+
+historyIsStifled :: !*env -> (!Int, !*env)
+historyIsStifled e = code {
+ ccall cleanHistoryIsStifled ":I:A"
}
//Information About the History List
+historyList :: !*env -> (![HistoryItem], !*env)
+historyList e
+# ({entries,offset,flags}, e) = historyGetHistoryState e
+= (entries, e)
+
+whereHistory :: !*env -> (!Int, !*env)
+whereHistory e
+# ({entries,offset,flags}, e) = historyGetHistoryState e
+= (offset, e)
+
+currentHistory :: !*env -> (!Maybe HistoryItem, !*env)
+currentHistory e
+# ({entries,offset,flags}, e) = historyGetHistoryState e
+= (if (isEmpty entries) Nothing (Just (entries!!offset)), e)
+
+historyGet :: !Int !*env -> (!Maybe HistoryItem, !*env)
+historyGet i e
+# ({entries,offset,flags}, e) = historyGetHistoryState e
+= (if (isEmpty entries) Nothing (Just (entries!!i)), e)
+
+historyGetTime :: HistoryItem -> String
+historyGetTime {line,timestamp} = timestamp
+
+historyTotalBytes :: !*env -> (!Int, !*env)
+historyTotalBytes e = code {
+ ccall cleanHistoryTotalBytes ":I:A"
+ }
//Moving Around the History List
//Searching the History List
historySearch :: !String !Int !*env-> (!Int, !*env)
historySearch s i e = code {
- ccall cleanHistorySearch "SI:I:A"
+ ccall cleanHistorySearch "SI:I:A"
}
historySearchPrefix :: !String !Int !*env-> (!Int, !*env)
historySearchPrefix s i e = code {
- ccall cleanHistorySearchPrefix "SI:I:A"
+ ccall cleanHistorySearchPrefix "SI:I:A"
}
historySearchPos :: !String !Int !Int !*env-> (!Int, !*env)
historySearchPos s i1 i2 e = code {
- ccall cleanHistorySearchPos "SI:I:A"
+ ccall cleanHistorySearchPos "SI:I:A"
}
//Managing the History File
readHistory :: !String !*env -> (!Bool, !*env)
readHistory s e = code {
- ccall cleanReadHistory "S:I:A"
+ ccall cleanReadHistory "S:I:A"
}
readHistoryRange :: !String !Int !Int !*env -> (!Bool, !*env)
readHistoryRange s i1 i2 e = code {
- ccall cleanReadHistoryRange "SII:I:A"
+ ccall cleanReadHistoryRange "SII:I:A"
}
writeHistory :: !String !*env -> (!Bool, !*env)
writeHistory s e = code {
- ccall cleanWriteHistory "S:I:A"
+ ccall cleanWriteHistory "S:I:A"
}
appendHistory :: !Int !String !*env -> (!Bool, !*env)
appendHistory i s e = code {
- ccall cleanWriteHistory "IS:I:A"
+ ccall cleanWriteHistory "IS:I:A"
}
historyTruncateFile :: !String !Int !*env -> (!Bool, !*env)
historyTruncateFile i s e = code {
- ccall cleanWriteHistory "SI:I:A"
+ ccall cleanWriteHistory "SI:I:A"
}
entries=[{HistoryItem | line="custom", timestamp=""}],
offset=1, flags=0}
-Start :: *World -> (Int, String, HistoryState, HistoryState, *World)
+Start :: *World -> (String, *World)
Start w
-# (f, w) = stdio w
#! w = setReadLineName "Test program" w
#! w = usingHistory w
#! (_, w) = readHistory "readline.history" w
#! w = addHistory "testentry" w
+#! w = addHistoryTime "time" w
+#! (hi, w) = removeHistory 1 w
+#! (hy, w) = replaceHistoryEntry 1 "replacement" w
#! (s, w) = readLine "first prompt: " True w
#! (s, w) = readLine "uparrow should word with history: " False w
#! (_, w) = writeHistory "readline.history" w
#! (i, w) = historySearch "testentry" -1 w
+#! (_, w) = historyList w
+#! (_, w) = whereHistory w
+#! (_, w) = currentHistory w
+#! (_, w) = historyGet 1 w
+#! (_, w) = historyTotalBytes w
+#! w = stifleHistory 2 w
+#! (i, w) = historyIsStifled w
+#! w = unstifleHistory w
+#! (i, w) = historyIsStifled w
#! (oh, w) = historyGetHistoryState w
#! w = historySetHistoryState testHistory w
#! (h, w) = historyGetHistoryState w
#! w = clearHistory w
-= (i, s, oh, h, w)
+= (
+ toString h,
+ w)