/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- parse.m for the Azalea window manager Copyright (c) 2006 Yen-Ju Chen parse.c for the Openbox window manager Copyright (c) 2003 Ben Jansens This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. See the COPYING file for a copy of the GNU General Public License. */ #import #import "parse.h" #import #import #import #import static BOOL xdg_start; static NSString *xdg_config_home_path; static NSString *xdg_data_home_path; static NSMutableArray *xdg_config_dir_paths; static NSMutableArray *xdg_data_dir_paths; @interface AZCallback: NSObject { NSString *tag; ParseCallback func; void *data; } - (NSString *) tag; - (ParseCallback) func; - (void *) data; - (void) set_tag: (NSString *) tag; - (void) set_func: (ParseCallback) func; - (void) set_data: (void *) data; @end @implementation AZCallback - (NSString *) tag { return tag; } - (ParseCallback) func { return func; } - (void *) data { return data; } - (void) set_tag: (NSString *) t { ASSIGNCOPY(tag, t); } - (void) set_func: (ParseCallback) f { func = f; } - (void) set_data: (void *) d { data = d; } - (void) dealloc { DESTROY(tag); [super dealloc]; } @end @implementation AZParser - (id) init { self = [super init]; callbacks = [[NSMutableDictionary alloc] init]; return self; } - (void) dealloc { DESTROY(callbacks); [super dealloc]; } - (void) registerTag: (NSString *) tag callback: (ParseCallback) func data: (void *) data { AZCallback *c; if ((c = [callbacks objectForKey: tag])) { NSLog(@"Warning: tag '%@' already registered", tag); return; } c = [[AZCallback alloc] init]; [c set_tag: tag]; [c set_func: func]; [c set_data: data]; [callbacks setObject: c forKey: tag]; DESTROY(c); } - (void) parseDocument: (xmlDocPtr) doc node: (xmlNodePtr) node; { while (node) { AZCallback *c = [callbacks objectForKey: [NSString stringWithCString: (char*)(node->name)]]; if (c) [c func](self , doc, node, [c data]); node = node->next; } } @end BOOL parse_load_rc(xmlDocPtr *doc, xmlNodePtr *root) { NSString *path; BOOL r = NO; int i, count = [xdg_config_dir_paths count]; for (i = 0; !r && (i < count); i++) { path = [NSString pathWithComponents: [NSArray arrayWithObjects: [xdg_config_dir_paths objectAtIndex: i], @"openbox", @"rc.xml", nil]]; r = parse_load(path, "openbox_config", doc, root); } if (!r) NSLog(@"Warning: unable to find a valid config file, using defaults"); return r; } BOOL parse_load_menu(NSString *file, xmlDocPtr *doc, xmlNodePtr *root) { NSString *path; BOOL r = NO; if ([file isAbsolutePath]) { r = parse_load(file, "openbox_menu", doc, root); } else { int i, count = [xdg_config_dir_paths count]; for (i = 0; !r && (i < count); i++) { path = [NSString pathWithComponents: [NSArray arrayWithObjects: [xdg_config_dir_paths objectAtIndex: i], @"openbox", file, nil]]; r = parse_load(path, "openbox_menu", doc, root); } } if (!r) NSLog(@"Warning: unable to find a valid menu file '%@'", file); return r; } BOOL parse_load(NSString *path, const char *rootname, xmlDocPtr *doc, xmlNodePtr *root) { if ((*doc = xmlParseFile([path fileSystemRepresentation]))) { *root = xmlDocGetRootElement(*doc); if (!*root) { xmlFreeDoc(*doc); *doc = NULL; NSLog(@"%@ is an empty document", path); } else { if (xmlStrcasecmp((*root)->name, (const xmlChar*)rootname)) { xmlFreeDoc(*doc); *doc = NULL; NSLog(@"document %@ is of wrong type. root node is " "not '%s'", path, rootname); } } } if (!*doc) return NO; return YES; } BOOL parse_load_mem(void *data, unsigned int len, const char *rootname, xmlDocPtr *doc, xmlNodePtr *root) { if ((*doc = xmlParseMemory(data, len))) { *root = xmlDocGetRootElement(*doc); if (!*root) { xmlFreeDoc(*doc); *doc = NULL; NSLog(@"Warning: Given memory is an empty document"); } else { if (xmlStrcasecmp((*root)->name, (const xmlChar*)rootname)) { xmlFreeDoc(*doc); *doc = NULL; NSLog(@"Warning: document in given memory is of wrong type. root " "node is not '%s'", rootname); } } } if (!*doc) return NO; return YES; } void parse_close(xmlDocPtr doc) { xmlFreeDoc(doc); } NSString *parse_string(xmlDocPtr doc, xmlNodePtr node) { xmlChar *c = xmlNodeListGetString(doc, node->children, YES); NSString *s; if (c) s = [NSString stringWithUTF8String: (char*)c]; else s = [NSString string]; xmlFree(c); return s; } int parse_int(xmlDocPtr doc, xmlNodePtr node) { xmlChar *c = xmlNodeListGetString(doc, node->children, YES); int i = atoi((char*)c); xmlFree(c); return i; } BOOL parse_bool(xmlDocPtr doc, xmlNodePtr node) { xmlChar *c = xmlNodeListGetString(doc, node->children, YES); BOOL b = NO; if (!xmlStrcasecmp(c, (const xmlChar*) "true")) b = YES; else if (!xmlStrcasecmp(c, (const xmlChar*) "yes")) b = YES; else if (!xmlStrcasecmp(c, (const xmlChar*) "on")) b = YES; xmlFree(c); return b; } BOOL parse_contains(const char *val, xmlDocPtr doc, xmlNodePtr node) { xmlChar *c = xmlNodeListGetString(doc, node->children, YES); BOOL r; r = !xmlStrcasecmp(c, (const xmlChar*) val); xmlFree(c); return r; } xmlNodePtr parse_find_node(const char *tag, xmlNodePtr node) { while (node) { if (!xmlStrcasecmp(node->name, (const xmlChar*) tag)) return node; node = node->next; } return NULL; } BOOL parse_attr_int(const char *name, xmlNodePtr node, int *value) { xmlChar *c = xmlGetProp(node, (const xmlChar*) name); BOOL r = NO; if (c) { *value = atoi((char*)c); r = YES; } xmlFree(c); return r; } BOOL parse_attr_string(const char *name, xmlNodePtr node, NSString **value) { xmlChar *c = xmlGetProp(node, (const xmlChar*) name); BOOL r = NO; if (c) { *value = [NSString stringWithUTF8String: (char*)c ]; r = YES; } xmlFree(c); return r; } BOOL parse_attr_contains(const char *val, xmlNodePtr node, const char *name) { xmlChar *c = xmlGetProp(node, (const xmlChar*) name); BOOL r; r = !xmlStrcasecmp(c, (const xmlChar*) val); xmlFree(c); return r; } void parse_paths_startup() { NSString *p; NSProcessInfo *processInfo = [NSProcessInfo processInfo]; NSDictionary *env = [processInfo environment]; if (xdg_start) return; xdg_start = YES; p = [env objectForKey: @"XDG_CONFIG_HOME"]; if (p && [p length] > 0) /* not unset or empty */ ASSIGNCOPY(xdg_config_home_path, p); else ASSIGN(xdg_config_home_path, [NSHomeDirectory() stringByAppendingPathComponent: @".config"]); p = [env objectForKey: @"XDG_DATA_HOME"]; if (p && [p length] > 0) /* not unset or empty */ ASSIGNCOPY(xdg_data_home_path, p); else ASSIGN(xdg_data_home_path, [[NSHomeDirectory() stringByAppendingPathComponent: @".local"] stringByAppendingPathComponent: @"share"]); p = [env objectForKey: @"XDG_CONFIG_DIRS"]; xdg_config_dir_paths = [[NSMutableArray alloc] init]; [xdg_config_dir_paths addObject: xdg_config_home_path]; [xdg_config_dir_paths addObject: [[NSBundle mainBundle] resourcePath]]; if (p && [p length] > 0) /* not unset or empty */ [xdg_config_dir_paths addObjectsFromArray: [p componentsSeparatedByString: @":"]]; else { [xdg_config_dir_paths addObject: [NSString pathWithComponents: [NSArray arrayWithObjects: @"/", @"etc", @"xdg", nil]]]; } p = [env objectForKey: @"XDG_DATA_DIRS"]; xdg_data_dir_paths = [[NSMutableArray alloc] init]; [xdg_data_dir_paths addObject: xdg_data_home_path]; [xdg_data_dir_paths addObject: [[NSBundle mainBundle] resourcePath]]; if (p && [p length] > 0) /* not unset or empty */ [xdg_data_dir_paths addObjectsFromArray: [p componentsSeparatedByString: @":"]]; else { [xdg_data_dir_paths addObject: [NSString pathWithComponents: [NSArray arrayWithObjects: @"/", @"usr", @"local", @"share", nil]]]; [xdg_data_dir_paths addObject: [NSString pathWithComponents: [NSArray arrayWithObjects: @"/", @"usr", @"share", nil]]]; } } void parse_paths_shutdown() { if (!xdg_start) return; xdg_start = NO; DESTROY(xdg_config_dir_paths); DESTROY(xdg_data_dir_paths); } BOOL parse_mkdir_path(NSString *path, int mode) { if ((path == nil) || ([path isAbsolutePath] == NO)) return NO; BOOL isDir; NSFileManager *fm = [NSFileManager defaultManager]; if ([fm fileExistsAtPath: path isDirectory: &isDir] && (isDir == YES)) return YES; /* Make each subdirectory */ NSEnumerator *e = [[path pathComponents] objectEnumerator]; NSString *p, *test_path = @""; while ((p = [e nextObject])) { test_path = [test_path stringByAppendingPathComponent: p]; if ([fm fileExistsAtPath: test_path isDirectory: &isDir] == NO) { /* Create new */ [fm createDirectoryAtPath: test_path attributes: [NSDictionary dictionaryWithObject: [NSNumber numberWithInt: mode] forKey: NSFilePosixPermissions]]; } else { if (isDir == NO) { /* file exists, but not a directory: failed */ return NO; } else { /* directory exists */ continue; } } } return YES; } NSString* parse_xdg_config_home_path() { return xdg_config_home_path; } NSString* parse_xdg_data_home_path() { return xdg_data_home_path; } NSArray* parse_xdg_config_dir_paths() { return xdg_config_dir_paths; } NSArray * parse_xdg_data_dir_paths() { return xdg_data_dir_paths; }