Programování pro PalmOS počítače krok za krokem (28)

Minule jsme si uváděli příklady použití přemístitelných a nepřemístitelných bloků paměti. V následující tabulce shrneme rozdíly mezi oběma dvěma typy bloků paměti. Dokončíme si popis bloků paměti a povíme si o práci s řetězci v prostředí PalmOS.
  Nepřemístitelné bloky paměti Přemístitelné bloky paměti
Proměnná, kterou se na blok odkazujeme Adresa počátku bloku MemPtr Ovladač bloku MemHandle
Inicializace a zrušení funkcemi MemPtrNew(), MemPtrFree() funkcemi MemHandleNew(), MemHandleFree()
Ukládání a čtení dat Je možné ihned od adresy počátku bloku Pouze z uzamknutého bloku (mezi voláním funkce MemHandleLock() a MemHandleUnlock())
Změna velikosti funkce MemPtrResize() funkce MemHandleResize(), blok nesmí být uzamčen
Dotaz na velikost bloku paměti funkce MemPtrSize() funkce MemHandleSize()

Dosud popsané postupy zacházení s přemístitelnými a nepřemístitelnými bloky paměti se vztahovaly zatím pouze na dynamickou paměť. Pokud v naší aplikaci potřebujeme použít větší množství paměti, než kolik se nám vejde do oblasti dynamické paměti, musíme bloky paměti alokovat v oblasti úložné paměti. O práci s úložnou pamětí si povíme při popisu správce databází PalmOS v některé z příštích kapitol.

3.7. Funkce PalmOS pro zacházení s řetězci

Jádro operačního systému PalmOS v sobě obsahuje funkce pro práci s řetězci. Podobně jako v jazyce C/C++ jsou podporovány řetězce jako pole znaků libovolné délky ukončené znakem '\0'. Protože funkce pro práci s řetězci jsou již obsažené v jádru operačního systému, tak nepotřebujeme při překladu připojovat k naší aplikaci žádnou speciální knihovnu pro práci s řetězci.

Doporučované datové typy pro práci se znaky a s řetězci v PalmOS ve verzi 3.0 a vyšší jsou uvedeny v následující tabulce:

 standardní C/C++PalmOS
