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; }
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; }
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); }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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)); }
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); }