Category Archives: C/C++ - Page 2

My tree command for POSIX systems in C

I like the tree command. It’s nice to have when working with lots of directories and it brings an ‘graphic’ element to the command line 🙂 I’m here going to show a simple tree solution in C that I usually use as a base for more complicated implementations.

#include <string>
#include <dirent.h>
 
void rec_walker(const char *path, int level);
char* writer(int level);
 
int main(int argc, char const *argv[]) {
 
	DIR        *dir;
	const char *path;
 
	path = argv[1];
 
	// If no path set current path
	if (path == NULL) {
		path = ".";
	}
 
	// Test if dir  	
  	dir = opendir(path);
 
  	if(dir) {  		
    	    rec_walker(path, 0);
  	}
  	else {
  		printf("%s is not a directory\n", argv[1]);
  		return 1;
  	}
 
	return 0;
}

Im here using the standard library for common string operations and the dirent.h for easy access to the filesystem. First we have to define our external (not in main()) functions, rec_walker() and the writer() function (more about these later).
Then we set the path that we want to traverse. If no path from argv[] we set current directory as path. Now that we have a path we test to see if it is a directory and if it is we call the rec_walker() function:

void rec_walker(const char *path, int level){
	struct dirent *file;
	DIR *directory;
 
	chdir(path);
 
	directory = opendir(".");
 
	if(directory){
		while ((file = readdir(directory)) != NULL) {
 
			if (strcmp( file->d_name, "." ) != 0 && strcmp( file->d_name, ".." ) != 0) {			
 
				if (file->d_type == DT_DIR) {
					printf("%s%s:\n", writer(level + 1), file->d_name);
					rec_walker(file->d_name, level + 1);
				}
				else{
	      			printf("%s%s\n", writer(level), file->d_name);
	      		}
	      	}	
    	}
    	closedir(directory);
    }	
 
}

The rec_walker() function takes the path (as string) and a level (as int). The level variable is uses for a little ‘pretty print’. The rec_walker() function lists all files in the directory, and if the ‘file’ is a directory (DT_DIR) it will recursively call itself with the new path and an incremented level. It continues to do this until no directories are left.

Now we add a little ‘pretty print’ with the writer() function:

char* writer(int level){
 
	const char characters[] = "-----------------------------------";
	char result[] = "";
 
	// Max levels 
	if (level > 18)	{
		level = 18;
	}
 
	return strncat(result, characters, level * 2);
 
}

This function simply returns some lines to ‘indent’ the different levels to make it easier to read (very simple)

Example output from the above code:

--test:
--test_file.txt
----test_lvl2:
----test_file_lvl2.txt
treeplus
treeplus.c

Tested on gcc 4.2.1 and OSX 10.7.5

How to access a Sqlite database in C

I’m here going to demonstrate a simple connection and query to a SQLite database using C.

First you need to download and build (if necessary) the SQLite code so you get the sqlite3.so (or sqlite3.lib on Windows) and the necessary header and c files (sqlite3.h, sqlite3.c). I will not go into how this is done here.

After the environment is setup we start with connecting to the SQLite database:

 
#include "sqlite3.h"

int main(int argc, char const *argv[]) {
        
    sqlite3 *conn; // Database struct handle
    const char *dbname = "test.db"; // Database file name
    int dbhandle; // Resource handle

    // Open database
    dbhandle = sqlite3_open_v2(dbname, &conn, SQLITE_OPEN_READONLY, NULL);

    if(dbhandle == SQLITE_OK) {
        fprintf(stdout, "Database open\n");
    }
    else {		
        fprintf(stderr, "Could not open database: %s\n", sqlite3_errmsg(conn) );
        return 1;
   }

   // Cleanup
   sqlite3_close(conn);

   return 0;

}

In short this code will do the following:
1. Create necessary variables for connection, resource handle and the database file name
2. Call sqlite3_open_v2() to open a read only connection to the SQLite database (test.db)
3. Check if we succeeded and report result to console
4. Cleanup connection object

I choose here to use the sqlite3_open_v2() function due to two main reasons:
1. I don’t want to create the database if it does not exist. This is the default behavior of sqlite3_open()
2. I want to be able to open the database as readonly (SQLITE_OPEN_READONLY) or as readwrite (SQLITE_OPEN_READWRITE)

Now we are also going to query the database and present the result. We start with adding a callback function to handle the output like this:

static int callback(void *NotUsed, int argc, char **argv, char **colname){

	NotUsed = 0;
	int i;
	for (i = 0; i < argc; i++){

		printf("%s = %s\n", colname[i], argv[i] ? argv[i] : "NULL");
	}
	printf("\n");
	return 0;
}

This function is going to be called from sqlite3_exec() function later. Once per row of results from query. It will print a list with “column name = cell value” rows

 
#include "sqlite3.h"

int main(int argc, char const *argv[]) {
    
    // Connection variables    
    sqlite3 *conn; // Database struct handle
    const char *dbname = "test.db"; // Database file name
    int dbhandle; 

    // Query variables
    int stmthandle;  // Statement handel
    char *errorMsg = 0; // Error message holder
    const char *query = "SELECT * FROM user";  // Query to run 

    // Open database
    dbhandle = sqlite3_open_v2(dbname, &conn, SQLITE_OPEN_READONLY, NULL);

    if(dbhandle == SQLITE_OK) {
        fprintf(stdout, "Database open\n");
    }
    else {		
        fprintf(stderr, "Could not open database: %s\n", sqlite3_errmsg(conn) );
        return 1;
    }
   
    // Execute query
    stmthandle = sqlite3_exec(conn, query, callback, 0, &errorMsg);

    if (stmthandle == SQLITE_OK) {
        fprintf(stdout, "Query successful\n");
    }
    else {
         fprintf(stderr, "Could not run query: %s\n", errorMsg );
         return 1;
    }

    // Cleanup
    sqlite3_close(conn);
    
    return 0;

}

I have now added the sqlite3_exec() wrapper function (it handles sqlite3_prepare_v2(), sqlite3_step() and sqlite3_finalize() all into one nifty function) and the necessary query variables (statement handle, error message holder and SQL statement).

The sqlite3_exec() function takes the following input:
1. Connection handle to the database
2. SQL query
3. Name of callback function to call for every row of results from database
4. First argument to callback function (the NotUsed argument in the callback function above)
5. Error message holder to return error messages in (if any)

After these arguments have all been satisfied, sqlite3_exec() will call the callback function with the results. Here is an example of output:

Database open
id = 1
login = anders
password = dator123

id = 2
login = niklas
password = dator123

id = 3
login = miew
password = dator123

Query successful

and that is it. We now have a small and simple example of how you connect and query a SQLite database using C.

NOTE: When compiling do not forget to add the -lsqlite3 argument to gcc:

gcc test.c -o test -lsqlite3 -Wall

This has been tested on SQLite 3.7.15.2, gcc 4.2 and OSX 10.7.5