Appaserver's Core Principles

Functional declarative programming provides both air-tight execution and algorithm leverage. However, Appaserver is written in C -- an imperative programming language. To bridge the gap, you can program functionally in C.

  1. Create structures (objects).
  2. Write functions for the objects (operations).
  3. Execute functions just-in-time.
  4. Minimize variables.

The goal is to write C code that reads like a rosetta stone between the CPU and the user experience. To develop this skill, master the program modules section in Wikipedia's computer program article.

The ideal function should have only input parameters and return a single object. Appaserver's developers achieve functional cohesion and data coupling by constructing abstract datatypes.

The syntax for an operation is either:

Datatype *ClassName_Verb( parameter list );

Or

Datatype *ClassName[_OptionalContext]_Datatype( parameter list );

For example:

/* person.h */
/* -------- */
#ifndef PERSON_H
#define PERSON_H

#include "list.h"

typedef struct
{
	char *full_name;
	char *street_address;
	char *zip_code;
	char *birth_date;
} PERSON;

int person_age_integer(	char *current_date,
			char *birth_date );

LIST *person_zip_code_list(
			char *zip_code );

LIST *person_list(	char *where );

PERSON *person_fetch(	char *full_name,
			char *street_address );

PERSON *person_new(	char *full_name,
			char *street_address );

/* Returns program memory */
/* ---------------------- */
char *person_select_string(
			void );

/* Returns static memory */
/* --------------------- */
char *person_primary_where_string(
			char *full_name,
			char *street_address );

PERSON *person_parse(	char *input_buffer );

#endif

/* person.c */
/* -------- */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "person.h"
#include "date.h"
#include "piece.h"
#include "security.h"
#include "list.h"

PERSON *person_new( char *full_name, char *street_address )
{
	PERSON *person;

	if ( ! ( person = calloc( 1, sizeof( PERSON ) ) ) )
	{	
		fprintf(stderr,
		"ERROR in %s/%()/%d: calloc() returned empty.\n",
			__FILE__,
			__FUNCTION__,
			__LINE__ );
		return (PERSON *)0;
	}
	person->full_name = full_name;
	person->street_address = street_address;
	return person;
}

char *person_select_string( void )
{
	return "full_name, street_address, zip_code, birth_date";
}

PERSON *person_parse( char *input_buffer )
{
	char full_name[ 128 ];
	char street_address[ 128 ];
	char buffer[ 128 ];
	PERSON *person;

	if ( !input_buffer || !*input_buffer ) return (PERSON *)0;

	piece( full_name, SQL_DELIMITER, input_buffer, 0 );
	piece( street_address, SQL_DELIMITER, input_buffer, 1 );

	if ( ! ( person =
			person_new(
				strdup( full_name ),
				strdup( street_address ) ) ) )
	{
		return (PERSON *)0;
	}

	piece( buffer, SQL_DELIMITER, input_buffer, 2 );
	person->zip_code = strdup( buffer );

	piece( buffer, SQL_DELIMITER, input_buffer, 3 );
	person->birth_date = strdup( buffer );

	return person;
}

char *person_primary_where_string(
			char *full_name,
			char *street_address )
{
	static char where[ 1024 ];

	sprintf( where,
		 "full_name = '%s' and street_address = '%s'",
		 security_sql_injection_escape(
			full_name ),
		 security_sql_injection_escape(
			street_address ) );

	return where;
}

PERSON *person_fetch(	char *full_name,
			char *street_address )
{
	char system_string[ 1024 ];
	char input_buffer[ 1024 ];
	FILE *input_pipe;

	sprintf( system_string,
		 "echo \"select %s from person where %s;\" | sql",
		 /* ---------------------- */
		 /* Returns program memory */
		 /* ---------------------- */
		 person_select_string(),
		 /* --------------------- */
		 /* Returns static memory */
		 /* --------------------- */
		 person_primary_where_string(
			full_name,
			street_address ) );

	input_pipe = popen( system_string, "r" );

	if ( !get_line( input_buffer, input_pipe, 1024 )
	||   !*input_buffer )
	{
		fprintf( stderr,
			 "ERROR in %s/%s()/%s: fetch failed for [%s/%s]\n",
			 __FILE__,
			 __FUNCTION__,
			 __LINE__,
			 full_name,
			 street_address ); 

		pclose( input_pipe );
		return (PERSON *)0;
	}

	pclose( input_pipe );

	return person_parse( input_buffer );
}

LIST *person_list( char *where )
{
	char system_string[ 1024 ];
	LIST *list;
	char input_buffer[ 1024 ];
	FILE *input_pipe;
	PERSON *person;

	sprintf( system_string,
		 "echo \"select %s from %s where %s order by %s;\"	|"
		 "sql							",
		 /* ---------------------- */
		 /* Returns program memory */
		 /* ---------------------- */
		 person_select_string(),
		 "person",
		 where,
		 person_select_string() );

	if ( ! ( list = list_new() ) )
	{
		fprintf( stderr,
			 "ERROR in %s/%s()/%d: list_new() failed.\n",
			 __FILE__,
			 __FUNCTION__,
			 __LINE__ );

		return (LIST *)0;
	}

	input_pipe = popen( system_string, "r" );

	while( get_line( input_buffer, input_pipe, 1024 ) )
	{
		if ( ! ( person = person_parse( input_buffer ) ) )
		{
			fprintf( stderr,
				 "ERROR in %s/%s/%d: person_parse(%s) failed\n",
				 __FILE__,
				 __FUNCTION__,
				 __LINE__,
				 input_buffer );

			pclose( input_pipe );
			return (LIST *)0;
		}

		list_set( list, person );
	}

	pclose( input_pipe );
	return list;
}

LIST *person_zip_code_list( char *zip_code )
{
	char where[ 512 ];

	sprintf( where,
		 "zip_code = '%s'",
		 security_sql_injection_escape(
			zip_code ) );

	return person_list( where );
}

int person_age_integer( char *current_date, char *birth_date )
{
	if ( !current_date || !birth_date ) return -1;

	return date_subtract_years( current_date, birth_date );
}

/* main.c */
/* ------ */
#include <stdio.h>
#include "person.h"
#include "date.h"

int main( void )
{
	PERSON *person;

	if ( ( person =
			person_fetch(
				"Bill Gates",
				"1234 Seattle Ave" ) ) )
	{
		printf( "Got age = %d\n",
			person_age_integer(
				date_current(),
				person->birth_date ) );
		return 0;
	}
	else
	{
		exit( 1 );
	}
}
Home | Appaserver | Contact Us |