Jednotlivé znaky char nebo unsigned char (8bitový datový typ) WChar (16bitový datový typ, ve kterém mohou být uloženy i dvoubytové znaky UNICODE)
Řetězec
char text[100];
(pole 8bitových znaků)
Char text[100];
(pole osmibitových znaků, ve kterém však mohou být zařazeny i dvoubytové znaky UNICODE
Ukazatel na řetězec
char* ukazatel;
Char* ukazatel;

Doporučení používat pro uložení jednotlivých znaků 16bitový datový typ WChar místo 8bitového (Char) má základ v široké podpoře PalmOS pro jazyky používající nestandardní abecedy. Samotné řetězce jsou uloženy z důvodů úspory paměti jako pole 8bitových znaků Char a systémové funkce dovedou správně rozlišit jedno a dvoubytové znaky, které se v řetězcích nacházejí.


Char* s1 = "ahoj";    

// Deklarace řetězcové konstanty s hodnotou "ahoj". Tato konstanta
// zabírá v paměti 5 byte: 
// s1[0] = 'a' 
// s1[1] = 'h' 
// s1[2] = 'o' 
// s1[3] = 'j' 
// s1[4] = '\0'

WChar znak = s1[3]; // znak má hodnotu 'o'

Char s2[30];

// Deklarace řetězce, který může obsahovat nejvíce 29 znaků
// (poslední znak bude ukončující '\0')

Char* s3 = s1;

// s3 ukazuje na stejný řetězec jako s1 (obsahující "ahoj")

Funkce PalmOS pro práci s řetězci

Při psaní aplikací pro PalmOS doporučují vývojáři společnosti Palm, Inc. nepoužívat funkce standardní knihovny C/C++ (jako strlen(), strcat(), toupper() a podobně). Pokud kteroukoliv z těchto funkcí použijeme, bude při překladu k naší aplikaci připojena standardní knihovna C/C++, která zvětší velikost naší aplikace o 1-10 kB.

UInt16 StrLen(const Char* src)

Zjistí délku řetězce.

Vstupní parametry
  • src - adresa řetězce
Vrácená hodnota
  • délka řetězce = počet znaků (8bitových) před ukončujícím znakem '\0'. Jsou-li v řetězci vícebytové znaky, tak nemusí vrácená hodnota odpovídat skutečnému počtu znaků.

 

Char* StrCopy(Char* kam, const Char* odkud)

Zkopíruje jeden řetězec do druhého.

Vstupní parametry
  • odkud - adresa počátku zdrojového řetězce.
  • kam - adresa počátku řetězce, do kterého bude zdrojový řetězec kopírován (cílový řetězec).
Vrácená hodnota
  • ukazatel na cílový řetězec (kam)

Pokud se zdrojový i cílový řetězec překrývají, tak se může funkce StrCopy() chovat nepředvídatelně. Použití funkce je následující (pro připomenutí budu ve většině příkladů v této kapitole používat i bloky paměti):

Char* a = "abcde";            // řetězcová konstanta
Char b[100];
Char* c = (Char*)MemPtrNew(100); // můžeme použít i blok paměti 

n = StrLen(a);         // n bude rovné pěti

n = StrLen("");        // n bude rovno nule

StrCopy(b, a);         // b bude mít hodnotu "abcde"

StrCopy(c, "kocka");   // c bude mít hodnotu "kocka"

MemPtrFree((MemPtr)c); // nesmíme zapomenout uvolnit paměť

 

Char* StrNCopy(Char* cíl, const Char* zdroj, Int16 n)

Zkopíruje zdrojový řetězec na místo cílového. Ohlídá přitom, aby nebyla překročena největší délka cílového řetězce.

Vstupní parametry
  • zdroj - adresa počátku zdrojového řetězce.
  • cíl - adresa počátku řetězce, do kterého bude zdrojový řetězec kopírován (cílový řetězec).
  • n - maximální délka proměnné, ve které bude uložen cílový řetězec.
Vrácená hodnota
  • ukazatel na cílový řetězec (kam)

Po volání funkce StrNCopy() bude cílový řetězec dlouhý nejvýše (n - 1) znaků a bude ukončen znakem '\0'. Celý se tedy vejde do oblasti paměti o délce n byte. Tuto funkci je vhodné používat ve všech případech, kdy kopírujeme řetězce proto, aby nedocházelo k překročení maximální povolené délky řetězce. Funkce v následujícím rámečku zkopíruje text do oblasti přemístitelného bloku paměti a ohlídá si, aby nebyla překročena jeho délka:

void Kopiruj(MemHandle hKam, Char* odkud)
{
    StrNCopy((Char*)MemHandleLock(hKam), odkud, MemHandleSize(hKam));
    MemHandleUnlock(hKam);
}

Funkce StrCopy() a StrNCopy() jsou ekvivalenty funkcí strcpy() a strncpy() z knihovny řetězcových funkcí jazyka C/C++.

Char* StrCat(Char* cíl, const Char* text)

Spojí dva řetězce - zkopíruje řetězec text na konec řetězce cíl.

Vstupní parametry
  • cíl - adresa řetězce, na jehož konec bude připojen řetězec text
  • text - adresa připojovaného řetězce
Vrácená hodnota
  • ukazatel na řetězec cíl (to znamená na výsledný řetězec) obsahující spojené texty

Funkce StrCopy() a StrCat() vrací adresu výsledného řetězce - to je možné využít - například po volání

Char text[10];
StrCopy(text, StrCat("a", "b"))
obsahuje proměnná text text "ab".

Char* StrNCat(Char* cíl, const Char* text, Int16 n)

Spojí dva řetězce - zkopíruje řetězec text na konec řetězce cíl a ohlídá, aby se výsledný řetězec vešel do n byte.

Vstupní parametry
  • cíl - adresa řetězce, na jehož konec bude připojen řetězec text
  • text - adresa připojovaného řetězce
  • n - maximální délka proměnné cíl, která nebude při kopírování překročena
Vrácená hodnota
  • ukazatel na řetězec cíl (to znamená na výsledný řetězec) obsahující spojené texty

Při kopírování řetězců zadaných uživatelem nebo takových, u kterých neznáme přesně jejich délku, se doporučuje použít funkcí StrNCopy() a StrNCat(). Tím zabráníme chybám, které vzniknou při překročení místa v paměti vyhrazeného proměnné.

Char* StrToLower(Char* cíl, const Char* zdroj)

Zkopíruje řetězce a převede všechny znaky na malá písmena.

Vstupní parametry
  • zdroj - adresa počátku zdrojového řetězce.
  • cíl - adresa počátku řetězce do kterého bude zdrojový řetězec kopírován (cílový řetězec).
Vrácená hodnota
  • podobně jako funkce StrCopy() vrací tato funkce adresu proměnné cíl, do které je text zkopírován

Na systémech, které podporují mezinárodní znaky (PalmOS 3.3 a vyšší) nebo v aplikacích, které speciálně připravíme pro zpracování mezinárodních znaků na starších operačních systémech, převádí tato funkce správně i česká akcentovaná písmena. O správné lokalizaci našich aplikací si povíme později.

Int16 StrCompare(const Char* s1, const Char* s2)
Int16 StrCaselessCompare(const Char* s1, const Char* s2)

Porovná řetězce s1 a s2. Funkce StrCaselessCompare() porovnává bez ohledu na velká a malá písmena.

Vstupní parametry
  • s1 - adresa prvního řetězce
  • s2 - adresa druhého řetězce
Vrácená hodnota
  • -1 - s1 je v abecedě před s2
  • 0 - řetězce jsou totožné
  • 1 - s1 je v abecedě za s2

Pro správné abecední porovnání dvou řetězců je nutné volat obě tyto funkce - nejprve StrCaselessCompare() a poté teprve funkci StrCompare() jako v následujícím příkladu:

Int16 PorovnejAbecedne(Char* s1, Char* s2)
{
  Int16 vysledek = StrCaselessCompare(s1, s2);
  
  return vysledek == 0 ? StrCompare(s1, s2) : vysledek;
}

 

Int16 StrNCompare(const Char* s1, const Char* s2, UInt32 n)
Int16 StrNCaselessCompare(const Char* s1, const Char* s2, Int32 n)

Porovná prvních n (nebo méně) znaků s1 a s2. Funkce StrNCaselessCompare() porovnává bez ohledu na velká a malá písmena.

Vstupní parametry
  • s1 - adresa prvního řetězce
  • s2 - adresa druhého řetězce
  • n - počet znaků, které budou porovnávány
Vrácená hodnota
  • -1 - s1 (resp. jeho prvních n znaků) je v abecedě před s2
  • 0 - prvních n znaků s1 a s2 je totožných
  • 1 - s1 (resp. jeho prvních n znaků) je v abecedě za s2

Ve verzích operačního systému, které podporují mezinárodní znaky řadí porovnávací funkce české akcentované znaky správně.

Char* StrStr(const Char* kde, const Char* co)

Vyhledá první výskyt řetězce co v řetězci kde.

Vstupní parametry
  • kde - text, ve kterém vyhledáváme
  • co - text, který hledáme v řetězci kde
Vrácená hodnota
  • NULL - v řetězci kde se nevyskytuje řetězec co
  • adresa počátku prvního výskytu řetězce co v řetězci kde

 

Char* StrChr(const Char* kde, WChar znak)

Vyhledá první výskyt znaku znak v řetězci kde.

Vstupní parametry
  • kde - text, ve kterém vyhledáváme
  • znak -zkak, který hledáme v řetězci kde
Vrácená hodnota
  • NULL - v řetězci kde se nevyskytuje řetězec co
  • adresa počátku prvního výskytu řetězce co v řetězci kde

Předáme-li funkci StrChr() znak, který bude větší než 255, tak zobrazí chybovou hlášku. Bude-li znak roven '\0', tak nebude ve verzi PalmOS 1.0 nalezen správně.


Příště si dokončíme popis funkcí pro práci s řetězci popisem funkcí pro převod čísel na text.