Answers/Solutions to Exercises in Chapter 10, Exercise 6

E6: Extend the program from exercise 5 to include localization tracing using a stack for function names (see Appendix C.).

A6:  A sample program is below. Note that we have to make sure that the allocation/deallocation in the tracing functions is not included in our tracing. The best is to have it in a separate file, compile it separately, and link it with the program being traced. But here we included it in one program.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>

void sys_exit(char *fmt, ...);
void sys(char *fmt, ...);
void msg_exit(char *fmt, ...);
void msg(char *fmt, ...);
void Sys_exit(char *fmt, ...);
void Msg_exit(char *fmt, ...);
void Sys(char *fmt, ...);
void Msg(char *fmt, ...);
void print_msg(char *fmt,va_list ap,char* where);
void open_log(char* name);
char logpath[500] = "";
char buf[500];


#define TRACE(a) PUSH_TRACE(#a);
#define RETURN {POP_TRACE(); return; }
#define RETURN1(a) {POP_TRACE(); return(a); }
#define REPORT() REPORT_TRACE(3)

//#include "trace.c"
// the function trace stack is a simple linked list of 
// pointers to function identifiers
// the head of the list is the op of the stack
struct TRACE_NODE_STRUCT {
  char* floc;                      // ptr to function identifier
  struct TRACE_NODE_STRUCT* next;  // ptr to next frama
};
typedef struct TRACE_NODE_STRUCT TRACE_NODE;
static TRACE_NODE* TRACETop = NULL;       // ptr to the top of the stack


/* function PUSH_TRACE ---------------------------------------------- */
void PUSH_TRACE(char* p)          // push p on the stack
{
  TRACE_NODE* tnode;
  static char glob[]="global";

  if (TRACETop==NULL) {
    // initialize the stack with "global" identifier

    TRACETop=(TRACE_NODE*) malloc(sizeof(TRACE_NODE));

    // no recovery needed if allocation failed, this is only
    // used in debugging, not in production
    if (TRACETop==NULL) { 
      printf("PUSH_TRACE: memory allocation error\n");
      exit(1);   
    }

    TRACETop->floc = glob;
    TRACETop->next=NULL;
  }
  // now create the node for p

  tnode = (TRACE_NODE*) malloc(sizeof(TRACE_NODE));

  // no recovery needed if allocation failed, this is only
  // used in debugging, not in production
  if (tnode==NULL) {
    printf("PUSH_TRACE: memory allocation error\n");
    exit(1);
  }

  tnode->floc=p;
  tnode->next = TRACETop;  // insert fnode as the first in the list
  TRACETop=tnode;          // point TRACETop to the first node

}/*end PUSH_TRACE*/

/* function POP_TRACE ---------------------------------------------- */
void POP_TRACE()    // remove the op of the stack
{
  TRACE_NODE* tnode;
  tnode = TRACETop;
  TRACETop = tnode->next;
  free(tnode);

}/*end POP_TRACE*/

/* report `depth' top entries from the stack in the form
   fun1:fun2:fun3:....:funk  meaning fun1 called from fun2
   that was called from fun3 ... that was called from funk
   where k = depth
   The calling path may be up to 100 characters, if longer
   it is truncated  */

/* function REPORT_TRACE ---------------------------------------------- */
char* REPORT_TRACE(int depth)
{
  int i, length, j;
  TRACE_NODE* tnode;
  static char buf[100];
 
  if (TRACETop==NULL) {     // stack not initialized yet, so we are
    strcpy(buf,"global");   // still in the `global' area
    return buf;
  }

  /* peek at the depth top entries on the stactk, but do not
     go over 100 chars and do not go over the bottom of the
     stack */

  sprintf(buf,"%s",TRACETop->floc);
  length = strlen(buf);                  // length of the string so far
  for(i=1, tnode=TRACETop->next; 
                        tnode!=NULL && i < depth; 
                                  i++,tnode=tnode->next) {
    j = strlen(tnode->floc);             // length of what we want to add
    if (length+j+1 < 100) {              // total length is ok
      sprintf(buf+length,":%s",tnode->floc);
      length += j+1;
    }else                                // it would be too long
      break;
  }
  return buf;
}
#define TRACE_ON


