Pascal Sizeof
Pascal Sizeof
Table 6-1 and Table 6-2 list the default sizes and alignments of compatible types for C and Pascal.
Table 6-1 C and Pascal Size and Alignment of Compatible Types
double double 8 8
longreal double 8 8
real double 8 8
single float 4 4
shortreal float 4 4
integer32 int 4 4
integer int 4 4
-128..127 char 1 1
boolean char 1 1
char char 1 1
Table 6-2 C and Pascal Size and Alignment of Compatible Types with -xl -
real float 4 4
The commands to compile and execute SimVar.p and SimVarMain.c hostname% pc -c SimVar.p
hostname% cc SimVar.o SimVarMain.c
hostname% a.out
00000001 00000000 z 9 9 9.9 9.9
Simple Types with -xl
With the -xl option, the Pascal real must be paired with a C float, and the Pascal integer must be paired with a
C short int.
Strings of Characters
The C counterpart to the Pascal alfa and string types are arrays; C passes all arrays by reference. The C
counterpart to the Pascal varying is a structure; C passes structures by value.
Before you call Pascal with a null varying string, set the byte count to zero because that is what Pascal
assumes about such strings.
C can pass a structure consisting of a four-byte integer and an array of characters to a Pascal procedure,
expecting a var parameter that is a variable-length string.
See the following example:
The Pascal procedure, StrVar.p type
The commands to compile and hostname% pc -c StrVar.p hostname% cc StrVar.o StrVarMain.c -lpc
execute StrVar.p and StrVarMain.c hostname% a.out s10='abcdefghi'
s80='abcdefghijklmnopqrtstuvwxyz' s25='varstr' strlen(s25)=6
Fixed Arrays
For a fixed array parameter, pass the same type and size by reference, as shown in the following example:
The Pascal procedure, FixVec.p type
VecTyp = array [0..8] of integer;
procedure FixVec(var V: TVec; var Sum: integer);
var i: integer;
begin Sum := 0; for i := 0 to 8 do Sum := Sum + V[i]
end; { FixVec }
Although it does not apply in this example, arrays of aggregates in Pascal have, by default, a size that is
always a multiple of four bytes. When you use the -calign option to compile the Pascal code, that difference
with C is eliminated.
The following example illustrates this point. The string 'Sunday' only gets through to the C main program
when you compile the Pascal routine using
-calign.
The Pascal procedure, DaysOfWeek.p type
TDay= array [0..8] of char;
TWeek = array [0..6] of day;
TYear = array [0..51] of week;
procedure DaysOfWeek(var Y: TYear);
begin v[1][1] := 'Sunday'; end;
The C main program, #include <stdio.h>
DaysOfWeekMain.c extern void DaysOfWeek(char [][7][9]);
int main(void)
{ char Year[52][7][9]; DaysOfWeek(Year);
printf(" Day = '%s' \n", Year[1][1]);}
The commands to compile and execute DaysOfWeek.p and hostname% pc -c -calign DaysOfWeek.p
DaysOfWeekMain.c with -calign hostname% cc DaysOfWeek.o
DaysOfWeekMain.c -lpc
hostname% a.out
day = 'Sunday '
The commands to compile and execute UniVec.p and hostname% pc -c -calign UniVec.p
UniVecMain.c with -calign hostname% cc UniVec.o UniVecMain.c -lpc
hostname% a.out 24
Conformant Arrays
For single-dimension conformant arrays, pass upper and lower bounds, placed after the declared parameter
list. If the array is multidimensional, pass element widths as well, one element width for each dimension,
except the last one.
See this example:
function ip(var x: array [lb..ub: integer] of real): real;
extern double ip(double [], int, int); ... double v1[10]; double z; z = ip(v1, 0, 9); ...
One bounds pair may apply to several arrays if they are declared in the same parameter group:
function ip(var x,y:array[lb..ub:integer] of real):real;
... double v1[10], v2[10] ; extern double ip() ; double z ; z = ip ( v1, v2, 0, 9 ) ; ...
With multidimensional arrays, for all dimensions but the last one, pass the low bound, high bound, and
element width.
Examples of single-dimension, multidimension, and array-of-character conformant arrays follow.
Conformant arrays are included here only because they are a relatively standard feature; there are usually
more efficient and simpler ways to do the same thing.
Example 1: Single-Dimension Array
The Pascal procedure, IntCA.p. Pascal procedure IntCA(var a: array [lb..ub: integer] of integer);
passes the bounds pair. begin a[1] := 1; a[2] := 2 end; { IntCA }
The C main program, IntCAMain.c #include <stdio.h> extern void IntCA(int [], int, int);
int main(void)
{ int k ; static int s[] = { 0, 0, 0 };
IntCA (s, 0, sizeof(s)-1); for (k=0 ; k < 3 ; k++)
printf(" %d \n", s[k]); }
If wc is the width of the smallest element, as determined by sizeof(), then the width of the next largest
element is the number of those smaller elements in the next larger element multiplied by wc.
width of next largest element = (ub - lb + 1) * wc
In general, (lb, ub, wc) are the bounds and element width of the next lower dimension of the array. This
definition is recursive.
Example 3: Array of Characters
The Pascal procedure, ChrCAVar.p procedure ChrCAVar(var a: array [lb..ub: integer] of char);
begin a[0] := 'T'; a[13] := 'o'; end; { ChrCAVar }
The C main program, #include <stdio.h> extern void ChrCAVar(char [], int, int);
ChrCAVarMain.c. For C, the lower int main(void)
bound is always 0. { static char s[] = "this is a string" ;
ChrCAVar( s, 0, sizeof(s)-1) ; /*(s, lower, upper)*/
printf("%11s \n", s) ;}
The C main program, StruChrMain.c #include <stdio.h> #include <string.h> struct TVarLenStr {
int NBytes; char a[25];};
extern void StruChr(struct TVarLenStr *);
int main(void)
{ struct TVarLenStr vls; char s25[25]; vls.NBytes = 0;
StruChr(&vls); strncpy(s25, vls.a, vls.NBytes);
printf(" s25 = '%s' \n", s25);
printf(" strlen(s25) = %d \n", strlen(s25));}
The record in the example above has, by default, the same size and alignment as the equivalent C record.
Some records, though, are laid out differently unless you use the -calign option.
Consider this example:
The Pascal routine, DayWeather.p Type TDayWeather = record
TDay: array [0..8] of char;
TWeather: array [0..20] of char;
end;
TDayWeatherArray = array [0..1] of TDayWeather;
procedure DayWeather(var W: TDayWeatherArray;
var WeatherSize: integer);
begin W[1].TDay := 'Sunday' + chr(0);
W[1].TWeather := 'Sunny' + chr(0);
WeatherSize := 5; end; { StruChr }
When you compile the Pascal routine without using the -calign option, the program does not work correctly.
The commands to compile and hostname% pc -c DayWeather.p
execute DayWeather.p and hostname% cc DayWeather.o DayWeatherMain.c -lpc
DayWeatherMain.c without -calign hostname% a.out day = '' weather = ' sun'
Variant Records
C equivalents of variant records can sometimes be constructed, although there is some variation with
architecture and sometimes a need to adjust alignment. You can avoid the need to adjust alignment by using
the -calign option.
The Pascal procedure, VarRec.p type
vr = record
case tag: char of
'a': (ch1, ch2: char);
'b': (flag: boolean);
'K': (ALIGN: integer);
end;
procedure VarRec(var x: vr);
begin if x.ch1 = 'a' then x.ch2 := 'Z' end; { VarRec }
set+0: 7, 6, 5, 4, 3, 2, 1, 0
In C, a set could be described as a short-word array beginning at an even address. With the current set
representation, it does not matter what the lower-bound value is.
The nth element in a set [lower...upper] can be tested as follows:
#define LG2BITSLONG 5 /* log2( bits in long word) */
#define LG2BITSWORD 4 /* log2( bits in short word) */
#define MSKBITSLONG 0x1f
#define MSKBITSHORT 0x0
short *setptr; /* set as array of shorts */ int upper; /* upper bound of the set */
int elem; /* ordinal value of set element */ int i;
if ( setptr[elem >> LG2BITSWORD] & (1 << (elem & MSKBITSWORD)) ) {
/* elem is in set */ }
Pascal intset Type
The Pascal intset type is predefined as set of [0..127]. A variable of this type takes 16 bytes of storage.
The Pascal procedure, IntSetVar.p, which has an intset of the elements procedure IntSetVar(var s: intset);
[1, 3, 7, 8] begin
s := [1, 3, 7, 8]
end; { IntSetVar }
The C main program, #include <stdio.h> extern void IntSetVar(unsigned int *); int main(void)
IntSetVarMain.c { int w ; unsigned int *p, *s ; s = (unsigned int *) malloc(16);
IntSetVar(s) ; for (w = 0, p = s ; w < 4 ; w++, p++)
printf("%012o %3d \n", *p, w); printf(" 110 001 010 (binary, word 4) \n");
printf(" 876 543 210 (bits, word 4)" \n"); }
The C main program, SimValMain.c #include <stdio.h> extern void SimVal(char, char, char, short,
int, float, double, int *); int main(void)
{ char t = 1, f = 0; char c = 'z';
short si = 9; int i = 9; float sr = 9.9;
double r = 9.9; int args;
SimVal(t, f, c, si, i, sr, r, &args);
printf(" args = %06o \n", args);
The commands to compile and hostname% pc -c SimVal.p hostname% cc SimVal.o SimValMain.c –lpc
execute SimVal.p and SimValMain.c hostname% a.out args=111111
If no function prototype is provided for SimVal in SimValMain.c, then sr:shortreal must be changed to sr:real
in SimVal.p. This change is necessary because in C, a float is promoted to double in the absence of function
prototypes. In -xl mode, change sr:shortreal to sr:longreal.
Simple Types with -xl
With -xl, the Pascal real must be paired with a C float, and the Pascal integer must be paired with a C short
int.
Arrays
Since C cannot pass arrays by value, it cannot pass strings of characters, fixed arrays, or univ arrays by value.
Conformant Arrays
Pascal passes all value parameters on the stack or in registers, except for value conformant array parameters,
which are handled by creating a copy in the caller environment and passing a pointer to the copy. In addition,
the bounds of the array must be passed (see "Conformant Arrays" on page 105).
This example is the same as the single-dimension example in "Conformant Arrays," except that the var prefix
is deleted.
The Pascal procedure, ChrCAVal.p procedure ChrCAVal(a: array [lb..ub: integer] of char);
begin a[0] := 'T'; a[13] := 'o'; end; { ChrCAVal }
The C main program, #include <stdio.h> extern void ChrCAVal(char [], int, int);
ChrCAValMain.c int main(void) { static char s[] = "This is a string";
ChrCAVal(s, 0, sizeof(s) -1); printf(" %11s \n", s); }
The C main program, RetRealMain.c #include <stdio.h> extern double RetReal(double); int main(void)
{ double r, s; r = 2.0; s = RetReal(r); printf(" %f \n", s);}
The commands to compile and execute hostname% pc -c RetReal.p hostname% cc RetReal.o RetRealMain.c
RetReal.p and RetRealMain.c hostname% a.out 3.000000
Also, in the C main program just before exit, add the following line:
PASCAL_IO_DONE();
See this example:
The Pascal procedure, pasc_read.p procedure pasc_read;
var Tfile : text; data : integer;
begin writeln ('In Pascal procedure');
reset(Tfile, 'data.txt');
while not eof(Tfile) do begin
readln (Tfile,data) end;
writeln ('At end of Pascal procedure',data) end;
The C main program, main.c #include <stdio.h> extern void pasc_read(); int main(void)
{FILE *ptr; printf ("Calling Pascal routine\n");PASCAL_IO_INIT();
pasc_read(); PASCAL_IO_DONE(); printf ("After Pascal routine\n");}
The commands to compile and execute hostname% cc -c SimRef.c hostname% pc SimRef.o SimRefMain.p
SimRef.c and SimRefMain.p hostname% a.out true false z 9 9 9.9 9.9
Strings of Characters
The alfa and string types pass simply; varying strings are more complicated. All pass by reference.
The C #include <string.h> struct TVarLenStr { int nbytes; char a[26];
function, }; void StrVar(char *s10, char *s80, struct TVarLenStr *vls) {
StrVar.c static char ax[11] = "abcdefghij"; static char sx[81] = "abcdefghijklmnopqrstuvwxyz";
static char vx[6] = "varstr"; strncpy(s10, ax, 11); strncpy(s80, sx, 80); strncpy(vls->a, vx, 6);
vls->nbytes = 6;}
Avoid constructs that rely on strings being in static variable storage. For example, you could use mktemp(3)
in Pascal as follows:
Incorrect use of string in static variable storage tmp := mktemp('/tmp/eph.xxxxxx')
This use is incorrect, since mktemp()modifies its argument. Instead, use the C library routine strncpy() (see
string(3)) to copy the string constant to a declared char array variable, as in:
Correct solution using the C program Use_mktemp ;
library routine strncpy() procedure strncpy( var dest: univ string ; var srce: univ string ;
length: integer) ; external c ;
procedure mktemp(var dest: univ string); external c;
... var path: string ;
begin ... strncpy( path, '/tmp/eph.xxxxxx', sizeof(path)) ;
mktemp( path ) ; ... end .
Fixed Arrays
For a fixed-array parameter, pass the same type and size, as in this example:
The C function, FixVec.c void FixVec(int V[9], int *Sum)
{ int i; *Sum = 0; for (i = 0; i <= 8; i++) *Sum = *Sum + V[i];}
The -calign option is not needed for this example, but may be necessary if the array parameter is an array of
aggregates.
The univ Arrays
The univ arrays that are in, out, in out, or var parameters pass by reference.
Here is an example:
The C function, UniVec.c void UniVec(int V[3], int Last, int *Sum)
{ int i; *Sum = 0; for (i = 0; i <= Last; i++) *Sum += V[i];}
The commands to compile and execute hostname% cc -c StruChr.c hostname% pc -calign StruChr.o
StruChr.c and StruChrMain.p StruChrMain.p hostname% a.out string=' strvar' length= 6
Variant Records
C equivalents of variant records can sometimes be constructed, although there is some variation with the
architecture, and sometimes you have to adjust the alignment.
Following are some examples:
The C function, VarRec.c struct vlr { char tag; union {struct { char ch1, ch2;} a_var;struct {
char flag;}b_var;struct { int ALIGN; }c_var;} var_part;};
void VarRec(struct vlr *x) {if (x->var_part.a_var.ch1 == 'a')
x->var_part.a_var.ch2 = 'Z';}
The commands to compile and execute hostname% cc -c VarRec.c hostname% pc -calign VarRec.o
VarRec.c and VarRecMain.p VarRecMain.p hostname% a.out Z
The -calign option is not needed in the previous example, but may be necessary if the record contains
aggregates.
Non-Pascal Procedures
When you use the -xl option in compiling Pascal code, you can use the nonpascal keyword to declare that an
external procedure is written in another language. This keyword generally causes everything to be passed by
reference.
See this example:
The C function, NonPas.c. In the function for_C, s #include <stdio.h> void for_C(char *s, int len)
is a pointer (declared var in the procedure {int i; for (i = 0; i < len; i++) putchar(s[i]);
declaration), and len is not a pointer (not declared putchar('\n');}
var in the procedure declaration). In the function void for_NonPascal(char *s, int *len)
for_nonpascal, s is still a pointer (though not { int i; for (i = 0; i < *len; i++) putchar(s[i]);
declared var in the procedure declaration), and len putchar('\n');}
is now a pointer (though not declared var).
Value Parameters
In general, Pascal passes value parameters in registers or on the stack, widening to a full word if necessary.
Simple Types
With value parameters, simple types match, as in the following example:
The C function, SimVal.c void SimVal(char t,char f, char c, short si, int i, float sr, double r,
int *reply)
{*reply = 0; if (t) *reply += 01; if (!f) *reply += 010;
if (c == 'z') *reply += 0100; if (si == 9) *reply += 01000;
if (i == 9) *reply += 010000; if (sr ==(float)9.9) *reply += 0100000;
if (r == 9.9) *reply +=01000000;}
The C main program, #include <stdio.h> extern void GloVar(); int Year;
GloVarMain.c int main(void) { Year = 2042; GloVar(); printf( " %d \n", Year ) ; }
Hello, we meet again! Nice to see ya! I know you're eager to finish this last chapter of the first lesson. It's still
about the file. It is similar to the previous chapter. If you don't understand chapter 13, you'd better not carry
on, but re-learn it instead. This time, we will discuss :
1. Typed files
2. Untyped files
3. File commands
4. Directory commands
There are two kinds of binary files :
1. Typed files
2. Untyped files
Typed file means that the file has a uniform format throughout its contents. This kind of file includes
databases, because all of them contains the data records. Simply said, file of records. Untyped file means that
the file contains no uniform data. Although you may have seen records stored in this kind of file, that file
contains some additional information that may be different record structure. Simply said, file with no distinct
records.
First, we discuss typed files. Suppose you define a record like this :
type
Temployee = record name : string[20]; address : string[40];
phone : string[15]; age : byte; salary : longint; end;
Typed file of THAT record is defined like this :
Var F : file of Temployee;
The steps of using typed file is just the same as using text file.
1. You associate it with file name using assign.
2. Open it, using reset, OR Create it, using rewrite.
3. Use it.
Writeln in text file MUST BE CHANGED into Write and Readln with Read respectively.
4. Close it using close.
All error handling and IOResult use is all the same, so that I don't have to re-mention it all over again.
The difference is : If you open typed file with reset it doesn't mean that you can only read it (just in the text
files), but you may write on it and modify it. The command rewrite is still the same, create a new one,
discarding the file previous contents. Then, look at this example :
Easy, right ? After creating database, display it. Modify the above program to read the file contents. This is
the hint :
1. Change rewrite to reset.
2. After the second clrscr (inside repeat..until block), add : read(F,r);
3. Remove the line "write(F,r)"
That's all. You may alter the displayed message to the appropriate one. Run it and see how it's done. Good !
You've done it !
Now, it's time to understand file pointer. In order to know the current position of the file, Pascal use a file
pointer. It's simply points to the next record or byte to read. To move the file pointer, use seek :
seek(F,recordno);
The recordno simply said the record number. If you want to read the tenth record of the file at any instant, use
this :
seek(F,9); { Data record number started from 0 }
read(F,r); { r is the record variable }
You may conclude that it is easy to access the records. Say the record number, seek it, and read it. Any record
number in range could be accessed. In range means not exceeding the maximum number of record inside that
file. Therefore, it is called Random File Access.
In the other hand, text files could not behave like that. So that it requires to be handled sequentially.
Therefore, there comes the jargon Sequential File Access.
Append DOES NOT work in typed files or untyped files. It is specially designed for text files. Then how can
we append data to typed files ? Easy. Follow these steps :
1. Open the file with reset.
2. Move the file pointer after the last record using seek.
Reset causes file opened but the file pointer points to the first record. How can we know the number of
records that is stored inside a file ? Number of records can be calculated as follows :
totalrecord := filesize(f);
Here is an example of a 'crude' database. It creates a new database if it is not exist, otherwise it appends data.
repeat
: : : { All remains the same } : :
Now, how can we delete a data ? The only routine that Pascal provides is Truncate. It deletes all data starting
from where file pointer points to the end of file. You may wonder how to delete a single data record. This is
how : Suppose the record number you want to delete is stored in n.
for i:=n to totalrecord-1 do
begin seek(f,i); read(f,r); seek(f,i-1); write(f,r); end;
seek(f,totalrecord-1); truncate(f); dec(totalrecord);
Yes, you move the next record to the deleted record. The second next to the next and so on until the end of
data. After that, you can safely truncate the last record, since the last record is already stored in record
number totalrecord-1 and the last record would be a mere duplicate. Last step you must make is that you must
adjust the totalrecord to comply with present situation (after deletion).
Easy, right ? Oh, yes ! I forgot to mention : Flush cannot be applied to binary files. It's just for text files.
It is unpractical to always having file pointer tracked. You can obtain the file pointer position by using filepos
:
n:=filepos(F);
N will hold the current file position (the record number).
That's all about typed files. You may want to see this program for better details. Run it and learn how it
works.
{ A crude database recording }
uses crt;
type Temployee = record
name : string[20]; address : string[40]; phone : string[15];
age : byte; salary : longint; end;
var F : file of Temployee; c : char; r : Temployee; s : string; n : integer;
begin clrscr; write('Input file name to record databases : '); readln(s);
assign(F,s); { Associate it } {$I-} reset(F); { First, open it } {$I+}
n:=IOResult; if n<>0 then { If it's doesn't exist then }
begin {$I-} rewrite(F); { Create it }
{$I+} n:=IOResult; if n<>0 then
begin writeln('Error creating file !'); halt; end;
end
else begin { If it exists then } n:=filesize(F); { Calculate total record }
seek(F,n); { Move file pointer PAST the last record }
end;
repeat clrscr; writeln('File position : ',filepos(f));
write('Name = '); readln(r.name); { Input data }
write('Address = '); readln(r.address); write('Phone = '); readln(r.phone);
write('Age = '); readln(r.age); write('Salary = '); readln(r.salary);
write(F,r); { Write data to file } write('Input data again (Y/N) ?');
repeat
c:=upcase(readkey); { Ask user : Input again or not }
until c in ['Y','N']; writeln(c);
until c='N'; close(F); end.
Before you fully understand typed files, DO NOT CONTINUE to untyped one, it will just make you more
confused.
Text files are usually used for INI files or setting files. Or, if your game needs special setup, you can use this
skill to modify AUTOEXEC.BAT, CONFIG.SYS or even *.INI in WINDOWS directory. Typed files are
usually done for recording high scores of your game, while untyped ones are for reading your game data :
pictures, sounds, etc. Serious applications make an extensive use of file. Databases usually use typed files.
Text files are used for making memos. Untyped ones is for reading pictures and sounds, for perhaps, you
want to make presentations or just displaying the company logo.
Untyped Files
Now, we're going to discuss the untyped files. The basics is all the same. Imagine you have a typed file, but
the record is one byte long. The declaration is a bit different from typed files :
var
F : file;
This declare F as untyped files. Assign and Close are still the same, but Reset and Rewrite are a little bit
different. Instead of just passing the F, you have to specify the "record size" for that file like this:
reset(F,1);
Rewrite is just similar. What is the "record size" for? It is used to specify the number of bytes each time you
read or write from that file. Let me explain that a bit later.
The command write and read cannot be used in untyped file. Use blockwrite and blockread instead. Here is
the syntax :
blockread (f,buffer,count,actual);
blockwrite(f,buffer,count,actual);
uses dos;
var s : string;
begin s:=FSearch('FORMAT.COM','C:\DOS;C:\WINDOWS');
if s='' then writeln('FORMAT.COM not found')
else writeln('FORMAT.COM found in ',s);
end.
When found, s returns complete path and filename, otherwise empty. You may extend the directory list (the
second parameter of FSearch) using semicolon such as :
... FSearch( ... , 'C:\DOS;C:\WINDOWS;C:\SCAN;C:\TOOL');
You may wonder that you can even search a file in the PATH environment variable. Yes, you COULD ! Do it
like this :
... FSearch( ... , getenv('PATH'));
FExpand
FExpand expands a simple file name into a full name (drive, full directory, and the file name itself). It is
especially useful when user inputs a relative directory, like this (s is a string) :
s:=FExpand('..\README');
S will be like this (for example) : 'C:\PASCAL\LESSON.1\README'
FSplit
It is just contrary to FExpand, splits a fully qualified name into directory, file name, and extension. Example :
Var s : string; d : dirstr; n : namestr; e : extstr; : : s:='C:\WINDOWS\WIN.INI';
fsplit(s,d,n,e); { d = 'C:\WINDOWS\', n = 'WIN', e = '.INI' }
Look at this program for better details.
uses dos;
var s : string; d : dirstr; n : namestr; e : extstr;
begin s:=FSearch('FORMAT.COM',getenv('PATH'));
if s='' then begin writeln('FORMAT.COM not found'); halt; end;
writeln('FORMAT.COM found in ',s); fsplit(s,d,n,e); writeln(d,' ',n,' ',e);
end.
uses dos;
var s : TSearchrec; q : string;
begin write ('Enter qualifier to search = '); readln(q);
findfirst(q,AnyFile,s); while DosError=0 do begin
writeln(s.name); findnext(s); end;
end.
You may wonder how file date and time can be depicted as long integer. DOS is actually packed them. So,
after the call of findfirst and findnext, the s.time is in a packed form. How to unpack them ? Use unpacktime.
The syntax is :
unpacktime(s.time,dt);
s.time is the packed form, dt is the unpacked form. Dt is a record of DateTime, defined as follows :
type DateTime = record
Year,Month,Day,Hour, Min,Sec: Word;
end;
So, after unpacktime : dt.year holds the year dt.month holds the month, and so on (respectively).
Look at the following example, that display the file with its size and its date/time :
uses dos;
var dt : DateTime s : TSearchrec; q : string;
begin write ('Enter qualifier to search = '); readln(q);
findfirst(q,AnyFile,s); while DosError=0 do begin
unpacktime(s.time,dt); write (s.name :15, s.size:8,' ');
write (dt.month:2,'/',dt.day:2,'/',dt.year:4,' '); writeln(dt.hour :2,':',dt.min:2,':',dt.sec);
findnext(s); end;
end.
How about the attribute ? Is it packed too ? Not exactly. To detect each attribute you must do this :
if s.attr and ReadOnly = ReadOnly then write('Read only ');
if s.attr and Hidden = Hidden then write('Hidden ');
if s.attr and SysFile = SysFile then write('System ');
and so on.
You can do that detection routine to any attribute name shown above EXCEPT for AnyFile.
How can I search for ReadOnly or Hidden files only, but not archives and system files ? Do this at findfirst :
findfirst(q,ReadOnly or Hidden,s);
You may combine the attribute with OR, not and. Also, you may not combine AnyFile with others, because
the combination would not take effect.
Actually, processing attributes is a bit-wise operation, which I haven't taught you yet (later in lesson 2). But I
made it as simple as possible, so that you can understand.
PackTime, GetFTime, and SetFTime
UnpackTime has been described above. Now you may wonder how to PackTime. PackTime is used like this :
packtime(dt,n);
dt is DateTime variable (unpacked time), n is a long integer holds packed time. What does it for ? It's for
setting the file time by setftime :
setftime(f,n);
F is any file variable (text, typed or untyped), n is the packed form of date/time. Don't forget to assign f with
a file name first.
GetFTime returns the date/time of the file :
getftime(f,n);
F and n is the same as in setftime. After getftime, don't forget to unpack it first with unpacktime.
GetFAttr and SetFAttr
Likewise, you can set or get a file's attribute using setfattr and getfattr. Suppose f is any file variable (text,
typed, or untyped), and n is a word variable :
getfattr(f,n);
This will get the file attribute in n. Don't forget to associate f with a file name first. Detecting the attribute is
just the same as shown in findfirst and findnext. Setting attribute takes the same syntax. Suppose you want to
set the file as hidden and read-only :
n:=ReadOnly or Hidden;
setfattr(f,n);
DiskFree and DiskSize
DiskFree returns the number of bytes free in a specified drive. DiskSize returns the disk total size of a drive.
Both take a byte as parameter :
n:=DiskFree(d); { d is a byte, n is a longint }
n:=DiskSize(d);
d is the drive qualifier. D = 0 means that you want to search info in the current drive, d = 1 for drive A, d = 2
for drive B, d = 3 for drive C and so on. If n = -1, means that you have input an invalid drive.
Directory commands
We'll discuss these directory commands :
1. Chdir
2. Mkdir
3. Rmdir
4. Getdir
Chdir, Mkdir, and Rmdir is just the same as DOS command cd, md, and rd. All of them takes a string
parameter :
chdir('\DOS'); { same as cd\dos } mkdir('\TEMP'); { same as md\temp }
rmdir('\TEMP'); { same as rd\temp }
Getdir is used to get the directory, just like you type cd in DOS prompt, then press enter. The difference is
that getdir can be used to get the current directory of any drive, not just current drive as cd does. Getdir
syntax is like this :
getdir(d,s); { d is a byte, s is a string }
d is the drive qualifier. D = 0 means that you want to search info in the current drive, d = 1 for drive A, d = 2
for drive B, d = 3 for drive C and so on. S will return the directory. If d is invalid s just say the root directory.
Suppose d:=23 (drive W) is invalid, s will return 'W:\' as it were a root directory.
Phew ! A tedious lesson has finished. That's all folks ! If you DO understand what I've taught so long, then
congratulations ! If you might want to continue the second lesson, wait for another issue ! So long !