OSDN Git Service

avoid having multiple connections to a single host.
authorAkira <akohta001@gmail.com>
Sat, 14 Dec 2013 10:08:54 +0000 (19:08 +0900)
committerAkira <akohta001@gmail.com>
Sat, 14 Dec 2013 10:08:54 +0000 (19:08 +0900)
background update for favorites data.
auto scroll resview.
use offlaw.so when open a favorite thread that is not listed on the subject.txt.

25 files changed:
Makefile
Makefile.in
README
config.h
configure
configure.ac
help.txt
src/_2ch/_2ch.c
src/env.c
src/inc/config.h
src/inc/env.h
src/inc/net/nt_socket.h
src/inc/ui/disp.h
src/inc/utils/nt_mutex.h
src/inc/utils/nt_timer.h [new file with mode: 0644]
src/main.c
src/net/nt_socket.c
src/net/nt_ssl_socket.c
src/ui/disp_favorite.c
src/ui/disp_reslist.c
src/ui/disp_threadlist.c
src/usr/favorite_t.c
src/utils/nt_mutex.c
src/utils/nt_pthread.c
src/utils/nt_timer.c [new file with mode: 0644]

index 74ad5de..34098b9 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -22,6 +22,7 @@ OBJS = ${OBJ_DIR}/main.o ${OBJ_DIR}/utils/nt_std_t.o \
     ${OBJ_DIR}/utils/nt_conv_char.o \
     ${OBJ_DIR}/utils/nt_mutex.o \
     ${OBJ_DIR}/utils/nt_pthread.o \
+    ${OBJ_DIR}/utils/nt_timer.o \
     ${OBJ_DIR}/net/nt_socket.o \
     ${OBJ_DIR}/net/nt_ssl_socket.o \
     ${OBJ_DIR}/net/nt_http.o \
@@ -76,6 +77,7 @@ INC_FILES = ${INC_DIR}/config.h \
        ${INC_DIR}/utils/nt_conv_char.h \
        ${INC_DIR}/utils/nt_mutex.h \
        ${INC_DIR}/utils/nt_pthread.h \
+       ${INC_DIR}/utils/nt_timer.h \
        ${INC_DIR}/utils/nt_std_t.h
 
 SHELL = /bin/sh
@@ -215,6 +217,10 @@ $(OBJ_DIR)/utils/nt_pthread.o : ${SRC_DIR}/utils/nt_pthread.c ${INC_FILES}
        @ ${SHELL} prepare_proj.sh
        ${CC} ${CFLAGS} ${INCLUDES} -c -o $@ $< 
 
+$(OBJ_DIR)/utils/nt_timer.o : ${SRC_DIR}/utils/nt_timer.c ${INC_FILES}
+       @ ${SHELL} prepare_proj.sh
+       ${CC} ${CFLAGS} ${INCLUDES} -c -o $@ $< 
+
 $(OBJ_DIR)/_2ch/_2ch.o : ${SRC_DIR}/_2ch/_2ch.c ${INC_FILES}
        @ ${SHELL} prepare_proj.sh
        ${CC} ${CFLAGS} ${INCLUDES} -c -o $@ $< 
index b6690d1..095ed41 100644 (file)
@@ -22,6 +22,7 @@ OBJS = ${OBJ_DIR}/main.o ${OBJ_DIR}/utils/nt_std_t.o \
     ${OBJ_DIR}/utils/nt_conv_char.o \
     ${OBJ_DIR}/utils/nt_mutex.o \
     ${OBJ_DIR}/utils/nt_pthread.o \
+    ${OBJ_DIR}/utils/nt_timer.o \
     ${OBJ_DIR}/net/nt_socket.o \
     ${OBJ_DIR}/net/nt_ssl_socket.o \
     ${OBJ_DIR}/net/nt_http.o \
@@ -76,6 +77,7 @@ INC_FILES = ${INC_DIR}/config.h \
        ${INC_DIR}/utils/nt_conv_char.h \
        ${INC_DIR}/utils/nt_mutex.h \
        ${INC_DIR}/utils/nt_pthread.h \
+       ${INC_DIR}/utils/nt_timer.h \
        ${INC_DIR}/utils/nt_std_t.h
 
 SHELL = /bin/sh
@@ -215,6 +217,10 @@ $(OBJ_DIR)/utils/nt_pthread.o : ${SRC_DIR}/utils/nt_pthread.c ${INC_FILES}
        @ ${SHELL} prepare_proj.sh
        ${CC} ${CFLAGS} ${INCLUDES} -c -o $@ $< 
 
+$(OBJ_DIR)/utils/nt_timer.o : ${SRC_DIR}/utils/nt_timer.c ${INC_FILES}
+       @ ${SHELL} prepare_proj.sh
+       ${CC} ${CFLAGS} ${INCLUDES} -c -o $@ $< 
+
 $(OBJ_DIR)/_2ch/_2ch.o : ${SRC_DIR}/_2ch/_2ch.c ${INC_FILES}
        @ ${SHELL} prepare_proj.sh
        ${CC} ${CFLAGS} ${INCLUDES} -c -o $@ $< 
diff --git a/README b/README
index 8a1ac44..47f8627 100644 (file)
--- a/README
+++ b/README
@@ -1,5 +1,5 @@
 
-    ntch  version 1.0.2.0
+    ntch  version 1.0.2.1
 
     This file is part of ntch.
 
@@ -22,13 +22,13 @@ Linux用 2ch専用ブラウザー
 
 ntch のインストール方法
 
-ダウンロードファイルを使用する場合、適当なディレクトリにntch-1.0.1.8.tgzファイルを解凍します
+ダウンロードファイルを使用する場合、適当なディレクトリにntch-1.0.2.1.tgzファイルを解凍します
 
-tar zxvf ntch-1.0.1.8.tgz
+tar zxvf ntch-1.0.2.1.tgz
 
 作成されたディレクトリに移動します
 
-cd ntch-1.0.1.8
+cd ntch-1.0.2.1
 
 以下のコマンドを実行して、実行ファイルを作成します
 
index f716993..7c00dc2 100644 (file)
--- a/config.h
+++ b/config.h
 #define PACKAGE_NAME "ntch"
 
 /* Define to the full name and version of this package. */
-#define PACKAGE_STRING "ntch 1.0.2.0"
+#define PACKAGE_STRING "ntch 1.0.2.1"
 
 /* Define to the one symbol short name of this package. */
 #define PACKAGE_TARNAME "ntch"
 #define PACKAGE_URL "https://sourceforge.jp/projects/ntch/"
 
 /* Define to the version of this package. */
-#define PACKAGE_VERSION "1.0.2.0"
+#define PACKAGE_VERSION "1.0.2.1"
 
 /* Define to 1 if you have the ANSI C header files. */
 #define STDC_HEADERS 1
