Showing posts with label Linux C. Show all posts
Showing posts with label Linux C. Show all posts

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做修改之前一定要保存一份,程序结束后回复。

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

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

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. 这个特性可以方便编程。