Wednesday, January 11, 2012

[L] curses

curses里面封装了一下对terminal 还有cursor的用法,从我之前一篇blog也可以看出如果不封装是多么令人肾虚。

需要搞明白一点的是,前面是对terminal进行操作,这个是对X window进行操作。所以从本质上来讲是不一样的。但是用起来感觉没什么大不同。。

1. initscr(), endwin()
  init之后,整个屏幕被刷掉,生成一个新屏幕。在这里只能用curses里面的printw,scanw之类的。因为这是它自己的屏幕。之后endwin()退出。

2. move(x,y)
  封装得够简单了。

3. attron, attroff
  对输出属性进行设置,试一下就知道了。
  至于属性设置参考这里:
  http://www.mkssoftware.com/docs/man3/curs_attr.3.asp

4. refresh()
  把整个屏幕刷新一遍。比如initscr之后,如果不refresh,那么屏幕原来有的还在,很混乱。
  本来应该是所有动作之后都应该refresh一下,但是有些试了下不要也行。个人猜测是覆盖的原因。如果有覆盖的话要refresh().
  还有一点要注意的就是,必须有change 才会刷新。如果没有change还是不变的。如果没有change硬要刷新的话也行,用touchwin(WINDOW).

5. cbreak(), echo()
  前者相当于之前的non-canonical,就是不是一行输入了。变成一个个输入,包括换行。
  后者指定是否回显。

实践代码如下,因为都是终端运行即可见了,所以样例也不用贴了。


代码一:

*注意一点:中间getchar()的时候,不论输入什么也不会回显的。这是因为被流弄走了,但是不会保留在window上。而getstr(), getch()则会留在屏幕上,如果不把echo()关掉的话。


/*
 * =====================================================================================
 *
 *       Filename:  screen1.c
 *
 *    Description:  Uses of curses.h
 *
 *        Version:  1.0
 *        Created:  Wednesday, January 11, 2012 02:55:22 HKT
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Hongchao Deng (fengjingchao), fengjingchao@gmail.com
 *        Company:  Sun Yat-sen University
 *
 * =====================================================================================
 */


#include <errno.h>
#include <math.h>  
#include <stdio.h> 
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <curses.h>


#define PW_LEN 256
#define NAME_LEN 256


/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  main
 *  Description:  main function
 * =====================================================================================
 */
int
main ( int argc, char *argv[] )
{
   /* Parameters */
   char *scan_ptr;
   char witch_one[] = "First Witch  ";
   char witch_two[] = "Second Witch ";


   /* TODO */
   initscr();


    
   move(5,15);
   attron(A_BOLD);
   printw("%s", "Macintosh");
   attroff(A_BOLD);
   refresh();
   getchar();
   
   move(8,15);
   attron(A_STANDOUT);
   printw("Thunder and lighting");
   attroff(A_STANDOUT);
   refresh();
   getchar();


   move(10,10);
   printw("TEST PRINT");
   move(11,23);
   printw("TEST PRINT");
   refresh();
   getchar();


   attron(A_DIM);
   scan_ptr = witch_one + strlen(witch_one) - 1;
   while(scan_ptr != witch_one){
      move(10,10);
      insch(*--scan_ptr);
   }
   attroff(A_DIM);
   refresh();
   getchar();


   move(LINES -1, COLS -1);
   printw("%s",witch_two);
   refresh();
   getchar();


   clear(); 


   char name[NAME_LEN];
   char password[PW_LEN];


   char *real_password = "123456";


   move(5,10);
   printw("Please login");


   move(7,10);
   printw("User name: ");
   getstr(name);


   move(8,10);
   printw("Password: ");
//   refresh();
   
   cbreak();
   noecho();


   memset(password,0,sizeof(password));
   
   int i=0;
   for(;i<PW_LEN;i++){
      password[i] = getch();
      if( password[i] == '\n') break;
      move(8,20+i);
      addch('*');
//      refresh();
   }
   
   echo();
   nocbreak();


   endwin();
return EXIT_SUCCESS;
} /* ----------  end of function main  ---------- */




××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
代码二:
展示多个window的情况





/*
 * =====================================================================================
 *
 *       Filename:  multiw.c
 *
 *    Description:  Managing Multiple Windows
 *
 *        Version:  1.0
 *        Created:  Wednesday, January 11, 2012 07:42:44 HKT
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Hongchao Deng (fengjingchao), fengjingchao@gmail.com
 *        Company:  Sun Yat-sen University
 *
 * =====================================================================================
 */




