V7_PRIVATE enum v7_err do_exec(struct v7 *v7, const char *file_name, const char *source_code, int sp) { int has_ret = 0; struct v7_pstate old_pstate = v7->pstate; enum v7_err err = V7_OK; v7->pstate.source_code = v7->pstate.pc = source_code; v7->pstate.file_name = file_name; v7->pstate.line_no = 1; // Prior calls to v7_exec() may have left current_scope modified, reset now // TODO(lsm): free scope chain v7->this_obj = &v7->root_scope; next_tok(v7); while ((err == V7_OK) && (v7->cur_tok != TOK_END_OF_INPUT)) { // Reset stack on each statement if ((err = inc_stack(v7, sp - v7->sp)) == V7_OK) { err = parse_statement(v7, &has_ret); } } //printf("%s: [%s] %d %d\n", __func__, file_name, v7->pstate.line_no, err); assert(v7->root_scope.proto == &s_global); v7->pstate = old_pstate; return err; }
void eat_it(tokenizer_t t, token_kind_t kind) { if(cur_tok(t).kind == kind) { next_tok(t); } else { //printf("exit\n"); exit(1); } }
void eat_it(tokenizer_t t, token_kind_t tok_kind){ struct token tok = cur_tok(t); if (tok_kind != TOK_ANY && tok.kind != tok_kind){ printf("expected "); output_token_kind(tok_kind); printf("unexpected "); output_token_kind(tok.kind); syntax_error(t, "eat_it error"); } output_token(t); next_tok(t); }
int main(int argc, char ** argv){ tokenizer_t t = mk_tokenizer(argv[1]); while(cur_tok(t).kind != tok_eof){ if(cur_tok(t).kind == tok_nl){ t->num = 0; next_tok(t); } else{ int x = eat_int(t); while(cur_tok(t).kind != tok_nl){ eat_plus(t); int y = eat_int(t); x = x + y; } t->num = 0; next_tok(t); printf("sum = %d\n", x); } } return 0; }
tokenizer_t mk_tokenizer(char * filename){ tokenizer_t t = (tokenizer_t)malloc(sizeof(struct tokenizer)); FILE * fp = safe_fopen(filename, "r"); t->tok.filename = (char *)malloc((strlen(filename)+1)*sizeof(char)); int c; t->tok.a = (char *)malloc(sizeof(char) * 100); t->tok.num = (char *)malloc(sizeof(char) * 100); c = fgetc(fp); t->c = c; t->fp = fp; t->tok.filename = filename; t->tok.line_num = 1; next_tok(t); return t; }
int eval_expression(struct eval *eval, const tchar *expr, const tchar *elim, unsigned long *result) { struct tok *tok, *op; trans_fn fn; int n; if (eval == NULL || expr == NULL || expr > elim || result == NULL) { PMNO(errno = EINVAL); return -1; } if (expr == elim) { *result = 0; return 0; } do { if ((n = next_tok(eval, expr, elim, &tok)) == -1) { AMSG(""); return -1; } do { op = stack_peek(eval->opstk); fn = trans_matrix[tok->type - 1][op->type - 1]; if (fn && fn(eval, tok) == -1) { AMSG(""); return -1; } } while (fn == pop); expr += n; } while (n); if ((tok = stack_pop(eval->stk))) { *result = tok->val; } else { *result = 0; } return 0; }
void hpcrun_sample_sources_from_eventlist(char* evl) { if (evl == NULL) { hpcrun_ssfail_none(); } TMSG(EVENTS,"evl (before processing) = |%s|",evl); for(char *event = start_tok(evl); more_tok(); event = next_tok()){ sample_source_t *s; if (strcasecmp(event, "LIST") == 0) { hpcrun_display_avail_events(); } else if ( (s = hpcrun_source_can_process(event)) ){ add_source(s); METHOD_CALL(s, add_event, event); } else { hpcrun_ssfail_unknown(event); } } }
token get_tok(char *s, unsigned *k) { token tok; while ((tok = next_tok(s, k)).type == WHITE); return tok; }
/* * Parses string containing encoded plot limits and writes then to 'limits' * returns 1 on success, 0 if parse error. */ static int parse_limits(Limits * limits, char *lim_string) { token *tok; char *tmp; int i, lim_pos = 0, sign = 1; if (!limits) return 0; /* parse all 4 limits */ for (i = 0; i < 4; i++) { if (i > 0) { tok = next_tok(lim_string, lim_pos); if (tok->type != T_COLON) { (void) parse_error(tok, "Delimiter expected"); free(tok); return 0; } lim_pos += tok->len; free(tok); } sign = 1; tok = next_tok(lim_string, lim_pos); /* minus does not bind to a number, it behaves like an unary operator */ if (tok->type == T_OP && lim_string[tok->pos] == '-') { sign = -1; lim_pos += tok->len; free(tok); tok = next_tok(lim_string, lim_pos); } tmp = (char *) malloc(sizeof(char) * (tok->len + 1)); assert(tmp); strncpy(tmp, lim_string + tok->pos, tok->len); tmp[tok->len] = '\0'; /* parse number according to its type */ switch (tok->type) { case T_HEX: case T_DEC: case T_OCT: *((double *) limits + i) = sign * (double) strtoul(tmp, NULL, 0); break; case T_FLOAT: *((double *) limits + i) = sign * (double) strtod(tmp, NULL); break; /* handle errors by the same function that is used by main parser */ default: (void) parse_error(tok, "Number expected"); free(tmp); free(tok); return 0; } lim_pos += tok->len; free(tmp); free(tok); } /* check if last token is eof */ tok = next_tok(lim_string, lim_pos); if (tok->type != T_EOF) { (void) parse_error(tok, "Redundant"); free(tok); return 0; } free(tok); /* Perform check on limits, do not allow reversed x-axis */ if (limits->x_low >= limits->x_high || limits->y_low >= limits->y_high) { fprintf(stderr, "Low limit must be less than high limit\n"); return 0; } return 1; }
// take a tokenized expression (expr) with precalculated internal values (llp and ldp) and evaluate it // HIHI maybe put the return value in an arg, and pass back an error flag? -- otherwise need *inf, so I can show_errors? // -- move this back into cpp?? It's not generic enough. int32_t calculate_expr(uint8_t *expr, uint64_t *llp, int32_t llcnt, double *ldp, int32_t ldblcnt) { uint8_t *s, *e, *p, *c, restart, tok, type[200]; int i; restart = 0; i = 200; while (--i >= 0) type[i] = 0; // init the unused part of the array to 0 i = llcnt; while (--i >= 0) type[i] = 1; // init all the ints to uint64_t i = ldblcnt; while (--i >= 0) type[199 - i] = 42; // init all the floats to long double // HIHI! enforce that llcnt + ldblcnt < 256 - TOK_SIZEOF s = expr; // scan to the first ')' token, scan backwards to the first '(' token -- then evaluate that subexpression // -- each pair of parens get deleted after their whole subexpression is done parsing while (*s != TOK_C_PAREN && *s != TOK_ILLEGAL) ++s; while (*s != TOK_ILLEGAL) { e = s; while (*--s != TOK_O_PAREN); // find the highest precedence operator in the expression // no "primary" operators are allowed in the preprocessor -- scan right to left for the first active unary operator p = e; // + - ! ~ sizeof(cast) (casts)=masking while (*--p != TOK_O_PAREN && restart == 0) { if (*p == TOK_B_NOT || *p == TOK_NOT) // in this compiler, bitwise not and boolean not are the same operator { tok = next_tok(p); // the next token *must* be an rvalue for the operator // if (tok <= TOK_SIZEOF, or if the variable is a float?) show_error; // modify the rvalue at the right end of the expression llp[tok - TOK_SIZEOF - 1] = ~llp[tok - TOK_SIZEOF - 1]; *p = TOK_NO_OP; // now that the operator has been processed, delete it p = e; } // a minus sign is a NEG unary operator if there is another operator (and not a "variable") to the left // HIHI!! gotta handle the float case, too! else if (*p == TOK_SUB && prev_tok(p) <= TOK_SIZEOF) { tok = next_tok(p); // the next token *must* be an rvalue for the operator // if (tok <= TOK_SIZEOF) show_error; // modify the rvalue at the right end of the expression // check "type" to see if this tok is a float llp[tok - TOK_SIZEOF - 1] = - (int64_t) llp[tok - TOK_SIZEOF - 1]; *p = TOK_NO_OP; // now that the operator has been processed, delete it p = e; } // a plus sign is a unary operator (and a no-op) if there is another operator (and not a "variable") to the left else if (*p == TOK_ADD && prev_tok(p) <= TOK_SIZEOF) { *p = TOK_NO_OP; // delete the + operator and restart the scan p = e; } else if (*p >= TOK_BOOL_T && *p <= TOK_UNSGN_T) { // either this is an input into sizeof (as a cast), or it's a cast of the following value // -- so (multiple) type keywords should be the only thing inside the parens // -- because the preprocessor doesn't know about function or variable declarations c = p - 1; while (*c == TOK_NO_OP || (*c >= TOK_BOOL_T && *c <= TOK_UNSGN_T)) --c; // verify the open and close parens around this (cast) // obviously, s also points at the '(' and e points at the ')' // HIHI!!! woops! the next tok may be a *, and not a paren! Need to scan that direction, too! if (next_tok(p) != TOK_C_PAREN || c != s) { i = 0; // show_error(0,"typecast(?) not in parens",NULL,1); } p = s; while (*--p == TOK_NO_OP); if (*p == TOK_SIZEOF) // immediately convert a sizeof(cast) into a variable (with the correct value) { // get the next open int variable number type[llcnt] = 0; i = -1; while (type[++i] != 0); if (i == llcnt) ++llcnt; // HIHI!! need to put a 199 limit on llcnt! // replace the sizeof() token with the actual size, and no-op the cast *p = i + TOK_SIZEOF + 1; llp[i] = size_of(s + 1); type[i] = 1; while (*++p != TOK_C_PAREN) *p = TOK_NO_OP; *p = TOK_NO_OP; restart = 1; } else { // do an immediate mask and type modification of the rvalue variable tok = next_tok(p); // get the variable index i = size_of(s + 1) - 1; // get the byte count - 1 if (i == 3) i = 2; // convert to a mask index if (i < 3) llp[tok - TOK_SIZEOF - 1] &= size_mask[i]; else i = 3; type[tok - TOK_SIZEOF - 1] = 4 - i; // convert to a type (maybe I should reverse the order of the types?? HIHI) } } } // then the multiplicative operators -- p already points to the start while (restart == 0 && *++p != TOK_C_PAREN) { if (*p == TOK_MULT || *p == TOK_DIV || *p == TOK_MOD) { restart = 1; binary_op(p, llp, type); } } // then additiive p = s; while (restart == 0 && *++p != TOK_C_PAREN) { if (*p == TOK_ADD || *p == TOK_SUB) { restart = 1; binary_op(p, llp, type); } } // then shifts p = s; while (restart == 0 && *++p != TOK_C_PAREN) { if (*p == TOK_SHR || *p == TOK_SHL) { restart = 1; binary_op(p, llp, type); } } // then relational conditionals p = s; while (restart == 0 && *++p != TOK_C_PAREN) { if (*p == TOK_B_LT || *p == TOK_B_GT || *p == TOK_B_LE || *p == TOK_B_GE) { restart = 1; binary_op(p, llp, type); } } // then equality conditionals p = s; while (restart == 0 && *++p != TOK_C_PAREN) { if (*p == TOK_B_EQ || *p == TOK_B_NE) { restart = 1; binary_op(p, llp, type); } } // then bitwise operators -- AND & p = s; while (restart == 0 && *++p != TOK_C_PAREN) { if (*p == TOK_AND) { restart = 1; binary_op(p, llp, type); } } // XOR ^ p = s; while (restart == 0 && *++p != TOK_C_PAREN) { if (*p == TOK_XOR) { restart = 1; binary_op(p, llp, type); } } // OR | p = s; while (restart == 0 && *++p != TOK_C_PAREN) { if (*p == TOK_OR) { restart = 1; binary_op(p, llp, type); } } // then booleans && p = s; while (restart == 0 && *++p != TOK_C_PAREN) { if (*p == TOK_B_AND) { restart = 1; binary_op(p, llp, type); } } // || p = s; while (restart == 0 && *++p != TOK_C_PAREN) { if (*p == TOK_B_OR) { restart = 1; binary_op(p, llp, type); } } // and last, the stupid "ternary condtional" ? evaluate right to left, p is already set properly while (restart == 0 && *--p != TOK_O_PAREN) { if (*p == TOK_QMARK) i = 8; // HIHI!!! gotta parse it and eliminate it from the expr } // are there any operators left between s and e? If not, destroy the parens of this fully evaluated subexpression. p = s + 1; while (*p > TOK_SIZEOF || *p == TOK_NO_OP) ++p; if (*p == TOK_C_PAREN) { *s = TOK_NO_OP; *p = TOK_NO_OP; } restart = 0; s = expr; while (*s != TOK_C_PAREN && *s != TOK_ILLEGAL) ++s; } // there must be one variable left in the expression now -- that's the return value p = expr + 1; while (*p < TOK_SIZEOF) ++p; if (llp[*p - TOK_SIZEOF - 1] == 0) return 0; return -1; }
// HIHI!! almost certainly need to change the return value -- return error codes, return float values, or int values void binary_op(uint8_t *p, uint64_t *llp, uint8_t *type) { uint64_t result; uint8_t rval_idx, op, i, j; op = *p; // preserve the operator token rval_idx = next_tok(p); if (rval_idx <= TOK_SIZEOF) rval_idx = TOK_SIZEOF + 1; // a blank "variable" means a value of 0 while (*--p == TOK_NO_OP); // find the lval if (*p <= TOK_SIZEOF) *++p = TOK_SIZEOF + 1; i = rval_idx - TOK_SIZEOF - 1; j = *p - TOK_SIZEOF - 1; result = 0; switch (op) { case TOK_B_EQ: if (llp[j] == llp[i]) result = BOOL_TRUE; break; case TOK_B_NE: if (llp[j] != llp[i]) result = BOOL_TRUE; break; case TOK_B_LT: if (llp[j] < llp[i]) result = BOOL_TRUE; break; case TOK_B_GT: if (llp[j] > llp[i]) result = BOOL_TRUE; break; case TOK_B_LE: if (llp[j] <= llp[i]) result = BOOL_TRUE; break; case TOK_B_GE: if (llp[j] >= llp[i]) result = BOOL_TRUE; break; case TOK_MULT: result = llp[j] * llp[i]; break; case TOK_DIV: result = llp[j] / llp[i]; break; case TOK_MOD: result = llp[j] % llp[i]; break; case TOK_ADD: result = llp[j] + llp[i]; break; case TOK_SUB: result = llp[j] - llp[i]; break; case TOK_SHL: result = llp[j] << (char) llp[i]; break; case TOK_SHR: result = llp[j] >> (char) llp[i]; break; case TOK_B_AND: case TOK_AND: result = llp[j] & llp[i]; break; case TOK_XOR: result = llp[j] ^ llp[i]; break; case TOK_B_OR: case TOK_OR: result = llp[j] | llp[i]; } // delete the variable with the shorter type -- set its type to 0 (longer types have lower "type" values) // -- unless the varaible was undefined (and has a value of 0) if (type[i] < type[j]) i = j, j = rval_idx - TOK_SIZEOF - 1; if (i != 0) type[i] = 0; // if *BOTH* variables were undefined, then allocate an actual variable for the result if (j == 0) { while (type[++j] != 0); // the caller is required to have one slot open in the array type[j] = 1; } // if the result was from a boolean operation, set the type of the remaining variable to bool, and mask to 1 byte if (op == TOK_B_EQ || op == TOK_B_NE || op == TOK_B_LT || op == TOK_B_GT || op == TOK_B_LE || op == TOK_B_GE || op == TOK_B_AND || op == TOK_B_OR) { type[j] = 4; result &= 0xff; } // store result in the remaining variable llp[j] = result; // overwrite *p with the variable token *p = j + TOK_SIZEOF + 1; // scan forward to the operator, overwrite with a no-op while (*++p == TOK_NO_OP); *p = TOK_NO_OP; // scan forward to the rval, overwrite it with a no-op -- if it existed! if (rval_idx != TOK_SIZEOF + 1) { while (*++p == TOK_NO_OP); *p = TOK_NO_OP; } }
static void METHOD_FN(process_event_list, int lush_metrics) { // fetch the event string for the sample source char* _p = METHOD_CALL(self, get_event_str); // // EVENT: Only 1 wallclock event // char* event = start_tok(_p); char name[1024]; // local buffer needed for extract_ev_threshold TMSG(_TST_CTL,"checking event spec = %s",event); // extract event threshold hpcrun_extract_ev_thresh(event, sizeof(name), name, &period, DEFAULT_THRESHOLD); // store event threshold METHOD_CALL(self, store_event, _TST_EVENT, period); TMSG(OPTIONS,"_TST period set to %ld",period); // set up file local variables for sample source control int seconds = period / 1000000; int microseconds = period % 1000000; TMSG(OPTIONS,"init timer w sample_period = %ld, seconds = %ld, usec = %ld", period, seconds, microseconds); // signal once after the given delay itimer.it_value.tv_sec = seconds; itimer.it_value.tv_usec = microseconds; // macros define whether automatic restart or not itimer.it_interval.tv_sec = AUTOMATIC_ITIMER_RESET_SECONDS(seconds); itimer.it_interval.tv_usec = AUTOMATIC_ITIMER_RESET_MICROSECONDS(microseconds); // handle metric allocation hpcrun_pre_allocate_metrics(1 + lush_metrics); int metric_id = hpcrun_new_metric(); METHOD_CALL(self, store_metric_id, _TST_EVENT, metric_id); // set metric information in metric table #ifdef USE_ELAPSED_TIME_FOR_WALLCLOCK # define sample_period 1 #else # define sample_period period #endif TMSG(_TST_CTL, "setting metric _TST, period = %ld", sample_period); hpcrun_set_metric_info_and_period(metric_id, "_TST", MetricFlags_ValFmt_Int, sample_period, metric_property_none); if (lush_metrics == 1) { int mid_idleness = hpcrun_new_metric(); lush_agents->metric_time = metric_id; lush_agents->metric_idleness = mid_idleness; hpcrun_set_metric_info_and_period(mid_idleness, "idleness (ms)", MetricFlags_ValFmt_Real, sample_period, metric_property_none); } event = next_tok(); if (more_tok()) { EMSG("MULTIPLE _TST events detected! Using first event spec: %s"); } }
void eat_plus(tokenizer_t t){ token tok = cur_tok(t); if (tok.kind != tok_plus) syntax_error(t); next_tok(t); }
int eat_int(tokenizer_t t){ token tok = cur_tok(t); if(tok.kind != tok_int) syntax_error(t); next_tok(t); return tok.ival; }
static void METHOD_FN(process_event_list, int lush_metrics) { char name[1024]; // local buffer needed for extract_ev_threshold TMSG(ITIMER_CTL, "process event list, lush_metrics = %d", lush_metrics); // fetch the event string for the sample source char* evlist = METHOD_CALL(self, get_event_str); char* event = start_tok(evlist); TMSG(ITIMER_CTL,"checking event spec = %s",event); if (hpcrun_ev_is(event, WALLCLOCK_EVENT_NAME)) { #ifdef HOST_SYSTEM_IBM_BLUEGENE use_itimer = true; the_event_name = WALLCLOCK_EVENT_NAME; the_metric_name = WALLCLOCK_METRIC_NAME; the_signal_num = ITIMER_SIGNAL; #else #ifdef ENABLE_CLOCK_CPUTIME use_cputime = true; the_event_name = CPUTIME_EVENT_NAME; the_metric_name = CPUTIME_METRIC_NAME; the_signal_num = REALTIME_SIGNAL; #else EEMSG("Event %s (%s) is not available on this system.", WALLCLOCK_EVENT_NAME, CPUTIME_EVENT_NAME); hpcrun_ssfail_unknown(event); #endif #endif } if (hpcrun_ev_is(event, REALTIME_EVENT_NAME)) { #ifdef ENABLE_CLOCK_REALTIME use_realtime = true; the_event_name = REALTIME_EVENT_NAME; the_metric_name = REALTIME_METRIC_NAME; the_signal_num = REALTIME_SIGNAL; #else EEMSG("Event %s is not available on this system.", REALTIME_EVENT_NAME); hpcrun_ssfail_unknown(event); #endif } if (hpcrun_ev_is(event, CPUTIME_EVENT_NAME)) { #ifdef ENABLE_CLOCK_CPUTIME use_cputime = true; the_event_name = CPUTIME_EVENT_NAME; the_metric_name = CPUTIME_METRIC_NAME; the_signal_num = REALTIME_SIGNAL; #else EEMSG("Event %s is not available on this system.", CPUTIME_EVENT_NAME); hpcrun_ssfail_unknown(event); #endif } if (hpcrun_ev_is(event, ITIMER_EVENT_NAME)) { use_itimer = true; the_event_name = ITIMER_EVENT_NAME; the_metric_name = ITIMER_METRIC_NAME; the_signal_num = ITIMER_SIGNAL; } if (!use_itimer && !use_realtime && !use_cputime) { // should never get here if supports_event is true hpcrun_ssfail_unknown(event); } // extract event threshold hpcrun_extract_ev_thresh(event, sizeof(name), name, &period, DEFAULT_PERIOD); // store event threshold METHOD_CALL(self, store_event, ITIMER_EVENT, period); TMSG(OPTIONS,"wallclock period set to %ld",period); // set up file local variables for sample source control int seconds = period / 1000000; int microseconds = period % 1000000; TMSG(ITIMER_CTL, "init %s sample_period = %ld, seconds = %d, usec = %d", the_event_name, period, seconds, microseconds); itval_start.it_value.tv_sec = seconds; itval_start.it_value.tv_usec = microseconds; itval_start.it_interval.tv_sec = 0; itval_start.it_interval.tv_usec = 0; itspec_start.it_value.tv_sec = seconds; itspec_start.it_value.tv_nsec = 1000 * microseconds; itspec_start.it_interval.tv_sec = 0; itspec_start.it_interval.tv_nsec = 0; // older versions of BG/P incorrectly delivered SIGALRM when // interval is zero. I (krentel) believe this is no longer // necessary, but it can't really hurt. #ifdef HOST_SYSTEM_IBM_BLUEGENE itval_start.it_interval.tv_sec = 3600; itspec_start.it_interval.tv_sec = 3600; #endif memset(&itval_stop, 0, sizeof(itval_stop)); memset(&itspec_stop, 0, sizeof(itspec_stop)); sigemptyset(&timer_mask); sigaddset(&timer_mask, the_signal_num); // handle metric allocation hpcrun_pre_allocate_metrics(1 + lush_metrics); int metric_id = hpcrun_new_metric(); METHOD_CALL(self, store_metric_id, ITIMER_EVENT, metric_id); // set metric information in metric table TMSG(ITIMER_CTL, "setting metric timer period = %ld", sample_period); hpcrun_set_metric_info_and_period(metric_id, the_metric_name, MetricFlags_ValFmt_Int, sample_period, metric_property_time); if (lush_metrics == 1) { int mid_idleness = hpcrun_new_metric(); lush_agents->metric_time = metric_id; lush_agents->metric_idleness = mid_idleness; hpcrun_set_metric_info_and_period(mid_idleness, IDLE_METRIC_NAME, MetricFlags_ValFmt_Real, sample_period, metric_property_time); } event = next_tok(); if (more_tok()) { EEMSG("Can't use multiple timer events in the same run."); hpcrun_ssfail_conflict("timer", event); } }
static NSS_STATUS fill_grent(struct group *result, struct winbindd_gr *gr, char *gr_mem, char **buffer, size_t *buflen) { fstring name; int i; char *tst; /* Group name */ if ((result->gr_name = get_static(buffer, buflen, strlen(gr->gr_name) + 1)) == NULL) { /* Out of memory */ return NSS_STATUS_TRYAGAIN; } strlcpy(result->gr_name, gr->gr_name, strlen(gr->gr_name) + 1); /* Password */ if ((result->gr_passwd = get_static(buffer, buflen, strlen(gr->gr_passwd) + 1)) == NULL) { /* Out of memory */ return NSS_STATUS_TRYAGAIN; } strlcpy(result->gr_passwd, gr->gr_passwd, strlen(gr->gr_passwd) + 1); /* gid */ result->gr_gid = gr->gr_gid; /* Group membership */ if ((gr->num_gr_mem < 0) || !gr_mem) { gr->num_gr_mem = 0; } /* this next value is a pointer to a pointer so let's align it */ /* Calculate number of extra bytes needed to align on pointer size boundry */ if ((i = (unsigned long)(*buffer) % sizeof(char*)) != 0) i = sizeof(char*) - i; if ((tst = get_static(buffer, buflen, ((gr->num_gr_mem + 1) * sizeof(char *)+i))) == NULL) { /* Out of memory */ return NSS_STATUS_TRYAGAIN; } result->gr_mem = (char **)(tst + i); if (gr->num_gr_mem == 0) { /* Group is empty */ *(result->gr_mem) = NULL; return NSS_STATUS_SUCCESS; } /* Start looking at extra data */ i = 0; while(next_tok((char **)&gr_mem, name, ",", sizeof(fstring))) { /* Allocate space for member */ if (((result->gr_mem)[i] = get_static(buffer, buflen, strlen(name) + 1)) == NULL) { /* Out of memory */ return NSS_STATUS_TRYAGAIN; } strlcpy((result->gr_mem)[i], name, strlen(name) + 1); i++; } /* Terminate list */ (result->gr_mem)[i] = NULL; return NSS_STATUS_SUCCESS; }