#include "common.h" #include "question.h" #include "template.h" #include "strutl.h" #include "configuration.h" #include "database.h" #include "frontend.h" #include struct question *question_new(const char *tag) { struct question *q; q = NEW(struct question); memset(q, 0, sizeof(struct question)); q->ref = 1; q->tag = STRDUP(tag); q->priority = NULL; return q; } void question_delete(struct question *question) { struct questionowner **ownerp; DELETE(question->tag); if (question->template) template_deref(question->template); for (ownerp = &question->owners; *ownerp != NULL;) { struct questionowner *currentp = *ownerp; *ownerp = currentp->next; DELETE(currentp->owner); DELETE(currentp); } free(question->priority); DELETE(question); } void question_ref(struct question *q) { ++q->ref; } void question_deref(struct question *q) { if (q == NULL) return; if (--q->ref == 0) question_delete(q); } struct question *question_dup(const struct question *q) { struct question *ret = question_new(q->tag); struct questionvariable *qv = q->variables; struct questionowner *qo = q->owners; ret->value = STRDUP(q->value); ret->flags = q->flags; ret->template = q->template; template_ref(ret->template); /* ret->template = template_dup(q->template); */ while (qv) { question_variable_add(ret,qv->variable,qv->value); qv = qv->next; } while (qo) { question_owner_add(ret,qo->owner); qo = qo->next; } return ret; } void question_setvalue(struct question *q, const char *value) { /* Be careful about the self-assignment case... */ if (q->value != value) { DELETE(q->value); q->value = STRDUP(value); } } /* Note that Default-* fields contain *untranslated* choices, so it's usual * to call this with lang="" and then compare the answer with untranslated * choices. */ const char *question_getvalue(const struct question *q, const char *lang) { if (q->value) return q->value; return template_lget(q->template, lang, "default"); } const char *question_get_variable(const struct question *q, const char *var) { struct questionvariable *qvi = q->variables; for (; qvi != 0; qvi = qvi->next) if (strcmp(qvi->variable, var) == 0) return qvi->value; return NULL; } void question_variable_add(struct question *q, const char *var, const char *value) { struct questionvariable *qvi = q->variables; struct questionvariable **qlast = &q->variables; INFO(INFO_DEBUG, "Adding [%s] -> [%s]", var, value); for (; qvi != 0; qlast = &qvi->next, qvi = qvi->next) if (strcmp(qvi->variable, var) == 0 && qvi->value != value) { DELETE(qvi->value); qvi->value = STRDUP(value); return; } qvi = NEW(struct questionvariable); memset(qvi, 0, sizeof(struct questionvariable)); qvi->variable = STRDUP(var); qvi->value = STRDUP(value); *qlast = qvi; } void question_owner_add(struct question *q, const char *owner) { struct questionowner **ownerp = &q->owners; while (*ownerp != 0) { if (strcmp((*ownerp)->owner, owner) == 0) return; ownerp = &(*ownerp)->next; } *ownerp = NEW(struct questionowner); memset(*ownerp, 0, sizeof(struct questionowner)); (*ownerp)->owner = STRDUP(owner); (*ownerp)->next = 0; } void question_owner_delete(struct question *q, const char *owner) { struct questionowner **ownerp; for (ownerp = &q->owners; *ownerp != 0;) { if (strcmp((*ownerp)->owner, owner) == 0) { struct questionowner *currentp = *ownerp; *ownerp = currentp->next; DELETE(currentp->owner); DELETE(currentp); } else { ownerp = &(*ownerp)->next; } } } static const struct { const char *name; unsigned int value; } flags[] = { { DC_QFLAG_SEEN, (1 << 0) }, { 0, 0 } }; static int flag_value(const char *type) { int i; if (!type) return 0; for (i = 0; flags[i].name != NULL; i++) { if (0 == strcmp(flags[i].name, type)) return flags[i].value; } return 0; } void question_set_flag(struct question *q, const char *flag) { q->flags |= flag_value(flag); } void question_clear_flag(struct question *q, const char *flag) { q->flags &= ~flag_value(flag); } int question_get_flag(const struct question *q, const char *flag) { return q->flags & flag_value(flag); } /* used by question_expand_vars */ static const char * lookup_vars(const char * name, struct questionvariable * variables) { struct questionvariable * current; /* Skip directives */ if ('!' == name[0]) { return NULL; } for (current = variables; NULL != current; current = current->next) { if (0 == strcmp(current->variable, name)) { return current->value; } } return ""; } static char *question_expand_vars(const struct question *q, const char *field) { return strexpand(field, LOOKUP_FUNCTION(lookup_vars), q->variables); } char *question_get_raw_field(const struct question *q, const char *lang, const char *field) { char *ret = NULL; assert(q); assert(field); if (strcmp(field, "value") == 0) ret = question_expand_vars(q, question_getvalue(q, lang)); else if (strcasecmp(field, "owners") == 0) { struct questionowner *owner = q->owners; while (owner) { if (ret) { char *oldret = ret; ret = realloc(ret, strlen(ret) + 2 + strlen(owner->owner) + 1); if (ret) { strcat(ret, ", "); strcat(ret, owner->owner); } else ret = oldret; } else ret = strdup(owner->owner); owner = owner->next; } } else ret = question_expand_vars(q, template_lget(q->template, lang, field)); /* question_get_field must always return a valid string. */ if (ret == NULL) return strdup(""); else return ret; } static const char * lookup_directive(const char * directive, struct frontend * fe) { assert('!' == directive[0]); return fe->methods.lookup_directive(fe, directive + 1 /* drop '!' */); } char * question_get_field(struct frontend * fe, const struct question * q, const char * lang, const char * field) { char * raw; char * ret; raw = question_get_raw_field(q, lang, field); ret = strexpand(raw, LOOKUP_FUNCTION(lookup_directive), fe); free(raw); return ret; } const char *question_get_priority(const struct question *q) { return q->priority; } const char *question_get_tag(const struct question *q) { return q->tag; } /* * Function: question_get_text * Input: struct frontend *obj - frontend object * const char *template - template name * const char *fallback - string to use if not available * Output: const char * - ptr to string, translated if possible * Description: get the translated version of a string * Assumptions: None. */ const char * question_get_text(struct frontend *obj, const char *template, const char *fallback) { struct question *q = obj->qdb->methods.get(obj->qdb, template); const char *text; text = (q ? q_get_description(obj, q) : fallback); question_deref(q); return text; }