OSDN Git Service

The character widths list is needed because retrieving the widths from the dict is...
[fukui-no-namari/fukui-no-namari.git] / src / FukuiNoNamari / misc.py
1 # Copyright (C) 2006 by Aiwota Programmer
2 # aiwotaprog@tetteke.tk
3 #
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 2 of the License, or
7 # (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
18 import os.path
19 import re
20 import threading
21 from datetime import tzinfo, timedelta, datetime
22 import itertools
23
24 import config
25 from BbsType import bbs_type_exception
26
27 REG_EXPR_HTTPDATE = re.compile("[^ ,]{3}, (?P<day>\d{2}) (?P<month>(?:Jan)|(?:Feb)|(?:Mar)|(?:Apr)|(?:May)|(?:Jun)|(?:Jul)|(?:Aug)|(?:Sep)|(?:Oct)|(?:Nov)|(?:Dec)) (?P<year>\d{4}) (?P<hour>\d{2}):(?P<minute>\d{2}):(?P<second>\d{2}) GMT")
28 MON_DICT = {"Jan":1, "Feb":2, "Mar":3, "Apr":4, "May":5, "Jun":6, "Jul":7,
29             "Aug":8, "Sep":9, "Oct":10, "Nov":11, "Dec":12}
30
31 def _check_thread(bbs_type):
32     """if bbs_type is not thread, raise BbsTypeError"""
33
34     if not bbs_type.is_thread():
35         raise bbs_type_exception.BbsTypeError, \
36               "the bbs_type does not represent thread: " + bbs_type.uri
37
38 def get_logs_dir_path():
39     return os.path.join(config.get_config_dir_path(), "logs")
40
41 def get_thread_dat_dir_path(bbs_type):
42     """Returns dir path for saving thread dat file"""
43
44     return os.path.join(get_board_dir_path(bbs_type), "dat")
45
46 def get_thread_idx_dir_path(bbs_type):
47     """Returns dir path for saving thread index file"""
48
49     return os.path.join(get_board_dir_path(bbs_type), "idx")
50
51 def get_thread_states_dir_path(bbs_type):
52     """Returns dir path for saving thread states file"""
53
54     return os.path.join(get_board_dir_path(bbs_type), "states")
55
56 def get_thread_dat_path(bbs_type):
57     """Returns thread dat file path"""
58
59     _check_thread(bbs_type)
60
61     return os.path.join(get_thread_dat_dir_path(bbs_type),
62                         bbs_type.thread + ".dat")
63
64 def get_board_subjecttxt_path(bbs_type):
65     """Returns subject.txt file path"""
66
67     return os.path.join(get_board_dir_path(bbs_type), "subject.txt")
68
69 def get_thread_states_path(bbs_type):
70     """Returns thread states file path"""
71
72     _check_thread(bbs_type)
73
74     return os.path.join(get_thread_states_dir_path(bbs_type),
75                         bbs_type.thread + ".states")
76
77 def get_board_states_path(bbs_type):
78     """Returns board states file path"""
79
80     return os.path.join(get_board_dir_path(bbs_type), "board.states")
81
82 def get_board_idx_path(bbs_type):
83     """Returns board idx file path"""
84
85     return os.path.join(get_board_dir_path(bbs_type), "subject.idx")
86
87 def get_board_dir_path(bbs_type):
88     """Returns board dir path"""
89
90     return os.path.join(get_logs_dir_path(), bbs_type.get_board_dir_path())
91
92 def get_thread_idx_path(bbs_type):
93     """Returns idx file path of thread"""
94
95     _check_thread(bbs_type)
96
97     return os.path.join(get_thread_idx_dir_path(bbs_type),
98                         bbs_type.thread + ".idx")
99
100 def get_board_cache_path(bbs_type):
101     """Returns .cache file path of board"""
102
103     return os.path.join(get_thread_idx_dir_path(bbs_type), ".cache")
104
105 ZERO = timedelta(0)
106 HOUR = timedelta(hours=1)
107 class UTC(tzinfo):
108     """UTC"""
109
110     def utcoffset(self, dt):
111         return ZERO
112
113     def tzname(self, dt):
114         return "UTC"
115
116     def dst(self, dt):
117         return ZERO
118
119 utc = UTC()
120
121 epoch = datetime(1970, 1, 1, 0, 0, 0, 0, utc)
122
123 def httpdate_to_secs(httpdate):
124     """Returns the seconds since the epoch"""
125
126     if not httpdate:
127         return 0
128
129     m = REG_EXPR_HTTPDATE.match(httpdate)
130     if m:
131         tm_day = int(m.group("day"))
132         tm_mon = MON_DICT[m.group("month")]
133         tm_year = int(m.group("year"))
134         tm_hour = int(m.group("hour"))
135         tm_min = int(m.group("minute"))
136         tm_sec = int(m.group("second"))
137         
138         d = datetime(tm_year, tm_mon, tm_day, tm_hour, tm_min, tm_sec, 0, utc)
139         delta = d - epoch
140         return delta.days*24*60*60 + delta.seconds
141     else:
142         raise ValueError
143
144
145 class ThreadInvoker(threading.Thread):
146     def __init__(self, on_end, *methods):
147         super(ThreadInvoker, self).__init__()
148         self.on_end = on_end
149         self.methods = methods
150     def run(self):
151         try:
152             for m in self.methods:
153                 m()
154         finally:
155             self.on_end()
156
157
158 class FileWrap:
159     def __init__(self, path, mode="a+"):
160         self.__file = None
161         self.__path = path
162         self.__mode = mode
163     def __del__(self):
164         self.close()
165     def seek(self, size):
166         self.file().seek(size)
167     def write(self, data):
168         self.file().write(data)
169     def writelines(self, sequence):
170         self.file().writelines(sequence)
171     def close(self):
172         if self.__file:
173             self.__file.close()
174             self.__file = None
175     def file(self):
176         if not self.__file:
177             basedir = os.path.dirname(self.__path)
178             if not os.path.isdir(basedir):
179                 os.makedirs(basedir)
180             self.__file = file(self.__path, self.__mode)
181         return self.__file
182
183 def unpack_ifilter(predicate, iterable):
184     """For multiple argument"""
185     for item in iterable:
186         if predicate(*item):
187             yield item
188
189 def split_key_and_value(key_equal_value):
190     try:
191         index = key_equal_value.index("=")
192     except ValueError:
193         pass
194     else:
195         key = key_equal_value[:index]
196         value = key_equal_value[index+1:]
197         return key, value
198
199 def tabbed_to_dict_generator(tabbed, sep="\t"):
200     iterable = tabbed.rstrip().split(sep)
201     iterable = itertools.imap(split_key_and_value, iterable)
202     iterable = itertools.ifilter(None, iterable)
203     return iterable
204
205 def tabbed_to_dict(tabbed, sep="\t"):
206     """Creates a dict from key equal value pairs seperated with tab"""
207     return dict([pair for pair in tabbed_to_dict_generator(tabbed, sep)])