I am trying to call an internal entry in cobol.
The call is OK, but the problem that there is some paragraphs after the entry that are also wrongly executed.
Here is my program:
IDENTIFICATION DIVISION.
PROGRAM-ID. ENTR1POW.
DATA DIVISION.
WORKING-STORAGE SECTION.
LOCAL-STORAGE SECTION.
PROCEDURE DIVISION.
display "BEFORE CALL NOM_PROC1======================="
PERFORM NOM_PROC1 THRU E--NOM_PROC1
display "AFTER CALL NOM_PROC1======================="
display "CALL NOM_PROC2============================="
PERFORM NOM_PROC2 THRU E--NOM_PROC2
display "CALL ENTRY1============================"
CALL 'ENTRY1'
GOBACK.
NOM_PROC1.
display "PGM ENTR1POW: BEGIN NOM_PROC1"
display "PGM ENTR1POW: END NOM_PROC1"
CONTINUE.
E--NOM_PROC1.
EXIT.
NOM_PROC2 SECTION.
display "PGM ENTR1POW: BEGIN NOM_PROC2"
ENTRY 'ENTRY1'
display "===========BEGIN ENTRY ENTRY1"
display "===========END ENTRY ENTRY1"
ENTRY 'ENTRY2'
display "===========BEGIN ENTRY ENTRY2"
display "===========END ENTRY ENTRY2"
ENTRY 'ENTRY3'
display "===========BEGIN ENTRY ENTRY3"
display "===========END ENTRY ENTRY3"
display "PGM ENTR1POW: END NOM_PROC2"
CONTINUE.
E--NOM_PROC2.
EXIT.
NOM_PROC3 SECTION.
display "PGM ENTR1POW: BEGIN NOM_PROC3"
display "PGM ENTR1POW: END NOM_PROC3"
CONTINUE.
E--NOM_PROC3 SECTION.
EXIT.
NOM_PROC4.
display "PGM ENTR1POW: BEGIN NOM_PROC4"
display "PGM ENTR1POW: END NOM_PROC4"
CONTINUE.
E--NOM_PROC4.
EXIT.
The output that i obtained is:
BEFORE CALL NOM_PROC1=======================
PGM ENTR1POW: BEGIN NOM_PROC1
PGM ENTR1POW: END NOM_PROC1
AFTER CALL NOM_PROC1=======================
CALL NOM_PROC2=============================
PGM ENTR1POW: BEGIN NOM_PROC2
===========BEGIN ENTRY ENTRY1
===========END ENTRY ENTRY1
===========BEGIN ENTRY ENTRY2
===========END ENTRY ENTRY2
===========BEGIN ENTRY ENTRY3
===========END ENTRY ENTRY3
PGM ENTR1POW: END NOM_PROC2
CALL ENTRY1============================
===========BEGIN ENTRY ENTRY1
===========END ENTRY ENTRY1
===========BEGIN ENTRY ENTRY2
===========END ENTRY ENTRY2
===========BEGIN ENTRY ENTRY3
===========END ENTRY ENTRY3
PGM ENTR1POW: END NOM_PROC2
PGM ENTR1POW: BEGIN NOM_PROC3
PGM ENTR1POW: END NOM_PROC3
PGM ENTR1POW: BEGIN NOM_PROC4
PGM ENTR1POW: END NOM_PROC4
I think that the call to the paragraphs NOM_PROC3 and NOM_PROC4 shouldn't happen.
First, think hard before you use ENTRY. In 30 years of coding, I've encountered it once, in a program written in the early 1970s, and there it served no useful purpose. Consider nested programs if you see a need for ENTRY. #BrianTiffin makes a case for ENTRY in non-mainframe environments in the comments.
The ENTRY statement establishes an alternate entry point in your code. It's not like a PERFORM. You have to explicitly return from that alternate entry point just like you return from your main entry point. This is typically done with a GOBACK statement.
Your program is behaving as it should. You have no GOBACK after the ENTRY 'ENTRY1' statement so when you CALL 'ENTRY1' your code execution continues until it encounters end of program.
Related
I'm a starter programmer and I'm trying to make a text-based RPG game (Like Zork) using Delphi Pascal language.
I made an event in which the main character open a chest and find some items:
begin
text1.text := 'You see a chest. It is unlocked.';
end;
if edit1.Text = 'Open Chest' then
text1.Text := 'You found 50 Gold Pieces, a Short Sword, a Cloth Armor and a Satchel Bag.';
end;
But I want to make it in a way that, whenever someone opens the chest AFTER the first time, the chest will be empty, since the player already took the items.
In other words, when someone type 'Open Chest' in the TEdit for the second time, it says something like "It is empty."
But how?
You have to use additional variable that will tell you whether chest has already been opened or not.
var
ChestOpened: boolean;
// initialize at beginning
ChestOpened := false;
...
if Edit1.text = 'Open Chest' then
begin
if ChestOpened then
Text1.Text := 'Chest is empty'
else
begin
ChestOpened := true;
Text1.Text := 'You found 50 Gold Pieces, a Short Sword, a Cloth Armor and a Satchel Bag.'
end;
end;
I'm starting with PL/SQL, this is my first Procedure and I find it difficult to compile; I have tried so many different versions, I carry the last attempt. I don't understand why SQLDEVELOPER say me: "procedure compiled (with errors)".
The compiler say me:" Errore(10,1): PLS-00103: Trovato il simbolo (find) "DECLARE" instead: begin function pragma procedure subtype type current cursor delete exists prior "
If there are other errors (also logical) please tell me. I would like to improve.
Thank you all for the answers
My Procedure:
create or replace PROCEDURE calcola_giorn (giornata IN INTEGER) is
-- si tenga presente che in realtà giornata=idPartita
somma NUMBER;
idcal NUMBER;
nometorn VARCHAR2;
idformaz NUMBER;
nomesquadr VARCHAR2;
DECLARE;
SELECT idcalendario INTO idcal FROM partita WHERE id= giornata;
SELECT nometorneo INTO nometorn FROM calendario WHERE id= idcal;
CURSOR formazioni_di_giornata IS
SELECT id, nomesquadra FROM formazione where idpartita= giornata;
CURSOR giocatori_di_giornata IS
SELECT votogiocatore FROM schiera WHERE idformazione= idformaz;
Begin
OPEN formazioni_di_giornata;
FOR tupla_formazione IN formazioni_di_giornata LOOP
somma:=0;
FETCH formazioni_di_giornata INTO idformaz, nomesquadr;
OPEN giocatori_di_giornata;
FOR tupla_giocatore IN giocatori_di_giornata LOOP
somma:= somma + tupla_giocatore.votogiocatore;
END LOOP;
CLOSE giocatori_di_giornata;
UPDATE partecipa SET punti= somma WHERE ( (nomesquadra= nomesquadr) AND (nometorneo= nometorn));
END LOOP;
CLOSE formazioni_di_giornata;
EXCEPTION WHEN OTHERS THEN raise_application_error(-20001,'An error was encountered - '||SQLCODE||' -ERROR- '||SQLERRM);
END calcola_giorn;
Varchar limit should be defined, like varchar2(100)
Replace DECLARE; with BEGIN
All your cursors should go before BEGIN
Put END; for the procedure
You can try compiling after making these changes.
I use a server client component, and when a file is being received in the TransferFile event of this component, I use an alert message component. So I want, if the user clicks on the alert message, the program to continue executing code in the TransferFile event to accept the file transfer in case the button is clicked, or to exit the procedure when not.
pls see bellow code:
procedure TfrmReadFile.ServerReceiveEvent(Sender: TObject;
Client: TSimpleTCPClient; Event: TTOOCSEvent);
begin
if (Event is TTOOCSEventFileTransfert) then
begin
Alert.Show;
if Alert.OnAlertClick then
begin
with (Event as TTOOCSEventFileTransfert) do
if (dlgSaveFile.Execute) then
with TMemoryStream.Create do
try
Write(Content[1], Length(Content));
SaveToFile(dlgSaveFile.FileName);
finally
Free;
end;
end;
end;
end;
but "if Alert.OnAlertClick then" is wrong
procedure TfrmReadFile.AlertAlertClick(Sender: TObject);
begin
end;
Please help me for these codes.
the AlertMessage is one of the TMS component and it hasn't ShowModal but it has Alert.Show Procedure that I use. and I want to pause the executing code untill the alert show time is finish and if user not click on alert executing the code aborted and no file saved.
From your code it's obvious that by the time you get to show the Alert, the file transfer already occurred: it's only a matter of "Do I save to file" or "Do I discard the content I already received". I'm inferring this information from your use of the TMemoryStream.Write() - that function takes a buffer as a parameter, so I assume the Content[1] gives your the buffer. This also means the Content is allready populated with the data you need. Too late to NOT transfer it, it's already in memory, all you can do is save it to disk or discard it.
I also have no idea how TMS's Alert works, but I'm going to assume only one Alert can be shown at any given time, and I'm going to assume you dropped your Alert on a component (ie: There's only one Alert in the whole program).
You should first alter the code for your "received event" to immediately move the content to a TMemoryStream. Also make sure you don't get into trouble with recursive re-entrance. Add a private field to your form, call it FLastContentReceived: TMemoryStream; Now alter your code to look like this:
procedure TfrmReadFile.ServerReceiveEvent(Sender: TObject;
Client: TSimpleTCPClient; Event: TTOOCSEvent);
begin
if (Event is TTOOCSEventFileTransfert) then
begin
// Re-entry before we managed to handle the previous received file?
if Assigned(FLastContentReceived) then
raise Exception.Create('Recursive re-entry not supported.');
// No re-entry, let's save the content we received so we can save it to file
// if the user clicks the Alert button.
FLastContentReceived := TMemoryStream.Create;
// I don't know what Content is, but you've got that in your code so I
// assume this will work:
FLastContentReceived.Write(Content[1], Length(Content);
// Show the alert; If the OnAlertClick event fires we'll have the received file content
// in the FLastContentRecevied and we'll use that to save the file.
Alert.Show;
end;
end;
You're trying to do an if on Alert.OnAlertClick - so I assume there's an event in your Alert component that's called OnAlertClick. Write this in it's event handler:
procedure TfrmReadFile.AlertAlertClick(Sender: TObject);
begin
if not Assigned(FLastContentReceived) then raise Exception.Create('Bug');
try
if dlgSaveFile.Execute then
FLastContentReceived.SaveToFile(dlgSaveFile.FileName);
finally FreeAndNil(FLastContentReceived);
end;
end;
You'd also need a way to discard the FLastContentReceived if the form is closed before the Alert button gets clicked OR there's a time-out (the Alert goes away without the user clicking it). The first job (getting rid of FLastContentReceived) when the form is closed is simle: add this to your form's OnDestroy:
FLastContentRecevid;Free;
Handling the timeout might a bit more difficult. If the Alert has an event that's called when the alert times out and the Balloon goes away without being clicked then use that event handler to do this:
FreeAndNil(FLastContentRecevid);
If it offers no such thing you could set up a TTimer for an interval equal to the timeout of the alert (or slightly longer to be safe), enable it before showing the alert and do this from it's OnTimer:
procedure TFrmReadFile.Timer1Timer(Sender: TObject);
begin
Timer1.Enabled := False;
FreeAndNil(FLastContentRecevid);
end;
I need to automate entering a certain character (Russian letter Э). In Spy++ the corresponding message looks like this:
WM_CHAR chCharCode: '221' (221) cRepeat:1 ScanCode:28 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
In order to send this message programmatically, I use this Delphi code:
SendMessage(Self.PassengerGrid, WM_CHAR, WPARAM(221), LPARAM($280001));
When I examine the results of running my code in Spy++, I see following message:
WM_CHAR chCharCode: '89' (89) cRepeat:1 ScanCode:28 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
Something must be wrong with wParam of my SendMessage call.
How can I fix it (so that the chCharcode is equal to 221)` ?
Update 1:
The machine, where this error occurs, has two keyboard languages - English and Russian.
I noticed that when the following code
SendMessage(MyGridHandle, WM_KEYDOWN, VK_OEM_7, LPARAM($390000));
SendMessage(MyGridHandle, WM_CHAR, WPARAM(221), LPARAM($280001));
SendMessage(MyGridHandle, WM_KEYUP, VK_OEM_7, LPARAM($c0390001));
is executed, the selected language (according to tray icon) changes from Russian to English.
Whatever character I transmit in WM_CHAR, WPARAM of the message is always 0x59 (89).
Update 2: Using WM_UNICHAR instead of WM_CHAR doesn't help.
You should send UTF-16 code of a character as WPARAM (that is 1069 for Russian 'Э'), ex:
procedure TForm1.Button1Click(Sender: TObject);
begin
PostMessage(Edit1.Handle, WM_CHAR, WPARAM(1069), LPARAM(0));//$280001));
end;
I'm currently trying to create a "Profile Manager" using a TIniFile to store the data, and displaying the data in various components on a form (editboxes and such).
On the form, i've got a Combobox. This serves as a way of displaying the "Profile Name" as set by the user.
The data is being stored in the format of 1 profile per inifile section. Each section contains the configuration data for 1 profile including the Profile Name. The profile name key is the same across each section. This is the sort of layout i've currently got in the inifile (as an example);
[0]
PROFILE_NAME=Profile 1A
PROFILE_DATA=Profile Data 1A
PROFILE_PASS=Profile Password 1
PROFILE_USER=Profile Username 1
[1]
PROFILE_NAME=Profile 1B
PROFILE_DATA=Profile Data 1B
PROFILE_PASS=Profile Password 1B
PROFILE_USER=Profile Username 1B
What i want to do is load a list of all values with the key "PROFILE_NAME" into a combobox regardless of what section they're located in. The section names themselves are references to the itemindex in the combobox when that data was added.
From there, i can handle loading the other data into it's relevant fields, but i'm having a problem figuring out how to load the "PROFILE_NAME" values into the combobox. Any ideas?
For those familiar with the Voice Communication program "Ventrilo", it features something similar to what i'm trying to achieve with it's "Server and User Manager". It's inifile layout is very similar, and the only difference i can find is that it has a "USER_COUNT" value referencing how many users have been added. Each user has servers assigned to them, rather than the servers being accessible by every user.
Is it possible for me to achieve this?
You have to use TIniFile.ReadSections to get a list of all the section names, and then you can loop through them and read the individual PROFILE_NAME from each of those sections. (I prefer TMemIniFile, as TIniFile is based on the WinAPI functions directly and has issues sometimes on network drives when trying to update with new values. TMemIniFile also works cross-platform when you get to XE2.)
I'm creating the TMemIniFile and TStringList and freeing them, but if you're using them repeatedly you'll probably want to create them in your form's OnCreate and free them in FormClose instead; that way you'll have a list of the section names to match back to the items in the ComboBox when you want to access the rest of the items in the OnClick event to populate the rest of the form.
var
Sections: TStringList;
Ini: TMemIniFile;
s: string;
begin
Sections := TStringList.Create;
try
Ini := TMemIniFile.Create('YourIniFile.ini');
try
Ini.ReadSections(Sections);
for s in Sections do
ComboBox1.Items.Add(Ini.ReadString(s, `PROFILE_NAME`, `Empty`);
finally
Ini.Free;
end;
finally
Sections.Free;
end;
end;
To make it easier to tie back to the items in the ComboBox, declare a new integer variable (i in my snippet below), and change the for loop to this (make sure you don't sort the Sections - let the ComboBox handle the sorting!):
for i := 0 to Sections.Count - 1 do
begin
s := Ini.ReadString(Sections[i], 'PROFILE_NAME', 'Empty');
ComboBox1.Items.AddObject(s, TObject(i));
end;
To get the section name again when the user clicks a combobox item:
procedure TForm1.ComboBox1Click(Sender: TObject);
var
i: Integer;
SectionName: string;
begin
// Get the Sections item index we stored above
i := Integer(ComboBox1.Items.Objects[ComboBox1.ItemIndex]));
// Get the associated Sections section name
SectionName := Sections[i];
// Use the retrieved section name to get the rest of the values
ProfileNameEdit.Text := Ini.ReadString(SectionName, 'PROFILE_NAME', '');
ProfileDataEdit.Text := Ini.ReadString(SectionName, 'PROFILE_DATA', ''); // etc
end;