2007-01-21

regex in Linux with C

在Linux中,很多应用程序都需要对正则表达式的支持(如:grep,sed,awk等)。所以提供有POSIX式regex支持:
#include <sys/types.h>
#include <regex.h>

/* is  used to compile a regular expression into a form that is
       suitable for subsequent regexec() searches. */
int    regcomp(regex_t *preg, const char *regex, int cflags);

如果是正确的正则式返回0

/* used to match a null-terminated string against the precom-
       piled  pattern  buffer */
int    regexec(const  regex_t  *preg,  const  char *string, size_t nmatch, regmatch_t pmatch[], int eflags);

成功匹配返回0,pmatch[0].rm_so,pmatch[0].rm_eo分别是第一个匹配串在string中的始终位置(-1表示没有匹配的)。
注意:这里pmatch[i](i=1,2,...)不是表示第二,三…个匹配,而是第一个匹配串中的子匹配。如果要找之后的匹配应该从第一个匹配的终位置开始在string中再次regexec()

/* free the memory allocated to the pattern buffer by  the  compiling  process */
void   regfree(regex_t *preg);

用完正则表达式后,或者要使用新的正则表达式的时候,我们可以用这个函数清空preg指向的regex_t结构体的内容,请记住,如果是使用新的正则表达式,一定要先清空regex_t结构体。

/* turn the error codes that can be returned by both regcomp() and regexec() */
size_t regerror(int errcode, const regex_t *preg, char *errbuf,  size_t errbuf_size);

返回regcomp/regexec的错误信息,其中errcode是regcomp/regexec的返回,errbuf是最后得到的错误信息。

使用:
先用regcomp()初始化正则式,然后用regexec()查找匹配串,最后别忘了用regfree()清除正则式。
有错误的话用regerror()来获取错误信息。例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <regex.h>

#define SUBSLEN    10
#define EBUFLEN    128    /* error buffer length */
#define BUFLEN    1024    /* matched buffer length */

int
main (int argc, char **argv)
{
    FILE *fp;
    size_t len=0;    /* store error message length */
    regex_t re;    /* store compilned regular expression */
    regmatch_t subs[SUBSLEN];    /* store matched string position */
    char matched[BUFLEN];    /* store matched strings */
    char errbuf[EBUFLEN];    /* store error message */
    int err, i;

    char string[] = "AAaba(125){3a}babAbAbCdCd123123  11(923){82}aslfk(72){4}";
    char pattern[] = "(\\([0-9]+\\))(\\{[0-9]+\\}{1})";
/*注意: 对于C/C++的正则式,这里要注意的是‘\’字符,因为C中‘\’是转义符,正则式中‘\’也是转义符,所以要匹配的信息中有‘\’时,C的正则式中就要用“\\\\”(C字符串“\\\\”=>正则式“\\”=>字符“\”)
*/

    printf ("String: %s\n", string);
    printf ("Pattern: \"%s\"\n", pattern);

    /* compile regular expression */
    err = regcomp (&re, pattern, REG_EXTENDED);

    if (err) {
        len = regerror (err, &re, errbuf, sizeof(errbuf));
        fprintf (stderr, "error: regcomp: %s\n", errbuf);
        return (1);
    }
    printf ("Total has subexpression: %d\n", re.re_nsub);
int offset = 0;
while (1) {
    /* execute pattern match */
    err = regexec (&re, string+offset, (size_t)SUBSLEN, subs, 0);
    if (err == REG_NOMATCH) {
        fprintf (stderr, "Sorry, no match ...\n");
        regfree (&re);
        return (0);
    } else if (err) {
        len = regerror (err, &re, errbuf, sizeof (errbuf));
        fprintf (stderr, "error: regexec: %s\n", errbuf);
        return (1);
    }

    /* if no REG_NOMATCH and no error, then pattern matched */
    printf ("\nOK, has matched ...\n\n");
    for (i=0; i<=re.re_nsub; i++) {
        if (i==0) {
            printf ("begin: %d, end: %d, ", subs[i].rm_so, subs[i].rm_eo);
        } else {
            printf ("subexpression %d begin: %d, end: %d, ", i, subs[i].rm_so, subs[i].rm_eo);
        }
        len = (int)subs[i].rm_eo - (int)subs[i].rm_so;
        memcpy (matched, string + offset + subs[i].rm_so, len);
        matched[len] = '\0';
        printf ("match: %s\n", matched);
    }
offset += (int)subs[0].rm_eo;
} /* while (1) */
    regfree (&re);
    return 0;
}
//EOF Read More...

some messages echo

