libubox组件(2)——blob/blobmsg (转载 https://segmentfault.com/a/1190000002391970)
一:blob相关接口
1.数据结构
1: struct blob_attr {
2: uint32_t id_len; /** 高1位为extend标志,高7位存储id,
3: * 低24位存储data的内存大小+结构大小(blob_attr) */
4: char data[];
5: } __packed;
6: 实际使用中每个blob_attr的长度包含:结构长度(4)+数据长度+对齐特性= id_len+pad_len
7: struct blob_attr_info {
8: unsigned int type;
9: unsigned int minlen;
10: unsigned int maxlen;
11: bool (*validate)(const struct blob_attr_info *, struct blob_attr *);
12: };
13:
14: struct blob_buf {
15: struct blob_attr *head;
16: bool (*grow)(struct blob_buf *buf, int minlen);
17: int buflen;
18: void *buf;
19: };
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
2. 存储结构
3.获取BLOB属性信息
1: /**
2: * 返回指向BLOB属性数据区指针
3: */
4: static inline void * blob_data(const struct blob_attr *attr)
5:
6: /**
7: * 返回BLOB属性ID
8: */
9: static inline unsigned int blob_id(const struct blob_attr *attr)
10:
11: /**
12: * 判断BLOB属性扩展标志是否为真
13: */
14: static inline bool blob_is_extended(const struct blob_attr *attr)
15:
16: /**
17: * 返回BLOB属性有效存储空间大小
18: */
19: static inline unsigned int blob_len(const struct blob_attr *attr)
20:
21: /*
22: * 返回BLOB属性完全存储空间大小(包括头部)
23: */
24: static inline unsigned int blob_raw_len(const struct blob_attr *attr)
25:
26: /*
27: * 返回BLOB属性填补后存储空间大小(包括头部)
28: */
29: static inline unsigned int blob_pad_len(const struct blob_attr *attr)
4.获取BLOB数据信息
1: static inline uint8_t blob_get_u8(const struct blob_attr *attr)
2:
3: static inline uint16_t blob_get_u16(const struct blob_attr *attr)
4:
5: static inline uint32_t blob_get_u32(const struct blob_attr *attr)
6:
7: static inline uint64_t blob_get_u64(const struct blob_attr *attr)
8:
9: static inline int8_t blob_get_int8(const struct blob_attr *attr)
10:
11: static inline int16_t blob_get_int16(const struct blob_attr *attr)
12:
13: static inline int32_t blob_get_int32(const struct blob_attr *attr)
14:
15: static inline int64_t blob_get_int64(const struct blob_attr *attr)
16:
17: static inline const char * blob_get_string(const struct blob_attr *attr)
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
1: static inline struct blob_attr *
2: blob_put_string(struct blob_buf *buf, int id, const char *str)
3:
4: static inline struct blob_attr *
5: blob_put_u8(struct blob_buf *buf, int id, uint8_t val)
6:
7: static inline struct blob_attr *
8: blob_put_u16(struct blob_buf *buf, int id, uint16_t val)
9:
10: static inline struct blob_attr *
11: blob_put_u32(struct blob_buf *buf, int id, uint32_t val)
12:
13: static inline struct blob_attr *
14: blob_put_u64(struct blob_buf *buf, int id, uint64_t val)
15:
16: #define blob_put_int8 blob_put_u8
17: #define blob_put_int16 blob_put_u16
18: #define blob_put_int32 blob_put_u32
19: #define blob_put_int64 blob_put_u64
20:
21: struct blob_attr *
22: blob_put(struct blob_buf *buf, int id, const void *ptr, unsigned int len)
23:
24: /**
25: * ptr - 指向struct blob_attr
26: */
27: struct blob_attr *
28: blob_put_raw(struct blob_buf *buf, const void *ptr, unsigned int len)
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
6. 遍历
#define __blob_for_each_attr(pos, attr, rem)
#define blob_for_each_attr(pos, attr, rem)
7. 复制
struct blob_attr * blob_memdup(struct blob_attr *attr)
8. 数据类型判断
1: enum {
2: BLOB_ATTR_UNSPEC,
3: BLOB_ATTR_NESTED, /** 嵌套 */
4: BLOB_ATTR_BINARY,
5: BLOB_ATTR_STRING,
6: BLOB_ATTR_INT8,
7: BLOB_ATTR_INT16,
8: BLOB_ATTR_INT32,
9: BLOB_ATTR_INT64,
10: BLOB_ATTR_LAST
11: };
12: bool blob_check_type(const void *ptr, unsigned int len, int type)
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
9.嵌套操作
1: void * blob_nest_start(struct blob_buf *buf, int id)
2: Void blob_nest_end(struct blob_buf *buf, void *cookie)
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
10.判断
bool blob_attr_equal(const struct blob_attr *a1, const struct blob_attr *a2)
11.初始/销毁,解析
1: /**
2: * 初始化BLOB buffer
3: */
4: int blob_buf_init(struct blob_buf *buf, int id)
5:
6: /**
7: * 销毁BLOB buffer
8: */
9: void blob_buf_free(struct blob_buf *buf)
10:
11: /**
12: * 从attr串中根据info策略过滤,得到的结果存储在data属性数组中
13: *
14: * @param attr 输入BLOB属性串
15: * @param data 输出BLOB属性数组
16: * @param info 属性过滤策略
17: * @param max data数组大小
18: */
19: int blob_parse(struct blob_attr *attr, struct blob_attr **data,
20: const struct blob_attr_info *info, int max)
二:blobmsg相关接口
1.数据结构
1: struct blobmsg_hdr {
2: uint16_t namelen;
3: uint8_t name[];
4: } __packed;
5:
6: struct blobmsg_policy {
7: const char *name;
8: enum blobmsg_type type;
9: };
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
1: enum blobmsg_type {
2: BLOBMSG_TYPE_UNSPEC,
3: BLOBMSG_TYPE_ARRAY,
4: BLOBMSG_TYPE_TABLE,
5: BLOBMSG_TYPE_STRING,
6: BLOBMSG_TYPE_INT64,
7: BLOBMSG_TYPE_INT32,
8: BLOBMSG_TYPE_INT16,
9: BLOBMSG_TYPE_INT8,
10: __BLOBMSG_TYPE_LAST,
11: BLOBMSG_TYPE_LAST = __BLOBMSG_TYPE_LAST - 1,
12: BLOBMSG_TYPE_BOOL = BLOBMSG_TYPE_INT8,
13: };
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
4.基本操作
1: /**
2: * 根据BLOB消息名字长度计算出blobmsg头部大小
3: */
4: static inline int blobmsg_hdrlen(unsigned int namelen)
5:
6: /**
7: * 获取BLOB消息名字
8: */
9: static inline const char *blobmsg_name(const struct blob_attr *attr)
10:
11: /**
12: * 获取BLOB消息类型
13: */
14: static inline int blobmsg_type(const struct blob_attr *attr)
15:
16: /**
17: * 获取BLOB消息数据内容
18: */
19: static inline void *blobmsg_data(const struct blob_attr *attr)
20:
21: /**
22: * 获取BLOB消息数据内容大小
23: */
24: static inline int blobmsg_data_len(const struct blob_attr *attr)
25: static inline int blobmsg_len(const struct blob_attr *attr)
26: 数据类型判断
27:
28: /**
29: * 判断BLOBMSG属性类型是否合法
30: */
31: bool blobmsg_check_attr(const struct blob_attr *attr, bool name)
32: 设置
33:
34: int blobmsg_add_field(struct blob_buf *buf, int type, const char *name,
35: const void *data, unsigned int len)
36:
37: static inline int
38: blobmsg_add_u8(struct blob_buf *buf, const char *name, uint8_t val)
39:
40: static inline int
41: blobmsg_add_u16(struct blob_buf *buf, const char *name, uint16_t val)
42:
43: static inline int
44: blobmsg_add_u32(struct blob_buf *buf, const char *name, uint32_t val)
45:
46: static inline int
47: blobmsg_add_u64(struct blob_buf *buf, const char *name, uint64_t val)
48:
49: static inline int
50: blobmsg_add_string(struct blob_buf *buf, const char *name, const char *string)
51:
52: static inline int
53: blobmsg_add_blob(struct blob_buf *buf, struct blob_attr *attr)
54:
55: /**
56: * 格式化设备BLOGMSG
57: */
58: void blobmsg_printf(struct blob_buf *buf, const char *name, const char *format, ...)
59: 获取
60:
61: static inline uint8_t blobmsg_get_u8(struct blob_attr *attr)
62: static inline bool blobmsg_get_bool(struct blob_attr *attr)
63: static inline uint16_t blobmsg_get_u16(struct blob_attr *attr)
64: static inline uint32_t blobmsg_get_u32(struct blob_attr *attr)
65: static inline uint64_t blobmsg_get_u64(struct blob_attr *attr)
66: static inline char *blobmsg_get_string(struct blob_attr *attr)
67: 创建
68:
69: /**
70: * 创建BLOBMSG,返回数据区开始地址
71: */
72: void *blobmsg_alloc_string_buffer(struct blob_buf *buf, const char *name,
73: unsigned int maxlen)
74:
75: /**
76: * 扩大BLOGMSG,返回数据区开始地址
77: */
78: void *blobmsg_realloc_string_buffer(struct blob_buf *buf, unsigned int maxlen)
79:
80: void blobmsg_add_string_buffer(struct blob_buf *buf)
81: 遍历
82:
83: #define blobmsg_for_each_attr(pos, attr, rem)
84: 嵌套
85:
86: static inline void * blobmsg_open_array(struct blob_buf *buf, const char *name)
87: static inline void blobmsg_close_array(struct blob_buf *buf, void *cookie)
88:
89: static inline void *blobmsg_open_table(struct blob_buf *buf, const char *name)
90: static inline void blobmsg_close_table(struct blob_buf *buf, void *cookie)
91: 解析BLOGMSG
92:
93: /**
94: * 从data BLOGMSG串中根据policy策略过滤,得到的结果存储在tb BLOGATTR数组中
95: *
96: * @param policy 过滤策略
97: * @param policy_len 策略个数
98: * @param tb 返回属性数据
99: * @param len data属性个数
100: */
101: int blobmsg_parse(const struct blobmsg_policy *policy, int policy_len,
102: struct blob_attr **tb, void *data, unsigned int len)
三:实例操作
把UCI转化为BLOB
UCI配置文件:
/etc/config/test
config policy test
option name 'test'
option enable '1'
option dns '1.1.1.1 2.2.2.2'
1: 定义参数列表:
2:
3: enum {
4: POLICY_ATTR_NAME, /** name */
5: POLICY_ATTR_ENABLE, /** enable */
6: POLICY_ATTR_DNS, /** dns */
7: __POLICY_ATTR_MAX
8: };
9:
10: static const struct blobmsg_policy policy_attrs[__POLICY_ATTR_MAX] = {
11: [POLICY_ATTR_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING },
12: [POLICY_ATTR_ENABLE] = { .name = "enable", .type = BLOBMSG_TYPE_BOOL },
13: [POLICY_ATTR_DNS] = { .name = "dns", .type = BLOBMSG_TYPE_ARRAY },
14: };
15:
16: /** 定义BLOBMSG_TYPE_ARRAY类型参数的实际数据类型 */
17: static const struct uci_blob_param_info policy_attr_info[__POLICY_ATTR_MAX] = {
18: [POLICY_ATTR_DNS] = { .type = BLOBMSG_TYPE_STRING },
19: };
20:
21: static const struct uci_blob_param_list policy_attr_list = {
22: .n_params = __POLICY_ATTR_MAX,
23: .params = policy_attrs,
24: .info = policy_attr_info,
25: };
26: 转化为BLOB:
27:
28: static struct uci_context *g_uci_ctx;
29: static struct blob_buf *b;
30:
31: void
32: transform(const char *config)
33: {
34: struct uci_context *ctx = g_uci_ctx;
35: struct uci_package *p = NULL;
36:
37: if (!ctx) {
38: ctx = uci_alloc_context();
39: g_uci_ctx = ctx;
40: uci_set_confdir(ctx, NULL);
41: } else {
42: p = uci_lookup_package(ctx, config);
43: if (p)
44: uci_unload(ctx, p);
45: }
46:
47: if (uci_load(ctx, config, &p))
48: return;
49:
50: struct uci_element *e;
51: struct blob_attr *config = NULL;
52: uci_foreach_element(&p->sectons, e) {
53: struct uci_section *s = uci_to_section(e);
54:
55: blob_buf_init(&b, 0);
56: uci_to_blob(&b, s, &policy_attr_list);
57: config = blob_memdup(b.head);
58:
59: /**
60: * do something with `config`
61: * free(config), when not use it
62: */
63: }
64: }
65: 使用转化后的blob_attr
66:
67: void
68: foo(blob_attr *confg)
69: {
70: struct blob_attr *tb[__POLICY_ATTR_MAX];
71:
72: blobmsg_parse(policy_attrs, __POLICY_ATTR_MAX, tb,
73: blob_data(config), blob_len(config));
74:
75: /**
76: * do something with *tb[]
77: */
78: }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
libubox组件(2)——blob/blobmsg (转载 https://segmentfault.com/a/1190000002391970)的更多相关文章
- (转载https://segmentfault.com/a/1190000016313947)了解RestFul Api架构风格设计
最近几年REST API越来越流行,特别是随着微服务的概念被广泛接受和应用,很多Web Service都使用了REST API. REST是HTTP规范主要编写者之一的Roy Fielding提出的, ...
- 使用 Redis 实现排行榜功能 (转载 https://segmentfault.com/a/1190000002694239)
排行榜功能是一个很普遍的需求.使用 Redis 中有序集合的特性来实现排行榜是又好又快的选择. 一般排行榜都是有实效性的,比如"用户积分榜".如果没有实效性一直按照总榜来排,可能榜 ...
- 【极力分享】[C#/.NET]Entity Framework(EF) Code First 多对多关系的实体增,删,改,查操作全程详细示例【转载自https://segmentfault.com/a/1190000004152660】
[C#/.NET]Entity Framework(EF) Code First 多对多关系的实体增,删,改,查操作全程详细示例 本文我们来学习一下在Entity Framework中使用Cont ...
- 正则表达式(转自https://segmentfault.com/a/1190000000699097)
https://segmentfault.com/a/1190000000699097
- https://segmentfault.com/a/1190000004518374#articleHeader3
https://segmentfault.com/a/1190000004518374#articleHeader3 https://segmentfault.com/q/10100000049065 ...
- https://segmentfault.com/a/1190000014637728
原网站地址:https://segmentfault.com/a/1190000009657295#articleHeader3 基于 vue2 + element-ui 构建的后台管理系统 vue. ...
- 解决 VUE 微信登录验证 【感谢原文:https://segmentfault.com/a/1190000009493199】
[感谢原文:https://segmentfault.com/a/1190000009493199] SPA单页应用中微信授权登录的一点思路 单页应用应该如何解决微信授权登录的尴尬跳转?后退无法返回? ...
- https://segmentfault.com/bookmark/1230000008276077
https://segmentfault.com/bookmark/1230000008276077
- https://segmentfault.com/a/1190000012844836---------关于SpringBoot上传图片的几种方式
关于SpringBoot上传图片的几种方式 https://segmentfault.com/a/1190000012844836
随机推荐
- hadoop map(分片)数量确定
之前学习hadoop的时候,一直希望可以调试hadoop源码,可是一直没找到有效的方法,今天在调试矩阵乘法的时候发现了调试的方法,所以在这里记录下来. 1)事情的起因是想在一个Job里设置map的数量 ...
- hadoop中URI理解
1)在编写MR程序的时候经常会有如下代码: String uri=“....”: Configuration conf=new Configuration(): FileSystem fs=FileS ...
- awk-使用
http://www.cnblogs.com/ggjucheng/archive/2013/01/13/2858470.html 命令格式: awk [-F field-separator] 'pat ...
- 【spring mvc】spring mvc POST方式接收单个字符串参数,不加注解,接收到的值为null,加上@RequestBody,接收到{"uid":"品牌分类大”},加上@RequestParam报错 ---- GET方式接收单个参数的方法
spring mvc POST方式 接收单个参数,不加任何注解,参数名对应,接收到的值为null spring mvc POST方式 接收单个参数,加上@RequestBody,接收到参数格式:{&q ...
- OpenGL ES2.0编程三步曲 -转
原地址:http://blog.csdn.net/myarrow/article/details/7707943 1. 保存全局变量的数据结构 以下例子程序均基于Linux平台. typedef st ...
- webpack 打包压缩 ES6文件报错UglifyJs + Unexpected token punc «(», expected punc
- 所见即所得的网页设计工具 Macaw
所见即所得的网页设计工具 Macaw: 2014年最具前景的12款创新产品 1\ http://macaw.co/ 2\ http://www.kickstarter.com/projects ...
- Shell--nl命令
nl命令在linux系统中用来计算文件中行号.nl 可以将输出的文件内容自动的加上行号!其默认的结果与 cat -n 有点不太一样, nl 可以将行号做比较多的显示设计,包括位数与是否自动补齐 0 等 ...
- elasticsearch term 查询二:Range Query
Range Query 将文档与具有一定范围内字词的字段进行匹配. Lucene查询的类型取决于字段类型,对于字符串字段,TermRangeQuery,对于数字/日期字段,查询是NumericRang ...
- 【枚举】【SDOI 2011】【bzoj 2241】打地鼠
2241: [SDOI2011]打地鼠 Time Limit: 10 Sec Memory Limit: 512 MB Submit: 877 Solved: 557 Description 打地鼠是 ...