Lighttpd1.4.30源码分析之array.c

ISP图像处理芯片-FH8510简介 FH8510是一款针对CIS(CMOS Image Sensor)的图像信号处理芯片,它内置强大图像处理引擎,CMOS图像传感器接口,TV编码器,D/A转换器,提供NTSC/PAL的输出,同时也提供ITU.BT656 10Bit的输出,主要应用于中低端标清模拟CCTV摄像机、车载后视摄像机及楼宇对讲摄像机。 阅读详情
Lighttpd提供了一个通用数组,这个数组与程序的其他部分练习较少,因此可以单独进行分析。
首先要说一下Lighttpd中的定义的一些数据结构。
在array.h中有下面的定义:
 typedef enum { 
         TYPE_UNSET,         /* 数据的类型未设置,
                                这几种数据类型使用了面向对象的设计思想,
                                这个类型相当于父类型,继承关系见后面 
                              */
         TYPE_STRING,         /* 字符串类型 */
         TYPE_COUNT,         /* COUNT类型 */
         TYPE_ARRAY,         /* 数组类型 */
         TYPE_INTEGER,     /* 整数类型 */
         TYPE_FASTCGI,     /* FASTCGI类型 */
         TYPE_CONFIG         /* CONFIG类型 */
 } data_type_t;

这是一个枚举类型,定义了各个数据类型的标志。从中可以看出程序中所定义使用的数据类型的种类和个数。
Lighttpd在定义数据类型的时候使用了面向对象的思想,因此,程序具有很好的扩展性和适应性。这些类型中,最重要的是UNSET类型,这个类型在所有的数据类型中,起到了父类型的作用。在array.h中,UNSET类型的定义如下:
#define DATA_UNSET \
    data_type_t type; \
    buffer *key; \
    int is_index_key; /* 1 if key is a array index */ \
    struct data_unset *(*copy)(const struct data_unset *src); \
    void (* free)(struct data_unset *p); \
    void (* reset)(struct data_unset *p); \
        int (*insert_dup)(struct data_unset *dst, struct data_unset *src); \
    void (*print)(const struct data_unset *p, int depth)

typedef struct data_unset {
    DATA_UNSET;
} data_unset;

其中,UNSET类型数据的定义中,数据的实际定义部分使用宏DATA_UNSET,这样可以方便其他类型在定义中直接引用DATA_UNSET宏来模拟继承。在宏DATA_UNSET中,定义了下面五个函数指针:
 struct data_unset *(*copy)(const struct data_unset *src); 
 void (* free)(struct data_unset *p); 
 void (* reset)(struct data_unset *p); 
 int (*insert_dup)(struct data_unset *dst, struct data_unset *src); 
 void (*print)(const struct data_unset *p, int depth)
下面分析一下STRING类型的初始化函数data_string * data_string_init(void):
 data_string *data_string_init(void)
 {
     data_string *ds;
     /*
 分配内存空间。
 这里用的是calloc函数,分配的空间会自动清零。
 */
     ds = calloc(1, sizeof(*ds));
     assert(ds);
     /*
 初始化各个数据成员,
 这里调用buffer_init函数,主要就是分配内存空间
 */
     ds->key = buffer_init();
     ds->value = buffer_init();
     /*确定成员函数的具体调用函数,对函数指针赋值*/
     ds->copy = data_string_copy;
     ds->free = data_string_free;
     ds->reset = data_string_reset;
     ds->insert_dup = data_string_insert_dup;
     ds->print = data_string_print;
     ds->type = TYPE_STRING;
     return ds;
 }

其他类型的init函数,以及其他函数都不难,读者可自行查看代码。
至于各个类型的用处以及各个类型中个成员变量的含义,暂且不用关心,只要知道这七个类型之间的关系即可,除了UNSET类型,其他类型的操作函数的实现都在文件data_XXXXX.c中。这些函数的实现都很简单,不在一一介绍,读者可自己看看。这七个类型构成了通用数组所要处理的类型,其中,在数组的定义和实现中只使用UNSET类型,利用上面的定义,通用数组可以不用关心数组中存储的到底是哪种具体的类型,只需将其按照UNSET类型来处理就可以了。这就实现了通用数组。
下面这个定义是通用数组的核心定义,就是定义了数组。
typedef struct 
{
    /* UNSET类型的指针型数组,存放数组中的元素 */
    data_unset **data;
    /* 存放着排好序的各个元素的下标的数组 */
    size_t *sorted;
    size_t used;    /* data中使用了的长度,也就是数组中元素个数 */

        /* data的大小。data的大小会根据数据的多少变化,会为以后的数据预先分
           配空间 */
    size_t size;    
    
        size_t unique_ndx;        /*  */
        /* 比used大的最小的2的倍数。也就是离used最近的且比used大的2的倍
              数 ,用于在数组中利用二分法查找元素*/
    size_t next_power_of_2;
        /* data is weakref, don't bother the data */
        /* data就是一个指针,不用关系其所指向的内容 */
    int is_weakref;                
} array;