昨天看LFS启动脚本时想到的。
Linux启动时会在每一行信息后都输出一个"[  OK  ]"、"[ WARN ]"或"[ FAIL ]",这种输出方式在LFS启动脚本的function中可以得到解答:

#!/bin/bash
# output just like linux-bootup message ".... [  OK  ]"

## Screen Dimensions
# Find current screen size
if [ -z "${COLUMNS}" ]; then
        COLUMNS=$(stty size)
        COLUMNS=${COLUMNS##* }
fi

# When using remote connections, such as a serial port, stty size returns 0
if [ "${COLUMNS}" = "0" ]; then
        COLUMNS=80
fi

## Measurements for positioning result messages
COL=$((${COLUMNS} - 8))
WCOL=$((${COL} - 2))

## Set Cursor Position Commands, used via echo -e
SET_COL="\\033[${COL}G"      # at the $COL char
SET_WCOL="\\033[${WCOL}G"    # at the $WCOL char
CURS_UP="\\033[1A\\033[0G"   # Up one line, at the 0'th char


## Set color commands, used via echo -e
# Please consult `man console_codes for more information
# under the "ECMA-48 Set Graphics Rendition" section
#
# Warning: when switching from a 8bit to a 9bit font,
# the linux console will reinterpret the bold (1;) to
# the top 256 glyphs of the 9bit font.  This does
# not affect framebuffer consoles
NORMAL="\\033[0;39m"         # Standard console grey
SUCCESS="\\033[1;32m"        # Success is green
WARNING="\\033[1;33m"        # Warnings are yellow
FAILURE="\\033[1;31m"        # Failures are red
INFO="\\033[1;36m"           # Information is light cyan
BRACKET="\\033[1;34m"        # Brackets are blue

STRING_LENGTH="0"   # the length of the current message


echo -n -e "test test test .............. 11111"
echo -n " ||| now the fkjsal;kfa"
echo -e "${SET_COL}""${BRACKET}""[""${SUCCESS}""  OK  ""${BRACKET}""]""${NORMAL}"

echo -n -e "test est esttt esttt ------------ 2222"
echo -e "${SET_COL}""${BRACKET}""[""${FAILURE}"" FAIL ""${BRACKET}""]""${NORMAL}"

echo -n -e "test ewa tasfj a;ksljet;a ljkeakl;j"
echo -e "${SET_COL}""${BRACKET}""[""${WARNING}"" WARN ""${BRACKET}""]""${NORMAL}"


另外,以前看到过的一个旋转的棍子表示进度的,用这种方式:
#!/bin/bash
# a rout-line

if [ -z "${COLUMNS}" ]; then
        COLUMNS=$(stty size)
        COLUMNS=${COLUMNS##* }
fi
if [ "${COLUMNS}" = "0" ]; then
        COLUMNS=80
fi

COL=$((${COLUMNS} - 20))
SET_COL="\\033[${COL}G"      # at the $COL char

echo -n "asfdl;adfd;jja;:"
let n=0
while test $n -lt 5000 ; do
    let n=`expr $n+1`    # 这主要还起延时的作用,要不用`let n++`就行了
    echo -en "${SET_COL}/"
    let n=`expr $n+1`
    echo -en "${SET_COL}|"
    let n=`expr $n+1`
    echo -en "${SET_COL}\\"
    let n=`expr $n+1`
    echo -en "${SET_COL}-"
done
echo -e "${SET_COL}[ OK ]"

//EOF Read More...

2007-01-20

LFS单用户模式

今天发现LFS进单用户时会提示:

Give root password for maitenance
(or type Control-D to continue)

-_-还要输入密码!?和我平时印象中的单用户不同啊。
虽然在改grub的时候后面加个" init=/bin/bash"也可以进“单用户”。但还是不想这样麻烦。

单用户是[init 1]模式,启动脚本在/etc/rc.d/rc1.d/中,但光看这个目录里的东西是看不出什么的。
这里说一下,LFS的启动脚本和FC6的不同的地方。最大的不同是rcsysinit,LFS中和其他启动级别一样是一个目录的形式以'S'/'K'来判断启动与否(判断模式单一),FC6中是一个rc.sysinit的bash脚本(好处是:模式选则的多样性)
那么大多问题是出在这里,这里不想改动太多就在/etc/rc.d/init.d/中添加一脚本'single',链接之:
ln -sv ../init.d/single /etc/rc.d/rc1.d/S00single

single文件内容:
#!/bin/bash
echo "########## Entering Single Mode ##########"
/bin/bash

但注意,/etc/inittab中,需要:
...
l1:S1:wait:/etc/rc.d/init.d/rc 1
...

//EOF Read More...