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
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!
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;
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.
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;
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;