各个变量的含义见上。
array.h中还有一个定义:
 typedef struct {
   DATA_UNSET;
   array *value;
 } data_array;

这个定义了一个array类型的数据,也就是说,通用数组中存放的数据可以数通用数组,这样可以形成多维的通用数组。
在array.h中定义了如下的通用数组操作函数:
1、array *array_init(void);
初始化数组,分配空间。
2、array *array_init_array(array * a);
用数组a来初始化一个数组。也就是得到一个a的深拷贝。
3、void array_free(array * a);
释放数组。释放所有空间。
4、void array_reset(array * a);
重置data中的所有数据(调用UNSET类型数据中的reset函数),并将used设为0。相当于清空数组。
5、int array_insert_unique(array * a, data_unset * str);
将str插入到数组中。
6、data_unset *array_pop(array * a);
弹出data中的最后一个元素,返回奇指针,data中的最后一个位置设为NULL。
7、int array_print(array * a, int depth);
打印数组中的内容。depth参数用于在打印多维数组时,实现缩进。
8、a_unset *array_get_unused_element(array * a, data_type_t t);
返回第一个未使用的数据,也就是used位置的数据,这个数据不在数组中,返回这个数据指针后,将data[unsed]设为NULL。可能返回NULL。
9、data_unset *array_get_element(array * a, const char *key);
根据key值,返回数组中key值与之相同的数据
10、data_unset *array_replace(array * a, data_unset * du);
       如果数组中有与du的key值相同的数据,则用du替换那个数据,并返回那个数据的指针。如果不存在,则把du插入到数组中。(调用data_insert_unique函数)
11、 int array_strcasecmp(const char *a, size_t a_len, const char *b, size_t b_len);
这个函数并没用实现,仅仅给出了上面的定义。也许这个是用来比较两个字符串,并且可能会忽略大小写。
12、void array_print_indent(int depth);
根据depth打印空白,实现缩进。
13、size_t array_get_max_key_length(array * a);
返回数组中最长的key的长度。

另外,在array.c中定义了一个辅助函数static intarray_get_index(array *a, const char *key, size_t keylen, int *rndx)。这个函数的作用是通过key值,查找数据,返回其在数组data中的下标位置,并通过参数rndx返回其下标在数组sorted中的位置。
函数的定义如下:
 static int array_get_index(array *a, const char *key, size_t keylen, int *rndx) 
 {
     /*参数keylen是key的长度*/
     int ndx = -1;
     int i, pos = 0;
     if (key == NULL) return -1;
     /* try to find the string */
     /* 
 * sorted数组是个下标数组,存放的是排好序的输入元素的下标,
 * 相当于一个排好序的数组。
      * 利用sorted数组进行二分查找。
      * 若找到,返回元素在data数组中的位置,并通过rndx返回
 * 其在sorted数组中的位置。
      * 若没有找到,通过rndx返回此元素在sorted中的位置,并返回-1
      */
 /* pos中存放的是元素在数组data中的位置 */
 /*  
 当data的空间不够时,通用数组每次为data增加16个空间,第一次初始化时,
 data的长度为16。因此,size始终是16的倍数。
 used可以为任何数值,当然要大于等于0,小于size。
 而next_power_of_2是大于used最小的2的倍数,如used=5,那么
 next_power_of_2就等于8。
 这样,used始终大于等于next_power_of_2的1/2。
 */
 /*
  在这儿的二分搜索中,next_power_of_2是个很有创意的技巧。
 next_power_of_2类似于一个标杆,利用这个标杆进行二分搜索可以减少很多
 出错的几率,也使程序更加易懂。效率上当然没有什么损失。下面的程序读者可
 自行看看,并不是很难。
  */
     for (i = pos = a->next_power_of_2 / 2; ; i >>= 1) 
 {
  int cmp;
  if (pos < 0) {
  pos += i;
  } else if (pos >= (int)a->used) {
  pos -= i;
  } else {
  /* 比较两个元素的key值 */
  cmp = buffer_caseless_compare(key, keylen
 , a->data[a->sorted[pos]]->key->ptr
 , a->data[a->sorted[pos]]->key->used
 );
  if (cmp == 0) {
  /* found */
  ndx = a->sorted[pos];
  break;
  } else if (cmp < 0) {/* 所找数据在前半部分 */
  pos -= i;
  } else { /*  所找数据在后半部分*/
  pos += i;
  }
  }
  if (i == 0) break;
     }
     if (rndx) *rndx = pos;
     return ndx;
 }

