欢迎来到虫虫下载站 | 资源下载 资源专辑 关于我们
虫虫下载站

apr-tutorial.sgml

跨平台windowsunixlinux的c语言编程解决方案
SGML
第 1 页 / 共 5 页
字号:
- string formats (e.g. rfc822)We use the following APIs to convert apr_time_t to apr_time_exp_t structure./* excerpted from apr_time.h */<tscreen><verb>APR_DECLARE(apr_status_t) apr_time_exp_gmt(apr_time_exp_t *result, apr_time_t input);APR_DECLARE(apr_status_t) apr_time_exp_lt(apr_time_exp_t *result, apr_time_t input);</verb></tscreen>The apr_time_exp_gmt() returns the result in GMT timezone, and apr_time_exp_lt() returns the result in local timezone. The first argument of both APIs is result argument.We can do the opposite conversion. We use the following API to convert apr_time_exp_t structure to apr_time_t value./* excerpted from apr_time.h */<tscreen><verb>APR_DECLARE(apr_status_t) apr_time_exp_get(apr_time_t *result, apr_time_exp_t *input);</verb></tscreen>There are some APIs to convert apr_time_t to various string formats as follows:/* excerpted from apr_time.h */<tscreen><verb>APR_DECLARE(apr_status_t) apr_rfc822_date(char *date_str, apr_time_t t);APR_DECLARE(apr_status_t) apr_ctime(char *date_str, apr_time_t t);APR_DECLARE(apr_status_t) apr_strftime(char *s, apr_size_t *retsize, apr_size_t max, const char *format, apr_time_exp_t *tm);</verb></tscreen>On the other hand, if we convert such string formats to apr_time_t value, we have to call apr-util APIs, which are defined in apr_date.h.Please take a look at <htmlurl url="../sample/time-sample.c" name="time-sample.c"> about the usage of time APIs. <em>REMARK</em>: As stated above, apr_time_t is long long type (64bit). Note that the following sample code causes overflow.<tscreen><verb>/* BUGGY sample. This overflows */const apr_time_t ONE_HOUR = 1000 * 1000 * 60 * 60;</verb></tscreen>We can fix the bug by explicit type cast, but I recommend you to use implicit type cast which libapr provides. The following code shows it.<tscreen><verb>/* two examples to get around overflow above */const apr_time_t ONE_HOUR = APR_TIME_C(1000) * 1000 * 60 * 60;orconst apr_time_t ONE_HOUR = APR_USEC_PER_SEC * 60 * 60;</verb></tscreen><em>REMARK</em>: Sometimes, often in debugging, we want to print out time values. Unfortunately, Unix and Windows have different printf(3) format specifier for 64bit value. On Unix it is "%lld" and on Windows it is "%I64d". For such portability issues, libapr provides format specifiers, e.g. APR_INT64_T_FMT. There is APR_TIME_T_FMT in apr_time.h. We can write portable code with such format specifiers.<tscreen><verb>/* On Unix, APR_INT64_T_FMT is defined in apr.h */#define APR_INT64_T_FMT "lld"/* On Windows, APR_INT64_T_FMT is defined in apr.h */#define APR_INT64_T_FMT "I64d"/* excerpted from apr_time.h */#define APR_TIME_T_FMT APR_INT64_T_FMT/* We can use APR_TIME_T_FMT as follows */printf("The current time: %" APR_TIME_T_FMT "[us]\n", apr_time_now());</verb></tscreen><sect>command line options<p>For CLI(command line interface) tools, command line options are popular. libapr provides APIs to handle command line options easily. Here is an excerpted code from <htmlurl url="../sample/getopt-sample.c" name="getopt-sample.c">./* excerpted from <htmlurl url="../sample/getopt-sample.c" name="getopt-sample.c"> */<tscreen><verb>static const apr_getopt_option_t opt_option[] = {    /* long-option, short-option, has-arg flag, description */    { "in", 'i', TRUE, "input file" },      /* -i name or --in name */    { "out", 'o', TRUE, "output file" },    /* -o name or --out name */    { "help", 'h', FALSE, "show help" },    /* -h or --help */    { NULL, 0, 0, NULL }, /* end (a.k.a. sentinel) */};</verb></tscreen>At first, we should supply an array of apr_getopt_option_t elements. We call it option-list. Each element has four variables, i.e. long option, short option, flag of the trailing argument, and description. A long option is specified as '--help'. A short option is specified as '-h'. Short options are mandatory and long options are optional. We can set a long option to NULL. The third variable is flag of the existence of trailing argument. If a command line option works as '--in filename', i.e. the trailing argument is required, we have to set the flag to TRUE. If you run the program without the required argument, e.g. './a.out -in', it causes an error.The option-list must have a sentinel element as described above.To parse actual command line options based on the option-list, we have to call apr_getopt_init() at first. That initializes apr_getopt_t object. Next, we keep calling apr_getopt_long() while it returns APR_SUCCESS. Here is an excerpted code from <htmlurl url="../sample/getopt-sample.c" name="getopt-sample.c">./* excerpted from <htmlurl url="../sample/getopt-sample.c" name="getopt-sample.c"> */<tscreen><verb>/* initialize apr_getopt_t */apr_getopt_t *opt;apr_getopt_init(&amp;opt, mp, argc, argv);/* parse the all options based on opt_option[] */while ((rv = apr_getopt_long(opt, opt_option, &amp;optch, &amp;optarg)) == APR_SUCCESS) {    switch (optch) {    case 'i':        ...OMIT</verb></tscreen>During the loop, apr_getopt_long() processes the actual command line option one by one. If the option found is in the option-list, apr_getopt_long() returns APR_SUCCESS and set optch's value. When the option has the trailing argument, apr_getopt_long() parses it and set optarg's value. I show you an example. Let's think about the case that you run the program as './getopt-sample -h -i foo.txt'. At the first loop, apr_getopt_long() finds 'h' in the option-list. Then, apr_getopt_long() returns APR_SUCCESS and set optch to 'h'. At the next loop, apr_getopt_long() finds 'i' in the option-list and 'i' requiring the trailing argument, so it parses the trailing argument, 'foo.txt'. Thus, apr_getopt_long() returns APR_SUCCESS, and set optch to 'i' and optarg to "foo.txt". At the next loop, apr_getopt_long() finds no more options, so returns APR_EOF.<sect>memory map(mmap)<p>mmap is memory map. What it does is to map files into memory. mmap is mainly used as the following purposes.- read/write files with less overhead- allocate a bigger memory space (depends on OS)- shared memory between processesThink about the case that we read all contents from a file. In such a case, we might prepare a buffer and keep reading until the end of the file. It looks as follows:<tscreen><verb>/* naive code to read all contents of a file */apr_file_t *fp;apr_file_open(&amp;fp, filename, APR_READ, APR_OS_DEFAULT, mp);while (1) {   char buf[1024];   apr_size_t len = sizeof(buf);   rv = apr_file_read(fp, buf, &amp;len);   if (rv != APR_SUCCESS) {      break;   }   /* scan buf */}apr_file_close(fp);</verb></tscreen>We can do the same thing with apr_mmap_t as follows:/* excerpted from <htmlurl url="../sample/mmap-sample.c" name="mmap-sample.c">, but I omitted error checks */<tscreen><verb>apr_file_open(&amp;fp, filename, APR_READ, APR_OS_DEFAULT, mp);apr_finfo_t finfo;apr_file_info_get(&amp;finfo, APR_FINFO_SIZE, fp);apr_mmap_t *mmap;apr_mmap_create(&amp;mmap, fp, 0, finfo.size, APR_MMAP_READ, mp);/* scan mmap->mm */apr_mmap_delete(mmap);</verb></tscreen>If the file is big enough, mmap based code can be faster.More importantly, mmap can be against memory fragmentation. Most of dynamic memory allocation systems have memory fragmentation problem, but mmap is out of such user-space memory allocation managements. Unfortunatelly, on some OSes, mmap might be buggy or slow.We can use mmap to modify files. We open the file with APR_WRITE, and we have to mmap the file with APR_MMAP_WRITE flag.<em>REMARK</em>: You can't mmap the file that is opened with APR_BUFFERED flag. The following code returns APR_EBADF.<tscreen><verb>/* BUGGY mmap sample */apr_file_t *fp;apr_mmap_t *mm;apr_file_open(&amp;fp, fname, APR_READ|APR_BUFFERED, APR_OS_DEFAULT, mp);rv = apr_mmap_create(&amp;mm, fp, 0, finfo.size, APR_MMAP_READ, mp);/* BUG: rv==APR_EBADF */</verb></tscreen><sect>DSO(Dynamic Symbol Object)<p>You might know so(shared object) or dll(dynamic link library). Essentially, DSO is dependent on so/dll. Now, we call so/dll 'dynamic library' to distinguish from dso.To understand dso, we should know how link and load work. In general, when we use dynamic libraries, we link them with your program at a build time. ld(1) takes care of it on Unix. ld(1) is known as link editor. Since ld(1) is usually called by gcc(1) implicitly, you wouldn't be aware of ld(1). We sometimes happen to see link error messages at a compile time. It means ld(1) can't resolve the symbols that you're using in your program. At a runtime, ld.so(8) loads the dynamic libraries. If it failed, you would see load error messages. A summary is that link is done at a compile(build) time, and load is done at a runtime. If you want to know more, please read manuals of ld(1) and ld.so(8). By dso, both link and load are done at a runtime. Why do we use such a mechanism? The reason is that we can make plugin architecture. All we have to do during a build time is to define the interfaces(symbol names and how we call them) of loadable modules. The program loads the modules at a runtime and use them through the interfaces. Loadable modules can be developed by independent programmers. This can make the system very flexible and extensible.Let's take a look at <htmlurl url="../sample/dso-sample.c" name="dso-sample.c">. You can find two strings "libm.so" and "pow" in <htmlurl url="../sample/dso-sample.c" name="dso-sample.c">. In fact, pow(3) is a trivial function and it doesn't worth calling as dso, but it is just an example code.At first, we call apr_dso_load() and to pass the library file name, "libm.so"./* excerpted from <htmlurl url="../sample/dso-sample.c" name="dso-sample.c">, but I omitted error checks */<tscreen><verb>const char fname[] = "libm.so";apr_dso_handle_t *dso_h;apr_dso_load(&amp;dso_h, fname, mp);</verb></tscreen>As you can imagine, if you want your program to have plugins, you need a way to indicate the plugin file names. We can find such a system, apache modules. Their module names are specified in "httpd.conf" file.apr_dso_load() happens to fail. The cause is usually that it can't find the dynamic library file. The search path for dynamic library files at a runtime is dependent on OS. On GNU/Linux, it depends on LD_LIBRARY_PATH environment variable. On MS-Windows, it depends on PATH environment variable. After apr_dso_load() returns successfully, we can call apr_dso_sym(). The prototype declaration is as follows:/* excerpted from apr_dso.h */<tscreen><verb>APR_DECLARE(apr_status_t) apr_dso_sym(apr_dso_handle_sym_t *ressym,                                       apr_dso_handle_t *handle,                                      const char *symname);</verb></tscreen>By apr_dso_sym(), we can get a symbol object by a symbol name. The first argument is result argument. The second argument is dso handle, which we can get by apr_dso_open() above. The third argument is symbol name.The following code is excerpted from <htmlurl url="../sample/dso-sample.c" name="dso-sample.c">. The symbol name is "pow" and we get a function pointer as a symbol object. Since we know pow(3)'s interface, we can have typedef'd pow_fn_t.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -