<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Maven &#187; Software</title>
	<atom:link href="http://readme.maven.pl/category/software/feed/" rel="self" type="application/rss+xml" />
	<link>http://readme.maven.pl</link>
	<description>arekm page</description>
	<lastBuildDate>Sat, 17 Dec 2011 23:33:05 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>Mounting DOS HDD image</title>
		<link>http://readme.maven.pl/2011/12/18/mounting-dos-hdd-image/</link>
		<comments>http://readme.maven.pl/2011/12/18/mounting-dos-hdd-image/#comments</comments>
		<pubDate>Sat, 17 Dec 2011 23:08:19 +0000</pubDate>
		<dc:creator>arekm</dc:creator>
				<category><![CDATA[Software]]></category>

		<guid isPermaLink="false">http://readme.maven.pl/?p=76</guid>
		<description><![CDATA[Mounting dos hdd image, first partition: mount -o loop,offset=32256 dos-hdd.img dir I&#8217;m using such image to update BIOSes in machines where bios doesn&#8217;t fit into floppy image. Such hdd image can be places inside iso image to be booted at virtual or real cdrom. mkisofs -v -r -T -J &#8211;hard-disk-boot -b dos-hdd.img -o ../test.iso .]]></description>
			<content:encoded><![CDATA[<p>Mounting dos hdd image, first partition:</p>
<blockquote><p>
mount -o loop,offset=32256 dos-hdd.img dir
</p></blockquote>
<p>I&#8217;m using such image to update BIOSes in machines where bios doesn&#8217;t fit into floppy image. Such hdd image can be places inside iso image to be booted at virtual or real cdrom.</p>
<blockquote><p>
mkisofs -v -r -T -J &#8211;hard-disk-boot -b dos-hdd.img -o ../test.iso .
</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://readme.maven.pl/2011/12/18/mounting-dos-hdd-image/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tabs, vim and 256 colors &#8211; tips</title>
		<link>http://readme.maven.pl/2009/02/18/tabs-vim-and-256-colors-tips/</link>
		<comments>http://readme.maven.pl/2009/02/18/tabs-vim-and-256-colors-tips/#comments</comments>
		<pubDate>Wed, 18 Feb 2009 19:13:37 +0000</pubDate>
		<dc:creator>arekm</dc:creator>
				<category><![CDATA[Software]]></category>

		<guid isPermaLink="false">http://www.maven.pl/?p=48</guid>
		<description><![CDATA[Having tabs and spaces visible as separate entities in vim is very neat feature especially if you use colors to differentiate. Switch TERM to konsole-256color in kde konsole terminal emulator (or whatever emulator you use &#8211; rpm -ql ncurses terminfo &#124; grep 256 for more) and put into .vimrc: colorscheme darkblue highlight TabGroup ctermbg=233 guibg=233 [...]]]></description>
			<content:encoded><![CDATA[<p>Having tabs and spaces visible as separate entities in vim is very neat feature especially if you use colors to differentiate.</p>
<p>Switch <strong>TERM</strong> to <em>konsole-256color</em> in kde konsole terminal emulator (or whatever emulator you use &#8211; <em>rpm -ql ncurses terminfo | grep 256</em> for more) and put into <em>.vimrc</em>:</p>
<p><code><br />
colorscheme darkblue<br />
highlight TabGroup ctermbg=233 guibg=233<br />
match TabGroup /\t/<br />
</code></p>
<p>Now tab characters are a bit brighter than spaces.</p>
]]></content:encoded>
			<wfw:commentRss>http://readme.maven.pl/2009/02/18/tabs-vim-and-256-colors-tips/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to format your source code files using vim?</title>
		<link>http://readme.maven.pl/2008/03/02/how-to-format-your-source-code-files-using-vim/</link>
		<comments>http://readme.maven.pl/2008/03/02/how-to-format-your-source-code-files-using-vim/#comments</comments>
		<pubDate>Sun, 02 Mar 2008 00:41:53 +0000</pubDate>
		<dc:creator>arekm</dc:creator>
				<category><![CDATA[Software]]></category>

		<guid isPermaLink="false">http://www.maven.pl/2008/03/02/how-to-format-your-source-code-files-using-vim/</guid>
		<description><![CDATA[&#8230; in a batch mode: find . -name '*.somepattern' -exec vim -c 'norm gg=GZZ' "{}" ";"]]></description>
			<content:encoded><![CDATA[<p>&#8230; in a batch mode:<br />
<code><br />
find . -name '*.somepattern' -exec vim -c 'norm gg=GZZ' "{}" ";"<br />
</code></p>
]]></content:encoded>
			<wfw:commentRss>http://readme.maven.pl/2008/03/02/how-to-format-your-source-code-files-using-vim/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>lftp and editing remote files</title>
		<link>http://readme.maven.pl/2007/06/15/lftp-and-editing-remote-files/</link>
		<comments>http://readme.maven.pl/2007/06/15/lftp-and-editing-remote-files/#comments</comments>
		<pubDate>Fri, 15 Jun 2007 16:39:14 +0000</pubDate>
		<dc:creator>arekm</dc:creator>
				<category><![CDATA[Software]]></category>

		<guid isPermaLink="false">http://www.maven.pl/?p=39</guid>
		<description><![CDATA[lftp is a very nice piece of software (for people who like text console). How to edit remote files? Take a look! [arekm@tarm ~]$ cat .lftp/rc alias edit source -e ~/.lftp/edit.sh [arekm@tarm ~]$ cat .lftp/edit.sh #!/bin/sh tempid=$$ echo get $1 -o /tmp/$tempid$1 echo shell vim /tmp/$tempid$1 echo put -E /tmp/$tempid$1 -o $1 [arekm@tarm ~]$ lftp [...]]]></description>
			<content:encoded><![CDATA[<p>lftp is a very nice piece of software (for people who like text console).</p>
<p>How to edit remote files? Take a look!</p>
<p><code><br />
[arekm@tarm ~]$ cat .lftp/rc<br />
alias edit source -e ~/.lftp/edit.sh<br />
[arekm@tarm ~]$ cat .lftp/edit.sh<br />
#!/bin/sh<br />
tempid=$$<br />
echo get $1 -o /tmp/$tempid$1<br />
echo shell vim /tmp/$tempid$1<br />
echo put -E /tmp/$tempid$1 -o $1<br />
[arekm@tarm ~]$ lftp -u arm ftp.somewhere.pl<br />
Password:<br />
lftp arm@ftp.somewhere.pl:~&gt; ls<br />
drwxr-xr-x    2 0        0            4096 Jan 29 20:35 .<br />
drwxr-xr-x    2 0        0            4096 Jan 29 20:35 ..<br />
lftp arm@ftp.somewhere.pl:~&gt; edit test.txt<br />
get: Access failed: 550 Can't open test.txt: No such file or directory</code></p>
<p>[HERE vim is opened; after saving]</p>
<p><code>9 bytes transferred<br />
lftp arm@ftp.somewhere.pl:~&gt; rels<br />
drwx---r-x    3 10089    999            50 Jun 15 18:35 .<br />
drwxr-xr-x    2 0        0            4096 Jan 29 20:35 ..<br />
-rw-r--r--    1 10089    nogroup         9 Jun 15 18:35 test.txt<br />
lftp arm@ftp.somewhere.pl:~&gt; cat test.txt<br />
El test.<br />
10 bytes transferred<br />
lftp arm@ftp.somewhere.pl:~&gt; edit test.txt<br />
9 bytes transferred</code></p>
<p>[HERE again vim is opened; after saving]</p>
<p><code>23 bytes transferred<br />
lftp arm@ftp.somewhere.pl:~&gt; cat test.txt<br />
El test.<br />
Small change.<br />
25 bytes transferred<br />
lftp arm@ftp.somewhere.pl:~&gt;<br />
</code></p>
<p>Don&#8217;t we all love lftp?</p>
]]></content:encoded>
			<wfw:commentRss>http://readme.maven.pl/2007/06/15/lftp-and-editing-remote-files/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Opera Browser (for Linux) and multimedia</title>
		<link>http://readme.maven.pl/2007/05/26/opera-browser-for-linux-and-multimedia/</link>
		<comments>http://readme.maven.pl/2007/05/26/opera-browser-for-linux-and-multimedia/#comments</comments>
		<pubDate>Sat, 26 May 2007 19:51:54 +0000</pubDate>
		<dc:creator>arekm</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Software]]></category>

		<guid isPermaLink="false">http://www.maven.pl/?p=37</guid>
		<description><![CDATA[Did you ever try mplayerplug-in with Opera? It&#8217;s very bad. Pure X11, no GUI at all. Fortunately there is plugin rewrite under gecko-mediaplayer name which uses new gnome-mplayer tool. Works nicely with GUI under Opera web browser (of course other browsers like Mozilla are supported) ! Available in PLD Th (testing) as rpm packages. See screenshot:]]></description>
			<content:encoded><![CDATA[<p>Did you ever try <a HREF="http://mplayerplug-in.sourceforge.net/" TITLE="mplayerplug-in">mplayerplug-in</a> with <a HREF="http://www.opera.com/" TITLE="Opera Web Browser">Opera</a>? It&#8217;s very bad. Pure X11, no GUI at all. Fortunately there is plugin rewrite under <a HREF="http://dekorte.homeip.net/download/gecko-mediaplayer/" TITLE="gecko-mediaplayer">gecko-mediaplayer</a> name which uses new <a HREF="http://dekorte.homeip.net/download/gnome-mplayer/" TITLE="gnome-mplayer">gnome-mplayer</a> tool. Works nicely with GUI under Opera web browser (of course other browsers like Mozilla are supported) ! Available in<a HREF="http://www.pld-linux.org/" TITLE="PLD"> PLD Th</a> (testing) as rpm packages.</p>
<p>See screenshot:</p>
<p><a TITLE="gecko-mediaplayer plugin" HREF="http://readme.maven.pl/wp-content/uploads/2007/05/gecko-mediaplayer.png"><img ALT="gecko-mediaplayer plugin" SRC="http://readme.maven.pl/wp-content/uploads/2007/05/gecko-mediaplayer.thumbnail.png" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://readme.maven.pl/2007/05/26/opera-browser-for-linux-and-multimedia/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CVS &#8211; System Kontroli Wersji</title>
		<link>http://readme.maven.pl/2000/05/07/cvs-system-kontroli-wersji/</link>
		<comments>http://readme.maven.pl/2000/05/07/cvs-system-kontroli-wersji/#comments</comments>
		<pubDate>Sun, 07 May 2000 21:22:10 +0000</pubDate>
		<dc:creator>arekm</dc:creator>
				<category><![CDATA[Software]]></category>

		<guid isPermaLink="false">http://www.maven.pl/?p=14</guid>
		<description><![CDATA[CVS &#8211; System Kontroli Wersji Arkadiusz Miśkiewicz $Id: cvs-art.txt,v 1.7 2000/05/07 17:39:00 misiek Exp $Większość dostępnych programów oferowanych użytkownikom Linuksa jest dziś tworzonych przez duże grupy programistów. Zarządzanie takimi projektami jak jądro Linuksa, glibc czy XFree86 było by bardzo trudne i uciążliwe gdyby nie pomysłowi programiści, którzy stworzyli narzędzie CVS. CVS jest efektywnym systemem kontroli [...]]]></description>
			<content:encoded><![CDATA[<p><strong>			 CVS &#8211; System Kontroli Wersji<br />
</strong><br />
Arkadiusz Miśkiewicz<br />
$Id: cvs-art.txt,v 1.7 2000/05/07 17:39:00 misiek Exp $Większość dostępnych programów oferowanych użytkownikom Linuksa jest<br />
dziś tworzonych przez duże grupy programistów.  Zarządzanie takimi projektami<br />
jak jądro Linuksa, glibc czy XFree86 było by bardzo trudne i uciążliwe gdyby<br />
nie pomysłowi programiści, którzy stworzyli narzędzie CVS.</p>
<p>CVS jest efektywnym systemem kontroli wersji. System zapamiętuje<br />
wszystkie wersje wszystkich plików, które umieścisz w CVSie. </p>
<p><span id="more-14"></span></p>
<p>Dzięki temu w<br />
dowolnym momencie można powrócić do poprzednich wersji każdego pliku,<br />
porównywać wersje ze sobą, tworzyć odgałęzienia, przeglądać historię zmian<br />
itp. W jednym repozytorium CVS można przechowywać teoretycznie dowolną ilość<br />
programów w postaci źródłowej. Typowo każdy program będzie traktowany jako<br />
osobny ,,moduł&#8221;.<br />
CVS zorganizowany jest na zasadzie serwer <--> klienci. Na serwerze<br />
w tzw. repozytorium (repository) trzymane są wszystkie pliki (w specjalnym<br />
formacie rozumianym przez System Kontroli Rewizji (RCS)). Użytkownik chcący<br />
dokonać zmiany w którymś w plików najpierw musi pobrać dane z repozytorium do<br />
swojego lokalnego katalogu. Następnie po dokonaniu edycji przesyła poprawki do<br />
repozytorium (commit).<br />
Serwer CVS obsługuje po kolei żądania wprowadzenia zmian od<br />
użytkowników. W momencie gdy dwie osoby chcą przesłać poprawki, jedna zostanie<br />
obsłużona jako pierwsza. Poprawki drugiej osoby nie zostaną natomiast<br />
naniesione &#8211; system poprosi ją o zaktualizowanie danych z repozytorium.<br />
W chwili aktualizacji CVS spróbuje automatycznie połączyć poprawki pierwszej<br />
osoby z poprawkami drugiej. Jeśli zmiany kolidują ze sobą druga osoba będzie<br />
musiała dokonać połączenia ręcznie (CVS ułatwia nam sprawę informując<br />
o miejscach występowania konfliktów). Po połączeniu przesyłamy poprawki do<br />
repozytorium.<br />
Jak już pisałem CVS umożliwia dotarcie do dowolnej wersji każdego pliku.<br />
Jest to możliwe dzięki przypisaniu każdej wersji pliku numeru rewizji<br />
(revision). W przypadku przesłania poprawek numer rewizji jest inkrementowany<br />
podczas gdy stary numer nadal jest powiązany ze starą wersją pliku. System CVS<br />
umożliwia także znakowanie określonych plików w określonych wersjach poprzez<br />
nadawanie im nazw symbolicznych (tag). Warto tutaj nadmienić, że tylko jedna<br />
wersja danego pliku może być oznaczona pewną nazwą symboliczną &#8211; nie ma<br />
możliwości oznaczenia tą samą nazwą dwóch rewizji jednego pliku.<br />
Mamy już podstawowe wiadomości dotyczące CVSu. Możemy więc przystąpić<br />
do prób. Na początek należy zainstalować oprogramowanie rcs oraz cvs (adresy<br />
na końcu artykułu). Większość użytkowników znajdzie wspomniane oprogramowanie<br />
w archiwach pakietów swoich dystrybucji.</p>
<p>Po skompilowaniu pakietu CVS uzyskamy świetną dokumentację w postaci<br />
plików info, kilka skryptów oraz jeden plik binarny &#8211; program ,,cvs&#8221;.  Ogólna<br />
składnia tego programu wygląda następująco:</p>
<blockquote><p><em>cvs [-opcje] komenda [-opcje komendy] [argumenty]</em></p></blockquote>
<p>Najczęściej używane opcje (główne) to:</p>
<blockquote><p>-zX		kompresuj dane na poziomie X (zalecana wartość 7)<br />
-d [cvsroot]	,,ścieżka&#8221; do repozytorium<br />
-q		wyświetlaj tylko najważniejsze komunikaty</p></blockquote>
<p>Ścieżka ,,cvsroot&#8221; może wskazywać repozytorium lokalne lub na dowolnym<br />
serwerze w sieci (więcej o cvsroot w dalszej części artykułu).</p>
<p>Do pobierania plików z repozytorium służy komenda ,,checkout&#8221; (można także<br />
używać zamiennie co lub get). Przykład:</p>
<blockquote><p><em>[misiek@dark example]$ cvs -z7 checkout test</em><em><br />
</em><em>  cvs server: Updating test</em><em><br />
</em><em>  U test/testzlib.c</em><em><br />
</em><em>  [misiek@dark example]$ cd test &#038;&#038; ls -l</em><em><br />
</em><em>  razem 4</em><em><br />
</em><em>  drwxr-xr-x    2 misiek   users        4096 kwi 17 21:22 CVS</em><em><br />
</em><em>  -rw-r&#8211;r&#8211;    1 misiek   users         334 kwi 17 21:22 testzlib.c</em></p></blockquote>
<p>Jak widać do lokalnego katalogu został sprowadzony plik ,,testzlib.c&#8221;,<br />
który można edytować, poprawiać itp. CVS utworzył także katalog ,,CVS&#8221;, w<br />
którym przechowuje dane administracyjne o lokalnych wersjach plików.</p>
<p>Po wprowadzeniu zmian w lokalnej kopii używamy komendy ,,commit&#8221; (lub ci) by<br />
przesłać zmiany do repozytorium:</p>
<blockquote><p><em>[misiek@dark test]$ cvs commit testzlib.c</em><em><br />
</em><em>< ... Tutaj otwiera się edytor w którym opisujemy charakter poprawek</em><em><br />
</em><em>które nanieśliśmy. Edytor określamy poprzez zmienne środowiska:</em><em><br />
</em><em>$EDITOR lub $CVSEDITOR&#8230; ></em><em><br />
</em><em>Checking in testzlib.c;</em><em><br />
</em><em>/usr/src/CVSROOT/test/testzlib.c,v  <--  testzlib.c</em><em><br />
</em><em>new revision: 1.2; previous revision: 1.1</em><em><br />
</em><em>done</em></p></blockquote>
<p>Widać od razu, że numer rewizji został zwiększony o 1 na ostatnim miejscu.<br />
Charakter zmian można również opisywać bezpośrednio z linii poleceń:</p>
<blockquote><p><em>[misiek@dark test]$ cvs commit -m &#8220;- podawaj rozmiar bufora&#8221; testzlib.c</em></p></blockquote>
<p>Może się tak zdarzyć, że w momencie gdy wprowadzaliśmy zmiany do lokalnego<br />
pliku ktoś przesłał do repozytorium swoje zmiany. Wówczas przesłanie naszych<br />
zmian (commit) się nie powiedzie:</p>
<blockquote><p><em>[misiek@dark test]$ cvs commit -m &#8220;- fprintf zamiast printf&#8221; testzlib.c</em><em><br />
</em><em>cvs server: Up-to-date check failed for `testzlib.c&#8217;</em><em><br />
</em><em>cvs [server aborted]: correct above errors first!</em></p></blockquote>
<p>W takiej sytuacji korzystamy z komendy ,,update&#8221; (up), która uaktualni nasze<br />
pliki oraz spróbuje automatycznie połączyć nasze zmiany w uprzednio<br />
wprowadzonymi.</p>
<blockquote><p><em>[misiek@dark test]$ cvs commit -m &#8220;- fprintf zamiast printf&#8221; testzlib.c</em><em><br />
</em><em>cvs server: Up-to-date check failed for `testzlib.c&#8217;</em><em><br />
</em><em>cvs [server aborted]: correct above errors first!</em><em><br />
</em><em>[misiek@dark test]$ cvs up</em><em><br />
</em><em>cvs server: Updating .</em><em><br />
</em><em>RCS file: /usr/src/CVSROOT/test/testzlib.c,v</em><em><br />
</em><em>retrieving revision 1.2</em><em><br />
</em><em>retrieving revision 1.3</em><em><br />
</em><em>Merging differences between 1.2 and 1.3 into testzlib.c</em><em><br />
</em><em>M testzlib.c</em><em><br />
</em><em>[misiek@dark test]$ cvs commit -m &#8220;- fprintf zamiast printf&#8221; testzlib.c</em><em><br />
</em><em>Checking in testzlib.c;</em><em><br />
</em><em>/usr/src/CVSROOT/test/testzlib.c,v  <--  testzlib.c</em><em><br />
</em><em>new revision: 1.4; previous revision: 1.3</em><em><br />
</em><em>done</em></p></blockquote>
<p>CVS ściągnął i poprawnie połączył zmiany. Niestety CVS to nie człowiek, więc<br />
nie potrafi myśleć i dlatego nie zawsze uda mu się automatycznie połączyć<br />
zmiany. W takiej sytuacji zasygnalizuje błąd ,,conflicts during merge&#8221;.<br />
Dokończenia łączenia będzie musiał dokonać człowiek.</p>
<p>Podczas aktualizacji danych serwer informuje nas o statusie plików,<br />
z którymi miał do czynienia podczas przeprowadzania aktualizacji.<br />
Możliwe są następujące litery statusu:<br />
- U	serwer przesłał nam kompletny plik z repozytorium<br />
- P	serwer przesłał nam jedynie różnicę (diff) pomiędzy plikiem<br />
w repozytorium a naszym lokalnym<br />
- A	plik został dodany do lokalnej kopii ale informacja o tym nie<br />
została przesłana do repozytorium (nie wykonano komendy commit)<br />
- R	plik został usunięty z lokalnej kopii ale informacja o tym nie<br />
została przesłana do repozytorium (nie wykonano komendy commit)<br />
- M	kopia lokalna pliku został zmieniona<br />
- C	podczas próby automatycznego łączenia został wykryty konflikt<br />
- ?	plik istnieje tylko w lokalnej kopii i nie posiada odpowiednika<br />
w repozytorium</p>
<p>Możemy nakazać CVSowi ignorować określone pliki. Wystarczy wpisać nazwy<br />
plików do pliku ,,.cvsignore&#8221; i przesłać ów plik do repozytorium.</p>
<p>Inną przydatną komendą jest komenda ,,log&#8221; pozwalająca obejżeć historię<br />
wpisów dokonywanych przy przesyłaniu poprawek (commit -m xyz). Skrypt rcs2log<br />
dostępny wraz z pakietem cvs generuje pliki ChangeLog na podstawie informacji<br />
dostarczonych przez komendę ,,log&#8221;.</p>
<p>CVS połączył nam przed chwilą dwie wersje pliku &#8211; 1.2 oraz 1.3<br />
i w efekcie zapisał wersję 1.4. Załóżmy, że chcemy zobaczyć różnicę pomiędzy<br />
wersjami 1.2 oraz 1.3 &#8211; nic prostszego:</p>
<blockquote><p><em>[misiek@dark test]$ cvs diff -u -r1.2 -r1.3 testzlib.c</em><em><br />
</em><em>Index: testzlib.c</em><em><br />
</em><em>===================================================================</em><em><br />
</em><em>RCS file: /usr/src/CVSROOT/test/testzlib.c,v</em><em><br />
</em><em>retrieving revision 1.2</em><em><br />
</em><em>retrieving revision 1.3</em><em><br />
</em><em>diff -u -r1.2 -r1.3</em><em><br />
</em><em>&#8212; testzlib.c  2000/04/17 19:33:22     1.2</em><em><br />
</em><em>+++ testzlib.c  2000/04/17 19:43:25     1.3</em><em><br />
</em><em>@@ -7,7 +7,7 @@</em><em><br />
</em><em>FILE *f;</em><em><br />
</em><em>char buf[1024];</em></p></blockquote>
<blockquote><p><em>-       if ((f = gzopen(&#8220;test.gz&#8221;, &#8220;r&#8221;)) == NULL)</em><em><br />
</em><em>+       if ((f = gzopen(&#8220;test.gz&#8221;, &#8220;rb&#8221;)) == NULL)</em><em><br />
</em><em>{</em><em><br />
</em><em>fprintf(stderr, &#8220;Problem when opening test.gz file: %s\n&#8221;,</em><em><br />
</em><em>strerror(errno));</em></p></blockquote>
<p>Opcja ,,-r&#8221; pozwala na porównywanie wg. numerów rewizji. Możliwe jest<br />
także porównywanie wg. daty (opcja ,,-D&#8221;) jak i mieszane np.</p>
<blockquote><p><em>[misiek@dark test]$ cvs diff -u -r1.2 -Dnow testzlib.c</em><em><br />
</em><em>[misiek@dark test]$ cvs diff -u -D&#8217;1 minute ago&#8217; -Dnow testzlib.c</em><em><br />
</em><em>[misiek@dark test]$ cvs diff -u -D&#8217;1 minute ago&#8217; -Dnow testzlib.c</em><em><br />
</em><em>[misiek@dark test]$ cvs diff -u -D&#8217;2000-04-17&#8242; -Dnow testzlib.c</em></p></blockquote>
<p>Opcja ,,-u&#8221; (unified) ma takie samo znaczenie jak dla ogólnie znanego<br />
programu diff i nie będę jej tu opisywał.Do repozytorium możemy dodawać nowe pliki i katalogi, a także je usuwać (z<br />
usuwaniem katalogów bywają zazwyczaj problemy i dlatego zazwyczaj się ich nie<br />
usuwa). Operację dodawania realizuje się za pomocą komendy ,,add&#8221;, natomiast<br />
usuwania ,,remove&#8221;. Przykład:</p>
<blockquote><p><em>[misiek@dark test]$ mv testzlib.c tzlib.c</em><em><br />
</em><em>[misiek@dark test]$ cvs remove testzlib.c</em><em><br />
</em><em>cvs server: scheduling `testzlib.c&#8217; for removal</em><em><br />
</em><em>cvs server: use &#8216;cvs commit&#8217; to remove this file permanently</em><em><br />
</em><em>[misiek@dark test]$ cvs add tzlib.c</em><em><br />
</em><em>cvs server: scheduling file `tzlib.c&#8217; for addition</em><em><br />
</em><em>cvs server: use &#8216;cvs commit&#8217; to add this file permanently</em><em><br />
</em><em>[misiek@dark test]$ cvs commit -m &#8220;- zmiana nazwy&#8221; testzlib.c tzlib.c</em><em><br />
</em><em>Removing testzlib.c;</em><em><br />
</em><em>/usr/src/CVSROOT/test/testzlib.c,v  <--  testzlib.c</em><em><br />
</em><em>new revision: delete; previous revision: 1.4</em><em><br />
</em><em>done</em><em><br />
</em><em>RCS file: /usr/src/CVSROOT/test/tzlib.c,v</em><em><br />
</em><em>done</em><em><br />
</em><em>Checking in tzlib.c;</em><em><br />
</em><em>/usr/src/CVSROOT/test/tzlib.c,v  <--  tzlib.c</em><em><br />
</em><em>initial revision: 1.1</em><em><br />
</em><em>done</em></p></blockquote>
<p>W ten sposób dokonałem zmiany nazwy pliku testzlib.c na tzlib.c. Plik tzlib.c<br />
jest traktowany przez CVS jako całkowicie nowy plik. Oczywiście do starych<br />
wersji pliku testzlib.c nadal mamy dostęp (aż do momentu gdy ktoś nie doda<br />
nowego pliku pod nazwą testzlib.c) ! Podczas dodawania plików binarnych należy<br />
stosować opcję ,,-kb&#8221;, która wyłącza konwersję końca linii.</p>
<p>CVS udostępnia wiele informacji na temat każdego z plików. Jedną z komend<br />
podających status pliku jest komenda ,,status&#8221;. Typowe wywołanie to:</p>
<blockquote><p><em>[misiek@dark test]$ cvs status tzlib.c</em></p></blockquote>
<p>Otrzymamy informacje o numerze rewizji, lokalizacji pliku w repozytorium,<br />
oznakowaniu pliku (nazwami symbolicznymi) itp. Najistotniejsze dla nas jest<br />
pole ,,Status:&#8221;. Plik może mieć jeden z poniższych statusów:<br />
- Up-to-date			- plik jest aktualny (identyczny z wersją<br />
w repozytorium)<br />
- Locally Modified		- lokalna kopia pliku została zmieniona<br />
- Locally Added			- plik został dodany do lokalnej kopii<br />
- Locally Removed		- plik został usunięty z lokalnej kopii<br />
- Needs Checkout		- ktoś dokonał zmian w pliku i przesłał<br />
- Needs Patch			  zmiany do repozytorium. Należy wykonać<br />
update.<br />
- Needs Merge			- wymagane jest połączenie naszych zmian<br />
w pliku ze zmianami innej osoby<br />
- File had conflicts on merge	- podczas łączenia wystąpiły konflikty<br />
- Unknown			- plik istnieje tylko w lokalnej kopii<br />
i nie posiada odpowiednika w repozytorium</p>
<p>Potrafimy już operować danymi zawartymi w repozytorium więc przyszła<br />
teraz pora na stworzenie własnego repozytorium. Jest kilka rodzajów<br />
repozytoriów (lokalne, zdalne) i kilka sposobów autoryzacji (serwer haseł<br />
(pserver), kerberos, ssh, rsh). Opiszę jak stworzyć repozytorium lokalne oraz<br />
zdalne (przy użyciu serwera haseł).</p>
<p>Pliki w repozytorium lokalnym jak i zdalnym są identyczne, tak<br />
więc tworzymy je w identyczny sposób &#8211; za pomocą komendy ,,init&#8221;:</p>
<blockquote><p><em>[misiek@dark example]$ cvs -d :local:/home/misiek/CVSREPO init</em><em><br />
</em><em>[misiek@dark example]$ ls -l /home/misiek/CVSREPO</em><em><br />
</em><em>razem 4</em><em><br />
</em><em>drwxrwxr-x    3 misiek   users        4096 kwi 17 22:28 CVSROOT</em></p></blockquote>
<p>Jak widać powstał katalog CVSREPO zawierający katalog CVSROOT z danymi<br />
administracyjnymi serwera CVS. Program ,,cvs&#8221; podczas wykonywania<br />
jakichkolwiek operacji związanych z repozytorium CVS musi wiedzieć gdzie owo<br />
repozytorium się znajduje. W powyższym przykładzie lokalizację repozytorium<br />
podaliśmy jako parametr dla opcji ,,-d&#8221;. Nasuwa się pytanie jakim cudem w<br />
poprzednich przykładach wszystko działało mimo iż nie było tam opcji ,,-d&#8221; ?<br />
Otóż zamiast ciągłego wpisywania parametru ,,-d&#8221; można lokalizację<br />
repozytorium ustawić w zmiennej $CVSROOT:</p>
<blockquote><p><em>[misiek@dark example]$ CVSROOT=&#8221;:local:/home/misiek/CVSREPO&#8221;; export CVSROOT</em></p></blockquote>
<p>Od tego momentu mamy już w pełni sprawny serwer CVS, można więc dodać nowe<br />
moduły ze źródłami oprogramowania (o czym później).</p>
<p>Oczywiste jest, że dostęp do repozytorium będą mieli tylko lokalni użytkownicy<br />
z prawem odczytu (zapisu) do katalogu ,,/home/misiek/CVSREPO&#8221;. W momencie gdy<br />
odpowiedniej grupie użytkowników damy prawo do zapisu do tegoż katalogu to<br />
każdy z nich będzie mógł wykonać ,,rm -rf /home/misiek/CVSREPO&#8221; dzięli czemu<br />
całe repozytorium powędruje do /dev/null. Lepszym w tym wypadku rozwiązaniem<br />
będzie dostęp do repozytorium poprzez sieć i serwer haseł.</p>
<p>Na początek należy dodać następujące linijki do pliku /etc/services:</p>
<blockquote><p><em>cvspserver      2401/tcp                        # CVS client/server operations</em><em><br />
</em><em>cvspserver      2401/udp                        # CVS client/server operations</em></p></blockquote>
<p>Następnie do serwera inetd dodajemy informacje o serwerze haseł, którego<br />
rolę pełni program &#8230; ,,cvs&#8221;:</p>
<p>U mnie  (rlinetd, /etc/rlinetd.conf) konfiguracja wygląda następująco:</p>
<blockquote><p><em>service &#8220;cvspserver&#8221; {</em><em><br />
</em><em>protocol        tcp;</em><em><br />
</em><em>port            &#8220;cvspserver&#8221;;</em><em><br />
</em><em>user            &#8220;misiek&#8221;;</em><em><br />
</em><em>server          &#8220;/usr/bin/cvs&#8221;;</em><em><br />
</em><em>exec            &#8220;cvs -f &#8211;allow-root=/home/misiek/CVSREPO pserver&#8221;;</em><em><br />
</em><em>initgroups;</em><em><br />
</em><em>}</em></p></blockquote>
<p>natomiast w przypadku inetd (/etc/inetd.conf):</p>
<blockquote><p><em>cvspserver  stream  tcp  nowait  misiek  /usr/bin/cvs  cvs</em><em><br />
</em><em>-f  &#8211;allow-root=/home/misiek/CVSREPO  pserver</em></p></blockquote>
<p>(opcja -f nakazuje nie używać pliku ~/.cvsrc)</p>
<p>Prawo zapisu i odczytu do wszystkie plików w repozytorium<br />
(/home/misiek/CVSREPO) ma jedynie użytkownik ,,misiek&#8221; co zapobiega żartom<br />
użytkowników typu ,,rm -rf&#8221; (zazwyczaj na potrzeby serwera CVSu zakłada się<br />
osobne konto, a ze względów bezpieczeństwa cały serwer jest umieszczony w<br />
,,więzieniu&#8221; uzyskanym za pomocą funkcji chroot(2)).</p>
<p>W przypadku korzystania ze zdalnego serwera (poprzez serwer haseł) zmienna<br />
$CVSROOT wyglądać może następująco:<br />
CVSROOT=&#8221;:pserver:misiek@localhost:/home/misiek/CVSREPO&#8221;</p>
<p>Użytkowników i ich hasła należy umieścić w pliku<br />
/home/misiek/CVSREPO/CVSROOT/passwd. Format pliku to: &#8220;użytkownik:hasło:grupa&#8221;<br />
np. &#8220;misiek:$1$Ba2OGOy.$exqx4uSoXIMPCaoPvuAJy1:users&#8221;. Pole ,,grupa&#8221; pojawiło<br />
się w nowszych wersjach CVSu i umożliwia przydzielanie określonym użytkownikom<br />
praw dostępu do określonych częsci repozytorium CVS (standardowo każdy<br />
użytkownik ma dostęp do wszystkich modułów repozytorium).  Hasło jest<br />
oczywiście zaszyfrowame. Najprościej do szyfrowania wykorzystać perla:</p>
<p>perl -e &#8216;print crypt &#8220;hasło&#8221;, &#8220;dwa dowolne znaki&#8221;; print &#8220;\n&#8221;; &#8216;</p>
<p>Nasze repozytorium stoi gotowe &#8211; czas umieścić w nim jakieś pliki. Posłużymy<br />
się kolejną komendą &#8211; ,,import&#8221;, która dodaje w całości nowy moduł.<br />
Przechodzimy do katalogu zawierającego nasze pliki i:</p>
<blockquote><p><em>[misiek@dark nowe]$ cvs import -m &#8220;- nowy modul&#8221; mojmodul misiek poczatek</em><em><br />
</em><em>N mojmodul/testr.c</em></p></blockquote>
<blockquote><p><em>No conflicts created by this import</em></p></blockquote>
<p>mojmodul &#8211; nazwa nowego modułu; misiek &#8211; kto dodaje moduł (źródło pochodzenia<br />
modułu czyli tzw. vendortag); poczatek &#8211; początkowa nazwa symboliczna (tzw.<br />
release tag).  Nie podałem nazw plików więc CVS zaimportował wszystkie pliki<br />
z aktualnego katalogu. Teraz musimy ściągnąć pliki z repozytorium za pomocą<br />
znanej już komendy ,,checkout&#8221;.</p>
<p>CVS pozwala także na używanie kilku słów kluczowych, które automatycznie<br />
są zastępowane odpowiednimi ciągami znaków. Wystarczy umieścić słowo kluczowe<br />
w dowolnym pliku, a podczas przesyłania poprawki do repozytorium (commit) CVS<br />
dokona odpowiednich zastąpień. Przykładowe słowa kluczowe (zastąpione już<br />
przez CVS):</p>
<blockquote><p><em>$Id: cvs-art.txt,v 1.7 2000/05/07 17:39:00 misiek Exp $</em><em><br />
</em><em>$Date: 2000/05/07 17:39:00 $</em><em><br />
</em><em>$Revision: 1.7 $</em><em><br />
</em><em>$Header: /usr/src/CVSROOT/rozne/cvs-art.txt,v 1.7 2000/05/07 17:39:00 misiek Exp $</em></p></blockquote>
<p>Kolejną niezastąpioną zaletą CVSu są odgałęzienia (branch). CVS pozwala<br />
na równoczesne prowadzenie kilku wersji plików. Sytuacja taka występuje gdy<br />
np. część programistów zajmuje się wersją stabilną programu, a część zajmuje<br />
się wersją rozwojową. W tego typu sytuacjach za pomocą komendy tag lub rtag<br />
ale z opcją ,,-b&#8221;. CVS umożliwia także wprowadzanie zmian z np. odgałęzienia<br />
devel do odgałęzienia stable za pomocą komendy update z opcją ,,-j&#8221;.</p>
<p>Niemal wszystkie pliki konfiguracyjne związane z serwerem CVS znajdują<br />
się w specjalnym module o nazwie ,,CVSROOT&#8221;. Użytkownicy mają oczywiście<br />
dostęp do tego modułu i mogą go sprowadzić z repozytorium. Najbardziej<br />
interesujące są dla nas pliki:<br />
- checkoutlist<br />
Pliki znajdujące się w module CVSROOT, a których nazwy wpiszemy do<br />
pliku checkoutlist pojawią się po stronie serwera zarówno w formacie zrozumiałym<br />
przez RCS jak i w zwykłej postaci jaką użytkownicy widzą po sprowadzeniu plików<br />
do lokalnego repozytorium. Typowo w checkoutlist umieszcza się skrypty do<br />
generowania plików ChangeLog, do wysyłania informacji o zmianach w<br />
repozytorium na listę dyskusyjną itp. Ze względów bezpieczeństwa nie należy<br />
umieszczać tam pliku ,,passwd&#8221;.<br />
- commitinfo<br />
zazwyczaj w tym pliku umieszczamy wywołania skryptu (np. commit_scan)<br />
który przygotowuje dane przychodzące podczas przesyłania poprawek do obróbki<br />
przez kolejny skrypt (np. log_accum.pl).<br />
- config<br />
zawiera podstawowe opcje konfiguracji serwera CVS. Najistotniejszą<br />
opcją jest opcja SystemAuth. Ustawienie jej na ,,yes&#8221; wymusza na serwerze<br />
haseł przeszukiwanie systemowej bazy haseł (np. /etc/shadow) w przypadku gdy<br />
użytkownik nie został znaleziony w bazie serwera CVS (CVSROOT/passwd)).<br />
- cvswrappers<br />
pozwala wymusić pewne opcje podczas dodawania określonych plików i tak<br />
np. podanie w tym pliku ,, *.jpg -k &#8216;b&#8217; &#8221; jest równoważne z podawaniem opcji<br />
,,-kb&#8221; podczas dodawania plików *.jpg.<br />
- loginfo<br />
w tym pliku umieszczać należy wywołania skryptów operujących na danych<br />
dostarczonych podczas przesyłania poprawek (commit) i przetworzonych przez<br />
skrypty wywoływane w pliku commitinfo. Może to być wywołanie np. skryptu<br />
log_accum.pl.<br />
- modules<br />
zawiera listę modułów. Można tworzyć moduły odwołujące się do innych<br />
modułów itp.</p>
<p>W module CVSROOT może znajdować się dodatkowo kilka innych plików<br />
administracyjnych jednak nie są one aż tak istotne jak przedstawione powyżej.</p>
<p>W pewnych sytuacjach (szczególnie przy projektach, w których uczestniczy<br />
duża ilość programistów) rozwiązanie serwer <--> klienci powoduje znaczne<br />
obciążenie serwera, a co za tym idzie spowolnienie pracy i pogorszenie się<br />
komfortu wspólnej pracy nad projektem poprzez CVS. By odciążyć serwer stawia<br />
się serwery kopie udostępniające zasoby jedynie w trybie tylko do odczytu<br />
(serwery kopie mogą synchronizować swe zasoby np. za pomocą protokołu rsync<br />
rozwijanego przez SAMBA Team). Mimo to poprawki nadal muszą być przesyłane do<br />
serwera głównego.</p>
<p>W typowym projekcie serwer CVS poprzez komendy zawarte w plikach<br />
administracyjnych sprzężony jest z listą dyskusyjną na którą przesyłane są<br />
informacje o zmianach zachodzących w CVSie (po każdym wysłaniu poprawek),<br />
uruchamiane są programy generujące pliki ChangeLog itp. Ponadto zasoby<br />
serwerów CVS często bywają udostępniane poprzez www za pomocą skryptów cvsweb,<br />
viewcvs. Ze stron można ściągać określone wersje plików, różnice pomiędzy<br />
plikami, oglądać historie danych plików itp.</p>
<p>CVS jest wartościowym narzędziem również dla pojedynczych programistów<br />
(sam osobiście w lokalnym CVSie trzymam oprogramowanie, skrypty, artykuły,<br />
dokumentację itp.) czy nawet webmasterów (dla przykładu podam, że strony<br />
http://www.pld.org.pl/ są przechowywane i automatycznie uaktualniane właśnie<br />
na podstawie repozytorium). Innym udogodnieniem jakie niesie CVS jest np.<br />
możliwość łatwego generowania pakietów rpm na podstawie najnowszych zasobów<br />
znajdujących się w CVSie PLD. Przy odpowiednich ustawieniach wystarczy<br />
wykonać: cd rpm/SPECS &#038;&#038; ./builder -bb nazwa_speca.spec, a wszystkie niezbędne<br />
do wygenerowania binarnego pakietu rpm pliki zostaną automatycznie ściągnięte<br />
i przebudowane. Udogodnienie to jest specyficzne bo dotyczy niemal wyłącznie<br />
użytkowników CVSu PLD jednak podaję tu ten przykład by pokazać ogromne<br />
możliwości jakie dżemią w systemie kontroli wersji &#8211; możliwości zależne jedynie<br />
od pomysłów administratora czy programistów. Wspomnę jeszcze, że CVS istnieje<br />
również w wersji dla Windows co umożliwia wygodną pracę nad wielosystemowymi<br />
projektami programistom używającym różnych systemów operacyjnych.</p>
<p>Co i skąd ?<br />
Lista dyskusyjna dotycząca oprogramowania CVS:<br />
info-cvs@gnu.org (zapisy pod adresem: info-cvs-request@gnu.org)<br />
CVS	(system kontroli wersji)</p>
<p>http://download.cyclic.com/pub/</p>
<p>RCS	(system kontroli rewizji)<br />
ftp://ftp.task.gda.pl:/pub/gnu/rcs-5.7.tar.gz<br />
LinCVS	(graficzna nakładka na CVS wykorzystująca interfejs Qt)</p>
<p>http://www.iapp.de/~trogisch/linux/lincvsen.html</p>
<p>tkcvs	(graficzna nakładka na CVS wykorzystująca interfejs Tk)</p>
<p>http://www.teleport.com/~mokuren/</p>
<p>cvsweb	(bramka CVS -> WWW jako skrypt CGI w perlu)</p>
<p>http://www.freebsd.org/~fenner/cvsweb/</p>
<p>cvsweb	(rozbudowana wersja poprzedniego skryptu)</p>
<p>http://linux.fh-heilbronn.de/~zeller/cgi/cvsweb.cgi</p>
<p>Przykładowy serwis: http://cvs.pld.org.pl/<br />
viewcvs	(bramka CVS -> WWW jako skrypt CGI w pythonie)</p>
<p>http://www.lyra.org/greg/python/viewcvs/</p>
<p>Przykładowy serwis: http://cvsweb.pld.org.pl/<br />
cvs2cl	(odpowiednik rcs2log służący do generowania plików ChangeLog<br />
napisany w perlu)</p>
<p>http://www.red-bean.com/~kfogel/cvs2cl.shtml</p>
<p>O autorze:<br />
Autor jest studentem informatyki na Politechnice Wrocławskiej<br />
oraz członkiem zespołu PLD GNU/Linux.<br />
Z autorem można się skontaktować pod adresem: misiek@pld.org.pl</p>
<p><a href="http://www.maven.pl/wp-content/uploads/2006/04/CVSROOT-example.tar.gz" title="CVSROOT example">Przykłady</a></p>
]]></content:encoded>
			<wfw:commentRss>http://readme.maven.pl/2000/05/07/cvs-system-kontroli-wersji/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>GNU gettext z punktu widzenia programisty oraz tłumacza</title>
		<link>http://readme.maven.pl/2000/03/12/gnu-gettext-z-punktu-widzenia-programisty-oraz-tlumacza/</link>
		<comments>http://readme.maven.pl/2000/03/12/gnu-gettext-z-punktu-widzenia-programisty-oraz-tlumacza/#comments</comments>
		<pubDate>Sun, 12 Mar 2000 21:14:54 +0000</pubDate>
		<dc:creator>arekm</dc:creator>
				<category><![CDATA[Software]]></category>

		<guid isPermaLink="false">http://www.maven.pl/?p=13</guid>
		<description><![CDATA[GNU gettext dla programisty i tłumacza Arkadiusz Miśkiewicz $Id: gettext-art.lyx,v 1.1 2000/03/12 21:12:04 misiek Exp $ 1 Wprowadzenie Systemy UNIX, a w szczególności Linux zdobywają coraz większą popularność na świecie. Linux używany jest zarówno przez wyszkolonych administratorów jak i początkujących. Kilku programistów wychodząc na przeciw początkującym użytkownikom nie znającym języka angielskiego stworzyło pakiet GNU gettext. [...]]]></description>
			<content:encoded><![CDATA[<p><strong>GNU gettext dla programisty i tłumacza</strong></p>
<p>Arkadiusz Miśkiewicz <misiek@pld.org.pl></p>
<p>$Id: gettext-art.lyx,v 1.1 2000/03/12 21:12:04 misiek Exp $</p>
<p><strong>1 Wprowadzenie</strong></p>
<p>Systemy UNIX, a w szczególności Linux zdobywają coraz większą popularność<br />
na świecie. Linux używany jest zarówno przez wyszkolonych administratorów<br />
jak i początkujących. Kilku programistów wychodząc na przeciw początkującym<br />
użytkownikom nie znającym języka angielskiego stworzyło pakiet GNU<br />
gettext. GNU gettext jest zbiorem aplikacji oraz bibliotek przeznaczonych<br />
do tworzenia programów oraz skryptów potrafiących komunikować się<br />
z użytkownikiem w dowolnym (obsługiwanym) języku.</p>
<p><span id="more-13"></span></p>
<p><strong>2 Jak to działa ?</strong></p>
<p>GNU gettext działa na zasadzie modułowej. Każde nowe tłumaczenie programu<br />
jest osobnym plikiem tzw. plikiem MO (jeden plik dla każdego języka).<br />
W większości dystrybucji Linuxa tego typu pliki można znaleźć w katalogach<br />
/usr/share/locale/*/LC_MESSAGES/. Załóżmy, że jakiś program wyświetla<br />
tekst &#8220;Hello world!&#8221;. Gdy ów program będzie wykorzystywał gettext<br />
zostaną wykonane następujące operacje:</p>
<p>1. sprawdź aktualne zmienne locale (opisane w locale(7)). Najczęściej<br />
używa się zmiennych LC_ALL oraz LANG.</p>
<p>2. sprawdź czy istnieje odpowiedni plik MO dla języka określonego w<br />
zmiennych locale.</p>
<p>3. jeśli istnieje &#8211; wczytaj i używaj tłumaczeń; jeśli nie istnieje -<br />
użyj domyślnego języka (w naszym przykładzie jest to język angielski).</p>
<p>Zaletą takiego rozwiązania jest to, że na jednym systemie może pracować<br />
kilkunastu użytkowników używających różnych języków ! Ponadto dodanie<br />
nowego tłumaczenia to tylko dodanie jednego niewielkiego pliku. Jeśli<br />
czytelnik zaglądał to któregoś z plików MO to zapewne wie iż jest<br />
to plik binarny. Pliki binarne MO generowane są z plików tekstowych<br />
PO (zazwyczaj dostępnych wraz ze źródłami programu) przez niewielki<br />
program ,,msgfmt&#8221; należący do pakietu gettext.</p>
<p><strong>3 Chcę zostać tłumaczem.</strong></p>
<p>Pliki tekstowe PO są to pliki zawierające wszystkie komunikaty w języku<br />
domyślnym oraz (po przetłumaczeniu) komunikaty w języku docelowym<br />
(np. polskim). Fragment typowego pliku PO przed tłumaczeniem wygląda<br />
mniej więcej tak (w nawiasach klamrowych moje komentarze, których<br />
nie powinno być w oryginalnym pliku PO):</p>
<p>#: src/man-config.c:233<br />
{ nazwa pliku i numer lini, w której występuje podany tekst }<br />
#, c-format<br />
{ dodatkowe informacje o tekście }<br />
msgid &#8220;Reading config file %s\n&#8221;<br />
{ sam tekst w języku domyślnym }<br />
msgstr &#8220;&#8221;<br />
{ miejsce na tekst w języku docelowym }</p>
<p>Praca tłumacza sprowadza się do przetłumaczenia tekstu znajdującego<br />
się po polu msgid na język docelowy. Uwaga: nie wolno zmieniać tekstu<br />
znajdującego się po polu msgid ! Powyższy fragment po przetłumaczeniu<br />
może wyglądać tak:</p>
<p>#: src/man-config.c:233<br />
#, c-format<br />
msgid &#8220;Reading config file %s\n&#8221;<br />
msgstr &#8220;Odczytuję plik konfiguracyjny %s\n&#8221;</p>
<p>Powyżej, w komentarzu do ,,c-format&#8221; napisałem o ,,dodatkowych informacjach<br />
o tekście&#8221;. W miejscu tym może się pojawić kilka słów kluczowych:</p>
<p>* fuzzy. Generowane przez program msgmerge (o którym później). Oznacza<br />
to iż prawdopodobnie tłumaczenie nie jest prawidłowe. Po skontrolowaniu<br />
poprawności tłumaczenia usuwamy słowo fuzzy z pliku PO.</p>
<p>* c-format, no-c-format. Dodawane automatycznie (nie powinny być dodawane<br />
czy modyfikowane przez użytkownika). Odpowiednio oznaczają, że tekst<br />
zawiera znaki formatujące z języka C, oraz że ich nie zawiera. Słowo<br />
c-format jest jednocześnie sygnałem dla msgfmt by zwrócił większą<br />
uwagę na poprawność tłumaczenia tegoż tekstu podczas generowania<br />
plików MO.</p>
<p>Przed zabraniem się do tłumaczenia pliku PO pochodzącego z jakiegoś<br />
programu należy zaktualizować plik PO. W typowym programie wykorzystującym<br />
autoconf&#8217;a wygląda to mniej więcej tak: ./configure &#038;&#038; make -C po<br />
update-po. Oczywiście można wygenerować nowy plik PO (bez żadnych<br />
tłumaczeń) wykonując ./configure &#038;&#038; make -C po Nazwa_Programu.pot.<br />
Powstanie plik *.pot &#8211; zwykły plik PO nie zawierający żadnych tłumaczeń<br />
(POT == PO Template). Pozostaje jedynie zabranie się za tłumaczenie<br />
pliku. Przyjęto zasadę by w tłumaczeniach używać form bezosobowych.</p>
<p>Poprawność syntaksy przetłumaczonego pliku PO można sprawdzić przy<br />
użyciu msgfmt: msgfmt -v plik.po -o /dev/null. Program poinformuje<br />
o wszelkich nieprawidłowościach. Rola tłumacza właściwie się tu kończy.<br />
Przetłumaczony plik należy przesłać do odpowiedniej grupy tłumaczy<br />
GNU (np. polska grupa tłumaczy GNU jest dostępna pod adresem: pl@li.org)<br />
lub autora programu.</p>
<p><strong>4 Piszę program i chcę dodać obsługę wielu języków.</strong></p>
<p>Poniższy opis dotyczy nie tylko autorów nowych programów ale także<br />
wszystkich osób, które chcą dodać obsługę języków do już istniejącego<br />
oprogramowania. Na początek parę słów o programach oferowanych w pakiecie<br />
GNU gettext:</p>
<p>- gettextize; wykonanie tego skryptu w katalogu, w którym znajduje<br />
się nasz program spowoduje stworzenie struktury katalogów i skopiowanie<br />
standardowych plików używanych przez gettext podczas kompilacji itp.<br />
Ponadto skopiowane zostaną źródła biblioteki libintl na wypadek gdyby<br />
systemowa biblioteka nie obsługiwała funkcji gettext() i jej towarzyszących.</p>
<p>* msgcmp; porównuje dwa pliki PO, żeby sprawdzić czy zawierają te same<br />
zbiory łańcuchów msgid.</p>
<p>* msgcomm; wyszukuje podobne zbiory łańcuchów w plikach PO</p>
<p>* msgfmt; generuje binarne pliki MO z plików tekstowych PO</p>
<p>* msghack; do automatycznej zmiany plików PO np. zamiany miejscami<br />
zbiorów msgid z msgfmt.</p>
<p>* msgmerge; łączy dwa pliki PO, tak by wynikowy plik zawierał maksimum<br />
tłumaczeń z podanych dwóch plików</p>
<p>* msgunfmt; funkcja odwrotna do msgfmt</p>
<p>* xgettext; generuje plik PO z tekstami do przetłumaczenia wynajdując<br />
je w plikach źródłowych programu (*.c itp).</p>
<p>Część z powyższych programów nie wchodzi w skład standardowej dystrybucji<br />
GNU gettext i jest dostępna w formie patchy (pełny pakiet m.in. w<br />
PLD GNU/Linuxie).</p>
<p>Programiście pakiet gettext oferuje kilka funkcji:</p>
<p>char *textdomain (const char *domain_name);</p>
<p>- funkcja ustala tzw. TEXTDOMAIN. Tłumaczenia będą pobierane z pliku<br />
TEXTDOMAIN.mo z katalogu zależnego od ustawień systemowych (typowo<br />
jest to /usr/share/locale/).</p>
<p>char *bindtextdomain (const char *domain_name, const char *dir_name);</p>
<p>- funkcja ,,przydziela&#8221; danej domenie (domain_name) katalog, w którym<br />
będzie poszukiwany plik TEXTDOMAIN.mo (na wypadek gdyby występowało<br />
kilka plików *.mo o tej samej nazwie).</p>
<p>char *gettext (const char *msgid);</p>
<p>- funkcja, której przekazujemy string do tłumaczenia.</p>
<p>char *dgettext (const char *domain_name, const char *msgid);<br />
char *dcgettext (const char *domain_name, const char *msgid, int category);</p>
<p>- funkcje będące połączeniem funkcji gettext() z bindtextdomain();.</p>
<p>Poza powyższymi funkcjami wykorzystuje się jeszcze jedną zawartą w<br />
bibliotece glibc &#8211; setlocale(3). Funkcja ta służy do ustawienia aktualnie<br />
używanego locale. Prototyp tej funkcji to:</p>
<p>char *setlocale(int category, const char *locale);</p>
<p>gdzie category to nazwa kategorii dla jakiej ustawiamy locale (typowo<br />
jest to LC_ALL lub LC_MESSAGES) natomiast locale może być zarówno<br />
pustym stringiem &#8220;&#8221; (wtedy locale zostanie ustawione zgodnie z wartościami<br />
zmiennych powłoki odpowiedzialnych za locale tj. LC_ALL, LC_MESSAGES<br />
itd) lub stringiem oznaczającym język dla jakiego ustawiamy locale<br />
(np. &#8220;da_DK&#8221;). Ponieważ w większości wypadków program powinien wykorzystywać<br />
zmienne powłoki dlatego będziemy używali pustego stringu &#8220;&#8221; jako locale<br />
w funkcji setlocale(3).</p>
<p>Dla ułatwienia sobie pracy zamiast funkcji gettext będziemy używali<br />
makra _(). Ponadto zdefiniujemy puste makro pełniące funkcję informatora<br />
dla programu xgettext (o czym później).</p>
<p>#define _(String) gettext(String)<br />
#define N_(String) (String)</p>
<p>Dodajmy więc obsługę gettextu do przykładowego programu:</p>
<p>#include <stdio.h><br />
int main()<br />
{<br />
printf(&#8220;Hello world!\n&#8221;);<br />
exit(0);<br />
}</p>
<p>Po pierwsze musimy włączyć dodatkowe pliki nagłówkowe: &#8220;libintl.h&#8221;<br />
(zawiera funkcje typowe dla gettextu) oraz &#8220;locale.h&#8221; (prototyp funkcji<br />
setlocale(3)). Następnie dodajemy ustawienie locale, przydzielenie<br />
TEXTDOMAIN, a we wszystkie teksty, które mają być tłumaczone przekazujemy<br />
do funkcji gettext() (w naszym wypadku za pośrednictwem makra _()).<br />
W efekcie plik będzie wyglądał następująco:</p>
<p>#include <stdio.h><br />
#include</p>
<libintl.h>
#include <locale.h></p>
<p>#define _(String) gettext(String)</p>
<p>int main()<br />
{<br />
setlocale(LC_ALL, &#8220;&#8221;);<br />
bindtextdomain(&#8220;example&#8221;, &#8220;/usr/share/locale&#8221;);<br />
textdomain(&#8220;example&#8221;);<br />
printf(_(&#8220;Hello world!\n&#8221;));<br />
exit(0);<br />
}</p>
<p>Uważny czytelnik zapewne zauważył, że puste makro N_() nigdzie nie<br />
zostało użyte &#8211; więc po co ono jest potrzebne. Otóż program xgettext<br />
(o którym pisałem wcześniej) generuje plik PO wyszukując w plikach<br />
*.c teksty przekazywane do funkcji gettext(). W naszym programie przykładowym<br />
xgettext znalazł by tekst &#8220;Hello world!\n&#8221;. Niestety w pewnych okolicznościach<br />
nie można bezpośrednio używać funkcji gettext() np. mamy:</p>
<p>char *tablica[] = { &#8220;dog\n&#8221;, &#8220;cat\n&#8221;, &#8220;Poland\n&#8221; };<br />
[...]<br />
int main()<br />
{<br />
int i;<br />
[...]<br />
for (i = 0; i < 3; i++)<br />
printf(tablica[i]);<br />
}</p>
<p>Użycie funkcji gettext() w definicji "tablica" jest oczywistym błędem<br />
programisty. Wyjściem z tej sytuacji jest właśnie makro N_(). Powyższy<br />
program w wersji z obsługą gettextu:</p>
<p>#define _(String)       gettext(String)<br />
#define N_(String)      (String)<br />
char *tablica[] = { N_("dog\n"), N_("cat\n"), N_("Poland\n") };<br />
[...]<br />
int main()<br />
{<br />
int i;<br />
[...]   /* tutaj powinny znaleźć się funckcje<br />
setlocale(), textdomain() itd */<br />
for (i = 0; i < 3; i++)<br />
printf(_(tablica[i]));<br />
}</p>
<p>xgettext dzięki N_() będzie teraz ,,wiedział'', które teksty są przeznaczone<br />
do tłumaczenia, a sama funkcja gettext() zajmie się tłumaczeniem.</p>
<p>No dobrze. Mamy już pliki źródłowe zawierające odpowiednie wywołania<br />
funkcji gettext(). Jak teraz wygenerować plik PO ? Właśnie w tym momencie<br />
użyjemy programu xgettext:</p>
<p>$ xgettext -d example -o example.po -s plik1.c plik2.c plik3.c</p>
<p>W wyniku działania programu xgettext (na pliku z pierwszym przykładem<br />
- "Hello world" otrzymamy plik PO o następującej zawartości):</p>
<p># SOME DESCRIPTIVE TITLE.<br />
# Copyright (C) YEAR Free Software Foundation, Inc.<br />
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.<br />
#<br />
#, fuzzy<br />
msgid &#8220;&#8221;<br />
msgstr &#8220;&#8221;<br />
&#8220;Project-Id-Version: PACKAGE VERSION\n&#8221;<br />
&#8220;POT-Creation-Date: 2000-03-10 22:28+0100\n&#8221;<br />
&#8220;PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n&#8221;<br />
&#8220;Last-Translator: FULL NAME <EMAIL@ADDRESS>\n&#8221;<br />
&#8220;Language-Team: LANGUAGE <LL@li.org>\n&#8221;<br />
&#8220;MIME-Version: 1.0\n&#8221;<br />
&#8220;Content-Type: text/plain; charset=CHARSET\n&#8221;<br />
&#8220;Content-Transfer-Encoding: ENCODING\n&#8221;</p>
<p>#: przyklad1.c:17<br />
msgid &#8220;Hello world!\n&#8221;<br />
msgstr &#8220;&#8221;</p>
<p>Po przetłumaczeniu pliku PO generujemy plik MO:</p>
<p>$ msgfmt example.po -o example.mo</p>
<p>i kopiujemy go do katalogu /usr/share/locale/JĘZYK/LC_MESSAGES/ (gdzie<br />
JĘZYK to kilkuliterowa nazwa oznaczająca określony język. Dla języka<br />
polskiego będzie to &#8220;pl&#8221;).</p>
<p>Pozostaje już tylko podziwianie efektów naszej pracy:</p>
<p>$ LANG=pl ./przyklad1<br />
Witaj świecie!<br />
$ LANG=C  ./przyklad1<br />
Hello world!</p>
<p>(&#8220;C&#8221; &#8211; oznacza domyślny język ustawiony w bibliotece systemowej; typowo<br />
jest to język angielski).</p>
<p>Programiści stosujący pakiety automake oraz autoconf w swych programach<br />
mogą używać paru ułatwień związanych z gettextem. Po pierwsze należy<br />
uruchomić program gettextize (o którym już pisałem):</p>
<p>~/moj_program/$ gettextize -c -f</p>
<p>Do configure.in dodajemy:</p>
<p>ALL_LINGUAS=&#8221;pl&#8221; &#8211; lista języków dla których już posiadamy tłumaczenie<br />
(oddzielone spacją np. &#8220;pl fr de&#8221;)</p>
<p>AM_GNU_GETTEXT &#8211; makro robiące całą czarną robotę i przegenerowujemy<br />
skrypt configure (wywołując program: autoconf).</p>
<p>To już wszystkie najważniejsze rzeczy dotyczące dodawania gettextu<br />
do programów. Pełną informację jak zawsze można znaleźć na stronach<br />
info dostarczanych z pakietem GNU gettext.</p>
<p><strong>5 A co ze skryptami w shellu czy perlu lub innych językach ?</strong></p>
<p>Jedyną znaną mi powłoką obsługującą skrypty z tłumaczeniami jest bash<br />
2. W skrypcie basha 2 wpisujemy po prostu:</p>
<p>$ echo $&#8221;Hello world!&#8221;</p>
<p>Plik PO przygotowujemy natomiast przy użyciu samej powłoki:</p>
<p>$ bash &#8211;dump-po-strings skrypt.sh</p>
<p>Generację pliku MO przeprowadzamy już przy użyciu msgfmt z pakietu<br />
GNU gettext. Należy ponadto w skrypcie ustawić zmienną TEXTDOMAIN<br />
na nazwę tekstowej domeny. Niestety nie każdy ma czy chce używać basha<br />
2. Pozostali powinni wykorzystywać w swych skryptach program gettext<br />
zawarty w pakiecie GNU gettext. Przykładowe wywołanie to:</p>
<p>$ gettext &#8211;domain=TEXTDOMAIN &#8220;Hello world!&#8221;</p>
<p>Mogę na marginesie dodać, że dzięki tej metodzie skrypty startowe w<br />
PLD GNU/Linuxie potrafią komunikować się z użytkownikiem m.in. w języku<br />
polskim ! Podobna sytuacja jest w perlu &#8211; wystarczy ściągnąć dodatkowy<br />
moduł z archiwum CPAN dodający funkcję gettext. Z gettextu można również<br />
korzystać pisząc programy w innych, nie wspomnianych tutaj językach<br />
programowania np. w pascalu (FreePascal Compilator), a także pod innymi<br />
niż Unixowe systemami  &#8211; np. pod DOSem (dzięki źródłom biblioteki libintl).</p>
<p><strong>6 Problemy z GNU gettextem.</strong></p>
<p>Niestety gettext nie jest rozwiązaniem idealnym. Jest to narzędzie<br />
dość ograniczone. Podstawowym problemem jest odmiana czy liczba mnoga.<br />
W języku angielskim kilka plików to po prostu ,,files&#8221;. W języku<br />
polskim sytuacja się zmienia zależnie od ilości plików (2,3,4 pliki;<br />
5-21 plików itd), natomiast GNU gettext nie pozwala na tłumaczenie<br />
zależne od np. ilości plików. Problem ten nie został rozwiązany do<br />
dnia dzisiejszego (osobom zainteresowanym polecam kod źródłowy programu<br />
lftp, w którym gettext został uzupełniony o częściowe rozwiązanie<br />
umożliwiające tłumaczenie z uwzględnieniem odmian itp.).</p>
<p><strong>7 Na zakończenie.</strong></p>
<p>Mimo licznych ograniczeń GNU gettext jest ważnym narzędziem przybliżającym<br />
środowisko Linuxa ludziom z poza grona osób znających język angielski<br />
- np. sporej liczbie użytkowników polskiej wersji Windows 8-). Zapraszam<br />
wszystkich chętnych do tlumaczenia plików PO w ramach GNU Translation<br />
Project oraz do dodawania obsługi gettexu do już istniejących programów.</p>
<p><strong>8 Adresy.</strong></p>
<p>* GNU Translation Project</p>
<p>http://www.iro.umontreal.ca/~pinard/po/HTML/</p>
<p>http://www.iro.umontreal.ca/contrib/po/</p>
<p>* Polski ,,oddział&#8221; GNU Translation Project</p>
<p>http://www.ceti.com.pl/~kravietz/gnu/gnu_tp.html</p>
<p>* Repozytorium CVS PL GNU TP</p>
<p>http://cvsweb.pld.org.pl/index.cgi/i18n/</p>
<p>* Słownik informatyczny, zasady tłumaczenia tekstów informatycznych</p>
<p>http://venus.ci.uw.edu.pl/~milek/</p>
<p><strong>9. <a href="http://www.maven.pl/wp-content/uploads/2006/04/gettext-example.tar.gz" title="Przykłady z gettext">Przykłady</a></strong></p>
]]></content:encoded>
			<wfw:commentRss>http://readme.maven.pl/2000/03/12/gnu-gettext-z-punktu-widzenia-programisty-oraz-tlumacza/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