在上面列出的函数中,还有一个函数要重点讲解一下,也是最复杂的一个函数:int array_insert_unique(array *a, data_unset *str)。这个函数将数据str插入到数组中,当并不是单纯的插入,如果数组中存在key于str相同的数据,则把str的内容拷贝到这个数据中。
int array_insert_unique(array *a, data_unset *str) {
     int ndx = -1;
     int pos = 0;
     size_t j;
     /* generate unique index if neccesary */
     if (str->key->used == 0 || str->is_index_key) {
                buffer_copy_long(str->key, a->unique_ndx++);
                    str->is_index_key = 1;
     }
     /* 在数组中查找与str具有相同key的数据 */
     if (-1 != (ndx = array_get_index(a, str->key->ptr, str->key->used, &pos))) 
         {
             /* 找到,复制 */
              if (a->data[ndx]->type == str->type) 
               {
                        str->insert_dup(a->data[ndx], str);
               } 
               else 
               {
                        fprintf(stderr, "a\n");
               }
               return 0;
     }
     /* 当数组的长度大于最大值时,不进行插入,并返回-1 */
     if (a->used+1 > INT_MAX) {
                     /* we can't handle more then INT_MAX entries: see array_get_index() */
                    return -1;
     }
 
     if (a->size == 0) {
                /* 数组为空 */
                /* 初始data的长度为16 */
                a->size   = 16;
                a->data   = malloc(sizeof(*a->data)     * a->size);
                a->sorted = malloc(sizeof(*a->sorted)   * a->size);
                assert(a->data);
                assert(a->sorted);
                for (j = a->used; j < a->size; j++) 
                             a->data[j] = NULL;
     } 
         else if (a->size == a->used) 
         {
           /* data已经满了,对data进行扩容,增加16个空间。 */
           /* 这就是为什么size一定是16的倍数 */
                a->size  += 16;
                a->data   = realloc(a->data, sizeof(*a->data) * a->size);
                a->sorted = realloc(a->sorted, sizeof(*a->sorted) * a->size);
                assert(a->data);
                assert(a->sorted);
                for (j = a->used; j < a->size; j++)
                              a->data[j] = NULL;
     }
     ndx = (int) a->used;
     a->data[a->used++] = str;
     /*
                在上面调用函数array_get_index的时候,
               已将str应该在数组sorted中位置存放在了pos中。 
         */
     if (pos != ndx /* 要插入的位置在中部 */&&((pos < 0) /* 在开始位置插入 */
                             ||buffer_caseless_compare(str->key->ptr
                                           , str->key->used
                                           , a->data[a->sorted[pos]]->key->ptr
                                           , a->data[a->sorted[pos]]->key->used
                             ) > 0)) 
         {
                /* 判断当前pos所对应的元素是否比str小,若是,这pos后移一位 */
                pos++;
     }
     /* 移动sorted数组中后面的数据,腾出位置。 */
     if (pos != ndx) {
                memmove(a->sorted + (pos + 1), a->sorted + (pos), (ndx - pos) * sizeof(*a->sorted));
     }
     /* insert */
     a->sorted[pos] = ndx;
     /* 如果used==next_power_of_2时,扩展next_power_of_2 */
     if (a->next_power_of_2 == (size_t)ndx) 
               a->next_power_of_2 <<= 1;
     return 0;
 }
