Command Line Args in pascal - command-line-arguments

I am new in pascal I have a program which gives result ....
I need to pass command line input in in given variable ip1 and ip2.
Its can be achieved by ParamStr[1] but it doesn't work.
program main;
var
output : integer;
var
ip1 : integer;
var
ip2 : integer;
function add(input1,input2:integer) : integer;
var
result: integer;
begin
if (input1 > input2) then
result := input1
else
result := input2;
add := result;
end;
begin
ip1 := 2533;**{ command line input}**
ip2 := 555;**{ command line input}**
output := add(ip1,ip2);
writeln( ' output : ', output );
end.K

As the other answer says, you use ParamCount and ParamStr to access command line parameters.
ParamCount returns the number of parameters passed on the command line, so you should check it first to see if you've received enough information.
ParamStr allows you to access each of the parameters passed. ParamStr(0) always gives you the full name of the executing program (including the path). Additional parameters are retrieved using the ordinal order in which they were passed, with ParamStr(1) being the first, and ParamStr(ParamCount) being the last. Each value received using ParamStr is a string value, and therefore has to be converted into the appropriate type before you can use it.
Here's a working example (pretty trivial, and all error checking omitted - you should, for instance, protect the code using StrToInt to handle errors if something is provided that won't convert to an integer).
program TestParams;
uses
SysUtils;
var
Input1, Input2, Output: Integer;
begin
if ParamCount > 1 then
begin
Input1 := StrToInt(ParamStr(1));
Input2 := StrToInt(ParamStr(2));
Output := Input1 + Input2;
WriteLn(Format('%d + %d = %d', [Input1, Input2, Output]));
end
else
begin
WriteLn('Syntax: ', ParamStr(0)); { Just to demonstrate ParamStr(0) }
WriteLn('There are two parameters required. You provided ', ParamCount);
end;
WriteLn('Press ENTER to exit...');
ReadLn;
end.
Calling it without parameters (or only one) displays the following:
C:\Temp>TestParams
Syntax: C:\Temp\TestParams.exe
There are two parameters required. You provided 0
Press ENTER to exit...
C:\Temp>TestParams 2
Syntax: C:\Temp>TestParams.exe 2
There are two parameters required. You provided 1
Press ENTER to exit...
Calling it with two parameters displays
C:\Temp\TestParams 2 2
2 + 2 = 4
Press ENTER to exit...

You need to understand the difference between a string and an integer.
To convert betwwen an integer such as 123 and the string of characters 1 2 3 you need to use a function. strtoint is one such function, converting a string to an integer. inttostr is another, converting from an integer to a string.
The command-line data is supplied via paramstr(n) as a string.
intvar := strtoint(paramstr(n));
assigns the value of the string to the integer variable intvar.
Whereas writeln has facilities to convert an integer argument to a formatted string, the way you have used it is attempting to output a string, so you need to convert the integer output to a string.
writeln(' output : ', inttostr(output) );
should do that very nicely.
var
x : string;
pcnt : integer;
begin
writeln('Parameter count=',inttostr(paramcount));
for pcnt := 1 to paramcount do
writeln('Parameter ',pcnt, ' of ',paramcount,' = ',paramstr(pcnt));
readln(x);
end.
should display the parameter list.
Indeed it is the case that the writeln procedure will recognise the variable type and take steps to format the value appropriately as a string, as has arrogantly been pointed out.
The issue to me is the difference between a string and an integer. paramstr returns a string which must be converted to an integer. After more than forty years' experience in Pascal, it's my opinion that it's better for a beginner to go through the exercise of converting each way and then use the conversion facility inbuilt in writeln.
First walk, then run. You first need to understand the steps in the procedure. Then you can start using the shortcuts - once you've mastered the basics.

Related

how to validate input with "real" as the variable to numbers only?

im a coding newbie, currently using freepascal to learn. i want to make a simple temperature converter. im struggling at how to validate the input. because im using "real" as var, and i cant validate the input to numbers and negative sign only. i want to write "false input" and repeat to temperature input, if the input contains alphabet/alphanumeric. but when i input the temperature in alphabet/alphanumeric it will just exiting from program. how to do this correctly? is there any solution?
input validation with "real" as the variable
here's my current code
program Fahrenheit_to_Celsius;
uses crt;
function strtofloat (floatstring : string) : extended;
var F: string;
floatvalue: extended;
C: real;
exit: boolean;
decision: shortstring;
begin
clrscr;
textattr :=$3;
gotoxy (52,1);
writeln ('Fahrenheit to Celsius Converter');
repeat
write ('Input Fahrenheit: ');
readln (F);
begin
try
F := strtofloat ('10 E 2');
except
on exception : econverterror do
showmessage (exception.message);
end;
try
F := strtofloat ('$FF');
except
on exception : econverterror do
showmessage (exception.message);
end;
C := ((F-32)*(5/9));
writeln ('Temperature in Celsius: ', C:0:5);
begin
writeln;
gotoxy ((wherex () + 56), (wherey() - 0));
writeln ('Convert again or exit?');
gotoxy ((wherex () + 31), (wherey() - 0));
writeln ('Input e then press enter to exit or input anything else to convert again');
write ('Decision:');
readln (decision);
if (decision = 'e') then
exit := true
else
exit := false;
gotoxy ((wherex () + 0), (wherey() - 3));
delline;
gotoxy ((wherex () + 0), (wherey() - 0));
delline;
end;
until exit;
end.
It's been a long time since I practiced pascal but I will give you an idea, I think you cannot validate it this way because if you declare the input as real once the program recive an non valid input it exits, so what I suggest, is to declare the variable as string instead, then you create a function to validate it, finally if the function returns true you convert the string to float.
The function should loop through every character in the recieved string and returns false if
one character is not a number or not a .
the string contains more then one . ( create a variable and increment it every time you catch a character equal to . )
the first character is .
the last character is .

why does computer print a value which is out of range of string in pascal?

In pascal programming language i wrote the following code
Program practice;
//**** Function to get back N characters from a P position from a given string
Function get_char(s1:String;n,p :Integer): String;
Var
temp : String;
i : Integer;
Begin
temp:= s1[p];
For i:= p+1 To p+n-1 Do
temp := temp + s1[i];
get_char := temp;
End;
//**** end of the function *****
Var
s1,s2: String;
n,p: Integer;
Begin
Write('Enter the number of char:');
readln(n);
write('Enter the position:' );
readln(p);
write('Enter the string : ');
readln(s1);
write(get_char(s1,n,p));
Readkey;
End.
Know that this function gets back a certain number of characters given by the user from a certain postion in the string .
for example 'hello' with p = 1 and n =2 the result will be 'he' .
Now imagine p is 3 and n =4 then then the output of the function will be 'lloA'.
So my question is what happends in this case or why do we get such a result ? ( please give me details if its related to memory).
When your function reads characters beyond the end of the string, it reads memory content that happens to be in those memory positions, and interpretes that memory content as characters. Memory content beyond the length of a string is not defined, nor predictable. Some compilers add an explicit Char(0) as a terminating character. This zero character is not included in the length of the string.
To prevent wrong return values form your function, you can either,
a) turn range checking on in compiler settings, which will raise runtime errors
b) check that p + n - 1 <= Length(s) and if not, limit reading to Length(s).
Selecting option b gives a freedom to read until the end of any string by passing MaxInt for argument p.

Reading A Variable As Both A Number And String of Words

