From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.gentoo.org (pigeon.gentoo.org [208.92.234.80]) by finch.gentoo.org (Postfix) with ESMTP id 7C3151387C3 for ; Fri, 1 Feb 2013 10:49:53 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id 121D921C047; Fri, 1 Feb 2013 10:49:52 +0000 (UTC) Received: from smtp.gentoo.org (smtp.gentoo.org [140.211.166.183]) (using TLSv1 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id 4850921C031 for ; Fri, 1 Feb 2013 10:49:51 +0000 (UTC) Received: from hornbill.gentoo.org (hornbill.gentoo.org [94.100.119.163]) (using TLSv1 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 1904033DCAB for ; Fri, 1 Feb 2013 10:49:50 +0000 (UTC) Received: from localhost.localdomain (localhost [127.0.0.1]) by hornbill.gentoo.org (Postfix) with ESMTP id B0B94E408F for ; Fri, 1 Feb 2013 10:49:48 +0000 (UTC) From: "Sven Eden" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Sven Eden" Message-ID: <1359554426.44916f41c4e7b65f5e8829f00ec101c7f52e4d72.yamakuzure@gentoo> Subject: [gentoo-commits] proj/ufed:master commit in: / X-VCS-Repository: proj/ufed X-VCS-Files: ufed-types.c ufed-types.h X-VCS-Directories: / X-VCS-Committer: yamakuzure X-VCS-Committer-Name: Sven Eden X-VCS-Revision: 44916f41c4e7b65f5e8829f00ec101c7f52e4d72 X-VCS-Branch: master Date: Fri, 1 Feb 2013 10:49:48 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org X-Archives-Salt: 838168c4-a863-45ab-8b85-4e676e2effc6 X-Archives-Hash: 414d34146197b9ab15f4c9c10762a918 commit: 44916f41c4e7b65f5e8829f00ec101c7f52e4d72 Author: Sven Eden gmx de> AuthorDate: Wed Jan 30 14:00:26 2013 +0000 Commit: Sven Eden gmx de> CommitDate: Wed Jan 30 14:00:26 2013 +0000 URL: http://git.overlays.gentoo.org/gitweb/?p=proj/ufed.git;a=commit;h=44916f41 Moved type declaration of enums and structs to a central ufed-types.h and specific functions to ufed-types.c. The new structs sFlag and sDesc are desinged to substitute struct item and struct flag. They can handle much more details. This move is necessary to not have the original data structure to grow into an unmaintainable mess, and is useful to remove all the cross-casting done throughout the code. --- ufed-types.c | 301 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ufed-types.h | 155 ++++++++++++++++++++++++++++++ 2 files changed, 456 insertions(+), 0 deletions(-) diff --git a/ufed-types.c b/ufed-types.c new file mode 100644 index 0000000..694ea29 --- /dev/null +++ b/ufed-types.c @@ -0,0 +1,301 @@ +/* + * ufed-types.c + * + * Created on: 28.01.2013 + * Author: Sven Eden + */ +#include "ufed-types.h" +#include "ufed-curses.h" +#include +#include + +/* 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->forced = false; + newFlag->listline = line; + newFlag->masked = false; + 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->masked = true; + if (flag->desc[idx].isGlobal && ('+' == flag->desc[idx].stateForced)) + flag->forced = 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) { + // 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->desc[i].stateMasked) + || ('+' == flag->desc[i].stateForced) + || ( (' ' == flag->desc[i].stateMasked) + && flag->masked ) + || ( (' ' == flag->desc[i].stateForced) + && flag->forced ) ) { + 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 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 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; +} diff --git a/ufed-types.h b/ufed-types.h new file mode 100644 index 0000000..9953b6a --- /dev/null +++ b/ufed-types.h @@ -0,0 +1,155 @@ +/* + * ufed-types.h + * + * Created on: 28.01.2013 + * Author: Sven Eden + */ +#pragma once +#ifndef UFED_TYPES_H_INCLUDED +#define UFED_TYPES_H_INCLUDED 1 + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "ufed-debug.h" + +/* ============= + * === enums === + * ============= + */ + +/** @enum eMask_ + * @brief determine which flags are shown concerning masked status +**/ +typedef enum eMask_ { + eMask_unmasked, + eMask_both, + eMask_masked +} eMask; + + +/** @enum eOrder_ + * @brief determine whether package lists are shown left or right of the description +**/ +typedef enum eOrder_ { + eOrder_left, + eOrder_right +} eOrder; + + +/** @enum eScope_ + * @brief determine whether global, local or all flags are listed +**/ +typedef enum eScope_ { + eScope_all, + eScope_global, + eScope_local +} eScope; + + +/** @enum eState_ + * @brief determine whether installed, not installed or all packages are listed +**/ +typedef enum eState_ { + eState_all, + eState_installed, + eState_notinstalled +} eState; + + +/** @enum eWin_ + * @brief list of used curses windows +**/ +typedef enum eWin_ { + Top = 0, + Left, List, Input, Scrollbar, Right, Bottom, + wCount // always last +} eWin; + + +/* =============== + * === structs === + * =============== + */ + +/** @struct sDesc_ + * @brief Describe one description line +**/ +typedef struct sDesc_ { + char* desc; //!< The description line + bool isGlobal; //!< true if this is the global description and setting + bool isInstalled; //!< global: at least one pkg is installed, local: all in *pkg are installed. + char* pkg; //!< affected packages + char stateForced; //!< unforced '-', forced '+' or not set ' ' by *use.force + char stateMasked; //!< unmasked '-', masked '+' or not sed ' ' by *use.mask + char statePackage; //!< disabled '-', enabled '+' or not set ' ' by package.use +} sDesc; + + +/** @struct sFlag_ + * @brief Describe one flag and its make.conf setting in a doubly linked ring +**/ +typedef struct sFlag_ { + int currline; //!< The current line on the screen this flag starts + sDesc* desc; //!< variable array of sDesc structs + bool forced; //!< true if the first global description is force enabled. + int listline; //!< The fixed line within the full list this flag starts + bool masked; //!< true if the first global description is mask enabled. + char* name; //!< Name of the flag or NULL for help lines + int ndesc; //!< number of description lines + struct + sFlag_* next; //!< Next flag in the doubly linked ring + struct + sFlag_* prev; //!< Previous flag in the doubly linked ring + char stateConf; //!< disabled '-', enabled '+' or not set ' ' by make.conf + char stateDefault; //!< disabled '-', enabled '+' or not set ' ' by make.defaults +} sFlag; + + +/** @struct sListStats_ + * @brief hold stats of the flag list like line counts +**/ +typedef struct sListStats_ { + int lineCountGlobal; + int lineCountGlobalInstalled; + int lineCountLocal; + int lineCountLocalInstalled; + int lineCountMasked; + int lineCountMaskedInstalled; +} sListStats; + + +/** @struct sKey_ + * @brief describe one main control key +**/ +typedef struct sKey_ { + int key; //!< curses key or -1 if no key shall be used + const char *descr; //!< Help text to display + size_t length; //!< length of the description +} sKey; + + +/** @struct sWindow_ + * @brief describe one curses window dimensions +**/ +typedef struct sWindow_ { + WINDOW *win; + const int top, left, height, width; +} sWindow; + + +/* ======================================= + * === public functions handling types === + * ======================================= + */ +sFlag* addFlag (sFlag** root, const char* name, int line, int ndesc, const char state[2]); +size_t addFlagDesc (sFlag* flag, const char* pkg, const char* desc, const char state[5]); +void addLineStats (const sFlag* flag, sListStats* stats); +void destroyFlag (sFlag** root, sFlag** flag); +int getFlagHeight(const sFlag* flag); +bool isDescLegal (const sFlag* flag, int idx); +bool isFlagLegal (const sFlag* flag); + +#endif /* UFED_TYPES_H_INCLUDED */