Previous Up Next

My life as an hacker


Notice: I am not someone who breaks into computers and such. I am someone that likes to play with computers and write programs. It is sad that nowadays almost everybody gives the term hacker a different meaning from its original definition.

It is useless to ask me for help with breaking passwords and such. I have no experience with such things, and even if I could, I will not help you, for the simple reason that I am not for hire for this kind of work.

A picture
of me in my
cyberpunk
t-shirt
As a young boy I already displayed a great interest in electricity and electronics, and did I dream about having my own computer center in the future, as some drawings indicated. My very first contact with real computers came through my cousin Frans Faase, who gave me a paper tape with one of his programs. At home I tried to decode this tape by hand, and got some of the lines decoded. I think it was part of an Algol 60 program. And because we happen to have the same (calling) name, I also adopted his account name at the university: FAAF, and used it whenever I dreamed about doing something with computers.

Henk Koppelaar: Algol 60

My life as a hacker really started in high school, when on December 9, 1977, during an outing with our class, I met Henk Koppelaar through one of my teachers. It was during a dinner in a Chinese restaurant that he concluded that I must be good with computers, after he heard I was good in everything in school except languages. Later that evening, at his home, he showed me some books about Artificial Intelligence. In March 1978, I got a book about Algol 60, and I started to write some programs. On May 5, I went to the Academic Computer Centre Utrecht (ACCU), where I met with Henk. He shows me around and taught me how to use the Cyber main frame (using NOS/BE 1.4 LVL 518*10). I had to use punch cards to run programs. Henk was using a simulation program, where each line contains a simulation rule. Henk told me that he sometimes shuffles the punch cards just before putting them in the card reader, just to baffle the others, because the order of the rules does not matter. I tried to run one of my own Algol 60 programs, but not which much success.

In the months that follow, I receive several letters for Henk, and also got some more books (including A Comparative study of Programming Languages). He also told me about recursive functions. On June 13, I designed my first programming language, which was a functional programming language using recursion. The next Monday, I also got the idea of writing a program for a "artificial brain" (neural network) with 84 nodes.

Summer of 78: Fortran on a Cyber main frame

