Friday 16 December 2011

Finite State Machine in C++

In my article "Finite State Machine in C" I gave a short introduction to Finite State Machines (FSM) and demonstrated two possible implementations of the Car state machine model.

In this article I will show C++ implementation of the same model, by using State Pattern. All state classes are derived from an abstract base class CState and each of them implements public method HandleEvent(EVENT evt). CSMManager class is a State Machine Manager and represents the core of our State Machine: it receives events and dispatches them to the current state for handling. Its private member m_pCurrState is a pointer to the CState base class but it always points to actual state objects. State transition is implemented as its reassignment to a different state object (object's address). This happens when some event occurs. Behaviour of this model is event-driven and, in contrast to C implementations, state transition control is not centralized here - it is not the State Manager who takes care of which state is going to be the next one. Current state decides on that itself, depending on its current conditions and events it receives.

Events.h:



States.h:



State.h:



StateTurnedOff.h:



StateTurnedOff.cpp:



StateIdle.h:



StateIdle.cpp:



StateMoving.h:



StateMoving.cpp:



StateInvalid.h:



StateInvalid.cpp:



SMManager.h:



SMManager.cpp:



main.cpp:



Output:


CStateTurnedOff::OnEntry()
Event received: EVENT_IGNITE
   Whoooa! I'm turned on!
CStateTurnedOff::OnExit()

CStateIdle::OnEntry()
Event received: EVENT_ACCELERATE
   Yipee! I'm accelerating!
CStateIdle::OnExit()

CStateMoving::OnEntry()
Event received: EVENT_BRAKE
   Whoops! Was I too fast?
CStateMoving::OnExit()

CStateIdle::OnEntry()
Event received: EVENT_TURN_OFF
   That was probably enough...
CStateIdle::OnExit()

CStateTurnedOff::OnEntry()
CStateTurnedOff::OnExit()


Note that State Manager's member which refers to the current state (m_pCurrState) is not of reference type (CState&) but a pointer (CState*). This is one of the cases where we MUST use pointer instead of reference because we want to have a variable which reffers to different objects throughout the execution and as re-seating the reference is not allowed, the only option is using a pointer. Please refer Parashift's FAQ on References and this SO question.

The reason for introducing m_prevStateID is that sometimes state machine (or some of its states) needs to know what was its previous state. Variable which keeps track of the previous state should not be of type reference (m_prevState : CState&) or pointer (m_pPrevState : CState*) as current state should not be able to access (members) of other states. It is therefore enough if it holds only the ID of the previous state.

Note that base abstract class CState declares OnEntry() and OnExit() methods - those which are executed when entering and leaving state. Current state executes HandleEvent(EVENT evt) each time it receives some event.

Friday 9 December 2011

Endianness: how does CPU read bytes from memory?

The simplest example is enough to give you the idea: CPU needs to read 2-byte data type from memory. The following example shows how do Big and Little endian machines read variable of type unsigned short from memory:

main.cpp



Output:

Memory layout:
arr[0] = 0xab
arr[1] = 0xcd
val (simple cast on little endian host) = 52651
val (as interpreted by little endian cpu) = 52651
val (as interpreted by big endian cpu) = 43981

Thursday 8 December 2011

Host endianness and data transfer over the network

Network components talk to each other by sending messages which are simply arrays of bytes. In order to understand them, parties in conversation need to know the communication protocol which defines message format and the length, order and the meaning of its parts.

Typically, message would comprise header and payload. Header can contain information about message itself, protocol version and information about the sender and receiver. Payload is actually information that sender wants to pass to receiver.

The simplest and shortest message one host can send is a message of a 1-byte length. In this case, protocol only needs to define how is this byte treated - as a character, signed or unsigned number. For example, if protocol says that message contains value of type unsigned char, and the message is 0x8b, receiver will treat this as a positive integer, of value 139. If that was a value of signed char, receiver would understand that this is a negative integer, -117.

There is one problem for messages made of two or more bytes. Bytes are send and received in the same order they are written in the sending buffer. But the way how are bytes copied from register to memory (buffer) and vice versa can be different on different hosts and this depends on their endianness. If sender has a big endian (BE) CPU and receiver has a small endian (SE) CPU, receiver might interpret received values in a wrong way.

Let's look at the case when the message comprises of 2-byte integer value, let's say of type unsigned short. This type has a range of values between 0 and 65535 (0x0000 and 0xffff). If BE sender wants to send value 0xabcd (43981) it will copy this value from registry to buffer keeping the same byte order and buffer will be like this: | 0xab | 0xcd |. Most significant byte (MSB) is at the lower address in memory. The other side will receive bytes in the same order. When copying bytes to the registry, BE receiver will treat the byte from the lowest memory address as the MSB and put it first so the registry will filled with bytes in the same order they are in the memory (0xabcd) and everything would be fine. But LE receiver will treat byte from the lowest address as the Least Significant Byte (LSB) and put it at the last position in the registry - it would swap the order and read received value as 0xcdab (52651), which is wrong! Sender should know the endianness of the client so can send bytes in the correct order, but that is impractical.

Solution to this is a simple rule: sender should always send bytes in big endian order (network byte order) and receiver should always convert received bytes from network to its own byte order. This makes sending and receiving code portable.

Both Windows and *NIX networking frameworks offer helper functions which are able to convert integers from host to network byte order and vice versa. They are:

uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);


