summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSven Eden <sven.eden@gmx.de>2013-01-31 19:17:18 +0100
committerSven Eden <sven.eden@gmx.de>2013-01-31 19:17:18 +0100
commit34e1d52dfebe0758f3433ee5c7c2c625ca9b5411 (patch)
tree01375f93b4fe53686e7173ca990817aa7932bdfc /ufed-curses-types.c
parentRemoved obsolete passages and changed the output to include the many more det... (diff)
downloadufed-34e1d52dfebe0758f3433ee5c7c2c625ca9b5411.tar.gz
ufed-34e1d52dfebe0758f3433ee5c7c2c625ca9b5411.tar.bz2
ufed-34e1d52dfebe0758f3433ee5c7c2c625ca9b5411.zip
Renamed ufed-curses-debug.h, ufed-types.c and ufed-types.h to ufed-curses-debug.h, ufed-curses-types.c and ufed-curses-types.h to match the naming of the other files
Diffstat (limited to 'ufed-curses-types.c')
-rw-r--r--ufed-curses-types.c342
1 files changed, 342 insertions, 0 deletions
diff --git a/ufed-curses-types.c b/ufed-curses-types.c
new file mode 100644
index 0000000..7b208fa
--- /dev/null
+++ b/ufed-curses-types.c
@@ -0,0 +1,342 @@
+/*
+ * ufed-types.c
+ *
+ * Created on: 28.01.2013
+ * Author: Sven Eden
+ */
+#include "ufed-curses-types.h"
+#include "ufed-curses.h"
+#include <stdlib.h>
+#include <string.h>
+
+/* external members */
+extern eMask e_mask;
+extern eScope e_scope;
+extern eState e_state;
+
+/* function implementations */
+
+/** @brief create a new flag without description lines
+ * As this is a crucial initialization task, the function will
+ * terminate the program if an error occurs.
+ * @param[in,out] root the new item will be *root if *root is null and its previous flag otherwise.
+ * @param[in] name the name to set, must not be NULL.
+ * @param[in] line the fixed line in the list this item starts.
+ * @param[in] ndesc number of description lines to allocate and initialize.
+ * @param[in] state '+','-',' ' for stateConf and stateDefault in that order.
+ */
+sFlag* addFlag (sFlag** root, const char* name, int line, int ndesc, const char state[2])
+{
+ sFlag* newFlag = NULL;
+
+ // Exit early if root is NULL:
+ if (!root)
+ ERROR_EXIT(-1, "root must not be %s\n", "NULL")
+
+ if (name) {
+
+ // state is a byte mask. Check it first:
+ for (int i = 0; i < 2; ++i) {
+ if (('+' != state[i]) && ('-' != state[i]) && (' ' != state[i]))
+ ERROR_EXIT(-1, "Illegal character '%c' in state string at position %d\n",
+ state[i], i)
+ }
+
+ newFlag = (sFlag*)malloc(sizeof(sFlag));
+ if (newFlag) {
+ newFlag->currline = 0;
+ newFlag->desc = (sDesc*)malloc(sizeof(sDesc) * ndesc);
+
+ if (newFlag->desc) {
+ for (int i = 0; i < ndesc; ++i) {
+ newFlag->desc[i].desc = NULL;
+ newFlag->desc[i].isGlobal = false;
+ newFlag->desc[i].isInstalled = false;
+ newFlag->desc[i].pkg = NULL;
+ newFlag->desc[i].stateForced = ' ';
+ newFlag->desc[i].stateMasked = ' ';
+ newFlag->desc[i].statePackage = ' ';
+ }
+ } else
+ ERROR_EXIT(-1, "Unable to allocate %lu bytes for %d sDesc_ structs\n",
+ sizeof(sDesc) * ndesc, ndesc)
+
+ newFlag->globalForced = false;
+ newFlag->globalMasked = false;
+ newFlag->listline = line;
+ newFlag->name = strdup(name);
+ newFlag->ndesc = ndesc;
+ newFlag->next = NULL;
+ newFlag->prev = NULL;
+ newFlag->stateConf = state[0];
+ newFlag->stateDefault = state[1];
+
+ // Eventually put the new flag into the doubly linked ring:
+ if (*root) {
+ newFlag->next = *root;
+ newFlag->prev = (*root)->prev;
+ (*root)->prev = newFlag;
+ if (newFlag->prev)
+ newFlag->prev->next = newFlag;
+ } else {
+ newFlag->next = newFlag;
+ newFlag->prev = newFlag;
+ *root = newFlag;
+ }
+
+ } else
+ ERROR_EXIT(-1, "Unable to allocate %lu bytes for sFlag_ struct\n", sizeof(sFlag))
+ } else
+ ERROR_EXIT(-1, "The new flags must have a name, not %s\n", "NULL")
+
+ return newFlag;
+}
+
+
+/** @brief add a flag description line to an existing flag
+ * As this is a crucial initialization task, the function will
+ * terminate the program if an error occurs.
+ * @param[in,out] flag pointer to the flag to manipulate. Must not be NULL
+ * @param[in] pkg list of affected packages or NULL if no packages are affected
+ * @param[in] desc description line
+ * @param[in] state '+','-',' ' for global, installed, forced, masked, package - in that order.
+ * @return the full length of the description including package list and separators
+**/
+size_t addFlagDesc (sFlag* flag, const char* pkg, const char* desc, const char state[5])
+{
+ size_t result = 3; // space and brackets.
+ if (flag) {
+ int idx = 0;
+ for ( ; (idx < flag->ndesc) && flag->desc[idx].desc ; ++idx) ;
+ if (idx < flag->ndesc) {
+
+ // state is a byte mask. Check it first:
+ for (int i = 0; i < 5; ++i) {
+ if (('+' != state[i]) && ('-' != state[i]) && (' ' != state[i]))
+ ERROR_EXIT(-1, "Illegal character '%c' in state string at position %d\n",
+ state[i], i)
+ }
+
+ // Now apply.
+ if (pkg) flag->desc[idx].pkg = strdup(pkg);
+ if (desc) flag->desc[idx].desc = strdup(desc);
+ if ('+' == state[0]) flag->desc[idx].isGlobal = true;
+ if ('+' == state[1]) flag->desc[idx].isInstalled = true;
+ flag->desc[idx].stateForced = state[2];
+ flag->desc[idx].stateMasked = state[3];
+ flag->desc[idx].statePackage = state[4];
+
+ // Set flag mask and force status if this is a global and masked/forced description
+ if (flag->desc[idx].isGlobal && ('+' == flag->desc[idx].stateMasked))
+ flag->globalMasked = true;
+ if (flag->desc[idx].isGlobal && ('+' == flag->desc[idx].stateForced))
+ flag->globalForced = true;
+
+ // Determine width:
+ result += (flag->desc[idx].pkg ? strlen(flag->desc[idx].pkg) : 0)
+ + strlen(flag->desc[idx].desc);
+ } else
+ ERROR_EXIT(-1, "Too many lines for flag %s which is set to %d lines.\n desc: \"%s\"\n",
+ flag->name, flag->ndesc, desc ? desc : "no description provided")
+
+ } else
+ ERROR_EXIT(-1, "flag is NULL for description\n \"%s\"\n", desc ? desc : "no description provided")
+
+ return result;
+}
+
+
+/** @brief add statistics to @a stats according to the given flag stats
+ * This function simply counts how many lines are added in which filter case.
+ * @param[in] flag pointer to the flag to analyze.
+ * @param[out] stats pointer to the sListStats struct to update.
+ */
+void addLineStats (const sFlag* flag, sListStats* stats)
+{
+ if (flag && stats) {
+ for (int i = 0; i < flag->ndesc; ++i) {
+ if ( isDescMasked(flag, i) ) {
+ if (flag->desc[i].isInstalled)
+ ++stats->lineCountMaskedInstalled;
+ else
+ ++stats->lineCountMasked;
+ } else if (flag->desc[i].isGlobal) {
+ if (flag->desc[i].isInstalled)
+ ++stats->lineCountGlobalInstalled;
+ else
+ ++stats->lineCountGlobal;
+ } else {
+ if (flag->desc[i].isInstalled)
+ ++stats->lineCountLocalInstalled;
+ else
+ ++stats->lineCountLocal;
+ }
+ }
+ }
+}
+
+
+/** @brief destroy a given flag and set its pointer to the next flag or NULL
+ * This function never fails. It is completely safe to call it with
+ * a NULL pointer or a pointer to NULL.
+ * If the given @a flag is the last in the ring, @a root and @a flag
+ * are both set to NULL after the flags destruction.
+ * If @a flag equals @a root and there are items left in the
+ * ring, @a root is set to its successor.
+ * @param[in,out] root pointer to the root flag.
+ * @param[in,out] flag pointer to an sFlag pointer.
+**/
+void destroyFlag (sFlag** root, sFlag** flag)
+{
+ if (flag && *flag) {
+ sFlag* xFlag = *flag;
+ *flag = xFlag->next != xFlag ? xFlag->next : NULL;
+
+ // a) determine whether the ring is closed:
+ if (*root == xFlag)
+ *root = *flag;
+
+ // b) destroy description lines
+ for (int i = 0; i < xFlag->ndesc; ++i) {
+ if (xFlag->desc[i].pkg)
+ free (xFlag->desc[i].pkg);
+ if (xFlag->desc[i].desc)
+ free (xFlag->desc[i].desc);
+ }
+ if (xFlag->desc)
+ free (xFlag->desc);
+
+ // c) Destroy name and detach from the ring
+ if (xFlag->name)
+ free (xFlag->name);
+ if (xFlag->next && (xFlag->next != xFlag)) {
+ if (xFlag->prev && (xFlag->prev != xFlag))
+ xFlag->prev->next = xFlag->next;
+ xFlag->next->prev = xFlag->prev;
+ } else if (xFlag->prev && (xFlag->prev != xFlag))
+ xFlag->prev->next = NULL;
+ xFlag->next = NULL;
+ xFlag->prev = NULL;
+
+ // d) destroy remaining flag struct and set pointer to NULL
+ free (xFlag);
+ }
+}
+
+
+/** @brief determine the number of lines used by @a flag
+ * This method checks the flag and its description line(s)
+ * settings against the globally active filters.
+ * If @a flag is NULL, the result will be 0.
+ * @param[in] flag pointer to the flag to check.
+ * @return number of lines needed to display the line *without* possible line wrapping.
+**/
+int getFlagHeight (const sFlag* flag)
+{
+ int result = 0;
+
+ if (flag) {
+ for (int i = 0; i < flag->ndesc; ++i)
+ result += isDescLegal(flag, i) ? 1 : 0;
+ }
+
+ return result;
+}
+
+
+/** @brief return true if a specific description line is force enabled
+ * If @a flag is NULL, the result will be false.
+ * @param[in] flag pointer to the flag to check.
+ * @param[in] idx index of the description line to check.
+ * @return true if the specific flag (global or local) is forced
+ */
+bool isDescForced(const sFlag* flag, int idx)
+{
+ bool result = false;
+
+ if (flag && (idx < flag->ndesc)) {
+ if ( ('+' == flag->desc[idx].stateForced)
+ || ( (' ' == flag->desc[idx].stateForced)
+ && flag->globalForced ) )
+ result = true;
+ }
+
+ return result;
+}
+
+
+/** @brief return true if the flag description @a idx is ok to display.
+ * If @a flag is NULL, the result will be false.
+ * @param[in] flag pointer to the flag to check.
+ * @param[in] idx index of the description line to check.
+ * @return true if at least one line has to be shown.
+ */
+bool isDescLegal (const sFlag* flag, int idx)
+{
+ bool result = false;
+
+ if (flag && (idx < flag->ndesc)) {
+ if ( // 1.: Check isGlobal versus e_scope
+ ( ( flag->desc[idx].isGlobal && e_scope != eScope_local)
+ || (!flag->desc[idx].isGlobal && e_scope != eScope_global) )
+ // 2.: Check isInstalled versus e_state
+ && ( ( flag->desc[idx].isInstalled && e_state != eState_notinstalled)
+ || (!flag->desc[idx].isInstalled && e_state != eState_installed) )
+ // 3.: Check stateMasked versus e_mask
+ && ( (('+' == flag->desc[idx].stateMasked) && e_mask != eMask_unmasked)
+ || (('+' != flag->desc[idx].stateMasked) && e_mask != eMask_masked) ) )
+ result = true;
+ }
+
+ return result;
+}
+
+
+/** @brief return true if a specific description line is masked
+ * If @a flag is NULL, the result will be false.
+ * @param[in] flag pointer to the flag to check.
+ * @param[in] idx index of the description line to check.
+ * @return true if the specific flag (global or local) is masked
+ */
+bool isDescMasked(const sFlag* flag, int idx)
+{
+ bool result = false;
+
+ // Note: Masked is true if the flag is globally masked/forced
+ // and the description is not explicitly unmasked/unforced,
+ // or if the description is explicitly masked/forced.
+ if (flag && (idx < flag->ndesc)) {
+ if ( ('+' == flag->desc[idx].stateMasked)
+ || ('+' == flag->desc[idx].stateForced)
+ || ( (' ' == flag->desc[idx].stateMasked)
+ && flag->globalMasked )
+ || ( (' ' == flag->desc[idx].stateForced)
+ && flag->globalForced ) )
+ result = true;
+ }
+
+ return result;
+}
+
+
+/** @brief return true if this flag has at least one line to display.
+ * This method checks the flag and its description line(s)
+ * settings against the globally active filters.
+ * The function returns as soon as the first displayable line is
+ * found and can be therefore faster than getFlagHeight().
+ * If @a flag is NULL, the result will be false.
+ * @param[in] flag pointer to the flag to check.
+ * @return true if at least one line has to be shown.
+ */
+bool isFlagLegal (const sFlag* flag)
+{
+ bool result = false;
+
+ if (flag) {
+ for (int i = 0; !result && (i < flag->ndesc); ++i) {
+ result = isDescLegal(flag, i);
+ }
+ }
+
+ return result;
+}