基于Linux开源VOIP系统LinPhone[一] LinPhone是一个网络电话或者IP语音电话(VOIP),是一款遵循GPL的开源的网络视频电话系统,其主要如下: 使用linphone,我们可以在互联网上随意的通信,通过语音、视频、即时文本消息。 linphone使用SIP协议,是一个标准的开源网络电话系统,你能将linphone与任何基于SIP的VoIP运营商连接起来,包括我们自己开发的免费的基于SIP的Audio/Video服务器。 LinPhone是一款自由软件(或者开源软件),你可以随意的下载和在LinPhone的基础上二次开发。 LinPhon 阅读详情

相关推荐

嵌入式Linux下BOA网页服务器的移植

BOA WebServer是一款单任务的HTTP服务器,与其他网页服务器不同之处,是当有连接请求到来是,它既不是为每个连接都单独创建进程,也不是采用复制自身进程处理多链接,而是通过建立HTTP请求列表来处理多路HTTP连接请求。

嵌入式与人工智能天地 1万+

CentOS下lighttpd+php安装

一、安装相关软件包 [root@web ~]# yum -y install pcre pcre-devel bzip2-devel zlib zlib-devel mysql-server php php-mysql 二、编译并安装lighttpd [root@web ~]# tar zxf lighttpd-1.4.30.tar.gz [root@we...

weixin_34015566的博客 224

嵌入式Linux下开源路由器OpenWRT简介

OpenWrt支持各种处理器架构,无论是对ARM,X86,PowerPC或者MIPS都有很好的支持。其多达3000多种软件包,囊括从工具链(toolchain),到内核(linux kernel),到软件包(packages),再到根文件系统(rootfs)整个体系,使得用户只需简单的一个make命令即可方便快速地定制一个具有特定功能的嵌入式系统来制作固件。其模块化设计也可以方便的移植各类功能到OpenWrt下,加快开发速度

嵌入式与人工智能天地 1万+

【解决方案】服务器支持 TLS Client-initiated 重协商攻击(CVE-2011-1473)

使用SSL开启重协商的服务都会受该漏洞影响 Apache解决办法: 升级到Apache 2.2.15以后版本 IIS解决办法: IIS 5.0启用SSL服务时,也会受影响。可以升级IIS 6.0到更高的版本。 Lighttpd解决办法: 建议升级到lighttpd 1.4.30或者更高,并设置ssl.disable-client-ren...

ak761636411的博客 1万+

基于嵌入式Linux下GCC编译器__sync_sub_and_fetch_4错误的解决心得

原子操作就是不可再分的操作,在多线程程序中原子操作是一个非常重要的概念,它常常用来实现一些同步机制。在Linux系统中的GCC或者嵌入式Linux的交叉编译GCC中从4.1.2提供了__sync_*系列的built-in函数,用于提供加减和逻辑运算的原子操作

嵌入式与人工智能天地 1万+

基于Linux下的GCC编译器的内部预宏定义与__attribute__属性

经常在一些开源的程序中看到一些宏定义,却看不到这些宏定义是在哪些地方定义的,其实有些宏定义是交叉编译工具GCC预定义好的,比如:__GNUC__,__ELF__等等,怎么看到这些宏定义呢

嵌入式与人工智能天地 1万+

lighttpd 各种配置详细文档

网址:http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs 网址内容链接 Documentation Overview¶ 目录 Documentation Overview Core Features Modules Modules (1.5 only (abandoned)) Internals Modules ...

caofengtao1314的专栏 5097

基于glib2.12.13编译出现的问题总结

glib库是Linux平台下最常用的C语言函数库,它具有很好的可移植性和实用性。glib是Gtk+库和Gnome的基础。glib可以在多个平台下使用,比如Linux、Unix、Windows等。glib为许多标准的、常用的C语言结构提供了相应的替代物。

嵌入式与人工智能天地 1万+

Lighttpd1.4.20源码分析 笔记 通用数组array.c(h)

首先回顾以下,在array.h中,UNSET类型是一个宏:#define DATA_UNSET \ data_type_t type; \ buffer *key; \ int is_index_key; /* 1 if key is a array index (autogenerated keys) */ \ struct data_unset *(*copy)(

jiange_zh的博客 1179

基于RDP协议的开源rdesktop简介

rdesktop 是一个在 Unix/Linux 下访问 Windows 远程桌面的客户端程序。当前,rdesktop 所支持的 Windows 系列版本包括 NT、2000、XP 和 2003。通过使用 rdesktop 所实现的远程桌面协议(RDP),你可以在 Unix/Linux 系统中呈现 Windows 桌面,并进行相应的操作。目前最新的版本rdesktop是rdesktop 1.8.2,这个是最新的版本。