Obviously, if host has network byte order (big endian), no conversion would take place, no matter whether it is on the sending or receiving side.

Sending and receiving buffers can be declared as char or unsigned char arrays. Values transported could be of signed or unsigned types. I made a set of several utility functions that insert and export values of desired integer types into/out from sending/receiving (probably socket) buffers. Prior to inserting, values are converted to network byte order (big endian) and after extraction, values are converted from network to host byte order. Tests prove that hton/ntoh functions can be applied both to signed and unsigned types as all they do is actually swapping bytes (if necessary).

NetBuffUtilCore.h:



NetBuffUtil.h:



NetBuffUtil.cpp:



main.cpp:



Output:

unsigned char buff
Original (unsigned short): 43981
Received val = 43981

char buff
Original (unsigned short): 43981
Received val = 43981

unsigned char buff
Original (short): -31234
Received val = -31234

char buff
Original (short): -31234
Received val = -31234

unsigned char buff
Original (unsigned long): 2882343476
Received val = 2882343476

char buff
Original (unsigned long): 2882343476
Received val = 2882343476

unsigned char buff
Original (long): -1107401523
Received val = -1107401523

char buff
Original (long): -1107401523
Received val = -1107401523

To avoid dependency on Winsock library, I implemented a function which swaps bytes for a given type (well, template should be constrained to only integer types...):

EndiannessUtil.h:



main.cpp:



So far, we were focused on transfer of integer types. What if message payload needs to contain strings, or, mashup of strings and integers?

Let's say that we need to send some ASCII string and some unsigned long number. Protocol should define message payload like this:

|L0|L1|S1|S1|S2|........|SK|N0|N1|N2|N3|

|L0|L1| - 2 bytes for unsigned short value that defines string length (K bytes)
|S1|S1|S2|........|SK| - string (K bytes)
|N0|N1|N2|N3| - 4 bytes for unsigned long number

Both integers should be converted to the network byte order prior to writing into sending buffer. But string does not need to be changed - that is ASCII string and each character is placed in a single byte. Receiving side will first read 2 bytes of payload, extract string length (K), allocate memory for string (K bytes) and then read (copy) next K bytes from receiving buffer into the string buffer. After that, receiver will read next 4 bytes and convert them from network byte order before passing it for further processing.

If sending Unicode string, we need to take care about endianness again as some of its characters use two or more bytes. Our protocol will define encoding applied (e.g. UTF-8 or UTF-16) but this time sender needs to send additional information as well - its endianness. This information is contained in Byte Order Mark (BOM) sequence which is prepended to our string. BOM helps Unicode decoder on the client side to decide whether to swap or not bytes for multi-byte characters.

