📄 unixprefs.cpp
字号:
/*____________________________________________________________________________
FreeAmp - The Free MP3 Player
Portions Copyright (C) 1998-1999 EMusic.com
Portions Copyright (C) 1999 Mark H. Weaver <mhw@netris.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: unixprefs.cpp,v 1.29 2000/09/20 11:03:51 ijr Exp $
____________________________________________________________________________*/
#include "config.h"
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#include <string>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <stdio.h>
#include "utility.h"
#include "unixprefs.h"
#include "prefixprefs.h"
// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
// THis module uses the strdup function to pass strings to the lists class
// (among others) which will in turn use delete to reclaim the memory.
// This is NOT VALID! A strdup()ed string must be free()ed, not deleted!
// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
// default values
const char* kDefaultLibraryPath = ".:~/."BRANDING_APP_NAME":"UNIX_LIBDIR"/"BRANDING_APP_NAME;
const char* kDefaultUI = "freeamp.ui";
const char* kDefaultTextUI = "freeampcmd.ui";
const char* kDefaultPMO = "soundcard.pmo";
const char* kDefaultALSADevice = "0:0";
const char* kDefaultESOUNDHost = "localhost";
class LibDirFindHandle {
public:
vector <char *> *m_pLibDirs;
int32 m_current;
};
static
Error
ScanQuotableString(const char *in, const char **endPtr,
char *out, int32 *lengthPtr, const char *delim)
{
bool quoted = false;
int32 length = 0;
// In case of error, clear return fields now
if (endPtr)
*endPtr = 0;
if (lengthPtr)
*lengthPtr = 0;
if (*in == '"')
{
in++;
quoted = true;
}
while (*in)
{
if (*in == '"' && quoted)
{
in++;
break;
}
else if ((isspace(*in) || strchr(delim, *in)) && !quoted)
break;
else if (*in == '\\' && quoted)
{
char ch;
in++;
switch (*in)
{
case '\\': ch = '\\'; in++; break;
case '"': ch = '"'; in++; break;
case 'n': ch = '\n'; in++; break;
case 't': ch = '\t'; in++; break;
default:
if (in[0] < '0' || in[0] > '3' ||
in[1] < '0' || in[1] > '7' ||
in[2] < '0' || in[2] > '7')
{
*endPtr = in;
return kError_SyntaxError;
}
ch = (char)(((in[0] - '0') << 6) |
((in[1] - '0') << 3) |
(in[2] - '0'));
in += 3;
break;
}
if (out)
*out++ = ch;
length++;
}
else if (*in == '\n')
{
if (quoted)
{
*endPtr = in;
return kError_SyntaxError;
}
break;
}
else
{
if (out)
*out++ = *in;
length++;
in++;
}
}
if (out)
*out++ = '\0';
if (lengthPtr)
*lengthPtr = length;
if (endPtr)
*endPtr = in;
return kError_NoErr;
}
static
char *
ReadQuotableString(const char *in, const char **endPtr, const char *delim)
{
Error error;
int32 length;
error = ScanQuotableString(in, endPtr, 0, &length, delim);
if (IsError(error))
return 0;
char *out = new char[length + 1];
ScanQuotableString(in, 0, out, 0, delim);
return out;
}
static
void
PrepareQuotableString(const char *str, bool *needQuotes,
char *out, int32 *lengthPtr, const char *delim)
{
int32 unquotedLength = 0;
int32 quotedLength = 2;
bool quoted = *needQuotes;
if (out && quoted)
*out++ = '"';
if (*str == '"')
*needQuotes = true;
for (; *str; str++)
{
if (strchr(delim, *str) || *str == ' ')
{
*needQuotes = true;
quotedLength++;
if (out)
*out++ = *str;
}
else if (*str == '\\' || *str == '"')
{
quotedLength += 2;
unquotedLength++;
if (out)
{
if (quoted)
*out++ = '\\';
*out++ = *str;
}
}
else if (*str == '\n' || *str == '\t')
{
*needQuotes = true;
quotedLength += 2;
if (out)
{
*out++ = '\\';
*out++ = (*str == '\n') ? 'n' : 't';
}
}
else if (isspace(*str) || !isgraph(*str))
{
*needQuotes = true;
quotedLength += 4;
if (out)
{
unsigned char ch = *str;
*out++ = '\\';
*out++ = '0' + (ch >> 6);
*out++ = '0' + ((ch >> 3) & 7);
*out++ = '0' + (ch & 7);
}
}
else
{
unquotedLength++;
quotedLength++;
if (out)
*out++ = *str;
}
}
if (out)
{
if (quoted)
*out++ = '"';
*out++ = '\0';
}
if (lengthPtr)
*lengthPtr = *needQuotes ? quotedLength : unquotedLength;
}
static
char *
WriteQuotableString(const char *str, const char *delim)
{
int32 length;
bool needQuotes = false;
PrepareQuotableString(str, &needQuotes, 0, &length, delim);
char *out = new char[length + 1];
PrepareQuotableString(str, &needQuotes, out, 0, delim);
return out;
}
static
void
AppendToString(char **destPtr, const char *src, int32 length)
{
char *oldStr = *destPtr;
int32 oldLen = oldStr ? strlen(oldStr) : 0;
int32 newLen = oldLen + length;
char *newStr = new char[newLen + 1];
if (oldStr)
{
strncpy(newStr, oldStr, oldLen);
delete[] oldStr;
*destPtr = NULL;
}
strncpy(newStr + oldLen, src, length);
newStr[newLen] = '\0';
*destPtr = newStr;
}
UnixPrefEntry::
UnixPrefEntry()
{
prefix = NULL;
key = NULL;
separator = NULL;
value = NULL;
suffix = NULL;
}
UnixPrefEntry::
~UnixPrefEntry()
{
if (prefix) delete [] prefix;
if (key) delete [] key;
if (separator) delete [] separator;
if (value) delete [] value;
if (suffix) delete [] suffix;
}
static bool file_exists(char *s)
{
struct stat st;
if ((!s) || (!*s))
return false;
if (stat(s, &st) < 0)
return false;
return true;
}
UnixPrefs::
UnixPrefs()
: m_prefsFilePath(0), m_errorLineNumber(0),
m_saveEnable(true), m_changed(false)
{
const char *old_suffix = "/.freeamp_prefs";
char *old_prefsFilePath;
const char *fadir = "/."BRANDING_APP_NAME;
const char *suffix = "/preferences";
char *homeDir = getenv("HOME");
if (!homeDir)
{
m_saveEnable = false;
return;
}
// Compute pathname of preferences file
old_prefsFilePath = new char[strlen(homeDir) + strlen(old_suffix) + 1];
strcpy(old_prefsFilePath, homeDir);
strcat(old_prefsFilePath, old_suffix);
m_prefsFilePath = new char[strlen(homeDir) + strlen(fadir) + strlen(suffix)
+ 1];
strcpy(m_prefsFilePath, homeDir);
strcat(m_prefsFilePath, fadir);
if (!file_exists(m_prefsFilePath))
mkdir(m_prefsFilePath, S_IRWXU);
strcat(m_prefsFilePath, suffix);
if (file_exists(old_prefsFilePath))
rename(old_prefsFilePath, m_prefsFilePath);
delete [] old_prefsFilePath;
FILE *prefsFile = fopen(m_prefsFilePath, "r");
if (!prefsFile && errno != ENOENT)
{
m_saveEnable = false;
fprintf(stderr, "Error opening %s: %s\n",
m_prefsFilePath, strerror(errno));
}
if (prefsFile)
{
UnixPrefEntry *entry = new UnixPrefEntry;
char buffer[1024];
char *p;
int lineNumber = 0;
while (fgets(buffer, sizeof(buffer) - 1, prefsFile))
{
lineNumber++;
p = buffer;
while (*p && (*p == ' ' && *p == '\t'))
p++;
if (*p == '#')
{
// No data on this line, skip to the end of the comment
while (*p)
p++;
}
if (p > buffer)
AppendToString(&entry->prefix, buffer, p - buffer);
if (*p)
{
char *end;
// char *out;
int32 length;
entry->key = ReadQuotableString(p, (const char **)&end, ":#");
if (entry->key && entry->key[0] == '/')
continue;
else if (entry->key && (m_ht.find(entry->key) == m_ht.end()))
m_ht[entry->key] = entry;
else if (!m_errorLineNumber)
m_errorLineNumber = lineNumber;
p = end;
while (*p && (*p == ' ' || *p == '\t'))
p++;
if (*p == ':')
p++;
else if (!m_errorLineNumber)
m_errorLineNumber = lineNumber;
while (*p && (*p == ' ' || *p == '\t'))
p++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -