2011年2月16日 星期三

hello bjam

目前決定用 Sqlite++ 來當我字典的資料庫,Sqlite++編譯時需要用到 boost.build tool 來編譯。
試了一陣子結果不行,決定研究一下 bjam 的編譯環境。

編譯 hello world

官方的說明文件:
http://www.boost.org/doc/tools/build/doc/html/index.html

electronic-blue's blog (寫的很好,很容易上手)
http://electronic-blue.wikidot.com/doc:bjam-quickstart

編譯時一開始我弄不清楚 Jamroot 和 Jamfile 的關西
看了electronic-blue 的說明後就成了~!!

2011年2月15日 星期二

聊天室 - based Command Tool

需求:

client:    傳送一個 message   ("filename","varname")
server:   將 filename 檔案內的 varname 的數值減一,減到零時回傳 YES, 否則回傳 NO

eq.  hello.txt
==================
fab = 100
Oxford = 99
==================

client 傳送 ("hello.txt","Oxford"),server便會將Oxford的值減一 => 98。

這樣的程式,可以用網路 http REST 來做,或是包成網路 API Service 來做(這我不會)
但這種簡單的需求,用 socket 就綽綽有餘了。

寫 socket 程式就需要自己定義 protocol,貪圖方便,我就拿了 boost/asio 的聊天室範例程式來修改 (chat):
http://www.boost.org/doc/libs/1_45_0/doc/html/boost_asio/examples.html
以下是其 protocol: |size|string|

class chat_message
{
public:
  enum { header_length = 4 };
  enum { max_body_length = 512 };

  chat_message()
    : body_length_(0)
  {
  }

  const char* data() const
  {
    return data_;
  }

  char* data()
  {
    return data_;
  }

  size_t length() const
  {
    return header_length + body_length_;
  }

  const char* body() const
  {
    return data_ + header_length;
  }

  char* body()
  {
    return data_ + header_length;
  }

  size_t body_length() const
  {
    return body_length_;
  }

  void body_length(size_t length)
  {
    body_length_ = length;
    if (body_length_ > max_body_length)
      body_length_ = max_body_length;
  }

  bool decode_header()
  {
    using namespace std; // For strncat and atoi.
    char header[header_length + 1] = "";
    strncat(header, data_, header_length);
    body_length_ = atoi(header);
    if (body_length_ > max_body_length)
    {
      body_length_ = 0;
      return false;
    }
    return true;
  }

  void encode_header()
  {
    using namespace std; // For sprintf and memcpy.
    char header[header_length + 1] = "";
    sprintf(header, "%4d", body_length_);
    memcpy(data_, header, header_length);
  }

private:
  char data_[header_length + max_body_length];
  size_t body_length_;
};

既然,protocol 都用此範例了,client & server 當然也用這個範例修改了。

比較麻煩的是,這個範例程式 client & server 都是非同步的方式,非同步在 server 是沒甚麼問題,但 client 使用非同步會很麻煩。需要再 while 迴圈前 Sleep 一秒左右,讓 ioservice 建立連線。
Note:
因為實際使用時,是把 while 中的使用者輸入 cin.getline 部分改成,用參數傳遞的 string,while 迴圈也要拿掉,因此若是非同步的方式,程式馬上就到 c.close(),修改這段程式花了我很大的時間除錯 = ="

boost::asio::io_service io_service;

    tcp::resolver resolver(io_service);
    tcp::resolver::query query(argv[1], argv[2]);
    tcp::resolver::iterator iterator = resolver.resolve(query);

    chat_client c(io_service, iterator);

    boost::thread t(boost::bind(&boost::asio::io_service::run, &io_service));

    char line[chat_message::max_body_length + 1];
    while (std::cin.getline(line, chat_message::max_body_length + 1))
    {
      using namespace std; // For strlen and memcpy.
      chat_message msg;
      msg.body_length(strlen(line));
      memcpy(msg.body(), line, msg.body_length());
      msg.encode_header();
      c.write(msg);
    }

    c.close();
    t.join();

因此我將 client 程式改成同步的方式來執行 (舒服)

boost::asio::io_service io_service;

        tcp::resolver resolver(io_service);
        tcp::resolver::query query(argv[1], argv[2]);
        tcp::resolver::iterator iterator = resolver.resolve(query);
        tcp::resolver::iterator end;

        tcp::socket s(io_service);
        boost::system::error_code error = boost::asio::error::host_not_found;
        while (error && iterator != end)
        {
            s.close();
            s.connect(*iterator++, error);
        }
        if (error)
            throw boost::system::system_error(error);

        char line[chat_message::max_body_length + 1];
        strcpy(line,"hello.txt Seg ");
        chat_message write_msgs_;
        write_msgs_.body_length(strlen(line));
        memcpy(write_msgs_.body(), line, write_msgs_.body_length());
        write_msgs_.encode_header();

        boost::asio::write(s, 
            boost::asio::buffer(write_msgs_.data(), write_msgs_.length()));

        chat_message read_msg_;
        //boost::asio::read(sread_msg_.body(), read_msg_.body_length()),
        
        size_t reply_length_header = boost::asio::read(s,
            boost::asio::buffer(read_msg_.data(), chat_message::header_length));
        std::cout << "reply_length_header = " << reply_length_header << std::endl;

        read_msg_.decode_header();

        size_t reply_length_body = boost::asio::read(s,
            boost::asio::buffer(read_msg_.body(), read_msg_.body_length()));

        std::cout << read_msg_.body() << std::endl;

        s.close();

等待時間的問題解決了,接下來要包成 library。

包成 static library 還有些 issue

1. boost library 的 BOOST_ALL_NO_LIB 問題:
我包成 foo.lib 給 test.exe 用但在編譯的時候 linker 竟然還會有問題
LINK : fatal error LNK1104: cannot open file 'libboost_thread-vc100-mt-1_45.lib'
參考下文:
http://stackoverflow.com/questions/4736877/how-to-link-boost-in-a-dependant-static-library

2. VS2010 的 Static Library 無法給 VC6 用


於是我就包成 DLL 的版本
修改下面的 code 包成的 (用 vs2010 建立的 dll wizard 我包失敗 = =)
http://www.codeguru.com/cpp/cpp/cpp_mfc/tutorials/article.php/c9855

於是我的情人節就給了這支程式了! e04!!

2011年2月12日 星期六

iPhone 利用 string 存取 member data

在 class 內有 member datas 以數字結尾,
eq.
      UIImageView* imageView1;
      UIImageView* imageView2;
      UIImageView* imageView3;

想利用 @"imageView%d" 之類的方始來存取?
參考了  Key-Value Coding Programming Guide  (看不是很了解@@)


不過可以這樣用:
for(int i=1;i<=3;i++){
    [self valueForKey:@"imageView%d"];
    ...
}

2011年2月11日 星期五

Split String in iPhone

我有個 JPEG 圖檔 Yo Yo.jpg,希望能夠取出 Yo Yo 的部分。
Java 有 split member function 可用。
查了一下 iPhone SDK 文件 "String Programming Guide"
拚出了下列的 code


  1. NSCharacterSet* doSet = [NSCharacterSet characterSetWithCharactersInString:@"."];
  2. NSScanner* theScanner = [NSScanner scannerWithString:@"Yo Yo.jpg"];
  3. NSString* imageName;
  4. [theScanner scanUpToCharactersFromSet:doSet intoString:&imageName];
  5. NSLog(@"imageName = %@",imageName);

Hierarchy NavigationBar 問題

假設我有需要 navigate 三層 View
現在遇到的問題是當在第一層按下按鈕時
需要 push ViewController
而我的 navigation controller 卻是在 AppDelegate

目前的想法是每一層 ViewController 都要有 navagation controller 的 data member
在 create ViewController 時傳過去

不知道有沒有比較好的解法

2011年2月10日 星期四

Test

===============================================================================================================================================================================================.comment-body-author {
margin:0;
padding:0 0 0 20px;
background-color:#C0C0C0;<>
}


SELECT *  FROM users
WHERE user_id = 1212;

Console 顏色設定

想要將查詢過的單字,利用顏色來區分,例如查詢過一兩次的單字用橘色、查詢過很多次的就用紅色來提醒自己。

由於我在 windows 平台開發,因次要用到 win32 的 api 來處理顏色,這很惱人~
之前寫的 PTT 截圖程式,就是用 win32 api,主要是用 SetConsoleTextAttribute 這個 api 來設定顏色。程式碼如下:

Console::ColorType Console::set_color(ColorType color) throw(std::logic_error)
{
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    WORD oldColor;

    if (GetConsoleScreenBufferInfo(out_, &csbi))
        oldColor = csbi.wAttributes;
    else
        throw std::logic_error("Can't Get Console Screen Buffer Info");

    if (color==0x00) color = FOREGROUND_RED | FOREGROUND_GREEN |
        FOREGROUND_BLUE | FOREGROUND_INTENSITY;

    /* set text and background color */
    SetConsoleTextAttribute(out_, color);
    /*
    FOREGROUND_BLUE(0x01), FOREGROUND_GREEN(0x02), FOREGROUND_RED(0x04), FOREGROUND_INTENSITY(0x08),
    BACKGROUND_BLUE(0x10), BACKGROUND_GREEN(0x20), BACKGROUND_RED(0x40), BACKGROUND_INTENSITY(0x80)
    ex: FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
    */
    return oldColor;
}

在 codeproject 找到了一篇文章,利用 IO manipulator 來包裝使得改變顏色變得很輕鬆。

Add Color to Console Projects
注意此文章的 Points of Interest 有說明 IO Manipulator 的運作原理。


程式碼如下:
//------------------------------------------------------------------------------
// Console.h: interface for the Console manipulators.
//------------------------------------------------------------------------------

#if !defined( CONSOLE_MANIP_H__INCLUDED )
#define CONSOLE_MANIP_H__INCLUDED

//------------------------------------------------------------------------------

//------------------------------------------------------------------"includes"--
#include <iostream>
#include <iomanip>
#include <windows.h>

namespace JadedHoboConsole
{
static const WORD bgMask( BACKGROUND_BLUE |
BACKGROUND_GREEN |
BACKGROUND_RED |
BACKGROUND_INTENSITY );
static const WORD fgMask( FOREGROUND_BLUE |
FOREGROUND_GREEN |
FOREGROUND_RED |
FOREGROUND_INTENSITY );

static const WORD fgBlack ( 0 );
static const WORD fgLoRed ( FOREGROUND_RED );
static const WORD fgLoGreen ( FOREGROUND_GREEN );
static const WORD fgLoBlue ( FOREGROUND_BLUE );
static const WORD fgLoCyan ( fgLoGreen | fgLoBlue );
static const WORD fgLoMagenta( fgLoRed | fgLoBlue );
static const WORD fgLoYellow ( fgLoRed | fgLoGreen );
static const WORD fgLoWhite ( fgLoRed | fgLoGreen | fgLoBlue );
static const WORD fgGray ( fgBlack | FOREGROUND_INTENSITY );
static const WORD fgHiWhite ( fgLoWhite | FOREGROUND_INTENSITY );
static const WORD fgHiBlue ( fgLoBlue | FOREGROUND_INTENSITY );
static const WORD fgHiGreen ( fgLoGreen | FOREGROUND_INTENSITY );
static const WORD fgHiRed ( fgLoRed | FOREGROUND_INTENSITY );
static const WORD fgHiCyan ( fgLoCyan | FOREGROUND_INTENSITY );
static const WORD fgHiMagenta( fgLoMagenta | FOREGROUND_INTENSITY );
static const WORD fgHiYellow ( fgLoYellow | FOREGROUND_INTENSITY );
static const WORD bgBlack ( 0 );
static const WORD bgLoRed ( BACKGROUND_RED );
static const WORD bgLoGreen ( BACKGROUND_GREEN );
static const WORD bgLoBlue ( BACKGROUND_BLUE );
static const WORD bgLoCyan ( bgLoGreen | bgLoBlue );
static const WORD bgLoMagenta( bgLoRed | bgLoBlue );
static const WORD bgLoYellow ( bgLoRed | bgLoGreen );
static const WORD bgLoWhite ( bgLoRed | bgLoGreen | bgLoBlue );
static const WORD bgGray ( bgBlack | BACKGROUND_INTENSITY );
static const WORD bgHiWhite ( bgLoWhite | BACKGROUND_INTENSITY );
static const WORD bgHiBlue ( bgLoBlue | BACKGROUND_INTENSITY );
static const WORD bgHiGreen ( bgLoGreen | BACKGROUND_INTENSITY );
static const WORD bgHiRed ( bgLoRed | BACKGROUND_INTENSITY );
static const WORD bgHiCyan ( bgLoCyan | BACKGROUND_INTENSITY );
static const WORD bgHiMagenta( bgLoMagenta | BACKGROUND_INTENSITY );
static const WORD bgHiYellow ( bgLoYellow | BACKGROUND_INTENSITY );

static class con_dev
{
        private:
HANDLE hCon;
DWORD cCharsWritten;
CONSOLE_SCREEN_BUFFER_INFO csbi;
DWORD dwConSize;

