Why sscanf crashes when adding more variables? - pascal

I have a string with a word at the begining (that I want to ignore) and then some numbers that I want to store in an array. Not all of them, just some.
I use sscanf like this
var
x: integer;
y: array[0..19] of integer;
s: pchar;
begin
...
sscanf(dataline, "%s %d %d %d %d %d %d %d %d %d %d %d",
[s, #x, #y[0], #y[1], #y[2], #y[3], #y[4],
#y[5], #y[6], #y[7], #y[8], #y[9]]);
...
end;
and it's ok. But if I want to read just one more
var
x: integer;
y: array[0..19] of integer;
s: pchar;
begin
...
sscanf(dataline, "%s %d %d %d %d %d %d %d %d %d %d %d %d",
[s, #x, #y[0], #y[1], #y[2], #y[3], #y[4],
#y[5], #y[6], #y[7], #y[8], #y[9], #y[10]]);
...
end;
then I get a runtime error: "The project myproject has thrown an exception of class 'External: SIGSEGV'. at address 82E37E1".
Any ideas of what can go wrong? Thank you very much.
I'm using lazarus 1.2.4 with fpc 2.6.4 in Linux Mint 17.1 32bits.
EDIT: As Abelisto suggested, the issue was about s, I changed it from PChar to String and initialized it with some spaces and everything works fine. The code reads the lines in a TMemo to get the data, then makes a table (in a TListView) adding the values and then the minimum, average and maximum value. Note that 1023 is the maximum value possible.
procedure TfMain.bGetDataClick(Sender: TObject);
const
dataPoints = 20;
var
it: TListItem;
n, i, x, avg, min, max: integer;
y: array[0 .. dataPoints - 1] of integer;
dataLine: string;
s: string = ' ';
begin
datalist.BeginUpdate;
datalist.Clear;
n := -1;
while n < cSerIn.Lines.Count do
begin
Inc(n);
dataLine := cSerIn.Lines[n];
sscanf(dataLine, '%s %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d',
[#s, #x, #y[0], #y[1], #y[2], #y[3], #y[4],
#y[5], #y[6], #y[7], #y[8], #y[9],
#y[10], #y[11], #y[12], #y[13], #y[14],
#y[15], #y[16], #y[17], #y[18], #y[19]]);
it := dataList.Items.Add;
it.Caption := IntToStr(x);
avg := 0;
min := 1023;
max := 0;
for i := 0 to dataPoints-1 do
begin
it.SubItems.Add(IntToStr(y[i]));
avg += y[i];
if y[i] < min then min := y[i];
if y[i] > max then max := y[i];
end;
avg := avg div dataPoints;
it.SubItems.Insert(0, IntToStr(max));
it.SubItems.Insert(0, IntToStr(avg));
it.SubItems.Insert(0, IntToStr(min));
end;
datalist.EndUpdate;
end;
Also I realized my fpc version is 2.6.4, not 2.6.0. Thanks everyone for the help!

program project1;
uses
sysutils;
const
CArrCnt = 19;
var
x: integer;
y: array[0..CArrCnt] of integer;
s: string; // changes here
dataline: string;
i: Integer;
begin
dataline := 'aaa 123 0 1 2 3 4 5 6 7 8 9 10 11';
s := ' '; // changes here
sscanf(dataline, '%s %d %d %d %d %d %d %d %d %d %d %d %d %d',
[#s, #x, #y[0], #y[1], #y[2], #y[3], #y[4], #y[5],
#y[6], #y[7], #y[8], #y[9], #y[10], #y[11]]);
WriteLn(s);
Writeln(x);
for i := 0 to CArrCnt do
WriteLn(y[i]);
ReadLn;
end.
works fine.
You have to show more of the program code. For example we are not know is memory for s: pchar; was allocated.
BTW: Win7, FPC 3.1.1 32 bit.

Related

Program behaving differently in FPC and ObjFPC

Following is a program in lazarus to perform RC4 encryption and decryption when given a string. When the compiler directive {$mode fpc} is used and the string 123 is entered it crashes with External: SIGSEGV. However there is no crash when inputting the same string in {$mode objfpc}. Another inconsistency is that in {$mode objfpc} the program raises the exception External: SIGSEGV again with the input of hellow.
//{$mode fpc}
{$mode objfpc}
program project1;
uses
sysutils, strutils;
type
myArray = array[0..255] of integer;
dynamicArray = array of integer;
dynamicArrayString = array of string;
const
key = 'qwertyui';
var
plaintext : string;
function KSA(const key: string): myArray;
var
i, j, key_length, temp: integer;
S : myArray;
begin
key_length := length(key);
j := 0;
for i := Low(S) to High(S) do
S[i] := i;
for i := Low(S) to High(S) do
begin
j := ((j + S[i] + ord(key[i mod key_length + 1])) mod 256);
temp := S[i];
S[i] := S[j];
S[j] := temp;
end;
KSA := S;
end;
function PRGA(S : myArray; n : integer) : dynamicArray;
var
i, j, K, temp, sizeOfArray : integer;
key : dynamicArray;
begin
i := 0;
j := 0;
K := 0;
temp := 0;
sizeOfArray := n - 1;
SetLength(key, sizeOfArray);
while n > 0 do
begin
n := n - 1;
i := (i + 1) mod 256;
j := (j + S[i]) mod 256;
temp := S[i];
S[i] := S[j];
S[j] := temp;
K := S[(S[i] + S[j]) mod 256];
key[i-1] := K;
end;
PRGA := key;
end;
procedure getPlaintext;
begin
readln(plaintext);
end;
function encrypt : string;
var
sizeOfArray, i : integer;
cipherString : string;
cipher, keystream: dynamicArray;
S : myArray;
begin
S := KSA(key);
keystream := PRGA(S, length(plaintext));
sizeOfArray := 0;
for i := 0 to (length(plaintext) - 1) do
begin
sizeOfArray := sizeOfArray + 1;
SetLength(cipher, sizeOfArray);
cipher[i] := (keystream[i]) xor (ord(plaintext[i + 1]));
end;
cipherString := '';
for i := 0 to High(cipher) do
cipherString := cipherString + IntToHex(cipher[I], 2);
encrypt := cipherString;
end;
function stringToHex(cipherString : string) : dynamicArrayString;
var
sizeOfArray, i: integer;
DecryptArrayString : dynamicArrayString;
begin
sizeOfArray := 0;
i := 0;
// Turn the string into an array of hex
while length(cipherString) > 0 do
begin
sizeOfArray := sizeOfArray + 1;
SetLength(DecryptArrayString, sizeOfArray);
DecryptArrayString[i] := cipherString[1] + cipherString[2];
i := i + 1;
cipherString := rightstr(cipherString, length(cipherString) - 2);
end;
stringToHex := DecryptArrayString;
end;
function hexToDecimal(DecryptArrayString : dynamicArrayString) : dynamicArray;
var
sizeOfDecryptArrayInt, i : integer;
DecryptArrayInt : dynamicArray;
begin
sizeOfDecryptArrayInt := 0;
// Hex to decimal
for i := 0 to high(DecryptArrayString) do
begin
sizeOfDecryptArrayInt := sizeOfDecryptArrayInt + 1;
SetLength(DecryptArrayInt, sizeOfDecryptArrayInt);
DecryptArrayInt[i] := Hex2Dec(DecryptArrayString[i]);
end;
hexToDecimal := DecryptArrayInt;
end;
function decrypt(DecryptArrayInt : dynamicArray) : string;
var
DecryptedString : string;
S : myArray;
keystream, Decrypted : dynamicArray;
sizeOfArray, i : integer;
begin
sizeOfArray := 0;
for i := 0 to high(DecryptArrayInt) do
begin
sizeOfArray := sizeOfArray + 1;
SetLength(Decrypted, sizeOfArray);
S := KSA(key);
keystream := PRGA(S, length(plaintext));
Decrypted[i] := (keystream[i] xor DecryptArrayInt[i]);
end;
decryptedString := '';
// Turn array to string
for i := 0 to high(Decrypted) do
decryptedString := decryptedString + chr(Decrypted[i]);
decrypt := decryptedString;
end;
procedure encryptDecrypt;
var
cipherString, DecryptedString : string;
DecryptArrayString : dynamicArrayString;
DecryptArrayInt : dynamicArray;
begin
cipherString := encrypt;
writeln(cipherString);
DecryptArrayString := stringToHex(cipherString);
DecryptArrayInt := hexToDecimal(DecryptArrayString);
DecryptedString := decrypt(DecryptArrayInt);
writeln(DecryptedString);
end;
begin
getPlaintext;
encryptDecrypt;
readln;
end.
I've not been able to find the many specific cases that makes the program crash apart from a string of any three characters will always crash in {$mode fpc} but not in {$mode objfpc}
You should debug (and watch) your code so any error can be traced more easily. Use the FP IDE, it helps a lot.
Meanwhile, watch this line:
keystream := PRGA(S, length(plaintext));
And inside the PRGA function watch these lines:
sizeOfArray := n - 1;
SetLength(key, sizeOfArray);
What's wrong here? Well, suppose "plaintext" has only 1 character. So, "Length(plaintext)"=1, right? In PRGA you do "sizeOfArray:= n-1;", so sizeOfArray = 0. When you do SetLength, "Key" will be NIL because you're indicating a zero indexes length. Later, on loop, you have:
key[i-1] := K;
the program will fail because you are accessing at index 0 and the Key variable is NIL.
Careful: On "SetLength(key, sizeOfArray);" valid indexes for key are in range [0..sizeOfArray-1], but sizeOfArray must be at least 1 to be valid (sizeOfArray >= 1).
So, you should check your PRGA function. It's up to you to find the definitive solution. Don't give up. Good luck!

Delphi Changing Dynamic Value of the GrayScale Weight

I know Delphi for almost a month,
I have found a function code that change the color of the gray-scale by changing the color weights, I would like to ask, is there a faster way than this code for changing color or weighting the color?
function tform1.changecolorweighting(coloredbmp:tbitmap):tbitmap;
Var
X, Y: Integer;
P : TColor;
r,g,b: byte;
RP,GP,BP:single;
changegray:tbitmap;
changecolor:tbitmap;
begin
x:=RedWeight.value+GreenWeight.value+BlueWeight.value;
RP:=RedWeight.value/x;
GP:=Greenweight.value/x;
BP:=BlueWeight.value/x;
changegray := tbitmap.Create;
changegray.Width := coloredbmp.Width;
changegray.Height := coloredbmp.Height;
changecolor.Assign(coloredbmp);
For X := 0 to changecolor.Width do
begin
For y := 0 to changecolor.Height do
begin
P := changecolor.Canvas.Pixels[X, Y];
r := (P and $00000FF);
g := (P and $00FF00) shr 8;
b := (P and $FF0000) shr 16;
changegray.Canvas.Pixels[X, Y] := round(r * RP + g * GP + b*BP) * $010101;
end;
end;
result := changegray;
end;
if there is someone of you has a faster way of changing the color weights, please correct the code that I have found in the internet, or if you have something to offer faster than that code, please help.
The code above, it takes 1 second before the gray-scale applied with the color weighting.
thank you
This is the answer that I'm looking for, it's from Embarcadero:
https://community.embarcadero.com/blogs/entry/converting-to-grayscale-with-tbitmapscanline-property-39051
procedure ToGray(aBitmap: Graphics.TBitmap; redweightvalue,greenweightvalue,blueweightvalue:integer);
var w, h: integer; CurrRow, OffSet: integer;
x: byte; pRed, pGreen, pBlue: PByte;
function RGBToGray(R, G, B: byte): byte;
var x:integer;
RP,GP,BP:single;
begin
x:=redweightvalue+greenweightvalue+blueweightvalue;
RP:=redweightvalue/x;
GP:=greenweightvalue/x;
BP:=blueweightvalue/x;
//Result := round(0.2989*R + 0.5870*G + 0.1141*B); // coeffs from Matlab
Result := round(rp*R + gp*G + bp*B);
end;
begin
if aBitmap.PixelFormat <> pf24bit then exit;
CurrRow := Integer(aBitmap.ScanLine[0]);
OffSet := Integer(aBitmap.ScanLine[1]) - CurrRow;
for h := 0 to aBitmap.Height - 1 do
begin
for w := 0 to aBitmap.Width - 1 do
begin
pBlue := pByte(CurrRow + w*3);
pGreen := pByte(CurrRow + w*3 + 1);
pRed := pByte(CurrRow + w*3 + 2);
x := RGBToGray(pRed^, pGreen^, pBlue^);
pBlue^ := x;
pGreen^ := x;
pRed^ := x;
end;
inc(CurrRow, OffSet);
end;
end;

Permutation of numbers - all possible combinations [duplicate]

this is my simple code to generate
all possible combinations of a set for
example
1,2,3:
Display:
123
132
213
231
312
321
i want to create variable number of for loops to let the user determine the length of given string...
does anyone have an idea...
thank's in advance.
type
TNumber = '0'..'9';
procedure TForm1.Button1Click(Sender: TObject);
var
Numbers: array[0..3] of TNumber;
a, b, c, d: Integer;
s: string;
begin
Numbers[0] := '1';
Numbers[1] := '8';
Numbers[2] := '7';
Numbers[3] := '2';
for a := low(Numbers) to High(Numbers) do
for b := low(Numbers) to High(Numbers) do
for c := low(Numbers) to High(Numbers) do
for d := low(Numbers) to High(Numbers) do
begin
s := Numbers[a] + Numbers[b] + Numbers[c] + Numbers[d];
if
(Occurrences('1', s) > 1 ) or
(Occurrences('8', s) > 1 ) or
(Occurrences('7', s) > 1 ) or
(Occurrences('2', s) > 1 )
then
Continue
else
Memo1.Lines.Add(s);
end;
end;
function TForm1.Occurrences(const Substring, Text: string): Integer;
var
Offset: Integer;
begin
Result := 0;
Offset := PosEx(Substring, Text, 1);
while Offset <> 0 do
begin
Inc(Result);
Offset := PosEx(Substring, Text, offset + length(Substring));
end;
end;
end.
Here is some code that produces the output you desire. You'd need to work it around a bit for your needs, but the concept expressed in this recursive solution is the important thing:
program Permuatations;
{$APPTYPE CONSOLE}
type
TElements = '1'..'3';
procedure EnumerateCombinations(const Stem: string; Len: Integer);
var
i: Integer;
el: TElements;
Used: set of TElements;
begin
if Len=0 then
exit;
Used := [];
for i := 1 to Length(Stem) do
Include(Used, Stem[i]);
for el := low(el) to high(el) do
begin
if el in Used then
continue;
if Len=1 then
Writeln(Stem+el)
else
EnumerateCombinations(Stem+el, Len-1)
end;
end;
procedure Main;
begin
EnumerateCombinations('', 1+ord(high(TElements))-ord(low(TElements)));
end;
begin
Main;
Readln;
end.
Output:
123
132
213
231
312
321
If you change the definition of TElements, for example to '1'..'4' then you will see the 24 possible permutations.

Correct way to do non overlapped communication via serial port (COM)

I am using Delphi XE2 and I try to communicate with some device via serial port. Communication should be straight forward, but I have some problems. The device communication protocol is as follows:
I (master) send frame starting with ":" and ending with CRLF.
The device (slave) sends response in the same format (starting with ":" and ending with CRLF).
I am using WinAPI and non overlapped IO. The problem I have is that, very often I receive #0 chars as response from the device. I am sure the problem is on my side, because I can use device provider application, and I can see that communication goes fine.
Here is how I setup my COM port:
Result := False;
FFileHandle := CreateFile('COM3', GENERIC_READ OR GENERIC_WRITE, 0, nil, OPEN_EXISTING, 0, 0);
if FFileHandle = INVALID_HANDLE_VALUE then
Exit;
if not GetCommState(FFileHandle, DCB) then
Exit;
DCB.BaudRate := ASettings.BaudRate;
DCB.Flags := 1 OR // BINARY
(DTR_CONTROL_ENABLE shl 4) OR
(RTS_CONTROL_ENABLE shl 12);
DCB.XonLim := 100; // transmit XON threshold
DCB.XoffLim := 100; // transmit XOFF threshold
DCB.ByteSize := 8; // number of bits/byte, 4-8
DCB.Parity := 0; // 0-4=no,odd,even,mark,space
DCB.StopBits := ONESTOPBIT; // 0,1,2 = 1, 1.5, 2
DCB.XonChar := #1; // Tx and Rx XON character
DCB.XoffChar := #2; // Tx and Rx XOFF character
DCB.ErrorChar := #$FF; // error replacement character
DCB.EofChar := #$0A; // end of input character
DCB.EvtChar := #$0A; // received event character
if not SetCommState(FFileHandle, DCB) then
Exit;
if not SetCommMask(FFileHandle, EV_RXCHAR OR EV_TXEMPTY OR EV_RXFLAG) then
Exit;
Timeouts.ReadIntervalTimeout := 1200;
Timeouts.ReadTotalTimeoutMultiplier := 1;
Timeouts.ReadTotalTimeoutConstant := 1200;
Timeouts.WriteTotalTimeoutMultiplier := 0;
Timeouts.WriteTotalTimeoutConstant := 0;
if not SetCommTimeouts(FFileHandle, Timeouts) then
Exit;
if not PurgeComm(FFileHandle, PURGE_TXABORT OR PURGE_RXABORT OR PURGE_TXCLEAR OR PURGE_RXCLEAR) then
Exit;
if not ClearCommError(FFileHandle, Errors, #ComStat) then
Exit;
if not SetupComm(FFileHandle, 1024, 1024) then
Exit;
Result := True;
Here is how I do write:
function TCOMPortWrapper.Write(const AFrame: AnsiString): TComPortWriteRes;
var
Written: Cardinal;
Err: Cardinal;
Stat: TComStat;
Mask: Cardinal;
begin
Result := CPW_ERROR;
ClearCommError(FFileHandle, Err, #Stat);
if not IsOpened then
Exit;
if not WriteFile(FFileHandle, AFrame[1], Length(AFrame), Written, nil) then
Exit;
Mask := EV_TXEMPTY;
if not WaitCommEvent(FFileHandle, Mask, nil) then
Exit;
ClearCommError(FFileHandle, Err, #Stat);
Result := CPW_OK;
end;
And finally here it is how I do reads:
function TCOMPortWrapper.Read(out Frame: AnsiString): TComPortReadRes;
var
S: AnsiString;
BytesRead: Cardinal;
Mask: Cardinal;
begin
Result := CPR_ERROR;
if not IsOpened then
Exit;
SetLength(S, 4096);
Mask := EV_RXFLAG;
if not WaitCommEvent(FFileHandle, Mask, nil) then
Exit;
if not ReadFile(FFileHandle, S[1], Length(S), BytesRead, nil) then
Exit;
SetLength(S, BytesRead);
Frame := S;
Result := CPR_OK;
end;
As I mentioned above, in reads instead of getting actual frame I do get string of #0 chars. I think, that my mistake might be with WaitCommEvent API calls, as I am very new to serial communication.
Thanks for help!
Maybe you forgot the "#": ReadFile(FFileHandle, # S[1], Length(S), BytesRead, nil)
I'm doing like this to read string from COM:
constructor TSerialPort.Create(const APortName: String);
begin
inherited Create;
FPortHandle := INVALID_HANDLE_VALUE;
FPortName := APortName;
FDCB.DCBlength := SizeOf(DCB);
FDCB.BaudRate := CBR_19200;
FDCB.Flags := MakeCommFlags(True, False, True, True, DTR_CONTROL_DISABLE,
False, False, False, False, False, False, RTS_CONTROL_DISABLE, False);
FDCB.wReserved := 0;
FDCB.XonLim := 2048;
FDCB.XoffLim := 512;
FDCB.ByteSize := 8;
FDCB.Parity := NOPARITY;
FDCB.StopBits := ONESTOPBIT;
FDCB.XonChar := #0;
FDCB.XoffChar := #0;
FDCB.ErrorChar := #0;
FDCB.EofChar := #255;
FDCB.EvtChar := #0;
FDCB.wReserved1 := 0;
FCTO.ReadIntervalTimeout := 0;
FCTO.ReadTotalTimeoutMultiplier := 20;
FCTO.ReadTotalTimeoutConstant := 500;
FCTO.WriteTotalTimeoutMultiplier := 10;
FCTO.WriteTotalTimeoutConstant := 200;
FEOSChar := #13;
end;
function TSerialPort.Open: Boolean;
begin
Result := False;
if FPortHandle <> INVALID_HANDLE_VALUE then
Close;
FPortHandle := CreateFile(PChar('\\.\'+FPortName), GENERIC_READ or GENERIC_WRITE, 0,
nil, OPEN_EXISTING, 0, 0);
if FPortHandle <> INVALID_HANDLE_VALUE then
begin
// setup device buffers
SetupComm(FPortHandle, 2048, 2048);
Flush; // purge any information in the buffer
Result := True;
end;
end;
function TSerialPort.ReadString(var S: SysUtils.TBytes): Boolean;
const
MAX_BUF = 255;
var
B: Byte;
iCounter: Integer;
begin
Result := True;
B := 0;
SetLength(S, MAX_BUF);
ZeroMemory(#S[0], Length(S));
iCounter := 0;
while (B <> Ord(FEOSChar)) and Result and (iCounter < MAX_BUF) do
begin
Result := Read(B, 1);
if (B <> Ord(FEOSChar)) and Result then
begin
S[iCounter] := B;
Inc(iCounter);
end;
end;
if Result then
begin // delete leading zeros
while (Length(S) > 0) and (S[0] = 0) do
begin
for iCounter := 0 to Length(S)-2 do
S[iCounter] := S[iCounter+1];
SetLength(S,Length(S)-1);
end;
end
else
SetLength(S, 0);
end;
function TSerialPort.Read(var inbuf; inlen: DWORD): Boolean;
var
dwBytesRead: DWORD;
begin
Result := False;
if FPortHandle = INVALID_HANDLE_VALUE then
Exit;
dwBytesRead := 0;
Result := ReadFile(FPortHandle, inbuf, inlen, dwBytesRead, nil);
end;
FEOSChar end of string byte/char. To get string from TBytes you can use SysUtils.StringOf() function
upd:
function MakeCommFlags(fBinary, fParity, fOutxCtsFlow, fOutxDsrFlow: Boolean;
fDtrControl: Byte; fDsrSensitivity, fTXContinueOnXoff, fOutX, fInX,
fErrorChar, fNull: Boolean; fRtsControl: Byte;
fAbortOnError: Boolean): DWORD;
begin
Result := 0;
fDtrControl := fDtrControl and $03;
fRtsControl := fRtsControl and $03;
Result := Result or (Byte(fBinary) shl 0);
Result := Result or (Byte(fParity) shl 1);
Result := Result or (Byte(fOutxCtsFlow) shl 2);
Result := Result or (Byte(fOutxDsrFlow) shl 3);
Result := Result or (Byte(fDtrControl) shl 4);
Result := Result or (Byte(fDsrSensitivity) shl 6);
Result := Result or (Byte(fTXContinueOnXoff) shl 7);
Result := Result or (Byte(fOutX) shl 8);
Result := Result or (Byte(fInX) shl 9);
Result := Result or (Byte(fErrorChar) shl 10);
Result := Result or (Byte(fNull) shl 11);
Result := Result or (Byte(fRtsControl) shl 12);
Result := Result or (Byte(fAbortOnError) shl 14);
end;

OctToInt in Pascal

I'm writing assembler for imaginary processor of my design (kinda like DCPU-16) and I want to include all major number bases. I've got hex,bin and dec, but I cannot get oct, because there seem to be no OctToInt function. Any help?
function OctToInt(Value: string): Longint;
var
i, int: Integer;
begin
int := 0;
for i := 1 to Length(Value) do
int := int * 8 + StrToInt(Copy(Value, i, 1));
Result := int;
end;

Resources