顯示具有 Linux 標籤的文章。 顯示所有文章
顯示具有 Linux 標籤的文章。 顯示所有文章

12 11月 2013

[Linux/Android] Export API for SharedLibrary (.so)

當開發一個 SharedLibrary (.so) 時,不想 Export 太多 API 出去(可能涉及商業機密或是單純的爽字),Windows or Linux 都有做法可以做到,這邊只說明一下 Linux / Android 的做法。

用 nm 觀察 .so 的 Symbol Table

nm -gC MyLib.so
  • -g : 只列出 external symbol
  • -C : 將 C++ 的 symbol 轉換成易讀的版本

09 5月 2008

[Linux] 基本的Timer介紹

Linux提供了兩種基本的Timer機制可以使用:
  • alarm
  • setitimer

● alarm
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
這是一個簡單的設定Timer介面。當呼叫了alarm( n )後,等待n秒後,就會觸發一次的SIGALRM的signal,所以必須要在呼叫alarm前,先設好SIGALRM的handler function才行。而當乎呼alarm(0)時,則表示停止當前的timer處理,不要發出SIGALRM的signal。

Return value : 返回上一次呼叫alarm的剩餘秒數。若未設定alarm,則返回0。

Example : 第一次等待1秒後觸發Timer,之後每隔2秒觸發一次。
#include <iostream>
#include <unistd.h>
#include <signal.h>

using namespace std;

void my_alarm_handler(int a)
{
cerr<<"my_alarm_handler"<<endl;
alarm(2);//重新設定
}

int main()
{
signal( SIGALRM, my_alarm_handler );
alarm(1);

while(1){}

return 0;
}

--------------------------------------------------------------------------------------
● setitimer
#include <sys/time.h>
#define ITIMER_REAL 0
#define ITIMER_VIRTUAL 1
#define ITIMER_PROF 2

int getitimer(int which, struct itimerval *value);

int setitimer(int which, const struct itimerval *value,
struct itimerval *ovalue);
setitimer與getitimer提供了三種類別的Timer使用:
  • ITIMER_REAL : 以系統真實的時間來計算,觸發時會送出SIGALRM。
  • ITIMER_VIRTUAL : 只計算process真正在執行的時間(在User Mode的處理),觸發時會送出SIGVTALRM。
  • ITIMER_PROF : 計算該process在User Mode與Kernel Mode的處理時間,觸發時送出SIGPROF。
透過第一個參數which指定要使用哪一種Timer (ITIMER_REAL, ITIMER_VIRTUAL, ITIMER_PROF )。setitimer是用來設定該種Timer的觸發時間為多少。getitimer則是取得上一次Timer設定的時間。設定的內容是一個系統內建的struct itimerval:
struct itimerval {
   struct timeval it_interval; /* next value : 下一次觸發所需的時間*/
   struct timeval it_value; /* current value : 目前距離觸發時間點 剩餘的時間*/
};
struct timeval {
   long tv_sec; /* seconds */
   long tv_usec; /* microseconds */
};

setitimer由第二個參數value設定觸發的時間。第三個參數ovalue用來取得上一次 setitimer設定的itimerval值(此參數可以為NULL)。值得注意的是,根據itimerval裡變數的意義,當it_interval設定為0時,Timer只會觸發一次。而it_value設定為0時,代表Timer結束。

Return value : 如果成功則return 0,失敗則return -1。

Example : 第一次等待1秒後觸發Timer,之後每隔2秒觸發一次。
#include <iostream>
#include <sys/time.h>
#include <signal.h>

using namespace std;

void my_alarm_handler(int a)
{
cerr<<"test "<<endl;
}


int main(){
struct itimerval t;
t.it_interval.tv_usec = 0;
t.it_interval.tv_sec = 2;
t.it_value.tv_usec = 0;
t.it_value.tv_sec = 1;

if( setitimer( ITIMER_REAL, &t, NULL) < 0 ){
cerr<<"settimer error."<<endl;
return -1;
}
signal( SIGALRM, my_alarm_handler );

while(1){
sleep(2);
}
return 0;
}

● 根據以上,可知Linux內建的Timer還是有點簡陋,而且setitimer同一時間只能處理3個Timer,如果應用程式需要多個Timer的話,這個Linux內建的Timer可能就不敷需求了!

03 1月 2008

[Linux] 搜尋資料夾底下 檔案內部文字

find "path name" -name "file name" -exec grep -H "search content" {} \;

find原本是用「檔案名稱」來搜尋在哪些地方有這些檔案,將這些路徑結果餵給grep後,就可以拿來搜尋檔案內部的文字片段。

Ex:
find ./kernel -name "*.c" -exec grep -H "main" {} \;
以上這段指令,是要搜尋./kernel底下所有的.c檔,內容含有"main"的地方。

find的參數:
  -name 要搜尋哪些檔名
  -exec utility name [argument...] {} \;
    搜尋出的檔名 交給哪個執行檔(utility name)處理
    {} 會被find搜尋後的檔名路徑名稱所取代
    \; 代表exec的參數到此為止

grep的參數:
  -H 列出搜尋到的檔案名稱路徑

16 11月 2007

Linux iconv遞迴轉換資料夾底下的檔案編碼

在Linuxl底下有個好用的轉編碼的小工具 - iconv
不過,這個iconv只能拿來轉單一個檔案,並不能直接指定一個資料夾下去遞迴轉換。所有當有大量的檔案需要轉編碼時,就變得有點麻煩了。還好Linux強大的shell指令,可以幫忙解決這個問題,而解決的曙光就來自於find!
find -type f -exec iconv --verbose -f BIG-5 -t UTF-8 {} -o {}.result \;  \
-exec mv {} {}.bak \; \
-exec mv {}.result {} \;

以上這段指令分三個階段執行,
  1. 將目前所在的資料夾的檔案找出,丟給iconv執行轉碼,先將結果暫存至{原檔名}.result
  2. 將原本的檔案,改名為{原檔名}.bak
  3. 再將剛暫存的{原檔名}.result,改名稱{原檔名}

iconv的簡介
-l 列出所有支援的編碼格式
-f 要轉換的來源編碼
-t 要轉換的結果編碼
-o 輸出結果的檔案
--verbose 列出處理的檔案名稱


find的簡介
-type [option] 想找出的檔案類型
  • f : 正規的檔案
  • d : 資料夾
-exec [command] 執行指定的command
  • 所有在exec之後的參數,都會被當成是該command的參數,直到 '\;' 符號出現為止
  • 正在處理的檔案名稱,以'{}'取代
-print 印出正在處理的檔名


%% 奇怪的事又發生了,我是使用Ubuntu,shell是tcsh,直接執行「find -type f -exec iconv --verbose -f BIG-5 -t UTF-8 {} -o {}.result \;」,結果檔並不會產生,真的是很奇怪,一定要三部分一起寫才有用,有高手可以跟我解釋一下嗎>_<

15 11月 2007

Linux中 字串的取代指令

一般人以為對字串的處理(刪除、取代)是用tr,但是實際上tr只能針對「字元」處理,如果要對「字串」做處理的話,則必須請出sed這個指令了。

以下簡單的比較了tr與sed的用法差別

tr [option] SET1 SET2
  • option -d 刪除, Ex: tr -d 't'
  • option -s 取代, Ex: tr -s 't' 'a'
可將[STDIN]的內容,做字元的取代或刪除
ex:
現有一File:source.txt內容為:
test
tttt
eeee
ssss
tttt
% cat source.txt | tr 'test' 'ABCD'
DBCD
DDDD
BBBB
CCCC
DDDD
注意到這個結果,tr只是單純的將test <=> ABCD做個對應,並將文件內容轉換為
  • t->D
  • e->B
  • s->C


sed [regurage] [file]
可充份地表示「正規表示式」,用法很像perl裡的寫法,input的方式,可由[STDIN]或是File
Ex: 想將'test'取代為'abcd'
% cat source.txt | sed s/test/abcd/g
% sed s/test/abcd/g source.txt
abcd
tttt
eeee
ssss
tttt
說明:
s/// 是取代的意思
s/[from]/[to]/
最後加個g,表示global,就是全部取代的意思,如果不加,則只會取代找到的第一個
[form] & [to]裡頭就可以寫正規表示式

這邊只是粗淺地介紹一下字串取代的功能部分,如果想深入了解,就再去找資料吧XD

15 10月 2007

[Linux] libtool: -e: command not found

最近弄嵌入式系統的作業,在compile i-boot-lite的時候,出現了這樣子的錯誤訊息
libtool: -e: command not found

