17.4. ICUGETV Funkce: Podprogram ICUGETV vyhradí úsek paměti o zadané délce a ztotožní jej se zadanou položkou z LINKAGE SECTION. Způsob volání: CALL 'ICUGETV' USING položka [délka] Pravidla: Položka uvedená za USING musí být popsána v LINKAGE SECTION (nebo teoreticky ve FILE SECTION) s číslem úrovně 01 nebo 77. Jak je uvedeno v 4.9., taková položka nemá v přeloženém programu vyhrazen žádný úsek paměti. Je jí přidělen pouze jeden ukazatel (typu "unsigned char*"). Aby bylo možno s položkou pracovat, musí být do tohoto ukazatele nejprve uložena adresa toho úseku paměti, s nímž má být naše položka "ztotožněna". Pro naplnění ukazatele adresou úseku paměti existují různé prostředky (klauzule EXTRN, příkaz ENTRY, záhlaví PROCEDURE DIVISION USING, příkaz CALL s argumentem /položka, příkaz UFO, příkaz LOAD, podprogramy ICUGETV a ICVIRG, příkaz CALL 'ICIDENT' atd.), mezi nimiž je podprogram ICUGETV jeden z nejdůležitějších. Je-li uveden druhý argument "délka" (jímž musí být celé číslo nebo celočíselná numerická položka s nezápornou hodnotou nejvýše 65517 bytů), zadává explicitně délku úseku paměti, jenž má být vyhrazen (implicitní délka prvního argumentu se pak ignoruje). Není-li druhý argument "délka" uveden, bude vyhrazen úsek paměti v implicitní délce prvního argumentu (uživatel pak musí ovšem zajistit, aby v době provádění příkazu CALL 'ICUGETV' bylo možno délku prvního argumentu vypočítat a aby tato délka měla vhodnou hodnotu). V obou případech nesmí délka úseku přesáhnout 65517 bytů. Podprogram ICUGETV vyvolá systémovou funkci malloc, čímž vyhradí nový úsek paměti o zadané délce. Adresu takto získaného úseku paměti dosadí do ukazatele přiděleného zadané položce. Takto je tedy zadaná položka ztotožněna s vyhrazeným úsekem paměti a může být v následujících příkazech libovolně zpracovávána. Její počáteční obsah je ovšem nedefinován. Poznámky: 1) Po úspěšném provedení příkazu CALL 'ICUGETV' lze používat nejen zadanou položku, ale též položky jí podřízené a dále též položky spojené s ní pomocí klauzule REDEFINES a položky jim podřízené. Pokud takové navzájem se redefinující položky mají různé délky, je vhodné uvést v příkazu CALL 'ICUGETV' tu nejdelší z nich nebo zadat maximální délku explicitně; jinak by byl totiž přidělen pouze kratší úsek paměti a přesahující byty delších položek by již neměly přidělenu paměť a nemohly by být tedy zpracovávány. 2) Je-li explicitně nebo implicitně zadaná délka úseku nulová, není to chyba, ovšem žádný úsek paměti se nevyhrazuje a položka nesmí být tedy zpracovávána (došlo by k havárii výpočtu nebo k přemazání paměti přidělené jiným objektům). Přidělený ukazatel není vynulován! 3) Nepodaří-li se systémové funkci malloc úsek paměti zadané délky vyhradit (je-li již vyčerpána celá volná paměť, např. volá-li uživatel podprogram ICUGETV nebo ICVIRG opakovaně, aniž mezitím uvolňuje vyhrazené úseky paměti pomocí podprogramu ICUFREE resp. ICVIRF, anebo je-li zadaná délka příliš velká), bude přidělený ukazatel vynulován, avšak nehlásí se žádná chyba, výpočet není ukončen a pokračuje normálně dál. Při pokusu o práci s položkou dojde pravděpodobně k havárii výpočtu. Uživatel si ovšem může po provedení příkazu CALL 'ICUGETV' zjistit, zda je přidělený ukazatel nulový nebo nenulový, a v případě nulového ukazatele provést nějaká opatření (třeba znovu vyvolat podprogram ICUGETV s menší délkou). Test ukazatele lze provést např. příkazem UFO: MOVE 65000 TO DELKA. ZNOVU. CALL 'ICUGETV' USING POLOZKA DELKA. UFO 'if (!' POLOZKA ') {' IF DELKA <= 10000 GO TO CHYBA. SUBTRACT 1000 FROM DELKA. GO TO ZNOVU. UFO '}' #0A#. Jinou možností pro test ukazatele je popsat v LINKAGE SECTION 4bytovou binární položku (např. 77 ALFA PIC S9(9) COMP.) a ztotožnit ji s ukazatelem přiděleným položce POLOZKA příkazem CALL 'ICIDENT' USING ALFA /POLOZKA. Test ukazatele lze pak provést jako test hodnoty položky ALFA (IF ALFA = 0 ...); zde se využívá skutečnosti, že nulový ukazatel má stejnou representaci jako nulová 4bytová binární položka. Použití: Je nevhodné popisovat položky zabírající stovky a více bytů ve WORKING-STORAGE SECTION, neboť jejich úseky paměti by byly v plné délce reservovány ve spustitelném programu, čímž se zbytečně zabírá místo na disku. Navíc hrozí možnost vyčerpání poměrně omezené kapacity tzv. statické paměti. Doporučujeme všechny dlouhé pracovní položky popsat v LINKAGE SECTION a přidělit jim paměť až během výpočtu před jejich prvním použitím (např. hned na začátku výpočtu) pomocí podprogramu ICUGETV. Je-li třeba, aby taková položka (anebo některá její podřízená položka) měla na začátku výpočtu nějakou počáteční hodnotu, nelze to zařídit pomocí klauzule VALUE, nýbrž je třeba provést mezi vyvoláním podprogramu ICUGETV a prvním použitím položky vhodný příkaz MOVE resp. INITIALIZE apod. Pro krátké položky zabírající maximálně desítky bytů není vyhrazování paměti podprogramem ICUGETV vhodné, je výhodnější popsat tyto položky ve WORKING-STORAGE SECTION. Příklad: LINKAGE SECTION. 01 TAB. 02 PRVEK OCCURS 2000. 03 KLIC PIC 9(4) COMP. 03 CISLO PIC 9(8) COMP. : PROCEDURE DIVISION. CALL 'ICUGETV' USING TAB. MOVE ALL #0100FFFFFFFF# TO TAB. Podprogram ICUGETV vyhradí úsek paměti o délce 12000 bytů a ztotožní jej s položkou TAB. Příkaz MOVE zde slouží jako náhrada za nepoužitelnou klauzuli VALUE. Příklad: LINKAGE SECTION. 01 A. 02 I PIC 9(4) COMP. 02 B PIC X(7) OCCURS 5000 DEPENDING I. Pokud položka A doposud neměla přidělenu paměť, nelze provést příkaz CALL 'ICUGETV' USING A; položka I totiž též nemá přidělenu paměť, takže nelze vypočítat délku položky A používanou jako délku vyhrazovaného úseku - došlo by k havárii nebo k chybnému výpočtu. Problém by bylo možno řešit umístěním popisu položky I do WORKING-STORAGE SECTION a naplněním této položky vhodnou hodnotou (např. 5000) před provedením příkazu CALL 'ICUGETV'. Jiným řešením je zadat délku úseku v příkazu CALL 'ICUGETV' explicitně: CALL 'ICUGETV' USING A 35002. Stejný účinek by mělo přidání dalšího popisu s pevnou délkou 01 C REDEFINES A PIC X(35002). a přidělení paměti oběma položkám A i C současně příkazem CALL 'ICUGETV' USING C.