Links and references:
htons(), htonl(), ntohs(), ntohl() (Beej's guide)
htons function (MSDN)
htonl function (MSDN)
ntohl function (MSDN)
ntohs function (MSDN)
Linux functions
Encodings and Unicode (Python)
Byte Order (Codecs)

Friday 4 November 2011

How to get notified when network adapters' IP addresses change? (Windows OS)

TCP/IP networking software requires at least one network adapter bounded to TCP/IP protocol stack. Each physical network card has unique MAC address and static or dynamic IP address. Static address (one or possibly more) is configured manually and dynamic address is assigned by Dynamic Host Configuration Protocol (DHCP) server (if DHCP is enabled; Obtain IP address automatically is ticked in TCP/IPv4 Properties window). Operating system maintains table which maps IP addresses to network interfaces. Use ipconfig command in command prompt window to display that table. If your adapter has DHCP enabled and you unplug/plug network cable (if using LAN adapter), disable/enable network adapter through adapter settings, issue ipconfig /release or /renew command, get out of/into WiFi range (if using WiFi adapter)...your adapter will loose existing or get a new IP address. NIC to IP address table will change.

Networking applications often need to be aware when changes in this table occur. Windows API function NotifyAddrChange notifies caller on this event. Here is an example of how to call it synchronously (when it's blocking):

#if !defined(_MT)
#error _beginthreadex requires a multithreaded C run-time library.
#endif

#include <winsock2.h>
#include <iphlpapi.h>
#include <Windows.h>
#include <iostream>
#include <sstream>
#include <process.h>
#include <iomanip>

#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")

#define APP_RETURN_CODE_SUCCESS 0
#define APP_RETURN_CODE_ERROR 1

#define THREAD_RETURN_CODE_SUCCESS 0
#define THREAD_RETURN_CODE_ERROR 1

// 127.0.0.1 in network byte order
#define IP_LOCALHOST 0x0100007F

void PrintIPTable()
    PMIB_IPADDRTABLE pIPAddrTable;

 pIPAddrTable = (MIB_IPADDRTABLE*)malloc(sizeof(MIB_IPADDRTABLE));

 if(!pIPAddrTable) 
 {
  std::cout << "malloc() failed" << std::endl;
  return;
 }
  
 // Before calling AddIPAddress we use GetIpAddrTable to get
 // an adapter to which we can add the IP
 // Make an initial call to GetIpAddrTable to get the
 // necessary size into the dwSize variable
 
 DWORD dwSize = 0;

 if(GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) 
 {
  free(pIPAddrTable);
  pIPAddrTable = (MIB_IPADDRTABLE*)malloc(dwSize);

  if(!pIPAddrTable) 
  {
   std::cout << "malloc() failed" << std::endl;
   return;
  }
 }
 
 DWORD dwRetVal = 0;
 LPVOID lpMsgBuf;

 // Make a second call to GetIpAddrTable to get the actual data we want
 if((dwRetVal = GetIpAddrTable(pIPAddrTable, &dwSize, 0)) != NO_ERROR ) 
 { 
  std::cout << "GetIpAddrTable() failed. Error code: " << dwRetVal << std::endl;
  
  if(FormatMessage(
   FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 
   NULL, dwRetVal, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),       
   (LPTSTR) & lpMsgBuf, 0, NULL)) 
  {
   std::cout << "\tError: " << lpMsgBuf << std::endl;
   LocalFree(lpMsgBuf);
  }

  free(pIPAddrTable);
  return;  
 }

 std::cout << "\tNum Entries: " << pIPAddrTable->dwNumEntries << std::endl;
  
 for(int i = 0; i < (int)pIPAddrTable->dwNumEntries; i++) 
 {   
  std::cout << "\n\tInterface Index[" << i << "]:\t" << pIPAddrTable->table[i].dwIndex << std::endl;

  IN_ADDR IPAddr;

  IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwAddr;
  std::cout << "\tIP Address[" << i << "]:     \t" << inet_ntoa(IPAddr) << std::endl;

  IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwMask;
  std::cout << "\tSubnet Mask[" << i << "]:    \t" << inet_ntoa(IPAddr) << std::endl;

  IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwBCastAddr;
  std::cout << "\tBroadCast[" << i << "]:      \t" << inet_ntoa(IPAddr) << "(" << pIPAddrTable->table[i].dwBCastAddr << ")" << std::endl;
  std::cout << "\tReassembly size[" << i << "]:\t" << pIPAddrTable->table[i].dwReasmSize << std::endl;

  std::cout << "\tType and State[" << i << "]:";

  if(pIPAddrTable->table[i].wType & MIB_IPADDR_PRIMARY)
   std::cout << "\tPrimary IP Address";

  if(pIPAddrTable->table[i].wType & MIB_IPADDR_DYNAMIC)
   std::cout << "\tDynamic IP Address";

  if(pIPAddrTable->table[i].wType & MIB_IPADDR_DISCONNECTED)
   std::cout << "\tAddress is on disconnected interface";

  if(pIPAddrTable->table[i].wType & MIB_IPADDR_DELETED)
   std::cout << "\tAddress is being deleted";

  if(pIPAddrTable->table[i].wType & MIB_IPADDR_TRANSIENT)
   std::cout << "\tTransient address";

  std::cout << std::endl;

  if(IP_LOCALHOST == pIPAddrTable->table[i].dwAddr)
  {
   std::cout << "\tLOCALHOST interface" << std::endl;
   // continue;
  }
    
  MIB_IFROW iInfo;
  memset(&iInfo, 0, sizeof(MIB_IFROW));
  iInfo.dwIndex = pIPAddrTable->table[i].dwIndex;
  GetIfEntry(&iInfo);

  std::cout << "\tNetwork interface name: " << iInfo.bDescr << std::endl;

  std::cout << "\tNetwork interface type: ";

  switch(iInfo.dwType)
  {
  case MIB_IF_TYPE_OTHER:
   std::cout << "OTHER" << std::endl;
   break;
  case MIB_IF_TYPE_ETHERNET:
   std::cout << "ETHERNET" << std::endl;
   break;
  case MIB_IF_TYPE_TOKENRING:
   std::cout << "TOKENRING" << std::endl;
   break;
  case MIB_IF_TYPE_FDDI:
   std::cout << "FDDI" << std::endl;
   break;
  case MIB_IF_TYPE_PPP:
   std::cout << "PPP" << std::endl;
   break;
  case MIB_IF_TYPE_LOOPBACK:
   std::cout << "LOOPBACK" << std::endl;
   break;
  case MIB_IF_TYPE_SLIP:
   std::cout << "SLIP" << std::endl;
   break;
  }

  const int unMACSegmentsCount = 6;

  if(unMACSegmentsCount == iInfo.dwPhysAddrLen)
  {      
   std::ostringstream ossMAC;
   ossMAC.fill('0');
   
   ossMAC << std::setw(2) << std::hex << static_cast<unsigned int>(iInfo.bPhysAddr[0]);

   for(int i = 1; i < unMACSegmentsCount; i++)
   {
    ossMAC << '-' << std::setw(2) << std::hex << static_cast<unsigned int>(iInfo.bPhysAddr[i]);
   }
    
   std::cout << "\tMAC Address:            " << ossMAC.str() << std::endl;   
  }  

  std::cout << std::endl;
 } 

 if (pIPAddrTable) 
 {
  free(pIPAddrTable);
  pIPAddrTable = 0;
 }
}

