- /* vim: ts=4 sw=4 sts=4 ff=unix fenc=utf-8 :
- * =====================================================================
- * sc_list.c
- * Copyright (c) 2003 - 2011 sys0tem
- * LICENSE :
- * LGPL (GNU Lesser General Public License - Version 3,29 June 2007)
- * http://www.gnu.org/copyleft/lesser.html
- * or
- * EPL (Eclipse Public License - v1.0)
- * http://www.eclipse.org/legal/epl-v10.html
- * =====================================================================
- */
- #include <string.h>
- #include <sc_os.h>
- #include <sc_error.h>
- #include <sc_mmgr.h>
- #include <sc_list.h>
-
-
- /* ---------------------------------------------------------------------
- * プロトタイプ宣言
- * ---------------------------------------------------------------------
- */
- static void* SC_List_add (SC_List*, int index, const void* obj, size_t size);
- static char* SC_List_addStr(SC_List* list, int index, const char* obj);
- static void* SC_List_get (SC_List*, int index, size_t* size);
- static char* SC_List_getStr(SC_List*, int index);
- static void SC_List_remove(SC_List*, int index);
- static void SC_List_clear (SC_List*);
- static SC_List_Entry* SC_List_search(SC_List* list, int index);
- static SC_List_Entry* SC_List_newEntry(const void* obj, size_t size);
-
-
- SC_List* SC_List_new(void)
- {
- SC_List* list;
- size_t size;
-
- size = sizeof(SC_List) + (sizeof(SC_List_Entry) * 2);
- list = (SC_List*) malloc(size);
- if (list == NULL)
- { /* メモリ確保失敗 */
- return NULL;
- }
- list->_head = (SC_List_Entry*) (list + 1);
- list->_tail = list->_head + 1;
-
- /* 初期設定 */
- list->size = 0;
- list->_head->next = list->_head->prev = list->_tail;
- list->_tail->next = list->_tail->prev = list->_head;
- list->_head->value = list->_tail->value = NULL;
-
- list->add = SC_List_add;
- list->addStr = SC_List_addStr;
- list->get = SC_List_get;
- list->getStr = SC_List_getStr;
- list->remove = SC_List_remove;
- list->clear = SC_List_clear;
-
- return list;
- }
-
-
- /**
- * リストを破棄します。
- * [注意] 参照していた値も破棄します。
- *
- * @param list リスト
- */
- void SC_List_delete(SC_List* list)
- {
- list->clear(list);
- free(list);
- }
-
-
- /**
- * リストの指定された index 位置にオブジェクトを挿入します。
- * オブジェクトはコピーされ、リストに保持されます。
- * 不正なインデックスが指定された場合、エラーコード SC_EINVAL が
- * メモリの確保に失敗した場合、エラーコード SC_ENOMEM がセットされ、
- * NULL を返します。
- *
- * @param list リスト
- * @param index インデックス
- * @param obj 挿入するオブジェクト
- * @param size オブジェクトのサイズ
- * @return 挿入したオブジェクトのコピー
- */
- static
- void* SC_List_add(SC_List* list, int index, const void* obj, size_t size)
- {
- SC_List_Entry* entry;
- SC_List_Entry* insertEntry;
-
- /* 挿入位置取得 */
- insertEntry = SC_List_search(list, index);
- if (insertEntry == NULL)
- { /* 挿入位置不正 */
- return NULL;
- }
-
- /* エントリ作成 */
- entry = SC_List_newEntry(obj, size);
- if (entry == NULL)
- { /* メモリ確保失敗 */
- return NULL;
- }
-
- /* リストに追加 (insertEntry より1つ前に追加) */
- list->size++;
- entry->next = insertEntry;
- entry->prev = insertEntry->prev;
- insertEntry->prev->next = entry;
- insertEntry->prev = entry;
- return entry->value;
- }
-
-
- /**
- * リストの指定された index 位置に文字列を挿入します。
- * 文字列はコピーされ、リストに保持されます。
- * 不正なインデックスが指定された場合、エラーコード SC_EINVAL が
- * メモリの確保に失敗した場合、エラーコード SC_ENOMEM がセットされ、
- * NULL を返します。
- *
- * @param list リスト
- * @param index インデックス
- * @param obj 挿入する文字列
- * @return 挿入した文字列のコピー
- */
- static
- char* SC_List_addStr(SC_List* list, int index, const char* obj)
- {
- return (char*) SC_List_add(list, index, obj, strlen(obj) + 1);
- }
-
-
- /**
- * 指定されたインデックス位置にある値を取得します。
- * size には、取得された値のサイズが格納されます。
- * (値のサイズが不要な場合、NULL を指定することが可能です。)
- * 不正なインデックスが指定された場合、エラーコード
- * SC_EINVAL がセットされ、NULL が返されます。
- *
- * @param list リスト
- * @param index インデックス
- * @param size 値のサイズが格納される
- * @return 値
- */
- static
- void* SC_List_get(SC_List* list, int index, size_t* size)
- {
- SC_List_Entry* entry;
- entry = SC_List_search(list, index);
- if ((entry == NULL) || (entry == list->_tail))
- { /* インデックス不正 */
- SC_setError(SC_EINVAL);
- return NULL;
- }
-
- if (size != NULL)
- { /* サイズ格納 */
- *size = entry->size;
- }
- return entry->value;
- }
-
-
- /**
- * 指定されたインデックス位置にある文字列を取得します。
- * size には、取得された値のサイズが格納されます。
- * (値のサイズが不要な場合、NULL を指定することが可能です。)
- * 不正なインデックスが指定された場合、エラーコード
- * SC_EINVAL がセットされ、NULL が返されます。
- *
- * @param list リスト
- * @param index インデックス
- * @param size 値のサイズが格納される
- * @return 文字列
- */
- static
- char* SC_List_getStr(SC_List* list, int index)
- {
- return (char*) SC_List_get(list, index, NULL);
- }
-
-
- /**
- * 指定されたインデックス位置にある値を削除します。
- * [注意] 参照していた値も削除されます。
- *
- * @param list リスト
- * @param index インデックス
- */
- static
- void SC_List_remove(SC_List* list, int index)
- {
- SC_List_Entry* entry;
- entry = SC_List_search(list, index);
- if ((entry == NULL) || (entry == list->_tail))
- { /* インデックス不正 */
- return;
- }
- entry->prev->next = entry->next;
- entry->next->prev = entry->prev;
- free(entry);
- list->size--;
- }
-
-
- /**
- * リストをクリアします。
- * [注意] 参照していた値も削除されます。
- *
- * @param list リスト
- */
- static void SC_List_clear(SC_List* list)
- {
- SC_List_Entry* entry;
- entry = list->_head->next;
- while (entry != list->_tail)
- {
- entry = entry->next;
- free(entry->prev);
- }
- list->size = 0;
- list->_head->next = list->_head->prev = list->_tail;
- list->_tail->next = list->_tail->prev = list->_head;
- list->_head->value = list->_tail->value = NULL;
- }
-
-
- /**
- * リストより指定されたインデックスのエントリを取得します。
- * インデックスが -1 または、現在の size 位置の場合、
- * list->tail を返します。
- * インデックス位置が不正な場合、エラーコード SC_EINVAL が
- * セットされ、NULL を返します。
- *
- * @param list リスト
- * @param index インデックス
- * @return エントリ
- */
- static
- SC_List_Entry* SC_List_search(SC_List* list, int index)
- {
- SC_List_Entry* tmpEntry;
- int i;
- int halfSize;
-
- if (index > (int) list->size)
- { /* インデックス位置不正 */
- SC_setError(SC_EINVAL);
- return NULL;
- }
-
- if ((index == -1) || (index == (int) list->size))
- { /* 最後尾 */
- return list->_tail;
- }
-
- halfSize = (int) list->size / 2;
- if (index > halfSize)
- { /* 前方より検索 */
- tmpEntry = list->_head;
- for (i = 0; i <= index; i++)
- {
- tmpEntry = tmpEntry->next;
- }
- }
- else
- { /* 後方より検索 */
- tmpEntry = list->_tail;
- for (i = list->size; i > index; i--)
- {
- tmpEntry = tmpEntry->prev;
- }
- }
- return tmpEntry;
- }
-
-
- /**
- * 新たなエントリを生成します。
- * 生成に失敗した場合、エラーコード SC_ENOMEM が
- * セットされ、NULL が返されます。
- *
- * @param obj オブジェクト
- * @param size サイズ
- * @return リストエントリ
- */
- static
- SC_List_Entry* SC_List_newEntry(const void* obj, size_t size)
- {
- size_t newSize = size + sizeof(SC_List_Entry);
- SC_List_Entry* entry = (SC_List_Entry*) malloc (newSize);
- if (entry == NULL)
- { /* メモリ確保失敗 */
- SC_setError(SC_ENOMEM);
- return NULL;
- }
- entry->value = (entry + 1);
- entry->size = size;
- memcpy(entry->value, obj, size);
- return entry;
- }
-