• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.10.4 API Reference
  • KDE Home
  • Contact Us
 

KDECore

  • kdecore
  • config
kconfigini.cpp
Go to the documentation of this file.
1 /*
2  This file is part of the KDE libraries
3  Copyright (c) 2006, 2007 Thomas Braxton <kde.braxton@gmail.com>
4  Copyright (c) 1999 Preston Brown <pbrown@kde.org>
5  Copyright (C) 1997-1999 Matthias Kalle Dalheimer (kalle@kde.org)
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Library General Public
9  License as published by the Free Software Foundation; either
10  version 2 of the License, or (at your option) any later version.
11 
12  This library is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  Library General Public License for more details.
16 
17  You should have received a copy of the GNU Library General Public License
18  along with this library; see the file COPYING.LIB. If not, write to
19  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  Boston, MA 02110-1301, USA.
21 */
22 
23 #include "kconfigini_p.h"
24 
25 #include "kconfig.h"
26 #include "kconfigbackend.h"
27 #include "bufferfragment_p.h"
28 #include "kconfigdata.h"
29 #include <ksavefile.h>
30 #include <kde_file.h>
31 #include "kstandarddirs.h"
32 
33 #include <qdatetime.h>
34 #include <qdir.h>
35 #include <qfile.h>
36 #include <qfileinfo.h>
37 #include <qdebug.h>
38 #include <qmetaobject.h>
39 #include <qregexp.h>
40 
41 extern bool kde_kiosk_exception;
42 
43 QString KConfigIniBackend::warningProlog(const QFile &file, int line)
44 {
45  return QString::fromLatin1("KConfigIni: In file %2, line %1: ")
46  .arg(line).arg(file.fileName());
47 }
48 
49 KConfigIniBackend::KConfigIniBackend()
50  : KConfigBackend()
51 {
52 }
53 
54 KConfigIniBackend::~KConfigIniBackend()
55 {
56 }
57 
58 KConfigBackend::ParseInfo
59  KConfigIniBackend::parseConfig(const QByteArray& currentLocale, KEntryMap& entryMap,
60  ParseOptions options)
61 {
62  return parseConfig(currentLocale, entryMap, options, false);
63 }
64 
65 KConfigBackend::ParseInfo
66 KConfigIniBackend::parseConfig(const QByteArray& currentLocale, KEntryMap& entryMap,
67  ParseOptions options, bool merging)
68 {
69  if (filePath().isEmpty() || !QFile::exists(filePath()))
70  return ParseOk;
71 
72  bool bDefault = options&ParseDefaults;
73  bool allowExecutableValues = options&ParseExpansions;
74 
75  QByteArray currentGroup("<default>");
76 
77  QFile file(filePath());
78  if (!file.open(QIODevice::ReadOnly|QIODevice::Text))
79  return ParseOpenError;
80 
81  QList<QByteArray> immutableGroups;
82 
83  bool fileOptionImmutable = false;
84  bool groupOptionImmutable = false;
85  bool groupSkip = false;
86 
87  int lineNo = 0;
88  // on systems using \r\n as end of line, \r will be taken care of by
89  // trim() below
90  QByteArray buffer = file.readAll();
91  BufferFragment contents(buffer.data(), buffer.size());
92  unsigned int len = contents.length();
93  unsigned int startOfLine = 0;
94 
95  while (startOfLine < len) {
96  BufferFragment line = contents.split('\n', &startOfLine);
97  line.trim();
98  lineNo++;
99 
100  // skip empty lines and lines beginning with '#'
101  if (line.isEmpty() || line.at(0) == '#')
102  continue;
103 
104  if (line.at(0) == '[') { // found a group
105  groupOptionImmutable = fileOptionImmutable;
106 
107  QByteArray newGroup;
108  int start = 1, end;
109  do {
110  end = start;
111  for (;;) {
112  if (end == line.length()) {
113  qWarning() << warningProlog(file, lineNo) << "Invalid group header.";
114  // XXX maybe reset the current group here?
115  goto next_line;
116  }
117  if (line.at(end) == ']')
118  break;
119  end++;
120  }
121  if (end + 1 == line.length() && start + 2 == end &&
122  line.at(start) == '$' && line.at(start + 1) == 'i')
123  {
124  if (newGroup.isEmpty())
125  fileOptionImmutable = !kde_kiosk_exception;
126  else
127  groupOptionImmutable = !kde_kiosk_exception;
128  }
129  else {
130  if (!newGroup.isEmpty())
131  newGroup += '\x1d';
132  BufferFragment namePart=line.mid(start, end - start);
133  printableToString(&namePart, file, lineNo);
134  newGroup += namePart.toByteArray();
135  }
136  } while ((start = end + 2) <= line.length() && line.at(end + 1) == '[');
137  currentGroup = newGroup;
138 
139  groupSkip = entryMap.getEntryOption(currentGroup, 0, 0, KEntryMap::EntryImmutable);
140 
141  if (groupSkip && !bDefault)
142  continue;
143 
144  if (groupOptionImmutable)
145  // Do not make the groups immutable until the entries from
146  // this file have been added.
147  immutableGroups.append(currentGroup);
148  } else {
149  if (groupSkip && !bDefault)
150  continue; // skip entry
151 
152  BufferFragment aKey;
153  int eqpos = line.indexOf('=');
154  if (eqpos < 0) {
155  aKey = line;
156  line.clear();
157  } else {
158  BufferFragment temp = line.left(eqpos);
159  temp.trim();
160  aKey = temp;
161  line.truncateLeft(eqpos + 1);
162  }
163  if (aKey.isEmpty()) {
164  qWarning() << warningProlog(file, lineNo) << "Invalid entry (empty key)";
165  continue;
166  }
167 
168  KEntryMap::EntryOptions entryOptions=0;
169  if (groupOptionImmutable)
170  entryOptions |= KEntryMap::EntryImmutable;
171 
172  BufferFragment locale;
173  int start;
174  while ((start = aKey.lastIndexOf('[')) >= 0) {
175  int end = aKey.indexOf(']', start);
176  if (end < 0) {
177  qWarning() << warningProlog(file, lineNo)
178  << "Invalid entry (missing ']')";
179  goto next_line;
180  } else if (end > start + 1 && aKey.at(start + 1) == '$') { // found option(s)
181  int i = start + 2;
182  while (i < end) {
183  switch (aKey.at(i)) {
184  case 'i':
185  if (!kde_kiosk_exception)
186  entryOptions |= KEntryMap::EntryImmutable;
187  break;
188  case 'e':
189  if (allowExecutableValues)
190  entryOptions |= KEntryMap::EntryExpansion;
191  break;
192  case 'd':
193  entryOptions |= KEntryMap::EntryDeleted;
194  aKey = aKey.left(start);
195  printableToString(&aKey, file, lineNo);
196  entryMap.setEntry(currentGroup, aKey.toByteArray(), QByteArray(), entryOptions);
197  goto next_line;
198  default:
199  break;
200  }
201  i++;
202  }
203  } else { // found a locale
204  if (!locale.isNull()) {
205  qWarning() << warningProlog(file, lineNo)
206  << "Invalid entry (second locale!?)";
207  goto next_line;
208  }
209 
210  locale = aKey.mid(start + 1,end - start - 1);
211  }
212  aKey.truncate(start);
213  }
214  if (eqpos < 0) { // Do this here after [$d] was checked
215  qWarning() << warningProlog(file, lineNo) << "Invalid entry (missing '=')";
216  continue;
217  }
218  printableToString(&aKey, file, lineNo);
219  if (!locale.isEmpty()) {
220  if (locale != currentLocale) {
221  // backward compatibility. C == en_US
222  if (locale.at(0) != 'C' || currentLocale != "en_US") {
223  if (merging)
224  entryOptions |= KEntryMap::EntryRawKey;
225  else
226  goto next_line; // skip this entry if we're not merging
227  }
228  }
229  }
230 
231  if (!(entryOptions & KEntryMap::EntryRawKey))
232  printableToString(&aKey, file, lineNo);
233 
234  if (options&ParseGlobal)
235  entryOptions |= KEntryMap::EntryGlobal;
236  if (bDefault)
237  entryOptions |= KEntryMap::EntryDefault;
238  if (!locale.isNull())
239  entryOptions |= KEntryMap::EntryLocalized;
240  printableToString(&line, file, lineNo);
241  if (entryOptions & KEntryMap::EntryRawKey) {
242  QByteArray rawKey;
243  rawKey.reserve(aKey.length() + locale.length() + 2);
244  rawKey.append(aKey.toVolatileByteArray());
245  rawKey.append('[').append(locale.toVolatileByteArray()).append(']');
246  entryMap.setEntry(currentGroup, rawKey, line.toByteArray(), entryOptions);
247  } else {
248  entryMap.setEntry(currentGroup, aKey.toByteArray(), line.toByteArray(), entryOptions);
249  }
250  }
251 next_line:
252  continue;
253  }
254 
255  // now make sure immutable groups are marked immutable
256  foreach(const QByteArray& group, immutableGroups) {
257  entryMap.setEntry(group, QByteArray(), QByteArray(), KEntryMap::EntryImmutable);
258  }
259 
260  return fileOptionImmutable ? ParseImmutable : ParseOk;
261 }
262 
263 void KConfigIniBackend::writeEntries(const QByteArray& locale, QFile& file,
264  const KEntryMap& map, bool defaultGroup, bool &firstEntry)
265 {
266  QByteArray currentGroup;
267  bool groupIsImmutable = false;
268  const KEntryMapConstIterator end = map.constEnd();
269  for (KEntryMapConstIterator it = map.constBegin(); it != end; ++it) {
270  const KEntryKey& key = it.key();
271 
272  // Either process the default group or all others
273  if ((key.mGroup != "<default>") == defaultGroup)
274  continue; // skip
275 
276  // the only thing we care about groups is, is it immutable?
277  if (key.mKey.isNull()) {
278  groupIsImmutable = it->bImmutable;
279  continue; // skip
280  }
281 
282  const KEntry& currentEntry = *it;
283  if (!defaultGroup && currentGroup != key.mGroup) {
284  if (!firstEntry)
285  file.putChar('\n');
286  currentGroup = key.mGroup;
287  for (int start = 0, end;; start = end + 1) {
288  file.putChar('[');
289  end = currentGroup.indexOf('\x1d', start);
290  if (end < 0) {
291  int cgl = currentGroup.length();
292  if (currentGroup.at(start) == '$' && cgl - start <= 10) {
293  for (int i = start + 1; i < cgl; i++) {
294  char c = currentGroup.at(i);
295  if (c < 'a' || c > 'z')
296  goto nope;
297  }
298  file.write("\\x24");
299  start++;
300  }
301  nope:
302  file.write(stringToPrintable(currentGroup.mid(start), GroupString));
303  file.putChar(']');
304  if (groupIsImmutable) {
305  file.write("[$i]", 4);
306  }
307  file.putChar('\n');
308  break;
309  } else {
310  file.write(stringToPrintable(currentGroup.mid(start, end - start), GroupString));
311  file.putChar(']');
312  }
313  }
314  }
315 
316  firstEntry = false;
317  // it is data for a group
318 
319  if (key.bRaw) // unprocessed key with attached locale from merge
320  file.write(key.mKey);
321  else {
322  file.write(stringToPrintable(key.mKey, KeyString)); // Key
323  if (key.bLocal && locale != "C") { // 'C' locale == untranslated
324  file.putChar('[');
325  file.write(locale); // locale tag
326  file.putChar(']');
327  }
328  }
329  if (currentEntry.bDeleted) {
330  if (currentEntry.bImmutable)
331  file.write("[$di]", 5); // Deleted + immutable
332  else
333  file.write("[$d]", 4); // Deleted
334  } else {
335  if (currentEntry.bImmutable || currentEntry.bExpand) {
336  file.write("[$", 2);
337  if (currentEntry.bImmutable)
338  file.putChar('i');
339  if (currentEntry.bExpand)
340  file.putChar('e');
341  file.putChar(']');
342  }
343  file.putChar('=');
344  file.write(stringToPrintable(currentEntry.mValue, ValueString));
345  }
346  file.putChar('\n');
347  }
348 }
349 
350 void KConfigIniBackend::writeEntries(const QByteArray& locale, QFile& file, const KEntryMap& map)
351 {
352  bool firstEntry = true;
353 
354  // write default group
355  writeEntries(locale, file, map, true, firstEntry);
356 
357  // write all other groups
358  writeEntries(locale, file, map, false, firstEntry);
359 }
360 
361 bool KConfigIniBackend::writeConfig(const QByteArray& locale, KEntryMap& entryMap,
362  WriteOptions options, const KComponentData &data)
363 {
364  Q_ASSERT(!filePath().isEmpty());
365 
366  KEntryMap writeMap;
367  const bool bGlobal = options & WriteGlobal;
368 
369  // First, reparse the file on disk, to merge our changes with the ones done by other apps
370  {
371  ParseOptions opts = ParseExpansions;
372  if (bGlobal)
373  opts |= ParseGlobal;
374  ParseInfo info = parseConfig(locale, writeMap, opts, true);
375  if (info != ParseOk) // either there was an error or the file became immutable
376  return false;
377  }
378 
379  const KEntryMapIterator end = entryMap.end();
380  for (KEntryMapIterator it=entryMap.begin(); it != end; ++it) {
381  if (!it.key().mKey.isEmpty() && !it->bDirty) // not dirty, doesn't overwrite entry in writeMap. skips default entries, too.
382  continue;
383 
384  const KEntryKey& key = it.key();
385 
386  // only write entries that have the same "globality" as the file
387  if (it->bGlobal == bGlobal) {
388  if (!it->bDeleted) {
389  writeMap[key] = *it;
390  } else {
391  KEntryKey defaultKey = key;
392  defaultKey.bDefault = true;
393  if (!entryMap.contains(defaultKey)) {
394  writeMap.remove(key); // remove the deleted entry if there is no default
395  //qDebug() << "Detected as deleted=>removed:" << key.mGroup << key.mKey << "global=" << bGlobal;
396  } else {
397  writeMap[key] = *it; // otherwise write an explicitly deleted entry
398  //qDebug() << "Detected as deleted=>[$d]:" << key.mGroup << key.mKey << "global=" << bGlobal;
399  }
400  }
401  it->bDirty = false;
402  }
403  }
404 
405  // now writeMap should contain only entries to be written
406  // so write it out to disk
407 
408  // check if file exists
409  QFile::Permissions fileMode = QFile::ReadUser | QFile::WriteUser;
410  bool createNew = true;
411 
412  QFileInfo fi(filePath());
413  if (fi.exists())
414  {
415  if (fi.ownerId() == ::getuid())
416  {
417  // Preserve file mode if file exists and is owned by user.
418  fileMode = fi.permissions();
419  }
420  else
421  {
422  // File is not owned by user:
423  // Don't create new file but write to existing file instead.
424  createNew = false;
425  }
426  }
427 
428  if (createNew) {
429  KSaveFile file( filePath(), data );
430  if (!file.open()) {
431  return false;
432  }
433 
434  file.setPermissions(fileMode);
435 
436  file.setTextModeEnabled(true); // to get eol translation
437  writeEntries(locale, file, writeMap);
438 
439  if (!file.flush()) {
440  // Couldn't write. Disk full?
441  kWarning() << "Couldn't write" << filePath() << ". Disk full?";
442  file.abort();
443  return false;
444  }
445 
446  if (!file.size() && (fileMode == (QFile::ReadUser | QFile::WriteUser))) {
447  // File is empty and doesn't have special permissions: delete it.
448  file.abort();
449 
450  if (fi.exists()) {
451  // also remove the old file in case it existed. this can happen
452  // when we delete all the entries in an existing config file.
453  // if we don't do this, then deletions and revertToDefault's
454  // will mysteriously fail
455  QFile::remove(filePath());
456  }
457  } else {
458  // Normal case: Close the file
459  return file.finalize();
460  }
461  } else {
462  // Open existing file. *DON'T* create it if it suddenly does not exist!
463 #ifdef Q_OS_UNIX
464  int fd = KDE_open(QFile::encodeName(filePath()), O_WRONLY | O_TRUNC);
465  if (fd < 0) {
466  return false;
467  }
468  FILE *fp = KDE_fdopen(fd, "w");
469  if (!fp) {
470  close(fd);
471  return false;
472  }
473  QFile f;
474  if (!f.open(fp, QIODevice::WriteOnly)) {
475  fclose(fp);
476  return false;
477  }
478  writeEntries(locale, f, writeMap);
479  f.close();
480  fclose(fp);
481 #else
482  QFile f( filePath() );
483  // XXX This is broken - it DOES create the file if it is suddenly gone.
484  if (!f.open( QIODevice::WriteOnly | QIODevice::Truncate )) {
485  return false;
486  }
487  f.setTextModeEnabled(true);
488  writeEntries(locale, f, writeMap);
489 #endif
490  }
491  return true;
492 }
493 
494 bool KConfigIniBackend::isWritable() const
495 {
496  if (!filePath().isEmpty()) {
497  if (KStandardDirs::checkAccess(filePath(), W_OK)) {
498  return true;
499  }
500  // The check might have failed because any of the containing dirs
501  // did not exist. If the file does not exist, check if the deepest
502  // existing dir is writable.
503  QFileInfo file(filePath());
504  if (!file.exists()) {
505  QFileInfo dir(file.absolutePath());
506  while (!dir.exists()) {
507  QString parent = dir.absolutePath(); // Go up. Can't use cdUp() on non-existing dirs.
508  if (parent == dir.filePath()) {
509  // no parent
510  return false;
511  }
512  dir.setFile(parent);
513  }
514  return dir.isDir() && dir.isWritable();
515  }
516  }
517 
518  return false;
519 }
520 
521 QString KConfigIniBackend::nonWritableErrorMessage() const
522 {
523  return i18n("Configuration file \"%1\" not writable.\n", filePath());
524 }
525 
526 void KConfigIniBackend::createEnclosing()
527 {
528  const QString file = filePath();
529  if (file.isEmpty())
530  return; // nothing to do
531 
532  // Create the containing dir, maybe it wasn't there
533  QDir dir;
534  dir.mkpath(QFileInfo(file).absolutePath());
535 }
536 
537 void KConfigIniBackend::setFilePath(const QString& file)
538 {
539  if (file.isEmpty())
540  return;
541 
542  Q_ASSERT(QDir::isAbsolutePath(file));
543 
544  const QFileInfo info(file);
545  if (info.exists()) {
546  setLocalFilePath(info.canonicalFilePath());
547  setLastModified(info.lastModified());
548  setSize(info.size());
549  } else {
550  setLocalFilePath(file);
551  setSize(0);
552  QDateTime dummy;
553  dummy.setTime_t(0);
554  setLastModified(dummy);
555  }
556 }
557 
558 KConfigBase::AccessMode KConfigIniBackend::accessMode() const
559 {
560  if (filePath().isEmpty())
561  return KConfigBase::NoAccess;
562 
563  if (isWritable())
564  return KConfigBase::ReadWrite;
565 
566  return KConfigBase::ReadOnly;
567 }
568 
569 bool KConfigIniBackend::lock(const KComponentData& componentData)
570 {
571  Q_ASSERT(!filePath().isEmpty());
572 
573  if (!lockFile) {
574  lockFile = new KLockFile(filePath() + QLatin1String(".lock"), componentData);
575  }
576 
577  if (lockFile->lock() == KLockFile::LockStale) // attempt to break the lock
578  lockFile->lock(KLockFile::ForceFlag);
579  return lockFile->isLocked();
580 }
581 
582 void KConfigIniBackend::unlock()
583 {
584  lockFile->unlock();
585  lockFile.clear();
586 }
587 
588 bool KConfigIniBackend::isLocked() const
589 {
590  return lockFile && lockFile->isLocked();
591 }
592 
593 QByteArray KConfigIniBackend::stringToPrintable(const QByteArray& aString, StringType type)
594 {
595  static const char nibbleLookup[] = {
596  '0', '1', '2', '3', '4', '5', '6', '7',
597  '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
598  };
599 
600  if (aString.isEmpty())
601  return aString;
602  const int l = aString.length();
603 
604  QByteArray result; // Guesstimated that it's good to avoid data() initialization for a length of l*4
605  result.resize(l * 4); // Maximum 4x as long as source string due to \x<ab> escape sequences
606  register const char *s = aString.constData();
607  int i = 0;
608  char *data = result.data();
609  char *start = data;
610 
611  // Protect leading space
612  if (s[0] == ' ' && type != GroupString) {
613  *data++ = '\\';
614  *data++ = 's';
615  i++;
616  }
617 
618  for (; i < l; ++i/*, r++*/) {
619  switch (s[i]) {
620  default:
621  // The \n, \t, \r cases (all < 32) are handled below; we can ignore them here
622  if (((unsigned char)s[i]) < 32)
623  goto doEscape;
624  *data++ = s[i];
625  break;
626  case '\n':
627  *data++ = '\\';
628  *data++ = 'n';
629  break;
630  case '\t':
631  *data++ = '\\';
632  *data++ = 't';
633  break;
634  case '\r':
635  *data++ = '\\';
636  *data++ = 'r';
637  break;
638  case '\\':
639  *data++ = '\\';
640  *data++ = '\\';
641  break;
642  case '=':
643  if (type != KeyString) {
644  *data++ = s[i];
645  break;
646  }
647  goto doEscape;
648  case '[':
649  case ']':
650  // Above chars are OK to put in *value* strings as plaintext
651  if (type == ValueString) {
652  *data++ = s[i];
653  break;
654  }
655  doEscape:
656  *data++ = '\\';
657  *data++ = 'x';
658  *data++ = nibbleLookup[((unsigned char)s[i]) >> 4];
659  *data++ = nibbleLookup[((unsigned char)s[i]) & 0x0f];
660  break;
661  }
662  }
663  *data = 0;
664  result.resize(data - start);
665 
666  // Protect trailing space
667  if (result.endsWith(' ') && type != GroupString) {
668  result.replace(result.length() - 1, 1, "\\s");
669  }
670  result.squeeze();
671 
672  return result;
673 }
674 
675 char KConfigIniBackend::charFromHex(const char *str, const QFile& file, int line)
676 {
677  unsigned char ret = 0;
678  for (int i = 0; i < 2; i++) {
679  ret <<= 4;
680  quint8 c = quint8(str[i]);
681 
682  if (c >= '0' && c <= '9') {
683  ret |= c - '0';
684  } else if (c >= 'a' && c <= 'f') {
685  ret |= c - 'a' + 0x0a;
686  } else if (c >= 'A' && c <= 'F') {
687  ret |= c - 'A' + 0x0a;
688  } else {
689  QByteArray e(str, 2);
690  e.prepend("\\x");
691  qWarning() << warningProlog(file, line) << "Invalid hex character " << c
692  << " in \\x<nn>-type escape sequence \"" << e.constData() << "\".";
693  return 'x';
694  }
695  }
696  return char(ret);
697 }
698 
699 void KConfigIniBackend::printableToString(BufferFragment* aString, const QFile& file, int line)
700 {
701  if (aString->isEmpty() || aString->indexOf('\\')==-1)
702  return;
703  aString->trim();
704  int l = aString->length();
705  char *r = aString->data();
706  char *str=r;
707 
708  for(int i = 0; i < l; i++, r++) {
709  if (str[i]!= '\\') {
710  *r=str[i];
711  } else {
712  // Probable escape sequence
713  i++;
714  if (i >= l) { // Line ends after backslash - stop.
715  *r = '\\';
716  break;
717  }
718 
719  switch(str[i]) {
720  case 's':
721  *r = ' ';
722  break;
723  case 't':
724  *r = '\t';
725  break;
726  case 'n':
727  *r = '\n';
728  break;
729  case 'r':
730  *r = '\r';
731  break;
732  case '\\':
733  *r = '\\';
734  break;
735  case 'x':
736  if (i + 2 < l) {
737  *r = charFromHex(str + i + 1, file, line);
738  i += 2;
739  } else {
740  *r = 'x';
741  i = l - 1;
742  }
743  break;
744  default:
745  *r = '\\';
746  qWarning() << warningProlog(file, line)
747  << QString::fromLatin1("Invalid escape sequence \"\\%1\".").arg(str[i]);
748  }
749  }
750  }
751  aString->truncate(r - aString->constData());
752 }
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Sat Jun 1 2013 12:05:01 by doxygen 1.8.1.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDECore

Skip menu "KDECore"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs-4.10.4 API Reference

Skip menu "kdelibs-4.10.4 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal