Switch commoncpp2 to ucommon to solve dependency conflicts.
libccrtp was depending on commoncpp2, and have been replaced by a version
depending on ucommon as well.
diff --git a/jni/libucommon/sources/inc/commoncpp/file.h b/jni/libucommon/sources/inc/commoncpp/file.h
new file mode 100644
index 0000000..4e2dd6d
--- /dev/null
+++ b/jni/libucommon/sources/inc/commoncpp/file.h
@@ -0,0 +1,901 @@
+// Copyright (C) 1999-2005 Open Source Telecom Corporation.
+// Copyright (C) 2006-2010 David Sugar, Tycho Softworks.
+//
+// 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+// This exception applies only to the code released under the name GNU
+// Common C++. If you copy code from other releases into a copy of GNU
+// Common C++, as the General Public License permits, the exception does
+// not apply to the code that you add in this way. To avoid misleading
+// anyone as to the status of such modified files, you must delete
+// this exception notice from them.
+//
+// If you write modifications of your own for GNU Common C++, it is your choice
+// whether to permit this exception to apply to your modifications.
+// If you do not wish that, delete this exception notice.
+//
+
+/**
+ * @file file.h
+ * @short Files and dynamic loader services.
+ **/
+
+#ifndef COMMONCPP_FILE_H_
+#define COMMONCPP_FILE_H_
+
+#ifndef COMMONCPP_CONFIG_H_
+#include <commoncpp/config.h>
+#endif
+
+#ifndef COMMONCPP_THREAD_H_
+#include <commoncpp/thread.h>
+#endif
+
+#ifndef COMMONCPP_EXCEPTION_H_
+#include <commoncpp/exception.h>
+#endif
+
+#ifndef WIN32
+# ifdef __BORLANDC__
+# include <stdio.h>
+# include <sys/types.h>
+# else
+# include <fcntl.h>
+# include <cstdio>
+# endif
+# include <dirent.h>
+# include <sys/stat.h>
+# include <sys/mman.h>
+#else
+# if __BORLANDC__ >= 0x0560
+# include <dirent.h>
+# include <sys/stat.h>
+# else
+# include <direct.h>
+# endif
+#endif
+
+NAMESPACE_COMMONCPP
+
+typedef unsigned long pos_t;
+#ifndef _MSWINDOWS_
+// use a define so that if the sys/types.h header already defines caddr_t
+// as it may on BSD systems, we do not break it by redefining again.
+#undef caddr_t
+#define caddr_t char *
+typedef size_t ccxx_size_t;
+#else
+typedef DWORD ccxx_size_t;
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX 256
+#endif
+
+#ifndef NAME_MAX
+#define NAME_MAX 64
+#endif
+
+class __EXPORT File
+{
+public:
+ enum Error {
+ errSuccess = 0,
+ errNotOpened,
+ errMapFailed,
+ errInitFailed,
+ errOpenDenied,
+ errOpenFailed,
+ errOpenInUse,
+ errReadInterrupted,
+ errReadIncomplete,
+ errReadFailure,
+ errWriteInterrupted,
+ errWriteIncomplete,
+ errWriteFailure,
+ errLockFailure,
+ errExtended
+ };
+ typedef enum Error Error;
+
+ enum Access {
+#ifndef _MSWINDOWS_
+ accessReadOnly = O_RDONLY,
+ accessWriteOnly= O_WRONLY,
+ accessReadWrite = O_RDWR
+#else
+ accessReadOnly = GENERIC_READ,
+ accessWriteOnly = GENERIC_WRITE,
+ accessReadWrite = GENERIC_READ | GENERIC_WRITE
+#endif
+ };
+ typedef enum Access Access;
+
+protected:
+ typedef struct _fcb {
+ struct _fcb *next;
+ caddr_t address;
+ ccxx_size_t len;
+ off_t pos;
+ bool locked;
+ } fcb_t;
+
+public:
+#ifdef _MSWINDOWS_
+ enum Open {
+ openReadOnly, // = FILE_OPEN_READONLY,
+ openWriteOnly, // = FILE_OPEN_WRITEONLY,
+ openReadWrite, // = FILE_OPEN_READWRITE,
+ openAppend, // = FILE_OPEN_APPEND,
+ openTruncate // = FILE_OPEN_TRUNCATE
+ };
+#else
+ enum Open {
+ openReadOnly = O_RDONLY,
+ openWriteOnly = O_WRONLY,
+ openReadWrite = O_RDWR,
+ openAppend = O_WRONLY | O_APPEND,
+#ifdef O_SYNC
+ openSync = O_RDWR | O_SYNC,
+#else
+ openSync = O_RDWR,
+#endif
+ openTruncate = O_RDWR | O_TRUNC
+ };
+ typedef enum Open Open;
+
+/* to be used in future */
+
+#ifndef S_IRUSR
+#define S_IRUSR 0400
+#define S_IWUSR 0200
+#define S_IRGRP 0040
+#define S_IWGRP 0020
+#define S_IROTH 0004
+#define S_IWOTH 0002
+#endif
+
+#endif // !WIN32
+
+#ifndef _MSWINDOWS_
+ enum Attr {
+ attrInvalid = 0,
+ attrPrivate = S_IRUSR | S_IWUSR,
+ attrGroup = attrPrivate | S_IRGRP | S_IWGRP,
+ attrPublic = attrGroup | S_IROTH | S_IWOTH
+ };
+#else // defined WIN32
+ enum Attr {
+ attrInvalid=0,
+ attrPrivate,
+ attrGroup,
+ attrPublic
+ };
+#endif // !WIN32
+ typedef enum Attr Attr;
+
+#ifdef _MSWINDOWS_
+ enum Complete {
+ completionImmediate, // = FILE_COMPLETION_IMMEDIATE,
+ completionDelayed, // = FILE_COMPLETION_DELAYED,
+ completionDeferred // = FILE_COMPLETION_DEFERRED
+ };
+
+ enum Mapping {
+ mappedRead,
+ mappedWrite,
+ mappedReadWrite
+ };
+#else
+ enum Mapping {
+ mappedRead = accessReadOnly,
+ mappedWrite = accessWriteOnly,
+ mappedReadWrite = accessReadWrite
+ };
+ enum Complete {
+ completionImmediate,
+ completionDelayed,
+ completionDeferred
+ };
+#endif
+ typedef enum Complete Complete;
+ typedef enum Mapping Mapping;
+
+public:
+ static const char *getExtension(const char *path);
+ static const char *getFilename(const char *path);
+ static char *getFilename(const char *path, char *buffer, size_t size = NAME_MAX);
+ static char *getDirname(const char *path, char *buffer, size_t size = PATH_MAX);
+ static char *getRealpath(const char *path, char *buffer, size_t size = PATH_MAX);
+};
+
+/**
+ * A low level portable directory class. Used to support ccstd Directory
+ * container. This provides a basic mechanism for allocating and
+ * accessing file entries.
+ *
+ * @author David Sugar <dyfet@ostel.com>
+ * @short low level directory access class.
+ */
+class __EXPORT Dir : public File
+{
+private:
+#ifndef _MSWINDOWS_
+ DIR *dir;
+ struct dirent *save;
+ char save_space[sizeof(struct dirent) + PATH_MAX + 1];
+ struct dirent *entry;
+#else
+ HANDLE hDir;
+ WIN32_FIND_DATA data, fdata;
+ char *name;
+#endif
+
+public:
+ Dir(const char *name = NULL);
+
+ static bool create(const char *path, Attr attr = attrGroup);
+ static bool remove(const char *path);
+ static bool setPrefix(const char *path);
+ static bool getPrefix(char *path, size_t size = PATH_MAX);
+
+ void open(const char *name);
+ void close(void);
+
+ virtual ~Dir();
+
+ const char *getName(void);
+
+ const char *operator++()
+ {return getName();};
+
+ const char *operator++(int)
+ {return getName();};
+
+ const char *operator*();
+
+ bool rewind(void);
+
+ bool operator!()
+#ifndef _MSWINDOWS_
+ {return !dir;};
+#else
+ {return hDir != INVALID_HANDLE_VALUE;};
+#endif
+
+ bool isValid(void);
+};
+
+/**
+ * A generic class to walk a hierarchical directory structure.
+ *
+ * @author David Sugar <dyfet@ostel.com>
+ * @short Directory tree walking.
+ */
+class __EXPORT DirTree
+{
+private:
+ char path[PATH_MAX + 1];
+ Dir *dir;
+ unsigned max, current, prefixpos;
+
+protected:
+ /**
+ * Virtual method to filter results. Virtual override methods
+ * should call baseclass method to assure . and .. names are
+ * stripped out.
+ *
+ * @return true if current filename is accepted.
+ * @param file path to examine
+ * @param ino info of type, date, etc.
+ */
+ virtual bool filter(const char *file, struct stat *ino);
+
+public:
+ /**
+ * Construct a directory tree walk starting at the specified
+ * prefix. A maximum subdirectory depth is also specified.
+ *
+ * @param prefix to start walk.
+ * @param maxdepth subdirectory depth to examine.
+ */
+ DirTree(const char *prefix, unsigned maxdepth);
+
+ /**
+ * Construct an un-opened directory tree of a known maximum depth
+ *
+ * @param maxdepth subdirectory subdirectory depth.
+ */
+ DirTree(unsigned maxdepth);
+
+ virtual ~DirTree();
+
+ /**
+ * Open a directory tree path.
+ *
+ * @param prefix directory path to open.
+ */
+ void open(const char *prefix);
+
+ /**
+ * Close the directory path.
+ */
+ void close(void);
+
+ /**
+ * Extract the next full pathname from the directory walk.
+ * When returning directories, a '/' is appended. The
+ * returned string is a buffer of MAX_PATH size.
+ *
+ * @return path of next subdirectory entry or NULL.
+ */
+ char *getPath(void);
+
+ /**
+ * This is used to step through the filter virtual for an
+ * entire subtree, and is used for cases where a derived
+ * DirTree class performs it's primary operations through
+ * filter rather than externally by calling getPath().
+ *
+ * @return number of files and directories examined.
+ * @param prefix directory path to examine.
+ */
+ unsigned perform(const char *prefix);
+};
+
+/**
+ * The purpose of this class is to define a base class for low level
+ * random file access that is portable between Win32 and Posix systems.
+ * This class is a foundation both for optimized thread shared and
+ * traditional locked file access that is commonly used to build
+ * database services, rather than the standard C++ streaming file classes.
+ *
+ * @author David Sugar <dyfet@ostel.com>
+ * @short Portable random disk file access.
+ */
+class __EXPORT RandomFile : protected Mutex, public File
+{
+private:
+ Error errid;
+ char *errstr;
+
+protected:
+#ifndef _MSWINDOWS_
+ int fd;
+ // FIXME: WIN32 as no access member
+ Access access;
+#else
+ HANDLE fd;
+#endif
+ char *pathname;
+
+ struct {
+ unsigned count : 16;
+ bool thrown : 1;
+ bool initial : 1;
+#ifndef _MSWINDOWS_
+ bool immediate : 1;
+#endif
+ bool temp : 1;
+ } flags;
+
+ /**
+ * Create an unopened random access file.
+ */
+ RandomFile(const char *name = NULL);
+
+ /**
+ * Default copy constructor.
+ */
+ RandomFile(const RandomFile &rf);
+
+ /**
+ * Post an error event.
+ *
+ * @return error code.
+ * @param errid error code.
+ * @param errstr error message string.
+ */
+ Error error(Error errid, char *errstr = NULL);
+
+ /**
+ * Post an extended string error message.
+ *
+ * @return errExtended.
+ * @param err error string.
+ */
+ inline Error error(char *err)
+ {return error(errExtended, err);};
+
+ /**
+ * Used to enable or disable throwing of exceptions on
+ * errors.
+ *
+ * @param enable true if errors will be thrown.
+ */
+ inline void setError(bool enable)
+ {flags.thrown = !enable;};
+
+#ifndef _MSWINDOWS_
+ /**
+ * Used to set file completion modes.
+ *
+ * @return errSuccess if okay.
+ * @param mode completion mode.
+ * @todo implement in win32
+ */
+ Error setCompletion(Complete mode);
+#endif
+
+ /**
+ * Used to set the temporary attribute for the file. Temporary
+ * files are automatically deleted when closed.
+ *
+ * @param enable true for marking as temporary.
+ */
+ inline void setTemporary(bool enable)
+ {flags.temp = enable;};
+
+ /**
+ * This method is used to initialize a newly created file as
+ * indicated by the "initial" flag. This method also returns
+ * the file access permissions that should be associated with
+ * the file. This method should never be called directly, but
+ * is instead used to impliment the "Initial" method. Typically
+ * one would use this to build an empty database shell when a
+ * previously empty database file is created.
+ *
+ * @return access, or attrInvalid if should be removed.
+ */
+ virtual Attr initialize(void);
+
+ /**
+ * Close the file.
+ */
+ void final(void);
+
+public:
+ /**
+ * Destroy a random access file or it's derived class.
+ */
+ virtual ~RandomFile();
+
+ /**
+ * This method should be called right after a RandomFile derived
+ * object has been created. This method will invoke initialize
+ * if the object is newly created, and set file access permissions
+ * appropriately.
+ *
+ * @return true if file had to be initialized.
+ */
+ bool initial(void);
+
+ /**
+ * Get current file capacity.
+ *
+ * @return total file size.
+ */
+ off_t getCapacity(void);
+
+ /**
+ * This method is commonly used to close and re-open an existing
+ * database. This may be used when the database has been unlinked
+ * and an external process provides a new one to use.
+ */
+ virtual Error restart(void);
+
+ /**
+ * Return current error id.
+ *
+ * @return last error identifier set.
+ */
+ inline Error getErrorNumber(void)
+ {return errid;};
+
+ /**
+ * Return current error string.
+ *
+ * @return last error string set.
+ */
+ inline char *getErrorString(void)
+ {return errstr;};
+
+ bool operator!(void);
+};
+
+/**
+ * This class defines a database I/O file service that can be shared
+ * by multiple processes. Each thread should access a dup of the database
+ * object, and mutex locks can be used to preserve transaction
+ * integrety if multiple threads are used.
+ *
+ * SharedFile is used when a database may be shared between multiple
+ * processes. SharedFile automatically applies low level byte-range "file
+ * locks", and provides an interface to fetch and release byte-range locked
+ * portions of a file.
+ *
+ * @author David Sugar <dyfet@ostel.com>
+ * @short This class defines a database I/O file service that can be shared by multiple processes.
+ */
+class __EXPORT SharedFile : public RandomFile
+{
+private:
+ fcb_t fcb;
+ Error open(const char *path);
+
+public:
+ /**
+ * Open or create a new database file. You should also use
+ * Initial.
+ *
+ * @param path pathname of database to open.
+ */
+ SharedFile(const char *path);
+
+ /**
+ * Create a shared file as a duplicate of an existing shared
+ * file.
+ *
+ * @param file original file.
+ */
+ SharedFile(const SharedFile &file);
+
+ /**
+ * Close and finish a database file.
+ */
+ virtual ~SharedFile();
+
+ /**
+ * Restart an existing database; close and re-open.
+ *
+ * @return errSuccess if successful.
+ */
+ Error restart(void)
+ {return open(pathname);};
+
+ /**
+ * Lock and Fetch a portion of the file into physical memory.
+ * This can use state information to fetch the current record
+ * multiple times.
+ *
+ * @return errSuccess on success.
+ * @param address address to use, or NULL if same as last I/O.
+ * @param length length to use, or 0 if same as last I/O.
+ * @param position file position to use -1 if same as last I/O.
+ */
+ Error fetch(caddr_t address = NULL, ccxx_size_t length = 0, off_t position = -1);
+
+ /**
+ * Update a portion of a file from physical memory. This can use
+ * state information to commit the last read record. The current
+ * lock is also cleared.
+ *
+ * @return errSuccess on success.
+ * @param address address to use, or NULL if same as last I/O.
+ * @param length length to use, or 0 if same as last I/O.
+ * @param position file position to use or -1 if same as last I/O.
+ */
+ Error update(caddr_t address = NULL, ccxx_size_t length = 0, off_t position = -1);
+
+ /**
+ * Clear a lock held from a previous fetch operation without
+ * updating.
+ *
+ * @return errSuccess on success.
+ * @param length length to use, or 0 if same as last I/O.
+ * @param pos file position to use or -1 if same as last I/O.
+ */
+ Error clear(ccxx_size_t length = 0, off_t pos = -1);
+
+ /**
+ * Add new data to the end of the file. Locks file during append.
+ *
+ * @param address address to use, or NULL if same as last I/O.
+ * @param length length to use, or 0 if same as last I/O.
+ */
+ Error append(caddr_t address = NULL, ccxx_size_t length = 0);
+
+ /**
+ * Fetch the current file position marker for this thread.
+ *
+ * @return file position offset.
+ */
+ off_t getPosition(void);
+
+ bool operator++(void);
+ bool operator--(void);
+};
+
+/**
+ * Create and map a disk file into memory. This portable class works
+ * under both Posix via mmap and under the win32 API. A mapped file
+ * can be referenced directly by it's memory segment. One can map
+ * and unmap portions of a file on demand, and update
+ * changed memory pages mapped from files immediately through sync().
+ *
+ * @author David Sugar <dyfet@ostel.com>
+ * @short Map a named disk file into memory.
+ */
+class __EXPORT MappedFile : public RandomFile
+{
+private:
+ fcb_t fcb;
+ int prot;
+#ifdef _MSWINDOWS_
+ HANDLE map;
+ char mapname[64];
+#endif
+
+public:
+ /**
+ * Open a file for mapping. More than one segment of a file
+ * may be mapped into seperate regions of memory.
+ *
+ * @param fname file name to access for mapping.
+ * @param mode access mode to map file.
+ */
+ MappedFile(const char *fname, Access mode);
+
+ /**
+ * Create if not exists, and map a file of specified size
+ * into memory.
+ *
+ * @param fname file name to access for mapping.
+ * @param mode access mode to map file.
+ * @param size of file to map.
+ */
+ MappedFile(const char *fname, Access mode, size_t size);
+
+ /**
+ * Map a portion or all of a specified file in the specified
+ * shared memory access mode. Valid mapping modes include
+ * mappedRead, mappedWrite, and mappedReadWrite.
+ *
+ * @param fname pathname of file to map into memory.
+ * @param offset from start of file to begin mapping in bytes.
+ * @param size of mapped area in bytes.
+ * @param mode to map file.
+ */
+ MappedFile(const char *fname, pos_t offset, size_t size, Access mode);
+
+ /**
+ * Release a mapped section of memory associated with a file. The
+ * mapped area is updated back to disk.
+ */
+ virtual ~MappedFile();
+
+ // FIXME: not use library function in header ??
+ /**
+ * Synchronize the contents of the mapped portion of memory with
+ * the disk file and wait for completion. This assures the memory
+ * mapped from the file is written back.
+ */
+ void sync(void);
+
+ /**
+ * Synchronize a segment of memory mapped from a segment fetch.
+ *
+ * @param address memory address to update.
+ * @param len size of segment.
+ */
+ void sync(caddr_t address, size_t len);
+
+ /**
+ * Map a portion of the memory mapped from the file back to the
+ * file and do not wait for completion. This is useful when mapping
+ * a database file and updating a single record.
+ *
+ * @param offset offset into the mapped region of memory.
+ * @param len length of partial region (example, record length).
+ */
+ void update(size_t offset = 0, size_t len = 0);
+
+ /**
+ * Update a mapped region back to disk as specified by address
+ * and length.
+ *
+ * @param address address of segment.
+ * @param len length of segment.
+ */
+ void update(caddr_t address, size_t len);
+
+ /**
+ * Release (unmap) a memory segment.
+ *
+ * @param address address of memory segment to release.
+ * @param len length of memory segment to release.
+ */
+ void release(caddr_t address, size_t len);
+
+ /**
+ * Fetch a pointer to an offset within the memory mapped portion
+ * of the disk file. This really is used for convience of matching
+ * operations between Update and Fetch, as one could simply have
+ * accessed the base pointer where the file was mapped directly.
+ *
+ * @param offset from start of mapped memory.
+ */
+ inline caddr_t fetch(size_t offset = 0)
+ {return ((char *)(fcb.address)) + offset;};
+
+ /**
+ * Fetch and map a portion of a disk file to a logical memory
+ * block.
+ *
+ * @return pointer to memory segment.
+ * @param pos offset of file segment to map.
+ * @param len size of memory segment to map.
+ */
+ caddr_t fetch(off_t pos, size_t len);
+
+ /**
+ * Lock the currently mapped portion of a file.
+ *
+ * @return true if pages are locked.
+ */
+ bool lock(void);
+
+ /**
+ * Unlock a locked mapped portion of a file.
+ */
+ void unlock(void);
+
+ /**
+ * Compute map size to aligned page boundry.
+ *
+ * @param size request.
+ * @return page aligned size.
+ */
+ size_t pageAligned(size_t size);
+};
+
+
+/**
+ * The DSO dynamic loader class is used to load object files. On
+ * elf based systems this is typically done with dlopen. A dummy
+ * stub class is generated for non-dl capable systems.
+ *
+ * @author David Sugar <dyfet@ostel.com>
+ * @short Dynamic class file loader.
+ */
+class __EXPORT DSO
+{
+private:
+ const char *err;
+ static Mutex mutex;
+ static DSO *first;
+ static DSO *last;
+ DSO *next, *prev;
+ const char *id;
+ void *image;
+
+ typedef ucommon::dso::addr_t addr_t;
+
+protected:
+ void loader(const char *filename, bool resolve);
+
+public:
+ /**
+ * Construct and load a DSO object file.
+ *
+ * @param filename pathname of object file to load.
+ */
+ DSO(const char *filename)
+ {loader(filename, true);};
+
+ DSO(const char *filename, bool resolve)
+ {loader(filename, resolve);};
+
+ /**
+ * Retrieve error indicator associated with DSO failure. This
+ * is often used in catch handlers.
+ */
+ inline const char *getError(void)
+ {return err;};
+
+ /**
+ * Detach a DSO object from running memory.
+ */
+ virtual ~DSO();
+
+ /**
+ * Lookup a symbol in the loaded file.
+ */
+ addr_t operator[](const char *sym);
+
+ static void dynunload(void);
+
+ /**
+ * Find a specific DSO object by filename.
+ *
+ * @param name of DSO object file (partial).
+ */
+ static DSO *getObject(const char *name);
+
+ /**
+ * See if DSO object is valid.
+ *
+ * @return true if valid.
+ */
+ bool isValid(void);
+
+ /**
+ * Install debug handler...
+ */
+ static void setDebug(void);
+};
+
+/** @relates RandomFile */
+bool __EXPORT isDir(const char *path);
+/** @relates RandomFile */
+bool __EXPORT isFile(const char *path);
+#ifndef WIN32
+/** @relates RandomFile */
+bool __EXPORT isDevice(const char *path);
+#else
+/** @relates RandomFile */
+inline bool isDevice(const char *path)
+{ return false; }
+#endif
+/** @relates RandomFile */
+bool __EXPORT canAccess(const char *path);
+/** @relates RandomFile */
+bool __EXPORT canModify(const char *path);
+/** @relates RandomFile */
+time_t __EXPORT lastModified(const char *path);
+/** @relates RandomFile */
+time_t __EXPORT lastAccessed(const char *path);
+
+#ifdef COMMON_STD_EXCEPTION
+
+class DirException : public IOException
+{
+public:
+ DirException(const String &str) : IOException(str) {};
+};
+
+class __EXPORT DSOException : public IOException
+{
+public:
+ DSOException(const String &str) : IOException(str) {};
+};
+
+class __EXPORT FileException : public IOException
+{
+public:
+ FileException(const String &str) : IOException(str) {};
+};
+
+#endif
+
+END_NAMESPACE
+
+#endif
+
+/** EMACS **
+ * Local variables:
+ * mode: c++
+ * c-basic-offset: 4
+ * End:
+ */