Almara Programmer's Guide

Almara project, http://almara.sourceforge.net/
(c) 2005 Almara team

Contents

1 Development
1.1 Rudiments
1.2 Communication
1.3 TLA
2 The Task
2.1 Why another viewer
2.2 Terminology and History
2.3 Reused
3 Modules Overview
3.1 Modules Layout
3.2 Chaerwottoch
3.3 Almara
3.4 Hallmara
4 Chaerwottoch
4.1 Requests
4.2 Scheduler
4.3 Compound request
4.4 Blocking request
4.5 Altering configuration
4.6 Undo
4.7 Metadata versus rendering
4.8 Image library and lossless JPEG transformations
4.9 Work size and cache
4.10 EXIF
4.11 Motion JPEG support
5 Almara
5.1 almara_album
5.2 Exif widget
6 Hallmara
6.1 Generally
6.2 Terminology
6.3 Data Structures and Variables
6.4 Provides (what and how)
7 Other modules
7.1 almara print
7.2 mjpeg2jpegs
7.3 jpegs2mjpeg
7.4 almara_mkalb
7.5 almara_mergalb
7.6 almara_webexport1_bin
7.7 almara_webexport
8 Our Libraries
8.1 Image library
8.2 Common
8.2.1 album_parser.h
8.2.2 config_parser.h
8.2.3 debug.h
8.2.4 file_utils.h
8.2.5 gtk_utils.h
8.2.6 io_parser.h
8.2.7 pixmap.h
8.2.8 tmp.h
8.2.9 type_convert.h
9 Development tools
9.1 Configure
9.2 Glade
9.3 Gettext
10 Appendix A -- ChT <-> GUI communication
10.1 Startup
10.2 Format of commands
10.3 Format of responses
10.4 Operations
11 Appendix B -- Almara External Protocol
11.1 Format of status messages sent to stderr
11.1.1 DEBUG keyword
11.1.2 INFO keyword
11.1.3 ERROR keyword
11.1.4 WARNING keyword
11.1.5 DONE keyword
11.1.6 PROGRESS keyword
11.1.7 <number> %
11.1.8 READING keyword
12 Appendix C -- Format of album file
12.1 Album information
12.2 Photo information
13 Appendix D -- Coding style
13.1 GPL header
13.2 tla change-log
13.3 Documentation
13.4 C coding
13.5 Headers
13.6 Others
13.7 Example of file.c
13.8 Example of file.h

1 Development

1.1 Rudiments

The Almara Photo Album is a school software project of four students and of the leader and author of the project (and also advisor) from the university stuff. We all study informatics at Charles University, Faculty of Mathematics and Physics, Prague.

Project started (and we met together first time) on autumn 2003. After a short period of planning (inter alia a coding style was ratified, see Appendix D for details), we started programming in november. The main programming language is C, the auxiliary and supporting scripting language is Python. We use GTK 2.0 and ImageMagick 6.0 (recomended) as the basic libraries (and Cygwin on MS Windows as well). We use threetimes vim and once emacs as "IDE". Also strace and gdb were excellent helpers. Then we used valgrind, Doxygen for generating a part of this documentation and for example archzoom

1.2 Communication

We founded an account on SourceForge, internal mailing list (with only 5 members), wiki web pages with all closed matters, documents, protocols, howtos, links, tutorials etc., bug track system and in the end we founded also an IRC channel for operative bug fixes and problem reporting. We used to have regular meetings for a few hours every week. We have more than 50 detailed text records which were distributed in e-mail after every meeting. There were also all tasks in those e-mails.

1.3 TLA

As a concurency system we chosed arch. It was continuosly mirrored. Here are some necessary commands:

2 The Task

2.1 Why another viewer

Almara should be the image viewer which is very simple and fast to manipulate with, which is completely controlled from keyboard (only operations such as crop needs mouse), which provides operations on more images at once. Yes, this viewer can do some simple operations with images (rotate, crop, scale, saturation, flip, ...); there's gimp for more complicated transformations, which can be run from Almara. Moreover Almara is suited for photos from digital cameras, so Almara understands Exif, can do some categorization, can group photos to albums, ...

Simply, Almara is a fast thing, which you import your new photos to, look over them, rotate landscape or portrait, crop off void places, increase brightness to the second half of photos and export whole album with thumbnails to web.

Additionally all these things can be undo, the undo list is unlimited. All operations are logged, so image is (for example) croped only in a flag. You will see it always croped -- in Almara. But other viewers will prove that the image wasn't modified. It will be untouched, until you explicitely say that this is exactly what you want. Then, when operations are really executed, they are executed on background, in one of subprocesses.

Almara provides also special work with motion jpegs. (Motion jpeg is cut up on frames and is considered album.) Almara can print. Almara can by run under MS Windows (in Cygwin).

Almara can do many things also when controlled from shell, not from GUI.

2.2 Terminology and History

The Almara Photo Album consists of three main modules. These modules can cooperate, but they can also run separately (with one exception). Further, there are many smaller parts in the package which make the work with Almara more comfortable and also very adjustable. Those three modules are little chaotic and messy in terminology. So we must explain the names of modules and a little history first.

The most visible module was called (logically) almara after the name of whole project. Almara is the graphic user interface for work with pictures. Because there were some interesting requirements on internal work with pictures (e.g. unlimited undo, logging of operations, work with metadata, smart printing, applying opperations on group of pictures, not to be limited by size of memory etc. -- more about this later in Chapter 4), we decided for some kernel module which will provide a support for GUI, for almara. This inner module -- surrounded later by all other modules (such as almara_print, mjpeg2jpegs, almara_webexport, ...) -- was named chaerwottoch (a. k. a. CHT). (The reasons: "Almara" means an old cupboard in Czech, and "chaerwottoch" means a wood-worm.) Name chaerwottoch is the only name which has survived up to now. The third big module is hallmara, The Hall of Almara. It was needed to operate on whole sets of pictures, albums, since almara is conditioned only for pictures itself.

But... almara is now called almara_album, while hallmara, the entering (and therefore first and great) binary was changed its name to almara (or Almara Hall). Because the reasons for name change was mainly simplicity and readibility for common users, in this programmer's guide (on the contrary of the user's guide) we will keep the original designation (with warnings in danger parts). So, we have kernel chaerwottoch, GUI for pictures almara and GUI for directories of pictures hallmara. Almara is primarily designed for photos, so hallmara takes care of photo albums.

2.3 Reused

And there is a list of reused components here:

3 Modules Overview

3.1 Modules Layout

In typical using, hallmara is run first. When the album is choosed in hallmara, almara is run and covers hallmara. almara being run execs CHT and starts communication through two pipes (there and back). Now you know the most important three parts of the project, in cooperation.

CHT providing support to GUI needs some services. This services are provided by those forementioned minor modules, small parts of almara project. A library for pictures (using some functions from ImageMagick) libimg. A print utility almara_print that can be used to advantage also from shell. A python scripts almara_mkalb for creating new album from directory with photos and almara_mergalb for merging two albums together. Python script almara_webexport1_bin, which allows export whole album for web. mjpeg2jpegs and jpegs2mjpeg convertor of motion jpegs. Some other shell scripts provide function of CHT without need of almara, just take control over the CHT and send it commands, because whole communication is designed in such way (see appendix B). It shows that almost any module is replaceable and/or can be connected to some other modules. That's how the modules can exist separately, and so you know both, now. (The exception mentioned in the beginning is that almara requires CHT -- and it is used to launch it.)

3.2 Chaerwottoch

CHT manages many processes. It has them for operations needed by commands. Most of them are its own forked subprocesses (small chaerwottoches), run on photos to satisfy some commands. No more than one process operates on one photo, so no conflicts may come. There are many difficult componants in CHT, such as scheduler with priority queues, command abort, compound commands. The protocol between GUI and CHT is in appendix A. It is able to run many external programs, both our own and the others, such as gimp. The special protocol AEP (Almara exernal protocol) is added as Appendix B. CHT also supports films from cameras, motion jpegs, which are cut frame by frame and give as many photos in album.

For details on chaerwottoch see chapter 4.

3.3 Almara

It has asynchronous communication with CHT on two pipes, so there is a separate thread in GUI dedicated to writing data to avoid deadlocking. Communication is held in "almara_io protocol", which uses spaces to separate individual tokens and newlines to separate commands. Special characters like spaces, newlines, etc. are escaped by backslash. It has the advantage that this protocol can be used also in shellscripts.

For details on almara see chapter 5.

3.4 Hallmara

hallmara is responsible for creating and managing albumfiles and launching almara (both on individual albums and on movies). It can be easily extended to support much wider range of operations with albums.

For details on hallmara see chapter 6.

4 Chaerwottoch

ChT (Chaerwottoch) is a "server" spawned by almara_album, but it can be used by shell scripts as well. It receives commands from standard input and sends responses to standard output. Standard error is used for debug messages.

ChT is responsible for actual working with album. Only one album can be opened at a time but ChT is able to work with another album after previous one is closed. For complete list of commands ChT recognizes, see appendix.

4.1 Requests

The main goal when implementing Cht was to assure that ChT is always ready to receive command and that every time-consuming command will be handled in the background. For the sake of this a "scheduler" was implemented. Every command received is turned into request. Request is held in a structure containing information about command ID, the command and its parameters, photo this request operates upon, and number of internal fields. Requests are of several types depending on a command:

Division of commands to above types is defined in cht/commands.h file.

4.2 Scheduler

Scheduler works with four levels of priorities (the number of priorities is adjustable in cht/scheduler.h - MAX_PRIORITY constant; max_working array in cht/scheduler.c needs to be modified appropriatelly in such case). Priority 0 is special and will be discussed later.

Every priority level has the maximum count of running requests defined (only requests running in subprocess at this or higher priority are counted). When this maximum is reached, no more requests of this priority are started. Requests handled in main process are assumed not to be time-consuming, so they are honoured regardless of number of requests running.

Priority 0 is special to the intent that no "left over" requests are allowed. So if the maximum count of running requests for priority 0 is reached, any other request at this priority is aborted. Note that maximum count for priority 0 is by default set to zero, so setting priority to 0 is effectively equal to aborting the command.

When request is considered to be run, it is checked that there exists no previous request operating on given photo. If such a request exists, considered request cannot be run. This check is made efficient by keeping linked list of so called "dependand requests", ie. requests operating on the same photo.

Aborting of request not yet running is simple - it is discarded from scheduler lists and response about aborting is emitted. When request is running (note that it means it is running in subprocess, as other requests are considered not time-consuming and are handled in main process) the situation is more complicated. SIGTERM signal is sent to the process and response about aborting is emitted. The process itself is responsible for proper clean-up of temporary files.

4.3 Compound request

When command corresponding to compound request is received, one internal request for every photo compound request is for is generated and scheduled as usual. Scheduler keeps track of requests that are part of compound command (it calls it "group"). When all requests from a group are finished, callback is called by scheduler and appropriate message is emitted. All errors occuring during run of compound command are gathered and just one error message is sent when group finishes.

There is also possibility to run external command after group is finished. This external program has to communicate in AEP protocol (see appendix) and appropriate message is send as late as external program requests it.

4.4 Blocking request

This request prevents all requests received later (only request operating on some photo, as there exist requests operating on no photo) to wait until the blocking request is finished. Only one blocking request can be scheduled at a time (error message is emitted when second such command is received).

4.5 Altering configuration

Configuration can be changed at any time. But it contains also export format, work size atc., which are parameters that must not alter previous request. For the sake of this every request has its own copy of configuration. It is freed as soon as request is finished.

4.6 Undo

If request is undoable (this flag is set when adding request to scheduler) and is finished, its structure is not destroyed. It stays in undo list instead. Undo list is linked list of requests (both finished and unfinished) in the reverse order they were received. When request for undo is received, the first request in undo list is undone. It means it is:

As no operation is actually performed and operations are logged, removing of effect means removing of last log entry. A client is responsbile for actual rerendering.

Irreversible operation such as commit removes appropriate requests from undo list.

4.7 Metadata versus rendering

All operations are logged only. That means that getting image dimensions is not as simple as inspecting image file header. Of course image dimensions can be always got by performing operations from log, but it can be very slow if we just want image dimensions. So image dimension are counted from size of original image and logged operations and rendering is used only as a fallback when dimensions cannot be counted (it happens for some unusual operations performed by third-party libraries, like rotation by any angle). Counting of dimension is complicated by lossless JPEG transformations, as they may affect dimensions depending on size of MCU block. The algorithm for dimensions counting deals correctly with it.

4.8 Image library and lossless JPEG transformations

When operation on image needs to be performed, appropriate function from image library is called. ChT needs to decide when particular operation should be performed losslessly and when not, as it needs to compute metadata and perform rendering in the same way.

4.9 Work size and cache

All images are rendered at "work size". It means they are scaled down to this size (they are not enlarged). It gives noticeable speed-up to image rendering.

Thumbnails are cached automatically. This cache is made persistent when the album is not temporary. Symlink to directory with cached thumbnails is created in directory with album when album is being closed.

Images are cached (at work size). Maximum cache size is adjustable at run time. When the maximum size is hit, the last used item is deleted from the cache. For maximal speed-up, images are saved in uncompressed format to the cache (currently BMP format is used).

4.10 EXIF

EXIFs are supported through libexif library. When JPEG image is exported or committed, EXIF is injected to the destination file and appropriate changes are made inside it - Orientation tag and image width and height tags are modified. Nearly all libraries which preserve EXIFs incorrectly preserve them as a whole (eg. ImageMagick in later versions), so original EXIF is always overwritten.

