Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

Fix the functions that have had code started in them (C Programing) #include #in

ID: 3749491 • Letter: F

Question

Fix the functions that have had code started in them (C Programing)

#include

#include

#include

#include

#include

#include "Debug.h"

#include "symbol.h"

/** @file symbol.c

* @brief You will modify this file and implement the symbol.h interface

* @details Your implementation of the functions defined in symbol.h.

* You may add other functions if you find it helpful. Added functions

* should be declared static to indicate they are only used

* within this file. The reference implementation added approximately

* 110 lines of code to this file. This count includes lines containing

* only a single closing bracket (}).

*

* @author Your name goes here

*/

/** size of LC3 memory */

#define LC3_MEMORY_SIZE (1 << 16)

/** Provide prototype for strdup() */

char *strdup(const char *s);

/** defines data structure used to store nodes in hash table */

typedef struct node {

struct node* next; /**< linked list of symbols at same index */

int hash; /**< hash value - makes searching faster */

symbol_t symbol; /**< the data the user is interested in */

} node_t;

/** defines the data structure for the hash table */

struct sym_table {

int capacity; /**< length of hast_table array */

int size; /**< number of symbols (may exceed capacity) */

node_t** hash_table; /**< array of head of linked list for this index */

char** addr_table; /**< look up symbols by addr (optional) */

};

/** djb hash - found at http://www.cse.yorku.ca/~oz/hash.html

* tolower() call to make case insensitive.

*/

static int symbol_hash (const char* name) {

unsigned char* str = (unsigned char*) name;

unsigned long hash = 5381;

int c;

while ((c = *str++))

hash = ((hash << 5) + hash) + tolower(c); /* hash * 33 + c */

c = hash & 0x7FFFFFFF; /* keep 31 bits - avoid negative values */

return c;

}

/** @todo implement this function */

sym_table_t* symbol_init (int capacity) {

struct sym_table *table;

table = malloc(1 * sizeof(struct sym_table));

table->size= capacity;

table->hash_table = malloc(capacity * sizeof(struct node *));

int i;

//printf("%d ", table->size);

for(i = 0; i < table->size; i++) {

table->hash_table[i] = NULL;

}

return table;

}

/** @todo implement this function */

void symbol_term (sym_table_t* symTab) {

}

/** @todo implement this function */

void symbol_reset(sym_table_t* symTab) {

}

/** @todo implement this function */

int symbol_add (sym_table_t* symTab, const char* name, int addr) {

int hash;

int index;

strdup(name);

struct node *node_new;

node_new = malloc(1 * sizeof(struct node));

node_new->next = symbol_search(symTab, name, &hash, &index);

if(node_new->next == NULL) {

return 0;

}

node_new->symbol.name = strdup(name);

node_new->symbol.addr = addr;

symTab->hash_table[index] = node_new;

printf("%s ", symTab->hash_table[index]->symbol.name);

return 1;

}

/** @todo implement this function */

struct node* symbol_search (sym_table_t* symTab, const char* name, int* hash, int* index) {

*hash = symbol_hash(name);

*index = *hash % symTab->size;

struct node *node_new;

node_new = malloc(1 * sizeof(struct node));

if(symbol_find_by_name(symTab,name) == NULL){

node_new->next = symTab->hash_table[*index];

return node_new;

}

return NULL;

}

/** @todo implement this function */

symbol_t* symbol_find_by_name (sym_table_t* symTab, const char* name) {

int i;

for(i = 0; i < symTab->size; i++) {

if(!(symTab->hash_table[i] == NULL))

{

if(strcasecmp(symTab->hash_table[i]->symbol.name,name)==0) {

// printf("%s ", "duplicate");

// printf("%s", symTab->hash_table[0]->symbol.name);

return symTab->hash_table[i]->symbol.name;

}

}

}

return NULL;

}

/** @todo implement this function */

char* symbol_find_by_addr (sym_table_t* symTab, int addr) {

return NULL;

}

