Thursday, May 6, 2010

FreeBSD: programming -->getopt



commands

เพื่อนๆ หลายท่านคงเคยใช้งานโปรแกรม แบบที่ต้องกำหนด option ด้วย เช่น
% find -n -x pattern filename
% grep -v R-dep


ซึ่งโปรแกรมลักษณะนี้ อำนวยความสะดวกให้ผู้ใช้มาก ในแง่ที่ว่า สามารถเพิ่มคุณลักษณะวิเศษไปจากเดิมได้ นิดหน่อย โดยไม่ต้องสั่งโปรแกรมเดิมมาทำงานซ้ำ

n, x หรือ v ในตัวอย่างนั้น เรียกว่า option การกำหนด option ให้กับโปรแกรมที่เขียนขึ้น แม้จะทำได้เองโดยง่าย แต่ในโลกของ unix แล้ว การใช้บริการของ system functions นั้นเป็นสิ่งที่ ต้องทำ เพราะอย่างน้อย ก็ ลดภาระ ของผู้พัฒนาโปรแกรม และ ทำให้ ตัดความกังวล เรื่อง ความปลอดภัยของระบบไปได้มาก

ความปลอดภัย เป็นเรื่องที่ล้อเล่นไม่ได้ น่ะ และในยามที่เรามีกฏหมายเกี่ยวกับคอมพิวเตอร์มาใช้งานแล้วเช่นนี้ หากโปรแกรมที่เราเขียนขึ้น มีช่องโหว่ว ก็ลำบากมากอยู่ ถ้าใช้กันผ่าน network

ในโอกาสพิเศษเช่นนี้ จึงใคร่ขอนำเสนอเรื่องสั้นๆ ไม่ยาวนัก แต่พอให้เกิดปัญญา มาตกลงปรองดองกันได้ ระหว่าง การเขียน code ขึ้นมาเอง กับการใช้บริการของ system functions (ผ่าน library)

function ที่ว่านี้ เรียกว่า getopt(3) ซึ่งเมื่อเปิด manual page ใน section ที่ 3 ดูก็ทราบรายละเอียดได้ว่า
  1. ต้อง link กับ standard C library (-lc) ในตอน compile ตัวอย่างคือ
    % cc -o programme programme.c -lc
  2. function นี้กำหนด prototype ไว้แล้วใน unistd.h header files ทำให้เราต้องรวมบรรทัด
    #include <unistd.h>
    เข้าไปด้วย


ตัวอย่าง ที่เขียนขึ้นจริงๆกับ โปรแกรมเรื่องสั้นภาค ๒ ที่เพิ่งส่งไปเมื่อวันอังคารที่ผ่านมานี้ ขอตัดมาให้ดูแต่เพียงบางส่วนเท่านั้น คือ
@ |getopt(3)|, one of many functions from system services
@<Getoption@>=
sflag = 0;
interactive=0;
while ((ch = getopt(argc, argv, "is:d:")) != -1) { <----
  switch (ch) {
   case 'i':@/
      interactive = 1;@/
      break;@/
   case 's':
      if ((fp = fopen(optarg, "r")) == NULL) {
       fprintf(stderr,"%s: %s: %s\n",programme, optarg, strerror(errno));
       status = OPEN_FILE;
      }
      sflag = 1;
      strcpy(filename,optarg); /* for later used */
      break;
   case 'd':
      if ((fp = fopen(optarg, "r")) == NULL) {
       fprintf(stderr,"%s: %s: %s\n",programme, optarg, strerror(errno));
       status = OPEN_FILE;
       }
      strcpy(filename,optarg); /* for later used */
      break;
   case '?':@/
   default:@/
      fprintf(stderr,"usage: %s -[[i]s|[i]d] data-filename\n%s\n", programme,
      strerror(errno));
      status = USAGE;
      break;
   }
  }
โดยที่ตรงบรรทัด while นั่นแหละ พอเดาออกน่ะครับว่า options ที่ใช้คือ i,s,d อันนี้ไม่ได้หมายถึง index for sustainable development ของการพัฒนาอย่างยั่งยืน อะไรหรอกน่ะ แต่มันเผอิญมาตรงกัน เท่านั้นเอง

กล่าวคือ option ของโปรแกรมที่ใช้งานจริงจริง เมื่อเรียกใช้ ก็จะอยู่ในรูป
% programme -i -sfilename | -dfilename
หรือ
% programme -isfilename | -idfilename
หรือ
% programme -sfilename | -dfilename
จาก manual page ทราบว่า เรามีภาระเพียงกำหนด argument ที่ 3 ให้กับ system function นี้ ซึ่ง มีรูปแบบ ที่แน่นอน ไว้ให้แล้ว พร้อมกับเขียน code มาเพื่อรองรับ option ที่กำหนดไว้ ก็เท่านั้นเอง

และในตัวอย่าง มะไฟ ก็เพียงเลือกเอาว่า จะใช้ option i,s,d โดยที่ ๒ อันหลังนั้นต้องมีชื่อแฟ้มตามมาด้วยเสมอ กล่าวคือ ต้องอยู่ในรูป
% programme -sfilename
หรือ
% programme -dfilename
ย่างนี้เป็นต้นเสมอ จะใช้แต่ option ใด option หนึ่งโดดๆ ไม่มีชื่อแฟ้มตามมาด้วย ไม่ได้

ใน manual page นั้น เขาบอกไว้ชัดเจนว่า option ที่มี argument ตามมานั้น ให้ตามหลัง option นั้นด้วย : เสมอ เพื่อแยกจาก option อื่นที่ไม่มี argument ตามมาด้วย ส่วนที่ว่า argument ที่ตามมาด้วยนั้น จะเขียนติดต่อกันไปเลย อย่างในตัวอย่างที่ยกมาให้ดู หรือ จะมี space ตามเพื่อความสวยงาม ก็ได้ ไม่ว่ากัน

ในตัวอย่างที่ยกมานั้น option s และ option d มี : ตามอยู่ด้วย ทำให้ทราบว่า ทั้ง ๒ option นั้นมี argument ตามมาแน่นอน ซึ่งก็คือชื่อของแฟ้มเอกสาร ที่จะเปิดเพื่ออ่านข้อมูลนั่นเอง

ก็หวังว่าคงพอเข้าใจบ้าง

และเมื่อลองเทียบ ความเรียบง่ายนี้ กับ codes ที่ต้องเขียนเองขึ้นมา โดยขอให้ไปดูจากหนังสือ The C Programming Language ในบทที่ ๕ section ที่ 10 Command-line Arguments ท่านก็จะพบว่า ยุ่งเหยิงมากกว่ากันเยอะเลย เอาแค่การตีความ precedence ของ pointers & operator ก็แทบจะพูดได้ว่า

โชคดีแล้ว ที่ไม่ต้องเขียนเอง

การใช้บริการของ system function ผ่าน library ทั้งหลายที่มีให้ จึงนับว่าดีที่สุด

ขอยกคุณงามความดีนี้ ถวายเป็นราชพลี ถวายเป็นปฏิบัติบูชา ในวาระ ฉัตรมงคลสมัย อันประเสริฐยิ่งนี้

อันใดที่บกพร่อง มะไฟ ฅนยาก ขอน้อมรับไว้แต่ผู้เดียว

No comments:


View My Stats