#include <errno.h>
#include <math.h>  
#include <stdio.h> 
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <curses.h>


/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  main
 *  Description:  main function
 * =====================================================================================
 */
int
main ( int argc, char *argv[] )
{
   WINDOW *new_window_ptr;
   WINDOW *popup_window_ptr;


   int x_loop;
   int y_loop;


   char letter = 'a';
   
   initscr();
   
   move(5,5);
   printw("Testing multiple windows");
   refresh();
   sleep(1);


   for ( y_loop = 0;y_loop < LINES -1 ;++y_loop ) {
      for (x_loop = 0; x_loop < COLS -1; ++x_loop) {
         mvaddch(y_loop,x_loop,letter);
         letter++;
         if(letter >'z') letter = 'a';
      }
   }
   refresh();
   getchar();


   new_window_ptr = newwin(10,20,5,5);
   mvwprintw(new_window_ptr,2,5,"Testing multiple windows");
   mvwprintw(new_window_ptr,5,10,"*********************************************************");
   wrefresh(new_window_ptr);
   getchar();


   letter = '0';
   for ( y_loop = 0;y_loop < LINES -1 ;++y_loop ) {
      for (x_loop = 0; x_loop < COLS -1; ++x_loop) {
         mvaddch(y_loop,x_loop,letter);
         letter++;
         if(letter >'9') letter = '0';
      }
   }
  
   refresh();
   getchar();


   wrefresh(new_window_ptr);
   getchar();


   touchwin(new_window_ptr);
   wrefresh(new_window_ptr);
   getchar();


   endwin();


return EXIT_SUCCESS;
} /* ----------  end of function main  ---------- */



Tuesday, January 10, 2012

[L] termios, curses, Terminal Control


好吧,终于到 terminal 了。那真叫一个纠结,最后还是看完了。。
附上实践:

/*
 * =====================================================================================
 *
 *       Filename:  menu.c
 *
 *    Description:  Reading Each Character, 
 *                    Without processing some signal characters even like C-c
 *                  Using Terminal Control
 *
 *        Version:  2.0
 *        Created:  Wednesday, December 28, 2011 11:27:45 HKT
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Hongchao Deng (fengjingchao), fengjingchao@gmail.com
 *        Company:  Sun Yat-sen University
 *
 * =====================================================================================
 */




#include <errno.h>
#include <math.h>  
#include <stdio.h> 
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <termios.h>
#include <term.h>
#include <ncurses.h>


char *menu[] = {
   "a - add new record",
   "d - delete record" ,
   "q - quit",
   NULL
};


FILE *output_stream = NULL;


/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  char_to_terminal
 *  Description: use output_stream to which the program writes the output.
 *                Otherwise in the getchoice() function we can use putp();
 * =====================================================================================
 */
int
char_to_terminal ( int char_to_write )
{
   if (output_stream) putc(char_to_write, output_stream);
   return 0;
} /* -----  end of function char_to_terminal  ----- */




/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  getchoice
 *  Description:  get the choice from prompt. 
 *                it will simply discard any invalid input including chars like ^C
 * =====================================================================================
 */
int
getchoice ( FILE *input, FILE *output)
{
   int choice;
   int chosen = 0;
   int screenrow = 4, screencol = 10;
   char **option;
   char *cursor, *clear;


   output_stream = output;


   setupterm(0,1,0);
   cursor = tigetstr("cup");
   clear = tigetstr("clear");


   tputs(clear, 1, char_to_terminal );


   while(!chosen){
      tputs(tparm(cursor,screenrow++,screencol), 1, char_to_terminal);
      fprintf(output,"Please select an option:\n");
      for(option = menu; *option != NULL; option++, screenrow++){
         tputs(tparm(cursor,screenrow++,screencol), 1, char_to_terminal);
         fprintf(output,"%s\n", *option);
      }


      for(choice = '\n'; choice == '\n';choice = fgetc(input));
      for(option = menu; *option != NULL; option++){
         if(choice == *option[0]){
            chosen = 1; break;
         }
      }
      if(!chosen) {
         tputs(tparm(cursor,screenrow++,screencol), 1, char_to_terminal);
         fprintf(output, "Incorrect choice: '%c'\n",choice);
      }
   }


   tputs(clear, 1, char_to_terminal );
   return choice;
} /* -----  end of function getchoice  ----- */