4.11 Motion JPEG support

ChT supports MJPEG files in both AVI and QuickTime format. When command for opening of album is received, it is checked if given filename corresponds to MJPEG file (by content, not by name - except for album.alb, which is always taken as an album name). If movie file was passed, it is cut to individual frames and temporary album file is created. In response to client it is indicated that opened album is a movie.

Cutting movie to individual frames and pasting them together is performed through external AEP programs mjpeg2jpegs and jpegs2mjpeg. First of them takes MJPEG file and generates a directory with individual frames and corresponding parts of audio track (ie. audiotrack is cut to pieces correspondent to fps). The second one takes a list of files and generates MJPEG movie, preserving all of metadata from the original movie.

mjpeg2jpegs can workaround bugs of some types of digital camera (Minolta seems to misinterpret QuickTime standard), jpegs2mjpeg can workaround some bugs in mplayer program (mplayer seems to have problems with QuickTime MJPEGs with 16bit audiotrack).

5 Almara

5.1 almara_album

Originally its name has been almara, but then hallmara assumes this name. But in the source code original names have been preserved, so this is the explanation for probably confused users.

GUI is divided to several components: image widget, filelist, iconlist, exif widget a menu and toolbar. Thanks to dock system it is possible to dock, float and hide these components independently. Each component keeps information about its position and after next start of the system uses the saved data. Config file path can be found at ~/.almara/almara_album.conf and ~/.almara/exif_widget.conf. The config file name can be changed in cfg.h:

Filelist and iconlist contain rendered thumbnails and decide according to current cursor position which photo will be displayed. Filelist is based on gtktreeview and iconlist is based on gtkiconlist (this structure is available only in gtk version >2.5) and both are based on the common model GtkTreeModelSort, which is based on GtkTreeModelFilter, which allows to control visibility in hierarchic groups. GtkTreeModel is built on GtkListSort containing pixbufs of thumbnails, name of an original photo and a description of a photo, and can sort according to these three items. The selection of photos using regular expressions is built on this structure too.

Every photograph in GtkListSort has an associated structure Picture, where additional information about joined audio record, exif data, advanced data and list of pending requests to CHT are stored. If you are curious what advanced data is, see CHT protocol (but generally it is data like compression method, volume, sound, description, keywords and user defined data).

These request are essential for GUI functionality and since the communication between CHT and GUI is asynchronous it is necessary to register callback for each GUI operation.

Communication with the CHT is provided by functions in the almara/kernel.[hc]. There is implemented hash table of requests sent to CHT, but not yet processed. There are pointers to four different callback in the table representing four different answers of CHT to requests:

If an answer from CHT comes and a callback for this request is registered, then callback is executed and request (except progress) is removed from the hash table.

Commands render/get_metadata/get_adv_metadata are a bit more complicated, because GUI wants to abort them sometimes and they are sometimes processed in advance, before their results are requested. In the struct image are therefore lists of request for render/get_metadata/get_adv_metadata, for each request GUI keeps information about its parameters.

Before request for any action like moving to the next photograph, then before the request to CHT is sent, first check is performed, whether the request with these parameters is not already solved or being processed and according to this the request is sent again or just its priority is adjusted (increased).

On the other side when it becomes clear that some preprocessed request is no more needed, the request is aborted and the piece of memory with the already rendered picture is released.

Another problem with rendering pictures is that we don't know its proportions at first and have to find out them with the get_metadata request. And after we received proportions from CHT, we can send render request with proper dimensions, revised according to current zoom. Therefore in the structure Picture we have to keep a list of callbacks, which we need to call for getting the metadata. Same problem and solution appears in case of display data in an exif_widget.

This code is a mesh of mutually tangled functions, especially functions show_image, show_image2, render_image*, get_metadata*, get_exifdata*. You are advised not to touch it unless you 100% understands it.

Here are some clues if you need to understand it:

Parameters for render requests are in the member list render_params of the structure Picture. Parameters get_metadata/get_adv_metadata are stored in the structure pointed by metadata_request/exifdata_request. If they point to NULL, there is no active request.

It is very important that data exchanged through register_cmd (struct pending_request) contain picture id. In the beginning of the callback function it is necessary to check whether picture still exists (get_pic(id) != NULL). Pending_request also contains pointer to structure with real parameters of the operation. It is necessary to check whether this structure is still valid (if it is referred from the list in struct Picture). If it is not, the structure is already released (probably because the request has been aborted).

The code deallocating structure with parameters render/get_metadata/ get_exifdata has to clear the reference in the proper list in the struct Picture, otherwise other callback functions will use it.

One of the main modules working with the requests for CHT is the operations module, where general callbacks for progress, done, error and abort actions are defined. This is far enough for simple operations, other more complex operations like render_image, render_thumb have to implement these callbacks themselves, since they have to be able to react to GUI request to pre-render next and previous photographs with the lower priority and to update this priority along with the movement of a cursor in a filelist or abort if this is not necessary for current pictures at this time.

Progress callback allows to display the state of separate operations and to distinguish with different colors, which operations are processed now, and while the operation with a higher priority (with different color) doesn't finish yet, the progress bar of the operation with the lower priority isn't visible.

Since the operations are not processed immediately, but after render requirement of given picture, it is not necessary to allow user to abort them, because it is happen automatically in CHT along with the current requirements.

GUI offers repeating of the last operation on the picture. So achive this all function that change the picture have to register their name and their parameters. The registered function is also exploited when given operation is called on selected group of pictures. Then the registered operation is applied stepwise to each selected picture.

Since some operations make possible preview rendering, it is necessary to register this function (last repeat operation) after the eventual confirmation. Preview is implemented as any other operation, but if user aborts it, undo operation is called.

The most important function is an image rendering. It is achieved through the named pipe. The name is sent by CHT in callback render_done. GUI data reads and deserializes. Data serialization uses the gdk structure GdkPixdata and gdk_pixdata_serialize() and gdk_pixdata_deserialize() functions to do the coding. In a similar way histograms are sent and when histograms have to be rendered, they are composed transparently over the given picture. Functions dealing with histograms are in lib/histogram.h and GUI functions for rendering histograms are in "histogram issue" in main_window.c (functions draw_histogram() and draw_image())

One of the last requirements of the task specification was the possibility of quick control with hotkeys. Here the need to adapt the GUI has arisen, because by default it works with the focus and without it, many of functions are not accessible. For the management of hotkeys the GtkUIManager has been used, where GtkAction are defined some callbacks are associated with them and it is possible to group callbacks to logical units which can be enabled and disabled at once. Then using the xml, definition menu is created and a toolbar with assigned actions too. With this concept it is also easy to change the menu structure. Internal keys of gtk (arrows, page up/down, etc.) have to be handled extra in each window (this is the docking system work) to accomplish the same control keys for all docked widgets. Each hotkeys has associated some actions so that it is easy to customize the widget control with assigning any other key to any action (see the User guide and gtk-can-change-accels = 1). Further we have to control that all the keys should be disabled while in actions like inplace edit mode using exif widget.

