import psensor trunk from private svn
authorJean-Philippe Orsini <jeanfi@gmail.com>
Thu, 21 Apr 2011 08:00:29 +0000 (08:00 +0000)
committerJean-Philippe Orsini <jeanfi@gmail.com>
Thu, 21 Apr 2011 08:00:29 +0000 (08:00 +0000)
116 files changed:
ABOUT-NLS [new file with mode: 0644]
AUTHORS [new file with mode: 0644]
COPYING [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
INSTALL [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
NEWS [new file with mode: 0644]
README [new file with mode: 0644]
configure.ac [new file with mode: 0644]
debian/changelog [new file with mode: 0644]
debian/control [new file with mode: 0644]
debian/copyright [new file with mode: 0644]
debian/docs [new file with mode: 0644]
debian/psensor-common.install [new file with mode: 0644]
debian/psensor-server.install [new file with mode: 0644]
debian/psensor-server.manpages [new file with mode: 0644]
debian/psensor.install [new file with mode: 0644]
debian/psensor.manpages [new file with mode: 0644]
debian/rules [new file with mode: 0755]
debian/watch [new file with mode: 0644]
pixmaps/16x16/psensor.png [new file with mode: 0644]
pixmaps/22x22/psensor.png [new file with mode: 0644]
pixmaps/24x24/psensor.png [new file with mode: 0644]
pixmaps/32x32/psensor.png [new file with mode: 0644]
pixmaps/48x48/Makefile.am [new file with mode: 0644]
pixmaps/48x48/psensor.png [new file with mode: 0644]
pixmaps/48x48/psensor_hot.png [new file with mode: 0644]
pixmaps/scalable/Makefile.am [new file with mode: 0644]
pixmaps/scalable/psensor.svg [new file with mode: 0644]
pixmaps/scalable/psensor_hot.svg [new file with mode: 0644]
po/LINGUAS [new file with mode: 0644]
po/Makefile.in.in [new file with mode: 0644]
po/Makevars [new file with mode: 0644]
po/POTFILES.in [new file with mode: 0644]
po/Rules-quot [new file with mode: 0644]
po/boldquot.sed [new file with mode: 0644]
po/en@boldquot.header [new file with mode: 0644]
po/en@quot.header [new file with mode: 0644]
po/fr.po [new file with mode: 0644]
po/insert-header.sin [new file with mode: 0644]
po/psensor.pot [new file with mode: 0644]
po/quot.sed [new file with mode: 0644]
po/remove-potcdate.sin [new file with mode: 0644]
po/zh_CN.po [new file with mode: 0644]
psensor.desktop [new file with mode: 0644]
src/Makefile.am [new file with mode: 0644]
src/cfg.c [new file with mode: 0644]
src/cfg.h [new file with mode: 0644]
src/compat.h [new file with mode: 0644]
src/description.txt [new file with mode: 0644]
src/glade/Makefile.am [new file with mode: 0644]
src/glade/psensor-pref.glade [new file with mode: 0644]
src/glade/sensor-edit.glade [new file with mode: 0644]
src/graph.c [new file with mode: 0644]
src/graph.h [new file with mode: 0644]
src/httpd/Makefile.am [new file with mode: 0644]
src/httpd/httpd.c [new file with mode: 0644]
src/httpd/httpd.h [new file with mode: 0644]
src/lib/Makefile.am [new file with mode: 0644]
src/lib/color.c [new file with mode: 0644]
src/lib/color.h [new file with mode: 0644]
src/lib/hdd.c [new file with mode: 0644]
src/lib/hdd.h [new file with mode: 0644]
src/lib/lmsensor.c [new file with mode: 0644]
src/lib/lmsensor.h [new file with mode: 0644]
src/lib/measure.c [new file with mode: 0644]
src/lib/measure.h [new file with mode: 0644]
src/lib/nvidia.c [new file with mode: 0644]
src/lib/nvidia.h [new file with mode: 0644]
src/lib/psensor.c [new file with mode: 0644]
src/lib/psensor.h [new file with mode: 0644]
src/libpsensor_json/Makefile.am [new file with mode: 0644]
src/libpsensor_json/psensor_json.c [new file with mode: 0644]
src/libpsensor_json/psensor_json.h [new file with mode: 0644]
src/main.c [new file with mode: 0644]
src/plib/Makefile.am [new file with mode: 0644]
src/plib/plib_io.c [new file with mode: 0644]
src/plib/plib_io.h [new file with mode: 0644]
src/plib/plib_luatpl.c [new file with mode: 0644]
src/plib/plib_luatpl.h [new file with mode: 0644]
src/plib/url.c [new file with mode: 0644]
src/plib/url.h [new file with mode: 0644]
src/rsensor.c [new file with mode: 0644]
src/rsensor.h [new file with mode: 0644]
src/server/Makefile.am [new file with mode: 0644]
src/server/description.txt [new file with mode: 0644]
src/server/server.c [new file with mode: 0644]
src/server/server.h [new file with mode: 0644]
src/server/server_lua.c [new file with mode: 0644]
src/server/server_lua.h [new file with mode: 0644]
src/server/sysinfo.c [new file with mode: 0644]
src/server/sysinfo.h [new file with mode: 0644]
src/ui.c [new file with mode: 0644]
src/ui.h [new file with mode: 0644]
src/ui_appindicator.c [new file with mode: 0644]
src/ui_appindicator.h [new file with mode: 0644]
src/ui_color.c [new file with mode: 0644]
src/ui_color.h [new file with mode: 0644]
src/ui_graph.c [new file with mode: 0644]
src/ui_graph.h [new file with mode: 0644]
src/ui_notify.c [new file with mode: 0644]
src/ui_notify.h [new file with mode: 0644]
src/ui_pref.c [new file with mode: 0644]
src/ui_pref.h [new file with mode: 0644]
src/ui_sensorlist.c [new file with mode: 0644]
src/ui_sensorlist.h [new file with mode: 0644]
src/unity/Makefile.am [new file with mode: 0644]
src/unity/ui_unity.c [new file with mode: 0644]
src/unity/ui_unity.h [new file with mode: 0644]
tests/Makefile.am [new file with mode: 0644]
tests/checkpatch.pl [new file with mode: 0755]
www/Makefile.am [new file with mode: 0644]
www/favicon.ico [new file with mode: 0644]
www/index.lua [new file with mode: 0644]
www/monitor.lua [new file with mode: 0644]
www/style.css [new file with mode: 0644]

diff --git a/ABOUT-NLS b/ABOUT-NLS
new file mode 100644 (file)
index 0000000..ec20977
--- /dev/null
+++ b/ABOUT-NLS
@@ -0,0 +1,1101 @@
+1 Notes on the Free Translation Project
+***************************************
+
+Free software is going international!  The Free Translation Project is
+a way to get maintainers of free software, translators, and users all
+together, so that free software will gradually become able to speak many
+languages.  A few packages already provide translations for their
+messages.
+
+   If you found this `ABOUT-NLS' file inside a distribution, you may
+assume that the distributed package does use GNU `gettext' internally,
+itself available at your nearest GNU archive site.  But you do _not_
+need to install GNU `gettext' prior to configuring, installing or using
+this package with messages translated.
+
+   Installers will find here some useful hints.  These notes also
+explain how users should proceed for getting the programs to use the
+available translations.  They tell how people wanting to contribute and
+work on translations can contact the appropriate team.
+
+   When reporting bugs in the `intl/' directory or bugs which may be
+related to internationalization, you should tell about the version of
+`gettext' which is used.  The information can be found in the
+`intl/VERSION' file, in internationalized packages.
+
+1.1 Quick configuration advice
+==============================
+
+If you want to exploit the full power of internationalization, you
+should configure it using
+
+     ./configure --with-included-gettext
+
+to force usage of internationalizing routines provided within this
+package, despite the existence of internationalizing capabilities in the
+operating system where this package is being installed.  So far, only
+the `gettext' implementation in the GNU C library version 2 provides as
+many features (such as locale alias, message inheritance, automatic
+charset conversion or plural form handling) as the implementation here.
+It is also not possible to offer this additional functionality on top
+of a `catgets' implementation.  Future versions of GNU `gettext' will
+very likely convey even more functionality.  So it might be a good idea
+to change to GNU `gettext' as soon as possible.
+
+   So you need _not_ provide this option if you are using GNU libc 2 or
+you have installed a recent copy of the GNU gettext package with the
+included `libintl'.
+
+1.2 INSTALL Matters
+===================
+
+Some packages are "localizable" when properly installed; the programs
+they contain can be made to speak your own native language.  Most such
+packages use GNU `gettext'.  Other packages have their own ways to
+internationalization, predating GNU `gettext'.
+
+   By default, this package will be installed to allow translation of
+messages.  It will automatically detect whether the system already
+provides the GNU `gettext' functions.  If not, the included GNU
+`gettext' library will be used.  This library is wholly contained
+within this package, usually in the `intl/' subdirectory, so prior
+installation of the GNU `gettext' package is _not_ required.
+Installers may use special options at configuration time for changing
+the default behaviour.  The commands:
+
+     ./configure --with-included-gettext
+     ./configure --disable-nls
+
+will, respectively, bypass any pre-existing `gettext' to use the
+internationalizing routines provided within this package, or else,
+_totally_ disable translation of messages.
+
+   When you already have GNU `gettext' installed on your system and run
+configure without an option for your new package, `configure' will
+probably detect the previously built and installed `libintl.a' file and
+will decide to use this.  This might not be desirable.  You should use
+the more recent version of the GNU `gettext' library.  I.e. if the file
+`intl/VERSION' shows that the library which comes with this package is
+more recent, you should use
+
+     ./configure --with-included-gettext
+
+to prevent auto-detection.
+
+   The configuration process will not test for the `catgets' function
+and therefore it will not be used.  The reason is that even an
+emulation of `gettext' on top of `catgets' could not provide all the
+extensions of the GNU `gettext' library.
+
+   Internationalized packages usually have many `po/LL.po' files, where
+LL gives an ISO 639 two-letter code identifying the language.  Unless
+translations have been forbidden at `configure' time by using the
+`--disable-nls' switch, all available translations are installed
+together with the package.  However, the environment variable `LINGUAS'
+may be set, prior to configuration, to limit the installed set.
+`LINGUAS' should then contain a space separated list of two-letter
+codes, stating which languages are allowed.
+
+1.3 Using This Package
+======================
+
+As a user, if your language has been installed for this package, you
+only have to set the `LANG' environment variable to the appropriate
+`LL_CC' combination.  Here `LL' is an ISO 639 two-letter language code,
+and `CC' is an ISO 3166 two-letter country code.  For example, let's
+suppose that you speak German and live in Germany.  At the shell
+prompt, merely execute `setenv LANG de_DE' (in `csh'),
+`export LANG; LANG=de_DE' (in `sh') or `export LANG=de_DE' (in `bash').
+This can be done from your `.login' or `.profile' file, once and for
+all.
+
+   You might think that the country code specification is redundant.
+But in fact, some languages have dialects in different countries.  For
+example, `de_AT' is used for Austria, and `pt_BR' for Brazil.  The
+country code serves to distinguish the dialects.
+
+   The locale naming convention of `LL_CC', with `LL' denoting the
+language and `CC' denoting the country, is the one use on systems based
+on GNU libc.  On other systems, some variations of this scheme are
+used, such as `LL' or `LL_CC.ENCODING'.  You can get the list of
+locales supported by your system for your language by running the
+command `locale -a | grep '^LL''.
+
+   Not all programs have translations for all languages.  By default, an
+English message is shown in place of a nonexistent translation.  If you
+understand other languages, you can set up a priority list of languages.
+This is done through a different environment variable, called
+`LANGUAGE'.  GNU `gettext' gives preference to `LANGUAGE' over `LANG'
+for the purpose of message handling, but you still need to have `LANG'
+set to the primary language; this is required by other parts of the
+system libraries.  For example, some Swedish users who would rather
+read translations in German than English for when Swedish is not
+available, set `LANGUAGE' to `sv:de' while leaving `LANG' to `sv_SE'.
+
+   Special advice for Norwegian users: The language code for Norwegian
+bokma*l changed from `no' to `nb' recently (in 2003).  During the
+transition period, while some message catalogs for this language are
+installed under `nb' and some older ones under `no', it's recommended
+for Norwegian users to set `LANGUAGE' to `nb:no' so that both newer and
+older translations are used.
+
+   In the `LANGUAGE' environment variable, but not in the `LANG'
+environment variable, `LL_CC' combinations can be abbreviated as `LL'
+to denote the language's main dialect.  For example, `de' is equivalent
+to `de_DE' (German as spoken in Germany), and `pt' to `pt_PT'
+(Portuguese as spoken in Portugal) in this context.
+
+1.4 Translating Teams
+=====================
+
+For the Free Translation Project to be a success, we need interested
+people who like their own language and write it well, and who are also
+able to synergize with other translators speaking the same language.
+Each translation team has its own mailing list.  The up-to-date list of
+teams can be found at the Free Translation Project's homepage,
+`http://www.iro.umontreal.ca/contrib/po/HTML/', in the "National teams"
+area.
+
+   If you'd like to volunteer to _work_ at translating messages, you
+should become a member of the translating team for your own language.
+The subscribing address is _not_ the same as the list itself, it has
+`-request' appended.  For example, speakers of Swedish can send a
+message to `sv-request@li.org', having this message body:
+
+     subscribe
+
+   Keep in mind that team members are expected to participate
+_actively_ in translations, or at solving translational difficulties,
+rather than merely lurking around.  If your team does not exist yet and
+you want to start one, or if you are unsure about what to do or how to
+get started, please write to `translation@iro.umontreal.ca' to reach the
+coordinator for all translator teams.
+
+   The English team is special.  It works at improving and uniformizing
+the terminology in use.  Proven linguistic skills are praised more than
+programming skills, here.
+
+1.5 Available Packages
+======================
+
+Languages are not equally supported in all packages.  The following
+matrix shows the current state of internationalization, as of October
+2006.  The matrix shows, in regard of each package, for which languages
+PO files have been submitted to translation coordination, with a
+translation percentage of at least 50%.
+
+     Ready PO files       af am ar az be bg bs ca cs cy da de el en en_GB eo
+                        +----------------------------------------------------+
+     GNUnet             |                                  []                |
+     a2ps               |             []                [] [] []     []      |
+     aegis              |                                  ()                |
+     ant-phone          |                                  ()                |
+     anubis             |                                  []                |
+     ap-utils           |                                                    |
+     aspell             |                      [] []    [] []        []      |
+     bash               |                      []          []             [] |
+     batchelor          |                                  []                |
+     bfd                |                                                    |
+     bibshelf           |                                  []                |
+     binutils           |                               []                   |
+     bison              |                               [] []                |
+     bison-runtime      |                                                    |
+     bluez-pin          | []                      []       [] []          [] |
+     cflow              |                               []                   |
+     clisp              |                                  []    []          |
+     console-tools      |                         []       []                |
+     coreutils          |                []    []          []                |
+     cpio               |                                                    |
+     cpplib             |                      []       [] []                |
+     cryptonit          |                                  []                |
+     darkstat           |                []             () []                |
+     dialog             |                      [] [] [] [] [] []             |
+     diffutils          |                      [] []    [] [] []          [] |
+     doodle             |                                  []                |
+     e2fsprogs          |                         []       []                |
+     enscript           |                      []       [] []        []      |
+     error              |                      []       [] []        []      |
+     fetchmail          |                      []       [] () []             |
+     fileutils          |                               [] []                |
+     findutils          |                []    []       []                   |
+     flex               |                      []       [] []                |
+     fslint             |                                  []                |
+     gas                |                                                    |
+     gawk               |                      []       [] []                |
+     gbiff              |                                  []                |
+     gcal               |                      []                            |
+     gcc                |                                  []                |
+     gettext-examples   | []                   []          [] []          [] |
+     gettext-runtime    |             []       []       [] []             [] |
+     gettext-tools      |                      []          []                |
+     gimp-print         |                         []    [] []        []      |
+     gip                |                []                                  |
+     gliv               |                                  []                |
+     glunarclock        |                []                                  |
+     gmult              | []                               []                |
+     gnubiff            |                                  ()                |
+     gnucash            |                                  () ()     []      |
+     gnucash-glossary   |                               [] ()                |
+     gnuedu             |                                                    |
+     gnulib             | []          [] []    []       [] []                |
+     gnunet-gtk         |                                                    |
+     gnutls             |                                                    |
+     gpe-aerial         |                         []       []                |
+     gpe-beam           |                         []       []                |
+     gpe-calendar       |                                                    |
+     gpe-clock          |                         []       []                |
+     gpe-conf           |                         []       []                |
+     gpe-contacts       |                                                    |
+     gpe-edit           |                         []                         |
+     gpe-filemanager    |                                                    |
+     gpe-go             |                         []                         |
+     gpe-login          |                         []       []                |
+     gpe-ownerinfo      |                         []       []                |
+     gpe-package        |                                                    |
+     gpe-sketchbook     |                         []       []                |
+     gpe-su             |                         []       []                |
+     gpe-taskmanager    |                         []       []                |
+     gpe-timesheet      |                         []                         |
+     gpe-today          |                         []       []                |
+     gpe-todo           |                                                    |
+     gphoto2            |                         []    [] []        []      |
+     gprof              |                               [] []                |
+     gpsdrive           |                                  ()    ()          |
+     gramadoir          | []                               []                |
+     grep               | []          [] []    []          [] []             |
+     gretl              |                                                    |
+     gsasl              |                                                    |
+     gss                |                                                    |
+     gst-plugins        | []                   [] []    []                   |
+     gst-plugins-base   |                []    []       []                   |
+     gst-plugins-good   | []       []    []    [] []    []           []      |
+     gstreamer          | []             []    [] []    [] []        []      |
+     gtick              |                                  ()                |
+     gtkam              |                         []    [] []                |
+     gtkorphan          |                []                []                |
+     gtkspell           |             []                   [] []          [] |
+     gutenprint         |                               []                   |
+     hello              |                []    []       [] []             [] |
+     id-utils           |                               [] []                |
+     impost             |                                                    |
+     indent             |                      []          []             [] |
+     iso_3166           |                                  []             [] |
+     iso_3166_2         |                                                    |
+     iso_4217           |                                  []                |
+     iso_639            |                                  []             [] |
+     jpilot             |                         []                         |
+     jtag               |                                                    |
+     jwhois             |                                                    |
+     kbd                |                         []    [] [] []             |
+     keytouch           |                                                    |
+     keytouch-editor    |                                                    |
+     keytouch-keyboa... |                                                    |
+     latrine            |                                  ()                |
+     ld                 |                               []                   |
+     leafpad            |                []    [] []       [] []             |
+     libc               |                      [] []    [] [] []             |
+     libexif            |                                  []                |
+     libextractor       |                                  []                |
+     libgpewidget       |                         []    [] []                |
+     libgpg-error       |                                  []                |
+     libgphoto2         |                               [] []                |
+     libgphoto2_port    |                               [] []                |
+     libgsasl           |                                                    |
+     libiconv           |                                  []             [] |
+     libidn             |                               []                [] |
+     lifelines          |                               [] ()                |
+     lilypond           |                                  []                |
+     lingoteach         |                                                    |
+     lynx               |                      [] []    [] []                |
+     m4                 |                         []    [] [] []             |
+     mailutils          |                      []                            |
+     make               |                               [] []                |
+     man-db             |                      [] ()    [] []                |
+     minicom            |                         []    [] []                |
+     mysecretdiary      |                               [] []                |
+     nano               |                []    []          []                |
+     nano_1_0           |                      [] ()    [] []                |
+     opcodes            |                                  []                |
+     parted             |                                                    |
+     pilot-qof          |                                            []      |
+     psmisc             |                []                                  |
+     pwdutils           |                                                    |
+     python             |                                                    |
+     qof                |                                                    |
+     radius             |                      []                            |
+     recode             |             []       []       [] [] []          [] |
+     rpm                |                         []    []                   |
+     screem             |                                                    |
+     scrollkeeper       |          [] []       [] [] [] [] []        []      |
+     sed                |                      []          []             [] |
+     sh-utils           |                               [] []                |
+     shared-mime-info   |                []       []                 []   [] |
+     sharutils          |                []    [] []    [] [] []             |
+     shishi             |                                                    |
+     silky              |                                                    |
+     skencil            |                               [] ()                |
+     sketch             |                               [] ()                |
+     solfege            |                                                    |
+     soundtracker       |                               [] []                |
+     sp                 |                                  []                |
+     stardict           |                         []                         |
+     system-tools-ba... |       []       [] [] [] []    [] [] []     []      |
+     tar                |                []                                  |
+     texinfo            |                               [] []             [] |
+     textutils          |                      []       [] []                |
+     tin                |                                  ()        ()      |
+     tp-robot           |                                  []                |
+     tuxpaint           | []             []             [] []        []      |
+     unicode-han-tra... |                                                    |
+     unicode-transla... |                                                    |
+     util-linux         |                      [] []    [] []                |
+     vorbis-tools       |             []          []    []           []      |
+     wastesedge         |                                  ()                |
+     wdiff              |                      []       [] []        []      |
+     wget               |                      []          []                |
+     xchat              |             [] []    []          [] []     []      |
+     xkeyboard-config   |                                                    |
+     xpad               |                []             []                   |
+                        +----------------------------------------------------+
+                          af am ar az be bg bs ca cs cy da de el en en_GB eo
+                          10  0  1  2  9 22  1 42 41  2 60 95 16  1  17   16
+
+                          es et eu fa fi fr  ga gl gu he hi hr hu id is it
+                        +--------------------------------------------------+
+     GNUnet             |                                                  |
+     a2ps               |    []       [] []                             () |
+     aegis              |                                                  |
+     ant-phone          |                []                                |
+     anubis             |                []                                |
+     ap-utils           |             [] []                                |
+     aspell             |                []  []                         [] |
+     bash               | []             []                    []          |
+     batchelor          |                []  []                            |
+     bfd                | []                                               |
+     bibshelf           | []                 []                         [] |
+     binutils           | []          [] []                                |
+     bison              | [] []          []  []                   []    [] |
+     bison-runtime      |    []          []  []                   []    [] |
+     bluez-pin          |             [] []  []                [] []       |
+     cflow              |                    []                            |
+     clisp              | []             []                                |
+     console-tools      |                                                  |
+     coreutils          | [] []       [] []  []                []          |
+     cpio               | []             []  []                            |
+     cpplib             | []             []                                |
+     cryptonit          |                []                                |
+     darkstat           | []             ()  []                [] []       |
+     dialog             | [] [] []    [] []  []                []       [] |
+     diffutils          | []          [] []  [] []    []       [] []    [] |
+     doodle             |                    []                         [] |
+     e2fsprogs          | []             []                             [] |
+     enscript           |                []  []             []             |
+     error              | []          [] []  []                []          |
+     fetchmail          | []                                               |
+     fileutils          | [] []          []  []                []       [] |
+     findutils          |    []          []  []                []          |
+     flex               | []             []  []                            |
+     fslint             |                []                                |
+     gas                | []             []                                |
+     gawk               | []             []  []       []                   |
+     gbiff              |                []                                |
+     gcal               | []             []                                |
+     gcc                | []                                               |
+     gettext-examples   | []             []  []                [] []    [] |
+     gettext-runtime    | []          [] []  []                   []    [] |
+     gettext-tools      | []             []                             [] |
+     gimp-print         | []             []                                |
+     gip                | []    []       []                                |
+     gliv               |                ()                                |
+     glunarclock        |             []     []                []          |
+     gmult              |       []       []                             [] |
+     gnubiff            |                ()                             () |
+     gnucash            | ()             ()                    ()          |
+     gnucash-glossary   | []                                            [] |
+     gnuedu             | []                                               |
+     gnulib             | [] [] []    [] []  [] []             []          |
+     gnunet-gtk         |                                                  |
+     gnutls             |                                                  |
+     gpe-aerial         | []             []                                |
+     gpe-beam           | []             []                                |
+     gpe-calendar       |                                                  |
+     gpe-clock          | []          [] []                    []          |
+     gpe-conf           |                []                                |
+     gpe-contacts       | []             []                                |
+     gpe-edit           | []             []                    [] []       |
+     gpe-filemanager    | []                                               |
+     gpe-go             | []             []                    []          |
+     gpe-login          | []             []                    []          |
+     gpe-ownerinfo      | []          [] []                    [] []       |
+     gpe-package        | []                                               |
+     gpe-sketchbook     | []             []                                |
+     gpe-su             | []          [] []                    []          |
+     gpe-taskmanager    | []          [] []                                |
+     gpe-timesheet      | []             []  []                   []       |
+     gpe-today          | []          [] []  []                            |
+     gpe-todo           | []                                               |
+     gphoto2            | []          [] []                    []       [] |
+     gprof              | []             []  []                   []       |
+     gpsdrive           | ()             ()                    []       () |
+     gramadoir          |                []  []                            |
+     grep               | [] [] []    [] []  [] []    []    [] [] []    [] |
+     gretl              | []             []                             [] |
+     gsasl              |                    []                   []       |
+     gss                |                []                                |
+     gst-plugins        |                []                    []       [] |
+     gst-plugins-base   |                                      []       [] |
+     gst-plugins-good   |       []                             []       [] |
+     gstreamer          |             []                       []       [] |
+     gtick              |                    []                            |
+     gtkam              | []             []                    []       [] |
+     gtkorphan          |                []                             [] |
+     gtkspell           | []    []    [] []  []                         [] |
+     gutenprint         |                                      []          |
+     hello              | [] [] [] [] [] []  [] []    []    [] [] []    [] |
+     id-utils           |                []  []                [] []    [] |
+     impost             |                []  []                            |
+     indent             | [] [] []    [] []  [] []             [] []    [] |
+     iso_3166           |             [] []                    []          |
+     iso_3166_2         |                []                                |
+     iso_4217           |    []       []        []             []          |
+     iso_639            |          [] [] []  []                []          |
+     jpilot             | []             []                                |
+     jtag               |                []                                |
+     jwhois             | []             []                    [] []    [] |
+     kbd                | []             []                                |
+     keytouch           |                    []                            |
+     keytouch-editor    |                    []                            |
+     keytouch-keyboa... |                    []                            |
+     latrine            |                []  []                         [] |
+     ld                 | []             []                                |
+     leafpad            | []             []  []       []       []       [] |
+     libc               | []          [] []     []             []          |
+     libexif            | []                                               |
+     libextractor       |                    []                            |
+     libgpewidget       | []             []  []                [] []       |
+     libgpg-error       |                                                  |
+     libgphoto2         | []             []                             [] |
+     libgphoto2_port    |                []                             [] |
+     libgsasl           |                []  []                            |
+     libiconv           |    []              []                            |
+     libidn             |                []                             [] |
+     lifelines          |                ()                                |
+     lilypond           |                []                                |
+     lingoteach         |                []                       []    [] |
+     lynx               |    []                                []       [] |
+     m4                 |                []  [] []                []       |
+     mailutils          | []             []                                |
+     make               | []          [] []  [] []    []    []    []       |
+     man-db             | ()                                               |
+     minicom            | []          [] []                    []          |
+     mysecretdiary      | []             []                       []       |
+     nano               | []    []       []  []                []       [] |
+     nano_1_0           | []             []     []                []    [] |
+     opcodes            | []          [] []  []                            |
+     parted             | []             []                       []    [] |
+     pilot-qof          |                                                  |
+     psmisc             |       []                             []       [] |
+     pwdutils           |                                                  |
+     python             |                                                  |
+     qof                |                                         []       |
+     radius             | []             []                                |
+     recode             | []             []  [] []    []       [] []    [] |
+     rpm                |                []                       []       |
+     screem             |                                                  |
+     scrollkeeper       | []          []                       []          |
+     sed                | [] []          []  []                []          |
+     sh-utils           | [] []       [] []  []                []       [] |
+     shared-mime-info   | []    []    [] []                    []       [] |
+     sharutils          | [] []       [] []  [] []             []       [] |
+     shishi             |                                                  |
+     silky              |                []                                |
+     skencil            | []             []                                |
+     sketch             | []             []                                |
+     solfege            |                                               [] |
+     soundtracker       | []             []                             [] |
+     sp                 |                []                                |
+     stardict           |                                      []          |
+     system-tools-ba... | []    []    [] []                 [] [] []    [] |
+     tar                | [] []       [] []  []                []       [] |
+     texinfo            |                []           []                   |
+     textutils          | []             []  [] []             []          |
+     tin                |    []          ()                                |
+     tp-robot           |             [] []  []                []          |
+     tuxpaint           |                    []                []          |
+     unicode-han-tra... |                                                  |
+     unicode-transla... |                []  []                            |
+     util-linux         | [] []       [] []                    [] []    [] |
+     vorbis-tools       | []             []                                |
+     wastesedge         |                ()                                |
+     wdiff              | [] []          []  [] []             [] []    [] |
+     wget               |    []       [] []  []             [] [] []    [] |
+     xchat              | []    []    [] []        []    []    []       [] |
+     xkeyboard-config   |             [] []                    []       [] |
+     xpad               | []                 []                []          |
+                        +--------------------------------------------------+
+                          es et eu fa fi fr  ga gl gu he hi hr hu id is it
+                          88 22 14  2 40 115 61 14  1  8  1  6 59 31  0 52
+
+                          ja ko ku ky lg lt lv mk mn ms mt nb ne nl nn no
+                        +-------------------------------------------------+
+     GNUnet             |                                                 |
+     a2ps               |    ()                      []          []    () |
+     aegis              |                                        ()       |
+     ant-phone          |                                        []       |
+     anubis             |                            []    []    []       |
+     ap-utils           |                            []                   |
+     aspell             |                         []             []       |
+     bash               |                                        []       |
+     batchelor          |                            []          []       |
+     bfd                |                                                 |
+     bibshelf           |                            []                   |
+     binutils           |                                                 |
+     bison              |                            []    []    []       |
+     bison-runtime      |                            []    []    []       |
+     bluez-pin          |       []                   []          []       |
+     cflow              |                                                 |
+     clisp              |                                        []       |
+     console-tools      |                                                 |
+     coreutils          |                                        []       |
+     cpio               |                                                 |
+     cpplib             |                                        []       |
+     cryptonit          |                                        []       |
+     darkstat           |                            []          []       |
+     dialog             |                            []          []       |
+     diffutils          | []                         []          []       |
+     doodle             |                                                 |
+     e2fsprogs          |                                        []       |
+     enscript           |                                        []       |
+     error              |                                        []       |
+     fetchmail          | []                                     []       |
+     fileutils          | []          []                                  |
+     findutils          |                                        []       |
+     flex               |    []                                  []       |
+     fslint             |                            []          []       |
+     gas                |                                                 |
+     gawk               | []                                     []       |
+     gbiff              |                                        []       |
+     gcal               |                                                 |
+     gcc                |                                                 |
+     gettext-examples   | []                                     []       |
+     gettext-runtime    | [] []                                  []       |
+     gettext-tools      | [] []                                           |
+     gimp-print         | []                                     []       |
+     gip                |                            []          []       |
+     gliv               |                                        []       |
+     glunarclock        |                            []          []       |
+     gmult              | []                         []                   |
+     gnubiff            |                                                 |
+     gnucash            | ()                               ()             |
+     gnucash-glossary   |                                        []       |
+     gnuedu             |                                                 |
+     gnulib             | [] []                      []          []       |
+     gnunet-gtk         |                                                 |
+     gnutls             |                                                 |
+     gpe-aerial         |                                        []       |
+     gpe-beam           |                                        []       |
+     gpe-calendar       | []                                              |
+     gpe-clock          | [] []                                  []       |
+     gpe-conf           |    []                                  []       |
+     gpe-contacts       |    []                                           |
+     gpe-edit           | [] []                                  []       |
+     gpe-filemanager    | [] []                                           |
+     gpe-go             | [] []                                  []       |
+     gpe-login          | [] []                                  []       |
+     gpe-ownerinfo      | []                                     []       |
+     gpe-package        | [] []                                           |
+     gpe-sketchbook     |    []                                  []       |
+     gpe-su             | [] []                                  []       |
+     gpe-taskmanager    | [] [] []                               []       |
+     gpe-timesheet      |                                        []       |
+     gpe-today          | []                                     []       |
+     gpe-todo           | []                                              |
+     gphoto2            | []                                     []       |
+     gprof              |                                                 |
+     gpsdrive           | ()                                     ()    () |
+     gramadoir          |                                        ()       |
+     grep               | []       []                      []    []       |
+     gretl              |                                                 |
+     gsasl              |                                        []       |
+     gss                |                                                 |
+     gst-plugins        |                                        []       |
+     gst-plugins-base   |                                                 |
+     gst-plugins-good   |                                        []       |
+     gstreamer          |                                        []       |
+     gtick              |                                                 |
+     gtkam              | []                                              |
+     gtkorphan          |                                        []       |
+     gtkspell           |                         []             []       |
+     gutenprint         |                                                 |
+     hello              | [] []                      []    []    [] []    |
+     id-utils           |                                        []       |
+     impost             |                                                 |
+     indent             | []                                     []       |
+     iso_3166           |                                        []       |
+     iso_3166_2         |                                        []       |
+     iso_4217           | []                      []             []       |
+     iso_639            | []                                     []       |
+     jpilot             | ()                                     ()    () |
+     jtag               |                                                 |
+     jwhois             |                                        []       |
+     kbd                |                                        []       |
+     keytouch           |                                        []       |
+     keytouch-editor    |                                                 |
+     keytouch-keyboa... |                                                 |
+     latrine            |                                        []       |
+     ld                 |                                                 |
+     leafpad            | []             []                               |
+     libc               | [] []                            []    []    [] |
+     libexif            |                                                 |
+     libextractor       |                                                 |
+     libgpewidget       |                                        []       |
+     libgpg-error       |                                                 |
+     libgphoto2         | []                                              |
+     libgphoto2_port    | []                                              |
+     libgsasl           |                                        []       |
+     libiconv           |                                                 |
+     libidn             | []                                     []       |
+     lifelines          |                                        []       |
+     lilypond           |                                                 |
+     lingoteach         |                                        []       |
+     lynx               | []                                     []       |
+     m4                 | []                                     []       |
+     mailutils          |                                                 |
+     make               | [] []                                  []       |
+     man-db             | ()                                              |
+     minicom            | []                                              |
+     mysecretdiary      |                                        []       |
+     nano               |                            []    []    []       |
+     nano_1_0           |                            []    []       []    |
+     opcodes            |                                        []       |
+     parted             | []                                     []       |
+     pilot-qof          |                                                 |
+     psmisc             | []                               []    []       |
+     pwdutils           |                                                 |
+     python             |                                                 |
+     qof                |                                                 |
+     radius             |                                                 |
+     recode             |                                        []       |
+     rpm                | [] []                                           |
+     screem             | []                                              |
+     scrollkeeper       |                                  [] [] [] []    |
+     sed                | []                                     []       |
+     sh-utils           | []                               []             |
+     shared-mime-info   |    []          []                []    [] []    |
+     sharutils          | []                                     []       |
+     shishi             |                                                 |
+     silky              |                                        []       |
+     skencil            |                                                 |
+     sketch             |                                                 |
+     solfege            |                                                 |
+     soundtracker       |                                                 |
+     sp                 | ()                                              |
+     stardict           |                      []                []       |
+     system-tools-ba... | [] []          []                      []       |
+     tar                | []       []                            []       |
+     texinfo            | []                               []    []       |
+     textutils          | [] []                            []             |
+     tin                |                                                 |
+     tp-robot           |                                        []       |
+     tuxpaint           |                                           []    |
+     unicode-han-tra... |                                                 |
+     unicode-transla... |                                                 |
+     util-linux         | []                                     []       |
+     vorbis-tools       |                                        []       |
+     wastesedge         |                                        []       |
+     wdiff              |                            []    []             |
+     wget               | []                                     []       |
+     xchat              | [] []                []                []       |
+     xkeyboard-config   |                                        []       |
+     xpad               |    []                      []          []       |
+                        +-------------------------------------------------+
+                          ja ko ku ky lg lt lv mk mn ms mt nb ne nl nn no
+                          52 24  2  2  1  3  0  2  3 21  0 15  1 97  5  1
+
+                          nso or pa pl pt pt_BR rm ro ru rw sk sl sq sr sv  ta
+                        +------------------------------------------------------+
+     GNUnet             |                                                      |
+     a2ps               |           ()     []      [] []       []    [] []     |
+     aegis              |                          () ()                       |
+     ant-phone          |                          []                   []     |
+     anubis             |           []             [] []                       |
+     ap-utils           |           ()                                         |
+     aspell             |                          [] []                       |
+     bash               |                  []      [] []                       |
+     batchelor          |                          []                   []     |
+     bfd                |                                                      |
+     bibshelf           |                                               []     |
+     binutils           |                             []                []     |
+     bison              |           []     []      [] []                []     |
+     bison-runtime      |           []             []          []       []     |
+     bluez-pin          |           []     []   [] [] []    [] []    [] []     |
+     cflow              |           []                                         |
+     clisp              |                             []                       |
+     console-tools      |                             []                       |
+     coreutils          |           []                []       []       []     |
+     cpio               |           []                []                []     |
+     cpplib             |                                               []     |
+     cryptonit          |                  []                           []     |
+     darkstat           |           []     []      []       []       [] []     |
+     dialog             |           [] []  []   [] [] [] []          [] []     |
+     diffutils          |           []     []      [] []             [] []     |
+     doodle             |                                         []    []     |
+     e2fsprogs          |           []                                  []     |
+     enscript           |                  []      [] []       []       []     |
+     error              |                  []      []       []          []     |
+     fetchmail          |           []                []          []           |
+     fileutils          |           []             [] []       []       []     |
+     findutils          |           [] []          []       [] []       []     |
+     flex               |           []     []      [] []                []     |
+     fslint             |                  []      []                [] []     |
+     gas                |                                                      |
+     gawk               |           []     []      []                   []     |
+     gbiff              |                          []                          |
+     gcal               |                                               []     |
+     gcc                |                                               []     |
+     gettext-examples   |           [] []          [] []    [] []    [] []     |
+     gettext-runtime    |           [] []          [] []    [] []    [] []     |
+     gettext-tools      |           []             [] []    [] []    [] []     |
+     gimp-print         |                                   []          []     |
+     gip                |                       []          []       [] []     |
+     gliv               |                  []      []       []          []     |
+     glunarclock        |                  []      [] []    []       [] []     |
+     gmult              |                       [] []                [] []     |
+     gnubiff            |                          ()                          |
+     gnucash            |           ()                                  []     |
+     gnucash-glossary   |              []                   []          []     |
+     gnuedu             |                                                      |
+     gnulib             |           []             [] []       []       []     |
+     gnunet-gtk         |                                               []     |
+     gnutls             |           []                                  []     |
+     gpe-aerial         |              []  []      [] []       []    [] []     |
+     gpe-beam           |              []  []      [] []       []    [] []     |
+     gpe-calendar       |                             []                       |
+     gpe-clock          |              []  []      [] []    [] []    [] []     |
+     gpe-conf           |              []  []      [] []    [] []       []     |
+     gpe-contacts       |                          [] []       []    [] []     |
+     gpe-edit           |              []  []      [] []    [] []    [] []     |
+     gpe-filemanager    |                                      []       []     |
+     gpe-go             |                  []      [] []       []    [] []     |
+     gpe-login          |              []  []      [] []    [] []    [] []     |
+     gpe-ownerinfo      |              []  []      [] []    [] []    [] []     |
+     gpe-package        |                                      []       []     |
+     gpe-sketchbook     |              []  []      [] []    [] []    [] []     |
+     gpe-su             |              []  []      [] []    [] []    [] []     |
+     gpe-taskmanager    |              []  []      [] []    [] []    [] []     |
+     gpe-timesheet      |              []  []      [] []    [] []    [] []     |
+     gpe-today          |              []  []      [] []    [] []    [] []     |
+     gpe-todo           |                             []       []    [] []     |
+     gphoto2            |           []             []       []       [] []     |
+     gprof              |                  []      []                   []     |
+     gpsdrive           |        []                []                   []     |
+     gramadoir          |                                   []          []     |
+     grep               |           [] []  []      [] []       []    [] []     |
+     gretl              |           []                                         |
+     gsasl              |           []                               [] []     |
+     gss                |           []             []                   []     |
+     gst-plugins        |     []                                  [] [] []     |
+     gst-plugins-base   |                                               []     |
+     gst-plugins-good   |     []                                  [] [] []     |
+     gstreamer          |                                         [] [] []     |
+     gtick              |                             []                       |
+     gtkam              |           []     []         []                []     |
+     gtkorphan          |                                               []     |
+     gtkspell           |                  []   [] [] []    [] []    [] []     |
+     gutenprint         |                                               []     |
+     hello              |           []     []      [] []    [] []    [] []     |
+     id-utils           |                  []      [] []                []     |
+     impost             |                                               []     |
+     indent             |                  []      [] []    []       [] []     |
+     iso_3166           |              []                []    [] [] [] []     |
+     iso_3166_2         |                                                      |
+     iso_4217           |                                []    []    [] []     |
+     iso_639            |                                []    []    [] []     |
+     jpilot             |                                                      |
+     jtag               |                                   []                 |
+     jwhois             |           []     []      []                   []     |
+     kbd                |           []             []                   []     |
+     keytouch           |                                               []     |
+     keytouch-editor    |                                               []     |
+     keytouch-keyboa... |                                               []     |
+     latrine            |                          []                   []     |
+     ld                 |                                               []     |
+     leafpad            |           [] []             []    []          []  [] |
+     libc               |           []     []         []    []          []     |
+     libexif            |           []                                         |
+     libextractor       |                          []                   []     |
+     libgpewidget       |              []  []      []       [] []    [] []     |
+     libgpg-error       |           []             []                          |
+     libgphoto2         |           []                                         |
+     libgphoto2_port    |           []                []                []     |
+     libgsasl           |           []             []                [] []     |
+     libiconv           |                                      []    []        |
+     libidn             |           []                               [] ()     |
+     lifelines          |           []                                  []     |
+     lilypond           |                                                      |
+     lingoteach         |                  []                                  |
+     lynx               |                  []         []                []     |
+     m4                 |           []     []      [] []                []     |
+     mailutils          |           []             [] []                []     |
+     make               |           []     []         []                []     |
+     man-db             |                          []                   []     |
+     minicom            |           []     []      [] []                []     |
+     mysecretdiary      |                  []      [] []                []     |
+     nano               |                  []      []                   []     |
+     nano_1_0           |           []             [] []                []     |
+     opcodes            |                          []                   []     |
+     parted             |           []                                         |
+     pilot-qof          |                                               []     |
+     psmisc             |           []                                  []     |
+     pwdutils           |           []                                  []     |
+     python             |                                                      |
+     qof                |                  []                           []     |
+     radius             |           []                []                       |
+     recode             |           [] []  []      [] []       []       []     |
+     rpm                |           [] []             []                []     |
+     screem             |                                                      |
+     scrollkeeper       |           []             [] []    []    [] [] []     |
+     sed                |           [] []  []      [] []    [] []    [] []     |
+     sh-utils           |                             []       []    []        |
+     shared-mime-info   |              []  []                     [] [] []     |
+     sharutils          |           []                []             [] []     |
+     shishi             |           []                                         |
+     silky              |                                   []                 |
+     skencil            |              []  []                           []     |
+     sketch             |              []  []                           []     |
+     solfege            |                                               []     |
+     soundtracker       |                                   []          []     |
+     sp                 |                                                      |
+     stardict           |                             []    []          []     |
+     system-tools-ba... |        [] [] []  []      []             [] [] []  [] |
+     tar                |           []             [] []       []       []     |
+     texinfo            |           []             [] []                []     |
+     textutils          |                             []       []       []     |
+     tin                |                             ()                       |
+     tp-robot           |                             []                       |
+     tuxpaint           |              []                      [] [] [] []     |
+     unicode-han-tra... |                                                      |
+     unicode-transla... |                                                      |
+     util-linux         |                  []         []       []       []     |
+     vorbis-tools       |                          [] []                       |
+     wastesedge         |                                                      |
+     wdiff              |           []     []      [] []    []          []     |
+     wget               |              []             []    []          []     |
+     xchat              |        []                   []    [] [] [] [] []     |
+     xkeyboard-config   |                                      []       []     |
+     xpad               |                                   [] []       []     |
+                        +------------------------------------------------------+
+                          nso or pa pl pt pt_BR rm ro ru rw sk sl sq sr sv  ta
+                           0   2  3 58 30  54    5 73 72  4 40 46 11 50 128  2
+
+                          tg th tk tr uk ven vi  wa xh zh_CN zh_HK zh_TW zu
+                        +---------------------------------------------------+
+     GNUnet             |                    []                             |  2
+     a2ps               |          [] []     []                             | 19
+     aegis              |                                                   |  0
+     ant-phone          |          []        []                             |  6
+     anubis             |          [] []     []                             | 11
+     ap-utils           |             ()     []                             |  4
+     aspell             |             []     []  []                         | 15
+     bash               |                    []                             | 11
+     batchelor          |          []        []                             |  9
+     bfd                |                                                   |  1
+     bibshelf           |                    []                             |  7
+     binutils           |          []        []                     []      |  9
+     bison              |          []        []                     []      | 19
+     bison-runtime      |                    []         []          []      | 15
+     bluez-pin          |          [] []     []  []     []          []      | 28
+     cflow              |             []     []                             |  5
+     clisp              |                                                   |  6
+     console-tools      |          []        []                             |  5
+     coreutils          |          []        []                             | 16
+     cpio               |          [] []     []                             |  9
+     cpplib             |          []        []         []          []      | 11
+     cryptonit          |                                                   |  5
+     darkstat           |                    []         ()          ()      | 15
+     dialog             |          [] []     []         []          []      | 30
+     diffutils          |          []        []         []          []      | 28
+     doodle             |                    []                             |  6
+     e2fsprogs          |          []        []                             | 10
+     enscript           |          [] []     []                             | 16
+     error              |          []        []         []          []      | 18
+     fetchmail          |          []        []                             | 12
+     fileutils          |          []                   []          []      | 18
+     findutils          |          []        []                     []      | 17
+     flex               |          []        []                             | 15
+     fslint             |                    []                             |  9
+     gas                |          []                                       |  3
+     gawk               |          []        []                             | 15
+     gbiff              |                    []                             |  5
+     gcal               |          []                                       |  5
+     gcc                |          []                   []          []      |  6
+     gettext-examples   |          [] []     []         []    []    []      | 27
+     gettext-runtime    |          [] []     []         []    []    []      | 28
+     gettext-tools      |          [] []     []         []          []      | 19
+     gimp-print         |             []     []                             | 12
+     gip                |                    []                     []      | 12
+     gliv               |          []        []                             |  8
+     glunarclock        |                    []  []                 []      | 15
+     gmult              |          []        []         []          []      | 15
+     gnubiff            |                    []                             |  1
+     gnucash            |          ()                                       |  2
+     gnucash-glossary   |                    []                     []      |  9
+     gnuedu             |                    []                             |  2
+     gnulib             |          [] []     []         []          []      | 28
+     gnunet-gtk         |                                                   |  1
+     gnutls             |                                                   |  2
+     gpe-aerial         |                    []         []                  | 14
+     gpe-beam           |                    []         []                  | 14
+     gpe-calendar       |                    []                             |  3
+     gpe-clock          |          []        []  []     []                  | 21
+     gpe-conf           |                    []         []                  | 14
+     gpe-contacts       |                    []         []                  | 10
+     gpe-edit           |          []        []  []                 []      | 20
+     gpe-filemanager    |                    []                             |  6
+     gpe-go             |          []        []                             | 15
+     gpe-login          |          []        []  []     []          []      | 21
+     gpe-ownerinfo      |          []        []         []          []      | 21
+     gpe-package        |                    []                             |  6
+     gpe-sketchbook     |          []        []                             | 16
+     gpe-su             |          []        []         []                  | 20
+     gpe-taskmanager    |          []        []         []                  | 20
+     gpe-timesheet      |          []        []         []          []      | 18
+     gpe-today          |          []        []  []     []          []      | 21
+     gpe-todo           |                    []                             |  7
+     gphoto2            |             []     []         []          []      | 20
+     gprof              |          []        []                             | 11
+     gpsdrive           |                                                   |  4
+     gramadoir          |                    []                             |  7
+     grep               |          [] []     []                     []      | 34
+     gretl              |                                                   |  4
+     gsasl              |                    []         []                  |  8
+     gss                |                    []                             |  5
+     gst-plugins        |             []     []                     []      | 15
+     gst-plugins-base   |             []     []         []                  |  9
+     gst-plugins-good   |             []     []         []    []    []      | 20
+     gstreamer          |          [] []     []                             | 17
+     gtick              |                    []                             |  3
+     gtkam              |                    []                             | 13
+     gtkorphan          |                    []                             |  7
+     gtkspell           |             []     []  []     []    []    []      | 26
+     gutenprint         |                                                   |  3
+     hello              |          [] []     []         []          []      | 37
+     id-utils           |          []        []                             | 14
+     impost             |                    []                             |  4
+     indent             |          []        []         []          []      | 25
+     iso_3166           |       [] []        []               []            | 16
+     iso_3166_2         |                                                   |  2
+     iso_4217           |          []        []                             | 14
+     iso_639            |                    []                             | 14
+     jpilot             |          [] []     []         []                  |  7
+     jtag               |                    []                             |  3
+     jwhois             |          []        []                     []      | 13
+     kbd                |          []        []                             | 12
+     keytouch           |                    []                             |  4
+     keytouch-editor    |                                                   |  2
+     keytouch-keyboa... |                    []                             |  3
+     latrine            |          []        []                             |  8
+     ld                 |          []        []         []          []      |  8
+     leafpad            |          []        []         []          []      | 23
+     libc               |          []                   []          []      | 23
+     libexif            |                    []                             |  4
+     libextractor       |                    []                             |  5
+     libgpewidget       |                    []  []     []                  | 19
+     libgpg-error       |                    []                             |  4
+     libgphoto2         |             []                                    |  8
+     libgphoto2_port    |             []     []                     []      | 11
+     libgsasl           |                    []                             |  8
+     libiconv           |                    []                             |  7
+     libidn             |                    []         []                  | 10
+     lifelines          |                                                   |  4
+     lilypond           |                                                   |  2
+     lingoteach         |                    []                             |  6
+     lynx               |          [] []     []                             | 15
+     m4                 |                    []         []          []      | 18
+     mailutils          |             []                                    |  8
+     make               |          []        []         []                  | 20
+     man-db             |                    []                             |  6
+     minicom            |                    []                             | 14
+     mysecretdiary      |          []        []                             | 12
+     nano               |                    []                     []      | 17
+     nano_1_0           |          [] []     []                             | 18
+     opcodes            |          []        []                             | 10
+     parted             |          [] []                            []      | 10
+     pilot-qof          |                    []                             |  3
+     psmisc             |                    []                             | 10
+     pwdutils           |                    []                             |  3
+     python             |                                                   |  0
+     qof                |                    []                             |  4
+     radius             |             []                                    |  6
+     recode             |          []        []         []                  | 25
+     rpm                |          [] []     []                     []      | 14
+     screem             |                    []                             |  2
+     scrollkeeper       |          [] []     []                     []      | 26
+     sed                |          []        []                     []      | 22
+     sh-utils           |          []                                       | 15
+     shared-mime-info   |             []     []         []          []      | 24
+     sharutils          |          []        []                     []      | 23
+     shishi             |                                                   |  1
+     silky              |                    []                             |  4
+     skencil            |                    []                             |  7
+     sketch             |                                                   |  6
+     solfege            |                                                   |  2
+     soundtracker       |          []        []                             |  9
+     sp                 |          []                                       |  3
+     stardict           |             []     []         []          []      | 11
+     system-tools-ba... |    []    [] []     []     []  []          []      | 37
+     tar                |          [] []     []                     []      | 20
+     texinfo            |          []        []         []                  | 15
+     textutils          |          []                   []          []      | 17
+     tin                |                                                   |  1
+     tp-robot           |                    []         []          []      | 10
+     tuxpaint           |                    []  []                 []      | 16
+     unicode-han-tra... |                                                   |  0
+     unicode-transla... |                                                   |  2
+     util-linux         |          [] []     []                             | 20
+     vorbis-tools       |             []     []                             | 11
+     wastesedge         |                                                   |  1
+     wdiff              |          []        []                             | 22
+     wget               |          []        []                     []      | 19
+     xchat              |             []     []         []          []      | 29
+     xkeyboard-config   |          [] []     []                     []      | 11
+     xpad               |                    []         []          []      | 14
+                        +---------------------------------------------------+
+       77 teams           tg th tk tr uk ven vi  wa xh zh_CN zh_HK zh_TW zu
+      170 domains          0  1  1 77 39  0  136 10  1  48     5    54    0  2028
+
+   Some counters in the preceding matrix are higher than the number of
+visible blocks let us expect.  This is because a few extra PO files are
+used for implementing regional variants of languages, or language
+dialects.
+
+   For a PO file in the matrix above to be effective, the package to
+which it applies should also have been internationalized and
+distributed as such by its maintainer.  There might be an observable
+lag between the mere existence a PO file and its wide availability in a
+distribution.
+
+   If October 2006 seems to be old, you may fetch a more recent copy of
+this `ABOUT-NLS' file on most GNU archive sites.  The most up-to-date
+matrix with full percentage details can be found at
+`http://www.iro.umontreal.ca/contrib/po/HTML/matrix.html'.
+
+1.6 Using `gettext' in new packages
+===================================
+
+If you are writing a freely available program and want to
+internationalize it you are welcome to use GNU `gettext' in your
+package.  Of course you have to respect the GNU Library General Public
+License which covers the use of the GNU `gettext' library.  This means
+in particular that even non-free programs can use `libintl' as a shared
+library, whereas only free software can use `libintl' as a static
+library or use modified versions of `libintl'.
+
+   Once the sources are changed appropriately and the setup can handle
+the use of `gettext' the only thing missing are the translations.  The
+Free Translation Project is also available for packages which are not
+developed inside the GNU project.  Therefore the information given above
+applies also for every other Free Software Project.  Contact
+`translation@iro.umontreal.ca' to make the `.pot' files available to
+the translation teams.
+
diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..5850e46
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,4 @@
+Authors of psensor.
+
+wpitchoune@gmail.com    all files.
+linux.dabao@gmail.com   po/zh_CN.po
\ No newline at end of file
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..c5611e4
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..7d1c323
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,365 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
+2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+
+   Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.  This file is offered as-is,
+without warranty of any kind.
+
+Basic Installation
+==================
+
+   Briefly, the shell commands `./configure; make; make install' should
+configure, build, and install this package.  The following
+more-detailed instructions are generic; see the `README' file for
+instructions specific to this package.  Some packages provide this
+`INSTALL' file but do not implement all of the features documented
+below.  The lack of an optional feature in a given package is not
+necessarily a bug.  More recommendations for GNU packages can be found
+in *note Makefile Conventions: (standards)Makefile Conventions.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+   It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring.  Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+   The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'.  You need `configure.ac' if
+you want to change it or regenerate `configure' using a newer version
+of `autoconf'.
+
+   The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.
+
+     Running `configure' might take a while.  While running, it prints
+     some messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package, generally using the just-built uninstalled binaries.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.  When installing into a prefix owned by root, it is
+     recommended that the package be configured and built as a regular
+     user, and only the `make install' phase executed with root
+     privileges.
+
+  5. Optionally, type `make installcheck' to repeat any self-tests, but
+     this time using the binaries in their final installed location.
+     This target does not install anything.  Running this target as a
+     regular user, particularly if the prior `make install' required
+     root privileges, verifies that the installation completed
+     correctly.
+
+  6. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+  7. Often, you can also type `make uninstall' to remove the installed
+     files again.  In practice, not all packages have tested that
+     uninstallation works correctly, even though it is required by the
+     GNU Coding Standards.
+
+  8. Some packages, particularly those that use Automake, provide `make
+     distcheck', which can by used by developers to test that all other
+     targets like `make install' and `make uninstall' work correctly.
+     This target is generally not run by end users.
+
+Compilers and Options
+=====================
+
+   Some systems require unusual options for compilation or linking that
+the `configure' script does not know about.  Run `./configure --help'
+for details on some of the pertinent environment variables.
+
+   You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment.  Here
+is an example:
+
+     ./configure CC=c99 CFLAGS=-g LIBS=-lposix
+
+   *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+   You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you can use GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.  This
+is known as a "VPATH" build.
+
+   With a non-GNU `make', it is safer to compile the package for one
+architecture at a time in the source code directory.  After you have
+installed the package for one architecture, use `make distclean' before
+reconfiguring for another architecture.
+
+   On MacOS X 10.5 and later systems, you can create libraries and
+executables that work on multiple system types--known as "fat" or
+"universal" binaries--by specifying multiple `-arch' options to the
+compiler but only a single `-arch' option to the preprocessor.  Like
+this:
+
+     ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+                 CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+                 CPP="gcc -E" CXXCPP="g++ -E"
+
+   This is not guaranteed to produce working output in all cases, you
+may have to build one architecture at a time and combine the results
+using the `lipo' tool if you have problems.
+
+Installation Names
+==================
+
+   By default, `make install' installs the package's commands under
+`/usr/local/bin', include files under `/usr/local/include', etc.  You
+can specify an installation prefix other than `/usr/local' by giving
+`configure' the option `--prefix=PREFIX', where PREFIX must be an
+absolute file name.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files.  Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.  In general, the
+default for these options is expressed in terms of `${prefix}', so that
+specifying just `--prefix' will affect all of the other directory
+specifications that were not explicitly provided.
+
+   The most portable way to affect installation locations is to pass the
+correct locations to `configure'; however, many packages provide one or
+both of the following shortcuts of passing variable assignments to the
+`make install' command line to change installation locations without
+having to reconfigure or recompile.
+
+   The first method involves providing an override variable for each
+affected directory.  For example, `make install
+prefix=/alternate/directory' will choose an alternate location for all
+directory configuration variables that were expressed in terms of
+`${prefix}'.  Any directories that were specified during `configure',
+but not in terms of `${prefix}', must each be overridden at install
+time for the entire installation to be relocated.  The approach of
+makefile variable overrides for each directory variable is required by
+the GNU Coding Standards, and ideally causes no recompilation.
+However, some platforms have known limitations with the semantics of
+shared libraries that end up requiring recompilation when using this
+method, particularly noticeable in packages that use GNU Libtool.
+
+   The second method involves providing the `DESTDIR' variable.  For
+example, `make install DESTDIR=/alternate/directory' will prepend
+`/alternate/directory' before all installation names.  The approach of
+`DESTDIR' overrides is not required by the GNU Coding Standards, and
+does not work on platforms that have drive letters.  On the other hand,
+it does better at avoiding recompilation issues, and works well even
+when some directory options were not specified in terms of `${prefix}'
+at `configure' time.
+
+Optional Features
+=================
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+   Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+   Some packages offer the ability to configure how verbose the
+execution of `make' will be.  For these packages, running `./configure
+--enable-silent-rules' sets the default to minimal output, which can be
+overridden with `make V=1'; while running `./configure
+--disable-silent-rules' sets the default to verbose, which can be
+overridden with `make V=0'.
+
+Particular systems
+==================
+
+   On HP-UX, the default C compiler is not ANSI C compatible.  If GNU
+CC is not installed, it is recommended to use the following options in
+order to use an ANSI C compiler:
+
+     ./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
+
+and if that doesn't work, install pre-built binaries of GCC for HP-UX.
+
+   On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
+parse its `<wchar.h>' header file.  The option `-nodtk' can be used as
+a workaround.  If GNU CC is not installed, it is therefore recommended
+to try
+
+     ./configure CC="cc"
+
+and if that doesn't work, try
+
+     ./configure CC="cc -nodtk"
+
+   On Solaris, don't put `/usr/ucb' early in your `PATH'.  This
+directory contains several dysfunctional programs; working variants of
+these programs are available in `/usr/bin'.  So, if you need `/usr/ucb'
+in your `PATH', put it _after_ `/usr/bin'.
+
+   On Haiku, software installed for all users goes in `/boot/common',
+not `/usr/local'.  It is recommended to use the following options:
+
+     ./configure --prefix=/boot/common
+
+Specifying the System Type
+==========================
+
+   There may be some features `configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on.  Usually, assuming the package is built to be run on the
+_same_ architectures, `configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
+`--build=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+     CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+     OS
+     KERNEL-OS
+
+   See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+   If you are _building_ compiler tools for cross-compiling, you should
+use the option `--target=TYPE' to select the type of system they will
+produce code for.
+
+   If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+   If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+   Variables not defined in a site shell script can be set in the
+environment passed to `configure'.  However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost.  In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'.  For example:
+
+     ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+Unfortunately, this technique does not work for `CONFIG_SHELL' due to
+an Autoconf bug.  Until the bug is fixed you can use this workaround:
+
+     CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+`configure' Invocation
+======================
+
+   `configure' recognizes the following options to control how it
+operates.
+
+`--help'
+`-h'
+     Print a summary of all of the options to `configure', and exit.
+
+`--help=short'
+`--help=recursive'
+     Print a summary of the options unique to this package's
+     `configure', and exit.  The `short' variant lists options used
+     only in the top level, while the `recursive' variant lists options
+     also present in any nested packages.
+
+`--version'
+`-V'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`--cache-file=FILE'
+     Enable the cache: use and save the results of the tests in FILE,
+     traditionally `config.cache'.  FILE defaults to `/dev/null' to
+     disable caching.
+
+`--config-cache'
+`-C'
+     Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to `/dev/null' (any error
+     messages will still be shown).
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`--prefix=DIR'
+     Use DIR as the installation prefix.  *note Installation Names::
+     for more details, including other options available for fine-tuning
+     the installation locations.
+
+`--no-create'
+`-n'
+     Run the configure checks, but stop before creating any output
+     files.
+
+`configure' also accepts some other, not widely useful, options.  Run
+`configure --help' for more details.
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..b60ef2a
--- /dev/null
@@ -0,0 +1,9 @@
+SUBDIRS = po src pixmaps/scalable pixmaps/48x48 www tests
+dist_doc_DATA = README COPYING NEWS AUTHORS INSTALL
+
+desktopdir = $(datadir)/applications
+desktop_DATA = psensor.desktop
+
+EXTRA_DIST = $(desktop_DATA)
+
+
diff --git a/NEWS b/NEWS
new file mode 100644 (file)
index 0000000..4cdefcd
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,248 @@
+* v0.6.2.8
+
+** psensor: escaped - in manpage
+** psensor-server: escaped - in manpage
+** psensor: add support of libnotify 0.7
+
+* v0.6.2.7
+
+** psensor: src/glade/psensor-pref.glade, added button separator.
+** psensor: src/glade/sensor-edit.glade, fixed horiz/vert padding.
+** psensor: src/lib/measure.c, initialize time.
+** psensor: fixed freeze when click on preferences appindicator with
+   natty.
+
+* v0.6.2.6
+
+** psensor: fixed min temp/fan of the graph
+** psensor: very minor optimization (graph.c)
+
+* v0.6.2.5
+
+** psensor: dialog box for editing psensor preferences is using Glade
+** psensor: dialog box for editing sensor preferences is using Glade
+** psensor: added support of negative temperatures (lm-sensors)
+
+* v0.6.2.4
+
+** psensor, graph: fixed padding bugs 
+** psensor, graph: drawing code refactored
+** psensor: the value of the first detected sensor is displayed in the
+unity launcher entry of psensor (requires unity >=3.4.2).
+
+* v0.6.2.3
+
+** psensor-server: new global variable 'psensor_version' for lua template
+** psensor-server: /index.html replaced by /index.lua
+** avoid useless lib linkage by using --as-needed
+
+* v0.6.2.2
+
+** psensor-server: web server support binary files
+** psensor-server: added favicon.ico
+** psensor-server: moved index.lua to monitor.lua
+** psensor-server: added index.html (welcome page)
+
+* v0.6.2.1
+
+** added uptime/memory information (psensor-server web)
+** added debug mode for psensor-server (--debug)
+** when used in debug mode, psensor-server can be stopped remotely
+   using http://hostname:port/api/1.0/server/stop
+** fixed memory leak (label of lmsensor)
+** some code cleanup/refactoring
+
+* v0.6.1.7
+
+** psensor: add support of libnotify 0.7
+
+* v0.6.1.6
+
+** psensor: escaped - in manpage
+** psensor-server: escaped - in manpage
+
+* v0.6.1.5
+
+** added multi-language for hdd.c/nvidia.c/lmsensor.c
+** some code cleanup/refactoring
+
+* v0.6.1.4
+
+** fixed manpage formatting in 'REPORTING BUGS' section
+** improved manpages
+** removed few useless translations (fr/zh_CN)
+** improved error messages for remote sensors + multilanguages support
+
+* v0.6.1.3
+
+** fixed compilation error of psensor when libcurl is present but not
+   libjson0
+** suppress pointer to Textinfo manual (psensor/psensor-server).
+** added --name to help2man call (psensor/psensor-server manpages).
+** added more information in the psensor/psensor-server manpages.
+** added warning about psensor-server and security in README.
+
+* v0.6.1.1
+
+** application icon is loaded using GtkIconTheme
+** appindicator icon is now the psensor one
+** added appindicator icon for status 'attention'
+
+* v0.6.1
+
+** added style.css for psensor-server
+** use some styling in index.lua
+** fixed typo in README
+** fixed psensor-server short option -p
+** multi-language support for psensor-server
+** added some translation for French language0
+** fixed psensor-server bug: first sensor was not displayed
+
+* v0.6.0.14
+
+** psensor (gtk client):
+
+*** added global preference: graph update interval
+*** added global preference: graph monitoring duration
+*** added global preference: sensor update interval
+*** standard gnu command line interface for psensor
+*** new psensor options: --help, --version, --url
+*** added generation and installation of the psensor man
+*** added remote monitoring it requires a new optionnal dependencies
+    (libjson0 and libcurl)
+*** added internationnalization support for the UI
+*** added Simplified Chinese Language (from DaBao <linux.dabao@gmail.com>)
+
+** psensor-server:
+
+*** psensor-server is now a minimal webserver based on microhttpd.
+    Lua5.1 is used to generate HTML pages to display temperatures and
+    gtop2 information
+*** temperature information can be retrieved using a webservice based
+    on json
+*** added cpu information (requires optional libgtop-2.0)
+*** psensor-server 
+*** psensor-server options: --port, --help, --version
+*** added generation and installation of the psensor-server man
+
+** common news for psensor and psensor-server:
+
+*** moved to autoconf/automake
+*** gnu standard: use NEWS instead of CHANGES file
+*** moved LICENSE to COPYING
+
+* v0.5.1
+
+** Makefile: avoid debug compilation by default
+** Makefile: fixed duplicate server.o in OBJS_SERVER
+** moved LICENSE to copyright
+** moved CHANGES to NEWS
+** Fixed creation of directories for the target 'install'
+
+* v0.5.0
+
+** Added double buffering of the graph to avoid flickering
+** Fixed README error gconf package name
+** Refactoring makefile
+** Added desktop notification support
+** Added application indicator support
+** Fixed MT issue (UI freeze, refresh_thread)
+** Added global preferences editor (right click on the graph)
+** Added sensor preferences editor (right click on the sensor table)
+** Displayed name of each sensor can be changed
+** Position of the sensor table can be changed
+** Window decoration can be hidden
+** Added 'keep window below' setting
+
+* v0.4.5
+
+** Makefile: fixed duplicate server.o in OBJS_SERVER
+
+v0.4.4
+Added README.debian
+
+v0.4.3
+Fixed foreground graph color first time psensor is started
+Added support of gtk 2.12 (used by Debian 5.0.6 Lenny) by redefining
+gtk_dialog_get_content_area which exist since 2.14
+
+v0.4.2
+Fixed potential MT issue (refresh_thread)
+Added double buffering of the graph to avoid flickering
+Fixed minor graph code bugs
+
+v0.4.1
+Fixed README error gconf package name
+Refactoring makefile
+
+v0.4.0
+Added FAN support
+Added HDD support (using hddtemp daemon)
+Added popup menu for changing graph bg/fg colors and opacity
+Graph background can be transparent, opacity can be changed
+Fixed BR3: sensors with the same name but different chips share the same color configuration
+Fixed BR4: wrong OBJS variable and gconf when calling pkg-config in Makefile.distrib for compiling with NVidia support
+Changed website URL
+Fixed BR5: Psensor crashes during startup with "You forgot to call g_type_init()"
+
+v0.3.3
+Fixed potential MT issue  (refresh_thread)
+Improved Makefile
+
+v0.3.2
+Fixed BR4: wrong OBJS variable and gconf when calling pkg-config in Makefile.distrib for compiling with NVidia support
+Changed website URL
+Fixed BR5: Psensor crashes during startup with "You forgot to call g_type_init()"
+
+v0.3.1
+Fixed BR3: sensors with the same name but different chips share the same color configuration
+
+v0.3.0
+Sensor graph colors can be changed: click on the colored sensor cell in the information table)
+Background color of the graph can be changed: click on the graph
+Configuration is stored using GConf
+Fixed not initialized memory bug (min/max) in nvidia support
+
+v0.2.7
+Updated the website URL
+Added contact information in the README
+Backported Makefile improvement from trunk
+Removed pwiki styling of the README
+Backport: Fixed not initialized memory bug (min/max) in nvidia support
+
+
+v0.2.6
+Changed default graph colors and background
+Added vertical padding for the graph canvas
+Disabled row selection of the sensor table
+Fixed BR2: nvidia gpu is always using black color
+
+v0.2.5
+Added a basic server to retrieve remotely temperatures
+
+v0.2.4
+Added application icon
+Added .desktop file
+
+v0.2.3
+Added max and min temperature information for each sensor
+Fixed a missing #include in nvidia.c
+Small UI improvements (scrollbar for the right panel + slider)
+
+v0.2.2
+Fixed compilation warning when NVidia support is disabled
+Fixed BR1: crash when no temperature sensor is available
+
+v0.2.1
+Compilation dependance to Nvidia lib is optional
+
+v0.2.0
+Added support of NVidia GPUs
+
+v0.1.1
+Improved right panel (list of sensors) + ability to disable each sensor graph
+
+v0.1.0
+Initial release
+
+
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..9f2cf4c
--- /dev/null
+++ b/README
@@ -0,0 +1,113 @@
+Psensor - Temperature Monitoring For Linux
+------------------------------------------
+
+Psensor is a graphical temperature monitor for Linux.
+
+It can monitor:
+
+  * the temperature of the motherboard and CPU sensors (using
+    lm-sensors).
+  * the temperature of the NVidia GPUs (using XNVCtrl).
+  * the temperature of the Hard Disk Drives (using hddtemp).
+  * the rotation speed of the fans (using lm-sensors).
+  * the temperature of a remote computer.
+
+Alarms using Desktop Notification can be set to each sensor to notify
+high temperatures.
+
+For Ubuntu users, Psensor is providing an Application Indicator to
+alert users when a temperature is too high.
+
+To monitor the temperature of a remote computer:
+
+  * start psensor-server on the remote computer. The default port is
+    3131 and can be changed by using the '--port=PORT' command line
+    option.
+
+  * start psensor with the '--url' option: 
+  psensor --url=http://hostname:3131
+
+WARNING: 
+psensor-server does not provide any way to restrict the connection to
+the HTTP server, worst, no effort has been made against malicious HTTP
+attacks.  You should make the psensor-server port available only to a
+network or computer you trust by using the usual network security
+tools of the system (for example, iptables).
+
+  
+Installation
+------------
+
+Ubuntu
+------
+
+For Ubuntu, the easy way to install Psensor and Psensor-server is to
+use the dedicated PPA.
+
+For the last stable version:
+sudo apt-get apt-add-repository ppa:/jfi/psensor
+sudo apt-get update
+sudo apt-get install psensor
+
+For the last development version:
+sudo apt-get apt-add-repository ppa:/jfi/psensor-unstable
+sudo apt-get update
+sudo apt-get install psensor
+sudo apt-get install psensor-server
+
+Alternatively, you can download Ubuntu binary packages from:
+http://wpitchoune.net/psensor/files/ubuntu/
+The manual installation of the psensor and psensor-server packages
+requires also the installation of psensor-common which contains
+the multiple languages support.
+
+Installation from source archive
+--------------------------------
+
+Psensor compilation requires:
+
+ * make/gcc    
+ * lm-sensors
+ * library sensors4
+ * library gtk2
+ * library gconf2
+ * help2man 
+ * library libnotify (optional)
+ * library libappindicator (optional)
+ * library libXNVCtrl (optional)
+ * library json0 and curl (optional, required for remote monitoring)
+ * library unity (>=v3.4.2, optional)
+
+Psensor-server compilation requires:
+ * make/gcc    
+ * lm-sensors
+ * library sensors4
+ * help2man 
+ * library libmicrohttpd 
+ * library json0
+ * library LUA5.1 (optional, required to enable HTML page generation   
+ of the psensor-server webserver)
+ * library gtop2 (optional, required for CPU usage)
+
+Compilation and Installation Steps
+----------------------------------
+
+ * Extract files from the source archive
+ * Compilation:
+   ./configure
+   make clean all
+   
+ * Installation:
+   make install
+
+ * Start the sensor detection script: 'sensors-detect' and follows the
+instructions
+
+ * Verify the sensor detection by running: 'sensors'
+
+ * Run 'psensor'
+
+Contact
+-------
+Bugs and comments can be sent to wpitchoune@gmail.com
+Home page: http://wpitchoune.net/psensor
\ No newline at end of file
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..17410da
--- /dev/null
@@ -0,0 +1,221 @@
+#                                               -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ([2.64])
+AC_INIT([psensor], [0.6.2.8],[wpitchoune@gmail.com],[psensor],[http://wpitchoune.net/psensor])
+
+AM_INIT_AUTOMAKE([-Wall -Werror gnu])
+
+AC_CONFIG_SRCDIR([src/compat.h])
+AC_CONFIG_HEADERS([config.h])
+
+# Checks for programs.
+AC_PROG_CC
+AM_PROG_CC_C_O
+
+# Checks lib build
+AC_PROG_RANLIB
+
+# Checks for header files.
+AC_PATH_X
+AC_CHECK_HEADERS([arpa/inet.h netinet/in.h stdint.h stdlib.h string.h sys/socket.h sys/time.h unistd.h getopt.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_TYPE_SIZE_T
+AC_TYPE_SSIZE_T
+
+# Checks for library functions.
+AC_FUNC_MALLOC
+AC_FUNC_REALLOC
+AC_CHECK_FUNCS([gettimeofday memmove socket strdup strtol])
+
+AM_GNU_GETTEXT_VERSION([0.16])
+AM_GNU_GETTEXT([external])
+
+############### common 
+
+# Checks sensors, required by psensor and psensor-server
+AC_CHECK_LIB(sensors, sensors_init)
+AC_CHECK_HEADERS([sensors/sensors.h sensors/errors.h])
+SENSORS_LIBS=-lsensors
+AC_SUBST(SENSORS_LIBS)
+
+############### psensor 
+
+### Required
+
+PKG_CHECK_MODULES(X11, x11)
+AC_SUBST(X11_CFLAGS)
+AC_SUBST(X11_LIBS)
+
+PKG_CHECK_MODULES(XEXT, xext)
+AC_SUBST(XEXT_CFLAGS)
+AC_SUBST(XEXT_LIBS)
+
+# Checks GTK 
+PKG_CHECK_MODULES(GTK, gtk+-2.0 )
+AC_SUBST(GTK_CFLAGS)
+AC_SUBST(GTK_LIBS)
+
+# Check GCONF
+PKG_CHECK_MODULES(GCONF, gconf-2.0)
+AC_SUBST(GCONF_CFLAGS)
+AC_SUBST(GCONF_LIBS)
+
+### Optional
+
+# Check libnotify
+LIBNOTIFY_LIBS=
+PKG_CHECK_MODULES(LIBNOTIFY, 
+  libnotify, 
+  [AC_DEFINE([HAVE_LIBNOTIFY],[1],[Use desktop notification])], 
+  [AC_MSG_WARN("Desktop notification disabled")])
+AM_CONDITIONAL(LIBNOTIFY, test -n "$LIBNOTIFY_LIBS")
+AC_SUBST(LIBNOTIFY_CFLAGS)
+AC_SUBST(LIBNOTIFY_LIBS)
+
+# Checks AppIndicator 
+APPINDICATOR_LIBS=
+PKG_CHECK_MODULES(APPINDICATOR, 
+     appindicator-0.1 = 0.2.9 , 
+     [AC_DEFINE([HAVE_APPINDICATOR],[1],[Use AppIndicator 0.2.9])
+      AC_DEFINE([HAVE_APPINDICATOR_029],[1],[Use AppIndicator 0.2.9])
+     ],
+     [AC_MSG_WARN(AppIndicator 0.2.9 not present")])
+
+if test "$APPINDICATOR_LIBS" == ""; then
+   PKG_CHECK_MODULES(APPINDICATOR, 
+     appindicator-0.1 > 0.2.9, 
+     [AC_DEFINE([HAVE_APPINDICATOR],[1],[Use AppIndicator > 0.2.9])], 
+     [AC_MSG_WARN("AppIndicator > 0.2.9 not present")])
+fi
+AM_CONDITIONAL(APPINDICATOR, test -n "$APPINDICATOR_LIBS")
+AC_SUBST(APPINDICATOR_CFLAGS)
+AC_SUBST(APPINDICATOR_LIBS)
+
+# Check CURL, needed for remote monitoring
+CURL_LIBS=
+PKG_CHECK_MODULES(CURL, 
+  libcurl, 
+  [AC_DEFINE([HAVE_CURL],[1],[Use CURL])], 
+  [AC_MSG_WARN("Remote monitoring disabled, curl missing")])
+AM_CONDITIONAL(CURL, test -n "$CURL_LIBS")
+AC_SUBST(CURL_CFLAGS)
+AC_SUBST(CURL_LIBS)
+
+# Check JSON, needed for remote monitoring
+JSON_LIBS=
+PKG_CHECK_MODULES(JSON, 
+  json, 
+  [AC_DEFINE([HAVE_JSON],[1],[Use JSON])], 
+  [AC_MSG_WARN("Remote monitoring disabled, json missing")])
+AM_CONDITIONAL(JSON, test -n "$JSON_LIBS")
+AC_SUBST(JSON_CFLAGS)
+AC_SUBST(JSON_LIBS)
+
+# Enables remote monitoring if JSON and CURL is present
+if test -n "$JSON_LIBS"; then
+   if test -n "$CURL_LIBS"; then
+   AC_DEFINE([HAVE_REMOTE_SUPPORT],[1],[Remote monitoring enabled])
+   fi
+fi
+
+# Checks NVIDIA
+# following code from sensors-applet
+# sensors-applet.sourceforge.net/
+AC_CHECK_HEADERS(NVCtrl/NVCtrl.h NVCtrl/NVCtrlLib.h, 
+                [ HAVE_NVIDIA=true ], [], 
+                 [ 
+                 #include <X11/Xlib.h>
+                 ])
+if test -n "${X11_LIBS}"; then
+LIBS="${LIBS} -lX11 -lXext"
+
+if test "${HAVE_NVIDIA}" = "true"; then
+  AC_CHECK_LIB(XNVCtrl,XNVCTRLQueryExtension, 
+                 [NVIDIA_LIBS="-lXNVCtrl -lX11 -lXext" 
+                  AC_DEFINE(HAVE_NVIDIA,1,[NVidia support enabled])
+                ])                     
+fi
+fi
+AM_CONDITIONAL(NVIDIA, test -n "$NVIDIA_LIBS")
+AC_SUBST(NVIDIA_CFLAGS)
+AC_SUBST(NVIDIA_LIBS)
+
+# Checks Unity
+PKG_CHECK_MODULES(UNITY, 
+                 unity >= 3.4.2,
+                 [AC_DEFINE([HAVE_UNITY],[1],[Use Unity])], 
+                 [AC_MSG_WARN(Unity not present)])
+AC_SUBST(UNITY_CFLAGS)
+AC_SUBST(UNITY_LIBS)
+AM_CONDITIONAL(UNITY, test -n "$UNITY_LIBS")
+
+############### psensor-server
+
+# Checks Lua 5.1 
+LUA_LIBS=
+PKG_CHECK_MODULES(LUA, 
+  lua, 
+  [AC_DEFINE([HAVE_LUA],[1],[Use Lua])], 
+  [AC_MSG_WARN(Lua not present, checks Lua5.1)])
+
+# Ubuntu pkg module is lua5.1 not lua
+if test "$LUA_LIBS" == ""; then
+   PKG_CHECK_MODULES(LUA, 
+     lua5.1, 
+     [AC_DEFINE([HAVE_LUA],[1],[Use Lua5.1])], 
+     [AC_MSG_WARN(Lua5.1 not present, psensor-server will NOT be built")])
+fi
+AM_CONDITIONAL(LUA, test -n "$LUA_LIBS")
+AC_SUBST(LUA_CFLAGS)
+AC_SUBST(LUA_LIBS)
+
+# libmicrohttpd, mandatory for psensor-server
+LIBMICROHTTPD_LIBS=
+PKG_CHECK_MODULES(LIBMICROHTTPD, 
+  libmicrohttpd, 
+  [AC_DEFINE([HAVE_LIBMICROHTTPD],[1],[Use libmicrohttpd])], 
+  [AC_MSG_WARN("libmicrohttpd not present, psensor-server will NOT be built")])
+AM_CONDITIONAL(LIBMICROHTTPD, test -n "$LIBMICROHTTPD_LIBS")
+AC_SUBST(LIBMICROHTTPD_CFLAGS)
+AC_SUBST(LIBMICROHTTPD_LIBS)
+
+# GTop, optional
+
+AC_ARG_WITH(gtop,
+[  --with-gtop[=yes|no]   use gtop],[
+       with_gtop=$withval],[
+       with_gtop="yes"
+])
+
+GTOP_LIBS=
+if test "$with_gtop" = "yes"; then
+PKG_CHECK_MODULES(GTOP, 
+  libgtop-2.0, 
+  [AC_DEFINE([HAVE_GTOP],[1],[Use GTOP])], 
+  [AC_MSG_WARN("gtop not present, CPU/Memory information will NOT be available")])
+fi
+AM_CONDITIONAL(GTOP, test -n "$GTOP_LIBS")
+AC_SUBST(GTOP_CFLAGS)
+AC_SUBST(GTOP_LIBS)
+
+AC_CONFIG_FILES([
+ Makefile
+ src/Makefile
+ src/glade/Makefile
+ src/plib/Makefile
+ src/lib/Makefile
+ src/unity/Makefile
+ src/libpsensor_json/Makefile
+ src/server/Makefile
+ pixmaps/scalable/Makefile
+ pixmaps/48x48/Makefile
+ www/Makefile
+ po/Makefile.in
+ tests/Makefile
+])
+
+AC_CHECK_PROGS([HELP2MAN], [help2man])
+
+AC_OUTPUT
diff --git a/debian/changelog b/debian/changelog
new file mode 100644 (file)
index 0000000..4bca628
--- /dev/null
@@ -0,0 +1,94 @@
+psensor (0.6.1.3-3) lucid; urgency=low
+
+  * bump lucid
+
+ -- Jean-Philippe Orsini <jeanfi@gmail.com>  Wed, 16 Feb 2011 10:13:55 +0100
+
+psensor (0.6.1.3-2) natty; urgency=low
+
+  * bump natty
+
+ -- Jean-Philippe Orsini <jeanfi@gmail.com>  Wed, 16 Feb 2011 10:13:08 +0100
+
+psensor (0.6.1.3-1) maverick; urgency=low
+
+  * upgrade upstream
+  * removed debian/tmp in .install files
+  * improved long description of the packages
+  * fixed debian/copyright(add real name and license preamble)
+  * use dh_installman
+  * added debian/watch file
+
+ -- Jean-Philippe Orsini <jeanfi@gmail.com>  Wed, 16 Feb 2011 09:56:05 +0100
+
+psensor (0.6.1.1-3) lucid; urgency=low
+
+  * bump lucid
+
+ -- jeanfi <jeanfi@gmail.com>  Tue, 15 Feb 2011 12:10:08 +0100
+
+psensor (0.6.1.1-2) natty; urgency=low
+
+  * bump natty
+
+ -- jeanfi <jeanfi@gmail.com>  Tue, 15 Feb 2011 12:09:19 +0100
+
+psensor (0.6.1.1-1) maverick; urgency=low
+
+  * upgrade upstream
+
+ -- jeanfi <jeanfi@gmail.com>  Tue, 15 Feb 2011 11:41:38 +0100
+
+psensor (0.6.1-4) natty; urgency=low
+
+  * bump natty
+
+ -- jeanfi <jeanfi@gmail.com>  Mon, 14 Feb 2011 12:18:28 +0100
+
+psensor (0.6.1-3) lucid; urgency=low
+
+  * bump lucid
+
+ -- jeanfi <jeanfi@gmail.com>  Mon, 14 Feb 2011 12:17:37 +0100
+
+psensor (0.6.1-2) maverick; urgency=low
+
+  * fixed file conflicts concerning doc dir
+
+ -- jeanfi <jeanfi@gmail.com>  Mon, 14 Feb 2011 11:47:16 +0100
+
+psensor (0.6.1-1) maverick; urgency=low
+
+  * upgrade upstream
+
+ -- jeanfi <jeanfi@gmail.com>  Mon, 14 Feb 2011 10:52:24 +0100
+
+psensor (0.6.0.14-5) karmic; urgency=low
+
+  * bump karmic
+
+ -- jeanfi <jeanfi@gmail.com>  Sun, 13 Feb 2011 14:05:07 +0100
+
+psensor (0.6.0.14-4) maverick; urgency=low
+
+  * www/index.lua in the psensor-server package
+
+ -- jeanfi <jeanfi@gmail.com>  Sun, 13 Feb 2011 13:30:30 +0100
+
+psensor (0.6.0.14-3) lucid; urgency=low
+
+  * bump lucid
+
+ -- jeanfi <jeanfi@gmail.com>  Sat, 12 Feb 2011 21:18:22 +0100
+
+psensor (0.6.0.14-2) natty; urgency=low
+
+  * bump natty
+
+ -- jeanfi <jeanfi@gmail.com>  Sat, 12 Feb 2011 21:16:38 +0100
+
+psensor (0.6.0.14-1) maverick; urgency=low
+
+  * upgrade upstream
+
+ -- jeanfi <jeanfi@gmail.com>  Sat, 12 Feb 2011 14:34:42 +0100
diff --git a/debian/control b/debian/control
new file mode 100644 (file)
index 0000000..a670a4f
--- /dev/null
@@ -0,0 +1,54 @@
+Source: psensor
+Section: utils
+Priority: optional
+Maintainer: Jean-Philippe Orsini <jeanfi@gmail.com>
+Build-Depends: debhelper (>= 7.0.50~),libgtk2.0-dev,libgconf2-dev,libnotify-dev,libsensors4-dev,nvidia-settings,help2man,libcurl4-openssl-dev,libjson0-dev,liblua5.1-0-dev,libmicrohttpd-dev,libgtop2-dev,perl,libappindicator-dev
+Standards-Version: 3.9.1
+Homepage: http://wpitchoune.net/psensor
+
+Package: psensor
+Architecture: any
+Depends: psensor-common (= ${source:Version}), ${shlibs:Depends}, ${misc:Depends}
+Recommends: hddtemp
+Description: Display graphs for monitoring hardware temperature.
+ Psensor is a GTK application for monitoring hardware sensors,
+ including temperatures and fan speeds.
+ .
+ It displays a curve for each sensor, alerts user using Desktop Notification
+ and Application Indicator when a temperature is too high. 
+ .
+ It can monitor:
+  * the temperature of the motherboard and CPU sensors (using lm-sensors).
+  * the temperature of the NVidia GPUs (using XNVCtrl).
+  * the temperature of the Hard Disk Drives (using hddtemp).
+  * the rotation speed of the fans (using lm-sensors).
+  * the sensors of a remote computer (using psensor-server).
+ . 
+
+Package: psensor-server
+Architecture: any
+Depends: psensor-common (= ${source:Version}), ${shlibs:Depends}, ${misc:Depends}
+Recommends: hddtemp
+Description: Psensor server for monitoring hardware sensors remotely.
+ .
+ Psensor server is an HTTP server providing a JSON Web service which can be
+ used by Psensor GTK Application to monitor remotely the hardware sensors
+ of a computer.
+ .
+ It can provide information about:
+  * the temperature of the motherboard and CPU sensors (using lm-sensors).
+  * the temperature of the NVidia GPUs (using XNVCtrl).
+  * the temperature of the Hard Disk Drives (using hddtemp).
+  * the rotation speed of the fans (using lm-sensors).
+ .
+ It is also possible to connect to Psensor server with a browser, a simple
+ Web page is displaying the information.
+ .
+
+Package: psensor-common
+Architecture: all
+Depends: ${misc:Depends}
+Description: Common files for Psensor and Psensor server.
+ . 
+ It contains languages packs for both Psensor and Psensor server.
+ .
\ No newline at end of file
diff --git a/debian/copyright b/debian/copyright
new file mode 100644 (file)
index 0000000..7be00c5
--- /dev/null
@@ -0,0 +1,32 @@
+This package was debianized by Jean-Philippe Orsini <jeanfi@gmail.com>
+Tue, 15 Feb 18:33:41 CET 2011.
+
+It was downloaded from: http://wpitchoune.net/psensor
+
+Upstream Author(s): Jean-Philippe Orsini <wpitchoune@gmail.com>
+
+Copyright:
+    Copyright (C) 2010-2011 by Jean-Philippe Orsini <wpitchoune@gmail.com>
+
+License:
+
+   This package 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; version 2 dated June, 1991.
+
+   This package 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 package; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+   MA 02110-1301, USA.
+
+On Debian/Ubuntu systems, the complete text of the GNU General Public
+License can be found in `/usr/share/common-licenses/GPL-2'.
+
+Packaging:
+        Copyright (C) 2010-2011 by Jean-Philippe Orsini <jeanfi@gmail.com>
+        released under GNU General Public License version 2.
\ No newline at end of file
diff --git a/debian/docs b/debian/docs
new file mode 100644 (file)
index 0000000..139597f
--- /dev/null
@@ -0,0 +1,2 @@
+
+
diff --git a/debian/psensor-common.install b/debian/psensor-common.install
new file mode 100644 (file)
index 0000000..94125c7
--- /dev/null
@@ -0,0 +1 @@
+/usr/share/locale
diff --git a/debian/psensor-server.install b/debian/psensor-server.install
new file mode 100644 (file)
index 0000000..7bcc095
--- /dev/null
@@ -0,0 +1,3 @@
+/usr/bin/psensor-server
+/usr/share/psensor/www/index.lua
+
diff --git a/debian/psensor-server.manpages b/debian/psensor-server.manpages
new file mode 100644 (file)
index 0000000..4d121e6
--- /dev/null
@@ -0,0 +1 @@
+debian/tmp/usr/share/man/man1/psensor-server.1
\ No newline at end of file
diff --git a/debian/psensor.install b/debian/psensor.install
new file mode 100644 (file)
index 0000000..8f69a68
--- /dev/null
@@ -0,0 +1,8 @@
+/usr/bin/psensor
+/usr/share/icons/hicolor/scalable/apps/psensor.svg
+/usr/share/icons/hicolor/scalable/apps/psensor_hot.svg
+/usr/share/icons/hicolor/48x48/apps/psensor.png
+/usr/share/icons/hicolor/48x48/apps/psensor_hot.png
+/usr/share/applications/psensor.desktop
+
+
diff --git a/debian/psensor.manpages b/debian/psensor.manpages
new file mode 100644 (file)
index 0000000..16e0814
--- /dev/null
@@ -0,0 +1,2 @@
+debian/tmp/usr/share/man/man1/psensor.1
+
diff --git a/debian/rules b/debian/rules
new file mode 100755 (executable)
index 0000000..b760bee
--- /dev/null
@@ -0,0 +1,13 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+# Sample debian/rules that uses debhelper.
+# This file was originally written by Joey Hess and Craig Small.
+# As a special exception, when this file is copied by dh-make into a
+# dh-make output file, you may use that output file without restriction.
+# This special exception was added by Craig Small in version 0.37 of dh-make.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+%:
+       dh $@ 
diff --git a/debian/watch b/debian/watch
new file mode 100644 (file)
index 0000000..8833e44
--- /dev/null
@@ -0,0 +1,3 @@
+version=3
+
+http://wpitchoune.net/psensor/files/psensor-(\d.*)\.tar\.gz
\ No newline at end of file
diff --git a/pixmaps/16x16/psensor.png b/pixmaps/16x16/psensor.png
new file mode 100644 (file)
index 0000000..d06f187
Binary files /dev/null and b/pixmaps/16x16/psensor.png differ
diff --git a/pixmaps/22x22/psensor.png b/pixmaps/22x22/psensor.png
new file mode 100644 (file)
index 0000000..be45344
Binary files /dev/null and b/pixmaps/22x22/psensor.png differ
diff --git a/pixmaps/24x24/psensor.png b/pixmaps/24x24/psensor.png
new file mode 100644 (file)
index 0000000..93f2d79
Binary files /dev/null and b/pixmaps/24x24/psensor.png differ
diff --git a/pixmaps/32x32/psensor.png b/pixmaps/32x32/psensor.png
new file mode 100644 (file)
index 0000000..02028ce
Binary files /dev/null and b/pixmaps/32x32/psensor.png differ
diff --git a/pixmaps/48x48/Makefile.am b/pixmaps/48x48/Makefile.am
new file mode 100644 (file)
index 0000000..7d09bac
--- /dev/null
@@ -0,0 +1,6 @@
+themedir = $(datadir)/icons/hicolor
+size = 48x48
+context = apps
+EXTRA_DIST = psensor.png psensor_hot.png
+psensordistpixdir = $(themedir)/$(size)/$(context)
+psensordistpix_DATA = $(EXTRA_DIST)
diff --git a/pixmaps/48x48/psensor.png b/pixmaps/48x48/psensor.png
new file mode 100644 (file)
index 0000000..3acb429
Binary files /dev/null and b/pixmaps/48x48/psensor.png differ
diff --git a/pixmaps/48x48/psensor_hot.png b/pixmaps/48x48/psensor_hot.png
new file mode 100644 (file)
index 0000000..6f05f59
Binary files /dev/null and b/pixmaps/48x48/psensor_hot.png differ
diff --git a/pixmaps/scalable/Makefile.am b/pixmaps/scalable/Makefile.am
new file mode 100644 (file)
index 0000000..47adc6c
--- /dev/null
@@ -0,0 +1,6 @@
+themedir = $(datadir)/icons/hicolor
+size = scalable
+context = apps
+EXTRA_DIST = psensor.svg psensor_hot.svg
+psensordistpixdir = $(themedir)/$(size)/$(context)
+psensordistpix_DATA = $(EXTRA_DIST)
diff --git a/pixmaps/scalable/psensor.svg b/pixmaps/scalable/psensor.svg
new file mode 100644 (file)
index 0000000..2bd5d03
--- /dev/null
@@ -0,0 +1,276 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="64px"
+   height="64px"
+   id="svg4212"
+   version="1.1"
+   inkscape:version="0.48.0 r9654"
+   sodipodi:docname="New document 6">
+  <defs
+     id="defs4214">
+    <filter
+       color-interpolation-filters="sRGB"
+       id="filter4705"
+       inkscape:label="Drop shadow"
+       width="1.5"
+       height="1.5"
+       x="-0.25"
+       y="-0.25">
+      <feGaussianBlur
+         id="feGaussianBlur4707"
+         in="SourceAlpha"
+         stdDeviation="2"
+         result="blur" />
+      <feColorMatrix
+         id="feColorMatrix4709"
+         result="bluralpha"
+         type="matrix"
+         values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.5 0 " />
+      <feOffset
+         id="feOffset4711"
+         in="bluralpha"
+         dx="4"
+         dy="4"
+         result="offsetBlur" />
+      <feMerge
+         id="feMerge4713">
+        <feMergeNode
+           id="feMergeNode4715"
+           in="offsetBlur" />
+        <feMergeNode
+           id="feMergeNode4717"
+           in="SourceGraphic" />
+      </feMerge>
+    </filter>
+    <filter
+       color-interpolation-filters="sRGB"
+       id="filter3940"
+       inkscape:label="Drop shadow"
+       width="1.5"
+       height="1.5"
+       x="-0.25"
+       y="-0.25">
+      <feGaussianBlur
+         id="feGaussianBlur3942"
+         in="SourceAlpha"
+         stdDeviation="2"
+         result="blur" />
+      <feColorMatrix
+         id="feColorMatrix3944"
+         result="bluralpha"
+         type="matrix"
+         values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 0.5 0 " />
+      <feOffset
+         id="feOffset3946"
+         in="bluralpha"
+         dx="4"
+         dy="4"
+         result="offsetBlur" />
+      <feMerge
+         id="feMerge3948">
+        <feMergeNode
+           id="feMergeNode3950"
+           in="offsetBlur" />
+        <feMergeNode
+           id="feMergeNode3952"
+           in="SourceGraphic" />
+      </feMerge>
+    </filter>
+    <filter
+       color-interpolation-filters="sRGB"
+       id="filter3884"
+       inkscape:label="Drop shadow"
+       width="1.5"
+       height="1.5"
+       x="-0.25"
+       y="-0.25">
+      <feGaussianBlur
+         id="feGaussianBlur3886"
+         in="SourceAlpha"
+         stdDeviation="2"
+         result="blur" />
+      <feColorMatrix
+         id="feColorMatrix3888"
+         result="bluralpha"
+         type="matrix"
+         values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.5 0 " />
+      <feOffset
+         id="feOffset3890"
+         in="bluralpha"
+         dx="4"
+         dy="4"
+         result="offsetBlur" />
+      <feMerge
+         id="feMerge3892">
+        <feMergeNode
+           id="feMergeNode3894"
+           in="offsetBlur" />
+        <feMergeNode
+           id="feMergeNode3896"
+           in="SourceGraphic" />
+      </feMerge>
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="5.5"
+     inkscape:cx="-0.94641485"
+     inkscape:cy="18.057188"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     inkscape:window-width="917"
+     inkscape:window-height="750"
+     inkscape:window-x="263"
+     inkscape:window-y="69"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata4217">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer">
+    <rect
+       style="fill:#f5f5f5;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;filter:url(#filter4705)"
+       id="rect4194"
+       width="288.90363"
+       height="717.20831"
+       x="189.90868"
+       y="38.169029"
+       transform="matrix(0.11117627,0,0,0.08577991,-6.1543153,-2.2951599)" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.42643818;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.903496,8.6255733 3.927422,0"
+       id="path3991-1"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:1.0958519;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.903496,10.645782 6.483944,0"
+       id="path3991-8"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.42643818;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.898037,6.8298457 3.927422,0"
+       id="path3991-1-0"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.42643818;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.92763,14.794556 3.92742,0"
+       id="path3991-1-9"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:1.0958519;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.890263,19.508361 6.483942,0"
+       id="path3991-8-8"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.42643818;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.922172,12.998819 3.927419,0"
+       id="path3991-1-0-7"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.42643818;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.898037,16.930852 3.927422,0"
+       id="path3991-1-9-2"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.42643818;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.890263,24.08748 3.92742,0"
+       id="path3991-1-9-6"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:1.0958519;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.852894,28.801285 6.483944,0"
+       id="path3991-8-8-6"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.42643818;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.884805,22.291743 3.927419,0"
+       id="path3991-1-0-7-4"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.42643818;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.86067,26.223776 3.92742,0"
+       id="path3991-1-9-2-1"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.42643818;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.852896,33.245729 3.92742,0"
+       id="path3991-1-9-0"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:1.0958519;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.815529,37.959534 6.483941,0"
+       id="path3991-8-8-9"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.42643818;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.847437,31.449992 3.927422,0"
+       id="path3991-1-0-7-42"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.42643818;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.823304,35.382024 3.927421,0"
+       id="path3991-1-9-2-4"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.42643818;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.890263,42.538653 3.92742,0"
+       id="path3991-1-9-0-3"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:1.0958519;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.852894,47.252458 6.483944,0"
+       id="path3991-8-8-9-3"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.42643818;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.884805,40.742926 3.927419,0"
+       id="path3991-1-0-7-42-0"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.42643818;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.86067,44.674948 3.92742,0"
+       id="path3991-1-9-2-4-0"
+       inkscape:connector-curvature="0" />
+    <rect
+       style="fill:#f5f5f5;fill-opacity:1;stroke:#000000;stroke-width:1.32799995;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;filter:url(#filter3940)"
+       id="rect3088"
+       width="54.285713"
+       height="519.38318"
+       x="-203.70616"
+       y="-268.3721"
+       transform="matrix(0.18760081,0,0,0.09664922,62.069208,30.973439)" />
+    <path
+       inkscape:connector-curvature="0"
+       id="rect3094"
+       style="fill:#4d9af5;fill-opacity:1;stroke:none;filter:url(#filter3884)"
+       d="m -199.51279,-181.60693 45.68928,0 0,431.9361 -45.68928,0 z m 63.13451,461.6397 c 0,20.36305 -18.09042,36.87057 -40.4061,36.87057 -22.31567,0 -40.4061,-16.50752 -40.4061,-36.87057 0,-20.36305 18.09043,-36.87057 40.4061,-36.87057 22.31568,0 40.4061,16.50752 40.4061,36.87057 z"
+       transform="matrix(0.18760081,0,0,0.09932296,62.069208,29.434345)" />
+  </g>
+</svg>
diff --git a/pixmaps/scalable/psensor_hot.svg b/pixmaps/scalable/psensor_hot.svg
new file mode 100644 (file)
index 0000000..c4e9e60
--- /dev/null
@@ -0,0 +1,276 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="64px"
+   height="64px"
+   id="svg4212"
+   version="1.1"
+   inkscape:version="0.48.0 r9654"
+   sodipodi:docname="psensor.svg">
+  <defs
+     id="defs4214">
+    <filter
+       color-interpolation-filters="sRGB"
+       id="filter4705"
+       inkscape:label="Drop shadow"
+       width="1.5"
+       height="1.5"
+       x="-0.25"
+       y="-0.25">
+      <feGaussianBlur
+         id="feGaussianBlur4707"
+         in="SourceAlpha"
+         stdDeviation="2"
+         result="blur" />
+      <feColorMatrix
+         id="feColorMatrix4709"
+         result="bluralpha"
+         type="matrix"
+         values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.5 0 " />
+      <feOffset
+         id="feOffset4711"
+         in="bluralpha"
+         dx="4"
+         dy="4"
+         result="offsetBlur" />
+      <feMerge
+         id="feMerge4713">
+        <feMergeNode
+           id="feMergeNode4715"
+           in="offsetBlur" />
+        <feMergeNode
+           id="feMergeNode4717"
+           in="SourceGraphic" />
+      </feMerge>
+    </filter>
+    <filter
+       color-interpolation-filters="sRGB"
+       id="filter3940"
+       inkscape:label="Drop shadow"
+       width="1.5"
+       height="1.5"
+       x="-0.25"
+       y="-0.25">
+      <feGaussianBlur
+         id="feGaussianBlur3942"
+         in="SourceAlpha"
+         stdDeviation="2"
+         result="blur" />
+      <feColorMatrix
+         id="feColorMatrix3944"
+         result="bluralpha"
+         type="matrix"
+         values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 0.5 0 " />
+      <feOffset
+         id="feOffset3946"
+         in="bluralpha"
+         dx="4"
+         dy="4"
+         result="offsetBlur" />
+      <feMerge
+         id="feMerge3948">
+        <feMergeNode
+           id="feMergeNode3950"
+           in="offsetBlur" />
+        <feMergeNode
+           id="feMergeNode3952"
+           in="SourceGraphic" />
+      </feMerge>
+    </filter>
+    <filter
+       color-interpolation-filters="sRGB"
+       id="filter3884"
+       inkscape:label="Drop shadow"
+       width="1.5"
+       height="1.5"
+       x="-0.25"
+       y="-0.25">
+      <feGaussianBlur
+         id="feGaussianBlur3886"
+         in="SourceAlpha"
+         stdDeviation="2"
+         result="blur" />
+      <feColorMatrix
+         id="feColorMatrix3888"
+         result="bluralpha"
+         type="matrix"
+         values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.5 0 " />
+      <feOffset
+         id="feOffset3890"
+         in="bluralpha"
+         dx="4"
+         dy="4"
+         result="offsetBlur" />
+      <feMerge
+         id="feMerge3892">
+        <feMergeNode
+           id="feMergeNode3894"
+           in="offsetBlur" />
+        <feMergeNode
+           id="feMergeNode3896"
+           in="SourceGraphic" />
+      </feMerge>
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="3.8890873"
+     inkscape:cx="-7.27031"
+     inkscape:cy="47.399556"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     inkscape:window-width="1239"
+     inkscape:window-height="738"
+     inkscape:window-x="61"
+     inkscape:window-y="71"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata4217">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer">
+    <rect
+       style="fill:#ff8080;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;filter:url(#filter4705)"
+       id="rect4194"
+       width="288.90363"
+       height="717.20831"
+       x="189.90868"
+       y="38.169029"
+       transform="matrix(0.11117627,0,0,0.08577991,-6.1543153,-2.2951599)" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.42643818;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.903496,8.6255733 3.927422,0"
+       id="path3991-1"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:1.0958519;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.903496,10.645782 6.483944,0"
+       id="path3991-8"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.42643818;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.898037,6.8298457 3.927422,0"
+       id="path3991-1-0"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.42643818;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.92763,14.794556 3.92742,0"
+       id="path3991-1-9"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:1.0958519;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.890263,19.508361 6.483942,0"
+       id="path3991-8-8"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.42643818;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.922172,12.998819 3.927419,0"
+       id="path3991-1-0-7"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.42643818;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.898037,16.930852 3.927422,0"
+       id="path3991-1-9-2"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.42643818;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.890263,24.08748 3.92742,0"
+       id="path3991-1-9-6"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:1.0958519;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.852894,28.801285 6.483944,0"
+       id="path3991-8-8-6"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.42643818;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.884805,22.291743 3.927419,0"
+       id="path3991-1-0-7-4"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.42643818;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.86067,26.223776 3.92742,0"
+       id="path3991-1-9-2-1"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.42643818;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.852896,33.245729 3.92742,0"
+       id="path3991-1-9-0"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:1.0958519;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.815529,37.959534 6.483941,0"
+       id="path3991-8-8-9"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.42643818;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.847437,31.449992 3.927422,0"
+       id="path3991-1-0-7-42"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.42643818;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.823304,35.382024 3.927421,0"
+       id="path3991-1-9-2-4"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.42643818;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.890263,42.538653 3.92742,0"
+       id="path3991-1-9-0-3"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:1.0958519;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.852894,47.252458 6.483944,0"
+       id="path3991-8-8-9-3"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.42643818;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.884805,40.742926 3.927419,0"
+       id="path3991-1-0-7-42-0"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.42643818;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 33.86067,44.674948 3.92742,0"
+       id="path3991-1-9-2-4-0"
+       inkscape:connector-curvature="0" />
+    <rect
+       style="fill:#f5f5f5;fill-opacity:1;stroke:#000000;stroke-width:1.32799995;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;filter:url(#filter3940)"
+       id="rect3088"
+       width="54.285713"
+       height="519.38318"
+       x="-203.70616"
+       y="-268.3721"
+       transform="matrix(0.18760081,0,0,0.09664922,62.069208,30.973439)" />
+    <path
+       inkscape:connector-curvature="0"
+       id="rect3094"
+       style="fill:#ff0000;fill-opacity:1;stroke:none;filter:url(#filter3884)"
+       d="m -199.51279,-181.60693 45.68928,0 0,431.9361 -45.68928,0 z m 63.13451,461.6397 c 0,20.36305 -18.09042,36.87057 -40.4061,36.87057 -22.31567,0 -40.4061,-16.50752 -40.4061,-36.87057 0,-20.36305 18.09043,-36.87057 40.4061,-36.87057 22.31568,0 40.4061,16.50752 40.4061,36.87057 z"
+       transform="matrix(0.18760081,0,0,0.09932296,62.069208,29.434345)" />
+  </g>
+</svg>
diff --git a/po/LINGUAS b/po/LINGUAS
new file mode 100644 (file)
index 0000000..12a5907
--- /dev/null
@@ -0,0 +1,10 @@
+# Set of available languages.
+#
+#  Copyright (C) 1992, 1993, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+#  2002, 2003, 2005, 2006, 2007 Free Software Foundation, Inc.
+#
+#  Copying and distribution of this file, with or without modification,
+#  are permitted in any medium without royalty provided the copyright
+#  notice and this notice are preserved.
+fr
+zh_CN
diff --git a/po/Makefile.in.in b/po/Makefile.in.in
new file mode 100644 (file)
index 0000000..5022b8b
--- /dev/null
@@ -0,0 +1,403 @@
+# Makefile for PO directory in any package using GNU gettext.
+# Copyright (C) 1995-1997, 2000-2006 by Ulrich Drepper <drepper@gnu.ai.mit.edu>
+#
+# This file can be copied and used freely without restrictions.  It can
+# be used in projects which are not available under the GNU General Public
+# License but which still want to provide support for the GNU gettext
+# functionality.
+# Please note that the actual code of GNU gettext is covered by the GNU
+# General Public License and is *not* in the public domain.
+#
+# Origin: gettext-0.16
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+
+SHELL = /bin/sh
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+datarootdir = @datarootdir@
+datadir = @datadir@
+localedir = @localedir@
+gettextsrcdir = $(datadir)/gettext/po
+
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+
+# We use $(mkdir_p).
+# In automake <= 1.9.x, $(mkdir_p) is defined either as "mkdir -p --" or as
+# "$(mkinstalldirs)" or as "$(install_sh) -d". For these automake versions,
+# @install_sh@ does not start with $(SHELL), so we add it.
+# In automake >= 1.10, @mkdir_p@ is derived from ${MKDIR_P}, which is defined
+# either as "/path/to/mkdir -p" or ".../install-sh -c -d". For these automake
+# versions, $(mkinstalldirs) and $(install_sh) are unused.
+mkinstalldirs = $(SHELL) @install_sh@ -d
+install_sh = $(SHELL) @install_sh@
+MKDIR_P = @MKDIR_P@
+mkdir_p = @mkdir_p@
+
+GMSGFMT_ = @GMSGFMT@
+GMSGFMT_no = @GMSGFMT@
+GMSGFMT_yes = @GMSGFMT_015@
+GMSGFMT = $(GMSGFMT_$(USE_MSGCTXT))
+MSGFMT_ = @MSGFMT@
+MSGFMT_no = @MSGFMT@
+MSGFMT_yes = @MSGFMT_015@
+MSGFMT = $(MSGFMT_$(USE_MSGCTXT))
+XGETTEXT_ = @XGETTEXT@
+XGETTEXT_no = @XGETTEXT@
+XGETTEXT_yes = @XGETTEXT_015@
+XGETTEXT = $(XGETTEXT_$(USE_MSGCTXT))
+MSGMERGE = msgmerge
+MSGMERGE_UPDATE = @MSGMERGE@ --update
+MSGINIT = msginit
+MSGCONV = msgconv
+MSGFILTER = msgfilter
+
+POFILES = @POFILES@
+GMOFILES = @GMOFILES@
+UPDATEPOFILES = @UPDATEPOFILES@
+DUMMYPOFILES = @DUMMYPOFILES@
+DISTFILES.common = Makefile.in.in remove-potcdate.sin \
+$(DISTFILES.common.extra1) $(DISTFILES.common.extra2) $(DISTFILES.common.extra3)
+DISTFILES = $(DISTFILES.common) Makevars POTFILES.in \
+$(POFILES) $(GMOFILES) \
+$(DISTFILES.extra1) $(DISTFILES.extra2) $(DISTFILES.extra3)
+
+POTFILES = \
+
+CATALOGS = @CATALOGS@
+
+# Makevars gets inserted here. (Don't remove this line!)
+
+.SUFFIXES:
+.SUFFIXES: .po .gmo .mo .sed .sin .nop .po-create .po-update
+
+.po.mo:
+       @echo "$(MSGFMT) -c -o $@ $<"; \
+       $(MSGFMT) -c -o t-$@ $< && mv t-$@ $@
+
+.po.gmo:
+       @lang=`echo $* | sed -e 's,.*/,,'`; \
+       test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \
+       echo "$${cdcmd}rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics -o $${lang}.gmo $${lang}.po"; \
+       cd $(srcdir) && rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics -o t-$${lang}.gmo $${lang}.po && mv t-$${lang}.gmo $${lang}.gmo
+
+.sin.sed:
+       sed -e '/^#/d' $< > t-$@
+       mv t-$@ $@
+
+
+all: all-@USE_NLS@
+
+all-yes: stamp-po
+all-no:
+
+# $(srcdir)/$(DOMAIN).pot is only created when needed. When xgettext finds no
+# internationalized messages, no $(srcdir)/$(DOMAIN).pot is created (because
+# we don't want to bother translators with empty POT files). We assume that
+# LINGUAS is empty in this case, i.e. $(POFILES) and $(GMOFILES) are empty.
+# In this case, stamp-po is a nop (i.e. a phony target).
+
+# stamp-po is a timestamp denoting the last time at which the CATALOGS have
+# been loosely updated. Its purpose is that when a developer or translator
+# checks out the package via CVS, and the $(DOMAIN).pot file is not in CVS,
+# "make" will update the $(DOMAIN).pot and the $(CATALOGS), but subsequent
+# invocations of "make" will do nothing. This timestamp would not be necessary
+# if updating the $(CATALOGS) would always touch them; however, the rule for
+# $(POFILES) has been designed to not touch files that don't need to be
+# changed.
+stamp-po: $(srcdir)/$(DOMAIN).pot
+       test ! -f $(srcdir)/$(DOMAIN).pot || \
+         test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES)
+       @test ! -f $(srcdir)/$(DOMAIN).pot || { \
+         echo "touch stamp-po" && \
+         echo timestamp > stamp-poT && \
+         mv stamp-poT stamp-po; \
+       }
+
+# Note: Target 'all' must not depend on target '$(DOMAIN).pot-update',
+# otherwise packages like GCC can not be built if only parts of the source
+# have been downloaded.
+
+# This target rebuilds $(DOMAIN).pot; it is an expensive operation.
+# Note that $(DOMAIN).pot is not touched if it doesn't need to be changed.
+$(DOMAIN).pot-update: $(POTFILES) $(srcdir)/POTFILES.in remove-potcdate.sed
+       if test -n '$(MSGID_BUGS_ADDRESS)' || test '$(PACKAGE_BUGREPORT)' = '@'PACKAGE_BUGREPORT'@'; then \
+         msgid_bugs_address='$(MSGID_BUGS_ADDRESS)'; \
+       else \
+         msgid_bugs_address='$(PACKAGE_BUGREPORT)'; \
+       fi; \
+       $(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \
+         --add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) \
+         --files-from=$(srcdir)/POTFILES.in \
+         --copyright-holder='$(COPYRIGHT_HOLDER)' \
+         --msgid-bugs-address="$$msgid_bugs_address"
+       test ! -f $(DOMAIN).po || { \
+         if test -f $(srcdir)/$(DOMAIN).pot; then \
+           sed -f remove-potcdate.sed < $(srcdir)/$(DOMAIN).pot > $(DOMAIN).1po && \
+           sed -f remove-potcdate.sed < $(DOMAIN).po > $(DOMAIN).2po && \
+           if cmp $(DOMAIN).1po $(DOMAIN).2po >/dev/null 2>&1; then \
+             rm -f $(DOMAIN).1po $(DOMAIN).2po $(DOMAIN).po; \
+           else \
+             rm -f $(DOMAIN).1po $(DOMAIN).2po $(srcdir)/$(DOMAIN).pot && \
+             mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot; \
+           fi; \
+         else \
+           mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot; \
+         fi; \
+       }
+
+# This rule has no dependencies: we don't need to update $(DOMAIN).pot at
+# every "make" invocation, only create it when it is missing.
+# Only "make $(DOMAIN).pot-update" or "make dist" will force an update.
+$(srcdir)/$(DOMAIN).pot:
+       $(MAKE) $(DOMAIN).pot-update
+
+# This target rebuilds a PO file if $(DOMAIN).pot has changed.
+# Note that a PO file is not touched if it doesn't need to be changed.
+$(POFILES): $(srcdir)/$(DOMAIN).pot
+       @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \
+       if test -f "$(srcdir)/$${lang}.po"; then \
+         test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \
+         echo "$${cdcmd}$(MSGMERGE_UPDATE) $${lang}.po $(DOMAIN).pot"; \
+         cd $(srcdir) && $(MSGMERGE_UPDATE) $${lang}.po $(DOMAIN).pot; \
+       else \
+         $(MAKE) $${lang}.po-create; \
+       fi
+
+
+install: install-exec install-data
+install-exec:
+install-data: install-data-@USE_NLS@
+       if test "$(PACKAGE)" = "gettext-tools"; then \
+         $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \
+         for file in $(DISTFILES.common) Makevars.template; do \
+           $(INSTALL_DATA) $(srcdir)/$$file \
+                           $(DESTDIR)$(gettextsrcdir)/$$file; \
+         done; \
+         for file in Makevars; do \
+           rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \
+         done; \
+       else \
+         : ; \
+       fi
+install-data-no: all
+install-data-yes: all
+       $(mkdir_p) $(DESTDIR)$(datadir)
+       @catalogs='$(CATALOGS)'; \
+       for cat in $$catalogs; do \
+         cat=`basename $$cat`; \
+         lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \
+         dir=$(localedir)/$$lang/LC_MESSAGES; \
+         $(mkdir_p) $(DESTDIR)$$dir; \
+         if test -r $$cat; then realcat=$$cat; else realcat=$(srcdir)/$$cat; fi; \
+         $(INSTALL_DATA) $$realcat $(DESTDIR)$$dir/$(DOMAIN).mo; \
+         echo "installing $$realcat as $(DESTDIR)$$dir/$(DOMAIN).mo"; \
+         for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \
+           if test -n "$$lc"; then \
+             if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \
+               link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \
+               mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \
+               mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \
+               (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \
+                for file in *; do \
+                  if test -f $$file; then \
+                    ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \
+                  fi; \
+                done); \
+               rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \
+             else \
+               if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \
+                 :; \
+               else \
+                 rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \
+                 mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \
+               fi; \
+             fi; \
+             rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \
+             ln -s ../LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \
+             ln $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \
+             cp -p $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \
+             echo "installing $$realcat link as $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo"; \
+           fi; \
+         done; \
+       done
+
+install-strip: install
+
+installdirs: installdirs-exec installdirs-data
+installdirs-exec:
+installdirs-data: installdirs-data-@USE_NLS@
+       if test "$(PACKAGE)" = "gettext-tools"; then \
+         $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \
+       else \
+         : ; \
+       fi
+installdirs-data-no:
+installdirs-data-yes:
+       $(mkdir_p) $(DESTDIR)$(datadir)
+       @catalogs='$(CATALOGS)'; \
+       for cat in $$catalogs; do \
+         cat=`basename $$cat`; \
+         lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \
+         dir=$(localedir)/$$lang/LC_MESSAGES; \
+         $(mkdir_p) $(DESTDIR)$$dir; \
+         for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \
+           if test -n "$$lc"; then \
+             if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \
+               link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \
+               mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \
+               mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \
+               (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \
+                for file in *; do \
+                  if test -f $$file; then \
+                    ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \
+                  fi; \
+                done); \
+               rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \
+             else \
+               if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \
+                 :; \
+               else \
+                 rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \
+                 mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \
+               fi; \
+             fi; \
+           fi; \
+         done; \
+       done
+
+# Define this as empty until I found a useful application.
+installcheck:
+
+uninstall: uninstall-exec uninstall-data
+uninstall-exec:
+uninstall-data: uninstall-data-@USE_NLS@
+       if test "$(PACKAGE)" = "gettext-tools"; then \
+         for file in $(DISTFILES.common) Makevars.template; do \
+           rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \
+         done; \
+       else \
+         : ; \
+       fi
+uninstall-data-no:
+uninstall-data-yes:
+       catalogs='$(CATALOGS)'; \
+       for cat in $$catalogs; do \
+         cat=`basename $$cat`; \
+         lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \
+         for lc in LC_MESSAGES $(EXTRA_LOCALE_CATEGORIES); do \
+           rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \
+         done; \
+       done
+
+check: all
+
+info dvi ps pdf html tags TAGS ctags CTAGS ID:
+
+mostlyclean:
+       rm -f remove-potcdate.sed
+       rm -f stamp-poT
+       rm -f core core.* $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po
+       rm -fr *.o
+
+clean: mostlyclean
+
+distclean: clean
+       rm -f Makefile Makefile.in POTFILES *.mo
+
+maintainer-clean: distclean
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+       rm -f stamp-po $(GMOFILES)
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+dist distdir:
+       $(MAKE) update-po
+       @$(MAKE) dist2
+# This is a separate target because 'update-po' must be executed before.
+dist2: stamp-po $(DISTFILES)
+       dists="$(DISTFILES)"; \
+       if test "$(PACKAGE)" = "gettext-tools"; then \
+         dists="$$dists Makevars.template"; \
+       fi; \
+       if test -f $(srcdir)/$(DOMAIN).pot; then \
+         dists="$$dists $(DOMAIN).pot stamp-po"; \
+       fi; \
+       if test -f $(srcdir)/ChangeLog; then \
+         dists="$$dists ChangeLog"; \
+       fi; \
+       for i in 0 1 2 3 4 5 6 7 8 9; do \
+         if test -f $(srcdir)/ChangeLog.$$i; then \
+           dists="$$dists ChangeLog.$$i"; \
+         fi; \
+       done; \
+       if test -f $(srcdir)/LINGUAS; then dists="$$dists LINGUAS"; fi; \
+       for file in $$dists; do \
+         if test -f $$file; then \
+           cp -p $$file $(distdir) || exit 1; \
+         else \
+           cp -p $(srcdir)/$$file $(distdir) || exit 1; \
+         fi; \
+       done
+
+update-po: Makefile
+       $(MAKE) $(DOMAIN).pot-update
+       test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES)
+       $(MAKE) update-gmo
+
+# General rule for creating PO files.
+
+.nop.po-create:
+       @lang=`echo $@ | sed -e 's/\.po-create$$//'`; \
+       echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \
+       exit 1
+
+# General rule for updating PO files.
+
+.nop.po-update:
+       @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \
+       if test "$(PACKAGE)" = "gettext-tools"; then PATH=`pwd`/../src:$$PATH; fi; \
+       tmpdir=`pwd`; \
+       echo "$$lang:"; \
+       test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \
+       echo "$${cdcmd}$(MSGMERGE) $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \
+       cd $(srcdir); \
+       if $(MSGMERGE) $$lang.po $(DOMAIN).pot -o $$tmpdir/$$lang.new.po; then \
+         if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \
+           rm -f $$tmpdir/$$lang.new.po; \
+         else \
+           if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \
+             :; \
+           else \
+             echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \
+             exit 1; \
+           fi; \
+         fi; \
+       else \
+         echo "msgmerge for $$lang.po failed!" 1>&2; \
+         rm -f $$tmpdir/$$lang.new.po; \
+       fi
+
+$(DUMMYPOFILES):
+
+update-gmo: Makefile $(GMOFILES)
+       @:
+
+Makefile: Makefile.in.in Makevars $(top_builddir)/config.status @POMAKEFILEDEPS@
+       cd $(top_builddir) \
+         && $(SHELL) ./config.status $(subdir)/$@.in po-directories
+
+force:
+
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/po/Makevars b/po/Makevars
new file mode 100644 (file)
index 0000000..32692ab
--- /dev/null
@@ -0,0 +1,41 @@
+# Makefile variables for PO directory in any package using GNU gettext.
+
+# Usually the message domain is the same as the package name.
+DOMAIN = $(PACKAGE)
+
+# These two variables depend on the location of this directory.
+subdir = po
+top_builddir = ..
+
+# These options get passed to xgettext.
+XGETTEXT_OPTIONS = --keyword=_ --keyword=N_
+
+# This is the copyright holder that gets inserted into the header of the
+# $(DOMAIN).pot file.  Set this to the copyright holder of the surrounding
+# package.  (Note that the msgstr strings, extracted from the package's
+# sources, belong to the copyright holder of the package.)  Translators are
+# expected to transfer the copyright for their translations to this person
+# or entity, or to disclaim their copyright.  The empty string stands for
+# the public domain; in this case the translators are expected to disclaim
+# their copyright.
+COPYRIGHT_HOLDER = Free Software Foundation, Inc.
+
+# This is the email address or URL to which the translators shall report
+# bugs in the untranslated strings:
+# - Strings which are not entire sentences, see the maintainer guidelines
+#   in the GNU gettext documentation, section 'Preparing Strings'.
+# - Strings which use unclear terms or require additional context to be
+#   understood.
+# - Strings which make invalid assumptions about notation of date, time or
+#   money.
+# - Pluralisation problems.
+# - Incorrect English spelling.
+# - Incorrect formatting.
+# It can be your email address, or a mailing list address where translators
+# can write to without being subscribed, or the URL of a web page through
+# which the translators can contact you.
+MSGID_BUGS_ADDRESS =
+
+# This is the list of locale categories, beyond LC_MESSAGES, for which the
+# message catalogs shall be used.  It is usually empty.
+EXTRA_LOCALE_CATEGORIES =
diff --git a/po/POTFILES.in b/po/POTFILES.in
new file mode 100644 (file)
index 0000000..e04b4b2
--- /dev/null
@@ -0,0 +1,12 @@
+src/main.c
+src/ui_sensorlist.c
+src/ui_appindicator.c
+src/ui_color.c  
+src/ui_notify.c  
+src/ui_pref.c  
+src/rsensor.c
+src/plib/plib_luatpl.c
+src/server/server.c
+src/lib/hdd.c
+src/lib/nvidia.c
+src/lib/lmsensor.c
diff --git a/po/Rules-quot b/po/Rules-quot
new file mode 100644 (file)
index 0000000..9c2a995
--- /dev/null
@@ -0,0 +1,47 @@
+# Special Makefile rules for English message catalogs with quotation marks.
+
+DISTFILES.common.extra1 = quot.sed boldquot.sed en@quot.header en@boldquot.header insert-header.sin Rules-quot
+
+.SUFFIXES: .insert-header .po-update-en
+
+en@quot.po-create:
+       $(MAKE) en@quot.po-update
+en@boldquot.po-create:
+       $(MAKE) en@boldquot.po-update
+
+en@quot.po-update: en@quot.po-update-en
+en@boldquot.po-update: en@boldquot.po-update-en
+
+.insert-header.po-update-en:
+       @lang=`echo $@ | sed -e 's/\.po-update-en$$//'`; \
+       if test "$(PACKAGE)" = "gettext"; then PATH=`pwd`/../src:$$PATH; GETTEXTLIBDIR=`cd $(top_srcdir)/src && pwd`; export GETTEXTLIBDIR; fi; \
+       tmpdir=`pwd`; \
+       echo "$$lang:"; \
+       ll=`echo $$lang | sed -e 's/@.*//'`; \
+       LC_ALL=C; export LC_ALL; \
+       cd $(srcdir); \
+       if $(MSGINIT) -i $(DOMAIN).pot --no-translator -l $$ll -o - 2>/dev/null | sed -f $$tmpdir/$$lang.insert-header | $(MSGCONV) -t UTF-8 | $(MSGFILTER) sed -f `echo $$lang | sed -e 's/.*@//'`.sed 2>/dev/null > $$tmpdir/$$lang.new.po; then \
+         if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \
+           rm -f $$tmpdir/$$lang.new.po; \
+         else \
+           if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \
+             :; \
+           else \
+             echo "creation of $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \
+             exit 1; \
+           fi; \
+         fi; \
+       else \
+         echo "creation of $$lang.po failed!" 1>&2; \
+         rm -f $$tmpdir/$$lang.new.po; \
+       fi
+
+en@quot.insert-header: insert-header.sin
+       sed -e '/^#/d' -e 's/HEADER/en@quot.header/g' $(srcdir)/insert-header.sin > en@quot.insert-header
+
+en@boldquot.insert-header: insert-header.sin
+       sed -e '/^#/d' -e 's/HEADER/en@boldquot.header/g' $(srcdir)/insert-header.sin > en@boldquot.insert-header
+
+mostlyclean: mostlyclean-quot
+mostlyclean-quot:
+       rm -f *.insert-header
diff --git a/po/boldquot.sed b/po/boldquot.sed
new file mode 100644 (file)
index 0000000..4b937aa
--- /dev/null
@@ -0,0 +1,10 @@
+s/"\([^"]*\)"/“\1”/g
+s/`\([^`']*\)'/‘\1’/g
+s/ '\([^`']*\)' / ‘\1’ /g
+s/ '\([^`']*\)'$/ ‘\1’/g
+s/^'\([^`']*\)' /‘\1’ /g
+s/“”/""/g
+s/“/“\e[1m/g
+s/”/\e[0m”/g
+s/‘/‘\e[1m/g
+s/’/\e[0m’/g
diff --git a/po/en@boldquot.header b/po/en@boldquot.header
new file mode 100644 (file)
index 0000000..fedb6a0
--- /dev/null
@@ -0,0 +1,25 @@
+# All this catalog "translates" are quotation characters.
+# The msgids must be ASCII and therefore cannot contain real quotation
+# characters, only substitutes like grave accent (0x60), apostrophe (0x27)
+# and double quote (0x22). These substitutes look strange; see
+# http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html
+#
+# This catalog translates grave accent (0x60) and apostrophe (0x27) to
+# left single quotation mark (U+2018) and right single quotation mark (U+2019).
+# It also translates pairs of apostrophe (0x27) to
+# left single quotation mark (U+2018) and right single quotation mark (U+2019)
+# and pairs of quotation mark (0x22) to
+# left double quotation mark (U+201C) and right double quotation mark (U+201D).
+#
+# When output to an UTF-8 terminal, the quotation characters appear perfectly.
+# When output to an ISO-8859-1 terminal, the single quotation marks are
+# transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to
+# grave/acute accent (by libiconv), and the double quotation marks are
+# transliterated to 0x22.
+# When output to an ASCII terminal, the single quotation marks are
+# transliterated to apostrophes, and the double quotation marks are
+# transliterated to 0x22.
+#
+# This catalog furthermore displays the text between the quotation marks in
+# bold face, assuming the VT100/XTerm escape sequences.
+#
diff --git a/po/en@quot.header b/po/en@quot.header
new file mode 100644 (file)
index 0000000..a9647fc
--- /dev/null
@@ -0,0 +1,22 @@
+# All this catalog "translates" are quotation characters.
+# The msgids must be ASCII and therefore cannot contain real quotation
+# characters, only substitutes like grave accent (0x60), apostrophe (0x27)
+# and double quote (0x22). These substitutes look strange; see
+# http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html
+#
+# This catalog translates grave accent (0x60) and apostrophe (0x27) to
+# left single quotation mark (U+2018) and right single quotation mark (U+2019).
+# It also translates pairs of apostrophe (0x27) to
+# left single quotation mark (U+2018) and right single quotation mark (U+2019)
+# and pairs of quotation mark (0x22) to
+# left double quotation mark (U+201C) and right double quotation mark (U+201D).
+#
+# When output to an UTF-8 terminal, the quotation characters appear perfectly.
+# When output to an ISO-8859-1 terminal, the single quotation marks are
+# transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to
+# grave/acute accent (by libiconv), and the double quotation marks are
+# transliterated to 0x22.
+# When output to an ASCII terminal, the single quotation marks are
+# transliterated to apostrophes, and the double quotation marks are
+# transliterated to 0x22.
+#
diff --git a/po/fr.po b/po/fr.po
new file mode 100644 (file)
index 0000000..feeede7
--- /dev/null
+++ b/po/fr.po
@@ -0,0 +1,329 @@
+# Oriya translations for psensor package.
+# Copyright (C) 2011 Free Software Foundation, Inc.
+# This file is distributed under the same license as the psensor package.
+# wpitchoune <wpitchoune@gmail.com>, 2011.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: psensor 0.6.0.9\n"
+"Report-Msgid-Bugs-To: wpitchoune@gmail.com\n"
+"POT-Creation-Date: 2011-04-03 18:46+0200\n"
+"PO-Revision-Date: 2011-02-07 21:18+0100\n"
+"Last-Translator: wpitchoune <wpitchoune@gmail.com>\n"
+"Language-Team: Oriya\n"
+"Language: or\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8-bit\n"
+
+#: src/main.c:73 src/server/server.c:80
+#, c-format
+msgid ""
+"Copyright (C) %s wpitchoune@gmail.com\n"
+"License GPLv2: GNU GPL version 2 or later <http://www.gnu.org/licenses/old-"
+"licenses/gpl-2.0.html>\n"
+"This is free software: you are free to change and redistribute it.\n"
+"There is NO WARRANTY, to the extent permitted by law.\n"
+msgstr ""
+
+#: src/main.c:83 src/server/server.c:90
+#, c-format
+msgid "Usage: %s [OPTION]...\n"
+msgstr ""
+
+#: src/main.c:85
+msgid ""
+"psensor is a GTK application for monitoring hardware sensors, including "
+"temperatures and fan speeds."
+msgstr ""
+
+#: src/main.c:89
+msgid "Options:"
+msgstr ""
+
+#: src/main.c:90 src/server/server.c:97
+msgid ""
+"  -h, --help          display this help and exit\n"
+"  -v, --version       display version information and exit"
+msgstr ""
+
+#: src/main.c:96
+msgid ""
+"  -u, --url=URL       the URL of the psensor-server, example: http://"
+"hostname:3131"
+msgstr ""
+
+#: src/main.c:102 src/server/server.c:110
+#, c-format
+msgid "Report bugs to: %s\n"
+msgstr ""
+
+#: src/main.c:104 src/server/server.c:112
+#, c-format
+msgid "%s home page: <%s>\n"
+msgstr ""
+
+#: src/main.c:327 src/server/server.c:376
+#, c-format
+msgid "Try `%s --help' for more information.\n"
+msgstr ""
+
+#: src/main.c:350
+#, fuzzy, c-format
+msgid "ERROR: lmsensor init failure: %s\n"
+msgstr "ERREUR: Echec de l'initialisation de 'lm-sensors'\n"
+
+#: src/main.c:361
+#, c-format
+msgid "ERROR: Not compiled with remote sensor support.\n"
+msgstr ""
+
+#: src/ui_sensorlist.c:285
+msgid "Preferences"
+msgstr ""
+
+#: src/ui_sensorlist.c:318
+msgid "Select foreground color"
+msgstr ""
+
+#: src/ui_sensorlist.c:401
+msgid "Sensor"
+msgstr "Sonde"
+
+#: src/ui_sensorlist.c:407
+msgid "Current"
+msgstr "Actuelle"
+
+#: src/ui_sensorlist.c:413
+msgid "Min"
+msgstr ""
+
+#: src/ui_sensorlist.c:419
+msgid "Max"
+msgstr ""
+
+#: src/ui_sensorlist.c:426
+msgid "Color"
+msgstr "Couleur"
+
+#: src/ui_sensorlist.c:439
+msgid "Enabled"
+msgstr "Activée"
+
+#: src/ui_sensorlist.c:468 src/ui_sensorlist.c:469 src/ui_sensorlist.c:470
+msgid "N/A"
+msgstr ""
+
+#: src/ui_notify.c:36
+#, c-format
+msgid "ERROR: failed gettimeofday\n"
+msgstr ""
+
+#: src/ui_notify.c:64
+msgid "Temperature alert"
+msgstr ""
+
+#: src/rsensor.c:131
+#, c-format
+msgid "ERROR: Fail to connect to: %s\n"
+msgstr ""
+
+#: src/rsensor.c:166
+#, c-format
+msgid "ERROR: Invalid content: %s\n"
+msgstr ""
+
+#: src/rsensor.c:204
+#, c-format
+msgid "ERROR: Invalid JSON: %s\n"
+msgstr ""
+
+#: src/plib/plib_luatpl.c:121
+#, c-format
+msgid "LUATPL Error: failed to load Lua script: %s.\n"
+msgstr ""
+
+#: src/plib/plib_luatpl.c:127
+#, c-format
+msgid "LUATPL Error: failed to call init function: %s.\n"
+msgstr ""
+
+#: src/plib/plib_luatpl.c:133
+#, c-format
+msgid "LUATPL Error:failed to execute Lua script (%s): %s.\n"
+msgstr ""
+
+#: src/plib/plib_luatpl.c:140
+#, c-format
+msgid "LUATPL Error:lua script (%s) returned a wrong type.\n"
+msgstr ""
+
+#: src/plib/plib_luatpl.c:147
+#, c-format
+msgid "LUATPL Error:failed to open lua state.\n"
+msgstr ""
+
+#: src/plib/plib_luatpl.c:154
+#, c-format
+msgid "LUATPL Error: code: %d.\n"
+msgstr ""
+
+#: src/server/server.c:56
+msgid ""
+"<html><body><p>Page not found - Go to <a href='/'>Main page</a></p></body>"
+msgstr ""
+
+#: src/server/server.c:92
+msgid ""
+"psensor-server is an HTTP server for monitoring hardware sensors remotely."
+msgstr ""
+
+#: src/server/server.c:103
+msgid ""
+"  -d,--debug     run in debug mode\n"
+"  -p,--port=PORT webserver port\n"
+"  -w,--wdir=DIR  directory containing webserver pages"
+msgstr ""
+
+#: src/server/server.c:184
+msgid "<html><body><p>Server stop requested</p></body></html>"
+msgstr ""
+
+#: src/server/server.c:315
+#, c-format
+msgid "HTTP Request: %s\n"
+msgstr ""
+
+#: src/server/server.c:382
+#, c-format
+msgid "ERROR: failed to init lm-sensors\n"
+msgstr "ERREUR: Echec de l'initialisation de 'lm-sensors'\n"
+
+#: src/server/server.c:389
+#, c-format
+msgid "ERROR: no sensors detected\n"
+msgstr "ERREUR: Aucune sonde detectee\n"
+
+#: src/server/server.c:396
+#, c-format
+msgid "ERROR: Fail to create web server\n"
+msgstr "ERREUR: Echec de la creation du serveur Web\n"
+
+#: src/server/server.c:400
+#, c-format
+msgid "Web server started on port: %d\n"
+msgstr "Server Web demarre sur le port: %d\n"
+
+#: src/server/server.c:401
+#, c-format
+msgid "WWW directory: %s\n"
+msgstr "WWW repertoire: %s\n"
+
+#: src/server/server.c:402
+#, c-format
+msgid "URL: http://localhost:%d\n"
+msgstr ""
+
+#: src/lib/hdd.c:59
+#, c-format
+msgid "ERROR: hdd_fetch, failed to open socket\n"
+msgstr ""
+
+#: src/lib/hdd.c:73
+#, c-format
+msgid "ERROR: hdd_fetch, failed to open connection\n"
+msgstr ""
+
+#: src/lib/hdd.c:182
+#, c-format
+msgid "ERROR: wrong hdd string: %s"
+msgstr ""
+
+#: src/lib/hdd.c:252
+#, c-format
+msgid "ERROR: wrong hdd string: %s\n"
+msgstr ""
+
+#: src/lib/nvidia.c:53
+#, c-format
+msgid "ERROR: failed to retrieve nvidia temperature\n"
+msgstr ""
+
+#: src/lib/nvidia.c:85
+#, c-format
+msgid "ERROR: nvidia initialization failure\n"
+msgstr ""
+
+#: src/lib/nvidia.c:99
+#, c-format
+msgid "ERROR: nvidia initialization failure: %d\n"
+msgstr ""
+
+#: src/lib/nvidia.c:132
+#, c-format
+msgid "ERROR: no nvidia chips or initialization failure\n"
+msgstr ""
+
+#: src/lib/lmsensor.c:43
+#, c-format
+msgid "ERROR: Can't get value of subfeature %s: %s\n"
+msgstr ""
+
+#: src/lib/lmsensor.c:122
+#, c-format
+msgid "ERROR: create_sensor, wrong feature type\n"
+msgstr ""
+
+#: src/lib/lmsensor.c:166
+#, c-format
+msgid "ERROR: lm-sensors initialization failure: %s\n"
+msgstr ""
+
+#~ msgid "Graph Colors"
+#~ msgstr "Couleurs du graphe"
+
+#~ msgid "Background:"
+#~ msgstr "Fond:"
+
+#~ msgid "Background opacity:"
+#~ msgstr "Opacite du fond:"
+
+#~ msgid "Position of sensors table:"
+#~ msgstr "Position de la table des sondes:"
+
+#~ msgid "Right"
+#~ msgstr "Droite"
+
+#~ msgid "Left"
+#~ msgstr "Gauche"
+
+#~ msgid "Top"
+#~ msgstr "Haut"
+
+#~ msgid "Bottom"
+#~ msgstr "Bas"
+
+#~ msgid "Name:"
+#~ msgstr "Nom:"
+
+#~ msgid "Draw sensor curve"
+#~ msgstr "Dessiner la courbe de la sonde"
+
+#, fuzzy
+#~ msgid "Color:"
+#~ msgstr "Couleur"
+
+#~ msgid "Alarm"
+#~ msgstr "Alarme"
+
+#~ msgid "Activate desktop notifications"
+#~ msgstr "Activer les notifications du bureau"
+
+#~ msgid "Show"
+#~ msgstr "Montrer"
+
+#~ msgid "ERROR: Lua support not enabled\n"
+#~ msgstr "ERREUR: Le support de Lua n'est pas active\n"
+
+#~ msgid "Psensor - Temperature Monitor"
+#~ msgstr "Psensor - Surveillance Des Temperatures"
diff --git a/po/insert-header.sin b/po/insert-header.sin
new file mode 100644 (file)
index 0000000..b26de01
--- /dev/null
@@ -0,0 +1,23 @@
+# Sed script that inserts the file called HEADER before the header entry.
+#
+# At each occurrence of a line starting with "msgid ", we execute the following
+# commands. At the first occurrence, insert the file. At the following
+# occurrences, do nothing. The distinction between the first and the following
+# occurrences is achieved by looking at the hold space.
+/^msgid /{
+x
+# Test if the hold space is empty.
+s/m/m/
+ta
+# Yes it was empty. First occurrence. Read the file.
+r HEADER
+# Output the file's contents by reading the next line. But don't lose the
+# current line while doing this.
+g
+N
+bb
+:a
+# The hold space was nonempty. Following occurrences. Do nothing.
+x
+:b
+}
diff --git a/po/psensor.pot b/po/psensor.pot
new file mode 100644 (file)
index 0000000..6c7f32a
--- /dev/null
@@ -0,0 +1,281 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Free Software Foundation, Inc.
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: wpitchoune@gmail.com\n"
+"POT-Creation-Date: 2011-04-03 18:46+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: src/main.c:73 src/server/server.c:80
+#, c-format
+msgid ""
+"Copyright (C) %s wpitchoune@gmail.com\n"
+"License GPLv2: GNU GPL version 2 or later <http://www.gnu.org/licenses/old-"
+"licenses/gpl-2.0.html>\n"
+"This is free software: you are free to change and redistribute it.\n"
+"There is NO WARRANTY, to the extent permitted by law.\n"
+msgstr ""
+
+#: src/main.c:83 src/server/server.c:90
+#, c-format
+msgid "Usage: %s [OPTION]...\n"
+msgstr ""
+
+#: src/main.c:85
+msgid ""
+"psensor is a GTK application for monitoring hardware sensors, including "
+"temperatures and fan speeds."
+msgstr ""
+
+#: src/main.c:89
+msgid "Options:"
+msgstr ""
+
+#: src/main.c:90 src/server/server.c:97
+msgid ""
+"  -h, --help          display this help and exit\n"
+"  -v, --version       display version information and exit"
+msgstr ""
+
+#: src/main.c:96
+msgid ""
+"  -u, --url=URL       the URL of the psensor-server, example: http://"
+"hostname:3131"
+msgstr ""
+
+#: src/main.c:102 src/server/server.c:110
+#, c-format
+msgid "Report bugs to: %s\n"
+msgstr ""
+
+#: src/main.c:104 src/server/server.c:112
+#, c-format
+msgid "%s home page: <%s>\n"
+msgstr ""
+
+#: src/main.c:327 src/server/server.c:376
+#, c-format
+msgid "Try `%s --help' for more information.\n"
+msgstr ""
+
+#: src/main.c:350
+#, c-format
+msgid "ERROR: lmsensor init failure: %s\n"
+msgstr ""
+
+#: src/main.c:361
+#, c-format
+msgid "ERROR: Not compiled with remote sensor support.\n"
+msgstr ""
+
+#: src/ui_sensorlist.c:285
+msgid "Preferences"
+msgstr ""
+
+#: src/ui_sensorlist.c:318
+msgid "Select foreground color"
+msgstr ""
+
+#: src/ui_sensorlist.c:401
+msgid "Sensor"
+msgstr ""
+
+#: src/ui_sensorlist.c:407
+msgid "Current"
+msgstr ""
+
+#: src/ui_sensorlist.c:413
+msgid "Min"
+msgstr ""
+
+#: src/ui_sensorlist.c:419
+msgid "Max"
+msgstr ""
+
+#: src/ui_sensorlist.c:426
+msgid "Color"
+msgstr ""
+
+#: src/ui_sensorlist.c:439
+msgid "Enabled"
+msgstr ""
+
+#: src/ui_sensorlist.c:468 src/ui_sensorlist.c:469 src/ui_sensorlist.c:470
+msgid "N/A"
+msgstr ""
+
+#: src/ui_notify.c:36
+#, c-format
+msgid "ERROR: failed gettimeofday\n"
+msgstr ""
+
+#: src/ui_notify.c:64
+msgid "Temperature alert"
+msgstr ""
+
+#: src/rsensor.c:131
+#, c-format
+msgid "ERROR: Fail to connect to: %s\n"
+msgstr ""
+
+#: src/rsensor.c:166
+#, c-format
+msgid "ERROR: Invalid content: %s\n"
+msgstr ""
+
+#: src/rsensor.c:204
+#, c-format
+msgid "ERROR: Invalid JSON: %s\n"
+msgstr ""
+
+#: src/plib/plib_luatpl.c:121
+#, c-format
+msgid "LUATPL Error: failed to load Lua script: %s.\n"
+msgstr ""
+
+#: src/plib/plib_luatpl.c:127
+#, c-format
+msgid "LUATPL Error: failed to call init function: %s.\n"
+msgstr ""
+
+#: src/plib/plib_luatpl.c:133
+#, c-format
+msgid "LUATPL Error:failed to execute Lua script (%s): %s.\n"
+msgstr ""
+
+#: src/plib/plib_luatpl.c:140
+#, c-format
+msgid "LUATPL Error:lua script (%s) returned a wrong type.\n"
+msgstr ""
+
+#: src/plib/plib_luatpl.c:147
+#, c-format
+msgid "LUATPL Error:failed to open lua state.\n"
+msgstr ""
+
+#: src/plib/plib_luatpl.c:154
+#, c-format
+msgid "LUATPL Error: code: %d.\n"
+msgstr ""
+
+#: src/server/server.c:56
+msgid ""
+"<html><body><p>Page not found - Go to <a href='/'>Main page</a></p></body>"
+msgstr ""
+
+#: src/server/server.c:92
+msgid ""
+"psensor-server is an HTTP server for monitoring hardware sensors remotely."
+msgstr ""
+
+#: src/server/server.c:103
+msgid ""
+"  -d,--debug     run in debug mode\n"
+"  -p,--port=PORT webserver port\n"
+"  -w,--wdir=DIR  directory containing webserver pages"
+msgstr ""
+
+#: src/server/server.c:184
+msgid "<html><body><p>Server stop requested</p></body></html>"
+msgstr ""
+
+#: src/server/server.c:315
+#, c-format
+msgid "HTTP Request: %s\n"
+msgstr ""
+
+#: src/server/server.c:382
+#, c-format
+msgid "ERROR: failed to init lm-sensors\n"
+msgstr ""
+
+#: src/server/server.c:389
+#, c-format
+msgid "ERROR: no sensors detected\n"
+msgstr ""
+
+#: src/server/server.c:396
+#, c-format
+msgid "ERROR: Fail to create web server\n"
+msgstr ""
+
+#: src/server/server.c:400
+#, c-format
+msgid "Web server started on port: %d\n"
+msgstr ""
+
+#: src/server/server.c:401
+#, c-format
+msgid "WWW directory: %s\n"
+msgstr ""
+
+#: src/server/server.c:402
+#, c-format
+msgid "URL: http://localhost:%d\n"
+msgstr ""
+
+#: src/lib/hdd.c:59
+#, c-format
+msgid "ERROR: hdd_fetch, failed to open socket\n"
+msgstr ""
+
+#: src/lib/hdd.c:73
+#, c-format
+msgid "ERROR: hdd_fetch, failed to open connection\n"
+msgstr ""
+
+#: src/lib/hdd.c:182
+#, c-format
+msgid "ERROR: wrong hdd string: %s"
+msgstr ""
+
+#: src/lib/hdd.c:252
+#, c-format
+msgid "ERROR: wrong hdd string: %s\n"
+msgstr ""
+
+#: src/lib/nvidia.c:53
+#, c-format
+msgid "ERROR: failed to retrieve nvidia temperature\n"
+msgstr ""
+
+#: src/lib/nvidia.c:85
+#, c-format
+msgid "ERROR: nvidia initialization failure\n"
+msgstr ""
+
+#: src/lib/nvidia.c:99
+#, c-format
+msgid "ERROR: nvidia initialization failure: %d\n"
+msgstr ""
+
+#: src/lib/nvidia.c:132
+#, c-format
+msgid "ERROR: no nvidia chips or initialization failure\n"
+msgstr ""
+
+#: src/lib/lmsensor.c:43
+#, c-format
+msgid "ERROR: Can't get value of subfeature %s: %s\n"
+msgstr ""
+
+#: src/lib/lmsensor.c:122
+#, c-format
+msgid "ERROR: create_sensor, wrong feature type\n"
+msgstr ""
+
+#: src/lib/lmsensor.c:166
+#, c-format
+msgid "ERROR: lm-sensors initialization failure: %s\n"
+msgstr ""
diff --git a/po/quot.sed b/po/quot.sed
new file mode 100644 (file)
index 0000000..0122c46
--- /dev/null
@@ -0,0 +1,6 @@
+s/"\([^"]*\)"/“\1”/g
+s/`\([^`']*\)'/‘\1’/g
+s/ '\([^`']*\)' / ‘\1’ /g
+s/ '\([^`']*\)'$/ ‘\1’/g
+s/^'\([^`']*\)' /‘\1’ /g
+s/“”/""/g
diff --git a/po/remove-potcdate.sin b/po/remove-potcdate.sin
new file mode 100644 (file)
index 0000000..2436c49
--- /dev/null
@@ -0,0 +1,19 @@
+# Sed script that remove the POT-Creation-Date line in the header entry
+# from a POT file.
+#
+# The distinction between the first and the following occurrences of the
+# pattern is achieved by looking at the hold space.
+/^"POT-Creation-Date: .*"$/{
+x
+# Test if the hold space is empty.
+s/P/P/
+ta
+# Yes it was empty. First occurrence. Remove the line.
+g
+d
+bb
+:a
+# The hold space was nonempty. Following occurrences. Do nothing.
+x
+:b
+}
diff --git a/po/zh_CN.po b/po/zh_CN.po
new file mode 100644 (file)
index 0000000..a85f583
--- /dev/null
@@ -0,0 +1,366 @@
+# Chinese translations for psensor package.
+# Copyright (C) 2011 Free Software Foundation, Inc.
+# This file is distributed under the same license as the psensor package.
+# wpitchoune <wpitchoune@gmail.com>, 2011.
+# Chinese translation from 大宝 <linux.dabao@gmail.com>
+msgid ""
+msgstr ""
+"Project-Id-Version: psensor 0.6.0.10\n"
+"Report-Msgid-Bugs-To: wpitchoune@gmail.com\n"
+"POT-Creation-Date: 2011-04-03 18:46+0200\n"
+"PO-Revision-Date: 2011-02-07 22:21+0100\n"
+"Last-Translator: 大宝 <linux.dabao@gmail.com>\n"
+"Language-Team: Chinese (simplified)\n"
+"Language: zh_CN\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: src/main.c:73 src/server/server.c:80
+#, c-format
+msgid ""
+"Copyright (C) %s wpitchoune@gmail.com\n"
+"License GPLv2: GNU GPL version 2 or later <http://www.gnu.org/licenses/old-"
+"licenses/gpl-2.0.html>\n"
+"This is free software: you are free to change and redistribute it.\n"
+"There is NO WARRANTY, to the extent permitted by law.\n"
+msgstr ""
+
+#: src/main.c:83 src/server/server.c:90
+#, c-format
+msgid "Usage: %s [OPTION]...\n"
+msgstr ""
+
+#: src/main.c:85
+msgid ""
+"psensor is a GTK application for monitoring hardware sensors, including "
+"temperatures and fan speeds."
+msgstr ""
+
+#: src/main.c:89
+msgid "Options:"
+msgstr ""
+
+#: src/main.c:90 src/server/server.c:97
+msgid ""
+"  -h, --help          display this help and exit\n"
+"  -v, --version       display version information and exit"
+msgstr ""
+
+#: src/main.c:96
+msgid ""
+"  -u, --url=URL       the URL of the psensor-server, example: http://"
+"hostname:3131"
+msgstr ""
+
+#: src/main.c:102 src/server/server.c:110
+#, c-format
+msgid "Report bugs to: %s\n"
+msgstr ""
+
+#: src/main.c:104 src/server/server.c:112
+#, c-format
+msgid "%s home page: <%s>\n"
+msgstr ""
+
+#: src/main.c:327 src/server/server.c:376
+#, c-format
+msgid "Try `%s --help' for more information.\n"
+msgstr ""
+
+#: src/main.c:350
+#, c-format
+msgid "ERROR: lmsensor init failure: %s\n"
+msgstr ""
+
+#: src/main.c:361
+#, c-format
+msgid "ERROR: Not compiled with remote sensor support.\n"
+msgstr ""
+
+#: src/ui_sensorlist.c:285
+msgid "Preferences"
+msgstr "选项"
+
+#: src/ui_sensorlist.c:318
+msgid "Select foreground color"
+msgstr ""
+
+#: src/ui_sensorlist.c:401
+msgid "Sensor"
+msgstr "监视设备"
+
+#: src/ui_sensorlist.c:407
+msgid "Current"
+msgstr "当前"
+
+#: src/ui_sensorlist.c:413
+msgid "Min"
+msgstr "最小值"
+
+#: src/ui_sensorlist.c:419
+msgid "Max"
+msgstr "最大值"
+
+#: src/ui_sensorlist.c:426
+msgid "Color"
+msgstr "颜色"
+
+#: src/ui_sensorlist.c:439
+msgid "Enabled"
+msgstr "激活"
+
+#: src/ui_sensorlist.c:468 src/ui_sensorlist.c:469 src/ui_sensorlist.c:470
+msgid "N/A"
+msgstr ""
+
+#: src/ui_notify.c:36
+#, c-format
+msgid "ERROR: failed gettimeofday\n"
+msgstr ""
+
+#: src/ui_notify.c:64
+msgid "Temperature alert"
+msgstr ""
+
+#: src/rsensor.c:131
+#, c-format
+msgid "ERROR: Fail to connect to: %s\n"
+msgstr ""
+
+#: src/rsensor.c:166
+#, c-format
+msgid "ERROR: Invalid content: %s\n"
+msgstr ""
+
+#: src/rsensor.c:204
+#, c-format
+msgid "ERROR: Invalid JSON: %s\n"
+msgstr ""
+
+#: src/plib/plib_luatpl.c:121
+#, c-format
+msgid "LUATPL Error: failed to load Lua script: %s.\n"
+msgstr ""
+
+#: src/plib/plib_luatpl.c:127
+#, c-format
+msgid "LUATPL Error: failed to call init function: %s.\n"
+msgstr ""
+
+#: src/plib/plib_luatpl.c:133
+#, c-format
+msgid "LUATPL Error:failed to execute Lua script (%s): %s.\n"
+msgstr ""
+
+#: src/plib/plib_luatpl.c:140
+#, c-format
+msgid "LUATPL Error:lua script (%s) returned a wrong type.\n"
+msgstr ""
+
+#: src/plib/plib_luatpl.c:147
+#, c-format
+msgid "LUATPL Error:failed to open lua state.\n"
+msgstr ""
+
+#: src/plib/plib_luatpl.c:154
+#, c-format
+msgid "LUATPL Error: code: %d.\n"
+msgstr ""
+
+#: src/server/server.c:56
+msgid ""
+"<html><body><p>Page not found - Go to <a href='/'>Main page</a></p></body>"
+msgstr ""
+
+#: src/server/server.c:92
+msgid ""
+"psensor-server is an HTTP server for monitoring hardware sensors remotely."
+msgstr ""
+
+#: src/server/server.c:103
+msgid ""
+"  -d,--debug     run in debug mode\n"
+"  -p,--port=PORT webserver port\n"
+"  -w,--wdir=DIR  directory containing webserver pages"
+msgstr ""
+
+#: src/server/server.c:184
+msgid "<html><body><p>Server stop requested</p></body></html>"
+msgstr ""
+
+#: src/server/server.c:315
+#, c-format
+msgid "HTTP Request: %s\n"
+msgstr ""
+
+#: src/server/server.c:382
+#, c-format
+msgid "ERROR: failed to init lm-sensors\n"
+msgstr ""
+
+#: src/server/server.c:389
+#, c-format
+msgid "ERROR: no sensors detected\n"
+msgstr ""
+
+#: src/server/server.c:396
+#, c-format
+msgid "ERROR: Fail to create web server\n"
+msgstr ""
+
+#: src/server/server.c:400
+#, c-format
+msgid "Web server started on port: %d\n"
+msgstr ""
+
+#: src/server/server.c:401
+#, c-format
+msgid "WWW directory: %s\n"
+msgstr ""
+
+#: src/server/server.c:402
+#, c-format
+msgid "URL: http://localhost:%d\n"
+msgstr ""
+
+#: src/lib/hdd.c:59
+#, c-format
+msgid "ERROR: hdd_fetch, failed to open socket\n"
+msgstr ""
+
+#: src/lib/hdd.c:73
+#, c-format
+msgid "ERROR: hdd_fetch, failed to open connection\n"
+msgstr ""
+
+#: src/lib/hdd.c:182
+#, c-format
+msgid "ERROR: wrong hdd string: %s"
+msgstr ""
+
+#: src/lib/hdd.c:252
+#, c-format
+msgid "ERROR: wrong hdd string: %s\n"
+msgstr ""
+
+#: src/lib/nvidia.c:53
+#, c-format
+msgid "ERROR: failed to retrieve nvidia temperature\n"
+msgstr ""
+
+#: src/lib/nvidia.c:85
+#, c-format
+msgid "ERROR: nvidia initialization failure\n"
+msgstr ""
+
+#: src/lib/nvidia.c:99
+#, c-format
+msgid "ERROR: nvidia initialization failure: %d\n"
+msgstr ""
+
+#: src/lib/nvidia.c:132
+#, c-format
+msgid "ERROR: no nvidia chips or initialization failure\n"
+msgstr ""
+
+#: src/lib/lmsensor.c:43
+#, c-format
+msgid "ERROR: Can't get value of subfeature %s: %s\n"
+msgstr ""
+
+#: src/lib/lmsensor.c:122
+#, c-format
+msgid "ERROR: create_sensor, wrong feature type\n"
+msgstr ""
+
+#: src/lib/lmsensor.c:166
+#, c-format
+msgid "ERROR: lm-sensors initialization failure: %s\n"
+msgstr ""
+
+#~ msgid "Graph Colors"
+#~ msgstr "图表颜色"
+
+#~ msgid "Foreground:"
+#~ msgstr "坐标栏:"
+
+#~ msgid "Background:"
+#~ msgstr "背景:"
+
+#~ msgid "Background opacity:"
+#~ msgstr "背景亮度:"
+
+#~ msgid "<i>Min</i>"
+#~ msgstr "<i>最小值</i>"
+
+#~ msgid "<i>Max</i>"
+#~ msgstr "<i>最大值</i>"
+
+#~ msgid "Graph"
+#~ msgstr "图表"
+
+#~ msgid "Interface"
+#~ msgstr "界面"
+
+#~ msgid "Position of sensors table:"
+#~ msgstr "监视设备列表位置:"
+
+#~ msgid "Right"
+#~ msgstr "右侧"
+
+#~ msgid "Left"
+#~ msgstr "左侧"
+
+#~ msgid "Top"
+#~ msgstr "顶部"
+
+#~ msgid "Bottom"
+#~ msgstr "底部"
+
+#~ msgid "Hide window decoration"
+#~ msgstr "隐藏窗口标题栏"
+
+#~ msgid "Keep window below"
+#~ msgstr "保持在最底层"
+
+#, fuzzy
+#~ msgid "Edit Preferences"
+#~ msgstr "监视设备选项"
+
+#~ msgid "Edit Sensor Preferences"
+#~ msgstr "监视设备选项"
+
+#~ msgid "Sensor Information"
+#~ msgstr "设备信息"
+
+#~ msgid "Id:"
+#~ msgstr "标识:"
+
+#~ msgid "Type:"
+#~ msgstr "类型:"
+
+#~ msgid "Name:"
+#~ msgstr "名称:"
+
+#~ msgid "Draw sensor curve"
+#~ msgstr "绘制监视曲线"
+
+#, fuzzy
+#~ msgid "Color:"
+#~ msgstr "颜色:"
+
+#~ msgid "Alarm"
+#~ msgstr "警告信息"
+
+#~ msgid "Activate desktop notifications"
+#~ msgstr "激活桌面气泡提示"
+
+#~ msgid "Temperature limit:"
+#~ msgstr "温度警戒线:"
+
+#~ msgid "Show"
+#~ msgstr "显示主窗口"
+
+#~ msgid "Quit"
+#~ msgstr "退出"
diff --git a/psensor.desktop b/psensor.desktop
new file mode 100644 (file)
index 0000000..ecc02db
--- /dev/null
@@ -0,0 +1,10 @@
+[Desktop Entry]
+Type=Application
+Version=1.0
+Name=Psensor
+GenericName=Psensor
+Comment=Psensor is a graphical temperature monitor for Linux
+Icon=psensor
+TryExec=psensor
+Exec=psensor
+Categories=Application;System;
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644 (file)
index 0000000..e567c83
--- /dev/null
@@ -0,0 +1,81 @@
+SUBDIRS = plib lib unity glade
+
+AM_LDFLAGS = -Wl,--as-needed 
+
+if JSON
+SUBDIRS += libpsensor_json
+endif
+
+if LIBMICROHTTPD
+if JSON
+if LUA
+SUBDIRS += server
+endif
+endif
+endif
+
+AM_CPPFLAGS = -Wall -pedantic -Werror -DDEFAULT_WWW_DIR=\""$(pkgdatadir)/www"\"\
+       -I$(top_srcdir)/src/lib \
+       -I$(top_srcdir)/src/unity \
+       $(GTK_CFLAGS)\
+       $(GCONF_CFLAGS)\
+       $(SENSORS_CFLAGS)
+
+DEFS = -DPACKAGE_DATA_DIR=\"$(pkgdatadir)\" -DLOCALEDIR=\"$(localedir)\" @DEFS@
+
+LIBS = \
+       plib/libplib.a \
+       lib/libpsensor.a \
+       $(GTK_LIBS)\
+       $(GCONF_LIBS)\
+       $(SENSORS_LIBS)
+
+bin_PROGRAMS = psensor
+psensor_SOURCES = \
+       compat.h \
+       cfg.h cfg.c \
+       graph.h graph.c \
+       main.c \
+       ui.h ui.c \
+       ui_color.h ui_color.c \
+       ui_graph.h ui_graph.c \
+       ui_pref.h ui_pref.c \
+       ui_sensorlist.h ui_sensorlist.c 
+
+if LIBNOTIFY
+psensor_SOURCES += ui_notify.h ui_notify.c
+LIBS += $(LIBNOTIFY_LIBS)
+AM_CPPFLAGS += $(LIBNOTIFY_CFLAGS)
+endif
+
+if APPINDICATOR 
+psensor_SOURCES += ui_appindicator.h ui_appindicator.c 
+LIBS +=        $(APPINDICATOR_LIBS)
+AM_CPPFLAGS += $(APPINDICATOR_CFLAGS)
+endif
+
+if NVIDIA
+AM_CPPFLAGS += $(NVIDIA_CFLAGS)
+LIBS +=  $(NVIDIA_LIBS)
+endif
+
+if UNITY
+AM_CPPFLAGS += $(UNITY_CFLAGS)
+LIBS += unity/libpsensor_unity.a $(UNITY_LIBS) 
+endif
+
+if CURL
+if JSON
+psensor_SOURCES += rsensor.h rsensor.c plib/url.c plib/url.h
+LIBS += $(CURL_LIBS) $(JSON_LIBS)
+AM_CPPFLAGS += $(CURL_CFLAGS) $(JSON_CFLAGS)
+endif
+endif
+
+dist_man_MANS = psensor.1
+
+
+psensor.1: main.c $(top_srcdir)/configure.ac
+       $(MAKE) $(AM_MAKEFLAGS) psensor$(EXEEXT)
+       help2man --include=description.txt -N --name="Temperature monitoring application" --output=psensor.1 ./psensor$(EXEEXT)
+
diff --git a/src/cfg.c b/src/cfg.c
new file mode 100644 (file)
index 0000000..24dedf0
--- /dev/null
+++ b/src/cfg.c
@@ -0,0 +1,456 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <gconf/gconf-client.h>
+
+#include "cfg.h"
+
+#define KEY_SENSOR_UPDATE_INTERVAL "/apps/psensor/sensor/update_interval"
+
+#define KEY_GRAPH_UPDATE_INTERVAL "/apps/psensor/graph/update_interval"
+#define KEY_GRAPH_MONITORING_DURATION "/apps/psensor/graph/monitoring_duration"
+
+#define KEY_GRAPH_BACKGROUND_COLOR "/apps/psensor/graph/background_color"
+#define DEFAULT_GRAPH_BACKGROUND_COLOR "#e8f4e8f4a8f5"
+
+#define KEY_GRAPH_BACKGROUND_ALPHA  "/apps/psensor/graph/background_alpha"
+#define DEFAULT_GRAPH_BACKGROUND_ALPHA "1.0"
+
+#define KEY_GRAPH_FOREGROUND_COLOR  "/apps/psensor/graph/foreground_color"
+#define DEFAULT_GRAPH_FOREGROUND_COLOR "#000000000000"
+
+#define KEY_ALPHA_CHANNEL_ENABLED  "/apps/psensor/graph/alpha_channel_enabled"
+#define DEFAULT_ALPHA_CHANNEL_ENABLED 0
+
+#define KEY_INTERFACE_SENSORLIST_POSITION \
+"/apps/psensor/interface/sensorlist_position"
+
+#define KEY_INTERFACE_WINDOW_DECORATION_DISABLED \
+"/apps/psensor/interface/window_decoration_disabled"
+
+#define KEY_INTERFACE_WINDOW_KEEP_BELOW_ENABLED \
+"/apps/psensor/interface/window_keep_below_enabled"
+
+GConfClient *client;
+
+char *config_get_string(char *key, char *default_value)
+{
+       char *value = gconf_client_get_string(client,
+                                             key,
+                                             NULL);
+
+       if (!value) {
+               value = strdup(default_value);
+
+               gconf_client_set_string(client, key, default_value, NULL);
+       }
+
+       return value;
+}
+
+struct color *config_get_background_color()
+{
+
+       char *scolor = config_get_string(KEY_GRAPH_BACKGROUND_COLOR,
+                                        DEFAULT_GRAPH_BACKGROUND_COLOR);
+
+       struct color *c = string_to_color(scolor);
+
+       free(scolor);
+
+       if (c == NULL)
+               return color_new(0xffff, 0xffff, 0xffff);
+
+       return c;
+}
+
+struct color *config_get_foreground_color()
+{
+       char *scolor = config_get_string(KEY_GRAPH_FOREGROUND_COLOR,
+                                        DEFAULT_GRAPH_FOREGROUND_COLOR);
+
+       struct color *c = string_to_color(scolor);
+
+       free(scolor);
+
+       if (c == NULL)
+               return color_new(0x0000, 0x0000, 0x0000);
+
+       return c;
+}
+
+int config_is_alpha_channel_enabled()
+{
+       gboolean b = gconf_client_get_bool(client,
+                                          KEY_ALPHA_CHANNEL_ENABLED,
+                                          NULL);
+
+       return b == TRUE;
+}
+
+void config_set_alpha_channel_enabled(int enabled)
+{
+       if (enabled)
+               gconf_client_set_bool(client,
+                                     KEY_ALPHA_CHANNEL_ENABLED, TRUE, NULL);
+       else
+               gconf_client_set_bool(client,
+                                     KEY_ALPHA_CHANNEL_ENABLED, FALSE, NULL);
+}
+
+int config_get_sensorlist_position()
+{
+       return gconf_client_get_int(client,
+                                   KEY_INTERFACE_SENSORLIST_POSITION, NULL);
+}
+
+void config_set_sensorlist_position(int pos)
+{
+       gconf_client_set_int(client,
+                            KEY_INTERFACE_SENSORLIST_POSITION, pos, NULL);
+}
+
+double config_get_graph_background_alpha()
+{
+       double a = gconf_client_get_float(client,
+                                         KEY_GRAPH_BACKGROUND_ALPHA,
+                                         NULL);
+
+       if (a == 0)
+               gconf_client_set_float(client,
+                                      KEY_GRAPH_BACKGROUND_ALPHA, 1.0, NULL);
+       return a;
+}
+
+void config_set_graph_background_alpha(double alpha)
+{
+       gconf_client_set_float(client, KEY_GRAPH_BACKGROUND_ALPHA, alpha, NULL);
+}
+
+void config_set_background_color(struct color *color)
+{
+       char *scolor = color_to_string(color);
+
+       if (!scolor)
+               scolor = strdup(DEFAULT_GRAPH_BACKGROUND_COLOR);
+
+       gconf_client_set_string(client,
+                               KEY_GRAPH_BACKGROUND_COLOR, scolor, NULL);
+
+       free(scolor);
+}
+
+void config_set_foreground_color(struct color *color)
+{
+       char *scolor = color_to_string(color);
+
+       if (!scolor)
+               scolor = strdup(DEFAULT_GRAPH_FOREGROUND_COLOR);
+
+       gconf_client_set_string(client,
+                               KEY_GRAPH_FOREGROUND_COLOR, scolor, NULL);
+
+       free(scolor);
+}
+
+char *config_get_sensor_key(char *sensor_name)
+{
+       char *escaped_name = gconf_escape_key(sensor_name, -1);
+       /* /apps/psensor/sensors/[sensor_name]/color */
+       char *key = malloc(22 + 2 * strlen(escaped_name) + 6 + 1);
+
+       sprintf(key, "/apps/psensor/sensors/%s/color", escaped_name);
+
+       free(escaped_name);
+
+       return key;
+}
+
+struct color *config_get_sensor_color(char *sensor_name,
+                                     struct color *default_color)
+{
+       char *key = config_get_sensor_key(sensor_name);
+
+       char *scolor = gconf_client_get_string(client,
+                                              key,
+                                              NULL);
+
+       struct color *color = NULL;
+
+       if (scolor)
+               color = string_to_color(scolor);
+
+       if (!scolor || !color) {
+               color = color_new(default_color->red,
+                                 default_color->green, default_color->blue);
+
+               scolor = color_to_string(color);
+
+               gconf_client_set_string(client, key, scolor, NULL);
+       }
+
+       free(scolor);
+       free(key);
+
+       return color;
+}
+
+void config_set_sensor_color(char *sensor_name, struct color *color)
+{
+       char *key = config_get_sensor_key(sensor_name);
+
+       char *scolor = color_to_string(color);
+
+       gconf_client_set_string(client, key, scolor, NULL);
+
+       free(scolor);
+}
+
+int config_get_sensor_alarm_limit(char *sensor_name, int def)
+{
+       int res;
+       char *escaped_name = gconf_escape_key(sensor_name, -1);
+       /* /apps/psensor/sensors/[sensor_name]/alarmlimit */
+       char *key = malloc(22 + 2 * strlen(escaped_name) + 1 + 10 + 1);
+
+       sprintf(key, "/apps/psensor/sensors/%s/alarmlimit", escaped_name);
+
+       res = gconf_client_get_int(client, key, NULL);
+
+       free(escaped_name);
+
+       return res ? res : def;
+}
+
+void config_set_sensor_alarm_limit(char *sensor_name, int alarm_limit)
+{
+       char *escaped_name = gconf_escape_key(sensor_name, -1);
+       /* /apps/psensor/sensors/[sensor_name]/alarmlimit */
+       char *key = malloc(22 + 2 * strlen(escaped_name) + 1 + 10 + 1);
+
+       sprintf(key, "/apps/psensor/sensors/%s/alarmlimit", escaped_name);
+
+       gconf_client_set_int(client, key, alarm_limit, NULL);
+
+       free(escaped_name);
+}
+
+int config_get_sensor_alarm_enabled(char *sid)
+{
+       gboolean res;
+       char *escaped_name = gconf_escape_key(sid, -1);
+       /* /apps/psensor/sensors/[sensor_name]/alarmenabled */
+       char *key = malloc(22 + 2 * strlen(escaped_name) + 1 + 12 + 1);
+
+       sprintf(key, "/apps/psensor/sensors/%s/alarmenabled", escaped_name);
+
+       res = gconf_client_get_bool(client, key, NULL);
+
+       free(escaped_name);
+
+       return res == TRUE;
+}
+
+void config_set_sensor_alarm_enabled(char *sid, int enabled)
+{
+       char *escaped_name = gconf_escape_key(sid, -1);
+       /* /apps/psensor/sensors/[sensor_name]/alarmenabled */
+       char *key = malloc(22 + 2 * strlen(escaped_name) + 1 + 12 + 1);
+
+       sprintf(key, "/apps/psensor/sensors/%s/alarmenabled", escaped_name);
+
+       gconf_client_set_bool(client, key, enabled, NULL);
+
+       free(escaped_name);
+}
+
+int config_is_sensor_enabled(char *sid)
+{
+       gboolean res;
+       char *escaped_name = gconf_escape_key(sid, -1);
+       /* /apps/psensor/sensors/[sensor_name]/enabled */
+       char *key = malloc(22 + 2 * strlen(escaped_name) + 1 + 7 + 1);
+
+       sprintf(key, "/apps/psensor/sensors/%s/enabled", escaped_name);
+
+       res = gconf_client_get_bool(client, key, NULL);
+
+       free(escaped_name);
+
+       return res == TRUE;
+
+}
+
+void config_set_sensor_enabled(char *sid, int enabled)
+{
+       char *escaped_name = gconf_escape_key(sid, -1);
+       /* /apps/psensor/sensors/[sensor_name]/enabled */
+       char *key = malloc(22 + 2 * strlen(escaped_name) + 1 + 7 + 1);
+
+       sprintf(key, "/apps/psensor/sensors/%s/enabled", escaped_name);
+
+       gconf_client_set_bool(client, key, enabled, NULL);
+
+       free(escaped_name);
+}
+
+char *config_get_sensor_name(char *sid)
+{
+       char *res;
+       char *escaped_name = gconf_escape_key(sid, -1);
+       /* /apps/psensor/sensors/[sensor_name]/name */
+       char *key = malloc(22 + 2 * strlen(escaped_name) + 1 + 4 + 1);
+
+       sprintf(key, "/apps/psensor/sensors/%s/name", escaped_name);
+
+       res = gconf_client_get_string(client, key, NULL);
+
+       free(escaped_name);
+
+       return res;
+}
+
+void config_set_sensor_name(char *sid, const char *name)
+{
+       char *escaped_name = gconf_escape_key(sid, -1);
+       /* /apps/psensor/sensors/[sensor_name]/name */
+       char *key = malloc(22 + 2 * strlen(escaped_name) + 1 + 4 + 1);
+
+       sprintf(key, "/apps/psensor/sensors/%s/name", escaped_name);
+
+       gconf_client_set_string(client, key, name, NULL);
+
+       free(escaped_name);
+}
+
+int config_is_window_decoration_enabled()
+{
+       gboolean b;
+
+       b = gconf_client_get_bool(client,
+                                 KEY_INTERFACE_WINDOW_DECORATION_DISABLED,
+                                 NULL);
+
+       return b == FALSE;
+}
+
+int config_is_window_keep_below_enabled()
+{
+       gboolean b;
+
+       b = gconf_client_get_bool(client,
+                                 KEY_INTERFACE_WINDOW_KEEP_BELOW_ENABLED,
+                                 NULL);
+
+       return b == TRUE;
+}
+
+void config_set_window_decoration_enabled(int enabled)
+{
+       if (enabled)
+               gconf_client_set_bool
+                   (client,
+                    KEY_INTERFACE_WINDOW_DECORATION_DISABLED, FALSE, NULL);
+       else
+               gconf_client_set_bool
+                   (client,
+                    KEY_INTERFACE_WINDOW_DECORATION_DISABLED, TRUE, NULL);
+}
+
+void config_set_window_keep_below_enabled(int enabled)
+{
+       if (enabled)
+               gconf_client_set_bool(client,
+                                     KEY_INTERFACE_WINDOW_KEEP_BELOW_ENABLED,
+                                     TRUE, NULL);
+       else
+               gconf_client_set_bool(client,
+                                     KEY_INTERFACE_WINDOW_KEEP_BELOW_ENABLED,
+                                     FALSE, NULL);
+}
+
+void config_init()
+{
+       client = gconf_client_get_default();
+}
+
+struct config *config_load()
+{
+       struct config *cfg = malloc(sizeof(struct config));
+
+       cfg->graph_bgcolor = config_get_background_color();
+       cfg->graph_fgcolor = config_get_foreground_color();
+       cfg->graph_bg_alpha = config_get_graph_background_alpha();
+       cfg->alpha_channel_enabled = config_is_alpha_channel_enabled();
+       cfg->sensorlist_position = config_get_sensorlist_position();
+       cfg->window_decoration_enabled = config_is_window_decoration_enabled();
+       cfg->window_keep_below_enabled = config_is_window_keep_below_enabled();
+
+       cfg->sensor_update_interval
+           = gconf_client_get_int(client, KEY_SENSOR_UPDATE_INTERVAL, NULL);
+       if (cfg->sensor_update_interval < 1)
+               cfg->sensor_update_interval = 1;
+
+       cfg->graph_update_interval
+           = gconf_client_get_int(client, KEY_GRAPH_UPDATE_INTERVAL, NULL);
+       if (cfg->graph_update_interval < 1)
+               cfg->graph_update_interval = 1;
+
+       cfg->graph_monitoring_duration
+           = gconf_client_get_int(client, KEY_GRAPH_MONITORING_DURATION, NULL);
+
+       if (cfg->graph_monitoring_duration < 1)
+               cfg->graph_monitoring_duration = 10;
+
+       cfg->sensor_values_max_length
+           =
+           (cfg->graph_monitoring_duration * 60) / cfg->sensor_update_interval;
+       if (cfg->sensor_values_max_length < 3)
+               cfg->sensor_values_max_length = 3;
+
+       return cfg;
+}
+
+void config_save(struct config *cfg)
+{
+       config_set_background_color(cfg->graph_bgcolor);
+       config_set_foreground_color(cfg->graph_fgcolor);
+       config_set_graph_background_alpha(cfg->graph_bg_alpha);
+       config_set_sensorlist_position(cfg->sensorlist_position);
+       config_set_window_decoration_enabled(cfg->window_decoration_enabled);
+       config_set_window_keep_below_enabled(cfg->window_keep_below_enabled);
+
+       gconf_client_set_int(client,
+                            KEY_GRAPH_UPDATE_INTERVAL,
+                            cfg->graph_update_interval, NULL);
+
+       gconf_client_set_int(client,
+                            KEY_GRAPH_MONITORING_DURATION,
+                            cfg->graph_monitoring_duration, NULL);
+
+       gconf_client_set_int(client,
+                            KEY_SENSOR_UPDATE_INTERVAL,
+                            cfg->sensor_update_interval, NULL);
+
+}
diff --git a/src/cfg.h b/src/cfg.h
new file mode 100644 (file)
index 0000000..f6c46e3
--- /dev/null
+++ b/src/cfg.h
@@ -0,0 +1,80 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#ifndef _PSENSOR_CONFIG_H_
+#define _PSENSOR_CONFIG_H_
+
+#include "color.h"
+
+#define SENSORLIST_POSITION_RIGHT 0
+#define SENSORLIST_POSITION_LEFT 1
+#define SENSORLIST_POSITION_TOP 2
+#define SENSORLIST_POSITION_BOTTOM 3
+
+struct config {
+       struct color *graph_bgcolor;
+       struct color *graph_fgcolor;
+
+       double graph_bg_alpha;
+
+       int alpha_channel_enabled;
+
+       /*
+          Position of the sensors list table
+        */
+       int sensorlist_position;
+
+       int window_decoration_enabled;
+
+       int window_keep_below_enabled;
+
+       int graph_update_interval;
+       int graph_monitoring_duration;
+
+       int sensor_values_max_length;
+       int sensor_update_interval;
+};
+
+/*
+  Loads config from GConf
+*/
+struct config *config_load();
+
+void config_save(struct config *);
+
+void config_init();
+
+struct color *config_get_sensor_color(char *sensor_name,
+                                     struct color *default_color);
+
+void config_set_sensor_color(char *sensor_name, struct color *color);
+
+int config_get_sensor_alarm_limit(char *, int);
+void config_set_sensor_alarm_limit(char *sensor_name, int alarm_limit);
+
+int config_get_sensor_alarm_enabled(char *);
+void config_set_sensor_alarm_enabled(char *, int);
+
+int config_is_sensor_enabled(char *);
+void config_set_sensor_enabled(char *, int);
+
+char *config_get_sensor_name(char *);
+void config_set_sensor_name(char *, const char *);
+
+#endif
diff --git a/src/compat.h b/src/compat.h
new file mode 100644 (file)
index 0000000..243c46f
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+/*
+  gtk_dialog_get_content_area exists since gtk 2.14 As debian 5.0.6
+   (lenny) is using gtk 2.12 defines the function by using a macro.
+*/
+#if !defined(gtk_dialog_get_content_area)
+#define gtk_dialog_get_content_area(dialog) (GTK_DIALOG(dialog)->vbox)
+#endif
diff --git a/src/description.txt b/src/description.txt
new file mode 100644 (file)
index 0000000..27d3db9
--- /dev/null
@@ -0,0 +1,32 @@
+[description]
+
+/psensor is a/
+
+It displays a curve for each sensor, and uses Desktop Notification to
+raise an alarm when a temperature is too high. On Ubuntu an
+Application Indicator is also available, its icon changes when a
+temperature alert is raised.
+
+It can monitor:
+  * the temperature of the motherboard and CPU sensors (using lm\-sensors).
+  * the temperature of the NVidia GPUs (using XNVCtrl).
+  * the temperature of the Hard Disk Drives (using hddtemp).
+  * the rotation speed of the fans (using lm\-sensors).
+  * the sensors of a remote computer (using psensor\-server).
+
+Psensor requires lm\-sensors to be correctly installed and configured,
+it can be checked by running the command 'sensors'. If it has never be
+done, you may need to run the command 'sensors\-detect' and follow the
+instruction. See the manpages of sensors(1) and sensors\-detect(8) for
+more information.
+
+To retrieve the temperature of the Hard Disk Drives, the hddtemp
+daemon must be running.
+
+For remote monitoring:
+  * start psensor\-server(1) on the remote computer
+  * run psensor with '\-\-url' option: 'psensor \-\-url=http://localhost:3131'
+
+[SEE ALSO]
+
+psensor\-server(1), sensors(1), sensors\-detect(8), hddtemp(8)
diff --git a/src/glade/Makefile.am b/src/glade/Makefile.am
new file mode 100644 (file)
index 0000000..58d1551
--- /dev/null
@@ -0,0 +1,6 @@
+gladedir = $(pkgdatadir)
+glade_DATA = \
+       sensor-edit.glade \
+       psensor-pref.glade
+
+EXTRA_DIST = $(glade_DATA) 
diff --git a/src/glade/psensor-pref.glade b/src/glade/psensor-pref.glade
new file mode 100644 (file)
index 0000000..1501644
--- /dev/null
@@ -0,0 +1,534 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <!-- interface-naming-policy project-wide -->
+  <object class="GtkDialog" id="dialog1">
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Edit Preferences</property>
+    <property name="modal">True</property>
+    <property name="destroy_with_parent">True</property>
+    <property name="type_hint">normal</property>
+    <property name="has_separator">True</property>
+    <child internal-child="vbox">
+      <object class="GtkVBox" id="dialog-vbox1">
+        <property name="visible">True</property>
+        <property name="spacing">2</property>
+        <child>
+          <object class="GtkTable" id="table1">
+            <property name="visible">True</property>
+            <property name="n_rows">16</property>
+            <property name="n_columns">3</property>
+            <child>
+              <object class="GtkLabel" id="label1">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">Graph Colors</property>
+                <attributes>
+                  <attribute name="weight" value="bold"/>
+                </attributes>
+              </object>
+              <packing>
+                <property name="right_attach">3</property>
+                <property name="x_padding">4</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label2">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">Foreground:</property>
+              </object>
+              <packing>
+                <property name="top_attach">1</property>
+                <property name="bottom_attach">2</property>
+                <property name="x_padding">14</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label3">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">Background:</property>
+              </object>
+              <packing>
+                <property name="top_attach">2</property>
+                <property name="bottom_attach">3</property>
+                <property name="x_padding">14</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label4">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">Background opacity:</property>
+              </object>
+              <packing>
+                <property name="right_attach">3</property>
+                <property name="top_attach">3</property>
+                <property name="bottom_attach">4</property>
+                <property name="x_padding">14</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkColorButton" id="color_fg">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="color">#000000000000</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">3</property>
+                <property name="top_attach">1</property>
+                <property name="bottom_attach">2</property>
+                <property name="x_options"></property>
+                <property name="x_padding">4</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkColorButton" id="color_bg">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="color">#000000000000</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">3</property>
+                <property name="top_attach">2</property>
+                <property name="bottom_attach">3</property>
+                <property name="x_options"></property>
+                <property name="x_padding">4</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label5">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">Graph</property>
+                <attributes>
+                  <attribute name="weight" value="bold"/>
+                </attributes>
+              </object>
+              <packing>
+                <property name="right_attach">3</property>
+                <property name="top_attach">5</property>
+                <property name="bottom_attach">6</property>
+                <property name="x_padding">4</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label6">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">Update interval:</property>
+              </object>
+              <packing>
+                <property name="top_attach">6</property>
+                <property name="bottom_attach">7</property>
+                <property name="x_padding">14</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label7">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">Monitoring duration:</property>
+              </object>
+              <packing>
+                <property name="top_attach">7</property>
+                <property name="bottom_attach">8</property>
+                <property name="x_padding">14</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label8">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">second(s)</property>
+              </object>
+              <packing>
+                <property name="left_attach">2</property>
+                <property name="right_attach">3</property>
+                <property name="top_attach">6</property>
+                <property name="bottom_attach">7</property>
+                <property name="x_padding">4</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label9">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">minute(s)</property>
+              </object>
+              <packing>
+                <property name="left_attach">2</property>
+                <property name="right_attach">3</property>
+                <property name="top_attach">7</property>
+                <property name="bottom_attach">8</property>
+                <property name="x_padding">4</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label10">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">Sensor</property>
+                <attributes>
+                  <attribute name="weight" value="bold"/>
+                </attributes>
+              </object>
+              <packing>
+                <property name="right_attach">3</property>
+                <property name="top_attach">8</property>
+                <property name="bottom_attach">9</property>
+                <property name="x_padding">4</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label11">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">Measure update interval:</property>
+              </object>
+              <packing>
+                <property name="top_attach">9</property>
+                <property name="bottom_attach">10</property>
+                <property name="x_padding">14</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label12">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">second(s)</property>
+              </object>
+              <packing>
+                <property name="left_attach">2</property>
+                <property name="right_attach">3</property>
+                <property name="top_attach">9</property>
+                <property name="bottom_attach">10</property>
+                <property name="x_padding">4</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label13">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">Interface</property>
+                <attributes>
+                  <attribute name="weight" value="bold"/>
+                </attributes>
+              </object>
+              <packing>
+                <property name="right_attach">3</property>
+                <property name="top_attach">10</property>
+                <property name="bottom_attach">11</property>
+                <property name="x_padding">4</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label14">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">Position of sensors table:</property>
+              </object>
+              <packing>
+                <property name="top_attach">11</property>
+                <property name="bottom_attach">12</property>
+                <property name="x_padding">14</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="hide_window_decoration">
+                <property name="label" translatable="yes">Hide window decoration</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="xalign">0</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="right_attach">3</property>
+                <property name="top_attach">12</property>
+                <property name="bottom_attach">13</property>
+                <property name="x_padding">14</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="keep_window_below">
+                <property name="label" translatable="yes">Keep window below</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="xalign">0</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="right_attach">3</property>
+                <property name="top_attach">13</property>
+                <property name="bottom_attach">14</property>
+                <property name="x_padding">14</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkSpinButton" id="update_interval">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="invisible_char">•</property>
+                <property name="adjustment">secs</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">6</property>
+                <property name="bottom_attach">7</property>
+                <property name="x_padding">4</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkSpinButton" id="monitoring_duration">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="invisible_char">•</property>
+                <property name="adjustment">mins</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">7</property>
+                <property name="bottom_attach">8</property>
+                <property name="x_padding">4</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkSpinButton" id="sensor_update_interval">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="invisible_char">•</property>
+                <property name="adjustment">secs2</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">9</property>
+                <property name="bottom_attach">10</property>
+                <property name="x_padding">4</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkComboBox" id="sensors_list_position">
+                <property name="visible">True</property>
+                <property name="model">liststore1</property>
+                <child>
+                  <object class="GtkCellRendererText" id="renderer1"/>
+                  <attributes>
+                    <attribute name="text">0</attribute>
+                  </attributes>
+                </child>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">3</property>
+                <property name="top_attach">11</property>
+                <property name="bottom_attach">12</property>
+                <property name="x_padding">4</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkHBox" id="hbox1">
+                <property name="visible">True</property>
+                <property name="spacing">8</property>
+                <child>
+                  <object class="GtkLabel" id="label15">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">&lt;i&gt;Min&lt;/i&gt;</property>
+                    <property name="use_markup">True</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkHScale" id="bg_opacity">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="adjustment">opacity</property>
+                    <property name="draw_value">False</property>
+                  </object>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label16">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">&lt;i&gt;Max&lt;/i&gt;</property>
+                    <property name="use_markup">True</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="right_attach">3</property>
+                <property name="top_attach">4</property>
+                <property name="bottom_attach">5</property>
+                <property name="x_padding">14</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="enable_menu">
+                <property name="label" translatable="yes">Enable menu</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="right_attach">3</property>
+                <property name="top_attach">14</property>
+                <property name="bottom_attach">15</property>
+                <property name="x_padding">14</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="enable_launcher_counter">
+                <property name="label" translatable="yes">Enable Unity Launcher counter</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="xalign">0</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="right_attach">3</property>
+                <property name="top_attach">15</property>
+                <property name="bottom_attach">16</property>
+                <property name="x_padding">14</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <object class="GtkHButtonBox" id="dialog-action_area1">
+            <property name="visible">True</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="button1">
+                <property name="label">gtk-ok</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="button2">
+                <property name="label">gtk-cancel</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="-3">button1</action-widget>
+      <action-widget response="0">button2</action-widget>
+    </action-widgets>
+  </object>
+  <object class="GtkAdjustment" id="opacity">
+    <property name="upper">1</property>
+    <property name="step_increment">0.01</property>
+    <property name="page_increment">0.10000000000000001</property>
+  </object>
+  <object class="GtkListStore" id="liststore1">
+    <columns>
+      <!-- column-name gchararray1 -->
+      <column type="gchararray"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0" translatable="yes">Right</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Left</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Top</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Bottom</col>
+      </row>
+    </data>
+  </object>
+  <object class="GtkAdjustment" id="secs">
+    <property name="value">1</property>
+    <property name="lower">1</property>
+    <property name="upper">256</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
+  <object class="GtkAdjustment" id="mins">
+    <property name="value">10</property>
+    <property name="lower">1</property>
+    <property name="upper">65535</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
+  <object class="GtkAdjustment" id="secs2">
+    <property name="lower">1</property>
+    <property name="upper">256</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
+</interface>
diff --git a/src/glade/sensor-edit.glade b/src/glade/sensor-edit.glade
new file mode 100644 (file)
index 0000000..fd5acea
--- /dev/null
@@ -0,0 +1,329 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <!-- interface-naming-policy project-wide -->
+  <object class="GtkDialog" id="dialog1">
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Edit Sensor Preferences</property>
+    <property name="modal">True</property>
+    <property name="destroy_with_parent">True</property>
+    <property name="type_hint">dialog</property>
+    <property name="has_separator">True</property>
+    <child internal-child="vbox">
+      <object class="GtkVBox" id="dialog-vbox1">
+        <property name="visible">True</property>
+        <property name="spacing">2</property>
+        <child>
+          <object class="GtkTable" id="table1">
+            <property name="visible">True</property>
+            <property name="n_rows">10</property>
+            <property name="n_columns">2</property>
+            <child>
+              <object class="GtkLabel" id="sensor_id">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">N/A</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">1</property>
+                <property name="bottom_attach">2</property>
+                <property name="x_padding">4</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label3">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="xpad">10</property>
+                <property name="label" translatable="yes">Name:</property>
+              </object>
+              <packing>
+                <property name="top_attach">3</property>
+                <property name="bottom_attach">4</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="x_padding">4</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkEntry" id="sensor_name">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="invisible_char">•</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">3</property>
+                <property name="bottom_attach">4</property>
+                <property name="x_padding">4</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label4">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">Type:</property>
+              </object>
+              <packing>
+                <property name="top_attach">2</property>
+                <property name="bottom_attach">3</property>
+                <property name="x_padding">14</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="sensor_type">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">N/A</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">2</property>
+                <property name="bottom_attach">3</property>
+                <property name="x_padding">4</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label2">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">Id:</property>
+              </object>
+              <packing>
+                <property name="top_attach">1</property>
+                <property name="bottom_attach">2</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="x_padding">14</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label5">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">Graph</property>
+                <attributes>
+                  <attribute name="weight" value="bold"/>
+                </attributes>
+              </object>
+              <packing>
+                <property name="right_attach">2</property>
+                <property name="top_attach">4</property>
+                <property name="bottom_attach">5</property>
+                <property name="x_padding">4</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label7">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">Color:</property>
+              </object>
+              <packing>
+                <property name="top_attach">6</property>
+                <property name="bottom_attach">7</property>
+                <property name="x_padding">14</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label6">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">Alarm</property>
+                <attributes>
+                  <attribute name="weight" value="bold"/>
+                </attributes>
+              </object>
+              <packing>
+                <property name="right_attach">2</property>
+                <property name="top_attach">7</property>
+                <property name="bottom_attach">8</property>
+                <property name="x_padding">4</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="sensor_alarm">
+                <property name="label" translatable="yes">Activate desktop notifications</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="right_attach">2</property>
+                <property name="top_attach">8</property>
+                <property name="bottom_attach">9</property>
+                <property name="x_padding">14</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label8">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">Temperature limit:</property>
+              </object>
+              <packing>
+                <property name="top_attach">9</property>
+                <property name="bottom_attach">10</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="x_padding">14</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label1">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">Sensor Information</property>
+                <attributes>
+                  <attribute name="weight" value="bold"/>
+                </attributes>
+              </object>
+              <packing>
+                <property name="right_attach">2</property>
+                <property name="x_padding">4</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="sensor_draw">
+                <property name="label" translatable="yes">Draw sensor curve</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="yalign">0.41999998688697815</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="right_attach">2</property>
+                <property name="top_attach">5</property>
+                <property name="bottom_attach">6</property>
+                <property name="x_padding">14</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkHBox" id="hbox1">
+                <property name="visible">True</property>
+                <child>
+                  <object class="GtkSpinButton" id="sensor_temp_limit">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="max_length">3</property>
+                    <property name="invisible_char">•</property>
+                    <property name="adjustment">temp_limit</property>
+                    <property name="climb_rate">1</property>
+                    <property name="snap_to_ticks">True</property>
+                    <property name="numeric">True</property>
+                    <property name="update_policy">if-valid</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label9">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">°C</property>
+                  </object>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">9</property>
+                <property name="bottom_attach">10</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkColorButton" id="sensor_color">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="xalign">0</property>
+                <property name="color">#000000000000</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">6</property>
+                <property name="bottom_attach">7</property>
+                <property name="x_options"></property>
+                <property name="x_padding">4</property>
+                <property name="y_padding">4</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <object class="GtkHButtonBox" id="dialog-action_area1">
+            <property name="visible">True</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="btn_ok">
+                <property name="label">gtk-ok</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="btn_cancel">
+                <property name="label">gtk-cancel</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="-3">btn_ok</action-widget>
+      <action-widget response="0">btn_cancel</action-widget>
+    </action-widgets>
+  </object>
+  <object class="GtkAdjustment" id="temp_limit">
+    <property name="upper">256</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
+</interface>
diff --git a/src/graph.c b/src/graph.c
new file mode 100644 (file)
index 0000000..3b70d3e
--- /dev/null
@@ -0,0 +1,331 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#include <stdlib.h>
+#include <sys/time.h>
+#include <gtk/gtk.h>
+
+#include "cfg.h"
+#include "psensor.h"
+
+/* horizontal padding */
+#define GRAPH_H_PADDING 4
+/* vertical padding */
+#define GRAPH_V_PADDING 4
+
+static time_t get_graph_end_time_s()
+{
+       struct timeval tv;
+
+       if (gettimeofday(&tv, NULL) == 0)
+               return tv.tv_sec;
+       else
+               return 0;
+}
+
+static time_t get_graph_begin_time_s(struct config *cfg)
+{
+       int ct;
+
+       ct = get_graph_end_time_s();
+
+       if (!ct)
+               return 0;
+
+       return ct - cfg->graph_monitoring_duration * 60;
+}
+
+static int compute_y(double value, double min, double max, int height, int off)
+{
+       double t = value - min;
+       return height - ((double)height * (t / (max - min))) + off;
+}
+
+static char *time_to_str(time_t s)
+{
+       char *str;
+       /* note: localtime returns a static field, no free required */
+       struct tm *tm = localtime(&s);
+
+       if (!tm)
+               return NULL;
+
+       str = malloc(6);
+       strftime(str, 6, "%H:%M", tm);
+
+       return str;
+}
+
+static void
+draw_graph_background(cairo_t *cr,
+                     int width, int height, struct config *config)
+{
+       struct color *bgcolor = config->graph_bgcolor;
+
+       /* draw background */
+       if (config->alpha_channel_enabled)
+               cairo_set_source_rgba(cr,
+                                     bgcolor->f_red,
+                                     bgcolor->f_green,
+                                     bgcolor->f_blue, config->graph_bg_alpha);
+       else
+               cairo_set_source_rgb(cr,
+                                    bgcolor->f_red,
+                                    bgcolor->f_green, bgcolor->f_blue);
+
+       cairo_rectangle(cr, 0, 0, width, height);
+       cairo_fill(cr);
+}
+
+/* setup dash style */
+static double dashes[] = {
+       1.0,            /* ink */
+       1.0,            /* skip */
+       1.0,            /* ink */
+       1.0             /* skip */
+};
+static int ndash = sizeof(dashes) / sizeof(dashes[0]);
+
+static void draw_background_lines(cairo_t *cr,
+                                 struct color *color,
+                                 int g_width, int g_height,
+                                 int g_xoff, int g_yoff,
+                                 int min, int max)
+{
+       int i;
+
+       /* draw background lines */
+       cairo_set_dash(cr, dashes, ndash, 0);
+       cairo_set_line_width(cr, 1);
+       cairo_set_source_rgb(cr,
+                            color->f_red, color->f_green, color->f_blue);
+
+       /* vertical lines representing time steps */
+       for (i = 0; i <= 5; i++) {
+               int x = i * (g_width / 5) + g_xoff;
+               cairo_move_to(cr, x, g_yoff);
+               cairo_line_to(cr, x, g_yoff + g_height);
+               cairo_stroke(cr);
+       }
+
+       /* horizontal lines draws a line for each 10C step */
+       for (i = min; i < max; i++) {
+               if (i % 10 == 0) {
+                       int y = compute_y(i, min, max, g_height, g_yoff);
+
+                       cairo_move_to(cr, g_xoff, y);
+                       cairo_line_to(cr, g_xoff + g_width, y);
+                       cairo_stroke(cr);
+               }
+       }
+
+       /* back to normal line style */
+       cairo_set_dash(cr, 0, 0, 0);
+
+}
+
+static void draw_sensor_curve(struct psensor *s,
+                             cairo_t *cr,
+                             double min,
+                             double max,
+                             int bt,
+                             int et,
+                             int g_width,
+                             int g_height,
+                             int g_xoff,
+                             int g_yoff)
+{
+       int first = 1;
+       int i;
+
+       cairo_set_source_rgb(cr,
+                            s->color->f_red,
+                            s->color->f_green,
+                            s->color->f_blue);
+       cairo_set_line_width(cr, 1);
+
+       for (i = 0; i < s->values_max_length; i++) {
+               int x, y, t;
+               double v;
+
+               t = s->measures[i].time.tv_sec;
+               v = s->measures[i].value;
+
+               if (v == UNKNOWN_VALUE || !t || (t - bt) < 0)
+                       continue;
+
+               x = (t - bt) * g_width / (et - bt) + g_xoff;
+
+               y = compute_y(v, min, max, g_height, g_yoff);
+
+               if (first) {
+                       cairo_move_to(cr, x, y);
+                       first = 0;
+               } else {
+                       cairo_line_to(cr, x, y);
+               }
+
+       }
+       cairo_stroke(cr);
+}
+
+
+void
+graph_update(struct psensor **sensors,
+            GtkWidget *w_graph, struct config *config)
+{
+       struct color *fgcolor = config->graph_fgcolor;
+       int et, bt;
+       double min_rpm = get_min_rpm(sensors);
+       double max_rpm = get_max_rpm(sensors);
+
+       double mint = get_min_temp(sensors);
+       char *strmin = psensor_value_to_string(SENSOR_TYPE_TEMP, mint);
+
+       double maxt = get_max_temp(sensors);
+       char *strmax = psensor_value_to_string(SENSOR_TYPE_TEMP, maxt);
+
+       int width = w_graph->allocation.width;
+       int height = w_graph->allocation.height;
+
+       int g_width, g_height;
+
+       /* horizontal and vertical offset of the graph */
+       int g_xoff, g_yoff;
+
+       cairo_surface_t *cst = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
+                                                         width,
+                                                         height);
+       cairo_t *cr = cairo_create(cst);
+       cairo_t *cr_pixmap;
+
+       char *str_btime = time_to_str(get_graph_begin_time_s(config));
+       cairo_text_extents_t te_btime;
+
+       char *str_etime = time_to_str(get_graph_end_time_s());
+       cairo_text_extents_t te_etime;
+
+       cairo_text_extents_t te_max, te_min;
+
+       struct psensor **sensor_cur;
+
+       draw_graph_background(cr, width, height, config);
+
+       cairo_select_font_face(cr,
+                              "sans-serif",
+                              CAIRO_FONT_SLANT_NORMAL,
+                              CAIRO_FONT_WEIGHT_NORMAL);
+       cairo_set_font_size(cr, 10.0);
+
+       cairo_text_extents(cr, str_etime, &te_etime);
+       cairo_text_extents(cr, str_btime, &te_btime);
+       cairo_text_extents(cr, strmax, &te_max);
+       cairo_text_extents(cr, strmin, &te_min);
+
+       g_yoff = GRAPH_V_PADDING;
+
+       g_height = height - GRAPH_V_PADDING;
+       if (te_etime.height > te_btime.height)
+               g_height -= GRAPH_V_PADDING + te_etime.height + GRAPH_V_PADDING;
+       else
+               g_height -= GRAPH_V_PADDING + te_btime.height + GRAPH_V_PADDING;
+
+       if (te_min.width > te_max.width)
+               g_xoff = (2 * GRAPH_H_PADDING) + te_max.width;
+       else
+               g_xoff = (2 * GRAPH_H_PADDING) + te_min.width;
+
+       g_width = width - g_xoff - GRAPH_H_PADDING;
+
+       cairo_set_source_rgb(cr,
+                            fgcolor->f_red, fgcolor->f_green, fgcolor->f_blue);
+
+       /* draw graph begin time */
+       cairo_move_to(cr, g_xoff, height - GRAPH_V_PADDING);
+       cairo_show_text(cr, str_btime);
+       free(str_btime);
+
+       /* draw graph end time */
+       cairo_move_to(cr,
+                     width - te_etime.width - GRAPH_H_PADDING,
+                     height - GRAPH_V_PADDING);
+       cairo_show_text(cr, str_etime);
+       free(str_etime);
+
+       /* draw min and max temp */
+       cairo_move_to(cr, GRAPH_H_PADDING, te_max.height + GRAPH_V_PADDING);
+       cairo_show_text(cr, strmax);
+       free(strmax);
+
+       cairo_move_to(cr,
+                     GRAPH_H_PADDING, height - (te_min.height / 2) - g_yoff);
+       cairo_show_text(cr, strmin);
+       free(strmin);
+
+       draw_background_lines(cr, fgcolor,
+                             g_width, g_height,
+                             g_xoff, g_yoff,
+                             mint, maxt);
+
+       /* .. and finaly draws the temperature graphs */
+       bt = get_graph_begin_time_s(config);
+       et = get_graph_end_time_s();
+
+       if (bt && et) {
+               sensor_cur = sensors;
+               while (*sensor_cur) {
+                       struct psensor *s = *sensor_cur;
+
+                       if (s->enabled) {
+                               double min, max;
+
+                               if (is_fan_type(s->type)) {
+                                       min = min_rpm;
+                                       max = max_rpm;
+                               } else {
+                                       min = mint;
+                                       max = maxt;
+                               }
+
+                               draw_sensor_curve(s, cr,
+                                                 min, max,
+                                                 bt, et,
+                                                 g_width, g_height,
+                                                 g_xoff, g_yoff);
+                       }
+
+                       sensor_cur++;
+               }
+       }
+
+       cr_pixmap = gdk_cairo_create(w_graph->window);
+
+       if (cr_pixmap) {
+
+               if (config->alpha_channel_enabled)
+                       cairo_set_operator(cr_pixmap, CAIRO_OPERATOR_SOURCE);
+
+               cairo_set_source_surface(cr_pixmap, cst, 0, 0);
+               cairo_paint(cr_pixmap);
+       }
+
+       cairo_destroy(cr_pixmap);
+       cairo_surface_destroy(cst);
+       cairo_destroy(cr);
+}
diff --git a/src/graph.h b/src/graph.h
new file mode 100644 (file)
index 0000000..77ed5ed
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#ifndef _PSENSOR_GRAPH_H_
+#define _PSENSOR_GRAPH_H_
+
+#include <gtk/gtk.h>
+
+#include "psensor.h"
+#include "cfg.h"
+
+void graph_update(struct psensor **, GtkWidget *, struct config *config);
+
+#endif
diff --git a/src/httpd/Makefile.am b/src/httpd/Makefile.am
new file mode 100644 (file)
index 0000000..34c10fc
--- /dev/null
@@ -0,0 +1,41 @@
+AM_CPPFLAGS = -pedantic -Werror -DDEFAULT_WWW_DIR=\""$(pkgdatadir)/www"\"\
+       -I$(top_srcdir)/src \
+       -I$(top_srcdir)/src/lib \
+       $(LUA_CFLAGS)\
+       $(GTK_CFLAGS)\
+       $(APPINDICATOR_CFLAGS)\
+       $(GCONF_CFLAGS)\
+       $(SENSORS_CFLAGS)\
+       $(NVIDIA_CFLAGS)\
+       $(CURL_CFLAGS)\
+       $(JSON_CFLAGS)\
+       $(GTOP_CFLAGS)\
+       $(LIBMICROHTTPD_CFLAGS)
+
+LIBS = \
+       $(top_srcdir)/src/plib/libplib.a \
+       $(top_srcdir)/src/lib/libpsensor.a \
+       $(LUA_LIBS)\
+       $(GTK_LIBS)\
+       $(APPINDICATOR_LIBS)\
+       $(GCONF_LIBS)\
+       $(SENSORS_LIBS)\
+       $(NVIDIA_LIBS)\
+       $(CURL_LIBS)\
+       $(JSON_LIBS)\
+       $(GTOP_LIBS)\
+       $(LIBMICROHTTPD_LIBS)
+
+bin_PROGRAMS =  psensor-server
+
+psensor_server_SOURCES = httpd.c httpd.h
+
+
+
+
+dist_man_MANS =  psensor-server.1
+
+
+psensor-server.1: httpd.c $(top_srcdir)/configure.ac
+       $(MAKE) $(AM_MAKEFLAGS) psensor-server$(EXEEXT)
+       help2man --output=psensor-server.1 ./psensor-server$(EXEEXT)
\ No newline at end of file
diff --git a/src/httpd/httpd.c b/src/httpd/httpd.c
new file mode 100644 (file)
index 0000000..fccccac
--- /dev/null
@@ -0,0 +1,426 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+#include "config.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <getopt.h>
+#include <stdint.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <microhttpd.h>
+#include <json/json.h>
+
+#ifdef HAVE_GTOP
+#include <glibtop/cpu.h>
+#endif
+
+#define lua_c
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+#include "plib/url.h"
+#include "httpd.h"
+#include "psensor.h"
+#include "hdd.h"
+#include "nvidia.h"
+#include "lmsensor.h"
+
+#define DEFAULT_PORT 3131
+
+
+#define PAGE_NOT_FOUND \
+"<html><body><p>Page not found - Go to <a href='/index.lua'>Main page</a>\
+</p></body>"
+
+
+#define PSENSOR_SERVER_OPTIONS "  --help    display this help and exit\n\
+  --version   output version information and exit\n\
+  --port=PORT webserver port\n\
+  --wdir=DIR  directory containing webserver pages"
+
+#define PSENSOR_SERVER_USAGE "Usage: psensor-server [OPTION]"
+
+#define PSENSOR_SERVER_DESCRIPTION \
+"HTTP server for retrieving hardware temperatures."
+
+#define PSENSOR_SERVER_CONTACT "Report bugs to: psensor@wpitchoune.net\n\
+Psensor home page: <http://wpitchoune.net/psensor/>"
+
+#define PSENSOR_SERVER_COPYRIGHT \
+"Copyright (C) 2010-2011 wpitchoune@gmail.com\n\
+License GPLv2: GNU GPL version 2 or later \
+<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>\n\
+This is free software: you are free to change and redistribute it.\n\
+There is NO WARRANTY, to the extent permitted by law."
+
+#define OPT_PORT "port"
+#define OPT_HELP "help"
+#define OPT_VERSION "version"
+#define OPT_WWW_DIR "wdir"
+
+static struct option long_options[] = {
+       {OPT_VERSION, no_argument, 0, 'v'},
+       {OPT_HELP, no_argument, 0, 'h'},
+       {OPT_PORT, required_argument, 0, 'p'},
+       {OPT_WWW_DIR, required_argument, 0, 'w'},
+       {0, 0, 0, 0}
+};
+
+static char *www_dir = DEFAULT_WWW_DIR;
+
+#ifdef HAVE_GTOP
+static float cpu_rate;
+static glibtop_cpu *cpu;
+#endif
+
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+json_object *sensor_to_json_object(struct psensor *s)
+{
+       json_object *mo;
+       json_object *obj = json_object_new_object();
+       struct measure *m;
+
+       json_object_object_add(obj, "id", json_object_new_string(s->id));
+       json_object_object_add(obj, "name", json_object_new_string(s->name));
+       json_object_object_add(obj, "type", json_object_new_int(s->type));
+       json_object_object_add(obj, "min", json_object_new_double(s->min));
+       json_object_object_add(obj, "max", json_object_new_double(s->max));
+
+       m = psensor_get_current_measure(s);
+       mo = json_object_new_object();
+       json_object_object_add(mo, "value", json_object_new_double(m->value));
+       json_object_object_add(mo, "time",
+                              json_object_new_int((m->time).tv_sec));
+       json_object_object_add(obj, "last_measure", mo);
+
+       return obj;
+}
+
+char *sensor_to_json_string(struct psensor *s)
+{
+       char *str;
+       json_object *obj = sensor_to_json_object(s);
+
+       str = strdup(json_object_to_json_string(obj));
+
+       json_object_put(obj);
+
+       return str;
+}
+
+char *sensors_to_json_string(struct psensor **sensors)
+{
+       struct psensor **sensors_cur;
+       char *str;
+
+       json_object *obj = json_object_new_array();
+
+       sensors_cur = sensors;
+
+       while (*sensors_cur) {
+               struct psensor *s = *sensors_cur;
+
+               json_object_array_add(obj, sensor_to_json_object(s));
+
+               sensors_cur++;
+       }
+
+       str = strdup(json_object_to_json_string(obj));
+
+       json_object_put(obj);
+
+       return str;
+}
+
+char *lua_to_html_page(struct psensor **sensors, const char *url)
+{
+       struct psensor **s_cur;
+       char *page = NULL;
+       int i;
+       char *lua_fpath;
+
+       lua_State *L = lua_open();      /* create state */
+
+       if (!L)
+               return NULL;
+
+       luaL_openlibs(L);
+
+#ifdef HAVE_GTOP
+       lua_newtable(L);
+       lua_pushstring(L, "load");
+       lua_pushnumber(L, cpu_rate);
+       lua_settable(L, -3);
+       lua_setglobal(L, "cpu");
+#endif
+
+       lua_newtable(L);
+
+       s_cur = sensors;
+       i = 0;
+       while (*s_cur) {
+
+               lua_pushinteger(L, i);
+
+               lua_newtable(L);
+
+               lua_pushstring(L, "name");
+               lua_pushstring(L, (*s_cur)->name);
+               lua_settable(L, -3);
+
+               lua_pushstring(L, "measure_last");
+               lua_pushnumber(L, psensor_get_current_value(*s_cur));
+               lua_settable(L, -3);
+
+               lua_pushstring(L, "measure_min");
+               lua_pushnumber(L, (*s_cur)->min);
+               lua_settable(L, -3);
+
+               lua_pushstring(L, "measure_max");
+               lua_pushnumber(L, (*s_cur)->max);
+               lua_settable(L, -3);
+
+               lua_pushstring(L, "id");
+               lua_pushstring(L, (*s_cur)->id);
+               lua_settable(L, -3);
+
+               lua_settable(L, -3);
+
+               s_cur++;
+               i++;
+       }
+
+       lua_setglobal(L, "sensors");
+
+       lua_fpath = malloc(strlen(www_dir) + strlen(url) + 1);
+       strcpy(lua_fpath, www_dir);
+       strcat(lua_fpath, url);
+
+       if (!luaL_loadfile(L, lua_fpath) && !lua_pcall(L, 0, 1, 0))
+               page = strdup(lua_tostring(L, -1));
+
+       lua_close(L);
+
+       free(lua_fpath);
+
+       return page;
+}
+
+static int cbk_http_request(void *cls,
+                           struct MHD_Connection *connection,
+                           const char *url,
+                           const char *method,
+                           const char *version,
+                           const char *upload_data,
+                           size_t *upload_data_size, void **ptr)
+{
+       struct psensor **sensors = cls;
+       static int dummy;
+       struct MHD_Response *response;
+       int ret;
+       char *nurl;
+       unsigned int resp_code;
+       char *page = NULL;
+
+       if (strcmp(method, "GET"))
+               return MHD_NO;  /* unexpected method */
+
+       if (&dummy != *ptr) {
+               /* The first time only the headers are valid, do not
+                  respond in the first round... */
+               *ptr = &dummy;
+               return MHD_YES;
+       }
+
+       if (*upload_data_size)
+               return MHD_NO;  /* upload data in a GET!? */
+
+       *ptr = NULL;            /* clear context pointer */
+
+       nurl = url_normalize(url);
+
+       pthread_mutex_lock(&mutex);
+
+       if (!strcmp(nurl, URL_BASE_API_1_0_SENSORS)) {
+               page = sensors_to_json_string(sensors);
+
+       } else if (!strncmp(nurl, URL_BASE_API_1_0_SENSORS,
+                           strlen(URL_BASE_API_1_0_SENSORS))
+                  && nurl[strlen(URL_BASE_API_1_0_SENSORS)] == '/') {
+
+               char *sid = nurl + strlen(URL_BASE_API_1_0_SENSORS) + 1;
+               struct psensor *s = psensor_list_get_by_id(sensors, sid);
+
+               if (s)
+                       page = sensor_to_json_string(s);
+
+       } else {
+               page = lua_to_html_page(sensors, nurl);
+       }
+
+       if (page) {
+               resp_code = MHD_HTTP_OK;
+       } else {
+               page = strdup(PAGE_NOT_FOUND);
+               resp_code = MHD_HTTP_NOT_FOUND;
+       }
+
+       pthread_mutex_unlock(&mutex);
+
+       response = MHD_create_response_from_data(strlen(page),
+                                                (void *)page, MHD_YES, MHD_NO);
+
+       ret = MHD_queue_response(connection, resp_code, response);
+       MHD_destroy_response(response);
+
+       free(nurl);
+
+       return ret;
+}
+
+int main(int argc, char *argv[])
+{
+       float last_used = 0;
+       float last_total = 0;
+       struct MHD_Daemon *d;
+       struct psensor **sensors;
+       int port = DEFAULT_PORT;
+
+       while (1) {
+               int c, option_index = 0;
+
+               c = getopt_long(argc, argv, "vhpw:", long_options,
+                               &option_index);
+
+               if (c == -1)
+                       break;
+
+               switch (c) {
+
+               case 0:
+                       break;
+
+               case 'w':
+                       if (optarg)
+                               www_dir = strdup(optarg);
+                       break;
+
+               case 'p':
+                       if (optarg)
+                               port = atoi(optarg);
+
+                       break;
+
+               case 'h':
+                       printf("%s\n%s\n\n%s\n\n%s\n",
+                              PSENSOR_SERVER_USAGE,
+                              PSENSOR_SERVER_DESCRIPTION,
+                              PSENSOR_SERVER_OPTIONS, PSENSOR_SERVER_CONTACT);
+                       exit(EXIT_SUCCESS);
+
+               case 'v':
+                       printf("psensor-server %s\n", VERSION);
+                       printf("%s\n", PSENSOR_SERVER_COPYRIGHT);
+
+                       exit(EXIT_SUCCESS);
+
+               case '?':
+                       break;
+
+               default:
+                       abort();
+               }
+       }
+
+       if (optind != argc) {
+               fprintf(stderr, "Invalid usage.\n");
+               exit(EXIT_FAILURE);
+       }
+
+       if (!lmsensor_init()) {
+               fprintf(stderr, "failed to init lm-sensors\n");
+               exit(EXIT_FAILURE);
+       }
+
+       sensors = get_all_sensors(1);
+
+       if (!sensors || !*sensors) {
+               fprintf(stderr, "no sensors detected\n");
+               exit(EXIT_FAILURE);
+       }
+
+       d = MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION,
+                            port,
+                            NULL, NULL, &cbk_http_request, sensors,
+                            MHD_OPTION_END);
+       if (!d) {
+               fprintf(stderr, "Fail to create web server\n");
+               exit(EXIT_FAILURE);
+       }
+
+       printf("Web server started on port: %d\n", port);
+       printf("Psensor URL: http://localhost:%d\n", port);
+
+       while (1) {
+               unsigned long int used = 0;
+               unsigned long int dt;
+
+               pthread_mutex_lock(&mutex);
+
+#ifdef HAVE_GTOP
+               if (!cpu)
+                       cpu = malloc(sizeof(glibtop_cpu));
+
+               glibtop_get_cpu(cpu);
+
+               used = cpu->user + cpu->nice + cpu->sys;
+
+               dt = cpu->total - last_total;
+
+               if (dt)
+                       cpu_rate = (used - last_used) / dt;
+
+               last_used = used;
+               last_total = cpu->total;
+
+               psensor_list_update_measures(sensors);
+#endif
+
+               pthread_mutex_unlock(&mutex);
+               sleep(5);
+       }
+
+       MHD_stop_daemon(d);
+
+#ifdef HAVE_GTOP
+       free(cpu);
+#endif
+
+       return 0;
+}
diff --git a/src/httpd/httpd.h b/src/httpd/httpd.h
new file mode 100644 (file)
index 0000000..c493c2b
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#ifndef _PSENSOR_HTTPD_H_
+#define _PSENSOR_HTTPD_H_
+
+#define URL_BASE_API_1_0 "/api/1.0"
+#define URL_BASE_API_1_0_SENSORS "/api/1.0/sensors"
+
+#endif
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
new file mode 100644 (file)
index 0000000..eb10b2f
--- /dev/null
@@ -0,0 +1,15 @@
+noinst_LIBRARIES = libpsensor.a
+
+libpsensor_a_CFLAGS = -pedantic -Werror
+
+libpsensor_a_SOURCES = \
+       measure.h measure.c \
+       color.h color.c \
+       psensor.h psensor.c\
+       hdd.h hdd.c\
+       nvidia.h \
+       lmsensor.h lmsensor.c
+
+if NVIDIA
+libpsensor_a_SOURCES += nvidia.c
+endif
diff --git a/src/lib/color.c b/src/lib/color.c
new file mode 100644 (file)
index 0000000..e747701
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "color.h"
+
+void
+color_set(struct color *color,
+         unsigned int red, unsigned int green, unsigned int blue)
+{
+       color->red = red;
+       color->green = green;
+       color->blue = blue;
+
+       color->f_red = ((double)color->red) / 65535;
+       color->f_green = ((double)color->green) / 65535;
+       color->f_blue = ((double)color->blue) / 65535;
+}
+
+struct color *color_new(unsigned int red, unsigned int green, unsigned int blue)
+{
+       struct color *color = malloc(sizeof(struct color));
+
+       color_set(color, red, green, blue);
+
+       return color;
+}
+
+struct color *color_dup(struct color *color)
+{
+       return color_new(color->red, color->green, color->blue);
+}
+
+int is_color(const char *str)
+{
+       int n = strlen(str);
+       int i;
+
+       if (n != 13 || str[0] != '#')
+               return 0;
+
+       for (i = 1; i < n; i++)
+               if (isxdigit(str[i]) == 0)
+                       return 0;
+
+       return 1;
+}
+
+struct color *string_to_color(const char *str)
+{
+       char tmp[5];
+       unsigned int red, green, blue;
+
+       if (!is_color(str))
+               return NULL;
+
+       strncpy(tmp, str + 1, 4);
+       tmp[4] = '\0';
+       red = strtol(tmp, NULL, 16);
+
+       strncpy(tmp, str + 5, 4);
+       tmp[4] = '\0';
+       green = strtol(tmp, NULL, 16);
+
+       strncpy(tmp, str + 9, 4);
+       tmp[4] = '\0';
+       blue = strtol(tmp, NULL, 16);
+
+       return color_new(red, green, blue);
+}
+
+char *color_to_string(struct color *color)
+{
+       char *str = malloc(1 + 12 + 1);
+
+       sprintf(str, "#%.4x%.4x%.4x", color->red, color->green, color->blue);
+
+       return str;
+}
diff --git a/src/lib/color.h b/src/lib/color.h
new file mode 100644 (file)
index 0000000..2ac5525
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#ifndef _PSENSOR_COLOR_H_
+#define _PSENSOR_COLOR_H_
+
+/* Represents a RGB color.
+
+   Contains integer and floating RGB representation to avoid useless
+conversion.
+
+   Uses color_set to maintain the coherence of the both
+   representation.
+*/
+struct color {
+       /* rgb 0..65535 */
+       unsigned int red;
+       unsigned int green;
+       unsigned int blue;
+
+       /* rgb floating 0..1 */
+       double f_red;
+       double f_green;
+       double f_blue;
+};
+
+struct color *color_new(unsigned int red,
+                       unsigned int green, unsigned int blue);
+
+struct color *color_dup(struct color *);
+
+void color_set(struct color *,
+              unsigned int red, unsigned int green, unsigned int blue);
+
+int is_color(const char *str);
+
+struct color *string_to_color(const char *str);
+
+char *color_to_string(struct color *color);
+
+#endif
diff --git a/src/lib/hdd.c b/src/lib/hdd.c
new file mode 100644 (file)
index 0000000..27fd296
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#include <locale.h>
+#include <libintl.h>
+#define _(str) gettext(str)
+
+/*
+  Following code is based on GNOME sensors applet code hddtemp-plugin.c
+  see http://sensors-applet.sourceforge.net/
+*/
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+
+#include "psensor.h"
+
+#define HDDTEMP_SERVER_IP_ADDRESS "127.0.0.1"
+#define HDDTEMP_PORT_NUMBER 7634
+#define HDDTEMP_OUTPUT_BUFFER_LENGTH 4048
+
+struct hdd_info {
+       char *name;
+       int temp;
+};
+
+char *hdd_fetch()
+{
+       int sockfd;
+       ssize_t n = 1;
+       int output_length = 0;
+       char *pc;
+       char *buffer;
+       struct sockaddr_in address;
+
+       sockfd = socket(AF_INET, SOCK_STREAM, 0);
+       if (sockfd == -1) {
+               fprintf(stderr, _("ERROR: hdd_fetch, failed to open socket\n"));
+               return NULL;
+       }
+
+       address.sin_family = AF_INET;
+       address.sin_addr.s_addr = inet_addr(HDDTEMP_SERVER_IP_ADDRESS);
+       address.sin_port = htons(HDDTEMP_PORT_NUMBER);
+
+       buffer = NULL;
+
+       if (connect(sockfd,
+                   (struct sockaddr *)&address,
+                   (socklen_t) sizeof(address)) == -1) {
+               fprintf(stderr,
+                       _("ERROR: hdd_fetch, failed to open connection\n"));
+       } else {
+               buffer = malloc(HDDTEMP_OUTPUT_BUFFER_LENGTH);
+
+               pc = buffer;
+               while ((n = read(sockfd,
+                                pc,
+                                HDDTEMP_OUTPUT_BUFFER_LENGTH -
+                                output_length)) > 0) {
+
+                       output_length += n;
+                       pc = &pc[n];
+               }
+
+               buffer[output_length] = '\0';
+       }
+
+       close(sockfd);
+
+       return buffer;
+}
+
+int str_index(char *str, char d)
+{
+       char *c;
+       int i;
+
+       if (!str || *str == '\0')
+               return -1;
+
+       c = str;
+
+       i = 0;
+       while (*c) {
+               if (*c == d)
+                       return i;
+               i++;
+               c++;
+       }
+
+       return -1;
+}
+
+struct psensor *hdd_create_sensor(char *id, char *name, int values_max_length)
+{
+       return psensor_create(id, name, SENSOR_TYPE_HDD_TEMP,
+                             values_max_length);
+}
+
+char *next_hdd_info(char *string, struct hdd_info *info)
+{
+       char *c;
+       int idx_name_n, i, temp;
+
+       if (!string || strlen(string) <= 5      /* at least 5 pipes */
+           || string[0] != '|')
+               return NULL;
+
+       /* skip first pipe */
+       c = string + 1;
+
+       /* name */
+       idx_name_n = str_index(c, '|');
+
+       if (idx_name_n == -1)
+               return NULL;
+       c = c + idx_name_n + 1;
+
+       /* skip label */
+       i = str_index(c, '|');
+       if (i == -1)
+               return NULL;
+       c = c + i + 1;
+
+       /* temp */
+       i = str_index(c, '|');
+       if (i == -1)
+               return NULL;
+       temp = atoi(c);
+       c = c + i + 1;
+
+       /* skip unit  */
+       i = str_index(c, '|');
+       if (i == -1)
+               return NULL;
+       c = c + i + 1;
+
+       info->name = malloc(idx_name_n + 1);
+       strncpy(info->name, string + 1, idx_name_n);
+       info->name[idx_name_n] = '\0';
+
+       info->temp = temp;
+
+       return c;
+}
+
+struct psensor **hdd_psensor_list_add(struct psensor **sensors,
+                                     int values_max_length)
+{
+       char *hddtemp_output = hdd_fetch();
+       char *c;
+       struct hdd_info info;
+       struct psensor **result;
+
+       if (!hddtemp_output)
+               return sensors;
+
+       if (hddtemp_output[0] != '|') {
+               fprintf(stderr,
+                       _("ERROR: wrong hdd string: %s"), hddtemp_output);
+
+               free(hddtemp_output);
+
+               return sensors;
+       }
+
+       c = hddtemp_output;
+
+       result = sensors;
+
+       while (c && (c = next_hdd_info(c, &info))) {
+               struct psensor *sensor;
+               struct psensor **tmp_sensors;
+
+               char *id = malloc(strlen("hdd ") + strlen(info.name) + 1);
+               strcpy(id, "hdd ");
+               strcat(id, info.name);
+
+               sensor = hdd_create_sensor(id, info.name, values_max_length);
+
+               tmp_sensors = psensor_list_add(result, sensor);
+
+               if (result != sensors)
+                       free(result);
+
+               result = tmp_sensors;
+       }
+
+       free(hddtemp_output);
+
+       return result;
+}
+
+void hdd_psensor_update(struct psensor **sensors, struct hdd_info *info)
+{
+       struct psensor **sensor_cur = sensors;
+
+       while (*sensor_cur) {
+               if ((*sensor_cur)->type == SENSOR_TYPE_HDD_TEMP
+                   && !strcmp((*sensor_cur)->id + 4, info->name))
+                       psensor_set_current_value(*sensor_cur,
+                                                 (float)info->temp);
+
+               sensor_cur++;
+       }
+}
+
+void hdd_psensor_list_update(struct psensor **sensors)
+{
+       char *hddtemp_output = hdd_fetch();
+
+       if (!hddtemp_output)
+               return;
+
+       if (hddtemp_output[0] == '|') {
+
+               char *c = hddtemp_output;
+               struct hdd_info info;
+               info.name = NULL;
+               info.temp = 0;
+
+               while (c && (c = next_hdd_info(c, &info))) {
+
+                       hdd_psensor_update(sensors, &info);
+
+                       free(info.name);
+               }
+       } else {
+               fprintf(stderr,
+                       _("ERROR: wrong hdd string: %s\n"), hddtemp_output);
+       }
+
+       free(hddtemp_output);
+}
diff --git a/src/lib/hdd.h b/src/lib/hdd.h
new file mode 100644 (file)
index 0000000..0e31b49
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#ifndef _PSENSOR_HDD_H_
+#define _PSENSOR_HDD_H_
+
+#include "psensor.h"
+
+struct psensor **hdd_psensor_list_add(struct psensor **sensors,
+                                     int values_max_length);
+
+void hdd_psensor_list_update(struct psensor **sensors);
+
+#endif
diff --git a/src/lib/lmsensor.c b/src/lib/lmsensor.c
new file mode 100644 (file)
index 0000000..5149e80
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#include <locale.h>
+#include <libintl.h>
+#define _(str) gettext(str)
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sensors/sensors.h>
+#include <sensors/error.h>
+
+#include "psensor.h"
+
+double
+lmsensor_get_value(const sensors_chip_name *name,
+                  const sensors_subfeature *sub)
+{
+       double val;
+       int err;
+
+       err = sensors_get_value(name, sub->number, &val);
+       if (err) {
+               fprintf(stderr,
+                       _("ERROR: Can't get value of subfeature %s: %s\n"),
+                       sub->name, sensors_strerror(err));
+               val = UNKNOWN_VALUE;
+       }
+       return val;
+}
+
+double lmsensor_get_temp_input(struct psensor *sensor)
+{
+       const sensors_chip_name *chip = sensor->iname;
+       const sensors_feature *feature = sensor->feature;
+
+       const sensors_subfeature *sf;
+
+       sf = sensors_get_subfeature(chip,
+                                   feature, SENSORS_SUBFEATURE_TEMP_INPUT);
+       if (sf)
+               return lmsensor_get_value(chip, sf);
+       else
+               return UNKNOWN_VALUE;
+}
+
+double lmsensor_get_fan_input(struct psensor *sensor)
+{
+       const sensors_chip_name *chip = sensor->iname;
+       const sensors_feature *feature = sensor->feature;
+
+       const sensors_subfeature *sf;
+
+       sf = sensors_get_subfeature(chip,
+                                   feature, SENSORS_SUBFEATURE_FAN_INPUT);
+       if (sf)
+               return lmsensor_get_value(chip, sf);
+       else
+               return UNKNOWN_VALUE;
+}
+
+void lmsensor_psensor_list_update(struct psensor **sensors)
+{
+       struct psensor **s_ptr = sensors;
+
+       while (*s_ptr) {
+               struct psensor *sensor = *s_ptr;
+
+               if (sensor->type == SENSOR_TYPE_LMSENSOR_TEMP)
+                       psensor_set_current_value
+                           (sensor, lmsensor_get_temp_input(sensor));
+               else if (sensor->type == SENSOR_TYPE_LMSENSOR_FAN)
+                       psensor_set_current_value
+                           (sensor, lmsensor_get_fan_input(sensor));
+
+               s_ptr++;
+       }
+}
+
+struct psensor *
+lmsensor_psensor_create(const sensors_chip_name *chip,
+                       const sensors_feature *feature,
+                       int values_max_length)
+{
+       char name[200];
+       const sensors_subfeature *sf;
+       char *label;
+       int type;
+       char *id;
+       struct psensor *psensor;
+       sensors_subfeature_type fault_subfeature;
+
+       if (sensors_snprintf_chip_name(name, 200, chip) < 0)
+               return NULL;
+
+       if (feature->type == SENSORS_FEATURE_TEMP) {
+               fault_subfeature = SENSORS_SUBFEATURE_TEMP_FAULT;
+
+       } else if (feature->type == SENSORS_FEATURE_FAN) {
+               fault_subfeature = SENSORS_SUBFEATURE_FAN_FAULT;
+
+       } else {
+               fprintf(stderr,
+                       _("ERROR: create_sensor, wrong feature type\n"));
+               return NULL;
+       }
+
+       sf = sensors_get_subfeature(chip, feature, fault_subfeature);
+       if (sf && lmsensor_get_value(chip, sf))
+               return NULL;
+
+       label = sensors_get_label(chip, feature);
+       if (!label)
+               return NULL;
+
+       type = 0;
+       if (feature->type == SENSORS_FEATURE_TEMP)
+               type = SENSOR_TYPE_LMSENSOR_TEMP;
+       else if (feature->type == SENSORS_FEATURE_FAN)
+               type = SENSOR_TYPE_LMSENSOR_FAN;
+       else
+               return NULL;
+
+       id = malloc(strlen("lmsensor ") + 1 + strlen(name) + 1 + strlen(label) +
+                   1);
+       sprintf(id, "lmsensor %s %s", name, label);
+
+       psensor = psensor_create(id, label, type, values_max_length);
+
+       psensor->iname = chip;
+       psensor->feature = feature;
+
+       if (feature->type == SENSORS_FEATURE_TEMP
+           && (lmsensor_get_temp_input(psensor) == UNKNOWN_VALUE)) {
+               free(psensor);
+               return NULL;
+       }
+
+       return psensor;
+}
+
+int lmsensor_init()
+{
+       int err = sensors_init(NULL);
+
+       if (err) {
+               fprintf(stderr,
+                       _("ERROR: lm-sensors initialization failure: %s\n"),
+                       sensors_strerror(err));
+               return 0;
+       } else {
+               return 1;
+       }
+}
diff --git a/src/lib/lmsensor.h b/src/lib/lmsensor.h
new file mode 100644 (file)
index 0000000..3efe6ed
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#ifndef _PSENSOR_LMSENSOR_H_
+#define _PSENSOR_LMSENSOR_H_
+
+#include <sensors/sensors.h>
+
+struct psensor *lmsensor_psensor_create(const sensors_chip_name *chip,
+                                       const sensors_feature *feature,
+                                       int values_max_length);
+int lmsensor_init();
+void lmsensor_psensor_list_update(struct psensor **sensors);
+
+#endif
diff --git a/src/lib/measure.c b/src/lib/measure.c
new file mode 100644 (file)
index 0000000..7dcacc3
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "measure.h"
+
+struct measure *measures_create(int size)
+{
+       int i;
+       struct measure *result;
+
+       result = malloc(size * sizeof(struct measure));
+
+       for (i = 0; i < size; i++) {
+               result[i].value = UNKNOWN_VALUE;
+               timerclear(&result[i].time);
+       }
+
+       return result;
+}
+
+void measures_free(struct measure *measures)
+{
+       free(measures);
+}
+
+void measure_copy(struct measure *src, struct measure *dst)
+{
+       dst->time = src->time;
+       dst->value = src->value;
+}
diff --git a/src/lib/measure.h b/src/lib/measure.h
new file mode 100644 (file)
index 0000000..f1380a5
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#ifndef _PSENSOR_MEASURE_H_
+#define _PSENSOR_MEASURE_H_
+
+#include <sys/time.h>
+#include <float.h>
+
+#define UNKNOWN_VALUE DBL_MIN
+
+struct measure {
+       double value;
+       struct timeval time;
+};
+
+void measure_copy(struct measure *src, struct measure *dst);
+
+struct measure *measures_create(int size);
+
+void measures_free(struct measure *measures);
+
+#endif
diff --git a/src/lib/nvidia.c b/src/lib/nvidia.c
new file mode 100644 (file)
index 0000000..4a74bbf
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#include <locale.h>
+#include <libintl.h>
+#define _(str) gettext(str)
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <X11/Xlib.h>
+
+#include <NVCtrl/NVCtrl.h>
+#include <NVCtrl/NVCtrlLib.h>
+
+
+#include "psensor.h"
+
+Display *nvidia_sensors_dpy;
+
+int nvidia_get_sensor_temp(struct psensor *sensor)
+{
+       int temp;
+       Bool res;
+
+       res = XNVCTRLQueryTargetAttribute(nvidia_sensors_dpy,
+                                         NV_CTRL_TARGET_TYPE_GPU,
+                                         sensor->nvidia_id,
+                                         0,
+                                         NV_CTRL_GPU_CORE_TEMPERATURE, &temp);
+
+       if (res == True) {
+               return temp;
+       } else {
+               fprintf(stderr,
+                       _("ERROR: failed to retrieve nvidia temperature\n"));
+               return 0;
+       }
+}
+
+struct psensor *nvidia_create_sensor(int id, int values_max_length)
+{
+       char name[200];
+       char *sid;
+       struct psensor *s;
+
+       sprintf(name, "GPU%d", id);
+
+       sid = malloc(strlen("nvidia") + 1 + strlen(name) + 1);
+       sprintf(sid, "nvidia %s", name);
+
+       s = psensor_create(sid, strdup(name),
+                          SENSOR_TYPE_NVIDIA, values_max_length);
+
+       s->nvidia_id = id;
+
+       return s;
+}
+
+int nvidia_init()
+{
+       int event_base, error_base;
+       int num_gpus;
+
+       nvidia_sensors_dpy = XOpenDisplay(NULL);
+
+       if (!nvidia_sensors_dpy) {
+               fprintf(stderr, _("ERROR: nvidia initialization failure\n"));
+               return 0;
+       }
+
+       if (XNVCTRLQueryExtension(nvidia_sensors_dpy, &event_base,
+                                 &error_base)) {
+               if (XNVCTRLQueryTargetCount(nvidia_sensors_dpy,
+                                           NV_CTRL_TARGET_TYPE_GPU,
+                                           &num_gpus)) {
+                       return num_gpus;
+               }
+
+       }
+
+       fprintf(stderr, _("ERROR: nvidia initialization failure: %d\n"),
+               error_base);
+
+       return 0;
+}
+
+void nvidia_psensor_list_update(struct psensor **sensors)
+{
+       struct psensor **s_ptr = sensors;
+
+       while (*s_ptr) {
+               struct psensor *sensor = *s_ptr;
+
+               if (sensor->type == SENSOR_TYPE_NVIDIA) {
+                       int val = nvidia_get_sensor_temp(sensor);
+
+                       psensor_set_current_value(sensor, (double)val);
+               }
+
+               s_ptr++;
+       }
+}
+
+struct psensor **nvidia_psensor_list_add(struct psensor **sensors,
+                                        int values_max_length)
+{
+       int i;
+       int nvidia_gpus_count = nvidia_init();
+       struct psensor **res = sensors;
+
+
+       if (!nvidia_gpus_count) {
+               fprintf(stderr,
+                       _("ERROR: "
+                         "no nvidia chips or initialization failure\n"));
+       }
+
+       for (i = 0; i < nvidia_gpus_count; i++) {
+               struct psensor *sensor
+                       = nvidia_create_sensor(i, values_max_length);
+
+               struct psensor **tmp_psensors = psensor_list_add(res,
+                                                                sensor);
+
+               if (res != sensors)
+                       free(res);
+
+               res = tmp_psensors;
+       }
+
+       return res;
+}
diff --git a/src/lib/nvidia.h b/src/lib/nvidia.h
new file mode 100644 (file)
index 0000000..8a9e4e7
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#ifndef _PSENSOR_NVIDIA_H_
+#define _PSENSOR_NVIDIA_H_
+
+#include "psensor.h"
+
+int nvidia_get_sensor_temp(struct psensor *);
+
+struct psensor *nvidia_create_sensor(int id, int values_max_length);
+
+int nvidia_init();
+
+void nvidia_psensor_list_update(struct psensor **sensors);
+
+
+/*
+  Adds NVIDIA sensors to a given list of sensors.
+
+  Returns the new allocated list of sensors if sensors have been added otherwise
+  returns 'sensors'. The list is 'NULL' terminated.
+ */
+struct psensor **nvidia_psensor_list_add(struct psensor **sensors,
+                                        int values_max_length);
+
+
+#endif
diff --git a/src/lib/psensor.c b/src/lib/psensor.c
new file mode 100644 (file)
index 0000000..f735a5e
--- /dev/null
@@ -0,0 +1,422 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <sensors/sensors.h>
+#include <sensors/error.h>
+
+#include "hdd.h"
+#include "psensor.h"
+#include "lmsensor.h"
+
+struct psensor *psensor_create(char *id, char *name,
+                              unsigned int type, int values_max_length)
+{
+       struct psensor *psensor
+           = (struct psensor *)malloc(sizeof(struct psensor));
+
+       psensor->id = id;
+       psensor->name = name;
+       psensor->enabled = 1;
+       psensor->min = UNKNOWN_VALUE;
+       psensor->max = UNKNOWN_VALUE;
+
+       psensor->type = type;
+
+       psensor->values_max_length = values_max_length;
+       psensor->measures = measures_create(values_max_length);
+
+       psensor->alarm_limit = 0;
+
+       psensor->cb_alarm_raised = NULL;
+       psensor->cb_alarm_raised_data = NULL;
+       psensor->alarm_raised = 0;
+
+       psensor->alarm_enabled = 0;
+
+       psensor->url = NULL;
+
+       psensor->color = NULL;
+
+       return psensor;
+}
+
+void psensor_values_resize(struct psensor *s, int new_size)
+{
+       struct measure *new_ms, *cur_ms;
+       int cur_size;
+
+       cur_size = s->values_max_length;
+       cur_ms = s->measures;
+       new_ms = measures_create(new_size);
+
+       if (cur_ms) {
+               int i;
+               for (i = 0; i < new_size - 1 && i < cur_size - 1; i++)
+                       measure_copy(&cur_ms[cur_size - i - 1],
+                                    &new_ms[new_size - i - 1]);
+
+               measures_free(s->measures);
+       }
+
+       s->values_max_length = new_size;
+       s->measures = new_ms;
+}
+
+void psensor_free(struct psensor *sensor)
+{
+       if (sensor) {
+               free(sensor->name);
+               free(sensor->id);
+
+               if (sensor->color)
+                       free(sensor->color);
+
+               measures_free(sensor->measures);
+
+               free(sensor->url);
+
+               free(sensor);
+       }
+}
+
+void psensor_list_free(struct psensor **sensors)
+{
+       struct psensor **sensor_cur;
+
+       if (sensors) {
+               sensor_cur = sensors;
+
+               while (*sensor_cur) {
+                       psensor_free(*sensor_cur);
+
+                       sensor_cur++;
+               }
+
+               free(sensors);
+
+               sensors = NULL;
+       }
+}
+
+int psensor_list_size(struct psensor **sensors)
+{
+       int size;
+       struct psensor **sensor_cur;
+
+       if (!sensors)
+               return 0;
+
+       size = 0;
+       sensor_cur = sensors;
+
+       while (*sensor_cur) {
+               size++;
+               sensor_cur++;
+       }
+       return size;
+}
+
+int psensor_list_contains_type(struct psensor **sensors, unsigned int type)
+{
+       struct psensor **s;
+
+       if (!sensors)
+               return 0;
+
+       s = sensors;
+       while (*s) {
+               if ((*s)->type == type)
+                       return 1;
+               s++;
+       }
+
+       return 0;
+}
+
+struct psensor **psensor_list_add(struct psensor **sensors,
+                                 struct psensor *sensor)
+{
+       int size = psensor_list_size(sensors);
+
+       struct psensor **result
+           = malloc((size + 1 + 1) * sizeof(struct psensor *));
+
+       if (sensors)
+               memcpy(result, sensors, size * sizeof(struct psensor *));
+
+       result[size] = sensor;
+       result[size + 1] = NULL;
+
+       return result;
+}
+
+struct psensor *psensor_list_get_by_id(struct psensor **sensors, const char *id)
+{
+       struct psensor **sensors_cur = sensors;
+
+       while (*sensors_cur) {
+               if (!strcmp((*sensors_cur)->id, id))
+                       return *sensors_cur;
+
+               sensors_cur++;
+       }
+
+       return NULL;
+}
+
+int is_temp_type(unsigned int type)
+{
+       return type & SENSOR_TYPE_TEMP;
+}
+
+int is_fan_type(unsigned int type)
+{
+       return type & SENSOR_TYPE_FAN;
+}
+
+char *psensor_value_to_string(unsigned int type, double value)
+{
+       /* should not be possible to exceed 20 characters with temp or
+          rpm values the .x part is never displayed */
+       char *str = malloc(20);
+
+       char *unit;
+
+       if (is_temp_type(type))
+               unit = "C";
+       else
+               unit = "";
+
+       sprintf(str, "%.0f%s", value, unit);
+
+       return str;
+}
+
+void psensor_set_current_value(struct psensor *sensor, double value)
+{
+       struct timeval tv;
+
+       if (gettimeofday(&tv, NULL) != 0)
+               timerclear(&tv);
+
+       psensor_set_current_measure(sensor, value, tv);
+}
+
+void
+psensor_set_current_measure(struct psensor *s,
+                           double v, struct timeval tv)
+{
+       memmove(s->measures,
+               &s->measures[1],
+               (s->values_max_length - 1) * sizeof(struct measure));
+
+       s->measures[s->values_max_length - 1].value = v;
+       s->measures[s->values_max_length - 1].time = tv;
+
+       if (s->min == UNKNOWN_VALUE || v < s->min)
+               s->min = v;
+
+       if (s->max == UNKNOWN_VALUE || v > s->max)
+               s->max = v;
+
+       if (s->alarm_limit && s->alarm_enabled) {
+               if (v > s->alarm_limit) {
+                       if (!s->alarm_raised && s->cb_alarm_raised)
+                               s->cb_alarm_raised(s,
+                                                  s->cb_alarm_raised_data);
+
+                       s->alarm_raised = 1;
+               } else {
+                       s->alarm_raised = 0;
+               }
+       }
+}
+
+double psensor_get_current_value(struct psensor *sensor)
+{
+       return sensor->measures[sensor->values_max_length - 1].value;
+}
+
+struct measure *psensor_get_current_measure(struct psensor *sensor)
+{
+       return &sensor->measures[sensor->values_max_length - 1];
+}
+
+/*
+  Returns the minimal value of a given 'type' (SENSOR_TYPE_TEMP or
+  SENSOR_TYPE_FAN)
+ */
+double get_min_value(struct psensor **sensors, int type)
+{
+       double m = UNKNOWN_VALUE;
+       struct psensor **s = sensors;
+
+       while (*s) {
+               struct psensor *sensor = *s;
+
+               if (sensor->enabled && (sensor->type & type)) {
+                       int i;
+                       double t;
+
+                       for (i = 0; i < sensor->values_max_length; i++) {
+                               t = sensor->measures[i].value;
+
+                               if (t == UNKNOWN_VALUE)
+                                       continue;
+
+                               if (m == UNKNOWN_VALUE || t < m)
+                                       m = t;
+                       }
+               }
+               s++;
+       }
+
+       return m;
+}
+
+/*
+  Returns the maximal value of a given 'type' (SENSOR_TYPE_TEMP or
+  SENSOR_TYPE_FAN)
+ */
+static double get_max_value(struct psensor **sensors, int type)
+{
+       double m = UNKNOWN_VALUE;
+       struct psensor **s = sensors;
+
+       while (*s) {
+               struct psensor *sensor = *s;
+
+               if (sensor->enabled && (sensor->type & type)) {
+                       int i;
+                       double t;
+                       for (i = 0; i < sensor->values_max_length; i++) {
+                               t = sensor->measures[i].value;
+
+                               if (t == UNKNOWN_VALUE)
+                                       continue;
+
+                               if (m == UNKNOWN_VALUE || t > m)
+                                       m = t;
+                       }
+               }
+               s++;
+       }
+
+       return m;
+}
+
+double get_min_temp(struct psensor **sensors)
+{
+       return get_min_value(sensors, SENSOR_TYPE_TEMP);
+}
+
+double get_min_rpm(struct psensor **sensors)
+{
+       return get_min_value(sensors, SENSOR_TYPE_FAN);
+}
+
+double get_max_rpm(struct psensor **sensors)
+{
+       return get_max_value(sensors, SENSOR_TYPE_FAN);
+}
+
+double get_max_temp(struct psensor **sensors)
+{
+       return get_max_value(sensors, SENSOR_TYPE_TEMP);
+}
+
+struct psensor **get_all_sensors(int values_max_length)
+{
+       struct psensor **psensors = NULL;
+       int count = 0;
+       const sensors_chip_name *chip;
+       int chip_nr = 0;
+       struct psensor **tmp_psensors;
+       const sensors_feature *feature;
+       struct psensor *psensor;
+       int i;
+
+       while ((chip = sensors_get_detected_chips(NULL, &chip_nr))) {
+               i = 0;
+               while ((feature = sensors_get_features(chip, &i))) {
+
+                       if (feature->type == SENSORS_FEATURE_TEMP
+                           || feature->type == SENSORS_FEATURE_FAN) {
+
+                               psensor = lmsensor_psensor_create
+                                       (chip, feature, values_max_length);
+
+                               if (psensor) {
+                                       tmp_psensors
+                                               = psensor_list_add(psensors,
+                                                                  psensor);
+
+                                       free(psensors);
+
+                                       psensors = tmp_psensors;
+
+                                       count++;
+                               }
+                       }
+               }
+       }
+
+       tmp_psensors = hdd_psensor_list_add(psensors, values_max_length);
+
+       if (tmp_psensors != psensors) {
+               free(psensors);
+               psensors = tmp_psensors;
+       }
+
+       if (!psensors) {        /* there is no detected sensors */
+               psensors = malloc(sizeof(struct psensor *));
+               *psensors = NULL;
+       }
+
+       return psensors;
+}
+
+const char *psensor_type_to_str(unsigned int type)
+{
+       if (type & SENSOR_TYPE_REMOTE)
+               return "Remote";
+
+       if (type & SENSOR_TYPE_LMSENSOR_TEMP)
+               return "Temperature";
+
+       if (type & SENSOR_TYPE_LMSENSOR_FAN)
+               return "Fan";
+
+       if (type & SENSOR_TYPE_NVIDIA)
+               return "NVidia GPU Temperature";
+
+       if (type & SENSOR_TYPE_HDD_TEMP)
+               return "HDD Temperature";
+
+       return "N/A";           /* should not be possible */
+}
+
+void psensor_list_update_measures(struct psensor **sensors)
+{
+       lmsensor_psensor_list_update(sensors);
+       hdd_psensor_list_update(sensors);
+}
diff --git a/src/lib/psensor.h b/src/lib/psensor.h
new file mode 100644 (file)
index 0000000..ad7364e
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#ifndef _PSENSOR_PSENSOR_H_
+#define _PSENSOR_PSENSOR_H_
+
+#include "config.h"
+#include <sensors/sensors.h>
+
+#include "color.h"
+#include "measure.h"
+
+enum psensor_type {
+       SENSOR_TYPE_TEMP = 0x0001,
+       SENSOR_TYPE_FAN = 0x0002,
+       SENSOR_TYPE_REMOTE = 0x0004,
+
+       SENSOR_TYPE_LMSENSOR_TEMP = 0x0100 | SENSOR_TYPE_TEMP,
+       SENSOR_TYPE_NVIDIA = 0x0200 | SENSOR_TYPE_TEMP,
+       SENSOR_TYPE_HDD_TEMP = 0x0300 | SENSOR_TYPE_TEMP,
+       SENSOR_TYPE_LMSENSOR_FAN = 0x0400 | SENSOR_TYPE_FAN
+};
+
+struct psensor {
+       /* Human readable name of the sensor.  It may not be uniq. */
+       char *name;
+
+       /* Uniq id of the sensor */
+       char *id;
+
+       /* lm-sensor */
+       const sensors_chip_name *iname;
+       const sensors_feature *feature;
+
+       /* Maximum length of 'values' */
+       int values_max_length;
+
+       /* Last registered measures of the sensor.  Index 0 for the
+          oldest measure.  */
+       struct measure *measures;
+
+       /* Color of the sensor used for the graph */
+       struct color *color;
+
+       /* Whether the sensor is displayed in the graph */
+       int enabled;
+
+       /* see psensor_type */
+       unsigned int type;
+
+       /* The maximum detected value of the sensor */
+       double max;
+
+       /* The minimum detected value of the sensor */
+       double min;
+
+       /*
+          Whether alarm alerts is enabled for this sensor
+        */
+       int alarm_enabled;
+
+       /*
+          An alarm is raised if the current sensor value is bigger. 0
+          means no limit
+        */
+       double alarm_limit;
+
+       /* Whether the current value is bigger than 'alarm_limit'.  */
+       int alarm_raised;
+
+       void (*cb_alarm_raised) (struct psensor *, void *);
+       void *cb_alarm_raised_data;
+
+#ifdef HAVE_NVIDIA
+       /* Nvidia id for the nvctrl */
+       int nvidia_id;
+#endif
+
+       char *url;
+
+};
+
+struct psensor *psensor_create(char *id,
+                              char *name, unsigned int type,
+                              int values_max_length);
+
+void psensor_values_resize(struct psensor *s, int new_size);
+
+void psensor_free(struct psensor *sensor);
+
+void psensor_list_free(struct psensor **sensors);
+int psensor_list_size(struct psensor **sensors);
+
+struct psensor *psensor_list_get_by_id(struct psensor **sensors,
+                                      const char *id);
+
+/*
+  Return 1 if there is at least one sensor of a given type, else
+  returns 0 */
+int psensor_list_contains_type(struct psensor **sensors, unsigned int type);
+
+int is_temp_type(unsigned int type);
+int is_fan_type(unsigned int type);
+
+double get_min_temp(struct psensor **sensors);
+double get_max_temp(struct psensor **sensors);
+
+double get_min_rpm(struct psensor **sensors);
+double get_max_rpm(struct psensor **sensors);
+
+/*
+  Converts the value of a sensor to a string.
+
+  parameter 'type' is SENSOR_TYPE_LMSENSOR_TEMP, SENSOR_TYPE_NVIDIA,
+  or SENSOR_TYPE_LMSENSOR_FAN
+*/
+char *psensor_value_to_string(unsigned int type, double value);
+
+struct psensor **get_all_sensors(int values_max_length);
+
+struct psensor **psensor_list_add(struct psensor **sensors,
+                                 struct psensor *sensor);
+
+void psensor_set_current_value(struct psensor *sensor, double value);
+void psensor_set_current_measure(struct psensor *sensor, double value,
+                                struct timeval tv);
+
+double psensor_get_current_value(struct psensor *sensor);
+
+struct measure *psensor_get_current_measure(struct psensor *sensor);
+
+/*
+  Returns a string representation of a psensor type.
+*/
+const char *psensor_type_to_str(unsigned int type);
+
+void psensor_list_update_measures(struct psensor **sensors);
+
+#endif
diff --git a/src/libpsensor_json/Makefile.am b/src/libpsensor_json/Makefile.am
new file mode 100644 (file)
index 0000000..a85c829
--- /dev/null
@@ -0,0 +1,12 @@
+noinst_LIBRARIES = libpsensor_json.a
+
+libpsensor_json_a_CFLAGS = -pedantic -Werror
+
+libpsensor_json_a_SOURCES = \
+       psensor_json.h psensor_json.c 
+
+LIBS = ../lib/libpsensor.a \
+       $(JSON_LIBS)
+
+AM_CPPFLAGS = $(JSON_CFLAGS) -I$(top_srcdir)/src/lib 
+
diff --git a/src/libpsensor_json/psensor_json.c b/src/libpsensor_json/psensor_json.c
new file mode 100644 (file)
index 0000000..b476439
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#include <string.h>
+
+#include "psensor_json.h"
+
+#define ATT_SENSOR_ID "id"
+#define ATT_SENSOR_NAME "name"
+#define ATT_SENSOR_TYPE "type"
+#define ATT_SENSOR_MIN "min"
+#define ATT_SENSOR_MAX "max"
+#define ATT_SENSOR_LAST_MEASURE "last_measure"
+#define ATT_MEASURE_VALUE "value"
+#define ATT_MEASURE_TIME "time"
+
+json_object *sensor_to_json_object(struct psensor *s)
+{
+       json_object *mo;
+       json_object *obj = json_object_new_object();
+       struct measure *m;
+
+       json_object_object_add(obj,
+                              ATT_SENSOR_ID,
+                              json_object_new_string(s->id));
+       json_object_object_add(obj,
+                              ATT_SENSOR_NAME,
+                              json_object_new_string(s->name));
+       json_object_object_add(obj,
+                              ATT_SENSOR_TYPE, json_object_new_int(s->type));
+       json_object_object_add(obj,
+                              ATT_SENSOR_MIN, json_object_new_double(s->min));
+       json_object_object_add(obj,
+                              ATT_SENSOR_MAX, json_object_new_double(s->max));
+
+       m = psensor_get_current_measure(s);
+       mo = json_object_new_object();
+       json_object_object_add(mo,
+                              ATT_MEASURE_VALUE,
+                              json_object_new_double(m->value));
+       json_object_object_add(mo, ATT_MEASURE_TIME,
+                              json_object_new_int((m->time).tv_sec));
+       json_object_object_add(obj, ATT_SENSOR_LAST_MEASURE, mo);
+
+       return obj;
+}
+
+char *sensor_to_json_string(struct psensor *s)
+{
+       char *str;
+       json_object *obj = sensor_to_json_object(s);
+
+       str = strdup(json_object_to_json_string(obj));
+
+       json_object_put(obj);
+
+       return str;
+}
+
+char *sensors_to_json_string(struct psensor **sensors)
+{
+       struct psensor **sensors_cur;
+       char *str;
+
+       json_object *obj = json_object_new_array();
+
+       sensors_cur = sensors;
+
+       while (*sensors_cur) {
+               struct psensor *s = *sensors_cur;
+
+               json_object_array_add(obj, sensor_to_json_object(s));
+
+               sensors_cur++;
+       }
+
+       str = strdup(json_object_to_json_string(obj));
+
+       json_object_put(obj);
+
+       return str;
+}
+
diff --git a/src/libpsensor_json/psensor_json.h b/src/libpsensor_json/psensor_json.h
new file mode 100644 (file)
index 0000000..c97e6f6
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#ifndef _PSENSOR_PSENSOR_JSON_H_
+#define _PSENSOR_PSENSOR_JSON_H_
+
+#include <json/json.h>
+
+#include "psensor.h"
+
+json_object *sensor_to_json_object(struct psensor *s);
+char *sensor_to_json_string(struct psensor *s);
+char *sensors_to_json_string(struct psensor **sensors);
+
+
+#endif
diff --git a/src/main.c b/src/main.c
new file mode 100644 (file)
index 0000000..3a092a8
--- /dev/null
@@ -0,0 +1,420 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#include <locale.h>
+
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <gtk/gtk.h>
+
+#include <sensors/sensors.h>
+#include <sensors/error.h>
+
+#include "config.h"
+
+#include "cfg.h"
+#include "hdd.h"
+#include "psensor.h"
+#include "graph.h"
+#include "ui.h"
+#include "ui_sensorlist.h"
+#include "ui_color.h"
+#include "lmsensor.h"
+#include "ui_pref.h"
+#include "ui_graph.h"
+
+#ifdef HAVE_UNITY
+#include "ui_unity.h"
+#endif
+
+#ifdef HAVE_NVIDIA
+#include "nvidia.h"
+#endif
+
+#ifdef HAVE_REMOTE_SUPPORT
+#include "rsensor.h"
+#endif
+
+#if defined(HAVE_APPINDICATOR) || defined(HAVE_APPINDICATOR_029)
+#include "ui_appindicator.h"
+#endif
+
+#ifdef HAVE_LIBNOTIFY
+#include "ui_notify.h"
+#endif
+
+#include "compat.h"
+
+static const char *program_name;
+
+void print_version()
+{
+       printf("psensor %s\n", VERSION);
+       printf(_("Copyright (C) %s wpitchoune@gmail.com\n\
+License GPLv2: GNU GPL version 2 or later \
+<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>\n\
+This is free software: you are free to change and redistribute it.\n\
+There is NO WARRANTY, to the extent permitted by law.\n"),
+              "2010-2011");
+}
+
+void print_help()
+{
+       printf(_("Usage: %s [OPTION]...\n"), program_name);
+
+       puts(_("psensor is a GTK application for monitoring hardware sensors, "
+              "including temperatures and fan speeds."));
+
+       puts("");
+       puts(_("Options:"));
+       puts(_("\
+  -h, --help          display this help and exit\n\
+  -v, --version       display version information and exit"));
+
+       puts("");
+
+       puts(_("\
+  -u, --url=URL       \
+the URL of the psensor-server, example: http://hostname:3131"));
+
+       puts("");
+
+       printf(_("Report bugs to: %s\n"), PACKAGE_BUGREPORT);
+       puts("");
+       printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
+}
+
+/*
+  Updates the size of the sensor values if different than the
+  configuration.
+ */
+void
+update_psensor_values_size(struct psensor **sensors, struct config *cfg)
+{
+       struct psensor **cur;
+
+       cur = sensors;
+       while (*cur) {
+               struct psensor *s = *cur;
+
+               if (s->values_max_length != cfg->sensor_values_max_length)
+                       psensor_values_resize(s,
+                                             cfg->sensor_values_max_length);
+
+               cur++;
+       }
+}
+
+void update_psensor_measures(struct ui_psensor *ui)
+{
+       struct psensor **sensors = ui->sensors;
+       struct config *cfg = ui->config;
+
+       while (1) {
+               /*gdk_threads_enter();*/
+               g_mutex_lock(ui->sensors_mutex);
+
+               if (!sensors)
+                       return;
+
+               update_psensor_values_size(sensors, ui->config);
+
+               psensor_list_update_measures(sensors);
+#ifdef HAVE_REMOTE_SUPPORT
+               remote_psensor_list_update(sensors);
+#endif
+#ifdef HAVE_NVIDIA
+               nvidia_psensor_list_update(sensors);
+#endif
+
+               /*gdk_threads_leave();*/
+               g_mutex_unlock(ui->sensors_mutex);
+
+               sleep(cfg->sensor_update_interval);
+       }
+}
+
+gboolean ui_refresh_thread(gpointer data)
+{
+       struct config *cfg;
+       gboolean ret;
+       struct ui_psensor *ui = (struct ui_psensor *)data;
+
+       ret = TRUE;
+       cfg = ui->config;
+
+       g_mutex_lock(ui->sensors_mutex);
+       /*gdk_threads_enter();*/
+
+       graph_update(ui->sensors, ui->w_graph, ui->config);
+
+       ui_sensorlist_update(ui->ui_sensorlist);
+
+#if defined(HAVE_APPINDICATOR) || defined(HAVE_APPINDICATOR_029)
+       ui_appindicator_update(ui);
+#endif
+
+#ifdef HAVE_UNITY
+       ui_unity_launcher_entry_update(ui->sensors);
+#endif
+
+       if (ui->graph_update_interval != cfg->graph_update_interval) {
+               ui->graph_update_interval = cfg->graph_update_interval;
+               ret = FALSE;
+       }
+
+       g_mutex_unlock(ui->sensors_mutex);
+       /*gdk_threads_leave();*/
+
+       if (ret == FALSE)
+               g_timeout_add(1000 * ui->graph_update_interval,
+                             ui_refresh_thread, ui);
+
+       return ret;
+}
+
+void cb_alarm_raised(struct psensor *sensor, void *data)
+{
+#ifdef HAVE_LIBNOTIFY
+       if (sensor->enabled)
+               ui_notify(sensor, (struct ui_psensor *)data);
+#endif
+}
+
+void associate_colors(struct psensor **sensors)
+{
+       /* number of uniq colors */
+#define COLORS_COUNT 8
+
+       unsigned int colors[COLORS_COUNT][3] = {
+               {0x0000, 0x0000, 0x0000},       /* black */
+               {0xffff, 0x0000, 0x0000},       /* red */
+               {0x0000, 0.0000, 0xffff},       /* blue */
+               {0x0000, 0xffff, 0x0000},       /* green */
+
+               {0x7fff, 0x7fff, 0x7fff},       /* grey */
+               {0x7fff, 0x0000, 0x0000},       /* dark red */
+               {0x0000, 0x0000, 0x7fff},       /* dark blue */
+               {0x0000, 0x7fff, 0x0000}        /* dark green */
+       };
+
+       struct psensor **sensor_cur = sensors;
+       int i = 0;
+       while (*sensor_cur) {
+               struct color default_color;
+               color_set(&default_color,
+                         colors[i % COLORS_COUNT][0],
+                         colors[i % COLORS_COUNT][1],
+                         colors[i % COLORS_COUNT][2]);
+
+               (*sensor_cur)->color
+                   = config_get_sensor_color((*sensor_cur)->id,
+                                             &default_color);
+
+               sensor_cur++;
+               i++;
+       }
+}
+
+void
+associate_cb_alarm_raised(struct psensor **sensors, struct ui_psensor *ui)
+{
+       struct psensor **sensor_cur = sensors;
+       while (*sensor_cur) {
+               struct psensor *s = *sensor_cur;
+
+               s->cb_alarm_raised = cb_alarm_raised;
+               s->cb_alarm_raised_data = ui;
+
+               if (is_temp_type(s->type)) {
+                       s->alarm_limit
+                           = config_get_sensor_alarm_limit(s->id, 60);
+                       s->alarm_enabled
+                           = config_get_sensor_alarm_enabled(s->id);
+               } else {
+                       s->alarm_limit = 0;
+                       s->alarm_enabled = 0;
+               }
+
+               sensor_cur++;
+       }
+}
+
+void associate_preferences(struct psensor **sensors)
+{
+       struct psensor **sensor_cur = sensors;
+       while (*sensor_cur) {
+               char *n;
+               struct psensor *s = *sensor_cur;
+
+               s->enabled = config_is_sensor_enabled(s->id);
+
+               n = config_get_sensor_name(s->id);
+
+               if (n)
+                       s->name = n;
+
+               sensor_cur++;
+       }
+}
+
+
+static struct option long_options[] = {
+       {"version", no_argument, 0, 'v'},
+       {"help", no_argument, 0, 'h'},
+       {"url", required_argument, 0, 'u'},
+       {0, 0, 0, 0}
+};
+
+int main(int argc, char **argv)
+{
+       struct ui_psensor ui;
+       GError *error;
+       GThread *thread;
+       int err, optc;
+       char *url = NULL;
+       int cmdok = 1;
+
+       program_name = argv[0];
+
+       setlocale(LC_ALL, "");
+
+#if ENABLE_NLS
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+#endif
+
+       while ((optc = getopt_long(argc, argv, "vhu:", long_options,
+                                  NULL)) != -1) {
+               switch (optc) {
+               case 'u':
+                       if (optarg)
+                               url = strdup(optarg);
+                       break;
+               case 'h':
+                       print_help();
+                       exit(EXIT_SUCCESS);
+               case 'v':
+                       print_version();
+                       exit(EXIT_SUCCESS);
+               default:
+                       cmdok = 0;
+                       break;
+               }
+       }
+
+       if (!cmdok || optind != argc) {
+               fprintf(stderr, _("Try `%s --help' for more information.\n"),
+                       program_name);
+               exit(EXIT_FAILURE);
+       }
+
+       g_thread_init(NULL);
+       gdk_threads_init();
+       /* gdk_threads_enter(); */
+
+       gtk_init(&argc, &argv);
+
+#ifdef HAVE_LIBNOTIFY
+       ui.notification_last_time = NULL;
+#endif
+
+       ui.sensors_mutex = g_mutex_new();
+
+       config_init();
+
+       ui.config = config_load();
+
+       err = lmsensor_init();
+       if (!err) {
+               fprintf(stderr, _("ERROR: lmsensor init failure: %s\n"),
+                       sensors_strerror(err));
+               exit(EXIT_FAILURE);
+       }
+
+       if (url) {
+#ifdef HAVE_REMOTE_SUPPORT
+               rsensor_init();
+               ui.sensors = get_remote_sensors(url, 600);
+#else
+               fprintf(stderr,
+                       _("ERROR: Not compiled with remote sensor support.\n"));
+               exit(EXIT_FAILURE);
+#endif
+       } else {
+#ifdef HAVE_NVIDIA
+               struct psensor **tmp;
+
+               tmp = get_all_sensors(600);
+               ui.sensors = nvidia_psensor_list_add(tmp, 600);
+
+               if (tmp != ui.sensors)
+                       free(tmp);
+#else
+               ui.sensors = get_all_sensors(600);
+#endif
+       }
+
+       associate_preferences(ui.sensors);
+       associate_colors(ui.sensors);
+       associate_cb_alarm_raised(ui.sensors, &ui);
+
+       /* main window */
+       ui.main_window = ui_window_create(&ui);
+       ui.main_box = NULL;
+
+       /* drawing box */
+       ui.w_graph = ui_graph_create(&ui);
+
+       /* sensor list */
+       ui.ui_sensorlist = ui_sensorlist_create(ui.sensors);
+
+       ui_main_box_create(&ui);
+
+       gtk_widget_show_all(ui.main_window);
+
+       thread = g_thread_create((GThreadFunc) update_psensor_measures,
+                                &ui, TRUE, &error);
+
+       if (!thread)
+               g_error_free(error);
+
+       ui.graph_update_interval = ui.config->graph_update_interval;
+
+       g_timeout_add(1000 * ui.graph_update_interval, ui_refresh_thread, &ui);
+
+#if defined(HAVE_APPINDICATOR) || defined(HAVE_APPINDICATOR_029)
+       ui_appindicator_init(&ui);
+#endif
+
+       /* main loop */
+       gtk_main();
+
+       sensors_cleanup();
+
+       psensor_list_free(ui.sensors);
+
+       /* gdk_threads_leave(); */
+
+       return 0;
+}
diff --git a/src/plib/Makefile.am b/src/plib/Makefile.am
new file mode 100644 (file)
index 0000000..6b6dd69
--- /dev/null
@@ -0,0 +1,21 @@
+
+AM_CPPFLAGS = \
+       -I$(top_srcdir)/src
+
+noinst_LIBRARIES = libplib.a
+
+libplib_a_CFLAGS = -pedantic
+
+libplib_a_SOURCES = \
+       url.c url.h \
+       plib_io.h plib_io.c
+
+if LUA
+noinst_LIBRARIES += libplib_luatpl.a
+
+libplib_luatpl_a_CFLAGS = -pedantic \
+       $(LUA_CFLAGS)
+
+libplib_luatpl_a_SOURCES = \
+       plib_luatpl.h plib_luatpl.c 
+endif
\ No newline at end of file
diff --git a/src/plib/plib_io.c b/src/plib/plib_io.c
new file mode 100644 (file)
index 0000000..7396ad0
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <dirent.h>
+
+#include "plib_io.h"
+
+int is_dir(const char *path)
+{
+       struct stat st;
+
+       int ret = lstat(path, &st);
+
+       if (ret == 0 && S_ISDIR(st.st_mode))
+               return 1;
+
+       return 0;
+}
+
+int is_file(const char *path)
+{
+       struct stat st;
+
+       int ret = lstat(path, &st);
+
+       if (ret == 0 && S_ISREG(st.st_mode))
+               return 1;
+
+       return 0;
+}
+
+char *dir_normalize(const char *dpath)
+{
+       char *npath;
+       int n;
+
+       if (!dpath || !strlen(dpath))
+               return NULL;
+
+       npath = strdup(dpath);
+
+       n = strlen(npath);
+
+       if (n > 1 && npath[n - 1] == '/')
+               npath[n - 1] = '\0';
+
+       return npath;
+}
+
+char **dir_list(const char *dpath, int (*filter) (const char *path))
+{
+       struct dirent *ent;
+       DIR *dir;
+       char **paths;
+       int n;
+
+       dir = opendir(dpath);
+
+       if (!dir)
+               return NULL;
+
+       n = 1;
+       paths = malloc(sizeof(void *));
+       *paths = NULL;
+
+       while ((ent = readdir(dir)) != NULL) {
+               char *fpath;
+               char *name = ent->d_name;
+
+               if (!strcmp(name, ".") || !strcmp(name, ".."))
+                       continue;
+
+               fpath = malloc(strlen(dpath) + 1 + strlen(name) + 1);
+
+               strcpy(fpath, dpath);
+               strcat(fpath, "/");
+               strcat(fpath, name);
+
+               if (!filter || filter(fpath)) {
+                       char **npaths;
+
+                       n++;
+                       npaths = malloc(n * sizeof(void *));
+                       memcpy(npaths + 1, paths, (n - 1) * sizeof(void *));
+                       free(paths);
+                       paths = npaths;
+                       *npaths = fpath;
+
+               } else {
+                       free(fpath);
+               }
+       }
+
+       closedir(dir);
+
+       return paths;
+}
+
+void paths_free(char **paths)
+{
+       char **paths_cur;
+
+       paths_cur = paths;
+       while (*paths_cur) {
+               free(*paths_cur);
+
+               paths_cur++;
+       }
+
+       free(paths);
+}
+
+char *file_get_content(const char *fpath)
+{
+       long size;
+
+       char *page;
+
+       size = file_get_size(fpath);
+
+       if (size == -1) {
+               page = NULL;
+
+       } else if (size == 0) {
+               page = malloc(1);
+               *page = '\0';
+
+       } else {
+               FILE *fp = fopen(fpath, "rb");
+               if (fp) {
+                       page = malloc(size + 1);
+                       if (!page || size != fread(page, 1, size, fp)) {
+                               free(page);
+                               return NULL;
+                       }
+
+                       *(page + size) = '\0';
+
+                       fclose(fp);
+               } else {
+                       page = NULL;
+               }
+       }
+
+       return page;
+}
+
+long file_get_size(const char *path)
+{
+       FILE *fp;
+
+       if (!is_file(path))
+               return -1;
+
+       fp = fopen(path, "rb");
+       if (fp) {
+               long size;
+
+               if (fseek(fp, 0, SEEK_END) == -1)
+                       return -1;
+
+               size = ftell(fp);
+
+               fclose(fp);
+
+               return size;
+       }
+
+       return -1;
+}
+
+#define FCOPY_BUF_SZ 4096
+static int FILE_copy(FILE *src, FILE *dst)
+{
+       int ret = 0;
+       char *buf = malloc(FCOPY_BUF_SZ);
+       int n;
+
+       if (!buf)
+               return FILE_COPY_ERROR_ALLOC_BUFFER;
+
+       while (!ret) {
+               n = fread(buf, 1, FCOPY_BUF_SZ, src);
+               if (n) {
+                       if (fwrite(buf, 1, n, dst) != n)
+                               ret = FILE_COPY_ERROR_WRITE;
+               } else {
+                       if (!feof(src))
+                               ret = FILE_COPY_ERROR_READ;
+                       else
+                               break;
+               }
+       }
+
+       free(buf);
+
+       return ret;
+}
+
+int
+file_copy(const char *src, const char *dst)
+{
+       FILE *fsrc, *fdst;
+       int ret = 0;
+
+       fsrc = fopen(src, "r");
+
+       if (fsrc) {
+               fdst = fopen(dst, "w+");
+
+               if (fdst) {
+                       ret = FILE_copy(fsrc, fdst);
+                       fclose(fdst);
+               } else {
+                       ret = FILE_COPY_ERROR_OPEN_DST;
+               }
+
+               fclose(fsrc);
+       } else {
+               ret = FILE_COPY_ERROR_OPEN_SRC;
+       }
+
+       return ret;
+}
+
+char *path_append(const char *dir, const char *path)
+{
+       char *ret, *ndir;
+
+       ndir = dir_normalize(dir);
+
+       if (!ndir && (!path || !strlen(path)))
+               ret = NULL;
+
+       else if (!ndir) {
+               ret = strdup(path);
+
+       } else if (!path || !strlen(path)) {
+               return ndir;
+
+       } else {
+               ret = malloc(strlen(ndir) + 1 + strlen(path) + 1);
+               strcpy(ret, ndir);
+               strcat(ret, "/");
+               strcat(ret, path);
+       }
+
+       free(ndir);
+
+       return ret;
+}
+
+void
+file_copy_print_error(int code, const char *src, const char *dst)
+{
+       switch (code) {
+       case 0:
+               break;
+       case FILE_COPY_ERROR_OPEN_SRC:
+               printf("File copy error: failed to open %s.\n", src);
+               break;
+       case FILE_COPY_ERROR_OPEN_DST:
+               printf("File copy error: failed to open %s.\n", dst);
+               break;
+       case FILE_COPY_ERROR_READ:
+               printf("File copy error: failed to read %s.\n", src);
+               break;
+       case FILE_COPY_ERROR_WRITE:
+               printf("File copy error: failed to write %s.\n", src);
+               break;
+       case FILE_COPY_ERROR_ALLOC_BUFFER:
+               printf("File copy error: failed to allocate buffer.\n");
+               break;
+       default:
+               printf("File copy error: unknown error %d.\n", code);
+       }
+}
diff --git a/src/plib/plib_io.h b/src/plib/plib_io.h
new file mode 100644 (file)
index 0000000..a20d76e
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#ifndef _P_IO_H
+#define _P_IO_H
+
+/* Returns '1' if a given 'path' denotates a directory else returns
+   0 */
+int is_dir(const char *path);
+
+/* Returns '1' if a given 'path' denotates a file else returns
+   0 */
+int is_file(const char *path);
+
+/*  Returns a normalized path */
+char *path_normalize(const char *dpath);
+
+/*  Returns the null-terminated entries of a directory */
+char **dir_list(const char *dpath, int (*filter) (const char *path));
+void paths_free(char **paths);
+
+char *path_append(const char *dir, const char *path);
+
+/*
+   Returns the size of a file.
+   Returns '-1' if the size cannot be retrieved or not a file.
+*/
+long file_get_size(const char *path);
+
+/*
+   Returns the content of a file.
+   Returns 'NULL' if the file cannot be read or failed to allocate
+   enough memory.
+   Returns an empty string if the file exists but is empty.
+*/
+char *file_get_content(const char *path);
+
+enum file_copy_error {
+       FILE_COPY_ERROR_OPEN_SRC = 1,
+       FILE_COPY_ERROR_OPEN_DST,
+       FILE_COPY_ERROR_READ,
+       FILE_COPY_ERROR_WRITE,
+       FILE_COPY_ERROR_ALLOC_BUFFER
+};
+
+void file_copy_print_error(int code, const char *src, const char *dst);
+
+/*
+  Copy a file.
+
+  Returns '0' if sucessfull, otherwise return the error code.
+*/
+int file_copy(const char *src, const char *dst);
+
+#endif
diff --git a/src/plib/plib_luatpl.c b/src/plib/plib_luatpl.c
new file mode 100644 (file)
index 0000000..dd46213
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+#include <locale.h>
+#include <libintl.h>
+#define _(str) gettext(str)
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <lualib.h>
+#include <lauxlib.h>
+
+#include "plib_luatpl.h"
+
+char *
+luatpl_generate(const char *lua,
+               int (*init) (lua_State *, void *),
+               void *init_data,
+               struct luatpl_error *err)
+{
+       lua_State *L;
+       char *page = NULL;
+
+       L = lua_open();
+       if (!L) {
+               err->code = LUATPL_ERROR_LUA_STATE_OPEN;
+               return NULL;
+       }
+
+       luaL_openlibs(L);
+
+       if (!init || init(L, init_data)) {
+
+               if (!luaL_loadfile(L, lua)) {
+                       if (!lua_pcall(L, 0, 1, 0)) {
+                               if (lua_isstring(L, -1))
+                                       page = strdup(lua_tostring(L, -1));
+                               else
+                                       err->code =
+                                               LUATPL_ERROR_WRONG_RETURN_TYPE;
+                       } else {
+                               err->code = LUATPL_ERROR_LUA_EXECUTION;
+                               err->message = strdup(lua_tostring(L, -1));
+                       }
+               } else {
+                       err->code = LUATPL_ERROR_LUA_FILE_LOAD;
+               }
+       } else {
+               err->code = LUATPL_ERROR_INIT;
+       }
+
+       lua_close(L);
+
+       return page;
+}
+
+int
+luatpl_generate_file(const char *lua,
+                    int (*init) (lua_State *, void *),
+                    void *init_data,
+                    const char *dst_path,
+                    struct luatpl_error *err)
+{
+       FILE *f;
+       int ret;
+       char *content;
+
+       ret = 1;
+
+       content = luatpl_generate(lua, init, init_data, err);
+
+       if (content) {
+               f = fopen(dst_path, "w");
+
+               if (f) {
+                       if (fputs(content, f) == EOF)
+                               ret = 0;
+
+                       if (fclose(f) == EOF)
+                               ret = 0;
+               } else {
+                       ret = 0;
+               }
+
+               free(content);
+       } else {
+               ret = 0;
+       }
+
+       return ret;
+}
+
+void
+luatpl_fprint_error(FILE *stream,
+                   const struct luatpl_error *err,
+                   const char *lua,
+                   const char *dst_path)
+{
+       if (!err || !err->code)
+               return ;
+
+       switch (err->code) {
+       case LUATPL_ERROR_LUA_FILE_LOAD:
+               fprintf(stream,
+                       _("LUATPL Error: failed to load Lua script: %s.\n"),
+                       lua);
+               break;
+
+       case LUATPL_ERROR_INIT:
+               fprintf(stream,
+                       _("LUATPL Error: failed to call init function: %s.\n"),
+                       lua);
+               break;
+
+       case LUATPL_ERROR_LUA_EXECUTION:
+               fprintf(stream,
+                       _("LUATPL Error:"
+                         "failed to execute Lua script (%s): %s.\n"),
+                       lua, err->message);
+               break;
+
+       case LUATPL_ERROR_WRONG_RETURN_TYPE:
+               fprintf(stream,
+                       _("LUATPL Error:"
+                         "lua script (%s) returned a wrong type.\n"),
+                       lua);
+               break;
+
+       case LUATPL_ERROR_LUA_STATE_OPEN:
+               fprintf(stream,
+                       _("LUATPL Error:"
+                         "failed to open lua state.\n"));
+               break;
+
+
+       default:
+               fprintf(stream,
+                       _("LUATPL Error: code: %d.\n"),
+                       err->code);
+       }
+}
diff --git a/src/plib/plib_luatpl.h b/src/plib/plib_luatpl.h
new file mode 100644 (file)
index 0000000..4e36856
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#ifndef _P_LUATPL_H
+#define _P_LUATPL_H
+
+#include <lua.h>
+
+#define LUATPL_ERROR_LUA_FILE_LOAD 1
+#define LUATPL_ERROR_INIT 2
+#define LUATPL_ERROR_LUA_EXECUTION 3
+#define LUATPL_ERROR_WRONG_RETURN_TYPE 4
+#define LUATPL_ERROR_LUA_STATE_OPEN 5
+
+struct luatpl_error {
+       unsigned int code;
+
+       char *message;
+};
+
+/*
+  Generates a string which is the result of a Lua script execution.
+
+  The string is retrieved from the top element of the Lua stack
+  after the Lua script execution.
+
+  If not 'NULL' the 'init' function is called after Lua environment
+  setup and before Lua script execution. This function typically puts
+  input information for the Lua script into the stack.
+
+  'init_data' is passed to the second parameter of 'init' function
+
+  Returns the generated string on success, or NULL on error.
+ */
+char *luatpl_generate(const char *lua,
+                     int (*init) (lua_State *, void *),
+                     void *init_data,
+                     struct luatpl_error *err);
+
+/*
+  Generates a file which is the result of a Lua script execution.
+
+  See luatpl_generate function for 'init', 'init_data', and 'err'
+  parameters.
+
+  'dst_path' is the path of the generated file
+
+  Returns '1' on success, or '0' on error.
+
+ */
+int luatpl_generate_file(const char *lua,
+                        int (*init) (lua_State *, void *),
+                        void *init_data,
+                        const char *dst_path,
+                        struct luatpl_error *err);
+
+void luatpl_fprint_error(FILE *stream,
+                        const struct luatpl_error *err,
+                        const char *lua,
+                        const char *dst_path);
+
+#endif
diff --git a/src/plib/url.c b/src/plib/url.c
new file mode 100644 (file)
index 0000000..7a87adf
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+    Copyright (C) 2010 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+/*
+  Part of the following code is based on:
+  http://www.geekhideout.com/urlcode.shtml
+*/
+
+#include "plib/url.h"
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+char *url_normalize(const char *url)
+{
+       int n = strlen(url);
+       char *ret = strdup(url);
+
+       if (url[n - 1] == '/')
+               ret[n - 1] = '\0';
+
+       return ret;
+}
+
+char to_hex(char code)
+{
+       static char hex[] = "0123456789abcdef";
+       return hex[code & 0x0f];
+}
+
+/*
+   Returns a url-encoded version of str.
+*/
+char *url_encode(const char *str)
+{
+       char *c, *buf, *pbuf;
+
+       buf = malloc(strlen(str) * 3 + 1);
+       pbuf = buf;
+
+       c = (char *)str;
+
+       while (*c) {
+
+               if (isalnum(*c) ||
+                   *c == '.' || *c == '_' || *c == '-' || *c == '~')
+                       *pbuf++ = *c;
+               else {
+                       *pbuf++ = '%';
+                       *pbuf++ = to_hex(*c >> 4);
+                       *pbuf++ = to_hex(*c & 0x0f);
+               }
+               c++;
+       }
+       *pbuf = '\0';
+
+       return buf;
+}
diff --git a/src/plib/url.h b/src/plib/url.h
new file mode 100644 (file)
index 0000000..53a1406
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+    Copyright (C) 2010 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#ifndef _PLIB_URL_H_
+#define _PLIB_URL_H_
+
+char *url_encode(const char *str);
+char *url_normalize(const char *url);
+
+#endif
diff --git a/src/rsensor.c b/src/rsensor.c
new file mode 100644 (file)
index 0000000..7f13c30
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#include <locale.h>
+#include <libintl.h>
+#define _(str) gettext(str)
+
+#include "plib/url.h"
+#include "server/server.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <curl/curl.h>
+#include <json/json.h>
+
+#include "rsensor.h"
+
+struct ucontent {
+       char *data;
+       size_t len;
+};
+
+static CURL *curl;
+
+size_t cbk_curl(void *buffer, size_t size, size_t nmemb, void *userp)
+{
+       size_t realsize = size * nmemb;
+       struct ucontent *mem = (struct ucontent *)userp;
+
+       mem->data = realloc(mem->data, mem->len + realsize + 1);
+
+       memcpy(&(mem->data[mem->len]), buffer, realsize);
+       mem->len += realsize;
+       mem->data[mem->len] = 0;
+
+       return realsize;
+}
+
+char *create_api_1_0_sensors_url(const char *base_url)
+{
+       char *nurl = url_normalize(base_url);
+       int n = strlen(nurl) + strlen(URL_BASE_API_1_0_SENSORS) + 1;
+       char *ret = malloc(n);
+
+       strcpy(ret, nurl);
+       strcat(ret, URL_BASE_API_1_0_SENSORS);
+
+       free(nurl);
+
+       return ret;
+}
+
+struct psensor *json_object_to_psensor(json_object * o,
+                                      const char *sensors_url,
+                                      int values_max_length)
+{
+       json_object *oid;
+       json_object *oname;
+       json_object *otype;
+       struct psensor *s;
+       char *eid;
+       char *url;
+
+       oid = json_object_object_get(o, "id");
+       oname = json_object_object_get(o, "name");
+       otype = json_object_object_get(o, "type");
+
+       eid = url_encode(json_object_get_string(oid));
+       url = malloc(strlen(sensors_url) + 1 + strlen(eid) + 1);
+       sprintf(url, "%s/%s", sensors_url, eid);
+
+       s = psensor_create(strdup(url),
+                          strdup(json_object_get_string(oname)),
+                          json_object_get_int(otype) | SENSOR_TYPE_REMOTE,
+                          values_max_length);
+       s->url = url;
+
+       free(eid);
+
+       return s;
+}
+
+void rsensor_init()
+{
+       curl = curl_easy_init();
+}
+
+void rsensor_end()
+{
+       curl_easy_cleanup(curl);
+}
+
+json_object *get_json_object(const char *url)
+{
+
+       struct ucontent chunk;
+       json_object *obj = NULL;
+
+       if (!curl)
+               return NULL;
+
+       chunk.data = malloc(1);
+       chunk.len = 0;
+
+       curl_easy_setopt(curl, CURLOPT_URL, url);
+       curl_easy_setopt(curl, CURLOPT_VERBOSE, 0);
+       curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cbk_curl);
+       curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
+
+       if (curl_easy_perform(curl) == CURLE_OK)
+               obj = json_tokener_parse(chunk.data);
+       else
+               fprintf(stderr, _("ERROR: Fail to connect to: %s\n"), url);
+
+       free(chunk.data);
+
+       return obj;
+}
+
+struct psensor **get_remote_sensors(const char *server_url,
+                                   int values_max_length)
+{
+       struct psensor **sensors = NULL;
+       char *url;
+       json_object *obj;
+
+       url = create_api_1_0_sensors_url(server_url);
+
+       obj = get_json_object(url);
+
+       if (obj && !is_error(obj)) {
+               int i;
+               int n = json_object_array_length(obj);
+               sensors = malloc((n + 1) * sizeof(struct psensor *));
+
+               for (i = 0; i < n; i++) {
+                       struct psensor *s = json_object_to_psensor
+                           (json_object_array_get_idx(obj, i),
+                            url,
+                            values_max_length);
+                       sensors[i] = s;
+               }
+
+               sensors[n] = NULL;
+
+               json_object_put(obj);
+       } else {
+               fprintf(stderr, _("ERROR: Invalid content: %s\n"), url);
+       }
+
+       free(url);
+
+       if (!sensors) {
+               sensors = malloc(sizeof(struct psensor *));
+               *sensors = NULL;
+       }
+
+       return sensors;
+}
+
+void remote_psensor_update(struct psensor *s)
+{
+       json_object *obj = get_json_object(s->url);
+
+       if (obj && !is_error(obj)) {
+               json_object *om;
+
+               om = json_object_object_get(obj, "last_measure");
+
+               if (!is_error(obj)) {
+                       json_object *ov, *ot;
+                       struct timeval tv;
+
+                       ov = json_object_object_get(om, "value");
+                       ot = json_object_object_get(om, "time");
+
+                       tv.tv_sec = json_object_get_int(ot);
+                       tv.tv_usec = 0;
+
+                       psensor_set_current_measure
+                           (s, json_object_get_double(ov), tv);;
+               }
+
+               json_object_put(obj);
+       } else {
+               printf(_("ERROR: Invalid JSON: %s\n"), s->url);
+       }
+
+}
+
+void remote_psensor_list_update(struct psensor **sensors)
+{
+       struct psensor **cur = sensors;
+
+       while (*cur) {
+               struct psensor *s = *cur;
+
+               if (s->type & SENSOR_TYPE_REMOTE)
+                       remote_psensor_update(s);
+
+               cur++;
+       }
+}
diff --git a/src/rsensor.h b/src/rsensor.h
new file mode 100644 (file)
index 0000000..bd7a44b
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#ifndef _PSENSOR_RSENSOR_H_
+#define _PSENSOR_RSENSOR_H_
+
+#include "psensor.h"
+
+struct psensor **get_remote_sensors(const char *server_url,
+                                   int values_max_length);
+
+void remote_psensor_list_update(struct psensor **sensors);
+
+void rsensor_init();
+
+#endif
diff --git a/src/server/Makefile.am b/src/server/Makefile.am
new file mode 100644 (file)
index 0000000..73192bf
--- /dev/null
@@ -0,0 +1,42 @@
+bin_PROGRAMS =  psensor-server
+psensor_server_SOURCES = server.c server.h
+
+AM_CPPFLAGS = -pedantic -Werror -DDEFAULT_WWW_DIR=\""$(pkgdatadir)/www"\"\
+       -I$(top_srcdir)/src \
+       -I$(top_srcdir)/src/lib \
+       -I$(top_srcdir)/src/libpsensor_json \
+       $(SENSORS_CFLAGS)\
+       $(JSON_CFLAGS)\
+       $(LIBMICROHTTPD_CFLAGS)
+
+DEFS = -DLOCALEDIR=\"$(localedir)\" @DEFS@
+
+LIBS = \
+       ../plib/libplib.a \
+       ../lib/libpsensor.a \
+       ../libpsensor_json/libpsensor_json.a \
+       $(SENSORS_LIBS) \
+       $(JSON_LIBS) \
+       $(LIBMICROHTTPD_LIBS)
+
+if LUA
+AM_CPPFLAGS += $(LUA_CFLAGS)
+LIBS += ../plib/libplib_luatpl.a \
+       $(LUA_LIBS)
+psensor_server_SOURCES += server_lua.h server_lua.c
+endif
+
+if GTOP
+AM_CPPFLAGS += $(GTOP_CFLAGS)
+LIBS += $(GTOP_LIBS) 
+psensor_server_SOURCES += sysinfo.h sysinfo.c
+AM_LDFLAGS = -Wl,--as-needed
+endif
+
+
+
+dist_man_MANS =  psensor-server.1
+EXTRA_DIST = description.txt
+psensor-server.1: server.c $(top_srcdir)/configure.ac
+       $(MAKE) $(AM_MAKEFLAGS) psensor-server$(EXEEXT)
+       help2man --include=description.txt -N --name="Temperature and system monitoring Web server" --output=psensor-server.1 ./psensor-server$(EXEEXT)
\ No newline at end of file
diff --git a/src/server/description.txt b/src/server/description.txt
new file mode 100644 (file)
index 0000000..309bfed
--- /dev/null
@@ -0,0 +1,33 @@
+[DESCRIPTION]
+
+/psensor-server is a/
+
+It provides a JSON Web service which can be used by psensor(1) to
+monitor remotely the hardware sensors of a computer.
+
+It can provide information about:
+  * the temperature of the motherboard and CPU sensors (using lm\-sensors).
+  * the temperature of the Hard Disk Drives (using hddtemp).
+  * the rotation speed of the fans (using lm\-sensors).
+
+The entry point of the JSON Web service is:
+http://hostname:3131/api/1.0/sensors.
+
+It is also possible to connect to the psensor\-server with a browser, a
+simple Web page is displaying the sensors information and the CPU
+usage.
+
+If run in debug mode, psensor\-server can be stopped by sending an HTTP
+request with the URL 'http://hostname:port/api/1.0/server/stop'.
+
+[WARNING]
+
+psensor\-server does not provide any way to restrict the connection to
+the HTTP server, worst, no effort has been made against malicious HTTP
+attacks.  You should make the psensor\-server port available only to a
+network or computer you trust by using the usual network security
+tools of the system (for example, iptables(8) ).
+
+[SEE ALSO]
+
+psensor(1), sensors(1), sensors\-detect(8)
diff --git a/src/server/server.c b/src/server/server.c
new file mode 100644 (file)
index 0000000..673964c
--- /dev/null
@@ -0,0 +1,428 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+#include <locale.h>
+#include <libintl.h>
+#define _(str) gettext(str)
+
+#include "config.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <getopt.h>
+#include <stdint.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <microhttpd.h>
+
+#ifdef HAVE_GTOP
+#include "sysinfo.h"
+#endif
+
+#ifdef HAVE_LUA
+#include "server_lua.h"
+#endif
+
+#include "psensor_json.h"
+#include "plib/url.h"
+#include "plib/plib_io.h"
+#include "server.h"
+
+static const char *program_name;
+
+#define DEFAULT_PORT 3131
+
+#define PAGE_NOT_FOUND (_("<html><body><p>\
+Page not found - Go to <a href='/'>Main page</a>\
+</p></body>"))
+
+static struct option long_options[] = {
+       {"version", no_argument, 0, 'v'},
+       {"help", no_argument, 0, 'h'},
+       {"port", required_argument, 0, 'p'},
+       {"wdir", required_argument, 0, 'w'},
+       {"debug", no_argument, 0, 'd'},
+       {0, 0, 0, 0}
+};
+
+static struct server_data server_data;
+
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static int debug;
+
+static int server_stop_requested;
+
+void print_version()
+{
+       printf("psensor-server %s\n", VERSION);
+       printf(_("Copyright (C) %s wpitchoune@gmail.com\n\
+License GPLv2: GNU GPL version 2 or later \
+<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>\n\
+This is free software: you are free to change and redistribute it.\n\
+There is NO WARRANTY, to the extent permitted by law.\n"),
+              "2010-2011");
+}
+
+void print_help()
+{
+       printf(_("Usage: %s [OPTION]...\n"), program_name);
+
+       puts(_("psensor-server is an HTTP server "
+              "for monitoring hardware sensors remotely."));
+
+       puts("");
+       puts("Options:");
+       puts(_("\
+  -h, --help          display this help and exit\n\
+  -v, --version       display version information and exit"));
+
+       puts("");
+
+       puts(_("\
+  -d,--debug     run in debug mode\n\
+  -p,--port=PORT webserver port\n\
+  -w,--wdir=DIR  directory containing webserver pages"));
+
+       puts("");
+
+       printf(_("Report bugs to: %s\n"), PACKAGE_BUGREPORT);
+       puts("");
+       printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
+}
+
+/*
+  Returns '1' if the path denotates a Lua file, otherwise returns 0.
+ */
+int is_path_lua(const char *path)
+{
+       char *dot = rindex(path, '.');
+
+       if (dot && !strcasecmp(dot, ".lua"))
+               return 1;
+
+       return 0;
+}
+
+/*
+  Returns the file path corresponding to a given URL
+*/
+char *get_path(const char *url, const char *www_dir)
+{
+       const char *p;
+       char *res;
+
+       if (!strlen(url) || !strcmp(url, ".") || !strcmp(url, "/"))
+               p = "/index.lua";
+       else
+               p = url;
+
+       res = malloc(strlen(www_dir)+strlen(p)+1);
+
+       strcpy(res, www_dir);
+       strcat(res, p);
+
+       return res;
+}
+
+static int
+file_reader(void *cls, uint64_t pos, char *buf, int max)
+{
+       FILE *file = cls;
+
+       fseek(file, pos, SEEK_SET);
+       return fread(buf, 1, max, file);
+}
+
+struct MHD_Response *
+create_response_api(const char *nurl,
+                   const char *method,
+                   unsigned int *rp_code)
+{
+       char *page = NULL;
+
+       if (!strcmp(nurl, URL_BASE_API_1_0_SENSORS))  {
+
+               page = sensors_to_json_string(server_data.sensors);
+
+       } else if (!strncmp(nurl, URL_BASE_API_1_0_SENSORS,
+                           strlen(URL_BASE_API_1_0_SENSORS))
+                  && nurl[strlen(URL_BASE_API_1_0_SENSORS)] == '/') {
+
+               const char *sid = nurl + strlen(URL_BASE_API_1_0_SENSORS) + 1;
+
+               struct psensor *s
+                       = psensor_list_get_by_id(server_data.sensors, sid);
+
+               if (s)
+                       page = sensor_to_json_string(s);
+
+       } else if (debug && !strcmp(nurl, URL_API_1_0_SERVER_STOP)) {
+
+               server_stop_requested = 1;
+               page = strdup(_("<html><body><p>"
+                               "Server stop requested</p></body></html>"));
+       }
+
+       if (page) {
+               *rp_code = MHD_HTTP_OK;
+
+               return MHD_create_response_from_data
+                       (strlen(page), page, MHD_YES, MHD_NO);
+       }
+
+       return NULL;
+}
+
+struct MHD_Response *
+create_response_lua(const char *nurl,
+                   const char *method,
+                   unsigned int *rp_code,
+                   const char *fpath)
+{
+#ifdef HAVE_LUA
+       char *page = lua_to_html_page(&server_data, fpath);
+
+       if (page) {
+               *rp_code = MHD_HTTP_OK;
+
+               return MHD_create_response_from_data
+                       (strlen(page), page, MHD_YES, MHD_NO);
+       }
+#endif
+
+       return NULL;
+}
+
+struct MHD_Response *
+create_response_file(const char *nurl,
+                    const char *method,
+                    unsigned int *rp_code,
+                    const char *fpath)
+{
+       if (is_file(fpath)) {
+               FILE *file = fopen(fpath, "rb");
+
+               if (file) {
+                       struct stat buf;
+
+                       stat(fpath, &buf);
+                       *rp_code = MHD_HTTP_OK;
+
+                       if (!buf.st_size) {
+                               fclose(file);
+                               return MHD_create_response_from_data
+                                       (0, NULL, MHD_NO, MHD_NO);
+                       }
+
+                       return MHD_create_response_from_callback
+                               (buf.st_size,
+                                32 * 1024,
+                                &file_reader,
+                                file,
+                                (MHD_ContentReaderFreeCallback)&fclose);
+
+               }
+       }
+
+       return NULL;
+}
+
+struct MHD_Response *
+create_response(const char *nurl, const char *method, unsigned int *rp_code)
+{
+       struct MHD_Response *resp = NULL;
+
+       if (!strncmp(nurl, URL_BASE_API_1_0, strlen(URL_BASE_API_1_0))) {
+               resp = create_response_api(nurl, method, rp_code);
+       } else {
+               char *fpath = get_path(nurl, server_data.www_dir);
+
+               if (is_path_lua(fpath))
+                       resp = create_response_lua
+                               (nurl, method, rp_code, fpath);
+               else
+                       resp = create_response_file
+                               (nurl, method, rp_code, fpath);
+
+               free(fpath);
+       }
+
+       if (resp) {
+               return resp;
+       } else {
+               char *page = strdup(PAGE_NOT_FOUND);
+               *rp_code = MHD_HTTP_NOT_FOUND;
+
+               return MHD_create_response_from_data
+                       (strlen(page), page, MHD_YES, MHD_NO);
+       }
+}
+
+static int
+cbk_http_request(void *cls,
+                struct MHD_Connection *connection,
+                const char *url,
+                const char *method,
+                const char *version,
+                const char *upload_data,
+                size_t *upload_data_size, void **ptr)
+{
+       static int dummy;
+       struct MHD_Response *response;
+       int ret;
+       char *nurl;
+       unsigned int resp_code;
+       char *page = NULL;
+
+       if (strcmp(method, "GET"))
+               return MHD_NO;
+
+       if (&dummy != *ptr) {
+               /* The first time only the headers are valid, do not
+                  respond in the first round... */
+               *ptr = &dummy;
+               return MHD_YES;
+       }
+
+       if (*upload_data_size)
+               return MHD_NO;
+
+       *ptr = NULL;            /* clear context pointer */
+
+       if (debug)
+               printf(_("HTTP Request: %s\n"), url);
+
+       nurl = url_normalize(url);
+
+       pthread_mutex_lock(&mutex);
+       response = create_response(nurl, method, &resp_code);
+       pthread_mutex_unlock(&mutex);
+
+       ret = MHD_queue_response(connection, resp_code, response);
+       MHD_destroy_response(response);
+
+       free(nurl);
+
+       return ret;
+}
+
+int main(int argc, char *argv[])
+{
+       struct MHD_Daemon *d;
+       int port = DEFAULT_PORT;
+       int optc;
+       int cmdok = 1;
+
+       program_name = argv[0];
+
+       setlocale(LC_ALL, "");
+
+#if ENABLE_NLS
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+#endif
+
+       server_data.www_dir = DEFAULT_WWW_DIR;
+
+       while ((optc = getopt_long(argc, argv,
+                                  "vhp:w:d", long_options, NULL)) != -1) {
+               switch (optc) {
+               case 'w':
+                       if (optarg)
+                               server_data.www_dir = strdup(optarg);
+                       break;
+               case 'p':
+                       if (optarg)
+                               port = atoi(optarg);
+                       break;
+               case 'h':
+                       print_help();
+                       exit(EXIT_SUCCESS);
+               case 'v':
+                       print_version();
+                       exit(EXIT_SUCCESS);
+               case 'd':
+                       debug = 1;
+                       break;
+               default:
+                       cmdok = 0;
+                       break;
+               }
+       }
+
+       if (!cmdok || optind != argc) {
+               fprintf(stderr, _("Try `%s --help' for more information.\n"),
+                       program_name);
+               exit(EXIT_FAILURE);
+       }
+
+       if (!lmsensor_init()) {
+               fprintf(stderr, _("ERROR: failed to init lm-sensors\n"));
+               exit(EXIT_FAILURE);
+       }
+
+       server_data.sensors = get_all_sensors(1);
+
+       if (!*server_data.sensors)
+               fprintf(stderr, _("ERROR: no sensors detected\n"));
+
+       d = MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION,
+                            port,
+                            NULL, NULL, &cbk_http_request, server_data.sensors,
+                            MHD_OPTION_END);
+       if (!d) {
+               fprintf(stderr, _("ERROR: Fail to create web server\n"));
+               exit(EXIT_FAILURE);
+       }
+
+       printf(_("Web server started on port: %d\n"), port);
+       printf(_("WWW directory: %s\n"), server_data.www_dir);
+       printf(_("URL: http://localhost:%d\n"), port);
+
+       while (!server_stop_requested) {
+               pthread_mutex_lock(&mutex);
+
+#ifdef HAVE_GTOP
+               sysinfo_update(&server_data.psysinfo);
+#endif
+               psensor_list_update_measures(server_data.sensors);
+
+               pthread_mutex_unlock(&mutex);
+               sleep(5);
+       }
+
+       MHD_stop_daemon(d);
+
+       /* sanity cleanup for valgrind */
+       psensor_list_free(server_data.sensors);
+       free(server_data.www_dir);
+       sensors_cleanup();
+
+#ifdef HAVE_GTOP
+       sysinfo_cleanup();
+#endif
+
+       return EXIT_SUCCESS;
+}
diff --git a/src/server/server.h b/src/server/server.h
new file mode 100644 (file)
index 0000000..2770844
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#ifndef _PSENSOR_SERVER_H_
+#define _PSENSOR_SERVER_H_
+
+#include "psensor.h"
+#include "sysinfo.h"
+
+#define URL_BASE_API_1_0 "/api/1.0"
+#define URL_BASE_API_1_0_SENSORS "/api/1.0/sensors"
+#define URL_API_1_0_SERVER_STOP "/api/1.0/server/stop"
+
+struct server_data {
+       struct psensor **sensors;
+       struct psysinfo psysinfo;
+       char *www_dir;
+};
+
+#endif
diff --git a/src/server/server_lua.c b/src/server/server_lua.c
new file mode 100644 (file)
index 0000000..3d9eb38
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "server_lua.h"
+
+#include "plib/plib_luatpl.h"
+
+int init_lua(lua_State *L, void *data)
+{
+       struct server_data *server_data = data;
+       struct psensor **s_cur;
+       struct psensor **sensors = server_data->sensors;
+       int i;
+       static float load_scale = 1 << SI_LOAD_SHIFT;
+
+       lua_newtable(L);
+
+#ifdef HAVE_GTOP
+       lua_pushstring(L, "load");
+       lua_pushnumber(L, server_data->psysinfo.cpu_rate);
+       lua_settable(L, -3);
+#endif
+
+       lua_pushstring(L, "uptime");
+       lua_pushnumber(L, server_data->psysinfo.sysinfo.uptime);
+       lua_settable(L, -3);
+
+       lua_pushstring(L, "load_1mn");
+       lua_pushnumber(L, server_data->psysinfo.sysinfo.loads[0] / load_scale);
+       lua_settable(L, -3);
+
+       lua_pushstring(L, "load_5mn");
+       lua_pushnumber(L, server_data->psysinfo.sysinfo.loads[1] / load_scale);
+       lua_settable(L, -3);
+
+       lua_pushstring(L, "load_15mn");
+       lua_pushnumber(L, server_data->psysinfo.sysinfo.loads[2] / load_scale);
+       lua_settable(L, -3);
+
+       lua_pushstring(L, "freeram");
+       lua_pushnumber(L, server_data->psysinfo.sysinfo.freeram);
+       lua_settable(L, -3);
+
+       lua_pushstring(L, "sharedram");
+       lua_pushnumber(L, server_data->psysinfo.sysinfo.sharedram);
+       lua_settable(L, -3);
+
+       lua_pushstring(L, "bufferram");
+       lua_pushnumber(L, server_data->psysinfo.sysinfo.bufferram);
+       lua_settable(L, -3);
+
+       lua_pushstring(L, "totalswap");
+       lua_pushnumber(L, server_data->psysinfo.sysinfo.totalswap);
+       lua_settable(L, -3);
+
+       lua_pushstring(L, "freeswap");
+       lua_pushnumber(L, server_data->psysinfo.sysinfo.freeswap);
+       lua_settable(L, -3);
+
+       lua_pushstring(L, "procs");
+       lua_pushnumber(L, server_data->psysinfo.sysinfo.procs);
+       lua_settable(L, -3);
+
+       lua_pushstring(L, "totalhigh");
+       lua_pushnumber(L, server_data->psysinfo.sysinfo.totalhigh);
+       lua_settable(L, -3);
+
+       lua_pushstring(L, "freehigh");
+       lua_pushnumber(L, server_data->psysinfo.sysinfo.freehigh);
+       lua_settable(L, -3);
+
+       lua_pushstring(L, "totalram");
+       lua_pushnumber(L, server_data->psysinfo.sysinfo.totalram);
+       lua_settable(L, -3);
+
+       lua_pushstring(L, "mem_unit");
+       lua_pushnumber(L, server_data->psysinfo.sysinfo.mem_unit);
+       lua_settable(L, -3);
+
+
+       lua_setglobal(L, "sysinfo");
+
+
+       lua_newtable(L);
+
+       s_cur = sensors;
+       i = 1;
+       while (*s_cur) {
+               lua_pushnumber(L, i);
+
+               lua_newtable(L);
+
+               lua_pushstring(L, "name");
+               lua_pushstring(L, (*s_cur)->name);
+               lua_settable(L, -3);
+
+               lua_pushstring(L, "measure_last");
+               lua_pushnumber(L, psensor_get_current_value(*s_cur));
+               lua_settable(L, -3);
+
+               lua_pushstring(L, "measure_min");
+               lua_pushnumber(L, (*s_cur)->min);
+               lua_settable(L, -3);
+
+               lua_pushstring(L, "measure_max");
+               lua_pushnumber(L, (*s_cur)->max);
+               lua_settable(L, -3);
+
+               lua_settable(L, -3);
+
+               s_cur++;
+               i++;
+       }
+
+       lua_setglobal(L, "sensors");
+
+       lua_pushstring(L, VERSION);
+       lua_setglobal(L, "psensor_version");
+
+       return 1;
+}
+
+char *lua_to_html_page(struct server_data *server_data, const char *fpath)
+{
+       char *page = NULL;
+       struct luatpl_error err;
+
+       err.message = NULL;
+
+       page = luatpl_generate(fpath,
+                              init_lua,
+                              server_data,
+                              &err);
+
+       if (!page) {
+               luatpl_fprint_error(stderr,
+                                   &err,
+                                   fpath,
+                                   "outstring");
+               free(err.message);
+       }
+
+       return page;
+}
diff --git a/src/server/server_lua.h b/src/server/server_lua.h
new file mode 100644 (file)
index 0000000..d3e4e9f
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#ifndef _PSENSOR_SERVER_LUA_H_
+#define _PSENSOR_SERVER_LUA_H_
+
+#include "server.h"
+
+char *lua_to_html_page(struct server_data *data, const char *fpath);
+
+#endif
diff --git a/src/server/sysinfo.c b/src/server/sysinfo.c
new file mode 100644 (file)
index 0000000..cef2872
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#include <stdlib.h>
+#include <glibtop/cpu.h>
+#include <sys/sysinfo.h>
+
+#include "sysinfo.h"
+
+static glibtop_cpu *cpu;
+static float last_used;
+static float last_total;
+
+
+void sysinfo_update(struct psysinfo *info)
+{
+       unsigned long int used = 0;
+       unsigned long int dt;
+
+       /* cpu */
+       if (!cpu)
+               cpu = malloc(sizeof(glibtop_cpu));
+
+       glibtop_get_cpu(cpu);
+
+       used = cpu->user + cpu->nice + cpu->sys;
+
+       dt = cpu->total - last_total;
+
+       if (dt)
+               info->cpu_rate = (used - last_used) / dt;
+
+       last_used = used;
+       last_total = cpu->total;
+
+       /* memory */
+       sysinfo(&info->sysinfo);
+}
+
+void sysinfo_cleanup()
+{
+       if (cpu)
+               free(cpu);
+}
diff --git a/src/server/sysinfo.h b/src/server/sysinfo.h
new file mode 100644 (file)
index 0000000..c62ec25
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#ifndef _PSENSOR_SYSINFO_H_
+#define _PSENSOR_SYSINFO_H_
+
+#include <sys/sysinfo.h>
+
+struct psysinfo {
+       float cpu_rate;
+
+       struct sysinfo sysinfo;
+};
+
+void sysinfo_update(struct psysinfo *sysinfo);
+void sysinfo_cleanup();
+
+#endif
diff --git a/src/ui.c b/src/ui.c
new file mode 100644 (file)
index 0000000..5f038fd
--- /dev/null
+++ b/src/ui.c
@@ -0,0 +1,126 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#include "cfg.h"
+#include "ui.h"
+#include "ui_graph.h"
+#include "ui_sensorlist.h"
+
+void on_destroy(GtkWidget *widget, gpointer data)
+{
+       ui_psensor_exit();
+}
+
+void ui_psensor_exit()
+{
+       gtk_main_quit();
+}
+
+GtkWidget *ui_window_create(struct ui_psensor * ui)
+{
+       GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+       GdkScreen *screen;
+       GdkColormap *colormap;
+       GdkPixbuf *icon;
+       GtkIconTheme *icon_theme;
+
+       gtk_window_set_default_size(GTK_WINDOW(window), 800, 200);
+
+       gtk_window_set_title(GTK_WINDOW(window),
+                            _("Psensor - Temperature Monitor"));
+       gtk_window_set_role(GTK_WINDOW(window), "psensor");
+
+       screen = gtk_widget_get_screen(window);
+
+       if (ui->config->alpha_channel_enabled
+           && gdk_screen_is_composited(screen)) {
+
+               colormap = gdk_screen_get_rgba_colormap(screen);
+               if (colormap)
+                       gtk_widget_set_colormap(window, colormap);
+               else
+                       ui->config->alpha_channel_enabled = 0;
+       } else {
+               ui->config->alpha_channel_enabled = 0;
+       }
+
+       icon_theme = gtk_icon_theme_get_default();
+       icon = gtk_icon_theme_load_icon(icon_theme, "psensor", 48, 0, NULL);
+       if (icon)
+               gtk_window_set_icon(GTK_WINDOW(window), icon);
+       else
+               fprintf(stderr, _("ERROR: Failed to load psensor icon.\n"));
+
+       g_signal_connect(window, "destroy", G_CALLBACK(on_destroy), ui);
+
+       gtk_window_set_decorated(GTK_WINDOW(window),
+                                ui->config->window_decoration_enabled);
+
+       gtk_window_set_keep_below(GTK_WINDOW(window),
+                                 ui->config->window_keep_below_enabled);
+
+       return window;
+}
+
+void ui_main_box_create(struct ui_psensor *ui)
+{
+       struct config *cfg;
+       GtkWidget *w_sensorlist;
+
+       cfg = ui->config;
+
+       if (ui->main_box) {
+               ui_sensorlist_create_widget(ui->ui_sensorlist);
+
+               gtk_container_remove(GTK_CONTAINER(ui->main_window),
+                                    ui->main_box);
+
+               ui->w_graph = ui_graph_create(ui);
+               ui->w_sensorlist = ui->ui_sensorlist->widget;
+       }
+
+       if (cfg->sensorlist_position == SENSORLIST_POSITION_RIGHT
+           || cfg->sensorlist_position == SENSORLIST_POSITION_LEFT)
+               ui->main_box = gtk_hpaned_new();
+       else
+               ui->main_box = gtk_vpaned_new();
+
+       w_sensorlist = gtk_scrolled_window_new(NULL, NULL);
+       gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(w_sensorlist),
+                                      GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+       gtk_container_add(GTK_CONTAINER(w_sensorlist),
+                         ui->ui_sensorlist->widget);
+
+       gtk_container_add(GTK_CONTAINER(ui->main_window), ui->main_box);
+
+       if (cfg->sensorlist_position == SENSORLIST_POSITION_RIGHT
+           || cfg->sensorlist_position == SENSORLIST_POSITION_BOTTOM) {
+               gtk_paned_pack1(GTK_PANED(ui->main_box),
+                               GTK_WIDGET(ui->w_graph), TRUE, TRUE);
+               gtk_paned_pack2(GTK_PANED(ui->main_box),
+                               w_sensorlist, FALSE, TRUE);
+       } else {
+               gtk_paned_pack1(GTK_PANED(ui->main_box),
+                               w_sensorlist, FALSE, TRUE);
+               gtk_paned_pack2(GTK_PANED(ui->main_box),
+                               GTK_WIDGET(ui->w_graph), TRUE, TRUE);
+       }
+
+       gtk_widget_show_all(ui->main_box);
+}
diff --git a/src/ui.h b/src/ui.h
new file mode 100644 (file)
index 0000000..24778dd
--- /dev/null
+++ b/src/ui.h
@@ -0,0 +1,77 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#ifndef _PSENSOR_UI_H_
+#define _PSENSOR_UI_H_
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#if defined(HAVE_APPINDICATOR) || defined(HAVE_APPINDICATOR_029)
+#include <libappindicator/app-indicator.h>
+#endif
+
+#include "psensor.h"
+
+struct ui_psensor {
+       struct psensor **sensors;
+
+       GtkWidget *w_graph;
+
+       struct ui_sensorlist *ui_sensorlist;
+
+       struct config *config;
+
+       GtkWidget *main_window;
+
+       GtkWidget *main_box;
+
+       GtkWidget *w_sensorlist;
+
+       int graph_update_interval;
+
+       GMutex *sensors_mutex;
+
+#ifdef HAVE_LIBNOTIFY
+       /*
+        * Time of the last notification
+        */
+       struct timeval *notification_last_time;
+#endif
+
+#if defined(HAVE_APPINDICATOR) || defined(HAVE_APPINDICATOR_029)
+       AppIndicator *indicator;
+#endif
+};
+
+void ui_main_box_create(struct ui_psensor *);
+
+/*
+  Must be called to terminate Psensor UI.
+*/
+void ui_psensor_exit();
+
+/*
+  Creates the main GTK window
+*/
+GtkWidget *ui_window_create(struct ui_psensor * ui);
+
+#endif
diff --git a/src/ui_appindicator.c b/src/ui_appindicator.c
new file mode 100644 (file)
index 0000000..d68bc42
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gtk/gtk.h>
+#include <libappindicator/app-indicator.h>
+
+#include "psensor.h"
+#include "ui.h"
+#include "ui_appindicator.h"
+#include "ui_pref.h"
+
+static void cb_appindicator_show(gpointer data,
+                                guint cb_action,
+                                GtkWidget *item)
+{
+       struct ui_psensor *ui = (struct ui_psensor *)data;
+
+       gtk_window_present(GTK_WINDOW(ui->main_window));
+}
+
+static void cb_appindicator_quit(gpointer data,
+                                       guint cb_action,
+                                       GtkWidget *item)
+{
+       ui_psensor_exit(data);
+}
+
+static void cb_appindicator_preferences(gpointer data,
+                                       guint cb_action,
+                                       GtkWidget *item)
+{
+#ifdef HAVE_APPINDICATOR_029
+       gdk_threads_enter();
+#endif
+
+       ui_pref_dialog_run((struct ui_psensor *)data);
+
+#ifdef HAVE_APPINDICATOR_029
+       gdk_threads_leave();
+#endif
+}
+
+static GtkItemFactoryEntry menu_items[] = {
+       {"/Show",
+        NULL, cb_appindicator_show, 0, "<Item>"},
+       {"/Preferences",
+        NULL, cb_appindicator_preferences, 0, "<Item>"},
+       {"/sep1",
+        NULL, NULL, 0, "<Separator>"},
+       {"/Quit",
+        "", cb_appindicator_quit, 0, "<StockItem>", GTK_STOCK_QUIT},
+};
+
+static gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
+GtkWidget *ui_appindicator_get_menu(struct ui_psensor *ui)
+{
+       GtkItemFactory *item_factory;
+
+       item_factory = gtk_item_factory_new(GTK_TYPE_MENU, "<main>", NULL);
+
+       gtk_item_factory_create_items(item_factory,
+                                     nmenu_items, menu_items, ui);
+       return gtk_item_factory_get_widget(item_factory, "<main>");
+}
+
+void ui_appindicator_update(struct ui_psensor *ui)
+{
+       struct psensor **sensor_cur = ui->sensors;
+       AppIndicatorStatus status;
+       int attention = 0;
+
+       if (!ui->indicator)
+               return;
+
+       while (*sensor_cur) {
+               struct psensor *s = *sensor_cur;
+
+               if (s->alarm_enabled && s->alarm_raised) {
+                       attention = 1;
+                       break;
+               }
+
+               sensor_cur++;
+       }
+
+       status = app_indicator_get_status(ui->indicator);
+
+       if (!attention && status == APP_INDICATOR_STATUS_ATTENTION)
+               app_indicator_set_status
+                   (ui->indicator, APP_INDICATOR_STATUS_ACTIVE);
+
+       if (attention && status == APP_INDICATOR_STATUS_ACTIVE)
+               app_indicator_set_status
+                   (ui->indicator, APP_INDICATOR_STATUS_ATTENTION);
+}
+
+void ui_appindicator_init(struct ui_psensor *ui)
+{
+       GtkWidget *indicatormenu;
+
+       ui->indicator
+           = app_indicator_new("psensor",
+                               "psensor",
+                               APP_INDICATOR_CATEGORY_APPLICATION_STATUS);
+
+       app_indicator_set_status(ui->indicator, APP_INDICATOR_STATUS_ACTIVE);
+       app_indicator_set_attention_icon(ui->indicator, "psensor_hot");
+
+       indicatormenu = ui_appindicator_get_menu(ui);
+       app_indicator_set_menu(ui->indicator, GTK_MENU(indicatormenu));
+}
diff --git a/src/ui_appindicator.h b/src/ui_appindicator.h
new file mode 100644 (file)
index 0000000..409671b
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#ifndef _PSENSOR_UI_APPINDICATOR_H_
+#define _PSENSOR_UI_APPINDICATOR_H_
+
+#include "ui.h"
+
+void ui_appindicator_init(struct ui_psensor *ui);
+void ui_appindicator_update(struct ui_psensor *ui);
+
+#endif
diff --git a/src/ui_color.c b/src/ui_color.c
new file mode 100644 (file)
index 0000000..fa715a5
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#include <gtk/gtk.h>
+
+#include "ui_color.h"
+
+int ui_change_color(const char *title, struct color *col)
+{
+       GdkColor color;
+       GtkColorSelection *colorsel;
+       int res;
+       GtkColorSelectionDialog *colordlg;
+
+       color.red = col->red;
+       color.green = col->green;
+       color.blue = col->blue;
+
+       colordlg = (GtkColorSelectionDialog *)
+           gtk_color_selection_dialog_new(title);
+
+       colorsel = GTK_COLOR_SELECTION(colordlg->colorsel);
+
+       gtk_color_selection_set_previous_color(colorsel, &color);
+       gtk_color_selection_set_current_color(colorsel, &color);
+
+       res = gtk_dialog_run(GTK_DIALOG(colordlg));
+
+       if (res == GTK_RESPONSE_OK) {
+               gtk_color_selection_get_current_color(colorsel, &color);
+
+               color_set(col, color.red, color.green, color.blue);
+       }
+
+       gtk_widget_destroy(GTK_WIDGET(colordlg));
+
+       return res == GTK_RESPONSE_OK;
+}
diff --git a/src/ui_color.h b/src/ui_color.h
new file mode 100644 (file)
index 0000000..c20a4b5
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#ifndef _PSENSOR_UI_COLOR_H_
+#define _PSENSOR_UI_COLOR_H_
+
+#include "color.h"
+
+/*
+  UI to change a given color.
+
+  Returns 1 if the color has been modified.
+ */
+int ui_change_color(const char *title, struct color *col);
+
+#endif
diff --git a/src/ui_graph.c b/src/ui_graph.c
new file mode 100644 (file)
index 0000000..7c1a2c1
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#include "graph.h"
+#include "ui_graph.h"
+#include "ui_pref.h"
+
+static void
+cb_preferences(gpointer data, guint callback_action, GtkWidget *item)
+{
+       ui_pref_dialog_run((struct ui_psensor *)data);
+}
+
+static GtkItemFactoryEntry menu_items[] = {
+       {N_("/Preferences"),
+        NULL, cb_preferences, 0, "<Item>"},
+
+       {"/sep1",
+        NULL, NULL, 0, "<Separator>"},
+
+       {N_("/Quit"),
+        "", ui_psensor_exit, 0, "<StockItem>", GTK_STOCK_QUIT},
+};
+
+static gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
+
+GtkWidget *ui_graph_create_popupmenu(struct ui_psensor *ui)
+{
+       GtkItemFactory *item_factory;
+
+       item_factory = gtk_item_factory_new(GTK_TYPE_MENU, "<main>", NULL);
+       gtk_item_factory_create_items(item_factory,
+                                     nmenu_items, menu_items, ui);
+       return gtk_item_factory_get_widget(item_factory, "<main>");
+}
+
+int on_graph_clicked(GtkWidget *widget, GdkEventButton *event, gpointer data)
+{
+       GtkWidget *menu;
+
+       if (event->type != GDK_BUTTON_PRESS)
+               return FALSE;
+
+       menu = ui_graph_create_popupmenu((struct ui_psensor *)data);
+
+       gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
+                      event->button, event->time);
+
+       return TRUE;
+}
+
+gboolean
+on_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data)
+{
+       struct ui_psensor *ui_psensor = (struct ui_psensor *)data;
+
+       graph_update(ui_psensor->sensors,
+                    ui_psensor->w_graph, ui_psensor->config);
+
+       return FALSE;
+}
+
+GtkWidget *ui_graph_create(struct ui_psensor * ui)
+{
+       GtkWidget *w_graph;
+
+       w_graph = gtk_drawing_area_new();
+
+       g_signal_connect(G_OBJECT(w_graph),
+                        "expose-event", G_CALLBACK(on_expose_event), ui);
+
+       gtk_widget_add_events(w_graph, GDK_BUTTON_PRESS_MASK);
+       gtk_signal_connect(GTK_OBJECT(w_graph),
+                          "button_press_event",
+                          (GCallback) on_graph_clicked, ui);
+
+       return w_graph;
+}
diff --git a/src/ui_graph.h b/src/ui_graph.h
new file mode 100644 (file)
index 0000000..4df9ef5
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#ifndef _PSENSOR_UI_GRAPH_H_
+#define _PSENSOR_UI_GRAPH_H_
+
+#include <gtk/gtk.h>
+
+#include "ui.h"
+
+GtkWidget *ui_graph_create(struct ui_psensor * ui);
+
+#endif
diff --git a/src/ui_notify.c b/src/ui_notify.c
new file mode 100644 (file)
index 0000000..29d9636
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include <libnotify/notify.h>
+
+#include "ui.h"
+#include "ui_notify.h"
+
+void ui_notify(struct psensor *sensor, struct ui_psensor *ui)
+{
+       struct timeval *t = malloc(sizeof(struct timeval));
+       char *name;
+       NotifyNotification *notif;
+
+       if (gettimeofday(t, NULL) != 0) {
+               fprintf(stderr, _("ERROR: failed gettimeofday\n"));
+               free(t);
+
+               return;
+       }
+
+       if (!ui->notification_last_time) {
+               /* first notification */
+               ui->notification_last_time = t;
+       } else {
+
+               if (t->tv_sec - ui->notification_last_time->tv_sec < 60) {
+                       /* last notification less than 1mn ago */
+                       free(t);
+                       return;
+               } else {
+                       /* last notification more than 1mn ago */
+                       free(ui->notification_last_time);
+                       ui->notification_last_time = t;
+               }
+       }
+
+       if (notify_is_initted() == FALSE)
+               notify_init("psensor");
+
+       if (notify_is_initted() == TRUE) {
+               name = strdup(sensor->name);
+
+#ifdef NOTIFY_VERSION_MAJOR
+               notif = notify_notification_new(_("Temperature alert"),
+                                               name,
+                                               NULL);
+#else
+               notif = notify_notification_new(_("Temperature alert"),
+                                               name,
+                                               NULL,
+                                               GTK_WIDGET(ui->main_window));
+#endif
+
+
+               notify_notification_show(notif, NULL);
+
+               g_object_unref(notif);
+       }
+}
diff --git a/src/ui_notify.h b/src/ui_notify.h
new file mode 100644 (file)
index 0000000..94b37db
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#ifndef _PSENSOR_UI_NOTIFY_H_
+#define _PSENSOR_UI_NOTIFY_H_
+
+#include "psensor.h"
+#include "ui.h"
+
+void ui_notify(struct psensor *sensor, struct ui_psensor *ui);
+
+#endif
diff --git a/src/ui_pref.c b/src/ui_pref.c
new file mode 100644 (file)
index 0000000..809ee20
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "ui.h"
+#include "cfg.h"
+#include "ui_pref.h"
+#include "ui_color.h"
+#include "compat.h"
+
+GdkColor *color_to_gdkcolor(struct color *color)
+{
+       GdkColor *c = malloc(sizeof(GdkColor));
+
+       c->red = color->red;
+       c->green = color->green;
+       c->blue = color->blue;
+
+       return c;
+}
+
+void ui_pref_dialog_run(struct ui_psensor *ui)
+{
+       GtkDialog *diag;
+       gint result;
+       struct config *cfg;
+       GtkBuilder *builder;
+       guint ok;
+       GError *error = NULL;
+       GdkColor *color_fg, *color_bg;
+       GtkColorButton *w_color_fg, *w_color_bg;
+       GtkHScale *w_bg_opacity;
+       GtkSpinButton *w_update_interval, *w_monitoring_duration,
+               *w_s_update_interval;
+       GtkComboBox *w_sensorlist_pos;
+       GtkToggleButton *w_hide_window_decoration, *w_keep_window_below;
+
+       cfg = ui->config;
+
+       builder = gtk_builder_new();
+
+       ok = gtk_builder_add_from_file
+               (builder,
+                PACKAGE_DATA_DIR G_DIR_SEPARATOR_S "psensor-pref.glade",
+                &error);
+
+       if (!ok) {
+               g_warning("%s", error->message);
+               g_free(error);
+               return ;
+       }
+
+       diag = GTK_DIALOG(gtk_builder_get_object(builder, "dialog1"));
+
+       color_fg = color_to_gdkcolor(cfg->graph_fgcolor);
+       w_color_fg = GTK_COLOR_BUTTON(gtk_builder_get_object(builder,
+                                                            "color_fg"));
+       gtk_color_button_set_color(w_color_fg, color_fg);
+
+       color_bg = color_to_gdkcolor(cfg->graph_bgcolor);
+       w_color_bg = GTK_COLOR_BUTTON(gtk_builder_get_object(builder,
+                                                            "color_bg"));
+       gtk_color_button_set_color(w_color_bg, color_bg);
+
+       w_bg_opacity = GTK_HSCALE(gtk_builder_get_object(builder,
+                                                        "bg_opacity"));
+       gtk_range_set_value(GTK_RANGE(w_bg_opacity), cfg->graph_bg_alpha);
+
+       w_update_interval = GTK_SPIN_BUTTON(gtk_builder_get_object
+                                           (builder, "update_interval"));
+       gtk_spin_button_set_value(w_update_interval,
+                                 cfg->graph_update_interval);
+
+       w_s_update_interval
+               = GTK_SPIN_BUTTON(gtk_builder_get_object
+                                 (builder, "sensor_update_interval"));
+       gtk_spin_button_set_value(w_s_update_interval,
+                                 cfg->sensor_update_interval);
+
+       w_monitoring_duration
+               = GTK_SPIN_BUTTON(gtk_builder_get_object
+                                 (builder, "monitoring_duration"));
+       gtk_spin_button_set_value(w_monitoring_duration,
+                                 cfg->graph_monitoring_duration);
+
+       w_sensorlist_pos = GTK_COMBO_BOX
+               (gtk_builder_get_object(builder,
+                                       "sensors_list_position"));
+       gtk_combo_box_set_active(w_sensorlist_pos, cfg->sensorlist_position);
+
+       w_hide_window_decoration = GTK_TOGGLE_BUTTON
+               (gtk_builder_get_object(builder,
+                                       "hide_window_decoration"));
+       gtk_toggle_button_set_active(w_hide_window_decoration,
+                                    !cfg->window_decoration_enabled);
+
+       w_keep_window_below = GTK_TOGGLE_BUTTON
+               (gtk_builder_get_object(builder,
+                                       "keep_window_below"));
+       gtk_toggle_button_set_active(w_keep_window_below,
+                                    cfg->window_keep_below_enabled);
+
+       result = gtk_dialog_run(diag);
+
+       if (result == GTK_RESPONSE_ACCEPT) {
+               double value;
+               GdkColor color;
+
+               g_mutex_lock(ui->sensors_mutex);
+
+               gtk_color_button_get_color(w_color_fg, &color);
+               color_set(cfg->graph_fgcolor,
+                         color.red, color.green, color.blue);
+
+               gtk_color_button_get_color(w_color_bg, &color);
+               color_set(cfg->graph_bgcolor,
+                         color.red, color.green, color.blue);
+
+               value = gtk_range_get_value(GTK_RANGE(w_bg_opacity));
+               cfg->graph_bg_alpha = value;
+
+               if (value == 1.0)
+                       cfg->alpha_channel_enabled = 0;
+               else
+                       cfg->alpha_channel_enabled = 1;
+
+               cfg->sensorlist_position
+                       = gtk_combo_box_get_active(w_sensorlist_pos);
+
+               cfg->window_decoration_enabled =
+                       !gtk_toggle_button_get_active(w_hide_window_decoration);
+
+               cfg->window_keep_below_enabled
+                       = gtk_toggle_button_get_active(w_keep_window_below);
+
+               gtk_window_set_decorated(GTK_WINDOW(ui->main_window),
+                                        cfg->window_decoration_enabled);
+
+               gtk_window_set_keep_below(GTK_WINDOW(ui->main_window),
+                                         cfg->window_keep_below_enabled);
+
+               cfg->sensor_update_interval
+                       = gtk_spin_button_get_value_as_int(w_s_update_interval);
+
+               cfg->graph_update_interval = gtk_spin_button_get_value_as_int
+                       (w_update_interval);
+
+               cfg->graph_monitoring_duration
+                   = gtk_spin_button_get_value_as_int
+                       (w_monitoring_duration);
+
+               cfg->sensor_values_max_length
+                   = (cfg->graph_monitoring_duration * 60) /
+                   cfg->sensor_update_interval;
+
+               config_save(cfg);
+
+               g_mutex_unlock(ui->sensors_mutex);
+
+               ui_main_box_create(ui);
+       }
+       g_object_unref(G_OBJECT(builder));
+       gtk_widget_destroy(GTK_WIDGET(diag));
+}
diff --git a/src/ui_pref.h b/src/ui_pref.h
new file mode 100644 (file)
index 0000000..f3cd95f
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#ifndef _PSENSOR_UI_PREF_H_
+#define _PSENSOR_UI_PREF_H_
+
+#include "ui.h"
+
+void ui_pref_dialog_run(struct ui_psensor *);
+GdkColor *color_to_gdkcolor(struct color *color);
+
+#endif
diff --git a/src/ui_sensorlist.c b/src/ui_sensorlist.c
new file mode 100644 (file)
index 0000000..0bade13
--- /dev/null
@@ -0,0 +1,492 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "ui.h"
+#include "ui_pref.h"
+#include "ui_sensorlist.h"
+#include "cfg.h"
+#include "ui_color.h"
+#include "compat.h"
+
+enum {
+       COL_NAME = 0,
+       COL_TEMP,
+       COL_TEMP_MIN,
+       COL_TEMP_MAX,
+       COL_COLOR,
+       COL_COLOR_STR,
+       COL_ENABLED,
+       COL_EMPTY,
+       COLS_COUNT
+};
+
+struct cb_data {
+       struct ui_sensorlist *ui_sensorlist;
+       struct psensor *sensor;
+};
+
+int col_index_to_col(int idx)
+{
+       if (idx == 5)
+               return COL_ENABLED;
+       else if (idx > 5)
+               return -1;
+
+       return idx;
+}
+
+void ui_sensorlist_update(struct ui_sensorlist *list)
+{
+       GtkTreeIter iter;
+       GtkTreeModel *model
+           = gtk_tree_view_get_model(GTK_TREE_VIEW(list->widget));
+       gboolean valid = gtk_tree_model_get_iter_first(model, &iter);
+       struct psensor **sensor = list->sensors;
+
+       while (valid && *sensor) {
+               struct psensor *s = *sensor;
+
+               char *str;
+
+               str = psensor_value_to_string(s->type,
+                                             s->measures[s->values_max_length -
+                                                         1].value);
+               gtk_list_store_set(GTK_LIST_STORE(model), &iter, COL_TEMP, str,
+                                  -1);
+               free(str);
+
+               str = psensor_value_to_string(s->type, s->min);
+               gtk_list_store_set(GTK_LIST_STORE(model), &iter,
+                                  COL_TEMP_MIN, str, -1);
+               free(str);
+
+               str = psensor_value_to_string(s->type, s->max);
+               gtk_list_store_set(GTK_LIST_STORE(model), &iter,
+                                  COL_TEMP_MAX, str, -1);
+               free(str);
+
+               valid = gtk_tree_model_iter_next(model, &iter);
+               sensor++;
+       }
+}
+
+/*
+ * Returns the sensor corresponding to the x/y position
+ * in the table.
+ *
+ * <null> if none.
+ */
+struct psensor *ui_sensorlist_get_sensor_at_pos(GtkTreeView * view,
+                                               int x,
+                                               int y, struct psensor **sensors)
+{
+       GtkTreePath *path;
+
+       gtk_tree_view_get_path_at_pos(view, x, y, &path, NULL, NULL, NULL);
+
+       if (path) {
+               gint *i = gtk_tree_path_get_indices(path);
+               if (i)
+                       return *(sensors + *i);
+       }
+       return NULL;
+}
+
+/*
+ * Returns the index of the column corresponding
+ * to the x position in the table.
+ *
+ * -1 if none
+ */
+int ui_sensorlist_get_col_index_at_pos(GtkTreeView *view, int x)
+{
+       GList *columns = gtk_tree_view_get_columns(view);
+       GList *node;
+       int colx = 0;
+       int coli = 0;
+
+       for (node = columns; node; node = node->next) {
+               GtkTreeViewColumn *checkcol = (GtkTreeViewColumn *) node->data;
+
+               if (x >= colx && x < (colx + checkcol->width))
+                       return coli;
+               else
+                       colx += checkcol->width;
+
+               coli++;
+       }
+
+       return -1;
+}
+
+void ui_sensorlist_update_sensors_preferences(struct ui_sensorlist *list)
+{
+       GtkTreeIter iter;
+       GtkTreeModel *model
+           = gtk_tree_view_get_model(GTK_TREE_VIEW(list->widget));
+       gboolean valid = gtk_tree_model_get_iter_first(model, &iter);
+       struct psensor **sensor = list->sensors;
+
+       while (valid && *sensor) {
+               GdkColor color;
+               gchar *scolor;
+
+               color.red = (*sensor)->color->red;
+               color.green = (*sensor)->color->green;
+               color.blue = (*sensor)->color->blue;
+
+               scolor = gdk_color_to_string(&color);
+
+               gtk_list_store_set(GTK_LIST_STORE(model),
+                                  &iter, COL_NAME, (*sensor)->name, -1);
+
+               gtk_list_store_set(GTK_LIST_STORE(model),
+                                  &iter, COL_COLOR_STR, scolor, -1);
+
+               gtk_list_store_set(GTK_LIST_STORE(model),
+                                  &iter, COL_ENABLED, (*sensor)->enabled, -1);
+
+               free(scolor);
+
+               valid = gtk_tree_model_iter_next(model, &iter);
+               sensor++;
+       }
+}
+
+static void cb_sensor_settings_activated(GtkWidget *menu_item, gpointer data)
+{
+       struct cb_data *cb_data = data;
+       struct psensor *sensor = cb_data->sensor;
+       GtkDialog *diag;
+       gint result;
+       GtkBuilder *builder;
+       GError *error = NULL;
+       GtkLabel *w_id, *w_type;
+       GtkEntry *w_name;
+       GtkToggleButton *w_draw, *w_alarm;
+       GtkColorButton *w_color;
+       GtkSpinButton *w_temp_limit;
+       GdkColor *color;
+       guint ok;
+
+       builder = gtk_builder_new();
+
+       ok = gtk_builder_add_from_file
+               (builder,
+                PACKAGE_DATA_DIR G_DIR_SEPARATOR_S "sensor-edit.glade",
+                &error);
+
+       if (!ok) {
+               g_warning("%s", error->message);
+               g_free(error);
+               return ;
+       }
+
+       w_id = GTK_LABEL(gtk_builder_get_object(builder, "sensor_id"));
+       gtk_label_set_text(w_id, sensor->id);
+
+       w_type = GTK_LABEL(gtk_builder_get_object(builder, "sensor_type"));
+       gtk_label_set_text(w_type, psensor_type_to_str(sensor->type));
+
+       w_name = GTK_ENTRY(gtk_builder_get_object(builder, "sensor_name"));
+       gtk_entry_set_text(w_name, sensor->name);
+
+       w_draw = GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder,
+                                                         "sensor_draw"));
+       gtk_toggle_button_set_active(w_draw, sensor->enabled);
+
+       color = color_to_gdkcolor(sensor->color);
+       w_color = GTK_COLOR_BUTTON(gtk_builder_get_object(builder,
+                                                         "sensor_color"));
+       gtk_color_button_set_color(w_color, color);
+
+       w_alarm = GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder,
+                                                          "sensor_alarm"));
+       w_temp_limit
+               = GTK_SPIN_BUTTON(gtk_builder_get_object(builder,
+                                                        "sensor_temp_limit"));
+
+       if (is_temp_type(sensor->type)) {
+               gtk_toggle_button_set_active(w_alarm, sensor->alarm_enabled);
+               gtk_spin_button_set_value(w_temp_limit, sensor->alarm_limit);
+       } else {
+               gtk_widget_set_sensitive(GTK_WIDGET(w_alarm), FALSE);
+               gtk_widget_set_sensitive(GTK_WIDGET(w_temp_limit), FALSE);
+       }
+
+       diag = GTK_DIALOG(gtk_builder_get_object(builder, "dialog1"));
+       result = gtk_dialog_run(diag);
+
+       if (result == GTK_RESPONSE_ACCEPT) {
+
+               free(sensor->name);
+               sensor->name = strdup(gtk_entry_get_text(w_name));
+               config_set_sensor_name(sensor->id, sensor->name);
+
+               sensor->enabled = gtk_toggle_button_get_active(w_draw);
+               config_set_sensor_enabled(sensor->id, sensor->enabled);
+
+               sensor->alarm_limit = gtk_spin_button_get_value(w_temp_limit);
+               config_set_sensor_alarm_limit(sensor->id, sensor->alarm_limit);
+
+               sensor->alarm_enabled = gtk_toggle_button_get_active(w_alarm);
+               config_set_sensor_alarm_enabled(sensor->id,
+                                               sensor->alarm_enabled);
+
+               gtk_color_button_get_color(w_color, color);
+               color_set(sensor->color, color->red, color->green, color->blue);
+               config_set_sensor_color(sensor->id, sensor->color);
+
+               ui_sensorlist_update_sensors_preferences
+                   (cb_data->ui_sensorlist);
+       }
+
+       g_object_unref(G_OBJECT(builder));
+
+       gtk_widget_destroy(GTK_WIDGET(diag));
+}
+
+GtkWidget *create_sensor_popup(struct ui_sensorlist *ui_sensorlist,
+                              struct psensor *sensor)
+{
+       GtkWidget *menu;
+       GtkWidget *item;
+       GtkWidget *separator;
+       struct cb_data *data;
+
+       menu = gtk_menu_new();
+
+       item = gtk_menu_item_new_with_label(sensor->name);
+       gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+
+       separator = gtk_separator_menu_item_new();
+       gtk_menu_shell_append(GTK_MENU_SHELL(menu), separator);
+
+       item = gtk_menu_item_new_with_label(_("Preferences"));
+       gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+
+       data = malloc(sizeof(struct cb_data));
+       data->ui_sensorlist = ui_sensorlist;
+       data->sensor = sensor;
+
+       g_signal_connect(item,
+                        "activate",
+                        G_CALLBACK(cb_sensor_settings_activated), data);
+
+       gtk_widget_show_all(menu);
+
+       return menu;
+}
+
+int
+cb_sensor_line_clicked(GtkWidget *widget,
+                      GdkEventButton *event, gpointer data)
+{
+       struct ui_sensorlist *list = (struct ui_sensorlist *)data;
+       GtkTreeView *view = GTK_TREE_VIEW(list->widget);
+
+       struct psensor *sensor = ui_sensorlist_get_sensor_at_pos(view,
+                                                                event->x,
+                                                                event->y,
+                                                                list->sensors);
+
+       if (sensor) {
+               int coli = col_index_to_col(ui_sensorlist_get_col_index_at_pos
+                                           (view, event->x));
+
+               if (coli == COL_COLOR) {
+                       if (ui_change_color(_("Select foreground color"),
+                                           sensor->color)) {
+                               ui_sensorlist_update_sensors_preferences(list);
+                               config_set_sensor_color(sensor->id,
+                                                       sensor->color);
+                       }
+               } else if (coli >= 0 && coli != COL_ENABLED) {
+                       GtkWidget *menu = create_sensor_popup(list,
+                                                             sensor);
+
+                       gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
+                                      event->button, event->time);
+
+               }
+
+       }
+       return FALSE;
+}
+
+void
+ui_sensorlist_on_toggled(GtkCellRendererToggle *cell,
+                        gchar *path_str, gpointer data)
+{
+       struct ui_sensorlist *list = (struct ui_sensorlist *)data;
+       GtkTreeModel *model
+           = gtk_tree_view_get_model(GTK_TREE_VIEW(list->widget));
+       GtkTreeIter iter;
+       GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
+       gboolean fixed;
+       gint *i;
+
+       gtk_tree_model_get_iter(model, &iter, path);
+       gtk_tree_model_get(model, &iter, COL_ENABLED, &fixed, -1);
+
+       fixed ^= 1;
+
+       i = gtk_tree_path_get_indices(path);
+       if (i) {
+               int n = *i;
+               struct psensor **sensor = list->sensors;
+               while (n--)
+                       sensor++;
+               (*sensor)->enabled = fixed;
+               config_set_sensor_enabled((*sensor)->id, (*sensor)->enabled);
+       }
+
+       gtk_list_store_set(GTK_LIST_STORE(model),
+                          &iter, COL_ENABLED, fixed, -1);
+
+       gtk_tree_path_free(path);
+}
+
+void ui_sensorlist_create_widget(struct ui_sensorlist *ui)
+{
+       GtkListStore *store;
+       GtkCellRenderer *renderer;
+       struct psensor **sensor_cur;
+       struct psensor **sensors;
+
+       sensors = ui->sensors;
+
+       store = gtk_list_store_new(COLS_COUNT,
+                                  G_TYPE_STRING,
+                                  G_TYPE_STRING,
+                                  G_TYPE_STRING,
+                                  G_TYPE_STRING,
+                                  G_TYPE_STRING,
+                                  G_TYPE_STRING,
+                                  G_TYPE_BOOLEAN, G_TYPE_STRING);
+
+       if (ui->widget)
+               gtk_widget_destroy(ui->widget);
+
+       ui->widget =
+           GTK_WIDGET(gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)));
+
+       gtk_tree_selection_set_mode(gtk_tree_view_get_selection
+                                   (GTK_TREE_VIEW(ui->widget)),
+                                   GTK_SELECTION_NONE);
+
+       renderer = gtk_cell_renderer_text_new();
+       gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(ui->widget),
+                                                   -1,
+                                                   _("Sensor"),
+                                                   renderer,
+                                                   "text", COL_NAME, NULL);
+
+       gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(ui->widget),
+                                                   -1,
+                                                   _("Current"),
+                                                   renderer,
+                                                   "text", COL_TEMP, NULL);
+
+       gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(ui->widget),
+                                                   -1,
+                                                   _("Min"),
+                                                   renderer,
+                                                   "text", COL_TEMP_MIN, NULL);
+
+       gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(ui->widget),
+                                                   -1,
+                                                   _("Max"),
+                                                   renderer,
+                                                   "text", COL_TEMP_MAX, NULL);
+
+       renderer = gtk_cell_renderer_text_new();
+       gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(ui->widget),
+                                                   -1,
+                                                   _("Color"),
+                                                   renderer,
+                                                   "text", COL_COLOR,
+                                                   "background", COL_COLOR_STR,
+                                                   NULL);
+
+       g_signal_connect(ui->widget,
+                        "button-press-event",
+                        (GCallback) cb_sensor_line_clicked, ui);
+
+       renderer = gtk_cell_renderer_toggle_new();
+       gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(ui->widget),
+                                                   -1,
+                                                   _("Enabled"),
+                                                   renderer,
+                                                   "active", COL_ENABLED,
+                                                   NULL);
+       g_signal_connect(G_OBJECT(renderer), "toggled",
+                        (GCallback) ui_sensorlist_on_toggled, ui);
+
+       renderer = gtk_cell_renderer_text_new();
+       gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(ui->widget),
+                                                   -1,
+                                                   "",
+                                                   renderer,
+                                                   "text", COL_EMPTY, NULL);
+
+       sensor_cur = sensors;
+       while (*sensor_cur) {
+               GtkTreeIter iter;
+               GdkColor color;
+               gchar *scolor;
+
+               color.red = (*sensor_cur)->color->red;
+               color.green = (*sensor_cur)->color->green;
+               color.blue = (*sensor_cur)->color->blue;
+
+               scolor = gdk_color_to_string(&color);
+
+               gtk_list_store_append(store, &iter);
+               gtk_list_store_set(store, &iter,
+                                  COL_NAME, (*sensor_cur)->name,
+                                  COL_TEMP, _("N/A"),
+                                  COL_TEMP_MIN, _("N/A"),
+                                  COL_TEMP_MAX, _("N/A"),
+                                  COL_COLOR_STR, scolor,
+                                  COL_ENABLED, (*sensor_cur)->enabled, -1);
+
+               free(scolor);
+
+               sensor_cur++;
+       }
+}
+
+struct ui_sensorlist *ui_sensorlist_create(struct psensor **sensors)
+{
+       struct ui_sensorlist *list;
+
+       list = malloc(sizeof(struct ui_sensorlist));
+       list->sensors = sensors;
+       list->widget = NULL;
+
+       ui_sensorlist_create_widget(list);
+
+       return list;
+
+}
diff --git a/src/ui_sensorlist.h b/src/ui_sensorlist.h
new file mode 100644 (file)
index 0000000..421550e
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#ifndef _PSENSOR_UI_SENSORLIST_H_
+#define _PSENSOR_UI_SENSORLIST_H_
+
+#include <gtk/gtk.h>
+
+#include "psensor.h"
+
+struct ui_sensorlist {
+       GtkWidget *widget;
+
+       struct psensor **sensors;
+};
+
+struct ui_sensorlist *ui_sensorlist_create(struct psensor **);
+
+/* Update values current/min/max */
+void ui_sensorlist_update(struct ui_sensorlist *list);
+
+void ui_sensorlist_update_sensors_preferences(struct ui_sensorlist *);
+
+void ui_sensorlist_create_widget(struct ui_sensorlist *ui);
+
+#endif
diff --git a/src/unity/Makefile.am b/src/unity/Makefile.am
new file mode 100644 (file)
index 0000000..2e7c8ea
--- /dev/null
@@ -0,0 +1,14 @@
+if UNITY
+noinst_LIBRARIES = libpsensor_unity.a
+
+# no -pedantic because not supported by dee.h
+libpsensor_unity_a_CFLAGS = -Wall -Werror
+
+libpsensor_unity_a_SOURCES = \
+       ui_unity.h ui_unity.c
+
+AM_CPPFLAGS = $(UNITY_CFLAGS) \
+       -I$(top_srcdir)/src/lib
+
+LIBS += $(UNITY_LIBS)
+endif
\ No newline at end of file
diff --git a/src/unity/ui_unity.c b/src/unity/ui_unity.c
new file mode 100644 (file)
index 0000000..aff0b7a
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#include <unity.h>
+
+#include "psensor.h"
+
+static int initialized;
+static UnityLauncherEntry *psensor_entry;
+
+void ui_unity_launcher_entry_update(struct psensor **sensors)
+{
+       if (!initialized) {
+               psensor_entry = unity_launcher_entry_get_for_desktop_file
+                       ("psensor.desktop");
+               unity_launcher_entry_set_count_visible(psensor_entry, TRUE);
+               unity_launcher_entry_set_count(psensor_entry, 0);
+               initialized = 1;
+       }
+
+       if (sensors && *sensors) {
+               struct psensor *s = *sensors;
+               double v = psensor_get_current_value(s);
+
+               unity_launcher_entry_set_count(psensor_entry, v);
+       }
+}
diff --git a/src/unity/ui_unity.h b/src/unity/ui_unity.h
new file mode 100644 (file)
index 0000000..f4ddddc
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+    Copyright (C) 2010-2011 wpitchoune@gmail.com
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA
+*/
+
+#ifndef _PSENSOR_UI_UNITY_H_
+#define _PSENSOR_UI_UNITY_H_
+
+#include "psensor.h"
+
+void ui_unity_launcher_entry_update(struct psensor **sensors);
+
+#endif
diff --git a/tests/Makefile.am b/tests/Makefile.am
new file mode 100644 (file)
index 0000000..1acf104
--- /dev/null
@@ -0,0 +1,5 @@
+check-local: checkpatch.pl
+       find $(top_srcdir)/src -name \*.c -exec $(srcdir)/checkpatch.pl -q --no-tree  -emacs -f {} \;
+       find $(top_srcdir)/src -name \*.h -exec $(srcdir)/checkpatch.pl -q --no-tree  -emacs -f {} \;
+
+EXTRA_DIST = checkpatch.pl 
\ No newline at end of file
diff --git a/tests/checkpatch.pl b/tests/checkpatch.pl
new file mode 100755 (executable)
index 0000000..0b0defa
--- /dev/null
@@ -0,0 +1,2823 @@
+#!/usr/bin/perl -w
+
+# This script has been copied from Linux Kernel sources.
+#
+# (c) 2001, Dave Jones. (the file handling bit)
+# (c) 2005, Joel Schopp <jschopp@austin.ibm.com> (the ugly bit)
+# (c) 2007,2008, Andy Whitcroft <apw@uk.ibm.com> (new conditions, test suite)
+# (c) 2008,2009, Andy Whitcroft <apw@canonical.com>
+# Licensed under the terms of the GNU GPL License version 2
+
+use strict;
+
+my $P = $0;
+$P =~ s@.*/@@g;
+
+my $V = '0.30';
+
+use Getopt::Long qw(:config no_auto_abbrev);
+
+my $quiet = 0;
+my $tree = 1;
+my $chk_signoff = 1;
+my $chk_patch = 1;
+my $tst_only;
+my $emacs = 0;
+my $terse = 0;
+my $file = 0;
+my $check = 0;
+my $summary = 1;
+my $mailback = 0;
+my $summary_file = 0;
+my $root;
+my %debug;
+my $help = 0;
+
+sub help {
+       my ($exitcode) = @_;
+
+       print << "EOM";
+Usage: $P [OPTION]... [FILE]...
+Version: $V
+
+Options:
+  -q, --quiet                quiet
+  --no-tree                  run without a kernel tree
+  --no-signoff               do not check for 'Signed-off-by' line
+  --patch                    treat FILE as patchfile (default)
+  --emacs                    emacs compile window format
+  --terse                    one line per report
+  -f, --file                 treat FILE as regular source file
+  --subjective, --strict     enable more subjective tests
+  --root=PATH                PATH to the kernel tree root
+  --no-summary               suppress the per-file summary
+  --mailback                 only produce a report in case of warnings/errors
+  --summary-file             include the filename in summary
+  --debug KEY=[0|1]          turn on/off debugging of KEY, where KEY is one of
+                             'values', 'possible', 'type', and 'attr' (default
+                             is all off)
+  --test-only=WORD           report only warnings/errors containing WORD
+                             literally
+  -h, --help, --version      display this help and exit
+
+When FILE is - read standard input.
+EOM
+
+       exit($exitcode);
+}
+
+GetOptions(
+       'q|quiet+'      => \$quiet,
+       'tree!'         => \$tree,
+       'signoff!'      => \$chk_signoff,
+       'patch!'        => \$chk_patch,
+       'emacs!'        => \$emacs,
+       'terse!'        => \$terse,
+       'f|file!'       => \$file,
+       'subjective!'   => \$check,
+       'strict!'       => \$check,
+       'root=s'        => \$root,
+       'summary!'      => \$summary,
+       'mailback!'     => \$mailback,
+       'summary-file!' => \$summary_file,
+
+       'debug=s'       => \%debug,
+       'test-only=s'   => \$tst_only,
+       'h|help'        => \$help,
+       'version'       => \$help
+) or help(1);
+
+help(0) if ($help);
+
+my $exit = 0;
+
+if ($#ARGV < 0) {
+       print "$P: no input files\n";
+       exit(1);
+}
+
+my $dbg_values = 0;
+my $dbg_possible = 0;
+my $dbg_type = 0;
+my $dbg_attr = 0;
+for my $key (keys %debug) {
+       ## no critic
+       eval "\${dbg_$key} = '$debug{$key}';";
+       die "$@" if ($@);
+}
+
+if ($terse) {
+       $emacs = 1;
+       $quiet++;
+}
+
+if ($tree) {
+       if (defined $root) {
+               if (!top_of_kernel_tree($root)) {
+                       die "$P: $root: --root does not point at a valid tree\n";
+               }
+       } else {
+               if (top_of_kernel_tree('.')) {
+                       $root = '.';
+               } elsif ($0 =~ m@(.*)/scripts/[^/]*$@ &&
+                                               top_of_kernel_tree($1)) {
+                       $root = $1;
+               }
+       }
+
+       if (!defined $root) {
+               print "Must be run from the top-level dir. of a kernel tree\n";
+               exit(2);
+       }
+}
+
+my $emitted_corrupt = 0;
+
+our $Ident     = qr{
+                       [A-Za-z_][A-Za-z\d_]*
+                       (?:\s*\#\#\s*[A-Za-z_][A-Za-z\d_]*)*
+               }x;
+our $Storage   = qr{extern|static|asmlinkage};
+our $Sparse    = qr{
+                       __user|
+                       __kernel|
+                       __force|
+                       __iomem|
+                       __must_check|
+                       __init_refok|
+                       __kprobes|
+                       __ref
+               }x;
+
+# Notes to $Attribute:
+# We need \b after 'init' otherwise 'initconst' will cause a false positive in a check
+our $Attribute = qr{
+                       const|
+                       __read_mostly|
+                       __kprobes|
+                       __(?:mem|cpu|dev|)(?:initdata|initconst|init\b)|
+                       ____cacheline_aligned|
+                       ____cacheline_aligned_in_smp|
+                       ____cacheline_internodealigned_in_smp|
+                       __weak
+                 }x;
+our $Modifier;
+our $Inline    = qr{inline|__always_inline|noinline};
+our $Member    = qr{->$Ident|\.$Ident|\[[^]]*\]};
+our $Lval      = qr{$Ident(?:$Member)*};
+
+our $Constant  = qr{(?:[0-9]+|0x[0-9a-fA-F]+)[UL]*};
+our $Assignment        = qr{(?:\*\=|/=|%=|\+=|-=|<<=|>>=|&=|\^=|\|=|=)};
+our $Compare    = qr{<=|>=|==|!=|<|>};
+our $Operators = qr{
+                       <=|>=|==|!=|
+                       =>|->|<<|>>|<|>|!|~|
+                       &&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|%
+                 }x;
+
+our $NonptrType;
+our $Type;
+our $Declare;
+
+our $UTF8      = qr {
+       [\x09\x0A\x0D\x20-\x7E]              # ASCII
+       | [\xC2-\xDF][\x80-\xBF]             # non-overlong 2-byte
+       |  \xE0[\xA0-\xBF][\x80-\xBF]        # excluding overlongs
+       | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}  # straight 3-byte
+       |  \xED[\x80-\x9F][\x80-\xBF]        # excluding surrogates
+       |  \xF0[\x90-\xBF][\x80-\xBF]{2}     # planes 1-3
+       | [\xF1-\xF3][\x80-\xBF]{3}          # planes 4-15
+       |  \xF4[\x80-\x8F][\x80-\xBF]{2}     # plane 16
+}x;
+
+our $typeTypedefs = qr{(?x:
+       (?:__)?(?:u|s|be|le)(?:8|16|32|64)|
+       atomic_t
+)};
+
+our $logFunctions = qr{(?x:
+       printk|
+       pr_(debug|dbg|vdbg|devel|info|warning|err|notice|alert|crit|emerg|cont)|
+       dev_(printk|dbg|vdbg|info|warn|err|notice|alert|crit|emerg|WARN)|
+       WARN|
+       panic
+)};
+
+our @typeList = (
+       qr{void},
+       qr{(?:unsigned\s+)?char},
+       qr{(?:unsigned\s+)?short},
+       qr{(?:unsigned\s+)?int},
+       qr{(?:unsigned\s+)?long},
+       qr{(?:unsigned\s+)?long\s+int},
+       qr{(?:unsigned\s+)?long\s+long},
+       qr{(?:unsigned\s+)?long\s+long\s+int},
+       qr{unsigned},
+       qr{float},
+       qr{double},
+       qr{bool},
+       qr{struct\s+$Ident},
+       qr{union\s+$Ident},
+       qr{enum\s+$Ident},
+       qr{${Ident}_t},
+       qr{${Ident}_handler},
+       qr{${Ident}_handler_fn},
+);
+our @modifierList = (
+       qr{fastcall},
+);
+
+sub build_types {
+       my $mods = "(?x:  \n" . join("|\n  ", @modifierList) . "\n)";
+       my $all = "(?x:  \n" . join("|\n  ", @typeList) . "\n)";
+       $Modifier       = qr{(?:$Attribute|$Sparse|$mods)};
+       $NonptrType     = qr{
+                       (?:$Modifier\s+|const\s+)*
+                       (?:
+                               (?:typeof|__typeof__)\s*\(\s*\**\s*$Ident\s*\)|
+                               (?:$typeTypedefs\b)|
+                               (?:${all}\b)
+                       )
+                       (?:\s+$Modifier|\s+const)*
+                 }x;
+       $Type   = qr{
+                       $NonptrType
+                       (?:[\s\*]+\s*const|[\s\*]+|(?:\s*\[\s*\])+)?
+                       (?:\s+$Inline|\s+$Modifier)*
+                 }x;
+       $Declare        = qr{(?:$Storage\s+)?$Type};
+}
+build_types();
+
+$chk_signoff = 0 if ($file);
+
+my @dep_includes = ();
+my @dep_functions = ();
+my $removal = "Documentation/feature-removal-schedule.txt";
+if ($tree && -f "$root/$removal") {
+       open(my $REMOVE, '<', "$root/$removal") ||
+                               die "$P: $removal: open failed - $!\n";
+       while (<$REMOVE>) {
+               if (/^Check:\s+(.*\S)/) {
+                       for my $entry (split(/[, ]+/, $1)) {
+                               if ($entry =~ m@include/(.*)@) {
+                                       push(@dep_includes, $1);
+
+                               } elsif ($entry !~ m@/@) {
+                                       push(@dep_functions, $entry);
+                               }
+                       }
+               }
+       }
+       close($REMOVE);
+}
+
+my @rawlines = ();
+my @lines = ();
+my $vname;
+for my $filename (@ARGV) {
+       my $FILE;
+       if ($file) {
+               open($FILE, '-|', "diff -u /dev/null $filename") ||
+                       die "$P: $filename: diff failed - $!\n";
+       } elsif ($filename eq '-') {
+               open($FILE, '<&STDIN');
+       } else {
+               open($FILE, '<', "$filename") ||
+                       die "$P: $filename: open failed - $!\n";
+       }
+       if ($filename eq '-') {
+               $vname = 'Your patch';
+       } else {
+               $vname = $filename;
+       }
+       while (<$FILE>) {
+               chomp;
+               push(@rawlines, $_);
+       }
+       close($FILE);
+       if (!process($filename)) {
+               $exit = 1;
+       }
+       @rawlines = ();
+       @lines = ();
+}
+
+exit($exit);
+
+sub top_of_kernel_tree {
+       my ($root) = @_;
+
+       my @tree_check = (
+               "COPYING", "CREDITS", "Kbuild", "MAINTAINERS", "Makefile",
+               "README", "Documentation", "arch", "include", "drivers",
+               "fs", "init", "ipc", "kernel", "lib", "scripts",
+       );
+
+       foreach my $check (@tree_check) {
+               if (! -e $root . '/' . $check) {
+                       return 0;
+               }
+       }
+       return 1;
+}
+
+sub expand_tabs {
+       my ($str) = @_;
+
+       my $res = '';
+       my $n = 0;
+       for my $c (split(//, $str)) {
+               if ($c eq "\t") {
+                       $res .= ' ';
+                       $n++;
+                       for (; ($n % 8) != 0; $n++) {
+                               $res .= ' ';
+                       }
+                       next;
+               }
+               $res .= $c;
+               $n++;
+       }
+
+       return $res;
+}
+sub copy_spacing {
+       (my $res = shift) =~ tr/\t/ /c;
+       return $res;
+}
+
+sub line_stats {
+       my ($line) = @_;
+
+       # Drop the diff line leader and expand tabs
+       $line =~ s/^.//;
+       $line = expand_tabs($line);
+
+       # Pick the indent from the front of the line.
+       my ($white) = ($line =~ /^(\s*)/);
+
+       return (length($line), length($white));
+}
+
+my $sanitise_quote = '';
+
+sub sanitise_line_reset {
+       my ($in_comment) = @_;
+
+       if ($in_comment) {
+               $sanitise_quote = '*/';
+       } else {
+               $sanitise_quote = '';
+       }
+}
+sub sanitise_line {
+       my ($line) = @_;
+
+       my $res = '';
+       my $l = '';
+
+       my $qlen = 0;
+       my $off = 0;
+       my $c;
+
+       # Always copy over the diff marker.
+       $res = substr($line, 0, 1);
+
+       for ($off = 1; $off < length($line); $off++) {
+               $c = substr($line, $off, 1);
+
+               # Comments we are wacking completly including the begin
+               # and end, all to $;.
+               if ($sanitise_quote eq '' && substr($line, $off, 2) eq '/*') {
+                       $sanitise_quote = '*/';
+
+                       substr($res, $off, 2, "$;$;");
+                       $off++;
+                       next;
+               }
+               if ($sanitise_quote eq '*/' && substr($line, $off, 2) eq '*/') {
+                       $sanitise_quote = '';
+                       substr($res, $off, 2, "$;$;");
+                       $off++;
+                       next;
+               }
+               if ($sanitise_quote eq '' && substr($line, $off, 2) eq '//') {
+                       $sanitise_quote = '//';
+
+                       substr($res, $off, 2, $sanitise_quote);
+                       $off++;
+                       next;
+               }
+
+               # A \ in a string means ignore the next character.
+               if (($sanitise_quote eq "'" || $sanitise_quote eq '"') &&
+                   $c eq "\\") {
+                       substr($res, $off, 2, 'XX');
+                       $off++;
+                       next;
+               }
+               # Regular quotes.
+               if ($c eq "'" || $c eq '"') {
+                       if ($sanitise_quote eq '') {
+                               $sanitise_quote = $c;
+
+                               substr($res, $off, 1, $c);
+                               next;
+                       } elsif ($sanitise_quote eq $c) {
+                               $sanitise_quote = '';
+                       }
+               }
+
+               #print "c<$c> SQ<$sanitise_quote>\n";
+               if ($off != 0 && $sanitise_quote eq '*/' && $c ne "\t") {
+                       substr($res, $off, 1, $;);
+               } elsif ($off != 0 && $sanitise_quote eq '//' && $c ne "\t") {
+                       substr($res, $off, 1, $;);
+               } elsif ($off != 0 && $sanitise_quote && $c ne "\t") {
+                       substr($res, $off, 1, 'X');
+               } else {
+                       substr($res, $off, 1, $c);
+               }
+       }
+
+       if ($sanitise_quote eq '//') {
+               $sanitise_quote = '';
+       }
+
+       # The pathname on a #include may be surrounded by '<' and '>'.
+       if ($res =~ /^.\s*\#\s*include\s+\<(.*)\>/) {
+               my $clean = 'X' x length($1);
+               $res =~ s@\<.*\>@<$clean>@;
+
+       # The whole of a #error is a string.
+       } elsif ($res =~ /^.\s*\#\s*(?:error|warning)\s+(.*)\b/) {
+               my $clean = 'X' x length($1);
+               $res =~ s@(\#\s*(?:error|warning)\s+).*@$1$clean@;
+       }
+
+       return $res;
+}
+
+sub ctx_statement_block {
+       my ($linenr, $remain, $off) = @_;
+       my $line = $linenr - 1;
+       my $blk = '';
+       my $soff = $off;
+       my $coff = $off - 1;
+       my $coff_set = 0;
+
+       my $loff = 0;
+
+       my $type = '';
+       my $level = 0;
+       my @stack = ();
+       my $p;
+       my $c;
+       my $len = 0;
+
+       my $remainder;
+       while (1) {
+               @stack = (['', 0]) if ($#stack == -1);
+
+               #warn "CSB: blk<$blk> remain<$remain>\n";
+               # If we are about to drop off the end, pull in more
+               # context.
+               if ($off >= $len) {
+                       for (; $remain > 0; $line++) {
+                               last if (!defined $lines[$line]);
+                               next if ($lines[$line] =~ /^-/);
+                               $remain--;
+                               $loff = $len;
+                               $blk .= $lines[$line] . "\n";
+                               $len = length($blk);
+                               $line++;
+                               last;
+                       }
+                       # Bail if there is no further context.
+                       #warn "CSB: blk<$blk> off<$off> len<$len>\n";
+                       if ($off >= $len) {
+                               last;
+                       }
+               }
+               $p = $c;
+               $c = substr($blk, $off, 1);
+               $remainder = substr($blk, $off);
+
+               #warn "CSB: c<$c> type<$type> level<$level> remainder<$remainder> coff_set<$coff_set>\n";
+
+               # Handle nested #if/#else.
+               if ($remainder =~ /^#\s*(?:ifndef|ifdef|if)\s/) {
+                       push(@stack, [ $type, $level ]);
+               } elsif ($remainder =~ /^#\s*(?:else|elif)\b/) {
+                       ($type, $level) = @{$stack[$#stack - 1]};
+               } elsif ($remainder =~ /^#\s*endif\b/) {
+                       ($type, $level) = @{pop(@stack)};
+               }
+
+               # Statement ends at the ';' or a close '}' at the
+               # outermost level.
+               if ($level == 0 && $c eq ';') {
+                       last;
+               }
+
+               # An else is really a conditional as long as its not else if
+               if ($level == 0 && $coff_set == 0 &&
+                               (!defined($p) || $p =~ /(?:\s|\}|\+)/) &&
+                               $remainder =~ /^(else)(?:\s|{)/ &&
+                               $remainder !~ /^else\s+if\b/) {
+                       $coff = $off + length($1) - 1;
+                       $coff_set = 1;
+                       #warn "CSB: mark coff<$coff> soff<$soff> 1<$1>\n";
+                       #warn "[" . substr($blk, $soff, $coff - $soff + 1) . "]\n";
+               }
+
+               if (($type eq '' || $type eq '(') && $c eq '(') {
+                       $level++;
+                       $type = '(';
+               }
+               if ($type eq '(' && $c eq ')') {
+                       $level--;
+                       $type = ($level != 0)? '(' : '';
+
+                       if ($level == 0 && $coff < $soff) {
+                               $coff = $off;
+                               $coff_set = 1;
+                               #warn "CSB: mark coff<$coff>\n";
+                       }
+               }
+               if (($type eq '' || $type eq '{') && $c eq '{') {
+                       $level++;
+                       $type = '{';
+               }
+               if ($type eq '{' && $c eq '}') {
+                       $level--;
+                       $type = ($level != 0)? '{' : '';
+
+                       if ($level == 0) {
+                               last;
+                       }
+               }
+               $off++;
+       }
+       # We are truly at the end, so shuffle to the next line.
+       if ($off == $len) {
+               $loff = $len + 1;
+               $line++;
+               $remain--;
+       }
+
+       my $statement = substr($blk, $soff, $off - $soff + 1);
+       my $condition = substr($blk, $soff, $coff - $soff + 1);
+
+       #warn "STATEMENT<$statement>\n";
+       #warn "CONDITION<$condition>\n";
+
+       #print "coff<$coff> soff<$off> loff<$loff>\n";
+
+       return ($statement, $condition,
+                       $line, $remain + 1, $off - $loff + 1, $level);
+}
+
+sub statement_lines {
+       my ($stmt) = @_;
+
+       # Strip the diff line prefixes and rip blank lines at start and end.
+       $stmt =~ s/(^|\n)./$1/g;
+       $stmt =~ s/^\s*//;
+       $stmt =~ s/\s*$//;
+
+       my @stmt_lines = ($stmt =~ /\n/g);
+
+       return $#stmt_lines + 2;
+}
+
+sub statement_rawlines {
+       my ($stmt) = @_;
+
+       my @stmt_lines = ($stmt =~ /\n/g);
+
+       return $#stmt_lines + 2;
+}
+
+sub statement_block_size {
+       my ($stmt) = @_;
+
+       $stmt =~ s/(^|\n)./$1/g;
+       $stmt =~ s/^\s*{//;
+       $stmt =~ s/}\s*$//;
+       $stmt =~ s/^\s*//;
+       $stmt =~ s/\s*$//;
+
+       my @stmt_lines = ($stmt =~ /\n/g);
+       my @stmt_statements = ($stmt =~ /;/g);
+
+       my $stmt_lines = $#stmt_lines + 2;
+       my $stmt_statements = $#stmt_statements + 1;
+
+       if ($stmt_lines > $stmt_statements) {
+               return $stmt_lines;
+       } else {
+               return $stmt_statements;
+       }
+}
+
+sub ctx_statement_full {
+       my ($linenr, $remain, $off) = @_;
+       my ($statement, $condition, $level);
+
+       my (@chunks);
+
+       # Grab the first conditional/block pair.
+       ($statement, $condition, $linenr, $remain, $off, $level) =
+                               ctx_statement_block($linenr, $remain, $off);
+       #print "F: c<$condition> s<$statement> remain<$remain>\n";
+       push(@chunks, [ $condition, $statement ]);
+       if (!($remain > 0 && $condition =~ /^\s*(?:\n[+-])?\s*(?:if|else|do)\b/s)) {
+               return ($level, $linenr, @chunks);
+       }
+
+       # Pull in the following conditional/block pairs and see if they
+       # could continue the statement.
+       for (;;) {
+               ($statement, $condition, $linenr, $remain, $off, $level) =
+                               ctx_statement_block($linenr, $remain, $off);
+               #print "C: c<$condition> s<$statement> remain<$remain>\n";
+               last if (!($remain > 0 && $condition =~ /^(?:\s*\n[+-])*\s*(?:else|do)\b/s));
+               #print "C: push\n";
+               push(@chunks, [ $condition, $statement ]);
+       }
+
+       return ($level, $linenr, @chunks);
+}
+
+sub ctx_block_get {
+       my ($linenr, $remain, $outer, $open, $close, $off) = @_;
+       my $line;
+       my $start = $linenr - 1;
+       my $blk = '';
+       my @o;
+       my @c;
+       my @res = ();
+
+       my $level = 0;
+       my @stack = ($level);
+       for ($line = $start; $remain > 0; $line++) {
+               next if ($rawlines[$line] =~ /^-/);
+               $remain--;
+
+               $blk .= $rawlines[$line];
+
+               # Handle nested #if/#else.
+               if ($rawlines[$line] =~ /^.\s*#\s*(?:ifndef|ifdef|if)\s/) {
+                       push(@stack, $level);
+               } elsif ($rawlines[$line] =~ /^.\s*#\s*(?:else|elif)\b/) {
+                       $level = $stack[$#stack - 1];
+               } elsif ($rawlines[$line] =~ /^.\s*#\s*endif\b/) {
+                       $level = pop(@stack);
+               }
+
+               foreach my $c (split(//, $rawlines[$line])) {
+                       ##print "C<$c>L<$level><$open$close>O<$off>\n";
+                       if ($off > 0) {
+                               $off--;
+                               next;
+                       }
+
+                       if ($c eq $close && $level > 0) {
+                               $level--;
+                               last if ($level == 0);
+                       } elsif ($c eq $open) {
+                               $level++;
+                       }
+               }
+
+               if (!$outer || $level <= 1) {
+                       push(@res, $rawlines[$line]);
+               }
+
+               last if ($level == 0);
+       }
+
+       return ($level, @res);
+}
+sub ctx_block_outer {
+       my ($linenr, $remain) = @_;
+
+       my ($level, @r) = ctx_block_get($linenr, $remain, 1, '{', '}', 0);
+       return @r;
+}
+sub ctx_block {
+       my ($linenr, $remain) = @_;
+
+       my ($level, @r) = ctx_block_get($linenr, $remain, 0, '{', '}', 0);
+       return @r;
+}
+sub ctx_statement {
+       my ($linenr, $remain, $off) = @_;
+
+       my ($level, @r) = ctx_block_get($linenr, $remain, 0, '(', ')', $off);
+       return @r;
+}
+sub ctx_block_level {
+       my ($linenr, $remain) = @_;
+
+       return ctx_block_get($linenr, $remain, 0, '{', '}', 0);
+}
+sub ctx_statement_level {
+       my ($linenr, $remain, $off) = @_;
+
+       return ctx_block_get($linenr, $remain, 0, '(', ')', $off);
+}
+
+sub ctx_locate_comment {
+       my ($first_line, $end_line) = @_;
+
+       # Catch a comment on the end of the line itself.
+       my ($current_comment) = ($rawlines[$end_line - 1] =~ m@.*(/\*.*\*/)\s*(?:\\\s*)?$@);
+       return $current_comment if (defined $current_comment);
+
+       # Look through the context and try and figure out if there is a
+       # comment.
+       my $in_comment = 0;
+       $current_comment = '';
+       for (my $linenr = $first_line; $linenr < $end_line; $linenr++) {
+               my $line = $rawlines[$linenr - 1];
+               #warn "           $line\n";
+               if ($linenr == $first_line and $line =~ m@^.\s*\*@) {
+                       $in_comment = 1;
+               }
+               if ($line =~ m@/\*@) {
+                       $in_comment = 1;
+               }
+               if (!$in_comment && $current_comment ne '') {
+                       $current_comment = '';
+               }
+               $current_comment .= $line . "\n" if ($in_comment);
+               if ($line =~ m@\*/@) {
+                       $in_comment = 0;
+               }
+       }
+
+       chomp($current_comment);
+       return($current_comment);
+}
+sub ctx_has_comment {
+       my ($first_line, $end_line) = @_;
+       my $cmt = ctx_locate_comment($first_line, $end_line);
+
+       ##print "LINE: $rawlines[$end_line - 1 ]\n";
+       ##print "CMMT: $cmt\n";
+
+       return ($cmt ne '');
+}
+
+sub raw_line {
+       my ($linenr, $cnt) = @_;
+
+       my $offset = $linenr - 1;
+       $cnt++;
+
+       my $line;
+       while ($cnt) {
+               $line = $rawlines[$offset++];
+               next if (defined($line) && $line =~ /^-/);
+               $cnt--;
+       }
+
+       return $line;
+}
+
+sub cat_vet {
+       my ($vet) = @_;
+       my ($res, $coded);
+
+       $res = '';
+       while ($vet =~ /([^[:cntrl:]]*)([[:cntrl:]]|$)/g) {
+               $res .= $1;
+               if ($2 ne '') {
+                       $coded = sprintf("^%c", unpack('C', $2) + 64);
+                       $res .= $coded;
+               }
+       }
+       $res =~ s/$/\$/;
+
+       return $res;
+}
+
+my $av_preprocessor = 0;
+my $av_pending;
+my @av_paren_type;
+my $av_pend_colon;
+
+sub annotate_reset {
+       $av_preprocessor = 0;
+       $av_pending = '_';
+       @av_paren_type = ('E');
+       $av_pend_colon = 'O';
+}
+
+sub annotate_values {
+       my ($stream, $type) = @_;
+
+       my $res;
+       my $var = '_' x length($stream);
+       my $cur = $stream;
+
+       print "$stream\n" if ($dbg_values > 1);
+
+       while (length($cur)) {
+               @av_paren_type = ('E') if ($#av_paren_type < 0);
+               print " <" . join('', @av_paren_type) .
+                               "> <$type> <$av_pending>" if ($dbg_values > 1);
+               if ($cur =~ /^(\s+)/o) {
+                       print "WS($1)\n" if ($dbg_values > 1);
+                       if ($1 =~ /\n/ && $av_preprocessor) {
+                               $type = pop(@av_paren_type);
+                               $av_preprocessor = 0;
+                       }
+
+               } elsif ($cur =~ /^($Type)\s*(?:$Ident|,|\)|\()/) {
+                       print "DECLARE($1)\n" if ($dbg_values > 1);
+                       $type = 'T';
+
+               } elsif ($cur =~ /^($Modifier)\s*/) {
+                       print "MODIFIER($1)\n" if ($dbg_values > 1);
+                       $type = 'T';
+
+               } elsif ($cur =~ /^(\#\s*define\s*$Ident)(\(?)/o) {
+                       print "DEFINE($1,$2)\n" if ($dbg_values > 1);
+                       $av_preprocessor = 1;
+                       push(@av_paren_type, $type);
+                       if ($2 ne '') {
+                               $av_pending = 'N';
+                       }
+                       $type = 'E';
+
+               } elsif ($cur =~ /^(\#\s*(?:undef\s*$Ident|include\b))/o) {
+                       print "UNDEF($1)\n" if ($dbg_values > 1);
+                       $av_preprocessor = 1;
+                       push(@av_paren_type, $type);
+
+               } elsif ($cur =~ /^(\#\s*(?:ifdef|ifndef|if))/o) {
+                       print "PRE_START($1)\n" if ($dbg_values > 1);
+                       $av_preprocessor = 1;
+
+                       push(@av_paren_type, $type);
+                       push(@av_paren_type, $type);
+                       $type = 'E';
+
+               } elsif ($cur =~ /^(\#\s*(?:else|elif))/o) {
+                       print "PRE_RESTART($1)\n" if ($dbg_values > 1);
+                       $av_preprocessor = 1;
+
+                       push(@av_paren_type, $av_paren_type[$#av_paren_type]);
+
+                       $type = 'E';
+
+               } elsif ($cur =~ /^(\#\s*(?:endif))/o) {
+                       print "PRE_END($1)\n" if ($dbg_values > 1);
+
+                       $av_preprocessor = 1;
+
+                       # Assume all arms of the conditional end as this
+                       # one does, and continue as if the #endif was not here.
+                       pop(@av_paren_type);
+                       push(@av_paren_type, $type);
+                       $type = 'E';
+
+               } elsif ($cur =~ /^(\\\n)/o) {
+                       print "PRECONT($1)\n" if ($dbg_values > 1);
+
+               } elsif ($cur =~ /^(__attribute__)\s*\(?/o) {
+                       print "ATTR($1)\n" if ($dbg_values > 1);
+                       $av_pending = $type;
+                       $type = 'N';
+
+               } elsif ($cur =~ /^(sizeof)\s*(\()?/o) {
+                       print "SIZEOF($1)\n" if ($dbg_values > 1);
+                       if (defined $2) {
+                               $av_pending = 'V';
+                       }
+                       $type = 'N';
+
+               } elsif ($cur =~ /^(if|while|for)\b/o) {
+                       print "COND($1)\n" if ($dbg_values > 1);
+                       $av_pending = 'E';
+                       $type = 'N';
+
+               } elsif ($cur =~/^(case)/o) {
+                       print "CASE($1)\n" if ($dbg_values > 1);
+                       $av_pend_colon = 'C';
+                       $type = 'N';
+
+               } elsif ($cur =~/^(return|else|goto|typeof|__typeof__)\b/o) {
+                       print "KEYWORD($1)\n" if ($dbg_values > 1);
+                       $type = 'N';
+
+               } elsif ($cur =~ /^(\()/o) {
+                       print "PAREN('$1')\n" if ($dbg_values > 1);
+                       push(@av_paren_type, $av_pending);
+                       $av_pending = '_';
+                       $type = 'N';
+
+               } elsif ($cur =~ /^(\))/o) {
+                       my $new_type = pop(@av_paren_type);
+                       if ($new_type ne '_') {
+                               $type = $new_type;
+                               print "PAREN('$1') -> $type\n"
+                                                       if ($dbg_values > 1);
+                       } else {
+                               print "PAREN('$1')\n" if ($dbg_values > 1);
+                       }
+
+               } elsif ($cur =~ /^($Ident)\s*\(/o) {
+                       print "FUNC($1)\n" if ($dbg_values > 1);
+                       $type = 'V';
+                       $av_pending = 'V';
+
+               } elsif ($cur =~ /^($Ident\s*):(?:\s*\d+\s*(,|=|;))?/) {
+                       if (defined $2 && $type eq 'C' || $type eq 'T') {
+                               $av_pend_colon = 'B';
+                       } elsif ($type eq 'E') {
+                               $av_pend_colon = 'L';
+                       }
+                       print "IDENT_COLON($1,$type>$av_pend_colon)\n" if ($dbg_values > 1);
+                       $type = 'V';
+
+               } elsif ($cur =~ /^($Ident|$Constant)/o) {
+                       print "IDENT($1)\n" if ($dbg_values > 1);
+                       $type = 'V';
+
+               } elsif ($cur =~ /^($Assignment)/o) {
+                       print "ASSIGN($1)\n" if ($dbg_values > 1);
+                       $type = 'N';
+
+               } elsif ($cur =~/^(;|{|})/) {
+                       print "END($1)\n" if ($dbg_values > 1);
+                       $type = 'E';
+                       $av_pend_colon = 'O';
+
+               } elsif ($cur =~/^(,)/) {
+                       print "COMMA($1)\n" if ($dbg_values > 1);
+                       $type = 'C';
+
+               } elsif ($cur =~ /^(\?)/o) {
+                       print "QUESTION($1)\n" if ($dbg_values > 1);
+                       $type = 'N';
+
+               } elsif ($cur =~ /^(:)/o) {
+                       print "COLON($1,$av_pend_colon)\n" if ($dbg_values > 1);
+
+                       substr($var, length($res), 1, $av_pend_colon);
+                       if ($av_pend_colon eq 'C' || $av_pend_colon eq 'L') {
+                               $type = 'E';
+                       } else {
+                               $type = 'N';
+                       }
+                       $av_pend_colon = 'O';
+
+               } elsif ($cur =~ /^(\[)/o) {
+                       print "CLOSE($1)\n" if ($dbg_values > 1);
+                       $type = 'N';
+
+               } elsif ($cur =~ /^(-(?![->])|\+(?!\+)|\*|\&\&|\&)/o) {
+                       my $variant;
+
+                       print "OPV($1)\n" if ($dbg_values > 1);
+                       if ($type eq 'V') {
+                               $variant = 'B';
+                       } else {
+                               $variant = 'U';
+                       }
+
+                       substr($var, length($res), 1, $variant);
+                       $type = 'N';
+
+               } elsif ($cur =~ /^($Operators)/o) {
+                       print "OP($1)\n" if ($dbg_values > 1);
+                       if ($1 ne '++' && $1 ne '--') {
+                               $type = 'N';
+                       }
+
+               } elsif ($cur =~ /(^.)/o) {
+                       print "C($1)\n" if ($dbg_values > 1);
+               }
+               if (defined $1) {
+                       $cur = substr($cur, length($1));
+                       $res .= $type x length($1);
+               }
+       }
+
+       return ($res, $var);
+}
+
+sub possible {
+       my ($possible, $line) = @_;
+       my $notPermitted = qr{(?:
+               ^(?:
+                       $Modifier|
+                       $Storage|
+                       $Type|
+                       DEFINE_\S+
+               )$|
+               ^(?:
+                       goto|
+                       return|
+                       case|
+                       else|
+                       asm|__asm__|
+                       do
+               )(?:\s|$)|
+               ^(?:typedef|struct|enum)\b
+           )}x;
+       warn "CHECK<$possible> ($line)\n" if ($dbg_possible > 2);
+       if ($possible !~ $notPermitted) {
+               # Check for modifiers.
+               $possible =~ s/\s*$Storage\s*//g;
+               $possible =~ s/\s*$Sparse\s*//g;
+               if ($possible =~ /^\s*$/) {
+
+               } elsif ($possible =~ /\s/) {
+                       $possible =~ s/\s*$Type\s*//g;
+                       for my $modifier (split(' ', $possible)) {
+                               if ($modifier !~ $notPermitted) {
+                                       warn "MODIFIER: $modifier ($possible) ($line)\n" if ($dbg_possible);
+                                       push(@modifierList, $modifier);
+                               }
+                       }
+
+               } else {
+                       warn "POSSIBLE: $possible ($line)\n" if ($dbg_possible);
+                       push(@typeList, $possible);
+               }
+               build_types();
+       } else {
+               warn "NOTPOSS: $possible ($line)\n" if ($dbg_possible > 1);
+       }
+}
+
+my $prefix = '';
+
+sub report {
+       if (defined $tst_only && $_[0] !~ /\Q$tst_only\E/) {
+               return 0;
+       }
+       my $line = $prefix . $_[0];
+
+       $line = (split('\n', $line))[0] . "\n" if ($terse);
+
+       push(our @report, $line);
+
+       return 1;
+}
+sub report_dump {
+       our @report;
+}
+sub ERROR {
+       if (report("ERROR: $_[0]\n")) {
+               our $clean = 0;
+               our $cnt_error++;
+       }
+}
+sub WARN {
+       if (report("WARNING: $_[0]\n")) {
+               our $clean = 0;
+               our $cnt_warn++;
+       }
+}
+sub CHK {
+       if ($check && report("CHECK: $_[0]\n")) {
+               our $clean = 0;
+               our $cnt_chk++;
+       }
+}
+
+sub check_absolute_file {
+       my ($absolute, $herecurr) = @_;
+       my $file = $absolute;
+
+       ##print "absolute<$absolute>\n";
+
+       # See if any suffix of this path is a path within the tree.
+       while ($file =~ s@^[^/]*/@@) {
+               if (-f "$root/$file") {
+                       ##print "file<$file>\n";
+                       last;
+               }
+       }
+       if (! -f _)  {
+               return 0;
+       }
+
+       # It is, so see if the prefix is acceptable.
+       my $prefix = $absolute;
+       substr($prefix, -length($file)) = '';
+
+       ##print "prefix<$prefix>\n";
+       if ($prefix ne ".../") {
+               WARN("use relative pathname instead of absolute in changelog text\n" . $herecurr);
+       }
+}
+
+sub process {
+       my $filename = shift;
+
+       my $linenr=0;
+       my $prevline="";
+       my $prevrawline="";
+       my $stashline="";
+       my $stashrawline="";
+
+       my $length;
+       my $indent;
+       my $previndent=0;
+       my $stashindent=0;
+
+       our $clean = 1;
+       my $signoff = 0;
+       my $is_patch = 0;
+
+       our @report = ();
+       our $cnt_lines = 0;
+       our $cnt_error = 0;
+       our $cnt_warn = 0;
+       our $cnt_chk = 0;
+
+       # Trace the real file/line as we go.
+       my $realfile = '';
+       my $realline = 0;
+       my $realcnt = 0;
+       my $here = '';
+       my $in_comment = 0;
+       my $comment_edge = 0;
+       my $first_line = 0;
+       my $p1_prefix = '';
+
+       my $prev_values = 'E';
+
+       # suppression flags
+       my %suppress_ifbraces;
+       my %suppress_whiletrailers;
+       my %suppress_export;
+
+       # Pre-scan the patch sanitizing the lines.
+       # Pre-scan the patch looking for any __setup documentation.
+       #
+       my @setup_docs = ();
+       my $setup_docs = 0;
+
+       sanitise_line_reset();
+       my $line;
+       foreach my $rawline (@rawlines) {
+               $linenr++;
+               $line = $rawline;
+
+               if ($rawline=~/^\+\+\+\s+(\S+)/) {
+                       $setup_docs = 0;
+                       if ($1 =~ m@Documentation/kernel-parameters.txt$@) {
+                               $setup_docs = 1;
+                       }
+                       #next;
+               }
+               if ($rawline=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) {
+                       $realline=$1-1;
+                       if (defined $2) {
+                               $realcnt=$3+1;
+                       } else {
+                               $realcnt=1+1;
+                       }
+                       $in_comment = 0;
+
+                       # Guestimate if this is a continuing comment.  Run
+                       # the context looking for a comment "edge".  If this
+                       # edge is a close comment then we must be in a comment
+                       # at context start.
+                       my $edge;
+                       my $cnt = $realcnt;
+                       for (my $ln = $linenr + 1; $cnt > 0; $ln++) {
+                               next if (defined $rawlines[$ln - 1] &&
+                                        $rawlines[$ln - 1] =~ /^-/);
+                               $cnt--;
+                               #print "RAW<$rawlines[$ln - 1]>\n";
+                               last if (!defined $rawlines[$ln - 1]);
+                               if ($rawlines[$ln - 1] =~ m@(/\*|\*/)@ &&
+                                   $rawlines[$ln - 1] !~ m@"[^"]*(?:/\*|\*/)[^"]*"@) {
+                                       ($edge) = $1;
+                                       last;
+                               }
+                       }
+                       if (defined $edge && $edge eq '*/') {
+                               $in_comment = 1;
+                       }
+
+                       # Guestimate if this is a continuing comment.  If this
+                       # is the start of a diff block and this line starts
+                       # ' *' then it is very likely a comment.
+                       if (!defined $edge &&
+                           $rawlines[$linenr] =~ m@^.\s*(?:\*\*+| \*)(?:\s|$)@)
+                       {
+                               $in_comment = 1;
+                       }
+
+                       ##print "COMMENT:$in_comment edge<$edge> $rawline\n";
+                       sanitise_line_reset($in_comment);
+
+               } elsif ($realcnt && $rawline =~ /^(?:\+| |$)/) {
+                       # Standardise the strings and chars within the input to
+                       # simplify matching -- only bother with positive lines.
+                       $line = sanitise_line($rawline);
+               }
+               push(@lines, $line);
+
+               if ($realcnt > 1) {
+                       $realcnt-- if ($line =~ /^(?:\+| |$)/);
+               } else {
+                       $realcnt = 0;
+               }
+
+               #print "==>$rawline\n";
+               #print "-->$line\n";
+
+               if ($setup_docs && $line =~ /^\+/) {
+                       push(@setup_docs, $line);
+               }
+       }
+
+       $prefix = '';
+
+       $realcnt = 0;
+       $linenr = 0;
+       foreach my $line (@lines) {
+               $linenr++;
+
+               my $rawline = $rawlines[$linenr - 1];
+
+#extract the line range in the file after the patch is applied
+               if ($line=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) {
+                       $is_patch = 1;
+                       $first_line = $linenr + 1;
+                       $realline=$1-1;
+                       if (defined $2) {
+                               $realcnt=$3+1;
+                       } else {
+                               $realcnt=1+1;
+                       }
+                       annotate_reset();
+                       $prev_values = 'E';
+
+                       %suppress_ifbraces = ();
+                       %suppress_whiletrailers = ();
+                       %suppress_export = ();
+                       next;
+
+# track the line number as we move through the hunk, note that
+# new versions of GNU diff omit the leading space on completely
+# blank context lines so we need to count that too.
+               } elsif ($line =~ /^( |\+|$)/) {
+                       $realline++;
+                       $realcnt-- if ($realcnt != 0);
+
+                       # Measure the line length and indent.
+                       ($length, $indent) = line_stats($rawline);
+
+                       # Track the previous line.
+                       ($prevline, $stashline) = ($stashline, $line);
+                       ($previndent, $stashindent) = ($stashindent, $indent);
+                       ($prevrawline, $stashrawline) = ($stashrawline, $rawline);
+
+                       #warn "line<$line>\n";
+
+               } elsif ($realcnt == 1) {
+                       $realcnt--;
+               }
+
+               my $hunk_line = ($realcnt != 0);
+
+#make up the handle for any error we report on this line
+               $prefix = "$filename:$realline: " if ($emacs && $file);
+               $prefix = "$filename:$linenr: " if ($emacs && !$file);
+
+               $here = "#$linenr: " if (!$file);
+               $here = "#$realline: " if ($file);
+
+               # extract the filename as it passes
+               if ($line=~/^\+\+\+\s+(\S+)/) {
+                       $realfile = $1;
+                       $realfile =~ s@^([^/]*)/@@;
+
+                       $p1_prefix = $1;
+                       if (!$file && $tree && $p1_prefix ne '' &&
+                           -e "$root/$p1_prefix") {
+                               WARN("patch prefix '$p1_prefix' exists, appears to be a -p0 patch\n");
+                       }
+
+                       if ($realfile =~ m@^include/asm/@) {
+                               ERROR("do not modify files in include/asm, change architecture specific files in include/asm-<architecture>\n" . "$here$rawline\n");
+                       }
+                       next;
+               }
+
+               $here .= "FILE: $realfile:$realline:" if ($realcnt != 0);
+
+               my $hereline = "$here\n$rawline\n";
+               my $herecurr = "$here\n$rawline\n";
+               my $hereprev = "$here\n$prevrawline\n$rawline\n";
+
+               $cnt_lines++ if ($realcnt != 0);
+
+#check the patch for a signoff:
+               if ($line =~ /^\s*signed-off-by:/i) {
+                       # This is a signoff, if ugly, so do not double report.
+                       $signoff++;
+                       if (!($line =~ /^\s*Signed-off-by:/)) {
+                               WARN("Signed-off-by: is the preferred form\n" .
+                                       $herecurr);
+                       }
+                       if ($line =~ /^\s*signed-off-by:\S/i) {
+                               WARN("space required after Signed-off-by:\n" .
+                                       $herecurr);
+                       }
+               }
+
+# Check for wrappage within a valid hunk of the file
+               if ($realcnt != 0 && $line !~ m{^(?:\+|-| |\\ No newline|$)}) {
+                       ERROR("patch seems to be corrupt (line wrapped?)\n" .
+                               $herecurr) if (!$emitted_corrupt++);
+               }
+
+# Check for absolute kernel paths.
+               if ($tree) {
+                       while ($line =~ m{(?:^|\s)(/\S*)}g) {
+                               my $file = $1;
+
+                               if ($file =~ m{^(.*?)(?::\d+)+:?$} &&
+                                   check_absolute_file($1, $herecurr)) {
+                                       #
+                               } else {
+                                       check_absolute_file($file, $herecurr);
+                               }
+                       }
+               }
+
+# UTF-8 regex found at http://www.w3.org/International/questions/qa-forms-utf-8.en.php
+               if (($realfile =~ /^$/ || $line =~ /^\+/) &&
+                   $rawline !~ m/^$UTF8*$/) {
+                       my ($utf8_prefix) = ($rawline =~ /^($UTF8*)/);
+
+                       my $blank = copy_spacing($rawline);
+                       my $ptr = substr($blank, 0, length($utf8_prefix)) . "^";
+                       my $hereptr = "$hereline$ptr\n";
+
+                       ERROR("Invalid UTF-8, patch and commit message should be encoded in UTF-8\n" . $hereptr);
+               }
+
+# ignore non-hunk lines and lines being removed
+               next if (!$hunk_line || $line =~ /^-/);
+
+#trailing whitespace
+               if ($line =~ /^\+.*\015/) {
+                       my $herevet = "$here\n" . cat_vet($rawline) . "\n";
+                       ERROR("DOS line endings\n" . $herevet);
+
+               } elsif ($rawline =~ /^\+.*\S\s+$/ || $rawline =~ /^\+\s+$/) {
+                       my $herevet = "$here\n" . cat_vet($rawline) . "\n";
+                       ERROR("trailing whitespace\n" . $herevet);
+               }
+
+# check for Kconfig help text having a real description
+               if ($realfile =~ /Kconfig/ &&
+                   $line =~ /\+?\s*(---)?help(---)?$/) {
+                       my $length = 0;
+                       for (my $l = $linenr; defined($lines[$l]); $l++) {
+                               my $f = $lines[$l];
+                               $f =~ s/#.*//;
+                               $f =~ s/^\s+//;
+                               next if ($f =~ /^$/);
+                               last if ($f =~ /^\s*config\s/);
+                               $length++;
+                       }
+                       WARN("please write a paragraph that describes the config symbol fully\n" . $herecurr) if ($length < 4);
+               }
+
+# check we are in a valid source file if not then ignore this hunk
+               next if ($realfile !~ /\.(h|c|s|S|pl|sh)$/);
+
+#80 column limit
+               if ($line =~ /^\+/ && $prevrawline !~ /\/\*\*/ &&
+                   $rawline !~ /^.\s*\*\s*\@$Ident\s/ &&
+                   $line !~ /^\+\s*$logFunctions\s*\(\s*(?:KERN_\S+\s*)?"[X\t]*"\s*(?:,|\)\s*;)\s*$/ &&
+                   $length > 80)
+               {
+                       WARN("line over 80 characters\n" . $herecurr);
+               }
+
+# check for spaces before a quoted newline
+               if ($rawline =~ /^.*\".*\s\\n/) {
+                       WARN("unnecessary whitespace before a quoted newline\n" . $herecurr);
+               }
+
+# check for adding lines without a newline.
+               if ($line =~ /^\+/ && defined $lines[$linenr] && $lines[$linenr] =~ /^\\ No newline at end of file/) {
+                       WARN("adding a line without newline at end of file\n" . $herecurr);
+               }
+
+# Blackfin: use hi/lo macros
+               if ($realfile =~ m@arch/blackfin/.*\.S$@) {
+                       if ($line =~ /\.[lL][[:space:]]*=.*&[[:space:]]*0x[fF][fF][fF][fF]/) {
+                               my $herevet = "$here\n" . cat_vet($line) . "\n";
+                               ERROR("use the LO() macro, not (... & 0xFFFF)\n" . $herevet);
+                       }
+                       if ($line =~ /\.[hH][[:space:]]*=.*>>[[:space:]]*16/) {
+                               my $herevet = "$here\n" . cat_vet($line) . "\n";
+                               ERROR("use the HI() macro, not (... >> 16)\n" . $herevet);
+                       }
+               }
+
+# check we are in a valid source file C or perl if not then ignore this hunk
+               next if ($realfile !~ /\.(h|c|pl)$/);
+
+# at the beginning of a line any tabs must come first and anything
+# more than 8 must use tabs.
+               if ($rawline =~ /^\+\s* \t\s*\S/ ||
+                   $rawline =~ /^\+\s*        \s*/) {
+                       my $herevet = "$here\n" . cat_vet($rawline) . "\n";
+                       ERROR("code indent should use tabs where possible\n" . $herevet);
+               }
+
+# check for space before tabs.
+               if ($rawline =~ /^\+/ && $rawline =~ / \t/) {
+                       my $herevet = "$here\n" . cat_vet($rawline) . "\n";
+                       WARN("please, no space before tabs\n" . $herevet);
+               }
+
+# check we are in a valid C source file if not then ignore this hunk
+               next if ($realfile !~ /\.(h|c)$/);
+
+# check for RCS/CVS revision markers
+               if ($rawline =~ /^\+.*\$(Revision|Log|Id)(?:\$|)/) {
+                       WARN("CVS style keyword markers, these will _not_ be updated\n". $herecurr);
+               }
+
+# Blackfin: don't use __builtin_bfin_[cs]sync
+               if ($line =~ /__builtin_bfin_csync/) {
+                       my $herevet = "$here\n" . cat_vet($line) . "\n";
+                       ERROR("use the CSYNC() macro in asm/blackfin.h\n" . $herevet);
+               }
+               if ($line =~ /__builtin_bfin_ssync/) {
+                       my $herevet = "$here\n" . cat_vet($line) . "\n";
+                       ERROR("use the SSYNC() macro in asm/blackfin.h\n" . $herevet);
+               }
+
+# Check for potential 'bare' types
+               my ($stat, $cond, $line_nr_next, $remain_next, $off_next,
+                   $realline_next);
+               if ($realcnt && $line =~ /.\s*\S/) {
+                       ($stat, $cond, $line_nr_next, $remain_next, $off_next) =
+                               ctx_statement_block($linenr, $realcnt, 0);
+                       $stat =~ s/\n./\n /g;
+                       $cond =~ s/\n./\n /g;
+
+                       # Find the real next line.
+                       $realline_next = $line_nr_next;
+                       if (defined $realline_next &&
+                           (!defined $lines[$realline_next - 1] ||
+                            substr($lines[$realline_next - 1], $off_next) =~ /^\s*$/)) {
+                               $realline_next++;
+                       }
+
+                       my $s = $stat;
+                       $s =~ s/{.*$//s;
+
+                       # Ignore goto labels.
+                       if ($s =~ /$Ident:\*$/s) {
+
+                       # Ignore functions being called
+                       } elsif ($s =~ /^.\s*$Ident\s*\(/s) {
+
+                       } elsif ($s =~ /^.\s*else\b/s) {
+
+                       # declarations always start with types
+                       } elsif ($prev_values eq 'E' && $s =~ /^.\s*(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?((?:\s*$Ident)+?)\b(?:\s+$Sparse)?\s*\**\s*(?:$Ident|\(\*[^\)]*\))(?:\s*$Modifier)?\s*(?:;|=|,|\()/s) {
+                               my $type = $1;
+                               $type =~ s/\s+/ /g;
+                               possible($type, "A:" . $s);
+
+                       # definitions in global scope can only start with types
+                       } elsif ($s =~ /^.(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?($Ident)\b\s*(?!:)/s) {
+                               possible($1, "B:" . $s);
+                       }
+
+                       # any (foo ... *) is a pointer cast, and foo is a type
+                       while ($s =~ /\(($Ident)(?:\s+$Sparse)*[\s\*]+\s*\)/sg) {
+                               possible($1, "C:" . $s);
+                       }
+
+                       # Check for any sort of function declaration.
+                       # int foo(something bar, other baz);
+                       # void (*store_gdt)(x86_descr_ptr *);
+                       if ($prev_values eq 'E' && $s =~ /^(.(?:typedef\s*)?(?:(?:$Storage|$Inline)\s*)*\s*$Type\s*(?:\b$Ident|\(\*\s*$Ident\))\s*)\(/s) {
+                               my ($name_len) = length($1);
+
+                               my $ctx = $s;
+                               substr($ctx, 0, $name_len + 1, '');
+                               $ctx =~ s/\)[^\)]*$//;
+
+                               for my $arg (split(/\s*,\s*/, $ctx)) {
+                                       if ($arg =~ /^(?:const\s+)?($Ident)(?:\s+$Sparse)*\s*\**\s*(:?\b$Ident)?$/s || $arg =~ /^($Ident)$/s) {
+
+                                               possible($1, "D:" . $s);
+                                       }
+                               }
+                       }
+
+               }
+
+#
+# Checks which may be anchored in the context.
+#
+
+# Check for switch () and associated case and default
+# statements should be at the same indent.
+               if ($line=~/\bswitch\s*\(.*\)/) {
+                       my $err = '';
+                       my $sep = '';
+                       my @ctx = ctx_block_outer($linenr, $realcnt);
+                       shift(@ctx);
+                       for my $ctx (@ctx) {
+                               my ($clen, $cindent) = line_stats($ctx);
+                               if ($ctx =~ /^\+\s*(case\s+|default:)/ &&
+                                                       $indent != $cindent) {
+                                       $err .= "$sep$ctx\n";
+                                       $sep = '';
+                               } else {
+                                       $sep = "[...]\n";
+                               }
+                       }
+                       if ($err ne '') {
+                               ERROR("switch and case should be at the same indent\n$hereline$err");
+                       }
+               }
+
+# if/while/etc brace do not go on next line, unless defining a do while loop,
+# or if that brace on the next line is for something else
+               if ($line =~ /(.*)\b((?:if|while|for|switch)\s*\(|do\b|else\b)/ && $line !~ /^.\s*\#/) {
+                       my $pre_ctx = "$1$2";
+
+                       my ($level, @ctx) = ctx_statement_level($linenr, $realcnt, 0);
+                       my $ctx_cnt = $realcnt - $#ctx - 1;
+                       my $ctx = join("\n", @ctx);
+
+                       my $ctx_ln = $linenr;
+                       my $ctx_skip = $realcnt;
+
+                       while ($ctx_skip > $ctx_cnt || ($ctx_skip == $ctx_cnt &&
+                                       defined $lines[$ctx_ln - 1] &&
+                                       $lines[$ctx_ln - 1] =~ /^-/)) {
+                               ##print "SKIP<$ctx_skip> CNT<$ctx_cnt>\n";
+                               $ctx_skip-- if (!defined $lines[$ctx_ln - 1] || $lines[$ctx_ln - 1] !~ /^-/);
+                               $ctx_ln++;
+                       }
+
+                       #print "realcnt<$realcnt> ctx_cnt<$ctx_cnt>\n";
+                       #print "pre<$pre_ctx>\nline<$line>\nctx<$ctx>\nnext<$lines[$ctx_ln - 1]>\n";
+
+                       if ($ctx !~ /{\s*/ && defined($lines[$ctx_ln -1]) && $lines[$ctx_ln - 1] =~ /^\+\s*{/) {
+                               ERROR("that open brace { should be on the previous line\n" .
+                                       "$here\n$ctx\n$lines[$ctx_ln - 1]\n");
+                       }
+                       if ($level == 0 && $pre_ctx !~ /}\s*while\s*\($/ &&
+                           $ctx =~ /\)\s*\;\s*$/ &&
+                           defined $lines[$ctx_ln - 1])
+                       {
+                               my ($nlength, $nindent) = line_stats($lines[$ctx_ln - 1]);
+                               if ($nindent > $indent) {
+                                       WARN("trailing semicolon indicates no statements, indent implies otherwise\n" .
+                                               "$here\n$ctx\n$lines[$ctx_ln - 1]\n");
+                               }
+                       }
+               }
+
+# Check relative indent for conditionals and blocks.
+               if ($line =~ /\b(?:(?:if|while|for)\s*\(|do\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) {
+                       my ($s, $c) = ($stat, $cond);
+
+                       substr($s, 0, length($c), '');
+
+                       # Make sure we remove the line prefixes as we have
+                       # none on the first line, and are going to readd them
+                       # where necessary.
+                       $s =~ s/\n./\n/gs;
+
+                       # Find out how long the conditional actually is.
+                       my @newlines = ($c =~ /\n/gs);
+                       my $cond_lines = 1 + $#newlines;
+
+                       # We want to check the first line inside the block
+                       # starting at the end of the conditional, so remove:
+                       #  1) any blank line termination
+                       #  2) any opening brace { on end of the line
+                       #  3) any do (...) {
+                       my $continuation = 0;
+                       my $check = 0;
+                       $s =~ s/^.*\bdo\b//;
+                       $s =~ s/^\s*{//;
+                       if ($s =~ s/^\s*\\//) {
+                               $continuation = 1;
+                       }
+                       if ($s =~ s/^\s*?\n//) {
+                               $check = 1;
+                               $cond_lines++;
+                       }
+
+                       # Also ignore a loop construct at the end of a
+                       # preprocessor statement.
+                       if (($prevline =~ /^.\s*#\s*define\s/ ||
+                           $prevline =~ /\\\s*$/) && $continuation == 0) {
+                               $check = 0;
+                       }
+
+                       my $cond_ptr = -1;
+                       $continuation = 0;
+                       while ($cond_ptr != $cond_lines) {
+                               $cond_ptr = $cond_lines;
+
+                               # If we see an #else/#elif then the code
+                               # is not linear.
+                               if ($s =~ /^\s*\#\s*(?:else|elif)/) {
+                                       $check = 0;
+                               }
+
+                               # Ignore:
+                               #  1) blank lines, they should be at 0,
+                               #  2) preprocessor lines, and
+                               #  3) labels.
+                               if ($continuation ||
+                                   $s =~ /^\s*?\n/ ||
+                                   $s =~ /^\s*#\s*?/ ||
+                                   $s =~ /^\s*$Ident\s*:/) {
+                                       $continuation = ($s =~ /^.*?\\\n/) ? 1 : 0;
+                                       if ($s =~ s/^.*?\n//) {
+                                               $cond_lines++;
+                                       }
+                               }
+                       }
+
+                       my (undef, $sindent) = line_stats("+" . $s);
+                       my $stat_real = raw_line($linenr, $cond_lines);
+
+                       # Check if either of these lines are modified, else
+                       # this is not this patch's fault.
+                       if (!defined($stat_real) ||
+                           $stat !~ /^\+/ && $stat_real !~ /^\+/) {
+                               $check = 0;
+                       }
+                       if (defined($stat_real) && $cond_lines > 1) {
+                               $stat_real = "[...]\n$stat_real";
+                       }
+
+                       #print "line<$line> prevline<$prevline> indent<$indent> sindent<$sindent> check<$check> continuation<$continuation> s<$s> cond_lines<$cond_lines> stat_real<$stat_real> stat<$stat>\n";
+
+                       if ($check && (($sindent % 8) != 0 ||
+                           ($sindent <= $indent && $s ne ''))) {
+                               WARN("suspect code indent for conditional statements ($indent, $sindent)\n" . $herecurr . "$stat_real\n");
+                       }
+               }
+
+               # Track the 'values' across context and added lines.
+               my $opline = $line; $opline =~ s/^./ /;
+               my ($curr_values, $curr_vars) =
+                               annotate_values($opline . "\n", $prev_values);
+               $curr_values = $prev_values . $curr_values;
+               if ($dbg_values) {
+                       my $outline = $opline; $outline =~ s/\t/ /g;
+                       print "$linenr > .$outline\n";
+                       print "$linenr > $curr_values\n";
+                       print "$linenr >  $curr_vars\n";
+               }
+               $prev_values = substr($curr_values, -1);
+
+#ignore lines not being added
+               if ($line=~/^[^\+]/) {next;}
+
+# TEST: allow direct testing of the type matcher.
+               if ($dbg_type) {
+                       if ($line =~ /^.\s*$Declare\s*$/) {
+                               ERROR("TEST: is type\n" . $herecurr);
+                       } elsif ($dbg_type > 1 && $line =~ /^.+($Declare)/) {
+                               ERROR("TEST: is not type ($1 is)\n". $herecurr);
+                       }
+                       next;
+               }
+# TEST: allow direct testing of the attribute matcher.
+               if ($dbg_attr) {
+                       if ($line =~ /^.\s*$Modifier\s*$/) {
+                               ERROR("TEST: is attr\n" . $herecurr);
+                       } elsif ($dbg_attr > 1 && $line =~ /^.+($Modifier)/) {
+                               ERROR("TEST: is not attr ($1 is)\n". $herecurr);
+                       }
+                       next;
+               }
+
+# check for initialisation to aggregates open brace on the next line
+               if ($line =~ /^.\s*{/ &&
+                   $prevline =~ /(?:^|[^=])=\s*$/) {
+                       ERROR("that open brace { should be on the previous line\n" . $hereprev);
+               }
+
+#
+# Checks which are anchored on the added line.
+#
+
+# check for malformed paths in #include statements (uses RAW line)
+               if ($rawline =~ m{^.\s*\#\s*include\s+[<"](.*)[">]}) {
+                       my $path = $1;
+                       if ($path =~ m{//}) {
+                               ERROR("malformed #include filename\n" .
+                                       $herecurr);
+                       }
+               }
+
+# no C99 // comments
+               if ($line =~ m{//}) {
+                       ERROR("do not use C99 // comments\n" . $herecurr);
+               }
+               # Remove C99 comments.
+               $line =~ s@//.*@@;
+               $opline =~ s@//.*@@;
+
+# EXPORT_SYMBOL should immediately follow the thing it is exporting, consider
+# the whole statement.
+#print "APW <$lines[$realline_next - 1]>\n";
+               if (defined $realline_next &&
+                   exists $lines[$realline_next - 1] &&
+                   !defined $suppress_export{$realline_next} &&
+                   ($lines[$realline_next - 1] =~ /EXPORT_SYMBOL.*\((.*)\)/ ||
+                    $lines[$realline_next - 1] =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) {
+                       my $name = $1;
+                       if ($stat !~ /(?:
+                               \n.}\s*$|
+                               ^.DEFINE_$Ident\(\Q$name\E\)|
+                               ^.DECLARE_$Ident\(\Q$name\E\)|
+                               ^.LIST_HEAD\(\Q$name\E\)|
+                               ^.(?:$Storage\s+)?$Type\s*\(\s*\*\s*\Q$name\E\s*\)\s*\(|
+                               \b\Q$name\E(?:\s+$Attribute)*\s*(?:;|=|\[|\()
+                           )/x) {
+#print "FOO A<$lines[$realline_next - 1]> stat<$stat> name<$name>\n";
+                               $suppress_export{$realline_next} = 2;
+                       } else {
+                               $suppress_export{$realline_next} = 1;
+                       }
+               }
+               if (!defined $suppress_export{$linenr} &&
+                   $prevline =~ /^.\s*$/ &&
+                   ($line =~ /EXPORT_SYMBOL.*\((.*)\)/ ||
+                    $line =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) {
+#print "FOO B <$lines[$linenr - 1]>\n";
+                       $suppress_export{$linenr} = 2;
+               }
+               if (defined $suppress_export{$linenr} &&
+                   $suppress_export{$linenr} == 2) {
+                       WARN("EXPORT_SYMBOL(foo); should immediately follow its function/variable\n" . $herecurr);
+               }
+
+# check for external initialisers.
+               if ($line =~ /^.$Type\s*$Ident\s*(?:\s+$Modifier)*\s*=\s*(0|NULL|false)\s*;/) {
+                       ERROR("do not initialise externals to 0 or NULL\n" .
+                               $herecurr);
+               }
+# check for static initialisers.
+               if ($line =~ /\bstatic\s.*=\s*(0|NULL|false)\s*;/) {
+                       ERROR("do not initialise statics to 0 or NULL\n" .
+                               $herecurr);
+               }
+
+# check for new typedefs, only function parameters and sparse annotations
+# make sense.
+               if ($line =~ /\btypedef\s/ &&
+                   $line !~ /\btypedef\s+$Type\s*\(\s*\*?$Ident\s*\)\s*\(/ &&
+                   $line !~ /\btypedef\s+$Type\s+$Ident\s*\(/ &&
+                   $line !~ /\b$typeTypedefs\b/ &&
+                   $line !~ /\b__bitwise(?:__|)\b/) {
+                       WARN("do not add new typedefs\n" . $herecurr);
+               }
+
+# * goes on variable not on type
+               # (char*[ const])
+               if ($line =~ m{\($NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)\)}) {
+                       my ($from, $to) = ($1, $1);
+
+                       # Should start with a space.
+                       $to =~ s/^(\S)/ $1/;
+                       # Should not end with a space.
+                       $to =~ s/\s+$//;
+                       # '*'s should not have spaces between.
+                       while ($to =~ s/\*\s+\*/\*\*/) {
+                       }
+
+                       #print "from<$from> to<$to>\n";
+                       if ($from ne $to) {
+                               ERROR("\"(foo$from)\" should be \"(foo$to)\"\n" .  $herecurr);
+                       }
+               } elsif ($line =~ m{\b$NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)($Ident)}) {
+                       my ($from, $to, $ident) = ($1, $1, $2);
+
+                       # Should start with a space.
+                       $to =~ s/^(\S)/ $1/;
+                       # Should not end with a space.
+                       $to =~ s/\s+$//;
+                       # '*'s should not have spaces between.
+                       while ($to =~ s/\*\s+\*/\*\*/) {
+                       }
+                       # Modifiers should have spaces.
+                       $to =~ s/(\b$Modifier$)/$1 /;
+
+                       #print "from<$from> to<$to> ident<$ident>\n";
+                       if ($from ne $to && $ident !~ /^$Modifier$/) {
+                               ERROR("\"foo${from}bar\" should be \"foo${to}bar\"\n" .  $herecurr);
+                       }
+               }
+
+# # no BUG() or BUG_ON()
+#              if ($line =~ /\b(BUG|BUG_ON)\b/) {
+#                      print "Try to use WARN_ON & Recovery code rather than BUG() or BUG_ON()\n";
+#                      print "$herecurr";
+#                      $clean = 0;
+#              }
+
+               if ($line =~ /\bLINUX_VERSION_CODE\b/) {
+                       WARN("LINUX_VERSION_CODE should be avoided, code should be for the version to which it is merged\n" . $herecurr);
+               }
+
+# printk should use KERN_* levels.  Note that follow on printk's on the
+# same line do not need a level, so we use the current block context
+# to try and find and validate the current printk.  In summary the current
+# printk includes all preceeding printk's which have no newline on the end.
+# we assume the first bad printk is the one to report.
+               if ($line =~ /\bprintk\((?!KERN_)\s*"/) {
+                       my $ok = 0;
+                       for (my $ln = $linenr - 1; $ln >= $first_line; $ln--) {
+                               #print "CHECK<$lines[$ln - 1]\n";
+                               # we have a preceeding printk if it ends
+                               # with "\n" ignore it, else it is to blame
+                               if ($lines[$ln - 1] =~ m{\bprintk\(}) {
+                                       if ($rawlines[$ln - 1] !~ m{\\n"}) {
+                                               $ok = 1;
+                                       }
+                                       last;
+                               }
+                       }
+                       if ($ok == 0) {
+                               WARN("printk() should include KERN_ facility level\n" . $herecurr);
+                       }
+               }
+
+# function brace can't be on same line, except for #defines of do while,
+# or if closed on same line
+               if (($line=~/$Type\s*$Ident\(.*\).*\s{/) and
+                   !($line=~/\#\s*define.*do\s{/) and !($line=~/}/)) {
+                       ERROR("open brace '{' following function declarations go on the next line\n" . $herecurr);
+               }
+
+# open braces for enum, union and struct go on the same line.
+               if ($line =~ /^.\s*{/ &&
+                   $prevline =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?\s*$/) {
+                       ERROR("open brace '{' following $1 go on the same line\n" . $hereprev);
+               }
+
+# check for spacing round square brackets; allowed:
+#  1. with a type on the left -- int [] a;
+#  2. at the beginning of a line for slice initialisers -- [0...10] = 5,
+#  3. inside a curly brace -- = { [0...10] = 5 }
+               while ($line =~ /(.*?\s)\[/g) {
+                       my ($where, $prefix) = ($-[1], $1);
+                       if ($prefix !~ /$Type\s+$/ &&
+                           ($where != 0 || $prefix !~ /^.\s+$/) &&
+                           $prefix !~ /{\s+$/) {
+                               ERROR("space prohibited before open square bracket '['\n" . $herecurr);
+                       }
+               }
+
+# check for spaces between functions and their parentheses.
+               while ($line =~ /($Ident)\s+\(/g) {
+                       my $name = $1;
+                       my $ctx_before = substr($line, 0, $-[1]);
+                       my $ctx = "$ctx_before$name";
+
+                       # Ignore those directives where spaces _are_ permitted.
+                       if ($name =~ /^(?:
+                               if|for|while|switch|return|case|
+                               volatile|__volatile__|
+                               __attribute__|format|__extension__|
+                               asm|__asm__)$/x)
+                       {
+
+                       # cpp #define statements have non-optional spaces, ie
+                       # if there is a space between the name and the open
+                       # parenthesis it is simply not a parameter group.
+                       } elsif ($ctx_before =~ /^.\s*\#\s*define\s*$/) {
+
+                       # cpp #elif statement condition may start with a (
+                       } elsif ($ctx =~ /^.\s*\#\s*elif\s*$/) {
+
+                       # If this whole things ends with a type its most
+                       # likely a typedef for a function.
+                       } elsif ($ctx =~ /$Type$/) {
+
+                       } else {
+                               WARN("space prohibited between function name and open parenthesis '('\n" . $herecurr);
+                       }
+               }
+# Check operator spacing.
+               if (!($line=~/\#\s*include/)) {
+                       my $ops = qr{
+                               <<=|>>=|<=|>=|==|!=|
+                               \+=|-=|\*=|\/=|%=|\^=|\|=|&=|
+                               =>|->|<<|>>|<|>|=|!|~|
+                               &&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|%|
+                               \?|:
+                       }x;
+                       my @elements = split(/($ops|;)/, $opline);
+                       my $off = 0;
+
+                       my $blank = copy_spacing($opline);
+
+                       for (my $n = 0; $n < $#elements; $n += 2) {
+                               $off += length($elements[$n]);
+
+                               # Pick up the preceeding and succeeding characters.
+                               my $ca = substr($opline, 0, $off);
+                               my $cc = '';
+                               if (length($opline) >= ($off + length($elements[$n + 1]))) {
+                                       $cc = substr($opline, $off + length($elements[$n + 1]));
+                               }
+                               my $cb = "$ca$;$cc";
+
+                               my $a = '';
+                               $a = 'V' if ($elements[$n] ne '');
+                               $a = 'W' if ($elements[$n] =~ /\s$/);
+                               $a = 'C' if ($elements[$n] =~ /$;$/);
+                               $a = 'B' if ($elements[$n] =~ /(\[|\()$/);
+                               $a = 'O' if ($elements[$n] eq '');
+                               $a = 'E' if ($ca =~ /^\s*$/);
+
+                               my $op = $elements[$n + 1];
+
+                               my $c = '';
+                               if (defined $elements[$n + 2]) {
+                                       $c = 'V' if ($elements[$n + 2] ne '');
+                                       $c = 'W' if ($elements[$n + 2] =~ /^\s/);
+                                       $c = 'C' if ($elements[$n + 2] =~ /^$;/);
+                                       $c = 'B' if ($elements[$n + 2] =~ /^(\)|\]|;)/);
+                                       $c = 'O' if ($elements[$n + 2] eq '');
+                                       $c = 'E' if ($elements[$n + 2] =~ /^\s*\\$/);
+                               } else {
+                                       $c = 'E';
+                               }
+
+                               my $ctx = "${a}x${c}";
+
+                               my $at = "(ctx:$ctx)";
+
+                               my $ptr = substr($blank, 0, $off) . "^";
+                               my $hereptr = "$hereline$ptr\n";
+
+                               # Pull out the value of this operator.
+                               my $op_type = substr($curr_values, $off + 1, 1);
+
+                               # Get the full operator variant.
+                               my $opv = $op . substr($curr_vars, $off, 1);
+
+                               # Ignore operators passed as parameters.
+                               if ($op_type ne 'V' &&
+                                   $ca =~ /\s$/ && $cc =~ /^\s*,/) {
+
+#                              # Ignore comments
+#                              } elsif ($op =~ /^$;+$/) {
+
+                               # ; should have either the end of line or a space or \ after it
+                               } elsif ($op eq ';') {
+                                       if ($ctx !~ /.x[WEBC]/ &&
+                                           $cc !~ /^\\/ && $cc !~ /^;/) {
+                                               ERROR("space required after that '$op' $at\n" . $hereptr);
+                                       }
+
+                               # // is a comment
+                               } elsif ($op eq '//') {
+
+                               # No spaces for:
+                               #   ->
+                               #   :   when part of a bitfield
+                               } elsif ($op eq '->' || $opv eq ':B') {
+                                       if ($ctx =~ /Wx.|.xW/) {
+                                               ERROR("spaces prohibited around that '$op' $at\n" . $hereptr);
+                                       }
+
+                               # , must have a space on the right.
+                               } elsif ($op eq ',') {
+                                       if ($ctx !~ /.x[WEC]/ && $cc !~ /^}/) {
+                                               ERROR("space required after that '$op' $at\n" . $hereptr);
+                                       }
+
+                               # '*' as part of a type definition -- reported already.
+                               } elsif ($opv eq '*_') {
+                                       #warn "'*' is part of type\n";
+
+                               # unary operators should have a space before and
+                               # none after.  May be left adjacent to another
+                               # unary operator, or a cast
+                               } elsif ($op eq '!' || $op eq '~' ||
+                                        $opv eq '*U' || $opv eq '-U' ||
+                                        $opv eq '&U' || $opv eq '&&U') {
+                                       if ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) {
+                                               ERROR("space required before that '$op' $at\n" . $hereptr);
+                                       }
+                                       if ($op eq '*' && $cc =~/\s*$Modifier\b/) {
+                                               # A unary '*' may be const
+
+                                       } elsif ($ctx =~ /.xW/) {
+                                               ERROR("space prohibited after that '$op' $at\n" . $hereptr);
+                                       }
+
+                               # unary ++ and unary -- are allowed no space on one side.
+                               } elsif ($op eq '++' or $op eq '--') {
+                                       if ($ctx !~ /[WEOBC]x[^W]/ && $ctx !~ /[^W]x[WOBEC]/) {
+                                               ERROR("space required one side of that '$op' $at\n" . $hereptr);
+                                       }
+                                       if ($ctx =~ /Wx[BE]/ ||
+                                           ($ctx =~ /Wx./ && $cc =~ /^;/)) {
+                                               ERROR("space prohibited before that '$op' $at\n" . $hereptr);
+                                       }
+                                       if ($ctx =~ /ExW/) {
+                                               ERROR("space prohibited after that '$op' $at\n" . $hereptr);
+                                       }
+
+
+                               # << and >> may either have or not have spaces both sides
+                               } elsif ($op eq '<<' or $op eq '>>' or
+                                        $op eq '&' or $op eq '^' or $op eq '|' or
+                                        $op eq '+' or $op eq '-' or
+                                        $op eq '*' or $op eq '/' or
+                                        $op eq '%')
+                               {
+                                       if ($ctx =~ /Wx[^WCE]|[^WCE]xW/) {
+                                               ERROR("need consistent spacing around '$op' $at\n" .
+                                                       $hereptr);
+                                       }
+
+                               # A colon needs no spaces before when it is
+                               # terminating a case value or a label.
+                               } elsif ($opv eq ':C' || $opv eq ':L') {
+                                       if ($ctx =~ /Wx./) {
+                                               ERROR("space prohibited before that '$op' $at\n" . $hereptr);
+                                       }
+
+                               # All the others need spaces both sides.
+                               } elsif ($ctx !~ /[EWC]x[CWE]/) {
+                                       my $ok = 0;
+
+                                       # Ignore email addresses <foo@bar>
+                                       if (($op eq '<' &&
+                                            $cc =~ /^\S+\@\S+>/) ||
+                                           ($op eq '>' &&
+                                            $ca =~ /<\S+\@\S+$/))
+                                       {
+                                               $ok = 1;
+                                       }
+
+                                       # Ignore ?:
+                                       if (($opv eq ':O' && $ca =~ /\?$/) ||
+                                           ($op eq '?' && $cc =~ /^:/)) {
+                                               $ok = 1;
+                                       }
+
+                                       if ($ok == 0) {
+                                               ERROR("spaces required around that '$op' $at\n" . $hereptr);
+                                       }
+                               }
+                               $off += length($elements[$n + 1]);
+                       }
+               }
+
+# check for multiple assignments
+               if ($line =~ /^.\s*$Lval\s*=\s*$Lval\s*=(?!=)/) {
+                       CHK("multiple assignments should be avoided\n" . $herecurr);
+               }
+
+## # check for multiple declarations, allowing for a function declaration
+## # continuation.
+##             if ($line =~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Ident.*/ &&
+##                 $line !~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Type\s*$Ident.*/) {
+##
+##                     # Remove any bracketed sections to ensure we do not
+##                     # falsly report the parameters of functions.
+##                     my $ln = $line;
+##                     while ($ln =~ s/\([^\(\)]*\)//g) {
+##                     }
+##                     if ($ln =~ /,/) {
+##                             WARN("declaring multiple variables together should be avoided\n" . $herecurr);
+##                     }
+##             }
+
+#need space before brace following if, while, etc
+               if (($line =~ /\(.*\){/ && $line !~ /\($Type\){/) ||
+                   $line =~ /do{/) {
+                       ERROR("space required before the open brace '{'\n" . $herecurr);
+               }
+
+# closing brace should have a space following it when it has anything
+# on the line
+               if ($line =~ /}(?!(?:,|;|\)))\S/) {
+                       ERROR("space required after that close brace '}'\n" . $herecurr);
+               }
+
+# check spacing on square brackets
+               if ($line =~ /\[\s/ && $line !~ /\[\s*$/) {
+                       ERROR("space prohibited after that open square bracket '['\n" . $herecurr);
+               }
+               if ($line =~ /\s\]/) {
+                       ERROR("space prohibited before that close square bracket ']'\n" . $herecurr);
+               }
+
+# check spacing on parentheses
+               if ($line =~ /\(\s/ && $line !~ /\(\s*(?:\\)?$/ &&
+                   $line !~ /for\s*\(\s+;/) {
+                       ERROR("space prohibited after that open parenthesis '('\n" . $herecurr);
+               }
+               if ($line =~ /(\s+)\)/ && $line !~ /^.\s*\)/ &&
+                   $line !~ /for\s*\(.*;\s+\)/ &&
+                   $line !~ /:\s+\)/) {
+                       ERROR("space prohibited before that close parenthesis ')'\n" . $herecurr);
+               }
+
+#goto labels aren't indented, allow a single space however
+               if ($line=~/^.\s+[A-Za-z\d_]+:(?![0-9]+)/ and
+                  !($line=~/^. [A-Za-z\d_]+:/) and !($line=~/^.\s+default:/)) {
+                       WARN("labels should not be indented\n" . $herecurr);
+               }
+
+# Return is not a function.
+               if (defined($stat) && $stat =~ /^.\s*return(\s*)(\(.*);/s) {
+                       my $spacing = $1;
+                       my $value = $2;
+
+                       # Flatten any parentheses
+                       $value =~ s/\)\(/\) \(/g;
+                       while ($value =~ s/\[[^\{\}]*\]/1/ ||
+                              $value !~ /(?:$Ident|-?$Constant)\s*
+                                            $Compare\s*
+                                            (?:$Ident|-?$Constant)/x &&
+                              $value =~ s/\([^\(\)]*\)/1/) {
+                       }
+
+                       if ($value =~ /^(?:$Ident|-?$Constant)$/) {
+                               ERROR("return is not a function, parentheses are not required\n" . $herecurr);
+
+                       } elsif ($spacing !~ /\s+/) {
+                               ERROR("space required before the open parenthesis '('\n" . $herecurr);
+                       }
+               }
+
+# Need a space before open parenthesis after if, while etc
+               if ($line=~/\b(if|while|for|switch)\(/) {
+                       ERROR("space required before the open parenthesis '('\n" . $herecurr);
+               }
+
+# Check for illegal assignment in if conditional -- and check for trailing
+# statements after the conditional.
+               if ($line =~ /do\s*(?!{)/) {
+                       my ($stat_next) = ctx_statement_block($line_nr_next,
+                                               $remain_next, $off_next);
+                       $stat_next =~ s/\n./\n /g;
+                       ##print "stat<$stat> stat_next<$stat_next>\n";
+
+                       if ($stat_next =~ /^\s*while\b/) {
+                               # If the statement carries leading newlines,
+                               # then count those as offsets.
+                               my ($whitespace) =
+                                       ($stat_next =~ /^((?:\s*\n[+-])*\s*)/s);
+                               my $offset =
+                                       statement_rawlines($whitespace) - 1;
+
+                               $suppress_whiletrailers{$line_nr_next +
+                                                               $offset} = 1;
+                       }
+               }
+               if (!defined $suppress_whiletrailers{$linenr} &&
+                   $line =~ /\b(?:if|while|for)\s*\(/ && $line !~ /^.\s*#/) {
+                       my ($s, $c) = ($stat, $cond);
+
+                       if ($c =~ /\bif\s*\(.*[^<>!=]=[^=].*/s) {
+                               ERROR("do not use assignment in if condition\n" . $herecurr);
+                       }
+
+                       # Find out what is on the end of the line after the
+                       # conditional.
+                       substr($s, 0, length($c), '');
+                       $s =~ s/\n.*//g;
+                       $s =~ s/$;//g;  # Remove any comments
+                       if (length($c) && $s !~ /^\s*{?\s*\\*\s*$/ &&
+                           $c !~ /}\s*while\s*/)
+                       {
+                               # Find out how long the conditional actually is.
+                               my @newlines = ($c =~ /\n/gs);
+                               my $cond_lines = 1 + $#newlines;
+                               my $stat_real = '';
+
+                               $stat_real = raw_line($linenr, $cond_lines)
+                                                       . "\n" if ($cond_lines);
+                               if (defined($stat_real) && $cond_lines > 1) {
+                                       $stat_real = "[...]\n$stat_real";
+                               }
+
+                               ERROR("trailing statements should be on next line\n" . $herecurr . $stat_real);
+                       }
+               }
+
+# Check for bitwise tests written as boolean
+               if ($line =~ /
+                       (?:
+                               (?:\[|\(|\&\&|\|\|)
+                               \s*0[xX][0-9]+\s*
+                               (?:\&\&|\|\|)
+                       |
+                               (?:\&\&|\|\|)
+                               \s*0[xX][0-9]+\s*
+                               (?:\&\&|\|\||\)|\])
+                       )/x)
+               {
+                       WARN("boolean test with hexadecimal, perhaps just 1 \& or \|?\n" . $herecurr);
+               }
+
+# if and else should not have general statements after it
+               if ($line =~ /^.\s*(?:}\s*)?else\b(.*)/) {
+                       my $s = $1;
+                       $s =~ s/$;//g;  # Remove any comments
+                       if ($s !~ /^\s*(?:\sif|(?:{|)\s*\\?\s*$)/) {
+                               ERROR("trailing statements should be on next line\n" . $herecurr);
+                       }
+               }
+# if should not continue a brace
+               if ($line =~ /}\s*if\b/) {
+                       ERROR("trailing statements should be on next line\n" .
+                               $herecurr);
+               }
+# case and default should not have general statements after them
+               if ($line =~ /^.\s*(?:case\s*.*|default\s*):/g &&
+                   $line !~ /\G(?:
+                       (?:\s*$;*)(?:\s*{)?(?:\s*$;*)(?:\s*\\)?\s*$|
+                       \s*return\s+
+                   )/xg)
+               {
+                       ERROR("trailing statements should be on next line\n" . $herecurr);
+               }
+
+               # Check for }<nl>else {, these must be at the same
+               # indent level to be relevant to each other.
+               if ($prevline=~/}\s*$/ and $line=~/^.\s*else\s*/ and
+                                               $previndent == $indent) {
+                       ERROR("else should follow close brace '}'\n" . $hereprev);
+               }
+
+               if ($prevline=~/}\s*$/ and $line=~/^.\s*while\s*/ and
+                                               $previndent == $indent) {
+                       my ($s, $c) = ctx_statement_block($linenr, $realcnt, 0);
+
+                       # Find out what is on the end of the line after the
+                       # conditional.
+                       substr($s, 0, length($c), '');
+                       $s =~ s/\n.*//g;
+
+                       if ($s =~ /^\s*;/) {
+                               ERROR("while should follow close brace '}'\n" . $hereprev);
+                       }
+               }
+
+#studly caps, commented out until figure out how to distinguish between use of existing and adding new
+#              if (($line=~/[\w_][a-z\d]+[A-Z]/) and !($line=~/print/)) {
+#                  print "No studly caps, use _\n";
+#                  print "$herecurr";
+#                  $clean = 0;
+#              }
+
+#no spaces allowed after \ in define
+               if ($line=~/\#\s*define.*\\\s$/) {
+                       WARN("Whitepspace after \\ makes next lines useless\n" . $herecurr);
+               }
+
+#warn if <asm/foo.h> is #included and <linux/foo.h> is available (uses RAW line)
+               if ($tree && $rawline =~ m{^.\s*\#\s*include\s*\<asm\/(.*)\.h\>}) {
+                       my $file = "$1.h";
+                       my $checkfile = "include/linux/$file";
+                       if (-f "$root/$checkfile" &&
+                           $realfile ne $checkfile &&
+                           $1 ne 'irq')
+                       {
+                               if ($realfile =~ m{^arch/}) {
+                                       CHK("Consider using #include <linux/$file> instead of <asm/$file>\n" . $herecurr);
+                               } else {
+                                       WARN("Use #include <linux/$file> instead of <asm/$file>\n" . $herecurr);
+                               }
+                       }
+               }
+
+# multi-statement macros should be enclosed in a do while loop, grab the
+# first statement and ensure its the whole macro if its not enclosed
+# in a known good container
+               if ($realfile !~ m@/vmlinux.lds.h$@ &&
+                   $line =~ /^.\s*\#\s*define\s*$Ident(\()?/) {
+                       my $ln = $linenr;
+                       my $cnt = $realcnt;
+                       my ($off, $dstat, $dcond, $rest);
+                       my $ctx = '';
+
+                       my $args = defined($1);
+
+                       # Find the end of the macro and limit our statement
+                       # search to that.
+                       while ($cnt > 0 && defined $lines[$ln - 1] &&
+                               $lines[$ln - 1] =~ /^(?:-|..*\\$)/)
+                       {
+                               $ctx .= $rawlines[$ln - 1] . "\n";
+                               $cnt-- if ($lines[$ln - 1] !~ /^-/);
+                               $ln++;
+                       }
+                       $ctx .= $rawlines[$ln - 1];
+
+                       ($dstat, $dcond, $ln, $cnt, $off) =
+                               ctx_statement_block($linenr, $ln - $linenr + 1, 0);
+                       #print "dstat<$dstat> dcond<$dcond> cnt<$cnt> off<$off>\n";
+                       #print "LINE<$lines[$ln-1]> len<" . length($lines[$ln-1]) . "\n";
+
+                       # Extract the remainder of the define (if any) and
+                       # rip off surrounding spaces, and trailing \'s.
+                       $rest = '';
+                       while ($off != 0 || ($cnt > 0 && $rest =~ /\\\s*$/)) {
+                               #print "ADDING cnt<$cnt> $off <" . substr($lines[$ln - 1], $off) . "> rest<$rest>\n";
+                               if ($off != 0 || $lines[$ln - 1] !~ /^-/) {
+                                       $rest .= substr($lines[$ln - 1], $off) . "\n";
+                                       $cnt--;
+                               }
+                               $ln++;
+                               $off = 0;
+                       }
+                       $rest =~ s/\\\n.//g;
+                       $rest =~ s/^\s*//s;
+                       $rest =~ s/\s*$//s;
+
+                       # Clean up the original statement.
+                       if ($args) {
+                               substr($dstat, 0, length($dcond), '');
+                       } else {
+                               $dstat =~ s/^.\s*\#\s*define\s+$Ident\s*//;
+                       }
+                       $dstat =~ s/$;//g;
+                       $dstat =~ s/\\\n.//g;
+                       $dstat =~ s/^\s*//s;
+                       $dstat =~ s/\s*$//s;
+
+                       # Flatten any parentheses and braces
+                       while ($dstat =~ s/\([^\(\)]*\)/1/ ||
+                              $dstat =~ s/\{[^\{\}]*\}/1/ ||
+                              $dstat =~ s/\[[^\{\}]*\]/1/)
+                       {
+                       }
+
+                       my $exceptions = qr{
+                               $Declare|
+                               module_param_named|
+                               MODULE_PARAM_DESC|
+                               DECLARE_PER_CPU|
+                               DEFINE_PER_CPU|
+                               __typeof__\(|
+                               union|
+                               struct|
+                               \.$Ident\s*=\s*|
+                               ^\"|\"$
+                       }x;
+                       #print "REST<$rest> dstat<$dstat>\n";
+                       if ($rest ne '') {
+                               if ($rest !~ /while\s*\(/ &&
+                                   $dstat !~ /$exceptions/)
+                               {
+                                       ERROR("Macros with multiple statements should be enclosed in a do - while loop\n" . "$here\n$ctx\n");
+                               }
+
+                       } elsif ($ctx !~ /;/) {
+                               if ($dstat ne '' &&
+                                   $dstat !~ /^(?:$Ident|-?$Constant)$/ &&
+                                   $dstat !~ /$exceptions/ &&
+                                   $dstat !~ /^\.$Ident\s*=/ &&
+                                   $dstat =~ /$Operators/)
+                               {
+                                       ERROR("Macros with complex values should be enclosed in parenthesis\n" . "$here\n$ctx\n");
+                               }
+                       }
+               }
+
+# make sure symbols are always wrapped with VMLINUX_SYMBOL() ...
+# all assignments may have only one of the following with an assignment:
+#      .
+#      ALIGN(...)
+#      VMLINUX_SYMBOL(...)
+               if ($realfile eq 'vmlinux.lds.h' && $line =~ /(?:(?:^|\s)$Ident\s*=|=\s*$Ident(?:\s|$))/) {
+                       WARN("vmlinux.lds.h needs VMLINUX_SYMBOL() around C-visible symbols\n" . $herecurr);
+               }
+
+# check for redundant bracing round if etc
+               if ($line =~ /(^.*)\bif\b/ && $1 !~ /else\s*$/) {
+                       my ($level, $endln, @chunks) =
+                               ctx_statement_full($linenr, $realcnt, 1);
+                       #print "chunks<$#chunks> linenr<$linenr> endln<$endln> level<$level>\n";
+                       #print "APW: <<$chunks[1][0]>><<$chunks[1][1]>>\n";
+                       if ($#chunks > 0 && $level == 0) {
+                               my $allowed = 0;
+                               my $seen = 0;
+                               my $herectx = $here . "\n";
+                               my $ln = $linenr - 1;
+                               for my $chunk (@chunks) {
+                                       my ($cond, $block) = @{$chunk};
+
+                                       # If the condition carries leading newlines, then count those as offsets.
+                                       my ($whitespace) = ($cond =~ /^((?:\s*\n[+-])*\s*)/s);
+                                       my $offset = statement_rawlines($whitespace) - 1;
+
+                                       #print "COND<$cond> whitespace<$whitespace> offset<$offset>\n";
+
+                                       # We have looked at and allowed this specific line.
+                                       $suppress_ifbraces{$ln + $offset} = 1;
+
+                                       $herectx .= "$rawlines[$ln + $offset]\n[...]\n";
+                                       $ln += statement_rawlines($block) - 1;
+
+                                       substr($block, 0, length($cond), '');
+
+                                       $seen++ if ($block =~ /^\s*{/);
+
+                                       #print "cond<$cond> block<$block> allowed<$allowed>\n";
+                                       if (statement_lines($cond) > 1) {
+                                               #print "APW: ALLOWED: cond<$cond>\n";
+                                               $allowed = 1;
+                                       }
+                                       if ($block =~/\b(?:if|for|while)\b/) {
+                                               #print "APW: ALLOWED: block<$block>\n";
+                                               $allowed = 1;
+                                       }
+                                       if (statement_block_size($block) > 1) {
+                                               #print "APW: ALLOWED: lines block<$block>\n";
+                                               $allowed = 1;
+                                       }
+                               }
+                               if ($seen && !$allowed) {
+                                       WARN("braces {} are not necessary for any arm of this statement\n" . $herectx);
+                               }
+                       }
+               }
+               if (!defined $suppress_ifbraces{$linenr - 1} &&
+                                       $line =~ /\b(if|while|for|else)\b/) {
+                       my $allowed = 0;
+
+                       # Check the pre-context.
+                       if (substr($line, 0, $-[0]) =~ /(\}\s*)$/) {
+                               #print "APW: ALLOWED: pre<$1>\n";
+                               $allowed = 1;
+                       }
+
+                       my ($level, $endln, @chunks) =
+                               ctx_statement_full($linenr, $realcnt, $-[0]);
+
+                       # Check the condition.
+                       my ($cond, $block) = @{$chunks[0]};
+                       #print "CHECKING<$linenr> cond<$cond> block<$block>\n";
+                       if (defined $cond) {
+                               substr($block, 0, length($cond), '');
+                       }
+                       if (statement_lines($cond) > 1) {
+                               #print "APW: ALLOWED: cond<$cond>\n";
+                               $allowed = 1;
+                       }
+                       if ($block =~/\b(?:if|for|while)\b/) {
+                               #print "APW: ALLOWED: block<$block>\n";
+                               $allowed = 1;
+                       }
+                       if (statement_block_size($block) > 1) {
+                               #print "APW: ALLOWED: lines block<$block>\n";
+                               $allowed = 1;
+                       }
+                       # Check the post-context.
+                       if (defined $chunks[1]) {
+                               my ($cond, $block) = @{$chunks[1]};
+                               if (defined $cond) {
+                                       substr($block, 0, length($cond), '');
+                               }
+                               if ($block =~ /^\s*\{/) {
+                                       #print "APW: ALLOWED: chunk-1 block<$block>\n";
+                                       $allowed = 1;
+                               }
+                       }
+                       if ($level == 0 && $block =~ /^\s*\{/ && !$allowed) {
+                               my $herectx = $here . "\n";;
+                               my $cnt = statement_rawlines($block);
+
+                               for (my $n = 0; $n < $cnt; $n++) {
+                                       $herectx .= raw_line($linenr, $n) . "\n";;
+                               }
+
+                               WARN("braces {} are not necessary for single statement blocks\n" . $herectx);
+                       }
+               }
+
+# don't include deprecated include files (uses RAW line)
+               for my $inc (@dep_includes) {
+                       if ($rawline =~ m@^.\s*\#\s*include\s*\<$inc>@) {
+                               ERROR("Don't use <$inc>: see Documentation/feature-removal-schedule.txt\n" . $herecurr);
+                       }
+               }
+
+# don't use deprecated functions
+               for my $func (@dep_functions) {
+                       if ($line =~ /\b$func\b/) {
+                               ERROR("Don't use $func(): see Documentation/feature-removal-schedule.txt\n" . $herecurr);
+                       }
+               }
+
+# no volatiles please
+               my $asm_volatile = qr{\b(__asm__|asm)\s+(__volatile__|volatile)\b};
+               if ($line =~ /\bvolatile\b/ && $line !~ /$asm_volatile/) {
+                       WARN("Use of volatile is usually wrong: see Documentation/volatile-considered-harmful.txt\n" . $herecurr);
+               }
+
+# SPIN_LOCK_UNLOCKED & RW_LOCK_UNLOCKED are deprecated
+               if ($line =~ /\b(SPIN_LOCK_UNLOCKED|RW_LOCK_UNLOCKED)/) {
+                       ERROR("Use of $1 is deprecated: see Documentation/spinlocks.txt\n" . $herecurr);
+               }
+
+# warn about #if 0
+               if ($line =~ /^.\s*\#\s*if\s+0\b/) {
+                       CHK("if this code is redundant consider removing it\n" .
+                               $herecurr);
+               }
+
+# check for needless kfree() checks
+               if ($prevline =~ /\bif\s*\(([^\)]*)\)/) {
+                       my $expr = $1;
+                       if ($line =~ /\bkfree\(\Q$expr\E\);/) {
+                               WARN("kfree(NULL) is safe this check is probably not required\n" . $hereprev);
+                       }
+               }
+# check for needless usb_free_urb() checks
+               if ($prevline =~ /\bif\s*\(([^\)]*)\)/) {
+                       my $expr = $1;
+                       if ($line =~ /\busb_free_urb\(\Q$expr\E\);/) {
+                               WARN("usb_free_urb(NULL) is safe this check is probably not required\n" . $hereprev);
+                       }
+               }
+
+# warn about #ifdefs in C files
+#              if ($line =~ /^.\s*\#\s*if(|n)def/ && ($realfile =~ /\.c$/)) {
+#                      print "#ifdef in C files should be avoided\n";
+#                      print "$herecurr";
+#                      $clean = 0;
+#              }
+
+# warn about spacing in #ifdefs
+               if ($line =~ /^.\s*\#\s*(ifdef|ifndef|elif)\s\s+/) {
+                       ERROR("exactly one space required after that #$1\n" . $herecurr);
+               }
+
+# check for spinlock_t definitions without a comment.
+               if ($line =~ /^.\s*(struct\s+mutex|spinlock_t)\s+\S+;/ ||
+                   $line =~ /^.\s*(DEFINE_MUTEX)\s*\(/) {
+                       my $which = $1;
+                       if (!ctx_has_comment($first_line, $linenr)) {
+                               CHK("$1 definition without comment\n" . $herecurr);
+                       }
+               }
+# check for memory barriers without a comment.
+               if ($line =~ /\b(mb|rmb|wmb|read_barrier_depends|smp_mb|smp_rmb|smp_wmb|smp_read_barrier_depends)\(/) {
+                       if (!ctx_has_comment($first_line, $linenr)) {
+                               CHK("memory barrier without comment\n" . $herecurr);
+                       }
+               }
+# check of hardware specific defines
+               if ($line =~ m@^.\s*\#\s*if.*\b(__i386__|__powerpc64__|__sun__|__s390x__)\b@ && $realfile !~ m@include/asm-@) {
+                       CHK("architecture specific defines should be avoided\n" .  $herecurr);
+               }
+
+# Check that the storage class is at the beginning of a declaration
+               if ($line =~ /\b$Storage\b/ && $line !~ /^.\s*$Storage\b/) {
+                       WARN("storage class should be at the beginning of the declaration\n" . $herecurr)
+               }
+
+# check the location of the inline attribute, that it is between
+# storage class and type.
+               if ($line =~ /\b$Type\s+$Inline\b/ ||
+                   $line =~ /\b$Inline\s+$Storage\b/) {
+                       ERROR("inline keyword should sit between storage class and type\n" . $herecurr);
+               }
+
+# Check for __inline__ and __inline, prefer inline
+               if ($line =~ /\b(__inline__|__inline)\b/) {
+                       WARN("plain inline is preferred over $1\n" . $herecurr);
+               }
+
+# check for sizeof(&)
+               if ($line =~ /\bsizeof\s*\(\s*\&/) {
+                       WARN("sizeof(& should be avoided\n" . $herecurr);
+               }
+
+# check for new externs in .c files.
+               if ($realfile =~ /\.c$/ && defined $stat &&
+                   $stat =~ /^.\s*(?:extern\s+)?$Type\s+($Ident)(\s*)\(/s)
+               {
+                       my $function_name = $1;
+                       my $paren_space = $2;
+
+                       my $s = $stat;
+                       if (defined $cond) {
+                               substr($s, 0, length($cond), '');
+                       }
+                       if ($s =~ /^\s*;/ &&
+                           $function_name ne 'uninitialized_var')
+                       {
+                               WARN("externs should be avoided in .c files\n" .  $herecurr);
+                       }
+
+                       if ($paren_space =~ /\n/) {
+                               WARN("arguments for function declarations should follow identifier\n" . $herecurr);
+                       }
+
+               } elsif ($realfile =~ /\.c$/ && defined $stat &&
+                   $stat =~ /^.\s*extern\s+/)
+               {
+                       WARN("externs should be avoided in .c files\n" .  $herecurr);
+               }
+
+# checks for new __setup's
+               if ($rawline =~ /\b__setup\("([^"]*)"/) {
+                       my $name = $1;
+
+                       if (!grep(/$name/, @setup_docs)) {
+                               CHK("__setup appears un-documented -- check Documentation/kernel-parameters.txt\n" . $herecurr);
+                       }
+               }
+
+# check for pointless casting of kmalloc return
+               if ($line =~ /\*\s*\)\s*k[czm]alloc\b/) {
+                       WARN("unnecessary cast may hide bugs, see http://c-faq.com/malloc/mallocnocast.html\n" . $herecurr);
+               }
+
+# check for gcc specific __FUNCTION__
+               if ($line =~ /__FUNCTION__/) {
+                       WARN("__func__ should be used instead of gcc specific __FUNCTION__\n"  . $herecurr);
+               }
+
+# check for semaphores used as mutexes
+               if ($line =~ /^.\s*(DECLARE_MUTEX|init_MUTEX)\s*\(/) {
+                       WARN("mutexes are preferred for single holder semaphores\n" . $herecurr);
+               }
+# check for semaphores used as mutexes
+               if ($line =~ /^.\s*init_MUTEX_LOCKED\s*\(/) {
+                       WARN("consider using a completion\n" . $herecurr);
+
+               }
+# recommend strict_strto* over simple_strto*
+               if ($line =~ /\bsimple_(strto.*?)\s*\(/) {
+                       WARN("consider using strict_$1 in preference to simple_$1\n" . $herecurr);
+               }
+# check for __initcall(), use device_initcall() explicitly please
+               if ($line =~ /^.\s*__initcall\s*\(/) {
+                       WARN("please use device_initcall() instead of __initcall()\n" . $herecurr);
+               }
+# check for various ops structs, ensure they are const.
+               my $struct_ops = qr{acpi_dock_ops|
+                               address_space_operations|
+                               backlight_ops|
+                               block_device_operations|
+                               dentry_operations|
+                               dev_pm_ops|
+                               dma_map_ops|
+                               extent_io_ops|
+                               file_lock_operations|
+                               file_operations|
+                               hv_ops|
+                               ide_dma_ops|
+                               intel_dvo_dev_ops|
+                               item_operations|
+                               iwl_ops|
+                               kgdb_arch|
+                               kgdb_io|
+                               kset_uevent_ops|
+                               lock_manager_operations|
+                               microcode_ops|
+                               mtrr_ops|
+                               neigh_ops|
+                               nlmsvc_binding|
+                               pci_raw_ops|
+                               pipe_buf_operations|
+                               platform_hibernation_ops|
+                               platform_suspend_ops|
+                               proto_ops|
+                               rpc_pipe_ops|
+                               seq_operations|
+                               snd_ac97_build_ops|
+                               soc_pcmcia_socket_ops|
+                               stacktrace_ops|
+                               sysfs_ops|
+                               tty_operations|
+                               usb_mon_operations|
+                               wd_ops}x;
+               if ($line !~ /\bconst\b/ &&
+                   $line =~ /\bstruct\s+($struct_ops)\b/) {
+                       WARN("struct $1 should normally be const\n" .
+                               $herecurr);
+               }
+
+# use of NR_CPUS is usually wrong
+# ignore definitions of NR_CPUS and usage to define arrays as likely right
+               if ($line =~ /\bNR_CPUS\b/ &&
+                   $line !~ /^.\s*\s*#\s*if\b.*\bNR_CPUS\b/ &&
+                   $line !~ /^.\s*\s*#\s*define\b.*\bNR_CPUS\b/ &&
+                   $line !~ /^.\s*$Declare\s.*\[[^\]]*NR_CPUS[^\]]*\]/ &&
+                   $line !~ /\[[^\]]*\.\.\.[^\]]*NR_CPUS[^\]]*\]/ &&
+                   $line !~ /\[[^\]]*NR_CPUS[^\]]*\.\.\.[^\]]*\]/)
+               {
+                       WARN("usage of NR_CPUS is often wrong - consider using cpu_possible(), num_possible_cpus(), for_each_possible_cpu(), etc\n" . $herecurr);
+               }
+
+# check for %L{u,d,i} in strings
+               my $string;
+               while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) {
+                       $string = substr($rawline, $-[1], $+[1] - $-[1]);
+                       $string =~ s/%%/__/g;
+                       if ($string =~ /(?<!%)%L[udi]/) {
+                               WARN("\%Ld/%Lu are not-standard C, use %lld/%llu\n" . $herecurr);
+                               last;
+                       }
+               }
+
+# whine mightly about in_atomic
+               if ($line =~ /\bin_atomic\s*\(/) {
+                       if ($realfile =~ m@^drivers/@) {
+                               ERROR("do not use in_atomic in drivers\n" . $herecurr);
+                       } elsif ($realfile !~ m@^kernel/@) {
+                               WARN("use of in_atomic() is incorrect outside core kernel code\n" . $herecurr);
+                       }
+               }
+
+# check for lockdep_set_novalidate_class
+               if ($line =~ /^.\s*lockdep_set_novalidate_class\s*\(/ ||
+                   $line =~ /__lockdep_no_validate__\s*\)/ ) {
+                       if ($realfile !~ m@^kernel/lockdep@ &&
+                           $realfile !~ m@^include/linux/lockdep@ &&
+                           $realfile !~ m@^drivers/base/core@) {
+                               ERROR("lockdep_no_validate class is reserved for device->mutex.\n" . $herecurr);
+                       }
+               }
+       }
+
+       # If we have no input at all, then there is nothing to report on
+       # so just keep quiet.
+       if ($#rawlines == -1) {
+               exit(0);
+       }
+
+       # In mailback mode only produce a report in the negative, for
+       # things that appear to be patches.
+       if ($mailback && ($clean == 1 || !$is_patch)) {
+               exit(0);
+       }
+
+       # This is not a patch, and we are are in 'no-patch' mode so
+       # just keep quiet.
+       if (!$chk_patch && !$is_patch) {
+               exit(0);
+       }
+
+       if (!$is_patch) {
+               ERROR("Does not appear to be a unified-diff format patch\n");
+       }
+       if ($is_patch && $chk_signoff && $signoff == 0) {
+               ERROR("Missing Signed-off-by: line(s)\n");
+       }
+
+       print report_dump();
+       if ($summary && !($clean == 1 && $quiet == 1)) {
+               print "$filename " if ($summary_file);
+               print "total: $cnt_error errors, $cnt_warn warnings, " .
+                       (($check)? "$cnt_chk checks, " : "") .
+                       "$cnt_lines lines checked\n";
+               print "\n" if ($quiet == 0);
+       }
+
+       if ($clean == 1 && $quiet == 0) {
+               print "$vname has no obvious style problems and is ready for submission.\n"
+       }
+       if ($clean == 0 && $quiet == 0) {
+               print "$vname has style problems, please review.  If any of these errors\n";
+               print "are false positives report them to the maintainer, see\n";
+               print "CHECKPATCH in MAINTAINERS.\n";
+       }
+
+       return $clean;
+}
diff --git a/www/Makefile.am b/www/Makefile.am
new file mode 100644 (file)
index 0000000..60c1afa
--- /dev/null
@@ -0,0 +1,4 @@
+defaultwwwdir = $(pkgdatadir)/www
+defaultwww_DATA = monitor.lua style.css favicon.ico index.lua
+
+EXTRA_DIST=$(defaultwww_DATA)
diff --git a/www/favicon.ico b/www/favicon.ico
new file mode 100644 (file)
index 0000000..c78647d
Binary files /dev/null and b/www/favicon.ico differ
diff --git a/www/index.lua b/www/index.lua
new file mode 100644 (file)
index 0000000..817535a
--- /dev/null
@@ -0,0 +1,28 @@
+
+function footer()
+   return "<div class='footer'>"
+      .. "<a href='http://wpitchoune.net/psensor'>psensor-server</a> v"
+      .. psensor_version 
+      .. "</div>"
+end
+
+str = "\
+<html>\
+  <head>\
+    <title>Psensor Web Server</title>\
+    <link rel='stylesheet' type='text/css' href='/style.css' />\
+  </head>\
+\
+  <body>\
+\
+  <h1>Welcome to the Psensor Web Server!</h1>\
+\
+  <p>Go to the <a href='monitor.lua'>Monitoring Page</a>.</p>\
+\
+  <hr />"
+   .. footer() 
+   .. "</body>\
+\
+</html>"
+
+return str
\ No newline at end of file
diff --git a/www/monitor.lua b/www/monitor.lua
new file mode 100644 (file)
index 0000000..3042ad3
--- /dev/null
@@ -0,0 +1,188 @@
+--
+-- Convenient functions for HTML output
+-- 
+
+function td(content)
+   return "<td>" .. content .. "</td>"
+end
+
+function th(style, content)
+   if style then
+      return "<th class='"..style.."'>"..content.."</th>"
+   else
+      return "<th>"..content.."</th>"
+   end
+end
+
+function tr(style,...)
+   if style then
+      ret = "<tr class='"..style.."'>"
+   else 
+      ret = "<tr>"
+   end
+
+   for i,s in ipairs(arg) do
+      ret = ret .. s
+   end
+
+   ret = ret .. "</tr>\n"
+
+   return ret
+end
+
+function h2(str) 
+   return "<h2>"..str.."</h2>\n"
+end
+
+
+-- Formats sensor information to HTML 'tr'
+function sensor_to_tr(id,sensor)
+   return tr(nil,
+            td(sensor["name"]),
+            td(sensor["measure_last"]),
+            td(sensor["measure_min"]),
+            td(sensor["measure_max"]))
+end
+
+
+-- Formats number of bytes to string
+function format_mem_size(bytes)
+   if (bytes == 0) then
+      return "0"
+   end
+
+   if (bytes < 1024) then
+      return bytes .. " o";
+   end
+
+   mo_bytes = 1024 * 1024;
+
+   if (bytes < mo_bytes) then
+      return math.ceil(bytes / 1024) .. " Ko"
+   end
+
+   go_bytes = 1024 * mo_bytes;
+
+   if (bytes < go_bytes) then
+      return math.ceil(bytes / mo_bytes) .. " Mo"
+   end
+
+   return math.ceil(bytes / go_bytes) .. " Go"
+end
+
+-- Formats uptime to string
+function format_uptime(uptime)
+   uptime_s = sysinfo["uptime"]%60
+   uptime_mn = math.floor( (sysinfo["uptime"] / 60) % 60)
+   uptime_h = math.floor( (sysinfo["uptime"] / (60*60)) % 24)
+   uptime_d = math.floor(sysinfo["uptime"] / (60*60*24))
+
+   return uptime_d .. "d " ..
+      uptime_h .. "h " ..
+      string.format("%02.d",uptime_mn) .. "mn " ..
+      string.format("%02d",uptime_s) .. "s"
+end
+
+str = "<html><head><link rel='stylesheet' type='text/css' href='/style.css' /></head><body><h1>Psensor Monitoring Server</h1>"
+
+if sysinfo then
+
+--
+-- Uptime
+--
+
+   str = str .. "<p><strong>Uptime</strong>: " .. format_uptime(sysinfo["uptime"]) .. "</p>"
+
+--
+-- CPU
+--
+
+   str = str .. h2("CPU")
+
+   str = str .. "<table>"
+      .. tr("title",
+           th(nil,"Current usage"),
+           th(nil,"Load 1mn"),
+           th(nil,"Load 5mn"),
+           th(nil,"Load 15mn"))
+
+   str = str .. "<tr>"
+
+   if sysinfo["load"] then
+      str = str .. td(math.ceil(100*sysinfo["load"]) .. "%")
+   else
+      str = str .. td("N/A")
+   end
+
+   str = str  .. td(string.format("%.2f",sysinfo["load_1mn"])) ..
+   td(string.format("%.2f",sysinfo["load_5mn"])) ..
+   td(string.format("%.2f",sysinfo["load_15mn"])) ..
+   "</tr>" ..
+   "</table>"
+
+--
+-- Memory
+--
+
+   totalram = format_mem_size(sysinfo["totalram"] * sysinfo["mem_unit"])
+   freeram = format_mem_size(sysinfo["freeram"] * sysinfo["mem_unit"])
+   sharedram = format_mem_size(sysinfo["sharedram"] * sysinfo["mem_unit"])
+   bufferram = format_mem_size(sysinfo["bufferram"] * sysinfo["mem_unit"])
+   usedram = format_mem_size(sysinfo["totalram"] - sysinfo["freeram"])
+
+   totalswap = format_mem_size(sysinfo["totalswap"] * sysinfo["mem_unit"])
+   freeswap = format_mem_size(sysinfo["freeswap"] * sysinfo["mem_unit"])
+   usedswap = format_mem_size(sysinfo["totalswap"] - sysinfo["freeswap"])
+
+   str = str 
+      .. h2("Memory")
+
+      .. "<table>"
+
+      .. tr("title",
+           th(nil,""),
+           th(nil,"Total"),
+           th(nil,"Used"),
+           th(nil,"Free"),
+           th(nil,"Shared"),
+           th(nil,"Buffer"))
+
+      .. tr(nil,
+           th(nil,"Memory"),
+           td(totalram),
+           td(usedram),
+           td(freeram),
+           td(sharedram),
+           td(bufferram))
+   
+       .. tr(nil,
+            th(nil,"Swap"),
+            td(totalswap),
+            td(usedswap),
+            td(freeswap))
+    
+       .. "</table>"
+                                  
+end
+
+--
+-- Sensors
+-- 
+
+if sensors then
+
+   str = str .. "<h2>Sensors</h2>"
+      .. "<table>"
+      .. "<tr class='title'><th>Name</th><th>Value</th><th>Min</th><th>Max</th></tr>"
+
+   for i,sensor in ipairs(sensors) do 
+      str = str .. sensor_to_tr(i,sensor) 
+   end
+   
+   str = str .. "</table><hr /><a href='http://wpitchoune.net/psensor'>psensor-server</a></body></html>"
+
+end
+
+
+return str
+
diff --git a/www/style.css b/www/style.css
new file mode 100644 (file)
index 0000000..90d4dab
--- /dev/null
@@ -0,0 +1,23 @@
+body {
+    font-family: Ubuntu, Verdana, Helvetica, Arial, sans-serif;
+    background: #fff;
+    color: Black;
+    margin: 1em 0em 0em 1em;
+    padding-left: 0em 0em 0em 0em;
+}
+
+table {
+    border: 1px solid #ddd;
+}
+
+tr.title {
+    background-color: #eee;
+}
+
+th {
+    text-align: center;
+}
+
+td {
+    text-align: right;
+}
\ No newline at end of file