/** @todo implement this function */

void symbol_iterate (sym_table_t* symTab, iterate_fnc_t fnc, void* data) {

int i;

for(i = 0; i < symTab->size; i++) {

if(!(symTab->hash_table[i] == NULL))

{

printf("%s", symTab->hash_table[i]->symbol.name);

}

}

}

/** @todo implement this function */

int symbol_size (sym_table_t* symTab) {

return 0;

}

/** @todo implement this function */

int compare_names (const void* vp1, const void* vp2) {

// symbol_t* sym1 = *((symbol_t**) vp1); // study qsort to understand this

return 0;

}

/** @todo implement this function */

int compare_addresses (const void* vp1, const void* vp2) {

return 0;

}

/** @todo implement this function */

symbol_t** symbol_order (sym_table_t* symTab, int order) {

// will call qsort with either compare_names or compare_addresses

return NULL;

}

====================================================================

====================================================================

====================================================================

====================================================================

#ifndef __SYMBOL_H__
#define __SYMBOL_H__

/** @file symbol.h

* @brief Defines the interface to symbol.c functions (do not modify)
* @details This file defines the interface to a C file symbol.c that
* you will complete. The underlying data structure(s) used will be
* defined by the actual assignment. The assignment will define whether symbols
* are case sensitive or case in-sensitive.
* <p>
* In this implementation, you will learn about dynamic memory management using
* malloc/free. You will also learn about function pointers (callback functions).
*/

/** order in list is order in hash table */
#define HASH 0

/** order in list is alphabetical by name */
#define NAME 1

/** order in list is by increasing address */
#define ADDR 2

/** This defines an opaque type. The actual contents of the structure are hidden
* in the implementation (symbol.c) and only a pointer to this structure is
* used externally to that file. A pointer to an opaque structure is sometimes
* referred to as a handle.
*/

typedef struct sym_table sym_table_t;

/** The symbol_find methods return a pointer to this data structure. It is up
* to the implementor to decide how to use this stucture in the implementation.
*/

typedef struct symbol {
char* name; /**< the name of the symbol */
int addr; /**< symbol's address in the LC3 memory */
} symbol_t;

/** Add a symbol to the symbol table.
* @param symTab - pointer to the symbol table
* @param name - the name of the symbol
* @param addr - the address of the symbol
* @return 1 if name is currently in the symbol table,
* 0 otherwise
*/
int symbol_add (sym_table_t* symTab, const char* name, int addr);

/** Find a name by its LC3 address
* @param symTab - pointer to the symbol table
* @param addr - an LC3 address
* @return the <b>label</b> at that address or NULL if no symbol is
* associated with the adddress.
*/
char* symbol_find_by_addr (sym_table_t* symTab, int addr);

/** Find a symbol by its name
* @param symTab - pointer to the symbol table
* @param name - the symbols name
* @return the symbols information or NULL if no symbol is associated with
* the name.
* Most of the work is done by <code>symbol_search()</code>. That routine
* returns a <code>node_t*</code>, but this routine returns a
* <code>symbol_t*</code>. Study
* <a href="http://stackoverflow.com/questions/5767973/getting-the-address-of-a-struct-member">this</a> posting to understand how you might solve this.
*/
symbol_t* symbol_find_by_name (sym_table_t* symTab, const char* name);

/** Create a new symbol table and return a pointer to it. This function is a
* constructor for a symbol table. It allocates and initializes both the
* <code>hash_table</code> and the <code>addr_table</code>. The latter is
* an array of <code>char*</code> that is indexed by an LC3
* address to find the label (if any) associated with that address.
* @param capacity - the size of the hash table.
* @return a pointer to the symbol table.
*/
sym_table_t* symbol_init (int capacity);

