snownews/cat.c

207 lines
6.9 KiB
C

// This file is part of Snownews - A lightweight console RSS newsreader
//
// Copyright (c) 2003-2004 Oliver Feiler <kiza@kcore.de>
//
// Snownews is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 3
// as published by the Free Software Foundation.
//
// Snownews is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Snownews. If not, see http://www.gnu.org/licenses/.
#include "main.h"
#include "cat.h"
// Compare global category list with string categoryname and return 1 if a
// matching category was found.
static bool CategoryListItemExists (const char* categoryname)
{
for (const struct categories * category = _settings.global_categories; category; category = category->next)
if (strcasecmp (category->name, categoryname) == 0)
return true; // Matching category found.
return false;
}
// The following functions add items to/delete items from the global category list.
static void CategoryListAddItem (const char* categoryname)
{
if (CategoryListItemExists (categoryname)) {
// Only increase refcount
for (struct categories * category = _settings.global_categories; category; category = category->next)
if (strcasecmp (category->name, categoryname) == 0)
++category->refcount;
} else {
// Otherwise add item to structure
struct categories* category = malloc (sizeof (struct categories));
category->name = strdup (categoryname);
category->next = NULL;
if (!_settings.global_categories) { // Contains no elements
category->next = _settings.global_categories;
_settings.global_categories = category;
} else {
bool inserted = false;
struct categories* before_ptr = NULL;
for (struct categories * new_ptr = _settings.global_categories; new_ptr; new_ptr = new_ptr->next) {
if (strcasecmp (category->name, new_ptr->name) > 0)
before_ptr = new_ptr; // New category still below current one. Move on.
else {
if (!before_ptr) { // Insert before _settings.global_categories
category->next = _settings.global_categories;
_settings.global_categories = category;
} else { // Insert after category
before_ptr->next = category;
category->next = new_ptr;
}
inserted = true;
break; // Done with this loop.
}
}
if (!inserted) // No match from above. Insert new item at the end of the list.
before_ptr->next = category;
}
// Set refcount to 1 for newly added category.
category->refcount = 1;
}
}
// Delete item from category list. Decrease refcount for each deletion.
// If refcount hits 0, remove from list.
static void CategoryListDeleteItem (const char* categoryname)
{
for (struct categories * category = _settings.global_categories, *before_ptr = NULL; category; category = category->next) {
if (strcasecmp (category->name, categoryname) == 0) {
// Check refcount
if (category->refcount > 1) {
// Still at least one feed defining this category
--category->refcount;
break;
} else {
// Last feed using this category removed, kill off the structure
if (category == _settings.global_categories) {
_settings.global_categories = _settings.global_categories->next;
free (category->name);
free (category);
break;
} else {
before_ptr->next = category->next;
free (category->name);
free (category);
break;
}
}
}
before_ptr = category;
}
}
// The following two functions add items to/delete items from a feeds category list.
void FeedCategoryAdd (struct feed* cur_ptr, const char* categoryname)
{
struct feedcategories* category = malloc (sizeof (struct feedcategories));
category->name = strdup (categoryname);
category->next = NULL;
if (cur_ptr->feedcategories == NULL) {
// Contains no elements
category->next = cur_ptr->feedcategories;
cur_ptr->feedcategories = category;
} else {
bool inserted = false;
struct feedcategories* before_ptr = NULL;
for (struct feedcategories * new_ptr = cur_ptr->feedcategories; new_ptr != NULL; new_ptr = new_ptr->next) {
if (strcasecmp (category->name, new_ptr->name) > 0) {
// New category still below current one. Move on.
before_ptr = new_ptr;
} else {
if (before_ptr == NULL) {
category->next = cur_ptr->feedcategories;
cur_ptr->feedcategories = category;
} else {
// The new category is now > current one. Insert it here.
before_ptr->next = category;
category->next = new_ptr;
}
inserted = true;
break; // Done with this loop.
}
}
if (!inserted) // No match from above. Insert new item at the end of the list.
before_ptr->next = category;
}
CategoryListAddItem (category->name);
}
void FeedCategoryDelete (struct feed* cur_ptr, const char* categoryname)
{
// categoryname == category->name which will be freed by this function!
char* tmpname = strdup (categoryname);
for (struct feedcategories * category = cur_ptr->feedcategories, *before_ptr = NULL; category; category = category->next) {
if (strcasecmp (category->name, categoryname) == 0) {
if (category == cur_ptr->feedcategories) {
cur_ptr->feedcategories = cur_ptr->feedcategories->next;
free (category->name);
free (category);
break;
} else {
before_ptr->next = category->next;
free (category->name);
free (category);
break;
}
}
before_ptr = category;
}
// Decrease refcount in global category list.
CategoryListDeleteItem (tmpname);
free (tmpname);
}
// Compare a feeds category list with string categoryname.
// Return true if a matching category was found.
bool FeedCategoryExists (const struct feed* cur_ptr, const char* categoryname)
{
for (const struct feedcategories * category = cur_ptr->feedcategories; category; category = category->next)
if (strcasecmp (category->name, categoryname) == 0)
return true;
return false;
}
// Return a comma-separated list of categories defined for the provided feed,
// NULL if no category is defined for the feed.
//
// The caller must free the list.
char* GetCategoryList (const struct feed* feed)
{
if (!feed->feedcategories)
return NULL;
char* categories = malloc (1);
categories[0] = 0;
size_t len = 1;
for (const struct feedcategories * category = feed->feedcategories; category; category = category->next) {
len += strlen (", ") + strlen (category->name);
categories = realloc (categories, len);
if (categories[0])
strcat (categories, ", ");
strcat (categories, category->name);
}
return categories;
}
// Free and reset the filters list.
void ResetFilters (char** filters)
{
if (!filters)
return;
for (unsigned i = 0; i < 8; ++i) {
free (filters[i]);
filters[i] = NULL;
}
}