SWAGOLX.EXE (c) 1993 GDSOFT ALL RIGHTS RESERVED 00090 ANYTHING NOT OTHERWISE CLASSIFIED 1 05-28-9313:51ALL SWAG SUPPORT TEAM BOOKISBN.PAS IMPORT 14 {π For you Programming librarians: the following Turbo Pascal Programπ will verify any ISBN (International Standard Book Number).π}π(*******************************************************************)π Program VerifyISBN; { Verify any ISBN number. Turbo Pascal }π { 1992, 1993 Greg Vigneault }ππ Var ISBNstr : String[16];π loopc, ISBNlen, M, chksm : Byte;π beginπ WriteLn; WriteLn( 'ISBN Verification v0.1, Greg Vigneault',#10);ππ if ( ParamCount <> 1 ) then begin { we want just 1 input parm }π WriteLn( 'Syntax: ISBN <ISBN#>',#7 );π Halt(1);π end;π ISBNstr := ParamStr(1); { get ISBN# String }π Write( 'Checking ISBN# ', ISBNstr );π { eliminate any non-digit Characters from the ISBN String... }π ISBNlen := 0;π For loopc := 1 to orD( ISBNstr[0] ) doπ if ( ISBNstr[ loopc ] in ['0'..'9'] ) then beginπ inC( ISBNlen );π ISBNstr[ ISBNlen ] := ISBNstr[ loopc ];π end;π { an 'X' at the end of the ISBN affects the result }π if ( ISBNstr[ orD( ISBNstr[0] ) ] in ['X','x'] )π then M := 10π else M := orD( ISBNstr[ ISBNlen ] ) - 48;π ISBNstr[0] := CHR( ISBNlen ); { new ISBN str length }π chksm := 0;π For loopc := 1 to ISBNlen-1 doπ inC( chksm, ( orD( ISBNstr[ loopc ] ) - 48 ) * loopc );π Write( ' <--- ' );π if ( ( chksm MOD 11 ) = M )π then WriteLn( 'Okay' )π else WriteLn( 'ERRor!',#7 );π end {VerifyISBN}.π(********************************************************************)π 2 05-28-9313:51ALL SWAG SUPPORT TEAM CPAS-OBJ.PAS IMPORT 5 REYNIR STEFANSSONππ> Does anyone know of any way to convert a .TPU to a .BIN File toπ> use BIN2OBJ.EXE and then load it as an external? Any helpπ> appreciated...ππIt's a bit round-the-block, but you might get some exercise out of it,πassuming you have the source code:ππ1) Smash the source into C With a code converter.ππ2) Declare the Procedures as `void far PASCAL' and the Functions asπ `appropriate_Type far PASCAL'.ππ3) Compile it With Turbo C or similar.ππ 3 05-28-9313:51ALL SWAG SUPPORT TEAM DBASE4.PRG IMPORT 39 {πHello every one... Guys and gals is there any such a thing that you canπuse turbp pascal 6 with Dbase IV.. what I heard is I can.πif yes tell me how you export or whatever to use two of thewmπtogether,,,ππYes there is! I have been using it for some time now in dBase as I useπan XT and dBase's editor is too slow when the program has quite a fewπlines (some are 5,000) and the system just kind of dies. When I use TP'sπIDE the editor is FAST!!!! So after reading the books I designed aπprogram in order to use TP as using it in the TEDIT CONFIG.DB commandπwouldn't work as it needed more memory (I only have 640k).π}πππIn dBase's setup program, under the FILES MENU enter in eitherπPRGAPPLIC (overrides Application Control in the ASSIST menu only!) orπ Entry - C:\DBASEIV\EDIT2.PRGπ Exit - emptyπ Layout - emptyπPRGCC (allows you to use OPEN CUSTOM UTILIY option under Catalog Menu).π Entry - emptyπ Exit - emptyπ Layout - C:\DBASEIV\EDIT2.PRGππI am currently using PRGAPPLIC as I do most of my work in the ControlπCenter anyhow and don't need the Application Generator. Note - PRGCCπwill not pull in a PRG file unless you change the source code to ask forπone.ππHere is the dBase program that calls Turbo Pascal:ππ* <T>Program ----> EDIT2.PRGπ* <D>Language ---> dBase IV 1.5π* <P>Author -----> P.A.T. Systems° C.1993π* <T>Creation date -> 07/22/1992π* <L>Last update ---> 01/06/1993ππ* <G>From-> Control Centerπ* <N>To---> Noneπ* <T>Subs-> Noneππ* This program invokes an External Editor such as Turbo Pascal 6.0'sπ* (TP) Desktop Editor by using the PRGAPPLIC setup in the Config.dbπ* file. Even though it is only for Entry Programs, with some trickyπ* commands we can get it to invoke an External Editor such as TP.ππ* Although I can't do any Compiling or Help Lookup (another use for theπ* Manuals), it still is a great and FAST!!!! Editor to work with.ππ* This program will work with any editor that will accept a filenameπ* as a parameter.ππ* Example TURBO filename.prg (Turbo Pascal) ORπ* WP filename.prg (Word Perfect)ππ* As I am used to TP's Editor, I wished I could use it when I wanted toπ* edit a program. Especially a long program that when loaded intoπ* dBase's editor is extremely slow, but in TP, editing is FAST!!! Andπ* with dBase IV 1.5's NEW Open Architecture, I now have a way to do it.ππ* This program uses the RUN() function to swap out memory to disk soπ* that the editor can load in. With the TEDIT command in the Config.dbπ* setup, there wasn't enough memory (on an XT) to load in the editor.π* So I read the manuals (Yes, I do read them occasionally!) and figuredπ* out a way to use an External Editor by utilizing the Control Center'sπ* NEW Open Architecture.ππ* First, copy this program into dBase's Startup Directory.ππ* You next have to change dBase's setup using DBSETUP at the DOS promptπ* and load in the current configuration and then on the Files Menuπ* change the option of PRGAPPLIC so that it readsπ* "C:\DBASEIV\EDIT2.PRG". Once done, save the new configuration andπ* exit to DOS. Then enter dBase in your usual way. Next, create orπ* edit an existing program through the Control Center's Applicationπ* Menu. The Control Center will execute this .PRG file (it willπ* automatically compile it) and load up your Editor with the programπ* ready to edit!ππ* ***Note***π* This program will only work through the Control Center. If you typeπ* "MODI COMM filename" at the DOT PROMPT, the original editor will beπ* loaded as the Open Architecture only works with the Control Centerπ* applications.ππ* Hope you enjoy this program!!!!ππ* Parameters passed from Control Center to Application Designerπ* Panel Name, Filename (Programming in dBase IV - Chapter 17, pg 4)ππPARAMETERS cPanelName, cFileNameππ* Clear screen and turn on cursorπ* (MODI COMM turns off cursor when loading and then turns it backπ* on when editing - Why? I don't know. When I invoked my editor, Iπ* found that the cursor had disappeared, so I included this Commandπ* and my cursor came back!)ππCLEARπSET CURSOR ONππ* Store Editor's filename and dBase .PRG Filename to variable forπ* Macro Executionππ* (You can enter your own Editor's file name here if you wish, justπ* include the FULL PATH NAME just in case, and don't forget the SPACE!)ππ* uncomment this line for PRGCC or it will load CATALOG FILEπ* STORE "" TO cFileNameπSTORE "D:\TP\TURBO " + cFileName TO cExecEditππ* Invoke RUN() function to swap out memoryππSTORE RUN("&cExecEdit",.T.) TO nRunππ* Change filename so we can erase .DBO file for proper compilingπ* If creating a new file, no need to erase .DBO fileππIF .NOT. ISBLANK(cFileName)π STORE SUBSTR(cFileName, 1, AT(".PRG", cFileName)) + "DBO" TO ;π cExecEditππ* Erase the .DBO fileππ ERASE &cExecEditπENDIFππ* Return directly to Control Center instead of invoking Command EditorππRETURN TO MASTERππ* Endπ 4 05-28-9313:51ALL SWAG SUPPORT TEAM FLIPLAY.PAS IMPORT 255 {$G+}ππProgram FliPlayer;ππ{ v1.1 made by Thaco }π{ (c) EPOS, August 1992 }πππConstπ CLOCK_HZ =4608; { Frequency of clock }π MONItoR_HZ =70; { Frequency of monitor }π CLOCK_SCALE =CLOCK_HZ div MONItoR_HZ;ππ BUFFERSIZE =$FFFE; { Size of the framebuffer, must be an even number }π CDATA =$040; { Port number of timer 0 }π CMODE =$043; { Port number of timers control Word }π CO80 =$3; { Number For standard Text mode }π KEYBOARD =28; { Numbers returned by PorT[$64] indicating what hardware caused inT 09/the - }π MOUSE =60; { - number on PorT[$60] }π MCGA =$13; { Number For MCGA mode }π MCGACheck:Boolean =True; { Variable For MCGA checking }π UseXMS:Boolean =True; { Variable For XMS usage }π XMSError:Byte =0; { Variable indicating the errornumber returned from the last XMS operation }ππTypeπ EMMStructure =Recordπ BytestoMoveLo, { Low Word of Bytes to move. NB: Must be even! }π BytestoMoveHi, { High Word of Bytes to move }π SourceHandle, { Handle number of source (SH=0 => conventional memory) }π SourceoffsetLo, { Low Word of source offset, or ofS if SH=0 }π SourceoffsetHi, { High Word of source offset, or SEG if SH=0 }π DestinationHandle, { Handle number of destination (DH=0 => conventional memory) }π DestinationoffsetLo, { Low Word of destination offset, or ofS if DH=0 }π DestinationoffsetHi :Word; { High Word of destination offset, or SEG if DH=0 }π end;π HeaderType =Array[0..128] of Byte; { A bufferType used to read all kinds of headers }πππVarπ Key, { Variable used to check if a key has been pressed }π OldKey :Byte; { Variable used to check if a key has been pressed }π XMSRecord :EMMStructure; { Variable For passing values to the XMS routine }π InputFile :File; { Variable For the incomming .FLI File }π Header :HeaderType; { Buffer used to read all kinds of headers }π Counter, { General purpose counter }π Speed :Integer; { Timedifference in video tics from one frame to the next }π FileCounter, { Variable telling the point to read from in the File stored in XMS }π FileSize, { Size of the .FLI-File }π FrameSize, { Variable indicating the datasize of current frame }π NextTime, { Variable saying when it is time to move on to the next frame }π TimeCounter, { Holding the current time in video tics }π SecondPos :LongInt; { Number of Bytes to skip from the start of the .FLI File when starting - }π { - from the beginning again }π Buffer, { Pointer to the Framebuffer }π XMSEntryPoint :Pointer; { Entry point of the XMS routine in memory }π SpeedString :String[2]; { String used to parse the -sNN command }π FileName :String[13]; { String holding the name of the .FLI-File }π BufferHandle, { Handle number returned from the XMS routine }π BytesRead, { Variable telling the numbers of Bytes read from the .FLI File }π FrameNumber, { Number of the current frame }π Frames, { total number of frames }π Chunks :Word; { total number of chunks in a frame }πππFunction UpCaseString(Streng:String):String;π{ takes a String and convert all letters to upperCase }πVarπ DummyString :String;π Counter :Integer;πbeginπ DummyString:='';π For Counter:=1 to Length(Streng) doπ DummyString:=DummyString+UpCase(Streng[Counter]);π UpCaseString:=DummyString;πend;πππProcedure InitMode(Mode:Word); Assembler;π{ Uses BIOS interrupts to set a videomode }πAsmπ mov ax,Modeπ int 10hπend;πππFunction ModeSupport(Mode:Word):Boolean; Assembler;π{ Uses BIOS interrupts to check if a videomode is supported }πLabel Exit, Last_Modes, No_Support, Supported;πVarπ DisplayInfo :Array[1..64] of Byte; { Array For storing Functionality/state inFormation }πAsmπ push esππ mov ah,1Bh { the Functionality/state inFormation request at int 10h }π mov bx,0 { 0 = return Functionality/state inFormation }π push ds { push DS on the stack and pop it into ES so ES:DI could be used to - }π pop es { - address DisplayInfo, as demanded of the interrupt Function }π mov di,offset DisplayInfoπ int 10hππ les di,[dWord ptr es:di] { The first dWord in the buffer For state inFormation is the address - }π { - of static funtionality table }π mov cx,Mode { Can only check For the 0h-13h modes }π cmp cx,13hπ ja No_Support { Return 'no support' For modes > 13h }ππ mov ax,1 { Shift the right Byte the right - }π { - times and test For the right - }π cmp cx,10h { - bit For knowing if the - }π jae Last_Modes { - videomode is supported - }π { - }π shl ax,cl { - }π test ax,[Word ptr es:di+0] { - }π jz No_Support { - }π jmp Supported { - }π { - }πLast_Modes: { - }π sub cx,10h { - }π shl ax,cl { - }π test al,[Byte ptr es:di+2] { - }π jz No_Support { - }ππSupported:π mov al,1 { AL=1 makes the Function return True }π jmp ExitππNo_Support:π mov al,0 { AL=0 makes the Function return True }ππExit:π pop esπend;πππFunction NoXMS:Boolean; Assembler;π{ checks out if there is a XMS driver installed, and in Case it initialize theπ XMSEntryPoint Variable }πLabel JumpOver;πAsmπ push esππ mov ax,4300h { AX = 4300h => inSTALLATION CHECK }π int 2Fh { use int 2Fh Extended MEMorY SPECifICATION (XMS) }π mov bl,1 { use BL as a flag to indicate success }π cmp al,80h { is a XMS driver installed? }π jne JumpOverπ mov ax,4310h { AX = 4310h => GET DRIVER ADDRESS }π int 2Fhπ mov [Word ptr XMSEntryPoint+0],BX { initialize low Word of XMSEntryPoint }π mov [Word ptr XMSEntryPoint+2],ES { initialize high Word of XMSEntryPoint }π mov bl,0 { indicate success }πJumpOver:π mov al,bl { make the Function return True (AH=1) or False (AH=0) }ππ pop esπend;πππFunction XMSMaxAvail:Word; Assembler;π{ returns size of largest contiguous block of XMS in kilo (1024) Bytes }πLabel JumpOver;πAsmπ mov ah,08h { 'Query free Extended memory' Function }π mov XMSError,0 { clear error Variable }π call [dWord ptr XMSEntryPoint]π or ax,ax { check For error }π jnz JumpOverπ mov XMSError,bl { errornumber stored in BL }πJumpOver: { AX=largest contiguous block of XMS }πend;πππFunction XMSGetMem(SizeInKB:Word):Word; Assembler;π{ allocates specified numbers of kilo (1024) Bytes of XMS and return a handleπ to this XMS block }πLabel JumpOver;πAsmπ mov ah,09h { 'Allocate Extended memory block' Function }π mov dx,SizeInKB { number of KB requested }π mov XMSError,0 { clear error Variable }π call [dWord ptr XMSEntryPoint]π or ax,ax { check For error }π jnz JumpOverπ mov XMSError,bl { errornumber stored in BL }πJumpOver:π mov ax,dx { return handle number to XMS block }πend;πππProcedure XMSFreeMem(Handle:Word); Assembler;πLabel JumpOver;πAsmπ mov ah,0Ah { 'Free Extended memory block' Function }π mov dx,Handle { XMS's handle number to free }π mov XMSError,0 { clear error Variable }π call [dWord ptr XMSEntryPoint]π or ax,ax { check For error }π jnz JumpOverπ mov XMSError,bl { errornumber stored in BL }πJumpOver:πend;πππProcedure XMSMove(Var EMMParamBlock:EMMStructure); Assembler;πLabel JumpOver;πAsmπ push dsπ push esπ push dsπ pop esπ mov ah,0Bh { 'Move Extended memory block' Function }π mov XMSError,0 { clear error Variable }π lds si,EMMParamBlock { DS:SI -> data to pass to the XMS routine }π call [dWord ptr es:XMSEntryPoint]π or ax,ax { check For error }π jnz JumpOverπ mov XMSError,bl { errornumber stored in BL }πJumpOver:π pop esπ pop dsπend;πππProcedure ExitDuetoXMSError;πbeginπ InitMode(CO80);π WriteLn('ERRor! XMS routine has reported error ',XMSError);π XMSFreeMem(BufferHandle);π Halt(0);πend;πππProcedure GetBlock(Var Buffer; Size:Word);π{ reads a specified numbers of data from a diskFile or XMS into a buffer }πVarπ XMSRecord :EMMStructure;π NumberofBytes :Word;πbeginπ if UseXMS thenπ beginπ NumberofBytes:=Size;π if Size MOD 2=1 thenπ Inc(NumberofBytes); { one must allways ask For a EQUAL number of Bytes }π With XMSRecord doπ beginπ BytestoMoveLo :=NumberofBytes;π BytestoMoveHi :=0;π SourceHandle :=BufferHandle;π SourceoffsetLo :=FileCounter MOD 65536;π SourceoffsetHi :=FileCounter div 65536;π DestinationHandle :=0;π DestinationoffsetLo:=ofs(Buffer);π DestinationoffsetHi:=Seg(Buffer);π end;π XMSMove(XMSRecord);π if XMSError<>0 thenπ ExitDuetoXMSError;π Inc(FileCounter,Size);π endπ elseπ BlockRead(InputFile,Buffer,Size);πend;πππProcedure InitClock; Assembler; {Taken from the FLILIB source}πAsmπ mov al,00110100b { put it into liNear count instead of divide by 2 }π out CMODE,alπ xor al,alπ out CDATA,alπ out CDATA,alπend;πππFunction GetClock:LongInt; Assembler; {Taken from the FLILIB source}π{ this routine returns a clock With occassional spikes where timeπ will look like its running backwards 1/18th of a second. The resolutionπ of the clock is 1/(18*256) = 1/4608 second. 66 ticks of this clockπ are supposed to be equal to a monitor 1/70 second tick.}πAsmπ mov ah,0 { get tick count from Dos and use For hi 3 Bytes }π int 01ah { lo order count in DX, hi order in CX }π mov ah,dlπ mov dl,dhπ mov dh,clππ mov al,0 { read lo Byte straight from timer chip }π out CMODE,al { latch count }π mov al,1π out CMODE,al { set up to read count }π in al,CDATA { read in lo Byte (and discard) }π in al,CDATA { hi Byte into al }π neg al { make it so counting up instead of down }πend;πππProcedure TreatFrame(Buffer:Pointer;Chunks:Word); Assembler;π{ this is the 'workhorse' routine that takes a frame and put it on the screen }π{ chunk by chunk }πLabelπ Color_Loop, Copy_Bytes, Copy_Bytes2, Exit, Fli_Black, Fli_Brun, Fli_Color,π Fli_Copy, Fli_Lc, Fli_Loop, Jump_Over, Line_Loop, Line_Loop2, Next_Line,π Next_Line2, Pack_Loop, Pack_Loop2;πAsmπ cli { disable interrupts }π push dsπ push es π lds si,Buffer { let DS:SI point at the frame to be drawn }ππFli_Loop: { main loop that goes through all the chunks in a frame }π cmp Chunks,0 { are there any more chunks to draw? }π je Exitπ dec Chunks { decrement Chunks For the chunk to process now }ππ mov ax,[Word ptr ds:si+4] { let AX have the ChunkType }π add si,6 { skip the ChunkHeader }ππ cmp ax,0Bh { is it a FLI_COLor chunk? }π je Fli_Colorπ cmp ax,0Ch { is it a FLI_LC chunk? }π je Fli_Lcπ cmp ax,0Dh { is it a FLI_BLACK chunk? }π je Fli_Blackπ cmp ax,0Fh { is it a FLI_BRUN chunk? }π je Fli_Brunπ cmp ax,10h { is it a FLI_COPY chunk? }π je Fli_Copyπ jmp Fli_Loop { This command should not be necessary since the Program should make one - }π { - of the other jumps }ππFli_Color:π mov bx,[Word ptr ds:si] { number of packets in this chunk (allways 1?) }π add si,2 { skip the NumberofPackets }π mov al,0 { start at color 0 }π xor cx,cx { reset CX }ππColor_Loop:π or bx,bx { set flags }π jz Fli_Loop { Exit if no more packages }π dec bx { decrement NumberofPackages For the package to process now }ππ mov cl,[Byte ptr ds:si+0] { first Byte in packet tells how many colors to skip }π add al,cl { add the skiped colors to the start to get the new start }π mov dx,$3C8 { PEL Address Write Mode Register }π out dx,al { tell the VGA card what color we start changing }ππ inc dx { at the port abow the PEL_A_W_M_R is the PEL Data Register }π mov cl,[Byte ptr ds:si+1] { next Byte in packet tells how many colors to change }π or cl,cl { set the flags }π jnz Jump_Over { if NumberstoChange=0 then NumberstoChange=256 }π inc ch { CH=1 and CL=0 => CX=256 }πJump_Over:π add al,cl { update the color to start at }π mov di,cx { since each color is made of 3 Bytes (Red, Green & Blue) we have to - }π shl cx,1 { - multiply CX (the data counter) With 3 }π add cx,di { - CX = old_CX shl 1 + old_CX (the fastest way to multiply With 3) }π add si,2 { skip the NumberstoSkip and NumberstoChange Bytes }π rep outsb { put the color data to the VGA card FAST! }ππ jmp Color_Loop { finish With this packet - jump back }πππFli_Lc:π mov ax,0A000hπ mov es,ax { let ES point at the screen segment }π mov di,[Word ptr ds:si+0] { put LinestoSkip into DI - }π mov ax,di { - to get the offset address to this line we have to multiply With 320 - }π shl ax,8 { - DI = old_DI shl 8 + old_DI shl 6 - }π shl di,6 { - it is the same as DI = old_DI*256 + old_DI*64 = old_DI*320 - }π add di,ax { - but this way is faster than a plain mul }π mov bx,[Word ptr ds:si+2] { put LinestoChange into BX }π add si,4 { skip the LinestoSkip and LinestoChange Words }π xor cx,cx { reset cx }ππLine_Loop:π or bx,bx { set flags }π jz Fli_Loop { Exit if no more lines to change }π dec bxππ mov dl,[Byte ptr ds:si] { put PacketsInLine into DL }π inc si { skip the PacketsInLine Byte }π push di { save the offset address of this line }ππPack_Loop:π or dl,dl { set flags }π jz Next_Line { Exit if no more packets in this line }π dec dlπ mov cl,[Byte ptr ds:si+0] { put BytestoSkip into CL }π add di,cx { update the offset address }π mov cl,[Byte ptr ds:si+1] { put BytesofDatatoCome into CL }π or cl,cl { set flags }π jns Copy_Bytes { no SIGN means that CL number of data is to come - }π { - else the next data should be put -CL number of times }π mov al,[Byte ptr ds:si+2] { put the Byte to be Repeated into AL }π add si,3 { skip the packet }π neg cl { Repeat -CL times }π rep stosbπ jmp Pack_Loop { finish With this packet }ππCopy_Bytes: π add si,2 { skip the two count Bytes at the start of the packet }π rep movsbπ jmp Pack_Loop { finish With this packet }ππNext_Line:π pop di { restore the old offset address of the current line }π add di,320 { offset address to the next line }π jmp Line_LoopπππFli_Black:π mov ax,0A000hπ mov es,ax { let ES:DI point to the start of the screen }π xor di,diπ mov cx,32000 { number of Words in a screen }π xor ax,ax { color 0 is to be put on the screen }π rep stoswπ jmp Fli_Loop { jump back to main loop }πππFli_Brun:π mov ax,0A000hπ mov es,ax { let ES:DI point at the start of the screen }π xor di,diπ mov bx,200 { numbers of lines in a screen }π xor cx,cxππLine_Loop2:π mov dl,[Byte ptr ds:si] { put PacketsInLine into DL }π inc si { skip the PacketsInLine Byte }π push di { save the offset address of this line }ππPack_Loop2:π or dl,dl { set flags }π jz Next_Line2 { Exit if no more packets in this line }π dec dlπ mov cl,[Byte ptr ds:si] { put BytesofDatatoCome into CL }π or cl,cl { set flags }π js Copy_Bytes2 { SIGN meens that CL number of data is to come - }π { - else the next data should be put -CL number of times }π mov al,[Byte ptr ds:si+1] { put the Byte to be Repeated into AL }π add si,2 { skip the packet }π rep stosbπ jmp Pack_Loop2 { finish With this packet }ππCopy_Bytes2:π inc si { skip the count Byte at the start of the packet }π neg cl { Repeat -CL times }π rep movsbπ jmp Pack_Loop2 { finish With this packet }ππNext_Line2:π pop di { restore the old offset address of the current line }π add di,320 { offset address to the next line }π dec bx { any more lines to draw? }π jnz Line_Loop2π jmp Fli_Loop { jump back to main loop }πππFli_Copy:π mov ax,0A000hπ mov es,ax { let ES:DI point to the start of the screen }π xor di,diπ mov cx,32000 { number of Words in a screen }π rep movswπ jmp Fli_Loop { jump back to main loop }πππExit:π sti { enable interrupts }π pop esπ pop dsπend;ππππbeginπ WriteLn;π WriteLn('.FLI-Player v1.1 by Thaco');π WriteLn(' (c) EPOS, August 1992');π WriteLn;π if ParamCount=0 then { if no input parameters then Write the 'usage Text' }π beginπ WriteLn('USAGE: FLIPLAY <options> <Filename>');π WriteLn(' '+#24+' '+#24);π WriteLn(' │ └── Filename of .FLI File');π WriteLn(' └──────────── -d = Do not use XMS');π WriteLn(' -i = InFormation about the Program');π WriteLn(' -n = No checking of MCGA mode support');π WriteLn(' -sNN = Set playspeed to NN video ticks (0-99)');π WriteLn(' ( NN=70 ≈ frame Delay of 1 second )');π Halt(0);π end;ππ For Counter:=1 to ParamCount do { search through the input parameters For a -Info option }π if Pos('-I',UpCaseString(ParamStr(Counter)))<>0 thenπ beginπ WriteLn('Program inFormation:');π WriteLn('This Program plays animations (sequences of pictures) made by Programs like',#10#13,π 'Autodesk Animator (so called .FLI-Files). The Program decodes the .FLI File,',#10#13,π 'frame by frame, and Uses the systemclock For mesuring the time-Delay between',#10#13,π 'each frame.');π WriteLn('Basis For the Program was the FliLib package made by Jim Kent, but since the',#10#13,π 'original source was written in C, and I am not a good C-Writer, I decided',#10#13,π 'to Write my own .FLI-player in Turbo Pascal v6.0.');π WriteLn('This Program was made by Eirik Milch Pedersen (thaco@solan.Unit.no).');π WriteLn('Copyright Eirik Pedersens Own SoftwareCompany (EPOS), August 1992');π WriteLn;π WriteLn('Autodesk Animator is (c) Autodesk Inc');π WriteLn('FliLib is (c) Dancing Flame');π WriteLn('Turbo Pascal is (c) Borland International Inc');π Halt(0);π end;ππ Speed:=-1;π Counter:=1;π While (Copy(ParamStr(Counter),1,1)='-') and (ParamCount>=Counter) do { search through the input parameters to assemble them }π beginπ if Pos('-D',UpCaseString(ParamStr(Counter)))<>0 then { do not use XMS For storing the File into memory }π UseXMS:=Falseπ elseπ if Pos('-N',UpCaseString(ParamStr(Counter)))<>0 then { do not check For a vga card present }π MCGACheck:=Falseπ elseπ if Pos('-S',UpCaseString(ParamStr(Counter)))<>0 then { speed override has been specified }π beginπ SpeedString:=Copy(ParamStr(Counter),3,2); { cut out the NN parameter }π if not(SpeedString[1] in ['0'..'9']) or { check if the NN parameter is legal }π (not(SpeedString[2] in ['0'..'9',' ']) and (Length(SpeedString)=2)) thenπ beginπ WriteLn('ERRor! Can not parse speed ''',SpeedString,'''.');π Halt(0);π end;π Speed:=Byte(SpeedString[1])-48; { take the first number, in ASCII, and convert it to a standard number }π if Length(SpeedString)=2 then { if there is two numbers then multiply the first With 10 and add the next }π Speed:=Speed*10+Byte(SpeedString[2])-48;π Speed:=Speed*CLOCK_SCALE; { convert the speed to number of clock tics }π end;π Inc(Counter);π end;ππ if ParamCount<Counter thenπ beginπ WriteLn('ERRor! No Filename specified.');π Halt(0);π end;ππ FileName:=UpCaseString(ParamStr(Counter));π if Pos('.',FileName)=0 then { find out if there exist a . in the Filename }π FileName:=FileName+'.FLI'; { if not then add the .FLI extension on the Filename }ππ if MaxAvail<BUFFERSIZE then { check if there is enough memory to the frame buffer }π beginπ WriteLn('ERRor! Can not allocate enough memory to a frame buffer.');π Halt(0);π end;ππ GetMem(Buffer,BUFFERSIZE);π Assign(InputFile,FileName);π Reset(InputFile,1);π if Ioresult<>0 then { has an error occured during opening the File? }π beginπ WriteLn('ERRor! Can not open File ''',FileName,'''.');π Halt(0);π end;ππ if not(MCGACheck) or ModeSupport(MCGA) thenπ InitMode(MCGA)π elseπ beginπ WriteLn('ERRor! Video mode 013h - 320x200x256 colors - is not supported.');π Halt(0);π end;ππ BlockRead(InputFile,Header,128); { read the .FLI main header }ππ if not((Header[4]=$11) and (Header[5]=$AF)) then { check if the File has got the magic number }π beginπ InitMode(CO80);π WriteLn('ERRor! File ''',FileName,''' is of a wrong File Type.');π Halt(0);π end;ππ if NoXMS then { if no XMS driver present then do not use XMS }π UseXMS:=False;ππ if UseXMS thenπ beginπ FileSize:=Header[0]+256*(LongInt(Header[1])+256*(LongInt(Header[2])+256*LongInt(Header[3])));π if XMSMaxAvail<=(FileSize+1023) SHR 10 then { is there enough XMS (rounded up to Nearest KB) availible? }π beginπ WriteLn('ERRor! not enough XMS For the File');π Halt(0);π endπ elseπ beginπ Seek(InputFile,0); { skip back to start of .FLI-File to put it all into XMS }π BufferHandle:=XMSGetMem((FileSize+1023) SHR 10); { allocate XMS For the whole .FLI File }π FileCounter:=0;π Repeatπ BlockRead(InputFile,Buffer^,BUFFERSIZE,BytesRead); { read a part from the .FLI File }π if BytesRead MOD 2=1 then { since BUFFERSIZE shoud be an even number, the only time this triggers is the last part }π Inc(BytesRead); { must be done because the XMS routine demands an even number of Bytes to be moved }π if BytesRead<>0 thenπ beginπ With XMSRecord do { put data into the XMSRecord }π beginπ BytestoMoveLo :=BytesRead;π BytestoMoveHi :=0;π SourceHandle :=0;π SourceoffsetLo :=ofs(Buffer^);π SourceoffsetHi :=Seg(Buffer^);π DestinationHandle :=BufferHandle;π DestinationoffsetLo:=FileCounter MOD 65536;π DestinationoffsetHi:=FileCounter div 65536;π end;π XMSMove(XMSRecord); { move Bytes to XMS }π if XMSError<>0 then { have any XMS errors occured? }π ExitDuetoXMSError;π Inc(FileCounter,BytesRead); { update the offset into XMS where to put the next Bytes }π end;π Until BytesRead<>BUFFERSIZE; { Repeat Until Bytes read <> Bytes tried to read => end of File }π end;π FileCounter:=128; { we continue (after reading the .FLI File into XMS) right after the .FLI main header }π end;ππ Frames:=Header[6]+Header[7]*256; { get the number of frames from the .FLI-header }π if Speed=-1 then { if speed is not set by a speed override then get it from the .FLI-header }π Speed:=(Header[16]+Integer(Header[17])*256)*CLOCK_SCALE;π InitClock; { initialize the System Clock }π OldKey:=PorT[$60]; { get the current value from the keyboard }π Key:=OldKey; { and set the 'current key' Variable to the same value }ππ GetBlock(Header,16); { read the first frame-header }π FrameSize:=Header[0]+256*(LongInt(Header[1])+256*(LongInt(Header[2])+256*LongInt(Header[3])))-16; { calculate framesize }π SecondPos:=128+16+FrameSize; { calculate what position to skip to when the .FLI is finished and is going to start again - }π { the position = .FLI-header + first_frame-header + first_framesize }π Chunks:=Header[6]+Header[7]*256; { calculate number of chunks in frame }π GetBlock(Buffer^,FrameSize); { read the frame into the framebuffer }π TreatFrame(Buffer,Chunks); { treat the first frame }ππ TimeCounter:=GetClock; { get the current time }ππ {π The first frame must be handeled separatly from the rest. This is because the rest of the frames are updates/changes of theπ first frame.π At the end of the .FLI-File there is one extra frame who handles the changes from the last frame to the first frame.π }ππ Repeatπ FrameNumber:=1; { we start at the first frame (after the initial frame) }π Repeatπ GetBlock(Header,16); { read frame-header }π FrameSize:=Header[0]+256*(LongInt(Header[1])+256*(LongInt(Header[2])+256*LongInt(Header[3])))-16; { size of frame }π if FrameSize<>0 then { sometimes there are no changes from one frame to the next (used For extra Delays). In such - }π { - Cases the size of the frame is 0 and we don't have to process them }π beginπ Chunks:=Header[6]+Header[7]*256; { calculate number of chunks in the frame }π GetBlock(Buffer^,FrameSize); { read the frame into the framebuffer }π TreatFrame(Buffer,Chunks); { treat the frame }π end;ππ NextTime:=TimeCounter+Speed; { calculate the Delay to the next frame }π While TimeCounter<NextTime do { wait For this long }π TimeCounter:=GetClock;ππ if PorT[$64]=KEYBOARD then { check if the value at the keyboard port is caused by a key pressed }π Key:=PorT[$60]; { get the current value from the keyboard }π Inc(FrameNumber); { one frame finished, over to the next one }π Until (FrameNumber>Frames) or (Key<>OldKey); { Repeated Until we come to the last frame or a key is pressed }ππ if UseXMS thenπ FileCounter:=SecondPosπ elseπ Seek(InputFile,SecondPos); { set current position in the File to the second frame }ππ Until Key<>OldKey; { Exit the loop if a key has been pressed }ππ InitMode(CO80); { get back to Text mode }ππ Close(InputFile); { be a kind boy and close the File beFore we end the Program }π FreeMem(Buffer,BUFFERSIZE); { and free the framebuffer }ππ if UseXMS thenπ XMSFreeMem(BufferHandle);πEND. 5 05-28-9313:51ALL SWAG SUPPORT TEAM GLOBALS.PAS IMPORT 146 Unit globals;ππ{ Use this Unit For Procedures, Functions and Variables that every Program youπ Write will share.π}ππInterfaceππUses π Dos;π πTypeπ str1 = String[1]; str2 = String[2]; str3 = String[3];π str4 = String[4]; str5 = String[5]; str6 = String[6];π str7 = String[7]; str8 = String[8]; str9 = String[9];π str10 = String[10]; str11 = String[11]; str12 = String[12];π str13 = String[13]; str14 = String[14]; str15 = String[15];π str16 = String[16]; str17 = String[17]; str18 = String[18];π str19 = String[19]; str20 = String[20]; str21 = String[21];π str22 = String[22]; str23 = String[23]; str24 = String[24];π str25 = String[25]; str26 = String[26]; str27 = String[27];π str28 = String[28]; str29 = String[29]; str30 = String[30];π str31 = String[31]; str32 = String[32]; str33 = String[33];π str34 = String[34]; str35 = String[35]; str36 = String[36];π str37 = String[37]; str38 = String[38]; str39 = String[39];π str40 = String[40]; str41 = String[41]; str42 = String[42];π str43 = String[43]; str44 = String[44]; str45 = String[45];π str46 = String[46]; str47 = String[47]; str48 = String[48];π str49 = String[49]; str50 = String[50]; str51 = String[51];π str52 = String[52]; str53 = String[53]; str54 = String[54];π str55 = String[55]; str56 = String[56]; str57 = String[57];π str58 = String[58]; str59 = String[59]; str60 = String[60];π str61 = String[61]; str62 = String[62]; str63 = String[63];π str64 = String[64]; str65 = String[65]; str66 = String[66];π str67 = String[67]; str68 = String[68]; str69 = String[69];π str70 = String[70]; str71 = String[71]; str72 = String[72];π str73 = String[73]; str74 = String[74]; str75 = String[75];π str76 = String[76]; str77 = String[77]; str78 = String[78];π str79 = String[79]; str80 = String[80]; str81 = String[81];π str82 = String[82]; str83 = String[83]; str84 = String[84];π str85 = String[85]; str86 = String[86]; str87 = String[87];π str88 = String[88]; str89 = String[89]; str90 = String[90];π str91 = String[91]; str92 = String[92]; str93 = String[93];π str94 = String[94]; str95 = String[95]; str96 = String[96];π str97 = String[97]; str98 = String[98]; str99 = String[99];π str100 = String[100]; str101 = String[101]; str102 = String[102];π str103 = String[103]; str104 = String[104]; str105 = String[105];π str106 = String[106]; str107 = String[107]; str108 = String[108];π str109 = String[109]; str110 = String[110]; str111 = String[111];π str112 = String[112]; str113 = String[113]; str114 = String[114];π str115 = String[115]; str116 = String[116]; str117 = String[117];π str118 = String[118]; str119 = String[119]; str120 = String[120];π str121 = String[121]; str122 = String[122]; str123 = String[123];π str124 = String[124]; str125 = String[125]; str126 = String[126];π str127 = String[127]; str128 = String[128]; str129 = String[129];π str130 = String[130]; str131 = String[131]; str132 = String[132];π str133 = String[133]; str134 = String[134]; str135 = String[135];π str136 = String[136]; str137 = String[137]; str138 = String[138];π str139 = String[139]; str140 = String[140]; str141 = String[141];π str142 = String[142]; str143 = String[143]; str144 = String[144];π str145 = String[145]; str146 = String[146]; str147 = String[147];π str148 = String[148]; str149 = String[149]; str150 = String[150];π str151 = String[151]; str152 = String[152]; str153 = String[153];π str154 = String[154]; str155 = String[155]; str156 = String[156];π str157 = String[157]; str158 = String[158]; str159 = String[159];π str160 = String[160]; str161 = String[161]; str162 = String[162];π str163 = String[163]; str164 = String[164]; str165 = String[165];π str166 = String[166]; str167 = String[167]; str168 = String[168];π str169 = String[169]; str170 = String[170]; str171 = String[171];π str172 = String[172]; str173 = String[173]; str174 = String[174];π str175 = String[175]; str176 = String[176]; str177 = String[177];π str178 = String[178]; str179 = String[179]; str180 = String[180];π str181 = String[181]; str182 = String[182]; str183 = String[183];π str184 = String[184]; str185 = String[185]; str186 = String[186];π str187 = String[187]; str188 = String[188]; str189 = String[189];π str190 = String[190]; str191 = String[191]; str192 = String[192];π str193 = String[193]; str194 = String[194]; str195 = String[195];π str196 = String[196]; str197 = String[197]; str198 = String[198];π str199 = String[199]; str200 = String[200]; str201 = String[201];π str202 = String[202]; str203 = String[203]; str204 = String[204];π str205 = String[205]; str206 = String[206]; str207 = String[207];π str208 = String[208]; str209 = String[209]; str210 = String[210];π str211 = String[211]; str212 = String[212]; str213 = String[213];π str214 = String[214]; str215 = String[215]; str216 = String[216];π str217 = String[217]; str218 = String[218]; str219 = String[219];π str220 = String[220]; str221 = String[221]; str222 = String[222];π str223 = String[223]; str224 = String[224]; str225 = String[225];π str226 = String[226]; str227 = String[227]; str228 = String[228];π str229 = String[229]; str230 = String[230]; str231 = String[231];π str232 = String[232]; str233 = String[233]; str234 = String[234];π str235 = String[235]; str236 = String[236]; str237 = String[237];π str238 = String[238]; str239 = String[239]; str240 = String[240];π str241 = String[241]; str242 = String[242]; str243 = String[243];π str244 = String[244]; str245 = String[245]; str246 = String[246];π str247 = String[247]; str248 = String[248]; str249 = String[249];π str250 = String[250]; str251 = String[251]; str252 = String[252];π str253 = String[253]; str254 = String[254]; str255 = String[255];ππConstπ MaxWord = $ffff;π MinWord = 0;π MinInt = Integer($8000);π MinLongInt = $80000000;π UseCfg = True;ππ {Color Constants:π Black = 0; Blue = 1; Green = 2; Cyan = 3; Red = 4;π Magenta = 5; Brown = 6; LtGray = 7;π DkGray = 8; LtBlue = 9; LtGreen = A; LtCyan = B; LtRed = C;π LtMagenta = D; Yellow = E; White = Fπ }ππConst Blink = $80;ππ {Screen color Constants}πConst BlackOnBlack = $00; BlueOnBlack = $01;πConst BlackOnBlue = $10; BlueOnBlue = $11;πConst BlackOnGreen = $20; BlueOnGreen = $21;πConst BlackOnCyan = $30; BlueOnCyan = $31;πConst BlackOnRed = $40; BlueOnRed = $41;πConst BlackOnMagenta = $50; BlueOnMagenta = $51;πConst BlackOnBrown = $60; BlueOnBrown = $61;πConst BlackOnLtGray = $70; BlueOnLtGray = $71;πConst GreenOnBlack = $02; CyanOnBlack = $03;πConst GreenOnBlue = $12; CyanOnBlue = $13;πConst GreenOnGreen = $22; CyanOnGreen = $23;πConst GreenOnCyan = $32; CyanOnCyan = $33;πConst GreenOnRed = $42; CyanOnRed = $43;πConst GreenOnMagenta = $52; CyanOnMagenta = $53;πConst GreenOnBrown = $62; CyanOnBrown = $63;πConst GreenOnLtGray = $72; CyanOnLtGray = $73;πConst RedOnBlue = $14; MagentaOnBlue = $15;πConst RedOnGreen = $24; MagentaOnGreen = $25;πConst RedOnCyan = $34; MagentaOnCyan = $35;πConst RedOnRed = $44; MagentaOnRed = $45;πConst RedOnMagenta = $54; MagentaOnMagenta = $55;πConst RedOnBrown = $64; MagentaOnBrown = $65;πConst RedOnLtGray = $74; MagentaOnLtGray = $75;πConst BrownOnBlack = $06; LtGrayOnBlack = $07;πConst BrownOnBlue = $16; LtGrayOnBlue = $17;πConst BrownOnGreen = $26; LtGrayOnGreen = $27;πConst BrownOnCyan = $36; LtGrayOnCyan = $37;πConst BrownOnRed = $46; LtGrayOnRed = $47;πConst BrownOnMagenta = $56; LtGrayOnMagenta = $57;πConst BrownOnBrown = $66; LtGrayOnBrown = $67;πConst BrownOnLtGray = $76; LtGrayOnLtGray = $77;πConst DkGrayOnBlack = $08; LtBlueOnBlack = $09;πConst DkGrayOnBlue = $18; LtBlueOnBlue = $19;πConst DkGrayOnGreen = $28; LtBlueOnGreen = $29;πConst DkGrayOnCyan = $38; LtBlueOnCyan = $39;πConst DkGrayOnRed = $48; LtBlueOnRed = $49;πConst DkGrayOnMagenta = $58; LtBlueOnMagenta = $59;πConst DkGrayOnBrown = $68; LtBlueOnBrown = $69;πConst DkGrayOnLtGray = $78; LtBlueOnLtGray = $79;πConst LtGreenOnBlack = $0A; LtCyanOnBlack = $0B;πConst LtGreenOnBlue = $1A; LtCyanOnBlue = $1B;πConst LtGreenOnGreen = $2A; LtCyanOnGreen = $2B;πConst LtGreenOnCyan = $3A; LtCyanOnCyan = $3B;πConst LtGreenOnRed = $4A; LtCyanOnRed = $4B;πConst LtGreenOnMagenta = $5A; LtCyanOnMagenta = $5B;πConst LtGreenOnBrown = $6A; LtCyanOnBrown = $6B;πConst LtGreenOnLtGray = $7A; LtCyanOnLtGray = $7B;πConst LtRedOnBlue = $1C; LtMagentaOnBlue = $1D;πConst LtRedOnGreen = $2C; LtMagentaOnGreen = $2D;πConst LtRedOnCyan = $3C; LtMagentaOnCyan = $3D;πConst LtRedOnRed = $4C; LtMagentaOnRed = $4D;πConst LtRedOnMagenta = $5C; LtMagentaOnMagenta = $5D;πConst LtRedOnBrown = $6C; LtMagentaOnBrown = $6D;πConst LtRedOnLtGray = $7C; LtMagentaOnLtGray = $7D;πConst YellowOnBlack = $0E; WhiteOnBlack = $0F;πConst YellowOnBlue = $1E; WhiteOnBlue = $1F;πConst YellowOnGreen = $2E; WhiteOnGreen = $2F;πConst YellowOnCyan = $3E; WhiteOnCyan = $3F;πConst YellowOnRed = $4E; WhiteOnRed = $4F;πConst YellowOnMagenta = $5E; WhiteOnMagenta = $5F;πConst YellowOnBrown = $6E; WhiteOnBrown = $6F;πConst YellowOnLtGray = $7E; WhiteOnLtGray = $7F;πConst BlackOnDkGray = Blink + $00; BlueOnDkGray = Blink + $01;πConst BlackOnLtBlue = Blink + $10; BlueOnLtBlue = Blink + $11;πConst BlackOnLtGreen = Blink + $20; BlueOnLtGreen = Blink + $21;πConst BlackOnLtCyan = Blink + $30; BlueOnLtCyan = Blink + $31;πConst BlackOnLtRed = Blink + $40; BlueOnLtRed = Blink + $41;πConst BlackOnLtMagenta = Blink + $50; BlueOnLtMagenta = Blink + $51;πConst BlackOnYellow = Blink + $60; BlueOnYellow = Blink + $61;πConst BlackOnWhite = Blink + $70; BlueOnWhite = Blink + $71;πConst GreenOnDkGray = Blink + $02; CyanOnDkGray = Blink + $03;πConst GreenOnLtBlue = Blink + $12; CyanOnLtBlue = Blink + $13;πConst GreenOnLtGreen = Blink + $22; CyanOnLtGreen = Blink + $23;πConst GreenOnLtCyan = Blink + $32; CyanOnLtCyan = Blink + $33;πConst GreenOnLtRed = Blink + $42; CyanOnLtRed = Blink + $43;πConst GreenOnLtMagenta = Blink + $52; CyanOnLtMagenta = Blink + $53;πConst GreenOnYellow = Blink + $62; CyanOnYellow = Blink + $63;πConst GreenOnWhite = Blink + $72; CyanOnWhite = Blink + $73;πConst RedOnDkGray = Blink + $04; MagentaOnDkGray = Blink + $05;πConst RedOnLtBlue = Blink + $14; MagentaOnLtBlue = Blink + $15;πConst RedOnLtGreen = Blink + $24; MagentaOnLtGreen = Blink + $25;πConst RedOnLtCyan = Blink + $34; MagentaOnLtCyan = Blink + $35;πConst RedOnLtRed = Blink + $44; MagentaOnLtRed = Blink + $45;πConst RedOnLtMagenta = Blink + $54; MagentaOnLtMagenta= Blink + $55;πConst RedOnYellow = Blink + $64; MagentaOnYellow = Blink + $65;πConst RedOnWhite = Blink + $74; MagentaOnWhite = Blink + $75;πConst BrownOnDkGray = Blink + $06; LtGrayOnDkGray = Blink + $07;πConst BrownOnLtBlue = Blink + $16; LtGrayOnLtBlue = Blink + $17;πConst BrownOnLtGreen = Blink + $26; LtGrayOnLtGreen = Blink + $27;πConst BrownOnLtCyan = Blink + $36; LtGrayOnLtCyan = Blink + $37;πConst BrownOnLtRed = Blink + $46; LtGrayOnLtRed = Blink + $47;πConst BrownOnLtMagenta = Blink + $56; LtGrayOnLtMagenta = Blink + $57;πConst BrownOnYellow = Blink + $66; LtGrayOnYellow = Blink + $67;πConst BrownOnWhite = Blink + $76; LtGrayOnWhite = Blink + $77;πConst DkGrayOnDkGray = Blink + $08; LtBlueOnDkGray = Blink + $09;πConst DkGrayOnLtBlue = Blink + $18; LtBlueOnLtBlue = Blink + $19;πConst DkGrayOnLtGreen = Blink + $28; LtBlueOnLtGreen = Blink + $29;πConst DkGrayOnLtCyan = Blink + $38; LtBlueOnLtCyan = Blink + $39;πConst DkGrayOnLtRed = Blink + $48; LtBlueOnLtRed = Blink + $49;πConst DkGrayOnLtMagenta = Blink + $58; LtBlueOnLtMagenta = Blink + $59;πConst DkGrayOnYellow = Blink + $68; LtBlueOnYellow = Blink + $69;πConst DkGrayOnWhite = Blink + $78; LtBlueOnWhite = Blink + $79;πConst LtGreenOnDkGray = Blink + $0A; LtCyanOnDkGray = Blink + $0B;πConst LtGreenOnLtBlue = Blink + $1A; LtCyanOnLtBlue = Blink + $1B;πConst LtGreenOnLtGreen = Blink + $2A; LtCyanOnLtGreen = Blink + $2B;πConst LtGreenOnLtCyan = Blink + $3A; LtCyanOnLtCyan = Blink + $3B;πConst LtGreenOnLtRed = Blink + $4A; LtCyanOnLtRed = Blink + $4B;πConst LtGreenOnLtMagenta= Blink + $5A; LtCyanOnLtMagenta = Blink + $5B;πConst LtGreenOnYellow = Blink + $6A; LtCyanOnYellow = Blink + $6B;πConst LtGreenOnWhite = Blink + $7A; LtCyanOnWhite = Blink + $7B;πConst LtRedOnDkGray = Blink + $0C; LtMagentaOnDkGray = Blink + $0D;πConst LtRedOnLtBlue = Blink + $1C; LtMagentaOnLtBlue = Blink + $1D;πConst LtRedOnLtGreen = Blink + $2C; LtMagentaOnLtGreen= Blink + $2D;πConst LtRedOnLtCyan = Blink + $3C; LtMagentaOnLtCyan = Blink + $3D;πConst LtRedOnLtRed = Blink + $4C; LtMagentaOnLtRed = Blink + $4D;πConst LtRedOnLtMagenta = Blink + $5C; LtMagentaOnLtMagenta= Blink + $5D;πConst LtRedOnYellow = Blink + $6C; LtMagentaOnYellow = Blink + $6D;πConst LtRedOnWhite = Blink + $7C; LtMagentaOnWhite = Blink + $7D;πConst YellowOnDkGray = Blink + $0E; WhiteOnDkGray = Blink + $0F;πConst YellowOnLtBlue = Blink + $1E; WhiteOnLtBlue = Blink + $1F;πConst YellowOnLtGreen = Blink + $2E; WhiteOnLtGreen = Blink + $2F;πConst YellowOnLtCyan = Blink + $3E; WhiteOnLtCyan = Blink + $3F;πConst YellowOnLtRed = Blink + $4E; WhiteOnLtRed = Blink + $4F;πConst YellowOnLtMagenta = Blink + $5E; WhiteOnLtMagenta = Blink + $5F;πConst YellowOnYellow = Blink + $6E; WhiteOnYellow = Blink + $6F;πConst YellowOnWhite = Blink + $7E; WhiteOnWhite = Blink + $7F;ππVarπ TempStr : String;π TempStrLen : Byte Absolute TempStr;π πFunction Exist(fn: str80): Boolean;π{ Returns True if File fn exists in the current directory }ππFunction ExistsOnPath(Var fn: str80): Boolean;π{ Returns True if File fn exists in any directory specified in the current }π{ path and changes fn to a fully qualified path/File. }ππFunction StrUpCase(s : String): String;π{ Returns an upper Case String from s. Applicable to the English language. }ππFunction StrLowCase(s : String): String;π{ Returns a String = to s With all upper Case Characters converted to lower }ππFunction Asc2Str(Var s; max: Byte): String;π{ Converts an ASCIIZ String to a Turbo Pascal String With a maximum length }π{ of max Characters. }ππProcedure Str2Asc(s: String; Var ascStr; max: Word);π{ Converts a TP String to an ASCIIZ String of no more than max length. }π{ WARNinG: No checks are made that there is sufficient room in destination }π{ Variable. }ππFunction LastPos(ch: Char; s: String): Byte;π{ Returns the last position of ch in s }ππProcedure CheckIO(a: Byte);ππImplementationππFunction Exist(fn: str80): Boolean;π beginπ TempStrLen := 0;π TempStr := FSearch(fn,'');π Exist := TempStrLen <> 0;π end; { Exist }ππFunction ExistsOnPath(Var fn: str80): Boolean;π beginπ TempStrLen := 0;π TempStr := FSearch(fn,GetEnv('PATH'));π ExistsOnPath := TempStrLen <> 0;π fn := FExpand(TempStr);π end; { ExistsOnPath }ππFunction StrUpCase(s : String): String;π Var x : Byte;π beginπ StrUpCase[0] := s[0];π For x := 1 to length(s) doπ StrUpCase[x] := UpCase(s[x]);π end; { StrUpCase }ππFunction StrLowCase(s : String): String;π Var x : Byte;π beginπ StrLowCase[0] := s[0];π For x := 1 to length(s) doπ Case s[x] ofπ 'a'..'z': StrLowCase[x] := chr(ord(s[x]) and $df);π else StrLowCase[x] := s[x];π end; { Case }π end; { StrLowCase }ππFunction Asc2Str(Var s; max: Byte): String;π Var stArray : Array[1..255] of Char Absolute s;π len : Integer;π beginπ len := pos(#0,stArray)-1; { Get the length }π if (len > max) or (len < 0) then { length exceeds maximum }π len := max; { so set to maximum }π Asc2Str := stArray;π Asc2Str[0] := chr(len); { Set length }π end; { Asc2Str }ππProcedure Str2Asc(s: String; Var ascStr; max: Word);π beginπ FillChar(AscStr,max,0);π if length(s) < max thenπ move(s[1],AscStr,length(s))π elseπ move(s[1],AscStr,max);π end; { Str2Asc }πππFunction LastPos(ch: Char; s: String): Byte;π Var x : Word;π beginπ x := succ(length(s));π Repeatπ dec(x);π Until (s[x] = ch) or (x = 0);π end; { LastPos }ππProcedure CheckIO(a: Byte);π Var e : Integer;π beginπ e := Ioresult;π if e <> 0 then beginπ Writeln('I/O error ',e,' section ',a);π halt(e);π end;π end; { CheckIO }ππend. { Globals }π π 6 05-28-9313:51ALL SWAG SUPPORT TEAM HEBREW.PAS IMPORT 118 {πDAVID SOLLYππFrom Israel Moshe Harel was heard to say to David SollyππThank you For taking the time to answer my many questions. I have toπtell you, though, that I was lucky to have received your letter becauseπit was addressed to David SALLY and not David SOLLY.ππ> Are you familiar With a Hebrew Text processor Program called QText?π> I have been able to obtain version 2.10 as public domain software but Iπ> am wondering if there has been an update. Have you ever heard of aππMH>Current version of QText is 5.0 and it is commercial :-(π >It comes now With a full set of utilities, including FAX support.ππDid you know that Q-Text version 2.10 was written in Turbo Pascal 3? Iπwonder if Itschak Maynts (Isaac Mainz?) has continued to use it in hisπlater versions. Anyway, I would be interested in obtaining the latestπversion of Q-Text. Can you give me the distributor's address and theπapproximate price? Thank you.ππ>Most Israeli Printers have a special ROM. You may use downloadable Characterπ>sets or even Graphic printing if needed. I once used LETTRIX For this purposπ>on a Hebrew-less Printer, and it worked fine (but S L O W . . .).πππI have Letrix 3.6. This was what I was trying to use to print theπQ-Text Files I was writing. I wrote a Program in Turbo Pascal toπconvert the Q-Text Files into Letrix Files. The printing is slow butπthe results are favourable. Another advantage to Letrix Hebrew Files isπthat they are written completely in low-ASCII and almost readableπwithout transliteration if one is at all familiar With Hebrew. It is aπgood format For posting Hebrew Text on the Multi-Lingual echo not onlyπbecause it is low-ASCII but also because the method of transliterationπis consistent.ππBelow is my Q-Text File to Letrix File conversion Program. I hope youπwill find it useful.π}ππProgram QTextLetrix;ππ{$D-}ππUsesπ Crt, Dos;πππVarπ InFile,π TransFile : Text;π InFilenm,π TransFilenm : PathStr;π Letter, Ans : Char;π Printable,π Hebrew,π Niqud,π Roman : Set of Char;π Nkdm, Rom : Boolean;ππ{π "UpItsCase" is a Function that takes a sting of any length andπ sets all of the Characters in the String to upper case. It is handyπ For comparing Strings.π}ππFunction UpItsCase (SourceStr : PathStr) : PathStr;πVarπ i : Integer;πbeginπ For i := 1 to length(SourceStr) doπ SourceStr[i] := UpCase(SourceStr[i]);π UpItsCase := SourceStrπend; {Function UpItsCase}πππFunction Exist(fname : PathStr) : Boolean;πVarπ f : File;πbeginπ{$F-,I-}π Assign(f, fname);π Reset(f);π Close(f);π{$I+}π Exist := (IOResult = 0) and (fname <> '')πend; {Function exist}ππProcedure Help;πbeginπ Writeln;π Writeln ('QTLT (Version 1.0)');π Writeln ('Hebrew Text File Conversion');π Writeln ('Q-Text 2.10 File to Letrix(R) 3.6 Hebrew File');π Writeln;π Writeln;π Writeln ('QTLT converts Q-Text Files to Letrix Hebrew format Files.');π Writeln;π Writeln ('QTLT expects two parameters on the command line.');π Writeln ('The first parameter is the name of the File to convert,');π Writeln ('the second is the name of the new File.');π Writeln;π Writeln ('Example: QTLT HKVTL.HEB HKVTL.TXT');π Writeln;π Writeln ('If no parameters are found, QTLT will display this message.');π Writeln;π Halt;πend; {Procedure Help}ππ{π "ParseCommandLine" is a Procedure that checks if any data was inputπ at the Dos command line. If no data is there, then the "Help"π Procedure is executed and the Program is halted. Otherwise, theπ Mode strig Variable is set equal to the Text on the command line.π}ππProcedure ParseCommandLine;πbeginπ if (ParamCount = 0) or (ParamCount <> 2) thenπ Helpπ elseπ beginπ InFilenm := ParamStr(1);π InFilenm := UpItsCase(InFilenm);π TransFilenm := ParamStr(2);π TransFilenm := UpItsCase(TransFilenm);π end;πend; {Procedure ParseCommandLine}ππProcedure OpenFiles;πbeginπ {Open input/output Files}π If not exist(InFilenm) thenπ beginπ Writeln;π Writeln (InFilenm, ' not found');π Halt;π endπ Elseπ beginπ Assign (InFile, InFilenm);π Reset (InFile);π end;ππ If exist (TransFilenm) thenπ beginπ Writeln;π Writeln (TransFilenm, ' already exists!');π Write ('OverWrite it? (Y/N) > ');π Repeatπ Ans := ReadKey;π Ans := Upcase(Ans);π If Ans = 'N' then Halt;π Until Ans = 'Y';π end;ππ Assign (TransFile, TransFilenm);π ReWrite (TransFile);π Writeln;πend; {Procedure OpenFiles}ππππProcedure UseOfRoman;πbeginπ Writeln ('QTLT has detected Roman letters in the source Text.');π Writeln;π Writeln ('Letrix expects access to a Roman font to print these Characters');π Writeln ('otherwise Letrix will report an error condition of fail to perform.');π Writeln;π Writeln ('Sample Letrix load instruction: LX Hebrew Roman');π Writeln;π Writeln ('Be sure that these instances are enclosed within the proper');π Writeln ('Letrix font switch codes so they are not printed as Hebrew Character');π Writeln;πend; {Procedure UseOfRoman}ππProcedure Niqudim (Var Letter : Char);π{π Letrix Uses some standard Characters to represent niqudimπ While Q-Text does not.ππ This table ensures that certain Characters do not becomeπ niqudim when translated to Letrix by inserting the tokensπ which instruct the Letrix Program to use the alternateπ alphabet -- which by default is number 2.π}πbeginπ If Not Nkdm thenπ beginπ Writeln;π Writeln ('QTLT has detected Q-Text Characters which Letrix normaly Uses for');π Writeln ('has transcribed them to print as normal Characters.');π Writeln;π Writeln ('Letrix expects access a Roman font to print these Characters');π Writeln ('otherwise Letrix will report an error condition of fail to perfect');π Writeln;π Writeln ('Sample Letrix load instruction: LX Hebrew Roman');π Writeln;π Nkdm := True;π end; {if not Nkdm}ππ Case Letter ofππ '!' : Write (TransFile, '\2!\1');π '@' : Write (TransFile, '\2@\1');π '#' : Write (TransFile, '\2#\1');π '$' : Write (TransFile, '\2$\1');π '%' : Write (TransFile, '\2%\1');π '^' : Write (TransFile, '\2^\1');π '&' : Write (TransFile, '\2&\1');π '*' : Write (TransFile, '\2*\1');π '(' : Write (TransFile, '\2(\1');π ')' : Write (TransFile, '\2)\1');π '+' : Write (TransFile, '\2+\1');π '=' : Write (TransFile, '\2=\1');ππ end; {Case}ππend; {Procedure Nikudim}ππππProcedure QT_Table (Var Letter : Char);π{π This section reviews each QText letter and matches it With aπ Letrix equivalent where possibleπ}πbeginπ Case Letter ofππ #128 : Write (TransFile, 'a'); {Alef}π #129 : Write (TransFile, 'b'); {Bet }π #130 : Write (TransFile, 'g'); {Gimmel etc. }π #131 : Write (TransFile, 'd');π #132 : Write (TransFile, 'h');π #133 : Write (TransFile, 'w');π #134 : Write (TransFile, 'z');π #135 : Write (TransFile, 'H');π #136 : Write (TransFile, 'T');π #137 : Write (TransFile, 'y');π #138 : Write (TransFile, 'C');π #139 : Write (TransFile, 'c');π #140 : Write (TransFile, 'l');π #141 : Write (TransFile, 'M');π #142 : Write (TransFile, 'm');π #143 : Write (TransFile, 'N');π #144 : Write (TransFile, 'n');π #145 : Write (TransFile, 'S');π #146 : Write (TransFile, 'i');π #147 : Write (TransFile, 'F');π #148 : Write (TransFile, 'p');π #149 : Write (TransFile, 'X');π #150 : Write (TransFile, 'x');π #151 : Write (TransFile, 'k');π #152 : Write (TransFile, 'r');π #153 : Write (TransFile, 's');π #154 : Write (TransFile, 't');ππ end; {Case of}ππend; {Procedure QT_Table}πππProcedure DoIt;π{π Special commands requred by Letrix.π Proportional spacing off, line justification off,π double-strike on, pitch set to 12 Characters per inch.π}πbeginππ Writeln(transFile,'\p\j\D\#12');π {Transcription loop}π While not eof(InFile) doπ beginπ Read(InFile, Letter);ππ If (Letter in Printable) thenπ Write(TransFile, Letter);ππ If (Letter in Niqud) thenπ Niqudim(Letter);ππ If (Letter in Hebrew) thenπ QT_Table(Letter);ππ If (Letter in Roman) and (Rom = False) thenπ beginπ UseOfRoman;π Rom := True;π end; {Roman Detection}ππ end; {while}ππ {Close Files}ππ Close (TransFile);π Close (InFile);ππ {Final message}ππ Writeln;π Writeln;π Writeln('QTLT (Version 1.0)');π Writeln('Hebrew Text File Conversion');π Writeln('Q-Text 2.10 Files to Letrix(R) 3.6 Hebrew File');π Writeln;π Writeln ('Task Complete');π Writeln;π Writeln ('QTLT was written and released to the public domain by David Solly');π Writeln ('Bibliotheca Sagittarii, Ottawa, Canada (2 December 1992).');π Writeln;ππend; {Procedure DoIt}πππbeginππ {Initialize Variables}π Printable := [#10,#12,#13,#32..#127];π Roman := ['A'..'Z','a'..'z'];π Niqud := ['!','@','#','$','%','^','&','*','(',')','+','='];π Printable := Printable - Niqud;π Hebrew := [#128..#154];π Rom := False;π Nkdm := False;ππParseCommandLine;πOpenFiles;πDoIt;ππend.ππ{ππ Please find below the Turbo Pascal source code For the conversionπProgram For making Letrix Hebrew Files into Q-Text 2.10 Files. I couldπnot find a way to make this conversion Program convert embedded RomanπText without making it into a monster. If you have any suggestions, Iπwould be thankful to the input.ππ========================= Cut Here ========================π}ππProgram LetrixQText;ππ{$D-}ππUsesπ Crt, Dos;ππVarπ InFile,π TransFile : Text;π InFilenm,π TransFilenm : PathStr;π Letter, Ans : Char;π Printable,π HiASCII : Set of Char;ππ{π "UpItsCase" is a Function that takes a sting of any length andπ sets all of the Characters in the String to upper case. It is handyπ For comparing Strings.π}ππFunction UpItsCase (SourceStr : PathStr): PathStr;πVarπ i : Integer;πbeginπ For i := 1 to length(SourceStr) doπ SourceStr[i] := UpCase(SourceStr[i]);π UpItsCase := SourceStrπend; {Function UpItsCase}πππFunction Exist(fname : PathStr) : Boolean;πVarπ f : File;πbeginπ {$F-,I-}π Assign(f, fname);π Reset(f);π Close(f);π {$I+}π Exist := (IOResult = 0) and (fname <> '')πend; {Function exist}ππProcedure Help;πbeginπ Writeln;π Writeln ('LTQT (Version 1.0)');π Writeln ('Hebrew Text File Conversion');π Writeln ('Letrix(R) 3.6 File to Q-Text 2.10 File');π Writeln;π Writeln;π Writeln ('LTQT converts Letrix Hebrew format Files to Q-Text format Files.')π Writeln;π Writeln ('LTQT expects two parameters on the command line.');π Writeln ('The first parameter is the name of the File to convert,');π Writeln ('the second is the name of the new File.');π Writeln;π Writeln ('Example: LTQT HKVTL.TXT HKVTL.HEB');π Writeln;π Writeln ('If no parameters are found, LTQT will display this message.');π Writeln;π Halt;πend; {Procedure Help}ππ{π "ParseCommandLine" is a Procedure that checks if any data was inputπ at the Dos command line. If no data is there, then the "Help"π Procedure is executed and the Program is halted. Otherwise, theπ Mode strig Variable is set equal to the Text on the command line.π}πProcedure ParseCommandLine;πbeginπ if (ParamCount = 0) or (ParamCount <> 2) thenπ Helpπ elseπ beginπ InFilenm := ParamStr(1);π InFilenm := UpItsCase(InFilenm);π TransFilenm := ParamStr(2);π TransFilenm := UpItsCase(TransFilenm);π end;πend; {Procedure ParseCommandLine}ππProcedure OpenFiles;πbeginπ {Open input/output Files}π If not exist(InFilenm) thenπ beginπ Writeln;π Writeln (InFilenm, ' not found');π Halt;π endπ Elseπ beginπ Assign (InFile, InFilenm);π Reset (InFile);π end;ππ If exist (TransFilenm) thenπ beginπ Writeln;π Writeln (TransFilenm, ' already exists!');π Write ('OverWrite it? (Y/N) > ');π Repeatπ Ans := ReadKey;π Ans := Upcase(Ans);π If Ans = 'N' then Halt;π Until Ans = 'Y';π end;ππ Assign (TransFile, TransFilenm);π ReWrite (TransFile);π Writeln;ππend; {Procedure OpenFiles}ππππProcedure LT_Table (Var Letter : Char);π{π This section reviews each Letrix letter and matches it With aπ Q-Text equivalent where possibleπ}πbeginπ Case Letter ofππ 'a' : Write (TransFile, #128);π 'b', 'B','v' : Write (TransFile, #129); {Vet, Bet}π 'g' : Write (TransFile, #130);π 'd' : Write (TransFile, #131);π 'h' : Write (TransFile, #132);π 'V', 'o', 'u', 'w' : Write (TransFile, #133); {Vav, Holem male, Shuruq}π 'z' : Write (TransFile, #134);π 'H' : Write (TransFile, #135);π 'T' : Write (TransFile, #136);π 'y', 'e' : Write (TransFile, #137); {Yod}π 'C', 'Q', 'W' : Write (TransFile, #138); {Khaf-Sofit}π 'c', 'K' : Write (TransFile, #139); {Khaf, Kaf}π 'l' : Write (TransFile, #140);π 'M' : Write (TransFile, #141);π 'm' : Write (TransFile, #142);π 'N' : Write (TransFile, #143);π 'n' : Write (TransFile, #144);π 'S' : Write (TransFile, #145);π 'i' : Write (TransFile, #146);π 'F' : Write (TransFile, #147);π 'p', 'P', 'f' : Write (TransFile, #148); {Fe, Pe}π 'X' : Write (TransFile, #149);π 'x' : Write (TransFile, #150);π 'k' : Write (TransFile, #151);π 'r' : Write (TransFile, #152);π 's' : Write (TransFile, #153);π 't' : Write (TransFile, #154);π 'A' : Write (TransFile, '-');ππ {Niqudim and unused letters}ππ 'D','E', 'G', 'I', 'J', 'j', 'O', 'q', 'R', 'U', 'Y', 'Z' :π Write(TransFile, '');π elseπ Write(TransFile, Letter);ππ end; {Case of}ππend; {Procedure LT_Table}πππProcedure DoIt;πbeginπ {Transcription loop}π While not eof(InFile) doπ beginπ Read(InFile, Letter);ππ If (Letter in Printable) thenπ LT_Table(Letter);ππ If (Letter in HiASCII) thenπ Write(TransFile, Letter);π end; {while}ππ {Close Files}ππ Close (TransFile);π Close (InFile);ππ {Final message}ππ Writeln;π Writeln;π Writeln('LTQT Version 1.0');π Writeln('Hebrew Text File Conversion');π Writeln('Letrix(R) 3.6 File to Q-Text 2.10 File');π Writeln;π Writeln;π Writeln ('Letrix Hebrew File to Q-Text File conversion complete.');π Writeln;π Writeln('Special Note:');π Writeln;π Writeln ('Q-Text does not support either dagesh or niqudim (vowels).');π Writeln ('Letters containing a dagesh-qol are reduced to their simple form.');π Writeln ('Holam male and shuruq are transcribed as vav. Roman letters used');π Writeln ('to represent niqudim are ignored. All other symbols are transcribed'π Writeln ('without change.');π Writeln;π Writeln ('There is no foreign language check -- Anything that can be transcribeπ Writeln ('into Hebrew Characters will be.');π Writeln;π Writeln ('LTQT was written and released to the public domain by David Solly');π Writeln ('Bibliotheca Sagittarii, Ottawa, Canada (8 December 1992).');π Writeln;ππend; {Procedure DoIt}πππbeginπ {Initialize Variables}π Printable := [#10,#12,#13,#32..#127];π HiASCII := [#128..#154];ππ ParseCommandLine;π OpenFiles;π DoIt;πend.ππ 7 05-28-9313:51ALL SWAG SUPPORT TEAM LONGJUMP.PAS IMPORT 22 Unit LongJump;ππ{ This Unit permits a long jump from deeply nested Procedures/Functions back }π{ to a predetermined starting point. }ππ{ Whilst the purists may shudder at such a practice there are times when such}π{ an ability can be exceedingly useful. An example of such a time is in a }π{ BBS Program when the carrier may be lost unexpectedly whilst a user is on }π{ line and the requirement is to "back out" to the initialisation reoutines }π{ at the start of the Program. }ππ{ to use the facility, it is required that a call be made to the SetJump }π{ Function at the point to where you wish the execution to resume after a }π{ long jump. When the time comes to return to that point call FarJump. }ππ{ if you are an inexperienced Programmer, I do not recommend that this Unit }π{ be used For other than experimentation. Usually there are better ways to }π{ achieve what you want to do by proper planning and structuring. It is }π{ rare to find a well written Program that will need such and ability. }ππInterfaceππConstπ normal = -1; { return was not from a LongJump call }πTypeπ jumpType = Record { the data need For a return jump }π bp,sp,cs,ip : Word;π end;ππFunction SetJump(Var JumpData : jumpType): Integer;πProcedure FarJump(JumpData : jumpType; IDInfo : Integer);ππImplementationππTypeπ WordPtr = ^Word;ππFunction SetJump(Var JumpData : jumpType): Integer;π begin { store the return address (the old bp register) }π JumpData.bp := WordPtr(ptr(SSeg,SPtr+2))^;π JumpData.ip := WordPtr(ptr(SSeg,SPtr+4))^;π JumpData.cs := WordPtr(ptr(SSeg,SPtr+6))^;π JumpData.SP := SPtr;π SetJump := normal; { show that this is not a FarJump call }π end; { SetJump }ππProcedure FarJump(JumpData : jumpType; IDInfo : Integer );π beginπ { change the return address of the calling routine of the stack so that }π { a return can be made to the caller of SetJump }π { Use IDInfo as an identifier of the routine the jump occurred from }π WordPtr(ptr(SSeg,JumpData.SP))^ := JumpData.bp;π WordPtr(ptr(SSeg,JumpData.SP+2))^ := JumpData.ip;π WordPtr(ptr(SSeg,JumpData.SP+4))^ := JumpData.cs;π Inline($8b/$46/$06); { mov ax,[bp+6] }π Inline($8b/$ae/$fa/$ff); { mov bp,[bp-6] }π end; { FarJump }ππend. { LongJump }πππ 8 05-28-9313:51ALL SWAG SUPPORT TEAM MAKEDATA.PAS IMPORT 7 {> I need about 10 megs of raw data and am looking For info-pascal archives.π> Do they exist? ...and if so could someone please direct me to where I canπI wish everyone made such easy requests to fulfil. Try the followingπProgram. With minor changes, it will supply you With almost any amountπof data For which you could ask.π}πProgram GenerateData;πUsesπ Crt;πConstπ DataWanted = 3.0E5;πVarπ Data : File of Byte;π Count : LongInt;π Garbage : Byte;πbeginπ Assign(Data, 'Data.1MB');π ReWrite(Data);π Count := 0;π Garbage := 1;π For Count := 1 to Round(DataWanted) doπ beginπ Write(Data, garbage); (* smile *)π GotoXY(1,1);π Write(Count);π Inc(Count);π end;π Close(Data)πend.π 9 05-28-9313:51ALL SWAG SUPPORT TEAM MAZE.PAS IMPORT 14 {πSEAN PALMERππ> Hello there.. I was just wondering.. Since I am completely 'C'π> illiterate, could someone please make an effort and convert theπ> following code in Pascal For me? (Its supposedly makes a solveableπ> maze every time, Cool)ππ{originally by jallen@ic.sunysb.edu}π{Turbo Pascal conversion by Sean Palmer from original C}ππConstπ h = 23; {height}π w = 79; {width}ππConstπ b : Array [0..3] of Integer = (-w, w, 1, -1);π { incs For up, down, right, left }ππVarπ a : Array [0..w * h - 1] of Boolean; { the maze (False = wall) }ππProcedure m(p : Integer);πVarπ i, d : Byte;πbeginπ a[p] := True; {make a path}π Repeatπ d := 0; {check For allowable directions}π if (p > 2 * w) and not (a[p - w - w]) thenπ inc(d, 1); {up}π if (p < w * (h - 2)) and not (a[p + w + w]) thenπ inc(d, 2); {down}π if (p mod w <> w - 2) and not (a[p + 2]) thenπ inc(d, 4); {right}π if (p mod w <> 1) and not (a[p - 2]) thenπ inc(d, 8); {left}π if d <> 0 thenπ beginπ Repeat {choose a direction that's legal}π i := random(4);π Until Boolean(d and(1 shl i));ππ a[p + b[i]] := True; {make a path}π m(p + 2 * b[i]); {recurse}π end;π Until d = 0; {Until stuck}πend;ππVarπ i : Integer;ππbeginπ randomize;π fillChar(a, sizeof(a), False);π m(succ(w)); {start at upper left}π For i := 0 to pred(w * h) doπ begin {draw}π if i mod w = 0 thenπ Writeln;π if a[i] thenπ Write(' ')π elseπ Write('█');π end;πend.π 10 05-28-9313:51ALL SWAG SUPPORT TEAM MISCFUNC.PAS IMPORT 52 Unit MiscFunc;ππ{ MiscFunc version 1.0 Scott D. Ramsay }ππ{ This is my misc. Function Unit. Some of the Functions have }π{ nothing to do With games design but, my Units use it so ... }π{ MiscFunc.pas is free. Go crazy. }π{ I've been writing comments to these Units all night. Since you }π{ have the source to this, I'll let you figure out what each one }π{ does. }ππInterfaceππFunction strint(s:String):LongInt;πFunction intstr(l:LongInt):String;πFunction ups(s:String):String;πFunction st(h:LongInt):String;πFunction Compare(s1,s2:String):Boolean;πFunction dtcmp(Var s1,s2;size:Word):Boolean;πFunction lz(i,w:LongInt):String;πFunction vl(h:String):LongInt;πFunction spaces(h:Integer):String;πFunction repstr(h:Integer;ch:Char):String;πFunction anything(s:String):Boolean;πFunction exist(f:String):Boolean;πFunction errmsg(n:Integer):String;πFunction turboerror(errorcode:Integer) : String;πProcedure funpad(Var s:String);πProcedure unpad(Var s:String);πProcedure munpad(Var s:String;b:Byte);πFunction fpad(s:String;h:Integer):String;πProcedure pad(Var s:String;h:Integer);πProcedure fix(Var s:String;h:String);πProcedure fixh(Var s:String);πFunction range(x,y,x1,y1,x2,y2:Integer) : Boolean;πFunction between(x,x1,x2:Integer):Boolean;ππImplementationπππFunction range(x,y,x1,y1,x2,y2:Integer) : Boolean;π{ returns True if (x,y) is in the rectangular region (x1,y1,x2,y2) }πbeginπ range := ((x>=x1) and (x<=x2) and (y>=y1) and (y<=y2));πend;πππProcedure fix(Var s:String;h:String);πbeginπ if pos('.',s)=0π then s := s+h;πend;πππProcedure fixh(Var s:String);πVarπ d : Integer;πbeginπ For d := 1 to length(s) doπ if s[d]<#32π then s[d] := ' ';π For d := length(s)+1 to 255 doπ s[d] := ' ';πend;πππFunction strint(s:String):LongInt;πVarπ l : LongInt;πbeginπ move(s[1],l,sizeof(l));π strint := l;πend;πππFunction intstr(l:LongInt):String;πVarπ s : String;πbeginπ move(l,s[1],sizeof(l));π s[0] := #4;π intstr := s;πend;πππFunction ups(s:String):String;πVarπ d : Integer;πbeginπ For d := 1 to length(s) doπ s[d] := upCase(s[d]);π ups := s;πend;πππFunction st(h:LongInt):String;πVarπ s : String;πbeginπ str(h,s);π st := s;πend;πππFunction Compare(s1,s2:String):Boolean;πVarπ d : Byte;π e : Boolean;πbeginπ e := True;π For d := 1 to length(s1) doπ if upCase(s1[d])<>upCase(s2[d])π then e := False;π Compare := e;πend;πππFunction dtcmp(Var s1,s2;size:Word):Boolean;πVarπ d : Word;π e : Boolean;πbeginπ e := True;π d := size;π While (d>0) and e doπ beginπ dec(d);π e := (mem[seg(s1):ofs(s1)+d]=mem[seg(s2):ofs(s2)+d]);π end;π dtcmp := e;πend;πππFunction lz(i,w:LongInt):String;πVarπ d : LongInt;π s : String;πbeginπ str(i,s);π For d := length(s) to w-1 doπ s := concat('0',s);π lz := s;πend;πππFunction vl(h:String):LongInt;πVarπ d : LongInt;π e : Integer;πbeginπ val(h,d,e);π vl := d;πend;πππFunction spaces(h:Integer):String;πVarπ s : String;πbeginπ s := '';π While h>0 doπ beginπ dec(h);π s := concat(s,' ');π end;π spaces := s;πend;πππFunction repstr(h:Integer;ch:Char):String;πVarπ s : String;πbeginπ s := '';π While h>0 doπ beginπ dec(h);π s := s+ch;π end;π repstr := s;πend;πππFunction anything(s:String):Boolean;πVarπ d : Integer;π h : Boolean;πbeginπ if length(s)=0π thenπ beginπ anything := False;π Exit;π end;π h := False;π For d := 1 to length(s) doπ if s[d]>#32π then h := True;π anything := h;πend;πππFunction exist(f:String):Boolean;πVarπ fil : File;πbeginπ if f=''π thenπ beginπ exist := False;π Exit;π end;π assign(fil,f);π {$i- }π reset(fil);π close(fil);π {$i+ }π exist := (ioresult=0);πend;πππFunction errmsg(n:Integer):String;πbeginπ Case n ofπ -1 : errmsg := '';π -2 : errmsg := 'Error reading data File';π -3 : errmsg := '';π -4 : errmsg := 'equal current data File name';π 150 : errmsg := 'Disk is Write protected';π 152 : errmsg := 'Drive is not ready';π 156 : errmsg := 'Disk seek error';π 158 : errmsg := 'Sector not found';π 159 : errmsg := 'Out of Paper';π 160 : errmsg := 'Error writing to Printer';π 1000 : errmsg := 'Record too large';π 1001 : errmsg := 'Record too small';π 1002 : errmsg := 'Key too large';π 1003 : errmsg := 'Record size mismatch';π 1004 : errmsg := 'Key size mismatch';π 1005 : errmsg := 'Memory overflow';π else errmsg := 'Error result #'+st(n);π end;πend;πππFunction turboerror(errorcode:Integer) : String;πbeginπ Case errorcode ofπ 1: turboerror := 'Invalid Dos Function code';π 2: turboerror := 'File not found';π 3: turboerror := 'Path not found';π 4: turboerror := 'too many open Files';π 5: turboerror := 'File access denied';π 6: turboerror := 'Invalid File handle';π 8: turboerror := 'not enough memory';π 12: turboerror := 'Invalid File access code';π 15: turboerror := 'Invalid drive number';π 16: turboerror := 'Cannot remove current directory';π 17: turboerror := 'Cannot rename across drives';π 100: turboerror := 'Disk read error';π 101: turboerror := 'Disk Write error';π 102: turboerror := 'File not assigned';π 103: turboerror := 'File not open';π 104: turboerror := 'File not open For input';π 105: turboerror := 'File not open For output';π 106: turboerror := 'Invalid numeric Format';π 200: turboerror := 'division by zero';π 201: turboerror := 'Range check error';π 202: turboerror := 'Stack overflow error';π 203: turboerror := 'Heap overflow error';π 204: turboerror := 'Invalid Pointer operation';π else turboerror := errmsg(errorcode);π end;πend;πππProcedure funpad(Var s:String);πbeginπ While s[1]=' ' doπ delete(s,1,1);πend;πππProcedure unpad(Var s:String);πbeginπ While (length(s)>0) and (s[length(s)]<=' ') doπ delete(s,length(s),1);πend;πππProcedure munpad(Var s:String;b:Byte);πbeginπ s[0] := Char(b);π While (length(s)>0) and (s[length(s)]<=' ') doπ delete(s,length(s),1);πend;πππFunction fpad(s:String;h:Integer):String;πbeginπ While length(s)<h doπ s := concat(s,' ');π fpad := s;πend;πππProcedure pad(Var s:String;h:Integer);πbeginπ While length(s)<h doπ s := concat(s,' ');πend;πππFunction between(x,x1,x2:Integer):Boolean;πbeginπ between := ((x>=x1) and (x<=x2));πend;πππend. 11 05-28-9313:51ALL SWAG SUPPORT TEAM PATCHEXE.PAS IMPORT 22 {π>If this cannot be done, then hhow can one include a pcx directly insideπ>the compiled File???ππ There's a trick to do that :π Suppose your Program is called PROG.EXE and your PCX File IMAGE.PCXππ After each compile of PROG.EXE, do :π COPY /B PROG.EXE+IMAGE.PCXππ Then, when you want to display the PCX, open the EXE File, read it'sπ header :π}ππFunction GetExeSize(ExeName:String; Var TotSize,Expect:LongInt):Boolean;π{ returns True if EXE is already bind }πTypeπ ExeHeaderRec = Record {Information describing EXE File}π Signature : Word; {EXE File signature}π LengthRem : Word; {Number of Bytes in last page of EXE imageπ LengthPages : Word; {Number of 512 Byte pages in EXE image}π NumReloc : Word; {Number of relocation items}π HeaderSize : Word; {Number of paraGraphs in EXE header}π MinHeap,MaxHeap : Word; {ParaGraphs to keep beyond end of image}π StackSeg,StackPtr : Word; {Initial SS:SP, StackSeg relative to imageπ CheckSum : Word; {EXE File check sum, not used}π IpInit, CodeSeg : Word; {Initial CS:IP, CodeSeg relative to imageπ RelocOfs : Word; {Bytes into EXE For first relocation item}π OverlayNum : Word; {Overlay number, not used here}π end;ππVarπ ExeF : File;π ExeHeader : ExeHeaderRec;π ExeValue : LongInt;π count : Word;ππbeginπ TotSize:=0; Expect:=0;π Assign(ExeF,ExeName); Reset(ExeF,1);π if IoResult=0 thenπ beginπ TotSize:=FileSize(ExeF);π BlockRead(ExeF,ExeHeader,SizeOf(ExeHeaderRec),Count);π With ExeHeader doπ if Signature=$5A4D thenπ beginπ if LengthRem=0 thenπ ExeValue:=LongInt(LengthPages) shl 9π elseπ ExeValue:=(LongInt(Pred(LengthPages)) shl 9)π Expect:=ExeValue;π end;π end;π Close(ExeF);π GetExeSize:=(TotSize<>Expect);πend;ππ{π If GetExeSize returns True, your PCX has been placed at the end of theπ EXE (you did not forget :)) and all you have to do next is skip theπ Program itself : Seek(ExeF,Expect);ππ Then starts your PCX. If you know in advance the sizes of the PCXπ File, you can place any data you want (including lots of PCX) at theπ end of your EXE.ππ This example is taken from a Unit I wrote a long time ago (was calledπ Caravane) and it worked very well. I accessed the end of my exe Fileπ like a normal Typed File. Quite funny but I do not use this anymore.π Note that you can LzExe or Pklite the EXE part (not the PCX one). Youπ can DIET both parts With the resident version.ππ I hope the Function GetExeSize is not copyrighted since it is much tooπ commented to be one of my work :)π 12 05-28-9313:51ALL SWAG SUPPORT TEAM REBOOT1.PAS IMPORT 9 { Subject: How to reboot With TP7.0 ??? }πVarπ hook : Word Absolute $0040:$0072;ππProcedure Reboot(Cold : Boolean); Far;πbeginπ if (Cold = True) thenπ hook := $0000π elseπ hook := $1234;ππ ExitProc := ptr($FFFF,$0000);πend;πππ{πP.S. Note that it does not require any Units to compile. Thoughπdepending on your Implementation, you may need to call HALT toπtrip the Exit code (which caUses a reboot).π}ππProgram reset;πUsesπ Dos;πVarπ regs : Registers;πbeginπ intr(25,regs);πend.ππ{ Yeah but it is easier to do it in Inline Asmπeg:π}πProgram reset;πbeginπ Asmπ INT 19h; {19h = 25 decimal}π end;πend.ππ{πOne Word about this interupt is that it is the fastest rebootπI know of but some memory managers, eg QEMM 6.03 don't like it,πIt will seriously hang Windows if called from a Dos Shell,πMicrosoft Mouse Driver 8.20 doesn't seem to like being runπafter you call int 19h and it was resident.πOther than that it works like a gem!π}π 13 05-28-9313:51ALL SWAG SUPPORT TEAM REBOOT2.PAS IMPORT 7 {πKARIM SULTANππBelieve it or not, Int 19h is not he way to go. It will stimulate a warmπboot, but it is not very safe. It doesn't do some of the shutdown workπnecessary For some applications, and the preferred method is to set the Wordπat location 40:72 and to jump to $FFFF:0.πHere are my Procedures For doing reboots from a Program:π}πProcedure ColdBoot; Assembler;πAsmπ Xor AX, AXπ Mov ES, AXπ Mov Word PTR ES:[472h],0000h {This is not a WARM boot}π Mov AX, 0F000hπ Push AXπ Mov AX, 0FFF0hπ Push AXπ Retfπend;ππProcedure WarmBoot; Assembler;πAsmπ Xor AX, AXπ Mov ES, AXπ Mov Word PTR ES:[472h],1234h {This is not a COLD boot}π Mov AX, 0F000hπ Push AXπ Mov AX, 0FFF0hπ Push AXπ Retfπend;π 14 05-28-9313:51ALL SWAG SUPPORT TEAM REBOOT3.PAS IMPORT 4 {πREYNIR STEFANSSONππFor anyone wondering how to reboot a PClone from Within Turbo Pascal:πThe Inline code is a far jump to the restart vector at $FFFF:0.π}ππProcedure ColdStart;πbeginπ MemW[$40:$72] := 0;π Inline($EA/0/0/$FF/$FF);πend;ππProcedure WarmStart;πbeginπ MemW[$40:$72] := $1234;π Inline($EA/0/0/$FF/$FF);πend;ππ 15 05-28-9313:51ALL SWAG SUPPORT TEAM SUNDRY.PAS IMPORT 99 Unit sundry;ππInterfaceππUsesπ Dos,π sCrt,π Strings;ππTypeπ LongWds = Recordπ loWord,π hiWord : Word;π end;π ica_rec = Recordπ Case Integer ofπ 0: (Bytes : Array[0..15] of Byte);π 1: (Words : Array[0..7] of Word);π 2: (Integers: Array[0..7] of Integer);π 3: (strg : String[15]);π 4: (longs : Array[0..3] of LongInt);π 5: (dummy : String[13]; chksum: Integer);π 6: (mix : Byte; wds : Word; lng : LongInt);π end;π{-This simply creates a Variant Record which is mapped to 0000:04F0π which is the intra-applications communications area in the bios areaπ of memory. A Program may make use of any of the 16 Bytes in this areaπ and be assured that Dos and the bios will not interfere With it. Thisπ means that it can be effectively used to pass values/inFormationπ between different Programs. It can conceivably be used to storeπ inFormation from an application, then terminate from that application,π run several other Programs, and then have another Program use theπ stored inFormation. As the area can be used by any Program, it is wiseπ to incorporate a checksum to ensure that the intermediate applicationsπ have not altered any values. It is of most use when executing childπ processes or passing values between related Programs that are runπ consecutively.}ππ IOproc = Procedure(derror:Byte; msg : String);ππConstπ ValidChars : String[40] = ' ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-'+#39;π HexChars : Array[0..15] of Char = '0123456789ABCDEF';ππVarπ ica : ica_rec Absolute $0000:$04f0;π FilePosition : LongInt;π(* OldRecSize : Word; *)π TempStr : String;ππProcedure CheckIO(Error_action : IOproc; msg : String);ππFunction CompressStr(Var n): String;π {-Will Compress 3 alpha-numeric Bytes into 2 Bytes}ππFunction DeCompress(Var s): String;π {-DeCompresses a String Compressed by CompressStr}ππFunction NumbofElements(Var s; size : Word): Word;π {-returns the number of active elements in a set}ππFunction PrinterStatus : Byte;π {-Gets the Printer status}ππFunction PrinterReady(Var b : Byte): Boolean;ππFunction TestBbit(n,b: Byte): Boolean;πFunction TestWbit(Var n; b: Byte): Boolean;πFunction TestLbit(n: LongInt; b: Byte): Boolean;ππProcedure SetBbit(Var n: Byte; b: Byte);πProcedure SetWbit(Var n; b: Byte);πProcedure SetLbit(Var n: LongInt; b: Byte);ππProcedure ResetBbit(Var n: Byte; b: Byte);πProcedure ResetWbit(Var n; b: Byte);πProcedure ResetLbit(Var n: LongInt; b: Byte);ππFunction right(Var s; n : Byte): String;πFunction left(Var s; n : Byte): String;πFunction shleft(Var s; n : Byte): String;πFunction nExtStr(Var s1; s2 : String; n : Byte): String;πProcedure WriteAtCr(st: String; col,row: Byte);πProcedure WriteLnAtCr(st: String; col,row: Byte);πProcedure WriteLNCenter(st: String; width: Byte);πProcedure WriteCenter(st: String; width: Byte);πProcedure GotoCR(col,row: Byte);ππ {-These Functions and Procedures Unit provides the means to do randomπ access reads on Text Files. }ππFunction Exist(fn : String) : Boolean;ππFunction Asc2Str(Var s; max: Byte): String;ππProcedure DisableBlink(State:Boolean);ππFunction Byte2Hex(numb : Byte) : String;ππFunction Numb2Hex(Var numb) : String;ππFunction Long2Hex(long : LongInt): String;ππFunction Hex2Byte(HexStr : String) : Byte;ππFunction Hex2Word(HexStr : String) : Word;ππFunction Hex2Integer(HexStr : String) : Integer;ππFunction Hex2Long(HexStr : String) : LongInt;ππ{======================================================================}πππImplementationππProcedure CheckIO(error_action : IOproc;msg : String);π Var c : Word;π beginπ c := Ioresult;π if c <> 0 then error_action(c,msg);π end;πππ{$F+}πProcedure ReportError(c : Byte; st : String);π beginπ Writeln('I/O Error ',c);π Writeln(st);π halt(c);π end;π{$F-}ππFunction StUpCase(Str : String) : String;πVarπ Count : Integer;πbeginπ For Count := 1 to Length(Str) doπ Str[Count] := UpCase(Str[Count]);π StUpCase := Str;πend;ππππFunction CompressStr(Var n): String;π Varπ S : String Absolute n;π InStr : String;π len : Byte Absolute InStr;π Compstr: Recordπ Case Byte ofπ 0: (Outlen : Byte;π OutArray: Array[0..84] of Word);π 1: (Out : String[170]);π end;π temp,π x,π count : Word;π beginπ FillChar(InStr,256,32);π InStr := S;π len := (len + 2) div 3 * 3;π FillChar(CompStr.Out,171,0);π InStr := StUpCase(InStr);π x := 1; count := 0;π While x <= len do beginπ temp := pos(InStr[x+2],ValidChars);π inc(temp,pos(InStr[x+1],ValidChars) * 40);π inc(temp,pos(InStr[x],ValidChars) * 1600);π inc(x,3);π CompStr.OutArray[count] := temp;π inc(count);π end;π CompStr.Outlen := count shl 1;π CompressStr := CompStr.Out;π end; {-CompressStr}ππFunction DeCompress(Var s): String;π Varπ CompStr : Recordπ clen : Byte;π arry : Array[0..84] of Word;π end Absolute s;π x,π count,π temp : Word;π beginπ With CompStr do beginπ DeCompress[0] := Char((clen shr 1) * 3);π x := 0; count := 1;π While x <= clen shr 1 do beginπ temp := arry[x] div 1600;π dec(arry[x],temp*1600);π DeCompress[count] := ValidChars[temp];π temp := arry[x] div 40;π dec(arry[x],temp*40);π DeCompress[count+1] := ValidChars[temp];π temp := arry[x];π DeCompress[count+2] := ValidChars[temp];π inc(count,3);π inc(x);π end;π end;π end;ππFunction NumbofElements(Var s; size : Word): Word;π {-The Variable s can be any set Type and size is the Sizeof(s)}π Varπ TheSet : Array[1..32] of Byte Absolute s;π count,x,y : Word;π beginπ count := 0;π For x := 1 to size doπ For y := 0 to 7 doπ inc(count, 1 and (TheSet[x] shr y));π NumbofElements := count;π end;ππFunction PrinterStatus : Byte;π Var regs : Registers; {-from the Dos Unit }π beginπ With regs do beginπ dx := 0; {-The Printer number LPT2 = 1 }π ax := $0200; {-The Function code For service wanted }π intr($17,regs); {-$17= ROM bios int to return Printer status}π PrinterStatus := ah;{-Bit 0 set = timed out }π end; { 1 = unused }π end; { 2 = unused }π { 3 = I/O error }π { 4 = Printer selected }π { 5 = out of paper }π { 6 = acknowledge }π { 7 = Printer not busy }ππFunction PrinterReady(Var b : Byte): Boolean;π beginπ b := PrinterStatus;π PrinterReady := (b = $90) {-This may Vary between Printers}π end;ππFunction TestBbit(n,b: Byte): Boolean;π beginπ TestBbit := odd(n shr b);π end;ππFunction TestWbit(Var n; b: Byte): Boolean;π Var t: Word Absolute n;π beginπ if b < 16 thenπ TestWbit := odd(t shr b);π end;ππFunction TestLbit(n: LongInt; b: Byte): Boolean;π beginπ if b < 32 thenπ TestLbit := odd(n shr b);π end;ππProcedure SetBbit(Var n: Byte; b: Byte);π beginπ if b < 8 thenπ n := n or (1 shl b);π end;ππProcedure SetWbit(Var n; b: Byte);π Var t : Word Absolute n; {-this allows either a Word or Integer}π beginπ if b < 16 thenπ t := t or (1 shl b);π end;ππProcedure SetLbit(Var n: LongInt; b: Byte);π beginπ if b < 32 thenπ n := n or (LongInt(1) shl b);π end;ππProcedure ResetBbit(Var n: Byte; b: Byte);π beginπ if b < 8 thenπ n := n and not (1 shl b);π end;ππProcedure ResetWbit(Var n; b: Byte);π Var t: Word Absolute n;π beginπ if b < 16 thenπ t := t and not (1 shl b);π end;ππProcedure ResetLbit(Var n: LongInt; b: Byte);π beginπ if b < 32 thenπ n := n and not (LongInt(1) shl b);π end;ππFunction right(Var s; n : Byte): String;π Varπ st : String Absolute s;π len: Byte Absolute s;π beginπ if n >= len then right := st elseπ right := copy(st,len+1-n,n);π end;ππFunction shleft(Var s; n : Byte): String;π Varπ st : String Absolute s;π stlen: Byte Absolute s;π temp : String;π len : Byte Absolute temp;π beginπ if n < stlen then beginπ move(st[n+1],temp[1],255);π len := stlen - n;π shleft := temp;π end;π end;ππFunction left(Var s; n : Byte): String;π Varπ st : String Absolute s;π temp: String;π len : Byte Absolute temp;π beginπ temp := st;π if n < len then len := n;π left := temp;π end;ππFunction nExtStr(Var s1;s2 : String; n : Byte): String;π Varπ main : String Absolute s1;π second : String Absolute s2;π len : Byte Absolute s2;π beginπ nExtStr := copy(main,pos(second,main)+len,n);π end;ππProcedure WriteAtCr(st: String; col,row: Byte);π beginπ GotoXY(col,row);π Write(st);π end;πππProcedure WriteLnAtCr(st: String; col,row: Byte);π beginπ GotoXY(col,row);π Writeln(st);π end;ππFunction Charstr(ch : Char; by : Byte) : String;πVarπ Str : String;π Count : Integer;πbeginπ Str := '';π For Count := 1 to by doπ Str := Str + ch;π CharStr := Str;πend;πππProcedure WriteLnCenter(st: String; width: Byte);π beginπ TempStr := CharStr(' ',(width div 2) - succ((length(st) div 2)));π st := TempStr + st;π Writeln(st);π end;ππProcedure WriteCenter(st: String; width: Byte);π beginπ TempStr := CharStr(' ',(width div 2)-succ((length(st) div 2)));π st := TempStr + st;π Write(st);π end;ππProcedure GotoCR(col,row: Byte);π beginπ GotoXY(col,row);π end;ππFunction Exist(fn : String): Boolean;π Varπ f : File;π OldMode : Byte;π beginπ OldMode := FileMode;π FileMode:= 0;π assign(f,fn);π {$I-} reset(f,1); {$I+}π if Ioresult = 0 then beginπ close(f);π Exist := True;π endπ elseπ Exist := False;π FileMode:= OldMode;π end; {-Exist}ππFunction Asc2Str(Var s; max: Byte): String;π Var stArray : Array[0..255] of Byte Absolute s;π st : String;π len : Byte Absolute st;π beginπ move(stArray[0],st[1],255);π len := max;π len := (max + Word(1)) * ord(pos(#0,st) = 0) + pos(#0,st)-1;π Asc2Str := st;π end;πππProcedure DisableBlink(state : Boolean);π { DisableBlink(True) allows use of upper eight colors as background }π { colours. DisableBlink(False) restores the normal mode and should }π { be called beFore Program Exit }πVarπ regs : Registers;πbeginπ With regs doπ beginπ ax := $1003;π bl := ord(not(state));π end;π intr($10,regs);πend; { DisableBlink }ππFunction Byte2Hex(numb : Byte) : String;π beginπ Byte2Hex[0] := #2;π Byte2Hex[1] := HexChars[numb shr 4];π Byte2Hex[2] := HexChars[numb and 15];π end;ππFunction Numb2Hex(Var numb) : String;π { converts an Integer or a Word to a String. Using an unTypedπ argument makes this possible. }π Var n : Word Absolute numb;π beginπ Numb2Hex := Byte2Hex(hi(n))+Byte2Hex(lo(n));π end;ππFunction Long2Hex(long : LongInt): String;π beginπ With LongWds(long) do { Type casting makes the split up easy}π Long2Hex := Numb2Hex(hiWord) + Numb2Hex(loWord);π end;ππFunction Hex2Byte(HexStr : String) : Byte;π beginπ Hex2Byte := pos(UpCase(HexStr[2]),HexChars)-1 +π ((pos(UpCase(HexStr[1]),HexChars))-1) shl 4 { * 16}π end;ππFunction Hex2Word(HexStr : String) : Word;π { This requires that the String passed is a True hex String of 4π Chars and not in a Format like $FDE0 }π beginπ Hex2Word := pos(UpCase(HexStr[4]),HexChars)-1 +π ((pos(UpCase(HexStr[3]),HexChars))-1) shl 4 + { * 16}π ((pos(UpCase(HexStr[2]),HexChars))-1) shl 8 + { * 256}π ((pos(UpCase(HexStr[1]),HexChars))-1) shl 12; { *4096}π end;ππFunction Hex2Integer(HexStr : String) : Integer;π beginπ Hex2Integer := Integer(Hex2Word(HexStr));π end;ππFunction Hex2Long(HexStr : String) : LongInt;π Var Long : LongWds;π beginπ Long.hiWord := Hex2Word(copy(HexStr,1,4));π Long.loWord := Hex2Word(copy(HexStr,5,4));π Hex2Long := LongInt(Long);π end;ππbeginπ FilePosition := 0;πend.π 16 05-28-9313:51ALL SWAG SUPPORT TEAM TPASM.PAS IMPORT 79 { Ok here it is.. I have disasembled the following TP Program toπshow you the inner workings of TP (well at least 6.0). TheπFolloing Program was Compiled in the IDE With RANGE, I/O, STACKπchecking turned off. Look at the code close and see if you canπfind a nasty little bug in it beFore I show you the Asm that TPπCreated on disk.π}ππProgram TstFiles;ππType MyRec = Recordπ LInt : LongInt;π Hi : Word;π Lo : Word;π B1 : Byte;π B2 : Byte;π B3 : Byte;π B4 : Byte;π end; {Record Size 12 Bytes}ππConst MaxRecs = 100;πππVar MyTypedFile : File of MyRec;π MyUnTypedFile : File;ππ Rec : MyRec;π RecCnt : Word;πππProcedure FillRec (RecSeed : LongInt);ππ beginπ Rec.Lint := RecSeed;π Rec.Hi := Hi (Rec.Lint);π Rec.Lo := Lo (Rec.Lint);π Rec.B1 := Lo (Rec.Lo);π Rec.B2 := Hi (Rec.Lo);π Rec.B3 := Lo (Rec.Hi);π Rec.B4 := Hi (Rec.Hi);π end;πππππbeginπAssign (MyTypedFile, 'Type.Dat');πAssign (MyUnTypedFile, 'UnTyped.Dat');πReWrite (MyTypedFile);πReWrite (MyUnTypedFile);ππFor RecCnt := 1 to MaxRecs doπ beginπ FillRec (RecCnt);ππ Write (MyTypedFile , Rec);π{ Write (MyUnTypedFile, Rec);} {Illegal can't do this}ππ FillRec (RecCnt + $FFFF);ππ{ BlockWrite (MyTypedFile, Rec, 1);} {Illegal Can't do this eather}ππ BlockWrite (MyUnTypedFile, Rec, Sizeof (MyRec));π end;πππend.πππThe Asm Break down is in the next two messages...ππTSTFileS.38: beginπ cs:0051 9A0000262D call 2D26:0000 <-------TP Start Up Codeπ cs:0056 55 push bpπ cs:0057 89E5 mov bp,spπTSTFileS.39: Assign (MyTypedFile, 'Type.Dat');π cs:0059 BF4400 mov di,0044π cs:005C 1E push dsπ cs:005D 57 push diπ cs:005E BF3C00 mov di,003Cπ cs:0061 0E push csπ cs:0062 57 push diπ cs:0063 9AC004262D call 2D26:04C0 <-------TP's Routine to setπ up File Records.πTSTFileS.40: Assign (MyUnTypedFile, 'UnTyped.Dat');π cs:0068 BFC400 mov di,00C4π cs:006B 1E push dsπ cs:006C 57 push diπ cs:006D BF4500 mov di,0045π cs:0070 0E push csπ cs:0071 57 push diπ cs:0072 9AC004262D call 2D26:04C0 <-------TP's Routine to setπ up File Records.πTSTFileS.41: ReWrite (MyTypedFile);π cs:0077 BF4400 mov di,0044π cs:007A 1E push dsπ cs:007B 57 push diπ cs:007C B80C00 mov ax,000Cπ cs:007F 50 push axπ cs:0080 9AF704262D call 2D26:04F7 <-------TP's Routine toπ Create File.πTSTFileS.42: ReWrite (MyUnTypedFile);π cs:0085 BFC400 mov di,00C4π cs:0088 1E push dsπ cs:0089 57 push diπ cs:008A B88000 mov ax,0080π cs:008D 50 push axπ cs:008E 9AF704262D call 2D26:04F7 <-------TP's Routine toπ Create File.πTSTFileS.44: For RecCnt := 1 to MaxRecs doπ cs:0093 C70650010100 mov Word ptr [TSTFileS.RECCNT],00π *** Clear the loop counter For first loopπ cs:0099 EB04 jmp TSTFileS.46 (009F)π *** Jump to the start of the Loopπ cs:009B FF065001 inc Word ptr [TSTFileS.RECCNT]π *** The Loop returns to here to inC the loop counterπTSTFileS.46: FillRec (RecCnt);π cs:009F A15001 mov ax,[TSTFileS.RECCNT]π *** Move our RecCnt Var into AX registerπ cs:00A2 31D2 xor dx,dxπ *** Clear the DX Registerπ cs:00A4 52 push dxπ cs:00A5 50 push axπ *** Push the DX and AX Registers on the stack. Remember ourπ FillRec Routine expects a LongInt to be passed and RecCntπ is only a Word. So it Pushes the DX as the 0 Upper Wordπ of the LongInt.π cs:00A6 0E push csπ *** Push the code segment For some reasion.π cs:00A7 E856FF call TSTFileS.FILLRECπ *** Call our FillRec RoutineπTSTFileS.48: Write (MyTypedFile , Rec);π cs:00AA BF4400 mov di,0044π cs:00AD 1E push dsπ cs:00AE 57 push diπ *** These instructions push the address of MyTypedFile Recordπ on the stack. The first paramiterπ cs:00AF BF4401 mov di,0144π cs:00B2 1E push dsπ cs:00B3 57 push diπ *** These instructions push the address of Rec Recordπ on the stack. The second paramiterπ cs:00B4 9AAA05262D call 2D26:05AAπ *** Call the System Function to Write a Typed File. (In next msg)π cs:00B9 83C404 add sp,0004π *** Remove our passed parameters from the stackπTSTFileS.51: FillRec (RecCnt + $FFFF);π cs:00BC A15001 mov ax,[TSTFileS.RECCNT]π cs:00BF 05FFFF add ax,FFFFπ cs:00C2 31D2 xor dx,dxπ cs:00C4 52 push dxπ cs:00C5 50 push axπ cs:00C6 0E push csπ cs:00C7 E836FF call TSTFileS.FILLRECπ *** Now heres a NASTY littel bug With the code!!! Look at theπ above routine. We wanted to pass a LongInt $FFFF + rec cntπ But we wound up adding the $FFFF to a Word then passing aπ LongInt. if you Compile the sample pas File you'll be ableπ to see this bug in action.. Good reasion to use a Debugger.πTSTFileS.55: BlockWrite (MyUnTypedFile, Rec, Sizeof (MyRec))π cs:00CA BFC400 mov di,00C4π cs:00CD 1E push dsπ cs:00CE 57 push diπ *** These instructions push the address of MyUnTypeFile Recordπ on the stack. The First paramiterπ cs:00CF BF4401 mov di,0144π cs:00D2 1E push dsπ cs:00D3 57 push diπ cs:0594 26817D02B3D7 cmp es:Word ptr [di+02],D7B3π *** Armed With the address of the File Record in ES:DIπ Check the File mode For a In/Out operation. See Dosπ Unit Constant definitions.π cs:059A 7406 je 05A2π *** if that Compare was equal then jump to returnπ cs:059C C7063C006700 mov Word ptr [SYSTEM.inOUTRES],0069π *** if we didn't jump then put File not oopen For output inπ Ioresult.π cs:05A2 C3 retπ *** Go back to where we were calledπ cs:05A3 B43F mov ah,3Fπ cs:05A5 BA6400 mov dx,0064π cs:05A8 EB05 jmp 05AFππ *** The Write instruction entered the system Unit hereπ cs:05AA B440 mov ah,40π *** Load Dos Function in AHπ cs:05AC BA6500 mov dx,0065π *** Default error code 101 disk Write error load in DXπ cs:05AF 55 push bpπ *** Save the BP registerπ cs:05B0 8BEC mov bp,spπ *** Load the BP Register With the stack Pointerπ cs:05B2 C47E0A les di,[bp+0A]π *** Load Address of MyTypeFile Rec in ES:SIπ cs:05B5 E8DCFF call 0594π *** Call check For File mode. See top of messageπ cs:05B8 751B jne 05D5π *** if error jump out of thisπ cs:05BA 1E push dsπ cs:05BB 52 push dxπ *** Save These Registers as we'er going to use themπ cs:05BC C55606 lds dx,[bp+06]π *** Load the address of our Rec in DS:DX Registersπ cs:05BF 268B4D04 mov cx,es:[di+04]π *** Look up Record structure For a File Rec and you'll seeπ that RecSize is Byte # 4. Move that value to CXπ cs:05C3 268B1D mov bx,es:[di]π *** First Byte of a File Rec is the Handel. Move into BXπ cs:05C6 CD21 int 21π *** Make the Dos CALL to Write. AH = 40π BX = File Handelπ CX = # of Bytes to Write.π DS:DX = Address of Bufferπ Returns Error In AX if Carry flag set orπ if good CF = 0 number of Bytes written in AXπ cs:05C8 5A pop dxπ cs:05C9 1F pop dsπ *** Restore the Registersπ cs:05CA 7206 jb 05D2π *** Jump if there was an error (if Carry flag Set)π cs:05CC 3BC1 cmp ax,cxπ *** Comp Bytes requested to what was writtenπ cs:05CE 7405 je 05D5π *** if equal then jump out we'r just about doneπ cs:05D0 8BC2 mov ax,dxπ *** Move default errorcode 101 to AXπ cs:05D2 A33C00 mov [SYSTEM.inOUTRES],ax <--Set Ioresultπ *** Store 101 to Ioresultπ cs:05D5 5D pop bpπ *** Restore BP registerπ cs:05D6 CA0400 retf 0004π *** We'r out of hereππ cs:05D9 B33F mov bl,3Fπ cs:05DB B96400 mov cx,0064π cs:05DE EB05 jmp 05E5πππ *** The BlockWrite instruction entered the system Unit hereπ cs:05E0 B340 mov bl,40π *** Move Dos Function in BLπ cs:05E2 B96500 mov cx,0065π *** Default error 101 Write error in CXπ cs:05E5 55 push bpπ *** Save BP Registerπ cs:05E6 8BEC mov bp,spπ *** Move Stack Pointer to BPπ cs:05E8 C47E10 les di,[bp+10]π *** Load Address of MyUnTypedFile Record in ES:DIπ cs:05EB E8A6FF call 0594π *** Check For Open in Write Mode See top of messageπ cs:05EE 753F jne 062Fπ *** Jump if not in Write modeπ cs:05F0 8B460A mov ax,[bp+0A] ]π *** Move File Record cnt in to axπ cs:05F3 0BC0 or ax,axπ *** Check For 0 Record requestπ cs:05F5 741C je 0613π *** Jump if 0 rec requestedπ cs:05F7 1E push dsπ cs:05F8 51 push cxπ *** Save them we'er going to use themπ cs:05F9 26F76504 mul es:Word ptr [di+04]π *** Multiply Record size With RecCnt in AX result in DX & AXπ cs:05FD 8BC8 mov cx,axπ 17 05-28-9313:51ALL SWAG SUPPORT TEAM ZTRAS.PAS IMPORT 33 Unit Globals;ππInterfaceππUses Crt{, Dos?};ππ{ Special keyboard Characters: }π{ I've squeezed them into a couple of lines so that they'd fit in aπmessage.. might be an idea to expand them back to ~20 lines or so..}ππ NULL = #0; BS = #8; ForMFEED = #12; CR = #13; ESC = #27;ππ HOMEKEY = #199; {Values apply if only used With the 'Getkey' Function}π endKEY = #207; UPKEY = #200; doWNKEY = #208;π PGUPKEY = #201; PGDNKEY = #209; LEFTKEY = #203;π inSKEY = #210; RIGHTKEY = #205; DELKEY = #211;π CTRLLEFTKEY = #243; CTRLRIGHTKEY = #244;π F1 = #187; F2 = #188; F3 = #189; F4 = #190; F5 = #191;π F6 = #192; F7 = #193; F8 = #194; F9 = #195; F10 = #196;ππType CurType = ( off, Big, Small );ππVar Ins : Boolean; { Global Var containing status of Insert key}ππ{-----------------------------------------------------------------------------}πFunction GetKey : Char;πProcedure EdReadln(Var S : String);ππProcedure Cursor( Size : CurType ); { Either off, Big or Small }πProcedure ChangeCursor( Ins : Boolean );ππ{-----------------------------------------------------------------------------}πImplementationππFunction GetKey; { : Char; }ππVar C : Char;ππbeginπ C := ReadKey;π Repeatπ if C = NULL thenπ beginπ C := ReadKey;π if ord(C) > 127 thenπ C := NULLπ elseπ GetKey := Chr(ord(C) + 128);π end else GetKey := C;π Until C <> NULL;πend; { GetKey }ππ{-----------------------------------------------------------------------------}πProcedure EdReadln; { (Var S : String); }ππ{ Legal : IString; MaxLength : Word; Var ESCPressed : Boolean); }ππVar CPos : Word;π Ch : Char;π OldY : Byte;ππ Legal : String[1];π MaxLength : Byte;π EscPressed : Boolean;ππbeginπ OldY := WhereY - 1;π ChangeCursor(Ins);π CPos := 1; {Place cursor at START of line}π{ CPos := Succ(Length(S));} {Whereas this places cursor at end of line}π Legal := ''; {Legal and Maxlength originally passed as params}π MaxLength := Lo( WindMax ) - Lo( WindMin );ππ Repeatπ Cursor( off );π GotoXY(1, WhereY);π Write(S, '':(MaxLength - Length(S)));π GotoXY(CPos, WhereY);π ChangeCursor(Ins);π Ch := GetKey;π Case Ch ofπ HOMEKEY : CPos := 1;π endKEY : CPos := Succ(Length(S));π inSKEY : beginπ Ins := not Ins;π ChangeCursor(Ins);π end;π LEFTKEY : if CPos > 1 then Dec(CPos);π RIGHTKEY : if CPos <= Length(S) then Inc(CPos);π BS : if CPos > 1 thenπ beginπ Delete(S, Pred(CPos), 1);π Dec(CPos);π end;π DELKEY : if CPos <= Length(S) then Delete(S, CPos, 1);π CR : ;π ESC : beginπ S := '';π CPos := 1;π end;π elseπ beginπ if ((Legal = '') or (Pos(Ch, Legal) <> 0)) andπ ((Ch >= ' ') and (Ch <= '~')) andπ (Length(S) < MaxLength) thenπ beginπ if Ins then Insert(Ch, S, CPos) elseπ if CPos > Length(S) then S := S + Ch elseπ S[CPos] := Ch;π Inc(CPos);π end;π end;π end; { Case }π Until (Ch = CR);π Cursor( Small );π ESCPressed := Ch <> ESC;π Writeln;πend; { EditString }ππ{-----------------------------------------------------------------------------}πProcedure Cursor; { ( Size : CurType ); { Either off, Big or Small }ππVar Regs : Registers;ππbeginπ With Regs Do beginπ Ax := $100;π Case Size ofπ off : Cx := $3030;π Big : Cx := $0F;π Small : Cx := $607;π end;π Intr ( $10, Regs );π end;πend;ππ{-----------------------------------------------------------------------------}πProcedure ChangeCursor; { ( Ins : Boolean ); }π{Changes cursor size depending on status of insert key}ππbeginπ if Ins then Cursor( Small ) else Cursor( Big );πend;ππbeginπend.π 18 05-10-9314:24ALL COLIN BUCKLEY Compiler Directives (232)T_Pascal_R 32 So I'm using a common include file, which I'll add to the end of this message,πand I've noticed something very strange. I used the Object browser to findπall the units, and I have triple checked to ensure they all include theπinclude file and this is what I've found:ππWith DEBUGGING set my file compiles to 115KπWithout DEBUGGING set 81KππWhen I look at the file there is still loads of symbol information there.πAfter TDStrip of the above file, it's down to 55K (81-55=26). That's a 26Kπdifference. Where is it coming from? Sure I'm using CRT and DOS, andπobviously the include file doesn't work for them, but after looking at theπremaining symbol information, it's alot of stuff from my various unitsπaswell as CRT and DOS.ππWhat's the deal with the symbols coming from my units when I tell themπnot to? I say symbols as it's all declarations from my interfaceπsections like variables and procedure names, etc.ππAnyways, I wasn't interested in using multiple configuration files, butπI guess I'll have to as I forgot about Borland units, and I guess everyoneπelse did aswell.ππ----------------------------- OPTIONS.INC --------------------------------π{πTurbo Pascal Compiler Directivesπ}ππ{$DEFINE i286}π{$DEFINE DEBUGGING}ππ{$A+} { Data Alignment........Word }π{$I-} { I/O Checking..........Off }π{$X-} { Enhanced Syntax.......Off }π{$V-} { String Type Checking..Relaxed }π{$P-} { Open Strings..........Off }π{$T-} { @ Pointers............UnTyped }ππ{$IFDEF i286}π{$G+} { 286 OpCodes...........On }π{$ELSE}π{$G-} { 286 OpCodes...........Off }π{$ENDIF}ππ{$IFDEF OVERLAYS}π{$F+} { Far Calls.............On }π{$O+} { Overlays Allowed......Yes }π{$ELSE}π{$F-} { Far Calls.............Off }π{$O-} { Overlays Allowed......No }π{$ENDIF}ππ{$IFDEF DEBUGGING}π{$B+} { Boolean Evaluation....Complete }π{$D+} { Debugging Info........On }π{$L+} { Line Numbers..........On }π{$Y+} { Symbol Information....On }π{$R+} { Range Checking........On }π{$S+} { Stack Checking........On }π{$Q+} { Overflow Checking.....On }π{$ELSE}π{$B-} { Boolean Evaluation....Short Circuit }π{$D-} { Debugging Info........Off }π{$L-} { Line Numbers..........Off }π{$Y-} { Symbol Information....Off }π{$R-} { Range Checking........Off }π{$S-} { Stack Checking........Off }π{$Q-} { Overflow Checking.....On }π{$ENDIF}ππ{πProgram Memory Requirementsπ}π{$M 32000,0,0} { Stack Size............32000 Heap.....0 }ππ.----------------------------------------------------.π| Colin Buckley |π| Toronto, Ontario, Canada |π| InterNet: colin.buckley@rose.com |π| |π| So Eager to Play, So Relunctant to Admit it... |π`----------------------------------------------------'ππ---π ■ RoseReader 2.10ß P003288 Entered at [ROSE]π * Rose Media, Toronto, Canada : 416-733-2285π * PostLink(tm) v1.04 ROSE (#1047) : RelayNet(tm)ππ 19 05-31-9308:05ALL FLOOR NAAIJKENS RANDOM NUMBER GENERATOR IMPORT 21 ==============================================================================π BBS: The Sand Box BBS - SourceNet Central HUBπ To: JUD MCCRANIE Date: 12-17─92 (16:42)πFrom: TREVOR CARLSEN Number: 531 [87] FD-PascalπSubj: BP 7 DIFFERENCE Status: Publicπ------------------------------------------------------------------------------π JM> The behavior of RANDOM (with RandSeed set) is different inπ JM> BP7 (and presumably TP7) from that in TP 5.5. (I don't knowπ JM> how TP 6 compares since I burned it off my disk).ππ JM> RandSeed := 123;π JM> for i := 1 to 8 do writeln( random( 1000));ππ JM> TP 5.5: 343 282 986 996 781 855 343 32π JM> BP 7.0: 859 80 869 854 317 257 20 46ππ JM> ...both are consistant, but they are different sequences.π JM> This can have some dire consequences. ...ππIt certainly could if you did not know about it and unfortunately I canπfind no reference to the changes in the documentation. (Richard Nelson?)ππHere is a fix (supplied to me via Netmail courtesy Joe Lamoine - thanks Joe).ππ>Quote........ππI posted a message on Compuserve last nite and got the followingπunit in a response. It seems to work fine!πππ{ * Turbo Pascal Runtime Library Version 6.0 * ;π * Random Number Generator * ;π * * ;π * Copyright (C) 1988,92 Borland International * }ππ unit TP6Rand;ππ interfaceππ function Random(Max: Integer): Integer;ππ implementationππ constπ { Scaling constant}π ConstM31 = Longint(-31);π { Multiplication factor}π Factor: Word = $8405;πππ function NextRand: Longint; assembler;π { Compute next random numberπ New := 8088405H * Old + 1π Out DX:AX = Next random numberπ }π asmπ MOV AX,RandSeed.Word[0]π MOV BX,RandSeed.Word[2]π MOV CX,AXπ MUL Factor.Word[0] { New = Old.w0 * 8405H }π SHL CX,1 { New.w2 += Old.w0 * 808H }π SHL CX,1π SHL CX,1π ADD CH,CLπ ADD DX,CXπ ADD DX,BX { New.w2 += Old.w2 * 8405H }π SHL BX,1π SHL BX,1π ADD DX,BXπ ADD DH,BLπ MOV CL,5π SHL BX,CLπ ADD DH,BLπ ADD AX,1 { New += 1 }π ADC DX,0π MOV RandSeed.Word[0],AXπ MOV RandSeed.Word[2],DXπ end;ππfunction Random(Max: Integer): Integer; assembler;π asmπ CALL NextRandπ XOR AX,AXπ MOV BX,Max.Word[0]π OR BX,BXπ JE @@1π XCHG AX,DXπ DIV BXπ XCHG AX,DXπ @@1:π end;ππend.ππ>End of quote.πππTeeCeeπππ--- TC-ED v2.01π * Origin: The Pilbara's Pascal Centre (+61 91 732930) (3:690/644)π 20 06-22-9309:24ALL SWAG SUPPORT TEAM Hi Resolution Timer IMPORT 20 UNIT Timer;ππ{ TIMER - Fine resolution timer functions }ππINTERFACEπUSES Crt,Dos;πCONSTπ TixSec = 18.20648193;π TixMin = TixSec * 60.0;π TixHour = TixMin * 60.0;π TixDay = TixHour * 24.0;πTYPEπ DiffType = String[16];πVARπ tGet : Longint ABSOLUTE $0040:$006C;πFUNCTION tStart: Longint;πFUNCTION tDiff(StartTime,EndTime: Longint) : Real;πFUNCTION tFormat(T1,T2:Longint): DiffType;πPROCEDURE GetTime(H,M,S,S100:Word);ππIMPLEMENTATIONππVARπ TimeDiff : DiffType;ππ{ tStart - wait for a new tick, and return theπ tick number to the caller. The wait allowsπ us to be sure the user gets a start at theπ beginning of the second. }ππFUNCTION tStart: Longint;πVARπ StartTime : Longint;πBEGINπ StartTime := tGet;π WHILE StartTime = tGet DO;π tStart := tGetπEND;ππ{ tDiff - compute the difference between twoπ timepoints (in seconds). }ππFUNCTION tDiff(StartTime,EndTime: Longint) : Real;πBEGINπ tDiff := (EndTime-StartTime)/TixSec;πEND;ππPROCEDURE GetTime(H,M,S,S100:Word);πVARπ Regs : Registers;πBEGINπ Regs.AH := $2C;π MsDos(Regs);π H := Regs.CH;π M := Regs.CL;π S := Regs.DH;π S100 := Regs.DLπEND;ππ{ tFormat - given two times, return a pointerπ to a (static) string that is the differenceπ in the times, formatted HH:MM:SS }ππFUNCTION tFormat(T1,T2:Longint): DiffType;ππFUNCTION rMod(P1,P2: Real): Real;πBEGINπ rMod := Frac(P1/P2) * P2πEND;ππVARπ Temp : Real;π tStr : String;π TempStr : String[2];π TimeValue : ARRAY [1..4] OF Longint;π I : Integer;πBEGINπ Temp := t2-t1; { Time diff. }π {Adj midnight crossover}π IF Temp < 0 THENπ Temp := Temp + TixDay;π TimeValue[1] := Trunc(Temp/TixHour); {hours}π Temp := rMod(Temp,TixHour);π TimeValue[2] := Trunc(Temp/TixMin); {minutes}π Temp := rMod(Temp,TixMin);π TimeValue[3] := Trunc(Temp/TixSec); {seconds}π Temp := rMod(Temp,TixSec); {milliseconds}π TimeValue[4] := Trunc(Temp*100.0/TixSec+0.5);π STR(TimeValue[1]:2,tStr);π IF tStr[1] = ' ' THEN tStr[1] := '0';π FOR I := 2 TO 3 DOπ BEGINπ STR(TimeValue[I]:2,TempStr);π IF TempStr[1]=' ' THENπ TempStr[1]:='0';π tStr := tStr + ':'+ TempStrπ END;π STR(TimeValue[4]:2,TempStr);π IF TempStr[1]=' ' THEN TempStr[1]:='0';π tStr := tStr + '.' + TempStr;π tFormat := tStrπEND;ππEND.π 21 07-16-9306:11ALL SWAG SUPPORT TEAM A source code mangler IMPORT 43 èo {πHere is a VERY simple source-code mangler that I just made. It simply:ππ1) Removes whitespace,π2) Removes comments (but not Compiler-directives!),π3) Makes everything upper-Case.π4) Make lines max. 127 Chars wide (max. For Turbo Pascal),π5) Doesn't mess up literal Strings :-)ππI don't imagine that this is anything Near perfect - but it's better thanπnothing...ππ}ππProgram Mangler;ππConstπ Alpha : Set of Char = ['a'..'z', 'A'..'Z', '0'..'9'];ππVarπ F, F2 : Text;π R, S : String;π X : Byte;π InString : Boolean;ππFunction NumChar(C : Char; S : String; Max : Byte) : Byte;πVarπ N, Y : Byte;πbeginπ N := 0;π For Y := 1 to Max doπ if S[Y] = C then Inc(N);π NumChar := N;πend;ππFunction TrimF(T : String) : String;πVarπ T2 : String;πbeginπ T2 := T;π While (Length(T2) > 0) and (T2[1] = ' ') doπ Delete(T2, 1, 1);π TrimF := T2;πend;ππFunction Trim(T : String) : String;πVarπ T2 : String;πbeginπ T2 := TrimF(T);π While (Length(T2) > 0) and (T2[Length(T2)] = ' ') doπ Delete(T2, Length(T2), 1);π Trim := T2;πend;ππProcedure StripComments(Var T : String);πVarπ Y : Byte;π Rem : Boolean;πbeginπ Rem := True;π if Pos('(*', T) > 0 thenπ beginπ For Y := Pos('(*', T) to Pos('*)', T) doπ if (T[Y] = '$') or (T[Y] = '''') thenπ Rem := False;π if (Rem) and (not Odd(NumChar('''', T, Pos('(*', T)))) thenπ Delete(T, Pos('(*', T), Pos('*)', T)+2-Pos('(*', T));π end;π if Pos('{', T) > 0 thenπ beginπ For Y := Pos('{', T) to Pos('}', T) doπ if (T[Y] = '$') or (T[Y] = '''') thenπ Rem := False;π if (Rem) and (not Odd(NumChar('''', T, Pos('(*', T)))) thenπ Delete(T, Pos('{', T), Pos('}', T)+1-Pos('{', T));π end;πend;ππbeginπ ReadLn(S);π Assign(F, S);π Reset(F);π ReadLn(S);π Assign(F2, S);π ReWrite(F2);π R := '';π S := '';ππ While not EoF(F) doπ beginπ ReadLn(F, R);π StripComments(R);π R := Trim(R);π X := 1;π While X <= Length(R) doπ beginπ InString := (R[X] = '''') xor InString;π if not InString thenπ beginπ if R[X] = #9 thenπ R[X] := ' ';π if ((R[X] = ' ') and (R[X+1] = ' ')) thenπ beginπ Delete(R, X, 1);π if X > 1 thenπ Dec(X);π end;π if ((R[X] = ' ') and not(R[X+1] in Alpha)) thenπ Delete(R, X, 1);π if ((R[X+1] = ' ') and not(R[X] in Alpha)) thenπ Delete(R, X+1, 1);π R[X] := UpCase(R[X]);π end;π Inc(X);π end;π if (Length(R) > 0) and (R[Length(R)] <> ';') thenπ R := R+' ';π if Length(R)+Length(S) <= 127 thenπ S := TrimF(S+R)π elseπ beginπ WriteLn(F2, Trim(S));π S := TrimF(R);π end;π end;ππ WriteLn(F2, S);π Close(F);π Close(F2);πend.π{π > 1) Remove whitespace.πJust removes indentation now.π > 2) Put lines together (max. length approx. 120 Chars).πThis is going to be one of the harder parts.π > 3) Make everything lower-Case (or upper-Case).πNo need.. see 4.π4. Convert all Types, Consts, and VarS to an encypted name, like so:π IIl0lll1O0lI1π5. Convert all Procedures, and Functions like #4π6. On Objects, Convert all "data" fields. Leave alone all others except Forπthe "ConstRUCtoR" and on that, only check to see if any Types are being used.πConstructors are the only ones that can change from the ancestor.π7. on Records, When Typed like this:πaRec.Name:='Rob Green'; check to see if arec is in the list, if not, skip.πif like this:π With arec doπ name:='Rob Green'; do the same as above, but check For begin and end.π8. Leave externals alone.π9. Also mangle the Includes.π10. Leave Any Interface part alone, and only work With the Implementation.πThis is what my mangler currently does.(all except For #7 and #10, havent gotπthat Far yet.) Any ways it works pretty good. im happy With the results iπam getting With it. It makes it "VERY" hard to read. The only thing i seeπhaving trouble With down the line, is the "Compressing" of mulitiple lines.ππAnyways, heres a small Program, and then what PAM(Pascal automatic mangler)πdid to it:π}ππProgram test;ππTypeπ pstr30 = ^str30;π str30 = String[30];ππVarπ b : Byte;π s : pstr30;ππFunction hex(b : Byte) : String;πConstπ Digits : Array [0..15] of Char = '0123456789ABCDEF';πVarπ s:String;πbeginπ s:='';π s[0] := #2;π s[1] := Digits [b shr 4];π s[2] := Digits [b and $F];π hex:=s;πend;ππbeginπ new(s);π s^:='Hello world';π Writeln(s^);π Writeln('Enter a Byte to convert to hex:');π readln(b);π s^:=hex(b);π Writeln('Byte :',b,' = $',s^);π dispose(s);πend.πππProgram test;πTypeπ IO1II0IO00O = ^II0lOl1011I;π II0lOl1011I = String[30];πVarπ III0O1ll10l:Byte;π I11110I11Il0:IO1II0IO00O;ππFunction Il00O011IO0I(III0O1ll10l:Byte):String;πConstπ Illl1OOOO0I : Array [0..15] of Char = '0123456789ABCDEF';πVarπ I11110I11Il0:String;πbeginπ I11110I11Il0:='';π I11110I11Il0[0] := #2;π I11110I11Il0[1] := Illl1OOOO0I [III0O1ll10l shr 4];π I11110I11Il0[2] := Illl1OOOO0I [III0O1ll10l and $F];π Il00O011IO0I:=I11110I11Il0;πend;πbeginπ new(I11110I11Il0);π I11110I11Il0^:='Hello world';π Writeln(I11110I11Il0^);π Writeln('Enter a Byte to convert to hex:');π readln(III0O1ll10l);π I11110I11Il0^:=Il00O011IO0I(III0O1ll10l);π Writeln('Byte :',III0O1ll10l,' = $',I11110I11Il0^);π dispose(I11110I11Il0);πend.ππ 22 07-16-9306:13ALL KENT BRIGGS Randmom Number Function IMPORT 16 èo ===========================================================================π BBS: Canada Remote SystemsπDate: 06-18-93 (23:27) Number: 26893πFrom: KENT BRIGGS Refer#: NONEπ To: BRIAN PAPE Recvd: NO πSubj: RANDOM NUMBERS Conf: (1221) F-PASCALπ---------------------------------------------------------------------------π -=> Quoting Brian Pape to Erik Johnson <=-ππ BP> Please- I *am* looking for the source code to a decent random numberπ BP> generator so that I'm not dependant on Borland.ππ Brian, Borland did change their random:word function when they releasedπ 7.0. However the random:real function, the randomize procedure, and theirπ method of updating randseed remain the same as ver 6.0. Using DJ Murdoch'sπ CycleRandseed procedure and reverse engineering TP6's and TP7's Randomπ functions, I came up with the following routines:ππconst rseed: longint = 0;ππprocedure randomize67; {TP 6.0 & 7.0 seed generator}πbeginπ reg.ah:=$2c;π msdos(reg); {get time: ch=hour,cl=min,dh=sec,dl=sec/100}π rseed:=reg.dx;π rseed:=(rseed shl 16) or reg.cx;πend;ππfunction rand_word6(x: word): word; {TP 6.0 RNG: word}πbeginπ rseed:=rseed*134775813+1;π rand_word6:=(rseed shr 16) mod x;πend;ππfunction rand_word7(x: word): word; {TP 7.0 RNG: word}πbeginπ rseed:=rseed*134775813+1;π rand_word7:=((rseed shr 16)*x+((rseed and $ffff)*x shr 16)) shr 16;πend;ππfunction rand_real67: real; {TP 6.0 & 7.0 RNG: real}πbeginπ rseed:=rseed*134775813+1;π if rseed<0 then rand_real67:=rseed/4294967296.0+1.0 elseπ rand_real67:=rseed/4294967296.0;πend;ππIf anyone can improve on these please post some code here, thanks.ππ___ Blue Wave/QWK v2.12π--- Renegade v06-11 Betaππ * Origin: Snipe's Castle BBS, Waco TX (817)-757-0169 (1:388/26)π 23 08-18-9312:20ALL JOSE ALMEIDA Get the active code page IMPORT 20 èo { Gets the active (set by user) and system (at boot byte) code page.π Part of the Heartware Toolkit v2.00 (HTelse.PAS) for Turbo Pascal.π Author: Jose Almeida. P.O.Box 4185. 1504 Lisboa Codex. Portugal.π I can also be reached at RIME network, site ->TIB or #5314.π Feel completely free to use this source code in any way you want, and, ifπ you do, please don't forget to mention my name, and, give me and Swag theπ proper credits. }ππPROCEDURE Get_Code_Page(var Active_CP : word;π var System_CP : word;π var Error_Code : byte);π{ DESCRIPTION:π Gets the active (set by user) and system (at boot byte) code page.π SAMPLE CALL:π Get_Code_Page(Active_CP,Default_CP,Error_Code);π RETURNS:π Active : active code page set by userπ System : system code page at boot timeπ Error_Codeπ 0 : no errorπ else : see The Programmers PC Source Book 3.191π NOTES:π Applies to all versions beginning with v3.3.π See Get_Code_Page_Text() in order to get string text. }ππvarπ HTregs : registers;ππBEGIN { Get_Code_Page }π HTregs.AX := $6601;π MsDos(HTregs);π if HTregs.Flags and FCarry <> 0 thenπ beginπ Active_CP := $FFFF; { on error set to $FFFF }π System_CP := $FFFF; { on error set to $FFFF }π Error_Code := HTregs.AL;π endπ elseπ beginπ Active_CP := HTregs.BX;π System_CP := HTregs.DX;π Error_Code := 0;π end;πEND; { Get_Code_Page }ππππFUNCTION Get_Code_Page_Text(CP : word) : String14;ππ{ DESCRIPTION:π Gets the current active code page in string form.π SAMPLE CALL:π St := Get_Code_Page_Text(860);π RETURNS:π e.g.: 'Portugal'π NOTES:π None. }ππBEGIN { Get_Code_Page_Text }π case CP ofπ 437 : Get_Code_Page_Text := 'USA English';π 850 : Get_Code_Page_Text := 'Multilingual';π 852 : Get_Code_Page_Text := 'CZ/SL/HU/PL/YU';π { CZ and SL = Czechoslovakia (Czech & Slovak) }π { HU = Hungary }π { PL = Poland }π { YU = Yugoslavia }π 854 : Get_Code_Page_Text := 'Spain';π 860 : Get_Code_Page_Text := 'Portugal';π 863 : Get_Code_Page_Text := 'Canada-French';π 865 : Get_Code_Page_Text := 'Norway/Denmark';π elseπ Get_Code_Page_Text := 'Unknown';π end;πEND; { Get_Code_Page_Text }π 24 08-18-9312:27ALL JOSE ALMEIDA Intra-App Comm Area IMPORT 15 èo { Gets or puts information in the Intra-Application Communications Area (ICA).π Part of the Heartware Toolkit v2.00 (HTmemory.PAS) for Turbo Pascal.π Author: Jose Almeida. P.O.Box 4185. 1504 Lisboa Codex. Portugal.π I can also be reached at RIME network, site ->TIB or #5314.π Feel completely free to use this source code in any way you want, and, ifπ you do, please don't forget to mention my name, and, give me and Swag theπ proper credits. }ππPROCEDURE ICA(GetPut : boolean;π var SourceDest);π{ DESCRIPTION:π Gets or puts information in the Intra-Application Communications Area (ICA).π SAMPLE CALL:π ICA(True,MyVar);π orπ ICA(False,MyVar);π RETURNS:π See notes (bellow).π NOTES:π These sixteen bytes, called the Intra-Application Communications Areaπ (ICA) can be used by any program for any purpose, Usually it is usedπ to pass data betwenn two or more programs. Not many programs use thisπ area. If you wish to use this area, make sure checksums and signaturesπ are used to insure the reliability of your data, since another programπ may also decide to use this area.π [in The Assembly Language Database, Peter Norton]π The incomming SourceDir variable may be of any type.π Nevertheless, the size of that variable MUST be at least 16 bytes long,π or unpredictable results may occur...π The programer before changing this area contents, should keep itsπ contents in a variable for later restore. It is not a very good ideiaπ to not restore the contents before the program end, because thatπ area may being used by another program. }ππBEGIN { ICA }π if GetPut thenπ Move(Mem[$0000:$04F0],SourceDest,16)π elseπ Move(SourceDest,Mem[$0000:$04F0],16)πEND; { ICA }π 25 08-18-9312:28ALL JOSE ALMEIDA Get Print Screen Status IMPORT 8 èo { Gets the status of the last or current Print Screen operation.π Part of the Heartware Toolkit v2.00 (HTparal.PAS) for Turbo Pascal.π Author: Jose Almeida. P.O.Box 4185. 1504 Lisboa Codex. Portugal.π I can also be reached at RIME network, site ->TIB or #5314.π Feel completely free to use this source code in any way you want, and, ifπ you do, please don't forget to mention my name, and, give me and Swag theπ proper credits. }ππFUNCTION PrtSc_Status : byte;π{ DESCRIPTION:π Gets the status of the last or current Print Screen operation.π SAMPLE CALL:π NB := PrtSc_Status;π RETURNS:π 00h : Print Screen completeπ 01h : Print Screen currently in progressπ FFh : Error occurred during Print Screen }ππBEGIN { PrtSc_Status }π PrtSc_Status := Mem[$0000:$0500];πEND; { PrtSc_Status }π 26 08-27-9320:00ALL SWAG SUPPORT TEAM Finding Anagrams IMPORT 47 èo {$A+,B+,D+,E-,F+,G+,I+,L+,N-,O+,P+,Q+,R+,S+,T+,V-,X+,Y+}π{$M 65520,100000,655360}π{πProgram compiled and tested With BP 7.0ππWARNING since this Program is not using the fastest algorithm toπfind it's Anagrams, long Delays can be expected For largeπinput-Strings.ππTest have shown the following results:ππ Length of Input Number of anagrams foundππ 2 2π 3 6π 4 24π 5 120π 6 720π 7 5040ππAs can plainly be seen from this, the number of Anagrams For aπString of length N is a direct Function of the number of AnagramsπFor a String of N-1. In fact the result is f(N) = N * f(N-1).ππYou might have recognised the infamous FACTORIAL Function!!!ππTypeπ MyType = LongInt;ππFunction NumberOfAnagrams(Var InputLen : MyType) : MyType;ππ Varπ Temp : MyType;ππ beginπ Temp := InputLen;π if Temp >1 thenπ beginπ Temp := Temp - 1;π NumberOfAnagrams := InputLen * NumberOfAnagrams(Temp);π end elseπ NumberOfAnagrams := InputLen;π end;ππThe above Function has been tested and found to work up to an inputπlength of 12. After that, Real numbers must be used. As a side noteπthe Maximum value computable was 1754 With MyType defined asπExtended and Numeric-Coprocessor enabled of course. Oh and BTW, theπparameter is passed as a Var so that the Stack doesn't blow up whenπyou use Extended Type!!!! As a result, you can't pass N-1 to theπFunction. You have to STORE N-1 in a Var and pass that as parameter.πThe net effect is that With Numeric Copro enabled, at 1754 it blowsπup because of a MATH OVERFLOW, not a STACK OVERFLOW!!!ππBased on these findings, I assume the possible anagrams can beπcomputed a lot faster simply by Realising that the possible AnagramsπFor an input length of (N) can be found by finding all anagrams forπan input Length of (N-1) and inserting the additional letter in eachπ(N) positions in those Strings. Since this can not be doneπrecursively in memory, the obvious solution would be to to outputπthe anagrams strating With the first 4 or 5 caracters to a File,πbecause those can be found quickly enough, and then to read in eachπString and apply the following caracters to each and Repeat thisπprocess Until the final File is produced.ππHere is an example:ππ Anagrams For ABCDππ Output Anagrams For AB to Fileππ Giving AB and BAππ read that in and apply the next letter in all possible positionsππ Givingπ abCπ aCbπ Cabπ &π baCπ bCaπ Cbaππ Now Apply the D to this and getππ abcDπ abDcπ aDbcπ Dabcπ &ππ acbDπ acDbπ aDcbπ Dacbππ Etc... YOU GET THE POINT!!!ππBTW Expect LARGE Files if you become too enthousiastic With this!!!ππ An Input of just 20 caracters long will generate a File ofππ 2,432,902,008,176,640,000 Anagramsπ That'sπ 2.4 Quintillion Anagramsππ Remember that each of those are 20 caracters long,π add Carriage-return and line-feeds and you've got yourself aπ HUGE File ;-)ππ In fact just a 10 Caracter input length will generate 3.6 Millionπ Anagrams from a 10 Caracter input-String. Again add Cr-LFs andπ you've got yourself a 43.5 MEGAByte File!!!!!! but consider youπ are generating it from the previous File which comes to 3.5 MEGπ For an Input Length of 9 and you've got yourself 45 MEG of DISK inπ use For this job.ππ}πUsesπ Strings, Crt;ππConstπ MaxAnagram = 1000;ππTypeπ AnagramArray = Array[0..MaxAnagram] of Word;π AnagramStr = Array[0..MaxAnagram] of Char;ππVarπ Target : AnagramStr;π Size : Word;π Specimen : AnagramArray;π Index : Word;π AnagramCount : LongInt;ππProcedure working;πConstπ CurrentCursor : Byte = 0;π CursorArray : Array[0..3] of Char = '|/-\';πbeginπ CurrentCursor := Succ(CurrentCursor) mod 4;π Write(CursorArray[CurrentCursor], #13);πend;ππProcedure OutPutAnagram(Target : AnagramStr;π Var Specimen : AnagramArray; Size : Word);πVarπ Index : Word;πbeginπ For Index := 0 to (Size - 1) doπ Write(Target[Specimen[Index]]);π Writeln;πend;ππFunction IsAnagram(Var Specimen : AnagramArray; Size : Word) : Boolean;πVarπ Index1,π Index2 : Word;π Valid : Boolean;πbeginπ Valid := True;π Index1 := 0;π While (Index1<Pred(Size)) and Valid doπ beginπ Index2 := Index1 + 1;π While (Index2 < Size) and Valid doπ beginπ if Specimen[Index1] = Specimen[Index2] thenπ Valid := False;π inc(Index2);π end;π inc(Index1);π end;π IsAnagram := Valid;πend;ππProcedure FindAnagrams(Target : AnagramStr;π Var Specimen : AnagramArray; Size : Word);πVarπ Index : Word;π Carry : Boolean;πbeginπ Repeatπ working;π if IsAnagram(Specimen, Size) thenπ beginπ OutputAnagram(Target, Specimen, Size);π inc(AnagramCount);π end;π Index := 0;π Repeatπ Specimen[Index] := (Specimen[Index] + 1) mod Size;π Carry := not Boolean(Specimen[Index]);π Inc(Index);π Until (not Carry) or (Index >= Size);π Until Carry and (Index >= Size);πend;ππbeginπ ClrScr;π Write('Enter anagram Target: ');π readln(Target);π Writeln;π AnagramCount := 0;π Size := Strlen(Target);π For Index := 0 to MaxAnagram doπ Specimen[Index] := 0;π For Index := 0 to Size - 1 doπ Specimen[Index] := Size - Index - 1;π FindAnagrams(Target, Specimen, Size);π Writeln;π Writeln(AnagramCount, ' Anagrams found With Source ', Target);πend.π 27 08-27-9320:01ALL MARK OUELLET Fast Anagrams IMPORT 20 èo {$A+,B+,D+,E-,F+,G+,I+,L+,N-,O+,P+,Q+,R+,S+,T+,V-,X+,Y+}π{$M 65520,100000,655360}π{π Copyright 1993 Mark Ouellet. All rights reserved.ππ May be freely distributed and incorporated in your own code, in partπ or in it's entirety as long as due credit is given to it's authorππ All I ask is that you state my name if you use ALL or PART of it inπ your own code.π}ππProgram FastAnagrams;ππUsesπ Crt;ππTypeπ StrPointer = ^String;π NodePtr = ^Node;π Node = Recordπ Anagram : StrPointer;π Next : NodePtr;π end;ππVarπ OldAnagrams : NodePtr;π NewAnagrams : NodePtr;π OldCursor : NodePtr;π NewCursor : NodePtr;π InputStr : String;ππProcedure GetInput;πbeginπ ClrScr;π Write('Input your String: ');π readln(InputStr);πend;ππProcedure FindAnagrams;ππVarπ OldIndex : Word;π NewIndex : Word;ππbeginπ OldAnagrams := NIL;π OldCursor := NIL;π NewAnagrams := NIL;π NewCursor := NIL;ππ New(OldCursor);π OldCursor^.Next := OldAnagrams;π GetMem(OldCursor^.Anagram, 2);π OldCursor^.Anagram^ := Copy(InputStr, 1, 1);π OldAnagrams := OldCursor;ππ For OldIndex := 2 to Ord(InputStr[0]) doπ beginπ OldCursor := OldAnagrams;π While OldCursor <> NIL doπ beginπ For NewIndex := 1 to Ord(OldCursor^.Anagram^[0])+1 doπ beginπ New(NewCursor);π NewCursor^.Next := NewAnagrams;π getmem(NewCursor^.Anagram, sizeof(OldCursor^.Anagram^)+1);π NewCursor^.Anagram^ := OldCursor^.Anagram^;π Insert(Copy(InputStr, OldIndex, 1),π NewCursor^.Anagram^, NewIndex);π NewAnagrams := NewCursor;π end;π OldCursor := OldCursor^.Next;π FreeMem(OldAnagrams^.Anagram, Ord(OldAnagrams^.Anagram^[0])+1);π OldAnagrams^.Anagram := nil;π Dispose(OldAnagrams);π OldAnagrams := OldCursor;π end;π OldAnagrams := NewAnagrams;π OldCursor := OldAnagrams;π NewAnagrams := NIL;π NewCursor := NIL;π end;πend;ππProcedure OutputAnagrams;πVarπ Count : Word;πbeginπ Count := 0;π OldCursor := OldAnagrams;π While OldCursor <> NIL doπ beginπ OldCursor := OldCursor^.Next;π Writeln(OldAnagrams^.Anagram^);π FreeMem(OldAnagrams^.Anagram, sizeof(OldAnagrams^.Anagram^));π dispose(OldAnagrams);π OldAnagrams := OldCursor;π Inc(Count);π end;π Writeln;π Writeln(Count, ' Anagrams found.');πend;ππbeginπ GetInput;π Writeln;π Writeln(MaxAvail, ' Available memory.');π Writeln;π FindAnagrams;π OutputAnagrams;πend.π 28 08-27-9320:35ALL DAVID JURGENS dBase II File Structure IMPORT 17 èo HelpPC 2.0 PC Programmers Referenceπ Copyright (c) 1990 David Jurgensππ dBASE - File Header Structure (dBASE II)ππ Offset Size Descriptionππ 00 byte dBASE version number 02h=dBASE IIπ 01 word number of data records in fileπ 03 byte month of last updateπ 04 byte day of last updateπ 05 byte year of last updateπ 06 word size of each data recordπ 08 512bytes field descriptors (see below)π 520 byte 0Dh if all 32 field descriptors used; otherwise 00hππ - dBASE II file header has a fixed size of 521 bytesπππ DBASE - File header structure (DBASE III)ππ Offset Size Descriptionππ 00 byte dBASE vers num 03h=dBASE III w/o .DBTπ 83h=dBASE III w .DBTπ 01 byte year of last updateπ 02 byte month of last updateπ 03 byte day of last updateπ 04 dword long int number of data records in fileπ 08 word header structure lengthπ 10 word data record lengthπ 12 20bytes version 1.0 reserved data spaceπ 32-n 32bytes ea. field descriptors (see below)π n+1 byte 0dH field terminator.πππ - unlike dBASE II, dBASE III has a variable length headerπππ dBASE - Field Descriptorsππ dBASE II Field Descriptors (header contains 32 FDs)ππ Offset Size Descriptionππ 00 11bytes null terminated field name string, 0Dh as firstπ byte indicates end of FDsπ 11 byte data type, Char/Num/Logical (C,N,L)π 12 byte field lengthπ 13 word field data address, (set in memory)π 15 byte number of decimal placesπππ dBASE III Field Descriptors (FD count varies):ππ Offset Size Descriptionππ 00 11bytes null terminated field name stringπ 11 byte data type, Char/Num/Logical/Date/Memoπ 12 dword long int field data address, (set in memory)π 16 byte field lengthπ 17 byte number of decimal placesπ 18 14bytes version 1.00 reserved data areaππ 29 08-27-9320:38ALL GORDON TACKETT Device Driver in TP IMPORT 8 èo {πGORDON TACKETTππIn version 7 of TP/BP you can write a device driver But it is tricky! Theπfollowing code is not fully tested but seems to work. After looking at someπdisassembly listings I added the patch file section. Use or abuse at your ownπrisk :-)π}ππProgram TestDriver;ππProcedure Dev_Strategy; Forward;πProcedure Dev_Int; Forward;ππProcedure DeviceDriverHeader;πbeginπ Inline(π $FFFF/π $FFFF/π $2000/π $0000/π $0000/π $FFFF/$FFFF/$FFFF/$FFFF/0);πEnd;ππProcedure Dev_Strategy;πBeginπEnd;ππProcedure Dev_Int;πBeginπEnd;ππVarπ F : File;ππBeginπ If ParamCount = 999 Thenπ DeviceDriverHeaderπ elseπ Beginπ {patch driver}π movemem(devicedriverheader, DeviceDriverHeader + 3, 20);π Assign(F, ParamStr(0));π Reset(F, 1);π BlockWrite(F, DeviceDriverHeader, 20);π Close(F);π End;πEnd.ππ 30 08-27-9320:38ALL D.J. MURDOCK Another Device in TP IMPORT 42 èo {πI've written a simple device driver in TP, and it works. From some things I'veπheard, it won't work in all versions of DOS (it's an .EXE format device driver,πnot a .BIN format one). There are tons of restrictions on what you can do inπit - DOS isn't reentrant, and the TP system library isn't designed to do thingsπwhile DOS is active, so I don't even let it get initialized, etc., etc.ππIt's still a bit of a mess, but here it is, for your enjoyment and edification:π a character device driver that keeps a buffer of 255 characters, calledπTPDEVICE.ππTo try it out, compile it (you'll need OPro or TPro; sorry, but stack swappingπis essential, and I wouldn't want to try to write code to do it myself), put itπinto your CONFIG.SYS (on a floppy disk, please!) asππ device=tpdev.exeππand then reboot. Hopefully you won't crash, but if you do, you'll have toπreboot from a different disk and remove it from CONFIG.SYS.ππThen you can tryππ COPY TPDEVICE CONππto see the initialization message, andππ ECHO This is a line for the buffer >TPDEVICEππto replace it with a new one.π}π{ DOS character device driver written entirely in TP 6 }ππ{ Written by D.J. Murdoch for the public domain, May 1991 }ππ{$S-,F-} { Stack checking wouldn't work here, and we assume near calls }π{$M $1000,0,0} { We can't use the heap and don't use the stack. Thisπ setting doesn't really matter though, since you normallyπ won't run TPDEV }ππprogram tpdev;ππusesπ opint; { OPro interrupt services, needed for stack switching }ππprocedure strategy_routine(bp:word); interrupt; forward;πprocedure interrupt_routine(bp:word); interrupt; forward;ππprocedure header; assembler;π{ Here's the trick: an assembler routine in the main program, guaranteed toπ be linked first in the .EXE file!!}πasmπ dd $FFFFFFFF { next driver }π dw $8000 { attributes of simple character device }π dw offset strategy_routineπ dw offset interrupt_routineπ db 'TPDEVICE'πend;ππconstπ stDone = $100;π stBusy = $200;ππ cmInit = 0;π cmInput = 4;π cmInput_no_wait = 5;π cmInput_status = 6;π cmInput_flush = 7;π cmOutput = 8;π cmOutput_Verify = 9;π cmOutput_status = 10;π cmOutput_flush = 11;ππtypeπ request_header = recordπ request_length : byte;π subunit : byte;π command_code : byte;π status : word;π reserved : array[1..8] of byte;π case byte ofπ cmInit : (num_units : byte;π first_free : pointer;π args : ^char;π drive_num : byte;);π cmInput : { also used for output }π (media_descriptor : byte;π buffer : pointer;π byte_count : word);π cmInput_no_wait : (next_char : char);π end;ππvarπ local_stack : array[1..4000] of byte;π end_of_stack : byte;π request : ^request_header;π line : string;ππprocedure handler(var regs : intregisters);π{ This routine is called by the strategy routine, and handles all requests.π The data segment is okay, and we're running on the local_stack so we've gotπ plenty of space, but remember:π ****** The initialization code for SYSTEM and all other units hasn'tπ ever been called!! ******** }πbeginπ with request^ doπ beginπ case command_code ofππ cmInit :π beginπ { Last thing in the data segment in TP6 - No heap!!}π first_free := ptr(dseg, ofs(saveint75) + 4);π status := stDone;π line := 'TPDRIVER successfully initialized.';π end;ππ cmInput :π beginπ if byte_count > length(line) thenπ byte_count := length(line);π move(line[1], buffer^, byte_count);π line := copy(line, byte_count + 1, 255);π status := stDone;π end;ππ cmInput_no_wait :π beginπ if length(line) > 0 thenπ beginπ next_char := line[1];π status := stDone;π endπ elseπ status := stBusy;π end;ππ cmInput_Status,π cmOutput_Status,π cmInput_Flush,π cmOutput_Flush : status := stDone;ππ cmOutput,π cmOutput_Verify :π beginπ if byte_count + length(line) > 255 thenπ byte_count := 255 - length(line);π move(buffer^, line[length(line) + 1], byte_count);π line[0] := char(byte(byte_count + length(line)));π status := stDone;π end;π end;π end;πend;ππprocedure RetFar; assembler;π{ Replacement for the IRET code that ends the interrupt routines below }πasmπ mov sp,bpπ pop bpπ pop esπ pop dsπ pop diπ pop siπ pop dxπ pop cxπ pop bxπ pop axπ retfπend;ππprocedure strategy_routine(bp : word);πvarπ regs : intregisters absolute bp;πbeginπ with regs doπ request := ptr(es, bx);π RetFar;πend;ππprocedure interrupt_routine(bp : word);πvarπ regs : intregisters absolute bp;πbeginπ SwapStackandCallNear(Ofs(handler), @end_of_stack, regs);π RetFar;πend;ππbeginπ writeln('TPDEVICE - DOS device driver written *entirely* in Turbo Pascal.');π writeln('Install using DEVICE=TPDEV.EXE in CONFIG.SYS.');π request := @header; { Need a reference to pull in the header. }πend.π 31 08-27-9320:55ALL JACK MOFFITT File at end of EXE IMPORT 25 èo {πJACK MOFFITTππ>Okay, how about this: If I wanted to attach it to the back of an EXE, Iπ>COPY /B it. Now, in the source code, how do I find the picture and setπ>everything up? I mean do you LoadGif (Ofs,Seg) or something? That's whatπ>I mean, and I'm sorry to put you through this.ππOk.. here we go.. everyone seems to be asking this, so i'll just postπsome source. Granted this is not a COMPLETE program, just an example onπhow to read the header, and get a pointer to the GIF.π}ππ(* This code originally by Scott Johnson, I revised it later *)ππfunction GetSize(N : byte) : word;πfunction GetData(N : byte) : pointer;πfunction GetDataCount : byte;ππimplementationππusesπ Dos;ππtypeπ DataRec = recordπ Size : word;π Loc : longint;π end;π DataArray = array [1..255] of DataRec;π DataArrayPtr = ^DataArray;ππ ExeDataRec = recordπ ActSize : word;π end;πππvarπ ExeFile : file;π DataCount : byte; { count of data records }π Data : DataArrayPtr;ππprocedure OpenExe;πbeginπ assign(ExeFile, ParamStr(0));π reset(ExeFile, 1);πend;ππprocedure CloseExe;πbeginπ Close(ExeFile);πend;ππprocedure InitExe;πvarπ ExeHdr : recordπ M, Z : char;π Len : word;π Pages : word;π end;π ExeLoc : longint;π I : byte;π ExeData : ExeDataRec;πbeginπ OpenExe;π BlockRead(ExeFile, ExeHdr, SizeOf(ExeHdr));π if ExeHdr.Len = 0 thenπ ExeHdr.Len := $200;π ExeLoc := (longint(ExeHdr.Pages) - 1) shl 9 + longint(ExeHdr.Len);π Seek(ExeFile, ExeLoc);π BlockRead(ExeFile, DataCount, 1); { read data count byte }π Inc(ExeLoc);π GetMem(Data, SizeOf(DataRec) * DataCount);π for I := 1 to DataCount doπ beginπ Seek(ExeFile, ExeLoc);π BlockRead(ExeFile, ExeData, SizeOf(ExeData));π Data^[I].Loc := ExeLoc;π Data^[I].Size := ExeData.ActSize;π Inc(ExeLoc, ExeData.ActSize + 2);π end;π CloseExe;πend;ππfunction GetSize(N : byte) : word;πbeginπ if N > DataCount thenπ RunError(201);π GetSize := Data^[N].Size;πend;ππfunction GetData(N : byte) : pointer;πvarπ P, D : pointer;π DataLoc : longint;π E : ExeDataRec;πbeginπ if N > DataCount thenπ RunError(201);π GetMem(P, Data^[N].Size);π OpenExe;π Seek(ExeFile, Data^[N].Loc + 2); { +2 is to get past info record }π BlockRead(ExeFile, P^, Data^[N].Size);π CloseExe;π GetData := P;πend;ππfunction GetDataCount : byte;πbeginπ GetDataCount := DataCount;πend;ππbeginπ InitExe;πend.ππ{πOk.. that's it. Call GetData(x) to get the location of the firstπelement. Datacount is the number of GIFs or whatever you have in thereπand the first two bytes are the actual size.. So to add a file, justπmake a temp file called ADDED.DAT, write a byte value for the datacount,πand a word value for the filesize of the data you're adding, and thenπthe data. Hope this help all of you who wanted to be able to add ANSis,πGIFs, and whatnot onto exes. Also, with little modification, you canπmake it read from .DAT files with multiple gifs and stuff in them.π}π 32 08-27-9320:55ALL GABE KRUPA Modify EXE constants IMPORT 65 èo (*πGABE KRUPAππ> I need to add some information to the end of an EXE file and be ableπ> Say a PCX image for example. I'm concerned about the EXE file alreadπ> open due to being executed. Does info tacked to the end of an EXE geπ> into memory automatically, etc. I haven't tried this yet but am abouπ> hoping someone who has tried it can assist me to avoid some of the piπ> they may have encountered. Thanks. (BTW, I am experienced in Pas &ππ Well, I made a unit for that purpose, but my unit only tacks on 1K ofπstorage space... You can make it as large as you want it, but it'll be aπREAL time consumer and it might push your text editor to the limits (I'mπnot sure if the IDE has a file size limit).ππ Here it is (in a VERY shortened version )π}πunit inject1k;ππinterfaceπimplementationπconst doesnt_matter_what_this_is_called : boolean = false;ππprocedure never_really_call_this_procedure;πbeginπ if doesnt_matter_what_this_is_called thenπ inline( 228/229/230/231/231/233/234/ { this I use for a ID string }π 234/234/234/234/234/234/234/π 234/234/234/234/243/234/234/π{ repeat as many times until you get enough .. each '234/' is 1 byte }π 234/234/234/234/234/234/234/π 234/234/234/234/234/234/234/ { this is the actual 'junk' }π ); { inline }πend; { procedure }ππend. { unit }π{π I only inject 1024 into my EXE file... If you want, you can makeπidentical units like that, but the DATA area will NOT be in one longπstring unless all the bytes are in one unit.π I use the ID string to correctly place the file pointer. Just open theπEXE, read in bytes until you get a 228. Read another, if it's a 229πetc.. Keep looping until you get a 228-229-230-231-232-233-234 and thenπyou can start reading/writing. It's by no means the easiest way, but Iπprefer it over trying to append to the end. I tried that, but I keptπgetting errors and such. As long as the PCX file is fairly small, youπwon't have too much of a problem.π I'm not sure what the chances are, they must be pretty slim to find aπstring (228-234) one after the other in an EXE. If you think they areπhigher, or whatever, just put your own in. You could probably even putπtext in like this:π}πinline('D'/'A'/'T'/'A'/' '/'S'/'T'/'A'/'R'/'T'/'S'/' '/'H'/'E'/'R'/'E'/π111/111/111/111 { etc... } );π{π I hope this helps, or gives you some ideas. Note, the unit willπbe about TWICE as large as the number of bytes you inject (maybe 1000πmore), but the EXE will only increse by the number you add. I'm prettyπsure that the extra bytes are just data/debug info in the TPU file.π*)ππ{πMARK LEWISππ> I need to add some information to the end of an EXE file and be ableπ> Say a PCX image for example. I'm concerned about the EXE file alreadππ[... trim ...]ππ> Well, I made a unit for that purpose, but my unit only tacks onπ> 1K of storage space... You can make it as large as you want it,π> but it'll be a REAL time consumer and it might push your textπ> editor to the limits (I'm not sure if the IDE has a file sizeπ> limit). Here it is (in a VERY shortened version )π> unit inject1k;ππ[... trim ...]ππinteresting<<smile>>... i never thought of doing it like that.. hehe.. here'sπa unit i got from this echo or the other PASCAL echo several years ago.. i'veπused it in self-limiting programs (ones that only run a certain number ofπtimes) and other programs that may be subject to hacking of various forms...πi've modified it slightly for my purposes...π}πunit selfmod;ππ{ Allows a program to self modify a typed constant in the .exe file. It }π{ also performs an automatic checksum type .exe file integrity check. }π{ A longint value is added to the end of the exe file. This can be read by }π{ a separate configuration program to enable it to determine the start of }π{ the programs configuration data area. To use this the configuration }π{ typed constant should be added immediately following the declaration of }π{ ExeData. }π{ Where this unit is used, it should always be the FIRST unit listed in the }π{ uses declaration area of the main program. }π{ Requires DOS 3.3 or later. Program must not be used with PKLite or LZExe }π{ or any similar exe file compression programs. }π{ The stack size needed is at least 9,000 bytes. }ππinterfaceππtypeπ ExeDatatype = recordπ IDStr : string[8];π FirstTime : boolean;π Hsize : word;π ExeSize : longint;π CheckSum : longint;π StartConst : longint;π end;ππconstπ ExeData : ExeDatatype = (IDStr : 'IDSTRING';π FirstTime : true;π Hsize : 0;π ExeSize : 0;π CheckSum : 0;π StartConst: 0);ππ{ IMPORTANT: Put any config data typed constants here }ππprocedure Write2Exec(var data; size: word);ππ{============================================================================}ππimplementationππprocedure InitConstants;π varπ f : file;π tbuff : array[0..1] of word;ππ function GetCheckSum : longint;π { Performs a checksum calculation on the exe file }π varπ finished : boolean;π x,π CSum : longint;π BytesRead : word;π buffer : array[0..4095] of word;π beginπ {$I-}π seek(f,0);π finished := false; CSum := 0; x := 0;π BlockRead(f,buffer,sizeof(buffer),BytesRead);π while not finished do begin { do the checksum calculations }π repeat { until file has been read up to start of config area }π inc(CSum,buffer[x mod 4096]);π inc(x);π finished := ((x shl 1) >= ExeData.StartConst);π until ((x mod 4096) = 0) or finished;π if not finished then { data area has not been reached }π BlockRead(f,buffer,sizeof(buffer),BytesRead);π end;π GetCheckSum := CSum;π end;ππ beginπ assign(f, ParamStr(0));π {$I-} Reset(f,1);π with ExeData do beginπ if FirstTime and (IOResult = 0) then beginπ Seek(f,2); { this location has the executable size }π BlockRead(f,tbuff,4);π ExeSize := tbuff[0]+(pred(tbuff[1]) shl 9);π seek(f,8); { get the header size }π BlockRead(f,hsize,2);π FirstTime := false;π StartConst := longint(hsize+Seg(ExeData)-PrefixSeg) shl 4 +π Ofs(ExeData) - 256;π CheckSum := GetCheckSum;π Seek(f,StartConst);π BlockWrite(f,ExeData,sizeof(ExeData));π seek(f,FileSize(f));π BlockWrite(f,StartConst,4);π endπ elseπ if GetCheckSum <> CheckSum then beginπ writeln;π writeln(#7,#7,'Program file has been UNLAWFULLY modified!',#7,#7);π writeln;π writeln('It may have a Virus attached or someone may have made');π writeln('an attempt to HACK it. You should check your system for');π writeln('virus'' before continuing....');π writeln;π writeln('Please reinstall the .EXE file from the original archive.');π writeln('Aborting....');π halt(255);π endπ elseπ beginπ writeln;π writeln('Integrity Validated.');π end;π end; { with }π Close(f); {$I+}π if IOResult <> 0 then beginπ writeln('Unable to initialise program');π halt;π end;π end; { InitConstants }ππprocedure Write2Exec(var data; size: word);π { writes a new typed constant into the executable file. }π varπ f : file;π beginπ assign(f, ParamStr(0));π {$I-} Reset(f,1);π Seek(f,longint(ExeData.Hsize+Seg(data)-PrefixSeg) shl 4 + Ofs(data)- 256);π BlockWrite(f,data,size);π Close(f); {$I+}π if IOResult <> 0 then;π end; { Write2Exec }ππbeginπ writeln('Please Standby...');π InitConstants;πend.ππ 33 08-27-9321:01ALL STEVE ROGERS True EXE Size IMPORT 12 èo {πSTEVE ROGERSππ> Also, does anyone know how PKware wrote the ZIP2EXE Program? I'm alsoπ>writing an encryption Program, and I thought a 'self-decrypting' Fileπ>would be neat, so I had some ideas on how to do it. Could you justπ>append the encrypted data to the end of a short 'stub' Program, whichπ>just seeks in how ever many Bytes and reads from there? Or would Iπ>have to somehow assign all the data to a few Typed Constants?ππJust so happens I have been dealing With the same problem. I haveπwritten a Procedure to show the "True" size of an EXE File. Knowing thisπyou can easily get to your "data area" by seeking past the "True" size.ππ( Acknowledgements to Andy McFarland and Ray Duncan )π}ππFunction exesize(fname : String) : LongInt;πTypeπ t_size = Recordπ mz : Array [1..2] of Char;π remainder,π pages : Word;π end;ππVarπ f : File of t_size;π sz : t_size;ππbeginπ assign(f,fname);π {$i-}π reset(f);π {$i+} { io checking should be off }π if (ioresult <> 0) thenπ exesize:= 0π elseπ beginπ read(f,sz);π close(f);π With sz doπ exesize := remainder + (pred(pages) * 512);π end;πend;πππ{πThis thing reads the header of an EXE File and gets the info there. Iπwas amazed when I ran this on a bunch of progs and found how many haveπdata appended. Hope it helps. :)π} 34 08-27-9321:23ALL GERD KORTEMEYER Detect Float Error IMPORT 132 èo {πGERD KORTEMEYERππhere are two Units For trapping float-exceptions. In your Program youπwill have to addππ Uses err387ππand at the beginning of your main Program say For exampleππbeginπ exception(overflow, masked);π exception(underflow, dumpask);π exception(invalid, dumpexit);π autocorrect(zerodiv, 1.0);π exception(precision, masked);ππIn this way you can choose For any kind of exception in which way it isπto be handeled. After the lines above the result of a division by zeroπwill be '1.0', in Case of an underflow there will be a dump of the coproπand the user will be asked For the result he wants the operation to have,πin Case of an overflow the largest available number will be chosen andπso on ...ππHere are the Unitsππ err387 and dis387π}ππ{ ---------------------------------------------------------- }π{ Fehlerbehandlungsroutinen fuer den Intel 80387 bzw. 486 DX }π{ Geschrieben in Turbo Pascal 6.0 }π{ von Gerd Kortemeyer, Hannover }π{ ---------------------------------------------------------- }ππUnit err387;ππInterfaceππUsesπ dis387, Dos, Crt;ππConstπ invalid = 1;π denormal = 2;π zero_div = 4;π overflow = 8;π underflow = 16;π precision = 32;π stackfault= 64;π con1 = 512;ππ masked = 0;π runtime = 1;π dump = 2;π dumpexit = 3;π dumpask = 4;π autocorr = 5;πππProcedure exception(which, what : Word);πProcedure autocorrect(which : Word; by : Extended);ππProcedure handle_off;πProcedure handle_on;ππProcedure restore_masks;ππProcedure clear_copro;πFunction status_Word : Word;ππVarπ do_again : Word;ππImplementationππConstπ valid = 0;π zero = 1;π spec = 2;π empty = 3;ππ topmask : Word = 14336;π topdiv = 2048;ππ anyerrors : Word = 63;ππ zweipot : Array [0..15] of Word =π (1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,π 2048, 4096, 8192, 16384, 32768);ππ ex_nam : Array[0..5] of String=π ('Invalid ',π 'Denormal ',π 'Zero-Div ',π 'Overflow ',π 'Underflow ',π 'Precision ');ππVarπ setmasks : Byte;π normal : Recordπ Case Boolean OFπ True : (adr : Pointer);π False: (pro : Procedure);π end;ππ Exit_on,π dump_on,π ask_on,π auto_on,π standard : Word;ππ auto_val : Array [0..5] of Extended;ππProcedure Mask(which : Word);πVarπ cw : Word;πbeginπ Asmπ fstcw cwπ end;π cw := cw or which;π setmasks := Lo(cw);π Asmπ fldcw cwπ end;πend;ππProcedure Unmask(which : Word);πVarπ cw : Word;πbeginπ Asmπ fclexπ fstcw cwπ end;π cw := cw and not (which);π setmasks := Lo(cw);π Asmπ fldcw cwπ end;πend;ππProcedure restore_masks;πVarπ setm : Word;π i :Integer;πbeginπ setm:=setmasks;π For i := 0 to 5 doπ if (setm and zweipot[i]) <> 0 thenπ Mask (zweipot[i])π elseπ Unmask(zweipot[i]);πend;ππProcedure clear_copro;πVarπ cw : Word;πbeginπ Asmπ fstcw cwπ end;π setmasks := Lo(cw);π Asmπ finitπ end;πend;ππFunction status_Word;πbeginπ Asmπ fstsw @resultπ end;πend;ππ{ Bei welcher Exception soll was passieren? }πProcedure exception;πbeginπ Case what OFππ masked : Mask(which);ππ runtime :π beginπ Unmask(which);π standard := standard or which;π end;ππ dump :π beginπ Unmask(which);π standard := standard and NOT(which);π dump_on := dump_on or which;π Exit_on := Exit_on and NOT(which);π ask_on := ask_on and NOT(which);π auto_on := auto_on and NOT(which);π end;ππ dumpexit :π beginπ Unmask(which);π standard := standard and NOT(which);π dump_on := dump_on or which;π Exit_on := Exit_on or which;π ask_on := ask_on and NOT(which);π auto_on := auto_on and NOT(which);π end;ππ dumpask :π beginπ Unmask(which);π standard := standard and NOT(which);π dump_on := dump_on or which;π Exit_on := Exit_on and NOT(which);π ask_on := ask_on or which;π auto_on := auto_on and NOT(which);π end;π end;πend;ππ{ zum Setzen von Auto-Korrekt-Werten }ππProcedure autocorrect;πVarπ i : Integer;πbeginπ Unmask(which);π standard := standard and NOT(which);π dump_on := dump_on and NOT(which);π Exit_on := Exit_on and NOT(which);π ask_on := ask_on and NOT(which);π auto_on := auto_on or which;π For i := 0 to 5 doπ if (which and zweipot[i]) <> 0 thenπ auto_val[i] := by;πend;ππ{ ------------- Die Interrupt-Routine selbst ------------- }ππProcedure errorcon; Interrupt;πVarπ copro : Recordπ control_Word,π status_Word,π tag_Word, op,π instruction_Pointer,π ip, operand_Pointer, : Word;π st : Array [0..7] of Extended;π end;ππ top : Integer; { welches Register ist Stacktop? }ππ masked, { welche Exceptions maskiert? }π occured : Byte; { welche Exceptions aufgetreten? }ππ opcode : Word;ππ inst_seg, { Instruction-Pointer, Segment }π inst_off, { " , Offset }π oper_seg, { Operand-Pointer , Segment }π oper_off: Word; { " , Offset }ππ inst_point : ^Word; { zum Adressieren des Opcodes }ππ oper_point : Recordπ Case Integer of { zum Adressieren des Operanden }π 1 : (ex : ^Extended);π 2 : (db : ^Double);π 3 : (si : ^Single);π 4 : (co : ^Comp);π end;ππ marker: Array [0..7] of Word; { Register-Marker nach Tag-Word }ππ opt_dump, { soll ausgeben werden? }π opt_exit, { soll aufgehoert werden? }π opt_ask, { soll Ergebnis abgefragt werden? }π opt_auto : Boolean; { soll Ergebnis automatisch korrigiert werden? }ππ i : Integer;ππ mem_access: Boolean; { gibt es Speicherzugriff? }ππ op_name : String; { Mnemonik des Befehls }ππ{ Ersetze Stacktop durch abgefragten Wert }πProcedure ask_correct;πVarπ res : Extended;π ch : Char;π t : String;π code : Integer;πbeginπ Asmπ fstp resπ end;π WriteLN;π Write('The result would be ', res, '. Change? (y/n) ' );π Repeatπ Repeat Until KeyPressed;π ch := ReadKey;;π Until ch in ['Y','y','N','n'];π Writeln;π if ch in ['Y','y'] thenπ Repeatπ Write('New value : ');π READLN(t);π VAL(t, res, code);π Until code = 0;π Asmπ fld resπ end;πend;ππFunction hex(w : Word) : String; { Ausgabe als HeX-Zahl }πConstπ zif : Array [0..15] of Char = ('0','1','2','3','4','5','6','7','8','9',π 'a','b','c','d','e','f');πbeginπ hex := zif[w div zweipot[12]] +π zif[(w MOD zweipot[12]) div zweipot[8]] +π zif[(w MOD zweipot[8]) div zweipot[4]] +π zif[w MOD zweipot[4]];πend;ππProcedure choice;πVarπ ch : Char;πbeginπ WriteLN;π Write('C)ontinue, A)bort ');π Repeatπ Repeat Until KeyPressed;π ch:=ReadKey;;π if ch in ['A','a'] thenπ Halt(0);π Until ch in ['C','c'];π WriteLN;πend;ππProcedure showcopro; { Ausgeben des FSAVE - Records }πVarπ i : Integer;πbeginπ TextMode(LastMode);π HighVideo;π WriteLN('Floating point exception, last opcode: ',hex(opcode),π ' (',op_name,')');π NormVideo;π WriteLN('Instruction Pointer : ',hex(inst_seg),':',hex(inst_off),π ' (',hex(inst_point^),')');π if mem_access thenπ beginπ WriteLN('Operand Pointer : ',hex(oper_seg),':',hex(oper_off));π WriteLN('( Extended: ',oper_point.ex^,', Double: ',oper_point.db^);π WriteLN(' Single : ',oper_point.si^,', Comp : ',oper_point.co^,' )');π endπ elseπ beginπ WriteLN;π WriteLN ('No memory access');π WriteLN;π end;π HighVideo;π if (occured and stackfault) = 0 thenπ beginπ WriteLN('Exception ','Masked':8,'Occured':8,'Should be masked':18);π NormVideo;π For i:=0 to 5 doπ WriteLN(ex_nam[i], (masked and zweipot[i]) <> 0 : 8,π (occured and zweipot[i]) <> 0 : 8,π (setmasks and zweipot[i]) <> 0 : 18);π HighVideo;π endπ elseπ beginπ WriteLN('Invalid Operation:');π if (copro.status_Word and con1) <> 0 thenπ WriteLN(' -- Stack Overflow --')π elseπ WriteLN(' -- Stack Underflow --');π WriteLN;π end;ππ WriteLN('Reg ','Value':29,'Marked':10);π Normvideo;π For i := 0 to 7 doπ beginπ Write('st(',i,')', copro.st[i] : 29);π Case marker[i] OFπ valid : WriteLN('Valid' : 10);π spec : WriteLN('Special' : 10);π empty : WriteLN('Empty' : 10);π zero : WriteLN('Zero' : 10);π end;π end;πend;ππ{ Ersetze Stacktop durch Auto-Korrekt-Wert }ππProcedure auto_corr;πVarπ res : Extended;π i : Integer;πbeginπ Asmπ fstp resπ end;π For i := 0 to 5 doπ if ((occured and zweipot[i]) <> 0) andπ ((auto_on and zweipot[i]) <> 0) thenπ res := auto_val[i];π Asmπ fld resπ end;πend;πππProcedure do_it_again;πTypeπ codearr = Array[0..4] of Byte;πVarπ sam : Recordπ Case Boolean OFπ True : (b: ^codearr );π False: (p: Procedure);π end;ππ op_point : Pointer;π x : extended;πbeginπ New(sam.b);π sam.b^[0]:=Hi(opcode);π sam.b^[1]:=Lo(opcode);π if mem_access thenπ beginπ { --- mod r/m auf ds:[di] stellen (00ttt101) --- }π sam.b^[1] := sam.b^[1] and not (zweipot[7] + zweipot[6] + zweipot[1]);π sam.b^[1] := sam.b^[1] or (zweipot[2] + zweipot[0]);π end;π sam.b^[2] := $ca; { retf 0000 }π sam.b^[3] := $00;π sam.b^[4] := $00;π op_point := oper_point.ex;π Asmπ push dsπ lds di, op_pointπ end;ππ sam.p;ππ Asmπ pop dsπ end;π Dispose(sam.b);πend;ππbeginπ Asmπ push axπ xor al,alπ out 0f0h,alπ mov al,020hπ out 0a0h,alπ out 020h,alπ pop axπ fsave coproπ end;ππ { === Pruefen, ob Bearbeitung durch ERRORCON erwuenscht === }π if (copro.status_Word and standard) <> 0 thenπ beginπ Asmπ frstor coproπ end;π normal.pro; { Bye, bye ... }π end;π { === Auswerten des FSAVE-Records ========================= }π { --- Opcode wie im Copro gespeichert --- }π opcode := zweipot[15] + zweipot[14] + zweipot[12] + zweipot[11] +π (copro.ip MOD zweipot[11]);π op_name := dis(opcode);π mem_access := op_name='...';π { --- Was war maskiert, was ist passiert? --- }π masked := Lo(copro.control_Word);π occured := Lo(copro.status_Word );π { --- Der Instruction-Pointer --- }π inst_seg := copro.ip and (zweipot[15] + zweipot[14] + zweipot[13] +π zweipot[12]);π inst_off := copro.instruction_Pointer;π inst_point := Ptr(inst_seg,inst_off);π { --- Der Operand-Pointer --- }π oper_seg := copro.op and (zweipot[15] + zweipot[14] + zweipot[13] +π zweipot[12]);π oper_off := copro.operand_Pointer;π oper_point.ex := Ptr(oper_seg,oper_off);π { --- Wer ist gerade Stacktop? --- }π top := (copro.status_Word and topmask) div topdiv;π { --- Einlesen der Marker aus Tag-Word --- }π For i := 0 to 7 doπ beginπ marker[(8 + i - top) MOD 8] := (copro.tag_Word and (zweipot[i * 2] +π zweipot[i * 2 + 1])) div zweipot[i * 2];π end;ππ { --- Welche Aktionen sollen ausgefuehrt werden? --- }π opt_dump := (copro.status_Word and dump_on) <> 0;π opt_exit := (copro.status_Word and Exit_on) <> 0;π opt_ask := (copro.status_Word and ask_on ) <> 0;π opt_auto := (copro.status_Word and auto_on) <> 0;ππ { === Aktionen ============================================ }π if opt_dump thenπ showcopro;π if opt_exit thenπ beginπ WriteLN;π WriteLN('Exit Program due to Programmers request');π HALT; { Bye, bye ... }π end;π if opt_dump and not (opt_ask) thenπ choice;ππ copro.control_Word := copro.control_Word or anyerrors;π Asmπ frstor coproπ fclexπ end;π { --- Befehl nochmals ausfuehren --- }π if (occured and do_again) <> 0 thenπ do_it_again;π { --- Noch was? --- }π if opt_auto thenπ auto_corr;π if opt_ask thenπ ask_correct;π restore_masks;πend;ππ{ ------------- Ein- und Ausschalten ------------- }ππProcedure handle_on;πbeginπ Getintvec($75, normal.adr);π Setintvec($75, @errorcon);πend;ππProcedure handle_off;πbeginπ Setintvec($75, normal.adr);πend;ππbeginπ handle_on;π dump_on :=0;π Exit_on :=0;π ask_on :=0;π auto_on :=0;π standard:=0;π do_again:=invalid+zero_div+denormal;π clear_copro;πend.πππππππUnit dis387;ππInterfaceππFunction dis(opco : Word) : String;ππImplementationππFunction dis;πVarπ d, op : String;ππ Procedure opcr(st : Word);π Varπ t : String;π beginπ str(st, t);π op := ' st,st(' + t + ')';π end;ππ Procedure opc(st : Word);π Varπ t : String;π beginπ str(st, t);π op := ' st(' + t + '),st';π end;ππ Procedure op1(st : Word);π Varπ t : String;π beginπ str(st, t);π op := ' st(' + t + ')';π end;ππbeginπ d := '...';π op := '';ππ Case Hi(opco) OFπ $d8 :π Case Lo(opco) div 16 OFπ $c :π if opco MOD 16 >= 8 thenπ beginπ d := 'fmul';π opcr(opco MOD 16 - 8);π endπ elseπ beginπ d := 'fadd';π opcr(opco MOD 16);π end;ππ $e :π if opco MOD 16 >= 8 thenπ beginπ d := 'fsubr';π opcr(opco MOD 16 - 8);π endπ elseπ beginπ d := 'fsub';π opcr(opco MOD 16);π end;ππ $f :π if opco MOD 16 >= 8 thenπ beginπ d := 'fdivr';π opcr(opco MOD 16 - 8);π endπ elseπ beginπ d := 'fdiv';π opcr(opco MOD 16);π end;π end;ππ $d9 :π Case Lo(opco) OFπ $d0 : d := 'fnop';π $e0 : d := 'fchs';π $e1 : d := 'fabs';π $e4 : d := 'ftst';π $e5 : d := 'fxam';π $e8 : d := 'fld1';π $e9 : d := 'fld2t';π $ea : d := 'fld2e';π $eb : d := 'fldpi';π $ec : d := 'fldlg2';π $ed : d := 'fldln2';π $ee : d := 'fldz';π $f0 : d := 'f2xm1';π $f1 : d := 'fyl2x';π $f2 : d := 'fptan';π $f3 : d := 'fpatan';π $f4 : d := 'fxtract';π $f5 : d := 'fprem1';π $f6 : d := 'fdecstp';π $f7 : d := 'fincstp';π $f8 : d := 'fprem';π $f9 : d := 'fyl2xp1';π $fa : d := 'fsqrt';π $fb : d := 'fsincos';π $fc : d := 'frndint';π $fd : d := 'fscale';π $fe : d := 'fsin';π $ff : d := 'fcos';π end;ππ $db :π Case Lo(opco) OFπ $e2 : d := 'fclex';π $e3 : d := 'finit';π end;π $dc :π Case Lo(opco) div 16 OFπ $c :π if opco MOD 16 >= 8 thenπ beginπ d := 'fmul';π opc(opco MOD 16-8);π endπ elseπ beginπ d := 'fadd';π opc(opco MOD 16);π end;ππ $e : if opco MOD 16 >= 8 thenπ beginπ d := 'fsub';π opc(opco MOD 16 - 8);π endπ elseπ beginπ d := 'fsubr';π opc(opco MOD 16);π end;ππ $f :π if opco MOD 16 >= 8 thenπ beginπ d := 'fdiv';π opc(opco MOD 16 - 8);π endπ elseπ beginπ d := 'fdivr';π opc(opco MOD 16);π end;π end;ππ $dd :π Case Lo(opco) div 16 OFπ $c :π beginπ d := 'ffree';π op1(opco MOD 16);π end;π $d :π if opco MOD 16 >= 8 thenπ beginπ d := 'fstp';π op1(opco MOD 16 - 8);π endπ elseπ beginπ d := 'fst';π op1(opco MOD 16);π end;π $e :π if opco MOD 16 >= 8 thenπ beginπ d := 'fucomp';π op1(opco MOD 16 - 8);π endπ elseπ beginπ d := 'fucom';π op1(opco MOD 16);π end;π end;ππ $de :π Case Lo(opco) div 16 OFπ $c :π if opco MOD 16 >= 8 thenπ beginπ d := 'fmulp';π opc(opco MOD 16 - 8);π endπ elseπ beginπ d := 'faddp';π opc(opco MOD 16);π end;ππ $d : d := 'fcompp';ππ $e :π if opco MOD 16 >= 8 thenπ beginπ d := 'fsubp';π opc(opco MOD 16 - 8);π endπ elseπ beginπ d := 'fsubrp';π opc(opco MOD 16);π end;ππ $f :π if opco MOD 16 >= 8 thenπ beginπ d := 'fdivp';π opc(opco MOD 16 - 8);π endπ elseπ beginπ d := 'fdivrp';π opc(opco MOD 16);π end;π end;π end;ππ dis := d + op;πend;ππbeginπend.π 35 08-27-9321:40ALL SEAN PALMER Simple Multi-Tasker IMPORT 22 èo {π by Sean L. Palmerπ Public Domainππ This is a 'multitasking' Program in the sense that it hooks intoπ the timer interrupt, but what that interrupt ends up actuallyπ doing is controlled by the current value in SaveAdr, whichπ changes With each interrupt as the routine passes control backπ to the tick handler not by Exiting normally, but by an explicitπ transfer of control.π The end result of this is that you can Write a state-drivenπ interrupt handlerπ The included example is RealLY simplistic, and barely tested.π I intend to use this to Write a comm port driver thatπ parses the incoming data as it receives it which wouldπ be nice in a communications Program that shells to Dos, asπ the incoming Chars could be saved to disk in the backgroundπ With buffered ZModem or something...π}ππProgram intTest;ππUsesπ Dos;ππVarπ saveAdr : Word; {offset in this code segment of where we are now}π active : Boolean; {to avoid re-entrancy}ππProcedure intHandler; Far; Assembler;πAsmπ pushaπ mov ax, seg @DATAπ mov ds, axππ {anything you need to do before continuing (reading port data?), do here}ππ in al, $61 {click speaker as an example}π xor al, 2π out $61, alππ test active, $FF {exit now if interrupted ourselves}π jz @OKπ popaπ iretππ @OK:π inc Byte ptr activeπ stiπ jmp [saveAdr] {near jump to continue where handler last left off}πend;ππ{call this Procedure from StateHandler to suspend execution Until next time}ππProcedure wait; near; Assembler;πAsm {wait For next interrupt}π pop Word ptr saveAdr {save where to continue next time}π dec Byte ptr activeπ popa {restore caller regs}π iretπend;ππConstπ c : Char = '.';ππProcedure stateHandler;πbeginπ{π a stateHandler Procedure should never ever Exit (only by calling 'wait'),π shouldn't have any local Variables or parameters, and shouldn't callπ 'wait' With anything on the stack (like from a subroutine).π This routine is using the caller's (interrupted Program's) stack, so beπ very very careful}ππ Asmπ pop bp {clean up stack mess left by Turbo's Procedure header}π end;π {^ alternative method here is to init saveAdr to offset(proc)+3 and skipπ the push bp; mov bp,sp altogether}ππ Repeat {this is an example only}π c := '@';π wait;π c := '.';π wait;π Until False; {don't let it return normally!!}πend;ππVarπ oldHook : Procedure;π i : Integer;ππbeginπ saveAdr := ofs(stateHandler);π getIntVec($1C, @oldHook);π setIntVec($1C, @intHandler);π For i := 1 to 1500 doπ Write(c);π setIntVec($1C, @oldHook);πend.πππ 36 08-27-9322:12ALL DAVID DOTY Writing To EXE File IMPORT 73 èo {π> How are you saaving the CFG into the .EXE?? Mind posting some code that wilπ> save the CFG to the EXE?(When you get all your bugs fixed!)ππI use these routines in my self-modifying .EXE's. They work pretty good.π}ππUnit WritExec;ππ { ==================================================================ππ Unit: WritExecπ Author: David Dotyπ Skipjack Softwareπ Columbia, Marylandπ CompuServe User I.D.: 76244,1043ππ This Unit is based on a previously published Program:ππ Program: AutoInst v2.0π Author: David Duboisπ Zelkop Softwareπ Halifax, Nova Scotiaπ CompuServe User I.D.: 71401,747π Date last revised: 1988.04.24ππ ==================================================================ππ This source code is released to the public domain. if further changesπ are made, please include the above credits in the distributed code.ππ This Unit allows a Program to change the value of a Typed Constant in itsπ own .EXE File. When the Program is run again, the data will be initializedπ to the new value. No external configuration Files are necessary.ππ Usesππ Examples of the usefulness of this technique would be:ππ o A Program that allows the user to change default display colors.ππ o A Program that keeps track of a passWord that the user can change.ππ HOW IT WORKSππ You don't have to understand all the details in order to use thisπ technique, but here they are.ππ The data to be changed must be stored in a TurboPascal Typedπ Constant. In all effect, a Typed Constant is actually a pre-π initialized Variable. It is always stored in the Program's Dataπ Segment. The data can be of any Type.ππ First, the Procedure finds the .EXE File by examining the Dos commandπ line, stored With the copy of the Dos environment For the Program. Thisπ allows the Program to find itself no matter where is resides on disk andπ no matter how its name is changed by the user.ππ The unTyped File is opened With a Record size of 1. This allows usπ to read or Write a String of Bytes using BlockRead and BlockWrite.ππ As documented in the Dos Technical Reference, the size of the .EXEπ header, in paraGraphs (a paraGraph is 16 Bytes), is stored as aπ two-Byte Word at position 8 of the File. This is read into theπ Variable HeaderSize.ππ The next step is to find the position of the Typed Constant in theπ .EXE File. This requires an understanding of the Turbo Pascal 4.0π memory map, documented on the first and second pages of the Insideπ Turbo Pascal chapter. (That's chapter 26, pages 335 and 336 in myπ manual.)ππ First, find the address in memory where the Typed Constant isπ stored. This can be done in Turbo Pascal by using the Seg and Ofsπ Functions. Next find the segment of the PSP (Program segmentπ prefix). This should always be the value returned by PrefixSeg.π That will mark the beginning of the Program in memory. Theπ position of the Typed Constant in the .EXE image should be theπ number of Bytes between these two places in memory. But ...ππ But, two corrections must be made. First, the PSP is not stored inπ the .EXE File. As mentioned on page 335, the PSP is always 256π Bytes. We must subtract that out. Secondly, there is the .EXE Fileπ header. The size of this has already been read in and must beπ added in to our calculations.ππ Once the position has been determined, the data stored in theπ Typed Constant is written in one fell swoop using a BlockWrite.π This replaces the original data, so that the next time the Programπ is run, the new values will used.ππ LIMITATIONSππ You cannot use MicroSoft's EXEPACK on the .EXE File, or any otherπ packing method I know of. This may change the position, or evenπ the size of the Typed Constant in the File image.ππ NOTESππ Since Typed Constants are always stored in the data segment, theπ Function call to Seg( ObjectToWrite ) can be replaced With DSeg. Iπ prefer using Seg since it is more descriptive.ππ One might think that Cseg can used as an alternative to usingπ PrefixSeg and subtracting 256. This will work only if the codeπ resides in the main Program. If, on the other hand, the code isπ used in a Unit, PrefixSeg must be used as described here. Youπ might as well use PrefixSeg and save yourself some headaches.ππ if you have any comments or questions we would be glad to hearπ them. if you're on CompuServe, you can EasyPlex a letter toπ 76244,1043 or 71401,747. Or leave a message on the Borland Programmer's Aπ Forum (GO BPROGA). Or, you can Write toππ Skipjack Softwareπ P. O. Box 61π Simpsonville Maryland 21150ππ orππ Zelkop Softwareπ P.O. Box 5177π Armdale, N.S.π Canadaπ B3L 4M7ππ ==================================================================}πππInterfaceππFunction GetExecutableName : String;π{ This Function returns the full drive, path, and File name of the applicationπ Program that is running. This Function is of more general interest thanπ just For writing into the EXE File.ππ NOTE: THIS Function WILL ONLY WORK UNDER Dos 3.X + !!! }ππFunction WriteToExecutable(Var ObjectToWrite; ObjectSize : Word) : Integer;π{ This Procedure modifies the EXE File on disk to contain changes to Typedπ Constants. NOTE - the Object MUST be a Typed Constant. It may be foundπ in any part of the Program (i.e., main Program or any Unit). The call isπ made by unTyped address, to allow any kind of Object to be written. Theπ Function returns the Dos error code from the I/O operation that failedπ (if any did); if all operations were successful, the Function returns 0. }ππImplementationππFunction GetExecutableName : String;πTypeπ Environment = Array[0..32766] of Char;πConstπ NullChar : Char = #0;π SearchFailed = $FFFF;πVarπ MyEnviron : ^Environment;π Loop : Word;π TempWord : Word;π EnvironPos : Word;π FilenamePos : Word;π TempString : String;πbegin { Function GetExecutableName }π { Get Pointer to Dos environment }π MyEnviron := Ptr(MemW[PrefixSeg : $2C], 0);ππ { Look For end of environment }π EnvironPos := SearchFailed;π Loop := 0;ππ While Loop <= 32767 DOπ beginπ if MyEnviron^[ Loop ] = NullChar thenπ if MyEnviron^[ Loop + 1 ] = NullChar thenπ begin { found two nulls - this is end of environment }π EnvironPos := Loop;π Loop := 32767π end; { found two nulls }π Inc(Loop);π end; { While Loop }ππ if EnvironPos = SearchFailed thenπ GetExecutableName := ''π elseπ begin { found end of environment - now look For path/File of exec }π EnvironPos := EnvironPos + 4;π FilenamePos := SearchFailed;π TempWord := EnvironPos;π Loop := 0;ππ While Loop <= 127 DOπ beginπ if MyEnviron^[TempWord] = NullChar thenπ begin { found a null - this is end of path/File of exec }π FilenamePos := Loop;π Loop := 127π end; { found a null }π Inc(Loop);π Inc(TempWord);π end; { While Loop }ππ if FilenamePos = SearchFailed thenπ GetExecutableName := ''π elseπ begin { found executable name - move into return String }π TempString[0] := Chr(FilenamePos);π Move(MyEnviron^[EnvironPos], TempString[1], FilenamePos);π GetExecutableName := TempString;π end; { found executable name }π end; { found environment end }πend; { Function GetExecutableName }πππFunction WriteToExecutable(Var ObjectToWrite; ObjectSize : Word ) : Integer;πConstπ PrefixSize = 256; { number of Bytes in the Program Segment Prefix }πVarπ Executable : File;π HeaderSize : Word;π ErrorCode : Integer;πbeginπ Assign(Executable, GetExecutableName);π {$I-}π Reset(Executable, 1);π ErrorCode := IOResult;ππ if ErrorCode = 0 thenπ begin { seek position of header size in EXE File }π Seek(Executable, 8);π ErrorCode := IOResult;π end; { seek header }ππ if ErrorCode = 0 thenπ begin { read header size in EXE File }π BlockRead(Executable, HeaderSize, SizeOf(HeaderSize));π ErrorCode := IOResult;π end; { read header }ππ if ErrorCode = 0 thenπ begin { seek position of Object in EXE File }π Seek(Executable,π LongInt(16) * (HeaderSize + Seg(ObjectToWrite) - PrefixSeg) +π Ofs(ObjectToWrite) - PrefixSize);π ErrorCode := IOResult;π end; { Seek Object position in File }ππ if ErrorCode = 0 thenπ begin { Write new passWord in EXE File }π BlockWrite(Executable, ObjectToWrite, ObjectSize);π ErrorCode := IOResult;π end; { Write new passWord }ππ Close(Executable);π WriteToExecutable := ErrorCode;ππend; { Function WriteToExecutable }ππend. { Unit WritExec }π 37 11-02-9310:32ALL ANDY MCFARLAND Dealing Poker SWAG9311 5 èo { ANDY MCFARLAND }ππVarπ pick : Array [1..52] of Byte;π i, n,π temp : Word;ππbeginπ { start With an ordered deck }π For i := 1 to 52 doπ pick[i] := i ;ππ For i:= 52 downto 2 doπ begin { [i+1..52] has been shuffled }π { pick any card in the unshuffled part of the deck }π n := random(i) + 1 ; { N in [1..i] }π temp := pick[n] ; { exchange pick[i] pick[n] }π pick[n] := pick[i] ;π pick[i] := temp ;π end ;πend;π 38 11-02-9310:29ALL BOB SWART OPTIMIZE.PAS SWAG9311 31 èo {πBOB SWARTππ> Does anybody have any tips on optimizing TP Programs?πWhat kind of optimization? Speed or Size? Optimizing For one may not be theπsame as optimizing For the other...ππ> but now it has grown quite large (anybody want it? :), and I'd likeπ> to shrink it.πAh, so optimizing For size! Minimizing data space, code space (and stack/heapπusage as well).ππ> I've gotten it from 40k down to 29k after a lot of work, but that isπ> still too big.πDo you want to turn it into a TSR?ππ> Does anyone know of any common optimization techniques that would work?πDo you use BAsm code or plain Pascal?ππ> For instance, if inc(IntVar, amt) is more efficient (code size wise)π> than IntVar := IntVar + amt;πYes, try dumpprog (by our beloved moderator) on those two statements:ππtest.pas#4: i := i + 4;π 0000:000F A15000 MOV AX,[DS: i(0050)]π 0000:0012 050400 ADD AX,0004π 0000:0015 A35000 MOV [DS: i(0050)],AXππIt takes 9 Bytes For "i := i + 4;"ππtest.pas#5: Inc(i,4);π 0000:0018 8306500004 ADD [Word DS:+i(+0050)],+04ππIt takes only 5 Bytes to do "Inc(i,4);" (and it is also faster!!)πππ> That's the kind of thing that I'm looking for.πWell Brian, currently I'm working on a whole BOOK about 'Borland PascalπPerformance Optimization' (about 250-pages, english, early '94 ). In my book,πthe process op Program optimization is divided into four steps: 1. finding theπbottle-necks in your Program, 2. using better datastructures & algorithms, 3.πusing more efficient language Constructs, and 4. using BAsm code and InLineπmacros. There will be a whole chapter devoted to 'optimization techniques forπProgram size', but I will say a few Words here For you:ππMost of the times optimization is a matter of SPEED vs. SIZE. if you want theπsmallest code, then prepare let the Program do some more work. Eliminate bigπlook-up tables (if you use any), use small, simple datastructures (that oftenπimply not-so-efficient algorithms), do not use more Units than the ones youπAbsolutely need. Even then, try to code the routines from those Units yourselfπ(avoid any and all overhead from those Units). If, For example, you need aπReadKey-like Function, don't use the Crt Unit, but implement your own ReadKeyπFunction like this:ππ{$A-,B-,D-,E-,F-,G-,I-,L-,N-,O-,P-,Q-,R-,S+,T-,V-,X+}π{.$DEFINE Crt}πProgram test;π{$IFDEF Crt}π{ Code size: 3056π Data size: 690π .EXE size: 3232π}πUses Crt;π{$else}π{ Code size: 1504 --> 1552 Bytes lessπ Data size: 672 --> 18 Bytes lessπ .EXE size: 1680 --> 1552 Bytes lessπ}πConstπ ScanCode : Byte = 0;π _ReadKey : Byte = $00;ππFunction ReadKey : Char; Assembler;πAsmπ mov AL, ScanCode { check old ScanCode }π mov ScanCode,0 { empty old ScanCode }π or AL, AL { AL = 0? }π jne @end { no: return ScanCode }π xor AH, AH { AH := 0 }π int $16 { read Character }π or AL, AL { AL = 0? }π jne @end { no: simple Character }π mov ScanCode, AH { yes: extended Character }π @end:πend;π{$endIF}ππVarπ t : Char;πbeginπ t := ReadKey;πend.ππThe resulting code is 1552 Bytes less when using your own ReadKey instead ofπthe Crt Unit. This is mainly due to the initalization code of the Crt Unit, ofπcourse, but even For you 1.5 Kb is about 5% code size...ππAs you can see above, if you try to push your code to the limit, you MUST useπBAsm or InLine macros. The Turbo/Borland Pascal compilers simply do notπgenerate code as efficient as a good Programmer can do.ππFinally, if you can't wait Until early '94, an article about Borland PascalπPerformance Optimization will be published in an opcoming issue of PCπTechniques. if you want more information about the book send me some netmail orπWrite to the address below. I'll send you some information on paper.ππ 39 11-21-9309:50ALL BOB SWART UUDCODE.PAS SWAG9311 30 èo {πFrom: BOB SWARTπSubj: UUDECODE.PASπHere is my version of UUDECODE.PAS (also fully compatible):π}ππ{$IFDEF VER70}π{$A+,B-,D-,E-,F-,G-,I-,L-,N-,O-,P-,Q-,R-,S+,T-,V-,X-}π{$ELSE}π{$A+,B-,D-,E-,F-,G-,I-,L-,N-,O-,R-,S+,V-,X-}π{$ENDIF}π{$M 8192,0,0}π{π UUDeCode 3.0π Borland Pascal (Objects) 7.0.π Copr. (c) 9-29-1993 DwarFools & Consultancy drs. Robert E. Swartπ P.O. box 799π 5702 NP Helmondπ The Netherlandsπ Code size: 4832 bytesπ Data size: 1330 bytesπ .EXE size: 3337 bytesπ ----------------------------------------------------------------π This program uudecodes files.π}ππConstπ SP = Byte(' ');ππ Typeπ TTriplet = Array[0..2] of Byte;π TKwartet = Array[0..3] of Byte;ππvar f: Text;π g: File of Byte;π FileName: String[12];π Buffer: String;π Kwartets: recordπ lengte: Byte;π aantal: Byte;π kwart: Array[1..64] of TKwartet;π end absolute Buffer;π Trip: TTriplet;π i: Integer;ππ FUNCTION UpperStr(S : STRING) : STRING;π VAR sLen : BYTE ABSOLUTE S;π I : BYTE;π BEGINπ FOR I := 1 TO sLEN DO S := UpCase(S[i]);π UpperStr := S;π END;ππ procedure Kwartet2Triplet(Kwartet: TKwartet; var Triplet: TTriplet);π beginπ Triplet[0] := ((Kwartet[0] - SP) SHL 2) +π (((Kwartet[1] - SP) AND $30) SHR 4);π Triplet[1] := (((Kwartet[1] - SP) AND $0F) SHL 4) +π (((Kwartet[2] - SP) AND $3C) SHR 2);π Triplet[2] := (((Kwartet[2] - SP) AND $03) SHL 6) +π ((Kwartet[3] - SP) AND $3F)π end {Kwartet2Triplet};πππbeginπ writeln('UUDeCode 3.1 (c) 1993 DwarFools & Consultancy' +π ', by drs. Robert E. Swart'#13#10);π if ParamCount = 0 thenπ beginπ writeln('Usage: UUDeCode infile [outfile]');π Haltπ end;ππ if UpperStr(ParamStr(1)) = UpperStr(ParamStr(2)) thenπ beginπ writeln('Error: infile = outfile');π Halt(1)π end;ππ Assign(f,ParamStr(1));π FileMode := $40;π reset(f);π if IOResult <> 0 thenπ beginπ writeln('Error: could not open file ',ParamStr(1));π Halt(2)π end;π repeatπ readln(f,Buffer) { skip }π until eof(f) or (Copy(Buffer,1,5) = 'begin');π if Buffer[11] = #32 then FileName := Copy(Buffer,12,12)π elseπ if Buffer[10] = #32 then FileName := Copy(Buffer,11,12)π else FileName := ParamStr(2);π {$IFDEF DEBUG}π writeln(FileName);π {$ENDIF}ππ if UpperStr(ParamStr(1)) = UpperStr(FileName) thenπ beginπ writeln('Error: input file = output file');π Halt(1)π end;ππ Assign(g,FileName);π if ParamCount > 1 thenπ beginπ FileMode := $02;π reset(g);π if IOResult = 0 thenπ beginπ writeln('Error: file ',FileName,' already exists.');π Halt(3)π endπ end;π rewrite(g);π if IOResult <> 0 thenπ beginπ writeln('Error: could not create file ',FileName);π Halt(4)π end;ππ while (not eof(f)) and (Buffer <> 'end') doπ beginπ FillChar(Buffer,SizeOf(Buffer),#32);π readln(f,Buffer);π if Buffer <> 'end' thenπ beginπ for i:=1 to (Kwartets.aantal-32) div 3 doπ beginπ Kwartet2Triplet(Kwartets.kwart[i],Trip);π write(g,Trip[0],Trip[1],Trip[2])π end;π if ((Kwartets.aantal-32) mod 3) > 0 thenπ beginπ Kwartet2Triplet(Kwartets.kwart[i+1],Trip);π for i:=1 to ((Kwartets.aantal-32) mod 3) do write(g,Trip[i-1])π endπ endπ end;π close(f);π close(g);ππ if ParamCount > 1 thenπ writeln('UUDeCoded file ',FileName,' created.');π writelnπend.π 40 11-21-9309:49ALL BOB SWART UUENCODE SWAG9311 34 èo {πFrom: BOB SWARTπSubj: UUENCODE.PASπHere is my version of UUENCODE.PAS (fully compatible):π}ππ{$IFDEF VER70}π{$A+,B-,D-,E-,F-,G-,I-,L-,N-,O-,P-,Q-,R-,S+,T-,V-,X-}π{$ELSE}π{$A+,B-,D-,E-,F-,G-,I-,L-,N-,O-,R-,S+,V-,X-}π{$ENDIF}π{$M 8192,0,0}π{π UUEnCode 3.0π Borland Pascal (Objects) 7.0.π Copr. (c) 9-29-1993 DwarFools & Consultancy drs. Robert E. Swartπ P.O. box 799π 5702 NP Helmondπ The Netherlandsπ Code size: 4880 bytesπ Data size: 1122 bytesπ .EXE size: 3441 bytesπ ----------------------------------------------------------------π This program uuencodes files.π}ππConstπ SP = Byte(' ');ππTypeπ TTriplet = Array[0..2] of Byte;π TKwartet = Array[0..3] of Byte;ππvar Triplets: Array[1..15] of TTriplet;π kwar: TKwartet;π FileName: String[12];π i,j: Integer;π f: File;π g: Text;πππ FUNCTION UpperStr(S : STRING) : STRING;π VAR sLen : BYTE ABSOLUTE S;π I : BYTE;π BEGINπ FOR I := 1 TO sLEN DO S := UpCase(S[i]);π UpperStr := S;π END;ππ procedure Triplet2Kwartet(Triplet: TTriplet; var Kwartet: TKwartet);π var i: Integer;π beginπ Kwartet[0] := (Triplet[0] SHR 2);π Kwartet[1] := ((Triplet[0] SHL 4) AND $30) +π ((Triplet[1] SHR 4) AND $0F);π Kwartet[2] := ((Triplet[1] SHL 2) AND $3C) +π ((Triplet[2] SHR 6) AND $03);π Kwartet[3] := (Triplet[2] AND $3F);π for i:=0 to 3 doπ beginπ if Kwartet[i] = 0 then Kwartet[i] := $40;π Inc(Kwartet[i],SP)π endπ end {Triplet2Kwartet};πππbeginπ writeln('UUEnCode 3.0 (c) 1993 DwarFools & Consultancy' +π ', by drs. Robert E. Swart'#13#10);π if ParamCount = 0 thenπ beginπ writeln('Usage: UUEnCode infile [outfile]');π Haltπ end;π if UpperStr(ParamStr(1)) = UpperStr(ParamStr(2)) thenπ beginπ writeln('Error: infile = outfile');π Halt(1)π end;ππ Assign(f,ParamStr(1));π FileMode := $40;π reset(f,1);π if IOResult <> 0 thenπ beginπ writeln('Error: could not open file ',ParamStr(1));π Halt(2)π end;ππ if ParamCount <> 2 thenπ beginπ FileName := ParamStr(1);π i := Pos('.',FileName);π if i > 0 then Delete(FileName,i,Length(FileName));π FileName := FileName + '.UUE'π endπ else FileName := ParamStr(2);ππ if UpperStr(ParamStr(1)) = UpperStr(FileName) thenπ beginπ writeln('Error: input file = output file');π Halt(1)π end;ππ Assign(g,FileName);π if ParamCount > 1 thenπ beginπ FileMode := $02;π reset(g);π if IOResult = 0 thenπ beginπ writeln('Error: file ',FileName,' already exists.');π halt(3)π endπ end;π rewrite(g);π if IOResult <> 0 thenπ beginπ writeln('Error: could not create file ',FileName);π Halt(4)π end;ππ writeln(g,'begin 0777 ',ParamStr(1));π repeatπ FillChar(Triplets,SizeOf(Triplets),#0);π BlockRead(f,Triplets,SizeOf(Triplets),i);π write(g,Char(SP+i));π for j:=1 to (i+2) div 3 doπ beginπ Triplet2Kwartet(Triplets[j],kwar);π write(g,Char(kwar[0]),Char(kwar[1]),Char(kwar[2]),Char(kwar[3]))π end;π writeln(g)π until (i < SizeOf(Triplets));π writeln(g,'end');π close(f);π close(g);ππ if ParamCount > 1 thenπ writeln('UUEnCoded file ',FileName,' created.');π writelnπend.ππππThe basic scheme is to break groups of 3 eight bit characters (24 bits) into 4πsix bit characters and then add 32 (a space) to each six bit character whichπmaps it into the readily transmittable character. Another way of phrasing thisπis to say that the encoded 6 bit characters are mapped into the set:ππ !"#$%&'()*+,-./012356789:;<=>?@ABC...XYZ[\]^_ππfor transmission over communications lines.ππAs some transmission mechanisms compress or remove spaces, spaces are changedπinto back-quote characters (a 96). (A better scheme might be to use a bias ofπ33 so the space is not created, but this is not done.)ππThe advantage of this over just hex encoding is that it put in 6 bits of signalπper byte, instead of just 4. The target is to get the smallest uncompressedπsize, since the assumption is that you've already compressed as much redundancyπas possible out of the original.ππ 41 09-26-9310:51ALL DAVID DANIEL ANDERSON Queit Noisy programs SWAG9311 76 èo (*πFrom: DAVID DANIEL ANDERSON Refer#: NONEπSubj: QUIET USING BLOCKREADπ*)ππuses dos ;πconstπ bufsize = 16384;π progdata = 'QUIET- Free DOS utility: quiets noisy programs.';π{!} progdat2 =π'V1.00: August 27, 1993. (c) 1993 by David Daniel Anderson - Reign Ware.';π{!} usage =π 'Usage: QUIET noisy_prog {will OVERWRITE the file - use a backup!!!}';π outname = 'o$_$_$$!.DDA';π tmpname = 't$_$_$$!.DDA';πtypeπ buffer = array [1..bufsize] of char;πvarπ buf : buffer ;π infile,π outfile : file ;π bytesread,π byteswritten : word ;ππ nextchar : char ;ππ checknext,π extra_char,π lastbyte : boolean ;ππ fdt : longint ;ππ dirinfo : searchrec ; { contains filespec info. }π spath : pathstr ; { source file path, }π sdir : dirstr ; { directory, }π sname : namestr ; { name, }π sext : extstr ; { extension. }π sfn, dfn, tfn : string [64]; { Source/ Dest/ Temp FileName, including dir }π filesdone : array [1..512] of string [64]; { table of each dir+name }π done : boolean ; { done is used so a file is not processed twice }π { used with the array "filesdone" because a bug }π { (in DOS I think) causes files to be selected }π { based on FAT placement, rather than name when }π { wildcards are implemented. The BUG allows }π { files to be done repeatedly, every time they }π { are encountered. }ππ i, nmdone : word ; { i is a counter, }π { nmdone is number of files wrapped }πππprocedure showhelp ( errornum : byte );πvarπ message : string [80];πbeginπ writeln ( progdata );π writeln ( progdat2 );π writeln ;π writeln ( usage );π writeln ;π {!} { all of the case messages got reformatted }π case errornum ofπ 1 : message :=π'you must specify -exactly- one filespec (wildcards are OK).';π 2 : message :=π'could not open the "noisy" file: ' + sfn + ' (may be read-only).';π 3 : message :=π'could not open the temp file (does ' + outname + ' already exist?).';π 4 : message :=π'the blockread procedure failed ( error reading "noisy" file: ' + sfn + '.';π 5 : message :=π'rename procedure failed, "quiet" file is ' + outname + '.';π 6 : message :=π'original file was read only, is renamed to ' + tmpname + '.';π 7 : message :=π'you cannot just specify a path, add "*.*" or "\*.*" for all files.';π 8 : message :=π'could not find any matching files.';π end;π writeln ( 'ERROR: (#',errornum,') - ', message );π halt ( errornum );πend;πprocedure openfiles(var ofl, nfl : file; name1, name2 : string);πbeginπ{$i-}π assign ( ofl, name1 );π reset ( ofl,1 );π if ioresult <> 0 thenπ showhelp (2); { unable to open ??? }ππ assign ( nfl, name2 );π reset ( nfl );π if ( ioresult <> 0 ) then begin { if file does -NOT- exist }π rewrite ( nfl,1 ); { yet, it is save to proceed }π if ioresult <> 0 then { unable to open ??? }π showhelp (3) ;π endπ elseπ showhelp (3) ;π{$i+}πend;ππ{!} procedure quietbufπ ( var bufr : buffer; var chknext : boolean ; var noises : word );πconstπ noisea = 'µ';π noiseb = 'a';π NOPChar = 'É';πvarπ bf_indx : word ;πbeginπ for bf_indx := 1 to ( sizeof ( bufr ) - 1 ) doπ if ( ( bufr [ bf_indx ] = noisea ) andπ ( bufr [ bf_indx +1 ] = noiseb ) ) then beginππ noises := noises + 1 ;π bufr [ bf_indx ] := NOPChar;π bufr [ bf_indx +1 ] := NOPChar;π end;π chknext := ( bufr [ sizeof ( bufr ) ] = noisea );πend;ππprocedure quietfile ( var infile, outfile : file );πvarπ noises : word ;πbeginπ noises := 0;π repeatπ{$i-} blockread ( infile, buf, bufsize, bytesread ); {$i+}π if ioresult <> 0 thenπ showhelp (4) ;π quietbuf ( buf, checknext, noises );ππ if ( checknext and ( not eof ( infile ))) then beginπ blockread ( infile, nextchar, 1 );π extra_char := true ;π if nextchar = 'a' then beginπ noises := noises + 1 ;π buf [ sizeof ( buf ) ] := 'É';π nextchar := 'É';π end;π endπ else extra_char := false ;ππ blockwrite ( outfile, buf, bytesread, byteswritten );π if extra_char thenπ blockwrite ( outfile, nextchar, 1 );π lastbyte := (( bytesread = 0 ) or ( bytesread <> byteswritten ));π until lastbyte ;π writeln ( noises, ' noises found.' );πend;ππbegin { MAIN }π if paramcount <> 1 then showhelp (1);π nmdone := 1; { initialize number done to one since }π { count is incremented after process ends }ππ for i := 1 to 512 do { initialize array }π filesdone[i] := ''; { (I'm not sure if this is needed) }ππ spath := paramstr (1); { source path is first parameter }ππ fsplit ( fexpand (spath),sdir,sname,sext); { break up path into components }π if (sname = '') then { - but quit if only a path and no }π showhelp(7); { name is given }ππ findfirst (spath, archive, dirinfo); { find the first match of filespec }π if doserror <> 0 thenπ showhelp(8);ππ while doserror = 0 do { process all specified files }π beginπ sfn := sdir+dirinfo.name; { should have dir info so we are not }π { confused with current directory (?) }π { IS needed for dest and temp filenames }ππ done := false; { initialize for each "new" file found }π for i := 1 to 512 doπ if sfn = filesdone[i] then { check entire array to see if we }π done := true; { have done this file already }ππ if not done then begin { if not, then }π filesdone[nmdone] := sfn; { say we have now }π dfn := sdir+outname; { give both dest and }π tfn := sdir+tmpname; { and temp files unique names }ππ openfiles ( infile, outfile, sfn, dfn );π write ( 'Quieting ', sfn, ', ' );π quietfile ( infile, outfile );ππ getftime ( infile, fdt );π setftime ( outfile, fdt );ππ close (infile); { close in }π close (outfile); { and out files }ππ{i-}π rename ( infile, tfn ); { rename in to temp and then }π if ioresult <> 0 thenπ showhelp (5);π rename ( outfile, sfn ); { out to in, thereby SWITCHING }π erase ( infile ); { in with out so we can erase in (!) }π if ioresult <> 0 thenπ showhelp (6);π{$i+}π nmdone := nmdone + 1; { increment number processed }π end; { if not done }π findnext(dirinfo); { go to next (until no more) }π end; { while }πend.πππ QUIETπ Free DOS utility: quiets noisy programsπ Version 1.00 - August 27, 1993π (c) 1993π byπ David Daniel Andersonπ Reign WareππππππQUIET quiets noisy programs, by replacing certain noisemaking programπcodes.ππWARNING!!! QUIET OVERWRITES THE INPUT FILE, SO MAKE SURE THAT YOUπEITHER WORK ON A -COPY- OF YOUR FILE(S) OR YOU KNOW WHAT YOU AREπDOING BEFORE YOU START.ππUsage: QUIET noisy_progππExamples:ππ QUIET hangman.comπ QUIET *.exeπ QUIET pac*.*π QUIET d:\games\fire.comππQUIET needs one and only one parameter on the command line: the fileπto be silenced. By using wildcards (* and ?), multiple files can beπprocessed in one pass. (See the DOS manual for wildcard info.)ππQUIET will maintain the original date and time of the file(s).πππ How it works:ππQUIET simply replaces the two-byte sequence: µa with: ÉÉπIn hex, that is: E6 61 and: 90 90.πIn decimal it is: 230 97 and: 144 144.ππThe E6 61 code is simply an instruction to activate the speaker, andπthe 90 90 code is simply an instruction to do nothing.πππ Possible complications/ reasons for failure:ππ1) Some programs check themselves, and will not work at all if theyπhave been changed.ππ2) Many programs make noise by other methods, and will not be silenced.ππ3) If the file was read-only, it cannot be processed.ππ4) Some virus detectors will complain if you try this on a file whichπyou have told the watch dog program to monitor.ππNote: other errors are mentioned by the program when it encounters them.ππ---π ■ SLMR 2.1a ■π ■ RNET 2.00m: ILink: Channel 1(R) ■ Cambridge, MA ■ 617-354-7077π 42 11-02-9305:37ALL JON JASIUNAS Modify EXE Constants SWAG9311 19 èo {πJON JASIUNASππ>Is it possible to store variables in actual .EXE file of a TP program, insteπ>of making an external config file for it? Thanks.ππSure. Make them typed constants, then modify the .EXE whenever you wantπto store a change.π}ππtypeπ tOwnerName = string[30];π tRegCode = String[12];ππconstπ OwnerName : tOwnerName = '';π RegCode : tRegCode = '';ππbeginπ WriteLn('The current owner is : ', OwnerName);π WriteLn('The current registration code is : ', RegCode);π WriteLn;ππ Write('Enter the new owner name: ');π ReadLn(OwnerName);π Write('Enter the new registration code: ');π ReadLn(RegCode);ππ If Write2Exe(OwnerName, SizeOf(OwnerName)) <> 0 thenπ WriteLn('Owner name not updated!');ππ If Write2Exe(RegCode, SizeOf(RegCode)) <> 0 thenπ WriteLn('Registration code not updated!');πend.ππ{ Here's my self mod unit: }ππ{*****************************π * EXEMOD.PAS v1.0 *π * *π * General purose .EXE *π * self-modifying routines *π *****************************ππ1992-93 HyperDrive SoftwareπReleased into the public domain.}ππ{$S-,R-,D-,I-}π{$IFOPT O+}π {$F+}π{$ENDIF}ππunit ExeMod;ππinterfaceππvarπ ExeName : String;ππfunction Write2Exe(var Data2Write; DataSize : Word) : Integer;ππimplementationππfunction Write2Exe(var Data2Write; DataSize : Word): Integer;πconstπ PrefixSize = 256;πvarπ ExeFile : File;π HeaderSize : Word;π IoError : Integer;πbeginπ Assign(ExeFile, ExeName);π Reset(ExeFile, 1);π IoError := IOResult;ππ If IoError = 0 thenπ {-Seek position of header size in EXE File }π beginπ Seek(ExeFile, 8);π IoError := IOResult;π end; { If }ππ If IoError = 0 thenπ {-Read header size in EXE File }π beginπ BlockRead(ExeFile, HeaderSize, Sizeof(HeaderSize));π IoError := IOResult;π end;ππ If IoError = 0 thenπ {-Seek position of Data in EXE File }π beginπ Seek(ExeFile, LongInt(16) * (HeaderSize + Seg(Data2Write) - PrefixSeg) +π IoError := IOResult;π end;ππ If IoError = 0 thenπ {-Write new Data to EXE File }π beginπ BlockWrite(ExeFile, Data2Write, DataSize);π IoError := IOResult;π end;ππ Close(ExeFile);π Write2Exe := IoError;πend;ππbeginπ ExeName := ParamStr(0);πend.ππ 43 11-02-9305:35ALL JON JASIUNAS Trapping Runtime Errors SWAG9311 9 èo {πJON JASIUNASππI never use them. if a Program bombs because a disk is full, I justπ> catch the run-time error in an Exit proc and report so (I/O-checkingπ> must be set on, of course).ππ>I am curious, How do you go about Catching the Run-Time Error. Doesn't itπ>just say Runtime Error 103 ?????:?????ππYou can catch the run-time errors by linking into the Exit chain.πHere's a small example:π}ππUnit ErrTrap;ππInterfaceππImplementationππVarπ OldExit : Pointer;ππProcedure NewExit; Far; { MUST be far! }πbeginπ if ErrorAddr <> nil thenπ beginπ {-Display custom run-time error message }π WriteLn('Fatal error #', ExitCode);π WriteLn('Address = ', Seg(ErrorAddr^), ':', Ofs(ErrorAddr^));π {-Cancel run-time error so you don't get the default message, too }π ErrorAddr := nil;π {-Zero the errorlevel }π ExitCode := 0;π end;π ExitProc := OldExit;πend;ππbeginπ OldExit := ExitProc;π ExitProc := @NewExit;πend.πππ 44 11-02-9305:50ALL KAI ROHRBACHER HACKING in Pascal SWAG9311 11 èo {πKAI ROHRBACHERππI'm looking For a way to tell BorlandPascal that an allocated _data_πblock should now be treated as an executable routine (in Protected Mode).πHere is a little example to show the problem; it runs w/o problems inπReal Mode, but results in a GP-fault (despite the use of the alias-selector!):π}ππProgram SelfModify;ππConstπ AnzNOPs = 10;ππTypeπ TTestProc = Procedure;ππVarπ code : Pointer;π Run : TTestProc;π pb : ^Byte;π pw : ^Word Absolute pb;π i : LongInt;ππbeginπ GetMem(code, AnzNOPs + 7); {7 Bytes For proc header & end}π pb := code; {pb = ^start of routine to build}ππ pb^ := $55;π INC(pb); {push bp}π pw^ := $E589;π INC(pw); {mov bp,sp}π For i := 1 to AnzNOPs DOπ beginπ pb^ := $90;π INC(pb); {nop's}π end;π pb^ := $5D;π INC(pb); {pop bp}π pb^ := $CA;π INC(pb);π pw^ := $0000; {retf 0}ππ {$IFDEF DPMI}π WriteLN('Protected Mode');π code:= Ptr(Seg(code) + SelectorInc, Ofs(code)); {alias-selector}π {$else}π WriteLN('Real Mode');π {$endIF}ππ Run := TTestProc(code); {that's a Type-cast!}π Run; {call routine}ππ FreeMem(code, AnzNOPs + 7);π WriteLN('Alive and kicking!');πend.π 45 11-02-9310:33ALL LEE BARKER POKER Again and Again SWAG9311 15 èo {πLEE BARKERππ│ I'm trying to Write a small Poker game For a grade in myπ│ High School Pascal Class.ππWhile the Array of Strings will work, it is a lot of overheadπfor what you want to do. It is also difficult to do the scoring.πThe following is a small piece of code I posted a year or twoπago when someone asked a similar question. Offered as a studyπguide For your homework.π}ππConstπ Limit = 5; { Minimum cards before reshuffle }π MaxDecks = 1; { Number of decks in use }π NbrCards = MaxDecks * 52;π Cardvalue : Array [0..12] of String[5] =π ('Ace','Two','Three','Four','Five','Six','Seven',π 'Eight','Nine','Ten','Jack','Queen','King');π Suit : Array [0..3] of String[8] =π ('Hearts','Clubs','Diamonds','Spades');ππTypeπ DeckOfCards = Array [0..Pred(NbrCards)] of Byte;ππVarπ Count,π NextCard : Integer;π Cards : DeckOfCards;ππProcedure shuffle;πVarπ i, j,π k, n : Integer;πbeginπ randomize;π j := 0; { New Decks }π For i := 0 to pred(NbrCards) doπ beginπ Cards[i] := lo(j);π inc(j);π if j > 51 thenπ j := 0;π end;π For j := 1 to 3 do { why not ? }π For i := 0 to pred(NbrCards) doπ begin { swap }π n := random(NbrCards);π k := Cards[n];π Cards[n] := Cards[i];π Cards[i] := k;π end;π NextCard := NbrCards;πend;ππFunction CardDealt : Byte;πbeginπ Dec(NextCard);π CardDealt := Cards[NextCard];πend;ππProcedure ShowCard(b : Byte);πVarπ c, s : Integer;πbeginπ c := b mod 13;π s := b div 13;π Writeln('The ', Cardvalue[c], ' of ', Suit[s]);πend;ππbeginπ Shuffle;π Writeln('< The deck is shuffled >');π { if NextCard <= Limit then shuffle }π For Count := 1 to 5 doπ ShowCard(CardDealt);π Readln;πend.π 46 11-02-9306:02ALL MARTIN LARSEN BREAK and CONTINUE SWAG9311 3 èo {πMARTIN LARSENππThere are at least two nice features in BP7: BREAK and CONTINUE:π}ππRepeatπ Inc(Count);π if Odd(Count) then Continue; { Go to start of loop }π if Count = 10 then Break; { Go to sentence just after loop }πUntil False;π 47 09-26-9309:25ALL MARTIN RICHARDSON Convert REAL to INTEGER SWAG9311 7 èo {*****************************************************************************π * Function ...... RTOI()π * Purpose ....... To convert a real to an integerπ * Parameters .... RealNum Real type numberπ * Returns ....... The integer part of RealNumπ * Notes ......... Simply truncates the decimalsπ * . Uses function Leftπ * Author ........ Martin Richardsonπ * Date .......... May 13, 1992π *****************************************************************************}πFUNCTION RTOI( RealNum: REAL ): LONGINT;πVARπ s: STRING;π l: LONGINT;π i: INTEGER;πBEGINπ STR( RealNum:17:2, s );π s := Left( s, LENGTH(s) - 3 );π VAL( s, l, i );π RTOI := l;πEND;ππ 48 09-26-9309:28ALL MARTIN RICHARDSON Convert STRING to INTEGERSWAG9311 6 èo {*****************************************************************************π * Function ...... STOI()π * Purpose ....... To convert a string to an integerπ * Parameters .... cNum String to convert to integer formatπ * Returns ....... cNum as a numeric integerπ * Notes ......... Noneπ * Author ........ Martin Richardsonπ * Date .......... May 13, 1992π *****************************************************************************}πFUNCTION STOI( cNum: STRING ): LONGINT;πVARπ c: INTEGER;π i: LONGINT;πBEGINπ VAL( cNum, i, c );π STOI := i;πEND;ππ 49 09-26-9309:24ALL MARTIN RICHARDSON Generate RANDOM Number SWAG9311 6 èo {*****************************************************************************π * Function ...... RND()π * Purpose ....... To generate a random numberπ * Parameters .... i Max value for number rangeπ * Returns ....... A random number between 1 and iπ * Notes ......... Noneπ * Author ........ Martin Richardsonπ * Date .......... May 13, 1992π *****************************************************************************}π{ FUNCTION to generate a random number between 1 and i }πFUNCTION RND( i: LONGINT ): LONGINT;πBEGINπ RND := RANDOM( i ) + 1;πEND;ππ 50 09-26-9309:17ALL MARTIN RICHARDSON Get GREATER of Integers SWAG9311 7 èo {*****************************************************************************π * Function ...... MaxI()π * Purpose ....... To return the greater of two integersπ * Parameters .... nNum1, nNum2 The integers to compareπ * Returns ....... The greater of nNum1 and nNum2π * Notes ......... Noneπ * Author ........ Martin Richardsonπ * Date .......... September 30, 1992π *****************************************************************************}πFUNCTION MaxI( nNum1, nNum2: LONGINT ): LONGINT; ASSEMBLER;πASMπ MOV AX, WORD PTR nNum1[0]π MOV DX, WORD PTR nNum1[2]π CMP DX, WORD PTR nNum2[2]π JNLE @@2π JL @@1ππ CMP AX, WORD PTR nNum2[0]π JA @@2ππ@@1: MOV AX, WORD PTR nNum2[0]π MOV DX, WORD PTR nNum2[2]π@@2:πEND;π 51 09-26-9309:17ALL MARTIN RICHARDSON Get SMALLER of Integers SWAG9311 7 èo {*****************************************************************************π * Function ...... MinI()π * Purpose ....... To return the lesser of two integersπ * Parameters .... nNum1, nNum2 The integers to compareπ * Returns ....... The lesser of nNum1 and nNum2π * Notes ......... Noneπ * Author ........ Martin Richardsonπ * Date .......... September 30, 1992π *****************************************************************************}πFUNCTION MinI( nNum1, nNum2: LONGINT ): LONGINT; ASSEMBLER;πASMπ MOV AX, WORD PTR nNum1[0]π MOV DX, WORD PTR nNum1[2]π CMP DX, WORD PTR nNum2[2]π JL @@2π JNLE @@1ππ CMP AX, WORD PTR nNum2[0]π JB @@2ππ@@1: MOV AX, WORD PTR nNum2[0]π MOV DX, WORD PTR nNum2[2]π@@2:πEND;π 52 09-26-9309:01ALL MARTIN RICHARDSON Produce DOS Error MessageSWAG9311 18 èo {*****************************************************************************π * Function ...... ErrorMsg()π * Purpose ....... To produce a DOS error message based on the error codeπ * Parameters .... ErrorCode DOS error codeπ * Returns ....... Error message assosiated with passed codeπ * Notes ......... Uses function ITOSπ * Author ........ Martin Richardsonπ * Date .......... May 13, 1992π *****************************************************************************}πFUNCTION ErrorMsg( ErrorCode: INTEGER ): STRING;πBEGINπ CASE ErrorCode OFπ 0: ErrorMsg := 'No Error';π 2: ErrorMsg := 'File Not Found';π 3: ErrorMsg := 'Path Not Found';π 4: ErrorMsg := 'Too Many Open Files';π 5: ErrorMsg := 'File Access Denied';π 6: ErrorMsg := 'Invalid File Handle';π 12: ErrorMsg := 'Invalid File Access Code';π 15: ErrorMsg := 'Invalid Drive Number';π 16: ErrorMsg := 'Cannot Remove Current Directory';π 17: ErrorMsg := 'Cannot Rename Across Drives';π 18: ErrorMsg := 'File access error';π 100: ErrorMsg := 'Disk Read Error';π 101: ErrorMsg := 'Disk Write Error';π 102: ErrorMsg := 'File Not Assigned';π 103: ErrorMsg := 'File Not Open';π 104: ErrorMsg := 'File Not Open For Input';π 105: ErrorMsg := 'File Not Open For Output';π 106: ErrorMsg := 'Invalid Numeric Format';π 150: ErrorMsg := 'Disk Is Write-Protected';π 151: ErrorMsg := 'Unknown Unit';π 152: ErrorMsg := 'Drive Not Ready';π 153: ErrorMsg := 'Unknown Command';π 154: ErrorMsg := 'CRC Error In Data';π 155: ErrorMsg := 'Bad Drive Request Structure Length';π 156: ErrorMsg := 'Disk Seek Error';π 157: ErrorMsg := 'Unknown Media Type';π 158: ErrorMsg := 'Sector Not Found';π 159: ErrorMsg := 'Printer Out Of Paper';π 160: ErrorMsg := 'Device Write Fault';π 161: ErrorMsg := 'Device Read Fault';π 162: ErrorMsg := 'Hardware Failure';π ELSE ErrorMsg := 'Error Number: ' + ITOS( ErrorCode, 0 );π END; { CASE }πEND;ππ 53 11-02-9304:49ALL MAYNARD PHILBROOK ARRAY Pointer in ASM SWAG9311 8 èo {πMAYNARD PHILBROOKππ>> I've never had to do this, so I'm not sure, but can't you just pass aπ>> pointer to the array? eg.π>> typeπ>> DorkArray = Array[0..255] of Byte;π>> varπ>> Dork : ^DorkArray;π>π> but what exactly do I declare in the assembly procedure to get thsesπ> values?π}πASmπ Mov Word AX, [Dork];π Mov Word BX, [Dork+2];π Mov ES, BX;π Mov BX, AX;π { Now ES:BX } {equal the same value as Dork}π Mov Byte AL, [ES:BX]; {Get the first byte of Dork into AL. }π Mov Byte AL, [ES:BX+1]; {Get the Secoce Byte of Dork into al.}π Mov Word SI, 00;π Mov AL, [ES:BX+SI]; {also do this.}π Inc SI;π Mov AL {ES:BX+SI]; Ect//π { Another way to load up a poiter }π LES Dowrd BX, [Dork]; { This is simpler way of defining a piiner.π 54 11-26-9316:59ALL PAUL ROBINSON UU Encode files SWAG9311 27 èo {π Pascal program to UUDECODE files which were processedπ with UUENCODE. Or it will DECODE files which wereπ processed by ENCODEππ Paul Robinson TDARCOS@MCIMAIL.COMπ Tansin A. Darcos & Companyπ June 26, 1993π}ππvar inf,outf:text;π open:boolean;π ch:char;π buflen,tag:char;π tagfiller:array[1..80] of char;π buf:string[80] absolute buflen;π tag3:array[1..3] of char absolute tag;π tag6:array[1..6] of char absolute tag;π outfn:string[80];π bp,n:integer;ππfunction dec(c:char):byte;πbeginπ dec := (ord(c) - ord(' ')) and 63πend;ππprocedure short(msg:string);πbeginπ writeln(msg);π close(inf);π if open thenπ close(outf);π halt(1);πend;πππprocedure skip;πbeginπ while buf[bp] = ' ' doπ beginπ bp := bp+1;π if bp>=length(buf) thenπ short('Error 01 Bad begin line');π end;π while buf[bp] <> ' ' doπ beginπ bp := bp+1;π if bp>=length(buf) thenπ short('Error 02 Bad begin line');π end;π while buf[bp] = ' ' doπ beginπ bp := bp+1;π if bp>=length(buf) thenπ short('Error 03 Bad begin line');π end;π while (buf[bp] <> ' ') doπ beginπ outfn := outfn+buf[bp];π bp := bp+1;π end;πend;ππππ{ output a group of 3 bytes (4 input characters).π the input chars are pointed to by bp.π n is used to tell us not to output all of themπ at the end of the file.π}ππprocedure outdec(bp,n:integer);πvar c1,c2,c3:byte;πbeginπ c1 := (DEC(buf[bp]) shl 2) or (dec(buf[bp+1]) shr 4);π c2 := (dec(buf[bp+1]) shl 4) or (dec(buf[bp+2]) shr 2);π c3 := (dec(buf[bp+2]) shl 6) or dec(buf[bp+3]);π if n >= 1 thenπ write(outf,chr(c1));π if n >= 2 thenπ write(outf,chr(c2));π if n >= 3 thenπ write(outf,chr(c3));πend;ππprocedure decode;πbeginπ if eof(inf) thenπ short('Premature EOF');π repeatπ readln(inf,buf);π if length(buf)>0 thenπ beginπ n := dec(buf[1]);π if n > 0 thenπ beginπ bp := 2;π while n>0 doπ beginπ outdec(bp, n);π bp := bp+4;π n := n-3;π end;π end;π end;π until length(buf)<2;πend;ππππbeginπ if (paramcount <1) or ((paramcount >=1) and (paramstr(1)='/?')) thenπ beginπ writeln('Pascal UUDECODER by Paul Robinson - TDARCOS@MCIMAIL.COM');π writeln('Usage: DECODE filename');π halt(0);π end;π assign(inf,paramstr(1));π open := false;ππ {$I-} reset(inf); {$I+}π if IORESULT <> 0 thenπ short('File '+paramstr(1)+' cannot be opened.');π if not eof(inf) thenπ readln(inf,buf)π elseπ short('Empty file');π while tag6 <> 'begin ' doπ if not eof(inf) thenπ readln(inf,buf)π elseπ short('No begin line');π bp := 6;π buf := buf+' ';ππ{π format is 'begin nnn filename'π skip spaces before the nnnπ skip the nnnπ skip spaces after the nnnπ}π skip;π assign(outf,outfn);π{$I-} rewrite(outf); {$I+}π if IORESULT = 0 thenπ open := trueπ elseπ short('Cannot create file '+outfn);ππ decode;π readln(inf,buf);π if tag3 <> 'end' thenπ short('Warning: no end line');π close(inf);π if open thenπ close(outf);πend.π 55 11-02-9304:55ALL RANDALL ELTON DING Maze Generator SWAG9311 96 èo {πrandyd@csd4.csd.uwm.edu (Randall Elton Ding)ππThis is really for Allen who earlier in the month asked about generatingπa maze in pascal. It may not really be the fastest, but I know ofπno other way which is faster. Check it out, it lets you try to moveπthru the maze, when you give up it shows you the way. It has variableπdifficulty and size too.ππThis was origionally written in Apple][ 6502 machine language, I portedπit over to pascal a few years later.π}ππ(* Big Mind Over Mazeπ maze generator and solverπ created by Randy Dingπ July 16,1983 <April 21,1992> *)ππ{$R-} { range checking }ππprogram makemaze;ππusesπ crt, graph;ππconstπ screenwidth = 640;π screenheight = 350;π minblockwidth = 2;π maxx = 200; { [3 * maxx * maxy] must be less than 65520 (memory segment) }π maxy = 109; { here maxx/maxy about equil to screenwidth/screenheight }π flistsize = 5000; { flist size (fnum max, about 1/3 of maxx * maxy) }ππ background = black;π gridcolor = green;π solvecolor = white;ππ rightdir = $01;π updir = $02;π leftdir = $04;π downdir = $08;ππ unused = $00; { cell types used as flag bits }π frontier = $10;π reserved = $20;π tree = $30;πππtypeπ frec = recordπ column, row : byte;π end;π farr = array [1..flistsize] of frec;ππ cellrec = recordπ point : word; { pointer to flist record }π flags : byte;π end;π cellarr = array [1..maxx,1..maxy] of cellrec;ππ {π one byte per cell, flag bits...ππ 0: right, 1 = barrier removedπ 1: top "π 2: left "π 3: bottom "π 5,4: 0,0 = unused cell typeπ 0,1 = frontier "π 1,1 = tree "π 1,0 = reserved "π 6: (not used)π 7: solve path, 1 = this cell part of solve pathπ }πππvarπ flist : farr; { list of frontier cells in random order }π cell : ^cellarr; { pointers and flags, on heap }π fnum,π width,π height,π blockwidth,π halfblock,π maxrun : word;π runset : byte;π ch : char;ππprocedure initbgi;πvarπ grdriver,π grmode,π errcode : integer;πbeginπ grdriver := DETECT;π grmode := EGAhi;π initgraph(grdriver, grmode, 'e:\bp\bgi');π errcode:= graphresult;π if errcode <> grok thenπ beginπ writeln('Graphics error: ', grapherrormsg(errcode));π halt(1);π end;πend;πππfunction adjust(var x, y : word; d : byte) : boolean;πbegin { take x,y to next cell in direction d }π case d of { returns false if new x,y is off grid }π rightdir:π beginπ inc (x);π adjust:= x <= width;π end;ππ updir:π beginπ dec (y);π adjust:= y > 0;π end;ππ leftdir:π beginπ dec (x);π adjust:= x > 0;π end;ππ downdir:π beginπ inc (y);π adjust:= y <= height;π end;π end;πend;πππprocedure remove(x, y : word); { remove a frontier cell from flist }πvarπ i : word; { done by moving last entry in flist into it's place }πbeginπ i := cell^[x,y].point; { old pointer }π with flist[fnum] doπ cell^[column,row].point := i; { move pointer }π flist[i] := flist[fnum]; { move data }π dec(fnum); { one less to worry about }πend;πππprocedure add(x, y : word; d : byte); { add a frontier cell to flist }πvarπ i : byte;πbeginπ i := cell^[x,y].flags;π case i and $30 of { check cell type }π unused :π beginπ cell^[x,y].flags := i or frontier; { change to frontier cell }π inc(fnum); { have one more to worry about }π if fnum > flistsize thenπ begin { flist overflow error! }π dispose(cell); { clean up memory }π closegraph;π writeln('flist overflow! - To correct, increase "flistsize"');π write('hit return to halt program ');π readln;π halt(1); { exit program }π end;π with flist[fnum] doπ begin { copy data into last entry of flist }π column := x;π row := y;π end;π cell^[x,y].point := fnum; { make the pointer point to the new cell }π runset := runset or d; { indicate that a cell in direction d was }π end; { added to the flist }ππ frontier : runset := runset or d; { allready in flist }π end;πend;πππprocedure addfront(x, y : word); { change all unused cells around this }πvar { base cell to frontier cells }π j, k : word;π d : byte;πbeginπ remove(x, y); { first remove base cell from flist, it is now }π runset := 0; { part of the tree }π cell^[x,y].flags := cell^[x,y].flags or tree; { change to tree cell }π d := $01; { look in all four directions- $01,$02,$04,$08 }π while d <= $08 doπ beginπ j := x;π k := y;π if adjust(j, k, d) thenπ add(j, k, d); { add only if still in bounds }π d := d shl 1; { try next direction }π end;πend;πππprocedure remline(x, y : word; d : byte); { erase line connecting two blocks }πbeginπ setcolor(background);π x := (x - 1) * blockwidth;π y := (y - 1) * blockwidth;π case d ofπ rightdir : line (x + blockwidth, y + 1, x + blockwidth, y + blockwidth - 1);π updir : line (x + 1, y, x + blockwidth - 1, y);π leftdir : line (x, y + 1, x, y + blockwidth - 1);π downdir : line (x + 1, y + blockwidth, x + blockwidth - 1, y + blockwidth);π end;πend;πππ{ erase line and update flags to indicate the barrier has been removed }πprocedure rembar(x, y : word; d : byte);πvarπ d2 : byte;πbeginπ remline(x, y, d); { erase line }π cell^[x,y].flags := cell^[x,y].flags or d; { show barrier removed dir. d }π d2 := d shl 2; { shift left twice to reverse direction }π if d2 > $08 thenπ d2 := d2 shr 4; { wrap around }π if adjust(x, y, d) then { do again from adjacent cell back to base cell }π cell^[x,y].flags := cell^[x,y].flags or d2; { skip if out of bounds }πend;πππfunction randomdir : byte; { get a random direction }πbeginπ case random(4) ofπ 0 : randomdir := rightdir;π 1 : randomdir := updir;π 2 : randomdir := leftdir;π 3 : randomdir := downdir;π end;πend;πππprocedure connect(x, y : word); { connect this new branch to the tree }πvar { in a random direction }π j, k : word;π d : byte;π found : boolean;πbeginπ found := false;π while not found doπ begin { loop until we find a tree cell to connect to }π j := x;π k := y;π d := randomdir;π if adjust(j, k, d) thenπ found := cell^[j,k].flags and $30 = tree;π end;π rembar(x, y, d); { remove barrier connecting the cells }πend;πππprocedure branch(x, y : word); { make a new branch of the tree }πvarπ runnum : word;π d : byte;π i : boolean;πbeginπ runnum := maxrun; { max number of tree cells to add to a branch }π connect(x, y); { first connect frontier cell to the tree }π addfront(x, y); { convert neighboring unused cells to frontier }π dec(runnum); { number of tree cells left to add to this branch }π while (runnum > 0) and (fnum > 0) and (runset > 0) doπ beginπ repeatπ d := randomdir;π until d and runset > 0; { pick random direction to known frontier }π rembar(x, y, d); { and make it part of the tree }π i := adjust(x, y, d);π addfront(x, y); { then pick up the neighboring frontier cells }π dec(runnum);π end;πend;πππprocedure drawmaze;πvarπ x, y, i : word;πbeginπ setcolor(gridcolor); { draw the grid }π y := height * blockwidth;π for i := 0 to width doπ beginπ x := i * blockwidth;π line(x, 0, x, y);π end;π x := width * blockwidth;π for i := 0 to height doπ beginπ y := i * blockwidth;π line (0, y, x, y);π end;π fillchar(cell^, sizeof(cell^), chr(0)); { zero flags }π fnum := 0; { number of frontier cells in flist }π runset := 0; { directions to known frontier cells from a base cell }π randomize;π x := random(width) + 1; { pick random start cell }π y := random(height) + 1;π add(x, y, rightdir); { direction ignored }π addfront(x, y); { start with 1 tree cell and some frontier cells }π while (fnum > 0) doπ with flist[random(fnum) + 1] doπ branch(column, row);πend;ππprocedure dot(x, y, colr : word);πbeginπ putpixel(blockwidth * x - halfblock, blockwidth * y - halfblock, colr);πend;ππprocedure solve(x, y, endx, endy : word);πvarπ j, k : word;π d : byte;π i : boolean;πbeginπ d := rightdir; { starting from left side of maze going right }π while (x <> endx) or (y <> endy) doπ beginπ if d = $01 thenπ d := $08π elseπ d := d shr 1; { look right, hug right wall }π while cell^[x,y].flags and d = 0 doπ begin { look for an opening }π d := d shl 1; { if no opening, turn left }π if d > $08 thenπ d := d shr 4;π end;π j := x;π k := y;π i := adjust(x, y, d); { go in that direction }π with cell^[j,k] doπ begin { turn on dot, off if we were here before }π flags := ((((cell^[x,y].flags xor $80) xor flags) and $80) xor flags);π if flags and $80 <> 0 thenπ dot(j, k, solvecolor)π elseπ dot(j, k, background);π end;π end;π dot(endx, endy, solvecolor); { dot last cell on }πend;ππprocedure mansolve (x,y,endx,endy: word);πvarπ j, k : word;π d : byte;π ch : char;πbeginπ ch := ' ';π while ((x <> endx) or (y <> endy)) and (ch <> 'X') and (ch <> #27) doπ beginπ dot(x, y, solvecolor); { dot man on, show where we are in maze }π ch := upcase(readkey);π dot(x, y, background); { dot man off after keypress }π d := 0;π case ch ofπ #0:π beginπ ch := readkey;π case ch ofπ #72 : d := updir;π #75 : d := leftdir;π #77 : d := rightdir;π #80 : d := downdir;π end;π end;ππ 'I' : d := updir;π 'J' : d := leftdir;π 'K' : d := rightdir;π 'M' : d := downdir;π end;ππ if d > 0 thenπ beginπ j := x;π k := y; { move if no wall and still in bounds }π if (cell^[x,y].flags and d > 0) and adjust(j, k, d) thenπ beginπ x := j;π y := k;π end;π end;π end;πend;ππprocedure solvemaze;πvarπ x, y,π endx,π endy : word;π ch : char;πbeginπ x := 1; { pick random start on left side wall }π y := random(height) + 1;π endx := width; { pick random end on right side wall }π endy := random(height) + 1;π remline(x, y, leftdir); { show start and end by erasing line }π remline(endx, endy, rightdir);π mansolve(x, y, endx, endy); { try it manually }π solve(x, y, endx, endy); { show how when he gives up }π while keypressed doπ ch := readkey;π ch := readkey;πend;πππprocedure getsize;πvarπ j, k : real;πbeginπ clrscr;π writeln(' Mind');π writeln(' Over');π writeln(' Maze');π writeln;π writeln(' by Randy Ding');π writeln;π writeln('Use I,J,K,M or arrow keys to walk thru maze,');π writeln('then hit X when you give up!');π repeatπ writeln;π write('Maze size: ', minblockwidth, ' (hard) .. 95 (easy) ');π readln(blockwidth);π until (blockwidth >= minblockwidth) and (blockwidth < 96);π writeln;π write('Maximum branch length: 1 easy .. 50 harder, (0 unlimited) ');π readln(maxrun);π if maxrun <= 0 thenπ maxrun := 65535; { infinite }π j := screenwidth / blockwidth;π k := screenheight / blockwidth;π if j = int(j) thenπ j := j - 1;π if k = int(k) thenπ k := k - 1;π width := trunc(j);π height := trunc(k);π if (width > maxx) or (height > maxy) thenπ beginπ width := maxx;π height := maxy;π end;π halfblock := blockwidth div 2;πend;ππbeginπ repeatπ getsize;π initbgi;π new(cell); { allocate this large array on heap }π drawmaze;π solvemaze;π dispose(cell);π closegraph;π while keypressed doπ ch := readkey;π write ('another one? ');π ch := upcase (readkey);π until (ch = 'N') or (ch = #27);πend.ππ 56 11-02-9310:33ALL SEAN PALMER POKER Again SWAG9311 13 èo {πSEAN PALMERππ> I'm trying to Write a small Poker game For a grade in my Highπ> School Pascal Class. I set the deck up as an Array of String'sπ> (example: Deck: Array[1..52] of String)π> And then filled the Array With somthing like: Deck[1]:='2 ofπ> Diamonds'; I may have started wrongly, but I need a way to "Shuffle"π> the deck. I could probably read them into the Array Randomly, orπ> could I keep them in a logical order in the Array and shuffle theπ> Array itself? Let me know if you have any ideas concerning myπ> problem maybe you could post some code For me.ππThere are probably better ways to set up the data structure, such as:π}ππTypeπ tCardVal = (Two, Three, Four, Five, Six, Seven,π Eight, Nine, Ten, Jack, Queen, King, Ace);π tCardSuit = (Spades, Diamonds, Hearts, Clubs);ππ tCard = Recordπ val : tCardVal;π suit : tCardSuit;π end;ππConstπ valStrings : Array [tCardVal] of String[5] =π ('Two', 'Three', 'Four', 'Five', 'Six', 'Seven',π 'Eight', 'Nine', 'Ten', 'Jack', 'Queen', 'King', 'Ace');π suitStrings : Array [tCardSuit] of String[8] =π ('Spades', 'Diamonds', 'Hearts', 'Clubs');ππVarπ deck : Array [0..51] of tCard;ππ{ after initializing the deck, you could shuffle With a Procedure like this: }ππfor i := 300 + random(50) downto 0 doπbeginπ posn := random(51);π tempCard := deck[posn];π deck[posn] := deck[posn + 1];π deck[posn + 1] := tempCard;πend;ππ{πThis might be better if it swapped two randomly-picked cards, would shuffleπbetter... }π 57 11-26-9317:48ALL STEVE SCHAFER TRAP8087 Errors SWAG9311 16 èo {πHere is how to trap errors on the 80X87. I am not sure yet how it works withπthe FP emulation library, but if you have a math coprocessor, you can trapπany FP exceptions:π}ππ{$N+,E+}πprogram FloatTest;π{ compliments of Steve Schafer, Compuserve address 76711, 522 }πconstπ feInvalidOp = $01;π feDenormalOp = $02;π feZeroDivide = $04;π feOverFlow = $08;π feUnderFlow = $10;π fePrecision = $20;ππprocedure SetFpuExceptionMask (MaskBits: Byte); assembler;π{ Masks floating point exceptions so that they won't cause a crash }πvarπ Temp: word;πasmπ fstcw Tempπ fwaitπ mov ax, Tempπ and al, $F0π or al, MaskBitsπ mov Temp, axπ fldcw Tempπ fwaitπend;ππfunction GetFpuStatus: Byte; assembler;π{ determines the status of a previous FP operation }πvarπ Temp: word;πasmπ fstsw Tempπ fwaitπ mov ax, Tempπend;ππprocedure WriteStatus(Status: Byte);π{ This procedure is not necessary, it simply illustrates how to determineπ what happenend }πbeginπ if (Status and fePrecision) <> 0 then Write('P')π else Write('-');π if (Status and feUnderflow) <> 0 then Write('U')π else Write('-');π if (Status and feOverflow) <> 0 then Write('O')π else Write('-');π if (Status and feZeroDivide) <> 0 then Write('Z')π else Write('-');π if (Status and feDenormalOp) <> 0 then Write('D')π else Write('-');π if (Status and feInvalidOp) <> 0 then Write('I')π else Write('-');πend;ππvarπ X,Y: Single;ππbeginπ SetFPUExceptionMask (feInvalidOp + feDenormalOp + feZeroDivideπ + feOverflow + feUnderflow + fePrecision);ππ X:= -1.0;π Y:= Sqrt(X); { Invalid Operation }π WriteStatus(GetFPUStatus); π Writeln(' ', Y:12, ' ', X:12);ππ X:= 0.0;π Y:= 1.0;π Y:= Y/X; { divide by Zero }π WriteStatus(GetFPUStatus);π Writeln(' ', Y:12, ' ', X:12);ππ X:= 1.0E-34;π Y:= 1.0E-34;π Y:= Y*X; { Underflow }π WriteStatus(GetFPUStatus);π Writeln(' ', Y:12, ' ', X:12);ππend.π 58 11-26-9317:37ALL SWAG SUPPORT GROUP Pick Unit; Select Choice SWAG9311 99 èo (********************************************************)π(******************** PICK.PAS **************************)π(******* the pick unit; to select menu choice *******)ππUnit Pick;ππinterfaceππ{1} Function ScreenChar : Char; {return the char at the cursor}π{2} Procedure BlockCursor; {give us a block cursor; TP6 & 7 only}π{3} Procedure NormalCursor; {restore cursor to normal; TP6 & 7 only}ππ{4} Function PickByte(Left, Top, Bottom : Byte) : Byte;π {return the number of the item chosen as a byte, orπ return ZERO if ESCape is pressed}ππ{5} Function PickChar(Left, Top, Bottom : Byte) : Char;π {return the character at the cursor when ENTER is pressed}πππ{πNotes: for "Pick" functionsπ One returns a Byte and the other returns a Char - use oneπ or the other;ππ Parameters:π Left = the left side of the menu list (left side of window+1)π Top = the top of the menu list (top of window+1)π Bottom = the bottom of the menu list; (bottom of window-1)π}ππimplementationππusesπdos,πcrt,πkeyb;ππ{-----------------------------------------------------}πFunction PickByte(Left,Top,Bottom : byte) : Byte;π{return the number of the item chosen as a byte, orπreturn ZERO if ESCape is pressed}ππVarπx,y,x1,y1 : byte;πch : char;πint,total : byte;ππbeginπ PickByte := 0; {default to ZERO}π total := (Bottom - Top)+1; {total number of items in list}π x1 := WhereX; y1 := WhereY; {save the original location}ππ x := Left; y := Top;π BlockCursor; {give us a block cursor}ππ GotoXy(x, y);ππ int := 1;ππ Repeatπ Ch := GetKey;ππ Case Ch ofπ LeftArrow, UpArrow : {move up}π beginπ If y = Top thenπ beginπ y := Bottom;π int := total;π endπ elseπ beginπ Dec(y);π dec(int);π end;ππ GotoXy(x,y);π end; {leftarrow}ππ RightArrow, DownArrow : {move down}π beginπ If y = Bottom thenπ beginπ y := Top;π int := 1;π endπ elseπ beginπ Inc(y);π inc(int);π end;π GotoXy(x,y);π end; {rightarrow}ππ PgUp, Home : {go to top of list}π beginπ y := Top;π int := 1;π GotoXy(x,y);π end;ππ PgDn, EndKey : {go to bottom of list}π beginπ y := Bottom;π int := total;π GotoXy(x,y);π end;ππ #13 : PickByte := int; {return position of choice in the array}π End; {Case Ch}ππ Until (ch = #27) or (ch = #13); {loop until ESCape or ENTER}ππ GotoXY(x1,y1); {return to original location}π NormalCursor; {Restore the cursor}πend;π{---------------------------------------------}ππFunction PickChar(Left, Top,Bottom : byte) : Char;π{return the character at the cursor when ENTER is pressed}ππVarπx,y,x1,y1 : byte;πch : char;ππbeginπ PickChar := #27;π x1 := WhereX; y1 := WhereY;π x := Left; y := Top;ππ BlockCursor; {give us a block cursor}π GotoXy(x,y);ππ Repeatπ Ch := GetKey;π Case Ch ofπ LeftArrow, UpArrow :π beginπ If y = Top then y := Bottom else Dec(y);π GotoXy(x,y);π end; {leftarrow}ππ RightArrow, DownArrow :π beginπ If y = Bottom then y := Top else Inc(y);π GotoXy(x,y);π end; {leftarrow}ππ PgUp, Home :π beginπ y := Top;π GotoXy(x,y);π end;ππ PgDn, EndKey :π beginπ y := Bottom;π GotoXy(x,y);π end;ππ #13 : PickChar := ScreenChar; {return the char under the cursor}π End; {Case Ch}ππ Until (ch = #27) or (ch = #13);π GotoXY(x1,y1);π NormalCursor; {give us a block cursor}ππend;π{-----------------------------------------------}ππ{----------------------------------------}πFunction ScreenChar : Char; {return the character at the cursor}πVarπR : Registers;πbeginπ Fillchar(R, SizeOf(R), 0);π R.AH := 8;π R.BH := 0;π Intr($10, R);π ScreenChar := Chr(R.AL);πend;π{--------------------------------------------------}πππ{---------------------------------}πProcedure NormalCursor; {restore cursor to normal; TP6 & 7 only}πBEGINπ asmπ mov ah,1π mov ch,5 { / You will want to fool around with these two}π mov cl,6 { \ numbers to get the cursor you want}π int $10π END;πEND;ππ{--------------------------------}πProcedure BlockCursor; {give us a block cursor; TP6 & 7 only}πBEGINπ asmπ mov ah,1π mov ch,5 { / You will want to fool around with these two}π mov cl,8 { \ numbers to get the cursor you want; (1=big)}π int $10π END;πEND;π{-------------------------------------}ππEnd.ππ{----------------- end of PICK.PAS --------------------}πππππ(********************************************************)π(******************** KEYB.PAS **************************)π(******* the keyboard unit; for GetKey() function *******)ππUnit Keyb;ππInterfaceππUses Crt;ππConstπ F1 = #187;π F2 = #188;π F3 = #189;π F4 = #190;π F5 = #191;π F6 = #192;π F7 = #193;π F8 = #194;π F9 = #195;π F10 = #196;ππ ALTF1 = #232;π ALTF2 = #233;π ALTF3 = #234;π ALTF4 = #235;π ALTF5 = #236;π ALTF6 = #237;π ALTF7 = #238;π ALTF8 = #239;π ALTF9 = #240;π ALTF10 = #241;ππ CTRLF1 = #222;π CTRLF2 = #223;π CTRLF3 = #224;π CTRLF4 = #225;π CTRLF5 = #226;π CTRLF6 = #227;π CTRLF7 = #228;π CTRLF8 = #229;π CTRLF9 = #230;π CTRLF10 = #231;ππ SHFTF1 = #212;π SHFTF2 = #213;π SHFTF3 = #214;π SHFTF4 = #215;π SHFTF5 = #216;π SHFTF6 = #217;π SHFTF7 = #218;π SHFTF8 = #219;π SHFTF9 = #220;π SHFTF10 = #221;ππ UPARROW = #200;π RIGHTARROW = #205;π LEFTARROW = #203;π DOWNARROW = #208;ππ HOME = #199;π PGUP = #201;π ENDKEY = #207;π PGDN = #209;π INS = #210;π DEL = #211;π TAB = #9;π ESC = #27;π ENTER = #13;π SYSREQ = #183;π CTRLMINUS = #31;π SPACE = #32;π CTRL2 = #129;π CTRL6 = #30;π BACKSPACE = #8;π BS = #8; {2 NAMES FOR BACKSPACE}ππ CTRLBACKSLASH = #28;π CTRLLEFTBRACKET = #27;π CTRLRIGHTBRACKET = #29;π CTRLBACKSPACE = #127;π CTRLBS = #127;ππ ALTA = #158;π ALTB = #176;π ALTC = #174;π ALTD = #160;π ALTE = #146;π ALTF = #161;π ALTG = #162;π ALTH = #163;π ALTI = #151;π ALTJ = #164;π ALTK = #165;π ALTL = #166;π ALTM = #178;π ALTN = #177;π ALTO = #152;π ALTP = #153;π ALTQ = #144;π ALTR = #147;π ALTS = #159;π ALTT = #148;π ALTU = #150;π ALTV = #175;π ALTW = #145;π ALTX = #173;π ALTY = #149;π ALTZ = #172;ππ CTRLA = #1;π CTRLB = #2;π CTRLC = #3;π CTRLD = #4;π CTRLE = #5;π CTRLF = #6;π CTRLG = #7;π CTRLH = #8;π CTRLI = #9;π CTRLJ = #10;π CTRLK = #11;π CTRLL = #12;π CTRLM = #13;π CTRLN = #14;π CTRLO = #15;π CTRLP = #16;π CTRLQ = #17;π CTRLR = #18;π CTRLS = #19;π CTRLT = #20;π CTRLU = #21;π CTRLV = #22;π CTRLW = #23;π CTRLX = #24;π CTRLY = #25;π CTRLZ = #26;ππ ALT1 = #248;π ALT2 = #249;π ALT3 = #250;π ALT4 = #251;π ALT5 = #252;π ALT6 = #253;π ALT7 = #254;π ALT8 = #255;π ALT9 = #167;π ALT0 = #168;ππ ALTMINUS = #169;π ALTEQ = #170;π SHIFTTAB = #143;ππFunction GetKey : Char;πprocedure unGetKey(C : char);πprocedure FlushKbd;πprocedure flushBuffer;ππconstπ hasPushedChar : boolean = false;ππimplementationπvarπ pushedChar : char;πππ(******************************************************************************π* FlushKbd *π******************************************************************************)πprocedure FlushKbd;πvarπ C : char;πbeginπ hasPushedChar := False;π while (KeyPressed) doπ C := GetKey;πend; {flushKbd}ππ(******************************************************************************π* flushBuffer *π* Same as above, but if key was pushed by eventMgr, know about it !! *π******************************************************************************)πprocedure flushBuffer;πvarπ b : boolean;πbeginπ b := hasPushedChar;π flushKbd;π hasPushedChar := b;πend; {flushBuffer}πππ(******************************************************************************π* unGetKey *π* UnGetKey will put one character back in the input buffer. Push-back buffer *π* can contain only one character. *π* To avoid problems DO NOT CALL UNGETKEY WITHOUT FIRST CALLING GETKEY. If two *π* characters are pushed, the first is discarded. *π******************************************************************************)πprocedure unGetKey;πbeginπ hasPushedChar := True;π pushedChar := c;πend; {unGetKey}ππ(******************************************************************************π* GetKey *π******************************************************************************)πfunction GetKey : Char;πvarπ c : Char;πBeginπ if (hasPushedChar) then beginπ GetKey := pushedChar;π hasPushedChar := False;π exit;π end;π c := ReadKey;π if (Ord(c) = 0) then Beginπ c := ReadKey;π if c in [#128,#129,#130,#131]π then c := chr(ord(c) + 39)π else c := chr(ord(c) + 128); {map to suit keyboard constants}π End;π GetKey := c; {return keyboard (my..) code }πEnd; {getKey}ππEnd.π{--------------- End of KEYB.PAS ---------------}πππ(********************************************************)π(************************** TEST.PAS ********************)π(*************** to test the PICK unit ******************)π(*************** quit by pressing ESCape ****************)ππProgram Test;ππuses crt,pick;ππ{--------------- test program -----------------}πconstπmax = 6;πs : array[1..max] of string[18] =π(π'1. Number One ',π'2. Number Two ',π'3. Number Three ',π'4. Number Four ',π'5. Number Five ',π'6. Number Six ');ππvarπi : byte;πx : byte;πch : char;πj : byte;ππbeginπ clrscr;π x := 10; {left side of the list}πππ {------------------------- test using PickByte() ----------------}π for i := 1 to max doπ begin {display the list of menu items}π j := i+5; {start from row 6}π gotoxy(x,j);π writeln(s[i]);π end;ππ i := j;π repeatπ {ch := choice(x,1,i);}π j := pickbyte(x,6,i);ππ gotoxy(15,22);π writeln('You chose ',j);π until j = 0; {until Escape}ππ {------------------------- test using PickChar() ----------------}π ClrScr;ππ ch := 'A';π for i := 1 to max doπ beginπ s[i][1] := Ch; {change numbers to letters in menu list}π Inc(Ch);π end;ππ for i := 1 to max doπ begin {display the list of menu items}π gotoxy(x,i); {start from row 1}π writeln(s[i]);π end;ππ repeatπ ch := PickChar(x,1,i);π gotoxy(15,22);π writeln('You chose ',ch);π until ch = #27; {until Escape}ππend.π{------------------------ end of TEST.PAS ---------------------------}π 59 11-26-9317:39ALL SWAG SUPPORT GROUP RANDOM Numbers SWAG9311 17 èo πinterfaceππprocedure InitRandomGenerator(InitValue : longint);πfunction Random:real;ππimplementationπtypeπ Lint = recordπ a,b,c,d : word;π end;πvarπ yWertZufall : Lint;π Modul : Lint;π Faktor : integer;πprocedure LintMUL(var p1: Lint; p2: integer);πbeginπ asmπ mov cx,4π les di,p1π xor bx,bxπ cldπ @mull: mov ax,es:[di]π mov dx,p2π mul dxπ add ax,bxπ adc dx,0π mov bx,dxπ stoswπ loop @mullπ end;πend;πprocedure LintSub(var p1, p2: Lint);πvarπ result : longint;π carry : word;πbeginπ result := p1.a;π dec(result, p2.a);π if result < 0 thenπ beginπ carry := 1;π inc(result, 65536);π endπ elseπ carry := 0;π p1.a := result;π result := p1.b;π dec(result, carry);π dec(result, p2.b);π if result < 0 thenπ beginπ carry := 1;π inc(result, 65536);π endπ elseπ carry := 0;π p1.b := result;π result := p1.c;π dec(result, carry);π dec(result, p2.c);π if result < 0 thenπ beginπ carry := 1;π inc(result, 65536);π endπ elseπ carry := 0;π p1.c := result;π dec(p1.d, carry);π dec(p1.d, p2.d);πend;ππprocedure InitRandomGenerator(InitValue : longint);πbeginπ with yWertZufall doπ beginπ b := InitWert div 65536;π a := InitWert - b*65536;π c := 0;π d := 0;π end;πend; (* InitRandomGenerator *)ππfunction Random:real;πvarπ Wert : longint;πbeginπ LintMul(yWertZufall , Faktor);π if yWertZufall.b >32767 thenπ LintSub(yWertZufall,Modul);ππ Wert := 2*yWertZufall.c + 65536*yWertZufall.b+yWertZufall.a;π with yWertZufall do beginπ d := 0;π c := 0;π b := Wert shr 16;π a := Wert - (b*65536);π end;π Zufall := Wert / 2147483647;ππend; (* Zufall *)πbeginπ with yWertZufall doπ beginπ a := 0;π b := 0;π c := 0;π d := 0;π end;π Faktor := 16807;π with Modul doπ beginπ a := 65535;π b := 32767;π c := 0;π d := 0;π end;πend. (* _Zufall *)π 60 11-26-9317:11ALL SWAG SUPPORT GROUP Trap Floating point Errs SWAG9311 44 èo {π There was a discussion about how to trap floating point errorsπin TP. Here is the solution that traps any kind of run-timeπerrors. The idea is not mine. I saw it in a russian book about TPπand OOP.ππ The idea is quite simple. Instead of trying to trap all kind ofπerrors, we can let TP to do the job for us. Whenever TP stopsπexecution of the program ( because of a run time error or justπbecause the program stops in a natural way ) it executes theπdefault procedure of exit : ExitProc. Then TP checks the status ofπtwo variables from the SYSTEM unit : ErrorAddr and ExitCode. Ifπthere was a run time error then ErrorAddr is not NIL and ExitCodeπcontaines the run time error code. Otherwise ExitCode containes theπerrorlevel that will be set for DOS and ErrorAddr is NIL.πFortunatly we can easily redefine the ExitProc, and thus toπovertake the control from TP. The problem is that we got to be ableπto get back or to jump to any point of the program ( even to jumpπinside a procedure / function). The author of the book claimed thatπhe took his routines from Turbo Professional.ππ Well, there are two files you are gonna need. Save the first oneπas JUMP.PAS Compile it as a unit. The second one is a short programπthat shows how to use it. It asks for two numbers, divides theπfirst by the second and takes a natural logarithm of the result.πTry to divide by zero, logarithm of a negative number. Try enteringπletters instead of numbers and see how the program recovers.ππ The trapping works fine under Windows/Dos. To run it withπWINDOWS recompile the JUMP unit for Windows target. Then add WinCrtπto the Uses statement and remove Mark/Release lines ( because thereπis no Mark/Release for Windows ).π}ππUnit Jump;πInterfaceπType JumpRecord = Recordπ SpReg,π BpReg : Word;π JmpPt : Pointer;π end;ππProcedure SetJump ( Var JumpDest : JumpRecord );π{Storing SP,BP and the address}πinline(π $5F/ {pop di }π $07/ {pop es }π $26/$89/$25/ {mov es:[di],sp }π $26/$89/$6D/$02/ {mov es:[di+2],bp }π $E8/$00/$00/ {call null }π {null: }π $58/ {pop ax }π $05/$0C/$00/ {add ax,12 }π $26/$89/$45/$04/ {mov es:[di+4],ax }π $26/$8C/$4D/$06); {mov es:[di+6],cs }π {next: }ππProcedure LongJump ( Var JumpDest : JumpRecord );π{Restore everything and jump}πinline(π $5F/ {pop di }π $07/ {pop es }π $26/$8B/$25/ {mov sp,es:[di] }π $26/$8B/$6D/$02/ {mov bp,es:[di+2] }π $26/$FF/$6D/$04); {jmp far es:[di+4]}ππImplementationπEnd.πππ------------------------------try.pas------------------------------ππProgram Try;πUses Jump; {Uses Jump,WinCrt;}πVarπ OldExit : Pointer;π MyAddr : JumpRecord;π MyHeap : Pointer;ππ a1,a2,π a3,a4 : real;πππ{$F+}πProcedure MyExit;π{You can add your error handler here}πBeginπ If ErrorAddr<>Nil Then Beginπ case ExitCode ofπ 106 : Writeln('Invalid numeric format');π 200 : Writeln('Division by zero');π 205 : Writeln('Floating point overflow');π 206 : Writeln('Floating point underflow');π 207 : Writeln('Invalid floating point operation');π else Writeln('Hmmm... How did you do that ?');π end;π ErrorAddr:=Nil;π LongJump(MyAddr);π end;π ExitProc:=OldExit;πEnd;π{$F-}ππBeginπ OldExit:=ExitProc;π Mark(MyHeap); {Just an example of how to restore the heap }π {Actually we don't have to do that in }π {this program, because we dont use heap }π {at all. But anyway here it goes }π {Don't forget to remove when compiling this }π {for Windows }πππ SetJump(MyAddr); {We'll get back here whenever a run time }π {error occurs }π {This line should always be before }π { ExitProc:=MyExit; }π {Don't ask me why... It's much easier for me}π {to follow the rule then to understand it :)}π ExitProc:=@MyExit;ππ Release(MyHeap); {restoring the heap after a run time error }π {Remove this if you are compiling it for }π {Windows }ππ {Try entering whatever you want at the }π {prompt. It should trap every runtime error}π {you could possibly get. }π Repeatπ Writeln;π Write('Enter a number a1=');π Readln(a1);π Write('Enter a number a2=');π Readln(a2);π a3:=a1/a2;π Writeln('a1/a2=',a3:10:5);π a4:=ln(a3);π Writeln('ln(a1/a2)=',a4:10:5);π until a3=1;πend.π 61 11-21-9309:41ALL SWAG SUPPORT TEAM MAXMIN Bytes/Integers SWAG9311 22 èo {$R-}πUNIT MaxMin;π(**) INTERFACE (**)π FUNCTION MaxS(A, B : ShortInt) : ShortInt;π FUNCTION MinS(A, B : ShortInt) : ShortInt;π FUNCTION MaxB(A, B : Byte) : Byte;π FUNCTION MinB(A, B : Byte) : Byte;π FUNCTION MaxI(A, B : Integer) : Integer;π FUNCTION MinI(A, B : Integer) : Integer;π FUNCTION MaxW(A, B : Word) : Word;π FUNCTION MinW(A, B : Word) : Word;π FUNCTION MaxL(A, B : LongInt) : LongInt;π FUNCTION MinL(A, B : LongInt) : LongInt;π FUNCTION MaxU(A, B : LongInt) : LongInt;π FUNCTION MinU(A, B : LongInt) : LongInt;ππ(**) IMPLEMENTATION (**)π FUNCTION MaxS(A, B : ShortInt) : ShortInt; Assembler;π ASMπ MOV AL, Aπ CMP AL, Bπ JGE @noπ MOV AL, Bπ @no:π END;ππ FUNCTION MinS(A, B : ShortInt) : ShortInt; Assembler;π ASMπ MOV AL, Aπ CMP AL, Bπ JLE @noπ MOV AL, Bπ @no:π END;ππ FUNCTION MaxB(A, B : Byte) : Byte; Assembler;π ASMπ MOV AL, Aπ CMP AL, Bπ JAE @noπ MOV AL, Bπ @no:π END;ππ FUNCTION MinB(A, B : Byte) : Byte; Assembler;π ASMπ MOV AL, Aπ CMP AL, Bπ JBE @noπ MOV AL, Bπ @no:π END;ππ FUNCTION MaxI(A, B : Integer) : Integer; Assembler;π ASMπ MOV AX, Aπ CMP AX, Bπ JGE @noπ MOV AX, Bπ @no:π END;ππ FUNCTION MinI(A, B : Integer) : Integer; Assembler;π ASMπ MOV AX, Aπ CMP AX, Bπ JLE @noπ MOV AX, Bπ @no:π END;ππ FUNCTION MaxW(A, B : Word) : Word; Assembler;π ASMπ MOV AX, Aπ CMP AX, Bπ JAE @noπ MOV AX, Bπ @no:π END;ππ FUNCTION MinW(A, B : Word) : Word; Assembler;π ASMπ MOV AX, Aπ CMP AX, Bπ JBE @noπ MOV AX, Bπ @no:π END;ππ FUNCTION MaxL(A, B : LongInt) : LongInt; Assembler;π ASMπ MOV DX, Word(A+2)π MOV AX, Word(A)π CMP DX, Word(B+2)π JL @yesπ JG @noπ CMP AX, Word(B)π JGE @noπ @yes:π MOV DX, Word(B+2)π MOV AX, Word(B)π @no:π END;ππ FUNCTION MinL(A, B : LongInt) : LongInt; Assembler;π ASMπ MOV DX, Word(A+2)π MOV AX, Word(A)π CMP DX, Word(B+2)π JG @yesπ JL @noπ CMP AX, Word(B)π JLE @noπ @yes:π MOV DX, Word(B+2)π MOV AX, Word(B)π @no:π END;ππ FUNCTION MaxU(A, B : LongInt) : LongInt; Assembler;π ASMπ MOV DX, Word(A+2)π MOV AX, Word(A)π CMP DX, Word(B+2)π JB @yesπ JA @noπ CMP AX, Word(B)π JAE @noπ @yes:π MOV DX, Word(B+2)π MOV AX, Word(B)π @no:π END;ππ FUNCTION MinU(A, B : LongInt) : LongInt; Assembler;π ASMπ MOV DX, Word(A+2)π MOV AX, Word(A)π CMP DX, Word(B+2)π JA @yesπ JB @noπ CMP AX, Word(B)π JBE @noπ @yes:π MOV DX, Word(B+2)π MOV AX, Word(B)π @no:π END;πEND. 62 11-02-9318:41ALL VARIOUS AUTHORS ROMAN numbers SWAG9311 46 èo }πFrom: BRIAN PAPEπSubj: YEAR ( ROMAN )πThis is from last semester's computer bowl. Only problem is that itπconverts from Roman to Arabic. :)ππ LCCC Programming Teamππ East Central College Computer Bowlππ 03-21-93ππ "Computer Killers"π Brian Papeπ Brian Grammerπ Mike Lazarπ Christy Reedπ Matt Hayesπ Coach Steve Banjavcicππ Program #2-3π Time to Completion: 3:47π}ππprogram roman;πUSES PRINTER;πconstπ num = 'IVXLCDM';π value : array[1..7] of integer = (1,5,10,50,100,500,1000);πvarπ i : byte;π s : string;π sum : integer;πbeginπ assign(lst,'');rewrite(lst);π writeln('Enter the Roman Numerals: ');π readln(s);π i := length(s);π while (i>=1) doπ beginπ if i > 1 thenπ beginπ if pos(s[i],num) <= (pos(s[i-1],num)) thenπ beginπ sum := sum + value[pos(s[i],num)];π dec(i);π endπ elseπ beginπ sum := sum + value[pos(s[i],num)] - value[pos(s[i-1],num)];π dec(i,2);π end; { else }π endπ elseπ beginπ sum := sum + value[pos(s[1],num)];π dec(i);π end; { else }π end; { while }π WRITELN(LST);π writeln(LST,'Roman numeral: ',s);π writeln(LST,'Arabic value: ',sum);πend. { }ππ{*π *π * ROMAN.C - Converts integers to Roman numeralsπ *π * Written by: Jim Walshπ *π * Compiler : Microsoft QuickC v2.5π *π * This Program Is Released To The Public Domainπ *π * Additional Comments:π *π * Ported to TP v6.0 by Daniel Prosser.π *}ππVARπ Value, DValue, Error : INTEGER;π Roman : STRING[80];ππBEGINπ Roman := '';ππ IF ParamCount = 2 THENπ VAL(ParamStr(1), Value, Error)π ELSEπ BEGINπ Write ('Enter an integer value: ');π ReadLn (Value);π END; { ELSE }ππ DValue := Value;ππ WHILE Value >= 1000 DOπ BEGINπ Roman := Roman + 'M';π Value := Value - 1000;π END; { WHILE }ππ IF Value >= 900 THENπ BEGINπ Roman := Roman + 'CM';π Value := Value - 900;π END; { IF }ππ WHILE Value >= 500 DOπ BEGINπ Roman := Roman + 'D';π Value := Value - 500;π END; { WHILE }ππ IF Value >= 400 THENπ BEGINπ Roman := Roman + 'CD';π Value := Value - 400;π END; { IF }ππ WHILE Value >= 100 DOπ BEGINπ Roman := Roman + 'C';π Value := Value - 100;π END; { WHILE }ππ IF Value >= 90 THENπ BEGINπ Roman := Roman + 'XC';π Value := Value - 90;π END; { IF }ππ WHILE Value >= 50 DOπ BEGINπ Roman := Roman + 'L';π Value := Value - 50;π END; { WHILE }ππ IF Value >= 40 THENπ BEGINπ Roman := Roman + 'XL';π Value := Value - 40;π END; { WHILE }ππ WHILE Value >= 10 DOπ BEGINπ Roman := Roman + 'X';π Value := Value - 10;π END; { WHILE }ππ IF Value >= 9 THENπ BEGINπ Roman := Roman + 'IX';π Value := Value - 9;π END; { IF }ππ WHILE Value >= 5 DOπ BEGINπ Roman := Roman + 'V';π Value := Value - 5;π END; { WHILE }ππ IF Value >= 4 THENπ BEGINπ Roman := Roman + 'IV';π Value := Value - 4;π END; { IF }πππ WHILE Value > 0 DOπ BEGINπ Roman := Roman + 'I';π DEC (Value);π END; { WHILE }ππ WriteLn (DValue,' = ', Roman);πEND.ππ{--------------------- Begin of function -----------------------------}πππFunction Roman (Number: Integer): String;π{ Converts Number to the Roman format.π If (Number < 1) Or (Number > 3999), the returned string will be empty!π}πVarπ TempStr : String; { Temporary storage for the result string }πBeginπ TempStr := '';π If (Number > 0) And (Number < 4000) Thenπ Beginπ { One 'M' for every 1000 }π TempStr := Copy ('MMM', 1, Number Div 1000);π Number := Number MOD 1000;π If Number >= 900 Thenπ { Number >= 900, so append 'CM' }π Beginπ TempStr := TempStr + 'CM';π Number := Number - 900;π Endπ Elseπ { Number < 900 }π Beginπ If Number >= 500 Thenπ { Number >= 500, so append 'D' }π Beginπ TempStr := TempStr + 'D';π Number := Number - 500;π Endπ Elseπ If Number >= 400 Thenπ { 400 <= Number < 500, so append 'CD' }π Beginπ TempStr := TempStr + 'CD';π Number := Number - 400;π End;π { Now Number < 400!!! One 'C' for every 100 }π TempStr := TempStr + Copy ('CCC', 1, Number Div 100);π Number := Number Mod 100;π End;π If Number >= 90 Thenπ { Number >= 90, so append 'XC' }π Beginπ TempStr := TempStr + 'XC';π Number := Number - 90;π Endπ Elseπ { Number < 90 }π Beginπ If Number >= 50 Thenπ { Number >= 50, so append 'L'}π Beginπ TempStr := TempStr + 'L';π Number := Number - 50;π Endπ Elseπ If Number >= 40 Thenπ { 40 <= Number < 50, so append 'XL' }π Beginπ TempStr := TempStr + 'XL';π Number := Number - 40;π End;π { Now Number < 40!!! One 'X' for every 10 }π TempStr := TempStr + Copy ('XXX', 1, Number Div 10);π Number := Number Mod 10;π End;π If Number = 9 Thenπ { Number = 9, so append 'IX' }π Beginπ TempStr := TempStr + 'IX';π Endπ Elseπ { Number < 9 }π Beginπ If Number >= 5 Thenπ { Number >= 5, so append 'V' }π Beginπ TempStr := TempStr + 'V';π Number := Number - 5;π Endπ Elseπ If Number = 4 Thenπ { Number = 4, so append 'IV' }π Beginπ TempStr := TempStr + 'IV';π Number := Number - 4;π End;π { Now Number < 4!!! One 'I' for every 1 }π TempStr := TempStr + Copy ('III', 1, Number);π End;π End;π Roman := TempStr;πEnd;ππ 63 11-02-9305:39ALL WILBERT VAN LEIJEN Export data from OBJ fileSWAG9311 11 èo {πWILBERT VAN LEIJENππ> I want to pass its address to an external .obj procedure so I can setπ> DS:SI to it... how do I do this? I know how to do this sort of think if Iπ> use the tp60 built in asmm thingy, and I know that I can pass values usingπ> arg likeππYou cannot export data from an .OBJ file to a Pascal program. The linkerπcannot handle with public identifiers other than in a segment of class CODE,πalas.ππStore the data in a File of Byte (DORK.BIN), convert it with BINOBJ to DORK.OBJπ(suggested identifier: Procedure DorkData), link it to your program.π}ππProcedure DorkData; External;π{$L DORK.OBJ }ππTypeπ TDork = Array[0..255] of Byte;π PDork = ^TDork;ππVarπ Dork : PDork;π i : Integer;ππBeginπ Dork := @DorkData;π For i := Low(TDork) to High(TDork) Doπ Write(Dork^[i] : 4);πend.ππ{ If you want to use assembler to access DorkData: }ππASMπ CLDπ PUSH DSπ PUSH CS { Using "LDS SI, DorkData" will not work! }π POP DSπ LEA SI, DorkData { DS:SI points to DorkData }π MOV CX, Type(TDork) { = 256 }π @1: LODSB { TDork(DorkData[256-CX]) is now in AL }π { other code }π LOOP @1π POP DSπend;π 64 01-27-9411:53ALL HELGE HELGESEN ASM Calls and Jumps SWAG9402 8 èo {π> If I make a Assembly routine in a Turbo Pascal program,π> how can I make far jumps, calls, etc?ππHere's two procedures:π}ππprocedure CallFar(Where : pointer); assembler;πasmπ call Whereπend;ππprocedure JmpFar(Where : pointer); inline($cb);ππ{π> How can I make labels?πYou can make local labels.π}ππasmπ jcxz @1π shl ax, clπ @1:π add cx, bxπ ...πend;π{πBut with assembly in Pascal you can also make local variables;π}ππprocedure Test; assembler;πvarπ MyLocalVar : word; { a variable }πasmπ mov MyLocalVar, 0 { clear contents }πend;ππ{π> how to discover the offset of a certain instruction?ππTo discover the offset for a variable, you might use LEAπ(Load Effective Address).π}π LEA bx, MyLocalVar { for the above example }π{πWill NOT return the contents of MyLocalVar, but the offsetπwithin the stack segment to MyLocalVar.π} 65 01-27-9411:56ALL ANDRES CVITKOVICH BP Bug SWAG9402 18 èo {πI'm not sure if the following bug in Contains() of STDDLG.PAS has been fixedπin 7.01 (since I still don't have it) so I decided to post it.ππSTDDLG.PAS, function Contains()π}π{ Contains returns true if S1 contains any characters in S2 }πfunction Contains(S1, S2 : String): Boolean; near; assembler;πasmπ PUSH DSπ CLDπ LDS SI, S1π LES DI, S2π MOV DX, DIπ> INC DX { DX still pointed at len byte }π XOR AH, AHπ LODSBπ MOV BX, AXπ OR BX, BXπ JZ @@2π MOV AL, ES:[DI]π XCHG AX, CXπ @@1:π PUSH CXπ MOV DI, DXπ LODSBπ REPNE SCASBπ POP CXπ JE @@3π DEC BXπ JNZ @@1π @@2:π XOR AL, ALπ JMP @@4π @@3:π MOV AL, 1π @@4:π POP DSπend;ππ{πBUT: fixing the bug reveals another bug <g>ππThe function is used to determine whether a filename or path contains illegalπcharacters or not. The last character in the constant "IllegalChars" is theπbackslash "\" that would have been ignored by the buggy version of Contains().πHowever, the corrected version returns TRUE for Contains('\MYPATH\',πIllegalChars) (as it's supposed to). Since a path name created by FSplitπnormally contains a "\" the filename is considered as FALSE by ValidFileName.πMy solution is to add a second const named IllegalCharsFN for illegal chars inπthe filename (but legal chars in path names) currently just containing '\'.πFurthermore, I removed space ' ' from the list of illegal characters (since itπisn't an illegal char!) and added '/' instead. But have a look at my finalπcorrection suggestion:π}ππfunction ValidFileName(var FileName : PathStr) : Boolean;πconstπ IllegalCharsFN = '\';π IllegalChars = ';,=+<>|"[]/';πvarπ Dir : DirStr;π Name : NameStr;π Ext : ExtStr;ππ { Contains returns true if S1 contains any characters in S2 }π function Contains(S1, S2 : String) : Boolean; near; assembler;π asmπ {...see above...}π end;ππbeginπ ValidFileName := True;π FSplit(FileName, Dir, Name, Ext);π if not ((Dir = '') or PathValid(Dir)) orπ Contains(Name, IllegalChars + IllegalCharsFN) orπ Contains(Dir, IllegalChars) thenπ ValidFileName := False;πend;π 66 01-27-9411:57ALL BILL HIMMELSTOSS dBase Manipulation SWAG9402 65 èo {π{ If this code is used commercially, please send a few bucks to }π{ Bill Himmelstoss, PO BOX 23246, Jacksonville, FL 32241-3246, }π{ Otherwise, it's freely distributable. }ππunit DBF;ππinterfaceππusesπ Objects,π OString;ππtypeπ TYMDDate = recordπ Year,π Month,π Day: Byte;π end;ππ PDatabase = ^TDatabase;π TDatabase = object(TObject)π DatabaseType: Byte;π LastUpdate: TYMDDate;π NumRecords: Longint;π FirstRecordPos: Word;π RecordLength: Word;ππ S: TDosStream;π Pathname: TOString;π Modified: Boolean;π Fields: TCollection;ππ constructor Init(APathname: TOString);π constructor InitCreate(APathname: TOString; AFields: PCollection);π destructor Done; virtual;π procedure RefreshHeader;π procedure UpdateHeader;π function GetRecord(RecordNum: Longint): Pointer;π procedure PutRecord(RecordNum: Longint; Rec: Pointer);π procedure Append(Rec: Pointer);π procedure Zap;π procedure RefreshFields;π end;ππ PFieldDef = ^TFieldDef;π TFieldDef = object(TObject)π Name: TOString;π DataType: Char;π Displacement: Longint;π Length: Byte;π Decimal: Byte;ππ constructor Init(π AName: String;π ADataType: Char;π ALength,π ADecimal: Byte);π destructor Done; virtual;π constructor Load(var S: TStream);π procedure Store(var S: TStream);π end;ππimplementationππusesπ WinDos;ππconstructor TDatabase.Init(APathname: TOString); beginπ inherited Init;π Pathname.InitText(APathname);π S.Init(Pathname.CString, stOpen);π if S.Status <> stOk then Fail;π Fields.Init(5, 5);π RefreshHeader;πend;ππconstructor TDatabase.InitCreate(APathname: TOString; AFields: PCollection);πconstπ Terminator: Byte = $0D;πvarπ Year, Month, Day, Dummy: Word;ππ procedure CopyField(Item: PFieldDef); far;π beginπ Fields.Insert(Item);π end;ππ procedure WriteFieldSubrecord(Item: PFieldDef); far;π beginπ Item^.Store(S);π Inc(RecordLength, Item^.Length);π end;ππbeginπ inherited Init;ππ DatabaseType := $03;π GetDate(Year, Month, Day, Dummy);π LastUpdate.Year := Year - 1900;π LastUpdate.Month := Month;π LastUpdate.Day := Day;π NumRecords := 0;π RecordLength := 0;ππ Pathname.InitText(APathname);π S.Init(Pathname.CString, stCreate);π if S.Status <> stOk then Fail;π UpdateHeader;ππ S.Seek(32); { beginning of field subrecords }π Fields.Init(AFields^.Count, 5);π AFields^.ForEach(@CopyField);π Fields.ForEach(@WriteFieldSubrecord);ππ S.Write(Terminator, SizeOf(Terminator));π Modified := true;π FirstRecordPos := S.GetPos;π UpdateHeader;πend;ππdestructor TDatabase.Done;πbeginπ if Modified then UpdateHeader;π Pathname.Done;π S.Done;π Fields.Done;π inherited Done;πend;ππprocedure TDatabase.RefreshHeader;πvarπ OldPos: Longint;πbeginπ OldPos := S.GetPos;π S.Seek(0);π S.Read(DatabaseType, SizeOf(DatabaseType));π S.Read(LastUpdate, SizeOf(LastUpdate));π S.Read(NumRecords, SizeOf(NumRecords));π S.Read(FirstRecordPos, SizeOf(FirstRecordPos));π S.Read(RecordLength, SizeOf(RecordLength));π S.Seek(OldPos);π RefreshFields;πend;ππprocedure TDatabase.UpdateHeader;πvarπ OldPos: Longint;π Reserved: array[12..31] of Char;πbeginπ OldPos := S.GetPos;π S.Seek(0);π S.Write(DatabaseType, SizeOf(DatabaseType));π S.Write(LastUpdate, SizeOf(LastUpdate));π S.Write(NumRecords, SizeOf(NumRecords));π S.Write(FirstRecordPos, SizeOf(FirstRecordPos));π S.Write(RecordLength, SizeOf(RecordLength));π FillChar(Reserved, SizeOf(Reserved), #0);π S.Write(Reserved, SizeOf(Reserved));π S.Seek(OldPos);πend;ππfunction TDatabase.GetRecord(RecordNum: Longint): Pointer; varπ Temp: Pointer;π Pos: Longint;πbeginπ Temp := NIL;π GetMem(Temp, RecordLength);π if Temp <> NIL thenπ beginπ Pos := FirstRecordPos + ((RecordNum - 1) * RecordLength);π if S.GetPos <> Pos thenπ S.Seek(Pos);π S.Read(Temp^, RecordLength);π end;π GetRecord := Temp;πend;ππprocedure TDatabase.Append(Rec: Pointer); beginπ if Assigned(Rec) thenπ beginπ Modified := true;π Inc(NumRecords);π PutRecord(NumRecords, Rec);π end;πend;ππprocedure TDatabase.PutRecord(RecordNum: Longint; Rec: Pointer); varπ Pos: Longint;πbeginπ if Assigned(Rec) and (RecordNum <= NumRecords) thenπ beginπ Pos := FirstRecordPos + ((RecordNum - 1) * RecordLength);π if S.GetPos <> Pos thenπ S.Seek(Pos);π S.Write(Rec^, RecordLength);π end;πend;ππprocedure TDatabase.Zap;πvarπ T: TDosStream;π Temp, D, N, E: TOString;π F: File;πbeginπ D.Init(fsDirectory);π N.Init(fsFilename);π E.Init(fsExtension);π FileSplit(Pathname.CString, D.CString, N.CString, E.CString);π D.RecalcLength;π N.RecalcLength;π E.RecalcLength;π Temp.InitText(D);π Temp.Append(N);π Temp.AppendP('.TMP');π D.Done;π N.Done;π E.Done;ππ T.Init(Temp.CString, stCreate);π S.Seek(0);π T.CopyFrom(S, FirstRecordPos - 1);π T.Done;π S.Done;π Assign(F, Pathname.CString);π Erase(F);π Assign(F, Temp.CString);π Rename(F, Pathname.CString);π S.Init(Pathname.CString, stOpen);π NumRecords := 0;π Modified := false;π UpdateHeader;πend;ππprocedure TDatabase.RefreshFields;πvarπ Terminator: Byte;π HoldPos: Longint;π FieldDef: PFieldDef;πbeginπ S.Seek(32); { beginning of Field subrecords }ππ repeatπ HoldPos := S.GetPos;π S.Read(Terminator, SizeOf(Terminator));π if Terminator <> $0D thenπ beginπ S.Seek(HoldPos);π FieldDef := New(PFieldDef, Load(S));π Fields.Insert(FieldDef);π end;π until Terminator = $0D;πend;ππconstructor TFieldDef.Init(π AName: String;π ADataType: Char;π ALength,π ADecimal: Byte);πbeginπ inherited Init;π Name.InitTextP(AName);π DataType := ADataType;π Length := ALength;π Decimal := ADecimal;π Displacement := 0;πend;ππdestructor TFieldDef.Done;πbeginπ Name.Done;π inherited Done;πend;ππconstructor TFieldDef.Load(var S: TStream); varπ AName: array[1..11] of Char;π Reserved: array[18..31] of Char;πbeginπ S.Read(AName, SizeOf(AName));π Name.Init(SizeOf(AName));π Name.SetText_(@AName[1], 11);π S.Read(DataType, SizeOf(DataType));π S.Read(Displacement, Sizeof(Displacement));π S.Read(Length, SizeOf(Length));π S.Read(Decimal, SizeOf(Decimal));π S.Read(Reserved, SizeOf(Reserved));πend;ππprocedure TFieldDef.Store(var S: TStream); varπ Reserved: array[18..31] of Char;πbeginπ S.Write(Name.CString^, 11);π S.Write(DataType, SizeOf(DataType));π S.Write(Displacement, Sizeof(Displacement));π S.Write(Length, SizeOf(Length));π S.Write(Decimal, SizeOf(Decimal));π FillChar(Reserved, SizeOf(Reserved), #0);π S.Write(Reserved, SizeOf(Reserved));πend;ππend.ππππππprogram DbfTest;ππusesπ dbf, wincrt, ostring, objects, strings;ππtypeπ PDbfTest = ^TDbfTest;π TDbfTest = recordπ Deleted: Char; { ' '=no, '*'=yes }π AcctNo: array[1..16] of Char;π Chunk: array[1..8] of Char;π Baskard: array[1..5] of Char;π Extra: array[1..8] of Char;π Sandwich: array[1..25] of Char;π end;ππvarπ rec: PDbfTest;π database: tdatabase;π pathname: tostring;π temp: string;π fields: tcollection;ππ procedure DoShow;ππ procedure show(item: pfielddef); far;π beginπ writeln(π item^.name.cstring:15, ' ',π item^.datatype, ' ',π item^.length:10, ' ',π item^.decimal:10, ' ');π end;ππ beginπ database.fields.foreach(@show);π end;πππbeginπ InitWinCrt;ππ fields.init(5, 0);π fields.insert(new(pfielddef, init('ACCTNO', 'C', 16, 0)));π fields.insert(new(pfielddef, init('CHUNK', 'N', 8, 2)));π fields.insert(new(pfielddef, init('BASKARD', 'C', 5, 0)));π fields.insert(new(pfielddef, init('EXTRA', 'D', 8, 0)));π fields.insert(new(pfielddef, init('SANDWICH', 'C', 25, 0)));π pathname.inittextp('c:\dbftest.dbf');π database.initcreate(pathname, @fields);π pathname.done;π DoShow;ππ New(Rec);π with Rec^ doπ beginπ Acctno := '1313558000001005'; { <-will self-check, but not valid }π Chunk := ' 10.00';π Baskard := 'ABCDE';π Extra := '19931125';π Sandwich := 'Turkey Leftovers ';π end;π database.append(rec);π dispose(rec);ππ rec := database.getrecord(1);π writeln(rec^.acctno, ' ', rec^.Sandwich);π dispose(rec);ππ database.done;πend.π 67 01-27-9411:59ALL HERB BROWN Hexagonal Grid Info SWAG9402 50 èo {πI have a game I would like to make a PD project. It's a war game, based onπolder style equipment, i.e., no nukes and such. I haven't worked on it inπseveral years, though. I would like to make it multi node, or multi playerπsomehow. I think it would make a perfect object of discussion. It's writtenπin Pascal and was originally started in 4.0. It needs to be re-written intoπobjects and the code updated througout. (My programming habits have changedπsignifically, I may make less errors now, but, when I do, they are reallyπstupid.)ππCoordinating movements will be a challenge in a multi node system.ππthe logic would need to be changed, i.e., the movement directions, toπaccomodate ASCII characters that would represent the playing peices..ππHere is code for a grid system I wrote...π}ππProgram FillGrid;ππ{ example of filling a hex sided grid with data about itself and it'sπ neighbors.ππ Written By: Herbert Brown and released to the public domain (1993)π please give credit were credit is due.. }ππusesπ dos,π crt; { only for debugging }ππconstπ MaxRows = 7;π MaxColumns = 5;π MaxHex = 32; { only used for array and testing }ππtypeπ grid = recordπ id, nw, ne,π w, e, se, sw,π TerrainRec : Longint; { can be used as a reference to a database}π end;ππvarπ GridVar : Array [1..MaxHex] of grid;π gridCounter : Longint;π RowCounter,π ColCounter,π EndColumn : Longint;π OddRow,π finished : Boolean;π CurrentGrid : grid;π x : integer;πππprocedure getit(ColCounter, RowCounter, GridCounter, MaxColumns,π MaxRows : Longint; Var CurrentGrid : grid);ππbeginπ CurrentGrid.id := gridcounter;ππ { The 9 possible cases tested Middle tested first for speed because thereπ are more of these in large maps }ππ {middle}π if ((colcounter > 1) and (colcounter < EndColumn)) thenπ if (rowcounter <> 1) and (rowcounter <> maxrows) thenπ beginπ CurrentGrid.nw := (gridcounter-MaxColumns);π CurrentGrid.w := (gridcounter-1);π CurrentGrid.sw := (gridcounter+MaxColumns)-1;π CurrentGrid.se := gridcounter+maxColumns;π CurrentGrid.e := gridcounter+1;π CurrentGrid.ne := (gridcounter-MaxColumns)+1;π exit;π end;ππ {leftedge}π if (colcounter = 1) and (rowcounter <> 1) thenπ if (rowcounter <> maxrows) thenπ beginπ if oddrow thenπ CurrentGrid.nw := (gridcounter-MaxColumns)π elseπ CurrentGrid.nw := 0; { }π CurrentGrid.w := 0;π if oddrow thenπ CurrentGrid.sw := (gridcounter+MaxColumns)-1π elseπ CurrentGrid.sw := 0;π CurrentGrid.se := gridcounter+maxColumns;π CurrentGrid.e := gridcounter+1;π CurrentGrid.ne := (gridcounter-MaxColumns)+1;π exit;π end;ππ {rightedge}π if (colcounter = EndColumn) and (rowcounter <> 1) thenπ if (rowcounter <> maxrows) thenπ beginπ CurrentGrid.nw := (gridcounter-MaxColumns);π CurrentGrid.w := (gridcounter-1);π CurrentGrid.sw := (gridcounter+MaxColumns)-1;π if oddrow thenπ CurrentGrid.se := gridcounter+maxColumnsπ elseπ CurrentGrid.se := 0;π CurrentGrid.e := 0;π if oddrow thenπ CurrentGrid.ne := (gridcounter-MaxColumns)+1π elseπ CurrentGrid.ne := 0;π exit;π end;ππ {toprow}π if (rowcounter = 1) and (colcounter <> 1) thenπ if (colcounter <> maxcolumns) thenπ beginπ CurrentGrid.nw := 0;π CurrentGrid.w := (gridcounter-1);π CurrentGrid.sw := (gridcounter+MaxColumns)-1;π CurrentGrid.se := gridcounter+maxColumns;π CurrentGrid.e := gridcounter+1;π CurrentGrid.ne := 0;π exit;π end;ππ {BottomRow}π if (rowcounter = maxrows) and (colcounter <> 1) thenπ if (colcounter <> maxcolumns) thenπ beginπ CurrentGrid.nw := (gridcounter-MaxColumns);π CurrentGrid.w := (gridcounter-1);π CurrentGrid.sw := 0;π CurrentGrid.se := 0;π CurrentGrid.e := gridcounter+1;π CurrentGrid.ne := (gridcounter-MaxColumns)+1;π exit;π end;πππ {TopLeftCorner}π if (colcounter = 1) and (rowcounter = 1) thenπ beginπ CurrentGrid.nw := 0; { Can't leave edge! }π CurrentGrid.w := 0;π CurrentGrid.sw := 0;π CurrentGrid.se := gridcounter+maxColumns;π CurrentGrid.e := gridcounter+1;π CurrentGrid.ne := 0;π exit;π end;ππ {toprightcorner}π if (rowcounter = 1) and (colcounter = maxcolumns) thenπ beginπ CurrentGrid.nw := 0;π CurrentGrid.w := (gridcounter-1);π CurrentGrid.sw := (gridcounter+MaxColumns)-1;π CurrentGrid.se := 0;π CurrentGrid.e := 0;π CurrentGrid.ne := 0;π exit;π end;ππ {bottomleftCorner}π if (colcounter = 1) and (rowcounter = maxrows) thenπ beginπ CurrentGrid.nw := 0;π CurrentGrid.w := 0;π CurrentGrid.sw := 0;π CurrentGrid.se := 0;π CurrentGrid.e := gridcounter+1;π CurrentGrid.ne := (gridcounter-MaxColumns)+1;π exit;π end;ππ {BottomRightCorner}π if (colcounter = maxcolumns) and (rowcounter = maxrows) thenπ beginπ CurrentGrid.nw := (gridcounter-MaxColumns);π CurrentGrid.w := (gridcounter-1);π CurrentGrid.sw := 0;π CurrentGrid.se := 0;π CurrentGrid.e := 0;π CurrentGrid.ne := 0;π exit;π end;ππend;ππbeginπ clrscr;π { fill the record array out for debugging or "watch" purposesπ this loop was only used for debugging }π for x := 1 to MaxHex doπ beginπ GridVar[x].id := 0;π gridvar[x].nw := 0;π gridvar[x].ne := 0;π gridvar[x].w := 0;π gridvar[x].e := 0;π gridvar[x].se := 0;π gridvar[x].sw := 0;π gridVar[x].TerrainRec:=0;π end;ππ fillchar(CurrentGrid,sizeof(currentgrid),0);π GridCounter := 1;π RowCounter:=1;π ColCounter:=1;π Oddrow:=False;π Finished := False;π EndColumn := MaxColumns;ππ while not finished doπ begin { while }π getit(ColCounter,RowCounter,GridCounter,MaxColumns,MaxRows,CurrentGrid);π gridvar[gridcounter]:=CurrentGrid; { <- can be stored to a vitual array orπ data base file here }π Inc(ColCounter); { next grid id }π Inc(gridCounter);π if colcounter = EndColumn+1 thenπ beginπ Oddrow := not oddrow;π ColCounter:=1;π if rowcounter = MaxRows thenπ finished := True;π inc(rowcounter); { next row }π if not oddrow thenπ EndColumn := MaxColumnsπ elseπ EndColumn := MaxColumns - 1;π end;π end;πend.π 68 01-27-9412:02ALL GREG VIGNEAULT EXE to binary Converter SWAG9402 48 èo {π> Run this program, it will create ULONGS.ZIP, which contains theπ> ULONGS.OBJ file needed for the LongXXX functions...π> That's too cool! How'd you do that? You got a program to doπ> that with?ππ Yes, it's a little utility that I wrote, named GBUG...ππ It can transform a binary file into one of three ASCII files:π 1) a script that is fed to DEBUG.COM (this is the default mode)π 2) a Turbo Pascal source code file (using the /P option)π 3) a GW-BASIC source code file (using the /B option)ππ The output file (.SCR, .PAS, or .BAS) can then be posted onto text-π based mediums, such as BBS conferences. Receivers can recover theπ binary file without any special decoding utilities.ππ Since GBUG doesn't embed any error-detection code, it's best toπ _always_ compress the original binary -- so that transportationπ errors can be detected during the file decompression stage.ππ Here's GBUG15B.LZH, which contains GBUG version 1.5b ...ππ(**********************************************************************)π}πPROGRAM A; VAR G:File; CONST V:ARRAY [ 1..1326 ] OF BYTE =(π33,109,45,108,104,53,45,10,5,0,0,226,5,0,0,100,18,82,26,32,1,8,71,66,π85,71,46,67,79,77,20,118,77,0,0,4,211,107,163,22,54,148,47,236,176,138,π139,32,197,189,172,76,77,133,38,141,28,57,194,120,25,2,68,75,109,198,π186,228,53,214,109,193,10,2,28,77,52,95,2,195,192,50,15,129,44,51,180,π218,203,178,10,169,45,234,6,28,90,117,182,234,84,128,83,173,215,96,217,π187,247,36,49,174,237,157,117,70,98,230,147,253,251,111,42,69,192,48,π155,127,169,135,192,222,194,198,211,108,80,245,3,16,102,204,61,183,213,π54,96,166,204,193,155,51,172,78,1,134,123,200,39,157,207,9,217,33,140,π113,225,131,38,253,173,179,124,144,190,120,238,36,80,198,146,113,231,π157,8,61,32,202,143,28,93,48,188,191,11,216,81,96,7,43,8,128,61,124,144,π189,129,6,245,216,78,114,229,173,229,190,20,28,76,113,99,145,33,237,249,π142,26,154,220,157,226,53,228,183,121,119,133,27,175,215,201,155,48,47,π109,174,27,113,240,116,213,70,196,148,70,167,214,215,14,73,212,156,96,π59,126,31,174,13,211,171,201,81,251,151,95,108,113,60,135,1,216,113,133,π140,27,247,135,133,230,4,88,120,17,66,116,64,254,114,131,37,52,48,67,π148,25,65,138,240,34,146,124,3,159,134,55,100,80,207,189,119,20,140,24,π143,185,167,246,112,163,29,125,133,141,218,230,227,97,198,236,144,244,π50,93,192,232,197,36,184,250,249,228,72,4,100,147,18,20,72,176,57,225,π199,76,200,41,153,133,245,199,43,144,225,173,231,24,208,202,200,200,205,π196,39,137,97,130,225,189,224,99,18,92,111,114,234,216,217,179,38,119,π112,28,220,222,55,146,24,47,112,32,135,165,139,202,251,49,110,186,97,π66,236,148,202,222,231,233,111,151,252,38,196,74,52,39,231,69,56,34,78,π84,199,16,120,215,46,66,43,102,182,237,220,145,64,145,136,248,247,189,π209,61,58,36,49,10,25,209,5,255,252,141,241,60,64,126,25,130,238,249,π59,147,255,39,216,183,216,54,2,232,50,84,171,87,89,79,177,189,189,234,π212,245,129,168,85,24,202,115,50,247,163,165,175,224,19,207,82,21,73,π108,210,176,155,49,110,232,53,213,131,150,174,185,104,250,22,185,107,π198,253,214,121,57,110,155,172,170,75,110,63,10,104,94,186,206,99,188,π26,125,166,38,242,195,118,57,201,111,6,199,118,63,108,158,132,35,52,54,π227,151,235,75,217,211,210,158,118,122,183,84,201,145,218,229,208,71,π49,215,242,194,114,57,58,254,95,136,205,142,30,188,73,45,25,154,218,218,π8,210,172,51,92,46,242,209,244,80,153,253,181,197,89,169,167,173,90,57,π41,46,27,153,181,181,131,164,35,42,196,201,42,101,171,81,76,204,98,81,π60,205,6,67,76,72,197,107,9,11,146,51,51,106,9,10,180,35,218,104,22,56,π157,99,240,99,84,72,234,117,127,24,93,47,3,132,106,107,183,35,232,168,π195,177,187,27,41,226,102,136,154,116,42,36,88,233,13,150,103,151,165,π128,179,42,36,33,57,198,117,157,168,151,76,86,233,14,22,181,137,99,33,π49,119,99,6,225,81,122,67,5,106,166,67,21,158,252,107,242,168,9,194,70,π85,180,203,168,145,169,213,176,102,60,245,102,165,104,173,165,237,68,π134,27,145,212,72,81,176,92,132,211,75,64,60,186,116,49,93,120,215,33,π114,225,36,57,60,193,226,6,185,120,215,87,80,69,71,186,103,188,185,8,π238,167,18,53,64,60,205,99,188,213,127,12,254,117,19,11,1,101,3,41,83,π29,248,218,59,7,113,85,159,12,75,216,217,12,202,181,228,167,190,254,126,π200,218,251,10,217,236,217,165,58,175,133,235,250,118,155,51,61,15,82,π117,94,238,126,209,69,167,179,180,243,128,146,163,52,44,135,19,104,161,π244,38,156,208,122,84,140,89,140,130,6,104,111,199,47,102,211,244,6,170,π146,137,5,159,16,69,240,198,102,213,114,196,35,155,156,73,162,153,228,π248,235,56,61,165,227,179,249,6,156,241,59,204,158,170,78,192,218,31,π29,85,5,30,106,242,92,166,83,133,75,95,193,215,172,225,107,163,236,50,π255,81,118,184,48,17,180,169,65,23,89,205,16,7,22,145,139,33,214,175,π26,15,205,237,161,12,223,192,30,209,69,237,209,2,210,139,226,8,31,1,69,π239,145,7,204,83,11,33,131,88,81,117,104,131,231,40,28,234,64,48,42,169,π32,146,172,121,232,131,226,41,65,218,120,215,97,110,21,169,221,228,222,π120,229,40,236,82,119,151,15,77,85,20,218,72,130,42,97,84,113,176,21,π229,22,249,16,62,41,82,83,145,151,76,65,235,21,232,178,68,68,181,233,π220,204,143,218,200,102,194,84,150,216,105,229,36,55,90,36,8,38,33,44,π242,134,85,19,18,196,163,190,13,34,191,236,201,126,111,132,187,113,131,π213,83,106,69,116,42,146,172,30,34,120,144,204,107,188,10,137,153,121,π190,136,37,20,231,232,76,97,214,171,53,89,49,55,182,70,115,102,167,143,π207,22,0,210,147,44,78,132,61,55,26,197,154,92,13,29,234,116,79,48,184,π104,131,136,165,57,75,229,82,93,218,32,226,169,177,33,196,178,35,242,π80,35,70,15,190,138,238,69,21,29,242,210,68,22,234,116,230,95,8,44,212,π151,222,68,29,53,54,51,196,142,142,216,96,154,85,131,52,152,146,134,19,π36,224,169,96,200,105,228,79,238,75,158,12,133,37,242,70,9,106,104,209,π212,227,208,176,35,127,220,164,187,81,131,252,82,15,97,79,152,244,175,π27,105,237,183,0,217,97,54,241,119,239,226,70,80,162,85,198,248,26,63,π147,111,233,253,215,110,3,96,182,209,127,238,118,30,204,255,112,192,0π); BEGIN Assign(G,'GBUG15B.LZH'); Rewrite(G,SizeOf(V));π BlockWrite(G,V,1); Close(G); END {Gbug1.5b}.π 69 01-27-9412:15ALL MARTIN RICHARDSON Do Nothing! SWAG9402 16 èo {π>Well, Uh, I meant creating pascal compiled files, and basic compiledπ>files and putting them in a BAT file so that they will execute in order.ππ>Oh and, uh , how to do you compile programs in tp 7 so that they are notπ> broken (or shut off in the middle if someone pressed control break)?π>I can't stop the control break thing...ππA common question. Here is my solution:ππ{****************************************************************************π * Procedure ..... DoNothingπ * Purpose ....... A do-nothing procedure to intercept interrupts and stopπ * them from happening.π * Parameters .... Noneπ * Returns ....... Nothingπ * Notes ......... Noneπ * Author ........ Martin Richardsonπ * Date .......... February 19, 1993π ****************************************************************************}ππ{$F+}πPROCEDURE DoNothing; INTERRUPT;πBEGINπEND;π{$F-}ππ{****************************************************************************π * Procedure ..... SetBreak()π * Purpose ....... To dis-allow CTRL-BREAKING out of a program.π * Parameters .... SetOn False to turn CTRL-BREAK offπ * True to turn it back on againπ * Returns ....... Nothingπ * Notes ......... Uses the procedure DoNothing above to remap INT 1Bh to.π * Author ........ Martin Richardsonπ * Date .......... February 19, 1993π ****************************************************************************}πPROCEDURE SetBreak( SetOn: BOOLEAN );πCONST Int1BSave : Pointer = NIL;πBEGINπ IF NOT SetOn THEN BEGINπ GetIntVec($1B,Int1BSave);π SetIntVec($1B,Addr(DoNothing));π END ELSEπ IF Int1BSave <> NIL THEN SetIntVec($1B,Int1BSave);πEND;ππ{πHowever, this method will not prevent them from breaking out of the .BATπfile you described above to link the programs together with! (You willπneed a TSR to do that.)π}ππ 70 01-27-9412:16ALL PHIL NICKELL Do Nothing Again! SWAG9402 12 èo (*π│{$F+}π│PROCEDURE DoNothing; INTERRUPT;π│BEGINπ│END;π│{$F-}ππ Would you believe that the code in your DoNothing procedure can beπ improved for smaller size and better speed? (No, I'm not kidding,π please read on.) The standard preamble and postamble code generated byπ Turbo Pascal for a procedure of type Interrupt pushes a whole wad ofπ registers, sets the BP and DS registers, and then undoes it all beforeπ the IRET. Your DoNothing procedure compiles to code that looksπ something like this:ππ { preamble }π PUSH AX BX CX DX SI DI DS ES BPπ MOV BP, SPπ MOV AX, @DATAπ MOV DS, AXπ { postamble }π POP BP ES DS DI SI DX CX BX AXπ IRETππ The following procedure provides identical results and kills theπ overhead.π*)π {$f+}π PROCEDURE DoNothing; ASSEMBLER; { Coded as Int Handler }π asmπ IRET { return from interrupt }π end;π {$f-}π(*π With no parameters and no local vars Turbo Pascal generates no preambleπ code, and generates only a long return as postamble. The resultingπ compiled code from my DoNothing proc looks like this:ππ IRETπ RETππ The difference: 26 bytes and many stack memory accesses for the nullπ Interrupt procedure versus only 2 bytes in the null Assembler procedureπ with Iret. The RET never gets executed, of course.π*)π 71 01-27-9412:16ALL ALTON PRILLAMAN OP Pick Lists SWAG9402 51 èo {π>I've been trying to create a simple pick list using Object Proffesional andπ>can't seem to get it to do what I want. I'm using the expick.pas example asπ>start for creating my pick list. Everything is pretty much the same exceptπ>that I want my pick list to exit with other keys insted of the enter key.π>The manual doesn't go into detail about this.ππCheck out the docs for OpCmd. The procedure that you're wanting isπ"AddCommand". In my example below, I've set up a multiple choice listπthat "remaps" the <Enter> key to toggle (like the <SpaceBar>) and useπ<F10> to accept the choices. Here's my example:ππ{DON'T FORGET TO "USE" OpCmd}ππusesπ OpCmd; {among others}ππprocedure GetPicks;πvarπ PL :PickList;π PickDone :boolean;ππbeginπ if not PL.InitDeluxe(screenwidth shr 1-16,5,π screenwidth shr 1+15,screenheight-6,π AltMenuCS, {color set}π WinOpts, {window options}π 33, {width of pick list strings}π NumItems, {number of items}π UserStrings, {user-string proc}π PickVertical, {pick direction-type}π MultipleChoice,{single or multiple}π pkStick)then {stick at edges}π beginπ {error message}π exit;π end;π PickCommands.AddCommand(ccToggle,1,$1C0D,0); {Enter=Toggle}π PickCommands.AddCommand(ccSelect,1,$4400,0); {F10=Accept}π PickDone:=false;π repeatπ PL.Process;π case PL.GetLastCommand ofπ ccSelect: {F10}π beginπ end;ππ ccQuit:π PickDone:=true;ππ ccError:π beginπ PickDone:=true;π end;π end; {case}π until PickDone;π HideMouse;ππ {NOTE THE FOLLOWING LINES: They're needed to remap the <Enter>π key to its original setting and gets rid of the <F10> key asπ the ccSelect. If you want *ALL* of your pick lists throughoutπ your program to behave this way, use the PickCommands.AddCommandπ at the beginning of your program.}ππ PickCommands.AddCommand(ccSelect,1,$1C0D,0); {Enter=Toggle}π PickCommands.AddCommand(ccNone,1,$4400,0); {F10=Accept}π PL.Done;π end;πend;ππ{πCHARLES SERFOSSππ>I've been trying to create a simple pick list using Object Proffesional andπ>can't seem to get it to do what I want. I'm using the expick.pas example as aπ>start for creating my pick list. Everything is pretty much the same exceptπ>that I want my pick list to exit with other keys insted of the enter key.π>The manual doesn't go into detail about this.ππYou'll have to use the "AddCommand" method. Here's an example. This isπbased on "expick1.pas" from Page 4-186 of Book #1.π}ππprogram PickListExample;πusesπ OpCrt, OpRoot, OpCCmd, OpFrame, OpWindow, OpPick;πconstπ NumPizzaToppings = 5;πvarπ PizzaTop : PickList;π PickWindowOptions : Longint;ππprocedure PizzaTopping(Item : Word { etc... }) : Far;πbeginπend;ππbegin { Main }π if not PizzaTop.InitCustom(35, 5, 45, { etc ... }) then beginπ halt;π end;π PizzaTop.SetSearchMode(PicckCharSearch);π PizzaTop.EnableExplosion(20);π with PizzaTop.wFrame do beginπ AddShadow...π AddHeader...π end;π { *************** Decide Which Keys In Addition To Defaults To Allow }π { PickCommands is just mentioned at the end of page 4-207. The }π { CommandProcessor Type allows you to use the functions in section }π { (E) OPCMD - Page 3-82. See Page 3-95 for documentation on }π { the "AddCommand" method! }π { *******************************************************************}π with PickCommands doπ beginπ AddCommand(ccUser1,1,$5200,0); { $5200 = scan code for INS }π AddCommand(ccUser2,1,$5300,0); { $5300 = scan code for DEL }π end;π PizzaTop.Process;π PizzaTop.Erase;π case PizzaTop.GetLastCommand ofπ ccUser1 : ; { If User hits INS, this is executed }π ccUser2 : ; { If User hits DEL, this is executed }π ccSelect : writeln('You chose : ',PizzaTop.GetLastChoiceString);π end;π PizzaTop.Done;πend. { Main }ππ{πDAVID HOWORTHππ> I've been trying to create a simple pick list using Object Proffesionalπ> can't seem to get it to do what I want. I'm using the expick.pas examplπ> start for creating my pick list. Everything is pretty much the same excπ> that I want my pick list to exit with other keys insted of the enter keπ> The manual doesn't go into detail about this.ππNick--The manual does go into subtantial detail. You just need toπknow where to look. As with much of OPro, the things you want toπdo with a particular object may be implemented, not in the objectπper se, but in one of its ancestors. It always pays to look in theπmanual at the ancestor's methods.ππYou need to read up on CommandWindow, from which PickList isπdescended, and on CommandProcessor, in OpCmd. Here's a relevantπpiece of code from one of my programs. The first AddCommand addsπan additional Quit; the others are for purposes specific to myπapplication, not for predefined commands such as ccQuit.π}πwith DialPickList { a PickList descendent } doππ with PickCommands do beginπ { Simulate WordPerfect's exit command }π AddCommand(ccQuit,1,$4100,0); { F7 }ππ { ccUser0 = Add a new phone entry }π AddCommand(ccUser0,1,$1E00,0); {Alt-A}π AddCommand(ccUser0,1,$5200,0); {Ins}ππ { ccUser1 = Delete a phone entry }π AddCommand(ccUser1,1,$2000,0); {Alt-D}π AddCommand(ccUser1,1,$5300,0); {Del}ππ { ccUser2 = Edit a phone entry }π AddCommand(ccUser2,1,$1200,0); {Alt-E}ππ { ccUser3 = Reconfigure Comm Stuff }π AddCommand(ccUser3,1,$2E00,0); {Alt-C}ππ { ccUser4 = View log (the printing and purging routines branchπ from the browsing routine }π AddCommand(ccUser4,1,$2F00,0); {Alt-V}ππ end; { with PickCommands }ππend; { with DialPickList }π 72 01-27-9412:17ALL DJ MURDOCH Program Origin SWAG9402 3 èo π{$X+} { Need this for easy handling of Asciiz strings }πvarπ parentseg : ^word;π p : pchar;πbeginπ parentseg := ptr(prefixseg,$16);π p := ptr(parentseg^-1,8);π writeln('I was launched by ',p);πend.ππ 73 01-27-9412:19ALL PIGEON STEVEN Eight Queens SWAG9402 39 èo {πpigeons@JSP.UMontreal.CA (Pigeon Steven)ππ> Hey, I have a friend who is taking a Pascal class at another col-π>lege and he asked me to make a query of you all. Basically, he has toπ>do the "eight queens" on a chessboard (with none of them interferingπ>vertically, horizontally, or diagonally with each other) problem inπ>Pascal. The program has to use stacks. Its input is the number ofπ>queens (the dimensions of the chessboard are that number x that number).π>The output is that it can't be done with that number of queens or aπ>grid of the queens and either empty spaces or dashes. I was wonderingπ>if any of you had any similar programs in old code lying around, and ifπ>so if you could send it to me. My friend says it's a pretty classicπ>problem for programmers, so I figured I'd ask. Oh, and in case some ofπ>you think that I am this "friend", the only Pascal course here at Brownπ>(cs15) has already done its job with stacks, and it wasn't this. Btw,π>speaking of cs here, it's Object-Oriented; my friend's program needs toπ>be done procedureally (straight-line), not in OOPas. I thank you allπ>for your indulgence in allowing me to post this. Please don't flame me,π>as I am only trying to help out a friend. If there is a more appropriateπ>place for me to post this, please tell me (I am going to post this toπ>cs groups if possible). Oh, and as I don't get around here often, Iπ>would appreciate it much if any and all replies were sent to the addressπ>below. Thanx,π>ππHere's a programm that does that. It's a little bit strange, but I putπextra code so the board would not be passed as a parameter (since TurboπProfiler said :"Hey, 75% of your run time goes in copy of the board").πThe file is name REINES5.PAS (litterally QUEENS5.PAS) and it's limitedπ(so to say) to 64x64 boards (with 64 queens on it). It is fast enough.πππ}π program Probleme_des_reines;ππ const max = 64;π libre = 8;π reine = 8;ππ const colname:string =π 'abcdefghijklmnopqrstuvwxyz'+π 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'+π 'αßΓτΣσµΦΘΩδ';π type echiquier = array[1..max,1..max] of byte;π var sol,recursions:longint;π top:word;π Reines,Attaques:echiquier;πππ function min(a,b:integer):integer;π beginπ if a<bπ then min:=aπ else min:=b;π end;ππ procedure mark(x,y:integer);π var t,g,i:integer;π beginπ for t:=y+1 to top do inc(attaques[x,t]);ππ t:=x+1;π g:=y+1;ππ for i:=1 to min(top-t,top-g)+1 doπ beginπ inc(attaques[t,g]);π inc(t);π inc(g);π end;ππ t:=x-1;π g:=y+1;ππ if t>0 thenπ for i:=1 to min(top-g+1,t) doπ beginπ inc(attaques[t,g]);π dec(t);π inc(g);π end;ππ Reines[x,y]:=reine;ππ end;ππ procedure unmark(x,y:integer);π var t,g,i:integer;π beginπ for t:=y+1 to top do dec(attaques[x,t]);ππ t:=x+1;π g:=y+1;ππ for i:=1 to min(top-t,top-g)+1 doπ beginπ dec(attaques[t,g]);π inc(t);π inc(g);π end;πππ t:=x-1;π g:=y+1;ππ if t>0 thenπ for i:=1 to min(top-g+1,t) doπ beginπ dec(attaques[t,g]);π dec(t);π inc(g);π end;ππ Reines[x,y]:=libre;ππ end;ππππ procedure traduit;π var t,g:integer;π beginπ write(sol:4,'. ');π for t:=1 to top doπ for g:=1 to top doπ if Reines[g,t]=reine then write(colname[t],g,' ');π writeln(' ',recursions);π end;πππ function find(level,j:integer):integer;π beginπ inc(j);π while (attaques[j,level]<>libre) and (j<top) do inc(j);π if (attaques[j,level]=libre)π then find:=jπ else find:=0;π end;ππππ procedure recurse(level:integer);π var t:integer;π beginπ inc(recursions);π t:=0;π repeatπ t:=find(level,t);π if t<>0π then beginπ if level=topπ then beginπ inc(sol);π Reines[t,level]:=reine;π traduit;π Reines[t,level]:=libre;π endπ else beginπ mark(t,level);π recurse(level+1);π unmark(t,level);π end;π endπ until (t=0) or (t=top);π end;πππ function fact(n:real):real;π beginπ if n<=1 then fact:=1π else fact:=n*fact(n-1);π end;πππ var a:echiquier;π i:integer;π beginπππ sol:=0;π val(paramstr(1),top,i);π if top>maxπ then beginπ writeln('! ',Top,' a ete remis a ',max,' (max)');π top:=max;π end;ππ if top<1 then top:=1;ππ writeln;π writeln(' Le probleme des ',top,' reines FAST (c) 1992-1993 Steven Pigeon');π writeln;ππ recursions:=0;π fillchar(attaques,sizeof(attaques),libre);π fillchar(Reines,sizeof(Reines),libre);π recurse(1);π writeln;π writeln(' Solutions: ',sol);π writeln(' Recursions: ',recursions,' (au lieu de ',fact(top):0:0,')');π end.ππ 74 01-27-9412:23ALL TONY NUGENT TOT Info SWAG9402 24 èo {πI've just "completed" (are programs *ever* completed?:) a ratherπlarge programming project for a 3rd year uni subject.ππWe chose to use TechnoJock's Object Toolkit (currently availableπversion via Internet ftp) for much of the user interface (I'mπsorry we didn't look at TurboVision, but that's another story),πand I must admit that I was impressed with its overallπfunctionality (I counted 87 different objects along with manyπuseful non-object procedures), its ease of use and the generallyπflawless results it produced.ππHowever, there is a MAJOR point that I would like to share withπyou all about this great toolkit that is NOT documented butπESSENTIAL to know about if you use it.ππThe problem was that after a program that uses TOT was run, theπsystem became very unstable afterwards with memory problems,πusually locking up or something similar when subsequent programsπare run.ππI solved this problem by calling all the destructor Done methodsπof all the active TOT objects, then disposing of those on theπmemory heap just before exiting the program. Now the TOT docsπactually discourages this, but they don't mention that it doesπindeed NEED to be done before termination of the program.ππFor example:π}ππusesπ Crt, { Borland }π totINPUT,π totFAST,π totDir,π totIO1,π totMSG,π totKEY,π totWIN,π totLIST,π totLINK,π totLOOK,π totSYS,π totDATE;π { TechnoJocks }π { other units }ππ{ Then later... }ππprocedure TidyUpMess;π{ shutdown procedure }πbeginπ { Tidy up after ourselves }π dispose(myobjects, Done);π { Tidy up after TechnoJocks }π Mouse.Hide; { turn off the mouse }π Screen.CursOn; { vain attempt to get a cursor back in DOS }π Screen.Done; { totFAST - the screen object is a variable}π Key.Done; { totINPUT }π Mouse.Done { totINPUT }π Dispose(ALPHABETtot,Done); { totINPUT }π Dispose(LOOKtot,Done); { totLOOK }π Dispose(MONITOR,Done); { totSYS }π Dispose(IOtot,Done); { totIO }π Dispose(DATEtot,Done); { totDATE }π Dispose(SCROLLtot,Done); { totFAST }π Dispose(SHADOWtot,Done); { totFAST }πend;ππ{πThis does the job nicely... no more problems (that I could find,πanyway). Note that the order of some of these calls is important.ππThe only problem that remains is that on dropping back to dos theπcursor is no longer there (but only with command.com - NOT ifπ4dos is installed - _strange_ indeed).ππBTW, does anybody have a nice fix for this missing cursor?ππHopefully somebody will find this hard-found information useful.πIf someone knows how to email or netmail the authors, then I'mπsure that they would like to know about this too; all I've gotπabout them is the following:ππ TechnoJock Software, Inc.π PO Box 820927π Houston TX 77282π Enquiries (713) 493-6354π Compuserve ID: 74017,227π Fax: (713) 493-5872π}π 75 01-27-9412:24ALL PETER BEEFTINK UUDecode! SWAG9402 47 èo {π> Yeah ! Please post your UU(EN/DE)CODE here ! I am interested, as well !ππand the decode as well.π}ππprogram uudecode;ππ CONST defaultSuffix = '.uue';π offset = 32;ππ TYPE string80 = string[80];ππ VAR infile: text;π fi : file of byte;π outfile: file of byte;π lineNum: integer;π line: string80;π size,remaining :real;ππ procedure Abort(message: string80);ππ begin {abort}π writeln;π if lineNum > 0 then write('Line ', lineNum, ': ');π writeln(message);π haltπ end; {Abort}ππ procedure NextLine(var s: string80);ππ begin {NextLine}π LineNum := succ(LineNum);π {write('.');}π readln(infile, s);π remaining:=remaining-length(s)-2; {-2 is for CR/LF}π write('bytes remaining: ',remaining:7:0,' (',π remaining/size*100.0:3:0,'%)',chr(13));π end; {NextLine}ππ procedure Init;ππ procedure GetInFile;ππ VAR infilename: string80;ππ begin {GetInFile}π if ParamCount = 0 then abort ('Usage: uudecode <filename>');π infilename := ParamStr(1);π if pos('.', infilename) = 0π then infilename := concat(infilename, defaultSuffix);π assign(infile, infilename);π {$i-}π reset(infile);π {$i+}π if IOresult > 0 then abort (concat('Can''t open ', infilename));π writeln ('Decoding ', infilename);π assign(fi,infilename); reset(fi);π size:=FileSize(fi); close(fi);π if size < 0 then size:=size+65536.0;π remaining:=size;π end; {GetInFile}ππ procedure GetOutFile;ππ var header, mode, outfilename: string80;π ch: char;ππ procedure ParseHeader;ππ VAR index: integer;ππ Procedure NextWord(var word:string80; var index: integer);ππ begin {nextword}π word := '';π while header[index] = ' ' doπ beginπ index := succ(index);π if index > length(header) then abort ('Incomplete header')π end;π while header[index] <> ' ' doπ beginπ word := concat(word, header[index]);π index := succ(index)π endπ end; {NextWord}ππ begin {ParseHeader}π header := concat(header, ' ');π index := 7;π NextWord(mode, index);π NextWord(outfilename, index)π end; {ParseHeader}ππ begin {GetOutFile}π if eof(infile) then abort('Nothing to decode.');π NextLine (header);π while not ((copy(header, 1, 6) = 'begin ') or eof(infile)) doπ NextLine(header);π writeln;π if eof(infile) then abort('Nothing to decode.');π ParseHeader;π assign(outfile, outfilename);π writeln ('Destination is ', outfilename);π {$i-}π reset(outfile);π {$i+}π if IOresult = 0 thenπ beginπ { write ('Overwrite current ', outfilename, '? [Y/N] ');π repeatπ read (kbd, ch);π ch := UpCase(ch)π until ch in ['Y', 'N'];π writeln(ch);π if ch = 'N' then abort ('Overwrite cancelled.')}π end;π rewrite (outfile);π end; {GetOutFile}ππ begin {init}π lineNum := 0;π GetInFile;π GetOutFile;π end; { init}ππ Function CheckLine: boolean;ππ begin {CheckLine}π if line = '' then abort ('Blank line in file');π CheckLine := not (line[1] in [' ', '`'])π end; {CheckLine}πππ procedure DecodeLine;ππ VAR lineIndex, byteNum, count, i: integer;π chars: array [0..3] of byte;π hunk: array [0..2] of byte;ππ{ procedure debug;ππ var i: integer;ππ procedure writebin(x: byte);ππ var i: integer;ππ beginπ for i := 1 to 8 doπ beginπ write ((x and $80) shr 7);π x := x shl 1π end;π write (' ')π end;ππ beginπ writeln;π for i := 0 to 3 do writebin(chars[i]);π writeln;π for i := 0 to 2 do writebin(hunk[i]);π writelnπ end; }ππ function nextch: char;ππ begin {nextch}π lineIndex := succ(lineIndex);π if lineIndex > length(line) then abort('Line too short.');π if not (line[lineindex] in [' '..'`'])π then abort('Illegal character in line.');π{ write(line[lineindex]:2);}π if line[lineindex] = '`' then nextch := ' 'π else nextch := line[lineIndex]π end; {nextch}ππ procedure DecodeByte;ππ procedure GetNextHunk;ππ VAR i: integer;ππ begin {GetNextHunk}π for i := 0 to 3 do chars[i] := ord(nextch) - offset;π hunk[0] := (chars[0] shl 2) + (chars[1] shr 4);π hunk[1] := (chars[1] shl 4) + (chars[2] shr 2);π hunk[2] := (chars[2] shl 6) + chars[3];π byteNum := 0 {;π debug }π end; {GetNextHunk}ππ begin {DecodeByte}π if byteNum = 3 then GetNextHunk;π write (outfile, hunk[byteNum]);π {writeln(bytenum, ' ', hunk[byteNum]);}π byteNum := succ(byteNum)π end; {DecodeByte}ππ begin {DecodeLine}π lineIndex := 0;π byteNum := 3;π count := (ord(nextch) - offset);π for i := 1 to count do DecodeByteπ end; {DecodeLine}ππ procedure terminate;ππ var trailer: string80;ππ begin {terminate}π if eof(infile) then abort ('Abnormal end.');π NextLine (trailer);π if length (trailer) < 3 then abort ('Abnormal end.');π if copy (trailer, 1, 3) <> 'end' then abort ('Abnormal end.');π close (infile);π close (outfile)π end;ππ begin {uudecode}π init;π NextLine(line);π while CheckLine doπ beginπ DecodeLine;π NextLine(line)π end;π terminateπ end.ππ 76 01-27-9412:24ALL PETER BEEFTINK UUEncode! SWAG9402 38 èo {π> Yeah ! Please post your UU(EN/DE)CODE here ! I am interested, as well !ππHere she goes then.π}ππPROGRAM uuencode;ππUses Dos,Crt;ππCONSTπ Header = 'begin';π Trailer = 'end';π DefaultMode = '644';π DefaultExtension = '.uue';π OFFSET = 32;π CHARSPERLINE = 60;π BYTESPERHUNK = 3;π SIXBITMASK = $3F;πTYPEπ Str80 = STRING[80];πVARπ Infile: FILE OF Byte;π Outfile: TEXT;π Infilename, Outfilename, Mode: Str80;π lineLength, numbytes, bytesInLine: INTEGER;π Line: ARRAY [0..59] OF CHAR;π hunk: ARRAY [0..2] OF Byte;π chars: ARRAY [0..3] OF Byte;π size,remaining : longint; {v1.1 REAL;}πPROCEDURE Abort (Msg : Str80);π BEGINπ WRITELN(Msg);π {$I-} {v1.1}π CLOSE(Infile);π CLOSE(Outfile);π {$I+} {v1.1}π HALTπ END; {of Abort}πPROCEDURE Init;π PROCEDURE GetFiles;π VARπ i : INTEGER;π TempS : Str80;π Ch : CHAR;π BEGINπ IF ParamCount < 1 THEN Abort ('No input file specified.');π Infilename := ParamStr(1);π {$I-}π ASSIGN (Infile, Infilename);π RESET (Infile);π {$I+}π IF IOResult > 0 THEN Abort (CONCAT ('Can''t open file ', Infilename));π size := FileSize(Infile);π{ IF size < 0 THEN size:=size+65536.0; }π remaining := size;π WRITE('Uuencoding file ', Infilename);π i := POS('.', Infilename);π IF i = 0π THEN Outfilename := Infilenameπ ELSE Outfilename := COPY (Infilename, 1, PRED(i));π Mode := DefaultMode;π { Process 2d cmdline arg (if any).π It could be a new mode (rather than default "644")π or it could be a forced output name (rather thanπ "infile.uue") }π IF ParamCount > 1 {got more args}π THEN FOR i := 2 TO ParamCount DO BEGINπ TempS := ParamStr(i);π IF TempS[1] IN ['0'..'9'] {numeric : it's a mode}π THEN Mode := TempSπ ELSE Outfilename := TempS {it's output filename}π END;π IF POS ('.', Outfilename) = 0 {he didn't give us extension..}π {..so make it ".uue"}π THEN Outfilename := CONCAT(Outfilename, DefaultExtension);π ASSIGN (Outfile, Outfilename);π WRITELN (' to file ', Outfilename, '.');π {$I-}π RESET(Outfile);π {$I+}π IF IOResult = 0 THEN BEGIN {output file exists!}π WRITE ('Overwrite current ', Outfilename, '? [Y/N] ');π REPEATπ Ch := Upcase(ReadKey);π UNTIL Ch IN ['Y', 'N'];π WRITELN (Ch);π IF Ch = 'N' THEN Abort(CONCAT (Outfilename, ' not overwritten.'))π END;π {$I-}π CLOSE(Outfile);π IF IOResult <> 0 THEN ; {v1.1 we don't care}π REWRITE(Outfile);π {$I+}π IF IOResult > 0 THEN Abort(CONCAT('Can''t open ', Outfilename));π END; {of GetFiles}π BEGIN {Init}π GetFiles;π bytesInLine := 0;π lineLength := 0;π numbytes := 0;π WRITELN (Outfile, Header, ' ', Mode, ' ', Infilename);π END; {init}π{You'll notice from here on we don't do any error-trapping on diskπ read/writes. We just let DOS do the job. Any errors are terminalπ anyway, right? }πPROCEDURE FlushLine;π VAR i: INTEGER;π PROCEDURE WriteOut(Ch: CHAR);π BEGINπ IF Ch = ' ' THEN WRITE(Outfile, '`')π ELSE WRITE(Outfile, Ch)π END; {of WriteOut}π BEGIN {FlushLine}π {write ('.');}π WRITE('bytes remaining: ',remaining:7,' (',π remaining/size*100.0:3:0,'%)',CHR(13));π WriteOut(CHR(bytesInLine + OFFSET));π FOR i := 0 TO PRED(lineLength) DOπ WriteOut(Line[i]);π WRITELN (Outfile);π lineLength := 0;π bytesInLine := 0π END; {of FlushLine}πPROCEDURE FlushHunk;π VAR i: INTEGER;π BEGINπ IF lineLength = CHARSPERLINE THEN FlushLine;π chars[0] := hunk[0] ShR 2;π chars[1] := (hunk[0] ShL 4) + (hunk[1] ShR 4);π chars[2] := (hunk[1] ShL 2) + (hunk[2] ShR 6);π chars[3] := hunk[2] AND SIXBITMASK;π {debug;}π FOR i := 0 TO 3 DO BEGINπ Line[lineLength] := CHR((chars[i] AND SIXBITMASK) + OFFSET);π {write(line[linelength]:2);}π Inc(lineLength);π END;π {writeln;}π Inc(bytesInLine,numbytes);π numbytes := 0π END; {of FlushHunk}πPROCEDURE Encode1;π BEGINπ IF numbytes = BYTESPERHUNK THEN FlushHunk;ππ READ (Infile, hunk[numbytes]);π Dec(remaining);π Inc(numbytes);π END; {of Encode1}πPROCEDURE Terminate;π BEGINπ IF numbytes > 0 THEN FlushHunk;π IF lineLength > 0 THEN BEGINπ FlushLine;π FlushLine;π ENDπ ELSE FlushLine;π WRITELN (Outfile, Trailer);π CLOSE (Outfile);π CLOSE (Infile);π END; {Terminate}πBEGIN {uuencode}π Init;π WHILE NOT EOF (Infile) DO Encode1;π Terminate;π WRITELN;πEND. {uuencode}ππ 77 01-27-9413:33ALL GREG ESTABROOKS String Timing Demo SWAG9402 64 èo {$A+,B-,D-,E-,F-,I+,N-,O-,R-,S-,V+}ππprogram TestStringComp;πusesπ TpTimer; (* TurboPower's public domain TpTimer unit. *)ππ (* Run-Length-Encoded string compression. *)π function fustRLEcomp(stIn : string) : string;π varπ byCount,π byStInSize,π byStTempPos : byte;π woStInPos : word;π stTemp : string;π beginπ fillchar(stTemp, sizeof(stTemp), 0);π byCount := 1;π byStTempPos := 1;π woStInPos := 1;π byStInSize := ord(stIn[0]);π repeatπ if (woStInPos < byStInSize)π and (stIn[woStInPos] = stIn[succ(woStInPos)])π and (byCount < $7F) thenπ inc(byCount)π elseπ if (byCount > 3) thenπ beginπ stTemp[byStTempPos] := #0;π stTemp[(byStTempPos + 1)] := chr(byCount);π stTemp[(byStTempPos + 2)] := stIn[woStInPos];π inc(stTemp[0], 3);π inc(byStTempPos, 3);π byCount := 1π endπ elseπ beginπ move(stIn[succ(woStInPos - byCount)],π stTemp[byStTempPos], byCount);π inc(stTemp[0], byCount);π inc(byStTempPos, byCount);π byCount := 1π end;π inc(woStInPos, 1)π until (woStInPos > byStInSize);π fustRLEcomp := stTempπ end;πππ (* Run-Length-Encoded string expansion. *)π function fustRLEexp(stIn : string) : string;π varπ byStInSize,π byStTempPos : byte;π woStInPos : word;π stTemp : string;π beginπ fillchar(stTemp, sizeof(stTemp), 0);π byStInSize := ord(stIn[0]);π byStTempPos := 1;π woStInPos := 1;π repeatπ if (stIn[woStInPos] <> #0) thenπ beginπ stTemp[byStTempPos] := stIn[woStInPos];π inc(woStInPos, 1);π inc(byStTempPos, 1);π inc(stTemp[0], 1)π endπ elseπ beginπ fillchar(stTemp[byStTempPos], ord(stIn[succ(woStInPos)]),π stIn[(woStInPos + 2)]);π inc(byStTempPos, ord(stIn[succ(woStInPos)]));π inc(stTemp[0], ord(stIn[succ(woStInPos)]));π inc(woStInPos, 3)π endπ until (woStInPos > byStInSize);π fustRLEexp := stTempπ end;πππ (* 8 bit into 7 bit string compression. *)π function fustComp87(stIn : string) : string;π varπ stTemp : string;π byLoop, byTempSize, byOffset : byte;π beginπ if (stIn[0] < #255) thenπ stIn[succ(ord(stIn[0]))] := #0;π fillchar(stTemp, sizeof(stTemp), 0);π byTempSize := ord(stIn[0]) shr 3;π if ((ord(stIn[0]) mod 8) <> 0) thenπ inc(byTempsize, 1);π byOffset := 0;π for byLoop := 1 to byTempSize doπ beginπ stTemp[(byOffset * 7) + 1] :=π chr( ( (ord(stIn[(byOffset * 8) + 1]) and $7F) shl 1) +π ( (ord(stIn[(byOffset * 8) + 2]) and $40) shr 6) );π stTemp[(byOffset * 7) + 2] :=π chr( ( (ord(stIn[(byOffset * 8) + 2]) and $3F) shl 2) +π ( (ord(stIn[(byOffset * 8) + 3]) and $60) shr 5) );π stTemp[(byOffset * 7) + 3] :=π chr( ( (ord(stIn[(byOffset * 8) + 3]) and $1F) shl 3) +π ( (ord(stIn[(byOffset * 8) + 4]) and $70) shr 4) );π stTemp[(byOffset * 7) + 4] :=π chr( ( (ord(stIn[(byOffset * 8) + 4]) and $0F) shl 4) +π ( (ord(stIn[(byOffset * 8) + 5]) and $78) shr 3) );π stTemp[(byOffset * 7) + 5] :=π chr( ( (ord(stIn[(byOffset * 8) + 5]) and $07) shl 5) +π ( (ord(stIn[(byOffset * 8) + 6]) and $7C) shr 2) );π stTemp[(byOffset * 7) + 6] :=π chr( ( (ord(stIn[(byOffset * 8) + 6]) and $03) shl 6) +π ( (ord(stIn[(byOffset * 8) + 7]) and $7E) shr 1) );π if (byOffset < 31) thenπ stTemp[(byOffset * 7) + 7] :=π chr( ( ( ord(stIn[(byOffset * 8) + 7]) and $01) shl 7) +π ( ord(stIn[(byOffset * 8) + 8]) and $7F) )π elseπ stTemp[(byOffset * 7) + 7] :=π chr( ( ord(stIn[(byOffset * 8) + 7]) and $01) shl 7);π inc(byOffset, 1)π end;π stTemp[0] := chr(((ord(stIn[0]) div 8) * 7) + (ord(stIn[0]) mod 8) );π fustComp87 := stTempπ end;πππ (* 7 bit into 8 bit string expansion. *)π function fustExp78(stIn : string) : string;π varπ stTemp : string;π byOffset, byTempSize, byLoop : byte;π beginπ fillchar(stTemp, sizeof(stTemp), 0);π byTempSize := ord(stIn[0]) div 7;π if ((ord(stIn[0]) mod 7) <> 0)thenπ inc(byTempSize, 1);π byOffset := 0;π for byLoop := 1 to byTempSize doπ beginπ stTemp[(byOffset * 8) + 1] :=π chr( ord(stIn[(byOffset * 7) + 1]) shr 1);π stTemp[(byOffset * 8) + 2] :=π chr( ( ( ord(stIn[(byOffset * 7) + 1]) and $01) shl 6) +π ( ( ord(stIn[(byOffset * 7) + 2]) and $FC) shr 2) );π stTemp[(byOffset * 8) + 3] :=π chr( ( ( ord(stIn[(byOffset * 7) + 2]) and $03) shl 5) +π ( ord(stIn[(byOffset * 7) + 3]) shr 3) );π stTemp[(byOffset * 8) + 4] :=π chr( ( ( ord(stIn[(byOffset * 7) + 3]) and $07) shl 4) +π ( ord(stIn[(byOffset * 7) + 4]) shr 4) );π stTemp[(byOffset * 8) + 5] :=π chr( ( ( ord(stIn[(byOffset * 7) + 4]) and $0F) shl 3) +π ( ord(stIn[(byOffset * 7) + 5]) shr 5) );π stTemp[(byOffset * 8) + 6] :=π chr( ( ( ord(stIn[(byOffset * 7) + 5]) and $1F) shl 2) +π ( ord(stIn[(byOffset * 7) + 6]) shr 6) );π stTemp[(byOffset * 8) + 7] :=π chr( ( ( ord(stIn[(byOffset * 7) + 6]) and $3F) shl 1) +π ( ord(stIn[(byOffset * 7) + 7]) shr 7) );π if (byOffset < 31) thenπ stTemp[(byOffset * 8) + 8] :=π chr( (ord(stIn[(byOffset * 7) + 7]) and $7F) );π inc(byOffset, 1)π end;π stTemp[0] :=π chr( ( (ord(stIn[0]) div 7) * 8) + (ord(stIn[0]) mod 7) );π if (stTemp[ord(stTemp[0])] = #0) thenπ dec(stTemp[0], 1);π fustExp78 := stTempπ end;πππvarπ loStart, loStop : longint;ππ stMy1,π stMy2,π stMy3 : string;ππ (* Main program execution block. *)πBEGINππ (* Test string 1. *)π stMy1 := '12345678901111111111123456789022222222221234567890' +π '33333333331234567890444444444412345678905555555555' +π '12345678906666666666123456789077777777771234567890' +π '88888888881234567890999999999912345678900000000000' +π '1234567890AAAAAAAAAA1234567890BBBBBBBBBB1234567890' +π 'CCCCC';ππ (* Test string 2. *)π{ stMy1 := '12345678901234567890123456789012345678901234567890' +π '12345678901234567890123456789012345678901234567890' +π '12345678901234567890123456789012345678901234567890' +π '12345678901234567890123456789012345678901234567890' +π '12345678901234567890123456789012345678901234567890' +π '12345'; }ππ (* Test string 3. *)π{ stMy1 := '11111111111111111111111111111111111111111111111111' +π '11111111111111111111111111111111111111111111111111' +π '11111111111111111111111111111111111111111111111111' +π '11111111111111111111111111111111111111111111111111' +π '11111111111111111111111111111111111111111111111111' +π '11111'; }ππ loStart := ReadTimer;π stMy2 := fustComp87(fustRLEcomp(stMy1));π loStop := ReadTimer;π writeln(' Time to compress = ', ElapsedTimeString(loStart, loStop), ' ms');π loStart := ReadTimer;π stMy3 := fustRLEexp(fustExp78(stMy2));π loStop := ReadTimer;π writeln(' Time to expand = ', ElapsedTimeString(loStart, loStop), ' ms');π writeln;π writeln(stMy1);π writeln;π writeln(stMy2);π writeln;π writeln(stMy3);π writeln;π if (stMy1 <> stMy3) thenπ writeln(' Conversion Error')π elseπ writeln(' Conversion Match')πEND.πππ 78 01-27-9413:34ALL GREG ESTABROOKS Misc Utilities SWAG9402 87 èo UNIT Utils; { Misc Utilities Last Updates Nov 01/93 }π { Copyright (C) 1992,93 Greg Estabrooks }ππINTERFACEπ{ *********************************************************************}πUSESπ CRT,KeyIO,DOS;ππCONSTπ FpuType :ARRAY[0..3] OF STRING[10] =('None','8087','80287','80387');π CPU :ARRAY[0..3] Of STRING[13] =('8088/V20','80286',π '80386/80486','80486');πCONST { Define COM port Addresses }π ComPort :ARRAY[1..4] Of WORD = ($3F8,$2F8,$3E8,$2E8);ππCONSTπ Warm :WORD = 0000; { Predefined value for warm boot. }π Cold :WORD = 0001; { Predefined value for cold boot. }ππVARπ BiosDate :ARRAY[0..7] of CHAR Absolute $F000:$FFF5;π EquipFlag :WORD Absolute $0000:$0410;π CompID :BYTE Absolute $F000:$FFFE;ππFUNCTION CoProcessorExist :BOOLEAN;πFUNCTION NumPrinters :WORD;πFUNCTION GameIOAttached :BOOLEAN;πFUNCTION NumSerialPorts :INTEGER;πFUNCTION NumDisketteDrives :INTEGER;πFUNCTION InitialVideoMode :INTEGER;πPROCEDURE Noise(Pitch, Duration :INTEGER);πFUNCTION Time :STRING;πFUNCTION WeekDate :STRING;πFUNCTION DayOfWeek( Month, Day, Year :WORD ) :BYTE; { Returns 1-7 }πFUNCTION PrinterOK :BOOLEAN;πFUNCTION AdlibCard :BOOLEAN;πFUNCTION TrueDosVer :WORD;πPROCEDURE SetPrtScr( On_OFF :BOOLEAN );πFUNCTION CpuType :WORD;πPROCEDURE IdePause;πFUNCTION RingDetect( CPort :WORD) :BOOLEAN;πfunction DetectOs2: Boolean;πFUNCTION HiWord( Long :LONGINT ) :WORD;π { Routine to return high word of a LongInt. }πFUNCTION LoWord( Long :LONGINT ) :WORD;π { Routine to return low word of a LongInt. }πFUNCTION Running4DOS : Boolean;πPROCEDURE Reboot( BootCode :WORD );π { Routine to reboot system according to boot code.}πππFUNCTION GetChar( X,Y :WORD; VAR Attrib:BYTE ) :CHAR;ππIMPLEMENTATIONπ{ *********************************************************************}πFUNCTION CoProcessorExist :BOOLEAN;πBEGINπ CoProcessorExist := (EquipFlag And 2) = 2;πEND;ππFUNCTION NumPrinters :WORD;πBEGINπ NumPrinters := EquipFlag Shr 14;πEND;ππFUNCTION GameIOAttached :BOOLEAN;πBEGINπ GameIOAttached := (EquipFlag And $1000) = 1;πEND;ππFUNCTION NumSerialPorts :INTEGER;πBEGINπ NumSerialPorts := (EquipFlag Shr 9) And $07;πEND;ππFUNCTION NumDisketteDrives :INTEGER;πBEGINπ NumDisketteDrives := ((EquipFlag And 1) * (1+(EquipFlag Shr 6) And $03));πEND;ππFUNCTION InitialVideoMode :INTEGER;πBEGINπ InitialVideoMode := (EquipFlag Shr 4) And $03;πEND;ππPROCEDURE Noise( Pitch, Duration :INTEGER );πBEGINπ Sound(Pitch);π Delay(Duration);π NoSound;πEND;ππFunction Time : String;πVARπ Hour,Min,Sec :STRING[2];π H,M,S,T :WORD;ππBEGINπ GetTime(H,M,S,T);π Str(H,Hour);π Str(M,Min);π Str(S,Sec);π If S < 10 Thenπ Sec := '0' + Sec;π If M < 10 Thenπ Min := '0' + Min;π If H > 12 Thenπ BEGINπ Str(H - 12, Hour);π IF Length(Hour) = 1 Then Hour := ' ' + Hour;π Time := Hour + ':' + Min + ':' + Sec+' pm'π ENDπ ELSEπ BEGINπ If H = 0 Thenπ Time := '12:' + Min + ':' + Sec + ' am'π ELSEπ Time := Hour +':'+Min+':'+Sec+' am';π END;π If H = 12 Thenπ Time := Hour + ':' + Min + ':' + Sec + ' pm';πEND;ππFUNCTION WeekDate :STRING;πTYPEπ WeekDays = Array[0..6] Of STRING[9];π Months = Array[1..12] Of STRING[9];ππCONSTπ DayNames : WeekDays = ('Sunday','Monday','Tuesday','Wednesday',π 'Thursday','Friday','Saturday');π MonthNames : Months = ('January','February','March','April','May',π 'June','July','August','September',π 'October','November','December');πVARπ Y,π M,π D,π DayOfWeek :WORD;π Year :STRING;π Day :STRING;ππBEGINπ GetDate(Y,M,D,DayofWeek);π Str(Y,Year);π Str(D,Day);π WeekDate := DayNames[DayOfWeek] + ' ' + MonthNames[M] + ' ' + Day+ ', 'π + Year;πEND;ππFUNCTION DayOfWeek( Month, Day, Year :WORD ) :BYTE;πVAR ivar1, ivar2 : Integer;πBEGINπ IF (Day > 0) AND (Day < 32) AND (Month > 0) AND (Month < 13)π THENπ BEGINπ ivar1 := ( Year MOD 100 );π ivar2 := Day + ivar1 + ivar1 DIV 4;π CASE Month OFπ 4, 7 : ivar1 := 0;π 1, 10 : ivar1 := 1;π 5 : ivar1 := 2;π 8 : ivar1 := 3;π 2,3,11 : ivar1 := 4;π 6 : ivar1 := 5;π 9,12 : ivar1 := 6;π END; {case}π ivar2 := ( ivar1 + ivar2 ) MOD 7;π IF ( ivar2 = 0 ) THEN ivar2 := 7;π END {IF}π ELSEπ ivar2 := 0;π DayOfWeek := BYTE( ivar2 );πEND;ππFUNCTION PrinterOK :BOOLEAN;π { Determine whether printer is on or off line }πBEGINπ If (Port[$379]) And (16) <> 16 Thenπ PrinterOK := Falseπ Elseπ PrinterOK := True;πEND;ππFUNCTION AdlibCard :BOOLEAN;π { Routine to determine if a Adlib compatible card is installed }πVARπ Val1,Val2 :BYTE;πBEGINπ Port[$388] := 4; { Write 60h to register 4 }π Delay(3); { Which resets timer 1 and 2 }π Port[$389] := $60;π Delay(23);π Port[$388] := 4; { Write 80h to register 4 }π Delay(3); { Which enables interrupts }π Port[$389] := $80;π Delay(23);π Val1 := Port[$388]; { Read status byte }π Port[$388] := 2; { Write ffh to register 2 }π Delay(3); { Which is also Timer 1 }π Port[$389] := $FF;π Delay(23);π Port[$388] := 4; { Write 21h to register 4 }π Delay(3); { Which will Start Timer 1 }π Port[$389] := $21;π Delay(85); { wait 85 microseconds }π Val2 := Port[$388]; { read status byte }π Port[$388] := 4; { Repeat the first to steps }π Delay(3); { Which will reset both Timers }π Port[$389] := $60;π Delay(23);π Port[$388] := 4;π Delay(3);π Port[$389] := $80; { Now test the status bytes saved }π If ((Val1 And $E0) = 0) And ((Val2 And $E0) = $C0) Thenπ AdlibCard := True { Card was found }π Elseπ AdlibCard := False; { No Card Installed }πEND;ππFUNCTION TrueDosVer :WORD; ASSEMBLER;π { Returns true Dos Version. Not affected by Setver }πASMπ Mov AX,$3306 { get true dos ver }π Int $21 { Call Dos }π Mov AX,BX { Return proper results }ππ { DL = Revision Number }π { DH = V Flags, 8h = Dos in ROM, 10h Dos in HMA }πEND;{TrueDosVer}ππPROCEDURE SetPrtScr( On_OFF :BOOLEAN );π { Routine to Enable or disable Print screen key }πBEGINπ If On_OFF Then { Turn it on }π Mem[$0050:0000] := 0π Elseπ Mem[$0050:0000] := 1; { Turn it off }πEND;ππFUNCTION CpuType :WORD; ASSEMBLER;π { Returns a value depending on the type of CPU }π { 0 = 8088/V20 or compatible }π { 1 = 80286 2 = 80386/80486+ }πASMπ Xor DX,DX { Clear DX }π Push DXπ PopF { Clear Flags }π PushFπ Pop AX { Load Cleared Flags }π And AX,$0F000 { Check hi bits for F0h }π Cmp AX,$0F000π Je @Quit { Quit if 8088 }π Inc DXπ Mov AX,$0F000 { Now Check For 80286 }π Push AXπ PopFπ PushFπ Pop AXπ And AX,$0F000 { If The top 4 bits aren't set }π Jz @Quit { Its a 80286+ }π Inc DX { Else its a 80386 or better }π@Quit:π Mov AX,DX { Return Result in AX }πEND;{CpuType}ππprocedure idepause;πbeginπ gotoxy(1,25);π write('Press any key to return to IDE');π pausekey;πend;ππFUNCTION RingDetect( CPort :WORD) :BOOLEAN;π { Routine to detect whether or not the }π { phone is ringing by checking the comport}πBEGINπ RingDetect := ODD( PORT[CPort] SHR 6 );πEND;ππfunction DetectOs2: Boolean;πbeginπ { if you use Tpro, then write Hi(TpDos.DosVersion) }π DetectOs2 := (Lo(Dos.DosVersion) > 10);πend;ππFUNCTION HiWord( Long :LONGINT ) :WORD; ASSEMBLER;π { Routine to return high word of a LongInt. }πASMπ Mov AX,Long.WORD[2] { Move High word into AX. }πEND;ππFUNCTION LoWord( Long :LONGINT ) :WORD; ASSEMBLER;π { Routine to return low word of a LongInt. }πASMπ Mov AX,Long.WORD[0] { Move low word into AX. }πEND;ππFUNCTION Running4DOS : Boolean;πVAR Regs : Registers;πbeginπ With Regs doπ beginπ ax := $D44D;π bx := $00;π end;π Intr ($2F, Regs);π if Regs.ax = $44DD then Running4DOS := TRUEπ else Running4DOS := FALSEπend;ππPROCEDURE Reboot( BootCode :WORD );π { Routine to reboot system according to boot code.}π { Also flushes all DOS buffers. }π { NOTE: Doesn't update directory entries. }πBEGINπ Inline(π $BE/$0D/ { MOV AH,0Dh }π $CD/$21/ { INT 21h }π $FB/ { STI }π $B8/Bootcode/ { MOV AX,BootCode }π $8E/$D8/ { MOV DS,AX }π $B8/$34/$12/ { MOV AX,1234h }π $A3/$72/$04/ { MOV [0472h],AX }π $EA/$00/$00/$FF/$FF); { JMP FFFFh:0000h }πEND;πππFUNCTION GetChar( X,Y :WORD; VAR Attrib:BYTE ) :CHAR;π { Retrieves the character and attribute of }π { coordinates X,Y. }πVARπ Ofs :WORD;πBEGINπ Ofs := ((Y-1) * 160) + ((X SHL 1) - 1);π Attrib := MEM[$B800:Ofs];π GetChar := CHR( MEM[$B800:Ofs-1] );πEND;πππBEGINπEND. 79 01-27-9417:29ALL GAYLE DAVIS Loan Amortization Tables SWAG9402 30 èo program Amortization_Table;ππUses Crt,Printer;ππvar Month : 1..12;π Starting_Month : 1..12;π Balance : real;π Payment : real;π Interest_Rate : real;π Annual_Accum_Interest : real;π Year : integer;π Number_Of_Years : integer;π Original_Loan : real;πππprocedure Calculate_Payment; (* **************** calculate payment *)πvar Temp : real;π Index : integer;πbeginπ Temp := 1.0;π for Index := 1 to 12*Number_Of_Years doπ Temp := Temp * (1.0 + Interest_Rate);π Payment := Original_Loan*Interest_Rate/(1.0 - 1.0/Temp);πend;ππprocedure Initialize_Data; (* ******************** initialize data *)πbeginπ Writeln(' Pascal amortization program');π Writeln;π Write('Enter amount borrowed ');π Readln(Original_Loan);π Balance := Original_Loan;π Write('Enter interest rate as percentage (i.e. 13.5) ');π Readln(Interest_Rate);π Interest_Rate := Interest_Rate/1200.0;π Write('Enter number of years of payoff ');π Readln(Number_Of_Years);π Write('Enter month of first payment (i.e. 5 for May) ');π Readln(Starting_Month);π Write('Enter year of first payment (i.e. 1994) ');π Readln(Year);π Calculate_Payment;π Annual_Accum_Interest := 0.0; (* This is to accumulate Interest *)πend;ππprocedure Print_Annual_Header; (* ************ print annual header *)πbeginπ Writeln;π Writeln;π Writeln('Original loan amount = ',Original_Loan:10:2,π ' Interest rate = ',1200.0*Interest_Rate:6:2,'%');π Writeln;π Writeln('Month payment interest princ balance');π Writeln;π Writeln(Lst);π Writeln(Lst);π Writeln(Lst,'Original loan amount = ',Original_Loan:10:2,π ' Interest rate = ',1200.0*Interest_Rate:6:2,'%');π Writeln(Lst);π Writeln(Lst,'Month payment interest princ balance');π Writeln(Lst);πend;ππprocedure Calculate_And_Print; (* ************ calculate and print *)πvar Interest_Payment : real;π Principal_Payment : real;πbeginπ if Balance > 0.0 then beginπ Interest_Payment := Interest_Rate * Balance;π Principal_Payment := Payment - Interest_Payment;π if Principal_Payment > Balance then begin (* loan payed off *)π Principal_Payment := Balance; (* this month *)π Payment := Principal_Payment + Interest_Payment;π Balance := 0.0;π endπ else begin (* regular monthly payment *)π Balance := Balance - Principal_Payment;π end;π Annual_Accum_Interest := Annual_Accum_Interest+Interest_Payment;π Writeln(Month:5,Payment:10:2,Interest_Payment:10:2,π Principal_Payment:10:2,Balance:10:2);π Writeln(Lst,Month:5,Payment:10:2,Interest_Payment:10:2,π Principal_Payment:10:2,Balance:10:2);π end; (* of if Balance > 0.0 then *)πend;ππprocedure Print_Annual_Summary; (* ********** print annual summary *)πbeginπ Writeln;π Writeln('Total interest for ',Year:5,' = ',π Annual_Accum_Interest:10:2);π Writeln;π Writeln(Lst);π Writeln(Lst,'Total interest for ',Year:5,' = ',π Annual_Accum_Interest:10:2);π Annual_Accum_Interest := 0.0;π Year := Year + 1;π Writeln(Lst);πend;ππbegin (* ******************************************* main program *)π Clrscr;π Initialize_Data;π repeatπ Print_Annual_Header;π for Month := Starting_Month to 12 do beginπ Calculate_And_Print;π end;π Print_Annual_Summary;π Starting_Month := 1;π until Balance <= 0.0;πend. (* of main program *)π 80 01-27-9417:33ALL GAYLE DAVIS English Number Strings SWAG9402 25 èo {$S-,R-,V-,I-,N-,B-,F-}ππ{π Converts REAL number to ENGLISH stringsπ GAYLE DAVIS 1/21/94π Amounts up to and including $19,999,999.99 are supported.π If you write amounts larger than that, you don't need a computer !!π ======================================================================π Dedicated to the PUBLIC DOMAIN, this software code has been tested andπ used under BP 7.0/DOS and MS-DOS 6.2.π}ππ{$IFNDEF Ver40}π {Allow overlays}π {$F+,O-,X+,A-}π{$ENDIF}ππUSES CRT;ππCONSTπ Dot : CHAR = #42;ππVARπ SS : STRING;π AA : REAL;ππFUNCTION EnglishNumber (Amt : REAL) : STRING;ππTYPEπ Mword = STRING [10];π Amstw = STRING [80]; {for function TenUnitToWord output}ππCONSTπ NumStr : ARRAY [0..27] OF Mword =π ('', 'ONE ', 'TWO ', 'THREE ', 'FOUR ', 'FIVE ', 'SIX ', 'SEVEN ',π 'EIGHT ','NINE ', 'TEN ', 'ELEVEN ', 'TWELVE ', 'THIRTEEN ',π 'FOURTEEN ', 'FIFTEEN ', 'SIXTEEN ', 'SEVENTEEN ', 'EIGHTEEN ',π 'NINETEEN ', 'TWENTY ', 'THIRTY ', 'FORTY ', 'FIFTY ', 'SIXTY ',π 'SEVENTY ', 'EIGHTY ', 'NINETY ');πVARπ S : STRING;π Temp : REAL;π DigitA, DigitB : INTEGER;π Ams : STRING;π Ac : STRING [2];ππFUNCTION TenUnitToWord (TeUn : INTEGER) : Amstw;π { convert tens and units to words }π BEGINπ IF TeUn < 21 THEN TenUnitToWord := NumStr [TeUn]π ELSE TenUnitToWord := NumStr [TeUn DIV 10 + 18] + NumStr [TeUn MOD 10];π END; {function TenUnitToWord}ππBEGINππ { Nothing bigger than 20 million }π IF (Amt > 20000000.0) OR (Amt <= 0.0) THENπ BEGINπ EnglishNumber := ''; {null string if out of range}π EXIT;π END;π { Convert 1,000,000 decade }π Ams := '';π DigitA := TRUNC (Amt / 1E6);π IF DigitA > 0 THEN Ams := Ams + NumStr [DigitA] + 'MILLION ';π Temp := Amt - DigitA * 1E6;ππ { Convert 100,000, 10,000, 1,000 decades }ππ DigitA := TRUNC (Temp / 1E5); {extract 100,000 decade}π IF DigitA > 0 THEN Ams := Ams + NumStr [DigitA] + 'HUNDRED ';π Temp := Temp - DigitA * 1E5;π DigitB := TRUNC (Temp / 1000); {extract sum of 10,000 and 1,000 decades}π Ams := Ams + TenUnitToWord (DigitB);π IF ( (DigitA > 0) OR (DigitB > 0) ) THEN Ams := Ams + 'THOUSAND ';ππ {Convert 100, 10, unit decades}ππ Temp := Temp - DigitB * 1000.0;π DigitA := TRUNC (Temp / 100); {extract 100 decade}π IF DigitA > 0 THEN Ams := Ams + NumStr [DigitA] + 'HUNDRED ';π DigitB := TRUNC (Temp - DigitA * 100.0); {extract sum of 10 and unit decades}π Ams := Ams + TenUnitToWord (DigitB);ππ {Convert cents to form XX/100}ππ IF INT (Amt) > 0.0 THEN Ams := Ams + 'AND ';π DigitA := ROUND ( (FRAC (Amt) * 100) );π IF DigitA > 0 THENπ BEGINπ STR (DigitA : 2, Ac);π IF Ac [1] = ' ' THEN Ac [1] := '0';π Ams := Ams + Ac + '/100'π ENDπ ELSE Ams := Ams + 'NO/100';ππ EnglishNumber := Ams + ' Dollars';ππEND;ππBEGINπClrScr;πWriteLn(EnglishNumber (1234.55));πWriteLn(EnglishNumber (991234.55));πWriteLn(EnglishNumber (19891234.55));πReadkey;πEND.π 81 01-27-9417:36ALL SWAG SUPPORT TEAM Info on DBASE3 Files SWAG9402 115 èo Unit dbfinfo;πinterfaceπusesπ crt;ππvarπ dbfile : file;π currentrec : longint;π dbfilename : string;π dbfileok : boolean;π dberr : integer;πππprocedure dbwrthd; {writes the header info}πprocedure disprec; {displays the record data}πprocedure dbhdrd; {reads the header info}πprocedure waitforkey; {waits for key to be hit}ππimplementationπconstπ dbmaxflds = 128; {max. number of fields }π dbmaxrecsize = 4000; {max. size of a record }πππTypeππ DBfileinfo = record { first 32 bytes of DBF }π version : byte;π year : byte;π month : byte;π day : byte;π norecord : longint;π headlen : integer;π reclen : integer;π res : array[1..20] of byte;π end;ππ DBfieldinfo = record { 32 byte field info }π name : array[1..11] of char;π ftype : byte;π addr : longint;π len : byte;π dcnt : byte;π res : array[1..14] of char;π end;ππ dbfldar = array[1..dbmaxflds] of dbfieldinfo;π dbrecar = array[1..dbmaxrecsize] of char;ππvarπ dbhead : dbfileinfo;π dbfield : dbfldar;π dbnofld : integer;π dbrecord : dbrecar;πππprocedure waitforkey;πvarπ junk : char;πbeginπ writeln;π write('Hit any key to continue');π junk := readkey;πend;πππ{ read rdbase III header info }π{ blockread error - dberr = h = 0, l = number of records read}π{ bad header - dberr - h = 1, l = version }πprocedure dbhdrd;πvarπ i : integer;πbeginπ blockread(dbfile,dbhead,32,dberr);π dbfileok := (dberr = 32);π dbnofld := (dbhead.headlen - 33) div 32;π if not dbfileok then exit;ππ if not ((dbhead.version = $83) or (dbhead.version = $03)) thenπ beginπ dbfileok := false;π dberr := dbhead.version or $100;π exit;π end;ππ for i := 1 to dbnofld doπ beginπ blockread(dbfile,dbfield[i],32,dberr);π dbfileok := (dberr = 32);π if not dbfileok then exit;π end;ππend;ππ{ writes field titles on screen }πprocedure dbwrfldtit(line : integer);πbeginπ gotoxy(1,line);π write('Field Name Type Len Dec');π gotoxy(40,line);π writeln('Field Name Type Len Dec');π write('-----------------------------------------------------------------');πend;πππ{ writes all header info to the screen }πprocedure dbwrthd;πvarπ line,j,i : integer;ππbeginπ clrscr;π gotoxy(29,1);π write('DBase file ',dbfilename);π gotoxy(1,3);π with dbhead doπ beginπ write('Last Time File Updated - ',month:2,'/',day:2,'/',year:2);π gotoxy(40,3);π write('Number of records in file - ',norecord);π gotoxy(1,4);π write('Length of each record - ',reclen);π gotoxy(40,4);π end;π write('Number of fields - ',dbnofld);π dbwrfldtit(6);π line := 8;π for i := 1 to dbnofld doπ beginπ if odd(i) then gotoxy(1,line) else gotoxy(40,line);π with dbfield[i] doπ beginπ for j := 1 to 11 do write(name[j]);π write(' ',chr(ftype),' ',len:3,' ',dcnt:3);π end;π if not odd(i) thenπ beginπ line := succ(line);π if line = 24 thenπ beginπ if i < dbnofld thenπ beginπ line := 3;π writeln;π write('More ....');π waitforkey;π clrscr;π dbwrfldtit(1);π end;π end;π end;π end;π waitforkey;πend;ππ{ read and display a DBase III record }π{ if field data is larger than one line if will be truncated }ππprocedure dbreadrec(rec : longint);πconstπ maxchar = 65; {maximum characters to display from record}πvarπ temp : longint;π i,j,stoppos,startpos,maxlen : integer;π linecnt : integer;ππbeginπ with dbhead doπ beginπ if (rec < 1) or (rec > norecord) thenπ beginπ dberr := 0;π dbfileok := false;π exit;π end;π temp := rec;π rec := (rec - 1) * reclen + headlen;π seek(dbfile,rec);π blockread(dbfile,dbrecord,reclen,dberr);π end;π clrscr;π write('DBASE file ',dbfilename,' Record No. ',temp);π if dbrecord[1] = '*' then writeln(' DELETED') else writeln;π writeln;π startpos := 2;π linecnt := 1;π for i := 1 to dbnofld doπ beginπ with dbfield[i] doπ beginπ for j := 1 to 11 do write(name[j]);π write(' -- ');π if len > maxchar then maxlen := maxcharπ else maxlen := len;π stoppos := startpos + maxlen;π for j := startpos to stoppos -1 do write(dbrecord[j]);π startpos := startpos + len;π writeln;π linecnt := succ(linecnt);π if linecnt = 22 thenπ beginπ if i < dbnofld thenπ beginπ linecnt := 1;π write('More ....');π waitforkey;π for j := 3 to 25 doπ beginπ gotoxy(1,j);π clreol;π end;π gotoxy(1,3);π end;π end;π end;π end;π waitforkey;πend;ππprocedure disprec;πvarπ rec : string;π treal : real;π error : integer;ππbeginπ repeatπ clrscr;π writeln('DBASE file -- ',dbfilename);π writeln;π write('Total records = ',dbhead.norecord);π writeln(' Current Record = ',currentrec);π writeln;π write('Enter record to display (0 = exit, cr = next, - = previous)? ');π readln(rec);π if (rec = '') or (rec[1] = '-') thenπ beginπ if rec = '' then currentrec := succ(currentrec)π elseπ currentrec := pred(currentrec);π endπ elseπ beginπ val(rec,treal,error);π if error <> 0 then treal := 0.0;π currentrec := trunc(treal);π end;π if currentrec = 0 then exit;π if currentrec < 0 then currentrec := 1;π if currentrec > dbhead.norecord then currentrec := dbhead.norecord;π dbreadrec(currentrec);π until falseππend;πbeginπend.ππ Dbase III DBF File StructureπππHeaderπ------πππ πBYTE # Type Example Descriptionπ------ ---- ------- -----------π π0 Byte 1 DBASE Versionπ (83H with DBT file)π (03H without DBT file)ππ1 Byte 2 Year - Binaryππ2 Byte 3 Month - Binaryππ3 Byte 4 Day - Binaryππ4-7 32 bit integer 5 Number of records in fileππ8-9 16 bit integer 6 Length of headerππ10-11 16 bit integer 7 Length of recordππ12-31 20 Bytes 8 Reservedππ32-n 32 Bytes Field Descriptorπ (See below)π πn+1 Byte 9 0Dh field terminatorππN+2 Byte 10 00h In some older versionsπ (The length of header byteπ reflects this if present)π.paππField Descriptorπ----------------ππBYTE # Type Example Descriptionπ------ ---- ------- -----------ππ0-10 byte 11 Field name π (Zero filled)ππ11 Byte 12 Field Typeπ (N D L C M)ππ12-15 32 bit integer 13 Field data addressπ (Internal use)ππ16 Byte 14 Field length - Binaryππ17 Byte 15 Field decimal count - Binaryππ18-31 14 bytes 16 ReservedππππField Typesπ-----------πππN Numeric - 0 1 2 3 4 5 6 7 8 . -πππD Date - 8 Bytes (YYYYMMDD)πππL Logical - Y y N n T t F f ? (? = Not initialized)πππC Character - Any Ascii CharacterπππM Memo - 10 digits (DBT block Number)ππππData Recordsπ------------πππ All data is in Ascii.πππ There is no field seperators or record terminators.ππ The first byte is a space (20h) if record not deleted and anπ asterick (2AH) if deleted.ππππDBASE Limitationsπ-----------------ππFields - 128 Max.ππRecord - 4000 bytes Max.ππHeader - 4130 bytes Max.ππ (128 Fields * 32 bytes) + 32 bytes + 1 terminator + (1 null)ππNumber - 19 digitsπππππExample Fileπ------------πππ 1 2 3 4 5 6 7 8π || || || || |---------| |---| |---| |---------- π000000 83 55 0B 0E 31 00 00 00-81 01 89 00 00 00 00 00 .U..1...........ππ ----------------------------------------------|π000010 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ππ 11 12 13π |------------------------------| || |---------| π000020 46 49 52 53 54 4E 41 4D-45 00 00 43 13 01 9D 41 FIRSTNAME..C...Aππ 14 15 16π || || |---------------------------------------|π000030 14 00 00 00 01 00 00 00-00 00 00 00 00 00 00 00 ................ππ000040 4C 41 53 54 4E 41 4D 45-00 00 00 43 27 01 9D 41 LASTNAME...C'..Aππ000050 14 00 00 00 01 00 00 00-00 00 00 00 00 00 00 00 ................ππ000060 50 48 4F 4E 45 00 00 00-00 00 00 43 3B 01 9D 41 PHONE......C;..Aππ000070 0D 00 00 00 01 00 00 00-00 00 00 00 00 00 00 00 ................ππ000080 54 52 41 56 45 4C 43 4F-44 45 00 43 48 01 9D 41 TRAVELCODE.CH..Aππ000090 04 00 00 00 01 00 00 00-00 00 00 00 00 00 00 00 ................ππ0000A0 54 52 41 56 45 4C 50 4C-41 4E 00 43 4C 01 9D 41 TRAVELPLAN.CL..Aππ0000B0 28 00 00 00 01 00 00 00-00 00 00 00 00 00 00 00 (...............ππ0000C0 44 45 50 41 52 54 55 52-45 00 00 44 74 01 9D 41 DEPARTURE..Dt..Aππ0000D0 08 00 00 00 01 00 00 00-00 00 00 00 00 00 00 00 ................ππ0000E0 43 4F 53 54 00 50 41 49-44 00 00 4E 7C 01 9D 41 COST.PAID..N|..Aππ0000F0 0A 02 00 00 01 00 00 00-00 00 00 00 00 00 00 00 ................ππ000100 50 41 49 44 00 4F 54 45-53 00 00 4C 86 01 9D 41 PAID.OTES..L...Aππ000110 01 00 00 00 01 00 00 00-00 00 00 00 00 00 00 00 ................ππ000120 41 47 45 4E 54 00 00 00-00 00 00 43 87 01 9D 41 AGENT......C...Aππ000130 02 00 00 00 01 00 00 00-00 00 00 00 00 00 00 00 ................ππ000140 52 45 53 45 52 56 44 41-54 45 00 44 89 01 9D 41 RESERVDATE.D...Aππ000150 08 00 00 00 01 00 00 00-00 00 00 00 00 00 00 00 ................ππ000160 4E 4F 54 45 53 00 00 00-00 00 00 4D 91 01 9D 41 NOTES......M...Aππ000170 0A 00 00 00 01 00 00 00-00 00 00 00 00 00 00 00 ................ππ Firstnameπ || |----------------------------------------π000180 0D 20 43 6C 61 69 72 65-20 20 20 20 20 20 20 20 . Claire π π Lastnameπ ----------------| |----------------------------π000190 20 20 20 20 20 20 42 75-63 6B 6D 61 6E 20 20 20 Buckman ππ Phoneπ ----------------------------| |----------------π0001A0 20 20 20 20 20 20 20 20-20 20 28 35 35 35 29 34 (555)4ππ T - code T - planπ -------------------| |---------| |-------------π0001B0 35 36 2D 39 30 35 39 43-49 31 30 31 30 2D 6E 69 56-9059CI1010-niππ -----------------------------------------------π0001C0 67 68 74 20 43 61 72 69-62 62 65 61 6E 20 49 73 ght Caribbean Isππ -----------------------------------------------π0001D0 6C 61 6E 64 20 43 72 75-69 73 65 20 20 20 20 20 land Cruise ππ Departure Date Costπ -------| |---------------------| |------------- π0001E0 20 20 20 31 39 38 35 31-30 32 34 20 20 20 31 31 19851024 11ππ PD Age Res. Dateπ -------------| || |---| |---------------------|π0001F0 39 39 2E 30 30 54 4D 4D-31 39 38 35 30 37 31 35 99.00TMM19850715ππ.paπ Notesπ |---------------------------|π000200 20 20 20 20 20 20 20 20-20 31 20 52 69 63 6B 20 1 Rick ππ000210 20 20 20 20 20 20 20 20-20 20 20 20 20 20 20 4C Lππ000220 69 73 62 6F 6E 6E 20 20-20 20 20 20 20 20 20 20 isbonn ππ000230 20 20 20 28 35 35 35 29-34 35 35 2D 33 33 34 34 (555)455-3344ππ000240 41 56 31 30 39 2D 6E 69-67 68 74 20 41 6C 61 73 AV109-night Alasππ000250 6B 61 2F 56 61 6E 63 6F-75 76 65 72 20 43 72 75 ka/Vancouver Cruππ000260 69 73 65 20 20 20 20 20-20 20 20 20 31 39 38 35 ise 1985ππ000270 30 38 30 35 20 20 20 31-33 37 38 2E 30 30 54 4A 0805 1378.00TJππ000280 54 31 39 38 35 30 37 31-35 20 20 20 20 20 20 20 T19850715 ππ000290 20 20 32 20 48 61 6E 6B-20 20 20 20 20 20 20 20 2 Hankππ 82 01-27-9417:36ALL MIKE COPELAND Spell a Number SWAG9402 22 èo {πFrom: MIKE COPELANDπSubj: Spell a Numberπ---------------------------------------------------------------------------π>> I'm in the process of writing a Checkbook program for my Jobπ>> and I was wondering if anyone out there has a routine toπ>> convert a check amount written in numerical to text. Here's anπ>> example of what I need. Input Variable : 142.50π>> Needed Output : One Hundred Forty Two 50/100--------------------ππ What you're looking for is "spell-a-number", and here's a programπwhich does it. Note that this one operates only on integer-type data,πand you'll have to modify it for the decimal part - but that's theπeasiest task... If you have questions, just post them here.π}πprogram Spell_A_Number; { MRCopeland 901105 }πUSES CRT;πconst C_ONES : array[1..9] of string[6] = ('one ','two ','three ','four ',π 'five ','six ','seven ','eight ','nine ');π C_TEEN : array[0..9] of string[10] = ('ten ','eleven ','twelve ',π 'thirteen ','fourteen ','fifteen ',π 'sixteen ','seventeen ','eighteen',π 'nineteen');π C_TENS : array[2..9] of string[8] = ('twenty ','thirty ','forty ',π 'fifty ','sixty ','seventy ','eighty ',π 'ninety ');πvar I,J : LongInt; { global data }ππprocedure HUNS (N : LongInt); { process a 0-999 value }πvar P : integer; { local work variable }πbeginπ P := N div 100; N := N mod 100; { any 100-900? }π if P > 0 thenπ write (C_ONES[P],'hundred ');π P := N div 10; N := N mod 10; { 10-90 }π if P > 1 then { 20-90 }π write (C_TENS[P])π elseπ if P = 1 then { 10-19 }π write (C_TEEN[N]);π if (P <> 1) and (N > 0) then { remainder of 1-9, 20-99 }π write (C_ONES[N]);πend; { HUNS }ππbegin { MAIN LINE }π ClrScr;π write ('Enter a value> '); readln (I);π if I > 0 thenπ beginπ J := I div 1000000; I := I mod 1000000;π if J > 0 then { process millions }π beginπ HUNS (J); write ('million ')π end;π J := I div 1000; I := I mod 1000;π if J > 0 then { process thousands }π beginπ HUNS (J); write ('thousand ')π end;π HUNS (I) { process 0-999 remainder }π end { if }πend.π 83 01-27-9417:36ALL WAYNE MOSES Checkbook Number SWAG9402 45 èo {πFrom: WAYNE MOSESπSubj: Spell a Numberπ---------------------------------------------------------------------------π *> Quoting Chris Serino to All on 01-04-94 17:28π *> Re: Help Looking for a Numberππ Hello Chris:ππ CS> I'm in the process of writing a Checkbook program for my Job and Iπ CS> was wondering if anyone out there has a routine to convert a checkπ CS> amount written in numerical to text. Here's an example of what Iπ CS> need. Input Variable : 142.50π CS> Needed Output : One Hundred Foury Two 50/100--------------------ππ Weeeelllll ... since I am not really interested in releasing my personalπ check writing program to the world, I'll upload what I wrote last month.ππ ------- 8< ------------[ CUT LINE ]-------------- >8 -------π}πFunction Translate(var DollarAmt : real) : string;ππ(*π This is a module that converts the numerical dollar amount to a string,π for example it converts $156.15 to :ππ 'One Hundred and Fifty Six dollars ------------15/xx'.ππ The field length of the translated amount is limited to 53 characters.ππ Amounts up to and including $99,999.99 are supported. I rarely writeπ cheques larger than that, so they can be written by hand. ;-)ππ ======================================================================π Dedicated to the PUBLIC DOMAIN, this software code has been tested andπ used under TP 6.0/DOS and MS-DOS 6.2.π ======================================================================π*)ππconstπ SingleSpelled : array[1..9] of string = ('One ','Two ','Three ','Four ',π 'Five ','Six ','Seven ','Eight ',π 'Nine ');ππ TeenSpelled : array[1..9] of string = ('Eleven ','Twelve ','Thirteen ',π 'Fourteen ','Fifteen ','Sixteen ',π 'Seventeen ','Eighteen ','Nineteen');ππ TenSpelled : array[1..9] of string = ('Ten ','Twenty ','Thirty ','Forty ',π 'Fifty ','Sixty ','Seventy ','Eighty',π 'Ninety ');ππvarπ Dollars, Cents,π SingleStr, TenStr, HundredStr, ThousandStr : string;π Singles, Tens, Hundreds, Thousands, k, l : integer;ππbeginπ if DollarAmt = 0 then (* The amount to be translated is 0.00 *)π begin (* so the Dollars and Cents must be *)π Dollars := 'Zero '; (* to reflect this. *)π Cents := '00';π endππ elseπ begin (* Non trivial value for DollarAmt *)ππ SingleStr := ''; TenStr := ''; HundredStr := ''; ThousandStr := '';ππ { Parse the Cents out of DollarAmt }ππ Str(frac(DollarAmt):0:2, Cents);π if frac(DollarAmt) > 0 thenπ Cents := copy(Cents,pos('.',Cents)+1,2)π elseπ Cents := '00';ππ { Next parse the Dollars out of DollarAmt }ππ Str(int(DollarAmt):1:0, Dollars);ππ { Now, define the number of Singles, Tens, Hundreds, and Thousands }ππ Thousands := trunc(DollarAmt/1000);ππ Hundreds := trunc(DollarAmt/100)-Thousands*10;π HundredStr := SingleSpelled[Hundreds];ππ Tens := trunc(DollarAmt/10)-(Thousands*100+Hundreds*10);ππ Singles := trunc(DollarAmt)-(Thousands*1000+Hundreds*100+Tens*10);π SingleStr := SingleSpelled[Singles];ππ case Tens ofπ 1 : beginπ TenStr := TeenSpelled[Singles];π SingleStr := '';π end;π 2..9 : TenStr := TenSpelled[Tens];π end;ππ case Thousands ofπ 10,20,π 30,50,π 60,70,π 80,90 : ThousandStr := TenSpelled[trunc(Thousands/10)];π 1..9 : ThousandStr := SingleSpelled[Thousands];π 11..19 : ThousandStr := TeenSpelled[Thousands-10];ππ 21..29 : ThousandStr := TenSpelled[trunc(Thousands/10)]+π SingleSpelled[Thousands-20];π 31..39 : ThousandStr := TenSpelled[trunc(Thousands/10)]+π SingleSpelled[Thousands-30];π 41..49 : ThousandStr := TenSpelled[trunc(Thousands/10)]+π SingleSpelled[Thousands-40];π 51..59 : ThousandStr := TenSpelled[trunc(Thousands/10)]+π SingleSpelled[Thousands-50];π 61..69 : ThousandStr := TenSpelled[trunc(Thousands/10)]+π SingleSpelled[Thousands-60];π 71..79 : ThousandStr := TenSpelled[trunc(Thousands/10)]+π SingleSpelled[Thousands-70];π 81..89 : ThousandStr := TenSpelled[trunc(Thousands/10)]+π SingleSpelled[Thousands-80];π 91..99 : ThousandStr := TenSpelled[trunc(Thousands/10)]+π SingleSpelled[Thousands-90];π end;ππ if Thousands > 0 thenπ Dollars := ThousandStr+'Thousand '+HundredStr+'Hundred & 'π + TenStr + SingleStrπ elseπ if (Hundreds > 0) and (Thousands = 0) thenπ Dollars := HundredStr+'Hundred and '+ TenStr + SingleStrπ elseπ Dollars := TenStr + SingleStr;ππ end; (* End of block for non-trivial *)π (* value for DollarAmt *)π l := length(Dollars);ππ for k := 1 to 60-(10+l+length(Cents)) doπ Dollars := Dollars+'-';ππ If Thousands < 100 thenπ Translate := Dollars+Cents+'/xx'π elseπ beginπ TextColor(Yellow+Blink);π Translate := '******** INVALID! THIS AMOUNT NOT SUPPORTED ********';π end;πend;π 84 01-28-9408:55ALL BJORN FELTEN Simulate Phone Ringing SWAG9402 10 èo {π > I stumbled across the correct sequenceππ Well, why don't we let some more people stumble in on our little secret? :)ππSomething like this might do the trick. The brute delay code 'asm hlt end',πthat simply waits for the next interrupt (should be the timer IRQ) to occur,πmay not work on some machines -- especially when running some multitaskers.πIf so it can be changed to 'delay(50)' or something like that.π}ππprogram Ring;πuses crt;πvar i:word;πbeginπ for i:=0 to 6 doπ beginπ sound(523); asm hlt end;π Delay(50);π sound(659); asm hlt end;π Delay(50);π end;π nosoundπend.ππ{ Or, for those of you that don't like the crt unit, here's the same thing inπ BASM: }ππprogram Ring;πbeginπ asmπ mov al,0B6hπ out 43h,alπ in al,61hπ or al,3π out 61h,alπ mov cx,7π mov dx,42hπ@the_loop:π mov al,0E9hπ out dx,alπ mov al,8π out dx,alπ hltπ mov al,12hπ out dx,alπ mov al,7π out dx,alπ hltπ loop @the_loopπ in al,61hπ and al,0FChπ out 61h,alπ end;πend.ππ 85 02-03-9409:17ALL SCOTT R. HOUCK Write BANNERS SWAG9402 93 èo Program BannerC;ππ{$V-}ππ{ Written by Scott R. Houckππ This program produces banners which can be sent to the screenπ or to a file. If sent to a file, the output may be appended toπ to an existing file if desired.ππ The syntax is as follows:ππ BANNER [/B=banner] [/I=infile] [/O=outfile [/A]] [/C=char]ππ whereππ banner = a character string of maximum length 10π infile = an input file containing the banner(s)π outfile = an output file to which the banner(s) will be writtenπ char = character to be used in printing the bannerπ (default = the character being printed)ππ /A = append to file if it already existsπππ NOTES:ππ 1. Options may be specified in any order, but there must beπ at least one space between each one. Do not put spacesπ on either side of the equals sign.ππ 2. You may use PRN for the filename if you want to send theπ output to the printer. If you choose to do this, do notπ use the /A option.ππ 3. To indicate a space in the banner when using the /B option, useπ the carat symbol (^). Example: BANNER /O=DISKFILE /B=JOHN^DOEπ However, this is not necessary if you are using the /I option.ππ 4. Valid characters are 0-9, A-Z, and !"#$%&'()*+,-./:;<=>?@[\]π Any other characters will be printed as a space.ππ 6. All lower case letters are converted to upper case.ππ 7. Three blank lines are written before the banner is output.ππ 8. Note that /B and /I are mutually exclusive and will produce aπ syntax error if used together.ππ 9. If all options are omitted or if the command line does not containπ either /B or /I, the command syntax is printed.ππ 10. /A will produce a syntax error if used without /O.ππ 11. You may not use < or > with the /B option because DOS wouldπ interpret it as redirection of standard input and output.ππ}ππUSES DOS,CRT;ππTypeπ str13 = string[13];π str80 = string[80];π char_pattern = array[1..10] of integer;ππConstπ bit_value: array[1..10] of integer = (1,2,4,8,16,32,64,128,256,512);ππ char_def: array[#32..#94] of char_pattern = (ππ {32:' '} ($000,$000,$000,$000,$000,$000,$000,$000,$000,$000),π {33:'!'} ($030,$078,$0FC,$0FC,$078,$078,$030,$000,$030,$030),π {34:'"'} ($1CE,$1CE,$1CE,$1CE,$000,$000,$000,$000,$000,$000), π {35:'#'} ($0CC,$0CC,$0CC,$3FF,$0CC,$0CC,$3FF,$0CC,$0CC,$0CC), π {36:'$'} ($030,$1FE,$3FF,$330,$3FF,$1FF,$033,$3FF,$1FE,$030),π {37:'%'} ($1C3,$366,$36C,$1D8,$030,$060,$0CE,$19B,$31B,$20E),π {38:'&'} ($1E0,$330,$330,$1C0,$1E0,$331,$31A,$31C,$1FA,$0E1), π {39:'''} ($070,$0F8,$078,$010,$020,$000,$000,$000,$000,$000),π {40:'('} ($004,$018,$030,$060,$060,$060,$060,$030,$018,$004),π {41:')'} ($080,$060,$030,$018,$018,$018,$018,$030,$060,$080),π {42:'*'} ($000,$000,$000,$084,$048,$2FD,$048,$084,$000,$000),π {43:'+'} ($000,$000,$078,$078,$3FF,$3FF,$078,$078,$000,$000),π {44:','} ($000,$000,$000,$000,$000,$070,$0F8,$078,$010,$020),π {45:'-'} ($000,$000,$000,$000,$3FF,$3FF,$000,$000,$000,$000), π {46:'.'} ($000,$000,$000,$000,$000,$000,$000,$078,$0FC,$078),π {47:'/'} ($001,$003,$006,$00C,$018,$030,$060,$0C0,$180,$100),π {48:'0'} ($078,$0FC,$186,$303,$303,$303,$303,$186,$0FC,$078),π {49:'1'} ($030,$0F0,$0B0,$030,$030,$030,$030,$030,$3FF,$3FF),π {50:'2'} ($1FE,$3FF,$203,$003,$003,$018,$060,$0C0,$3FF,$3FF),π {51:'3'} ($3FF,$3FE,$00C,$018,$038,$00E,$006,$203,$3FF,$1FE),π {52:'4'} ($01C,$03C,$06C,$0CC,$18C,$3FF,$3FF,$00C,$00C,$00C),π {53:'5'} ($3FF,$3FF,$300,$300,$3FE,$3FF,$003,$203,$3FF,$1FE),π {54:'6'} ($1FE,$3FF,$301,$300,$3FE,$3FF,$303,$303,$3FF,$1FE),π {55:'7'} ($3FF,$3FF,$006,$00C,$018,$030,$060,$0C0,$300,$300),π {56:'8'} ($1FE,$3FF,$303,$303,$1FE,$1FE,$303,$303,$3FF,$1FE),π {57:'9'} ($1FE,$3FF,$303,$303,$3FF,$1FF,$003,$003,$3FF,$1FE),π {58:':'} ($000,$000,$000,$078,$0FC,$078,$000,$078,$0FC,$078),π {59:';'} ($000,$038,$07C,$038,$000,$038,$07C,$03C,$004,$008),π {60:'<'} ($000,$000,$003,$00C,$030,$0C0,$030,$00C,$003,$000),π {61:'='} ($000,$000,$000,$3FF,$3FF,$000,$3FF,$3FF,$000,$000),π {62:'>'} ($000,$000,$0C0,$030,$00C,$003,$00C,$030,$0C0,$000),π {63:'?'} ($1FE,$3FF,$303,$006,$00C,$018,$018,$000,$018,$018), π {64:'@'} ($1FE,$303,$33B,$36B,$363,$363,$366,$37C,$300,$1FE), π {65:'A'} ($1FE,$3FF,$303,$303,$303,$3FF,$3FF,$303,$303,$303),π {66:'B'} ($3FE,$3FF,$303,$303,$3FE,$3FE,$303,$303,$3FF,$3FE),π {67:'C'} ($1FE,$3FF,$301,$300,$300,$300,$300,$301,$3FF,$1FE),π {68:'D'} ($3FE,$3FF,$303,$303,$303,$303,$303,$303,$3FF,$3FE),π {69:'E'} ($3FF,$3FF,$300,$300,$3E0,$3E0,$300,$300,$3FF,$3FF),π {70:'F'} ($3FF,$3FF,$300,$300,$3E0,$3E0,$300,$300,$300,$300),π {71:'G'} ($1FE,$3FF,$300,$300,$31F,$31F,$303,$303,$3FF,$1FF),π {72:'H'} ($303,$303,$303,$303,$3FF,$3FF,$303,$303,$303,$303),π {73:'I'} ($3FF,$3FF,$030,$030,$030,$030,$030,$030,$3FF,$3FF),π {74:'J'} ($0FF,$0FF,$018,$018,$018,$018,$318,$318,$3F8,$1F0),π {75:'K'} ($303,$306,$318,$360,$3E0,$330,$318,$30C,$306,$303),π {76:'L'} ($300,$300,$300,$300,$300,$300,$300,$300,$3FF,$3FF),π {77:'M'} ($303,$3CF,$37B,$333,$333,$303,$303,$303,$303,$303),π {78:'N'} ($303,$383,$343,$363,$333,$333,$31B,$30B,$307,$303),π {79:'O'} ($1FE,$3FF,$303,$303,$303,$303,$303,$303,$3FF,$1FE),π {80:'P'} ($3FE,$3FF,$303,$303,$3FF,$3FE,$300,$300,$300,$300),π {81:'Q'} ($1FE,$3FF,$303,$303,$303,$303,$33B,$30F,$3FE,$1FB),π {82:'R'} ($3FE,$3FF,$303,$303,$3FF,$3FE,$318,$30C,$306,$303),π {83:'S'} ($1FE,$3FF,$301,$300,$3FE,$1FF,$003,$203,$3FF,$1FE),π {84:'T'} ($3FF,$3FF,$030,$030,$030,$030,$030,$030,$030,$030),π {85:'U'} ($303,$303,$303,$303,$303,$303,$303,$303,$3FF,$1FE),π {86:'V'} ($303,$303,$186,$186,$186,$186,$0CC,$0CC,$078,$030),π {87:'W'} ($303,$303,$303,$303,$333,$333,$333,$37B,$1CE,$186),π {88:'X'} ($303,$186,$0CC,$078,$030,$078,$0CC,$186,$303,$303),π {89:'Y'} ($303,$186,$0CC,$078,$030,$030,$030,$030,$030,$030),π {90:'Z'} ($3FF,$3FE,$00C,$018,$030,$030,$060,$0C0,$1FF,$3FF),π {91:'['} ($0FE,$0FE,$0C0,$0C0,$0C0,$0C0,$0C0,$0C0,$0FE,$0FE),π {92:'\'} ($200,$300,$180,$0C0,$060,$030,$018,$00C,$006,$002),π {93:']'} ($0FE,$0FE,$006,$006,$006,$006,$006,$006,$0FE,$0FE),π {94:'^'} ($000,$000,$000,$000,$000,$000,$000,$000,$000,$000) );ππVarπ character: char;π banner: str13;π Param: array[1..4] of str80;π InfileName, OutfileName: str80;π Infile, Outfile: text;π Slash_A, Slash_B, Slash_C, Slash_I, Slash_O: boolean;ππ{----------------------------------------------------------------------}ππProcedure Beep;ππbeginπ Sound(350);π Delay(300);π NoSound;πend;ππ{----------------------------------------------------------------------}ππProcedure UpperCase(var AnyStr: str80);ππvarπ i: integer;ππbeginπ For i := 1 to length(AnyStr) do AnyStr[i] := UpCase(AnyStr[i]);πend;ππ{----------------------------------------------------------------------}ππFunction Exist(filename: str80): boolean;ππvarπ tempfile: file;ππbeginπ Assign(tempfile,filename);π {$I-}π Reset(tempfile);π {$I+}π Exist := (IOresult = 0);π Close(tempfile);πend;ππ{----------------------------------------------------------------------}ππProcedure Print_Syntax;ππbeginπ Writeln('The syntax is as follows:'^J);π Writeln(' BANNER [/B=banner] [/I=infile] [/O=outfile [/A]] ',π '[/C=char]'^J);π Writeln('where'^J);π Writeln(' banner = character string of maximum length 10');π Writeln(' infile = input file containing banner text');π Writeln(' outfile = output file to which the banner(s) will be ',π 'written');π Writeln(' char = character to be used in printing the banner');π Writeln(' (default = the character being printed)'^J);π Writeln(' /A = append to file if it already exists'^J);π Writeln('Note that /B and /I are mutually exclusive.');π Writeln('Use a carat (^) for a space if using /B.');π Writeln('Valid characters are 0-9, A-Z, and ',π '!"#$%&''()*+,-./:;<=>?@[\]');πend;ππ{----------------------------------------------------------------------}ππProcedure Parse;ππvarπ n, b, c, i, o: integer;π ch1, ch2, ch3: char;ππ {*} procedure Error;π beginπ Beep;π Print_Syntax;π Halt;π end;ππbegin { Parse }ππ Slash_A := false;π Slash_B := false; b := 0;π Slash_C := false; c := 0;π Slash_I := false; i := 0;π Slash_O := false; o := 0;ππ If ParamCount = 0 thenπ beginπ Print_Syntax;π Halt;π end;ππ If ParamCount > 4 then Error;ππ For n := 1 to ParamCount doπ beginπ Param[n] := ParamStr(n);π UpperCase(Param[n]);π ch1 := Param[n][1];π ch2 := Param[n][2];π ch3 := Param[n][3];π If (ch1 <> '/') or not (ch2 in ['A','B','C','I','O']) then Error;π If ch2 = 'A' thenπ Slash_A := true;π If ch2 = 'B' thenπ beginπ Slash_B := true;π b := n;π end;π If ch2 = 'C' thenπ beginπ Slash_C := true;π c := n;π end;π If ch2 = 'I' thenπ beginπ Slash_I := true;π i := n;π end;π If ch2 = 'O' thenπ beginπ Slash_O := true;π o := n;π end;π If (ch2 in ['B','C','I','O']) and (ch3 <> '=') then Error;π If (ch2 = 'A') and (length(ch2) > 2) then Error;π end;ππ If Slash_B and Slash_I then Error;π If not Slash_B and not Slash_I then Error;π If Slash_A and not Slash_O then Error;π If Slash_B thenπ beginπ banner := Param[b];π Delete(banner,1,3);π end;π If Slash_C then character := Param[c][4];π If Slash_I thenπ beginπ InfileName := Param[i];π Delete(InfileName,1,3);π end;π If Slash_O thenπ beginπ OutfileName := Param[o];π Delete(OutfileName,1,3);π end;ππend;ππ{----------------------------------------------------------------------}ππProcedure Heading(message: str13);ππvarπ i, j, k: integer;ππbeginππ If Slash_Oπ then Writeln(Outfile,^M^J^M^J^M^J)π else Writeln(^J^J^J);ππ For i := 1 to 10 doπ beginπ For j := 1 to length(message) doπ beginπ If not (message[j] in [#32..#94]) then message[j] := #32;π For k := 10 downto 1 doπ If char_def[message[j],i] and bit_value[k] = bit_value[k]π thenπ beginπ If not Slash_C then character := message[j];π If Slash_Oπ then Write(Outfile,character)π else Write(character);π endπ elseπ beginπ If Slash_Oπ then Write(Outfile,' ')π else Write(' ');π end;π If Slash_Oπ then Write(Outfile,' ')π else Write(' ');π end;π If Slash_Oπ then Writeln(Outfile)π else Writeln;π end;ππend;ππ{----------------------------------------------------------------------}ππBegin { Banner }ππ Parse;ππ If Slash_O thenπ beginπ Assign(Outfile,OutfileName);π If Slash_A and Exist(OutfileName)π then Append(Outfile)π else Rewrite(Outfile);π end;ππ If Slash_I thenπ beginπ Assign(Infile,InfileName);π Reset(Infile);π While not Eof(Infile) doπ beginπ Readln(Infile,banner);π UpperCase(banner);π Heading(banner);π end;π Close(Infile);π endππ else Heading(banner);ππ If Slash_O then Close(Outfile);ππEnd.π 86 02-03-9409:59ALL SWAG SUPPORT TEAM Accessing DBASE3 Files SWAG9402 76 èo unit dbaseiii;π{ unit including procedures for accessing DBaseIII files}ππinterfaceππuses Crt;ππProcedure OpenDBFData;πProcedure OpenDBFMemo;πProcedure ReadDBFRecord(I : Longint);πProcedure WriteDBFRecord;πProcedure ReadDBFMemo(BlockNumber : integer);πProcedure WriteDBFMemo(var BlockNumberString : string);πProcedure CloseDBFData;πProcedure CloseDBFMemo;ππconstπ DBFMaxRecordLength = 4096;π DBFMemoBlockLength = 512;π DBFMaxMemoLength = 4096;ππtypeπ DBFHeaderRec = Recordπ HeadType : byte;π Year : byte;π Month : byte;π Day : byte;π RecordCount : longint;π HeaderLength : integer;π RecordSize : integer;π Garbage : array[1..20] of byte;π end;ππtypeπ DBFFieldRec = Recordπ FieldName : array[1..11] of char;π FieldType : char;π Spare1,π Spare2 : integer;π Width : byte;π Dec : byte;π WorkSpace : array[1..14] of byte;π end;ππvarπ DBFFileName : string;ππ DBFDataFile : File;π DBFDataFileAvailable : boolean;π DBFBuffer : array [1..DBFMaxRecordLength] of char;ππ DBFHeading : DBFHeaderRec;ππ DBFField : DBFFieldRec;π DBFFieldCount : integer;π DBFFieldContent : array [1..128] of string;ππ DBFNames : array [1..128] of string[10];π DBFLengths : array [1..128] of byte;π DBFTypes : array [1..128] of char;π DBFDecimals : array [1..128] of byte;π DBFContentStart : array [1..128] of integer;ππ DBFMemoFile : File;π DBFMemoFileAvailable : boolean;π DBFMemoBuffer : Array [1..DBFMemoBlockLength] of byte;π DBFMemo : Array [1..DBFMaxMemoLength] of char;ππ DBFMemoLength : integer;π DBFMemoEnd : boolean;π DBFMemoBlock : integer;ππ DBFDeleteField : char;π DBFFieldStart : integer;ππ DBFRecordNumber : longint;ππ(****************************************************************)ππimplementationππ(****************************************************************)ππProcedure ReadDBFHeader;ππvarπ RecordsRead : integer;ππbeginπ BlockRead (DBFDataFile, DBFHeading, SizeOf(DBFHeading), RecordsRead);πend;ππ(*****************************************************************)ππProcedure ProcessField (F : DBFFieldRec;π I : integer);πvarπ J : integer;ππbeginπ with F doπ beginπ DBFNames [I] := '';π J := 1;π while (J<11) and (FieldName[J] <> #0) doπ beginπ DBFNames[I] := DBFNames[I] + FieldName [J];π J := J + 1;π end;π DBFLengths [I] := Width;π DBFTypes [I] := FieldType;π DBFDecimals [I] := Dec;π DBFContentStart [I] := DBFFieldStart;π DBFFieldStart := DBFFieldStart + Width;π end;πend;ππ(***************************************************************)ππProcedure ReadFields;ππvarπ I : integer;π RecordsRead : integer;ππbeginπ Seek(DBFDataFile,32);π I := 1;π DBFFieldStart := 2;π DBFField.FieldName[1] := ' ';π while (DBFField.FieldName[1] <> #13) doπ beginπ BlockRead(DBFDataFile,DBFField.FieldName[1],1);π if (DBFField.FieldName[1] <> #13) thenπ beginπ BlockRead(DBFDataFile, DBFField.FieldName[2],SizeOf(DBFField) - 1, RecordsRead);π ProcessField (DBFField, I);π I := I + 1;π end;π end;π DBFFieldCount := I - 1;πend;ππ(***********************************************************)ππProcedure OpenDBFData;ππbeginπ DBFDataFileAvailable := false;π Assign(DBFDataFile, DBFFileName+'.DBF');ππ{$I-}π Reset(DBFDataFile,1);π If IOResult<>0 then exit;π{$I+}ππ DBFDataFileAvailable := true;π Seek(DBFDataFile,0);π ReadDBFHeader;π ReadFields;πend;ππ(******************************************************************)ππProcedure CloseDBFData;ππbeginπ if DBFDataFileAvailable then Close(DBFDataFile);πend;ππ(*******************************************************************)ππProcedure OpenDBFMemo;ππbeginπ DBFMemoFileAvailable := false;π Assign(DBFMemoFile, DBFFileName+'.DBT');ππ{$I-}π Reset(DBFMemoFile,1);π If IOResult<>0 then exit;π{$I+}ππ DBFMemoFileAvailable := true;π Seek(DBFMemoFile,0);πend;ππ(*******************************************************************)ππProcedure CloseDBFMemo;ππbeginπ If DBFMemoFileAvailable then close(DBFMemoFile);πend;ππ(*******************************************************************)ππProcedure GetDBFFields;ππvarπ I : byte;π J : integer;π Response : string;ππbeginπ DBFDeleteField := DBFBuffer[1];π For I:=1 to DBFFieldCount doπ beginπ DBFFieldContent[I] := '';π For J := DBFContentStart[I] to DBFContentStart [I] + DBFLengths[I] -1 doπ DBFFieldContent[I] := DBFFieldContent[I] + DBFBuffer[J];π For J := 1 to DBFLengths[I] doπ if DBFFieldContent[J]=#0 then DBFFieldContent[J]:=#32;π end;πend;ππ(***********************************************************************)ππProcedure ReadDBFRecord (I : Longint);ππvarπ RecordsRead : integer;ππbeginπ Seek(DBFDataFile, DBFHeading.HeaderLength + DBFHeading.RecordSize * (I - 1));π BlockRead (DBFDataFile, DBFBuffer, DBFHeading.RecordSize, RecordsRead);π GetDBFFields;πend;ππ(**********************************************************************)ππProcedure ReadDBFMemo(BlockNumber : integer);ππvarπ I : integer;π RecordsRead : word;ππbeginπ DBFMemoLength := 0;π DBFMemoEnd := false;π If not DBFMemoFileAvailable thenπ beginπ DBFMemoEnd := true;π exit;π end;π FillChar(DBFMemo[1],DBFMaxMemoLength,#0);π Seek(DBFMemoFile,BlockNumber*DBFMemoBlockLength);π repeatπ BlockRead(DBFMemoFile,DBFMemoBuffer,DBFMemoBlockLength,RecordsRead);π For I := 1 to RecordsRead doπ beginπ DBFMemoLength := DBFMemoLength + 1;π DBFMemo[DBFMemoLength] := chr(DBFMemoBuffer[I] and $7F);π If (DBFMemoBuffer[I] = $1A) or (DBFMemoBuffer[I] = $00) thenπ beginπ DBFMemoEnd := true;π DBFMemoLength := DBFMemoLength - 1;π exit;π end;π end;π until DBFMemoEnd;πend;ππ(*********************************************************************)ππProcedure WriteDBFMemo {(var BlockNumberString : string)};ππvarπ K : integer;π ReturnCode : integer;ππbeginπ Val(BlockNumberString,DBFMemoBlock,ReturnCode);π If ReturnCode>0 then DBFMemoBlock := 0;π If DBFMemoBlock>0 thenπ beginπ Writeln;π ReadDBFMemo(DBFMemoBlock);π If DBFMemoLength=0 then exit;π For K := 1 to DBFMemoLength doπ Write(DBFMemo[K]);π WriteLn;π end;πend;ππ(****************************************************************)ππProcedure WriteDBFRecord;ππvarπ J : byte;ππbeginπ For J := 1 to DBFFieldCount doπ beginπ Write(DBFNames[J]);π GoToXY(12,J);π WriteLn(DBFFieldContent[J]);π if DBFTypes[J]='M' then WriteDBFMemo(DBFFieldContent[J]);π end;πend;ππ(*******************************************************************)ππbeginπend.π 87 02-03-9410:57ALL WIM VAN DER VEGT Fuzzy logic unit (German)SWAG9402 151 èo {π---------------------------------------------------------------------------πKW>WV>Got some german pascal code on this subject. It seems to implement aπ > >.... (Bit large to send if nobody's interested).ππKW>Can you extract the specifically fuzzy logic parts?π >---πNo (didnt know where to look, how doesfuzzy pascal look :-) ) so here'sπthe complete program taken from a german magazineπ}ππUNIT Fuzzy;πINTERFACEππUses Graph,Crt,Dos;ππCONSTπ Infinity = 1.7e38;π NoRules = NIL;π ValueCol = LightMagenta;ππTYPEπ NameStr = String[20];π (* verschiedene Operatortypen *)π Inference = FUNCTION(Set1,Set2,Set3:Real):real;ππ FuzzySetList = ^FuzzySet;π FuzzyVarList = ^FuzzyVar;π FuzzyRuleList = ^FuzzyRule;ππ FuzzySet = Objectπ SetName : NameStr; (* Mengenbenzeichner *)π StartAt, (* Startwert *)π HighAt, (* Maximum bei ... *)π EndAt : Real; (* Endwert *)π Next : FuzzySetList;π Color : Byte;π MemberShip : Real; (* aktueller Wert der *)π (* Zugehörigkeit *)π Rules : FuzzyRuleList; (* Regelliste für diese *)π (* unscharfe Menge *)π Constructor Init( InitName : NameStr;π InitStart, InitHigh,π InitEnd : Real;π InitColor: Byte);π PROCEDURE Append( InitName : NameStr;π InitStart, InitHigh,π InitEnd : Real;π InitColor: Byte);π FUNCTION GetMemberShip(LingVal : Real):Real;π PROCEDURE DefineRule( InfType : Inference;π Var1 : FuzzyVarList;π SetName1: NameStr;π Var2 : FuzzyVarList;π SetName2: NameStr);π END;ππ FuzzyVar = Objectπ VarName : NameStr; (* Variablenname *)π PosX,PosY : WORD; (* Bildschirmkoordinaten*)π StartValue, (* Anfang und Ende des *)π EndValue, (* Koordinatensystems *)π Scale : Real; (* Maßstabsfaktor *)π UnitStr : NameStr; (* Einheit, z.B. °C *)π CurrentVal: Real; (* aktueller Wert *)π FuzzySets : FuzzySetList; (* Liste der unscharfen *)π (* Mengen *)π Result,BackGround :π ARRAY[1..5] OF PointType;π Constructor Init( InitName : NameStr;π InitX,InitY : WORD;π Sections : Byte;π InitStart,InitEnd,π InitValue : Real;π InitUnit : NameStr);π PROCEDURE CoordSystem(Sections : Byte);π FUNCTION RealToCoord(r:Real):WORD;π PROCEDURE DisplaySets;π PROCEDURE DisplayValue(TextColor:WORD);π PROCEDURE DisplayResultSets;π PROCEDURE Change(Diff : Real);π FUNCTION GetMemberShipOf(Name : NameStr):Real;π PROCEDURE Infer;π PROCEDURE DeFuzzy;π PROCEDURE DefineSet( InitName : NameStr;π InitStart, InitHigh,π InitEnd : Real;π InitColor: Byte);π PROCEDURE DefineRule(SetName : NameStr;π InfType : Inference;π Var1 : FuzzyVarList;π SetName1 : NameStr;π Var2 : FuzzyVarList;π SetName2 : NameStr);π END;ππ FuzzyRule = Objectπ Inf_Type : Inference; (* Operatortyp *)π Var1, Var2 : FuzzyVarList; (* Eingangsvariablen *)π SetName1, SetName2 : NameStr; (* Eingangsmengen *)π Next : FuzzyRuleList;π Constructor Init( InitInf : Inference;π InitVar1 : FuzzyVarList;π InitName1 : NameStr;π InitVar2 : FuzzyVarList;π InitName2 : NameStr);π PROCEDURE Append( InitInf : Inference;π InitVar1 : FuzzyVarList;π InitName1 : NameStr;π InitVar2 : FuzzyVarList;π InitName2 : NameStr);π FUNCTION Infer(HomeSetValue:Real):Real;π END;ππProcedure Buzz;πprocedure error(message : string);ππfunction Max( A, B: Real ): Real;πfunction Min( A, B: Real ): Real;ππFUNCTION AND_MaxMin(Set1,Set2,Set3:Real):Real;πFUNCTION OR_MaxMax(Set1,Set2,Set3:Real):Real;ππVARπ DisplayOn : BOOLEAN; (* Anzeige der unscharfen Mengen ein/aus *)π Regs : Registers;π ResultCol : WORD;ππImplementationππCONST OffSet = 20;ππVAR Buffer : String;ππPROCEDURE Buzz;πBEGIN sound(30); Delay(100); NoSound; END;ππprocedure error(message : string);πbeginπ CloseGraph; writeln(message); haltπend;ππfunction Max( A, B: Real ): Real;πbeginπ if A < B then Max := B else Max := A;πend;ππfunction Min( A, B: Real ): Real;πbeginπ if A > B then Min := B else Min := A;πend;ππ(* MaxMin-Operator für UND *)πFUNCTION AND_MaxMin(Set1,Set2,Set3:Real):Real;πBEGINπ AND_MaxMin:=Max(Set1,Min(Set2,Set3))πEND;ππ(* MaxMax-Operator für ODER *)πFUNCTION OR_MaxMax(Set1,Set2,Set3:Real):Real;πBEGINπ OR_MaxMax:=Max(Set1,Max(Set2,Set3))πEND;ππCONSTRUCTOR FuzzySet.Init;ππBEGINπ SetName := InitName;π StartAt := InitStart;π HighAt := InitHigh;π EndAt := InitEnd;π Color := InitColor;π Next := NIL;π Rules:= NoRules;π MemberShip := 0;πEND;ππPROCEDURE FuzzySet.Append;πBEGINπ IF Next=NILπ THEN New(Next,Init(InitName,InitStart,InitHigh,InitEnd,InitColor))π ELSE Next^.Append(InitName,InitStart,InitHigh,InitEnd,InitColor)πEND;ππFUNCTION FuzzySet.GetMemberShip;πBEGINπ IF (LingVal<=StartAt) THEN GetMemberShip:=0π ELSE IF (LingVal>=EndAt) THEN GetMemberShip:=0π ELSEπ BEGINπ IF ((StartAt=-Infinity) AND (LingVal<=HighAt))π OR ((EndAt=Infinity) AND (LingVal>=HighAt)) THEN GetMemberShip:=1π ELSE IF (LingVal<=HighAt)π THEN GetMemberShip:=(LingVal-StartAt)/(HighAt-StartAt)π ELSE GetMemberShip:=1-(LingVal-HighAt)/(EndAt-HighAt)π ENDπEND;ππPROCEDURE FuzzySet.DefineRule;πBEGINπ IF Rules=NoRules THENπ Rules:= new(FuzzyRuleList,π Init(InfType,Var1,SetName1,Var2,SetName2))π ELSE Rules^.Append(InfType,Var1,SetName1,Var2,SetName2)πEND;ππCONSTRUCTOR FuzzyVar.Init;πBEGINπ VarName:=InitName;π PosX:=InitX;π PosY:=InitY;π StartValue:=InitStart;π EndValue :=InitEnd;π Scale :=210/(EndValue-StartValue);π UnitStr :=InitUnit;π CurrentVal:=InitValue;π CoordSystem(Sections);π FuzzySets :=NIL;π BackGround[1].x:=PosX+1; BackGround[1].y:=PosY+100;π BackGround[2].x:=PosX+1; BackGround[2].y:=PosY+20;π BackGround[3].x:=PosX+250; BackGround[3].y:=PosY+20;π BackGround[4].x:=PosX+250; BackGround[4].y:=PosY+100;π BackGround[5]:=BackGround[1];πEND;ππFUNCTION FuzzyVar.RealToCoord(r:Real):WORD;πBEGINπ RealToCoord:=PosX+OffSet+Round((r-StartValue)*Scale);πEND;ππPROCEDURE FuzzyVar.CoordSystem(Sections: BYTE);π(* zeichnet ein Koordinatensystem *)π(* PosX, PosY bestimmen die linke obere Ecke *)πVAR N : Byte;π MarkerX : WORD;π Increment : Real;πBEGINπ SetColor(White);π SetTextJustify(CenterText,CenterText);π Line( PosX, PosY, PosX, PosY+103 );π Line( PosX-3, PosY+100, PosX+250, PosY+100 );π Line( PosX, PosY+20, PosX-3, PosY+20 );π OutTextXY( PosX-15, PosY+20, '1' );π OutTextXY( PosX-15, PosY+100, '0' );π Increment :=(EndValue-StartValue)/(Sections-1);π for N := 0 to Sections-1 doπ beginπ MarkerX:=RealToCoord(StartValue+N*Increment);π Line(MarkerX,PosY+101,MarkerX,PosY+103);π Str(Round(StartValue + N * Increment), Buffer );π OutTextXY(MarkerX, PosY+113, Buffer );π end;π OutTextXY( PosX + 270, PosY + 113, '['+UnitStr+']');π SetColor(Red);π SetTextJustify(LeftText,CenterText);π OutTextXY( PosX + 20, PosY + 140,VarName+' = ');π OutTextXY( PosX + 200,PosY + 140,UnitStr);πEND;ππPROCEDURE FuzzyVar.DisplayValue;ππBEGINπ SetWriteMode(XORPut);π SetColor(ValueCol);π IF (CurrentVal>=StartValue) AND (CurrentVal<=EndValue)π THEN Line(RealToCoord(CurrentVal),PosY+20,π RealToCoord(CurrentVal),PosY+100);π SetColor(TextColor);π SetTextJustify(RightText,CenterText);π Str(CurrentVal : 7 : 2, Buffer );π OutTextXY( PosX+190, PosY + 140 , Buffer );πEND;ππPROCEDURE FuzzyVar.Change;πBEGINπ IF (CurrentVal+Diff>=StartValue) AND (CurrentVal+Diff<=EndValue)π THENπ BEGINπ DisplayValue(0);π CurrentVal:=CurrentVal+Diff;π DisplayValue(ValueCol);π ENDπ ELSE (* Bereichsgrenzen überschritten *)π Buzz;πEND;ππPROCEDURE FuzzyVar.DisplaySets;π(* zeigt die unscharfen Mengen einer Variablen an *)πVAR SetPtr : FuzzySetList;πBEGINπ SetPtr:=FuzzySets;π WHILE SetPtr<>NIL DO WITH SetPtr^ DOπ BEGINπ SetColor(Color);π IF StartAt=-Infinity THEN SetTextJustify(RightText,CenterText)π ELSE IF EndAt=Infinity THEN SetTextJustify(LeftText,CenterText)π ELSE SetTextJustify(CenterText,CenterText);π OutTextXY(RealToCoord(HighAt),PosY+10,SetName);π IF StartAt=-Infinityπ THEN Line(PosX,PosY+20,RealToCoord(HighAt),PosY+20)π ELSE Line( RealToCoord(StartAt),PosY+100,π RealToCoord(HighAt),PosY+20);π IF EndAt=Infinityπ THEN Line(RealToCoord(HighAt),PosY+20,PosX+250,PosY+20)π ELSE Line(RealToCoord(HighAt),PosY+20,RealToCoord(EndAt),PosY+100);π SetPtr:=Nextπ ENDπEND;ππFUNCTION FuzzyVar.GetMemberShipOf;πVAR SetPtr : FuzzySetList;πBEGINπ SetPtr:=FuzzySets;π WHILE (SetPtr<>NIL) AND (SetPtr^.SetName<>Name) DO SetPtr:=SetPtr^.Next;π IF SetPtr=NIL THEN error( 'Menge '+Name+' ist in der Ling. Variablen 'π +VarName+' nicht definiert!')π ELSE GetMemberShipOf:=SetPtr^.GetMemberShip(CurrentVal)πEND;ππPROCEDURE FuzzyVar.DisplayResultSets;πVAR SetPtr : FuzzySetList;πBEGINπ SetWriteMode(CopyPut);π SetColor(ResultCol);π SetPtr:=FuzzySets;π WHILE SetPtr<>NIL DO WITH SetPtr^ DOπ BEGINπ IF MemberShip>0 THENπ BEGINπ IF StartAt<=StartValue THEN Result[1].x := RealToCoord(StartValue)π ELSE Result[1].x := RealToCoord(StartAt);π Result[1].y := PosY+99;π Result[2].x := RealToCoord(HighAt);π Result[2].y := PosY+99 - Round(MemberShip*79);π IF EndAt>=EndValue THEN Result[3].x := RealToCoord(EndValue)π ELSE Result[3].x:= RealToCoord(EndAt);π Result[3].y := PosY+99;π Result[4] := Result[1];π FillPoly( 4, Result )π END;π SetPtr:=nextπ ENDπEND;ππPROCEDURE FuzzyVar.Infer; (* alle Regeln antriggern *)πVARπ SetPtr : FuzzySetList;π RulePtr: FuzzyRuleList;πBEGINπ SetPtr:=FuzzySets;π WHILE SetPtr<>NIL DO WITH SetPtr^ DOπ BEGINπ RulePtr:=Rules;π MemberShip:=0;π WHILE RulePtr<>NIL DOπ BEGINπ MemberShip:=RulePtr^.Infer(MemberShip);π RulePtr:=RulePtr^.Nextπ END;π SetPtr:=Nextπ ENDπEND; (* FuzzyVar.Infer *)ππPROCEDURE FuzzyVar.Defuzzy;π(* Bestimmung des Flächenschwerpunktes der unscharfen *)π(* Ergebnismenge durch Auszählen der Pixel *)ππ(* Raster der Rechnergeschwindigkeit anpassen *)π(* größte Rechengenauigkeit bei Raster=1 *)πCONST Raster = 16;πVARπ X,Y,XOffSet : WORD;π Zaehler, Nenner: Real;πBEGINπ DisplayValue(Black);π SetFillStyle(SolidFill, Black);π SetColor(Black);π FillPoly(5, BackGround);π SetFillStyle(SolidFill, ResultCol);π IF DisplayOnπ THEN DisplaySets; (* verzerrt das Ergebnis auf Hercules *)π DisplayResultSets;π Zaehler :=0;π Nenner :=0;π XOffset :=PosX+20;π for X := 0 TO 210 DIV Raster DO (* Flächenschwerpunkt bestimmen *)π for Y := PosY + 20 to PosY + 100 doπ if GetPixel(Raster*X+XOffSet,Y) = ResultCol thenπ beginπ Nenner:=Nenner+1;π Zaehler:=Zaehler+Raster*X;π end;π IF Nenner=0 THEN CurrentVal:=0π ELSE CurrentVal :=Zaehler/Nenner/Scale+StartValue;π DisplayValue(ResultCol)πend;ππPROCEDURE FuzzyVar.DefineRule;πVAR SetPtr : FuzzySetList;πBEGINπ SetPtr:=FuzzySets;π WHILE (SetPtr<>NIL) AND (SetPtr^.SetName<>SetName)π DO SetPtr:=SetPtr^.Next;π IF SetPtr=NIL THEN error( 'Menge '+SetName+' ist in der Ling. '+π 'Variablen '+VarName+' nicht definiert!')π ELSE SetPtr^.DefineRule(InfType,Var1,SetName1,Var2,SetName2)πEND;ππPROCEDURE FuzzyVar.DefineSet;πBEGINπ IF FuzzySets = NILπ THEN FuzzySets:= new(FuzzySetList,π Init(InitName,InitStart,InitHigh,InitEnd,InitColor))π ELSE FuzzySets^.Append(InitName,InitStart,InitHigh,InitEnd,InitColor)πEND;ππCONSTRUCTOR FuzzyRule.Init;πBEGINπ Inf_Type :=InitInf;π Var1 :=InitVar1;π Var2 :=InitVar2;π SetName1 :=InitName1;π SetName2 :=InitName2;π Next :=NILπEND;ππPROCEDURE FuzzyRule.Append;πBEGINπ IF Next=NILπ THEN New(Next,Init(InitInf,InitVar1,InitName1,InitVar1,InitName2))π ELSE Next^.Append(InitInf,InitVar1,InitName1,InitVar2,InitName2)πEND;ππFUNCTION FuzzyRule.Infer; (* einzelne Regel abarbeiten *)πBEGINπ Infer:=Inf_Type(HomeSetValue, Var1^.GetMemberShipOf(SetName1),π Var2^.GetMemberShipOf(SetName2));πEND;ππBEGIN (* Fuzzy-Logic-Unit *)π (* Test auf Herculeskarte wg. Farbe für Ergebnismengen *)π Regs.ah:=15;π Intr($10,Regs);π IF Regs.AL=7 THEN (* Hercules-Karte *)π BEGINπ ResultCol :=Blue;π DisplayOn :=FALSE; (* siehe Artikel c't 3/91 *)π ENDπ ELSE (* EGA-/VGA-Karte *)π BEGINπ ResultCol :=LightGray;π DisplayOn :=TRUEπ ENDπEND.ππ{ -------------------------- DEMO PROGRAM ------------------------ }π{ I HOPE THAT YOU CAN READ GERMAN !! }ππprogram fuzzy_inf_demo; (* c't 3/91 / it / C.v.Altrock, RWTH Aachen *)πuses Graph, Crt, Fuzzy;πtype InputType = (temp,press,valve);πvarπ GraphDriver, GraphMode, RK : Integer;π StepWidth : Array[InputType] OF Real;π i,Input : InputType;π Ch : Char;π FuzzyVars : ARRAY[InputType] of FuzzyVarList;ππPROCEDURE InitGrafix;π(* Grafikmodus initialisieren und Hilfetexte schreiben *)πBEGINπ GraphDriver := Detect;π InitGraph(GraphDriver,GraphMode,'\turbo\tp');π SetTextJustify(CenterText,CenterText);π OutTextXY( GetMaxX DIV 2, 10, 'Demonstration der MAX-PROD-'π +'Inferenz (c''t 3/91 / C.v.Altrock, RWTH Aachen)');π OutTextXY( 500, 50, 'Eingabe Temperatur: ['+Chr(24)+']' );π OutTextXY( 500, 65, 'Eingabe Druck: ['+Chr(25)+']' );π OutTextXY( 500, 80, 'Erhöhen: ['+Chr(26)+']' );π OutTextXY( 500, 95, 'Vermindern: ['+Chr(27)+']' );π OutTextXY( 500, 110, 'Schrittweite: [Bild'+Chr(24)+Chr(25)+']' );π Rectangle(400,40,600,120);πEND; (* InitGrafix *)ππbegin (* main *)π InitGrafix;ππ (* Definition der linguistischen Variablen "Temperatur" *)π FuzzyVars[temp]:= new(FuzzyVarList,π Init('Temperatur',20,30,7,400,1000,650,'°C'));π WITH FuzzyVars[temp]^ DOπ BEGINπ (* Definition und Anzeige der Fuzzy Sets *)π DefineSet('niedrig',-Infinity,500,650,Blue);π DefineSet('mittel',500,650,800,LightGreen);π DefineSet('hoch',650,800,950,Red);π DefineSet('sehr_hoch',800,950,Infinity,Yellow);π DisplaySets; DisplayValue(ValueCol);π END;ππ (* Definition der linguistischen Variablen "Druck" *)π FuzzyVars[press]:= new(FuzzyVarList,π Init('Druck',20,210,4,38,41,40,'bar'));π WITH FuzzyVars[press]^ DOπ BEGINπ (* Definition und Anzeige der Fuzzy Sets *)π DefineSet('unter_normal',-Infinity,39,40,Blue);π DefineSet('normal',39,40,41,LightGreen);π DefineSet('über_normal',40,41,Infinity,Red);π DisplaySets; DisplayValue(ValueCol);π END;ππ (* Definition der linguistischen Variablen "Methanventil" *)π FuzzyVars[valve]:= new(FuzzyVarList,π Init('Methanventil',340,170,7,0,12,0,'m3/h'));π WITH FuzzyVars[valve]^ DOπ BEGINπ (* Definition der Fuzzy Sets *)π DefineSet('gedrosselt',-Infinity,0,4,Blue);π DefineSet('halboffen',0,4,8,Green);π DefineSet('mittel',4,8,12,LightGreen);π DefineSet('offen',8,12,Infinity,Yellow);π (* Definition der Inferenzregeln *)π (* 1 IF Temperatur ist niedrig OR Druck ist unter_normalπ THEN Methanventil ist offen *)π DefineRule('offen',OR_MaxMax, FuzzyVars[temp],'niedrig',π FuzzyVars[press],'unter_normal');π (* 2 IF Temperatur ist sehr_hoch OR Druck ist über_normalπ THEN Methanventil ist gedrosselt *)π DefineRule('gedrosselt',OR_MaxMax, FuzzyVars[temp],'sehr_hoch',π FuzzyVars[press],'über_normal');π (* 3 IF Temperatur ist hoch AND Druck ist normalπ THEN Methanventil ist halboffen *)π DefineRule('halboffen',AND_MaxMin, FuzzyVars[temp],'hoch',π FuzzyVars[press],'normal');π (* 4 IF Temperatur ist mittel AND Druck ist normalπ THEN Methanventil ist mittel *)π DefineRule('mittel',AND_MaxMin, FuzzyVars[temp],'mittel',π FuzzyVars[press],'normal');π IF DisplayOn THEN DisplaySets;π DisplayValue(ValueCol);π Infer;π Defuzzy;π END;ππ SetColor( Red );π OutTextXY( 540, 330, '(Resultat der Inferenz)' );π (* Schrittweiten für Druck und Temperatur intitialisieren *)π StepWidth[temp]:=25;π StepWidth[press]:=0.25;ππ Input:= temp;π Ch := ReadKey;π while Ch = #0 doπ beginπ RK := ord(ReadKey);π if RK = 72 then input := tempπ else if RK = 80 then input := pressπ else if (RK=73) then StepWidth[input]:=StepWidth[input] * 2π else if (RK=81) then Stepwidth[input]:= StepWidth[input] / 2π else if (RK=75) OR (RK=77) thenπ beginπ (* 1. Eingangsvariable ändern *)π if (RK=75) then FuzzyVars[Input]^.Change(-StepWidth[input])π ELSE FuzzyVars[Input]^.Change(StepWidth[input]);π (* 2. Inferenz durchführen *)π FuzzyVars[valve]^.Infer;π (* 3. Ergebnismenge defuzzifizieren *)π FuzzyVars[valve]^.Defuzzyπ end;π Ch := ReadKeyπ end;π CloseGraphπend.π 88 02-03-9416:12ALL PHIL NICKELL Min/Max Words or IntegersSWAG9402 16 èo π{$S-,R-}πUNIT MaxMinW;π(*π The source code for the MaxMinW unit is released to the public domain.π No rights are reserved. Phil Nickell. NSoft Co.π This Turbo Pascal unit implements four highly optimized assemblyπ language functions that provide MAX() and MIN() for unsigned words andπ signed integersπ*)πINTERFACEπ function MAXW (a,b:word) : Word; { max word }π function MINW (a,b:word) : Word; { min word }π function MAXI (a,b:integer) : Integer; { max integer }π function MINI (a,b:integer) : Integer; { min integer }ππIMPLEMENTATIONπfunction maxw(a,b:word):word; Assembler;π Asmπ mov ax, a { first parm in ax }π mov dx, b { second parm in dx }π cmp ax, dx { compare parms }π jae @1 { return 1st parm }π mov ax, dx { return 2nd parm }π @1:π End;ππfunction minw(a,b:word):word; Assembler;π Asmπ mov ax, a { first parm in ax }π mov dx, b { second parm in dx }π cmp ax, dx { compare parms }π jbe @1 { return 1st parm }π mov ax, dx { return 2nd parm }π @1:π End;ππfunction maxi(a,b:integer):integer; Assembler;π Asmπ mov ax, a { first parm in ax }π mov dx, b { second parm in dx }π cmp ax, dx { compare parms }π jge @1 { return 1st parm }π mov ax, dx { return 2nd parm }π @1:π End;ππfunction mini(a,b:integer):integer; Assembler;π Asmπ mov ax, a { first parm in ax }π mov dx, b { second parm in dx }π cmp ax, dx { compare parms }π jle @1 { return 1st parm }π mov ax, dx { return 2nd parm }π @1:π End;ππBegin {INITIALIZATION}πEnd.π 89 02-03-9416:15ALL PHIL NICKELL Min/Max Longs in ASM SWAG9402 31 èo πUNIT MaxMinL;π(*π The source code MaxMinL unit is released to the public domain. Noπ rights are reserved. Phil Nickell. NSoft Co.π This Turbo Pascal unit implements five highly optimized assemblyπ language functions that provide MAX() and MIN() for unsigned longwordπ and signed longintegers, and also a function for an unsigned longwordπ compare. The word functions treat the passed values as unsignedπ values. The integer functions treat the passed values as signedπ values. Turbo pascal does not have a LONGWORD data type, but theπ MAXLW() and MINLW() functions treat the passed longint types asπ unsigned words. Maxlw returns $ffffffff as greater than 0. Minlwπ returns 0 as less than $ffffffff.π*)π{$r-,S-}πINTERFACEπ FUNCTION MAXLW (a,b:longint) : Longint; { max longword }π FUNCTION MINLW (a,b:Longint) : Longint; { min longword }π FUNCTION MAXLI (a,b:longint) : Longint; { max longint }π function MINLI (a,b:Longint) : Longint; { min longint }π function LWGT (a,b:Longint) : Boolean; { long > unsigned }ππIMPLEMENTATIONπfunction maxlw(a,b:longint):longint; Assembler; {long word}π Asmπ les ax, a { load longint to es:ax }π mov dx, es { load longint to dx:ax }π cmp dx, word ptr b+2 { cmp high words }π ja @2 { high word > }π jb @1 { high word < }π cmp ax, word ptr b { comp low word }π jae @2 { low word >= }π @1: les ax, bπ mov dx, es { load int to dx:ax }π @2:π End;ππfunction minlw(a,b:longint):longint; Assembler; { longword }π Asmπ les ax, a { load longint to es:ax }π mov dx, es { load longint to dx:ax }π cmp dx, word ptr b+2 { cmp high words }π jb @2 { high word < }π ja @1 { high word > }π cmp ax, word ptr b { comp low word }π jbe @2 { low word >= }π @1: les ax, bπ mov dx, es { load int to dx:ax }π @2:π End;ππfunction maxli(a,b:longint):longint; Assembler;π Asmπ les ax, a { load longint to es:ax }π mov dx, es { load longint to dx:ax }π cmp dx, word ptr b+2 { cmp high words }π jg @2 { high word > }π jl @1 { high word < }π cmp ax, word ptr b { comp low word }π jae @2 { low word >= }π @1: les ax, bπ mov dx, es { load int to dx:ax }π @2:π End;ππfunction minli(a,b:longint):longint; Assembler;π Asmπ les ax, a { load longint to es:ax }π mov dx, es { load longint to dx:ax }π cmp dx, word ptr b+2 { cmp high words }π jl @2 { high word < }π jg @1 { high word > }π cmp ax, word ptr b { comp low word }π jbe @2 { low word >= }π @1: les ax, bπ mov dx, es { load int to dx:ax }π @2:π End;ππfunction lwgt(a,b:longint):boolean; Assembler; {unsigned longword greater thanπ}π Asmπ xor cx, cx { cx = 0 = false }π les ax, a { load longint to es:ax }π mov dx, es { load longint to dx:ax }π cmp dx, word ptr b+2 { cmp high words }π jb @2 { high word < }π ja @1 { high word > }π cmp ax, word ptr b { comp low word }π jbe @2 { low word <= }π @1: inc cx { cx = 1 = true }π @2: mov ax, cx { load result to ax }π End;ππBEGIN {INITIALIZATION}πEND.π 90 02-15-9407:54ALL BRIAN CORLL OOP Paradox Interface SWAG9402 107 èo {$F+,O+}πUNIT OOPX;π (**************************************)π (* OOPX Version 1.00 *)π (* Object-Oriented Interface for the *)π (* Paradox Engine Version 2.0 *)π (* and Turbo Pascal Version 6.0 *)π (* Copyright 1991 Brian Corll *)π (**************************************)π (* Portions Copyright 1990-1991 *)π (* Borland International *)π (**************************************)πππINTERFACEππUses PXEngine;ππππconstπ PXError : Integer = PXSUCCESS;π VarLong = 1;π VarInt = 2;π VarDate = 3;π VarDoub = 4;π VarAlpha = 5;π VarShort = 6;ππtypeπ DateRec = recordπ M,D,Y : Integer;π end;ππtypeπ PXObject = objectπ ErrCode : Integer;π THandle : TableHandle;π RHandle : RecordHandle;π LHandles: Array[1..32] of LockHandle;π SearchBuf : RecordHandle;π LastLock: Byte;π Name : String;π RecNo : RecordNumber;π Locked : Boolean;π UnLocked: Boolean;π constructor InitName(TblName : String);π constructor InitOpen(TblName : String;π IndexID : Integer;π SaveEveryChange : Boolean);π constructor InitCreate(TblName : String;π NFields : Integer;π Fields,Types : NamesArrayPtr);π destructor Done;π procedure ClearErrors;π procedure LockRecord;π procedure LockTable(LockType : Integer);π procedure UnLockRecord;π procedure UnLockTable(LockType : Integer);π procedure RenameTable(FromName,ToName : String);π procedure AddTable(AddTableName : String);π procedure CopyTable(CopyName : String);π procedure CreateIndex(NFlds : Integer;π FldHandles : FieldHandleArray;π Mode : Integer);π procedure Encrypt(Password : String);π procedure Decrypt(Password : String);π procedure DeleteIndex(IndexID : Integer);π procedure EmptyTable;π procedure EmptyRecord;π procedure ReadRecord;π procedure InsertRecord;π procedure AddRecord;π procedure UpdateRecord;π procedure DeleteRecord;π procedure NextRecord;π procedure PrevRecord;π procedure GotoRecord(R : RecordNumber);π procedure Flush;π procedure SearchField(FHandle : FieldHandle;Mode : Integer);π procedure SearchKey(NFlds : Integer;Mode : Integer);π procedure InitSearchBuf(FldName : NameString;var Variable;VarType : Byte);π procedure PutField(FldName : NameString;var Variable);π procedure PutLongField(FldName : NameString;var L : Longint);π procedure GetField(FldName : NameString;var Variable);π procedure GetLongField(FldName : NameString;var L : Longint);π function FieldNumber(FldName : NameString) : Integer;π function FieldName(FHandle : FieldHandle) : NameString;π function FieldType(FHandle : FieldHandle) : NameString;π function IsBlank(FldName : NameString) : Boolean;π function TableChanged : Boolean;π procedure Refresh;π procedure Top;π procedure Bottom;π function GetRecordNumber : Longint;π end;πππfunction PXOk : Boolean;ππIMPLEMENTATIONππ function PXOk : Boolean;π beginπ PXOk := (PXError = PXSUCCESS);π end;ππ constructor PXObject.InitName;π beginπ Name := TblName;π end;ππ constructor PXObject.InitOpen;π beginπ THandle := 0;π Name := '';π ErrCode := PXTblOpen(TblName,π THandle,π IndexID,π SaveEveryChange);π If ErrCode = PXSUCCESS thenπ beginπ Name := TblName;π ErrCode := PXRecBufOpen(THandle,RHandle);π ErrCode := PXRecBufOpen(THandle,SearchBuf);π end;π LastLock := 0;π FillChar(LHandles,32,0);π PXError := ErrCode;π Locked := False;π UnLocked := False;π end;ππ constructor PXObject.InitCreate(TblName : String;π NFields : Integer;π Fields,Types : NamesArrayPtr);π beginπ ErrCode := PXTblCreate(TblName,NFields,Fields,Types);π PXError := ErrCode;π end;ππ procedure PXObject.Encrypt(Password : String);π beginπ ErrCode := PXTblEncrypt(Name,Password);π If ErrCode = PXERR_TABLEOPEN thenπ beginπ ErrCode := PXTblClose(THandle);π If ErrCode = PXSUCCESS thenπ ErrCode := PXTblEncrypt(Name,Password);π end;π PXError := ErrCode;π end;ππ procedure PXObject.ClearErrors;π beginπ ErrCode := 0;π PXError := 0;π end;ππ procedure PXObject.Decrypt(Password : String);π beginπ ErrCode := PXPswAdd(Password);π If ErrCode = PXSUCCESS thenπ beginπ ErrCode := PXTblDecrypt(Name);π If ErrCode = PXERR_TABLEOPEN thenπ beginπ ErrCode := PXTblClose(THandle);π If ErrCode = PXSUCCESS thenπ ErrCode := PXTblDecrypt(Name);π end;π end;π PXError := ErrCode;π end;ππ procedure PXObject.CreateIndex(NFlds : Integer;π FldHandles : FieldHandleArray;π Mode : Integer);π beginπ ErrCode := PXKeyAdd(Name,NFlds,FldHandles,Mode);π PXError := ErrCode;π end;ππ procedure PXObject.DeleteIndex;π beginπ ErrCode := PXKeyDrop(Name,IndexID);π PXError := ErrCode;π end;ππ procedure PXObject.Flush;π beginπ ErrCode := PXSave;π PXError := ErrCode;π end;ππ procedure PXObject.LockRecord;π var LockTest : Boolean;π beginπ Locked := False;π Inc(LastLock);π ErrCode := PXNetRecLock(THandle,LHandles[LastLock]);π ErrCode := PXNetRecLocked(THandle,LockTest);π Locked := (ErrCode = PXSUCCESS)π and LockTest;π If not Locked then Dec(LastLock);π PXError := ErrCode;π end;ππ procedure PXObject.LockTable;π beginπ Locked := False;π ErrCode := PXNetTblLock(THandle,LockType);π Locked := (ErrCode = PXSUCCESS);π PXError := ErrCode;π end;ππ procedure PXObject.UnLockRecord;π beginπ UnLocked := False;π ErrCode := PXNetRecUnlock(THandle,LHandles[LastLock]);π If (ErrCode = PXSUCCESS) thenπ beginπ UnLocked := True;π LHandles[LastLock] := 0;π Dec(LastLock);π end;π end;ππ procedure PXObject.UnLockTable(LockType : Integer);π beginπ UnLocked := False;π ErrCode := PXNetTblUnlock(THandle,LockType);π PXError := ErrCode;π UnLocked := (PXError = PXSUCCESS);π end;ππ procedure PXObject.RenameTable(FromName,ToName : String);π beginπ ErrCode := PXTblRename(FromName,ToName);π PXError := ErrCode;π end;ππ procedure PXObject.AddTable(AddTableName : String);π beginπ ErrCode := PXTblAdd(AddTableName,Name);π PXError := ErrCode;π end;ππ procedure PXObject.CopyTable(CopyName : String);π beginπ ErrCode := PXTblCopy(Name,CopyName);π PXError := ErrCode;π end;ππ procedure PXObject.EmptyTable;π beginπ ErrCode := PXTblEmpty(Name);π PXError := ErrCode;π end;ππ procedure PXObject.EmptyRecord;π beginπ ErrCode := PXRecBufEmpty(RHandle);π PXError := ErrCode;π end;ππ procedure PXObject.ReadRecord;π beginπ ErrCode := PXRecGet(THandle,RHandle);π PXError := ErrCode;π end;ππ procedure PXObject.InsertRecord;π beginπ ErrCode := PXRecInsert(THandle,RHandle);π PXError := ErrCode;π end;ππ procedure PXObject.AddRecord;π beginπ ErrCode := PXRecAppend(THandle,RHandle);π PXError := ErrCode;π end;ππ procedure PXObject.UpdateRecord;π beginπ ErrCode := PXRecUpdate(THandle,RHandle);π PXError := ErrCode;π end;ππ procedure PXObject.DeleteRecord;π beginπ ErrCode := PXRecDelete(THandle);π PXError := ErrCode;π end;ππ procedure PXObject.NextRecord;π beginπ ErrCode := PXRecNext(THandle);π PXError := ErrCode;π end;ππ procedure PXObject.PrevRecord;π beginπ ErrCode := PXRecPrev(THandle);π PXError:= ErrCode;π end;ππ procedure PXObject.GotoRecord(R : RecordNumber);π beginπ ErrCode:= PXRecGoto(THandle,R);π PXError := ErrCode;π end;ππ procedure PXObject.PutField(FldName : NameString;var Variable);π var FType : NameString;π FirstChar : Char;π FHandle : FieldHandle;π beginπ FHandle := FieldNumber(FldName);π If (PXError <> PXSUCCESS) then Exit;π ErrCode := PXFldType(THandle,FHandle,FType);π FirstChar := FType[1];π case FirstChar ofπ 'D' : ErrCode := PXPutDate(RHandle,FHandle,TDate(Variable));π 'A' : ErrCode := PXPutAlpha(RHandle,FHandle,String(Variable));π '$','N'π : ErrCode := PXPutDoub(RHandle,FHandle,Double(Variable));π 'S' : ErrCode := PXPutShort(RHandle,FHandle,Integer(Variable));π end;π PXError := ErrCode;π end;ππ procedure PXObject.InitSearchBuf(FldName : NameString;var Variable;VarType : Byte);π var FHandle : FieldHandle;π beginπ FHandle := FieldNumber(FldName);π If (PXError <> PXSUCCESS) then Exit;π case VarType ofπ VarDate : ErrCode := PXPutDate(SearchBuf,FHandle,TDate(Variable));π VarAlpha : ErrCode := PXPutAlpha(SearchBuf,FHandle,String(Variable));π VarDoub : ErrCode := PXPutDoub(SearchBuf,FHandle,Double(Variable));π VarShort : ErrCode := PXPutShort(SearchBuf,FHandle,Integer(Variable));π VarLong : ErrCode := PXPutLong(SearchBuf,FHandle,Longint(Variable));π end;π PXError := ErrCode;π end;ππ procedure PXObject.PutLongField(FldName : NameString;var L : Longint);π var FHandle : FieldHandle;π beginπ FHandle := FieldNumber(FldName);π If (PXError <> PXSUCCESS) then Exit;π ErrCode := PXPutLong(RHandle,FHandle,L);π PXError := ErrCode;π end;ππ procedure PXObject.GetField(FldName : NameString;var Variable);π var FType : NameString;π FirstChar : Char;π FHandle : FieldHandle;π beginπ FHandle := FieldNumber(FldName);π If (PXError <> PXSUCCESS) then Exit;π ErrCode := PXFldType(THandle,FHandle,FType);π FirstChar := FType[1];π case FirstChar ofπ 'D' : ErrCode := PXGetDate(RHandle,FHandle,TDate(Variable));π 'A' : ErrCode := PXGetAlpha(RHandle,FHandle,String(Variable));π '$','N'π : ErrCode := PXGetDoub(RHandle,FHandle,Double(Variable));π 'S' : ErrCode := PXGetShort(RHandle,FHandle,Integer(Variable));π end;π PXError := ErrCode;π end;ππ procedure PXObject.GetLongField(FldName : NameString;var L : Longint);π var FHandle : FieldHandle;π beginπ FHandle := FieldNumber(FldName);π If (PXError <> PXSUCCESS) then Exit;π ErrCode := PXGetLong(RHandle,FHandle,L);π PXError := ErrCode;π end;ππ function PXObject.GetRecordNumber : Longint;π beginπ ErrCode := PXRecNum(THandle,RecNo);π If (ErrCode = PXSUCCESS) thenπ GetRecordNumber := RecNo;π PXError := ErrCode;π end;ππ function PXObject.FieldNumber(FldName : NameString) : Integer;π var FldHandle : FieldHandle;π beginπ ErrCode := PXFldHandle(THandle,FldName,FldHandle);π If (ErrCode = PXSUCCESS) then FieldNumber := FldHandleπ else FieldNumber := 0;π PXError := ErrCode;π end;ππ function PXObject.IsBlank(FldName : NameString) : Boolean;π var Blank : Boolean;π FHandle : FieldHandle;π beginπ FHandle := FieldNumber(FldName);π If (ErrCode <> PXSUCCESS) then PX(PXError);π IsBlank := False;π ErrCode := PXFldBlank(RHandle,FHandle,Blank);π If ErrCode = PXSUCCESS then IsBlank := Blank;π PXError := ErrCode;π end;ππ function PXObject.TableChanged : Boolean;π var Changed : Boolean;π beginπ TableChanged := False;π ErrCode := PXNetTblChanged(THandle,Changed);π If ErrCode = PXSUCCESS thenπ TableChanged := Changed;π PXError := ErrCode;π end;ππ procedure PXObject.Refresh;π beginπ ErrCode := PXNetTblRefresh(THandle);π PXError := ErrCode;π end;ππ function PXObject.FieldName(FHandle : FieldHandle) : NameString;π var FName : NameString;π beginπ ErrCode := PXFldName(THandle,FHandle,FName);π If ErrCode = PXSUCCESS thenπ FieldName := FNameπ elseπ FIeldName := '';π PXError := ErrCode;π end;ππ procedure PXObject.SearchField(FHandle : FieldHandle;Mode : Integer);π beginπ ErrCode := PXSrchFld(THandle,SearchBuf,FHandle,Mode);π PXError := ErrCode;π end;ππ procedure PXObject.SearchKey(NFlds : Integer;Mode : Integer);π beginπ ErrCode := PXSrchKey(THandle,SearchBuf,NFlds,Mode);π PXError := ErrCode;π end;ππ function PXObject.FieldType(FHandle : FieldHandle) : NameString;π var FType : NameString;π beginπ FieldType := '';π ErrCode := PXFldType(THandle,FHandle,FType);π If ErrCode = PXSUCCESS then FieldType := FType;π PXError := ErrCode;π end;ππ procedure PXObject.Top;π beginπ ErrCode := PXRecFirst(THandle);π PXError := ErrCode;π end;ππ procedure PXObject.Bottom;π beginπ ErrCode := PXRecLast(THandle);π PXError := ErrCode;π end;πππ destructor PXObject.Done;π beginπ ErrCode := PXRecBufClose(RHandle);π ErrCode := PXRecBufClose(SearchBuf);π ErrCode := PXTblClose(THandle);π PXError := ErrCode;π end;ππbeginπend.πππ