]> cygwin.com Git - cygwin-apps/setup.git/blame_incremental - LogFile.cc
Added dpiAwareness element to manifest
[cygwin-apps/setup.git] / LogFile.cc
... / ...
CommitLineData
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#include <stdlib.h>
19#include "LogFile.h"
20#include "io_stream.h"
21#include "win32.h"
22#include "msg.h"
23#include "dialog.h"
24#include "resource.h"
25#include <iostream>
26#include <sstream>
27#include <set>
28#include <time.h>
29#include <string>
30#include <stdexcept>
31#include "AntiVirus.h"
32#include "filemanip.h"
33#include "String++.h"
34#include "getopt++/BoolOption.h"
35
36static BoolOption VerboseOutput (false, 'v', "verbose", IDS_HELPTEXT_VERBOSE);
37
38/* private helper class */
39class filedef
40{
41public:
42 int level;
43 std::string key;
44 bool append;
45 filedef (const std::string& _path) : key (_path) {}
46 bool operator == (filedef const &rhs) const
47 {
48 return casecompare(key, rhs.key) == 0;
49 }
50 bool operator < (filedef const &rhs) const
51 {
52 return casecompare(key, rhs.key) < 0;
53 }
54};
55
56/* another */
57struct LogEnt
58{
59 LogEnt *next;
60 enum log_level level;
61 time_t when;
62 std::string msg;
63};
64
65static LogEnt *first_logent = 0;
66static LogEnt **next_logent = &first_logent;
67static LogEnt *currEnt = 0;
68
69int LogFile::exit_msg = 0;
70
71typedef std::set<filedef> FileSet;
72static FileSet files;
73static std::stringbuf *theStream;
74
75LogFile *
76LogFile::createLogFile()
77{
78 theStream = new std::stringbuf;
79 return new LogFile(theStream);
80}
81
82LogFile::LogFile(std::stringbuf *aStream) : LogSingleton (aStream)
83{
84}
85LogFile::~LogFile(){}
86
87void
88LogFile::clearFiles ()
89{
90 files.clear ();
91}
92
93void
94LogFile::setFile (int minlevel, const std::string& path, bool append)
95{
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);
104}
105
106std::string
107LogFile::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 return "<no log was in use>";
116}
117
118void
119LogFile::exit (int exit_code, bool show_end_install_msg)
120{
121 AntiVirus::AtExit();
122 static int been_here = 0;
123 /* Exitcode -1 is special... */
124 if (been_here)
125 ::exit (exit_code);
126 been_here = 1;
127
128 if (exit_msg)
129 {
130 std::wstring fmt = LoadStringWEx(exit_msg, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US));
131 std::wstring buf = format(fmt, backslash(getFileName(LOG_BABBLE)).c_str());
132 Log (LOG_PLAIN) << "note: " << wstring_to_string(buf) << endLog;
133 }
134
135 /* ... in that it skips the boring log messages. Exit code -1 is used when
136 just printing the help output and when we're self-elevating. */
137 if (show_end_install_msg)
138 Log (LOG_TIMESTAMP) << "Ending cygwin install" << endLog;
139
140 for (FileSet::iterator i = files.begin();
141 i != files.end(); ++i)
142 {
143 log_save (i->level, i->key, i->append);
144 }
145 // TODO: remove this when the ::exit issue is tidied up.
146 ::exit (exit_code);
147}
148
149void
150LogFile::flushAll ()
151{
152 Log (LOG_TIMESTAMP) << "Writing messages to log files without exiting" << endLog;
153
154 for (FileSet::iterator i = files.begin();
155 i != files.end(); ++i)
156 {
157 log_save (i->level, i->key, i->append);
158 }
159}
160
161void
162LogFile::log_save (int babble, const std::string& filename, bool append)
163{
164 static int been_here = 0;
165 if (been_here)
166 return;
167 been_here = 1;
168
169 io_stream::mkpath_p (PATH_TO_FILE, "file://" + filename, 0755);
170
171 io_stream *f = io_stream::open("file://" + filename, append ? "at" : "wt", 0644);
172 if (!f)
173 {
174 fatal (NULL, IDS_NOLOGFILE, filename.c_str());
175 return;
176 }
177
178 LogEnt *l;
179
180 for (l = first_logent; l; l = l->next)
181 {
182 if (babble || !(l->level == LOG_BABBLE))
183 {
184 const char *tstr = l->msg.c_str();
185 f->write (tstr, strlen (tstr));
186 if (tstr[strlen (tstr) - 1] != '\n')
187 f->write ("\n", 1);
188 }
189 }
190
191 delete f;
192 been_here = 0;
193}
194
195std::ostream &
196LogFile::operator() (log_level theLevel)
197{
198 if (theLevel < 1 || theLevel > 2)
199 throw new std::invalid_argument("Invalid log_level");
200 if (!theStream)
201 theStream = new std::stringbuf;
202 rdbuf (theStream);
203 currEnt = new LogEnt;
204 currEnt->next = 0;
205 currEnt->level = theLevel;
206 return *this;
207}
208
209void
210LogFile::endEntry()
211{
212 std::string buf = theStream->str();
213 delete theStream;
214
215 /* also write to stdout */
216 if ((currEnt->level >= LOG_PLAIN) || VerboseOutput)
217 {
218 /*
219 The log message is UTF-8 encoded. Re-encode this in the console output
220 codepage (so it can be correctly decoded by a Windows terminal).
221 Unfortunately there's no API for direct multibyte re-encoding, so we
222 must do it in two steps UTF-8 -> UTF-16 -> CP_COCP.
223
224 If the console output codepage is UTF-8, we already have the log message
225 in the correct encoding, so we can avoid doing all that work.
226
227 If the output is not a console, GetConsoleOutputCP() returns 0.
228 Possibly it's a Cygwin pty?
229 */
230 std::string cpbuf = buf;
231
232 unsigned int ocp = GetConsoleOutputCP();
233 if ((ocp != 0 ) && (ocp != 65001))
234 cpbuf = wstring_to_string(string_to_wstring(buf), ocp);
235
236 std::cout << cpbuf << std::endl;
237 }
238
239 if (!currEnt)
240 {
241 /* get a default LogEnt */
242 currEnt = new LogEnt;
243 currEnt->next = 0;
244 currEnt->level = LOG_PLAIN;
245 }
246 *next_logent = currEnt;
247 next_logent = &(currEnt->next);
248 time (&(currEnt->when));
249 if (currEnt->level == LOG_TIMESTAMP)
250 {
251 char b[100];
252 struct tm *tm = localtime (&(currEnt->when));
253 strftime (b, 1000, "%Y/%m/%d %H:%M:%S ", tm);
254 currEnt->msg = b;
255 }
256 currEnt->msg += buf;
257
258 /* reset for next use */
259 theStream = new std::stringbuf;
260 rdbuf (theStream);
261 init (theStream);
262}
This page took 0.02746 seconds and 6 git commands to generate.