5.2 Exif widget

This widget (see almara/exif_widget/) extends properties of GtkTreeView and allows to edit advanced data and to display exif information. Since the default keys for controlling GtkTreeView are filtered by the main window it is necessary to simulate this control with actions and right away it was extended by step by step edit mode (it edits editable items one by one). Paging with the movement of the cursor without the need of focus (shortcoming of gtk_utils). Data displayed by exif widget are stored in hash table with the string key, exif data are stored under their id, which is returned by libexif and the name and description are stored by an exif widget itself using the libexif. While display data of the next image, data of the previous image are invalidated by set of invalid flag but not deleted because information about the visibility and rank of items and edit-ability etc. are still necessary. If all data are set invalid information about the current position of the cursor is preserved and used after new data are loaded. During inplace editing all actions of GUI are forbidden and are allowed after the editing finishes. Position, visibility of items and columns and saved in config file.

6 Hallmara

6.1 Generally

The runtime of hallmara is based on GTK main loop. Before this main loop is started, there is only a few things to do:

The main loop started just after this initialization rests till the end. hallmara allows all the functionality mentioned (and explained) in chapter "Provides (what and how)".

The main window of hallmara was designed in Glade, but all the next features and look was done manually. Glade files were removed.

Libraries developed for almara project, which are used by hallmara are:

Besides well known headers such as stdio.h, string.h or sys/stat, these less common are included:.

6.2 Terminology

This won't (and neither cannot) be long. We just want to say some terms used in documentation and also in comments in source code.

Album list is the left part of the window. It consists of two columns, first with picture (sometimes called thumbnail), second with some text lines with some information on album (simply info). The second, right part of the window, is called album preview. It has three vertically organized segments. At the top, there is big red title of the album. Below, there is a photo index, many small thumbnails from the album. At the bottom, there is fullinfo list with complete set of information about album (including those from info column and some extra). Current album or focused album is the album under the cursor, the album, on which all the commands are applied. Temporary album -- album created for photos in read-only directory. Because the album.alb file cannot be written there, it is written into /tmp and this enable user to view the album and export eventual changes to another destination. The directory ~/.almara/albums, where all the albums are linked to, is called albums home.

6.3 Data Structures and Variables

Some data structures and variables interesting to mention:

6.4 Provides (what and how)

Hallmara can show known albums: All albums which were ever opened (and was not temporarily neither deleted by user) have their own link in ~/.almara/albums/. This link points to the directory, where all the photos are and where album.alb file was created. At every start of hallmara, this directory is walked and all correct albums are shown in the album list. (Incorrect and/or without album.alb are reported and unlinked.) "Shown in the album list" represents reading of album file, filling the struct alb_header, pushing this struct into the album_table, inserting a row into the album list and displaying the thumbnail and the information.

Hallmara can delete an album: Removing of album means only unlinking it from albums home and removing it from album_table. Deleting means also delete all files in the directory (no subdirectories) and delete a cache directory; then unlink.

Hallmara can open album: Hallmara find the current album, takes its path and run almara_album on it. Before this, it creates new struct running_almara, prepend it to the almaras list and register a callback to know, when this Almara ends.

Hallmara can open unknown album: If you remove album from album list or you have album from elsewhere, you can open it. The directory is searched for album.alb, and if it is found, it is linked into the albums home. The name of the link is the last part of the path. If this name already exists (and doesn't link at the same directory), the "name_2" is tried (and so on). And then it is shown same as in show known albums. At the end, almara is run on new album.

Hallmara can create (and open) new album: If it is as in previous case but no album.alb is found, the directory is tested for write permission. Then album.alb is created (using almara_mkalb) either standardly in the photo directory or (in case that this directory is read-only) in temp. If album.alb was not created only temporarily, the album is linked (as we know from previous paragraphs). And (in both cases) almara_album is run.

Hallmara can open recent: Every opened album (not movie and not a temporary album) is appended to recents. That means, that it appears in File|Recent albums menu at the top (pushing older albums down and removing the oldest recent album). Recents are keeped in two arrays, recents includes the paths and rec_nam includes the titles. Title is shown in menu, path is opened if it is clicked (and path is also compared when inserting new). These two arrays are filled at the start of hallmara from almara.conf file and also saved there at the closing of program. Inserting of new starts with searching, if this album isn't there yet. If so, the oldest recent album isn't removed and only small shuffle is done. Album "survives" in recents either its removing, so you can open still existing, but removing album in this way.

Hallmara can open mpegs: Its not hallmara's credit. It simply runs almara_album and album argument replaced with movie. almara runs CHT and CHT runs mjpeg2jpegs. And on this result almara works then.

Hallmara can show casual photo index: The photo index is created very simply: hallmara only takes first PHINDEX_H * PHINDEX_W pregenerated thumbnails from an album cache. If there are less thumbnails (or none), it doesn't matter, fewer (or nothing) will be displayed. This index is only as actual as the cache is.

Hallmara can edit album info: Editing album informations is done through a simple dialog. After this dialog is closed (by OK), all informations are rewritten in struct alb_header and immediately written into the album.alb. It is done in that way, that album.alb is opened twice (for reading and for writting). New header is written "over" old album.alb and then the rest of the old file is read and rewritten into the new. The album_parser library allows this. The edit dialog also provides potentiality to add own user defined information. The new list (see struct alb_header) is created from this user defined items, it is merged with old list to keep the inner items and then the old is freed and is replaced by this new.

Hallmara can reload new album info: As it was mentioned in open album, the list of all running almaras is kept and whenever some almara ends, the callback is called. This (dead) almara is removed from an almaras list and reload is undertaken. It aggregates reloading of title, photo index, short info and fullinfo.

Hallmara can block more almaras on one album: Before any almara is run, the almaras list is searched. Only if the current album is not served by almara, only then almara_album is run. Identically, if editing should start, this list is tested.

Hallmara can search: It searched regexp in one of four default items, in path or in user defined items (those given by regexp, again), or in several of them. After first search, the patterns and the found position is kept, so next search searched next matching pattern. More detailed info in doxygen, file hallmara/album_list.c.

7 Other modules

7.1 almara print

Module almara_print_bin is individual binary, which is run from either shell or (through the wrapper almara_print) from almara_album, GUI. This module gets many parameters and descriptions and can print for example 6 images on a page, all images with a filename and a description and an exposition time.

7.2 mjpeg2jpegs

This binary takes an input movie, cut it into separately frames (.jpg) and do the same thing with eventual audio track (.wav). Then any operations on frames are permitted. And jpegs2mjpeg can be run after that.

7.3 jpegs2mjpeg

It takes a directory of same sized photos and stick them together into a movie. Also put together the audio track, if there are any parts of it.

7.4 almara_mkalb

This script -- using for creating album files (see Appendix C for more info) in image directories -- is written in Python. All its outputs are converted to UTF-8. Because almara_mkalb accepts many arguments (see user's guide or type almara_mkalb --help for them), large part of script parses them.

Variable destdir keeps the important directory (either where album is, or where album will be -- in case of --copy-to or --move-to argument). Variable existing includes all photos (with all information) from old album (if --append was set) or is empty (otherwise). Then it places all participating files (depends on --recursive option and on list of file masks) into files, but removes those that was already in album file (if --append).

Then the album file itself is creating. Title of album is a name of directory by default, Album-owner is login name by default. After header is written, file by file is taken, .wav sound is assigned (and other items from arguments).

File .welcome.jpg (shown in hallmara in an album list) is also created by almara_mkalb. It is first image scaled into the box 120x100 px.

7.5 almara_mergalb

This script -- using for merging one album file into another -- is written it Python too. It takes image by image from source album file. If image.jpg already exists in destination directory, it tries image-1.jpg, then -2 etc. When the free suffix is found, the <first>/image.jpg is copy (or move: depends on --move argument) to <second>/image-<suffix>.jpg. And -- if exists -- also sound.wav to sound-<suffix>.wav. The appropriate rows from first album file are append to the destination album file.

almara_mkalb and almara_mergalb can be run directly from shell and also almara_mkalb is and almara_mergalb will be used by hallmara, which calls them.

7.6 almara_webexport1_bin

This script (also written in Python) is on contrary run only from CHT. Because it expects on stdin data in special format. Is is list of couples of key and value. These couples are separated by newlines and spaces, tabelators and newlines inside one line are replaced by strings \_, \t and \n respectively. First set of couples carries information about entire album, then empty line follows and all next sets belong to individual images. CHT sends this information from album file. Now it sends all of them, but it may send only those items, which are to place on web. In first set (about album) the item "Title" is guaranted, in other set (about image) items "File" and "Filename" must be included.

CHT must export the album to the special directory, before it calls almara_webexport1_bin. All this files (usually with thumbnails) it gives to the script in Filename: path/file and Thumbnail: path/file on stdin. From this, almara_webexport1_bin gets almost everything -- and the destination directory is the only argument of this script.

almara_webexport1_bin create index.html and n html pages for n images (and main.css). All these pages are valid XHTML 1.0 Strict. Yes, the style of pages is wired in. But there are two possitive points. 1) Style is given, but appereance of the style is user defined as much as Cascade Styles permit. Every tag has its own class with an apposite name and those classes are all prepared for defining in main.css (only some of them are defined and are intended for reedit). 2) There will be also almara_webexport2_bin and almara_webexport3_bin and others some day, which will provide more styles.

