]>
Commit | Line | Data |
---|---|---|
9f4a0c62 RC |
1 | /* |
2 | * Copyright (c) 2002, Robert Collins. | |
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 | * A copy of the GNU General Public License can be found at | |
10 | * http://www.gnu.org/ | |
11 | * | |
12 | * Written by Robert Collins <rbtcollins@hotmail.com> | |
13 | * | |
14 | */ | |
15 | ||
16 | /* Log to one or more files. */ | |
17 | ||
18 | #if 0 | |
19 | static const char *cvsid = | |
20 | "\n%%% $Id$\n"; | |
21 | #endif | |
22 | ||
23 | #include "LogFile.h" | |
24 | #include "io_stream.h" | |
25 | #include "win32.h" | |
9f4a0c62 RC |
26 | #include "msg.h" |
27 | #include "resource.h" | |
28 | #include <iostream> | |
c83c52d8 | 29 | #include <sstream> |
e2cdf72c | 30 | #include <set> |
9f4a0c62 | 31 | #include <time.h> |
74617327 | 32 | #include <string> |
f9e903a3 | 33 | #include "AntiVirus.h" |
eef9ea26 RC |
34 | #include "filemanip.h" |
35 | #include "cistring.h" | |
9f4a0c62 | 36 | |
6625e635 RC |
37 | using namespace std; |
38 | ||
9f4a0c62 RC |
39 | /* private helper class */ |
40 | class filedef | |
41 | { | |
42 | public: | |
43 | int level; | |
44 | String key; | |
45 | bool append; | |
e2cdf72c RC |
46 | filedef (String const &_path) : key (_path) {} |
47 | bool operator == (filedef const &rhs) const | |
48 | { | |
49 | return key.casecompare (rhs.key) == 0; | |
50 | } | |
51 | bool operator < (filedef const &rhs) const | |
52 | { | |
53 | return key.casecompare (rhs.key) < 0; | |
54 | } | |
9f4a0c62 RC |
55 | }; |
56 | ||
57 | /* another */ | |
58 | struct LogEnt | |
59 | { | |
60 | LogEnt *next; | |
61 | enum log_level level; | |
62 | time_t when; | |
63 | String msg; | |
64 | }; | |
65 | ||
66 | static LogEnt *first_logent = 0; | |
67 | static LogEnt **next_logent = &first_logent; | |
68 | static LogEnt *currEnt = 0; | |
69 | int exit_msg = 0; | |
70 | ||
e2cdf72c RC |
71 | typedef set<filedef> FileSet; |
72 | static FileSet files; | |
c83c52d8 | 73 | static stringbuf *theStream; |
9f4a0c62 | 74 | |
c83c52d8 RC |
75 | LogFile * |
76 | LogFile::createLogFile() | |
77 | { | |
78 | theStream = new std::stringbuf; | |
79 | return new LogFile(theStream); | |
80 | } | |
81 | ||
82 | LogFile::LogFile(std::stringbuf *aStream) : LogSingleton (aStream) | |
9f4a0c62 | 83 | { |
9f4a0c62 RC |
84 | } |
85 | LogFile::~LogFile(){} | |
86 | ||
87 | void | |
88 | LogFile::clearFiles () | |
89 | { | |
e2cdf72c | 90 | files.clear (); |
9f4a0c62 RC |
91 | } |
92 | ||
93 | void | |
94 | LogFile::setFile (int minlevel, String const &path, bool append) | |
95 | { | |
e2cdf72c RC |
96 | FileSet::iterator f = files.find (filedef(path)); |
97 | if (f != files.end ()) | |
98 | files.erase (f); | |
99 | ||
100 | filedef t (path); | |
101 | t.level = minlevel; | |
102 | t.append = append; | |
103 | files.insert (t); | |
9f4a0c62 RC |
104 | } |
105 | ||
eef9ea26 RC |
106 | String |
107 | LogFile::getFileName (int level) const | |
108 | { | |
109 | for (FileSet::iterator i = files.begin(); | |
110 | i != files.end(); ++i) | |
111 | { | |
112 | if (i->level == level) | |
113 | return i->key; | |
114 | } | |
115 | cistring bad_file; | |
116 | bad_file.Format(IDS_MISSING_LOG); | |
117 | return bad_file.c_str(); | |
118 | } | |
119 | ||
9f4a0c62 RC |
120 | void |
121 | LogFile::exit (int const exit_code) | |
122 | { | |
f9e903a3 | 123 | AntiVirus::AtExit(); |
9f4a0c62 RC |
124 | static int been_here = 0; |
125 | if (been_here) | |
560ac5e2 | 126 | ::exit (exit_code); |
9f4a0c62 RC |
127 | been_here = 1; |
128 | ||
129 | if (exit_msg) | |
eef9ea26 | 130 | note (NULL, exit_msg, backslash(getFileName(LOG_BABBLE)).cstr_oneuse()); |
9f4a0c62 RC |
131 | |
132 | log (LOG_TIMESTAMP) << "Ending cygwin install" << endLog; | |
133 | ||
e2cdf72c RC |
134 | for (FileSet::iterator i = files.begin(); |
135 | i != files.end(); ++i) | |
9f4a0c62 | 136 | { |
e2cdf72c | 137 | log_save (i->level, i->key, i->append); |
9f4a0c62 | 138 | } |
0df9be37 | 139 | // TODO: remove this when the ::exit issue is tidied up. |
560ac5e2 | 140 | ::exit (exit_code); |
9f4a0c62 RC |
141 | } |
142 | ||
143 | void | |
144 | LogFile::log_save (int babble, String const &filename, bool append) | |
145 | { | |
146 | static int been_here = 0; | |
147 | if (been_here) | |
148 | return; | |
149 | been_here = 1; | |
150 | ||
151 | io_stream::mkpath_p (PATH_TO_FILE, String("file://") + filename); | |
152 | ||
153 | io_stream *f = io_stream::open(String("file://") + filename, append ? "at" : "wt"); | |
154 | if (!f) | |
155 | { | |
156 | fatal (NULL, IDS_NOLOGFILE, filename.cstr_oneuse()); | |
157 | return; | |
158 | } | |
159 | ||
160 | LogEnt *l; | |
161 | ||
162 | for (l = first_logent; l; l = l->next) | |
163 | { | |
164 | if (babble || !(l->level == LOG_BABBLE)) | |
165 | { | |
166 | char *tstr = l->msg.cstr(); | |
167 | f->write (tstr, strlen (tstr)); | |
168 | if (tstr[strlen (tstr) - 1] != '\n') | |
169 | f->write ("\n", 1); | |
170 | } | |
171 | } | |
172 | ||
173 | delete f; | |
174 | been_here = 0; | |
175 | } | |
176 | ||
177 | ostream & | |
178 | LogFile::operator() (log_level theLevel) | |
179 | { | |
180 | if (theLevel < 1 || theLevel > 2) | |
181 | throw "barfoo"; | |
182 | if (!theStream) | |
c83c52d8 RC |
183 | theStream = new std::stringbuf; |
184 | rdbuf (theStream); | |
9f4a0c62 RC |
185 | currEnt = new LogEnt; |
186 | currEnt->next = 0; | |
187 | currEnt->level = theLevel; | |
188 | return *this; | |
189 | } | |
190 | ||
191 | void | |
192 | LogFile::endEntry() | |
193 | { | |
194 | if (!currEnt) | |
195 | { | |
196 | /* get a default LogEnt */ | |
197 | currEnt = new LogEnt; | |
198 | currEnt->next = 0; | |
199 | currEnt->level = LOG_PLAIN; | |
200 | } | |
201 | *next_logent = currEnt; | |
202 | next_logent = &(currEnt->next); | |
203 | time (&(currEnt->when)); | |
204 | if (currEnt->level == LOG_TIMESTAMP) | |
205 | { | |
206 | char b[100]; | |
207 | struct tm *tm = localtime (&(currEnt->when)); | |
208 | strftime (b, 1000, "%Y/%m/%d %H:%M:%S ", tm); | |
209 | currEnt->msg = b; | |
210 | } | |
74617327 RC |
211 | /* What follows is a hack to get around an (apparent) bug in libg++-3 with |
212 | * non-0 memory on alloc | |
213 | */ | |
c83c52d8 RC |
214 | currEnt->msg += theStream->str(); |
215 | // OLD code (libg++3) string(theStream->str()).substr(0,theStream->pcount()).c_str(); | |
216 | msg ("LOG: %d %s", currEnt->level, theStream->str().c_str()); | |
217 | //string(theStream->str()).substr(0,theStream->rdbuf()->pcount()).c_str()); | |
218 | // theStream->freeze(0); | |
9f4a0c62 RC |
219 | delete theStream; |
220 | /* reset for next use */ | |
c83c52d8 RC |
221 | theStream = new std::stringbuf; |
222 | rdbuf (theStream); | |
223 | init (theStream); | |
9f4a0c62 | 224 | } |