unsigned __stdcall thfn(void* args)
{
 HANDLE hTerminateEvent = *(HANDLE*)args;
 BOOL bTerminate = FALSE;
 
 OVERLAPPED overlap;
 overlap.hEvent = WSACreateEvent();

 if(overlap.hEvent == WSA_INVALID_EVENT)
 {
  std::cout << "WSACreateEvent() failed. Error code: " << WSAGetLastError() << std::endl;
  return THREAD_RETURN_CODE_ERROR;
 }

 while(!bTerminate)
 { 
  
  HANDLE h = 0;

  // call NotifyAddrChange in synchronous mode
  DWORD dwRetVal = NotifyAddrChange(&h, &overlap);

  if(dwRetVal != ERROR_IO_PENDING)
  {
   std::cout << "NotifyAddrChange() failed. Error code: " << WSAGetLastError() << std::endl;
   break;
  }

  HANDLE waitObjects[2] = {hTerminateEvent, overlap.hEvent};

  std::cout << "\nWaiting for IP Table change or termination request..." << std::endl;

  dwRetVal = WaitForMultipleObjects(2, waitObjects, FALSE, INFINITE);

  switch(dwRetVal)
  {
  case WAIT_OBJECT_0:
   std::cout << "WaitForSingleObject(waitObjects) returned WAIT_OBJECT_0 (hTerminateEvent is signaled)" << std::endl;
   bTerminate = TRUE;
   break;
  case WAIT_OBJECT_0 + 1:
   std::cout << "WaitForSingleObject(waitObjects) returned WAIT_OBJECT_0 + 1 (overlap.hEvent is signaled)" << std::endl;   
   
   if(!WSAResetEvent(overlap.hEvent))
   {
    std::cout << "WSAResetEvent() failed. Error code: " << WSAGetLastError() << std::endl;
    bTerminate = TRUE;
    break;
   }

   PrintIPTable();
   break;
  case WAIT_FAILED:
   std::cout << "WaitForSingleObject(waitObjects) returned WAIT_FAILED (function failed)" << std::endl;
   bTerminate = TRUE;
   break;
  }  
 }
 
 if(!WSACloseEvent(overlap.hEvent))
 {
  std::cout << "WSACloseEvent() failed. Error code: " << WSAGetLastError() << std::endl;
  return THREAD_RETURN_CODE_ERROR;
 }

 return THREAD_RETURN_CODE_SUCCESS;
}

void WaitUserInput()
{
 std::cin.clear(); 
 std::cin.ignore(1, '\n');
}

// NOTE: std::cout is shared between two threads and is not thread safe!
int main(int argc, char* argv[])
{
// std::cout << "main()" << std::endl;

 HANDLE hTerminateEvent = CreateEvent(0, TRUE, FALSE, 0);

 if(!hTerminateEvent)
 {
  std::cout << "CreateEvent() failed. Error code: " << GetLastError() << std::endl;
  return APP_RETURN_CODE_ERROR;
 }

 unsigned unThreadID = 0;
 HANDLE hThread = 0;

// std::cout << "Creating thread..." << std::endl;
 hThread = (HANDLE) _beginthreadex(0, 0, thfn, &hTerminateEvent, 0, &unThreadID);

 if(!hThread)
 {
  std::cout << "_beginthreadex() failed. Error code: " << errno << std::endl;
  return APP_RETURN_CODE_ERROR;
 }

 // (not reliable way to) make sure child thread has started before main thread continues
 Sleep(1000);

// std::cout << "Created thread with ID: " << unThreadID << std::endl;

 std::cout << "Press ENTER to terminate listening for changes in IP address table..." << std::endl;
 WaitUserInput();

 SetEvent(hTerminateEvent);

 // wait for thread to terminate
 DWORD dwRetVal = WaitForSingleObject(hThread, INFINITE);

 switch(dwRetVal)
 {
 case WAIT_OBJECT_0:
  std::cout << "WaitForSingleObject(hThread) returned WAIT_OBJECT_0 (event is signaled)" << std::endl;
  break;
 case WAIT_TIMEOUT:
  std::cout << "WaitForSingleObject(hThread) returned WAIT_TIMEOUT (timeout elapsed; event is nonsignaled)" << std::endl;
  break;
 case WAIT_FAILED:
  std::cout << "WaitForSingleObject(hThread) returned WAIT_FAILED (function failed)" << std::endl;
  break;
 }

 if(!CloseHandle(hThread))
 {
  std::cout << "CloseHandle() failed. Error code: " << GetLastError() << std::endl;
  return APP_RETURN_CODE_ERROR;
 }

 std::cout << "Press ENTER to exit..." << std::endl;
 WaitUserInput();

// std::cout << "~main()" << std::endl;
 return APP_RETURN_CODE_SUCCESS;
}

This is the output if we unplug network cable and then plug it back again:


Waiting for IP Table change or termination request...
Press ENTER to terminate listening for changes in IP address table...
WaitForSingleObject(waitObjects) returned WAIT_OBJECT_0 + 1 (overlap.hEvent is s
ignaled)
Num Entries: 2

Interface Index[0]: 17
IP Address[0]: 192.168.56.1
Subnet Mask[0]: 255.255.255.0
BroadCast[0]: 1.0.0.0(1)
Reassembly size[0]: 65535
Type and State[0]: Primary IP Address
Network interface name: VirtualBox Host-Only Ethernet Adapter
Network interface type: ETHERNET
MAC Address: 08-00-27-00-68-56


Interface Index[1]: 1
IP Address[1]: 127.0.0.1
Subnet Mask[1]: 255.0.0.0
BroadCast[1]: 1.0.0.0(1)
Reassembly size[1]: 65535
Type and State[1]: Primary IP Address
LOCALHOST interface
Network interface name: Software Loopback Interface 1
Network interface type: LOOPBACK


Waiting for IP Table change or termination request...
WaitForSingleObject(waitObjects) returned WAIT_OBJECT_0 + 1 (overlap.hEvent is s
ignaled)
Num Entries: 3

Interface Index[0]: 10
IP Address[0]: 192.168.253.122
Subnet Mask[0]: 255.255.255.0
BroadCast[0]: 1.0.0.0(1)
Reassembly size[0]: 65535
Type and State[0]: Primary IP Address Dynamic IP Address
Network interface name: Intel(R) 82566DC Gigabit Network Connection
Network interface type: ETHERNET
MAC Address: 00-19-d1-1b-e0-88


Interface Index[1]: 17
IP Address[1]: 192.168.56.1
Subnet Mask[1]: 255.255.255.0
BroadCast[1]: 1.0.0.0(1)
Reassembly size[1]: 65535
Type and State[1]: Primary IP Address
Network interface name: VirtualBox Host-Only Ethernet Adapter
Network interface type: ETHERNET
MAC Address: 08-00-27-00-68-56


Interface Index[2]: 1
IP Address[2]: 127.0.0.1
Subnet Mask[2]: 255.0.0.0
BroadCast[2]: 1.0.0.0(1)
Reassembly size[2]: 65535
Type and State[2]: Primary IP Address
LOCALHOST interface
Network interface name: Software Loopback Interface 1
Network interface type: LOOPBACK


Waiting for IP Table change or termination request...

WaitForSingleObject(waitObjects) returned WAIT_OBJECT_0 (hTerminateEvent is sign
aled)
WaitForSingleObject(hThread) returned WAIT_OBJECT_0 (event is signaled)
Press ENTER to exit...

Thursday 27 October 2011

How to include stdafx.h conditionally?

Don't try it as that's not possible!

If you try to put #include "stdafx.h" between #ifdef and #endif, you'll end up with error C1020: unexpected #endif. You need to include stdafx.h at the beginning of any source file in your project, apart from those files for which using precompiled headers is turned off.

There is one situation where this feature - setting using precompiled headers at the file level - comes very handy. Let's say we have some code file which does not include stdafx.h and we need to share it between project which uses precompiled headers - P1, and project which doesn't - P2. If we add that file to P1, this project won't compile  - compiler will complain with fatal error C1010: unexpected end of file while looking for precompiled header. We cannot include stdafx.h at the beginning of that file either as then P2 won't compile - it does not have stdafx.h. The only solution is to turn off using precompiled headers for that particular file.

Tuesday 25 October 2011

Finite State Machine in C

Finite State Machine is a way of modelling behaviour of some entity that can have a (finite) set of states. Depending on the received event, entity performs some action and changes its state (or remains in the current one).

Let's say we want to model a behaviour of some simple car. I call it "simple" as it has only ignition switch, accelerator and brake. Driver can turn it on, then accelerate, brake and, at the end of the journey, turn it off. If not careful, driver can break the car - if tries to turn it on (again) while driving. Driver's actions are events - inputs of our model. Car can be turned off, idling, moving or broken - and this is a set of our car's states. So, car is in some state, it reacts on driver's command (event), performs some action and goes into the next state.

We have a finite set of states and events and can draw a diagram which precisely define state transitions (state transition diagram):


FSM_CarExample_1

Now, how to implement this model and show how this state machine changes states after receiving events?

Each state can be represented as unique number - its code, or ID. The similar thing is with events. As we have finite number of both states and events, we can use enum type to represent them: one variable will be of enum STATE type and contain the ID of the current state and another variable will be of type enum EVENT and will contain the most recent event this system received. Initially, our car is turned off so the state variable will be set to STATE_TURNED_OFF. After this simple initialization we just need to wait for events and handle them in accordance to the given transition diagram. Events can be obtained from a keyboard or some other source and they are usually kept in a queue as sometimes a new event can be received before processing of the previous one is finished. In this example, in order to keep things simple, I'm gonna assume that processing is fast enough and will just create a predefined set of events and put them in an array.

As we have repetitive action - receiving and handling events - we'll put it in a loop. If our events source is keyboard and we don't know how many events will user issue, we can use while-loop and CTRL-C as a loop termination command. In this example, we have an array of events which is of predefined (known in advance) size so we can use for-loop. Inside this loop, we need to place event processing code for each event, received in each state. This means we will have switch-statement inside another switch-statement. So, here's the code:

main.c:



Output:

Whoooa! I'm turned on!
Yipee! I'm accelerating!
Whoops! Was I too fast?
That was probably enough...

Having a switch inside a switch looks a bit complex and difficult to maintain. If we add a new state, we need to add a new case-branch for each event. In the code above it would mean we need to make changes at 4 different places in the code! Not good!

A solution for this is a state transition table. It is basically a table in which each state has its column and each event has its row. Table elements are pairs action/next-state - let's put them in some structure called TRANSITION. If transition table is called trans_tbl its element, trans_tbl[evt][state] is of type TRANSITION and action is a function called during transition and next-state is the state our model goes into for the current event. Code tells this better:

main.c:


Output is the same:

Whoooa! I'm turned on!
Yipee! I'm accelerating!
Whoops! Was I too fast?
That was probably enough...

The code has shrunk and become easier to understand and maintain: if we want to add a new event or a state, we just need to change transition table (trans_tbl) - we don't need to touch the code in a loop!

My article "Finite State Machine in C++" shows how to use OOP and State design pattern in order to implement FSM described here.

Links and references:
Finite-state machine (Wikipedia)
UML Tutorial: Finite State Machines