/** Remove all the symbols from the symbol table. After this call the opaque
* symbol table pointer is still valid and new symbols may be added to it.
* If needed, clear the <code>addr_table</code>.
* @param symTab - pointer to the symbol table
*/
void symbol_reset (sym_table_t* symTab);

/** This function is only used internally and should be declared static. It is
* a useful support function for the <code>add()/find()</code> functions.
* It is declared here for documentation purposes. The function returns
* <b>three</b> values: one in the return value, and the other two using
* the pointers to the hash and index values.
* @param symTab - pointer to the symbol table
* @param name - the name of the symbol
* @param hash - pointer to location where hash value will be stored
* @param index - pointer to location where index will be stored
* @return the nodes information or NULL if no symbol is associated with
* the name.
*/
struct node* symbol_search (sym_table_t* symTab, const char* name, int* hash, int* index);

/** Remove all symbols from the symbol table, and free all allocated memory.
* This function is a destructor for a symbol table.
* There must not be any memory leaks. After executing this function, the
* opaque pointer to the symbol table is no longer valid.
*/
void symbol_term(sym_table_t* symTab);

/** Defines the signature of a callback function (also known as a function
* pointer). This is how languages such as Java and C++ do <b>dynamic</b>
* binding (i.e. figure out which function to call). Recall that in Java the
* code <code>obj.equals(object)</code> will call one of possibly many
* different methods depending on the actual type of <code>obj</code>. This
* is because the method <b>.equals()</b> may be <b>overridden</b>.
* <p>
* In the LC3, dynamic binding is based on the <b>JSRR</b> opcode. With this
* opcode, the address of the routine to call is stored in a register and can
* be changed at runtime. Compare this to a <b>JSR nameOfRoutine</b> opcode which
* specifies what routine to call from the label that follows it. Thus, the
* address is fixed at <b>assembly</b> time.
* <p>
* This is used in the symbol_iterate() function. An interesting variation
* would be to have the callback function return an integer which determines
* whether the iteration should contibue or terminate.
* @param symTab - pointer to the symbol table
* @param data - any additional information to be passed on to fnc. The called
* function will cast this to whatever type was actually passed.
*/
typedef void (*iterate_fnc_t)(symbol_t* sym, void* data);

/** This function calls the function for every entry in the symbol table.
* The assigment will define the order in which the entries should be visited.
* @param symTab - pointer to the symbol table
* @param fnc - the function to be called on every element
* @param data - any additional information to be passed on to fnc. The called
* function will cast this to whatever type was actually passed.
*/
void symbol_iterate (sym_table_t* symTab, iterate_fnc_t fnc, void* data);

/** A callback function for <code>qsort</code> to order by name in a case
* insensative way.
* @param vp1 pointer to first element
* @param vp2 pointer to second element
* @ return a number representing the correct ordering (neg, 0, pos)
*/
int compare_names (const void* vp1, const void* vp2);

/** A callback function for <code>qsort</code> to order by address
* <b>NOTE</b>: If two elements have the same address, then return the result
* of comparing by name, so that name becomes the secondary sort key.
* @param vp1 pointer to first element
* @param vp2 pointer to second element
* @ return a number representing the correct ordering (neg, 0, pos)
*/
int compare_addresses (const void* vp1, const void* vp2);

/** Return the number of elements currently in the symbol table
* @param symTab - pointer to the symbol table
* @return number of elements
*/
int symbol_size (sym_table_t* symTab);

/** This function returns an ordered, dymanically allocated array of
* <code>symbol_t*</code>. You may wish to use <code>qsort()</code> to order
* it. The caller will <code>free()</code> the return value.
* @param symTab - pointer to the symbol table
* @param order - defines the sorting order for the list (HASH, NAME, ADDR)
* @return pointer to an array of <code>symbol_t*</code>  
*/
symbol_t** symbol_order (sym_table_t* symTab, int order);

#endif /* __SYMBOL_H__ */

Explanation / Answer

testSymbol.c


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

#include "Debug.h"
#include "symbol.h"