7.7 almara_webexport

This script is finally not written in Python, but in shell. Is very simple and its only mission is to run CHT and gives it commands as if it isn't shell script but almara GUI. Then CHT executes all the work necessary for export for web (mentioned in previous paragraphs) and runs almara_webexport1_bin.

It sets handlers for SIGINT and SIGTERM, creates two named pipes in almara temp directory in /tmp and runs CHT with these two pipes as stdin and stdout. Then sends to CHT command for openning album, for web export, waits until CHT is done and returns done and then closes album and send exit to CHT. That's all. Everybody can write his own script for chaerwottoch.

8 Our Libraries

8.1 Image library

Image library (see libimg or a source code in the lib subdirectory) makes possible all the work with images of different graphic formats. It utilizes functions from other graphic libraries, mainly ImageMagick library, which does most of the operations (see almara/operations.h or doxygen docs to get the list of all supported operations) on an image.

It handles cases, when external program expects data on standard input, transparently saves the data to temporary files using almara's tmp support. It also backs up files if an extern program modifies directly the input file. Thanks to this support of extern programs it has been possible since the beginning of the project to implement lossless operations with the available lossless programs jpegtran and exiftran, which are able to do lossless operations like rotate, flip and crop. Now this functionality provides already library libjpegtran which has been created from the source code of jpegtran and allows lossless operations on pictures located either in a file or in a memory and thus makes the image processing faster. In addition lossless support using this library allows to find out if given operations on the given picture can be processed without sideffects inherent to an implementation of the jpeg format, which stores data in blocks, so operations are correctly processed only if the size of an image is a multiple of the size of a block.

The library itself provides computation and rendering of a histogram, converts image data between different bpp (bit per pixel), serializes data for transfer through pipe (this operation is used by CHT when sending data to GUI).

Most of the operations support display of progress bar with the name of the currently processed operation and phase the operation is in and react to user abort if possible.

Since we do not want to link GUI with this library, we provide in file img_formats.h all information about supported formats, color channels and scale filters including explaining description.

8.2 Common

Auxiliary functions used by other components are stored in directory common.

8.2.1 album_parser.h

This library provides simple and uniform access to album.alb in reading (same as in writting) from (into) it in all parts of Almara. Returns line by line splited into the couple key and value.

8.2.2 config_parser.h

All modules of Almara uses the same library config_parser for accessing configuration from their configuration files. They are stored in .almara directory in user's home. Configuration library allows users to make changes in configuration -- without losing comments they were made -- when configuration files are rewritten.

8.2.3 debug.h

Useful for debugging of Almara, allows simple print-out of debugging messages, if the project is compiled with the DEBUG macro. It can be easily configured using ALMARA_DEBUG environment variables (see description on the file common/debug.h). Messages are divided according to domains and it is easy to set on only that ones we need. Domains can be dynamically created or default domain for given component can be used. Default domain is registered in Makefile. It is possible also to add to each message the current time, number of process and name of the function and line in the source code the debug message is called from. In addition messages can be sent to a file or to stderr. If you want to use it you have to call debug_init() first and then use macro DEBUG_MSG("domain name", "debug message\n");. For further info about debug configuration see doxygen description of debug.h.

8.2.4 file_utils.h

Includes functions with similar effect as mkdir -p, cp, rm -rf and mv. And functions to split extension and to create a file with a unique name (adding increased infix).

8.2.5 gtk_utils.h

Functions for joining non-empty strings and for manipulating cursor of GtkTreeView (for moving to a next, previous, first and last image and previous and next page without change of the GtkTreeView focus).

8.2.6 io_parser.h

It provides comfortable reading and writing according to IO protocol between chaerwottoch and the GUI. It handles all neccessery escaping (for these escape sequences see Appendix A).

8.2.7 pixmap.h

Functions for register directories with pixmaps and their load or register as icons for toolbars and menus.

8.2.8 tmp.h

Functions for creating global temporary directory and local directories for separate processes. Also helps the library to reserve temporary files for external programs, when the file origins after the execution of given program and is reserved before using locks, which blocks creation of temporary files with the same name originating after the reservation.

8.2.9 type_convert.h

It converts little and big endians to host byte order and vice versa. It is need for mjpeg2jpegs and jpegs2mjpeg.

