Recently Written · git

clic

MIRROR ONLY Gopher client with pretty colours in Common Lisp

git clone https://github.com/equwal/clic

Log | Files | Refs


commit fb5155bf84450fec31f6b69a49fbdc07aee5aa70
Solene Rapenne <solene@perso.pw>
2018-04-06 10:08:01 +0200

Add kiosk mode and drop SBCL

 Makefile             |  17 +++-----
 README.md            |  38 +++++------------
 TODO                 |  14 -------
 clic.1               |   2 +-
 clic.lisp            |  88 +++++++++++++++++++-------------------
 extension.c          |  17 --------
 interactive-test.exp | 116 ---------------------------------------------------
 make-binary.lisp     |  16 -------
 run-test.sh          |  14 -------
 test.lisp            |  35 ----------------
 10 files changed, 62 insertions(+), 295 deletions(-)
diff --git a/Makefile b/Makefile
index 9c85c12..cef7270 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
 # See the LICENSE file for copyright and license details.
 .POSIX:
 
-VERSION = 0.1
+VERSION = 0.2
 
 BIN    = clic
 LISP   = ecl
@@ -10,17 +10,10 @@ PREFIX = /usr
 BINDIR = ${PREFIX}/bin
 MANDIR = ${PREFIX}/share/man
 
-all: extension.so ${BIN}
+all: ${BIN}
 
-${BIN}: clic.lisp make-binary.lisp
-	${LISP} --load make-binary.lisp
-
-standalone: clic.lisp extension.so make-binary.lisp
-	${MAKE} -e LISP=sbcl
-
-extension.so: extension.c
-	${CC} -Wall -fPIC -c extension.c
-	${LD} -shared -o extension.so extension.o
+${BIN}:	clic.lisp make-binary.lisp
+	ecl -load make-binary.lisp
 
 install: ${BIN}
 	@echo installing executable to "${DESTDIR}${PREFIX}/bin"
@@ -39,7 +32,7 @@ uninstall:
 	@rm -f ${DESTDIR}${MANDIR}/man1/clic.1
 
 clean:
-	rm -f "${BIN}" clic.o clic.eclh clic.cxx bookmark-test extension.so
+	rm -f "${BIN}" clic.o clic.eclh clic.cxx
 
 test: clean all
 	@sh run-test.sh ${LISP}
diff --git a/README.md b/README.md
index 6834acf..16b093b 100644
--- a/README.md
+++ b/README.md
@@ -12,46 +12,25 @@ Requirements
 clic requires a few dependencies :
 
    + ANSI compatible terminal emulator
-   + a Common LISP interpreter
+   + ecl common lisp interpreter
    + C compiler
    + Linux/OpenBSD/FreeBSD/NetBSD
 
-Both **ecl** and **sbcl** Common LISP compilers are supported.
-
 
 How to build
 ============
 
 `clic` binary must be compiled.
 
-To compile it with **ecl** :
+To compile it with **ecl**, it's really easy type the following
+command :
 
     make
 
-To compile it with **sbcl** :
-
-    make LISP=sbcl
-
 then you can use `make install` to deploy it in `/usr/bin/`.
 
-Note : when using sbcl, a shared library extension.o is created and
-then sbcl creates a binary linked against the library. But ecl will
-translate the whole lisp code to C and then compile it, but linking
-against ecl.
-
-**I (the author) recommend using ecl**.
-
-
-Information about the binary
-----------------------------
-If you compile clic with ecl, you will need ecl library installed on
-the computer, the startup time is really fast. While compiling clic
-with SBCL will provide a standalone binary embedding the whole SBCL
-compiler, weighting approximately 10 Mb with a slower startup time.
-
-If you use OpenBSD and SBCL, you will need wxallowed mountflag on the
-partition from where you try to start clic standalone because sbcl has
-a W^X issue.
+The binary will be linked to ecl shared library. You need to install
+ecl if you want to deploy clic binary on others systems.
 
 
 How to use clic
@@ -87,7 +66,12 @@ permitting to use clic with the numpad with only one hand :
 Command line usage
 ==================
 