Friday 14 October 2011

Reading XML with Guththila

Guththila is Apache XML parser for Axis2/C.

I've been playing with Guththila recently and just want to share code which demonstrates how to use Guththila in a standalone application, GuththilaTest. It will read data from the following XML file:

books.xml:

<?xml version="1.0" ?>
<books>
<Genre Name="Biography">
<Author Name="Michael Moore">
<Book Name="Here Comes Trouble" ISBN="9780713997019" PublishingDate="13-Sep-2011"/>
</Author>
<Author Name="Alan Sugar">
<Book Name="Way I See it" ISBN="9780230760899" PublishingDate="29-Sep-2011"/>
</Author>
</Genre>
<Genre Name="Fiction">
<Author Name="Ivo Andric">
<Book Name="Bridge Over the Drina" ISBN="9781860460586" PublishingDate="05-Apr-1994"/>                      
</Author>
<Author Name="Fyodor Dostoyevsky">
<Book Name="Crime and Punishment" ISBN="9780955816949" PublishingDate="30-Oct-2008"/>
   <Book Name="Brothers Karamazov" ISBN="9780140449242" PublishingDate="27-Feb-2003"/>
</Author>
</Genre>
</books>


We need to download Axis2/C binary package (or its source and build binaries ourselves) as Guththila requires axutil.dll and guththila.dll in a runtime and application that uses Guththila must be linked against its static libraries axutil.lib and guththila.lib.

Axis2/C manual suggest placing Axis2/C package at some location your disk (e.g. c:\axis2c) and setting environment variable AXIS2C_HOME to that path, plus adding %AXIS2C_HOME%/lib to Path environment variable so any application can find Axis2C libraries.

In this example, I will use minimalistic approach, putting all necessary libraries (axutil.dll, guththila.dll) in application's directory.

If path to necessary Axis2C DLLs is not in Path environment variable and if necessary DLLs are not in the application's directory, following message appears if you try to run the app:

---------------------------
GuththilaTest.exe - System Error
---------------------------
The program can't start because axutil.dll is missing from your computer. Try reinstalling the program to fix this problem.
---------------------------
OK
---------------------------

We need to create environment variable, and we want to have log file as well so we need to call axutil_env_create_all() function.

This algorithm explains the logic of the Axis2/C log file creation:

pass log file string to axutil_env_create_all() as an argument

axutil_env_create_all() forwards that string to axutil_log_create()

if (string is full path to log file, including its name)
   axutil_log_create() creates log file at the proved path
else (string is just log file name)
   axutil_log_create() tries to read path from AXIS2C_HOME environment variable
   if AXIS2C_HOME path obtained
      axutil_log_create() creates log file at AXIS2C_HOME/logs path
   else
     axutil_log_create() creates log file in the current directory

I don't want to change environment variables so just place axutil.dll and guththila.dll (together with books.xml) in the same directory with GuththilaTest.exe. As I don't set AXIS2C_HOME environment variable, Axis creates log file in the same directory.

So here is the code. ReadXML(...) outputs formatted content of the XML file to the standard output. GetBookInfo(...) performs search for a particular node. Each parsing session (going through XML) requires (re)initialized parser. guth_init(...) is therefore called before and guth_clean() after each of these two functions. GetStrLen(), CopyStrRealloc() and PrintSpaces() are some helper functions.

main.c:



This is the output:


..\GuththilaTest\Debug>GuththilaTest.exe
AXIS2C_HOME is not set - log is written to . dir
 <books>
  <Genre Name="Biography">
   <Author Name="Michael Moore">
    <Book PublishingDate="13-Sep-2011" ISBN="9780713997019" Name="Here Comes Tro
uble"/>
   </Author>
   <Author Name="Alan Sugar">
    <Book PublishingDate="29-Sep-2011" ISBN="9780230760899" Name="Way I See it"/
>
   </Author>
  </Genre>
  <Genre Name="Fiction">
   <Author Name="Ivo Andric">
    <Book PublishingDate="05-Apr-1994" ISBN="9781860460586" Name="Bridge Over th
e Drina"/>
   </Author>
   <Author Name="Fyodor Dostoyevsky">
    <Book PublishingDate="30-Oct-2008" ISBN="9780955816949" Name="Crime and Puni
shment"/>
    <Book PublishingDate="27-Feb-2003" ISBN="9780140449242" Name="Brothers Karam
azov"/>
   </Author>
  </Genre>
 </books>

Details for book "Brothers Karamazov" found: ISBN="9780140449242", PublishingDat
e="27-Feb-2003"
..\GuththilaTest\Debug>

And this is the content of the log file:

[Fri Oct 14 19:49:18 2011] [debug] c:\development\research\c\guththilatest\guththilatest\main.c(595)
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(534) reader created
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(517) DebugReader()
buff_size=-1163005939
type=1
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(553) parser created
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(502) DebugParser()
guththila_event=-1
last_start=-1
name=0
next=0
status=1

