📄 tree.c
字号:
/* This file is part of the program psim. Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au> 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. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#ifndef _PARSE_C_#define _PARSE_C_#include <stdio.h>#include <stdarg.h>#include "basics.h"#include "device.h"#include "tree.h"#ifdef HAVE_STDLIB_H#include <stdlib.h>#endif#ifdef HAVE_STRING_H#include <string.h>#else#ifdef HAVE_STRINGS_H#include <strings.h>#endif#endif#include <ctype.h>/* manipulate/lookup device names */typedef struct _name_specifier { /* components in the full length name */ char *path; char *property; char *value; /* current device */ char *name; char *base; char *unit; char *args; /* previous device */ char *last_name; char *last_base; char *last_unit; char *last_args; /* work area */ char buf[1024];} name_specifier;/* Given a device specifier, break it up into its main components: path (and if present) property name and property value. */STATIC_INLINE_TREE\(int)split_device_specifier(device *current, const char *device_specifier, name_specifier *spec){ char *chp = NULL; /* expand any leading alias if present */ if (current != NULL && *device_specifier != '\0' && *device_specifier != '.' && *device_specifier != '/') { device *aliases = tree_find_device(current, "/aliases"); char alias[32]; int len = 0; while (device_specifier[len] != '\0' && device_specifier[len] != '/' && device_specifier[len] != ':' && !isspace(device_specifier[len])) { alias[len] = device_specifier[len]; len++; if (len >= sizeof(alias)) error("split_device_specifier: buffer overflow"); } alias[len] = '\0'; if (aliases != NULL && device_find_property(aliases, alias)) { strcpy(spec->buf, device_find_string_property(aliases, alias)); strcat(spec->buf, device_specifier + len); } else { strcpy(spec->buf, device_specifier); } } else { strcpy(spec->buf, device_specifier); } /* check no overflow */ if (strlen(spec->buf) >= sizeof(spec->buf)) error("split_device_specifier: buffer overflow\n"); /* strip leading spaces */ chp = spec->buf; while (*chp != '\0' && isspace(*chp)) chp++; if (*chp == '\0') return 0; /* find the path and terminate it with null */ spec->path = chp; while (*chp != '\0' && !isspace(*chp)) chp++; if (*chp != '\0') { *chp = '\0'; chp++; } /* and any value */ while (*chp != '\0' && isspace(*chp)) chp++; spec->value = chp; /* now go back and chop the property off of the path */ if (spec->value[0] == '\0') { spec->property = NULL; /*not a property*/ spec->value = NULL; } else if (spec->value[0] == '>' || spec->value[0] == '<') { /* an interrupt spec */ spec->property = NULL; } else { chp = strrchr(spec->path, '/'); if (chp == NULL) { spec->property = spec->path; spec->path = strchr(spec->property, '\0'); } else { *chp = '\0'; spec->property = chp+1; } } /* and mark the rest as invalid */ spec->name = NULL; spec->base = NULL; spec->unit = NULL; spec->args = NULL; spec->last_name = NULL; spec->last_base = NULL; spec->last_unit = NULL; spec->last_args = NULL; return 1;}/* given a device specifier break it up into its main components - path and property name - assuming that the last `device' is a property name. */STATIC_INLINE_DEVICE\(int)split_property_specifier(device *current, const char *property_specifier, name_specifier *spec){ if (split_device_specifier(current, property_specifier, spec)) { if (spec->property == NULL) { /* force the last name to be a property name */ char *chp = strrchr(spec->path, '/'); if (chp == NULL) { spec->property = spec->path; spec->path = strrchr(spec->property, '\0');; } else { *chp = '\0'; spec->property = chp+1; } } return 1; } else return 0;}/* device the next device name and split it up, return 0 when no more names to device */STATIC_INLINE_TREE\(int)split_device_name(name_specifier *spec){ char *chp; /* remember what came before */ spec->last_name = spec->name; spec->last_base = spec->base; spec->last_unit = spec->unit; spec->last_args = spec->args; /* finished? */ if (spec->path[0] == '\0') { spec->name = NULL; spec->base = NULL; spec->unit = NULL; spec->args = NULL; return 0; } /* break the current device spec from the path */ spec->name = spec->path; chp = strchr(spec->name, '/'); if (chp == NULL) spec->path = strchr(spec->name, '\0'); else { spec->path = chp+1; *chp = '\0'; } /* break out the base */ if (spec->name[0] == '(') { chp = strchr(spec->name, ')'); if (chp == NULL) { spec->base = spec->name; } else { *chp = '\0'; spec->base = spec->name + 1; spec->name = chp + 1; } } else { spec->base = spec->name; } /* now break out the unit */ chp = strchr(spec->name, '@'); if (chp == NULL) { spec->unit = NULL; chp = spec->name; } else { *chp = '\0'; chp += 1; spec->unit = chp; } /* finally any args */ chp = strchr(chp, ':'); if (chp == NULL) spec->args = NULL; else { *chp = '\0'; spec->args = chp+1; } return 1;}/* device the value, returning the next non-space token */STATIC_INLINE_TREE\(char *)split_value(name_specifier *spec){ char *token; if (spec->value == NULL) return NULL; /* skip leading white space */ while (isspace(spec->value[0])) spec->value++; if (spec->value[0] == '\0') { spec->value = NULL; return NULL; } token = spec->value; /* find trailing space */ while (spec->value[0] != '\0' && !isspace(spec->value[0])) spec->value++; /* chop this value out */ if (spec->value[0] != '\0') { spec->value[0] = '\0'; spec->value++; } return token;}/* traverse the path specified by spec starting at current */STATIC_INLINE_TREE\(device *)split_find_device(device *current, name_specifier *spec){ /* strip off (and process) any leading ., .., ./ and / */ while (1) { if (strncmp(spec->path, "/", strlen("/")) == 0) { /* cd /... */ while (current != NULL && device_parent(current) != NULL) current = device_parent(current); spec->path += strlen("/"); } else if (strncmp(spec->path, "./", strlen("./")) == 0) { /* cd ./... */ current = current; spec->path += strlen("./"); } else if (strncmp(spec->path, "../", strlen("../")) == 0) { /* cd ../... */ if (current != NULL && device_parent(current) != NULL) current = device_parent(current); spec->path += strlen("../"); } else if (strcmp(spec->path, ".") == 0) { /* cd . */ current = current; spec->path += strlen("."); } else if (strcmp(spec->path, "..") == 0) { /* cd . */ if (current != NULL && device_parent(current) != NULL) current = device_parent(current); spec->path += strlen(".."); } else break; } /* now go through the path proper */ if (current == NULL) { split_device_name(spec); return NULL; } while (split_device_name(spec)) { device *child; for (child = device_child(current); child != NULL; child = device_sibling(child)) { if (strcmp(spec->name, device_name(child)) == 0) { if (spec->unit == NULL) break; else { device_unit phys; device_decode_unit(current, spec->unit, &phys); if (memcmp(&phys, device_unit_address(child), sizeof(device_unit)) == 0) break; } } } if (child == NULL) return current; /* search failed */ current = child; } return current;}STATIC_INLINE_TREE\(device *)split_fill_path(device *current, const char *device_specifier, name_specifier *spec){ /* break it up */ if (!split_device_specifier(current, device_specifier, spec)) device_error(current, "error parsing %s\n", device_specifier); /* fill our tree with its contents */ current = split_find_device(current, spec); /* add any additional devices as needed */ if (spec->name != NULL) { do { current = device_create(current, spec->base, spec->name, spec->unit, spec->args); } while (split_device_name(spec)); } return current;}INLINE_TREE\(void)tree_init(device *root, psim *system){ TRACE(trace_device_tree, ("tree_init(root=0x%lx, system=0x%lx)\n", (long)root, (long)system)); /* remove the old, rebuild the new */ tree_traverse(root, device_clean, NULL, system); tree_traverse(root, device_init_static_properties, NULL, system); tree_traverse(root, device_init_address, NULL, system); tree_traverse(root, device_init_runtime_properties, NULL, system); tree_traverse(root, device_init_data, NULL, system);}/* <non-white-space> */STATIC_INLINE_TREE\
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -