Logo Search packages:      
Sourcecode: zinf version File versions  Download package

unixprefs.cpp

/*____________________________________________________________________________
        
        Zinf - Zinf Is Not FreeA*p (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.15 2003/09/16 17:34:54 kgk Exp $
____________________________________________________________________________*/

#include "config.h"

#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif

#include <string>
#include <algorithm>
#include <iostream>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <stdio.h>

using namespace std;

#include "utility.h"
#include "unixprefs.h"
#include "prefixprefs.h"

static
Error
ScanQuotableString(const char *in, const char **endPtr,
                   char *out, int32_t *lengthPtr, const char *delim)
{
    bool quoted = false;
    int32_t 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_t 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_t *lengthPtr, const char *delim)
{
    int32_t unquotedLength = 0;
    int32_t 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_t length;
    bool needQuotes = false;

    PrepareQuotableString(str, &needQuotes, 0, &length, delim);

    char *out = new char[length + 1];

    PrepareQuotableString(str, &needQuotes, out, 0, delim);
    return out;
}
#if 0
static
void
AppendToString(char **destPtr, const char *src, int32_t length)
{
    char *oldStr = *destPtr;
    int32_t oldLen = oldStr ? strlen(oldStr) : 0;
    int32_t 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;
}
#endif

UnixPrefEntry::
UnixPrefEntry()
{
}

UnixPrefEntry::
~UnixPrefEntry()
{
}

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() : 
#if 0
      kDefaultLibraryPath(".:~/."BRANDING_APP_NAME":"UNIX_LIBDIR"/"BRANDING_APP_NAME),
      kDefaultUI("zinf.ui"),                                        
      kDefaultTextUI("zinfcmd.ui"),                                 
      kDefaultPMO("soundcard.pmo"),                                 
      kDefaultALSADevice("0:0"),                                    
      kDefaultESOUNDHost("localhost"),
#endif
      m_prefsFilePath(0), m_errorLineNumber(0),
      m_saveEnable(true), m_changed(false)
{
    const char *old_suffix = "/.zinf_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;
        UnixPrefEntry entry;
        char buffer[1024];
        char *p;
        int lineNumber = 0;

        while (fgets(buffer, sizeof(buffer) - 1, prefsFile))
        {
          entry = UnixPrefEntry();

            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);
              entry.prefix = string(buffer, 0, p - buffer);

            if (*p)
            {
                char *end;
                // char *out;
                int32_t length;
                char *key; 
                char *val;
                
                key = ReadQuotableString(p, (const char **)&end, ":#");
                if (key) {
                  entry.key = key;
                  delete[] key;
                  if (entry.key[0] == '/') continue;
                } 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++;
                
                entry.separator = string (end, 0, p - end);
                
                val = ReadQuotableString(p, (const char **)&end, "#");
                if (val){
                  entry.value = val;
                  delete[] val;
                } else if (!m_errorLineNumber)
                  m_errorLineNumber = lineNumber;
                p = end;
                length = strlen(p);
                if (p[length - 1] != '\n')
                {
                    p[length++] = '\n';
                    p[length] = '\0';
                }
                entry.suffix = string (p, 0, length);
                m_ht[entry.key] = entry.value;
            }
            m_entries.push_back(entry);
        }

        if (m_errorLineNumber)
            m_saveEnable = false;
        
        fclose(prefsFile);
    }

    SetDefaults();
    Save();

    // Test(this);
}

UnixPrefs::
~UnixPrefs()
{
    Save();

    delete [] m_libDirs;
    delete[] m_prefsFilePath;
}