// function Realloc -----------------------------------------
void* Realloc(void* p,size_t t,char* file,int line)
{
	msg("[file=\"%s\",line=%d,function=%s], reallocation segment at address %x to new size %d\n",
		file,line,REPORT(),p,t);
	p = realloc(p,t);	
	msg("[file=\"%s\",line=%d,function=%s],segment reallocated to address %x\n",
		file,line,REPORT(),p);
	return p;
}

// function Malloc -------------------------------------------
void* Malloc(size_t t,char* file,int line)
{
	void* p;
	p = malloc(t);
	msg("[file=\"%s\",line=%d,function=%s],segment of size %d allocated at address %x\n",
		file,line,REPORT(),t,p);
	return p;
}

// function Free ----------------------------------------------
void Free(void* p,char* file,int line)
{
	free(p);
	msg("[file=\"%s\",line=%d,function=%s],segment at address %x deallocated\n",
		file,line,REPORT(),p);
}

#define realloc(a,b) Realloc(a,b,__FILE__,__LINE__)
#define malloc(a) Malloc(a,__FILE__,__LINE__)
#define free(a) Free(a,__FILE__,__LINE__)



// function add_column -----------------------------------------
void add_column(int** array,int rows,int columns)
{
	TRACE(add_column)
	int i;

	for(i=0; i<rows; i++) {
	 array[i]=(int*) realloc(array[i],sizeof(int)*(columns+1));
	 array[i][columns]=10*i+columns;
	}
	RETURN

}// end add_column


// function doit ------------------------------------------
void doit()
{
TRACE(doit)
	int i, j, **array;

	array = (int**) malloc(sizeof(int*)*4);  // 4 rows
	for(i=0; i<4; i++) {
	 array[i]=(int*) malloc(sizeof(int)*3);  // 3 columns
	 for(j=0; j<3; j++)
	  array[i][j]=10*i+j;
	}
	for(i=0; i<4; i++)
	 for(j=0; j<3; j++)
	  printf("array[%d][%d]=%d\n",i,j,array[i][j]);

	// and a new column
	add_column(array,4,3);

	// now display it again
    for(i=0; i<4; i++)
	 for(j=0; j<4; j++)
	  printf("array[%d][%d]=%d\n",i,j,array[i][j]);

	 //now we are going to deallocate it
	 for(i=0; i<4; i++)
		 free((void*)array[i]);
	 free((void*)array);
	 
	 RETURN
}//end doit


// function main ----------------------------------------------
int main()
{
TRACE(main)

	doit();

RETURN1(0)
}// end main

/* simplified logging functions --- without locking, without time, without multiprocessing,
   without multithreading */

/* function sys_exit ------------------------------------------- */
void sys_exit(char *fmt, ...)
{
 va_list ap;

 printf("[system error] ");
 va_start(ap,fmt);
 print_msg(fmt,ap,0);
 va_end(ap);
 exit(1);
}/* end sys_exit */

/* function sys ------------------------------------------- */
void sys(char *fmt, ...)
{
 va_list ap;
 
 printf("[system error] ");
 va_start(ap,fmt);
 print_msg(fmt,ap,0);
 va_end(ap);
}/* end sys */

/* function msg_exit ------------------------------------------- */
void msg_exit(char *fmt, ...)
{
 va_list ap;
 
 va_start(ap,fmt);
 print_msg(fmt,ap,0);
 va_end(ap);
 exit(1);
}/* end msg_exit */
/* function msg ------------------------------------------- */
void msg(char *fmt, ...)
{
 va_list ap;
 
 va_start(ap,fmt);
 print_msg(fmt,ap,0);
 va_end(ap);
}/* end msg */

/* function Sys_exit ------------------------------------------- */
void Sys_exit(char *fmt, ...)
{
 va_list ap;

 va_start(ap,fmt);
 print_msg(fmt,ap,"[system error] ");
 va_end(ap);
 exit(1);
}/* end Sys_exit */

