how to hide the warnings from method READ-XML() - progress-4gl

When I read data into a dataset with the method hDataset:READ-XML() and the path to the file is incorrect, Progress first shows a warning message (warning nr 4065) and then an error message. I can catch (using a CATCH block) the error message, but not the warning. The user must remove the warning manually.
How can I suppress this warning?
DEFINE TEMP-TABLE tt NO-UNDO
FIELD a AS CHARACTER.
DEFINE DATASET ds FOR tt.
DO ON ERROR UNDO , LEAVE:
/* Reading non existing xml-file */
DATASET ds:READ-XML("FILE", "c:\dddw\s.xml","empty","", FALSE, "","" ).
CATCH err AS Progress.Lang.Error :
MESSAGE err:GETMESSAGE(1)
VIEW-AS ALERT-BOX INFO BUTTONS OK.
END CATCH.
END.

Generelly in Progress ABL you supress messages with adding NO-ERROR after the command/method.
hDataset:READ-XML() NO-ERROR.
After that you would normally check if ERROR-STATUS:STATUS = TRUE (an error occured), however that doesn's seem to work in this case.
This examples work:
DEFINE TEMP-TABLE tt NO-UNDO
FIELD a AS CHARACTER.
DEFINE DATASET ds FOR tt.
DEFINE VARIABLE i AS INTEGER NO-UNDO.
/* Reading non existing xml-file */
DATASET ds:READ-XML("FILE", "c:\dddw\s.xml","empty","", FALSE, "","" ) NO-ERROR.
/* This is false */
DISP ERROR-STATUS:ERROR.
/* However, ERROR-STATUS:NUM-MESSAGES shows 2 errors */
IF ERROR-STATUS:NUM-MESSAGES > 0 THEN DO:
DO i = 1 TO ERROR-STATUS:NUM-MESSAGES:
DISPLAY ERROR-STATUS:GET-MESSAGE(i) FORMAT "x(66)".
PAUSE.
END.
END.
If the file you want to read is local you can (should?) do SEARCH(path+file) first - that will return ? if the file doesn't exist.
IF SEARCH("/mydir/myfile.xml") = ? THEN DO:
MESSAGE "The file seems to be lost" VIEW-AS ALERT-BOX ERROR.
RETURN.
END.
ELSE DO:
/* Read XML etc */
END.

Related

change style code function VScode time optimisation while coding

my goal is change a function to a format where the return value of the function is treated :
For example ; treating a the function scanf()
Return value of scanf : The value EOF is returned if the end of input is reached before
either the first successful conversion or a matching failure occurs.
EOF is also returned if a read error occurs, in which case the error
indicator for the stream (see ferror(3)) is set, and errno is set to
indicate the error.
Thus
scanf("%d\n",&i);
will be change to
#define RVAL(exp) do {if ((exp) == -1) { perror (#exp); exit(1); }} while (0)
...
RVAL(scanf("%d\n",&i));
Thus I want this to be done quickly means :
so what i do is look for occurences of "scanf" and replace it with "RVAL(scanf"
but the problem is i have to add another right parentheses
Can this be done fast ? using a techniques ? or a style ? where each whenever I enter scanf(); its replaced witch rval(scanf());
If you don't have many ) in your format string you can use a regex with (scanf([^)]*)); and replace with rval(\1);
*see comment

Generic Procedure to generate report from browse in progress 4gl

Procedure should handle any table linked to browse means it should be generic.
please help.
/* below code is sample to Show the data in message box ,
but only first data it is showing right now.*/
DEFINE INPUT PARAMETER hRecord AS WIDGET-HANDLE.
DEFINE INPUT PARAMETER hQuery AS WIDGET-HANDLE .
DEF VAR hFld AS HANDLE NO-UNDO.
DEFINE VARIABLE iCOunt AS INTEGER INITIAL 0.
DEFINE VARIABLE i AS INTEGER NO-UNDO.
DEFINE VARIABLE j AS integer INITIAL 1.
MESSAGE hRecord:NUM-COL VIEW-AS ALERT-BOX.
DO WHILE TRUE:
hQuery:GET-NEXT().
iCount = iCount + 1.
DO i = 1 TO hRecord:NUM-COL:
hfld = hRecord:GET-BROWSE-COL(i).
MESSAGE hfld:SCREEN-VALUE.
END.
j = j + 1.
END.
MESSAGE iCount VIEW-AS ALERT-BOX.
END PROCEDURE.
You can get a buffer field like so:
hfld = hRecord:GET-BUFFER-FIELD(i).
and then get the field's value:
DISPLAY hfld:BUFFER-VALUE.
See the docs for an explanation of what these do.

