qDecoder On-line Reference

   * 컴파일과 설치 및 사용
        o 패키지 구하기
        o 압축 풀기
        o 컴파일
        o 설치
        o 제거
        o 테스트
        o Microsoft Visual C++ 환경에서의 사용

   * 화면 출력 함수군
        o qContentType()
        o qPrintf()
        o qPuts()
        o qError()
        o qErrorLog()
        o qErrorContact()
        o qRedirect()

   * 쿼리 관련 함수군
        o qDecoder()
        o qValue()
        o qiValue()
        o qValueDefault()
        o qValueNotEmpty()
        o qValueReplace()
        o qValueFirst()
        o qValueNext()
        o qGetFirstEntry()
        o qPrint()
        o qFree()

   * 쿠키(cookie) 관련 함수군
        o qSetCookie()
        o qcDecoder()
        o qcValue()
        o qciValue()
        o qcPrint()
        o qcFree()

   * 문자열 관련 함수군
        o qURLencode()
        o qURLdecode()
        o qRemoveSpace()
        o qStr09AZaz()
        o qStrupr()
        o qStristr()
        o qStricmp()
        o qitocomma()
        o qStrReplace()

   * 검색어 관련 함수군
        o qArgMake()
        o qArgMatch()
        o qArgEmprint()
        o qArgPrint()
        o qArgFree()

   * 파일 관련 함수군
        o qCheckFile()
        o qCatFile()
        o qReadFile()
        o qSaveStr()
        o qfGetLine()
        o qFileSize()

   * 형식화된 설정 파일을 다루는 함수군
        o qfDecoder()
        o qfValue()
        o qfiValue()
        o qfPrint()
        o qfFree()
        o qsDecoder()
        o qsValue()
        o qsiValue()
        o qsPrint()
        o qsFree()
        o qReadCounter()
        o qSaveCounter()
        o qUpdateCounter()
        o qAwkOpen()
        o qAwkNext()
        o qAwkClose()
        o qSedFile()
        o qSedStr()

   * 시간 관련 함수군
        o qGetTime()
        o qGetGMTime()

   * 형식 검사 함수군
        o qCheckEmail()
        o qCheckURL()

   * 기타 함수군
        o qGetEnv()
        o qCGIenv()
        o qCGIname()
        o qDownload()
        o qDownloadMime()
        o qReset()

  ------------------------------------------------------------------------

컴파일과 설치 및 사용

패키지 구하기

qDecoder의 최신버젼은 http://www.qDecoder.org나
ftp://ftp.qDecoder.org/pub/qDecoder/에서 구할 수 있다.

압축 풀기

qDecoder는 기본적으로 유닉스상에서 tar로 묶여져 compress로 압축해 제공된다.
압축을 풀기 위해서는 다음과 같은 절차를 따른다.

     $ uncompress qDecoder-VERSION.tar.Z
     $ tar xvf qDecoder-VERSION.tar

GNU Tar가 설치된 시스템에서는 다음과 같이 한번에 압축을 해제할 수도 있다.

     $ tar xvfZ qDecoder-VERSION.tar.Z

qDecoder-VERSION 에 해당하는 디렉토리가 생성되며 다음과 유사한 형태로
패키지가 풀려진다.

     $ cd qDecoder-VERSION
     $ ls -asCF
     total 289
       1 ./                    3 Makefile.in           1 examples/
       1 ../                  48 README                6 install-sh*
       1 AUTHORS             128 README.pdf            2 qDecoder.jpg
       8 CHANGES              55 configure*            1 rfc/
      26 COPYING               3 configure.in          1 src/
       2 DISCLAIMER            1 contrib/              1 win32/

     AUTHORS - 제작자 명단
     CHANGES - 버젼별 수정 내역
     COPYING - 저작권 관련 문서
     DISCLAIMER - 저작권 관련 서명서
     README - 사용법 문서
     README.pdf - 출력용 PDF 포맷 README 파일
     configure - 시스템 환경 설정 스크립트
     configure.in - Autoconf 구성 매크로 파일
     contrib/... - 배포되는 관련 프로그램들이 위치하는 디렉토리
     examples/... - 예제 소스 모음
     install-sh - Autoconf에서 사용되는 설치용 스크립트
     qDecoder.jpg - 로고 그림
     rfc/... - RFC 관련 문서 모음
     src/... - qDecoder 메인 소스
     win32/... - Microsoft Visual C++용 정적 라이브러리 생성 프로젝트 파일

컴파일

qDecoder는 대부분의 GNU 소프트웨어와 Free/Open Source 소프트웨어들이
채택하는 Autoconf를 적용(6.0.1 이상)하여 다양한 이기종간에 컴파일이 더욱
자유롭도록 하였다. 컴파일 방법은 일반적인 오픈소스의 그것과 같이
configure후 make를 통하는데, configure는 해당 시스템의 컴파일러 환경과
필요한 함수, 명령들이 사용가능한지 점검해 그 시스템에서 가장 효율적으로
컴파일 될 수 있도록 Makefile을 구성하는 역활을 한다.

     $ cd qDecoder-VERSION

     $ ./configure
     creating cache ./config.cache
     checking for gcc... gcc
     checking whether the C compiler (gcc  ) works... yes
     checking whether the C compiler (gcc  ) is a cross-compiler... no
     ...(생략)...
     creating Makefile
     creating src/Makefile
     creating examples/Makefile
     creating contrib/qValue-1.0.1/Makefile
     creating contrib/qcValue-1.0/Makefile

     $ ls -asCF (Makefile이 생성되었음을 알 수 있다)
     total 221
       1 ./                   44 README                1 contrib/
       1 ../                  60 README.pdf            1 examples/
       1 AUTHORS               2 config.cache          6 install-sh*
      26 COPYING               2 config.log            2 qDecoder.jpg
       2 DISCLAIMER            6 config.status*        1 rfc/
       3 Makefile             55 configure*            1 src/
       3 Makefile.in           3 configure.in

     $ make
     ===> src
     gcc -g -O2 -DSTDC_HEADERS=1 -DHAVE_CTYPE_H=1 -DHAVE_TIME_H=1 -DHAVE_SYS_STAT_H=1
      -DHAVE_SYS_TYPES_H=1 -DHAVE_STRFTIME=1 -DHAVE_VPRINTF=1 -DHAVE_STRDUP=1 -DHAVE_
     STRSTR=1 -I. -c -o qDecoder.o qDecoder.c
     ...(생략)...
     /bin/rm -f libqDecoder.so
     ln -s libqDecoder.so.1 libqDecoder.so
     <=== src
     ===> examples
     gcc -g -O2 -DSTDC_HEADERS=1 -DHAVE_CTYPE_H=1 -DHAVE_TIME_H=1 -DHAVE_SYS_STAT_H=1
      -DHAVE_SYS_TYPES_H=1 -DHAVE_STRFTIME=1 -DHAVE_VPRINTF=1 -DHAVE_STRDUP=1 -DHAVE_
     STRSTR=1 -I. -I../src -c -o fetch.o fetch.c
     ...(생략)...
     gcc -g -O2 -DSTDC_HEADERS=1 -DHAVE_CTYPE_H=1 -DHAVE_TIME_H=1 -DHAVE_SYS_STAT_H=1
      -DHAVE_SYS_TYPES_H=1 -DHAVE_STRFTIME=1 -DHAVE_VPRINTF=1 -DHAVE_STRDUP=1 -DHAVE_
     STRSTR=1 -I. -I../src -o arglist.cgi arglist.o ../src/libqDecoder.a
     <=== examples
     ...(생략)...