[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(517) DebugReader()
buff_size=-1163005939
type=1
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 0
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(103) GUTHTHILA_START_DOCUMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 0
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(239) GUTHTHILA_SPACE
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 1
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(115) GUTHTHILA_START_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(142) Name: "books"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(149) Number of attributes: 0
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 1
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(239) GUTHTHILA_SPACE
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 2
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(115) GUTHTHILA_START_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(142) Name: "Genre"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(149) Number of attributes: 1
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(177) AttribName: "Name"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(189) AttribVal: "Biography"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 2
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(239) GUTHTHILA_SPACE
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 3
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(115) GUTHTHILA_START_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(142) Name: "Author"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(149) Number of attributes: 1
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(177) AttribName: "Name"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(189) AttribVal: "Michael Moore"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 3
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(239) GUTHTHILA_SPACE
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 4
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(120) GUTHTHILA_EMPTY_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(142) Name: "Book"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(149) Number of attributes: 3
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(177) AttribName: "PublishingDate"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(189) AttribVal: "13-Sep-2011"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(177) AttribName: "ISBN"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(189) AttribVal: "9780713997019"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(177) AttribName: "Name"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(189) AttribVal: "Here Comes Trouble"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 3
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(239) GUTHTHILA_SPACE
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 2
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(212) GUTHTHILA_END_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(217) Name: "Author"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 2
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(239) GUTHTHILA_SPACE
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 3
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(115) GUTHTHILA_START_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(142) Name: "Author"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(149) Number of attributes: 1
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(177) AttribName: "Name"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(189) AttribVal: "Alan Sugar"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 3
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(239) GUTHTHILA_SPACE
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 4
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(120) GUTHTHILA_EMPTY_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(142) Name: "Book"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(149) Number of attributes: 3
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(177) AttribName: "PublishingDate"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(189) AttribVal: "29-Sep-2011"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(177) AttribName: "ISBN"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(189) AttribVal: "9780230760899"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(177) AttribName: "Name"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(189) AttribVal: "Way I See it"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 3
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(239) GUTHTHILA_SPACE
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 2
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(212) GUTHTHILA_END_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(217) Name: "Author"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 2
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(239) GUTHTHILA_SPACE
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 1
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(212) GUTHTHILA_END_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(217) Name: "Genre"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 1
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(239) GUTHTHILA_SPACE
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 2
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(115) GUTHTHILA_START_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(142) Name: "Genre"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(149) Number of attributes: 1
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(177) AttribName: "Name"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(189) AttribVal: "Fiction"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 2
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(239) GUTHTHILA_SPACE
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 3
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(115) GUTHTHILA_START_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(142) Name: "Author"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(149) Number of attributes: 1
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(177) AttribName: "Name"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(189) AttribVal: "Ivo Andric"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 3
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(239) GUTHTHILA_SPACE
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 4
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(120) GUTHTHILA_EMPTY_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(142) Name: "Book"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(149) Number of attributes: 3
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(177) AttribName: "PublishingDate"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(189) AttribVal: "05-Apr-1994"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(177) AttribName: "ISBN"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(189) AttribVal: "9781860460586"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(177) AttribName: "Name"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(189) AttribVal: "Bridge Over the Drina"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 3
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(239) GUTHTHILA_SPACE
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 2
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(212) GUTHTHILA_END_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(217) Name: "Author"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 2
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(239) GUTHTHILA_SPACE
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 3
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(115) GUTHTHILA_START_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(142) Name: "Author"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(149) Number of attributes: 1
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(177) AttribName: "Name"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(189) AttribVal: "Fyodor Dostoyevsky"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 3
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(239) GUTHTHILA_SPACE
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 4
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(120) GUTHTHILA_EMPTY_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(142) Name: "Book"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(149) Number of attributes: 3
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(177) AttribName: "PublishingDate"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(189) AttribVal: "30-Oct-2008"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(177) AttribName: "ISBN"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(189) AttribVal: "9780955816949"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(177) AttribName: "Name"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(189) AttribVal: "Crime and Punishment"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 3
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(239) GUTHTHILA_SPACE
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 4
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(120) GUTHTHILA_EMPTY_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(142) Name: "Book"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(149) Number of attributes: 3
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(177) AttribName: "PublishingDate"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(189) AttribVal: "27-Feb-2003"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(177) AttribName: "ISBN"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(189) AttribVal: "9780140449242"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(177) AttribName: "Name"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(189) AttribVal: "Brothers Karamazov"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 3
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(239) GUTHTHILA_SPACE
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 2
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(212) GUTHTHILA_END_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(217) Name: "Author"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 2
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(239) GUTHTHILA_SPACE
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 1
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(212) GUTHTHILA_END_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(217) Name: "Genre"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 1
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(239) GUTHTHILA_SPACE
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(97) Number of elements in guththila stack: 0
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(212) GUTHTHILA_END_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(217) Name: "books"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(566) guththila_reader_free() ok
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(573) guththila_un_init() ok
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(534) reader created
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(517) DebugReader()
buff_size=-1163005939
type=1
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(553) parser created
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(502) DebugParser()
guththila_event=-1
last_start=-1
name=0
next=0
status=1

[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(517) DebugReader()
buff_size=-1163005939
type=1
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(267) GetBookInfo()
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(268) Number of elements in guththila stack: 0
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(272) Number of elements in guththila stack: 0
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(278) GUTHTHILA_START_DOCUMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(272) Number of elements in guththila stack: 0
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(272) Number of elements in guththila stack: 1
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(290) GUTHTHILA_START_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(313) Name: "books"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(318) Is current node Genre node?
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(272) Number of elements in guththila stack: 1
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(272) Number of elements in guththila stack: 2
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(290) GUTHTHILA_START_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(313) Name: "Genre"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(318) Is current node Genre node?
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(322) Current node is Genre node
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(353) Number of attributes: 1
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(370) AttribName: "Name"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(385) AttribVal: "Biography"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(393) Name="Biography"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(272) Number of elements in guththila stack: 2
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(272) Number of elements in guththila stack: 3
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(290) GUTHTHILA_START_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(313) Name: "Author"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(318) Is current node Genre node?
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(272) Number of elements in guththila stack: 3
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(272) Number of elements in guththila stack: 4
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(295) GUTHTHILA_EMPTY_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(313) Name: "Book"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(318) Is current node Genre node?
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(272) Number of elements in guththila stack: 3
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(272) Number of elements in guththila stack: 2
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(468) GUTHTHILA_END_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(473) Name: "Author"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(272) Number of elements in guththila stack: 2
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(272) Number of elements in guththila stack: 3
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(290) GUTHTHILA_START_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(313) Name: "Author"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(318) Is current node Genre node?
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(272) Number of elements in guththila stack: 3
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(272) Number of elements in guththila stack: 4
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(295) GUTHTHILA_EMPTY_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(313) Name: "Book"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(318) Is current node Genre node?
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(272) Number of elements in guththila stack: 3
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(272) Number of elements in guththila stack: 2
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(468) GUTHTHILA_END_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(473) Name: "Author"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(272) Number of elements in guththila stack: 2
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(272) Number of elements in guththila stack: 1
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(468) GUTHTHILA_END_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(473) Name: "Genre"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(272) Number of elements in guththila stack: 1
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(272) Number of elements in guththila stack: 2
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(290) GUTHTHILA_START_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(313) Name: "Genre"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(318) Is current node Genre node?
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(322) Current node is Genre node
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(353) Number of attributes: 1
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(370) AttribName: "Name"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(385) AttribVal: "Fiction"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(393) Name="Fiction"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(400) Found Genre node with Name "Fiction"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(272) Number of elements in guththila stack: 2
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(272) Number of elements in guththila stack: 3
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(290) GUTHTHILA_START_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(313) Name: "Author"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(328) Is current node Author node?
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(332) Current node is Author node
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(353) Number of attributes: 1
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(370) AttribName: "Name"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(385) AttribVal: "Ivo Andric"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(393) Name="Ivo Andric"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(272) Number of elements in guththila stack: 3
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(272) Number of elements in guththila stack: 4
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(295) GUTHTHILA_EMPTY_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(313) Name: "Book"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(328) Is current node Author node?
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(272) Number of elements in guththila stack: 3
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(272) Number of elements in guththila stack: 2
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(468) GUTHTHILA_END_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(473) Name: "Author"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(272) Number of elements in guththila stack: 2
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(272) Number of elements in guththila stack: 3
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(290) GUTHTHILA_START_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(313) Name: "Author"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(328) Is current node Author node?
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(332) Current node is Author node
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(353) Number of attributes: 1
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(370) AttribName: "Name"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(385) AttribVal: "Fyodor Dostoyevsky"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(393) Name="Fyodor Dostoyevsky"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(411) Found Author node with Name "Fyodor Dostoyevsky"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(272) Number of elements in guththila stack: 3
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(272) Number of elements in guththila stack: 4
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(295) GUTHTHILA_EMPTY_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(313) Name: "Book"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(338) Is current node Book node?
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(343) Current node is Book node
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(353) Number of attributes: 3
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(370) AttribName: "PublishingDate"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(385) AttribVal: "30-Oct-2008"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(441) PublishingDate: "30-Oct-2008"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(451) pBookInfo->pszPublishingDate = "30-Oct-2008"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(370) AttribName: "ISBN"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(385) AttribVal: "9780955816949"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(427) ISBN: "9780955816949"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(437) pBookInfo->pszISBN = "9780955816949"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(370) AttribName: "Name"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(385) AttribVal: "Crime and Punishment"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(393) Name="Crime and Punishment"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(272) Number of elements in guththila stack: 3
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(272) Number of elements in guththila stack: 4
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(295) GUTHTHILA_EMPTY_ELEMENT
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(313) Name: "Book"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(338) Is current node Book node?
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(343) Current node is Book node
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(353) Number of attributes: 3
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(370) AttribName: "PublishingDate"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(385) AttribVal: "27-Feb-2003"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(441) PublishingDate: "27-Feb-2003"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(451) pBookInfo->pszPublishingDate = "27-Feb-2003"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(370) AttribName: "ISBN"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(385) AttribVal: "9780140449242"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(427) ISBN: "9780140449242"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(437) pBookInfo->pszISBN = "9780140449242"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(370) AttribName: "Name"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(385) AttribVal: "Brothers Karamazov"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(393) Name="Brothers Karamazov"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(421) Found Book node with Name "Brothers Karamazov"
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(495) ~GetBookInfo()
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(566) guththila_reader_free() ok
[Fri Oct 14 19:49:18 2011] [debug] \guththilatest\main.c(573) guththila_un_init() ok

Please be aware that Guththila is not intended for direct use but through its wrapper, axis2_parser [link]. That is probably the reason why there is no documentation about it available on the Internet.

axis2_parser is XML parser abstraction layer which can be either guththila or libxml2 wrapper. In the first case (in Axis2/C binary package), axis2_parser.dll depends on guththila.dll. In the second case (in custom Axis2/C builds), axis2_parser.dll depends on libxm2.dll, zlib1.dll and iconv.dll.