]> cygwin.com Git - cygwin-apps/setup.git/blame - LogFile.cc
Added dpiAwareness element to manifest
[cygwin-apps/setup.git] / LogFile.cc
CommitLineData
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
2e0aaec9 18#include <stdlib.h>
9f4a0c62
RC
19#include "LogFile.h"
20#include "io_stream.h"
21#include "win32.h"
9f4a0c62 22#include "msg.h"
7b21a88e 23#include "dialog.h"
9f4a0c62
RC
24#include "resource.h"
25#include <iostream>
c83c52d8 26#include <sstream>
e2cdf72c 27#include <set>
9f4a0c62 28#include <time.h>
74617327 29#include <string>
072fb49a 30#include <stdexcept>
f9e903a3 31#include "AntiVirus.h"
eef9ea26 32#include "filemanip.h"
08678720 33#include "String++.h"
9d350b6d
JT
34#include "getopt++/BoolOption.h"
35
20f237b4 36static BoolOption VerboseOutput (false, 'v', "verbose", IDS_HELPTEXT_VERBOSE);
9f4a0c62
RC
37
38/* private helper class */
39class filedef
40{
41public:
42 int level;
08678720 43 std::string key;
9f4a0c62 44 bool append;
08678720 45 filedef (const std::string& _path) : key (_path) {}
e2cdf72c
RC
46 bool operator == (filedef const &rhs) const
47 {
afa76033 48 return casecompare(key, rhs.key) == 0;
e2cdf72c
RC
49 }
50 bool operator < (filedef const &rhs) const
51 {
afa76033 52 return casecompare(key, rhs.key) < 0;
e2cdf72c 53 }
9f4a0c62
RC
54};
55
56/* another */
57struct LogEnt
58{
59 LogEnt *next;
60 enum log_level level;
61 time_t when;
08678720 62 std::string msg;
9f4a0c62
RC
63};
64
65static LogEnt *first_logent = 0;
66static LogEnt **next_logent = &first_logent;
67static LogEnt *currEnt = 0;
5fa64c3c
CV
68
69int LogFile::exit_msg = 0;
9f4a0c62 70
155eacb6 71typedef std::set<filedef> FileSet;
e2cdf72c 72static FileSet files;
155eacb6 73static std::stringbuf *theStream;
9f4a0c62 74
c83c52d8
RC
75LogFile *
76LogFile::createLogFile()
77{
78 theStream = new std::stringbuf;
79 return new LogFile(theStream);
80}
81
82LogFile::LogFile(std::stringbuf *aStream) : LogSingleton (aStream)
9f4a0c62 83{
9f4a0c62
RC
84}
85LogFile::~LogFile(){}
86
87void
88LogFile::clearFiles ()
89{
e2cdf72c 90 files.clear ();
9f4a0c62
RC
91}
92
93void
08678720 94LogFile::setFile (int minlevel, const std::string& path, bool append)
9f4a0c62 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
08678720 106std::string
eef9ea26
RC
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 }
af111c7d 115 return "<no log was in use>";
eef9ea26
RC
116}
117
9f4a0c62 118void
5fa64c3c 119LogFile::exit (int exit_code, bool show_end_install_msg)
9f4a0c62 120{
f9e903a3 121 AntiVirus::AtExit();
9f4a0c62 122 static int been_here = 0;
13aebdbb 123 /* Exitcode -1 is special... */
9f4a0c62 124 if (been_here)
5fa64c3c 125 ::exit (exit_code);
9f4a0c62 126 been_here = 1;
b08f9c71 127
9f4a0c62 128 if (exit_msg)
7b21a88e 129 {
b08f9c71
JT
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;
7b21a88e 133 }
b08f9c71 134
13aebdbb
CV
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. */
5fa64c3c
CV
137 if (show_end_install_msg)
138 Log (LOG_TIMESTAMP) << "Ending cygwin install" << endLog;
9f4a0c62 139
e2cdf72c
RC
140 for (FileSet::iterator i = files.begin();
141 i != files.end(); ++i)
9f4a0c62 142 {
e2cdf72c 143 log_save (i->level, i->key, i->append);
9f4a0c62 144 }
0df9be37 145 // TODO: remove this when the ::exit issue is tidied up.
560ac5e2 146 ::exit (exit_code);
9f4a0c62
RC
147}
148
aa09dcbb
CV
149void
150LogFile::flushAll ()
151{
157dc2b8 152 Log (LOG_TIMESTAMP) << "Writing messages to log files without exiting" << endLog;
aa09dcbb
CV
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
9f4a0c62 161void
08678720 162LogFile::log_save (int babble, const std::string& filename, bool append)
9f4a0c62
RC
163{
164 static int been_here = 0;
165 if (been_here)
166 return;
167 been_here = 1;
168
b41c2908 169 io_stream::mkpath_p (PATH_TO_FILE, "file://" + filename, 0755);
9f4a0c62 170
26922cd2 171 io_stream *f = io_stream::open("file://" + filename, append ? "at" : "wt", 0644);
9f4a0c62
RC
172 if (!f)
173 {
d2a3615c 174 fatal (NULL, IDS_NOLOGFILE, filename.c_str());
9f4a0c62
RC
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 {
d2a3615c 184 const char *tstr = l->msg.c_str();
9f4a0c62
RC
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
155eacb6 195std::ostream &
9f4a0c62
RC
196LogFile::operator() (log_level theLevel)
197{
198 if (theLevel < 1 || theLevel > 2)
155eacb6 199 throw new std::invalid_argument("Invalid log_level");
9f4a0c62 200 if (!theStream)
c83c52d8
RC
201 theStream = new std::stringbuf;
202 rdbuf (theStream);
9f4a0c62
RC
203 currEnt = new LogEnt;
204 currEnt->next = 0;
205 currEnt->level = theLevel;
206 return *this;
207}
208
209void
210LogFile::endEntry()
211{
155eacb6 212 std::string buf = theStream->str();
c8356810
CF
213 delete theStream;
214
9d350b6d
JT
215 /* also write to stdout */
216 if ((currEnt->level >= LOG_PLAIN) || VerboseOutput)
3f7be627
JT
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 }
c8356810 238
9f4a0c62
RC
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 }
c8356810 256 currEnt->msg += buf;
c8356810 257
9f4a0c62 258 /* reset for next use */
c83c52d8
RC
259 theStream = new std::stringbuf;
260 rdbuf (theStream);
261 init (theStream);
9f4a0c62 262}
This page took 0.148779 seconds and 6 git commands to generate.