I am trying to get Dep_Code to read as a string after choosing the options given (1, 2 or 3). I first had it set to integer in my first program (I think) and was able to get it to read out the options given as words (Accounts ACC or the others). However, it was accidentally deleted. I've tried various ways to get it even setting Dep_Code as a string but its not working and I keep getting a variety of errors. Btw, I'm not familiar with programming so I'm aware that the following code is quite incorrect... but I hope you all can help. Thank you!
REPEAT
writeln ('Please enter the Department Code:- ');
writeln;
writeln ('1. Accounts (ACC)');
writeln ('2. Human Resources (HR)');
writeln ('3. Operations (OP)');
writeln;
readln (Dep_Code);
IF Dep_Code = 1 THEN
Dep_Code := ('Accounts (ACC)')
ELSE IF Dep_Code = 2 THEN
Dep_Code := ('Human Resources(HR)')
ELSE IF Dep_Code = 3 THEN
Dep_Code := ('Operations (OP)');
UNTIL ((Dep_Code >= 1) AND (Dep_Code <= 3));
This is impossible. Pascal is a strictly typed language, and something cannot be an Integer and a string at the same time, and variables cannot change type either:
IF Dep_Code = 1 THEN
Dep_Code := ('Accounts (ACC)')
But you don't need a string at all. Keep it an integer. The functions that handle the various depts can write or define such strings, if necessary. Your logic for the menu does not need a string variable.
Do something like:
procedure HandleAccounts(var Error: Boolean);
begin
...
end;
// Skipped the other functions to keep this answer short ...
var
Dep_Code: Integer;
AllFine: Boolean;
// Skip the rest of the necessary code ...
repeat
// Skipped the Writelns to keep this answer short ...
Readln(Dep_Code);
Error := False;
case Dep_Code of
1: HandleAccounts(Error);
2: HandleHumanResources(Error);
3: HandleOperations(Error);
else
Error := True;
end;
until not Error;
Above, I skipped some of the code. You can fill in the blanks, I guess.

Binary file error in Lazarus Pascal with custom records - error SIGSEGV