On Tuesday, June 20, 1978, Henk phoned me up to tell me had a program, called SOCPAC, in IBM Fortran that he wanted to be ported to the Cyber. The next day, I went to his office to collect the box with approximately 1500 punch cards and found my way to the ACCU, and started working. At first I would load the whole deck of cards repeatedly. Soon I found I could store them, and edit them by giving commands that would remove or add lines at a time. On the next Friday, I also used a terminal to make some edits, and I showed my parents around the ACCU. Every time when I ran a job, I would sit down in front of a monitor showing the different queues of the main frame; the input, the running and the printing queue. I used the FIBMCDC conversion program to convert the program from IBM Fortran to CDC Fortran dialect, which costed 900000 Kws (Kilo word seconds??). That summer I learned Fortran, the batch language and the editing language Update mostly by myself. After having gone to England, I got the program running in August. Henk gave me the book `Finite Mathematics' by Seymour Lipschutz as a reward for my work.

4th World Congress of Cybernetics and Systems

This congress was held at Amsterdam, August 22-25, 1978. When Henk Koppelaar had to present a talk there, he invited me to join him on August 24. This became the first computer science conference I attended. At the end of the day, I also attend a chess match between Roland Lever and the Russian chess program Kaissa.

LISP 1.5

When I was in England that summer, on a language course, I bought the LISP 1.5 Programmer's Manual by John McCarthy from Dillons in London on July 21, because Henk had told me that it was the language for Artificial Intelligence. (Remember Eliza?) Of course, I read this book, and that is how I learned LISP. (Read a discussion about the origin of CAR and CDR, if you like.)

Because Henk had a budget on the computer that he was afraid to lose, he let me use it freely. So in the years that followed, I often went to Utrecht to either try out some kind of Fortran program, or to work with LISP. In Fortran I wrote my first program that could be used to count Hamilton paths in a square grid graph. (Of course, I did not know that they were called Hamilton paths at that time.) I wrote my own shortest path LISP function before I saw Dijkstra's algorithm for this. (I also wrote a program to find all the shortest paths in Fortran of order n^2 log(n), which is also known as Floyd's algorithm.) I wrote some list matching functions in LISP, as an extension to string matching ideas that I found in a language called METEOR that Henk and a student of him worked on. Finally, I managed to write a recursive-decent LL(1) compiler-compiler in LISP that generated LISP. This program consisted of about one thousand lines of LISP. If you wanted to use it you had to make a file that would contain:

The compiler-compiler would read the grammar rules, and based on these define some LISP functions that would form the compiler. These functions would then read the remaining of the input according the grammar rules and execute the generated code, consisting of some LISP functions. I did this without any books about compilers or compiler-compilers. Sadly enough, I lost the code. I also wrote a set of functions for formatting text and (a primitive form of) plotting to an ASCII file. (And of course, I tried to write a LISP interpreter in Fortran.)

Studying computer science

In my freshman year I learned Algol 68 (the most academical program language, ever made) and Pascal (which was initially only intended as a toy-language for a compiler construction course). (Algol 68 compilers are still being developed, I found out recently.)

One of my room mates bought a Acorn Atom, a home computer build around a 6502 processor. It is a fairly unknown machine made by the British Acorn company, which had a very nice dialect of Basic, that was designed rather orthogonal. It also had a build in assembler, which I started to use soon after I discovered it. I wrote a Hamilton path counting program in machine language, which took (at that time) almost a complete day to count the number of Hamilton paths in a grid of 7 by 7 that started in one of the corners. It found around 1.5 million paths. The computer was also used for some serious work. I developed a dorm administration program, which was used for calculating we had to pay each other with respect to the use of the telephone, coffee and joint meals. Ssomewhere in my third year, I also wrote a cross-assembler that generated code for a 6809 processor.

The Atari 800 XL

The Atari 800 XL is another home computer build around the 6502. On this we (a roommate and me) wrote our first complete compiler for a small language to 6502 machine code. It was written in Basic. The first thing we did when it was ready, was writing the compiler in the language and compile it with the compiler written in Basic. At the end this took around 20 minutes, but we got our compiler written in machine code. (A classical example of boots-trapping.)

The Atari 1000 ST

This we got at our dorm, only at the end of my study. As it had colour graphics I invested a lot of time in writing a program in GfA-Basic that could generated Mandelbrot fractals, in a way that you quickly get an impression of how the picture was going to look, without having to calculate all dots (line by line).

Another project I did was writing the software for an installation of an artist, which consisted of three televisions. These three televisions where put side-by-side, where the middle one could spin around the centre of the screen. The sequence of events would start with showing a Dutch soccer player (Koeman) kicking a ball in the direction of the centre screen. Then the centre screen would start spinning and display a bouncing ball. At some moment this ball would fly out to one of the screens on the outside, where a reverse slide show of the soccer player would catch the ball.
An Atari ST was used to read the position of the middle television by means of the joystick interface, and control the speed and direction of the motor attached to the middle television. The video output of the Atari was switched between the three televisions. Both the sensors and the accurators were rather primitive: only 16 different positions could be detected, and the motor control used only 4 levels (including off), which were not linear. The motor would not start running at the lower levels. The most difficult part turned out to be the controlling of the turning speed of the motor.
The installation was shown at several art-displays in Holland.

Master thesis

With all my previous experiences with compilers and compiler-compilers, it was to be expected that I would do something like that for my master thesis. My master thesis got the (horrible) title: An attribute evaluator generator. It was intended to become part of a compiler-compiler system, and consisted of a Pascal program that would generate Pascal code for attribute evaluation in Abstract Program Trees. In the three years after my graduation, I worked part-time at the University of Twente on finishing the program and writing the documentation for it. Up to now, its my best documented program, which sadly enough, has never been used, or read by someone, as far as I know. It was the first big program that I wrote, which consisted of about 500K of source code. The documentation consist of a technical report describing the functional specification of the program, and a technical report containing the source code and it documentation. I also worked on a variant called Propertied Abstract Trees or PAT for short.

Email and Relay

When I started to work at the University, it was also the first time I came in contact, what is now known as the Internet. At that time it consisted of a number of loosely connected networks, such as ARPA and EARN. The oldest email I have kept was sent to me on February 27, 1987 by Albert Nymeyer from Australia. My UUCP email address from that time was mcvax!utrcu1!utrinu!fransjf. My EARN email address was faase@hentht5.bitnet.

Besides email, I also made use of Relay, an early predecessor of IIRC. It was a simple command-line oriented interface. I did spend some time writing a Turbo Pascal program implementing a little better interface. This program would divide the screen into three parts. The top half would contain the list of participants, the lower half the lines that people wrote, and the bottom line was used as a command line. In coming status change messages (people joining or leaving the channel) were not displayed in the lower half but used to update the list in the top half of the screen.

PostScript

During this time, I also discovered that PostScript is a programming language. Here are some of my PostScript programs based on the ones that I wrote then: (Please, modify these before printing, as they contain endless loops!)

Working

Only three years after I graduated, I started working in the real world (with PC's), which was a refreshing experience, because I had to learn many new things. So far, I had only used Pascal, now I learned C, which since than became my prime programming language, and which I still use for all my private hacking. In the four years that I worked at the software company, I learned a lot about hacking.

Because I was working at many different projects, I often had to change the config.sys and the autoexec.bat files. Not soon, I wrote a the project.bat batch file, which would do this for me. It makes us of the program getjn, which asks a Yes/No question.

AutoLISP

One time I had to write a program in AutoLISP (part of AutoCAD) that had to read many small tables with information from external files. I decided to only read this files on demand, and use a LISP function that would redefine itself after having read the table, in such a way that it would just return the contents of the table as a single value. Such a function would look like:
(defun read_table_a ( / v)
(setq v (read_table 'format_fn "a.txt"))
(eval (list 'defun 'read_table_a '() (list 'quote v)))
)
And because I had many of these tables, I defined a LISP function that could define them, based on a file name, and a format description (in the form of a LISP function). To get the above definition one would call:
(def_read_table 'read_table "a.txt" 'format_fm)
This function is a function that defined functions that can redefine themselves. The function was loaded with quote, list and eval functions, but it worked. It looks like:
(defun def_read_table (fn filename format)
(eval
(list 'defun fn '( / v)
(list 'setq 'v (list 'read_table (list 'quote format) filename))
(list 'eval (list 'list ''defun (list 'quote fn) ''() '(list 'quote v)))
) )) 
The LISP function read_table was a function that read the input file, line by line, ignoring commented lines starting with percent-sign. Each line was converted to list of strings with the `words' on the line. The format function would then be applied to this list of strings to return a row in the table. I leave it up to the reader to define this LISP function.