-clic [url|file]
+clic [-k] [url|file]
+
+If you start clic with -k parameter, then kiosk mode is enabled, which
+mean it won't call any external program or save any data on the
+disk. Texts (type 0) will be shown as-this in the output. It only
+allow to use texts, menus and searches.
 
 If you pass a gopher url to clic (gopher:// isn't mandatory for the
 url), the behavor will change depending on two parameters :
diff --git a/TODO b/TODO
deleted file mode 100644
index 6f0c7d9..0000000
--- a/TODO
+++ /dev/null
@@ -1,14 +0,0 @@
-* FEATURE
-
-- DONE add a bookmark "a" function to store the current page location
-- DONE add a bookmark "b" function to display the bookmarks
-- TODO add a dump "d" function to display the raw response
-- DONE history mode which save every file into a filesystem tree to preserve data if gopherhole go offline
-
-
-* CODE
-
-- TODO remove the pagination if using stdout or not in shell
-- TODO make the c-termsize working on ecl
-- DONE use CLOS to store data
-- DONE store the whole page and deal with it later
diff --git a/clic.1 b/clic.1
index 21ed6f0..1280042 100644
--- a/clic.1
+++ b/clic.1
@@ -3,7 +3,7 @@
 clic \- a terminal gopher client
 .SH SYNOPSIS
 .B clic
-.IR [URL]
+.IR [-k] [URL]
 .PP
 .SH DESCRIPTION
 .B clic