/** Maximum length of command line processed */
#define MAX_LINE_LENGTH 128

/** Delimiter used separate tokens on line - used by strtok() */
const char *delim = " ";

/** Print a usage statement describing how program is used */
static void help() {
puts("Usage: testSymbol [-debug] ");
puts("then enter commands from keyboard, one per line: ");
puts("init capacity    - create symbol table with given capacity");
puts("                     MUST be first action taken");
puts("add name address - prints 1 on succeses, 0 on failure");
puts("count            - prints count of names/addresses");
puts("                     uses function pointers");
puts("debug level      - turn debug on/off (0 is off)");
puts("exit/quit        - terminates program");
puts("get name         - prints NULL or name/address");
puts("label address    - prints NULL or name associated with address");
puts("list             - prints all names/addresses");
puts("                     uses function pointers");
puts("order option     - calls symbol_order and print value(s)");
puts("                 - option is HASH|NAME|ADDR");
puts("search name      - prints NULL or name/address and hash/index");
puts("size             - call symbol_size()");
puts("reset            - call symbol_reset() ");
}

/** Print a usage statement describing how program is used, and exits */
static void usage() {
help();
}
static char* nextToken () {
char* tok = strtok(NULL, delim);
if (! tok)
    usage();
return tok;
}
static int nextInt() {
char* junk;
char* tok = nextToken();
return (int) strtol(tok, &junk, 0);
}
static void countSymbols (symbol_t* sym, void *data) {
int* ip = (int*) data;
*ip = *ip + 1;
}
static void printResult(symbol_t* sym, void* data) {
FILE* f = (FILE*) data;

if (! sym)
    fprintf(f, "NULL ");
else
    fprintf(f, "name:%-20s addr:%-6d ", sym->name, sym->addr);
}

static void printList (sym_table_t* symTab, int order) {
int        size = symbol_size(symTab);
symbol_t** list = symbol_order(symTab, order);

if (list) {
    for (int i = 0; i < size; i++)
      printResult(list[i], stdout);

    puts("");
    free(list);
}
}
int main (int argc, const char* argv[]) {
char line[MAX_LINE_LENGTH];
int count, addr;
char *cmd, *name;
sym_table_t* symTab = NULL;

debugInit(&argc, argv);

if (argc != 1)
    usage();

while (fgets(line, sizeof(line), stdin) != NULL) {
    char *cr = strchr(line ,' '); /* get rid of trailing , if any */

    if (cr)
      *cr = '';

    cmd = strtok(line, delim);

    if ((! cmd) || (*cmd == '#')) // skip blank lines, comments
      continue;

    if (strcmp(cmd, "debug") == 0) {
      debugLevel = nextInt();
    }
    else if ((strcmp(cmd, "exit") == 0) || (strcmp(cmd, "quit") == 0)) {
      break;
    }
    else if (strcmp(cmd, "help") == 0) {
      help();
    }
    else if (strcmp(cmd, "init") == 0) {
      count = nextInt();
      symTab = symbol_init(count);
      debug("initialized with size %d", count);
    }
    else if (symTab == NULL) {
      puts("Please initialize symbol table before use");
    }
    else if (strcmp(cmd, "add") == 0) {
      name = nextToken();
      addr = nextInt();
      printf("%s ", (symbol_add(symTab, name, addr) ? "OK" : "Duplicate"));
    }
    else if (strcmp(cmd, "count") == 0) {
      count = 0;
      symbol_iterate(symTab, countSymbols, &count);
      printf("symbol count: %d ", count);
    }
    else if (strcmp(cmd, "get") == 0) {
      name = nextToken();
      printResult(symbol_find_by_name(symTab, name), stdout);
    }
    else if (strcmp(cmd, "label") == 0) {
      addr = nextInt();
      printf("label at addr %d '%s' ", addr,
             symbol_find_by_addr(symTab, addr));
    }
    else if (strcmp(cmd, "list") == 0) {
      symbol_iterate(symTab, printResult, stdout);
      puts("");
    }
    else if (strcmp(cmd, "order") == 0) {
      name = nextToken();
      if (strcmp(name, "HASH") == 0)
        printList(symTab, HASH);
      else if (strcmp(name, "NAME") == 0)
        printList(symTab, NAME);
      else if (strcmp(name, "ADDR") == 0)
        printList(symTab, ADDR);
      else
        help();
    }
    else if (strcmp(cmd, "reset") == 0) {
      symbol_reset(symTab);
    }
    else if (strcmp(cmd, "search") == 0) {
      int hash, index;
      name              = nextToken();
      struct node* node = symbol_search(symTab, name, &hash, &index);
      printf("symbol '%s' hash: %d index: %d is %s in symbol table ", name,
             hash, index, (node ? "" : "NOT"));
    }
    else if (strcmp(cmd, "size") == 0) {
      printf("symbol table contains %d entries ", symbol_size(symTab));
    }
    else {
      help();
    }
}

symbol_term(symTab); /* can check for memory leaks now */

return 0;
}


