Annotation of embedaddon/php/ext/dba/libinifile/inifile.c, revision 1.1.1.2

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | PHP Version 5                                                        |
                      4:    +----------------------------------------------------------------------+
                      5:    | Copyright (c) 1997-2010 The PHP Group                                |
                      6:    +----------------------------------------------------------------------+
                      7:    | This source file is subject to version 3.01 of the PHP license,      |
                      8:    | that is bundled with this package in the file LICENSE, and is        |
                      9:    | available through the world-wide-web at the following url:           |
                     10:    | http://www.php.net/license/3_01.txt                                  |
                     11:    | If you did not receive a copy of the PHP license and are unable to   |
                     12:    | obtain it through the world-wide-web, please send a note to          |
                     13:    | license@php.net so we can mail you a copy immediately.               |
                     14:    +----------------------------------------------------------------------+
                     15:    | Author: Marcus Boerger <helly@php.net>                               |
                     16:    +----------------------------------------------------------------------+
                     17:  */
                     18: 
1.1.1.2 ! misho      19: /* $Id: 35930d10283d140c69e0bd485fa7c50938e37f8b $ */
1.1       misho      20: 
                     21: #ifdef HAVE_CONFIG_H
                     22: #include "config.h"
                     23: #endif
                     24: 
                     25: #include "php.h"
                     26: #include "php_globals.h"
                     27: 
                     28: #include <stdlib.h>
                     29: #include <string.h>
                     30: #include <errno.h>
                     31: #if HAVE_UNISTD_H
                     32: #include <unistd.h>
                     33: #endif
                     34: 
                     35: #include "inifile.h"
                     36: 
                     37: /* ret = -1 means that database was opened for read-only
                     38:  * ret = 0  success
                     39:  * ret = 1  key already exists - nothing done
                     40:  */
                     41: 
                     42: /* {{{ inifile_version */
                     43: char *inifile_version() 
                     44: {
1.1.1.2 ! misho      45:        return "1.0, $Id: 35930d10283d140c69e0bd485fa7c50938e37f8b $";
1.1       misho      46: }
                     47: /* }}} */ 
                     48: 
                     49: /* {{{ inifile_free_key */
                     50: void inifile_key_free(key_type *key)
                     51: {
                     52:        if (key->group) {
                     53:                efree(key->group);
                     54:        }
                     55:        if (key->name) {
                     56:                efree(key->name);
                     57:        }
                     58:        memset(key, 0, sizeof(key_type));
                     59: }
                     60: /* }}} */
                     61: 
                     62: /* {{{ inifile_free_val */
                     63: void inifile_val_free(val_type *val)
                     64: {
                     65:        if (val->value) {
                     66:                efree(val->value);
                     67:        }
                     68:        memset(val, 0, sizeof(val_type));
                     69: }
                     70: /* }}} */
                     71: 
                     72: /* {{{ inifile_free_val */
                     73: void inifile_line_free(line_type *ln)
                     74: {
                     75:        inifile_key_free(&ln->key);
                     76:        inifile_val_free(&ln->val);
                     77:        ln->pos = 0;
                     78: }
                     79: /* }}} */
                     80: 
                     81: /* {{{ inifile_alloc */
                     82: inifile * inifile_alloc(php_stream *fp, int readonly, int persistent TSRMLS_DC)
                     83: {
                     84:        inifile *dba;
                     85: 
                     86:        if (!readonly) {
                     87:                if (!php_stream_truncate_supported(fp)) {
                     88:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't truncate this stream");
                     89:                        return NULL;
                     90:                }
                     91:        }
                     92:  
                     93:        dba = pemalloc(sizeof(inifile), persistent);
                     94:        memset(dba, 0, sizeof(inifile));
                     95:        dba->fp = fp;
                     96:        dba->readonly = readonly;
                     97:        return dba;
                     98: }
                     99: /* }}} */
                    100: 
                    101: /* {{{ inifile_free */
                    102: void inifile_free(inifile *dba, int persistent)
                    103: {
                    104:        if (dba) {
                    105:                inifile_line_free(&dba->curr);
                    106:                inifile_line_free(&dba->next);
                    107:                pefree(dba, persistent);
                    108:        }
                    109: }
                    110: /* }}} */
                    111: 
                    112: /* {{{ inifile_key_split */
                    113: key_type inifile_key_split(const char *group_name)
                    114: {
                    115:        key_type key;
                    116:        char *name;
                    117:        
                    118:        if (group_name[0] == '[' && (name = strchr(group_name, ']')) != NULL) {
                    119:                key.group = estrndup(group_name+1, name - (group_name + 1));
                    120:                key.name = estrdup(name+1);
                    121:        } else {
                    122:                key.group = estrdup("");
                    123:                key.name = estrdup(group_name);
                    124:        }
                    125:        return key;
                    126: }
                    127: /* }}} */
                    128: 
                    129: /* {{{ inifile_key_string */
                    130: char * inifile_key_string(const key_type *key)
                    131: {
                    132:        if (key->group && *key->group) {
                    133:                char *result;
                    134:                spprintf(&result, 0, "[%s]%s", key->group, key->name ? key->name : "");
                    135:                return result;
                    136:        } else if (key->name) {
                    137:                return estrdup(key->name);
                    138:        } else {
                    139:                return NULL;
                    140:        }
                    141: }
                    142: /* }}} */
                    143: 
                    144: /* {{{ etrim */
                    145: static char *etrim(const char *str)
                    146: {
                    147:        char *val;
                    148:        size_t l;
                    149:        
                    150:        if (!str) {
                    151:                return NULL;
                    152:        }
                    153:        val = (char*)str;
                    154:        while (*val && strchr(" \t\r\n", *val)) {
                    155:                val++;
                    156:        }
                    157:        l = strlen(val);
                    158:        while (l && (strchr(" \t\r\n", val[l-1]))) {
                    159:                l--;
                    160:        }
                    161:        return estrndup(val, l);
                    162: }
                    163: /* }}} */
                    164: 
                    165: /* {{{ inifile_findkey
                    166:  */
                    167: static int inifile_read(inifile *dba, line_type *ln TSRMLS_DC) {
                    168:        char *fline;
                    169:        char *pos;
                    170: 
                    171:        inifile_val_free(&ln->val);
                    172:        while ((fline = php_stream_gets(dba->fp, NULL, 0)) != NULL) {
                    173:                if (fline) {
                    174:                        if (fline[0] == '[') {
                    175:                                /* A value name cannot start with '['
                    176:                                 * So either we find a ']' or we found an error
                    177:                                 */
                    178:                                pos = strchr(fline+1, ']');
                    179:                                if (pos) {
                    180:                                        *pos = '\0';
                    181:                                        inifile_key_free(&ln->key);
                    182:                                        ln->key.group = etrim(fline+1);
                    183:                                        ln->key.name = estrdup("");
                    184:                                        ln->pos = php_stream_tell(dba->fp);
                    185:                                        efree(fline);
                    186:                                        return 1;
                    187:                                } else {
                    188:                                        efree(fline);
                    189:                                        continue;
                    190:                                }
                    191:                        } else {
                    192:                                pos = strchr(fline, '=');
                    193:                                if (pos) {
                    194:                                        *pos = '\0';
                    195:                                        /* keep group or make empty if not existent */
                    196:                                        if (!ln->key.group) {
                    197:                                                ln->key.group = estrdup("");
                    198:                                        }
                    199:                                        if (ln->key.name) {
                    200:                                                efree(ln->key.name);
                    201:                                        }
                    202:                                        ln->key.name = etrim(fline);
                    203:                                        ln->val.value = etrim(pos+1);
                    204:                                        ln->pos = php_stream_tell(dba->fp);
                    205:                                        efree(fline);
                    206:                                        return 1;
                    207:                                } else {
                    208:                                        /* simply ignore lines without '='
                    209:                                         * those should be comments
                    210:                                         */
                    211:                                         efree(fline);
                    212:                                         continue;
                    213:                                }
                    214:                        }
                    215:                }
                    216:        }
                    217:        inifile_line_free(ln);
                    218:        return 0;
                    219: }
                    220: /* }}} */
                    221: 
                    222: /* {{{ inifile_key_cmp */
                    223: /* 0 = EQUAL
                    224:  * 1 = GROUP-EQUAL,NAME-DIFFERENT
                    225:  * 2 = DIFFERENT
                    226:  */
                    227: static int inifile_key_cmp(const key_type *k1, const key_type *k2 TSRMLS_DC)
                    228: {
                    229:        assert(k1->group && k1->name && k2->group && k2->name);
                    230:        
                    231:        if (!strcasecmp(k1->group, k2->group)) {
                    232:                if (!strcasecmp(k1->name, k2->name)) {
                    233:                        return 0;
                    234:                } else {
                    235:                        return 1;
                    236:                }
                    237:        } else {
                    238:                return 2;
                    239:        }
                    240: }
                    241: /* }}} */
                    242: 
                    243: /* {{{ inifile_fetch
                    244:  */
                    245: val_type inifile_fetch(inifile *dba, const key_type *key, int skip TSRMLS_DC) {
                    246:        line_type ln = {{NULL,NULL},{NULL}};
                    247:        val_type val;
                    248:        int res, grp_eq = 0;
                    249: 
                    250:        if (skip == -1 && dba->next.key.group && dba->next.key.name && !inifile_key_cmp(&dba->next.key, key TSRMLS_CC)) {
                    251:                /* we got position already from last fetch */
                    252:                php_stream_seek(dba->fp, dba->next.pos, SEEK_SET);
                    253:        } else {
                    254:                /* specific instance or not same key -> restart search */
                    255:                /* the slow way: restart and seacrch */
                    256:                php_stream_rewind(dba->fp);
                    257:                inifile_line_free(&dba->next);
                    258:        }
                    259:        if (skip == -1) {
                    260:                skip = 0;
                    261:        }
                    262:        while(inifile_read(dba, &ln TSRMLS_CC)) {
                    263:                if (!(res=inifile_key_cmp(&ln.key, key TSRMLS_CC))) {
                    264:                        if (!skip) {
                    265:                                val.value = estrdup(ln.val.value ? ln.val.value : "");
                    266:                                /* allow faster access by updating key read into next */
                    267:                                inifile_line_free(&dba->next);
                    268:                                dba->next = ln;
                    269:                                dba->next.pos = php_stream_tell(dba->fp);
                    270:                                return val;
                    271:                        }
                    272:                        skip--;
                    273:                } else if (res == 1) {
                    274:                        grp_eq = 1;
                    275:                } else if (grp_eq) {
                    276:                        /* we are leaving group now: that means we cannot find the key */
                    277:                        break;
                    278:                }
                    279:        }
                    280:        inifile_line_free(&ln);
                    281:        dba->next.pos = php_stream_tell(dba->fp);
                    282:        return ln.val;
                    283: }
                    284: /* }}} */
                    285: 
                    286: /* {{{ inifile_firstkey
                    287:  */
                    288: int inifile_firstkey(inifile *dba TSRMLS_DC) {
                    289:        inifile_line_free(&dba->curr);
                    290:        dba->curr.pos = 0;
                    291:        return inifile_nextkey(dba TSRMLS_CC);
                    292: }
                    293: /* }}} */
                    294: 
                    295: /* {{{ inifile_nextkey
                    296:  */
                    297: int inifile_nextkey(inifile *dba TSRMLS_DC) {
                    298:        line_type ln = {{NULL,NULL},{NULL}};
                    299: 
                    300:        /*inifile_line_free(&dba->next); ??? */
                    301:        php_stream_seek(dba->fp, dba->curr.pos, SEEK_SET);
                    302:        ln.key.group = estrdup(dba->curr.key.group ? dba->curr.key.group : "");
                    303:        inifile_read(dba, &ln TSRMLS_CC);
                    304:        inifile_line_free(&dba->curr);
                    305:        dba->curr = ln;
                    306:        return ln.key.group || ln.key.name;
                    307: }      
                    308: /* }}} */
                    309: 
                    310: /* {{{ inifile_truncate
                    311:  */
                    312: static int inifile_truncate(inifile *dba, size_t size TSRMLS_DC)
                    313: {
                    314:        int res;
                    315: 
                    316:        if ((res=php_stream_truncate_set_size(dba->fp, size)) != 0) {
                    317:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error in ftruncate: %d", res);
                    318:                return FAILURE;
                    319:        }
                    320:        php_stream_seek(dba->fp, size, SEEK_SET);
                    321:        return SUCCESS;
                    322: }
                    323: /* }}} */
                    324: 
                    325: /* {{{ inifile_find_group
                    326:  * if found pos_grp_start points to "[group_name]"
                    327:  */
                    328: static int inifile_find_group(inifile *dba, const key_type *key, size_t *pos_grp_start TSRMLS_DC) 
                    329: {
                    330:        int ret = FAILURE;
                    331: 
                    332:        php_stream_flush(dba->fp);
                    333:        php_stream_seek(dba->fp, 0, SEEK_SET);
                    334:        inifile_line_free(&dba->curr);
                    335:        inifile_line_free(&dba->next);
                    336: 
                    337:        if (key->group && strlen(key->group)) {
                    338:                int res;
                    339:                line_type ln = {{NULL,NULL},{NULL}};
                    340: 
                    341:                res = 1;
                    342:                while(inifile_read(dba, &ln TSRMLS_CC)) {
                    343:                        if ((res=inifile_key_cmp(&ln.key, key TSRMLS_CC)) < 2) {
                    344:                                ret = SUCCESS;
                    345:                                break;
                    346:                        }
                    347:                        *pos_grp_start = php_stream_tell(dba->fp);
                    348:                }
                    349:                inifile_line_free(&ln);
                    350:        } else {
                    351:                *pos_grp_start = 0;
                    352:                ret = SUCCESS;
                    353:        }
                    354:        if (ret == FAILURE) {
                    355:                *pos_grp_start = php_stream_tell(dba->fp);
                    356:        }
                    357:        return ret;
                    358: }
                    359: /* }}} */
                    360: 
                    361: /* {{{ inifile_next_group
                    362:  * only valid after a call to inifile_find_group
                    363:  * if any next group is found pos_grp_start points to "[group_name]" or whitespace before that
                    364:  */
                    365: static int inifile_next_group(inifile *dba, const key_type *key, size_t *pos_grp_start TSRMLS_DC) 
                    366: {
                    367:        int ret = FAILURE;
                    368:        line_type ln = {{NULL,NULL},{NULL}};
                    369: 
                    370:        *pos_grp_start = php_stream_tell(dba->fp);
                    371:        ln.key.group = estrdup(key->group);
                    372:        while(inifile_read(dba, &ln TSRMLS_CC)) {
                    373:                if (inifile_key_cmp(&ln.key, key TSRMLS_CC) == 2) {
                    374:                        ret = SUCCESS;
                    375:                        break;
                    376:                }
                    377:                *pos_grp_start = php_stream_tell(dba->fp);
                    378:        }
                    379:        inifile_line_free(&ln);
                    380:        return ret;
                    381: }
                    382: /* }}} */
                    383: 
                    384: /* {{{ inifile_copy_to
                    385:  */
                    386: static int inifile_copy_to(inifile *dba, size_t pos_start, size_t pos_end, inifile **ini_copy TSRMLS_DC)
                    387: {
                    388:        php_stream *fp;
                    389:        
                    390:        if (pos_start == pos_end) {
                    391:                *ini_copy = NULL;
                    392:                return SUCCESS;
                    393:        }
                    394:        if ((fp = php_stream_temp_create(0, 64 * 1024)) == NULL) {
                    395:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not create temporary stream");
                    396:                *ini_copy = NULL;
                    397:                return FAILURE;
                    398:        }
                    399: 
                    400:        if ((*ini_copy = inifile_alloc(fp, 1, 0 TSRMLS_CC)) == NULL) {
                    401:                /* writes error */
                    402:                return FAILURE;
                    403:        }
                    404:        php_stream_seek(dba->fp, pos_start, SEEK_SET);
                    405:        if (!php_stream_copy_to_stream(dba->fp, fp, pos_end - pos_start)) {
                    406:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not copy group [%zu - %zu] to temporary stream", pos_start, pos_end);
                    407:                return FAILURE;
                    408:        } 
                    409:        return SUCCESS;
                    410: }
                    411: /* }}} */
                    412: 
                    413: /* {{{ inifile_filter
                    414:  * copy from to dba while ignoring key name (group must equal)
                    415:  */
                    416: static int inifile_filter(inifile *dba, inifile *from, const key_type *key TSRMLS_DC) 
                    417: {
                    418:        size_t pos_start = 0, pos_next = 0, pos_curr;
                    419:        int ret = SUCCESS;
                    420:        line_type ln = {{NULL,NULL},{NULL}};
                    421: 
                    422:        php_stream_seek(from->fp, 0, SEEK_SET);
                    423:        php_stream_seek(dba->fp, 0, SEEK_END);
                    424:        while(inifile_read(from, &ln TSRMLS_CC)) {
                    425:                switch(inifile_key_cmp(&ln.key, key TSRMLS_CC)) {
                    426:                case 0:
                    427:                        pos_curr = php_stream_tell(from->fp);
                    428:                        if (pos_start != pos_next) {
                    429:                                php_stream_seek(from->fp, pos_start, SEEK_SET);
                    430:                                if (!php_stream_copy_to_stream(from->fp, dba->fp, pos_next - pos_start)) {
                    431:                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not copy [%zu - %zu] from temporary stream", pos_next, pos_start);
                    432:                                        ret = FAILURE;
                    433:                                }
                    434:                                php_stream_seek(from->fp, pos_curr, SEEK_SET);
                    435:                        }
                    436:                        pos_next = pos_start = pos_curr;
                    437:                        break;
                    438:                case 1:
                    439:                        pos_next = php_stream_tell(from->fp);
                    440:                        break;
                    441:                case 2:
                    442:                        /* the function is meant to process only entries from same group */
                    443:                        assert(0);
                    444:                        break;
                    445:                }
                    446:        }
                    447:        if (pos_start != pos_next) {
                    448:                php_stream_seek(from->fp, pos_start, SEEK_SET);
                    449:                if (!php_stream_copy_to_stream(from->fp, dba->fp, pos_next - pos_start)) {
                    450:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not copy [%zu - %zu] from temporary stream", pos_next, pos_start);
                    451:                        ret = FAILURE;
                    452:                }
                    453:        }
                    454:        inifile_line_free(&ln);
                    455:        return SUCCESS;
                    456: }
                    457: /* }}} */
                    458: 
                    459: /* {{{ inifile_delete_replace_append
                    460:  */
                    461: static int inifile_delete_replace_append(inifile *dba, const key_type *key, const val_type *value, int append TSRMLS_DC) 
                    462: {
                    463:        size_t pos_grp_start, pos_grp_next;
                    464:        inifile *ini_tmp = NULL;
                    465:        php_stream *fp_tmp = NULL;
                    466:        int ret;
                    467: 
                    468:        /* 1) Search group start
                    469:         * 2) Search next group
                    470:         * 3) If not append: Copy group to ini_tmp
                    471:         * 4) Open temp_stream and copy remainder
                    472:         * 5) Truncate stream
                    473:         * 6) If not append AND key.name given: Filtered copy back from ini_tmp 
                    474:         *    to stream. Otherwise the user wanted to delete the group.
                    475:         * 7) Append value if given
                    476:         * 8) Append temporary stream
                    477:         */
                    478: 
                    479:        assert(!append || (key->name && value)); /* missuse */
                    480: 
                    481:        /* 1 - 3 */
                    482:        inifile_find_group(dba, key, &pos_grp_start TSRMLS_CC);
                    483:        inifile_next_group(dba, key, &pos_grp_next TSRMLS_CC);
                    484:        if (append) {
                    485:                ret = SUCCESS;
                    486:        } else {
                    487:                ret = inifile_copy_to(dba, pos_grp_start, pos_grp_next, &ini_tmp TSRMLS_CC);
                    488:        }
                    489: 
                    490:        /* 4 */
                    491:        if (ret == SUCCESS) {
                    492:                fp_tmp = php_stream_temp_create(0, 64 * 1024);
                    493:                if (!fp_tmp) {
                    494:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not create temporary stream");
                    495:                        ret = FAILURE;
                    496:                } else {
                    497:                        php_stream_seek(dba->fp, 0, SEEK_END);
                    498:                        if (pos_grp_next != (size_t)php_stream_tell(dba->fp)) {
                    499:                                php_stream_seek(dba->fp, pos_grp_next, SEEK_SET);
                    500:                                if (!php_stream_copy_to_stream(dba->fp, fp_tmp, PHP_STREAM_COPY_ALL)) {
                    501:                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not copy remainder to temporary stream");
                    502:                                        ret = FAILURE;
                    503:                                }
                    504:                        }
                    505:                }
                    506:        }
                    507:        
                    508:        /* 5 */
                    509:        if (ret == SUCCESS) {
                    510:                if (!value || (key->name && strlen(key->name))) {
                    511:                        ret = inifile_truncate(dba, append ? pos_grp_next : pos_grp_start TSRMLS_CC); /* writes error on fail */
                    512:                }
                    513:        }
                    514: 
                    515:        if (ret == SUCCESS) {
                    516:                if (key->name && strlen(key->name)) {
                    517:                        /* 6 */
                    518:                        if (!append && ini_tmp) {
                    519:                                ret = inifile_filter(dba, ini_tmp, key TSRMLS_CC);
                    520:                        }
                    521: 
                    522:                        /* 7 */
                    523:                        /* important: do not query ret==SUCCESS again: inifile_filter might fail but
                    524:                         * however next operation must be done.
                    525:                         */
                    526:                        if (value) {
                    527:                                if (pos_grp_start == pos_grp_next && key->group && strlen(key->group)) {
                    528:                                        php_stream_printf(dba->fp TSRMLS_CC, "[%s]\n", key->group);
                    529:                                }
                    530:                                php_stream_printf(dba->fp TSRMLS_CC, "%s=%s\n", key->name, value->value ? value->value : "");
                    531:                        }
                    532:                }
                    533:                
                    534:                /* 8 */ 
                    535:                /* important: do not query ret==SUCCESS again: inifile_filter might fail but
                    536:                 * however next operation must be done.
                    537:                 */
                    538:                if (fp_tmp && php_stream_tell(fp_tmp)) {
                    539:                        php_stream_seek(fp_tmp, 0, SEEK_SET);
                    540:                        php_stream_seek(dba->fp, 0, SEEK_END);
                    541:                        if (!php_stream_copy_to_stream(fp_tmp, dba->fp, PHP_STREAM_COPY_ALL)) {
                    542:                                php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Could not copy from temporary stream - ini file truncated");
                    543:                                ret = FAILURE;
                    544:                        }
                    545:                }
                    546:        }
                    547: 
                    548:        if (ini_tmp) {
                    549:                php_stream_close(ini_tmp->fp);
                    550:                inifile_free(ini_tmp, 0);
                    551:        }
                    552:        if (fp_tmp) {
                    553:                php_stream_close(fp_tmp);
                    554:        }
                    555:        php_stream_flush(dba->fp);
                    556:        php_stream_seek(dba->fp, 0, SEEK_SET);
                    557: 
                    558:        return ret;
                    559: }
                    560: /* }}} */
                    561: 
                    562: /* {{{ inifile_delete
                    563:  */
                    564: int inifile_delete(inifile *dba, const key_type *key TSRMLS_DC) 
                    565: {
                    566:        return inifile_delete_replace_append(dba, key, NULL, 0 TSRMLS_CC);
                    567: }      
                    568: /* }}} */
                    569: 
                    570: /* {{{ inifile_relace
                    571:  */
                    572: int inifile_replace(inifile *dba, const key_type *key, const val_type *value TSRMLS_DC) 
                    573: {
                    574:        return inifile_delete_replace_append(dba, key, value, 0 TSRMLS_CC);
                    575: }
                    576: /* }}} */
                    577: 
                    578: /* {{{ inifile_append
                    579:  */
                    580: int inifile_append(inifile *dba, const key_type *key, const val_type *value TSRMLS_DC) 
                    581: {
                    582:        return inifile_delete_replace_append(dba, key, value, 1 TSRMLS_CC);
                    583: }
                    584: /* }}} */
                    585: 
                    586: /*
                    587:  * Local variables:
                    588:  * tab-width: 4
                    589:  * c-basic-offset: 4
                    590:  * End:
                    591:  * vim600: sw=4 ts=4 fdm=marker
                    592:  * vim<600: sw=4 ts=4
                    593:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>