        public:
con_dev()
{
hCon = GetStdHandle( STD_OUTPUT_HANDLE );
}
        private:
void GetInfo()
{
GetConsoleScreenBufferInfo( hCon, &csbi );
dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
}
        public:
void Clear()
{
COORD coordScreen = { 0, 0 };

GetInfo();
FillConsoleOutputCharacter( hCon, TEXT(' '),
dwConSize,
coordScreen,
&cCharsWritten );
GetInfo();
FillConsoleOutputAttribute( hCon,
csbi.wAttributes,
dwConSize,
coordScreen,
&cCharsWritten );
SetConsoleCursorPosition( hCon, coordScreen );
}
void SetColor( WORD wRGBI, WORD Mask )
{
GetInfo();
csbi.wAttributes &= Mask;
csbi.wAttributes |= wRGBI;
SetConsoleTextAttribute( hCon, csbi.wAttributes );
}
} console;

inline std::ostream& clr( std::ostream& os )
{
os.flush();
console.Clear();
return os;
};

inline std::ostream& fg_red( std::ostream& os )
{
os.flush();
console.SetColor( fgHiRed, bgMask );

return os;
}

inline std::ostream& fg_green( std::ostream& os )
{
os.flush();
console.SetColor( fgHiGreen, bgMask );

return os;
}

inline std::ostream& fg_blue( std::ostream& os )
{
os.flush();
console.SetColor( fgHiBlue, bgMask );

return os;
}

inline std::ostream& fg_white( std::ostream& os )
{
os.flush();
console.SetColor( fgHiWhite, bgMask );

return os;
}

inline std::ostream& fg_cyan( std::ostream& os )
{
os.flush();
console.SetColor( fgHiCyan, bgMask );

return os;
}

inline std::ostream& fg_magenta( std::ostream& os )
{
os.flush();
console.SetColor( fgHiMagenta, bgMask );

return os;
}

inline std::ostream& fg_yellow( std::ostream& os )
{
os.flush();
console.SetColor( fgHiYellow, bgMask );

return os;
}

inline std::ostream& fg_black( std::ostream& os )
{
os.flush();
console.SetColor( fgBlack, bgMask );

return os;
}

inline std::ostream& fg_gray( std::ostream& os )
{
os.flush();
console.SetColor( fgGray, bgMask );

return os;
}

inline std::ostream& bg_red( std::ostream& os )
{
os.flush();
console.SetColor( bgHiRed, fgMask );

return os;
}

inline std::ostream& bg_green( std::ostream& os )
{
os.flush();
console.SetColor( bgHiGreen, fgMask );

return os;
}

inline std::ostream& bg_blue( std::ostream& os )
{
os.flush();
console.SetColor( bgHiBlue, fgMask );

return os;
}

inline std::ostream& bg_white( std::ostream& os )
{
os.flush();
console.SetColor( bgHiWhite, fgMask );

return os;
}

inline std::ostream& bg_cyan( std::ostream& os )
{
os.flush();
console.SetColor( bgHiCyan, fgMask );

return os;
}

inline std::ostream& bg_magenta( std::ostream& os )
{
os.flush();
console.SetColor( bgHiMagenta, fgMask );

return os;
}

inline std::ostream& bg_yellow( std::ostream& os )
{
os.flush();
console.SetColor( bgHiYellow, fgMask );

return os;
}

inline std::ostream& bg_black( std::ostream& os )
{
os.flush();
console.SetColor( bgBlack, fgMask );

return os;
}

inline std::ostream& bg_gray( std::ostream& os )
{
os.flush();
console.SetColor( bgGray, fgMask );

return os;
}
}

//------------------------------------------------------------------------------
#endif //!defined ( CONSOLE_MANIP_H__INCLUDED )


於是設定顏色就和使用 std::setw(10) 的方式一樣:

#include "Console.h"


namespace con = JadedHoboConsole;

int main()
{
using std::cout;
using std::endl;

cout << "I like " << con::fg_green << "green" << con::fg_white << " eggs and ham." 
<< endl;
}

舒服!!