/*
 * TEST CASE: Tracing calls of C functions
 *
 * This code demonstrates how calls of registered C functions from within a
 * python script are not always traced depending on the functions'
 * parameters. As long as there are no keyword arguments, e.g.
 *
 *   'test.test ()' or 'test.test (1, 2)'
 *
 * the tracing/profiling function is called with 'what' set to
 * PyTrace_C_CALL/PyTrace_C_RETURN. As soon as keyword arguments are used,
 * e.g.
 *
 *   'test.test (a=1, b=2)'
 *
 * the tracing function is never called.
 */

#include <Python.h>
#include <frameobject.h>
#include <stdio.h>

static PyObject* exec_test (PyObject* self,
			    PyObject* args,
			    PyObject* keywords)
{
  Py_INCREF (Py_None);
  return Py_None;
}

static int trace_callback (PyObject* object,
			   PyFrameObject* frame,
			   int what,
			   PyObject* arg)
{
  switch (what)
    {
      case PyTrace_CALL:
	printf ("  CALL\n");
	break;
	    
      case PyTrace_C_CALL:
	printf ("  C-CALL\n");
	break;
	
      case PyTrace_RETURN:
	printf (("  RETURN\n"));
	break;
	
      case PyTrace_C_RETURN:
	printf (("  C-RETURN\n"));
	break;

      default:
	break;
    }

  return 0;
}

static PyMethodDef methods[] =
  { { "test", (PyCFunction)exec_test, METH_VARARGS | METH_KEYWORDS,
      "Test function."},
    { NULL, NULL, 0, NULL} };
  
    
int main (int argc, char** argv)
{
  Py_Initialize ();
  PyEval_SetProfile (trace_callback, Py_None);

  Py_InitModule ("test", methods);

  // Will call 'trace_callback'
  printf ("* Calling function without arguments\n");
  PyRun_SimpleString ("import test\n"
		      "test.test ()\n");

  // Will call 'trace_callback'
  printf ("* Calling function with regular arguments\n");
  PyRun_SimpleString ("import test\n"
		      "test.test (1, 2)\n");

  // Will NOT call 'trace_callback'
  printf ("* Calling function with keyword arguments\n");
  PyRun_SimpleString ("import test\n"
		      "test.test (a=1, b=2)\n");
  
  Py_Finalize ();
}

 	  	 