嵌入式与人工智能天地 9432

全数字(IP)楼宇对讲系统简介

数字IP楼宇对讲属于楼宇可视对讲系统发展的终极阶段,数字IP楼宇对讲系统全面解决了语音、视频、数据在互联网上的传输问题,使智能小区系统在真正意义上与Internet溶为一体,实现数据、语音、视频三线合一.

嵌入式与人工智能天地 9197

Lighttpd基础篇(一):Array.c

//作者:京东瀚览家居官方旗舰店     &lt;--点击关注 //文件名:Array.c   #include &lt;string.h&gt; #include &lt;stdio.h&gt; #include &lt;stdlib.h&gt; #include &lt;limits.h&gt; #include &lt;errno.h&gt; #include &lt;assert...

sms88的专栏 335

基于ARM嵌入式Linux网络编程实例解析

这段时间,因为项目的需要,了解了一下USBtoNet的驱动,同时采用IOCTL来设置MAC的地址,检测网卡的连接状态等等,因此,就从网络上了解了一下关于网络编程方面的知识.

嵌入式与人工智能天地 8836

开源SIP服务器OpenSIPS简介

OpenSIPS是一个成熟的开源SIP服务器,除了提供基本的SIP代理及SIP路由功能外,还提供了一些应用级的功能。OpenSIPS的结构非常灵活,其核心路由功能完全通过脚本来实现,可灵活定制各种路由策略,可灵活应用于语音、视频通信、IM以及Presence等多种应用。

嵌入式与人工智能天地 4万+

基于oSIP开源库的SIP代理服务器PartySIP[一]

Partysip 是基于osip实现的的sip服务器。实现了注册服务、重定向、定位、事务状态/无状态机。和eXosip框架思路一样,只是模块实现上面由于功能有所不同而区别。

嵌入式与人工智能天地 8083

Lighttpd 1.4.53

lighttpd(发音为lighty)是一套开放源代码的网页服务器,以BSD许可证放出.相较于其他的网页服务器,lighttpd仅需少量的 内存及CPU资源即可达到同样的效能. Lighttpd软件特性 lighttpd(发音为lighty

DirectFB简介以及移植[一]

DirectFB是一个轻量级的提供硬件图形加速,输入设备处理和抽象的图形库,它集成了支持半透明的视窗系统以及在LinuxFramebuffer驱动之上的多层显示。它是一个用软件封装当前硬件无法支持的图形算法来完成硬件加速的层。DirectFB是为嵌入式系统而设计。它是以最小的资源开销来实现最高的硬件加速性能。

嵌入式与人工智能天地 9669

点云直线检测-3DLineDetection复现

点云直线分割-Fast 3D line detection

阁楼 8156

开源浏览器:Dillo Web Browser简介

*************************************************************************************************************************** 作者:EasyWave

嵌入式与人工智能天地 6885

STM32G0实战:HAL库与LL库Flash操作避坑指南(附HardFault解决方案)

本文深入剖析了STM32G0系列微控制器在Flash操作中常见的HardFault问题,对比了HAL库与LL库在读写擦除操作上的底层差异与潜在陷阱。文章提供了基于寄存器状态分析的精准调试方法,并给出了经过实战检验的解决方案与健壮的代码框架,帮助开发者有效规避数据丢失与系统崩溃风险。

t8u9v0w1x的博客 730

零基础入门红外与可见光图像融合:DAF-Net 实战全指南

本文介绍了基于DAF-Net的红外与可见光图像融合技术,主要内容包括:技术原理、环境配置、数据准备和模型实现。DAF-Net通过双分支特征提取和动态注意力融合机制,有效结合红外图像的热辐射信息与可见光图像的纹理细节。文章详细讲解了开发环境搭建步骤(Python 3.8+PyTorch),TNO数据集的预处理方法,并提供了完整的DAF-Net实现代码,包含特征提取、注意力融合和图像重建三个关键模块。该技术可广泛应用于安防监控、自动驾驶等领域,帮助开发者快速入门多模态图像融合。

FJN110的博客 122
上一篇: C++标准转换运算符const_cast
下一篇: 基于android2.3.5系统:源码下载及android体系架构
wang-bob
博客等级 码龄20年 356粉丝 112原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值