Tuesday, April 24, 2012

Displaying special characters the hard way


Back in 1991 a programming language called Clipper (version Summer'87) was a popular choice for making simple business applications for IBM PC computers. Clipper was a specialised language designed to easily create business forms of 25 rows by 80 columns of characters. It was also very simple to read and write data using dBase IV format dbf files.

It had one tiny problem back then - it did not handle special Polish characters: ĄĆĘŁŃÓŚŹŻ, which at that time were encoded typically in the Mazovia code page.

Luckily, Clipper was extensible through the assembly language, so somebody wrote this little 8086 library to write and read characters using processor interrupts. I don't know who wrote it, because there was no author in the file, and every Clipper programmer had the source, so I assume it was, and is, in the public domain. The version presented here has been slightly updated by me, mainly by adding comments.

Please note: this program is very fragile and dangerous: inputs are not validated, which makes buffer overrun a possibility.

Clipper commands:
SCREENSTR read characters from SCREEN to Clipper STRing.
STRSCREEN write characters from Clipper STRing to SCREEN.

Assembly functions:
__RETNI, __PARNI, _RETC, __PARC allow passing of data to/from Clipper.
__PARNI, for example, allows passing of a Clipper numeric value to the assembly language, see Nantucket's Guide to Clipper here.
__PARC places the address of a Clipper character string in DX:AX.

16 bit registers like DX can can be accessed as DH and DL - higher and lower byte. Read the guide to 8086 registers, by Thomas Scarff, and the guide to Input and Output (I/O) in 8086 by Joe Carthy for more information.

And here is the assembly code:


PUBLIC   SCREENSTR
PUBLIC   STRSCREEN

EXTRN    __RETNI:FAR
EXTRN    __PARNI:FAR
EXTRN    __RETC :FAR
EXTRN    __PARC :FAR

DGROUP   GROUP   DATASG

DATASG   SEGMENT 'DATA'
; string to return to Clipper
         RETSTR DW 80 DUP (0)  
DATASG   ENDS

_PROG    SEGMENT 'CODE'
; cs -> code, ds -> data
         ASSUME cs:_PROG,ds:DGROUP 

SCREENSTR PROC   FAR


; save registers
          push bp         
          mov bp,sp
          push ds
          push es
          push si
          push di


; get param. #1: row into dh
          mov ax,1        
          push ax
          call __PARNI
          add sp,2
          mov dh, al
          push dx


; get param. #2: col into dl
          mov ax,2        
          push ax
          call __PARNI
          add sp,2
          pop dx
          mov dl, al      


; get video page in bh
          mov ah,0fh
          int 10h         


; set cursor
          mov ah,02h
          int 10h         


; get param. #3: count into cl
          mov ax,3        
          push ax
          call __PARNI
          add sp,2
          mov cl, al
          mov ch, 0        


; di is an index for RETSTR
          mov di, 0        
          push di


; start loop1
; bh: video page, read char
loop1:    mov ah,08h        
          int 10h           


; write to RETSTR
          pop di
          mov RETSTR[di],ax 


inc. offset  
          inc di             
          inc di
          push di


; inc column
          inc dl           


; set cursor
          mov ah,02h       
          int 10h         
; loop: dec cx 
          loop  loop1      


; restore registers
          pop di           
          pop di
          pop si
          pop es
          pop ds
          pop bp


; return string
          mov dx, seg RETSTR       
          mov ax, offset RETSTR
          push dx
          push ax
          call __RETC
          add sp,4

          ret

SCREENSTR ENDP

STRSCREEN PROC   FAR

          push bp
          mov bp,sp
          push ds
          push es
          push si
          push di


; get param. #2: row
          mov ax,2         
          push ax
          call __PARNI
          add sp,2
          mov dh, al
          push dx


; get param. #3: col
          mov ax,3         
          push ax
          call __PARNI
          add sp,2
          pop dx
          mov dl, al
          push dx


; get param. #4: count
          mov ax,4         
          push ax
          call __PARNI
          add sp,2
          mov ch,0
          mov cl, al
          push cx


; get param. #1: string
          mov ax,1         
          push ax
          call __PARC  
          add sp,2
          mov es,dx
          mov bp,ax


; get video page (in bh)         
          mov ah,0Fh
          int 10h          
          mov bl,0


; write to screen
          mov ah,13h
          mov al,2
          pop cx
          pop dx
          int 10h          

          pop di
          pop si
          pop es
          pop ds
          pop bp

          ret

STRSCREEN ENDP

_prog    ENDS
         END



Friday, April 13, 2012

Silence before the Storm


I'm scared. As a civilisation, we are moving very quickly towards our total destruction.

No, I am not talking about global warming. We can deal with that. Even if we do nothing to control the amounts of greenhouse gases in the atmosphere, and it becomes unbearably hot in some places, and sea levels rise 80 meters making countries like the Netherlands and Bangladesh disappear under water, we will survive. We will relocate to higher, cooler places. We will ban combustion engines, or more likely we will get CO2 out of the air and store it underground. Climate change will be disruptive, it will be unpleasant, but we will adjust. Countries will help each other, or will fight each other, or mayhem will rein, but our civilisation will survive. We may even be better off: we may develop technologies that allow us to control the climate globally whatever the cause, and we may embark on ambitious projects like making deserts habitable by changing local climate. All good stuff.

I am talking about something much more sinister, namely: robots and AI. We blindly keep developing technologies that are a mortal danger to us. Our latest "achievement" is Boston Dynamics' newest robot: PETMAN, or as it should be called, the Terminator, because it is ghastly similar to the original killing robot.

PETMAN's development started at least a year ago under a ruse of testing soldier uniforms. It is however the first serious example of a dangerous new weapon category: a humanoid robot. These robots will be able to use anything that was designed to be used by humans, anything that has a human interface. They will walk the stairs, open doors, move things, turn on and off switches, valves, operate heavy machinery, drive tanks, fly planes. They won't need machine guns for arms. They will be able to pick up any gun and use it. This is what makes them a new weapon category. There was no such thing in the past. We were making specialised military robots: flying drones, scouting, guarding, and combat vehicles, and now we created a robot that can control them.

Can we control it? Can we control the person who will send millions of these robots on a mission? As a civilisation we have a poor track record of stopping those in power from committing crimes against humanity. We actually have laws in place that give those in power immunity and the right to secrecy.

Combined with the latest advancements in sensory input processing and AI, examples of which are Google's self-driving cars, IBM's Watson supercomputer, and Apple's Siri, we are making a weapon much more dangerous than nuclear, chemical, or biological weapons. Those weapons were dumb. We would use them once or twice, see how terrible they were, and put them away. It may not be possible to put away a million highly intelligent PETMANs that can build, repair, and recharge themselves, know exactly were they are, access any map, and all human knowledge in milliseconds. Once let out, they may not come back.

Behind many of these technologies is DARPA, and their newest robotic challenge is probably one step too far. We could ban robotic and AI development on international level before singularity happens, but will we do it?

Post scriptum: PETMAN climbing stairs...