9 Development tools

9.1 Configure

Project takes advantage of the modern development tools autoconf and automake to check whether proper versions of all necessary libraries and other development tools for compiling are present in the system and then to achieve conditional compiling according to their presence and easy configuration to match user requirements. We then utilize libtool to let user choose if she wants to link with static or shared libraries.

To use only shared libraries use configure --enable-shared --disable-static for static only libraries configure --enable-static --disable-shared.

9.2 Glade

First version GUI was designed in Glade, but because of its breakneck control and especially lack of support of some desired features, we decided to write all dialogs on our own without the help of the Glade and finally stop using the Glade at all.

Also hallmara was started in Glade. But after creating main window and impressing the figure, there were o more need of Glade. So it was removed later.

9.3 Gettext

Almara supports gettext and therefore it is very easy to translate all texts to another language and thanks to automake also easy to maintain. Basic file po/almara.pot for localization is created and updated using Makefile (make almara.pot). When .po file for given language doesn't exist yet, copy the file almara.pot to a file id_of_the_language.po (e.g. for czech cs.po) and add record to the file po/LINGUAS. When the .po does exist it is enough to update it using make update-po in po directory and to translate all sentences (we recommend kbabel to do this).

10 Appendix A -- ChT <-> GUI communication

Every command or respond is terminated with newline ('\n' character). Command or respond consists of one or more tokens. Tokens are separated by any amount of spaces (' ') or tabs ('\t') or any of their combinations.

If there is a need to include reserved character ('\n', ' ', '\t', '\') in a token, it has to be escaped by backslash ('\') character:

Token can be a string or a number. Numbers are represented as strings in ASCII in C locale (eg. "3.14159").

Special token \0 (ie. token containing exactly '\\' followed by '0') means empty string ("").

Communication is done through stdin and stdout. Command or respond is written to stdout in whole, so it can be read in blocking mode at the other side.

10.1 Startup

When ChT successfuly starts, it sends "OK" command (ie. token "OK" followed by newline).

10.2 Format of commands

Commands for ChT have typically this form:

<string command> <int cid> [<parameter1> <parameter2> ...]

Where <cid> is integer choosen by sender of the command. It has to be unique through the time ChT is run (or at least unique through the time one album is opened).

10.3 Format of responses

Possible responses from ChT:
<cid> <string respond> [<parameter1> <parameter2> ...]
Where <cid> identifies command. <respond> is one of these strings:

"done" response:
<cid> done [<parameter1> <parameter2> ...]
- Tokens following "done" are command-specific and are explained below.

"error" response:
<cid> error <string message> [<parameter1> <parameter2> ...]
- "error" token is followed by token containing localized error message possible followed by other parameters (see commands explanation below).

"aborted" response:
<cid> aborted

"progress" response:
<cid> progress <int amount> <string comment>

10.4 Operations

Every command is described at several lines. First line contains format of command. This line can be followed by possible responses from ChT. Following lines contain description of command.

Possible responses follow these rules:

open <cid> <string albumname>
<cid> done <int album_type> <string title>
- Opens album.
- <album_type> is 0 when album is a normal album, 1 when album belongs to MJPEG.

close <cid> <int no_save>
<cid> done
- Closes album. May take some time.
- <no_save> should be 0. If close fails, it means album cannot be written. In such case it is allowed to recall "close" with <no_save> set to 1.

save <cid>
<cid> done
- Saves album to disk. Can be called periodically to minimize risc of data loss.
- It should be called after every "commit".

exit <cid>
<cid> done
- After sending "done" ChT will terminate.

abort <cid>
- Aborts request with given cid. No response is given (except for "<cid> aborted" sent by aborted request itself).

set_priority <cid> <int priority>
- Sets new priority to request with <cid>. No response is given by ChT.
- <priority> can be in range 3 (highest) to 0 (lowest). Requests at priority 0 can be aborted at ChT's discretion.

list <cid>
<cid> done <phid1> <filename1> <description1>
<phid2> <fname2> <desc2> ...
<cid> done <<photo1>> <<photo2>> ...
where every <<photo>> consists of:
<int phid> <int order-id> <string filename> <string desc> <string soundfile> <string keywords>
- Returns list of photos in album. <phid> is integer which uniquely identifies photo, <order-id> order identificator of the photo, <filename> physical name of file with photo, <desc> textual description of the photo and <soundfile> physical name of attached sound or empty string if there is no sound attached

list_one <cid> <phid>
<cid> done <order-id> <filename> <description> <soundfile> <keywords>
- One-photo-only version of "list" command.

render <cid> <phid> <priority> <int w> <int h>
<cid> done <filename>
- Renders image in specified dimensions. Filename is choosen by ChT and typically it will be named pipe. Rendering works at work size.

render_full <cid> <phid> <priority> <int w> <int h>
<cid> done <filename> <int size>
- Like "render", but works at full size (and not at work size) and if source image is JPEG, compression level is also applied.
- If source image is JPEG, a size of saved JPEG file is returned in <size>. In other cases, zero is returned in <size>.

thumb <cid> <phid> <priority> <int width> <int height>
<cid> done <filename>
- Renders thumbnail with specified maximal dimensions. Although dimensions can be specified, it is assumed they will be constant and they will never change.

histogram <cid> <phid> <priority> <int channel> <int width> <int height>
<cid> done <filename>
- Renders histogram and returns it twice. The first returned histogram is linear, the second one is logarithmic.

get_metadata <cid> <phid> <priority>
<cid> done <string key1> <value1> <key2> <value2> ...
- Returns metadata for given photo. Most noticable keys are "width", "height" and "depth".

get_adv_metadata <cid> <phid> <priority>
<cid> done <string key1> <value1> <key2> <value2> ...
- Returns advanced metadata, ie. exif and user-defined data. For exif, keys are represented numerically, values are localized strings. For user-defined data, keys are in form "User-XXX". "Compression" and "Volume" may be returned too. If photo has sound attached, metadata always contain "Volume" (and vice versa).

rotate <cid> <phid> <int degrees>
<cid> done

flip_horizontally <cid> <phid>
<cid> done

flip_vertically <cid> <phid>
<cid> done

crop <cid> <phid> <int x> <int y> <int w> <int h>
<cid> done

scale <cid> <phid> <int w> <int h> <int filter> <int blur>
<cid> done
- For <filter> and <blur> values see lib/img_formats.h (note that they are sent as integers, not as symbolic constants).

scale_adv <cid> <phid> <int w_type> <int h_type> <double width> <double height>
<bool aspect_ratio> <bool enlargeable> <int filter> <int blur>
- Advanced scale. <w_type> and <h_type> can be:
0: scale to given size (like simple "scale", but takes into account also <aspect_ratio>)
1: scale to given ratio (<width> or <height> contains value in range 0.0 to 1.0, <aspect_ratio> is taken into account)
2: scale image to fit in given bounding box (<width> or <height> contatins bounding box, <aspect_ratio> and <enlargeable> is taken into account)
3: ignore <width> or <height>

modulate <cid> <phid> <int brightness> <int saturation> <int hue>
<cid> done

despeckle <cid> <phid>
<cid> done

enhance <cid> <phid>
<cid> done

equalize <cid> <phid>
<cid> done

invert <cid> <phid>
<cid> done

normalize <cid> <phid>
<cid> done

sharpen_contrast <cid> <phid>
<cid> done

dull_contrast <cid> <phid>
<cid> done

change_metadata <cid> <phid> <string key1> <value1> <key2> <value2> ...
<cid> done
- Sets metadata. Accepted keys are:
= "Description"
= "Compression" (sets per-photo compression level)
= "Volume" (sets volume of attached sound in percents)
= "User-XXX" (where XXX represents any value)
= no other keys are accepted.
- Passing empty value means deleting of a metadata.

reorder <cid> <phid> <oid>
<cid> done
- Changes order-id of a photo.

delete <cid> <phid>
<cid> done
- Marks photo as deleted.

delete_sound <cid> <phid>
<cid> done
- Marks attached audio file as deleted.

undelete <cid>
<cid> done <phid1> <phid2> ...
- Undeletes all photos. Returns added phids or phids with added sound file.

edit_external <cid> <phid> <string prg_name> <string parm1> <parm2> ...
<cid> done <int deleted>
- Runs external program at given photo. Photo is committed first (so no undo is possible). Program doesn't need to be AEP conformant.
- <prg_name> is name of program to run, <parm>s are not mandatory and are passed to program as parameters. Parameter consisting of "{}" is replaced by photo filename. If no such parameter is specified, photo filename is passed as a last parameter.
- "done" is returned when specified program finishes. If photo was deleted during running of external program, <deleted> is 1.
- After every edit_external, "save" should be called.
- Even if error is returned, photo might be committed! Call undo_list_global to update undo list.

edit_audiotrack <cid> <string prg_name> <string param> <phid1> <phid2> ...
<cid> done
- Runs external program at audiotrack. Sounds attached to passed photos are pasted together and passed to given program.
- If no phids are listed, all photos are used.

undo_list_global <cid> <int max>
<cid> done <int undoid1> <string name1> <undoid2> <name2> ...
- Gets list of undoable operations, last used first. Returned names are localized. <max> is maximal number of returned undo items.

undo_group_start <unused>
- Starts undo group. No response is sent by ChT. <unused> parameter should be 0.

undo_group_end <unused>
- Ends undo group. See undo_group_start for explanation.

undo_global <cid> <int undoid>
<cid> done <<list1>> <<list2>> <<list3>> <<list4>> <int relist>
where every <<list>> consists of:
<n> <phid1> <phid2> ... <phid_n>
- Undos one or more operations. <undoid> contains number of operations to be undone and it corresponds to number returned by undo_list_global.
- <<list1>> is a list of photos removed by undo.
<<list2>> is a list of photos whose metadata was modified by undo.
<<list3>> is a list of photos modified by undo,
<<list4>> is a list of photos added by undo and
<relist> is 1 when new "list" command should be performed (order-ids changed)

debug <parm1> <parm2> ...
<parm1> <parm2>
- Local echo :-)

