static enum STATE read_tag ( FILE* file, struct xml_element* elem ) { int c = fgetc( file ); if ( c != '<' ) return PARSE_ERROR; c = fgetc( file ); if ( c == EOF ) return PARSE_ERROR; if( c == '?' || c == '!' ) return read_special_tag( file, elem ); bool close_tag = false; if ( c == '/' ) close_tag = true; else ungetc( c, file ); skip_space( file ); struct string str = init_str; c = fgetc( file ); if ( c == '>' ) return PARSE_ERROR; while ( c != '>' && c != '/' && !isspace(c) ) { if ( c == EOF || str_push_back( c, &str ) != OK ) { free( str.str ); return ( c == EOF ) ? PARSE_ERROR : MEMORY_ERROR; } c = fgetc( file ); } if ( close_tag ) { if ( c == '/' || strcmp( str.str, elem->father->name ) != 0 ) { free( str.str ); return PARSE_ERROR; } if ( c != '>') { skip_space( file ); if ( fgetc( file ) != '>' ) { free( str.str ); return PARSE_ERROR; } } free( str.str ); return CLOSE_TAG; } str_remove_trail_space( &str ); elem->name = str.str; ungetc( c, file ); return read_attr( file, elem ); }
static void bootstrap_attr_stack( int attr_stack, int builtin_attr, int git_attributes_file, int direction, int xdg_attributes_file) { int elem = 0; int elem_origin = 0; int elem_prev = 0; if (attr_stack) return; elem = read_attr_from_array(builtin_attr); elem_origin = NULL; elem_prev = attr_stack; attr_stack = elem; if (git_attr_system()) { elem = read_attr_from_file(git_etc_gitattributes(), 1); if (elem) { elem_origin = NULL; elem_prev = attr_stack; attr_stack = elem; } } if (!git_attributes_file) { home_config_paths(NULL, &xdg_attributes_file, "attributes"); git_attributes_file = xdg_attributes_file; } if (git_attributes_file) { elem = read_attr_from_file(git_attributes_file, 1); if (elem) { elem_origin = NULL; elem_prev = attr_stack; attr_stack = elem; } } if (!is_bare_repository() || direction == GIT_ATTR_INDEX) { elem = read_attr(GITATTRIBUTES_FILE, 1); elem_origin = xstrdup(""); elem_prev = attr_stack; attr_stack = elem; debug_push(elem); } elem = read_attr_from_file(git_path(INFOATTRIBUTES_FILE), 1); if (!elem) elem = xcalloc(1, sizeof(elem)); elem_origin = NULL; elem_prev = attr_stack; attr_stack = elem; }
static enum STATE read_attr ( FILE* file, struct xml_element* elem ) { enum STATE state; skip_space( file ); int c = fgetc( file ); if ( c == EOF || c == '=' ) return PARSE_ERROR; if ( c == '/' ) { skip_space( file ); c = fgetc( file ); return ( c == '>' ) ? ISOLATED_TAG : PARSE_ERROR; } if ( c == '>' ) return OPEN_TAG; ungetc( c, file ); struct xml_attribute* attr = calloc( 1, sizeof( struct xml_attribute ) ); if ( !attr ) return MEMORY_ERROR; attr->father = elem; attr->status = IS_ATTRIBUTE_STATUS; state = read_attr_name( file, attr ); if ( state != OK ) { free( attr ); return state; } c = fgetc( file ); if ( c != '=' ) { free( attr->name ); free( attr ); return PARSE_ERROR; } skip_space( file ); state = read_attr_value( file, attr ); if ( state != OK ) { free( attr->name ); free( attr ); return state; } state = read_attr( file, elem ); attr->next = elem->attr; elem->attr = attr; if ( attr->next ) attr->next->prev = attr; return state; }
void dumpdb(char *file) { int fp; int amt; struct server xserver; fp = open(file, O_RDONLY, 0); if (fp < 0) { perror("open failed"); fprintf(stderr, "unable to open file %s\n", file); exit(1); } amt = read(fp, &xserver.sv_qs, sizeof(xserver.sv_qs)); if (amt != sizeof(xserver.sv_qs)) { fprintf(stderr, "Short read of %d bytes, file %s\n", amt, file); } /* print out job structure */ prt_server_struct(&xserver); /* now do attributes, one at a time */ if (no_attributes == 0) { printf("--attributes--\n"); while (read_attr(fp)); } close(fp); printf("\n"); } /* END dumpdb */
static void bootstrap_attr_stack(const struct index_state *istate, struct attr_stack **stack) { struct attr_stack *e; if (*stack) return; /* builtin frame */ e = read_attr_from_array(builtin_attr); push_stack(stack, e, NULL, 0); /* system-wide frame */ if (git_attr_system()) { e = read_attr_from_file(git_xcode_gitattributes(), 1); push_stack(stack, e, NULL, 0); e = read_attr_from_file(git_etc_gitattributes(), 1); push_stack(stack, e, NULL, 0); } /* home directory */ if (get_home_gitattributes()) { e = read_attr_from_file(get_home_gitattributes(), 1); push_stack(stack, e, NULL, 0); } /* root directory */ e = read_attr(istate, GITATTRIBUTES_FILE, 1); push_stack(stack, e, xstrdup(""), 0); /* info frame */ if (startup_info->have_repository) e = read_attr_from_file(git_path_info_attributes(), 1); else e = NULL; if (!e) e = xcalloc(1, sizeof(struct attr_stack)); push_stack(stack, e, NULL, 0); }
int NdbOperation::read_attr(Uint32 anAttrId, Uint32 RegDest) { return read_attr(m_currentTable->getColumn(anAttrId), RegDest); }
int NdbOperation::read_attr(const char* anAttrName, Uint32 RegDest) { return read_attr(m_currentTable->getColumn(anAttrName), RegDest); }
static void prepare_attr_stack(const char *path, int dirlen, struct attr_stack **stack) { struct attr_stack *info; struct strbuf pathbuf = STRBUF_INIT; /* * At the bottom of the attribute stack is the built-in * set of attribute definitions, followed by the contents * of $(prefix)/etc/gitattributes and a file specified by * core.attributesfile. Then, contents from * .gitattribute files from directories closer to the * root to the ones in deeper directories are pushed * to the stack. Finally, at the very top of the stack * we always keep the contents of $GIT_DIR/info/attributes. * * When checking, we use entries from near the top of the * stack, preferring $GIT_DIR/info/attributes, then * .gitattributes in deeper directories to shallower ones, * and finally use the built-in set as the default. */ bootstrap_attr_stack(stack); /* * Pop the "info" one that is always at the top of the stack. */ info = *stack; *stack = info->prev; /* * Pop the ones from directories that are not the prefix of * the path we are checking. Break out of the loop when we see * the root one (whose origin is an empty string "") or the builtin * one (whose origin is NULL) without popping it. */ while ((*stack)->origin) { int namelen = (*stack)->originlen; struct attr_stack *elem; elem = *stack; if (namelen <= dirlen && !strncmp(elem->origin, path, namelen) && (!namelen || path[namelen] == '/')) break; debug_pop(elem); *stack = elem->prev; attr_stack_free(elem); } /* * bootstrap_attr_stack() should have added, and the * above loop should have stopped before popping, the * root element whose attr_stack->origin is set to an * empty string. */ assert((*stack)->origin); strbuf_addstr(&pathbuf, (*stack)->origin); /* Build up to the directory 'path' is in */ while (pathbuf.len < dirlen) { size_t len = pathbuf.len; struct attr_stack *next; char *origin; /* Skip path-separator */ if (len < dirlen && is_dir_sep(path[len])) len++; /* Find the end of the next component */ while (len < dirlen && !is_dir_sep(path[len])) len++; if (pathbuf.len > 0) strbuf_addch(&pathbuf, '/'); strbuf_add(&pathbuf, path + pathbuf.len, (len - pathbuf.len)); strbuf_addf(&pathbuf, "/%s", GITATTRIBUTES_FILE); next = read_attr(pathbuf.buf, 0); /* reset the pathbuf to not include "/.gitattributes" */ strbuf_setlen(&pathbuf, len); origin = xstrdup(pathbuf.buf); push_stack(stack, next, origin, len); } /* * Finally push the "info" one at the top of the stack. */ push_stack(stack, info, NULL, 0); strbuf_release(&pathbuf); }
int main( int argc, char *argv[]) { int amt; int err = 0; int f; int fp; int no_attributes = 0; job xjob; extern int optind; while ((f = getopt(argc, argv, "a")) != EOF) { switch (f) { case 'a': no_attributes = 1; break; default: err = 1; break; } } if (err || (argc - optind < 1)) { fprintf(stderr, "usage: %s [-a] file[ file]...}\n", argv[0]); return(1); } for (f = optind;f < argc;++f) { fp = open(argv[f], O_RDONLY, 0); if (fp < 0) { perror("open failed"); fprintf(stderr, "unable to open file %s\n", argv[f]); exit(1); } amt = read_ac_socket(fp, &xjob.ji_qs, sizeof(xjob.ji_qs)); if (amt != sizeof(xjob.ji_qs)) { fprintf(stderr, "Short read of %d bytes, file %s\n", amt, argv[f]); } if (xjob.ji_qs.qs_version != PBS_QS_VERSION) { printf("%s contains an old version of the ji_qs structure.\n" " expecting version %#010x, read %#010x\n" " Skipping prt_job_struct()\n" " pbs_server may be able to upgrade job automatically\n", argv[f], PBS_QS_VERSION, xjob.ji_qs.qs_version); close(fp); continue; } /* print out job structure */ prt_job_struct(&xjob); /* now do attributes, one at a time */ if (no_attributes == 0) { printf("--attributes--\n"); while (read_attr(fp)) /* NO-OP, reading */; } if (xjob.ji_qs.ji_un_type == JOB_UNION_TYPE_MOM) { printf("--TM info--\n"); read_tm_info(fp); } close(fp); printf("\n"); } /* END for (f) */ return(0); } /* END main() */
int Read_Syscheck(XML_NODE node, void *configp, void *mailp) { int i = 0; /* XML Definitions */ char *xml_directories = "directories"; char *xml_registry = "windows_registry"; char *xml_time = "frequency"; char *xml_scanday = "scan_day"; char *xml_scantime = "scan_time"; char *xml_ignore = "ignore"; char *xml_registry_ignore = "registry_ignore"; char *xml_auto_ignore = "auto_ignore"; char *xml_alert_new_files = "alert_new_files"; char *xml_disabled = "disabled"; char *xml_scan_on_start = "scan_on_start"; char *xml_prefilter_cmd = "prefilter_cmd"; /* Configuration example <directories check_all="yes">/etc,/usr/bin</directories> <directories check_owner="yes" check_group="yes" check_perm="yes" check_sum="yes">/var/log</directories> */ config *syscheck; syscheck = (config *)configp; while(node[i]) { if(!node[i]->element) { merror(XML_ELEMNULL, ARGV0); return(OS_INVALID); } else if(!node[i]->content) { merror(XML_VALUENULL, ARGV0, node[i]->element); return(OS_INVALID); } /* Getting directories */ else if(strcmp(node[i]->element,xml_directories) == 0) { char dirs[OS_MAXSTR]; #ifdef WIN32 ExpandEnvironmentStrings(node[i]->content, dirs, sizeof(dirs) -1); #else strncpy(dirs, node[i]->content, sizeof(dirs) -1); #endif if(!read_attr(syscheck, dirs, node[i]->attributes, node[i]->values)) { return(OS_INVALID); } } /* Getting windows registry */ else if(strcmp(node[i]->element,xml_registry) == 0) { #ifdef WIN32 if(!read_reg(syscheck, node[i]->content)) { return(OS_INVALID); } #endif } /* Getting frequency */ else if(strcmp(node[i]->element,xml_time) == 0) { if(!OS_StrIsNum(node[i]->content)) { merror(XML_VALUEERR,ARGV0,node[i]->element,node[i]->content); return(OS_INVALID); } syscheck->time = atoi(node[i]->content); } /* Getting scan time */ else if(strcmp(node[i]->element,xml_scantime) == 0) { syscheck->scan_time = OS_IsValidUniqueTime(node[i]->content); if(!syscheck->scan_time) { merror(XML_VALUEERR,ARGV0,node[i]->element,node[i]->content); return(OS_INVALID); } } /* Getting scan day */ else if(strcmp(node[i]->element,xml_scanday) == 0) { syscheck->scan_day = OS_IsValidDay(node[i]->content); if(!syscheck->scan_day) { merror(XML_VALUEERR,ARGV0,node[i]->element,node[i]->content); return(OS_INVALID); } } /* Getting if xml_scan_on_start. */ else if(strcmp(node[i]->element, xml_scan_on_start) == 0) { if(strcmp(node[i]->content, "yes") == 0) syscheck->scan_on_start = 1; else if(strcmp(node[i]->content, "no") == 0) syscheck->scan_on_start = 0; else { merror(XML_VALUEERR,ARGV0, node[i]->element, node[i]->content); return(OS_INVALID); } } /* Getting if disabled. */ else if(strcmp(node[i]->element,xml_disabled) == 0) { if(strcmp(node[i]->content, "yes") == 0) syscheck->disabled = 1; else if(strcmp(node[i]->content, "no") == 0) syscheck->disabled = 0; else { merror(XML_VALUEERR,ARGV0,node[i]->element,node[i]->content); return(OS_INVALID); } } /* Getting file/dir ignore */ else if(strcmp(node[i]->element,xml_ignore) == 0) { int ign_size = 0; /* For Windows, we attempt to expand environment variables. */ #ifdef WIN32 char *new_ig = NULL; os_calloc(2048, sizeof(char), new_ig); ExpandEnvironmentStrings(node[i]->content, new_ig, 2047); free(node[i]->content); node[i]->content = new_ig; #endif /* Adding if regex */ if(node[i]->attributes && node[i]->values) { if(node[i]->attributes[0] && node[i]->values[0] && (strcmp(node[i]->attributes[0], "type") == 0) && (strcmp(node[i]->values[0], "sregex") == 0)) { OSMatch *mt_pt; if(!syscheck->ignore_regex) { os_calloc(2, sizeof(OSMatch *),syscheck->ignore_regex); syscheck->ignore_regex[0] = NULL; syscheck->ignore_regex[1] = NULL; } else { while(syscheck->ignore_regex[ign_size] != NULL) ign_size++; os_realloc(syscheck->ignore_regex, sizeof(OSMatch *)*(ign_size +2), syscheck->ignore_regex); syscheck->ignore_regex[ign_size +1] = NULL; } os_calloc(1, sizeof(OSMatch), syscheck->ignore_regex[ign_size]); if(!OSMatch_Compile(node[i]->content, syscheck->ignore_regex[ign_size], 0)) { mt_pt = (OSMatch *)syscheck->ignore_regex[ign_size]; merror(REGEX_COMPILE, ARGV0, node[i]->content, mt_pt->error); return(0); } } else { merror(SK_INV_ATTR, ARGV0, node[i]->attributes[0]); return(OS_INVALID); } } /* Adding if simple entry -- checking for duplicates */ else if(!os_IsStrOnArray(node[i]->content, syscheck->ignore)) { if(!syscheck->ignore) { os_calloc(2, sizeof(char *), syscheck->ignore); syscheck->ignore[0] = NULL; syscheck->ignore[1] = NULL; } else { while(syscheck->ignore[ign_size] != NULL) ign_size++; os_realloc(syscheck->ignore, sizeof(char *)*(ign_size +2), syscheck->ignore); syscheck->ignore[ign_size +1] = NULL; } os_strdup(node[i]->content,syscheck->ignore[ign_size]); } } /* Getting registry ignore list */ else if(strcmp(node[i]->element,xml_registry_ignore) == 0) { #ifdef WIN32 int ign_size = 0; /* Adding if regex */ if(node[i]->attributes && node[i]->values) { if(node[i]->attributes[0] && node[i]->values[0] && (strcmp(node[i]->attributes[0], "type") == 0) && (strcmp(node[i]->values[0], "sregex") == 0)) { OSMatch *mt_pt; if(!syscheck->registry_ignore_regex) { os_calloc(2, sizeof(OSMatch *), syscheck->registry_ignore_regex); syscheck->registry_ignore_regex[0] = NULL; syscheck->registry_ignore_regex[1] = NULL; } else { while(syscheck->registry_ignore_regex[ign_size] !=NULL) ign_size++; os_realloc(syscheck->registry_ignore_regex, sizeof(OSMatch *)*(ign_size +2), syscheck->registry_ignore_regex); syscheck->registry_ignore_regex[ign_size +1] = NULL; } os_calloc(1, sizeof(OSMatch), syscheck->registry_ignore_regex[ign_size]); if(!OSMatch_Compile(node[i]->content, syscheck->registry_ignore_regex[ign_size], 0)) { mt_pt = (OSMatch *) syscheck->registry_ignore_regex[ign_size]; merror(REGEX_COMPILE, ARGV0, node[i]->content, mt_pt->error); return(0); } } else { merror(SK_INV_ATTR, ARGV0, node[i]->attributes[0]); return(OS_INVALID); } } /* We do not add duplicated entries */ else if(!os_IsStrOnArray(node[i]->content, syscheck->registry_ignore)) { if(!syscheck->registry_ignore) { os_calloc(2, sizeof(char *), syscheck->registry_ignore); syscheck->registry_ignore[0] = NULL; syscheck->registry_ignore[1] = NULL; } else { while(syscheck->registry_ignore[ign_size] != NULL) ign_size++; os_realloc(syscheck->registry_ignore, sizeof(char *)*(ign_size +2), syscheck->registry_ignore); syscheck->registry_ignore[ign_size +1] = NULL; } os_strdup(node[i]->content,syscheck->registry_ignore[ign_size]); } #endif } else if(strcmp(node[i]->element,xml_auto_ignore) == 0) { /* auto_ignore is not read here. */ } else if(strcmp(node[i]->element,xml_alert_new_files) == 0) { /* alert_new_files option is not read here. */ } else if(strcmp(node[i]->element,xml_prefilter_cmd) == 0) { char cmd[OS_MAXSTR]; struct stat statbuf; #ifdef WIN32 ExpandEnvironmentStrings(node[i]->content, cmd, sizeof(cmd) -1); #else strncpy(cmd, node[i]->content, sizeof(cmd)-1); #endif if (strlen(cmd) > 0) { char statcmd[OS_MAXSTR]; char *ix; strncpy(statcmd, cmd, sizeof(statcmd)-1); if (NULL != (ix = strchr(statcmd, ' '))) { *ix = '\0'; } if (stat(statcmd, &statbuf) == 0) { // More checks needed (perms, owner, etc.) os_calloc(1, strlen(cmd)+1, syscheck->prefilter_cmd); strncpy(syscheck->prefilter_cmd, cmd, strlen(cmd)); } else { merror(XML_VALUEERR,ARGV0, node[i]->element, node[i]->content); return(OS_INVALID); } } } else { merror(XML_INVELEM, ARGV0, node[i]->element); return(OS_INVALID); } i++; } return(0); }
int main(int argc, char **argv) { cib_t * the_cib = NULL; enum cib_errors rc = cib_ok; int cib_opts = cib_sync_call; int argerr = 0; int flag; int option_index = 0; crm_system_name = basename(argv[0]); crm_set_options("V?$GDQqN:U:u:s:n:v:l:t:i:!r:d:", "command -n attribute [options]", long_options, "Manage node's attributes and cluster options." "\n\nAllows node attributes and cluster options to be queried, modified and deleted.\n"); if(argc < 2) { crm_help('?', LSB_EXIT_EINVAL); } while (1) { flag = crm_get_option(argc, argv, &option_index); if (flag == -1) break; switch(flag) { case 'V': cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); break; case '$': case '?': crm_help(flag, LSB_EXIT_OK); break; case 'D': case 'G': case 'v': command = flag; attr_value = optarg; break; case 'q': case 'Q': BE_QUIET = TRUE; break; case 'U': case 'N': dest_uname = crm_strdup(optarg); break; case 'u': dest_node = crm_strdup(optarg); break; case 's': set_name = crm_strdup(optarg); break; case 'l': case 't': type = optarg; break; case 'n': attr_name = crm_strdup(optarg); break; case 'i': attr_id = crm_strdup(optarg); break; case 'r': rsc_id = optarg; break; case 'd': attr_default = optarg; break; case '!': crm_warn("Inhibiting notifications for this update"); cib_opts |= cib_inhibit_notify; break; default: printf("Argument code 0%o (%c) is not (?yet?) supported\n", flag, flag); ++argerr; break; } } if(BE_QUIET == FALSE) { crm_log_init(basename(argv[0]), LOG_ERR, FALSE, FALSE, argc, argv); } else { crm_log_init(basename(argv[0]), LOG_ERR, FALSE, FALSE, 0, NULL); } if (optind < argc) { printf("non-option ARGV-elements: "); while (optind < argc) printf("%s ", argv[optind++]); printf("\n"); } if (optind > argc) { ++argerr; } if (argerr) { crm_help('?', LSB_EXIT_GENERIC); } the_cib = cib_new(); rc = the_cib->cmds->signon(the_cib, crm_system_name, cib_command); if(rc != cib_ok) { fprintf(stderr, "Error signing on to the CIB service: %s\n", cib_error2string(rc)); return rc; } if(safe_str_eq(type, "reboot")) { type = XML_CIB_TAG_STATUS; } else if(safe_str_eq(type, "forever")) { type = XML_CIB_TAG_NODES; } if(type == NULL && dest_uname == NULL) { /* we're updating cluster options - dont populate dest_node */ type = XML_CIB_TAG_CRMCONFIG; } else { determine_host(the_cib, &dest_uname, &dest_node); } if(rc != cib_ok) { crm_info("Error during setup of %s=%s update", attr_name, command=='D'?"<none>":attr_value); } else if( (command=='v' || command=='D') && safe_str_eq(type, XML_CIB_TAG_STATUS) && attrd_lazy_update(command, dest_uname, attr_name, attr_value, type, set_name, NULL)) { crm_info("Update %s=%s sent via attrd", attr_name, command=='D'?"<none>":attr_value); } else if(command=='D') { rc = delete_attr(the_cib, cib_opts, type, dest_node, set_name, attr_id, attr_name, attr_value, TRUE); if(rc == cib_NOTEXISTS) { /* Nothing to delete... * which means its not there... * which is what the admin wanted */ rc = cib_ok; } else if(rc != cib_missing_data && safe_str_eq(crm_system_name, "crm_failcount")) { char *now_s = NULL; time_t now = time(NULL); now_s = crm_itoa(now); update_attr(the_cib, cib_sync_call, XML_CIB_TAG_CRMCONFIG, NULL, NULL, NULL, "last-lrm-refresh", now_s, TRUE); crm_free(now_s); } } else if(command=='v') { CRM_DEV_ASSERT(type != NULL); CRM_DEV_ASSERT(attr_name != NULL); CRM_DEV_ASSERT(attr_value != NULL); rc = update_attr(the_cib, cib_opts, type, dest_node, set_name, attr_id, attr_name, attr_value, TRUE); } else /* query */ { char *read_value = NULL; rc = read_attr(the_cib, type, dest_node, set_name, attr_id, attr_name, &read_value, TRUE); if(rc == cib_NOTEXISTS && attr_default) { read_value = crm_strdup(attr_default); rc = cib_ok; } crm_info("Read %s=%s %s%s", attr_name, crm_str(read_value), set_name?"in ":"", set_name?set_name:""); if(rc == cib_missing_data) { rc = cib_ok; } else if(BE_QUIET == FALSE) { fprintf(stdout, "%s%s %s%s %s%s value=%s\n", type?"scope=":"", type?type:"", attr_id?"id=":"", attr_id?attr_id:"", attr_name?"name=":"", attr_name?attr_name:"", read_value?read_value:"(null)"); } else if(read_value != NULL) { fprintf(stdout, "%s\n", read_value); } } the_cib->cmds->signoff(the_cib); if(rc == cib_missing_data) { printf("Please choose from one of the matches above and suppy the 'id' with --attr-id\n"); } else if(rc != cib_ok) { fprintf(stderr, "Error performing operation: %s\n", cib_error2string(rc)); } return rc; }
static gboolean push_chunk (GArray *ar, const gchar *str) { g_autofree gchar *attr = NULL; g_autofree gchar *post = NULL; g_autofree gchar *return_type = NULL; g_autofree gchar *ident = NULL; const gchar *pos; Chunk chunk = {0}; g_assert (ar); g_assert (str); if ((attr = read_attr (str, &pos))) { chunk.pre = g_strstrip (g_steal_pointer (&attr)); str = pos; } if (!(return_type = read_return_type (str, &pos))) goto failure; str = pos; chunk.return_type = g_strstrip (g_steal_pointer (&return_type)); if (!(ident = getword (str, &pos))) goto failure; if (*ident != '_' && !g_ascii_isalpha (*ident)) goto failure; str = pos; chunk.identifier = g_strstrip (g_steal_pointer (&ident)); if (!read_char (str, '(', &pos)) goto failure; str = pos; /* get params */ if (!(pos = strchr (str, ')'))) goto failure; { g_autofree gchar *inner = g_strndup (str, pos - str); chunk.params = parse_parameters (inner); str = pos; } if (!read_char (str, ')', &pos)) goto failure; str = pos; chunk.post = g_strstrip (g_strdup (str)); if (chunk.post[0] == 0) g_clear_pointer (&chunk.post, g_free); g_array_append_val (ar, chunk); return TRUE; failure: clear_chunk (&chunk); return FALSE; }