symbol.h

#ifndef __SYMBOL_H__
#define __SYMBOL_H__
#define HASH 0
#define NAME 1
#define ADDR 2
typedef struct sym_table sym_table_t;

typedef struct symbol {
    char* name; /**< the name of the symbol */
    int   addr; /**< symbol's address in the LC3 memory */
} symbol_t;
int symbol_add (sym_table_t* symTab, const char* name, int addr);
char* symbol_find_by_addr (sym_table_t* symTab, int addr);
symbol_t* symbol_find_by_name (sym_table_t* symTab, const char* name);
sym_table_t* symbol_init (int capacity);
void symbol_reset (sym_table_t* symTab);
struct node* symbol_search (sym_table_t* symTab, const char* name, int* hash, int* index);
void symbol_term(sym_table_t* symTab);
typedef void (*iterate_fnc_t)(symbol_t* sym, void* data);
void symbol_iterate (sym_table_t* symTab, iterate_fnc_t fnc, void* data);
int compare_names (const void* vp1, const void* vp2);

int compare_addresses (const void* vp1, const void* vp2);
int symbol_size (sym_table_t* symTab);
symbol_t** symbol_order (sym_table_t* symTab, int order);

#endif /* __SYMBOL_H__ */


symbol.c

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>

#include "Debug.h"
#include "symbol.h"
#define LC3_MEMORY_SIZE (1 << 16)
char *strdup(const char *s);
typedef struct node {
struct node* next;     /**< linked list of symbols at same index */
int          hash;     /**< hash value - makes searching faster */
symbol_t     symbol;   /**< the data the user is interested in   */
} node_t;

struct sym_table {
int      capacity;    /**< length of hast_table array                  */
int      size;        /**< number of symbols (may exceed capacity)     */
node_t** hash_table; /**< array of head of linked list for this index */
char**   addr_table; /**< look up symbols by addr (optional)          */
};
static int symbol_hash (const char* name) {
unsigned char* str = (unsigned char*) name;
unsigned long hash = 5381;
int c;

while ((c = *str++))
    hash = ((hash << 5) + hash) + tolower(c); /* hash * 33 + c */

c = hash & 0x7FFFFFFF; /* keep 31 bits - avoid negative values */

return c;
}


