Question Legacy Program : How Can I Fix It ?

Jonathan

New Member
Hi all, I am working on a legacy program that was coded before I was even born !
The code must work on version 9 and above. We have a developper license and want to iliminate it to distribute on several servers. To do that, we first ilimanted the use of *.q files to use only *.p and *.i files.

Now, I have this code (see below) that work fine in *.p file but can't compile and is called like 1000 of times with different parameters with no output parameters and the fantastic use of SHARED variables. I am tring to find a good solution to hopefully just change the *.p files that is called everywhere, do you guys have any suggestions ?

Define Shared Var {4} As {10}.
**** other not shared variables ****

Find First {1} {11} NO-LOCK NO-ERROR.
IF AVAILABLE ({1}) THEN
DO:
recno = recid({1}).
END.

FORM {1}.{2} {1}.{3}
With Frame {5} Row {7} Column {8} Overlay {6} Down
Title "{9}" no-labels no-attr-space.

*** A lot more stuff like that ****
 

Jonathan

New Member
Yeah I can understadn ofr the FIND FIRST or statement like that, but can I do for the declaration of the variable ? I can receive a SHARED variable named ABCD type int, a variable names DEFG type char or even the same name but not the same type as this *.p is called like everywhere.

I am also clueless as how I will be able to build the frame for the same reasons.
 

ForEachInvoiceDelete

Active Member
Your variable declarations dont have to be dynamic, or even variables for that matter. What could you use instead? (Today's clue)

Think outside the box for a bit and if you're still stuck tomorrow ill give you another clue.
 

Jonathan

New Member
Any hints for the Shared Variable (Define Shared Var {4} As {10}.) that the info is passed as strings from and can be anything ?
I am stuggling with the FORM creation too (FORM {1}.{2} {1}.{3}
With Frame {5} Row {7} Column {8} Overlay {6} Down
Title "{9}" no-labels no-attr-space. ) I am trying to use mu buffer to set fields but it doesn't work.
 

ForEachInvoiceDelete

Active Member
Take a look at the above knowledge base. You can use it to solve the shared variable issue.

Using a mix of the two KB articles will resolve your form issue too.
 

ForEachInvoiceDelete

Active Member
Instead of assigning shared variables in the calling procedure, build a dynamic temp-table of the parameters and pass that temp-table to the .p as a single input param.

That way you dont need to statically define data types.

Just make sure you create your table data in a logical way, IE Record 1 replaces shared variable number 1.

You could make fields like... "Value,DataType" etc and use buffer:field-value (or something similar, its late so probably not correct but its in the examples above) to extact the data into the .p.
 

Jonathan

New Member
Yes ... but that implicate that I will have to edit 1000+ files instead of juste changing the one that all the other calls ...
 

TomBascom

Curmudgeon
It is rather unclear to me what it is that you are trying to do.

Modernizing legacy code is, I suppose, admirable but "to distribute on several servers" isn't making any sense to me.

Includes (".i" files) are combined with source (".p" files) and compiled to create r-code (".r" files). You only need to distribute the r-code.

So while it is unfortunate that you have include files that are called by 1000+ programs, and that will pose a challenge from a modernization perspective, that doesn't stop you from achieving your goal "to distribute on several servers".
 

Jonathan

New Member
OK, the code is working fine in *.p format BUT it is not compiling the way it is so we can,t use .r file witch we need.
 

TomBascom

Curmudgeon
That was a bad idea.

How was the .q file previously used?

IOW: Was the code something like:
Code:
/* sample1.p
 */

{myquery.q p1 p2 p3}

or

Code:
/* sample2.p
 */

run myquery.q p1 p2 p3.
 

Jonathan

New Member
it was used like this :

run liste_trans.q "string1" "string"2" string"3".

where one of those strings represented the name of the Shared Variable that was then declared un the ".q" file like this "Define Shared Var {4} As {10}." and that variable ge the return value from the file.
Basicly this file open a menu with selection to complete a form.
 

TomBascom

Curmudgeon
That is called "compile on the fly".

You cannot compile those programs into r-code. References to them will need to be re-coded.

At a minimum you will need to pass the "arguments" as parameters into a program that uses dynamic constructs. Something like:

Code:
run dynamicSample.p ( input p1, input p2, output p3 ).

will need to be used in your 1000+ references to the old code.

The outline of the replacement code will be something like this:

Code:
/* dynamicSample.p
 */

define input parameter p1 as character no-undo.
define input parameter p2 as character no-undo.
define output parameter p3 as character no-undo.

/* lots of fancy code using dynamic stuff... */

return.
 

Jonathan

New Member
ok .. I will still try to make the "new" ".p" compile and I will use the shared variable as an output in all the files.
Is something like this will work, it would involve less work on the 1000+ files, just changing one string to an output var :

/* caller.p */
run liste.p "string1" "string2" "string3" OUTPUT xSharedVar.

/* end */

/* liste.p */
DEFINE INPUT parameter p1 as character no-undo.
DEFINE INPUT parameter p2 as character no-undo.
DEFINE INPUT parameter p3 as character no-undo.
DEFINE OUTPUT parameter p4 as character no-undo.
/*end*/


oh wait .... the output parameter can be a char or int ... any idea ?
 

LarryD

Active Member
As Tom stated, the reason you cannot do it is because the code you are trying to change is only good in a development environment with compile-on-the-fly.

It also looks like you haven't taken the time to look at the dynamic queries which would solve your problem

That being said, if you insist on going down the wrong bad path, there may be a "fix" that allows you to do this, but I must say it's ugly and maintaining it will in my opinion be nightmarish. You could also look at changing it to an internal procedure

- change it from a .p to a .i

- get rid of the shared variables and make them just normal variables.

- move all non-shared variables to the top of the calling .p

The new .i would look like something this:

Code:
Find First {1} {11} NO-LOCK NO-ERROR.
IF AVAILABLE ({1}) THEN
DO:
recno = recid({1}).
END.

FORM {1}.{2} {1}.{3}
With Frame {5} Row {7} Column {8} Overlay {6} Down
Title "{9}" no-labels no-attr-space.

display {1}.{2} {1}.{3} with frame {5}.

In your existing calling .p's change the run statment to:

{mygenericdisplay.i "<actual table>" "<field1>" "<field2>" "<origsharedvarname>" "<framename>" ...}. and so on

You should take the time and do it right instead of trying to kludge something to fit ancient code. You will regret it when you have to go back and revisit.
 
Top