5.4. IPK dla programistów

5.4.1. Interfejs biblioteki IPK

Częścią projektu IPK jest biblioteka, ułatwiająca korzystanie z konfiguracji programom użytkowym. Dzięki temu nie jest konieczne samodzielne parsowanie konfiguracji czy dokonywanie różnych przeliczeń.

Ze względu na dość sporą złożoność, oraz aby umożliwić łatwiejszą rozbudowę i przyszłe modyfikacje, biblioteka została napisana nie w C, ale w C++.

Dokładny opis wszystkich klas można otrzymać przez wygenerowanie dokumentacji z kodu źródłowego. W tym celu w repozytorium SZARP'a w podkatalogu libSzarp2 należy wydać komendę:

make doxy
W katalogu doxy zostanie wygenerowana dokumentacja, wersja HTML w podkatalogu html.

Struktura biblioteki odpowiada mniej więcej strukturze pliku IPK (zobacz Sekcja 5.2). Konfiguracja przechowywana jest w jednym głównym obiekcie typu TSzarpConfig. Obiekt ten zawiera listę elementów typu TDevice, opisujących poszczególne linie komunikacyjne, oraz listę parametrów definiowalnych. Obiekty klasy TDevice zawierają zaś wskaźniki do opisywanych linii radiowych, jednostek itd.

Przyjęto, zgodnie z metodologią obiektową, zasadę ukrywania implementacji poszczególnych elementów. Wszystkie atrybuty są chronione lub prywatne, jeżeli jest potrzeba dostępu do nich, definiowane są odpowiednie metody.

Należy zwrócić uwagę, że API biblioteki jest jeszcze na dość wstępnym etapie rozwoju. W miarę powstawania korzystających z biblioteki aplikacji będą się pojawiały nowe elementy. Mam nadzieję, że obiektowa struktura biblioteki pozwoli zachować kompatybilność wstecz.

W większości wypadków implementacja struktur danych wewnątrz biblioteki jest listowa. Dzięki temu możliwe jest łatwe dodawanie i usuwanie elementów (choć nie wszędzie są w tej chwili napisane odpowiednie interfejsy). Minusem jest liniowy czas dostępu do parametrów (np. wyszukiwanie parametrów według jakiś kryteriów). Niektóre algorytmy (np. tworzenie pliku eknrcor) mają złożoność kwadratową względem liczby parametrów. Jeżeli w jakiś aplikacjach będzie to powodowało problemy wydajnościowe, trzeba będzie zaimplementować jakieś bardziej ambitne algorytmy. Najprawdopodobniej jednak, przy typowych rozmiarach konfiguracji (maksymalnie tysiące parametrów) i obecnych mocach obliczeniowych aktualna prosta implementacja okaże się zupełnie wystarczająca.

Biblioteka nie przechowuje w tej chwili żadnych dodatkowych informacji pomocniczych, tak więc modyfikacje konfiguracji z poziomu biblioteki, podobnie jak operacje na pliku IPK, nie wymagają uaktualniania powiązanych informacji.

Do parsowania XML-a wykorzystywana jest biblioteka libxml2. Biblioteka ta przechowuje wszystkie dane tekstowe (także atrybuty) w kodowaniu UTF-8. Natomiast interfejs biblioteki IPK wykorzystuje kodowanie ISO-8859-2 (dokonując w razie potrzeby odpowiednich konwersji przy wywołaniach funkcji z biblioteki XML). Stąd też wszystkie parametry do funkcji biblioteki IPK powinny być podawane w tym kodowaniu.

Konstruktor obiektu przechowującego konfigurację jest bezparametrowy. Inicjalizacja następuje przez wczytanie informacji z pliku. Funkcja TSzarpConfig::loadSzarpConfig(char* directory) wczytuje konfigurację w formacie SZARP 2.1 z podanego katalogu. Należy zwrócić uwagę, że część z wykorzystywanych przez funkcję parserów plików konfiguracyjnych (napisanych we fleksie) nie jest 'reentrant' (jakiś polski odpowiednik?) i może być wykorzystywana tylko raz. Ogólnie więc funkcję tą można w programie wywołać tylko raz. Lepiej jest więc wczytywać konfigurację w formacie IPK, przy użyciu metody TSzarpConfig::loadXML(char* path).

Oto przykładowy program korzystający z biblioteki. Wypisuje on indeks IPC parametru o nazwie podanej jako drugi parametr (pierwszym jest nazwa pliku konfiguracyjnego):

#include <iostream>
#include <string>
using namespace std;

#include "szarp_config.h"

int main(int argc, char* argv[])
{
	TSzarpConfig * config;
	TParam * param;

	if (argc < 2) {
		cout << "Za mało parametrów\n" ;
		return 1;
	}

	config = new TSzarpConfig();
	
	if (config->loadXML(argv[1]) != 0) {
		cout << "Błąd podczas wczytywania pliku " << argv[1] << "\n";
		return 1;
	}
	
	param = config->getParamByName(argv[2]);

	if (param == NULL) {
		cout << "Nie znaleziono parametru '" << argv[2] << "'\n";
	} else {
		cout << "Indeks IPC parametru to " << param->GetIpcInd() << "\n";
	}

	delete config;
}
Kompilację i linkowanie programu można przeprowadzić za pomocą komend:
gcc -Iszarp/libSzarp2/include/ `xml2-config --cflags` -c -Wall getipc.cc
g++ -o getipc -L/usr/X11R6/lib -lXt szarp/libSzarp/libSzarp.so \
	szarp/libSzarp2/libSzarp2.so -lxml2 -lz -lm getipc.o

Biblioteka była testowana za pomocą debugerów pamięci. Polecanym przeze mnie programem jest valgrind, dostępny pod adresem http://freshmeat.net/projects/valgrind. Jest bardzo prosty w użyciu i pozwala na wykrycie błędów, których zlokalizowanie w inny sposób byłoby prawie niemożliwe.