diff --git a/clic.lisp b/clic.lisp
index f95ada5..7d822ab 100644
--- a/clic.lisp
+++ b/clic.lisp
@@ -1,23 +1,10 @@
 ;;; let's hide the loading
 (let ((*standard-output* (make-broadcast-stream)))
   (require 'asdf)
-  #+sbcl
-  (require 'sb-bsd-sockets)
   #+ecl
   (require 'sockets))
 
 ;;;; C binding to get terminal informations
-;;;; SBCL only
-#+sbcl
-(progn
-  (load-shared-object #p"./extension.so")
-  ;; getTerminalHeight
-  (declaim (inline getTerminalHeight))
-  (sb-alien:define-alien-routine "getTerminalHeight" unsigned-int)
-  (defun c-termsize ()
-    "return terminal height"
-    (sb-alien:with-alien ((res unsigned-int (getTerminalHeight))))))
-
 #+ecl
 (progn
   (ffi:clines "
@@ -41,7 +28,7 @@
 (defstruct location host port type uri
            :predicate)
 
-;;;; kiosk mode on/off
+;;;; kiosk mode 
 (defparameter *kiosk-mode* nil)
 
 (defmacro kiosk-mode(&body code)
@@ -98,8 +85,6 @@
   "return t if the output is a terminal"
   ;; we use this variable in case we don't want to be interactive
   ;; like when we use a cmd arg to get an image
-  #+sbcl
-  (interactive-stream-p *standard-output*)
   #+ecl
   (if (= 1 (c-ttyp))
       t
@@ -387,36 +372,44 @@
 (defun parse-url(url)
   "parse a gopher url and return a location"
 
-  (let ((url (if (search "gopher://" url)
-                 (subseq url 9)
-                 url)))
+  (cond ((or
+          (string= "--help" url)
+          (string= "-h"     url))
+         (help-shell)
+         (quit))
 
-    ;; splitting with / to get host:port and uri
-    ;; splitting host and port to get them
-    (let* ((infos      (split url #\/))
-           (host-port (split (pop infos) #\:)))
+        ((string= "-k" url)
+         (setf *kiosk-mode* t))
 
-      ;; create the location to visit
-      (make-location  :host (pop host-port)
-                          
-                      ;; default to port 70 if not supplied
-                      :port (if host-port ;; <- empty if no port given
-                                (parse-integer (car host-port))
-                                70)
-
-                      ;; if type is empty we default to "1"
-                      :type (let ((type (pop infos)))
-                              (if (< 0 (length type)) type "1"))
+        (t
+
+         (let ((url (if (search "gopher://" url)
+                        (subseq url 9)
+                        url)))
+
+           ;; splitting with / to get host:port and uri
+           ;; splitting host and port to get them
+           (let* ((infos      (split url #\/))
+                  (host-port (split (pop infos) #\:)))
+
+             ;; create the location to visit
+             (make-location  :host (pop host-port)
+                             ;; default to port 70 if not supplied
+                             :port (if host-port ;; <- empty if no port given
+                                       (parse-integer (car host-port))
+                                       70)
+
+                             ;; if type is empty we default to "1"
+                             :type (let ((type (pop infos)))
+                                     (if (< 0 (length type)) type "1"))
                           
-                      ;; glue remaining args between them
-                      :uri (format nil "~{/~a~}" infos)))))
+                             ;; glue remaining args between them
+                             :uri (format nil "~{/~a~}" infos)))))))
 
 (defun get-argv()
   "Parse argv and return it"
-  #+sbcl
-  (cadr *posix-argv*)
   #+ecl
-  (car (last (cdr (si::command-args)))))
+  (cdr (si::command-args)))
 
 (defun user-input(input)
   (cond
@@ -526,11 +519,13 @@
          do
            (formatted-output line)
 
+
          ;; split and ask to scroll or to type a command
            (when (= row rows)
              (setf row 0)
-             (format t "~a   press enter or a shell command ~a : "
+             (format t "~a~a   press enter or a shell command ~a : "
                      (get-color 'bg-black)
+                     (if *kiosk-mode* "KIOSK" "")
                      (get-color 'reset))
              (force-output)
              (let ((first-input (read-char *standard-input* nil nil t)))
@@ -659,7 +654,8 @@
 
 (defun display-prompt()
   (let ((last-page (car *history*)))
-    (format t "gopher://~a:~a/~a~a (~as) / (p)rev (r)edisplay (h)istory : "
+    (format t "~agopher://~a:~a/~a~a (~as) / (p)rev (r)edisplay (h)istory : "
+            (if *kiosk-mode* "KIOSK " "")
             (location-host last-page)
             (location-port last-page)
             (location-type last-page)
@@ -707,8 +703,14 @@
                                       :type "1"
                                       :uri argv))
                      ;; it's not a file, create a location
-                     (parse-url argv))
-                 (make-location :host "gopherproject.org" :port 70 :uri "/" :type "1")))))
+                     ;; it's either a list with parameters or a location
+                     (if (listp argv)
+                         (car (last (loop for element in argv collect (parse-url element))))
+                         (parse-url argv)))))))
+
+      ;; if we didn't passed a url as parameter, use a default
+      (if (not (location-p destination))
+          (setf destination (make-location :host "gopherproject.org" :port 70 :uri "/" :type "1")))
 
       ;; is there an output redirection ?
       (if (ttyp)
diff --git a/extension.c b/extension.c
deleted file mode 100644
index 498529d..0000000
--- a/extension.c
+++ /dev/null
@@ -1,17 +0,0 @@
-#include <limits.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-
-/**
- * @brief Get the height of the terminal in term of visible lines
- * @return the height of the terminal or UINT_MAX in case of error
- */
-unsigned int getTerminalHeight()
-{
-    struct winsize w;
-    if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) < 0) {
-        return UINT_MAX;
-    }
-
-    return w.ws_row;
-}
diff --git a/interactive-test.exp b/interactive-test.exp
deleted file mode 100644
index 8472b55..0000000
--- a/interactive-test.exp
+++ /dev/null
@@ -1,116 +0,0 @@
-proc user_input {} {
-
-    expect "clic => "
-
-    send "garbage\n"
-    expect "clic => "
-    send ". . ~. ~ .\n"
-    expect "clic => "
-
-    send "r\n"
-    expect "clic => "
-
-    send "help\n"
-    expect "clic => "
-    
-    send "5\n"
-    expect "clic => "
-    
-    send "p\n"
-    expect "clic => "
-
-    send "19\n"
-    expect " : "
-    send "\nr\n"
-    expect " : "
-
-    send "p\n"
-    expect "clic => "
-
-    send "r\n"
-    expect "clic => "
-    
-    send "h\n"
-    expect "clic => "
-    
-    send "a\n"
-    expect "clic => "
-    
-    send "b\n"
-    expect "clic => "
-}
-
-spawn ./clic gopher://bitreich.org
-set running [user_input]
-send "x\n"
-expect eof
-
-
-spawn sbcl
-expect "* "
-
-send "(require :sb-cover) (require :sb-bsd-sockets)\n"
-expect "* "
-
-send "(declaim (optimize sb-cover:store-coverage-data))\n"
-expect "* "
-
-send "(compile-file \"clic.lisp\")\n"
-expect "* "
-
-send "(load \"clic.fasl\")\n"
-expect "* "
-
-send "(setf *offline* t)\n"
-expect "* "
-
-send "(main)\n"
-set running [user_input]
-send "(pop *history*) (p) (r)\n"
-expect "* "
-
-send "19\n"
-expect " : "
-send "q\n"
-expect "* "
-
-send "(main)\n"
-expect "clic => "
-
-send "exit\n"
-expect "* "
-
-
-# add an argv to test argv parsing
-send "(setf *posix-argv* '(\"sbcl\" \"gopher://bitreich.org/0/documents/bitreich-manifesto.md\"))\n"
-expect "* "
-
-send "(main)\n"
-expect " : "
-send "q\n"
-expect "* "
-
-
-# add an argv to test argv parsing
-send "(setf *posix-argv* '(\"sbcl\" \"bitreich.org/1/usr/solene/\"))\n"
-expect "* "
-send "(main)\n"
-expect "clic => "
-send "q\n"
-expect "* "
-
-
-# add an argv to test argv parsing
-send "(setf *posix-argv* '(\"sbcl\" \"bitreich.org:70/\"))\n"
-expect "* "
-send "(main)\n"
-expect "clic => "
-send "q\n"
-expect "* "
-
-
-send "(sb-cover:report \"report/\")\n"
-expect "* "
-
-send "(quit)\n"
-expect eof
diff --git a/make-binary.lisp b/make-binary.lisp
index 510080f..f2048ce 100644
--- a/make-binary.lisp
+++ b/make-binary.lisp
@@ -1,6 +1,4 @@
 ;; ecl produces a linked binary to ecl shared library
-;; sbcl produces a static binary (~ 10Mb with compression / 70Mb without)
-
 (require 'asdf)
 #+ecl
 (require 'cmp)
@@ -10,20 +8,6 @@
 (progn
   (compile-file "clic.lisp" :system-p t)
   (c:build-program "clic" :epilogue-code '(progn (handler-case (main)  (condition () (quit)))) :lisp-files '("clic.o")))
-#+sbcl
-(progn
-  (require 'sb-bsd-sockets)
-  (sb-ext:disable-debugger)
-  (load "clic.lisp")
-  #+sb-core-compression
-  (sb-ext:save-lisp-and-die "clic"
-			    :executable t
-			    :compression 5
-			    :toplevel 'main)
-  #-sb-core-compression
-  (sb-ext:save-lisp-and-die "clic"
-			    :executable t
-			    :toplevel 'main))
 
 (format t "INFO => Compilation done (or at least it should be)~%")
 (quit)
diff --git a/run-test.sh b/run-test.sh
deleted file mode 100644
index d3aac3a..0000000
--- a/run-test.sh
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/bin/sh
-
-LISP=$1
-
-expect -f interactive-test.exp
-
-${LISP} --load clic.lisp --load test.lisp
-
-./clic gopher://bitreich.org:70/0/  | md5sum -
-./clic bitreich.org:70/0/  | md5sum -
-./clic bitreich.org/0/  | md5sum -
-echo "/" | nc bitreich.org 70 | md5sum -
-
-
diff --git a/test.lisp b/test.lisp
deleted file mode 100644
index 1f97d57..0000000
--- a/test.lisp
+++ /dev/null
@@ -1,35 +0,0 @@
-;; we can write scenario here
-
-(print (parse-url "gopher://perso.pw:70/0/"))
-(print (parse-url "gopher://perso.pw/0/a"))
-(print (parse-url "perso.pw/0/some/uri.txt"))
-(print (parse-url "perso.pw"))
-(print (parse-url "perso.pw:70"))
-
-
-(setf *bookmark-file* "bookmark-test")
-(load-bookmark)
-(p)
-(g 1)
-(add-bookmark)
-(getpage "bitreich.org" 70 "/")
-(display-buffer "1")
-(g 7) ;; going to radio
-(g 1) ;; going back
-(g 21) ;; banana !
-(p) ;; going back
-(g 15)
-(g 1)
-(p)
-(p)
-(add-bookmark)
-(show-bookmarks)
-(g 1)
-
-(print *links*)
-
-(print *history*)
-(format t "~%")
-
-
-(quit)