home texts sources

Source code examples

Author: Yegor Samusev <yegor@samusev.pp.ru>
Modified:2010-11-22

Here I put my own source code examples for various programming languages. All of them are placed in the public domain.

Contents

Modula-2

All examples can be compiled with XDS.

Have a look at my Modula-2 links ru.

Simple CGI application

Code:

MODULE SimpleCGIApplication;

  FROM STextIO IMPORT WriteString;
  FROM Strings IMPORT Concat;

  IMPORT ProgEnv; (* XDS only *)

  CONST
    CR = CHR(0DH);
    LF = CHR(0AH);
    CRLF = ARRAY OF CHAR {CR, LF};

  PROCEDURE WriteHeader(FieldName, FieldValue: ARRAY OF CHAR);
  VAR
    Buf: ARRAY [1..70] OF CHAR;
  BEGIN
    Concat(FieldName, ": ", Buf);
    Concat(Buf, FieldValue, Buf);
    Concat(Buf, CRLF, Buf);
    WriteString(Buf);
  END WriteHeader;

  PROCEDURE WriteEnvString(Name: ARRAY OF CHAR);
  VAR
    Buf: ARRAY [1..70] OF CHAR;
    EnvValue: ARRAY [1..30] OF CHAR;
  BEGIN
    IF ProgEnv.StringLength(Name) # 0 THEN
      ProgEnv.String(Name, EnvValue);
      Concat(Name, " = ", Buf);
      Concat(Buf, EnvValue, Buf);
      Concat(Buf, CRLF, Buf);
      WriteString(Buf);
    END;
  END WriteEnvString;

BEGIN
  WriteHeader("Content-Type", "text/plain");
  WriteString(CRLF);

  WriteEnvString("SERVER_SOFTWARE");
  WriteEnvString("SERVER_NAME");
  WriteEnvString("GATEWAY_INTERFACE");
  WriteEnvString("SERVER_PROTOCOL");
  WriteEnvString("SERVER_PORT");
  WriteEnvString("REQUEST_METHOD");
  WriteEnvString("HTTP_ACCEPT");
  WriteEnvString("PATH_INFO");
  WriteEnvString("PATH_TRANSLATED");
  WriteEnvString("SCRIPT_NAME");
  WriteEnvString("QUERY_STRING");
  WriteEnvString("REMOTE_HOST");
  WriteEnvString("REMOTE_ADDR");
  WriteEnvString("REMOTE_USER");
  WriteEnvString("AUTH_TYPE");
  WriteEnvString("CONTENT_TYPE");
  WriteEnvString("CONTENT_LENGTH");
END SimpleCGIApplication.

FreeBSD system call

Don't forget to pass the +M2EXTENSIONS argument to the Modula-2 compiler.

Code:

MODULE FreeBSDSystemCall;

  FROM Strings IMPORT Concat, Length;
  FROM STextIO IMPORT WriteString, WriteLn;
  FROM SWholeIO IMPORT WriteInt;

  TYPE
    size_t = CARDINAL;

  CONST
    LF = ARRAY OF CHAR {CHR(0AH)};

  VAR
    d: INTEGER;
    buf: ARRAY[1..16] OF CHAR;
    nbytes: CARDINAL;
    Val: INTEGER;

  PROCEDURE write(d: INTEGER; buf: ARRAY OF CHAR; nbytes: size_t): INTEGER;
  CONST
    SC_WRITE = 4;
  VAR
    Val: INTEGER;
  BEGIN
    ASM
      mov     eax,SC_WRITE
      push    nbytes
      push    DWORD PTR buf
      push    d
      push    eax
      int     080H
      add     esp,16
      mov     [Val],eax
    END;
    RETURN Val;
  END write;

BEGIN
  d := 1;
  Concat("Hello world!", LF, buf);
  nbytes := Length(buf);

  Val := write(d, buf, nbytes);
  WriteString("Return value of write(): ");
  WriteInt(Val, 1);
  WriteLn;
END FreeBSDSystemCall.

rep

rep (AKA librep) is a dialect of Lisp and Scheme.

Have a look at my rep links ru.

Tiny HTTP client

It supports only GET requests (and maybe some other).

Code:

(require 'rep.io.sockets)
(define (raw-http-client host
                         #!key (method 'get) (port 80) (path "/") (secs 10))
  (let* ((method (string-upcase (symbol-name method)))
         (stream (make-string-output-stream ""))
         (socket (socket-client host port stream)))
    (write socket (concat method " " path " HTTP/1.1\r\n"
                          "Host: " host ":" (number->string port) "\r\n"
                          "Connection: close\r\n\r\n"))
    (accept-socket-output-1 socket secs)
    (close-socket socket)
    stream))

Test:

user> (raw-http-client "fidoman.ru" #:method 'head)
("HTTP/1.1 200 OK\015\012Date: Mon, 21 Jun 2010 20:13:26 GMT\015\012Server: Apac
he/2.2.9 (Debian)\015\012Last-Modified: Thu, 04 Sep 2008 10:08:50 GMT\015\012ETa
g: \"3dd68-1ba-4560f23aed080\"\015\012Accept-Ranges: bytes\015\012Content-Length
: 442\015\012Connection: close\015\012Content-Type: text/html; charset=utf-8\015
\012\015\012" . 269)

Daytime server

It's a dirty example implementing the Daytime Protocol (RFC 867). It's dirty because you can't normally close a socket. The server runs in a forever loop. :)

Code:

(require 'rep.io.sockets)
(define (daytime-server #!key host (port 13) format)
  (let ((socket
         (socket-server host
                        port
                        (lambda (socket)
                          (let ((client (socket-accept socket)))
                            (write client
                                   (concat (current-time-string nil format)
                                           "\r\n"))
                            (close-socket client))))))
    (while t (accept-socket-output-1 socket 10))))

Run:

user> (daytime-server #:host "127.0.0.1" #:port 1313 #:format "%Y-%m-%d %H:%M:%S")

Test:

%nc 127.0.0.1 1313
2010-06-23 23:42:10

Scheme

Please read my notes about Scheme and have a look at my links ru.

Simple HTTP client

It supports GET and POST (it isn't well tested) requests. I'm sure you can write better.

Chicken:

(require-extension srfi-13)
(require-extension tcp)

(define (download input-port buffer-length content)
  (let ((buffer (read-string buffer-length input-port)))
    (if (string=? buffer "")
        content
        (download input-port
                  buffer-length
                  (string-concatenate (list content buffer))))))

(define (raw-http-client host #!key (port 80) (method 'get) (path "/")
                         (body "") (buffer-length 4096))
  (let* ((method (string-upcase (symbol->string method)))
         (base-headers (string-concatenate
                        (list method " " path " HTTP/1.1\r\n"
                              "Host: " host ":" (number->string port) "\r\n"
                              "Connection: close\r\n")))
         (query (string-concatenate
                 (if (string= method "POST")
                     (list base-headers
                           (string-concatenate
                            (list "Content-Length: "
                                  (number->string (string-length body))
                                  "\r\n\r\n"))
                           body)
                     (list base-headers "\r\n")))))
    (let-values (((input output) (tcp-connect host port)))
      (write-string query (string-length query) output)
      (download input buffer-length ""))))

Run:

> (raw-http-client "fidoman.ru" path: "/robots.txt" buffer-length: 83)
"HTTP/1.1 404 Not Found\r\nDate: Tue, 29 Jun 2010 22:42:58 GMT\r\nServer: Apache
/2.2.9 (Debian)\r\nContent-Length: 283\r\nConnection: close\r\nContent-Type: tex
t/html; charset=iso-8859-1\r\n\r\n<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0/
/EN\">\n<html><head>\n<title>404 Not Found</title>\n</head><body>\n<h1>Not Found
</h1>\n<p>The requested URL /robots.txt was not found on this server.</p>\n<hr>\
n<address>Apache/2.2.9 (Debian) Server at fidoman.ru Port 80</address>\n</body><
/html>\n"

Threading

Here are simple examples that show how to start threads. First of all we define a do-something function:

(define (display-numbers from till)
  (do ((n from ((if (> from till) - +) n 1)))
      ((= n till))
    (display n)
    (display " ")))

I'm sure you guess that it just displays numbers. :) Ok. Then we start two threads and every thread will execute this function but with different arguments. Because we have various Scheme implementations, we also have different ways to start threads but note that there is the “SRFI 18: Multithreading support” document and some Schemes follow this way.

Chicken (SRFI 18):

(require-extension srfi-18)
(let ((thread-1 (make-thread (lambda () (display-numbers 1000 2000))))
      (thread-2 (make-thread (lambda () (display-numbers 2000 3000)))))
  (begin (thread-start! thread-1)
         (thread-start! thread-2)
         (thread-join! thread-1)
         (thread-join! thread-2)))

Guile:

; Example #1
(let ((thread-1 (make-thread (lambda () (display-numbers 1000 2000))))
      (thread-2 (make-thread (lambda () (display-numbers 2000 3000)))))
  (begin (begin-thread thread-1 thread-2)
         (join-thread thread-1)
         (join-thread thread-2)))

; Example #2
(begin (call-with-new-thread (lambda () (display-numbers 1000 2000)))
       (call-with-new-thread (lambda () (display-numbers 2000 3000))))

Scheme 48:

Don't forget to do in REPL:

> ,open threads

Run:

(begin (spawn (lambda () (display-numbers 1000 2000)))
       (spawn (lambda () (display-numbers 2000 3000))))

N.B.: Scheme 48 is not a scripting language.