Export/import SQL script

One day a colleague of mine, needed to make some test input, based on the contents of an SQL database. So, he wanted to have an SQL select statement that would return insert statements with the contents of a table. So, I wrote something like:
select 'insert into TAB1 
values('||decode(KEY,NULL,'NULL',KEY)
||','||decode(NAME1,NULL,'NULL',''''||NAME1||'''')
||','||decode(NAME2,NULL,'NULL',''''||NAME2||'''')
||','||decode(NUM1,NULL,'NULL',NUM1)
||');' from TAB1;
This SQL script when executed will output for each row of the table TAB1 an insert statement, assuming that the table has the four columns: KEY, NAME1, NAME2 and NUM1, where KEY and NUM1 are numeric and the other fields strings. And when I had written this, he wanted to have a SQL statement that would return this SQL statement, given the name of the table (TAB1 in this example), using the contents of the data-dictionary tables. So, I wrote:
select decode(column_id, 
1, 'select ''insert into TAB1 values(''||',
'||'',''||') ||
'decode(' || 
column_name || 
',NULL,''NULL'',' ||
decode(data_type, 
'CHAR', '''''''''||'||column_name||'||''''''''',
column_name) ||
')'
from user_tab_columns
where table_name = TAB1
order by column_id;
select '||'');'' from TAB1;' from dual;
If this script is executed it will output the first select statement I wrote, assuming the table user_tab_columns contains the table definition of the above given definition of table TAB1. And when we got this, he wanted to have a script that would return the above two select statements for each table in the database (again using the data dictionary tables). Finally, we managed to do this using a single SQL*Plus (of Oracle) script, using the ability of SQL*Plus to redirect its output to a file, and to execute files. The final script looked like this:
set heading off
set feedback off
set linesize 90
set pagesize 2000
spool e__.sql
select 'spool exps.sql ' from dual;
select
'select decode(column_id, 1,'||
'''select ''''insert into '||table_name||' values(''''||'',',
'''||'''',''''||'')||'||
'''decode(''||column_name||'',NULL,''''NULL'''',''||',
'decode(data_type,''CHAR'','||
'''''''''''''''''''||''||column_name||''||'''''''''''''''''',',
'column_name)||'')'''||
'from user_tab_columns '||
'where table_name = '''||table_name||'''',
' order by column_id; ',
'select ''||'''');'''' from '||table_name||';'' from dual;'
from user_tables;
select 'spool off' from dual;
spool off
set linesize 120
start e__
If this script is executed the output of the select statements will to spooled to the file e__.sql, which will contain two select statements for each table name mentioned in the table user_tables. Secondly, the script will execute the e__.sql script. The e__.sql script will generate one select statement for each table in the file exps.sql. To generate a script import.sql containing an insert statement for each single row in the database, we have to execute the following commands:
spool import.sql
start exps
spool off
Thus you only need SQL*Plus to make a dump of a database, and import it in another instance of the database, with the added functionality of being able to edit the dump.

Implementation of a fast variant of the bubble sort

Bubble sort, can be considered as the most simple sort algorithm, but it is often characterised as not being very optimal. C-libraries often contain the function qsort() which is (in most cases -- don't let the name fool you) an implementation of the faster Quick-sort algorithm. What many people don't know is that this is a recursive algorithm, which can behave bad on an (almost) sorted array, and could lead to unwanted stack-overflows. Of course, proper implementations should not cause stack-overflows, and would not show bad behaviour on an (almost) sorted array by selecting a good `pivot' element. As this once happened to me (with the qsort() of an old version of MSC), I wrote a faster bubble sort function, based on some ideas that I read in some magazine somewhere. (Don't ask me which magazine. I have a good memory for algorithms, but a bad memory for data.) First of all bubble sort can be improved by using alternating passes. Secondly, it can be improved by starting comparing pairs of elements that are further away from each other. The algorithm I implemented here, starts of with comparing pairs in each half of the array, and reduces the distance after each pass. The distance is reduced faster, depending how many elements were exchanged. Although this algorithm is not n log(n), which is the optimal lower bound for sorting, it comes quite close in practice, which makes it much better than traditional bubble sort, which is n^2. Gareth McCaughan compared my program with some other sorting algorithms, wrote a small test report about it. I wrote a modified version of bsort.c, bsort_s.c, which work for arrays of simple types (like char, int and double) with the default compare operator `<'. When Lawrence Kirby made a request on comp.lang.c for (Quick) sort algorithm on list, I realized that my algorithm can be adapted for lists: bsort_l.c (Has not been tested yet). Later on, I wrote another version, which sorts the list instead of swapping the contents: bsort_rl.c.

Extending SemWare editor

My favourite editor on the DOS platform is q from SemWare. The latest version that I worked with was renamed into e. (Nice names for editors, as hackers do not like to type much.) For the last one, I wrote some extra functions in its macro language.

Other hacks

During this time I also started decoding the DWG-format that is being used by AutoCAD (Release 12). My boss had told me that some other company had taken a year to decode it. Within a month I decode half of it, the remaining only being some stupid work. A binary compare program that I had written (bfc.c) turned out to be very help full to find the main structure. So far, I have found nobody that is interested, or that would like to finish the work.

JavaScript

Lately, I have discovered JavaScript.

Converting MS Word 5.0 documents to HTML

When I wanted to convert some old MS Word 5.0 (on MSDOS) documents to the Word for Windows 97, I discovered that these old file formats are no longer recognized. Of course, I searched the web for this, but failed to find anything about this. Thus, I felt there was no other option left but to reverse engineer the Word 5.0 file format. (I vaguely remembered having seen a description of the format in some book about five years ago. I blamed myself for not buying the book then.) After some hours of puzzling, I discovered that the structure is actually not so complicated. It is even rather redundant in many ways, which made it easier to reverse engineer it for the matter. I finally managed to write a program for converting the documents into HTML. I have to admit that this program is not one of my best designed one, but what do you expect for a one time conversion program.

Reverse engineering the Quark Xpress file format

Because there are no free tools to export the contents a Quark Xpress file, I worked on reverse engineering the format by myself.

Previous projects

Currently, I do not have time to embark on any large projects, although I am often thinking about software engineering systems based on some ideas I described on the page "The Art of Programming". Some of the ideas presented there, I am trying to implement in a project, that I named the "MetaMeta" project.