PxPlus User Forum

Twitter Twitter Twitter

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - Loren Doornek

Pages: [1] 2 3 4
1
Programming / Re: Determining numbers used in an ASCII sequence.
« on: June 23, 2022, 03:24:25 PM »
That's an interesting challenge :-) 

I wrote a function to do this by converting the input values to a decimal number, then just subtracting the two values. You may need to tweak it depending on whether you need to include the starting/ending values.  You can test it by passing in hex values, then comparing to an actual hex value. 

Here's a couple examples of running it, and the code is further below.

Test two simple Hex values:
RUN
Value 1:0A
Value 2:0F
Type for each position: H
Difference is: 5

Test two numeric values:
RUN
Value 1:123
Value 2:456
Type for each position: NNN
Difference is: 333

Test two hex values, and validate result:
RUN
Value 1:01A1
Value 2:01F1
Type for each position: HHHH
Difference is: 80
PRINT DEC($0001A1$)
 417
PRINT DEC($0001F1$)
 497
PRNT 497-417
 80

Testing using your values:
RUN
Value 1:A000ZZ
Value 2:A001FF
Type for each position: ANNPAP
Difference is: 196

Here's the code:

Code: [Select]
0010 ! Trying to find the number of slots used between a starting and ending alphanumeric number, i.e. the number of slots used between A000ZZ and A0010F.  Positions 4 & 6 can be 0-Z, position 5 A-Z (with the exclusion of :;<=>?@)
0020 BEGIN
0030 LET type$="HHHHHH" ! Specify allowed characters for each slot.  H=Hex,N=Numbers,A=Alphanumeric,Blank=whatever default is setup in the function
0040 LET type$="ANNPAP",val1$="A000ZZ",val2$="A001FF" ! Defaults from example provided
0050 !
0060 INPUT EDIT "Value 1:",val1$
0070 INPUT EDIT "Value 2:",val2$
0080 INPUT EDIT "Type for each position: ",type$; LET type$=UCS(type$); IF POS("HNAP"^type$) THEN PRINT "Invalid Types"; GOTO *SAME
0090 !
0100 LET val1$=UCS(val1$),val2$=UCS(val2$)
0110 IF NUL(val1$) OR NUL(val2$) THEN END
0120 !
0130 LET ret1$=FNval$(val1$,type$)
0140 LET ret2$=FNval$(val2$,type$)
0150 !
0160 IF POS("ERROR"=ret1$+ret2$) THEN PRINT "Invalid Values Entered" ELSE PRINT "Difference is: "+STR(NUM(ret2$)-NUM(ret1$))
0170 END
0180 !
0200 ! ^100
0210 DEF FNval$(LOCAL val$, LOCAL type$)
0220 ! Define available characters
0230 LOCAL ret$,slots,alpha$,numer$,hex$,alphanumer$,i,val,deftype$
0240 LET alpha$="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
0250 LET numer$="0123456789"
0260 LET alphanumer$=numer$+alpha$
0270 LET hex$="0123456789ABCDEF"
0280 !
0290 ! Define maximum length of input value
0300 LET slots=6 ! Max length of input value
0310 IF LEN(val$)>slots THEN LET ret$="ERROR"; GOTO 0640
0320 !
0330 ! Define available characters for each position
0340 LET deftype$="H"; IF NOT(NUL(type$)) THEN IF POS(MID(type$,1,1)="HNAP") THEN LET deftype$=MID(type$,1,1) ! Set the default type to whatever the first specified type is, or Hex by default
0350 LOCAL DIM avlchar$[1:slots]
0360 LET avlchar${ALL}=TBL(POS(MID(type$,1,1)="HNAP"),hex$,hex$,numer$,alpha$,alphanumer$) ! Set the default allowed characters for each slot. Default is the allowed characters from the first specified column, or hex if nothing specified
0370 !
0380 ! Set the allowed characters for each slot
0390 LET type$=PAD(type$,slots,0,deftype$) ! Pad type$ to correct length using default type
0400 FOR i=1 TO slots
0410 LET avlchar$[i]=TBL(POS(MID(type$,i,1)="HNAP"),$$,hex$,numer$,alpha$,alphanumer$)
0420 NEXT i
0430 !
0440 ! Determine how much 1 unit in each slot is worth
0450 LOCAL DIM slotval[1:slots]
0460 LET slotval[slots]=1
0470 FOR i=slots-1 TO 1 STEP -1
0480 LET slotval[i]=slotval[i+1]*LEN(avlchar$[i+1])
0490 NEXT i
0500 !
0510 ! Pad the input string, and check for invalid characters
0520 LET val$=PAD(MID(val$,1,slots),slots,0,"0") ! Pad the initial value to the correct length by prefixing with zeroes
0530 FOR i=1 TO LEN(val$)
0540 IF NOT(POS(MID(val$,i,1)=avlchar$[i])) THEN LET ret$="ERROR"
0550 NEXT i
0560 IF NOT(NUL(ret$)) THEN GOTO 0640
0570 !
0580 ! Calculate the value
0590 FOR i=1 TO LEN(val$)
0600 LET val+=(POS(MID(val$,i,1)=avlchar$[i])-1)*slotval[i]
0610 NEXT i
0620 LET ret$=STR(val)
0630 !
0640 RETURN ret$
0650 END DEF