I don't work with Pascal very often so I apologise if this question is basic. I am working on a binary file program that writes an array of custom made records to a binary file.
Eventually I want it to be able to write multiple arrays of different custom record types to one single binary file.
For that reason I thought I would write an integer first being the number of bytes that the next array will be in total. Then I write the array itself. I can then read the first integer type block - to tell me the size of the next blocks to read in directly to an array.
For example - when writing the binary file I would do something like this:
assignfile(f,MasterFileName);
{$I-}
reset(f,1);
{$I+}
n := IOResult;
if n<> 0 then
begin
{$I-}
rewrite(f);
{$I+}
end;
n:= IOResult;
If n <> 0 then
begin
writeln('Error creating file: ', n);
end
else
begin
SetLength(MyArray, 2);
MyArray[0].ID := 101;
MyArray[0].Att1 := 'Hi';
MyArray[0].Att2 := 'MyArray 0 - Att2';
MyArray[0].Value := 1;
MyArray[1].ID := 102;
MyArray[1].Att1:= 'Hi again';
MyArray[1].Att2:= MyArray 1 - Att2';
MyArray[1].Value:= 5;
SizeOfArray := sizeOf(MyArray);
writeln('Size of character array: ', SizeOfArray);
writeln('Size of integer var: ', sizeof(SizeOfArray));
blockwrite(f,sizeOfArray,sizeof(SizeOfArray),actual);
blockwrite(f,MyArray,SizeOfArray,actual);
Close(f);
Then you could re-read the file with something like this:
Assign(f, MasterFileName);
Reset(f,1);
blockread(f,SizeOfArray,sizeof(SizeOfArray),actual);
blockread(f,MyArray,SizeOfArray,actual);
Close(f);
This has the idea that after these blocks have been read that you can then have a new integer recorded and a new array then saved etc.
It reads the integer parts of the records in but nothing for the strings. The record would be something like this:
TMyType = record
ID : Integer;
att1 : string;
att2 : String;
Value : Integer;
end;
Any help gratefully received!!
TMyType = record
ID : Integer;
att1 : string; // <- your problem
That field att1 declared as string that way means that the record contains a pointer to the actual string data (att1 is really a pointer). The compiler manages this pointer and the memory for the associated data, and the string can be any (reasonable) length.
A quick fix for you would be to declare att1 something like string[64], for example: a string which can be at maximum 64 chars long. That would eliminate the pointer and use the memory of the record (the att1 field itself, which now is a special static array) as buffer for string characters. Declaring the maximum length of the string, of course, can be slightly dangerous: if you try to assign the string a string too long, it will be truncated.
To be really complete: it depends on the compiler; some have a switch to make your declaration "string" usable, making it an alias for "string[255]". This is not the default though. Consider also that using string[...] is faster and wastes memory.
You have a few mistakes.
MyArray is a dynamic array, a reference type (a pointer), so SizeOf(MyArray) is the size of a pointer, not the size of the array. To get the length of the array, use Length(MyArray).
But the bigger problem is saving long strings (AnsiStrings -- the usual type to which string maps --, WideStrings, UnicodeStrings). These are reference types too, so you can't just save them together with the record. You will have to save the parts of the record one by one, and for strings, you will have to use a function like:
procedure SaveStr(var F: File; const S: AnsiString);
var
Actual: Integer;
Len: Integer;
begin
Len := Length(S);
BlockWrite(F, Len, SizeOf(Len), Actual);
if Len > 0 then
begin
BlockWrite(F, S[1], Len * SizeOf(AnsiChar), Actual);
end;
end;
Of course you should normally check Actual and do appropriate error handling, but I left that out, for simplicity.
Reading back is similar: first read the length, then use SetLength to set the string to that size and then read the rest.
So now you do something like:
Len := Length(MyArray);
BlockWrite(F, Len, SizeOf(Len), Actual);
for I := Low(MyArray) to High(MyArray) do
begin
BlockWrite(F, MyArray[I].ID, SizeOf(Integer), Actual);
SaveStr(F, MyArray[I].att1);
SaveStr(F, MyArray[I].att2);
BlockWrite(F, MyArray[I].Value, SizeOf(Integer), Actual);
end;
// etc...
Note that I can't currently test the code, so it may have some little errors. I'll try this later on, when I have access to a compiler, if that is necessary.
Update
As Marco van de Voort commented, you may have to do:
rewrite(f, 1);
instead of a simple
rewrite(f);
But as I replied to him, if you can, use streams. They are easier to use (IMO) and provide a more consistent interface, no matter to what exactly you try to write or read. There are streams for many different kinds of I/O, and all derive from (and are thus compatible with) the same basic abstract TStream class.

Separating numbers in a string. Pascal

I have a problem. I'm learning Pascal for only a couple of weeks and I don't know much. I have to write a program that has to calculate something out of 3 entered numbers. The problem is all 3 of them need to be entered in one edit with spaces in between. So basically I have a string 'number number number'. How do I separate these numbers as 3 separate strings so I can convert them into Integer.
In pascal there are built-in procedures to retrieve the input from the console.
The easiest way to get numeric inputs is to use Read()/ReadLn(), which also can make the conversion from string to a numeric value:
procedure GetNumbers(var x,y,z: Integer);
begin
WriteLn('Enter three numbers separated with space and then press enter.');
ReadLn(x,y,z);
end;
Here, the ReadLn() detects three inputs separated with a space, waits for the [Enter] key and assigns the integer values to the x,y,z variables.
Using the copy function is one way. Sorry about the formatting, I can't understand how to paste code snippets properly in these answer sections.
function TMyForm.Add( anEdit : TEdit ) : integer;
var
Idx : integer;
TempString : string;
function GetNext : integer;
begin
result := result + StrToInt( copy( TempString, 1, Idx - 1 ) );
TempString := copy( TempString, Idx + 1, MAXINT );
end;
begin
result := 0;
TempString := anEdit.Text;
repeat
Idx := pos( ' ', TempString );
if Idx > 0 then
result := GetNext;
until Idx = 0;
if trim( TempString ) <> '' then
//this is the last piece of it then
result := result + StrToInt( trim( TempString ) );
end;
You need to also take care that the values entered are numbers and not letters, usually done with try..except blocks.

Resources