/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  main
 *  Description:  main function
 * =====================================================================================
 */
int
main ( int argc, char *argv[] )
{


   int choice = 0;


   FILE *input;                  /* input-file pointer */
   input = fopen( "/dev/tty", "r" );
   
   FILE *output;
   output       = fopen( "/dev/tty", "w");


   if ( input == NULL || output == NULL ) {
      fprintf ( stderr, "couldn't open file '%s'; %s\n",
        "/dev/tty", strerror(errno) );
      exit (EXIT_FAILURE);
   }
   
   struct termios initialSetting, newSetting;


   tcgetattr(fileno(stdin),&initialSetting);
   newSetting = initialSetting;
   newSetting.c_lflag   &= ~ISIG;
   newSetting.c_lflag   &= ~ECHO;
   newSetting.c_cc[VMIN] = 1;
   newSetting.c_cc[VTIME]= 0;
   newSetting.c_lflag   &= ~ICANON;


   if(tcsetattr(fileno(stdin), TCSANOW , &newSetting) != 0)
      fprintf(stderr, "Could not set terminal attributes!");
   
   for(choice = 0; choice != 'q';){
      choice = getchoice(input, output);
      printf("You have chosen %c\n",choice);
      sleep(1);
   }
   
   tcsetattr(fileno(stdin), TCSANOW , &initialSetting); 


   if( fclose(input) == EOF || fclose(output) == EOF ) {/* close input file   */
      fprintf ( stderr, "couldn't close file '%s'; %s\n",
        "/dev/tty", strerror(errno) );
      exit (EXIT_FAILURE);
   }


return EXIT_SUCCESS;
} /* ----------  end of function main  ---------- */


输出可以当场试,都已经是 terminal 了。。


总结一下:
功能:
1. 能调整光标的行列。
2.    能使得输入输出不显示,操作输入输出怎么读写。

经验:
1.    setupterm就直接 setupterm(0,1,0), 不知道第二个参数 (flie descriptor) 干嘛用的。
2.    逃过stdout , 用‘/dev/tty’ .. 但是注意对terminal输出控制的时候不能用putp()了,要用tputs().
3.    其实操作terminal都是一堆字符输过去的,而且不同类型的terminal还有不同的控制方法,所以才有 curses这个库。
4.    父进程会直接将stdin这些copy到子进程里面,就是说如果不回复过来的话,那么terminal就变成那样了。。所以对std 三剑客in,out,err做修改之前一定要保存一份,程序结束后回复。

我也不太懂。。下次弄个牛逼一点的再写份好点的总结。这次算记录。。

Saturday, December 24, 2011

[L] Ubuntu: library curl not found

Just try this:

sudo apt-get install libcurl4-openssl-dev

You can't check it out in "aptitude search curl".

Friday, December 23, 2011

To my dear Yu

You Are Beautiful
No Matter What They Say
You Can Bring Me Down


You Are Wonderful
In Every Single Way
You Can Bring Me Down


So Don't You Bring Me Down Today

Thursday, December 22, 2011

[C] Resource Limit in Linux

之前开会大师兄问了下 'ulimit' 在底层用什么搞的,今天刚好遇到,就顺便写下来了。

内部有个“sys/resource.h”的库,里面主要有3个重要功能:
1. rlimit
2. rusage
3. priority

rlimit 挺好理解。rusage 跟 priority 不太懂,跟系统底层有关:一个是相关信息,一个是调度的优先级。

下面直接贴代码:
/*
 * =====================================================================================
 *
 *       Filename:  rlimit.c
 *
 *    Description:  Resources limit test
 *
 *        Version:  1.0
 *        Created:  Thursday, December 22, 2011 07:20:02 HKT
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Hongchao Deng (fengjingchao), fengjingchao@gmail.com
 *        Company:  Sun Yat-sen University
 *
 * =====================================================================================
 */




#include    <errno.h>
#include    <math.h> 
#include    <stdio.h>
#include    <stdlib.h>
#include    <string.h>


#include <sys/types.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <unistd.h>




/*
 * ===  FUNCTION  ======================================================================
 *         Name:  work
 *  Description:  This function writes a string to a temporary file 10,000 times and then
 *                performs some arithmetic to generate load on CPU. HOW BAD...
 * =====================================================================================
 */