2
Wish List / Re: Sort Array
« on: June 22, 2022, 06:50:36 PM »
I've sorted string arrays using this logic.  The sort is all done in one line (line 40).  The rest of this is just setup for demo purposes.

Code: [Select]
0010 BEGIN
0020 LET data$="Red,Orange,Yellow,Green,Blue,Indigo,Violet,"
0030 DIM a$[1:POS(","=data$,1,0)]; READ DATA FROM data$,SEP="," TO a${ALL}
0040 READ DATA FROM SRT(REC(CPL("iolist a${all}"))) TO a${ALL}
0050 PRINT "Raw Data:    ",data$
0060 PRINT "Sorted Data: ",REC(CPL("iolist a${all}"),SEP=",")

3
Web Services / Re: Setup EZWeb server and API calls
« on: June 02, 2022, 12:39:07 PM »
As on the previous reply from Michael Greer, it doesn't seem to me that you need EZWeb at all.  You will be making API calls *from* your PXPlus system *to* the TULIP system to retrieve data, correct?  If that's the case, there are several ways to do so, and EZWeb isn't needed.

- You can use *plus/web/request as Michael noted.
- You can also use "curl" on the Linux server by opening a channel with the "<" character (input from). For example: OPEN (1)"<curl www.google.com"  Using curl is often helpful since a lot of web API's provide examples using curl, and curl handles a lot of the overhead with security/SSL/etc.
- You can communicate directly with the web service using TCP sockets in PXPlus.  For example: OPEN (1)"[tcp]www.google.com;80".  This is a little more difficult since it requires you to build the HTTP requests.

4
Language / Re: Json Element addressing
« on: May 24, 2022, 01:30:36 PM »
I like Stephane's approach since it's simple and clean because the 'totalSize' tells you how many records are in each segment. 

I generally use WHILE/WEND, since I've never encountered any JSON that included a record count.  When using the WHILE/WEND, you just need to identify a field that will occur in each new segment to indicate a new record.  In this case, the "Id" field serves that purpose.  In case you run into a scenario where the record count ("totalSize") isn't included or isn't reliable, the bit of code below is an example of how to read through the JSON without relying on a record count.