index 9ae2a5a..65fc8aa 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for ntch 1.0.2.0.
+# Generated by GNU Autoconf 2.69 for ntch 1.0.2.1.
 #
 # Report bugs to <akohta001@gmail.com>.
 #
@@ -580,8 +580,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='ntch'
 PACKAGE_TARNAME='ntch'
-PACKAGE_VERSION='1.0.2.0'
-PACKAGE_STRING='ntch 1.0.2.0'
+PACKAGE_VERSION='1.0.2.1'
+PACKAGE_STRING='ntch 1.0.2.1'
 PACKAGE_BUGREPORT='akohta001@gmail.com'
 PACKAGE_URL='https://sourceforge.jp/projects/ntch/'
 
@@ -1230,7 +1230,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures ntch 1.0.2.0 to adapt to many kinds of systems.
+\`configure' configures ntch 1.0.2.1 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1291,7 +1291,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of ntch 1.0.2.0:";;
+     short | recursive ) echo "Configuration of ntch 1.0.2.1:";;
    esac
   cat <<\_ACEOF
 
@@ -1372,7 +1372,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-ntch configure 1.0.2.0
+ntch configure 1.0.2.1
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1795,7 +1795,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by ntch $as_me 1.0.2.0, which was
+It was created by ntch $as_me 1.0.2.1, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -4752,7 +4752,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by ntch $as_me 1.0.2.0, which was
+This file was extended by ntch $as_me 1.0.2.1, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -4819,7 +4819,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-ntch config.status 1.0.2.0
+ntch config.status 1.0.2.1
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
index e3e7083..501bcb4 100644 (file)
@@ -2,7 +2,7 @@
 # Process this file with autoconf to produce a configure script.
 
 AC_PREREQ([2.69])
-AC_INIT([ntch], [1.0.2.0], [akohta001@gmail.com],[ntch],[https://sourceforge.jp/projects/ntch/])
+AC_INIT([ntch], [1.0.2.1], [akohta001@gmail.com],[ntch],[https://sourceforge.jp/projects/ntch/])
 AC_CONFIG_SRCDIR([src/main.c])
 AC_CONFIG_HEADERS([config.h])
 
index 120fcb2..094f223 100644 (file)
--- a/help.txt
+++ b/help.txt
@@ -1,5 +1,5 @@
 
-    ntch  version 1.0.2.0
+    ntch  version 1.0.2.1
 
     This file is part of ntch.
 
@@ -131,9 +131,18 @@ Linux用 2ch専用ブラウザー
                     デフォルトでregex関数に渡されるので
                     標準関数の正規表現が使用できます
     :n :new 新規取得スレにジャンプ
+    :a :autoscroll 自動スクロール
+                    j,k,f,bキー以外の入力で自動スクロール解除
+                    k,bキーで反転スクロール
+          .ntchrcファイルにスクロールスピードを指定出来ます
+          以下の書式でIDとパスワードを指定して下さい。
+        auto-scroll-interval=[数字] ミリ秒で指定(標準値500msec)
 
 お気に入り一覧
     d   選択項目をお気に入りから削除
     l   直前に表示したお気に入りを再表示
     h   スレッド選択時にそのスレッドの上位の板を表示
+          .ntchrcファイルにお気に入りの更新頻度を指定出来ます
+          以下の書式でIDとパスワードを指定して下さい。
+        auto-update-interval=[数字] ミリ秒で指定(標準値60000msec)
 
index 09d71e6..2122782 100644 (file)
@@ -345,8 +345,6 @@ wchar_t* nt_read_thread_title(nt_board_handle h_board,
                free(outp);
                return NULL;
        }
-       //nt_thread_children_free(threadp);
-       //threadp->num_res = 0;
        if(!feof(fp_src)){
                s_src[0] = '\0';
                if(!fgets(s_src, S_SIZE, fp_src)){
@@ -406,7 +404,7 @@ BOOL nt_read_board(nt_2ch_selected_item_handle h_select)
                return FALSE;
        
        boardp = selectp->selected_boardp;
-       fwprintf(stderr, L"%ls\n", boardp->name);
+       //fwprintf(stderr, L"%ls\n", boardp->name);
        h_mutex = nt_board_get_mutex(&boardp->handle);
        if(!h_mutex)
                return FALSE;
@@ -919,6 +917,7 @@ int nt_read_board_list(nt_link_tp selitem_list)
                        nt_pthread_release_ref(h_pthread);
                        nt_2ch_selected_item_release_ref(h_select);
                }else{
+                       nt_pthread_release_ref(h_pthread);
                        num_success++;
                }
 #endif
@@ -956,7 +955,7 @@ BOOL nt_set_sel_item(nt_2ch_model_handle h_model,
                        nt_2ch_selected_item_handle *h_sel_itemp, 
                        nt_searched_thread_handle h_searched_thread, const wchar_t** errorpp)
 {
-       const wchar_t *board_name, *dat_name;
+       const wchar_t *board_name, *dat_name, *title;
        nt_category_handle h_category;
        nt_board_handle h_board;
        nt_thread_handle h_thread;
@@ -973,6 +972,7 @@ BOOL nt_set_sel_item(nt_2ch_model_handle h_model,
        assert(board_name);
        
        dat_name = nt_searched_thread_get_dat_name(h_searched_thread);
+       title = nt_searched_thread_get_title(h_searched_thread);
        
        h_board = nt_get_board_by_name(
                        h_model, board_name, &h_category);
@@ -981,7 +981,6 @@ BOOL nt_set_sel_item(nt_2ch_model_handle h_model,
                nt_2ch_selected_item_release_ref(h_sel_item);
                return FALSE;
        }
-       
        nt_set_selected_board(h_sel_item, h_category, h_board);
        
        
@@ -1008,8 +1007,13 @@ BOOL nt_set_sel_item(nt_2ch_model_handle h_model,
        }
        h_thread = nt_get_thread_by_dat_name(h_board, dat_name);
        if(!h_thread){
-               *errorpp = L"スレッド情報が見つかりませんでした";
-               goto ERROR_TRAP;
+               if(!title)
+                       title = L"Dummy";
+               h_thread = nt_thread_dummy_alloc(title, dat_name, 0);
+               if(!h_thread){
+                       *errorpp = L"スレッド情報が見つかりませんでした";
+                       goto ERROR_TRAP;
+               }
        }
        
        nt_set_selected_thread(h_sel_item, h_thread);
index e0acd6c..aedabfc 100644 (file)
--- a/src/env.c
+++ b/src/env.c
@@ -19,6 +19,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <limits.h>
 #include <errno.h>
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -43,9 +44,11 @@ char EDITOR_CMD[1024];
 int FORCE_REFRESH = 0; 
 int THREAD_SORT_TYPE = NT_THREAD_SORT_BY_READ; 
 int INIT_DISP_STATE = NT_INTI_DISP_BOARDMENU; 
-int NT_MAINLOOP_POOLING_INTERVAL;
+int NT_MAINLOOP_POLLING_INTERVAL;
 int NT_PTHREAD_POOL_SIZE;
 int NT_PTHREAD_POOL_QUEUE_SIZE;
+int NT_AUTO_SCROLL_INTERVAL;
+int NT_AUTO_UPDATE_INTERVAL;
 
 static char *app_name = PACKAGE_NAME;
 static char *version_name = PACKAGE_VERSION;
@@ -75,9 +78,12 @@ int set_option(int argc, char* argv[])
        MARU_ID = NULL;
        MARU_PW = NULL;
        
-       NT_MAINLOOP_POOLING_INTERVAL = 1000;
+       NT_MAINLOOP_POLLING_INTERVAL = 100;
        NT_PTHREAD_POOL_SIZE = 5;
        NT_PTHREAD_POOL_QUEUE_SIZE = 20;
+       
+       NT_AUTO_SCROLL_INTERVAL = 500;
+       NT_AUTO_UPDATE_INTERVAL = 60000;
 
        uid = getuid();
        pw = getpwuid(uid);
@@ -150,6 +156,7 @@ extern BOOL read_resource(const char *path)
        char *cptr, *key, *val;
        char *sort_type, *init_disp;
        char buf[128];
+       long int li;
 
        fp = fopen(path, "r");
        if(!fp)
@@ -201,6 +208,22 @@ extern BOOL read_resource(const char *path)
                        free(init_disp);
                        continue;
                }
+               key = strstr(buf, "auto-scroll-interval");
+               if(key){
+                       val = cptr+1;
+                       li = strtol(val, NULL, 10);
+                       if(li > 0 && li < LONG_MAX )
+                               NT_AUTO_SCROLL_INTERVAL = li;
+                       continue;
+               }
+               key = strstr(buf, "auto-update-interval");
+               if(key){
+                       val = cptr+1;
+                       li = strtol(val, NULL, 10);
+                       if(li > 0 && li < LONG_MAX )
+                               NT_AUTO_UPDATE_INTERVAL = li;
+                       continue;
+               }
        }
        fclose(fp);
        return TRUE;
index f716993..7c00dc2 100644 (file)
 #define PACKAGE_NAME "ntch"
 
 /* Define to the full name and version of this package. */
-#define PACKAGE_STRING "ntch 1.0.2.0"
+#define PACKAGE_STRING "ntch 1.0.2.1"
 
 /* Define to the one symbol short name of this package. */
 #define PACKAGE_TARNAME "ntch"
 #define PACKAGE_URL "https://sourceforge.jp/projects/ntch/"
 
 /* Define to the version of this package. */
-#define PACKAGE_VERSION "1.0.2.0"
+#define PACKAGE_VERSION "1.0.2.1"
 
 /* Define to 1 if you have the ANSI C header files. */
 #define STDC_HEADERS 1
index 66f9700..f5e295d 100644 (file)
@@ -31,9 +31,11 @@ extern char USR_FAVORITE_THREAD_FILE_PATH[];
 extern int FORCE_REFRESH;
 extern int THREAD_SORT_TYPE; 
 extern int INIT_DISP_STATE; 
-extern int NT_MAINLOOP_POOLING_INTERVAL;
+extern int NT_MAINLOOP_POLLING_INTERVAL;
 extern int NT_PTHREAD_POOL_SIZE;
 extern int NT_PTHREAD_POOL_QUEUE_SIZE;
+extern int NT_AUTO_UPDATE_INTERVAL;
+extern int NT_AUTO_SCROLL_INTERVAL;
 
 extern char EDITOR_CMD[]; 
 extern char *MARU_ID;
@@ -65,6 +67,7 @@ extern char *MARU_PW;
 #define NT_KEY_COMMAND2 '/' 
 #define NT_KEY_COMMAND3 '?'
 #define NT_KEY_CMD_BOARD_UPDATE (65536 + 1)
+#define NT_KEY_CMD_AUTO_SCROLL (65536 + 2)
 
 #define NT_COMMAND1_WRITE_MSG_1 "write"
 #define NT_COMMAND1_WRITE_MSG_2 "w"
@@ -88,6 +91,8 @@ extern char *MARU_PW;
 #define NT_COMMAND1_SEARCH_2 "se"
 #define NT_COMMAND1_FAVORITE_1 "favorite"
 #define NT_COMMAND1_FAVORITE_2 "f"
+#define NT_COMMAND1_AUTOSCROLL_1 "autoscroll"
+#define NT_COMMAND1_AUTOSCROLL_2 "a"
 
 extern int set_option(int argc, char* argv[]);
 
index 5ba427e..360f27d 100644 (file)
 #ifndef _NT_SOCKET_H_
 #define _NT_SOCKET_H_
 
+#include "utils/nt_mutex.h"
+
 typedef struct tag_nt_socket_t *nt_socket_tp;
 typedef struct tag_nt_socket_t{
        struct sockaddr_in  _sockaddr_in;
+       nt_mutex_handle h_mutex;
 } nt_socket_t;
 
 extern nt_socket_tp nt_socket_init(int port, char *addr);
index 6ee453a..e87dc59 100644 (file)
@@ -47,6 +47,7 @@
 #define DISP_CMD_SEL_FAVORITE_BOARD (5*256)
 #define DISP_CMD_SEL_FAVORITE_THREAD (6*256)
 #define DISP_CMD_UPDATE_FAVORITE (7*256)
+#define DISP_CMD_AUTO_SCROLL (8*256)
 
 extern int disp_board_menu(nt_window_tp wp, 
                nt_2ch_model_handle h_model, nt_2ch_selected_item_handle h_select);
index be5b009..5de739f 100644 (file)
@@ -20,6 +20,7 @@
 
 
 #define NT_MUTEX_ROOT_NAME_FILE (L"file:")
+#define NT_MUTEX_ROOT_NAME_NET (L"net:")
 
 typedef struct tag_nt_mutex_handle{
        int chk_sum;
@@ -33,6 +34,7 @@ extern BOOL nt_mutex_lock(nt_mutex_handle handle);
 extern BOOL nt_mutex_unlock(nt_mutex_handle handle);
 extern nt_mutex_handle nt_mutex_get_one_time_handle(const wchar_t *moniker);
 extern BOOL nt_mutex_add_moniker(nt_mutex_handle handle, const wchar_t *moniker);
+extern BOOL nt_mutex_add_mbs_moniker(nt_mutex_handle handle, const char *moniker);
 
 #endif /* _NT_MUTEX_H_ */
 
diff --git a/src/inc/utils/nt_timer.h b/src/inc/utils/nt_timer.h
new file mode 100644 (file)
index 0000000..e9fe720
--- /dev/null
@@ -0,0 +1,42 @@
+/* Copyright 2013 Akira Ohta (akohta001@gmail.com)
+    This file is part of ntch.
+
+    The ntch is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    The ntch 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 ntch.  If not, see <http://www.gnu.org/licenses/>.
+    
+*/
+#ifndef _NT_TIMER_h_
+#define _NT_TIMER_h_
+#include <sys/times.h>
+
+typedef int (*nt_timer_fn)(int id);
+
+typedef struct tag_nt_timer_handle *nt_timer_handle;
+typedef struct tag_nt_timer_handle{
+       int chk_sum;
+}nt_timer_handle_t;
+
+
+extern BOOL nt_timer_lib_init();
+extern void nt_timer_lib_finish();
+extern nt_timer_handle nt_timer_ring_a_bell();
+extern nt_timer_handle nt_timer_alloc(
+               int id, int interval, nt_timer_fn func);
+extern BOOL nt_timer_set_interval(nt_timer_handle h_timer, int interval);
+extern int nt_timer_get_interval(nt_timer_handle h_timer);
+extern int nt_timer_get_id(nt_timer_handle h_timer);
+extern int nt_timer_add_ref(nt_timer_handle h_timer);
+extern int nt_timer_release_ref(nt_timer_handle h_timer);
+
+
+#endif /* _NT_TIMER_h_ */
index 83f021a..f1fe2d3 100644 (file)
@@ -38,6 +38,7 @@
 #include "usr/usr_db_t.h"
 #include "utils/nt_mutex.h"
 #include "utils/nt_pthread.h"
+#include "utils/nt_timer.h"
 #include "usr/favorite_t.h"
 #include "_2ch/_2ch.h"
 #include "_2ch/maru_2ch.h"
@@ -94,15 +95,7 @@ int main(int argc, char *argv[])
                return 1;
        }
 
-       if(!nt_2ch_model_init()){
-               fputs("Failed to read board menu data.\n", stderr);
-               goto ERROR_TRAP;
-       }
-
-       if(!nt_init_board_menu()){
-               fputs("Failed to initialize board menu data.\n", stderr);
-               goto ERROR_TRAP;
-       }
+       nt_timer_lib_init();
        
        nt_mutex_lib_init();
        
@@ -114,6 +107,17 @@ int main(int argc, char *argv[])
                        fputs(err_msg, stderr);
                goto ERROR_TRAP;
        }
+       
+       if(!nt_2ch_model_init()){
+               fputs("Failed to read board menu data.\n", stderr);
+               goto ERROR_TRAP;
+       }
+
+       if(!nt_init_board_menu()){
+               fputs("Failed to initialize board menu data.\n", stderr);
+               goto ERROR_TRAP;
+       }
+       
 
        h_favorite = nt_favorite_alloc(L"favorite");
        if(!h_favorite){
@@ -183,9 +187,24 @@ ERROR_TRAP:
        
        nt_mutex_lib_finish();
 
+       nt_timer_lib_finish();
+       
        return (result);
 }
 
+#define TIMER_ID_AUTO_UPDATE_NONE 0
+#define TIMER_ID_AUTO_UPDATE 1
+#define TIMER_ID_AUTO_SCROLL 2
+static int auto_update_timer_func(int id)
+{
+       switch(id){
+       case TIMER_ID_AUTO_UPDATE:
+               return TIMER_ID_AUTO_UPDATE;
+       case TIMER_ID_AUTO_SCROLL:
+               return TIMER_ID_AUTO_SCROLL;
+       }
+       return TIMER_ID_AUTO_UPDATE_NONE;
+}
 
 static BOOL DoLoop(WINDOW *scrp, nt_usr_db_handle db_handle,
                nt_favorite_handle h_favorite, 
@@ -216,6 +235,10 @@ static BOOL DoLoop(WINDOW *scrp, nt_usr_db_handle db_handle,
        void *handle;
        nt_pthread_result_t async_data;
        nt_link_tp linkp;
+       BOOL auto_scrolling;
+       nt_timer_handle h_timer_auto_update;
+       nt_timer_handle h_timer_auto_scroll;
+       nt_timer_handle h_timer;
        
        state = DISP_STATE_BOARDMENU;
        if(INIT_DISP_STATE == NT_INTI_DISP_FAVORITE){
@@ -227,6 +250,10 @@ static BOOL DoLoop(WINDOW *scrp, nt_usr_db_handle db_handle,
 
        if(MARU_ID && MARU_PW) 
                marup = nt_maru_2ch_alloc(MARU_ID, MARU_PW);
+       h_timer_auto_scroll = nt_timer_alloc(
+                       TIMER_ID_AUTO_SCROLL, -1, auto_update_timer_func);
+       h_timer_auto_update = nt_timer_alloc(
+                       TIMER_ID_AUTO_UPDATE, NT_AUTO_UPDATE_INTERVAL, auto_update_timer_func);
 
        h_write_data = NULL;
        marup = NULL;
@@ -255,6 +282,8 @@ static BOOL DoLoop(WINDOW *scrp, nt_usr_db_handle db_handle,
                        wclear(scrp);
                else
                        werase(scrp);
+                       
+               
                switch(disp_state){
                case DISP_STATE_BOARDMENU:
                        werase(bwinp->wp);
@@ -397,6 +426,20 @@ static BOOL DoLoop(WINDOW *scrp, nt_usr_db_handle db_handle,
                                goto END_WHILE;
                        rwinp->key = ch;
                        state = disp_reslist(rwinp, state, h_sel_items, db_handle);
+                       auto_scrolling = FALSE;
+                       if(DISP_CMD(state)){
+                               if(DISP_CMD(state) == DISP_CMD_AUTO_SCROLL){
+                                       if(0 >= nt_timer_get_interval(h_timer_auto_scroll)){
+                                               nt_timer_set_interval(
+                                                       h_timer_auto_scroll, NT_AUTO_SCROLL_INTERVAL);
+                                       }
+                                       auto_scrolling = TRUE;
+                               }
+                               DISP_CLR_CMD(state);
+                       }
+                       if(!auto_scrolling){
+                               nt_timer_set_interval(h_timer_auto_scroll, -1);
+                       }
                        if(DISP_STATE_ERROR == state){
                                goto END_WHILE;
                        }else if(state == DISP_STATE_REFRESH){
@@ -618,14 +661,33 @@ static BOOL DoLoop(WINDOW *scrp, nt_usr_db_handle db_handle,
                touchwin(scrp);
                wrefresh(scrp);
                
-               timeout(NT_MAINLOOP_POOLING_INTERVAL);
+               timeout(NT_MAINLOOP_POLLING_INTERVAL);
                do{
                        ch = getch();
                        if(ch == ERR){
                                async_data = nt_pthread_get_result_from_que();
                                if(async_data.code == NT_PTHREAD_RESULT_UPDATE_BOARD){
-                                       
                                        ch = NT_KEY_CMD_BOARD_UPDATE;
+                                       //fprintf(stderr, "Async result recieved.!\n");
+                               }else{
+                                       h_timer = nt_timer_ring_a_bell();
+                                       if(h_timer){
+                                               switch(nt_timer_get_id(h_timer)){
+                                               case TIMER_ID_AUTO_SCROLL:
+                                                       ch = NT_KEY_CMD_AUTO_SCROLL;
+                                                       break;
+                                               case TIMER_ID_AUTO_UPDATE:
+                                                       linkp = nt_favorite_get_update_board_list(
+                                                                       app_2ch_model, h_favorite);
+                                                       if(linkp){
+                                                               nt_read_board_list(linkp);
+                                                               nt_all_link_free(linkp, _2ch_selected_item_free);
+                                                               //fprintf(stderr, "Update request calling.!\n");
+                                                       }
+                                                       break;
+                                               }
+                                               nt_timer_release_ref(h_timer);
+                                       }
                                }
                        }
                }while(ch == '\n' || ch == '\r' || ch == ERR);
@@ -680,6 +742,10 @@ static BOOL DoLoop(WINDOW *scrp, nt_usr_db_handle db_handle,
                }/* end switch*/
        }/* end while */
 END_WHILE:
+       if(h_timer_auto_update)
+               nt_timer_release_ref(h_timer_auto_update);
+       if(h_timer_auto_scroll)
+               nt_timer_release_ref(h_timer_auto_scroll);
        if(cookiep)
                nt_unload_cookie(cookiep);
        if(marup)
index 4b04b8e..fb1e6b6 100644 (file)
@@ -40,6 +40,16 @@ nt_socket_tp nt_socket_init(int port, char *addr)
        nt_socket_tp ptr = malloc(sizeof(nt_socket_t));
        if(ptr == NULL)
                return NULL;
+               
+       ptr->h_mutex = nt_mutex_get_one_time_handle(NT_MUTEX_ROOT_NAME_NET);
+       if(!ptr->h_mutex){
+               free(ptr);
+               return NULL;
+       }
+       if(!nt_mutex_add_mbs_moniker(ptr->h_mutex, addr)){
+               free(ptr);
+               return NULL;
+       }
        
        ptr->_sockaddr_in.sin_family = AF_INET;
        ptr->_sockaddr_in.sin_port = htons(port);
@@ -68,8 +78,11 @@ int nt_socket_connect(nt_socket_tp socketp, char* data, int data_len)
        if(sockfd == -1)
                return -1;
        len = sizeof(socketp->_sockaddr_in);
+       
+       nt_mutex_lock(socketp->h_mutex);
        result = connect(sockfd, 
                        (struct sockaddr *)&(socketp->_sockaddr_in), len);
+       nt_mutex_unlock(socketp->h_mutex);
        if(result == -1){
                close(sockfd);
                return -1;
index 337ed6f..98673fd 100644 (file)
@@ -23,6 +23,7 @@
 #include <openssl/err.h>
 
 #include "utils/nt_std_t.h"
+#include "utils/nt_mutex.h"
 
 
 
@@ -40,7 +41,9 @@ BOOL nt_ssl_connect(
        BOOL result = FALSE;
        int n, idx;
        int data_len;
+       nt_mutex_handle h_mutex;
 
+       
        data_len = *data_lenp;
 
        SSL_load_error_strings();
@@ -63,8 +66,17 @@ BOOL nt_ssl_connect(
 
        BIO_set_conn_hostname(bio, connect_host_string); 
 
-       if(BIO_do_connect(bio) <= 0)
+       h_mutex = nt_mutex_get_one_time_handle(NT_MUTEX_ROOT_NAME_NET);
+       if(!h_mutex)
+               goto ERROR_TRAP1;
+       if(!nt_mutex_add_mbs_moniker(h_mutex, connect_host_string))
                goto ERROR_TRAP1;
+       nt_mutex_lock(h_mutex);
+       if(BIO_do_connect(bio) <= 0){
+               nt_mutex_unlock(h_mutex);
+               goto ERROR_TRAP1;
+       }
+       nt_mutex_unlock(h_mutex);
        
        if(SSL_get_verify_result(ssl) != X509_V_OK){
                if(strict_verify)
index 588fe86..6187bfd 100644 (file)
@@ -239,7 +239,7 @@ int disp_favorite(nt_window_tp wp,
                                                result_state |= DISP_CMD_DEL_FAVORITE_THREAD;
                                        }else if(sel_flag){
                                                (*h_sel_threadp) = nt_searched_thread_alloc(
-                                                       board_name, dat_name, NULL);
+                                                       board_name, dat_name, title);
                                                if((*h_sel_threadp))
                                                        result_state |= DISP_CMD_SEL_FAVORITE_THREAD;
                                        }else if(sel_flag2){
index e011745..4475838 100644 (file)
 #define NT_CMD_ID 4
 #define NT_CMD_SEARCH_THREAD 5
 #define NT_CMD_FAVORITE 6
+#define NT_CMD_AUTO_SCROLL 7
+
+#define AUTO_SCROLL_NONE 0
+#define AUTO_SCROLL_UP  -1
+#define AUTO_SCROLL_DOWN 1
 
 typedef struct tag_ctx_reslist_t *ctx_reslist_tp;
 typedef struct tag_ctx_reslist_t
@@ -59,6 +64,8 @@ typedef struct tag_ctx_reslist_t
        BOOL regex_init;
        int sel_res_no;
        int sel_res_line;
+       
+       int auto_scroll;
 
        nt_link_tp res_disp_list;
        
@@ -82,7 +89,7 @@ static ctx_reslist_tp init_context(nt_2ch_selected_item_handle h_select,
                        nt_usr_db_handle usr_db_handle);
 static BOOL reslist_clone(nt_thread_handle h_thread, ctx_reslist_tp ctxp);
 static void int_ptr_free(void *ptr);
-static int parse_cmd1(const char *param, int *statep, const char **end);
+static int parse_cmd1(const char *param, const char **end);
 static BOOL search_line_asc(regex_t *regexp, nt_link_tp reslistp, 
                        int *sel_res_no, int *sel_res_line, int column);
 static BOOL search_line_desc(regex_t *regexp, ctx_reslist_tp ctxp,
@@ -122,7 +129,6 @@ int disp_reslist(nt_window_tp wp, int prev_state, nt_2ch_selected_item_handle h_
        wchar_t buf[1024*3+1];
        wchar_t *cptr;
        nt_link_tp link_curp;
-       int state;
        BOOL search_asc;
        BOOL adjust;
        BOOL set_value;
@@ -130,7 +136,9 @@ int disp_reslist(nt_window_tp wp, int prev_state, nt_2ch_selected_item_handle h_
        int  cmd;
        attr_t new_res_attr;
        const char *endp;
-
+       int result_state;
+       int auto_scroll_state;
+       
        ctxp = (ctx_reslist_tp)wp->data;
        if(!ctxp){
                ctxp = init_context(h_select, usr_db_handle);
@@ -150,7 +158,7 @@ int disp_reslist(nt_window_tp wp, int prev_state, nt_2ch_selected_item_handle h_
                ctxp->prev_state = prev_state;
 
        ch = wp->key;
-
+       result_state = DISP_STATE_RESLIST;
 
        if(ctxp->max_cur_res < 0 || ctxp->max_cur_offset < 0){
                wlines = wp->lines;
@@ -211,8 +219,27 @@ int disp_reslist(nt_window_tp wp, int prev_state, nt_2ch_selected_item_handle h_
                        clistp = clistp->prev;
                }
        }
+       
+       auto_scroll_state = ctxp->auto_scroll;
+       if(ch == NT_KEY_CMD_AUTO_SCROLL){
+               result_state |= DISP_CMD_AUTO_SCROLL;
+               if(ctxp->auto_scroll == AUTO_SCROLL_UP){
+                       ch = NT_KEY_UP;
+               }else{
+                       ch = NT_KEY_DOWN;
+                       ctxp->auto_scroll = AUTO_SCROLL_DOWN;
+               }
+       }else{
+               ctxp->auto_scroll = AUTO_SCROLL_NONE;
+       }
 
        switch(ch){
+       case NT_KEY_CMD_BOARD_UPDATE:
+               if(auto_scroll_state != AUTO_SCROLL_NONE){
+                       result_state |= DISP_CMD_AUTO_SCROLL;
+                       ctxp->auto_scroll = auto_scroll_state;
+               }
+               break;
        case NT_KEY_REFRESH:
                return DISP_STATE_REFRESH; 
        case NT_KEY_CLOSE:
@@ -395,14 +422,16 @@ int disp_reslist(nt_window_tp wp, int prev_state, nt_2ch_selected_item_handle h_
                break;
        case NT_KEY_COMMAND1:
                assert(wp->cmd_param);
-               cmd = parse_cmd1(wp->cmd_param, &state, &endp);
+               cmd = parse_cmd1(wp->cmd_param, &endp);
                switch(cmd){
+               case NT_CMD_AUTO_SCROLL:
+                       return DISP_CMD_AUTO_SCROLL | DISP_STATE_RESLIST;
                case NT_CMD_SEARCH_THREAD:
                        return DISP_STATE_SEARCH_THREAD;
                case NT_CMD_FAVORITE:
                        return DISP_STATE_FAVORITE;
                case NT_CMD_WRITE:
-                       return state;
+                       return DISP_STATE_EDITOR;
                case NT_CMD_JMP_NEW:
                        if(ctxp->prev_read_cnt <= 0)
                                ctxp->cur_res = 0;
@@ -458,6 +487,10 @@ int disp_reslist(nt_window_tp wp, int prev_state, nt_2ch_selected_item_handle h_
                break;
        case NT_KEY_UP:
        case KEY_UP:
+               if(auto_scroll_state != AUTO_SCROLL_NONE){
+                       result_state |= DISP_CMD_AUTO_SCROLL;
+                       ctxp->auto_scroll = AUTO_SCROLL_UP;
+               }
                ctxp->cur_res_offset--;
                if(0 <= ctxp->cur_res_offset){
                        break;
@@ -504,6 +537,10 @@ int disp_reslist(nt_window_tp wp, int prev_state, nt_2ch_selected_item_handle h_
                break;
        case NT_KEY_DOWN:
        case KEY_DOWN:
+               if(auto_scroll_state != AUTO_SCROLL_NONE){
+                       result_state |= DISP_CMD_AUTO_SCROLL;
+                       ctxp->auto_scroll = AUTO_SCROLL_DOWN;
+               }
                ctxp->cur_res_offset++;
                clistp = ctxp->res_disp_list;
                for(i = 0; i < ctxp->res_num; i++){
@@ -544,6 +581,10 @@ int disp_reslist(nt_window_tp wp, int prev_state, nt_2ch_selected_item_handle h_
                break;
        case NT_KEY_PAGEUP:
        case KEY_PPAGE:
+               if(auto_scroll_state != AUTO_SCROLL_NONE){
+                       result_state |= DISP_CMD_AUTO_SCROLL;
+                       ctxp->auto_scroll = AUTO_SCROLL_UP;
+               }
                ctxp->cur_res_offset -= wp->lines;
                if(ctxp->cur_res_offset >= 0){
                        break;
@@ -600,6 +641,10 @@ int disp_reslist(nt_window_tp wp, int prev_state, nt_2ch_selected_item_handle h_
                break;
        case NT_KEY_PAGEDOWN:
        case KEY_NPAGE:
+               if(auto_scroll_state != AUTO_SCROLL_NONE){
+                       result_state |= DISP_CMD_AUTO_SCROLL;
+                       ctxp->auto_scroll = AUTO_SCROLL_DOWN;
+               }
                clistp = ctxp->res_disp_list;
                if(0 > ctxp->cur_res)
                        ctxp->cur_res = 0;
@@ -773,7 +818,7 @@ int disp_reslist(nt_window_tp wp, int prev_state, nt_2ch_selected_item_handle h_
        }/* end for */
 END_FOR:
        
-       return DISP_STATE_RESLIST
+       return result_state
 }
 
 static int get_id_num(ctx_reslist_tp ctxp, const wchar_t *misc)
@@ -839,7 +884,7 @@ static BOOL set_res_header(ctx_reslist_tp ctxp, res_data_tp res_datap,
        return TRUE;
 }
 
-static int parse_cmd1(const char *param, int *statep, const char **end)
+static int parse_cmd1(const char *param, const char **end)
 {
        int len;
        const char *start;
@@ -855,7 +900,6 @@ static int parse_cmd1(const char *param, int *statep, const char **end)
        
        if(0 == strncmp(NT_COMMAND1_WRITE_MSG_1, start,len) ||
                0 == strncmp(NT_COMMAND1_WRITE_MSG_2, start,len)){
-               *statep = DISP_STATE_EDITOR;
                return NT_CMD_WRITE;
        }else if(0 == strncmp(NT_COMMAND1_JMP_NEW_1,start,len) ||
                0 == strncmp(NT_COMMAND1_JMP_NEW_2, start,len)){
@@ -876,6 +920,11 @@ static int parse_cmd1(const char *param, int *statep, const char **end)
                0 == strncmp(NT_COMMAND1_FAVORITE_2,param,
                        strlen(NT_COMMAND1_FAVORITE_2))){
                return NT_CMD_FAVORITE;
+       }else if(0 == strncmp(NT_COMMAND1_AUTOSCROLL_1,param,
+                       strlen(NT_COMMAND1_AUTOSCROLL_1)) ||
+               0 == strncmp(NT_COMMAND1_AUTOSCROLL_2,param,
+                       strlen(NT_COMMAND1_AUTOSCROLL_2))){
+               return NT_CMD_AUTO_SCROLL;
        }
        return NT_CMD_NONE;
 }
@@ -912,6 +961,7 @@ static ctx_reslist_tp init_context(nt_2ch_selected_item_handle h_select,
        ctxp->sel_res_line = -1;
        ctxp->child_ctx_stackp = NULL;
        ctxp->prev_state = DISP_STATE_THREADTITLE;
+       ctxp->auto_scroll = AUTO_SCROLL_NONE;
 
        b_result = reslist_clone(h_thread, ctxp);
        nt_thread_release_ref(h_thread);
index 8ce1dbe..0801d1b 100644 (file)
@@ -402,7 +402,9 @@ int disp_threadlist(nt_window_tp wp, int prev_state, nt_2ch_selected_item_handle
                if(!h_thread)
                        break;
                nt_set_selected_thread(h_select, h_thread);
+               nt_thread_release_ref(h_thread);
                result_state |= DISP_CMD_ADD_FAVORITE;
+               break;
        }
 
        clistp = ctxp->thread_disp_list;
index a35e6e3..36c2a65 100644 (file)
@@ -1294,7 +1294,8 @@ static nt_favorite_thread_tp parse_favorite_thread(const wchar_t *source)
        threadp->title = title;
        threadp->parent = NULL;
        threadp->ref_count = 1;
-       
+       threadp->num_read = 0;
+       threadp->num_res = 0;
        return threadp;
 }
 
index 890f00e..3d0a7ce 100644 (file)
@@ -151,6 +151,39 @@ BOOL nt_mutex_add_moniker(nt_mutex_handle handle, const wchar_t *moniker)
        return TRUE;
 }
 
+BOOL nt_mutex_add_mbs_moniker(nt_mutex_handle handle, const char *moniker)
+{
+       nt_mutex_tp mutexp;
+       nt_link_tp linkp;
+       wchar_t *wc;
+       int len;
+       
+       assert(handle);
+       mutexp = (nt_mutex_tp)handle;
+       assert(mutexp->handle.chk_sum == NT_MUTEX_CHK_SUM);
+       assert(mutexp->moniker);
+       
+       len = strlen(moniker);
+       if(len == 0)
+               return FALSE;
+       
+       wc = malloc(sizeof(wchar_t)*(len+2));
+       if(!wc)
+               return FALSE;
+       
+       if(0 >= mbstowcs(wc, moniker, len+2)){
+               free(wc);
+               return FALSE;
+       }
+       
+       linkp = nt_link_add_data(mutexp->moniker, wc);
+       if(!linkp){
+               free(wc);
+               return FALSE;
+       }
+       return TRUE;
+}
+
 BOOL nt_mutex_lock(nt_mutex_handle handle)
 {
        nt_mutex_tp mutexp;
@@ -204,9 +237,9 @@ BOOL nt_mutex_unlock(nt_mutex_handle handle)
        int err;
        
        assert(handle);
+       assert(handle->chk_sum == NT_MUTEX_CHK_SUM);
        
        mutexp = (nt_mutex_tp)handle;
-       assert(mutexp->handle.chk_sum == NT_MUTEX_CHK_SUM);
        err = pthread_mutex_unlock(&mutexp->mutex);
        if(err != 0)
                return FALSE;
index 5e2daf2..3e1627e 100644 (file)
@@ -54,7 +54,6 @@ static BOOL nt_pthread_exec(nt_pthread_handle h_pthread);
 static nt_pthread_result_t nt_pthread_call_result_func(nt_pthread_handle h_pthread);
 static BOOL nt_pthread_has_result(nt_pthread_handle h_pthread);
 
-
 BOOL nt_pthread_lib_init(int thread_pool_size, int queue_size,
                const char **error_msg)
 {
@@ -112,6 +111,9 @@ void nt_pthread_lib_finish()
        free(g_sem.pthreads);
        pthread_mutex_destroy(&(g_sem.mutex));
        sem_destroy(&g_sem.sem);
+       
+       nt_queue_free(g_sem.h_que, NULL);
+       nt_queue_free(g_sem.h_que_result, NULL);
 }
 
 BOOL nt_pthread_put_que(nt_pthread_handle h_pthread)
@@ -131,6 +133,8 @@ BOOL nt_pthread_put_que(nt_pthread_handle h_pthread)
        if(!nt_queue_push(g_sem.h_que, h_pthread))
                goto ERROR_TRAP;
        
+       nt_pthread_add_ref(h_pthread);
+       
        err = sem_post(&g_sem.sem);
        if(err != 0)
                goto ERROR_TRAP;
diff --git a/src/utils/nt_timer.c b/src/utils/nt_timer.c
new file mode 100644 (file)
index 0000000..bb3ece9
--- /dev/null
@@ -0,0 +1,258 @@
+/* Copyright 2013 Akira Ohta (akohta001@gmail.com)
+    This file is part of ntch.
+
+    The ntch is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    The ntch 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 ntch.  If not, see <http://www.gnu.org/licenses/>.
+    
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <wchar.h>
+#include <assert.h>
+
+#include "error.h"
+#include "utils/nt_std_t.h"
+#include "utils/nt_timer.h"
+
+#define NT_TIMER_CHK_SUM (1378428)
+
+
+struct _timer_ctx{
+       nt_link_tp timers;
+}g_timer_ctx;
+
+
+typedef struct tag_nt_timer_t *nt_timer_tp;
+typedef struct tag_nt_timer_t{
+       nt_timer_handle_t handle;
+       int ref_count;
+       int interval;/* -1. desable timer 0. immidiate expire NNN. inteval milli sec.
+                                               */
+       struct timespec expire;
+       
+       int id;
+       int status;
+       nt_timer_fn func;
+       
+}nt_timer_t;
+
+static BOOL set_current_time(struct timespec *pts);
+static void add_interval(struct timespec *pts, int interval);
+static void timer_free(void *ptr);
+static BOOL is_expired(const struct timespec *pts, nt_timer_tp);
+
+
+BOOL nt_timer_lib_init()
+{
+       g_timer_ctx.timers = NULL;
+       return TRUE;
+}
+
+
+void nt_timer_lib_finish()
+{
+       if(g_timer_ctx.timers)
+               nt_all_link_free(g_timer_ctx.timers, timer_free);
+}
+
+static BOOL is_expired(const struct timespec *pts, nt_timer_tp timerp)
+{
+       if(timerp->interval == 0)
+               return TRUE;
+       else if(timerp->interval < 0)
+               return FALSE;
+       else if(timerp->expire.tv_sec < pts->tv_sec)
+               return TRUE;
+       else if(timerp->expire.tv_sec > pts->tv_sec)
+               return FALSE;
+       else if(timerp->expire.tv_nsec < pts->tv_nsec)
+               return TRUE;
+       else
+               return FALSE;
+}
+
+nt_timer_handle nt_timer_ring_a_bell()
+{
+       struct timespec ts;
+       nt_timer_tp timerp;
+       nt_link_tp linkp;
+       
+       if(!set_current_time(&ts))
+               return NULL;
+       
+       if(!g_timer_ctx.timers)
+               return NULL;
+       linkp = g_timer_ctx.timers;
+       do{
+               timerp = linkp->data;
+               if(is_expired(&ts, timerp)){
+                       timerp->status =
+                               (timerp->func)(timerp->id);
+                       add_interval(&timerp->expire, timerp->interval);
+                       nt_timer_add_ref(&timerp->handle);
+                       return &timerp->handle;
+               }
+               linkp = linkp->next;
+       }while(linkp != g_timer_ctx.timers);
+       return NULL;
+}
+
+
+nt_timer_handle nt_timer_alloc(
+               int id, int interval, nt_timer_fn func)
+{
+       nt_timer_tp timerp;
+       struct timespec ts;
+       nt_link_tp linkp;
+       
+       if(interval > 0){
+               if(!set_current_time(&ts))
+                       return NULL;
+               add_interval(&ts, interval);
+       }else{
+               ts.tv_sec  = 0;
+               ts.tv_nsec = 0;
+       }
+       
+       timerp = malloc(sizeof(nt_timer_t));
+       if(!timerp)
+               return NULL;
+       timerp->id = id;
+       timerp->status = 0;
+       timerp->interval = interval;
+       timerp->func = func;
+       timerp->expire = ts;
+       timerp->handle.chk_sum = NT_TIMER_CHK_SUM;
+       timerp->ref_count = 1;
+       linkp = nt_link_add_data(g_timer_ctx.timers, timerp);
+       if(!linkp){
+               free(timerp);
+               return NULL;
+       }
+       if(!g_timer_ctx.timers)
+               g_timer_ctx.timers = linkp;
+       
+       return &timerp->handle;
+}
+
+BOOL nt_timer_set_interval(nt_timer_handle h_timer, int interval)
+{
+       nt_timer_tp timerp;
+       assert(h_timer);
+       assert(h_timer->chk_sum == NT_TIMER_CHK_SUM);
+       timerp = (nt_timer_tp)h_timer;
+       assert(timerp->ref_count > 0);
+       if(interval > 0){
+               if(!set_current_time(&timerp->expire))
+                       return FALSE;
+               add_interval(&timerp->expire, interval);
+       }else{
+               timerp->expire.tv_sec  = 0;
+               timerp->expire.tv_nsec = 0;
+       }
+       timerp->interval = interval;
+       return TRUE;
+}
+int nt_timer_get_interval(nt_timer_handle h_timer)
+{
+       nt_timer_tp timerp;
+       assert(h_timer);
+       assert(h_timer->chk_sum == NT_TIMER_CHK_SUM);
+       timerp = (nt_timer_tp)h_timer;
+       assert(timerp->ref_count > 0);
+       return timerp->interval;
+}
+int nt_timer_get_id(nt_timer_handle h_timer)
+{
+       nt_timer_tp timerp;
+       assert(h_timer);
+       assert(h_timer->chk_sum == NT_TIMER_CHK_SUM);
+       timerp = (nt_timer_tp)h_timer;
+       assert(timerp->ref_count > 0);
+       return timerp->id;
+}
+
+
+int nt_timer_add_ref(nt_timer_handle h_timer)
+{
+       nt_timer_tp timerp;
+       assert(h_timer);
+       assert(h_timer->chk_sum == NT_TIMER_CHK_SUM);
+       timerp = (nt_timer_tp)h_timer;
+       assert(timerp->ref_count > 0);
+       return ++timerp->ref_count;
+}
+
+int nt_timer_release_ref(nt_timer_handle h_timer)
+{
+       nt_timer_tp timerp;
+       nt_link_tp linkp;
+       
+       assert(h_timer);
+       assert(h_timer->chk_sum == NT_TIMER_CHK_SUM);
+       timerp = (nt_timer_tp)h_timer;
+       assert(timerp->ref_count > 0);
+       if(0 != --timerp->ref_count)
+               return timerp->ref_count;
+       
+       if(g_timer_ctx.timers){
+               linkp = g_timer_ctx.timers;
+               do{
+                       if(timerp == linkp->data){
+                               g_timer_ctx.timers =
+                                       nt_link_remove2(g_timer_ctx.timers, linkp);
+                               free(linkp);
+                               free(h_timer);
+                               return 0;
+                       }
+                       linkp = linkp->next;
+               }while(linkp != g_timer_ctx.timers);
+       }
+       assert(0);
+       return 0;
+}
+
+static void timer_free(void *ptr)
+{
+       nt_timer_release_ref((nt_timer_handle)ptr);
+}
+
+static BOOL set_current_time(struct timespec *pts)
+{
+#ifdef CLOCK_MONOTONIC_COARSE 
+       if(-1 == clock_gettime(CLOCK_MONOTONIC_COARSE , pts)){
+#else
+       if(-1 == clock_gettime(CLOCK_MONOTONIC , pts)){
+#endif
+               return FALSE;
+       }
+       return TRUE;
+}
+
+static void add_interval(struct timespec *pts, int interval)
+{
+       int i_sec, i_nsec;
+       i_sec = interval / 1000;
+       i_nsec = interval % 1000;
+       i_nsec *= 1000000;
+       pts->tv_sec += i_sec;
+       pts->tv_nsec += i_nsec;
+       if(pts->tv_nsec > 1000000000){
+               pts->tv_sec++;
+               pts->tv_nsec -= 1000000000;
+       }
+}
+
+