4GL ABL Openedge loop through handle?

here is my current code
def var hbTT as handle.
for each Cust:
hbTT:buffer-create().
assign
hbTT::Name = Cust.Name
hbTT::address = Cust.Address.
end.
now what I want to do is to loop through hbtt. How can I do that?
I tried
for each hbTT:
/* Do something */
end.
the error I get is
unknown or ambiguous table hbTT. (725)
thank you
You won't be able to do a loop that way, as for each requires a static name.
Instead, try this:
DEFINE VARIABLE hQuery AS HANDLE NO-UNDO.
create query hQuery.
hQuery:set-buffers(hbtt).
hquery:query-prepare('for each tt'). /* <-- Where tt is the original buffer name */
hquery:query-open().
hquery:get-first().
do while not hquery:query-off-end:
disp hbtt::name hbtt::address .
hquery:get-next().
end.

How to get the field name dynamically and update it to main table in progress

Program:It is a just maintenance program, in this one it displays the Item Code in one frame and it prompt for the input. if you enter the item code it has to displays what are the blank fields for that record in pt_mstr and display in one frame(No need to display all blank fields, just first 4 or 5 fields enough). and also in that frame only if user want to update it update directly to main table pt_mstr.
What i tried is, i just write the code for getting blank fields using buffer handle and after that i create one temp table and displaying the fields, i strucked there itself, i am unable to update fields.
My code:
/*Sample Item master Maintenance Program*/
/* DISPLAY TITLE */
{us/mf/mfdtitle.i "3+ "}
DEFINE VARIABLE hBuffer AS HANDLE NO-UNDO.
DEFINE VARIABLE i AS INTEGER NO-UNDO.
DEFINE VARIABLE j AS INTEGER NO-UNDO.
DEFINE VARIABLE hField AS HANDLE NO-UNDO.
define variable fldnm as character extent 10 no-undo.
define temp-table tt_temp no-undo
field tt_part like pt_part
field field1 as char extent 10.
form
pt_part colon 25
with frame a side-labels width 80.
setFrameLabels(frame a:handle).
/* DISPLAY */
view frame a.
repeat with frame a:
prompt-for pt_part
editing:
/* FIND NEXT/PREVIOUS RECORD */
{us/mf/mfnp.i pt_mstr pt_part "pt_mstr.pt_domain = global_domain and pt_part" pt_part pt_part pt_part }
if recno <> ? then
do:
display pt_part.
find pt_mstr where pt_part = input pt_part and pt_domain=global_domain no-lock no-error.
ASSIGN hBuffer = BUFFER pt_mstr:HANDLE.
empty temp-table tt_temp.
j = 1.
DO i = 1 TO 10:
ASSIGN hField = hBuffer:BUFFER-FIELD(i).
IF ((hField:BUFFER-VALUE = "" )) THEN
do:
/* message hField:NAME "test" view-as alert-box.*/
find first tt_temp where tt_part = pt_part no-lock no-error.
if not avail tt_temp then
do:
create tt_temp.
assign
tt_part = pt_part
field1[j] = hField:NAME.
j = j + 1.
end.
else do:
assign
field1[j] = hField:NAME.
j = j + 1.
end.
end.
end.
end.
for each tt_temp:
display field1[1] field1[2] field1[3] field1[4].
end.
end.
end.
Are you sure you need your temp-tables to do this? I've created an example using only the actual table (but created a fake temp-table instead). You would have to look into data error handling, data validation, transaction, locking etc before putting this into production of course.
/*First we need some fake data */
DEFINE TEMP-TABLE ttMockedData NO-UNDO
FIELD id AS INTEGER
FIELD dataName AS CHARACTER FORMAT "x(8)"
FIELD dataType AS CHARACTER FORMAT "x(8)"
FIELD dataDescrioption AS CHARACTER FORMAT "x(32)".
DEFINE VARIABLE iId AS INTEGER NO-UNDO.
DEFINE VARIABLE iSearch AS INTEGER NO-UNDO LABEL "Search".
PROCEDURE createData:
DEFINE INPUT PARAMETER pcName AS CHARACTER NO-UNDO.
DEFINE INPUT PARAMETER pcType AS CHARACTER NO-UNDO.
DEFINE INPUT PARAMETER pcDesc AS CHARACTER NO-UNDO.
iId = iId + 1.
CREATE ttMockedData.
ASSIGN
ttMockedData.id = iId
ttMockedData.dataName = pcName
ttMockedData.dataType = pcType
ttMockedData.dataDesc = pcDesc.
END PROCEDURE.
RUN createData("Test 1", "TESTTYPE", "A TEST").
RUN createData("Test 2", "", "ANOTHER TEST").
RUN createData("", "TESTTYPE 2", "").
RUN createData("4", "", "").
/* Program starts here */
updating:
REPEAT:
UPDATE iSearch WITH FRAME x0.
IF iSearch > 0 THEN DO:
FIND FIRST ttMockedData NO-LOCK WHERE ttMockedData.id = iSearch NO-ERROR.
IF NOT AVAILABLE ttMockedData THEN DO:
MESSAGE "Not found" VIEW-AS ALERT-BOX ERROR.
RETURN ERROR.
END.
ELSE DO:
DISP ttMockedData WITH FRAME x1 1 COLUMNS SIDE-LABELS.
/* Is there an empty field? - Then we update! */
IF ttMockedData.dataName = ""
OR ttMockedData.dataType = ""
OR ttMockedData.dataDescrioption = "" THEN DO:
DISPLAY
ttMockedData.dataName
ttMockedData.DataType
ttMockedData.dataDesc
WITH FRAME x2 1 COLUMN SIDE-LABELS TITLE "Complete the data...".
/* This isn't working with temp-tables of course! */
/* Just here to make sure you handle locking! */
FIND CURRENT ttMockedData EXCLUSIVE-LOCK.
UPDATE
ttMockedData.dataName WHEN ttMockedData.dataName = ""
ttMockedData.DataType WHEN ttMockedData.DataType = ""
ttMockedData.dataDesc WHEN ttMockedData.dataDesc = ""
WITH FRAME x2.
/* This isn't working with temp-tables of course! */
/* Just here to make sure you handle locking! */
FIND CURRENT ttMockedData NO-LOCK.
END.
END.
END.
ELSE LEAVE updating.
END.

Progress if statement

I'm a progress noob, actually having problem with basic blocks.
Below the issue is in my if else statement. It works fine when its just if, then, else then, but when I want to put in more than one statement into the if portion, I have to put it in a block, so I'm using if, then do: else, then do: but these aren't working for me. Any obvious errors you can see? My error message is **Colon followed by white space terminates a statement. (199)
INPUT FROM "r:\_content\stephen\4gl apps\dpl\output.csv".
REPEAT:
ASSIGN i_cntr = (i_cntr + 1).
myRow = "".
IMPORT DELIMITER ',' myRow.
IF myRow[5] <> "" THEN DO:
/*change this to assign 2 rows - 2 creates - 2 sets of four*/
c_fname = myRow[1].
MESSAGE
c_fname SKIP
myRow[2] SKIP
myRow[3] skip
myRow[4] skip
myRow[5] SKIP
i_cntr
VIEW-AS ALERT-BOX INFO BUTTONS OK.
END./*end of if, then do:*/
ELSE IF myRow[5] = "" THEN DO:
MESSAGE
myRow[1] SKIP
myRow[2] skip
myRow[3] skip
myRow[4] skip
i_cntr
VIEW-AS ALERT-BOX INFO BUTTONS OK.
END./*end of else if, then do:*/
END./*end of repeat*/
A very simple syntax error: you need at least one space after the END-statement.
END. /*end of if, then do:*/
/* ^ Make sure there's space above here! */
And if you don't want to follow the excellent advice in Tims answer (use CASE). This is the "complete" syntax of the IF statement.
IF expression1 THEN DO:
/* Code goes here */
END.
ELSE IF expression2 THEN DO:
/* Code goes here */
END.
ELSE DO:
/* Code goes here */
END.
expressions:
A constant, field name, variable name, or expression whose value is logical (TRUE or FALSE). The expression can include comparisons, logical operators, and parentheses.
You can also leave out the DO: END. When the IF code to be executed only consists of a single statement:
IF TRUE THEN DISPLAY "TRUE".
ELSE DISPLAY "NOT TRUE".
You could also use other block-statements (such as FOR or REPEAT) but that will most likely only create code that is hard to read.
Rather than using nested IF/ELSE, you'd be better off using a CASE statement like so:
CASE varname:
WHEN "" THEN DO: /*something */ END.
WHEN "value" THEN DO: /*something */ END.
OTHERWISE DO: /*something */ END.
END CASE.
Check the docs on this statement for more details.
I figured out the issue. This wasn't caused by a coding error. Apparently Progress doesn't like comments too close to the code, which caused it to throw an error.
END. /*end of if, then do:*/ => This is ok.
END./*end of if, then do:*/ => This caused the issue comments too close to statement.
Thanks To Tim Kuehn for his response.