Code: [Select]
0010 BEGIN
0020 LET json$=$7B22746F74616C53697A65223A312C22646F6E65223A747275652C227265636F726473223A5B7B2261747472696275746573223A7B2274797065223A224F72646572222C2275726C223A222F73657276696365732F646174612F7635342E302F736F626A656374732F4F726465722F383031324430303030303136787135514141227D2C224964223A22383031324430303030303136787135514141222C224F726465724E756D626572223A223030303030313030222C224372656174656444617465223A22323032322D30322D32315431333A31333A30312E3030302B30303030222C224F726465724974656D73223A7B22746F74616C53697A65223A312C22646F6E65223A747275652C227265636F726473223A5B7B2261747472696275746573223A7B2274797065223A224F726465724974656D222C2275726C223A222F73657276696365732F646174612F7635342E302F736F626A656374732F4F726465724974656D2F38303232443030303030314767563551414B227D2C224964223A2238303232443030303030314767563551414B222C2250726F6475637432223A7B2261747472696275746573223A7B2274797065223A2250726F6475637432222C2275726C223A222F73657276696365732F646174612F7635342E302F736F626A656374732F50726F64756374322F303174324430303030303530694B72514149227D2C2253746F636B4B656570696E67556E6974223A223235227D2C225175616E74697479223A352E302C22546F74616C5072696365223A313235302E307D5D7D7D5D7D$
0030 DIM LOAD test${ALL}=json$
0040 LET pf1=0
0050 WHILE 1
0060 LET pf1$="records."+STR(++pf1)+"."
0070 IF NOT(DIM(INDEX test$[pf1$+"Id"])) THEN BREAK
0080 PRINT test$[pf1$+"Id"]
0090 PRINT test$[pf1$+"attributes.type"]
0100 PRINT test$[pf1$+"attributes.url"]
0110 PRINT test$[pf1$+"OrderNumber"]
0120 PRINT test$[pf1$+"CreatedDate"]
0130 !
0140 LET pf2=0
0150 WHILE 1
0160 LET pf2$=pf1$+"OrderItems.records."+STR(++pf2)+"."
0170 IF NOT(DIM(INDEX test$[pf2$+"Id"])) THEN BREAK
0180 PRINT test$[pf2$+"Id"]
0190 PRINT test$[pf2$+"attributes.type"]
0200 PRINT test$[pf2$+"attributes.url"]
0210 PRINT test$[pf2$+"Product2.attributes.type"]
0220 PRINT test$[pf2$+"Product2.attributes.url"]
0230 PRINT test$[pf2$+"Product2.StockKeepingUnit"]
0240 PRINT test$[pf2$+"Quantity"]
0250 PRINT test$[pf2$+"TotalPrice"]
0260 WEND
0270 WEND

5
Programming / Re: Managing available memory (error 31)
« on: January 27, 2022, 11:51:48 AM »
Perfect!  Thanks, Mike!  I really wasn't looking forward to breaking up the JSON.  Kudos on the design of the associative arrays - they make handling the JSON a breeze, and the fact that they don't significantly affect the variable table is a relief.

6
Programming / Re: Managing available memory (error 31)
« on: January 27, 2022, 08:42:21 AM »
Splitting the program to reduce the number of variables seems to have resolved the issue.  Thanks to everyone for all of your suggestions!

One additional question:  The program is importing a lot of JSON data, and some of the JSON files are fairly large.  I'm reading them into an array using DIM LOAD arr${all}=json$, and these arrays sometimes have 20,000+ elements. 

Are all of the individual elements of the array equally affecting the variable table?  Ie: does the variable table just consider "arr${all}" as 1 item, or does it track each element (arr$[1] ,arr$[2], arr$[3],...) separately?  Also, since these array elements have named fields, (eg: arr$["field.1.name"]), I'm assuming that these named fields also may affect the variable table.

I'm working on re-designing the program to avoid this problem, while also allowing room for future enhancements.  If the JSON arrays are having a huge effect on the variable tables, I may need to change the routines that request the JSON to request smaller chunks of data.

7
Programming / Re: Managing available memory (error 31)
« on: January 26, 2022, 06:12:38 PM »
Mike, there are no EXECUTE commands, but the program uses a LOT of files with data dictionary variables (ie: open the channel with IOL=*, then read the records, thus pulling in all of those variables).  The program also dimensions quite a few variables to the IOL of a channel.  (ie: DIM REC$:IOL(chan); READ RECORD(CHAN)REC$) 

Based on your comment, these types of variables are also using up space in the variable name table, correct?

If so, I'll probably need to split this program out into a couple of smaller programs to eliminate that problem.

8
Programming / Re: Managing available memory (error 31)
« on: January 26, 2022, 05:18:54 PM »
Now this is getting interesting, since it doesn't seem to be a memory problem.

I followed all of the suggestions given:  Boosted the memory to 64megs, turned on the 'IZ' parameter to ignore memory limits, and set the '-B' flag on the trace channel.  The process is still dying at random points.  In my for most recent tests, the failing line of code was: trying to CLOSE a channel, PERFORMing a program/line_label, READing a channel to a data file, and setting some variables using an IOLIST.  The only thing in here that is remotely unique is the last item, which does LET KEY$=REC(IOL=KEY_IOL,SEP=$$), but that same code is executed multiple times in the program without a problem.

Since the 'IZ' parameter is set, it would seem to rule out this being a memory issue.

The program is large, and recently got larger.  Mike, we had discussed program size and variable name table size limitations in an earlier thread (https://forum1.pvxplus.com/index.php?topic=887.msg2983#msg2983).  I just checked the variable name table length using the info you provided in that thread, and the value returned is 29,015.

Is it possible that the variable name table size is causing this crash?  Any other suggestions on figuring out exactly what is causing this to crash?

9
Programming / Re: Managing available memory (error 31)
« on: January 26, 2022, 11:41:04 AM »
Question regarding the -B mnemonic: 

Can that be applied to just the trace file by printing the mnemonic to the channel (ie: PRINT (tracechannel)'-B'), or does it apply to the entire session (ie: PRINT '-B')?

10
Programming / Re: Managing available memory (error 31)
« on: January 26, 2022, 11:35:24 AM »
Stephane - I thought about using the 'IZ' switch, but I'd really rather figure out the problem before hitting it with that really big hammer of allowing unlimited memory.  I suspect that there is a memory leak somewhere (like using a "local" variable multiple times in a single routine, which I've seen in the past), and I'd rather find the problem if I can.  If not, I'll try the 'IZ' parameter to see if that helps.

Jason -  Thanks for that tip on buffering.  I don't have the -B switch turned on for the channel, so I'll try that to see if it gives me any different results.

11
Programming / Re: Managing available memory (error 31)
« on: January 25, 2022, 06:08:18 PM »
Thanks for the info, Mike.  The program is not self-modifying.  We have versioning turned off, so there are no extra versions in the program. The 407k is the value I get from the PSZ variable.

Also, we have program caching turned off (I forget why we turned it off, but there was a reason long ago).  I added a line SET_PARAM 'PC'=10 to the program since it's a cron that will only apply that parameter to the single session, rather than all sessions. 

I did see that the process is still randomly dying, even with the 'SZ' parameter set to 64000, so maybe the memory isn't the issue.  I'll watch the process more to see if the 'PC' param makes any difference.

Thanks again, Mike.  You're wealth of knowledge is always appreciated!

12
Programming / Managing available memory (error 31)
« on: January 25, 2022, 05:11:33 PM »
I have a large program (406k) that recently started dying, very unceremoniously!  No error traps were triggered even though an error handler program and a SETERR were in place.  I added traces to the program, and found that it was dying at completely random places each time.  This leads me to believe that it was a memory issue (ie: ran out of memory). The program runs on Linux as a cron process, and the startup environment allocates 32m of memory to all of the processes.  I added a SET_PARAM 'SZ'=64000 into the routine to increase the available memory, and that seems to have resolved the problem.

However, I'd like to see if there is a better way to handle this.

The program is large since it encompasses several CALLed routines, and it will CALL itself several times using line labels.  (eg:  call PGN+";line_label",a$,b$,c).  I suspect that each time it calls itself, a new copy of the (large) program is loaded into memory, thus using up a lot more memory.  Some of the called routines also call other routines in the same program, so a call which is several levels deep could be loading several copies of the program into memory *if that is how the CALL command works*.

My question is: 
- When a program CALLs itself, does it load a new copy of the program into memory?
- And if so, will using ADDR to lock the program in memory prevent a new copy of the program from being loaded into memory?  (and thus reduce my need to allocate additional memory to the session)

Thanks in advance for any info you can provide!




13
Nomads / Re: Finding the previous CTL ID on Default Push Button event
« on: October 27, 2021, 07:11:23 PM »
Try DEC(MID(MSE,25,2)).  That should return ID of the last control to lose focus.

14
Programming / Re: Error 99 in *plus/proj/pathinfo
« on: October 21, 2021, 05:54:55 AM »
Thanks for your help and explanations of this, Jane.  I've created a support ticket (687435) for your purposes, but the issue is resolved to our satisfaction  :D

15
Programming / Re: Error 99 in *plus/proj/pathinfo
« on: October 20, 2021, 02:50:31 PM »
Jane, that's it!  That flag was turned on for one of the files. 

Can we just turn that flag off and then update the file definition?

Then, how do I create a ticket on your HelpDesk?

Pages: [1] 2 3 4