export <cid> <priority> <string directory> <phid1> <phid2> ...
<cid> done
<cid> error <message> <phid1> <phid2> ...
- Exports photos to given directory. If no phid is given, all photos in album are exported.
- If error occured, not exported photo ids are returned.

external <cid> <priority> <string prg_name> <int thmb_x> <int thmb_y> <string dir> <phid1> <phid2> ...
<cid> done
<cid> error <message> <phid1> <phid2> ...
- Exports photos through given external program. If no phid is given, all photos in album are exported. Program MUST be AEP (Almara external protocol) conformant.
- <thmb_x> and <thmb_y> contain sizes (bounding box) of thumbnail. If they are equal to 0, no thumbnail is generated. For some programs, thumbnails have no sense (eg. almara_print, jpegs2mjpeg).
- <dir> is passed to external program. Not every program uses it.
- Use "almara_print_bin" as <prg_name> to print photos. almaraprint-bin doesn't make use of <dir> parameter.
- If error occurred during exporting photos for external program, not exported photo ids are returned and external program was not run. If error occurred during run of external program, no phids are returned.

commit <cid> <priority> <reserved> <phid1> <phid2> ...
<cid> done
<cid> error <message> <phid1> <phid2> ...
- Commits given or all photos (ie. performs image log in place).
- Like "export". <reserved> should be 0.
- When no phids are specified, commit is performed also on deleted photos (ie. they are physically deleted).
- After every commit, "save" should be called.

play_sound <cid> <phid> <priority> <string prg_name> <string parm1> <parm2> ...
<cid> done
- Plays sound through given external program.
- For explanation of <prg_name> and <parm>s see edit_external.

copy_from <cid> <phid>
<cid> done <string key1> <string value1> <key2> <value2> ...
- Sends data needed for copy and paste between ChTs.
paste_to <cid> <string key1> <string value1> <key2> <value2> ...
<cid> done <phid>
- Adds new photo to album. Keys and values are those obtained from "copy_from" command (order of keys MUST be preserved).
- As a result, photo id of newly added image is returned.

set_globals <cid> <string key1> <value1> <key2> <value2> ...
<cid> done
- Sets global options for ChT. It is not necessary to wait for "done", settings are guaranteed to have effect right after sending command (but for new requests only, old requests are not affected).
- As some of settings are loaded from/saved to album file, set_globals can be called only when album is opened.
- Currently allowed settings (<key>), saved in album file:
= "compression": sets compression level (0 to 100, 100 is the best)
= "export_fmt": "copy" or ".extension" (see lib/img_formats.c for full list)
- Currently allowed settings, not saved in album file and not returned by "get_globals":
= "gamma_r", "gamma_g", "gamma_b": sets gamma value (in doubles)
= "work_width", "work_height": sets size of work image (warning: this can come in effect very slowly because already cached images are not affected even if new operations are performed on them)
= "cache_size": sets maximum size of cache
= "scheduler": sets scheduler behaviour to given level. The level roughly corresponds to number of processors (but it has a sense to use lower or higher number depending on computer performance).

get_globals <cid>
<cid> done <string key1> <value1> <key2> <value2> ...
- Returns actual global options. This include:
= Title of album (key "title").
= Settings saved in album file (see set_globals).
= Other informations found in album header.
- Can be called only when album is opened.

11 Appendix B -- Almara External Protocol

Almara uses a number of external programs. To communicate effectively with them but allowing also their independent usage, Almara External Protocol (AEP) was defined.

Examples of AEP-conforming programs are mjpeg2jpegs, jpeg2mjpegs, almara_mkalb, almara_print, almara_webexport, etc.