Error
UnixPrefs::
SetDefaults()
{
  string dummy;
    if (GetPrefString(kDatabaseDirPref, dummy) == kError_NoPrefValue) {
        char *fadir = ZinfDir(NULL);
        string tempdir = fadir;
        tempdir += "/db";
        SetPrefString(kDatabaseDirPref, tempdir);
        delete [] fadir;
    }

    if (GetPrefString(kSaveMusicDirPref, dummy) == kError_NoPrefValue) {
        string tempdir = string(getenv("HOME"));
        tempdir += "/MyMusic";
        SetPrefString(kSaveMusicDirPref, tempdir);
    }

    if (GetPrefString(kWatchThisDirectoryPref, dummy) == kError_NoPrefValue) 
    {
        string tempdir = string(getenv("HOME"));
        tempdir += "/MyMusic";
        SetPrefString(kWatchThisDirectoryPref, tempdir);
    }

#define ZINF_PREF(T,V) setDefault(k##T##Pref,V);
#include "prefs.def"
#undef ZINF_PREF

    // Initialize the library path structures
    GetLibPath();


    return kError_NoErr;


#if 0
    string buf;
    if (GetPrefString(kInstallDirPref, buf) == kError_NoPrefValue)
        SetPrefString(kInstallDirPref, string(UNIX_LIBDIR));

    // set default zinf library path value
    if (GetPrefString(kLibraryPathPref, buf) == kError_NoPrefValue)
        SetPrefString(kLibraryPathPref, string(kDefaultLibraryPath));
    
    // set default ui value
    if (GetPrefString(kUIPref, buf) == kError_NoPrefValue)
        SetPrefString(kUIPref, string(kDefaultUI));
    
    // set default text ui value
    if (GetPrefString(kTextUIPref, buf) == kError_NoPrefValue)
        SetPrefString(kTextUIPref, string(kDefaultTextUI));
    
    // set default pmo value
    if (GetPrefString(kPMOPref, buf) == kError_NoPrefValue)
        SetPrefString(kPMOPref, string(kDefaultPMO));

    // set default ALSA device
    if (GetPrefString(kALSADevicePref, buf) == kError_NoPrefValue)
        SetPrefString(kALSADevicePref, string(kDefaultALSADevice));
   
    // set default ESD host
    if (GetPrefString(kESOUNDHostPref, buf) == kError_NoPrefValue)
        SetPrefString(kESOUNDHostPref, string(kDefaultESOUNDHost));


    if (GetPrefString(kDatabaseDirPref, buf) == kError_NoPrefValue) {
        char *fadir = ZinfDir(NULL);
        string tempdir = fadir;
        tempdir += "/db/";
        SetPrefString(kDatabaseDirPref, tempdir.c_str());
        delete [] fadir;
    }

    if (GetPrefString(kSaveMusicDirPref, buf) == kError_NoPrefValue) {
        string tempdir = string(getenv("HOME"));
        tempdir += "/MyMusic";
        SetPrefString(kSaveMusicDirPref, tempdir);
    }

    if (GetPrefString(kWatchThisDirectoryPref, buf) == kError_NoPrefValue) 
    {
        string tempdir = string(getenv("HOME"));
        tempdir += "/MyMusic";
        SetPrefString(kWatchThisDirectoryPref, tempdir);
    }

    Preferences::SetDefaults();
    return kError_NoErr;
#endif
}

Error
UnixPrefs::
Save()
{
    string tmpFilePath;
    string bakFilePath;

    if (!m_saveEnable || !m_changed)
        return kError_NoErr;

    // XXX: We should check the modification date of the file,
    //      and refuse to save if it's been modified since we
    //      read it.

    m_changed = false;

    tmpFilePath = m_prefsFilePath;
    tmpFilePath += ".tmp";
    bakFilePath = m_prefsFilePath;
    bakFilePath += ".bak";

    {
        FILE *prefsFile = fopen(tmpFilePath.c_str(), "w");
        if (!prefsFile)
        {
            return kError_UnknownErr; // XXX: Be more informative
        }

        //m_mutex.Acquire();
                
        for (EntriesT::iterator entry = m_entries.begin(); 
             entry != m_entries.end(); entry++)
        {
          string outStr;
          fputs(entry->prefix.c_str(), prefsFile);
          outStr = WriteQuotableString(entry->key.c_str(), ":#");
          fputs(outStr.c_str(), prefsFile);
          fputs(entry->separator.c_str(), prefsFile);
          outStr = WriteQuotableString(entry->value.c_str(), "#");
          fputs(outStr.c_str(), prefsFile);
          fputs(entry->suffix.c_str(), prefsFile);
        }
        
        //m_mutex.Release();

        if (ferror(prefsFile))
        {
            fclose(prefsFile);
            return kError_UnknownErr; // XXX: Be more informative
        }
        
        fclose(prefsFile);
    }

    if (rename(m_prefsFilePath, bakFilePath.c_str()) && errno != ENOENT)
    {
        return kError_UnknownErr; // XXX: Be more informative
    }

    if (rename(tmpFilePath.c_str(), m_prefsFilePath))
        rename(bakFilePath.c_str(), m_prefsFilePath);

    return kError_NoErr;
}

Preferences *
UnixPrefs::
ComponentPrefs(const char *componentName)
{
    return new PrefixPrefs(this, componentName);
}

Error
UnixPrefs::
GetPrefString(const string& pref, string &buf)
{
  //m_mutex.Acquire();
    EntryMapT::iterator entry = m_ht.find (pref);
    if(entry == m_ht.end()){
      //m_mutex.Release();
        return kError_NoPrefValue;
    }
    buf = entry->second;
    m_mutex.Release();
    return kError_NoErr;
}

Error
UnixPrefs::
GetPrefString(const char* pref, char* buf, uint32_t* len)
{
  string buffer;
  Error err = GetPrefString (string(pref), buffer);
  if (err != kError_NoErr)
    return err;
  if (buffer.size() >= *len)
    return kError_BufferTooSmall;
                                                                                                        
  *len = buffer.size()+1;
  strncpy (buf, buffer.c_str(), buffer.size()+1);
  return kError_NoErr;
}

Error
UnixPrefs::SetPrefString (const string& pref, const string& buffer)
{
    UnixPrefEntry entry;

    entry.key = pref;
    entry.separator = ": ";
    entry.suffix = "\n";
    entry.value = buffer;
    
    //m_mutex.Acquire();

    m_ht[pref] = buffer;
    EntriesT::iterator ei= find (m_entries.begin(), m_entries.end(), entry);
    if (ei == m_entries.end()) 
      m_entries.push_back (entry);
    else
      *ei = entry;

    m_changed = true;

    //m_mutex.Release();
    return kError_NoErr;
}


Error
UnixPrefs::
SetPrefString(const char* pref, const char* buf)
{
  return SetPrefString (string(pref), string (buf));
}

//char *UnixPrefs::m_libDirs = NULL;

string
UnixPrefs::
GetLibPath()
{
    string path;
    char *env = getenv(ZINF_PATH_ENV);

    if (env == 0) 
        GetPrefString (ZINF_PREF_TAG(LibraryPath), path);
    else 
      path = env;
        

    m_libdirs = SplitPath (path);
#if 0
    //cerr << "LibraryPath is " << path << endl;
    string::size_type start = 0;
    string::size_type colon = 0;
    m_libdirs.clear();
    for (;;){
        colon = path.find(':', start);
        if (colon == string::npos)  break;
        //cerr << "Path is " << path.substr(start, colon-start) << endl;
        m_libdirs.push_back(path.substr (start, colon-start));
        start = colon+1;
    }
    if (path.substr(start).size() != 0)
        m_libdirs.push_back(path.substr (start));
#endif
    
    return path;
}



#if 0
LibDirFindHandle *
UnixPrefs::
GetFirstLibDir(char *path, uint32_t *len)
{
    // if no ZINF_PATH, use kLibraryPathPref
    // if ZINF_PATH, then its ZINF_PATH
    string pEnv = getenv(ZINF_PATH_ENV);
    string pPath;


    if (pEnv.size()) {
//      cout << "Using env: " << pEnv << endl;
        pPath = pEnv;
    } else {
        GetPrefString (ZINF_PREF_TAG(LibraryPath), pPath);
    }
    pEnv = pPath;
    LibDirFindHandle *hLibDirFind = new LibDirFindHandle();
    //    hLibDirFind->m_pLibDirs = new vector<char *>();
    hLibDirFind->m_pLibDirs = new vector<string>();
    hLibDirFind->m_current = 0;

    string::size_type start = 0;
    string::size_type colon = 0;
    for (;;){
        colon = pPath.find(':', start);
        if (colon == string::npos)  break;
        push_back(pPath.substr (start, colon-start));
        start = colon+1;
    }

    if (hLibDirFind->m_pLibDirs->size() > 0) {
        
        strncpy(path, hLibDirFind->m_pLibDirs)[0].c_str() , *len);
        *len = strlen(pPath);
    } else {
        *path = '\0';
        *len = 0;
        delete hLibDirFind->m_pLibDirs;
        delete hLibDirFind;
        hLibDirFind = 0;
    }

    if (pEnv) delete[] pEnv;

    //cout << "returning " << path << endl;
    return hLibDirFind;
}

Error
UnixPrefs::
GetNextLibDir(LibDirFindHandle *hLibDirFind, char *path, uint32_t *len)
{
    if (hLibDirFind) {
        if (++hLibDirFind->m_current < (int32_t)hLibDirFind->m_pLibDirs->size()) {
            char *pPath = (char*)(*hLibDirFind->m_pLibDirs)[hLibDirFind->m_current].c_str();
            strncpy(path,pPath,*len);
            *len = strlen(pPath);
//          cout << "returning next: " << path << endl;
            return kError_NoErr;
        }
        *path = '\0';
        *len = 0;
//      cout << "returning no next " << path << endl;
    }
    return kError_NoMoreLibDirs;
}

Error
UnixPrefs::
GetLibDirClose(LibDirFindHandle *hLibDirFind)
{
    if (hLibDirFind) {
//         while (hLibDirFind->m_pLibDirs->size() > 0)
//         {
//             delete (*(hLibDirFind->m_pLibDirs))[0];
//             hLibDirFind->m_pLibDirs->erase(hLibDirFind->m_pLibDirs->begin());
//         }
        delete hLibDirFind->m_pLibDirs;
        delete hLibDirFind;
    }
    return kError_NoErr;
}
#endif

/* arch-tag: 025980a1-92d0-474f-b6f6-ef7da2245ca1
   (do not change this comment) */

Generated by  Doxygen 1.6.0   Back to index