void
work (  )
{
   FILE *f;
   int i;
   double x = 4.5;


   f = tmpfile();


   // Writing about 10K to the tmp file
   for (i = 0; i < 10000; i++) {
      /* code */
      fprintf(f, "Do some output.\n");
      if( ferror(f) )
      {
         fprintf(stderr,"Error while writing to temporary file.\n");
         exit(EXIT_FAILURE);
      }
   }
  
   for (i = 0; i < 1000000; i++) {
      /* code */
      x = log(x*x+3.21);
   }


}        /* -----  end of function work  ----- */




/*
 * ===  FUNCTION  ======================================================================
 *         Name:  rusage_test
 *  Description: 
 * =====================================================================================
 */
void
rusage_test ( )
{
   struct rusage r_usage;
   work();
   getrusage(RUSAGE_SELF, &r_usage);
  
   printf("\n**************************************\n");


   printf ( "rusage information:\n" );
   printf ( "  ru_utime:\n    tv_sec.tv_usec: %ld.%06ld (s)\n",
                    r_usage.ru_utime.tv_sec, r_usage.ru_utime.tv_usec );
   printf ( "  ru_stime:\n    tv_sec.tv_usec: %ld.%06ld (s)\n",
                    r_usage.ru_stime.tv_sec, r_usage.ru_stime.tv_usec );

}        /* -----  end of function rusage_test  ----- */


/*
 * ===  FUNCTION  ======================================================================
 *         Name:  main
 *  Description:  main function
 * =====================================================================================
 */
    int
main ( int argc, char *argv[] )
{
   // parameters
   struct rlimit r_limit;


   // todo
   rusage_test();
   rusage_test();
   rusage_test();


   printf("\n**************************************\n"); 
   printf("priority information:\n");
   printf("  process priority: %d\n", getpriority(PRIO_PROCESS,getpid()));
   printf("  group   priority: %d\n", getpriority(PRIO_PGRP,getgid()));
   printf("  user    priority: %d\n", getpriority(PRIO_PGRP,getuid()));


   printf("\n**************************************\n"); 
   printf("rlimit information: (RLIM_INFINITY=%ld)\n", RLIM_INFINITY);


   getrlimit(RLIMIT_CPU, &r_limit);
   printf ( "  rlimit_cpu:\n    s: %ld ; h: %ld\n", r_limit.rlim_cur, r_limit.rlim_max );


   getrlimit(RLIMIT_DATA, &r_limit);
   printf ( "  rlimit_data:\n    s: %ld ; h: %ld\n", r_limit.rlim_cur, r_limit.rlim_max );


   getrlimit(RLIMIT_FSIZE, &r_limit);
   printf ( "  rlimit_fsize:\n    s: %ld ; h: %ld\n", r_limit.rlim_cur, r_limit.rlim_max );


   getrlimit(RLIMIT_NOFILE, &r_limit);
   printf ( "  rlimit_nofile:\n    s: %ld ; h: %ld\n", r_limit.rlim_cur, r_limit.rlim_max );


   getrlimit(RLIMIT_NPROC, &r_limit);
   printf ( "  rlimit_nproc:\n    s: %ld ; h: %ld\n", r_limit.rlim_cur, r_limit.rlim_max );


   printf("\nNow try to set some limits:\n");
   r_limit.rlim_cur = 1024; r_limit.rlim_max = RLIM_INFINITY;
   setrlimit(RLIMIT_FSIZE, &r_limit);
   work();


    return EXIT_SUCCESS;
}        /* ----------  end of function main  ---------- */


输出样例:
**************************************
rusage information:
  ru_utime:
    tv_sec.tv_usec: 0.040002 (s)
  ru_stime:
    tv_sec.tv_usec: 0.000000 (s)

**************************************
rusage information:
  ru_utime:
    tv_sec.tv_usec: 0.084005 (s)
  ru_stime:
    tv_sec.tv_usec: 0.000000 (s)

**************************************
rusage information:
  ru_utime:
    tv_sec.tv_usec: 0.128008 (s)
  ru_stime:
    tv_sec.tv_usec: 0.000000 (s)

**************************************
priority information:
  process priority: 0
  group   priority: -1
  user    priority: -1

**************************************
rlimit information: (RLIM_INFINITY=-1)
  rlimit_cpu:
    s: -1 ; h: -1
  rlimit_data:
    s: -1 ; h: -1
  rlimit_fsize:
    s: -1 ; h: -1
  rlimit_nofile:
    s: 1024 ; h: 4096
  rlimit_nproc:
    s: 15915 ; h: 15915

Now try to set some limits:
File size limit exceeded



