annotate src/common.cpp @ 425:ad106f5fe75f

Add "Ignore Files" and "Edit Ignored List" to Work menu (latter is subsumed from Advanced menu formerly). Also subsume Serve via HTTP into File menu as Share Repository, and add a more helpful description of it. Remove Advanced menu
author Chris Cannam
date Thu, 23 Jun 2011 10:58:32 +0100
parents 498c2ca0b367
children 459b140032d4
rev   line source
Chris@57 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@57 2
Chris@57 3 /*
Chris@57 4 EasyMercurial
Chris@57 5
Chris@57 6 Based on HgExplorer by Jari Korhonen
Chris@57 7 Copyright (c) 2010 Jari Korhonen
Chris@244 8 Copyright (c) 2011 Chris Cannam
Chris@244 9 Copyright (c) 2011 Queen Mary, University of London
Chris@57 10
Chris@57 11 This program is free software; you can redistribute it and/or
Chris@57 12 modify it under the terms of the GNU General Public License as
Chris@57 13 published by the Free Software Foundation; either version 2 of the
Chris@57 14 License, or (at your option) any later version. See the file
Chris@57 15 COPYING included with this distribution for more information.
Chris@57 16 */
jtkorhonen@0 17
Chris@62 18 #include "common.h"
Chris@62 19 #include "debug.h"
jtkorhonen@0 20
Chris@62 21 #include <QFileInfo>
Chris@62 22 #include <QProcessEnvironment>
Chris@62 23 #include <QStringList>
Chris@77 24 #include <QDir>
Chris@172 25 #include <QRegExp>
jtkorhonen@0 26
Chris@62 27 #include <sys/types.h>
Chris@76 28
Chris@76 29 #ifdef Q_OS_WIN32
Chris@76 30 #define _WIN32_WINNT 0x0500
Chris@166 31 #define SECURITY_WIN32
Chris@76 32 #include <windows.h>
Chris@76 33 #include <security.h>
Chris@76 34 #else
Chris@78 35 #include <errno.h>
Chris@62 36 #include <pwd.h>
Chris@78 37 #include <unistd.h>
Chris@80 38 #include <sys/ioctl.h>
Chris@80 39 #include <sys/types.h>
Chris@80 40 #include <sys/stat.h>
Chris@80 41 #include <fcntl.h>
Chris@105 42 #include <signal.h>
Chris@76 43 #endif
Chris@62 44
Chris@172 45 QString findInPath(QString name, QString installPath, bool executableRequired)
Chris@62 46 {
Chris@77 47 bool found = false;
Chris@62 48 if (name != "") {
Chris@172 49 if (name[0] != '/'
Chris@172 50 #ifdef Q_OS_WIN32
Chris@178 51 && (QRegExp("^\\w:").indexIn(name) != 0)
Chris@172 52 #endif
Chris@178 53 ) {
Chris@77 54 #ifdef Q_OS_WIN32
Chris@77 55 QChar pathSep = ';';
Chris@77 56 #else
Chris@77 57 QChar pathSep = ':';
Chris@77 58 #endif
Chris@62 59 name = QFileInfo(name).fileName();
Chris@62 60 QString path =
Chris@62 61 QProcessEnvironment::systemEnvironment().value("PATH");
Chris@214 62 DEBUG << "findInPath: seeking location for binary " << name
Chris@74 63 << ": system path is " << path << endl;
Chris@172 64 if (installPath != "") {
Chris@214 65 DEBUG << "findInPath: install path is " << installPath
Chris@172 66 << ", adding to system path" << endl;
Chris@172 67 //!!! path = path + pathSep + installPath;
Chris@172 68 path = installPath + pathSep + path;
Chris@172 69 }
Chris@74 70 #ifndef Q_OS_WIN32
Chris@178 71 //!!!
Chris@74 72 path = path + ":/usr/local/bin";
Chris@74 73 DEBUG << "... adding /usr/local/bin just in case (fix and add settings dlg please)"
Chris@74 74 << endl;
Chris@74 75 #endif
Chris@62 76 QStringList elements = path.split(pathSep, QString::SkipEmptyParts);
Chris@62 77 foreach (QString element, elements) {
Chris@77 78 QString full = QDir(element).filePath(name);
Chris@62 79 QFileInfo fi(full);
Chris@214 80 DEBUG << "findInPath: looking at " << full << endl;
Chris@172 81 if (fi.exists() && fi.isFile()) {
Chris@214 82 DEBUG << "findInPath: it's a file" << endl;
Chris@172 83 if (!executableRequired || fi.isExecutable()) {
Chris@172 84 name = full;
Chris@214 85 DEBUG << "findInPath: found at " << name << endl;
Chris@172 86 found = true;
Chris@172 87 break;
Chris@172 88 }
Chris@62 89 }
Chris@62 90 }
Chris@214 91 } else {
Chris@214 92 // absolute path given
Chris@214 93 QFileInfo fi(name);
Chris@214 94 DEBUG << "findInPath: looking at absolute path " << name << endl;
Chris@214 95 if (fi.exists() && fi.isFile()) {
Chris@214 96 DEBUG << "findInPath: it's a file" << endl;
Chris@214 97 if (!executableRequired || fi.isExecutable()) {
Chris@214 98 DEBUG << "findInPath: found at " << name << endl;
Chris@214 99 found = true;
Chris@214 100 }
Chris@214 101 }
Chris@62 102 }
Chris@62 103 }
Chris@77 104 #ifdef Q_OS_WIN32
Chris@77 105 if (!found) {
Chris@77 106 if (!name.endsWith(".exe")) {
Chris@172 107 return findInPath(name + ".exe", installPath, executableRequired);
Chris@77 108 }
Chris@77 109 }
Chris@77 110 #endif
Chris@213 111 if (found) {
Chris@213 112 return name;
Chris@213 113 } else {
Chris@213 114 return "";
Chris@213 115 }
Chris@62 116 }
jtkorhonen@0 117
Chris@62 118 #ifdef Q_OS_WIN32
Chris@62 119 QString getUserRealName()
Chris@62 120 {
Chris@76 121 TCHAR buf[1024];
Chris@76 122 long unsigned int maxlen = 1000;
Chris@62 123 LPTSTR info = buf;
jtkorhonen@0 124
Chris@76 125 if (!GetUserNameEx(NameDisplay, info, &maxlen)) {
Chris@76 126 DEBUG << "GetUserNameEx failed: " << GetLastError() << endl;
Chris@62 127 return "";
Chris@62 128 }
jtkorhonen@0 129
Chris@76 130 #ifdef UNICODE
Chris@76 131 return QString::fromUtf16((const unsigned short *)info);
Chris@76 132 #else
Chris@76 133 return QString::fromLocal8Bit(info);
Chris@76 134 #endif
Chris@62 135 }
luisf@71 136 #else
luisf@71 137 #ifdef Q_OS_MAC
Chris@62 138 // Nothing here: definition is in common_osx.mm
Chris@62 139 #else
Chris@62 140 QString getUserRealName()
Chris@62 141 {
Chris@62 142 const int maxlen = 1023;
Chris@62 143 char buf[maxlen + 2];
jtkorhonen@0 144
Chris@62 145 if (getlogin_r(buf, maxlen)) return "";
jtkorhonen@0 146
Chris@62 147 struct passwd *p = getpwnam(buf);
Chris@62 148 if (!p) return "";
Chris@62 149
Chris@62 150 QString s(p->pw_gecos);
Chris@62 151 if (s != "") s = s.split(',')[0];
Chris@62 152 return s;
Chris@62 153 }
Chris@62 154 #endif
luisf@71 155 #endif
jtkorhonen@0 156
Chris@78 157 void loseControllingTerminal()
Chris@78 158 {
Chris@78 159 #ifndef Q_OS_WIN32
Chris@80 160
Chris@80 161 if (!isatty(0)) {
Chris@80 162 DEBUG << "stdin is not a terminal" << endl;
Chris@80 163 } else {
Chris@80 164 DEBUG << "stdin is a terminal, detaching from it" << endl;
Chris@80 165 if (ioctl(0, TIOCNOTTY, NULL) < 0) {
Chris@80 166 perror("ioctl failed");
Chris@83 167 DEBUG << "ioctl for TIOCNOTTY on stdin failed (errno = " << errno << ")" << endl;
Chris@78 168 } else {
Chris@83 169 DEBUG << "ioctl for TIOCNOTTY on stdin succeeded" << endl;
Chris@83 170 return;
Chris@78 171 }
Chris@80 172 }
Chris@80 173
Chris@80 174 int ttyfd = open("/dev/tty", O_RDWR);
Chris@80 175 if (ttyfd < 0) {
Chris@80 176 DEBUG << "failed to open controlling terminal" << endl;
Chris@80 177 } else {
Chris@80 178 if (ioctl(ttyfd, TIOCNOTTY, NULL) < 0) {
Chris@80 179 perror("ioctl failed");
Chris@83 180 DEBUG << "ioctl for TIOCNOTTY on controlling terminal failed (errno = " << errno << ")" << endl;
Chris@80 181 } else {
Chris@83 182 DEBUG << "ioctl for TIOCNOTTY on controlling terminal succeeded" << endl;
Chris@83 183 return;
Chris@78 184 }
Chris@78 185 }
Chris@80 186
Chris@78 187 #endif
Chris@78 188 }
Chris@79 189
Chris@105 190 void installSignalHandlers()
Chris@105 191 {
Chris@105 192 #ifndef Q_OS_WIN32
Chris@105 193 sigset_t sgnals;
Chris@105 194 sigemptyset (&sgnals);
Chris@105 195 sigaddset(&sgnals, SIGHUP);
Chris@105 196 sigaddset(&sgnals, SIGCONT);
Chris@105 197 pthread_sigmask(SIG_BLOCK, &sgnals, 0);
Chris@105 198 #endif
Chris@105 199 }
Chris@105 200
Chris@79 201 FolderStatus getFolderStatus(QString path)
Chris@79 202 {
Chris@85 203 if (path != "/" && path.endsWith("/")) {
Chris@85 204 path = path.left(path.length()-1);
Chris@85 205 }
Chris@84 206 DEBUG << "getFolderStatus: " << path << endl;
Chris@79 207 QFileInfo fi(path);
Chris@79 208 if (fi.exists()) {
Chris@84 209 DEBUG << "exists" << endl;
Chris@79 210 QDir dir(path);
Chris@79 211 if (!dir.exists()) { // returns false for files
Chris@84 212 DEBUG << "not directory" << endl;
Chris@79 213 return FolderIsFile;
Chris@79 214 }
Chris@79 215 if (QDir(dir.filePath(".hg")).exists()) {
Chris@84 216 DEBUG << "has repo" << endl;
Chris@79 217 return FolderHasRepo;
Chris@79 218 }
Chris@79 219 return FolderExists;
Chris@79 220 } else {
Chris@79 221 QDir parent = fi.dir();
Chris@79 222 if (parent.exists()) {
Chris@84 223 DEBUG << "parent exists" << endl;
Chris@79 224 return FolderParentExists;
Chris@79 225 }
Chris@79 226 return FolderUnknown;
Chris@79 227 }
Chris@79 228 }
Chris@79 229
Chris@79 230 QString getContainingRepoFolder(QString path)
Chris@79 231 {
Chris@79 232 if (getFolderStatus(path) == FolderHasRepo) return "";
Chris@79 233
Chris@79 234 QFileInfo me(path);
Chris@79 235 QFileInfo parent(me.dir().absolutePath());
Chris@79 236
Chris@79 237 while (me != parent) {
Chris@79 238 QString parentPath = parent.filePath();
Chris@79 239 if (getFolderStatus(parentPath) == FolderHasRepo) {
Chris@79 240 return parentPath;
Chris@79 241 }
Chris@79 242 me = parent;
Chris@79 243 parent = me.dir().absolutePath();
Chris@79 244 }
Chris@79 245
Chris@79 246 return "";
Chris@79 247 }
Chris@79 248
Chris@79 249 QString xmlEncode(QString s)
Chris@79 250 {
Chris@79 251 s
Chris@79 252 .replace("&", "&amp;")
Chris@79 253 .replace("<", "&lt;")
Chris@79 254 .replace(">", "&gt;")
Chris@79 255 .replace("\"", "&quot;")
Chris@79 256 .replace("'", "&apos;");
Chris@79 257
Chris@79 258 return s;
Chris@79 259 }
Chris@408 260
Chris@408 261 QString uniDecode(QString s)
Chris@408 262 {
Chris@408 263 QString d;
Chris@408 264 for (int i = 0; i < s.length(); ++i) {
Chris@412 265 // backslash escaped with another backslash: replace with a
Chris@410 266 // single backslash and skip on
Chris@411 267 if (i+1 < s.length() && s[i] == '\\' && s[i+1] == '\\') {
Chris@411 268 d += '\\';
Chris@411 269 i += 1;
Chris@410 270 continue;
Chris@410 271 }
Chris@410 272 // unescaped backslash followed by u and at least four more
Chris@410 273 // chars: replace with Unicode character
Chris@408 274 if (i+5 < s.length() && s[i] == '\\' && s[i+1] == 'u') {
Chris@408 275 QString uni = s.mid(i+2, 4);
Chris@408 276 QByteArray ba = QByteArray::fromHex(uni.toAscii());
Chris@408 277 d += QChar(ba[1], ba[0]);
Chris@408 278 i += 5;
Chris@410 279 continue;
Chris@408 280 }
Chris@410 281 // default case: leave alone
Chris@410 282 d += s[i];
Chris@408 283 }
Chris@408 284 return d;
Chris@408 285 }