浅析minigui-1.6.10启动脚本MiniGUI.cfg加载和section解析
《浅析MiniGuI v1.62配置文件MiniGUI.cfg所在目录获取的先后优先级》//=======================================================
//看看对hMgEtc实际使用
static inline int GetMgEtcValue(const char* pSection,
const char *pKey, char *pValue, int iLen)
{
#ifndef _INCORE_RES
if (!hMgEtc)
return GetValueFromEtcFile (ETCFILEPATH, pSection, pKey, pValue, iLen);
#endif
return GetValueFromEtc (hMgEtc, pSection, pKey, pValue, iLen);
}
industrialsample/libminigui-1.6.10/src/kernel/event.c
static void GetDblclickTime(void)
{
char szValue[11];
int ms;
dblclicktime = DEF_MSEC_DBLCLICK / 10;
// Mouse event parameters.
// #define MOUSEPARA "mouse"
// #define MOUSEPARA_DBLCLICKTIME "dblclicktime"
// 在MiniGUI.cfg中有如下节
// [mouse]
// dblclicktime=300
// 读取section名为mouse下key为dblclicktime的键值
if( GetMgEtcValue (MOUSEPARA, MOUSEPARA_DBLCLICKTIME, szValue, 10) < 0 )
return;
ms = atoi(szValue);
if (ms > 0 && ms < 1000) {
dblclicktime = ms / 10;
}
}
再来看看cursor指针的例子
BOOL realInitCursor(void)
{
......
// #define CURSORSECTION "cursorinfo"
// 查找节名为cursorinfo,key为cursornumber的键值
// 在MiniGUI.cfg中有如下节
// [cursorinfo]
// cursorpath=/usr/local/lib/minigui/res/cursor/
// cursornumber=23
// cursor0=d_arrow.cur
// cursor1=d_beam.cur
// cursor2=d_pencil.cur
// cursor3=d_cross.cur
// cursor4=d_move.cur
// cursor5=d_sizenwse.cur
// cursor6=d_sizenesw.cur
// cursor7=d_sizewe.cur
// cursor8=d_sizens.cur
// cursor9=d_uparrow.cur
// cursor10=d_none.cur
// cursor11=d_help.cur
// cursor12=d_busy.cur
// cursor13=d_wait.cur
// cursor14=g_rarrow.cur
// cursor15=g_col.cur
// cursor16=g_row.cur
// cursor17=g_drag.cur
// cursor18=g_nodrop.cur
// cursor19=h_point.cur
// cursor20=h_select.cur
// cursor21=ho_split.cur
// cursor22=ve_split.cur
if( GetMgEtcValue (CURSORSECTION, "cursornumber", szValue, 10) < 0 )
goto error;
number = atoi(szValue); // cursornumber=23
if(number <= 0)
return TRUE;
number = number < (MAX_SYSCURSORINDEX + 1) ?
number : (MAX_SYSCURSORINDEX + 1);
for(i = 0; i < number; i++) {
if ( !(SysCursor[i] = LoadSystemCursor(i)) ) // 加载23个cursor资源
goto error;
}
return TRUE;
error:
TerminateCursor();
return FALSE;
}
PCURSOR LoadSystemCursor (int i)
{
PCURSOR tempcsr;
char szValue[MAX_NAME + 1];
char szPathName[MAX_PATH + 1];
char szKey[10];
// #define CURSORSECTION "cursorinfo"
// 查找节名为cursorinfo,key为cursorpath的键值
// 在MiniGUI.cfg中有如下节
// [cursorinfo]
// cursorpath=/usr/local/lib/minigui/res/cursor/
// cursornumber=23
// cursor0=d_arrow.cur
// cursor1=d_beam.cur
// cursor2=d_pencil.cur
// cursor3=d_cross.cur
// ......
if (GetMgEtcValue (CURSORSECTION, "cursorpath", szPathName, MAX_PATH) < 0)
goto error;
sprintf (szKey, "cursor%d", i); // 获得key为cursor0 cursor1...等键值
if (GetMgEtcValue (CURSORSECTION, szKey, szValue, MAX_NAME) < 0)
goto error;
strcat (szPathName, szValue); // 读取/usr/local/lib/minigui/res/cursor/d_cross.cur
if (!(tempcsr = (PCURSOR)LoadCursorFromFile (szPathName))) // 加载到内存
goto error;
return tempcsr;
error:
return 0;
}
//=======================================================
//看看系统初始化
InitGUI==>InitMisc==>InitMgEtc
#ifndef _INCORE_RES
BOOL InitMgEtc (void)
{
if (hMgEtc)
return TRUE;
if ( !(hMgEtc = LoadEtcFile (ETCFILEPATH)) ) // 获取MiniGUI.cfg中脚本数据,源码见后
// 数据以key和value,这种字典形式保存[luther.gliethttp]
// hMgEtc是指向ETC_S存储空间的指针,只是这里hMgEtc以int形式存在[luther.gliethttp]
return FALSE;
return TRUE;
}
/* Terminate MiniGUI etc file object */
void TerminateMgEtc (void)
{
UnloadEtcFile (hMgEtc); // 释放内存
hMgEtc = 0;
}
#else
// 使用built-in方式的配置
extern GHANDLE __mg_get_mgetc (void);
BOOL InitMgEtc (void)
{
#ifndef DYNAMIC_LOAD
hMgEtc = __mg_get_mgetc (); // 获取MGETC全局量中定义的minigui资源配置信息,适合uc/os-ii或者FreeRTOS系统[lutehr.gliethttp]
#else
hMgEtc = set_mgetc ();
#endif
return TRUE;
}
void TerminateMgEtc (void) { }
#endif
#if defined (WIN32) || (defined (__THREADX__) && defined (__TARGET_VFANVIL__))
// 这里我们只关心MiniGUI.cfg脚本的加载和解析[luther.gliethttp]
GHANDLE GUIAPI LoadEtcFile (const char * pEtcFile)
{
FILE* fp = NULL;
ETC_S *petc;
char *filebuf;
char *pnextread;
int nReadByte, nFileSize, i;
#ifdef WIN32
struct stat filestat;
#endif
// 这里pEtcFile等于"/usr/local/etc/MiniGUI.cfg"
if (pEtcFile && !(fp = fopen (pEtcFile, "r")))
return 0;
petc = (ETC_S*) malloc (sizeof(ETC_S));
/* we allocate 15 sections first */
// misc.h
// #define NR_SECTS_INIT_ALLOC 16
petc->sections = // 先大概其的申请16个section空间
(PETCSECTION) malloc (sizeof(ETCSECTION)* NR_SECTS_INIT_ALLOC);
petc->section_nr = 0; // 当前1个都没有登记,16个空间全部是空的[luther.gliethttp]
petc->sect_nr_alloc = NR_SECTS_INIT_ALLOC; // 申请了16个
if (pEtcFile == NULL) { /* return an empty etc object */
// 此句判断没有意义,因为如果能执行到这里pEtcFile就一定非NULL
return (GHANDLE) petc;
}
#if defined (__THREADX__) && defined (__TARGET_VFANVIL__)
nFileSize = tp_flength(fp);
#else
fstat (fileno(fp), &filestat); // linux系统,获取MiniGUI.cfg文件大小[luther.gliethttp]
nFileSize = filestat.st_size;
#endif
if (nFileSize <= 0) {
goto endflag;
}
filebuf = (char *)calloc (1, nFileSize + 1); // 申请清0内存
if (filebuf == NULL)
goto endflag;
nReadByte = fread (filebuf, 1, nFileSize, fp); // 将MiniGUI.cfg内容一次性读入该内存
/*
if (nReadByte != nFileSize) { // 既然不做判断,变量就应该删掉,看来minigui对无用代码的清理工作做得不甚好.
goto endflag;
}
*/
filebuf [nFileSize] = '\0';
for (i = 0; i< nFileSize; i++) {
//if (filebuf [i] == '\n' || filebuf [i] == '\r')
if (filebuf [i] == 0x0D || filebuf [i] == 0x0A)
filebuf [i] = '\0'; // 每一行的'\r\n'均变为0,这样filebuf缓冲区就包含了
// 众多字符串[每一行对应一个字符串][luther.gliethttp].
}
pnextread = filebuf; // 使用临时指针,
while (etc_ReadSection (filebuf, nFileSize + 1, &pnextread,
petc->sections + petc->section_nr) == ETC_OK) {
petc->section_nr ++;
if (petc->section_nr == petc->sect_nr_alloc) {
/* add 5 sections each time we realloc */
petc->sect_nr_alloc += NR_SECTS_INC_ALLOC;
petc->sections = realloc (petc->sections,
sizeof (ETCSECTION)*petc->sect_nr_alloc);
}
}
endflag:
fclose (fp);
free (filebuf); // 释放内存
return (GHANDLE)petc;
}
#else
// 这才是ubuntu下实际使用到的函数呢,汗:(
GHANDLE GUIAPI LoadEtcFile (const char * pEtcFile)
{
FILE* fp = NULL;
ETC_S *petc;
// 这里pEtcFile等于"/usr/local/etc/MiniGUI.cfg"
if (pEtcFile && !(fp = fopen (pEtcFile, "r")))
return 0;
petc = (ETC_S*) malloc (sizeof(ETC_S));
petc->section_nr = 0; // 当前1个都没有登记,16个空间全部是空的[luther.gliethttp]
// misc.h
// #define NR_SECTS_INIT_ALLOC 16
petc->sect_nr_alloc = NR_SECTS_INIT_ALLOC; // 先大概其的申请16个section空间
/* we allocate 15 sections first */
petc->sections =
(PETCSECTION) malloc (sizeof(ETCSECTION)*NR_SECTS_INIT_ALLOC);
if (pEtcFile == NULL) { /* return an empty etc object */
// 此句判断没有意义,因为如果能执行到这里pEtcFile就一定非NULL
return (GHANDLE) petc;
}
while (etc_ReadSection (fp, petc->sections + petc->section_nr) == ETC_OK) {
// 向petc->section_nr[petc->section_nr]空间填入一个section信息.
petc->section_nr ++; // 下一个内存区
if (petc->section_nr == petc->sect_nr_alloc) {
/* add 5 sections each time we realloc */
// misc.h
// #define NR_SECTS_INC_ALLOC 8
petc->sect_nr_alloc += NR_SECTS_INC_ALLOC; // 那么重新申请16+8+...个
petc->sections = realloc (petc->sections,
sizeof(ETCSECTION)*petc->sect_nr_alloc);
}
}
fclose (fp);
return (GHANDLE)petc; // ok, 我们已经解析完毕MiniGUI.cfg所有脚本信息,将petc地址转为int类型返回给hMgEtc.
}
static int etc_ReadSection (FILE* fp, PETCSECTION psect)
{
char szBuff[ETC_MAXLINE + 1 + 1];
char* sect_name;
psect->name = NULL;
psect->key_nr = 0;
psect->keys = NULL;
psect->values = NULL;
while (TRUE) {
int bufflen;
if (!fgets(szBuff, ETC_MAXLINE, fp)) { // 读取一行数据
if (feof (fp)) { // 判断是否文件结尾了
if (psect->name)
break;
else
return ETC_SECTIONNOTFOUND;
}
else
return ETC_FILEIOFAILED;
}
bufflen = strlen (szBuff);
if (szBuff [bufflen - 1] == '\n')
szBuff [bufflen - 1] = '\0';
if (!psect->name) { /* read section name */
// 该psect内存空间还没有节名
sect_name = get_section_name (szBuff); // 尝试从szBuff中获取节名,源码见后
if (!sect_name) // 如果不是section name,那么continue,直到读取到一个合法的sect_name.
continue;
psect->name = FixStrDup (sect_name); // 调用FixStrAlloc()快速获取一块内存,之后拷贝sect_name到新内存空间
psect->key_nr = 0; // 初始化section name下包含的key内存
// misc.h
// #define NR_KEYS_INIT_ALLOC 8
// #define NR_KEYS_INC_ALLOC 4
psect->key_nr_alloc = NR_KEYS_INIT_ALLOC; // 申请8个key所需空间
// 之后按4个key大小增长该空间.
psect->keys = malloc (sizeof (char*) * NR_KEYS_INIT_ALLOC);
psect->values = malloc (sizeof (char*) * NR_KEYS_INIT_ALLOC);
}
else { /* read key and value */
int ret;
char *key, *value;
// 该section 已经有了名字,那么填充该section管理的属性值[luther.gliethttp]
ret = get_key_value (szBuff, &key, &value); // 源码见后
if (ret < 0) // 小于0表示此行无效,continue继续读取下一行
continue;
else if (ret > 0) { /* another section begins */
// 大于0表示下一个section开始符号'['被发现,此section所管理的内容到此结束
// 退回读取到的改行数据,fp指针调整[lutehr.gliethttp]
fseek (fp, -bufflen, SEEK_CUR);
break;
}
etc_NewKeyValue (psect, key, value); // 将该字典数据存入该psect所在内存空间,源码见后[luther.gliethttp]
}
}
return ETC_OK;
}
#endif
static char* get_section_name (char *section_line)
{
char* current;
char* name;
if (!section_line)
return NULL;
current = section_line; // 一串字符串
while (*current == ' ' || *current == '\t') current++; // 忽略空格和tab
if (*current == ';' || *current == '#') // 是否为注释
return NULL;
if (*current++ == '[') // 是否以[开头(这是有效section name的开始)
while (*current == ' ' || *current == '\t') current ++; // 过滤空格和tab
else
return NULL; // 不是以[开头,那么此行字符串不是section name,直接返回.
name = current; // ok, 现在current处在有效名字的第一个字符.
while (*current != ']' && *current != '\n' &&
*current != ';' && *current != '#' && *current != '\0')
current++; // 寻找section名字的结尾[luther.gliethttp]
*current = '\0'; // 截断字符串,这样name有了有效的字符串结尾0.
while (*current == ' ' || *current == '\t') {
*current = '\0'; // shorten name.
current--;
}
return name;
}
static int get_key_value (char *key_line, char **mykey, char **myvalue)
{
char* current;
char* tail;
char* value;
if (!key_line)
return -1;
current = key_line; // 一行字符串
while (*current == ' ' || *current == '\t') current++;
if (*current == ';' || *current == '#')
return -1; // 为注释行
if (*current == '[') // 为新的section
return 1;
if (*current == '\n' || *current == '\0')
return -1; // 一个只有回车的空行
tail = current;
// 寻找等号'='
while (*tail != '=' && *tail != '\n' &&
*tail != ';' && *tail != '#' && *tail != '\0')
tail++;
value = tail + 1; // 数据位于等号后面
if (*tail != '=')
*value = '\0';
*tail-- = '\0';
while (*tail == ' ' || *tail == '\t') {
*tail = '\0';
tail--;
}
tail = value;
while (*tail != '\n' && *tail != '\0') tail++;
*tail = '\0';
if (mykey)
*mykey = current; // key值,已经在'='所在位置填入字符串结尾符'\0'
if (myvalue)
*myvalue = value;
return 0;
}
static void etc_NewKeyValue (PETCSECTION psect,
const char* key, const char* value)
{
if (psect->key_nr == psect->key_nr_alloc) {
// 如果申请的key[]内存空间已经全部填充,那么realloc重新多申请8个key空间
psect->key_nr_alloc += NR_KEYS_INC_ALLOC;
psect->keys = realloc (psect->keys,
sizeof (char*) * psect->key_nr_alloc);
psect->values = realloc (psect->values,
sizeof (char*) * psect->key_nr_alloc);
}
psect->keys [psect->key_nr] = FixStrDup (key); // 调用FixStrAlloc()快速获取一块内存,之后拷贝sect_name到新内存空间
psect->values [psect->key_nr] = FixStrDup (value); // 调用FixStrAlloc()快速获取一块内存,之后拷贝sect_name到新内存空间
psect->key_nr++;
}
int GUIAPI UnloadEtcFile (GHANDLE hEtc)
{
int i;
ETC_S *petc = (ETC_S*) hEtc;
if (!petc)
return -1;
// 一共section_nr个section
for (i=0; i
section_nr; i++) {
PETCSECTION psect = petc->sections + i;
int j;
if (!psect->name) // 该section没有
continue;
// 该section共有key_nr个key
for (j=0; jkey_nr; j++) {
// 释放key和value
FreeFixStr (psect->keys [j]);
FreeFixStr (psect->values [j]);
}
free (psect->keys); // 释放malloc到的内存
free (psect->values);
FreeFixStr (psect->name); // 释放name
}
free (petc->sections); // 释放malloc到的内存
free (petc);
return 0;
}