노트) 솔라리스의 경우 ``make''가 기본 PATH에 설정되어 있지 않은 경우가 종종
있는데 이때에는 make가 위치하는 `/usr/ccs/bin/''디렉토리를 PATH에 추가한 후
시도하자.

노트) 컴파일에 의해 생성된 라이브러리와 오브젝트를 지우고 초기 배포판
생태를 유지하고자 한다면 ``make clean''을 입력하기 바란다. 이때 ``make
clean''은 편의상 configure에 의해 생성된 Makefile은 제거하지 않는데, 초기
배포판과 완전 동일한 환경을 만들고자 한다면 ``make distclean''을 사용하면
된다.

설치

라이브러리를 설치하기 위해서는 ``make install'' 명령을 사용한다. ``make
install''은 시스템에 라이브러리를 설치하여 주며, 헤더와 라이브러리의 설치
위치는 configure시 --prefix, --libdir, --includedir 옵션에 의해 조정된다.
설치되는 위치와 옵션과의 관계는 다음과 같으며, 아무 인자없이 configure를
수행하였을 경우엔 /usr/local/lib, /usr/local/include 로 설치위치가
설정된다.

     ${prefix}          ===> /usr/local        (기본값)
     ${libdir}          ===> ${prefix}/lib     (기본값)
     ${includedir}      ===> ${prefix}/include (기본값)

     libqDecoder.a      ===> ${libdir}/libqDecoder.a
     libqDecoder.so.[n] ===> ${libdir}/libqDecoder.so.[n]
     libqDecoder.so     ===> ${libdir}/libqDecoder.so
     qDecoder.h         ===> ${includedir}/include/qDecoder.h

     ex) $ ./configure --prefix=/usr
     ex) $ ./configure --libdir=/home/nobreak/mylib --includedir=/home/nobreak/myinclude

노트) libqDecoder.so는 실제 공유라이브러리 libqDecoder.so.[n]를 가르키는
심볼릭 링크이다. 여기서 n은 1부터 증가하는 정수로 하위 호환성이 결여될
경우에 증가한다. 예로 6.0.1 버젼의 경우 libqDecoder.so.1 인데 qDecoder의
자체 버젼이 7.0, 8.0으로 증가한다 해도 하위 호환성이 유지된다면,
공유라이브러리는 여전히 libqDecoder.so.1 로 생성될 것이다.

     $ cd qDecoder-VERSION

     $ make install
     ln -s libqDecoder.so.1 libqDecoder.so
     /usr/bin/install -c -m 444 qDecoder.h /usr/local/include/qDecoder.h
     /usr/bin/install -c -m 444 libqDecoder.a /usr/local/lib/libqDecoder.a
     /usr/bin/install -c -m 444 libqDecoder.so.1 /usr/local/lib/libqDecoder.so.1
     /bin/rm -f /usr/local/lib/libqDecoder.so
     ln -s /usr/local/lib/libqDecoder.so.1 /usr/local/lib/libqDecoder.so

노트) 시스템 영역에 설치하기 위해서는 root 권한이 필요하다.

제거

설치된 qDecoder는 ``make deinstall''을 통해 깨끗하게 제거된다.

     $ make deinstall
     /bin/rm -f /usr/local/include/qDecoder.h
     /bin/rm -f /usr/local/lib/libqDecoder.a
     /bin/rm -f /usr/local/lib/libqDecoder.so.1
     /bin/rm -f /usr/local/lib/libqDecoder.so

테스트

examples 디렉토리엔 미리 제작된 예제 소스들이 들어 있다, 소스들은 패키지
컴파일시 자동으로 컴파일이 되기 때문에 해당 디렉토리의 examples.html을
브라우저로 연후 바로 테스트를 할 수 있다. 소스코드와 Makefile 을 살펴보며
여러분의 프로그램에 어떻게 qDecoder를 적용해야 하는지 살펴보기 바란다.

예제는 정적 라이브러리(libqDecoder.a)로 링크되었는데, 공유
라이브러리(libqDecoder.so)를 링크하면 프로그램이 더욱 컴팩트해지고
효율적으로 동작한다. examples/Makefile 의 ``QLIB = ../src/libqDecoder.a''를
``QLIB = ../src/libqDecoder.so''로 수정한후 examples 디렉토리에서 ``make
clean all''명령을 통해 재 컴파일 해보자. (Makefile의 수정없이 examples
디렉토리에서 다음과 같이 하여도 동일한 결과를 얻을 수 있다. ``make clean
all QLIB=../src/libqDecoder.so'')

     $ make clean all QLIB=../src/libqDecoder.a (정적 라이브러리 링크시)
     $ ls -al *.cgi
     -rwxr-xr-x  1 root  power  61876   6  2 22:32 arglist.cgi
     -rwxr-xr-x  1 root  power  61210   6  2 22:32 fetch.cgi
     -rwxr-xr-x  1 root  power  61331   6  2 22:32 multivalue.cgi
     -rwxr-xr-x  1 root  power  61551   6  2 22:32 streamedit.cgi
     -rwsr-sr-x  1 root  power  61639   6  2 22:32 upload.cgi

     $ make clean all QLIB=../src/libqDecoder.so (공유 라이브러리 링크시)
     $ ls -al *.cgi
     -rwxr-xr-x  1 root  power  12682   6  2 22:33 arglist.cgi
     -rwxr-xr-x  1 root  power  11560   6  2 22:33 fetch.cgi
     -rwxr-xr-x  1 root  power  11852   6  2 22:33 multivalue.cgi
     -rwxr-xr-x  1 root  power  12052   6  2 22:33 streamedit.cgi
     -rwsr-sr-x  1 root  power  12393   6  2 22:33 upload.cgi

Microsoft Visual C++ 환경에서의 사용

qDecoder는 편의상 유닉스 패키징 도구를 사용해 제공되고 대부분의 예제가
유닉스 환경 기준하에 작성되어 있지만, NT도 환경에서도 사용 가능하도록
개발된다. 패키지(6.0.2) 부터는 편리를 위해 대부분의 Windows 개발자가
사용하는 Microsoft Visual C++ 환경에서 정적 라이브러리를 바로 생성할 수
있도록 미리 설정된 프로젝트 파일을 포함하여 제공한다. 다른 컴파일러
환경에서도 비슷한 맥락으로 사용이 가능 할 것이다.

  1. 패키지 구하기: 패키지 구하기를 참고한다.
  2. 압축 풀기: 압축 해제 프로그램(예: WinZip)을 통해 패키지를 특정
     디렉토리에 풀어 놓는다.
  3. 컴파일:
       1. ``File -> Open Workspace'' 메뉴를 통해 win32/qDecoder.dsw 를
          연다.
       2. ``Build -> Build qDecoder.lib'' 메뉴를 통해 라이브러리 생성한다.

               ----Configuration: qDecoder - Win32 Release----
               Compiling...
               qDecoder.c
               Creating library...

               qDecoder.lib - 0 error(s), 0 warning(s)

  4. 설치: src/qDecoder.h 헤더 파일과 생성된 win32/Release/qDecoder.lib를
     특정한 디렉토리 혹은 Visual C++의 기본 헤더, 라이브러리 디렉토리에
     각각 복사한다. (기본 디렉토리에 복사해 두면 헤더와 라이브러리 사용시
     별도의 경로를 지정할 필요가 없다)
     예) C:\Program Files\Microsoft Visual Studio\VC98\Lib\qDecoder.lib
     예) C:\Program Files\Microsoft Visual Studio\VC98\Include\qDecoder.h
  5. 사용:
       1. 소스 파일에 #include <qDecoder.h> 혹은 #include
          "...PATH...\qDecoder.h"를 삽입한다.
       2. ''Project -> Setting -> Link -> Object/library modules'에
          qDecoder.lib를 추가한다. (기본 라이브러리 디렉토리에 설치되지
          않은 경우엔 경로 명시)
  6. 테스트:
       1. ``File -> New -> Win32 Console Application'' 생성
       2. ``FileView -> Source Files -> Add Files to Folder''를 통해
          examples/fetch.c 삽입
       3. ``Project -> Setting -> Link -> Object/library modules''에
          qDecoder.lib 추가
       4. ``Build -> Build PRJ_NAME.exe'' 컴파일 및 실행파일 생성
       5. 로컬 웹서버(IIS)의 CGI 실행 가능 디렉토리에 PRJ_NAME.exe를 복사후
          브라우저를 통해 동작 확인.
          http://localhost/...PATH.../PRJ_NAME.exe?query=OK
          [Pic: Win32 Test Step 1] [Pic: Win32 Test Step 2]

          [Pic: Win32 Test Step 3] [Pic: Win32 Test Step 4]

          [Pic: Win32 Test Step 5]

  ------------------------------------------------------------------------

화면 출력 함수군

qContentType()

Syntax: void qContentType(char *mimetype);
Function: MimeType을 출력한다.
Return:
Note: 여러번 호출되어도 단 한번만 수행된다.
Example:

     qContentType("text/html");  // HTML 출력시
     qContentType("image/gif");  // GIF 이미지 출력시

  ------------------------------------------------------------------------

qPrintf()

Syntax: int qPrintf(int mode, char *format, ...);
Function: printf()와 동일한 사용방법으로 HTML TAG의 적용 유뮤와 자동 Link를
행한다.
Return: 성공시 출력한 bytes 갯수, 에러시 EOF
Note: 조합된 스트링의 최대 크기가 10K(1024 * 10 - 1)을 넘으면 안된다.
Example:

     Mode 0 : printf()와 동일하다, HTML이 적용됨을 뜻한다.
     Mode 1 : HTML TAG 자체를 출력한다. Link되는 부분 없음.
     Mode 2 : Mode 1 + 자동으로 link 시킴.
     Mode 3 : Mode 2 + link를 클릭했을시 전화면(target=_top) 출력한다.
     Mode 4 : HTML TAG를 무시한다. 출력되지 않음.
     Mode 5 : Mode 4 + 자동으로 Link 시킴.
     Mode 6 : Mode 5 + link를 클릭했을시 전화면(target=_top) 출력한다.
     Mode 10  :Mode 0 + Convert
     Mode 11 : Print HTML TAG + Convert
     Mode 12 : Mode 11 + Auto Link
     Mode 13 : Mode 12 + Auto Link to _top frame
     Mode 14 : Waste HTML TAG + Convert
     Mode 15 : Mode 14 + Auto Link
     Mode 16 : Mode 15 + Auto Link to _top frame

     Convert : " "   -> " "
               "  "  -> " &nbsp;"
               "   " -> " &nbsp;&nbsp;"
               "\r"  -> 무시
               "\n"  -> "<br>\n"

     10 이상의 Mode 값은 <pre> 태그를 사용치 않고서도, 연속된 공백을 화면에 보여주고자 할 때
     사용하면 효과적이다. 또한 이 경우엔 화면폭의 변화에 따라 자동으로 줄바꿈이 수행된다.

     qPrintf(i, "Mode %d: <font>\"http://www.hongik.com\"</font>\n", i);

     Mode 0: <font>"http://www.hongik.com"</font>
     Mode 1: &lt;font&gt;&quot;http://www.hongik.com&quot;&lt;/font&gt;
     Mode 2: &lt;font&gt;&quot;<a href="http://www.hongik.com" target="">http://www.hongik.com</a>&quot;&lt;/font&gt;
     Mode 3: &lt;font&gt;&quot;<a href="http://www.hongik.com" target="_top">http://www.hongik.com</a>&quot;&lt;/font&gt;
     Mode 4: &quot;http://www.hongik.com&quot;
     Mode 5: &quot;<a href="http://www.hongik.com" target="">http://www.hongik.com</a>&quot;
     Mode 6: &quot;<a href="http://www.hongik.com" target="_top">http://www.hongik.com</a>&quot;
     Mode 10: <font>"http://www.hongik.com"</font><br>
     Mode 11: &lt;font&gt;&quot;http://www.hongik.com&quot;&lt;/font&gt;<br>
     Mode 12: &lt;font&gt;&quot;<a href="http://www.hongik.com" target="">http://www.hongik.com</a>&quot;&lt;/font&gt;<br>
     Mode 13: &lt;font&gt;&quot;<a href="http://www.hongik.com" target="_top">http://www.hongik.com</a>&quot;&lt;/font&gt;<br>
     Mode 14: &quot;http://www.hongik.com&quot;<br>
     Mode 15: &quot;<a href="http://www.hongik.com" target="">http://www.hongik.com</a>&quot;<br>
     Mode 16: &quot;<a href="http://www.hongik.com" target="_top">http://www.hongik.com</a>&quot;<br>

     qPrintf(i, "Mode %d: ' ', '  ', '   ', '    '\n", i);

     Mode 0: ' ', '  ', '   ', '    '
     Mode 1: ' ', '  ', '   ', '    '
     Mode 2: ' ', '  ', '   ', '    '
     Mode 3: ' ', '  ', '   ', '    '
     Mode 4: ' ', '  ', '   ', '    '
     Mode 5: ' ', '  ', '   ', '    '
     Mode 6: ' ', '  ', '   ', '    '
     Mode 10: ' ', ' &nbsp;', ' &nbsp;&nbsp;', ' &nbsp;&nbsp;&nbsp;'<br>
     Mode 11: ' ', ' &nbsp;', ' &nbsp;&nbsp;', ' &nbsp;&nbsp;&nbsp;'<br>
     Mode 12: ' ', ' &nbsp;', ' &nbsp;&nbsp;', ' &nbsp;&nbsp;&nbsp;'<br>
     Mode 13: ' ', ' &nbsp;', ' &nbsp;&nbsp;', ' &nbsp;&nbsp;&nbsp;'<br>
     Mode 14: ' ', ' &nbsp;', ' &nbsp;&nbsp;', ' &nbsp;&nbsp;&nbsp;'<br>
     Mode 15: ' ', ' &nbsp;', ' &nbsp;&nbsp;', ' &nbsp;&nbsp;&nbsp;'<br>
     Mode 16: ' ', ' &nbsp;', ' &nbsp;&nbsp;', ' &nbsp;&nbsp;&nbsp;'<br>

  ------------------------------------------------------------------------

qPuts()

Syntax: void qPuts(int mode, char *buf);
Function: 포맷에 의한 인자 전달이 안된다는 점을 제외하면 qPrintf()와
동일하나 주어진 인자 buf 자체를 수정하기 때문에, 상수 문자열(ex: str =
"문자열")이나 다시 사용되어야 하는 변수를 qPuts()로 출력하진 말아햐 한다.
qPuts()가 존재하는 이유는 qPrintf()에서와 같은 인자 스트링의 길이 제한이
없으며 strdup() 함수가 사용되지 않기에 조금 더 빠르기 때문이다.
Note: 인자로 전해준 문자열이 변형된다. 따라서 qPuts(mode, "문자열");
이런식의 상수 문자열 사용은 오류를 잃으킨다. 이때에는 아래의 사용법처럼
인자를 복사한후 사용한다.
Example:

     char buf[100];
     strcpy(buf, "http://www.hongik.com mailto:nobreak@hongik.com");
     qPuts(2, buf);

     char *buf;
     buf = strdup("http://www.hongik.com mailto:nobreak@hongik.com");
     qPuts(2, buf);
     free(buf);

  ------------------------------------------------------------------------

qError()

Syntax: void qError(char *format, ...);
Function: 오류에대한 Message를 출력한다. printf() 함수와 사용법 동일.
Note: 조합된 오류 메시지의 최대 크기는 1024-1 byte를 넘지 않아야 한다.
Example:

     qError("오류메시지");
     qError("%s에 오류", buf);

  ------------------------------------------------------------------------

qErrorLog()

Syntax: void qErrorLog(char *filename);
Function: qError() 함수를 부를때 전달되는 오류 메시지들이 기록되는
로그파일을 설정한다.
Note: 로그를 기록할때 본파일을 직접 호출하는것이 아니라,
qErrorLog("logs/error.log") 와같이 프로그램 초기에 호출하면 그 후
qError()가 호출될때마다, 'logs/error.log' 파일에 로그가 자동 기록 된다.
Example:

     qErrorLog("로그파일명");        // enable log
     qErrorLog(NULL);                // disable log (default)

  ------------------------------------------------------------------------

qErrorContact()

Syntax: void qErrorContact(char *msg);
Function: 오류 메시지의 꼬리말로 qError() 호출시 항상 붙어 출력된다.
일반적으로 제작처등의 고정 정보를 제공하기 위해 사용한다.
Return:
Note:
Example:

     qErrorContact("- Author");
     qErrorContact(NULL);            // disable (default)

  ------------------------------------------------------------------------

qRedirect()

Syntax: void qRedirect(char *url);
Function: HTTP의 Location: 헤더를 사용해 특정 페이지로 점프한다.
Note: qRedirect는 HTTP 헤더를 사용하므로 qConteneType() 등을 이전에
사용하여서는 안되고, 해당 프로세스에서 스트림 아웃하는 유일한 명령이어야
한다.
Example:

     qRedirect("http://www.hongik.com/");

  ------------------------------------------------------------------------

쿼리 관련 함수군

qDecoder()

Syntax: int qDecoder(void);
Function: 인코딩된 Query String을 해석하여 linked-list에 저장
Return: 성공시 전달받은 인자의 갯수, 에러시 -1
Example:

          int num;
          num = qDecoder();

     다음 형식의 인코딩된 쿼리를 지원한다.

        * application/x-www-form-urlencoded (%xx로 인코딩되는 일반형)
        * multipart/form-data (File Uploading에 사용됨)

     Example 1: application/x-www-form-urlencoded
     웹상에서 직접 사용자로부터 입력을 받을경우 주로 사용한다. 다음과
     같은 URL Encoding 형식의 일반적 [HTML] 문이 전달될경우 링크드
     리스트에는 [결과]와 같이 저장되고, [C]와 같이 사용한다.

          [HTML]
          <form method="post" action="input.cgi">
            사용자번호 <input type="text" name="userID"><br>
            <input type="submit">
          </form>

          [결과]
          name  = "userID"
          value = "사용자가 입력한 문자열"

          [C]
          #include <stdio.h>
          #include "qDecoder.h"
          void main(void) {
            char *id;
            qContentType("text/html");
            id = qValue("userID");
            printf("%s", id);
          }

     Example 2: multipart/form-data

     파일 업로딩 등을 원할때 주로 사용된다. 다음과 같은 형식의 [HTML]
     문이 사용되고, 로컬PC에서 'a.gif'란 128byte 파일을 업로드 할경우,
     내부적으로 [결과]와 같이 저장되며 [C]와 같이 사용할수 있다.

          [HTML]
          <form method="post" action="upload.cgi" enctype="multipart/form-data">
            사용자번호 <input type="text" name="userID"><br>
            업로드파일 <input type="file" name="binary"><br>
            <input type="submit">
          </form>

          [결과]
          name  = "userID"
          value = "사용자가 입력한 문자열"

          name  = "binary"
          value = "a.gif의 2진 자료"
          name  = "binary.length"
          value = "128"
          name  = "binary.filename"
          value = "a.gif"

          [C]
          #include <stdio.h>
          #include <stdlib.h>
          #include "qDecoder.h"

          void main(void) {
            FILE *fp;
            char *userID;
            char *filedata, *filename;
            int  filelength, i;

            qContentType("text/plain");

            userID = qValue("userID");

            filedata   = qValue("binary");
            filelength = qiValue("binary.length");
            filename   = qValue("binary.filename");

            fp = fopen(filename, "wb");
            for(i = filelength; i > 0; i--) fprintf(fp, "%c", *(filedata++));
            fclose(fp);

            printf("%s : %s(%s bytes) saved.", userID, filename, filelength);
          }

     HTML상에서 type=text 일경우 사용은 동일하다. type=file 일경우에는
     '변수명.length'와 '변수명.name'의 변수가 자동으로 삽입된다.
     '변수명.length'는 자료의 바이트수가 저장되며, '변수명.name'은
     사용자가 전송한 파일명이 저장된다. 저장할 파일명을 별도로
     받고싶을경우, 입력을 type=text 로 받아 처리하면 되지만, 본
     라이브러리에서는 사용자가 로컬 PC에서 브라우징한 파일명 자체를
     알려준다. 파일명은 \ 등의 기호가 제거 되어 들어간다.
     ("C:\Data\a.gif"일경우 "a.gif"만이 저장된다) 복귀값의 카운터는
     type=file 일경우 총 3개의 리스트가 생성되지만 이것은 1개의 자료에
     대한 처리이므로 1개로 처리한다. 내부적으로 저장되는 리스트는
     qPrint() 를 활용하여 확인할수 있다.

  ------------------------------------------------------------------------

qValue()

Syntax: char *qValue(char *format, ...);
Function: Linked-list에서 변수명에대한 값(문자열)을 찾아 포인터를 넘겨줌.
qDecoder()가 사전에 호출되지 않았다면 내부적으로 qDecoder 호출.
Return: 변수명이 존재하면 변수값의 포인터, 변수명이 없으면 NULL
Note: qValue()는 qDecoder()에 의해 생성된 쿼리 인덱스의 포인터만을
복귀한다. 따라서 qValue로 전달받은 포인터를 free() 하여서는 안된다. 할당
메모리 해제는 qFree() 함수를 통해(일반적으로 프로그램 종료전) 수행하여야
한다.
Example:

     char *test;
     test = qValue("변수명");

     char *test;
     int i = 1;
     test = qValue("COUNT.%d", i);

  ------------------------------------------------------------------------

qiValue()

Syntax: int qiValue(char *format, ...);
Function: qValue()와 같으나, 값(숫자 문자열)을 정수로 변환하여 복귀함.
Return: 성공시 변수값(숫자 문자열)에 대한 정수값. 변수명이 존재하지 않거나
변환 불가능시 0
Example:

     int test;
     test = qiValue("변수명");

     int test, i = 1;
     test = qValue("COUNT.%d", i);

  ------------------------------------------------------------------------

qValueDefault()

Syntax: char *qValueDefault(char *defstr, char *format, ...);
Function: 쿼리가 없을때 기본 인자를 설정하기 위해 사용하는 qValue()의 간략
함수이다.
Return: qValue()와 같으나 NULL시 defstr의 포인터를 복귀.
Example:

     value = qValueDefault("서울", "COUNTRY");

  ------------------------------------------------------------------------

qValueNotEmpty()

Syntax: char *qValueNotEmpty(char *errmsg, char *format, ...);
Function: 쿼리가 없거나 공백 문자열("")이 복귀될 시 qError()함수를 사용해
지정된 에러메세지를 출력한다.
Return: NULL에 대한 오류처리가 내장된 것을 제외하곤 qValue()와 같다.
Example:

     value = qValueNotEmpty("지역명을 입력해 주세요", "COUNTRY");

  ------------------------------------------------------------------------

qValueReplace()

Syntax: char *qValueReplace(char *mode, char *name, char *tokstr, char
*word);
Function: Linked-list 문자열에 대한 문자열 및 토큰 치환을 한다.
Return: 치환된 문자열 포인터.
Example:

     qValueReplace()는 기본적으로 qStrReplace()의 Wrapping 함수이다.
     차이점은 소스 문자열을 쿼리 값(name에 대한 linked-list의
     value)으로 한다는 점이며, 그 변환이 linked-list 자체에 직접적으로
     가해질 수도 있음에 있다.

     따라서 qValueReplace()의 인자 사용법은 qStrReplace()와 기본적으로
     동일하다.

     'name' 인자는 소스 문자열로 사용할 linked-list의 쿼리명이며 해당
     value을 치환시 사용할 소스 문자열로 한다.

     'mode' 인자는 "sr"와 같이 두개의 분리된 문자로 구성된 문자열이다.

     첫번째 문자는 치환방법을 정의하며 't'나 's'가 위치할 수 있다.
     't'는 [t]oken을 의미하며 tokstr 문자열의 각 문자를 토큰으로 소스
     문자열 (주어진 name에 대한 linked-list의 value 문자열)을
     비교하여, 매칭이 되는 문자를 word 문자열로 치환한다. 's'는
     [s]tring을 의미하여 tokstr 스트링 자체를 하나의 토큰으로 하여
     소스 스트링내에 나타나는 tokstr 매칭 문자열을 word 문자열로
     치환한다.

     두번째 문자는 치환된 문자열에 대한 기록 형태를 나타내며 'n'과
     'r'이 사용될 수 있다. 'n'은 [n]ew를 나타내며 치환된 결과 문자열을
     새로운 메모리 공간에 저장하여 해당 포인터를 리턴하게 한다. 따라서
     소스 스트링 linked-list 자체는 원상태가 유지되고 해당 메모리는
     사용자 측면에서 free() 되어야 한다. 'r'은 [r]eplace를 의미하며
     치환 결과를 linked-list 자체에 덮어 씀을 의미한다. 이것은
     내부적으로 메모리 재할당을 통해 이루어 진다.

     결과적으로 'mode' 인자는 다음과 같이 4개의 조합 가능한 경우를
     갖는다.

            Mode "tn" : [t]oken 치환 & 새로운 공간에 결과를 담아 복귀
            Mode "tr" : [t]oken 치환 & linked-list 자체를 수정
            Mode "sn" : [s]tring 치환 & 새로운 공간에 결과를 담아 복귀
            Mode "sr" : [s]tring 치환 & linked-list 자체를 수정

          Example)
            char *retstr, *mode;
            mode = qValue("mode");
            qContentType("text/plain");

            printf("before %s : srcstr = %s\n", mode, qValue("srcstr"));
            retstr = qValueReplace(mode, "srcstr", "hello", "[?]");
            printf("after  %s : srcstr = %s\n", mode, qValue("srcstr"));
            printf("            retstr = %s\n\n", retstr);
            if(mode[1] == 'n') free(retstr);
            return 0;

          Result 'tn')
            before tn : srcstr = hello world
            after  tn : srcstr = hello world
                        retstr = [?][?][?][?][?] w[?]r[?]d

          Result 'tr')
            before tr : srcstr = hello world
            after  tr : srcstr = [?][?][?][?][?] w[?]r[?]d
                        retstr = [?][?][?][?][?] w[?]r[?]d

          Result 'sn')
            before sn : srcstr = hello world
            after  sn : srcstr = hello world
                        retstr = [?] world

          Result 'sr')
            before sr : srcstr = hello world
            after  sr : srcstr = [?] world
                        retstr = [?] world

  ------------------------------------------------------------------------

qValueFirst()

Syntax: char *qValueFirst(char *format, ...);
Function: 동일한 변수명을 갖는 인자들을 순차적으로 패치할 때 사용.
Return: 성공시 동일한 변수명을 갖는 인자들에 대한 첫번째 변수값 포인터를
복귀, 변수명이 없을시 NULL.
Example:

     qValueFirst("checklist");

  ------------------------------------------------------------------------

qValueNext()

Syntax: char *qValueNext(void);
Function: qValueFirst()로 찾는 것을 계속한다.
Return: 성공시 변수값의 포인터, 더이상의 동일 변수명이 없을때 NULL.
Example:

     char *list;
     for(list = qValueFirst("checklist"); list; list = qValueNext()) {
       printf("checklist = %s<br>\n", list);
     }

  ------------------------------------------------------------------------

qGetFirstEntry()

Syntax: Q_Entry *qGetFirstEntry(void);
Function: Linked-list의 첫번째 Q_Entry 포인터를 복귀한다. qDecoder()에 의해
사용되는 linked-list를 직접 조작하고자 할때 루트 포인터를 얻기위해
사용한다.
Example:

     Q_Entry *first;
     first = qGetFirstEntry();

  ------------------------------------------------------------------------

qPrint()

Syntax: void qPrint(void);
Function: 프로그램의 디버깅용으로 전달된 인자를 모두 출력한다.
Example:

     qPrint();

  ------------------------------------------------------------------------

qFree()

Syntax: void qFree(void);
Function: qDecoder()에 의해 할당된 Memory를 해제한다.
Example:

     qFree();

  ------------------------------------------------------------------------

쿠키(cookie) 관련 함수군

qSetCookie()

Syntax: void qSetCookie(char *name, char *value, int exp_days, char *path,
char *domain, char *secure);
Function: name=value 에 해당하는 쿠키를 설정함.
Note: qContentType()이 호출되기 전에 사용하여야 한다.
Example:

     char *name = "NAME", *value = "Kim";

     // NAME=Kim 이란 정보를 현재 도메인과 현재 디렉토리에 30일간 적용한다.
     qSetCookie(name, value, 30, NULL, NULL, NULL);

     // NAME=Kim 이란 정보를 "ANYTHING.qdecoder.org"의 "/" 디렉토리에 대해
     // 브라우저가 종료될 때 까지 적용한다.
     qSetCookie(name, value, 0, "/", ".qdecoder.org", NULL);

  ------------------------------------------------------------------------

qcDecoder()

Syntax: int qcDecoder(void);
Function: 쿠키를 해석하여 linked-list에 저장
Return: 성공시 전달받은 인자의 갯수, 에러시 -1
Note:
Example:

     int num;
     num = qcDecoder();

  ------------------------------------------------------------------------

qcValue()

Syntax: char *qcValue(char *format, ...);
Function: Linked-list에서 변수명에대한 값(문자열)을 찾아 포인터를 넘겨줌.
Return: 변수명이 존재하면 변수값의 포인터, 변수명이 없으면 NULL.
Note: qcDecoder()가 사전에 호출이 안되었으면, 자동 수행.
Example:

     char *value;
     value = qcValue("변수명");

  ------------------------------------------------------------------------

qciValue()

Syntax: int qciValue(char *format, ...);
Function: Linked-list에서 변수명에대한 값(숫자 문자열)을 찾아 정수로 변환후
넘겨줌.
Return: 성공시 변수값(숫자 문자열)에 대한 정수값. 변수명이 존재하지 않거나
변환 불가능시 0.
Note: qcDecoder()가 사전에 호출이 안되었으면 자동 수행
Example:

     int value;
     value = qciValue("변수명");

  ------------------------------------------------------------------------

qcPrint()

Syntax: void qcPrint(void);
Function: 프로그램의 디버깅용으로 쿠키값을 모두 출력한다.
Example:

     qcPrint();

  ------------------------------------------------------------------------

qcFree()

Syntax: void qcFree(void);
Function: qcDecoder()에 의해 할당된 Memory를 해제한다.
Example:

     qcFree();

  ------------------------------------------------------------------------

문자열 관련 함수군

qURLencode()

Syntax: char *qURLencode(char *str);
Function: 문자열을 URL Encoding 한다.
Return: URL Encoding된 문자열이 메모리 할당되어 복귀된다. 해제(free)는
사용자가 하여야 한다.
Example:

     char *encstr;
     encstr = qURLencode("안녕하세요?");

  ------------------------------------------------------------------------

qURLdecode()

Syntax: char *qURLdecode(char *str);
Function: %xx로 URL Encoding된 문자열을 해독한다.
Return: 문자열 포인터
Note: 해독된 문자열은 메모리 할당되지 않고 str 자체에 덮어 쓰여진다.
Example:

     char *encstr;
     qURLdecode(encstr);

  ------------------------------------------------------------------------

qRemoveSpace()

Syntax: char *qRemoveSpace(char *str);
Function: 문자열의 앞뒤 공백과 CR, LF를 제거한다.
Return: 성공시 문자열의 포인터, 실패시 NULL.
Note: qRemoveSpace("문자열"); 이런식의 사용은 오류를 잃으킬수 있다.
이때에는 아래의 사용법처럼 인자를 복사한후 사용한다.
Example:

     char teststr[100];
     strcpy(teststr, "  Hello, world    \r\n  ");
     qRemoveSpace(teststr); // 삭제후 teststr에는 "Hello, world"가 들어간다.

  ------------------------------------------------------------------------

qStr09AZaz()

Syntax: int qStr09AZaz(char *str);
Function: 문자열이 '0' - '9', 'A' - 'Z', 'a' - 'z'로 이루어졌는지 판별한다.

Return: 조건에 부합하면 1, 오류시 0
Example:

     if(qStr09AZaz("abc1234") == 1) printf("True");

  ------------------------------------------------------------------------

qStrupr()

Syntax: char *qStrupr(char *str);
Function: 인자로 주어진 문자열을 모두 대문자로 변환한다.
Return: 해당 문자열의 포인터
Example:

     char *str;
     str = strdup("Hello World");
     qStrupr(str);

  ------------------------------------------------------------------------

qStristr()

Syntax: char *qStristr(char *big, char *small);
Function: strstr() 함수와 같으나, 대소문자를 구분하지 않고 비교한다.
Return: strstr()과 같음
Example:

     printf("%s", qStristr("Hello World", "WORLD"));

  ------------------------------------------------------------------------

qStricmp()

Syntax: int qStricmp(char *s1, char *s2);
Function: strcmp() 함수와 같으나, 대소문자를 구분하지 않는다.
Return: strcmp()와 같음
Example:

     if(!qStricmp("Hello", "HELLO")) printf("Equal");
     else printf("Differ");

  ------------------------------------------------------------------------

qitocomma()

Syntax: char *qitocomma(int value);
Function: 숫자를 콤마 문자열로 변환한다.
Return: 문자로 변환된 스트링 포인터.
Note: 복귀 스트링 포인터는 사용자가 매번 free()하는 번거로움을 없애기 위해
메모리를 할당하여 반환치 않고 함수 내부에 static 선언되어 있다. 따라서
qitocomma()는 매번 동일한 스트링 포인터를 반환하게 되며 함수가 수행될 때
마다 이전 값이 지워짐에 유의하여야 한다.
Example:

     1) (O) 바른 사용 예, 단일 인자 사용시
        printf("Price = %s", qitocomma(1234567));
        Price = 1,234,567

     2) (O) 바른 사용 예, 복수 인자 사용시
        char a[14+1], b[14+1];
        strcpy(a, qitocomma(1234));
        strcpy(b, qitocomma(5678));
        printf("Price = %s + %s\n", a, b);
        Price = 1,234 + 5,678

     3) (X) 잘못된 사용예
        printf("%s %s\n", qitocomma(1234), qitocomma(5678));
        Price = 1,234 + 1,234

  ------------------------------------------------------------------------

qStrReplace()

Syntax: char *qStrReplace(char *mode, char *srcstr, char *tokstr, char
*word);
Function: 문자열에 대한 문자열 및 토큰 치환을 한다.
Return: 치환된 스트링 포인터.
Example:

     'mode' 인자는 "sr"와 같이 두개의 분리된 문자로 구성된 문자열이다.

     첫번째 문자는 치환방법을 정의하며 't'나 's'가 위치할 수 있다.
     't'는 [t]oken을 의미하며 tokstr 문자열의 각 문자를 토큰으로 소스
     문자열 srcstr을 비교하여, 매칭이 되는 문자를 word 문자열로
     치환한다. 's'는 [s]tring을 의미하여 tokstr 스트링 자체를 하나의
     토큰으로 하여 소스 스트링내에 나타나는 tokstr 매칭 문자열을 word
     문자열로 치환한다.

     두번째 문자는 치환된 문자열에 대한 기록 형태를 나타내며 'n'과
     'r'이 사용될 수 있다. 'n'은 [n]ew를 나타내며 치환된 결과 문자열을
     새로운 메모리 공간에 저장하여 해당 포인터를 리턴하게 한다. 따라서
     소스 스트링 자체는 원상태가 유지되고 해당 메모리는 사용자
     측면에서 free() 되어야 한다. 'r'은 [r]eplace를 의미하며 치환
     결과를 srcstr에 덮어 씀을 의미한다. 이때 srcstr이 충분히
     여유있다고 가정하므로(편리성의 이유로 메모리 재할당을 하지 않음)
     [r]eplace 모드를 사용하고자 할 때에는 이 점에 유의하여야 한다.

     결과적으로 'mode' 인자는 다음과 같이 4개의 조합 가능한 경우를
     갖는다.

            Mode "tn" : [t]oken 치환 & 새로운 공간에 결과를 담아 복귀
            Mode "tr" : [t]oken 치환 & linked-list 자체를 수정
            Mode "sn" : [s]tring 치환 & 새로운 공간에 결과를 담아 복귀
            Mode "sr" : [s]tring 치환 & linked-list 자체를 수정

          Example)
            int  i;
            char srcstr[256], *retstr;
            char mode[4][2+1] = {"tn", "tr", "sn", "sr"};

            for(i = 0; i < 4; i++) {
              strcpy(srcstr, "Welcome to the qDecoder project.");
              printf("before %s : srcstr = %s\n", mode[i], srcstr);

              retstr = qStrReplace(mode[i], srcstr, "the", "_");
              printf("after  %s : srcstr = %s\n", mode[i], srcstr);
              printf("            retstr = %s\n\n", retstr);
              if(mode[i][1] == 'n') free(retstr);
            }

          Result)
            before tn : srcstr = Welcome to the qDecoder project.
            after  tn : srcstr = Welcome to the qDecoder project.
                        retstr = W_lcom_ _o ___ qD_cod_r proj_c_.

            before tr : srcstr = Welcome to the qDecoder project.
            after  tr : srcstr = W_lcom_ _o ___ qD_cod_r proj_c_.
                        retstr = W_lcom_ _o ___ qD_cod_r proj_c_.

            before sn : srcstr = Welcome to the qDecoder project.
            after  sn : srcstr = Welcome to the qDecoder project.
                        retstr = Welcome to _ qDecoder project.

            before sr : srcstr = Welcome to the qDecoder project.
            after  sr : srcstr = Welcome to _ qDecoder project.
                        retstr = Welcome to _ qDecoder project.

  ------------------------------------------------------------------------

검색어 관련 함수군

qArgMake()

검색어 관련 함수군은 질의 문자열을 스페이스와 큰따옴표(") 기준으로 나누어
리스트에 담아주며, 대상 문자열과의 매칭 테스트와 출력에 관련된 함수군을
제공한다.

     ---- Example ----
     Query Input: I am a "pretty girl"
     -----------------
           |  |
           V  V
     ---- qArgMake() ----
     qlist[0] = I
     qlist[1] = am
     qlist[2] = a
     qlist[3] = pretty girl
     qlist[4] = NULL
     Return: 4 (4 Tokens)
     --------------------
           |  |
           V  V
     ---- qArgPrint() ----
     'I' (1 bytes)
     'am' (2 bytes)
     'a' (1 bytes)
     'pretty girl' (11 bytes)
     ---------------------
           |  |
           V  V
     ---- qArgMatch() ----
     Target String: Hi, I'm a pretty boy. Are you pretty girl?
                     =  =   =             =       ===========
                     0  0   2             2             3
     Return: 3 (3 matches: qlist[0], qlist[2], qlist[3])
     ---------------------
           |  |
           V  V
     ---- qArgEmprint() ----
     Target String..: Hi, I'm a pretty boy. Are you pretty girl?
     Result.........: Hi, I'm a pretty boy. Are you pretty girl?
                       =  =   =             =       ===========
                       1  2   3             4             5
     Return: 5 (5 matches)
     -----------------------

Syntax: int qArgMake(char *str, char **qlist);
Function: 쿼리를 토큰으로 분리한다. 구분자는 기본적으로 스페이스 문자 이며
쿼리의 앞뒤 공백과 토큰 사이의 중복된 스페이스는 무시된다.
Return: 구분된 토큰 수
Note: 쿼리내 큰따옴표(")로 둘러싸인 문자열은 그 자체를 하나의 토큰으로
취급한다.
Example:

     char *query="I am a \"pretty girl\".", *qlist[MAX_TOKENS];
     int queries;
     queries = qArgMake(query, qlist);

  ------------------------------------------------------------------------

qArgMatch()

Syntax: int qArgMatch(char *str, char **qlist);
Function: 대소문자를 구분하지 않고 토큰 매칭 테스트를 한다.
Return: 특정 문자열에서 발견되는 토큰의 개수를 복귀하며, 같은 토큰에
대해서는 중복되어 매칭되어도 1회로 계산한다. 중복 매칭을 포함하여 문자열내
총 매칭 카운트를 위해서는 qArgEmprint()의 복귀값을 참고하라. 이 값들은
qArgMake()에서 얻은 토큰의 총 개수로 백분율하여 검색 정확도를 계산하는데
쓰일 수 있다.
Example:

     int matches;
     matches = qArgMatch("Hi, I'm a pretty boy. Are you pretty girl?", qlist);

  ------------------------------------------------------------------------

qArgEmprint()

Syntax: int qArgEmprint(int mode, char *str, char **qlist);
Function: 문자열에서 토큰과 매칭되는 부분을 볼드(bold)처리하여 출력한다.
대소문자를 구분하지 않는다.
Return: 문자열에서 발견된 토큰의 개수를 복귀하며, qArgMatch()와는 다르게
중복 매칭을 포함하여 총 매칭 카운트를 복귀한다.
Note: mode값은 qPrintf()와 동일하며, 일반적인 목적엔 1이 주로 사용될 수
있겠다.
Example:

     qArgEmprint(1, "Hi, I'm a pretty boy. Are you pretty girl?", qlist);

  ------------------------------------------------------------------------

qArgPrint()

Syntax: void qArgPrint(char **qlist);
Function: 프로그램의 디버깅용으로 해석된 토큰을 모두 출력한다.
Example:

     qArgPrint(qlist);

  ------------------------------------------------------------------------

qArgFree()

Syntax: void qArgFree(char **qlist);
Function: 메모리 할당된 qlist를 해제한다.
Example:

     qArgFree(qlist);

  ------------------------------------------------------------------------

파일 관련 함수군

qCheckFile()

Syntax: int qCheckFile(char *filename);
Function: 화일의 존재여부를 파악한다.
Return: 화일이 존재 하면 1, 화일이 없으면 0.
Note: Permission에 의해 접근 불가능한 화일도 화일이 없다고 판단한다.
Example:

     if(qCheckFile("test.dat") == 0) qError("File not found");

  ------------------------------------------------------------------------

qCatFile()

Syntax: int qCatFile(char *filename);
Function: 화일의 내용을 출력한다.
Return: 정상시 출력된 문자수, 에러시 -1
Note:
Example:

     qContentType("image/gif");
     qCatFile("mypic.gif");

     qContentType("text/html");
     qCatFile("myhtml.html");

  ------------------------------------------------------------------------

qReadFile()

Syntax: char *qReadFile(char *filename, int &size);
Function: 파일을 읽어 메모리에 저장후 포인터 반환
Return: 정상시 스트링 포인터, 오류시 NULL.
Note: qReadFile은 실제 파일의 크기보다 1바이트 크게 메모리 할당 하여 스트링
종료문자 '\0'를 삽입한다. 이는 텍스트 파일을 읽어 다루기 편리하도록 함이다.
spsize에는 파일에서 읽어들인 캐릭터 개수가 저장된다. 캐릭터 개수가 필요치
않다면 spsize 항목에 NULL 인자를 전달한다.
Example:

     char *sp, *sp2;
     int spsize;
     sp  = qReadFile("filename", &spsize);
     sp2 = qReadFile("filename2", NULL);
     ...
     free(sp), free(sp2);

  ------------------------------------------------------------------------

qSaveStr()

Syntax: int qSaveStr(char *sp, int spsize, char *filename, char *mode);
Function: 스트링의 내용을 파일에 저장한다.
Return: 정상시 저장한 캐릭터 갯수(파일 크기), 오류시 -1, 퍼미션 조정 실패
-2
Note: mode 인자는 fopen 시에 사용되는 mode 값과 같다. qSaveStr은 해당
mode로 파일을 오픈할 것이다. 파일 퍼미션은 호출전의 umask() 설정값에
의존선을 갖는다.
Example:

     char *sp = "To subscribe qDecoder mailing list\nSend mail to majordomo@hongik.com";
     int len;
     umask(0);
     len = qSaveStr(sp, strlen(sp), "Howto-mailing.txt", "wt", 0644);

  ------------------------------------------------------------------------

qfGetLine()

Syntax: char *qfGetLine(FILE *fp);
Function: 화일에서 길이 제약없이 라인을 읽는다.
Return: 할당된 메모리 포인터, 파일 끝 NULL.
Note: 복귀된 스트링 포인터의 메모리 해제는 사용자가 하여야 한다.
Example:

     line = qfGetLine(fp);

  ------------------------------------------------------------------------

qFileSize()

Syntax: long qFileSize(char *filename);
Function: 파일의 용량을 byte 단위로 돌려줌
Return: 성공 파일의 용량, 파일 없음 -1
Example:

     long size;
     size = qFileSize("/home/nobreak/sample.pdf");

  ------------------------------------------------------------------------

형식화된 설정 파일을 다루는 함수군

qfDecoder()

     ## 아래와 같은 형식의 화일을 읽어 linked-list에 저장한다.
     ---- test.conf ----
     # this is comment.
     name  = Kim
     phone = 123-4567
     addr  = 한국
     -------------------

Syntax: Q_Entry *qfDecoder(char *filename);
Function: 화일을 읽어 linked-list에 저장한다. (화일의 행길이 제약없음)
Return: Linked-list의 첫번째 레코드 포인터, 에러시 NULL.
Note: 샵(#)으로 시작되는 행은 주석으로 처리해 해석하지 않는다.
Example:

     Q_Entry *firstRecord;
     firstRecord = qfDecoder("test.conf");

  ------------------------------------------------------------------------

qfValue()

Syntax: char *qfValue(Q_Entry *first, char *name);
Function: 변수명의 변수값을 얻는다.
Return: 성공시 변수값의 포인터, 실패시 NULL.
Example:

     char *value;
     value = qfValue(FirstRecord, "name");

  ------------------------------------------------------------------------

qfiValue()

Syntax: int qfiValue(char *format, ...);
Function: 변수값을 정수로 변환후 넘겨준다.
Return: 설공시 변수값(숫자 문자열)에 대한 정수값. 변수명이 존재하지 않거나,
해당 값이 정수로 변환 불가능 하면 0
Example:

     int counter;
     counter = qfiValue(FirstRecord, "counter");

  ------------------------------------------------------------------------

qfPrint()

Syntax: void qfPrint(Q_Entry *first);
Function: 프로그램의 디버깅용으로 해석한 인자를 모두 출력한다.
Example:

     qfPrint(FirstRecord);

  ------------------------------------------------------------------------

qfFree()

Syntax: void qfFree(Q_Entry *first);
Function: 할당된 Memory를 반환한다.
Example:

     qfFree(FirstRecord);

다음과 같은 형식의 문자열을 읽어 linked-list에 저장한다.

     ---- test.conf ----
     # this is comment.
     name  = Seung-young Kim
     age   = 26
     addr  = 한국
     -------------------

  ------------------------------------------------------------------------

qsDecoder()

Syntax: Q_Entry *qsDecoder(char *str);
Function: 문자열을 읽어 linked-list에 저장한다. (화일의 행길이 제약없음)
Return: Linked-list의 첫번째 레코드 포인터, 에러시 NULL.
Note:
Example:

     Q_Entry *FirstRecord;
     char *str="name=Seung-young Kim\nage=26\naddr=한국";
     FirstRecord = qsDecoder(str);

  ------------------------------------------------------------------------

qsValue()

Syntax: char *qsValue(Q_Entry *first, char *name);
Function: 변수명의 변수값을 얻는다.
Return: 성공시 변수값의 포인터, 실패시 NULL.
Note:
Example:

     char *name;
     name = qsValue(FirstRecord, "name");

  ------------------------------------------------------------------------

qsiValue()

Syntax: int qsiValue(char *format, ...);
Function: 변수값을 정수로 변환후 넘겨준다.
Return: 설공시 변수값(숫자 문자열)에 대한 정수값. 변수명이 존재하지 않거나,
해당 값이 정수로 변환 불가능 하면 0.
Note:
Example:

     int age;
     age = qsiValue(FirstRecord, "age");

  ------------------------------------------------------------------------

qsPrint()

Syntax: void qsPrint(Q_Entry *first);
Function: 프로그램의 디버깅용으로 해석한 인자를 모두 출력한다.
Example:

     qsPrint(FirstRecord);

  ------------------------------------------------------------------------

qsFree()

Syntax: void qsFree(Q_Entry *first);
Function: 할당된 Memory를 반환한다.
Return:
Note:
Example:

     qsFree(FirstRecord);

  ------------------------------------------------------------------------

qReadCounter()

다음과 같은 형식의 카운터 화일을 다룬다.

     ---- number.dat ----
     74
     --------------------

Syntax: int qReadCounter(char *filename);
Function: 화일명의 카운터 화일을 읽는다.
Return: 성공시 카운터값, 에러시 0
Example:

     int count;
     count = qReadCounter("number.dat");

  ------------------------------------------------------------------------

qSaveCounter()

Syntax: int qSaveCounter(char *filename, int number);
Function: 지정된 화일명에 카운터 값을 저장(갱신)한다.
Return: 성공시 1, 에러시 0
Example:

     qSaveCounter("number.dat", 75);

  ------------------------------------------------------------------------

qUpdateCounter()

Syntax: int qUpdateCounter(char *filename, int number);
Function: 지정된 화일명의 카운터 값을 number만큼 증가시킨다.
Return: 성공시 기존 카운터값 + number, 에러시 0
Example:

     int count;
     count = qUpdateCounter("number.dat", -3);

  ------------------------------------------------------------------------

qAwkOpen()

     ## UNIX 시스템의 AWK 명령과 흡사한 기능을 한다.
     ---- ex) /etc/passwd ----
     shpark:x:1008:1000:Sang-hyun Park:/home/shpark:/bin/csh
     teamwork:x:1011:1000:Seung-young Kim:/home/teamwork:/bin/csh
     kikuchi:x:1015:2000:KIKUCHI:/home/kikuchi:/bin/csh
     ---------------------

Syntax: int qAwkOpen(char *filename, char separator);
Function: 파일을 열고, 구분자를 설정한다.
Return: 성공시 1, 파일을 열 수 없을경우 0
Example:

     qAwkOpen("/etc/passwd", ':');

  ------------------------------------------------------------------------

qAwkNext()

Syntax: int qAwkNext(char array[][256]);
Function: 한행을 읽어 들여, 인자로 주어진 배열에 저장한다.
Return: 성공시 필드 수, 파일의 끝 -1
Note: 행길이는 제한이 없으나, 각 필드는 256 바이트를 넘어선 안된다.
Example:

     char array[7][256];
     qAwkOpen("/etc/passwd", ':');
     for( ; qAwkNext(array) > 0; ) printf("ID=%s, Name=%s", array[0], array[5]);
     qAwkClose();

  ------------------------------------------------------------------------

qAwkClose()

Syntax: int qAwkClose(void);
Return: 성공시 1, 열려있는 파일이 없을때 0.
Function: 오픈된 파일을 닫는다.
Example:

     qAwkClose();

  ------------------------------------------------------------------------

qSedFile()

     ## UNIX 시스템의 SED 명령과 흡사한 기능을 한다.
     ---- ex) streamedit.html.in ----
     Hi "${NAME}" <${EMAIL}>.
     <p>You got a really cool hobby.
     <br>I'm sure that your hobby, ${HOBBY},
     can make your life more compatible.
     ---------------------

Syntax: int qSedFile(char *filename, FILE *fpout, char **arg);
Function: 파일에서 지정된 기호를 정의된 문자열로 교체하여 출력하며, 일부
SSI 문법을 지원한다.
Return: 성공시 1, 파일을 열 수 없을경우 0
Note: 본 함수은 Unix 시스템의 Sed와 SSI 를 포괄적으로 지원하도록 확장될
예정이다.
Example:

     qSedFile를 활용하면, 프로그램내에 HTML 코드를 전혀 포함하지
     않고도 CGI 프로그래밍을 할 수 있다. UI와 관련된 디버깅 시간을
     대폭 줄일 수 있고, 디자인과 개발의 분리작업이 가능하며, 패키지
     제품의 경우 사용자 측면에서 손쉽게 커스터 마이징이 가능할 수
     있는등의 효용성을 동반할 수 있다.

     filename은 입력(대상)파일이고, fpout은 출력 스트림을 의미한다.
     결과를 파일로 출력을 하고 자 할경우엔 파일을 "wt"로 열어, 해당
     파일 포인터를 건네어 주면 되고, 화면 출력하고자 한다면, 그냥
     stdout 을 지정하면 된다.

     인자 목록은 다음과 같은 형식을 취한다.

     "명령+구분자+지정문자열+구분자+교체문자열+구분자"

          ex) char *arg[3 + 1] = { "s/${NAME}/Seung-young Kim/",
                                   "s%${EMAIL}%nobreak@hongik.com%",
                                   "s:${HOBBY}:Playing with Ji-su Hwang:",
                                   NULL };

     명령은 현재 's' 만이 지원되며, 이는 교체(replacement)를 의미한다.
     구분자는 1바이트의 특정 문자열로 사용자가 임의 지정하면 된다.
     보통 구분자로는 '/'나 '%'를 많이 사용하지만, 문자열내에 해당
     캐릭터가 나올 경우엔 '#', 'A'등의 임의 문자열을 사용하기 바란다.
     지정 문자열도 임의대로 지정이 가능하지만, 가시성과 원치않는
     교체를 막기위해 특별한 이유가 없다면, ${STING}과 같이
     쉘스크립트의 변수 명명법을 따르도록 하라.

     앞의 streamedit.html.in 파일을 위의 인자 목록으로 다음과 같이
     수행하였을 경우의 출력을 보자.

          ex) qSedFile("streamedit.html.in", stdout, arg);

          Hi "Seung-young Kim" <nobreak@hongik.com>.
          <p>You got a really cool hobby.
          <br>I'm sure that your hobby, Playing with Ji-su Hwang,
          can make your life more compatible.

     SSI 문법을 해석한다. (현재는 <!--#include file="FILEPATH"--> 만이
     지원됨) 문서내 다음과 같은 라인이 있을 경우, 해당 문서를 포함하여
     출력되며, 포함되는 문서에 대해서도 교체및 SSI 기능은 그대로
     유효하다. (Cascading)

          <!--#include file="streamedit.html.in"-->

     주의) include 되는 파일은 CGI가 실행되는 위치를 기준으로 상대경로
     표기 하거나, 시스템 절대경로 표기한다.

     문자열 교체를 하지않고, SSI 기능만을 사용코자 할 경우엔 다음과
     같이 arg 인자로 NULL 값을 전달한다.

          ex) qSedFile("streamedit.html.in", stdout, NULL);

  ------------------------------------------------------------------------

qSedStr()

Syntax: int qSedStr(char *srcstr, FILE *fpout, char **arg);
Function: qSedFile()과 동일한 기능을 하나, 입력을 문자열로 받는다.
Return: qSedFile()과 동일
Example:

     qSedStr("Hi my name is ${NAME}.", stdout, arg);

  ------------------------------------------------------------------------

시간 관련 함수군

qGetTime()

Syntax: struct tm *qGetTime(void);
Function: 시간을 구조체 tm에 저장한다.
Return: 구조체 tm의 포인터
Note:
Example:

     struct tm *mytime;
     mytime = qGetTime();

  ------------------------------------------------------------------------

qGetGMTime()

Syntax: time_t qGetGMTime(char *gmt, time_t plus_sec);
Function: '현재시간+plus_sec'을 쿠키에서 사용하는 GMT 문자열 시간으로
변환한다.
Return: 1970/1/1(00:00:00)부터 현제까지의 초 + plus_sec
Note:
Example:

     time_t plus_sec;
     char gmt[0xff];
     plus_sec = (time_t)300; /* 5분 */
     qGetGMTime(gmt, plus_sec);
     printf("%s", gmt); // "Fri, 22-Aug-1997 15:11:30 GMT"

  ------------------------------------------------------------------------

형식 검사 함수군

qCheckEmail()

Syntax: int qCheckEmail(char *email);
Function: E-mail 주소의 오류를 판별한다.
Return: 오류가 없으면 1, 문제가 발생하면 0.
Note:
Example:

     qCheckEmail("nobreak@hongik.com");

  ------------------------------------------------------------------------

qCheckURL()

Syntax: int qCheckURL(char *url);
Function: URL 주소의 오류를 판별한다.
Return: 오류가 없으면 1, 규칙에 준하지 않으면 0
Example:

     qCheckURL("http://www.hongik.com");

  ------------------------------------------------------------------------

기타 함수군

qGetEnv()

Syntax: char *qGetEnv(char *envname, char *nullstr);
Function: getenv()함수와 동일하게 동작하나, NULL 대신 디폴드 스트링을
복귀한다.
Example:

     char *name;
     name = qGetEnv("SCRIPT_NAME", "/cgi-bin/CrazyWWWBoard.cgi");
     name = qGetEnv("SCRIPT_NAME", NULL);

  ------------------------------------------------------------------------

qCGIenv()

Syntax: void qCGIenv(Q_CGIenv *env);
Function: CGI의 환경변수와 시간을 구조체에 저장한다.
Example:

     Q_CGIenv myenv;
     qCGIenv(&myenv);

     typedef struct Q_CGIenv Q_CGIenv;
     struct Q_CGIenv{
       char *auth_type;
       char *content_length;
       char *content_type;
       char *document_root;
       char *gateway_interface;
       char *http_accept;
       char *http_accept_encoding;
       char *http_accept_language;
       char *http_connection;
       char *http_cookie;
       char *http_host;
       char *http_referer;
       char *http_user_agent;
       char *query_string;
       char *remote_addr;
       char *remote_host;
       char *remote_port;
       char *remote_user;
       char *request_method;
       char *request_uri;
       char *script_filename;
       char *script_name;
       char *server_admin;
       char *server_name;
       char *server_port;
       char *server_protocol;
       char *server_software;
       char *server_signature;
       char *unique_id;

       /* Miscellaneous Informations Supported by qDecoder */
       int  year, mon, day, hour, min, sec;
     };

  ------------------------------------------------------------------------

qCGIname()

Syntax: char *qCGIname(void);
Function: 환경변수 SCRIPT_NAME에서 프로그램명만을 해석하여 복귀한다.
Return:
Note:
Example:

     char *cginame;
     cginame = qCGIname();

  ------------------------------------------------------------------------

qDownload()

Syntax: int qDownload(char *filename);
Function: 클라이언트로 파일을 전송하는데, 파일의 종류에 상관없이 브라우저에
다운로딩 상자가 나타나도록 한다.
Return: 성공 전송한 바이트수, 파일 없음 -1
Note: 본 함수는 편의를 위한 qDownloadMime()의 껍대기 함수이다.
Example:

     qDownload("/home/nobreak/myprg.exe");

  ------------------------------------------------------------------------

qDownloadMime()

Syntax: int qDownloadMime(char *filename, char *mime);
Function: 클라이언트로 마임에 준하여 파일을 전송한다.
Return: 성공 전송한 바이트수, 파일 없음 -1
Note: 본 함수는 해당 파일을 웹상에 직접 링크하였을 때와 동일한 결과를
갖지만, 사용자 인증이 되어야만 다운로드 할 수 있도록 전처리를 하거나,
웹상에 공개될 수 없는 파일을 특정 프로그램을 통해서만 다운받을 수 있게
하는데 유용하다. mime이 'application/octet-stream'일 경우에는 qDownload()와
동일하다. 또한 스트림이 종료될때 까지 프로세스가 실행되게 되므로, 웹상에도
링크가 걸릴 수 있는 파일인데 다운로딩 카운트등을 위한 전처리로 사용할
경우라면 qRedirect()를 활용하는 것이 좋다.
Example:

     qDownload("/home/nobreak/myprg.gif", "image/gif");

  ------------------------------------------------------------------------

qReset()

Syntax: void qReset(void);
Function: qDecoder를 초기화 한다.
Note: Daemon 형태의 반복적 프로그램을 작성하거나 qDecoder를 새롭게 초기화
하고자 할 때 본 함수가 사용될 수 있다. qReset()은 linked-list를 포함하여
자체적으로 할당한 메모리를 모두 반환하고 내부 정적 변수들을 초기 상태로
환원시키는 작업을 한다.
Example:

     qReset();
