Convert a file with FreeBasic
Case
In a laboratory there s an old MSDOS system collecting data and saving it to
files. I have no idea what components there is and what the system is doing.
The files are binary, meaning that they are not in human readable text format
and there is no documentation about the format.
The data can be converted to text with an original program. The problem is that
the program can not be used in batch, because it asks the filenames one by one.
The laboratory staff asked me, if I could build some special batch, wich could
handle the sittuation. After a quick check I found it easier to
build a totally new program to convert the data.
Tools
I have checked and rechecked many programming languages. I have found that good
old Basic is very powerfull in cases, where you make some rather simple file
conversions. Changing some binary data to some other format is a typical case.
In this case I found that the program got to be compiled so that users have no
possibility to mess it by editing the code.
This left out for example
SmallBasic
, whis is wonderful programming system by itself. MS has its own
SmallBasic
which produces compiled code, but misses very many important commands.
Then I found
FreeBasic
and there was what I had been looking for !
It's syntax is very near the good old QuickBasic. It has a separated IDE. You
can even select between some. I selected
Jelly Fish
, which somehow felt familiar to me.
There is versions for MSWindows as well as Linux.
How
In the beginning I had to build some simple "Hello World" programs to get
accustomed with
FreeBasic
and
JellyFish
Then I built a simple program only to read the data files character by
character and print them on screen. Every time I found some repeating syntax in
the dataflow, I made some pointer in the flow. If ther was a typical structure,
for example six characters in a row and then some special character, I added a
line feed there.
Slowly I found that in the beginning of the data there is a mass of characters,
which are not laboratory data. After that there was two massess of data. I
compared these with the tables built by the original converter program and
found the number of lines telling how many data points there is and how many
columns I should find.
I divided the data so that I go the right number of columns and rows.
Now I could see the data clearly. It was saved column by column. Every data was
built of many bytes. I had to find the right format: in the first place it has
to be either
decimal (523.4) or exponential format (5.234E2). Decimal is easier.
In this case I found that colum 1 was just an index 1 to N. Column 2 and 3
looked like decimal data with no decimal part. Columns 4 and 5 seemed to
contain the same data as 2
and 3 but in exponential format. This I found out reading the output of the
original converter. So I could leave the columns 4 and 5 out.
Now I had to find the format of colums 2 and 3. First I checked all the format
of the index column. There I found the data is in least-significant-byte-first
format. So I knew the columns 2 and 3 were similar and built a subfunction for
this:
sum = B1+B2*256+B3*256*256+B4*256*256*256 = B1+256*(B2+256*(B3+256*B4))
This made it. I had now columns 1, 2 and 3.
Now I returned to the data mass in the beginning of the file. I was sure it
contained information about the file and the measurement gadget. What I needed
was the number of data points. I was sure it can not be larger than 65536 which
is the largest number, which can be saved in two bytes.
I found there two bytes, whose product L=B1+B2*256 was exactly the number of
the data points in original file.
Now the mathematics were OK. I built the parts, which saved tha data to a new
file, which was compatible with MSExcel. Then I built routines, which can read
the parameters from command line, if the program is used in a batch.
Then I built routines, which are used, if the user wants to run the program
standalone.
In the end I built a simple help and error handling in the program.
I have a habit to write some simple comments in the program code. It helps me,
if I have to change something afterwards. In this case the comments are in
native Finnish language, because I had no intention to publish the program.
What now
The program is in active use and nobody has reported any errors. It took me
three days at 30% schedule to write the program.
If you have any use of the code, please enjoy yourself.
DIM SHARED versio AS string
versio="130209/2"
' Kari Loikas jatti jonkin mittalaitteen tuottaman tiedoston kasiteltavaksi.
' ratkaistu raalla voimalla (ja koristeltu;).
' Ohjelma kirjoitettu FreeBasic:llä
' Tama versio tuottaa txt-muotoisen tiedoston, jossa sarakkeet 1 ja 2
DIM i AS integer 'for/next laskuri
DIM j AS integer 'for/next laskuri
DIM temp AS string
DIM mrivi AS string
DIM rivi AS integer
DIM sar1 AS double 'ensimmaisen sarakkeen lukema siirrettaessa tiedostosta toiseen
DIM m1 AS string
DIM m2 AS string
DIM m3 AS string
DIM SHARED m4 AS string
DIM SHARED MM4 AS double
DIM MM3 AS double
DIM MM2 AS double
DIM MM1 AS double
DIM sum AS double
DIM lkm AS double
DIM lkm2 AS double 'rivien lkm
DIM ohi AS double 'ohitettujen rivien lkm
DIM merkkeja AS double 'merkkien lkm tiedostossa
DIM argc AS Integer, argv(5) AS String 'komentojonoparametrit
DIM sorsa AS string
DIM tulos AS string
'e:\Loikas_test\AA01.400 e:\loikas_test\AA01.txt
DECLARE SUB help()
DECLARE SUB kaiva(j AS integer)
temp=ENVIRON("temp") 'jarjestelman temp -hakemisto.
' Haetaan komentojonoparametrit
' argc vastaa itse ohjelman nimea
argc = 1
DO
argv(argc) = COMMAND( argc )
IF( LEN( argv(argc) ) = 0 ) THEN
EXIT DO
END IF
IF INSTR(argv(argc),"?")>0 THEN
'Komentorivilla '?', tulostetaan HELP
help()
END IF
argc += 1
LOOP
IF argc>4 THEN
'enintaan kolme parametria, virhetilassa tulostetaan help
PRINT "------------------------"
PRINT "------------------------"
PRINT "!! Liikaa parametreja !!" ;argc,argv(argc)
PRINT "------------------------"
PRINT "------------------------"
help()
ENDIF
IF argc=1 THEN
'ei komentoriviparametreja
PRINT "'#' lähdetiedoston nimen alussa lisää rivinumeroinnin tulostiedostoon": PRINT
INPUT "Lahdetiedosto";sorsa
INPUT"Tulostiedosto";tulos
'print "TULOS=>";tulos;"<"
IF sorsa="" THEN
PRINT"----------------------------"
help()
ENDIF
IF INSTR(sorsa,"#") THEN
sorsa=LTRIM(LTRIM(sorsa,"#")," ")
argv(1)="#"
ENDIF
ELSEIF argv(1)<>"#" THEN
' Ei risuaitaa komentorivin alussa
sorsa=argv(1)
tulos=argv(2)
ELSEIF argv(1)="#" THEN
'aitamerkki ensimmaisena parametrina
sorsa=argv(2)
tulos=argv(3)
IF argv(2)="" THEN
PRINT"-------------------------------------"
PRINT"-------------------------------------"
PRINT"--!!! PUUTTEELLISET LAHTOTIEDOT !!!--"
PRINT"-------------------------------------"
PRINT"-------------------------------------"
help()
ENDIF
ENDIF
OPEN sorsa FOR BINARY AS #1
' Toivottavasti tallaista tiedostoa ei ole olemassa:
temp=temp+"\q1w2e3r4.tmp"
OPEN temp FOR OUTPUT AS #2
merkkeja=LOF(1)
'PRINT"Tiedostossa merkkeja:";LOF(1)
FOR i=1 TO 60
'luetaan alusta pois 60 merkkiä
m1=INPUT$(1,1)
MM1=ASC(m1)
NEXT
ohi=60
'PRINT:PRINT"Alkutyhjat jatetty pois (60 kpl)"
' Kaivetaan tiedoston pituus.
' Jos rivien lukumaara on yli 256, tassa _saattaa_ tulla virhe, jolloin kaytetaan
' tassa alla olevaa ensimmaista laskutapaa.
m1=INPUT$(1,1)
MM1=ASC(m1)
m2=INPUT$(1,1)
MM2=ASC(m2)
lkm=MM1+MM2*256
m3=INPUT$(1,1)
MM3=ASC(m3)
'Jos virheellinen rivien lkm, komentoi alla oleva rivi:
lkm=MM2*256 + MM3
ohi=ohi+3
IF lkm=0 THEN
PRINT"-----------------------------------------------------"
PRINT"-----------------------------------------------------"
PRINT"SYOTTOTIEDOSTOA EI LOYDY TAI SEN SISALTO VIRHEELLINEN"
PRINT"-----------------------------------------------------"
PRINT"-----------------------------------------------------"
help()
ENDIF
/' Tarkistettu, rutiini toimii
IF argc=1 THEN
PRINT"------"
PRINT "( Lukumaara_2 = 256*asc(m2) + asc(m3) ) = ";lkm
PRINT"Jos rivien lukumaara on virheellinen, pitaa ohjelmakoodia muuttaa"
PRINT "Ota yhteytta: ptmusta@utu.fi"
PRINT"-------"
PRINT "Paina jotain nappainta"
DO:LOOP UNTIL inkey>""
ENDIF
'/
FOR i=64 TO 170
m1=INPUT$(1,1)
MM1=ASC(m1)
' Print mm1;
NEXT
ohi=ohi+106
FOR i=171 TO 194
m1=INPUT$(1,1)
MM1=ASC(m1)
' Print i, m1;mm1
NEXT
ohi=ohi+23
'----------------------------------- OLEELLINEN OSA TIEDOSTOSTA ALKAA-----------------------------------
FOR i=1 TO lkm
'Luetaan ensimmainen sarake ja viedaan temp-tiedostoon
sum=0
m1=INPUT$(1,#1):MM1=ASC(m1):sum=sum+MM1
m2=INPUT$(1,#1):MM2=ASC(m2):sum=sum+MM2*256
m3=INPUT$(1,#1):MM3=ASC(m3):sum=sum+MM3*256*256
m4=INPUT$(1,#1):MM4=ASC(m4):sum=sum+MM4*256*256*256
PRINT #2,sum
NEXT
CLOSE 2
ohi=ohi+lkm
' Avataan ensimmaisen sarakkeen sisaltava temptiedosto uudestaan luettavaksi
' Ja lopullinen tiedosto kirjoitettavaksi
OPEN temp FOR INPUT AS #2
IF tulos="" THEN
'tulostiedoston nimi puuttuu, annetaan nimeksi
'lähtötiedoston nimi ja jatkeeksi 'txt'
tulos="txt"
ENDIF
IF (LEN(tulos)<=3)AND(tulos<>"$") THEN
'komentorivillä annettu vain nimen jatke tulostiedoston nimen kohdalla
tulos=LEFT(sorsa,INSTR(sorsa,"."))+tulos
ENDIF
IF ((tulos<>"") AND (tulos<>"$")) THEN
'tulostus tiedostoon vain, jos tiedosto on nimetty
OPEN tulos FOR OUTPUT AS #3
ENDIF
rivi=0:mrivi=""
FOR i=1 TO lkm
'haetaan ensimmaisen sarakkeen rivi
INPUT #2,sar1
'lasketaan toisen sarakkeen arvo
sum=0
m1=INPUT$(1,#1):MM1=ASC(m1):sum=sum+MM1
m2=INPUT$(1,#1):MM2=ASC(m2):sum=sum+MM2*256
m3=INPUT$(1,#1):MM3=ASC(m3):sum=sum+MM3*256*256
m4=INPUT$(1,#1):MM4=ASC(m4):sum=sum+MM4*256*256*256
IF argv(1)="#" THEN
'rivinro tiedostoon vain, jos on pyydetty
rivi=rivi+1
mrivi=STR(rivi)+","
ENDIF
IF tulos="$" THEN
'tulostuu ruudulle, kun tulostiedoston nimi=$
PRINT mrivi;sar1;sum
ELSE
'tulostiedoston nimi annettu
PRINT #3,mrivi;sar1;",";sum
ENDIF
NEXT
CLOSE 2,3
ohi=ohi+lkm
PRINT"KASITELTY: ";sorsa
IF argc=1 THEN
'tyhjä syöttörivi
PRINT" Paina jotain nappainta"
DO:LOOP UNTIL INKEY$>""
PRINT
PRINT"-------------------"
PRINT
ENDIF
'----------------------------------- OLEELLINEN OSA TIEDOSTOSTA LOPPUU-----------------------------------
'-------------------------------------------
' Jatetaan loput kasittelematta. Tasta eteenpain ainoastaan kaiva() ja help() koodin lopussa
'-------------------------------------------
END
PRINT "Ohitettu sarake 2. Paina nappainta"
DO:LOOP UNTIL inkey>""
kaiva(lkm)
ohi=ohi+lkm
PRINT "Ohitettu sarake 3. Paina nappainta"
DO:LOOP UNTIL INKEY$>""
kaiva(lkm)
ohi=ohi+lkm
PRINT"Ohitettu sarake 4. Paina nappainta"
DO:LOOP UNTIL INKEY$>""
kaiva(lkm)
ohi=ohi+lkm
PRINT"Ohitettu sarake 5. Paina nappainta"
PRINT "Taytemerkkeja jaljella ";merkkeja-ohi
DO:LOOP UNTIL INKEY$>""
kaiva(merkkeja-ohi)
PRINT"Ohi on. Paina nappainta"
DO:LOOP UNTIL INKEY$>""
CLOSE 1
'--------------------------------------------------------------------------------------
SUB kaiva(BYVAL j AS integer)
DIM i AS integer 'for/next laskuri
FOR i=1 TO j
m4=INPUT$(1,#1):MM4=ASC(m4):PRINT i,m4;
m4=INPUT$(1,#1):MM4=ASC(m4):PRINT m4;
m4=INPUT$(1,#1):MM4=ASC(m4):PRINT m4;
m4=INPUT$(1,#1):MM4=ASC(m4):PRINT m4
NEXT
END SUB
'---------------------------------------------------------------------------------------
SUB help()
COLOR(14,0)
PRINT "B2XLS [#|?] sourcefile [destinationfile|jat|$]";
COLOR(7,0)
PRINT" (jarjestys on tarkea)"
PRINT "Ohjelma avaa annetun tiedoston ja poimii sielta kaksi ensimmaista saraketta."
PRINT "Sarakkeiden sisalto talletetaan uuteen tiedostoon."
PRINT "sarakkeiden erottimena on pilkku"
PRINT "'#' - tiedoston ensimmaiseksi sarakkeeksi rivin numero pilkulla erotettuna"
PRINT "'?' - tulostaa taman ohjeen"
PRINT "Jos tulostiedostoa ei anneta, tulostustiedoston nimi on lähdetiedoston nimi, jatkeena 'txt'"
PRINT "Jos tulostiedoston tilalla annetaan tiedoston jatke 'jat', käytetään tätä nimen jatkeena"
PRINT "'$' tulostiedoston nimenä tulostaa ruudulle"
PRINT "Tama ohjelma on rakennettu olemassaolevan lahde- ja tulostiedoston pohjalta"
PRINT "siita on jatetty pois kolmen viimeisen sarakkeen tulostus, koska nama sisaltavat"
PRINT "ainoastaan seuraavat tiedot:"
PRINT "- rivin jarjestysnumero"
print "- sarake 1. exponenttimuodossa"
PRINT "- sarake 2. exponenttimuodossa"
PRINT "Versio: ";versio; ", PTMusta@utu.fi"
DO:LOOP UNTIL inkey>""
END
END SUB
PTMUSTA at UTU.FI
|