解決方法:
export SED=sed

03 10月 2007

Linux下的重新命名(rename) & 新增檔案(new file)的指令

重新命名的指令:mv
其實在Linux底下沒有特別處理rename的直接指令,不過可以透過mv這個指令,得到rename的效果。mv原本是用來處理「移動檔案」到不同的目錄底下,因此可以透過mv將原檔案移至原目錄底下新的檔名,就是rename的效果。
Ex: 將a.out改名稱為b.out
% mv a.out b.out

新增檔案的指令:touch
Ex: 新增檔案a.txt
% touch a.txt
touch原本的意義是將檔案的建立時間更新至目前的時間,因為常常會有檔案的時間不一致,導致一些問題。比如Makefile更改時間跑到了未來,導致執行make時,會出現一些Warnning,可以透過touch Makefile來避免這個Warnning出現

MySQL++使用教學

MySQL++是一套提供C++程式可以對MySQL的Database做存取的Library。雖然MySQL原本就有提供mysql.h供人使用,但我認為MySQL++對學習C++的人而言,語法非常的簡易好用,整個用法感覺上跟PHP很像,如果學過PHP & C++的人,應該很快就能上手了~

MySQL++的相關網站:
‧首頁
‧Documentation
‧Simple Example

MySQL++執行環境:
‧GCC 3.x and 4.x on recent x86 Linuxes,
‧GCC 4.x from Xcode 2.x on Mac OS X 10.4
‧Visual C++ 2005 on 32-bit Windows.

而我的安裝環境是Linux的Ubuntu以下就針對Ubuntu的用者說明安裝過程
安裝MySQL++ in Ubuntu:

% sudo apt-get install libmysql++-dev  
% sudo apt-get install mysql-client-5.0

很簡單吧....不知不覺的,安裝結束了 XD,記得重開機一下,這樣等等compile程式時才抓得到library

Compile程式所需要相關MySQL++的參數:

% g++ [code-file-name] -I/usr/include/mysql++ -I/usr/include/mysql  \
-lmysqlpp -lmysqlclient

  • -I/usr/include/mysql
    • 因為MySQL++的程式都是建立在MySQL提供的mysql.h上,所以必須指名include mysql.h的路徑,這個路徑就因機器而異了,你可以locate mysql.h看看,我所寫的是Ubuntu預設的路徑
  • -I/usr/include/mysql++
    • 這個就是MySQL++的header file存放的路徑。
  • -lmysqlpp -lmysqlclient
    • 在linking time時,compiler會使用到這兩個系統註冊的library檔


MySQL++的基本類別(class)說明:
這些類別都是在mysqlpp的namespace底下,如果要使用的話,必須在程式開始就宣告using namespace mysqlpp,或是在程式中每個類別前都加上mysqlpp::Connection、mysqlpp::Query、等等。

  • Connection -- 可以與DB連線
  • Query -- 可對與DB連線的Connection下指令
  • Result -- 儲存Query執行後的結果值
  • Row -- 儲存Result中每一筆的內容


以下有個我參考官網附的Example修改的code,加上一點中文註解,希望有興趣的人可以更快學會MySQL++

#include <mysql++.h>
#include <iostream>

//這樣子之後的code裡的Connection, Query, Result, Row...
// 前面就不用加mysqlpp::
using namespace mysqlpp;
using namespace std;

int main(int argc, char *argv[])
{
/*** 連結到input輸入的argument的DB ***/
// Input argument format
// ./a.out <DB-Name> <DB-Host-IP> <Name> <Password>
Connection con(false);
if ( !con.connect( argv[1], argv[2], argv[3], argv[4] ) ){
cerr<<"connect DB error..."<<endl;
return -1;
}

/*** 從DB撈資料出來 ***/
Query query = con.query();// create一個Query
// 可以對con做讀取or寫入
query << "SELECT item FROM mydb";//輸入要query的command
Result res = query.store();//執行query,並把結果存至Result res

/*** 秀出所有的result set ***/
cout << "We have : " << endl;
if (res) {//如果res有抓到東西的話....

Row row;//row可儲存每一列的資料
Row::size_type i;
for (i = 0; row = res.at(i); ++i) {
cout << 't' << row.at(0) << endl;
}
}
else {
//秀出Query產生的Error
cerr << "Failed to get item list: "
<< query.error() << endl;
return -1;
}

return 0;
}

[Linux] 無法啟用or關閉Apache

今天看網頁怪怪的,很慢才出現,所以想說重新啟動Apache看看,可能會好一點,結果竟然出現錯誤,著實嚇了我一大跳...
% /etc/init.d/apache2 restart
(13)Permission denied: make_sock: could not bind to address [::]:80

後來才發現,原來是忘了用sudo了....Orz...要有root的權限才能啟用or關閉apache,發現原因後,覺得還滿白痴的=_="""
% sudo /etc/init.d/apache2 restart

將Lifetype Server從Windows搬移至Linux

由於本站之前在windows上執行,有時候會造成Apache莫名奇妙地失靈,所以才想將server移至Linux Ubuntu上執行。這樣子所吃的資源可能也會比較少一點。

以下紀錄了移機的過程,主要遇到的問題有...編碼以及轉簡潔網址的問題。

[事前準備工作]

  1. 將Windows的資料備份出來
    • 將apache底下的lifetype整個資料夾壓縮備份起來(用zip壓縮,傳至Linux上再用unzip解壓縮)
    • 進入phpMyAdmin後,將lifetype資料庫輸出至檔案中lifetype.sql(請選擇「使用完整新增指令」)
  2. 在Ubunte上安裝Apache、Mysql、PHP(在這邊不多加著墨)
    • sudo apt-get install apache2
    • sudo apt-get install mysql
    • sudo apt-get install php
    • sudo apt-get install php-mysql
  3. 將原本Windows的lifetype程式碼,傳至apache2預設資料夾/var/www/
    • unzip lifetype.zip
  4. 上網下載phpMyAdmin,用來管理mysql資料庫

[重建Database]

  1. 利用phpMyAdmin建立一個lifetype資料庫,校對要調成utf8_unicode_ci
  2. 在Windows匯出的lifetype.sql檔前面加上
    • SET NAMES utf8;
      SET CHARACTER_SET_CLIENT=utf8;
      SET CHARACTER_SET_RESULTS=utf8;
  3. 在cmd line下指令,匯入lifetype.sql檔
    • mysql [lifetype DB name] -u[Name] -p[Password] < lifetype.sql \
      --default-character-set=utf8
    • # 因為mysql的預設編碼為latin1,因為需設定正確的character-set才能匯入
    • # 或是直接更改mysql預設的編碼方式為utf8就更乾脆了,可修改mysql的設定檔my.cnf
    • # [client]
      # default-character-set=utf8
      # [mysqld]
      # default-character-set=utf8
      # default-collation=utf8_general_ci
  4. ---- Error Message ----
    都按照上面的步驟做的話,應該就不會有所謂的亂碼出現才對。一開始我沒就直接匯入,也不疑有他,結果就犯了全天下男人都會犯的錯…ERROR 1064 (42000) at line 330: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'xxxxxx' 主要的原因就是因為編碼問題,因為lifetype.sql中挾雜著鼎鼎大名的「許功蓋…」含有跳脫字元「」,所以就視為字串已結束,就出現錯了。
    不過我後來都照上面的做了,卻還是不斷出現同樣的錯誤訊息纏著我,讓我陷入人生中的低潮,後來才發現,原來是因為在Windows匯出lifetype.sql檔案,沒有選擇「使用完整新增指令」,所以才會不斷地出錯,當我又重新試了一次之後,終於成功了!!!讓我流下了感動的眼淚,並且大喝了一聲X,響徹雲霄!!!

[建置Lifetype網站]

  1. 把原本在Windows上的lifetype資料夾複製到/var/www後,建議是把wizard.php抓回來,重新建置一遍,這樣子會比較簡單一點,否則要自己動手修改一些東西。
    • 修改/lifetype/config/config.properties.php內的db_host為
      $config['db_host'] = localhost
    • 將tmp及gallery這兩個資料夾權限改為777
      % cd /var/www/lifetype
      % chmod 777 tmp
      % chmod 777 gallery
    • 為了安全性起見,不將gallery底下的資料夾權限全開,因此必須將它的Owner改為apache的名字,我的主機上apache的名稱為www-data
      % chown -R www-data gallery
    • 看gallery底下有幾個資料夾就改幾個資料夾的權限,因為這些都是blog user上傳檔案的資料夾,因為本站只有一個user,blog_user_id為1,所以就只有一個資料夾「1」
      % cd gallery
      % chmod 755 1
      再將1資料夾底下的previews&previews-med的權限改成755
      % cd 1
      % chmod 755 previews
      % chmod 755 previews-med
  2. 輸入網站的網址,試試看是否正常運作。照理來說,到目前為止應該都是正常的。
    % /etc/init.d/apache2 start
    如果出現Error Message: apache2: Could not determine the server's fully qualified domain name, using 127.0.1.1 for ServerName
    在/etc/apache2/apache2.conf中,加入ServerName localhost即可
  3. 但是,要進入admin.php的後台管理系統卻會失敗,因為原本網站的IP跟新網站的IP不一樣,而原本的DB中紀錄的base_url導致網頁中的連結都不正常了。
    @解決方法:利用phpMyAdmin進入lifetype的DB,進入lt_config這個Table。修改其中的兩項參數:
    base_url
    blog_does_not_exist_url
    將這兩個url參數中的網址改成新的IP就行了!
  4. 網站中有使用authImage外掛,可能會發現在產生驗證圖檔時,出現錯誤訊息「You don't have GD support compiled in, we cannot create an authimage. Please activate GD Support.」。這是因為你的php5沒有使用GD module,因為只要將GD module安裝起來即可,以下為Ubuntu的做法
    % apt-get install php5-gd
    % /etc/init.d/apache2 restart

[使用簡潔網址]

  1. 有使用簡潔網址的人,因為Ubuntu預設沒有掛載mod_rewrite,所以要先將module rewrite掛進來,因為apache在安裝時,其實已經裝載好,只是尚未load而已。而load的語法已寫好放在/etc/apache2/mods-available中,只要做個link放至mods-enabled,apache就會自動去load了
    % sudo ln -s /etc/apache2/mods-available/rewrite.load \
    /etc/apache2/mods-enabled/rewrite.load
    或是
    %
    sudo a2enmod rewrite
  2. 修改/etc/apache2/sites-enabled/000-default
    先找到
    <Directory /var/www>
    ...
    </Directory>
    將其中的AllowOverride後的None改為All
    Options後面要有FollowSymLinks

    然後重新啟動Apache
    /etc/init.d/apache2 restart
  3. 順利的話,應該就一切正常了:)
    可惜的是,我一點也不順利....Orz,我開網頁時,一直遇到error 500,打開apache的error.log檔來看時,顯示的錯誤是:「/var/www/lifetype/.htaccess: </Files> without matching <Files> section 」我一直不知道是哪裡的問題,千萬百試之後,才發現,我的.htaccess檔的編碼是utf8,後來把它改成ansi編碼就OK了~我猜可能是從windows複製過來linux後的才變這樣。

28 9月 2007

[Linux] 截取、忽略系統發出的segmentation fault signal

因為有個程式有需求,要暫時把segmentation fault的signal SIGSEGV這個訊號忽略掉,比較利於之後程式的debug。原本想說用single();這個function指定發生SIGSEGV時交給指定的handler function去處理,就可以忽略掉。結果…「代誌並不是憨人所想得呷呢簡單」,執行之後的結果,卻是系統不斷地發出SIGSEGV這個signal…停都停不下來,擋都擋不住...連ctrl+c都不行Orz...

原來在fault發生後,必須處理造成fault的原因,再返回程式執行,返回程式後,會重新執行faulting instruction。所以若是想忽略segmentation fault的話,就必須透過longjmp()跳過可能發生錯誤的code,然後再繼續執行。

 

#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/ipc.h>
#include <setjmp.h>

jmp_buf setjmp_buffer;

void segmentFault(){
std::err<<"get a segment Fault!"<<std::endl;
longjmp( setjmp_buffer, 1 );//用0的話, setjmp()就會收到0,那麼可能會無窮回圈
}

int main(){

//當發出SIGSEGV這個signal時,交給segmentFault這個function處理
signal( SIGSEGV,(sig_t)segmentFault );

if( setjmp( setjmp_buffer ) == 0 )
{
// do something
std::cout<<"longjmp!!n";
char *a= NULL;
std::cout<<"ok"<<std::endl;
a[0] = '1';//cause a Segmentation Fault
}
else
{
// do something
std::cout<<"after longjmp.n";
}
return 0;
}

 

27 9月 2007

[Linux] php5安裝extension xslt

## 此篇文章有更新 ##
## 以下為手動compile安裝xslt+php的步驟 ##
## 至於Ubuntu+php5+xsl 請參考我的新文章 ##

由於在php4.1以後的版本對extension xslt預設不再是support,因此如果想要為php安裝xslt的話,就變得有點麻煩了。最近正好要在Fedora5上安裝Apache+PHP+XSLT+Mysql,原本一切很順利得裝起來了,但是最後才發現PHP5不support XSLT了,原本全都用yum指令安裝的,或是用rpm安裝的,全都要移除重新安裝一次…

在Linux上,由於要讓PHP5裝上XSLT,就必須要自行下載source code經過compile後才能安裝,而要compile安裝PHP的話,也必須compile安裝Apache才行。

安裝XSLT所需要的套件是Sablot,而Sablot又需要先安裝Expat,所以安裝的順序為(以下版本為參考用):

  1. Expat-2.0.1
  2. Sablot-1.03 (Sablotron)
  3. Apache (httpd-2.0.59)
  4. PHP-5.2.3

以下為我的安裝指令,--prefix的路徑是可以自己設的,以自己的主機設定為主。

  • Expat
    • ./configure
    • make
    • make install
  • Sablot
    • 要-enable-shared才能讓PHP找到XSLT的library
    • ./configure --enable-shared
    • make
    • make install
  • Apache
    • 要--enable-module才能讓PHP順利安裝
    • ./configure --prefix=/usr/local/apache2 --enable-module=so
    • make
    • make install
  • PHP
    • ./configure --prefix=/usr/local/php \
    • --with-apxs2=/usr/local/apache2/bin/apxs \
    • --with-mysql=/usr/ \
    • --enable-xslt \
    • --with-xslt-sablot
    • make
    • make install

這只是在Linux上,安裝Apache+PHP再加上PHP的extension的XSLT,如果要加上其他的extension也是差不多依樣畫胡蘆就行了。若還是不太清楚,可以下./configure --help查一查,或是看看INSTALL檔案的內容,應該就滿清楚的了。


#ps. 最近改用Ubuntu照上面的步驟安裝,卻是屢裝屢敗,硬是不給我裝起來...明明phpinfo()的結果都看得到xslt了,執行時,就是給我出現Fatal error: Call to undefined function xslt_create() 的訊息...真的很幹!
後來改用php 4.4.7安裝後,才成功。真是奇怪...

[Ubuntu] 安裝phpMyAdmin

我之前已經安裝好了PHP5, Apache2, MySQL了,現在就缺phpMyAdmin來管理我的DB~

在Ubuntu上安裝上面那三個套件都很簡單
都用apt-get install就可以輕鬆安裝成功了~

原本以為用apt-get install phpmyadmin就可以了
結果Ubuntu竟然不能這樣直接安裝...Q_Q
所以只能自己做苦力囉~

首先,先至phpMyAdmindownload最新的phpMyAdmin的版本,我是下載all-languages-utf-8-only.tar.gz這個版本

% wget [URL]                                          
% tar -xvzf [file name]
% mv [director name] /var/www/
% sudo cp config.sample.inc.php config.inc.php

然後再修改config.inc.php裡面的內容~
/* Authentication type */
$cfg['Servers'][$i]['auth_type'] = 'cookie';
將cookie改成http,可以增加安全性

[Linux] 在Linux底下的getch() & getche()

因為C/C++語言中的getch() & getche()都只能在windows底下執行
但是在Unix/Linux底下 就必須自己寫個function囉~

#include<termios.h>
char getch(){
    int i;//判斷是否有read到值
    char ch;
    struct termios _old, _new;

    tcgetattr (0, &_old);
    memcpy (&_new, &_old, sizeof (struct termios));
    _new.c_lflag &= ~(ICANON | ECHO);
    tcsetattr (0, TCSANOW, &_new);
    i = read (0, &ch, 1);
    tcsetattr (0, TCSANOW, &_old);
    if (i == 1)/* ch is the character to use */ 
        return ch;
    else/* there was some problem; complain, return error, whatever */ 
        printf("error!n");;
    return 0;
}