AEP program sends its status to stderr and receives input (when requested) from stdin. Stdout is reserved for application use and is usualy connected to a terminal.

11.1 Format of status messages sent to stderr

Empty lines are ignored.

Every line should start with a keyword, possibly followed by a space character (' ') and code (depending on the keyword), followed by colon (:). The rest of line is ignored by reader and is used to output detailed information when running independently. Every line is terminated by newline ('\n').

Possible keywords are:

When PROGRESS have been sent, the line can also consist of number, space and percent sign (%).

11.1.1 DEBUG keyword

Used to output debug messages. They should be ignored by caller.

11.1.2 INFO keyword

Used to output informational messages for user running AEP program independently. Caller should ignore it.

11.1.3 ERROR keyword

ERROR keyword is followed by error code. Error codes are defined and reserved for individual applications as follows:

Program must not emit any message after ERROR.

11.1.4 WARNING keyword

WARNING is similar to ERROR (and it shares the same error codes), but problems reported by them are nonfatal. Caller should inform user about this warnings.

11.1.5 DONE keyword

Program finished its job successfully. No message may be emitted after DONE.

11.1.6 PROGRESS keyword

When seen for the first time, this keyword indicates start of progress. When seen second time, it indicates end of progress. Every program can emit at most one progress during its run.

11.1.7 <number> %

Progress is sent as number followed by space (' ') followed by percent sign ('%') followed by carriage return ('\r'). Line is NOT terminated by newline ('\n'). <number> can go from 0 to 100.

It is allowed for DEBUG, INFO, ERROR and WARNING keywords to appear during progress.

11.1.8 READING keyword

AEP program wants data at its stdin. AEP program may not send anything to stderr (else deadlock will occur). Program may close stdin anytime during reading, if it detects some error.

READING has two variants:

12 Appendix C -- Format of album file

Album file is a text file named album.alb (in some rare cases it can have another name - eg. album temporary made for read-only directory).

Lines beginning with '#' are ignored. Empty lines delimit sections in album file. All other lines consist of key, followed by separator - colon and space (": "), followed by a value. If value spreads more lines (ie. it should contain '\n'), the key and separator are repeated at every line.

First section in album contains information about album. There is only one mandatory item: "Title". It contains the name of album.

Next sections contain information about photos, one photo per section, up to the end of file.

12.1 Album information

This is the header of album.alb with information about album.

Title: title of album
Description: detailed description of album
Album-owner: name of author of album
Date: date when album was made
Eport-format: default export format
Compression: default compression
Compression: Compression is integer 0-100.
User-blahblah: user defined item and its value

12.2 Photo information

This is a structure of the rest of album.alb.

File: filename (without path)
Description: description of image
Order-id: order of photo in list of photos
Author: author of the photo
Sound: name of attached sound file (without path)
Volume: volume of attached sound file, integer 0-100.
Operation: log of operations performed at image,
Operation: one per line (for list of operations, see
Operation: Appendix A)
Deleted: photo is marked as deleted
Sound-deleted: attached sound is marked as deleted
User-XXX: user-defined fields

13 Appendix D -- Coding style

13.1 GPL header

GPL header, in every file, like this:

/** @file relativ/path/with/this/file/name.c
 * Short description of this file.
 * @author Author1
 * @author Author2
 *
 * Optionaly detailed description of this file
 * on more lines.
 */
  
  
/*
 *  This file is a part of Almara project
 *  (http://almara.sourceforge.net/).
 *  Copyright (C) 2004  Almara team
 *
 *  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.
 */

13.2 tla change-log

Use whole sentences. For each modification use new line. Or you write the theme, colon and then every change on new line, begin with "- ".

Example:

I done some bugfixes.
Library:
- I change the interface
- added some new functions

13.3 Documentation

Use Doxygen! Style JavaDoc.

13.4 C coding

if ([cond]) {
    [command];
    ...
    [command];
}
else {
    [command];
    ...
    [command];
}
  
  
if ([cond very very very very very very very very long] &&
    [cond2very very very very very very very very very long])
    [the only command];
  
  
switch ([var]) {
    case 0:
        [command];
        [command];
		break;
    case 1:
        [command]; break;
}
void bar([type var], [type var])
{
    [command];
    ...
    [command];
  
    return 0; // i.e. SUCCESS; if error, you must return
              // minus error number;
}

13.5 Headers

#ifndef _FILENAME_H

13.6 Others

Use spaces around every operator (except ".", "->", "++" and "--"); unary operator '*' and ampersand are missing the space from right; (and also unary '-').

As you can see above, parentheses are closed to inside, i.e. " (blah blah) " In "function([var])" there is no space before '('.

You MAY use more spaces than you OUGHT TO (according to this CodingStyle), if it makes your code nicer in being verticaly indented.

13.7 Example of file.c

(From docs/templates/template.c)

/** @file [[[ relativ/path/with/this/file/name.c ]]]
 * [[[ Short description of this file. ]]]
 * @author [[[ Author1 ]]]
 */
  
/*
 * [[[ GPL Licence ]]]
 */
  
  
[[[ #include "almara.h" ]]]
  
[[[ #include "template.h" ]]]
  
  
[[[ declarations here ... ]]]

13.8 Example of file.h

(From docs/templates/template.h)

/** @file [[[ relativ/path/with/this/file/name.h ]]]
 * [[[ Short description of this file. ]]]
 * @author [[[ Author1 ]]]
 * @author [[[ Author2 ]]]
 *
 * [[[ Optionaly detailed description of this file
 * on more lines. ]]]
 */
  
/*
 * GPL Licence
 */
  
#ifndef _[[[ relativ_path_with_this_file_name.h \
          (slashes converted to _ and  everything \
          is uppercase) ]]]
  
#define [[[ same as above ]]]
  
  
  
/* include almara's global header file */
  
#include "almara.h"
  
  
[[[
   definitions here ...
  
   /**
    * First sentence is Brief description of following
    * sample_function.
    * Continued with Detailed description of this function
    * on more lines (sentences).
    *
    * @param param1 is for ...
    * @param param2 is a something ...
    * @return description of return values
    */
   int sample_function(int param1, int param2);
  
   /**
    * @defgroup NameOfGroup First sentence is Brief
    * description of group of something (e.g. special
    * macros...). Continued with Detailed description of
    * this function on more lines (sentences).
    */
  
   /*@{*/
   #define MACRO1 1 /**< description of group member1. */
   #define MACRO2 1 /**< description of group member2. */
   #define MACRO3 1 /**< description of group member3. */
   /*@}*/
  
  /**
   * First sentence is Brief description of following enum.
   * Continued with Detailed description of this enum
   * on more lines (sentences).
   */
  
  typedef enum {
     ITEM_1,   /**< description of enum item 1 */
     ITEM_2,   /**< description of enum item 2 */
     ITEM_3,   /**< description of enum item 3 */
  } SampleEnum;
  
   ]]]
  
#endif