argent77 Posted June 11, 2016 Share Posted June 11, 2016 I'd like to build an array dynamically from lines read from a text file. I thought the following code would accomplish that: DEFINE_ACTION_FUNCTION READ_LINES RET lines BEGIN COPY - ~testfile.txt~ ~testfile.txt~ READ_ASCII 0 text (SOURCE_SIZE) INNER_PATCH_SAVE null_char ~ ~ BEGIN WRITE_BYTE 0 0 END INNER_PATCH_SAVE text ~%text%~ BEGIN REPLACE_TEXTUALLY ~\(%WNL%\)\|\(%LNL%\)\|\(%MNL%\)~ ~%null_char%~ END INNER_PATCH ~%text%~ BEGIN SET strlen = STRING_LENGTH ~%text%~ SET ofs = 0 SET idx = 0 WHILE (ofs < strlen) BEGIN READ_ASCII ofs line ELSE ~~ (strlen - ofs) NULL TEXT_SPRINT $EVAL lines(~%idx%~) ~%line%~ SET idx += 1 SET ofs += (STRING_LENGTH ~%line%~) + 1 END END END LAF READ_LINES RET lines END ACTION_PHP_EACH lines AS _ => line BEGIN PRINT ~Line: %line%~ END But it only triggers the following error message when I execute it: ERROR: Failure("Uninitialised return value: lines") The WeiDU docs are very sparse when it comes to array constructs. Am I missing something? Link to comment
subtledoctor Posted June 11, 2016 Share Posted June 11, 2016 EDIT - I didn't understand the question properly, ignore me... You could give your text file a .2da extension and then do stuff like COPY ~text.2da~ COUNT_2DA_ROWS rows FOR (row = 1 ; row < rows ; ++rows) READ_2DA_ENTRY row 0 1 ~first~ ACTION_DEFINE_ASSOCIATIVE_ARRAY ~lines~ ... ...etc. Link to comment
argent77 Posted June 11, 2016 Author Share Posted June 11, 2016 It looks like the issue is caused by the array construct itself. Even static arrays returned by a function are triggering this error message: DEFINE_ACTION_FUNCTION READ_LINES RET lines BEGIN ACTION_DEFINE_ARRAY lines BEGIN ~first line~ ~second line~ ~third line~ END END LAF READ_LINES RET lines END // triggers error message: ERROR: Failure("Uninitialised return value: lines") Is there a working method for returning arrays or what can be used as an alternative option to return a variable number of strings from a function? Link to comment
Ardanis Posted June 12, 2016 Share Posted June 12, 2016 The function's output is kinda broken, RET will fail unless the exact variable gets set in the function. Feel free to ask Wisp to adjust it, I asked Bigg twice but here we are still The other half of the problem is that RET interprets "lines" as a string, not array. In other words, you can't build an array with a function and then access it in outside environment. Use macro instead - you'll have to manually initialize and clear any internal variables, but the array itself will be accessible outside of it. PS I suppose, you could also make a function that will write new functions from a blueprint and run them via REINCLUDE, one per item, but macro is probably easier. PPS Or, if you're comfortable with parsing a text file, you could instead morph it into array definition code and then run normally. Link to comment
argent77 Posted June 12, 2016 Author Share Posted June 12, 2016 Thanks for the suggestions. Using macros instead of functions works well enough in my case. With LOCAL_SET/LOCAL_TEXT_SPRINT I can avoid some of the side effects of using macros. Link to comment
Ardanis Posted June 14, 2016 Share Posted June 14, 2016 Frankly, since you only replace the line breaks, you should be able to achieve the same effect by just wrapping the list into ACTION_DEFINE_ARRAY lines BEGIN // testfile.txt contents END and INCLUDE'ing it as tph. Link to comment
argent77 Posted June 14, 2016 Author Share Posted June 14, 2016 How exactly would I do this? Isn't DEFINE_ARRAY only useful for defining static arrays? Btw, I have only posted a simplified example in my first post. I'm also doing some filtering. The full code is (currently): DEFINE_PATCH_MACRO GET_WEIDU_LINES // RET weiduEntries BEGIN LOCAL_TEXT_SPRINT weidu ~~ LOCAL_TEXT_SPRINT null_char ~ ~ LOCAL_TEXT_SPRINT regWeidu ~~ LOCAL_SET curIdx = 0 LOCAL_SET strlen = 0 LOCAL_SET ofs = 0 READ_ASCII 0 weidu (SOURCE_SIZE) INNER_PATCH_SAVE null_char ~%null_char%~ BEGIN WRITE_BYTE 0 0 END INNER_PATCH_SAVE weidu ~%weidu%~ BEGIN REPLACE_TEXTUALLY ~\(%WNL%\)\|\(%LNL%\)\|\(%MNL%\)~ ~%null_char%~ END INNER_PATCH ~%weidu%~ BEGIN TEXT_SPRINT regWeidu "^[%TAB% ]*\(~[^~]+~[%TAB% ]*#[0-9]+[%TAB% ]*#[0-9]+\).*$" SET strlen = STRING_LENGTH ~%weidu%~ WHILE (ofs < strlen) BEGIN READ_ASCII ofs line ELSE ~~ (strlen - ofs) NULL PATCH_IF (~%line%~ STRING_MATCHES_REGEXP ~%regWeidu%~ = 0) BEGIN INNER_PATCH_SAVE line ~%line%~ BEGIN REPLACE_TEXTUALLY ~%regWeidu%~ ~\1~ END TEXT_SPRINT $EVAL weiduEntries(~%curIdx%~) ~%line%~ SET curIdx += 1 END SET ofs += (STRING_LENGTH ~%line%~) + 1 END END END COPY - ~weidu.log~ ~weidu.log~ LPM GET_WEIDU_LINES ACTION_PHP_EACH weiduEntries AS _ => weiduEntry BEGIN // ... END Link to comment
Ardanis Posted June 14, 2016 Share Posted June 14, 2016 Isn't DEFINE_ARRAY only useful for defining static arrays? DEFINE_ARRAY is more like a shortcut for a batch of SET $array("index")=value actions, than anything else. You can initiate D_A, then append it with several manual SETs/SPRINTs, then partially overwrite and/or append with another D_A, and WeiDU will still take it. The only thing it can't do is to change the range of PHP_EACH action while it's running, i.e. although you still can append the array with new entries, only the subsequent PHP_EACH will be able to grab them. Beside that, everything is pretty much as dynamic as it can get. Btw, I have only posted a simplified example in my first post. I'm also doing some filtering. Ah. I thought you were only reading a list of simple strings By the way, if you're later disassembling the entry into text and strrefs, you can set them as separate arguments when reading from file (not sure it can actually evaluate like this, but you should get the idea): INNER_PATCH ~%weidu%~ BEGIN TEXT_SPRINT regWeidu "^[%TAB% ]*\(~\([^~]+\)~[%TAB% ]*#\([0-9]+\)[%TAB% ]*#\([0-9]+\)\).*$" SET strlen = STRING_LENGTH ~%weidu%~ WHILE (ofs < strlen) BEGIN READ_ASCII ofs line ELSE ~~ (strlen - ofs) NULL PATCH_IF (~%line%~ STRING_MATCHES_REGEXP ~%regWeidu%~ = 0) BEGIN INNER_PATCH_SAVE line ~%line%~ BEGIN REPLACE_TEXTUALLY ~%regWeidu%~ ~\1~ END TEXT_SPRINT $EVAL weiduEntries(~%curIdx%~ ~\3~ ~\4~) ~\2~ SET curIdx += 1 END SET ofs += (STRING_LENGTH ~%line%~) + 1 END END // ... ACTION_PHP_EACH weiduEntries AS idx => weiduEntry BEGIN // curidx = idx strref1 = idx_1 strref2 = idx_2 SPRINT text ~%weiduEntry%~ // ... END Link to comment
argent77 Posted June 14, 2016 Author Share Posted June 14, 2016 Sounds like an interesting approach. I'm currently splitting each entry with three separate REPLACE_TEXTUALLY calls. Edit: I couldn't get it to work. Since RegExp groups can only be captured within the action that processed the regular expression (such as REPLACE_TEXTUALLY) it would require multiple PATCH_SAVE blocks anyway. Link to comment
Recommended Posts
Archived
This topic is now archived and is closed to further replies.