コード例 #1
0
ファイル: actions.c プロジェクト: Anonic/Meridian59
const_type make_literal_message(id_type id)
{
   const_type c = (const_type) SafeMalloc(sizeof(const_struct));

   lookup_id(id);		
   switch (id->type)
   {
   case I_MESSAGE:
      break;

   case I_MISSING:
      if (id->source != I_MESSAGE)
	 action_error("Identifier %s was referenced earlier with different type", id->name);
      break;

   default: 
      add_identifier(id, I_MISSING);
      id->source = I_MESSAGE;
      break;     
   }
   /* Make a constant expression whose value is the id # */
   c->type = C_MESSAGE;
   c->value.numval = id->idnum; 

   return c;
}
コード例 #2
0
ファイル: actions.c プロジェクト: Anonic/Meridian59
resource_type make_resource(id_type id, const_type c)
{
   resource_type r = (resource_type) SafeMalloc(sizeof(resource_struct));
   id_type old_id;

   id->ownernum = st.curclass;

   /* Left-hand side must not have appeared before, except maybe in dbase */
   old_id = lookup_id(id);
   switch(id->type) {
   case I_UNDEFINED:
      id->source = COMPILE;
      add_identifier(id, I_RESOURCE);
      break;

   case I_RESOURCE:
      /* Allow redefinition of resources listed in database file */
      if (id->source == COMPILE)
	 action_error("Resource %s is defined twice", id->name);
      else
	 old_id->source = COMPILE;

      id->source = COMPILE;
      break;
      
   default:
      action_error("Duplicate identifier %s", id->name);
   }

   r->lhs = id;
   r->rhs = c;
   return r;
}
コード例 #3
0
static int aPGSQL_query(struct cw_channel *chan, void *data) {


    char *s1,*s2,*s3,*s4;
    char s[100] = "";
    char *querystring;
    char *var;
    int l;
    int res,nres;
    PGconn *karoto;
    PGresult *PGSQLres;
    int id,id1;
    char *stringp=NULL;


    res=0;
    l=strlen(data)+2;
    s1=malloc(l);
    s2=malloc(l);
    strncpy(s1, data, l - 1);
    stringp=s1;
    strsep(&stringp," "); /* eat the first token, we already know it :P  */
    s3=strsep(&stringp," ");
    while (1) {	/* ugly trick to make branches with break; */
        var=s3;
        s4=strsep(&stringp," ");
        id=atoi(s4);
        querystring=strsep(&stringp,"\n");
        if ((karoto=find_identifier(id,CW_PGSQL_ID_CONNID))==NULL) {
            cw_log(LOG_WARNING,"Invalid connection identifier %d passed in aPGSQL_query\n",id);
            res=-1;
            break;
        }
        PGSQLres=PQexec(karoto,querystring);
        if (PGSQLres==NULL) {
            cw_log(LOG_WARNING,"aPGSQL_query: Connection Error (connection identifier = %d, error message : %s)\n",id,PQerrorMessage(karoto));
            res=-1;
            break;
        }
        if (PQresultStatus(PGSQLres) == PGRES_BAD_RESPONSE ||
                PQresultStatus(PGSQLres) == PGRES_NONFATAL_ERROR ||
                PQresultStatus(PGSQLres) == PGRES_FATAL_ERROR) {
            cw_log(LOG_WARNING,"aPGSQL_query: Query Error (connection identifier : %d, error message : %s)\n",id,PQcmdStatus(PGSQLres));
            res=-1;
            break;
        }
        nres=PQnfields(PGSQLres);
        id1=add_identifier(CW_PGSQL_ID_RESID,PGSQLres);
        snprintf(s, sizeof(s), "%d", id1);
        pbx_builtin_setvar_helper(chan,var,s);
        break;
    }

    free(s1);
    free(s2);

    return(res);
}
コード例 #4
0
ファイル: actions.c プロジェクト: Anonic/Meridian59
classvar_type make_classvar(id_type id, expr_type e)
{
   classvar_type cv;

   cv = (classvar_type) SafeMalloc(sizeof(classvar_struct));

   if (e->type != E_CONSTANT)
   {
      action_error("Classvar can only be initialized to a constant");
      return cv;
   }

   lookup_id(id);
   switch(id->type) 
   {
   case I_CONSTANT:
   case I_PROPERTY:
      action_error("Duplicate identifier %s", id->name);
      break;
      
      /* Legal if it hasn't yet appeared in this class */
   case I_CLASSVAR:
      if (id->ownernum == st.curclass && id->source == COMPILE)
	 action_error("Class variable %s appears twice", id->name);
      else 
      {
	 id->ownernum = st.curclass;
	 id->source = COMPILE;
	 add_identifier(id, I_CLASSVAR);
      }
      break;

   default:
      id->source = COMPILE;
      id->ownernum = st.curclass;
      add_identifier(id, I_CLASSVAR);
      break;
   }

   cv->id = id;
   cv->rhs = e->value.constval;
   return cv;   
}
コード例 #5
0
ファイル: actions.c プロジェクト: Anonic/Meridian59
param_type make_parameter(id_type id, expr_type e)
{
   param_type p = (param_type) SafeMalloc(sizeof(param_struct));

   if (e->type != E_CONSTANT)
   {
      action_error("Parameter can only be initialized to a constant");
      return p;
   }

   lookup_id(id);

   /* Left-hand side must not have appeared before, except perhaps as a parameter */
   switch (id->type) {
   case I_MISSING:
      /* The parameter has been referenced in a function call, but not declared anywhere 
       * We should use the existent id # and remove the id from the missing list.
       * First we must make sure that the missing id is supposed to be a missing parameter.
       */
      if (id->source != I_PARAMETER)
      {
	 action_error("Parameter %s was referenced elsewhere with different type", id->name);
	 break;
      }
      
      /* Insert directly into global table to preserve id # */
      id->type = I_PARAMETER;
      id->source = COMPILE;
      table_insert(st.globalvars, (void *) id, id_hash, id_compare);

      /* Remove from missing list */
      table_delete_item(st.missingvars, id, id_hash, id_compare);
      break;

   case I_UNDEFINED:   /* New parameter # */
      id->ownernum = st.curmessage;
      add_identifier(id, I_PARAMETER);
      break;

   case I_PARAMETER:
      /* Legal only if it hasn't yet appeared in this message */
      if (id->ownernum == st.curmessage && id->source == COMPILE)
	 action_error("Parameter %s appears twice", id->name);
      break;

   default:            /* Other types indicate name already used */
      action_error("Duplicate identifier %s", id->name);
   }

   p->lhs = id;
   p->rhs = e->value.constval;
   return p;
}
コード例 #6
0
ファイル: actions.c プロジェクト: Anonic/Meridian59
id_type make_var(id_type id)
{
   /* Add to list of local variables, if it hasn't been defined */
   lookup_id(id);

   switch(id->type)
   {
   case I_LOCAL:
      action_error("Duplicate identifier %s", id->name);

   default:
      id->ownernum = st.curmessage;
      add_identifier(id, I_LOCAL);
      break;

   }
   return id;
}
コード例 #7
0
static int aPGSQL_connect(struct cw_channel *chan, void *data) {

    char *s1;
    char s[100] = "";
    char *optionstring;
    char *var;
    int l;
    int res;
    PGconn *karoto;
    int id;
    char *stringp=NULL;


    res=0;
    l=strlen(data)+2;
    s1=malloc(l);
    strncpy(s1, data, l -1);
    stringp=s1;
    strsep(&stringp," "); /* eat the first token, we already know it :P  */
    var=strsep(&stringp," ");
    optionstring=strsep(&stringp,"\n");

    karoto = PQconnectdb(optionstring);
    if (PQstatus(karoto) == CONNECTION_BAD) {
        cw_log(LOG_WARNING,"Connection to database using '%s' failed. postgress reports : %s\n", optionstring,
               PQerrorMessage(karoto));
        res=-1;
    } else {
        cw_log(LOG_WARNING,"adding identifier\n");
        id=add_identifier(CW_PGSQL_ID_CONNID,karoto);
        snprintf(s, sizeof(s), "%d", id);
        pbx_builtin_setvar_helper(chan,var,s);
    }

    free(s1);
    return res;
}
コード例 #8
0
ファイル: actions.c プロジェクト: Anonic/Meridian59
stmt_type make_call(id_type function_id, list_type args)
{
   stmt_type stmt = (stmt_type) SafeMalloc(sizeof(stmt_struct));
   call_stmt_type s = (call_stmt_type) SafeMalloc(sizeof(call_stmt_struct));
   int argnum = 0, argtype, continuation = ANONE, minargs = 0, i, index;
   const char *fname;
   arg_type arg;
   id_type id, new_id;

   s->args = NULL;

   /* Verify that id is the name of a built-in function */
   lookup_id(function_id);

   if (function_id->type != I_FUNCTION)
   {
      action_error("Expecting a function name; found %s", function_id->name);
      return stmt;
   }

   index = function_id->idnum;  /* index # of function to call */

   fname = Functions[index].name;
   s->function = Functions[index].opcode;
      
   /* Check that types of arguments match "function prototype" in table */
   for ( ; args != NULL; args = args->next)
   {
      argtype = Functions[index].params[argnum];

      /* See if we are looking for one or more expressions or parameters */
      if (continuation != ANONE)
	 argtype = continuation;

      arg = (arg_type) args->data;
      switch (argtype) 
      {
      case ANONE:
	 action_error("Extra argument #%d to function %s", argnum+1, fname);
	 return stmt; /* Ignore additional extra arguments */
	 break;

      case AEXPRESSIONS:
	 continuation = AEXPRESSION;
	 /* fall through */
      case AEXPRESSION:
	 /* Must have an expression here */
	 if (arg->type != ARG_EXPR)
	    action_error("Expecting expression in argument #%d",
			 argnum+1, fname);
	 else
	    s->args = list_add_item(s->args, (void *) arg);
	 break;

      case ASETTINGS:
	 continuation = ASETTING;
	 /* fall through */
      case ASETTING:
	 if (arg->type != ARG_SETTING)
	 {
	    action_error("Expecting setting (i.e. #a=b ) in argument #%d",
			 argnum+1, fname);
	    break;
	 }
	 
	 /* Find parameter id */
	 id = arg->value.setting_val->id;
	 lookup_id(id);
	 
	 switch(id->type)
	 {
	 case I_UNDEFINED:
	    /* If parameter hasn't been defined yet, put on missing list */
	    add_identifier(id, I_MISSING);

	    /* Use source field to indicate where id came from for later checking */
	    id->source = I_PARAMETER;

	    s->args = list_add_item(s->args, (void *) arg);
	    break;
	    
	 case I_MISSING:
	    if (id->source != I_PARAMETER)
	    {
	       action_error("Duplicate identifier %s", id->name);
	       break;
	    }
	    s->args = list_add_item(s->args, (void *) arg);
	    break;

	    /* The tag here should be I_PARAMETER, but parameters also inserted as locals.
	     */
	 case I_LOCAL: 
	    /* Unfortunately, we want the parameter id #, and not the local id #.  So
	     * we have to look up the id again in the global table. */
	    new_id = (id_type) table_lookup(st.globalvars, (void *) id, id_hash, id_compare);

	    /* If it isn't there, then there happens to be a local variable of the same
	     * name as this parameter, and the parameter hasn't appeared before.  Thus the
	     * parameter id should be added as a missing variable.  We can't use the normal
	     * lookup_id and add_identifier procs, since the local variable will mask
	     * the missing one.
	     */
	    if (new_id == NULL)
	    {
	       /* Of course, the id might already have been inserted as a missing var */
	       new_id = (id_type) table_lookup(st.missingvars, (void *) id, id_hash, id_compare);
	       if (new_id == NULL)
	       {
		  id->source = I_PARAMETER;
		  id->type = I_MISSING;
		  id->idnum = ++st.maxid;
		  table_insert(st.missingvars, (void *) id, id_hash, id_compare);
	       }
	       else 
	       {
		  /* If it was already there, make sure that it was a parameter */
		  if (new_id->source != I_PARAMETER)
		     action_error("Duplicate identifier %s", id->name);
		  id->source = new_id->source;
		  id->type = I_MISSING;
		  id->source = I_PARAMETER;
		  id->idnum = new_id->idnum;
	       }
	       
	    }
	    else 
	    {
	       id = new_id;
	       if (id->type != I_PARAMETER)
		  action_error("Can't find parameter %s", id->name);
	    }

	    arg->value.setting_val->id = id;
	    /* If literal exists, proceed normally */
	    s->args = list_add_item(s->args, (void *) arg);
	    break;

	    /* But if the identifier is from another handler, might not be local */
	 case I_PARAMETER:
	    s->args = list_add_item(s->args, (void *) arg);
	    break;

	 default:
	    action_error("Literal %s is a duplicate identifier", id->name);
	 }
	 break;
      }
      
      argnum++;
   }
   /* Check that no arguments left out */
   for (i=0; i < MAXARGS; i++)
   {
      argtype = Functions[index].params[i];
      if (argtype == ANONE || argtype == ASETTINGS || argtype == AEXPRESSIONS)
	 break; /* Zero or more arguments follow */
      
      minargs++;
   }
   if (argnum < minargs)
      action_error("Expecting %d arguments to %s; found %d", minargs, fname, argnum);

   /* Sort parameter arguments in increasing order for server efficiency */
   s->args = SortArgumentList(s->args);

   stmt->type = S_CALL;
   stmt->value.call_stmt_val = s;
   return stmt;
}
コード例 #9
0
ファイル: actions.c プロジェクト: Anonic/Meridian59
property_type make_property(id_type id, expr_type e)
{
   property_type p = (property_type) SafeMalloc(sizeof(property_struct));

   if (e->type != E_CONSTANT)
   {
      action_error("Property can only be initialized to a constant");
      return p;
   }

   /* Left-hand side must not have appeared as a property before, except possibly as a
    * property of one of our superclasses.  Properties shadow other global names. */
   lookup_id(id);
   switch(id->type) {

   case I_CONSTANT:
      action_error("Duplicate identifier %s", id->name);
      break;
      
      /* Legal if it hasn't yet appeared in this class */
   case I_PROPERTY:
      if (id->ownernum == st.curclass && id->source == COMPILE)
	 action_error("Property %s appears twice", id->name);
      else 
      {
	 id->ownernum = st.curclass;
	 id->source = COMPILE;
	 add_identifier(id, I_PROPERTY);
      }
      break;

   case I_CLASSVAR:
      if (id->ownernum == st.curclass && id->source == COMPILE)
	 action_error("Property and classvar %s both appear in same class\n", id->name);
      else
      {
	 classvar_type new_cv;
	 id_type new_id;
	 const_type new_const;
	 
	 // Override classvar with special tag value
	 new_cv = (classvar_type) SafeMalloc(sizeof(classvar_struct));
	 new_const = (const_type) SafeMalloc(sizeof(const_struct));
	 new_id = duplicate_id(id);

	 new_cv->id = new_id;
	 new_cv->rhs = new_const;
	 new_id->ownernum = st.curclass;
	 new_id->source = COMPILE;
	 new_const->type = C_OVERRIDE;
	 
	 // Replace classvar with property in table
	 table_delete_item(st.classvars, id, id_hash, id_compare);
	 id->ownernum = st.curclass;
	 id->source = COMPILE;
	 add_identifier(id, I_PROPERTY);

	 // Store # of property in class var
	 new_const->value.numval = id->idnum;

	 st.override_classvars = list_add_item(st.override_classvars, new_cv);	 
      }
      break;

   default:
      id->source = COMPILE;
      id->ownernum = st.curclass;
      add_identifier(id, I_PROPERTY);
      break;
   }

   p->id = id;
   p->rhs = e->value.constval;
   return p;   
}
コード例 #10
0
ファイル: actions.c プロジェクト: Anonic/Meridian59
id_type make_constant_id(id_type id, expr_type expr)
{
   int numeric_val;

   /* Right hand side must be a number or a negative number */
   switch (expr->type)
   {
   case E_CONSTANT:
   {
      const_type c = (const_type) expr->value.constval;
      if (c->type == C_NUMBER)
	 numeric_val = c->value.numval;
      else action_error("Right hand side must be a numeric constant");
      break;
   }
   case E_UNARY_OP:
   {
      const_type c;
      expr_type sub_expr = expr->value.unary_opval.exp;
      int op = expr->value.unary_opval.op;
      
      if (op != NEG_OP || sub_expr->type != E_CONSTANT)
      {
         action_error("Right hand side must be a numeric constant");
         break;
      }
      
      c = (const_type) sub_expr->value.constval;
      if (c->type == C_NUMBER)
         numeric_val = - c->value.numval;
      else action_error("Right hand side must be a numeric constant");
      break;
   }
   default:
      action_error("Right hand side must be a numeric constant");
   }
   

   lookup_id(id);

   /* Left hand side cannot have appeared before */
   switch (id->type)
   {
   case I_UNDEFINED:
      id->ownernum = st.curclass;
      /* Store value in source field.  This is kind of a hack, but now we can 
	 insert just the id in st.constants, making it easy to find later. */
      id->source = numeric_val;
      add_identifier(id, I_CONSTANT);
      break;
      
   default:
      action_error("Duplicate identifier %s", id->name);
      break;
   }

   /* Add to list of constants in this class */
   st.constants = list_add_item(st.constants, id);
   
   return id;
}
コード例 #11
0
ファイル: actions.c プロジェクト: Anonic/Meridian59
class_type make_class_signature(id_type class_id, id_type superclass_id)
{
   list_type l;
   id_type old_id;
   class_type c = (class_type) SafeMalloc(sizeof(class_struct));
   c->superclass = NULL;  /* Will be set for real below */

   c->class_id = class_id;

   /* Class name must not have appeared before */
   old_id = lookup_id(class_id);

   switch(class_id->type)
   {
   case I_MISSING:
      /* The class has been referenced in a function call, but not declared anywhere 
       * We should use the existent class # and remove the id from the missing list 
       */
      if (class_id->source != I_CLASS)
      {
	 action_error("Class %s was referenced elsewhere with different type", class_id->name);
	 break;
      }

      /* Insert directly into global table to preserve id # */
      class_id->type = I_CLASS;
      class_id->source = COMPILE;
      table_insert(st.globalvars, (void *) class_id, id_hash, id_compare);

      /* Remove from missing list */
      table_delete_item(st.missingvars, class_id, id_hash, id_compare);

      break;
      
   case I_UNDEFINED:
      /* New class name--continue normally */
      add_identifier(class_id, I_CLASS);
      break;

   case I_CLASS:
      /* We are recompiling a previously existing class.  This is rather ugly, since
       * we want to replace all the old class's data with our new data.  However, to give
       * previously compiled subclasses a chance of working with the new version, we
       * should try to match class numbers, message #s, etc. with the old class.
       *   At this point, all the old class's data have been inserted into our hash
       * tables.  The new class will be inserted into st.globalvars.  We must remove the old class 
       * from the class list.
       */

      /* If class is given twice in source files, that's an error */
      if (class_id->source == COMPILE)
	 action_error("Class %s is given twice", class_id->name);
      else 
	 /* Change the existent class id to reflect the fact that the class has now
	  * been recompiled. */
	 old_id->source = COMPILE;

      class_id->source = COMPILE;

      /* Delete self from list of existent classes.  Give warnings for subclasses. */
	 
      for (l = st.classes; l != NULL; l = l->next)
	 if (is_parent(c, (class_type) l->data))
	 {
	    if (((class_type) l->data)->class_id->idnum == c->class_id->idnum)
	       st.classes = list_delete_item(st.classes, l->data, class_compare);
	    else
	       /* Don't give warning if deleted self from list */
	    {
	       recompile_type recompile_info = 
		  (recompile_type) SafeMalloc(sizeof(recompile_struct));
	       recompile_info->class_id = ((class_type) (l->data))->class_id;
	       recompile_info->superclass = c->class_id;
	       
	       /* Only add to list if it isn't already there */
	       if (list_find_item(st.recompile_list, recompile_info->class_id, 
				  recompile_compare) == NULL)
		  st.recompile_list = list_add_item(st.recompile_list, (void *) recompile_info);
	    }
	    
	 }
      break;
      
   default:
      action_error("Duplicate identifier %s", class_id->name);
   }

   /* Delete this class from list of those that need to be recompiled */
   st.recompile_list = 
      list_delete_item(st.recompile_list, (void *) c->class_id, recompile_compare);

   c->resources  = NULL;
   c->properties = NULL;
   c->messages   = NULL;
   c->is_new = True; /* We should generate code for this class */

   /* Superclass must be defined, if one is given */
   if (superclass_id != NULL)
   {
      lookup_id(superclass_id);
      if (superclass_id->type != I_CLASS)
	 action_error("Can't find superclass %s", superclass_id->name);
      else if (class_id->idnum == superclass_id->idnum)
	 action_error("Can't subclass from self", superclass_id->name);	 
      else 
      {
	 /* Find superclass's data and store a pointer to it. */
	 for (l = st.classes; l != NULL; l = l->next)
	    if (superclass_id->idnum == ((class_type) (l->data))->class_id->idnum)
	    {
	       c->superclass = (class_type) l->data;
	       break;
	    }

	 if (c->superclass == NULL)
	    action_error("Unable to find superclass %s", superclass_id->name);
      }
      
   }
   else c->superclass = NULL;

   st.curclass = class_id->idnum;

   /* Now add superclasses' properties to our own property table, but delete
    * them from our property list.  This way the table will hold all properties 
    * that can be referenced in the class, but the property list will only 
    * hold those that were declared in this class (need to know this for code gen) */
   add_parent_properties(c, c->superclass);

   /* Similarly, add superclasses' classvars.  This must be done AFTER adding the properties,
    * since some properties in a superclass could be overriding classvars in a superclass */
   add_parent_classvars(NULL, c, c->superclass);

   /* Add to list of classes */
   st.classes = list_add_item(st.classes, (void *) c);

   return c;   
}
コード例 #12
0
ファイル: actions.c プロジェクト: Anonic/Meridian59
message_header_type make_message_header(id_type id, list_type args)
{
   message_header_type s = (message_header_type) SafeMalloc(sizeof(message_header_struct));
   id_type old_id, temp_id;
   param_type param;
   list_type l;

   /* Messsage name must be unique in this class, but may be the same
    * as a message in a different class. */
   old_id = lookup_id(id);

   switch (id->type) {
   case I_MISSING:
      /* The message has been referenced in a function call, but not declared anywhere.
       * We should use the existent message # and remove the id from the missing list 
       */
      if (id->source != I_MESSAGE)
      {
	 action_error("Message %s was referenced elsewhere with different type", id->name);
	 break;
      }

      /* Insert directly into global table to preserve id # */
      id->type = I_MESSAGE;
      id->ownernum = st.curclass;
      id->source = COMPILE;
      table_insert(st.globalvars, (void *) id, id_hash, id_compare);

      /* Remove from missing list */
      table_delete_item(st.missingvars, id, id_hash, id_compare);

      break;

   case I_UNDEFINED:   /* New message # */
      id->ownernum = st.curclass;
      add_identifier(id, I_MESSAGE);
      break;

   case I_MESSAGE:     /* Make sure message hasn't appeared in this class */
      if (id->ownernum == st.curclass && id->source == COMPILE)
	 action_error("Message handler %s defined twice in same class", id->name);
      old_id->ownernum = st.curclass;
      old_id->source = COMPILE;
      break;

   default:            /* Other types indicate name already used */
      action_error("Duplicate identifier %s", id->name);
   }

   s->message_id = id;
   /* Sort parameters in increasing id # order */
   s->params = SortParameterList(args);

   /* Add parameters as handler's local variables--this must be done AFTER sorting */
   for (l = s->params; l != NULL; l = l->next)
   {
      param = (param_type) l->data;
      
      /* Make a copy of the id for the local table */
      temp_id = duplicate_id(param->lhs);
      temp_id->type = I_LOCAL;

      if (table_insert(st.localvars, (void *) temp_id, id_hash, id_compare) == 0)
	 temp_id->idnum = ++st.maxlocals;      
   }

   st.curmessage = id->idnum;

   return s;
}
コード例 #13
0
static int add_identifier_and_set_callweaver_int(struct cw_channel *chan, char *varname, int identifier_type, void *data) {
	return set_callweaver_int(chan,varname,add_identifier(identifier_type,data));
}
コード例 #14
0
static int aPGSQL_fetch(struct cw_channel *chan, void *data) {

    char *s1,*s2,*fetchid_var,*s4,*s5,*s6,*s7;
    char s[100];
    char *var;
    int l;
    int res;
    PGresult *PGSQLres;
    int id,id1,i,j,fnd;
    int *lalares=NULL;
    int nres;
    struct cw_var_t *variables;
    struct varshead *headp;
    char *stringp=NULL;

    headp=&chan->varshead;

    res=0;
    l=strlen(data)+2;
    s7=NULL;
    s1=malloc(l);
    s2=malloc(l);
    strncpy(s1, data, l - 1);
    stringp=s1;
    strsep(&stringp," "); /* eat the first token, we already know it :P  */
    fetchid_var=strsep(&stringp," ");
    while (1) {	/* ugly trick to make branches with break; */
        var=fetchid_var; /* fetchid */
        fnd=0;

        CW_LIST_TRAVERSE(headp,variables,entries) {
            if (strncasecmp(cw_var_name(variables),fetchid_var,strlen(fetchid_var))==0) {
                s7=cw_var_value(variables);
                fnd=1;
                break;
            }
        }

        if (fnd==0) {
            s7="0";
            pbx_builtin_setvar_helper(chan,fetchid_var,s7);
        }

        s4=strsep(&stringp," ");
        id=atoi(s4); /* resultid */
        if ((PGSQLres=find_identifier(id,CW_PGSQL_ID_RESID))==NULL) {
            cw_log(LOG_WARNING,"Invalid result identifier %d passed in aPGSQL_fetch\n",id);
            res=-1;
            break;
        }
        id=atoi(s7); /*fetchid */
        if ((lalares=find_identifier(id,CW_PGSQL_ID_FETCHID))==NULL) {
            i=0;       /* fetching the very first row */
        } else {
            i=*lalares;
            free(lalares);
            del_identifier(id,CW_PGSQL_ID_FETCHID); /* will re-add it a bit later */
        }

        if (i<PQntuples(PGSQLres)) {
            nres=PQnfields(PGSQLres);
            cw_log(LOG_WARNING,"cw_PGSQL_fetch : nres = %d i = %d ;\n",nres,i);
            for (j=0; j<nres; j++) {
                s5=strsep(&stringp," ");
                if (s5==NULL) {
                    cw_log(LOG_WARNING,"cw_PGSQL_fetch : More tuples (%d) than variables (%d)\n",nres,j);
                    break;
                }
                s6=PQgetvalue(PGSQLres,i,j);
                if (s6==NULL) {
                    cw_log(LOG_WARNING,"PWgetvalue(res,%d,%d) returned NULL in cw_PGSQL_fetch\n",i,j);
                    break;
                }
                cw_log(LOG_WARNING,"===setting variable '%s' to '%s'\n",s5,s6);
                pbx_builtin_setvar_helper(chan,s5,s6);
            }
            lalares=malloc(sizeof(int));
            *lalares = ++i; /* advance to the next row */
            id1 = add_identifier(CW_PGSQL_ID_FETCHID,lalares);
        } else {
            cw_log(LOG_WARNING,"cw_PGSQL_fetch : EOF\n");
            id1 = 0; /* no more rows */
        }
        snprintf(s, sizeof(s), "%d", id1);
        cw_log(LOG_WARNING,"Setting var '%s' to value '%s'\n",fetchid_var,s);
        pbx_builtin_setvar_helper(chan,fetchid_var,s);
        break;
    }

    free(s1);
    free(s2);
    return(res);
}