static int read_scores (const char *filename, struct score_entry **scores, ptrdiff_t *count, ptrdiff_t *alloc) { int readval = -1; ptrdiff_t scorecount = 0; ptrdiff_t cursize = 0; struct score_entry *ret = 0; struct score_entry entry; FILE *f = fopen (filename, "r"); int retval = -1; if (!f) return -1; while ((readval = read_score (f, &entry)) == 0) if (push_score (&ret, &scorecount, &cursize, &entry) < 0) return -1; if (readval > 0 && fclose (f) == 0) { *count = scorecount; *alloc = cursize; *scores = ret; retval = 0; } return retval; }
static int read_scores (const char *filename, struct score_entry **scores, ptrdiff_t *count, ptrdiff_t *alloc) { char *p, *filedata; ptrdiff_t filesize, nread; struct stat st; FILE *f = fopen (filename, "r"); if (!f) return -1; if (fstat (fileno (f), &st) != 0) return -1; if (! (0 <= st.st_size && st.st_size < min (PTRDIFF_MAX, SIZE_MAX))) { errno = EOVERFLOW; return -1; } filesize = st.st_size; filedata = malloc (filesize + 1); if (! filedata) return -1; nread = fread (filedata, 1, filesize + 1, f); if (filesize < nread) { errno = 0; return -1; } if (nread < filesize) filesize = nread; if (ferror (f) || fclose (f) != 0) return -1; filedata[filesize] = 0; if (strlen (filedata) != filesize) { errno = 0; return -1; } *scores = 0; *count = *alloc = 0; for (p = filedata; p < filedata + filesize; ) { struct score_entry entry; p = read_score (p, &entry); if (!p) { errno = 0; return -1; } if (push_score (scores, count, alloc, &entry) < 0) return -1; } return 0; }
int main (int argc, char **argv) { int c; bool running_suid; void *lockstate; char *scorefile; char *nl; const char *prefix, *user_prefix = NULL; struct stat buf; struct score_entry *scores; struct score_entry newscore; bool reverse = false; ptrdiff_t scorecount, scorealloc; ptrdiff_t max_scores = MAX_SCORES; srand (time (0)); while ((c = getopt (argc, argv, "hrm:d:")) != -1) switch (c) { case 'h': usage (EXIT_SUCCESS); break; case 'd': user_prefix = optarg; break; case 'r': reverse = 1; break; case 'm': { intmax_t m = strtoimax (optarg, 0, 10); if (m < 0) usage (EXIT_FAILURE); max_scores = min (m, MAX_SCORES); } break; default: usage (EXIT_FAILURE); } if (argc - optind != 3) usage (EXIT_FAILURE); running_suid = (getuid () != geteuid ()); prefix = get_prefix (running_suid, user_prefix); scorefile = malloc (strlen (prefix) + strlen (argv[optind]) + 2); if (!scorefile) lose_syserr ("Couldn't allocate score file"); strcpy (scorefile, prefix); strcat (scorefile, "/"); strcat (scorefile, argv[optind]); newscore.score = strtoimax (argv[optind + 1], 0, 10); newscore.data = argv[optind + 2]; if (strlen (newscore.data) > MAX_DATA_LEN) newscore.data[MAX_DATA_LEN] = '\0'; nl = strchr (newscore.data, '\n'); if (nl) *nl = '\0'; newscore.username = get_user_id (); if (! newscore.username) lose_syserr ("Couldn't determine user id"); if (stat (scorefile, &buf) < 0) lose_syserr ("Failed to access scores file"); if (lock_file (scorefile, &lockstate) < 0) lose_syserr ("Failed to lock scores file"); if (read_scores (scorefile, &scores, &scorecount, &scorealloc) < 0) { unlock_file (scorefile, lockstate); lose_syserr ("Failed to read scores file"); } if (push_score (&scores, &scorecount, &scorealloc, &newscore) < 0) { unlock_file (scorefile, lockstate); lose_syserr ("Failed to add score"); } sort_scores (scores, scorecount, reverse); /* Limit the number of scores. If we're using reverse sorting, then also increment the beginning of the array, to skip over the *smallest* scores. Otherwise, just decrementing the number of scores suffices, since the smallest is at the end. */ if (scorecount > max_scores) { if (reverse) scores += scorecount - max_scores; scorecount = max_scores; } if (write_scores (scorefile, scores, scorecount) < 0) { unlock_file (scorefile, lockstate); lose_syserr ("Failed to write scores file"); } if (unlock_file (scorefile, lockstate) < 0) lose_syserr ("Failed to unlock scores file"); exit (EXIT_SUCCESS); }
void test_scored_subexpression() { // Create a database with the default options. auto db = grnxx::open_db(""); // Create a table with the default options. auto table = db->create_table("Table"); constexpr size_t NUM_ROWS = 1 << 16; // Generate random values. grnxx::Array<grnxx::Float> float_values; grnxx::Array<grnxx::Int> ref_values; float_values.resize(NUM_ROWS); ref_values.resize(NUM_ROWS); for (size_t i = 0; i < NUM_ROWS; ++i) { float_values[i] = grnxx::Float(1.0 * rng() / rng.max()); // ref_values[i] = mersenne_twister() % NUM_ROWS; ref_values[i] = grnxx::Int(0); } // Create columns for Float and Int values. auto float_column = table->create_column("Float", GRNXX_FLOAT); grnxx::ColumnOptions options; options.reference_table_name = "Table"; auto ref_column = table->create_column("Ref", GRNXX_INT, options); // Store generated values into columns. for (size_t i = 0; i < NUM_ROWS; ++i) { grnxx::Int row_id = table->insert_row(); assert(row_id.match(grnxx::Int(i))); float_column->set(row_id, float_values[i]); } for (size_t i = 0; i < NUM_ROWS; ++i) { ref_column->set(grnxx::Int(i), ref_values[i]); } // Generate a list of records. grnxx::Array<grnxx::Record> records; auto cursor = table->create_cursor(); assert(cursor->read_all(&records) == table->num_rows()); // Set scores (Float). auto builder = grnxx::ExpressionBuilder::create(table); builder->push_column("Float"); auto expression = builder->release(); expression->adjust(&records); // Test an expression (Ref.(_score > 0.5)). builder->push_column("Ref"); builder->begin_subexpression(); builder->push_score(); builder->push_constant(grnxx::Float(0.5)); builder->push_operator(GRNXX_GREATER); builder->end_subexpression(); expression = builder->release(); expression->filter(&records); size_t count = 0; for (size_t i = 0; i < NUM_ROWS; ++i) { if (float_values[i].raw() > 0.5) { assert(records[count].row_id.match(grnxx::Int(i))); ++count; } } assert(records.size() == count); }
int main (int argc, char **argv) { int c; bool running_suid, running_sgid; void *lockstate; char *scorefile; char *end, *nl, *user, *data; const char *prefix, *user_prefix = NULL; struct score_entry *scores; struct score_entry newscore; bool reverse = false; ptrdiff_t scorecount, scorealloc; ptrdiff_t max_scores = MAX_SCORES; srand (time (0)); while ((c = getopt (argc, argv, "hrm:d:")) != -1) switch (c) { case 'h': usage (EXIT_SUCCESS); break; case 'd': user_prefix = optarg; break; case 'r': reverse = 1; break; case 'm': { intmax_t m = strtoimax (optarg, &end, 10); if (optarg == end || *end || m < 0) usage (EXIT_FAILURE); max_scores = min (m, MAX_SCORES); } break; default: usage (EXIT_FAILURE); } if (argc - optind != 3) usage (EXIT_FAILURE); running_suid = (getuid () != geteuid ()); running_sgid = (getgid () != getegid ()); if (running_suid && running_sgid) lose ("This program can run either suid or sgid, but not both."); prefix = get_prefix (running_suid || running_sgid, user_prefix); scorefile = malloc (strlen (prefix) + strlen (argv[optind]) + 2); if (!scorefile) lose_syserr ("Couldn't allocate score file"); char *z = stpcpy (scorefile, prefix); *z++ = '/'; strcpy (z, argv[optind]); newscore.score = normalize_integer (argv[optind + 1]); if (! newscore.score) { fprintf (stderr, "%s: Invalid score\n", argv[optind + 1]); return EXIT_FAILURE; } user = get_user_id (); if (! user) lose_syserr ("Couldn't determine user id"); data = argv[optind + 2]; if (strlen (data) > MAX_DATA_LEN) data[MAX_DATA_LEN] = '\0'; nl = strchr (data, '\n'); if (nl) *nl = '\0'; newscore.user_data = malloc (strlen (user) + 1 + strlen (data) + 1); if (! newscore.user_data || sprintf (newscore.user_data, "%s %s", user, data) < 0) lose_syserr ("Memory exhausted"); if (lock_file (scorefile, &lockstate) < 0) lose_syserr ("Failed to lock scores file"); if (read_scores (scorefile, &scores, &scorecount, &scorealloc) < 0) { unlock_file (scorefile, lockstate); lose_syserr ("Failed to read scores file"); } if (push_score (&scores, &scorecount, &scorealloc, &newscore) < 0) { unlock_file (scorefile, lockstate); lose_syserr ("Failed to add score"); } sort_scores (scores, scorecount, reverse); /* Limit the number of scores. If we're using reverse sorting, then also increment the beginning of the array, to skip over the *smallest* scores. Otherwise, just decrementing the number of scores suffices, since the smallest is at the end. */ if (scorecount > max_scores) { if (reverse) scores += scorecount - max_scores; scorecount = max_scores; } if (write_scores (scorefile, running_sgid ? 0664 : 0644, scores, scorecount) < 0) { unlock_file (scorefile, lockstate); lose_syserr ("Failed to write scores file"); } if (unlock_file (scorefile, lockstate) < 0) lose_syserr ("Failed to unlock scores file"); exit (EXIT_SUCCESS); }