--- /dev/null
+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.
+
--- /dev/null
+Authors of psensor.
+
+wpitchoune@gmail.com all files.
+linux.dabao@gmail.com po/zh_CN.po
\ No newline at end of file
--- /dev/null
+ 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.
--- /dev/null
+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.
+
--- /dev/null
+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)
+
+
--- /dev/null
+* 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
+
+
--- /dev/null
+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
--- /dev/null
+# -*- 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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+/usr/share/locale
--- /dev/null
+/usr/bin/psensor-server
+/usr/share/psensor/www/index.lua
+
--- /dev/null
+debian/tmp/usr/share/man/man1/psensor-server.1
\ No newline at end of file
--- /dev/null
+/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
+
+
--- /dev/null
+debian/tmp/usr/share/man/man1/psensor.1
+
--- /dev/null
+#!/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 $@
--- /dev/null
+version=3
+
+http://wpitchoune.net/psensor/files/psensor-(\d.*)\.tar\.gz
\ No newline at end of file
--- /dev/null
+themedir = $(datadir)/icons/hicolor
+size = 48x48
+context = apps
+EXTRA_DIST = psensor.png psensor_hot.png
+psensordistpixdir = $(themedir)/$(size)/$(context)
+psensordistpix_DATA = $(EXTRA_DIST)
--- /dev/null
+themedir = $(datadir)/icons/hicolor
+size = scalable
+context = apps
+EXTRA_DIST = psensor.svg psensor_hot.svg
+psensordistpixdir = $(themedir)/$(size)/$(context)
+psensordistpix_DATA = $(EXTRA_DIST)
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+# 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
--- /dev/null
+# 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:
--- /dev/null
+# 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 =
--- /dev/null
+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
--- /dev/null
+# 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
--- /dev/null
+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
--- /dev/null
+# 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.
+#
--- /dev/null
+# 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.
+#
--- /dev/null
+# 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"
--- /dev/null
+# 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
+}
--- /dev/null
+# 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 ""
--- /dev/null
+s/"\([^"]*\)"/“\1”/g
+s/`\([^`']*\)'/‘\1’/g
+s/ '\([^`']*\)' / ‘\1’ /g
+s/ '\([^`']*\)'$/ ‘\1’/g
+s/^'\([^`']*\)' /‘\1’ /g
+s/“”/""/g
--- /dev/null
+# 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
+}
--- /dev/null
+# 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 "退出"
--- /dev/null
+[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;
--- /dev/null
+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)
+
--- /dev/null
+/*
+ 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);
+
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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
--- /dev/null
+[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)
--- /dev/null
+gladedir = $(pkgdatadir)
+glade_DATA = \
+ sensor-edit.glade \
+ psensor-pref.glade
+
+EXTRA_DIST = $(glade_DATA)
--- /dev/null
+<?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"><i>Min</i></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"><i>Max</i></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>
--- /dev/null
+<?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>
--- /dev/null
+/*
+ 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);
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+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
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+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
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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);
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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;
+ }
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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);
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+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
+
--- /dev/null
+/*
+ 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;
+}
+
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+
+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
--- /dev/null
+/*
+ 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);
+ }
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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);
+ }
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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++;
+ }
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+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
--- /dev/null
+[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)
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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);
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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);
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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));
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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);
+ }
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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));
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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;
+
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+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
--- /dev/null
+/*
+ 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);
+ }
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+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
--- /dev/null
+#!/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;
+}
--- /dev/null
+defaultwwwdir = $(pkgdatadir)/www
+defaultwww_DATA = monitor.lua style.css favicon.ico index.lua
+
+EXTRA_DIST=$(defaultwww_DATA)
--- /dev/null
+
+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
--- /dev/null
+--
+-- 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
+
--- /dev/null
+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