Thursday, May 30, 2013

libxml2 - process node in the tree.

Because the original code example which libxml2 demo tree1.c how to traverse the tree was using Recursive to process the relationship between the children node and the next node, but I think it is dangerous because we don't know when the stack overflow problem happen and it will happen sometime in the future.

the original code example

static void print_element_names(xmlNode * a_node)
{
 xmlNode *cur_node = NULL;

 for (cur_node = a_node; cur_node; cur_node = cur_node->next) {
   if (cur_node->type == XML_ELEMENT_NODE) {
     printf("node type: Element, name: %s\n", cur_node->name);
   }
   print_element_names(cur_node->children);
 }
}

So I checked the xmlNode structure and find out the parent node is the useful hint to traverse the xml node tree.
  1. Process the current node first.
  2. Check the node if there is any children node and yes, process the children node.
  3. Check the node if there is any next node and yes, process the next node.
  4. If there is no children and next node,
    1. check if there is any parent node and yes, go back to the parent node
    2. When in the parent node, because it should be processed in step 0, check if there is any next node.
    3. If there is a next node, repeat step 3.
    4. If there is no any next node, repeat step 4.
  5. Finally there is no next and parent node, the node should be the XML_DOCUMENT_NODE.
void do_indent(int indent)
{
  for (; indent; --indent) {
    putchar(' ');
    putchar(' ');
  }
}

int getNextNode( xmlNode **pCurr, int *deepth )
{
  xmlNode *curr = *pCurr;

  if ( curr->children!=NULL ) {
    /* Move to the children node.
     */
    curr = curr->children;
    *deepth += 1;
  } else if ( curr->next==NULL && curr->parent) {
    /* Go back to the parent node.
       then go to the next node of the parent node or
       go to the parent node of the parent node if there is no any next node behind.
       if there is no any parent node, it should be the XML_DOCUMENT_NODE.
     */
    curr = curr->parent;
    *deepth -= 1;
    while ( curr->next==NULL && curr->parent!=NULL ) {
      curr = curr->parent;
      *deepth -= 1;
    }
    if ( curr->next!=NULL ) {
      curr = curr->next;
    } else {
      /* It should be XML_DOCUMENT_NODE.
       */
      curr = NULL;
    }
  } else {
    curr = curr->next;
  }

  *pCurr = curr;

}

void process_node(xmlNode *pNode)
{
  xmlNode *curr=NULL;

  int indent=0;

  if ( !pNode ) {
    printf("No Node exist\n");
    return;
  }

  for ( curr=pNode ; curr ; getNextNode(&curr, &indent)) {

    if (curr->type == XML_ELEMENT_NODE) {
      do_indent(indent);
      printf("node type: Element, name: %s", curr->name);

      if ( curr->properties ) {
        process_attr(curr->properties);
      }

      printf("\n");
    } else if ( curr->type==XML_TEXT_NODE ) {
      do_indent(indent);
      printf("node type: Text, name: %s\n", curr->content);
    }
  }
}

Tuesday, May 28, 2013

perl - lwp implement

#!/usr/bin/env perl

use strict;
use LWP;
use File::Basename;
use warnings;
use constant false => 0;
use constant true => 1;

my $host = "192.168.1.1";
my $prot = "https://";
my ($user, $pwd) = ("admin", "1234");
my @pathes = qw(/status_quickview.cgi);
my $ua = LWP::UserAgent->new();

$ua->cookie_jar({ file => "$ENV{HOME}/.cookies.txt", autosave=>1 });
push @{ $ua->requests_redirectable}, 'POST';
$ua->show_progress(true);

if ( is_login()==false ) {  do_login(); }
foreach my $p (@pathes) {
  do_get($p);
}
do_logout();

sub do_post {
  my ($path, $query) = @_;
  print "do_post($path)\n";
  my $url = $prot . $host . $path;
  my $req = HTTP::Request->new(POST => $url);
  $req->content_type('application/x-www-form-urlencoded');
  $req->content($query);
  # print $req->as_string(),"\n";
  my $resp = $ua->request($req);
  if ( $resp->is_error() ) {
    print $resp->status_line(), "\n";
    exit();
  }
  # print $resp->content, "\n"; return $resp;
}

sub do_get {
  my ($fullpath) = @_;
  my ($name, $path, $suffix) = fileparse($fullpath);
  print "do_get($fullpath)\n";
  my $url = $prot . $host . $fullpath;
  my $req = HTTP::Request->new(GET => $url);
  # my $resp = $ua->request($req, $name);
  my $resp = $ua->request($req);
  if ( $resp->is_error() ) {
    print $resp->status_line(), "\n";
    exit();
  }
  # print $resp->content(), "\n";
  return $resp;
}

sub do_login {
  print "do_login()\n";
  my $path = "/login_handler.cgi";
  my $query = sprintf("username=%s&password=%s&Signin=Login", $user, $pwd);
  my $resp = do_post($path, $query);
  if ( 1 and $resp->content=~m/type=(\w+)/ ) {
    # print "type=$1\n";
    $ua->cookie_jar->set_cookie(0, 'type', $1, '/', $host);
    $ua->cookie_jar->save();
  }
}

sub is_login {
  print "is_login()\n";
  my $path = "/status_quickview.cgi";
  my $resp = do_get($path);
  if ( index($resp->content, "login.cgi")!=-1 ) {
    return false;
  } else {
    return true;
  }
}

sub do_logout {
  print "do_logout()\n";
  my $path = "/tools_logout.cgi";
  my $resp = do_post($path, "apply=");
  # print $resp->content, "\n";
}

C - Key/Value Pair Programming

/* conf.txt a=1 b=2 c=3 x=4 y=5 z=6 */ #include <stdio.h> #include <stdlib.h> #include <string.h> struct { char *a; int b; char *c; int x; char *y; int z; } conf; struct config_t { char *key; enum { TYPE_STR, TYPE_INT, } value_type; union { char **str_var; int *int_var; }; } config_table[] = { {"a", TYPE_STR, {.str_var=&conf.a} }, {"b", TYPE_INT, {.int_var=&conf.b}}, {"c", TYPE_STR, {.str_var=&conf.c}}, {"x", TYPE_INT, {.int_var=&conf.x}}, {"y", TYPE_STR, {.str_var=&conf.y}}, {"z", TYPE_INT, {.int_var=&conf.z}}, {NULL, TYPE_STR, {NULL} } }; int main(int argc, char *argv[]) { char buf[80]; FILE *fp; struct config_t *pConfig; char *k, *v, *found; fp=fopen("conf.txt", "r"); if ( !fp ) { perror("fopen failed"); exit(1); } while ( fgets(buf, sizeof(buf), fp)!=NULL ) { found=strchr(buf, '\n'); if ( found ) { *found=0x00; } found = strchr(buf, '='); if ( !found ) { continue; } *found=0x00; k=buf; v=found+1; pConfig = config_table; for (; pConfig->key ; ++pConfig) { if ( strcmp(k, pConfig->key)==0 ) { if ( pConfig->value_type==TYPE_STR ) { *pConfig->str_var = strdup(v); } else if ( pConfig->value_type==TYPE_INT ) { *pConfig->int_var = atoi(v); } } } } printf("a:%s\nb:%d\nc:%s\n", conf.a, conf.b, conf.c); printf("x:%d\ny:%s\nz:%d\n", conf.x, conf.y, conf.z); return 0; }

Sunday, May 26, 2013

Perl experience - misc

In Perl, when to call subroutine with ampersand or parentheses. It's always confusing to me. Finally, I have some conclusion on it.

1. if perl can see the subroutine definition before invocation, ampersand can be omitted.
2. if perl can tell from the syntax that it's a subroutine call, for example sub(), ampersand can be omitted.
3. Otherwise, use &. Or you will get compilation error when using strict.

Correct Example
#!/usr/bin/env perl
use strict;
use warnings;

&sub1;

#
# the parentheses tell it's subroutine.
#
sub1();

sub sub1 { print "sub1\n"; }

#
# the subroutine defintion before invocation.
#
sub1;

Incorrect Example
#!/usr/bin/env perl
use strict;
use warnings;
sub1;
sub sub1 { print "sub1\n"; }

The Perl will complain
Bareword "sub1" not allowed while "strict subs" in use at sub.pl

Simple circular buffer implement

circular implement

#include
#include

#define BUF_SIZE 4

typedef struct {
  enum {
    BUFF_STATUS_EMPTY=0,
    BUFF_STATUS_NOTEMPTY,
    BUFF_STATUS_FULL
  } status;
  int b[BUF_SIZE];
  int i;
  int o;
} buff_t ;

void in(buff_t *buf)
{
  int newp;
  do {
    newp= (buf->i+1)%BUF_SIZE;
    if ( newp == buf->o ) {
      buf->status=BUFF_STATUS_FULL;
      break;
    } else {
      buf->status=BUFF_STATUS_NOTEMPTY;
      buf->i=newp;
      buf->b[buf->i]=buf->i;
    }
  } while (1) ;
}

void out(buff_t *buf)
{
  int newp;
  do {
    newp=(buf->o+1)%BUF_SIZE;
    if ( newp==buf->i ) {
      buf->status = BUFF_STATUS_EMPTY;
      break;
    } else {
      buf->o=newp;
      printf("%d:%d\n", buf->o, buf->b[buf->o]);
      buf->b[newp]=0x00;
    }
  } while (1);
}

int main(int argc, char *argv)
{
  buff_t b1;
  memset(&b1, 0x00, sizeof(b1));
  for (;1;) {
    if ( b1.status != BUFF_STATUS_FULL)
      in(&b1);
    if (b1.status != BUFF_STATUS_EMPTY)
      out(&b1);
  }
}

Stuff interested

List the stuff which I am interested.

Blackberry
C
C++
C#
Erlang
Java
Lua
Object C
Perl
Python
Ruby
Ubuntu