感悟:
1. 调用getrusage的时候,只是得到当前耗掉的时间,这点在上面我用了几次work中体现出来了。
2. priority是数值越小,优先越高。
3. 普通人set的时候只能变弱,即priority+,limit - 。superuser有能力set,但是在内核限制的范围内。
4. 为什么要有soft & hard limit 两种呢?查了下,是因为soft 是能提高的,但是hard普通用户只能减少,这样有个限度。

References:
http://linux.about.com/library/cmd/blcmdl2_setrlimit.htm
http://linux.die.net/man/2/getrusage
http://linux.die.net/man/2/gettimeofday
http://linux.die.net/man/2/setpriority
http://linux.die.net/man/2/nice

Tuesday, December 20, 2011

[S] TPM Emulator

 最简单的TPM Emulator安装。。可惜很乱。
http://tpm-emulator.berlios.de/installation.html

补充一点,
之前出现 ”Module tpmd_dev not found” 的错误,最后网上查到,要在
modprobe tpmd_dev "之前,先
depmod -a

至于你有没解决,反正我是解决了。。-_-|||

Monday, December 19, 2011

[C] ‘getopt()' function in Linux

先贴个网站(没错,是万恶又全能的Linux man page):
http://linux.die.net/man/3/getopt

再晒下自己代码:
/*
 * =====================================================================================
 *
 *       Filename:  argopt.c
 *
 *    Description:  Test example for 'getopt' function
 *
 *        Version:  1.0
 *        Created:  Monday, December 19, 2011 04:54:49 HKT
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Hongchao Deng (fengjingchao), fengjingchao@gmail.com
 *        Company:  Sun Yat-sen University
 *
 * =====================================================================================
 */

#include    <errno.h>
#include    <math.h> 
#include    <stdio.h>
#include    <stdlib.h>
#include    <string.h>
#include        <unistd.h>


/*
 * ===  FUNCTION  ======================================================================
 *         Name:  main
 *  Description:  main function
 * =====================================================================================
 */
    int
main ( int argc, char *argv[] )
{
   int opt;

   while ( (opt = getopt(argc, argv, ":if:lr")) != -1 )
   {
     
      switch ( opt ) {
      case 'i':   
      case 'l':   
      case 'r':   
         printf("option: %c\n",opt);
         break;

      case 'f':
         if(optarg[0] != '-')      printf ( "filename: %s\n",optarg );
         else{
            --optind;
            printf ( "Option '-f' needs a value\n" );
         }
         break;

      case ':':   
         printf ( "Option '-%c' needs a value\n", optopt );
         break;
        
      case '?':   
         printf ( "Unknown option: %c\n", optopt );
         break;

      default:   
         break;
      }                /* -----  end switch  ----- */
   }

  
   for ( ; optind < argc; ++optind)
   {
      printf ( "argument: %s\n", argv[optind] );
   }

   return EXIT_SUCCESS;
}  /* ----------  end of function main  ---------- */

测试用例:
./argopt -i -lr -f -i -f filename -q "Hello,world"
option: i
option: l
option: r
Option '-f' needs a value
option: i
filename: filename
Unknown option: q
argument: Hello,world

好玩吧。。说说感悟:
1. 匹配出错的时候 '当前option' 放在 'optopt' 这个变量里面。
2. optind是一个个move的。。你看上面那个 '-f' 出错的时候直接 " -- optind " 解决了。
3. option有value 的话放在 'optarg' 里面.
4. getopt()的第三个参数 optstring 前面有个 "+" | "-" , 还有个什么POSIX*****之类的环境变量,无视他们。。用最基础的就行。顺便说说加了个 ‘:’(注意如果有 +-, +- 要放前面),主要是关注出错的时候是 1.没有value, 还是 2. option不识别。
5. getopt()是自动permute的,注意最后所有变量都放在 optind -- argc之间。。

getiopt_long() 是GNU扩展版。看了man page 的样例后说说感想:
1. optstring可以有数字字符,即 [0-9], 其他的不知道,也没必要知道。你看Linux命令有 '-*', '-%'这样的吗。。。
2. optarg: 如果没有 arg, optarg = 0. 这个特性可以方便编程。

Saturday, December 17, 2011

[LK] Linux kernel book

I have found an interesting website with no code lines talking about the mechanisms and principles that Linux uses. It's a little obsolete as with 2.0 kernel, but good for learning, I guess...

http://tldp.org/LDP/tlk/tlk-toc.html