/* function Msg_exit ------------------------------------------- */
void Msg_exit(char *fmt, ...)
{
 va_list ap;
 
 va_start(ap,fmt);
 print_msg(fmt,ap,"[]");
 va_end(ap);
 exit(1);
}/* end Msg_exit */

/* function Sys ------------------------------------------- */
void Sys(char *fmt, ...)
{
 va_list ap;
 
 va_start(ap,fmt);
 print_msg(fmt,ap,"[]");
 va_end(ap);
}/* end Sys */
 
/* function Msg ------------------------------------------- */
void Msg(char *fmt, ...)
{
 va_list ap;
 
 va_start(ap,fmt);
 print_msg(fmt,ap,"[]");
 va_end(ap);
}/* end Msg */
 
/* function print_msg ------------------------------------------- */
void print_msg(char *fmt,va_list ap,char* where)
{
 FILE* fp;
 
 vsprintf(buf,fmt,ap);
 if (where==0) 
   printf("%s\n",buf);
 else{
   fp = fopen(logpath,"a");
   if (fp == NULL) {
     printf("problem to open log\n");
     exit(1);
   }
   fprintf(fp,"%s%s\n",where,buf);
 }
}/* end print_msg */

/* function open_log ------------------------------------------ */
void open_log(char* name)
{
 FILE* fp;

 strcpy(logpath,name);
 fp = fopen(logpath,"w");
 if (fp == NULL) {
   printf("error opening log\n");
   exit(1);
 }
 fprintf(fp,"log opened\n");
 fclose(fp);
}/* end open_log */

Output:

[file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp",
line=190,function=doit:main:global],segment of size 16 allocated at address 431f
a0

[file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp",
line=192,function=doit:main:global],segment of size 12 allocated at address 431f
60

[file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp",
line=192,function=doit:main:global],segment of size 12 allocated at address 431f
20

[file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp",
line=192,function=doit:main:global],segment of size 12 allocated at address 431e
e0

[file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp",
line=192,function=doit:main:global],segment of size 12 allocated at address 431e
a0

array[0][0]=0
array[0][1]=1
array[0][2]=2
array[1][0]=10
array[1][1]=11
array[1][2]=12
array[2][0]=20
array[2][1]=21
array[2][2]=22
array[3][0]=30
array[3][1]=31
array[3][2]=32
[file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp",
line=176,function=add_column:doit:main], reallocation segment at address 431f60
to new size 16

[file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp",
line=176,function=add_column:doit:main],segment reallocated to address 431f60

[file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp",
line=176,function=add_column:doit:main], reallocation segment at address 431f20
to new size 16

[file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp",
line=176,function=add_column:doit:main],segment reallocated to address 431f20

[file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp",
line=176,function=add_column:doit:main], reallocation segment at address 431ee0
to new size 16

[file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp",
line=176,function=add_column:doit:main],segment reallocated to address 431ee0

[file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp",
line=176,function=add_column:doit:main], reallocation segment at address 431ea0
to new size 16

[file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp",
line=176,function=add_column:doit:main],segment reallocated to address 431ea0

array[0][0]=0
array[0][1]=1
array[0][2]=2
array[0][3]=3
array[1][0]=10
array[1][1]=11
array[1][2]=12
array[1][3]=13
array[2][0]=20
array[2][1]=21
array[2][2]=22
array[2][3]=23
array[3][0]=30
array[3][1]=31
array[3][2]=32
array[3][3]=33
[file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp",
line=210,function=doit:main:global],segment at address 431f60 deallocated

[file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp",
line=210,function=doit:main:global],segment at address 431f20 deallocated

[file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp",
line=210,function=doit:main:global],segment at address 431ee0 deallocated

[file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp",
line=210,function=doit:main:global],segment at address 431ea0 deallocated

[file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp",
line=211,function=doit:main:global],segment at address 431fa0 deallocated

Back to Answers/Solutions Index                          Back to Answers/Solutions for Chapter 10 Index