sym_table_t* symbol_init (int capacity) {
    //allocate sym_table_t
    sym_table_t* t = (sym_table_t*)malloc(sizeof(sym_table_t));
  
    //initialize capacitiy
    t->capacity = capacity;
    t->size = 0;
    char **u = (char**)calloc(65535, sizeof(char*));
    t->addr_table = u;
    node_t** n = (node_t**)calloc(capacity, sizeof(node_t*));  
    t->hash_table = n;                     
    return t;
}
void symbol_term (sym_table_t* symTab) {
      symbol_reset(symTab);
      free(symTab->hash_table);
      symTab->hash_table = NULL;
    
      free(symTab->addr_table);
      symTab->addr_table = NULL;
    
      free(symTab);
      symTab = NULL;
}
void symbol_reset(sym_table_t* symTab) {
     for(int i = 0; i < symTab->capacity; i++){
          if(symTab->hash_table[i] == NULL)
              continue;
          else if(symTab->hash_table[i] != NULL && symTab->hash_table[i]->next != NULL){
              node_t* n = symTab->hash_table[i];
              node_t* next;
           while(n != NULL){            
              next = n->next;
              free(n->symbol.name);
              n->symbol.name = NULL;
              free(n);
              n = next;
            
            }
            symTab->hash_table[i] = NULL;
          }
         else{
            free(symTab->hash_table[i]->symbol.name);
            symTab->hash_table[i]->symbol.name = NULL;
            free(symTab->hash_table[i]);
            symTab->hash_table[i] = NULL;
         }
     }
     symTab->size = 0;
}

int symbol_add (sym_table_t* symTab, const char* name, int addr) {
    int index = symbol_hash(name) % symTab->capacity;
    int hash = symbol_hash(name);
    if(symTab->hash_table[index] == NULL){
      node_t* newNode = (node_t*)malloc(sizeof(node_t));
      char* yop = strdup(name);
      newNode->symbol.name = yop;
      newNode->symbol.addr = addr;
      newNode->next = NULL;
      newNode->hash = symbol_hash(name);
      symTab->hash_table[index] = newNode;
      symTab->size += 1;
      symTab->addr_table[addr] = yop;    
      return 1;  
    }
    else{
         if(symbol_search(symTab, name, &hash, &index) == NULL){
           if(symTab->capacity > index){
            node_t* newNode = (node_t*)malloc(sizeof(node_t));
            char* yop = strdup(name);
            newNode->symbol.name = yop;
            newNode->symbol.addr = addr;
            newNode->next = symTab->hash_table[index];
            newNode->hash = symbol_hash(name);
            symTab->hash_table[index] = newNode;
            symTab->size += 1;
            symTab->addr_table[addr] = yop;
            return 1;  
           }
         }
         else
            return 0;
     }
   
     return -1;
}

struct node* symbol_search (sym_table_t* symTab, const char* name, int* hash, int* index) {
*hash = symbol_hash(name);
*index = *hash % (symTab->capacity);
if(symTab->hash_table[*index] == NULL){
   return NULL;
}
    for(int i = 0; i <symTab->capacity; i++){
    node_t* n = symTab->hash_table[i];
    while(n != NULL){
     int result = strcasecmp(name, n->symbol.name);
      if(result == 0)
          return n;
      else
          n = n->next;
      
    }

   }
return NULL;
}

symbol_t* symbol_find_by_name (sym_table_t* symTab, const char* name) {
    int index = symbol_hash(name) % symTab->capacity;
    int hash = symbol_hash(name);
    node_t* n = symbol_search(symTab, name, &hash, &index);
     hash = n->hash;
     return &(symTab->hash_table[index]->symbol);
}
char* symbol_find_by_addr (sym_table_t* symTab, int addr) {  
     if(symTab->addr_table[addr] == NULL)
         return NULL;
     else{
          return symTab->addr_table[addr];
      }

return NULL;
}
void symbol_iterate (sym_table_t* symTab, iterate_fnc_t fnc, void* data) {
    if(symTab->capacity == 1){
        node_t* n = symTab->hash_table[0];
            while(n != NULL){
                (*fnc)(&(n->symbol),data);
                if(n->next == NULL)
                    break;
                else
                    n = n->next;
        }
    }
  
    else{
     for(int i = 0; i < symTab->capacity; i++){
      node_t* n = symTab->hash_table[i];  
          while(n != NULL){
             (*fnc)(&(n->symbol),data);
             if(n->next == NULL)
                 break;
             else
                n = n->next;
          }
     }
    }
}

