]>
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" | |
26 | #include "list.h" | |
27 | #include "msg.h" | |
28 | #include "resource.h" | |
29 | #include <iostream> | |
30 | #include <strstream> | |
31 | #include <time.h> | |
74617327 | 32 | #include <string> |
9f4a0c62 RC |
33 | |
34 | /* private helper class */ | |
35 | class filedef | |
36 | { | |
37 | public: | |
38 | int level; | |
39 | String key; | |
40 | bool append; | |
41 | }; | |
42 | ||
43 | /* another */ | |
44 | struct LogEnt | |
45 | { | |
46 | LogEnt *next; | |
47 | enum log_level level; | |
48 | time_t when; | |
49 | String msg; | |
50 | }; | |
51 | ||
52 | static LogEnt *first_logent = 0; | |
53 | static LogEnt **next_logent = &first_logent; | |
54 | static LogEnt *currEnt = 0; | |
55 | int exit_msg = 0; | |
56 | ||
57 | static list<filedef, String, String::casecompare> files; | |
58 | static ostrstream *theStream; | |
59 | ||
60 | LogFile::LogFile() | |
61 | { | |
62 | theStream = new ostrstream; | |
63 | rdbuf (theStream->rdbuf()); | |
64 | } | |
65 | LogFile::~LogFile(){} | |
66 | ||
67 | void | |
68 | LogFile::clearFiles () | |
69 | { | |
70 | while (files.number()) | |
71 | { | |
72 | filedef *f = files.removebyindex(1); | |
73 | delete f; | |
74 | } | |
75 | } | |
76 | ||
77 | void | |
78 | LogFile::setFile (int minlevel, String const &path, bool append) | |
79 | { | |
80 | filedef *f = files.getbykey (path); | |
81 | if (!f) | |
82 | { | |
83 | f = new filedef; | |
84 | f->key = path; | |
85 | files.registerbyobject (*f); | |
86 | } | |
87 | f->level = minlevel; | |
88 | f->append = append; | |
89 | } | |
90 | ||
91 | void | |
92 | LogFile::exit (int const exit_code) | |
93 | { | |
94 | static int been_here = 0; | |
95 | if (been_here) | |
96 | #ifndef _CYGWIN_ | |
97 | ExitProcess (1); | |
98 | #else | |
99 | exit (1); | |
100 | #endif | |
101 | been_here = 1; | |
102 | ||
103 | if (exit_msg) | |
104 | note (NULL, exit_msg); | |
105 | ||
106 | log (LOG_TIMESTAMP) << "Ending cygwin install" << endLog; | |
107 | ||
108 | for (unsigned int i = 1; i <= files.number(); ++i) | |
109 | { | |
110 | filedef *f = files[i]; | |
111 | log_save (f->level, f->key, f->append); | |
112 | } | |
113 | #ifndef _CYGWIN_ | |
114 | ExitProcess (exit_code); | |
115 | #else | |
116 | exit (1); | |
117 | #endif | |
118 | } | |
119 | ||
120 | void | |
121 | LogFile::log_save (int babble, String const &filename, bool append) | |
122 | { | |
123 | static int been_here = 0; | |
124 | if (been_here) | |
125 | return; | |
126 | been_here = 1; | |
127 | ||
128 | io_stream::mkpath_p (PATH_TO_FILE, String("file://") + filename); | |
129 | ||
130 | io_stream *f = io_stream::open(String("file://") + filename, append ? "at" : "wt"); | |
131 | if (!f) | |
132 | { | |
133 | fatal (NULL, IDS_NOLOGFILE, filename.cstr_oneuse()); | |
134 | return; | |
135 | } | |
136 | ||
137 | LogEnt *l; | |
138 | ||
139 | for (l = first_logent; l; l = l->next) | |
140 | { | |
141 | if (babble || !(l->level == LOG_BABBLE)) | |
142 | { | |
143 | char *tstr = l->msg.cstr(); | |
144 | f->write (tstr, strlen (tstr)); | |
145 | if (tstr[strlen (tstr) - 1] != '\n') | |
146 | f->write ("\n", 1); | |
147 | } | |
148 | } | |
149 | ||
150 | delete f; | |
151 | been_here = 0; | |
152 | } | |
153 | ||
154 | ostream & | |
155 | LogFile::operator() (log_level theLevel) | |
156 | { | |
157 | if (theLevel < 1 || theLevel > 2) | |
158 | throw "barfoo"; | |
159 | if (!theStream) | |
160 | theStream = new ostrstream; | |
161 | rdbuf (theStream->rdbuf()); | |
162 | currEnt = new LogEnt; | |
163 | currEnt->next = 0; | |
164 | currEnt->level = theLevel; | |
165 | return *this; | |
166 | } | |
167 | ||
168 | void | |
169 | LogFile::endEntry() | |
170 | { | |
171 | if (!currEnt) | |
172 | { | |
173 | /* get a default LogEnt */ | |
174 | currEnt = new LogEnt; | |
175 | currEnt->next = 0; | |
176 | currEnt->level = LOG_PLAIN; | |
177 | } | |
178 | *next_logent = currEnt; | |
179 | next_logent = &(currEnt->next); | |
180 | time (&(currEnt->when)); | |
181 | if (currEnt->level == LOG_TIMESTAMP) | |
182 | { | |
183 | char b[100]; | |
184 | struct tm *tm = localtime (&(currEnt->when)); | |
185 | strftime (b, 1000, "%Y/%m/%d %H:%M:%S ", tm); | |
186 | currEnt->msg = b; | |
187 | } | |
74617327 RC |
188 | /* What follows is a hack to get around an (apparent) bug in libg++-3 with |
189 | * non-0 memory on alloc | |
190 | */ | |
191 | currEnt->msg += string(theStream->str()).substr(0,theStream->pcount()).c_str(); | |
192 | msg ("LOG: %d %s", currEnt->level, string(theStream->str()).substr(0,theStream->rdbuf()->pcount()).c_str()); | |
9f4a0c62 RC |
193 | theStream->freeze(0); |
194 | delete theStream; | |
195 | /* reset for next use */ | |
196 | theStream = new ostrstream; | |
197 | rdbuf (theStream->rdbuf()); | |
74617327 | 198 | init (theStream->rdbuf()); |
9f4a0c62 | 199 | } |