int symbol_size (sym_table_t* symTab) {
return symTab->size;
}

int compare_names (const void* vp1, const void* vp2) {
   symbol_t* sym1 = *((symbol_t**) vp1);
   symbol_t* sym2 = *((symbol_t**) vp2);
   char* a = (sym1->name);
   char* b = (sym2->name);
   int result = strcasecmp(a, b);
    
   return result;
}
int compare_addresses (const void* vp1, const void* vp2) {
   symbol_t* sym1 = *((symbol_t**) vp1);
   symbol_t* sym2 = *((symbol_t**) vp2);
   int a = (sym1->addr) - (sym2->addr);
   if(a != 0)
       return a;
   else
       return compare_names(&sym1, &sym2);
}

symbol_t** symbol_order (sym_table_t* symTab, int order) {
// will call qsort with either compare_names or compare_addresses
symbol_t** s = (symbol_t**)calloc(symTab->size, sizeof(symbol_t*));
int j = 0;
for(int i = 0; i < symTab->capacity; i++){
    node_t* n = symTab->hash_table[i];
     if(symTab->hash_table[i] == NULL)
       continue;

   else{  
          while(n != NULL){
             s[j] = &(n->symbol);
             j += 1;
             if(n->next == NULL)
                 break;
             else
                n = n->next;
          }
      }
   }
if(order == 0 && s[0] != NULL)
    return s;
else if(order == 1 && s[0] != NULL){
    qsort(s, symTab->size, sizeof(symbol_t*), compare_names);
    return s;
}
else if(order == 2 && s[0] != NULL){
    qsort(s, symTab->size, sizeof(symbol_t*), compare_addresses);
    return s;
}
else
      return NULL;

return NULL;

}

Debug.h

#ifndef __DEBUG_H__
#define __DEBUG_H__
#ifdef __cplusplus
extern "C" {
#endif

#include <stdio.h>

void debugInit(int* argc, const char* argv[]);
void debugToFile(const char* fileName);
void debugClose(void);
extern int debugLevel;
extern FILE* debugFile;

#ifdef DEBUG
#define DEBUG_ENABLED 1 // debug code available at runtime
#else
#define DEBUG_ENABLED 0 // all debug code optimized out
#endif
#define HERE debug("HERE")
#define debugV(name) #name,(name)
#define vDebug(fmt, name) debug("%s=(" fmt ")" , debugV(name))
#define debug(fmt, ...) lDebug(1, fmt, ##__VA_ARGS__)
#define lDebug(level, fmt, ...)
do {
    if (DEBUG_ENABLED && (debugLevel >= level))
      fprintf((debugFile ? debugFile : stderr), "DEBUG %s[%d] %s() " fmt " ",
               __FILE__, __LINE__, __func__, ##__VA_ARGS__);
} while(0)

#ifdef __cplusplus
}
#endif

#endif


Debug.c

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

#include "Debug.h"

int debugLevel = 0;

FILE* debugFile = 0;

static const char* prefix = "-debug";

void debugInit (int* argc, const char* argv[]) {
debugFile = stderr;

if (*argc > 1) {
    const char* arg1 = argv[1];
    size_t len = strlen(prefix);

    if (strncmp(arg1, prefix, len) == 0) {
      debugLevel = 1;

      if (strlen(arg1) > len)
        debugLevel = atoi(arg1 + len);

      (*argc)--; // decrement number of arguments

      for (int i = 1; i < *argc; i++) // remove first argument
        argv[i] = argv[i+1];
    }
}
}

void debugToFile (const char* fileName) {
debugClose();
FILE* f = fopen(fileName, "w"); // "w+" ?
if (f)
    debugFile = f;
}

void debugClose(void) {
if (debugFile && (debugFile != stderr)) {
    fclose(debugFile);
    debugFile = stderr;
}
}