/*> ## Processing the input files So now we can start to process the files. Let's jump to the `main` function and see the good parts. First we get files to process and open the output file. If there are no input files, we terminate and wont overwrite an existing `README.md` file (just be save). <*/ int main(int argc, char **argv) { str_lst *files = get_list_of_files(); return_unless(files, EXIT_FAILURE, "can't read list of files"); return_unless(str_lst_count(files), EXIT_SUCCESS, "nothing to process"); FILE *out = fopen("README.md", "w"); if (!out) { str_lst_free(files); return_unless(false, EXIT_FAILURE, "can't open README.md"); } /*> Now we open each file and call the process function. The function needs to know, if the file contains MarkDown directly, or is a source code file, that only contains MarkDown in special comment blocks. We do the suffix magic to check, if it ends in `.md`. Otherwise we will assume it a source code file. <*/ for (char **cur = str_lst_begin(files); cur != str_lst_end(files); ++cur) { FILE *in = fopen(*cur, "r"); if (!in) { fclose(out); return_unless(false, EXIT_FAILURE, "can't read \"%s\"", *cur); } printf("processing \"%s\" ... ", *cur); size_t length = strlen(*cur); bool code_file = length < 3 || strcmp(*cur + length - 3, ".md"); puts(process_file(in, out, code_file) ? "ok" : "FAILED"); fclose(in); } fclose(out); str_lst_free(files); }
/*> The pointer adjustment checks both memory blocks and adjusts the other pointers of the `str_lst` structure. <*/ static bool str_lst_adjust_pointers(str_lst *sl, int capacity) { return_unless(sl, false, "no list"); return_unless(sl->begin, false, "no memory for buffer"); sl->end = sl->begin; sl->capacity = sl->begin + capacity; return true; }
void renderer::map (data::map const &map) { static int const layer = -1; for (size_t y = 0; y < array_size (win); y++) for (size_t x = 0; x < array_size (win[y]); x++) win[y][x] = L'_'; static data::glyph const space = { { { 0, 0, L'?' }, { 0, 0, L'?' } } }; static data::glyph const player = { { { 0, 0, L'@' }, { 0, 0, L'@' } } }; int const playerx = (W - !(W % 2)) / 2; int const playery = (H - !(H % 2)) / 2; int const offx = (map.w - W) / 2; int const offy = (map.h - H) / 2; return_unless (!data::glyphs.empty ()); for (int y = 0; y < H; y++) { int const mapy = y + map.y + offy; if (!map.rows.has (mapy)) continue; auto const &row = map.rows[mapy]; for (int x = 0; x < W; x++) { int const mapx = x + map.x + offx; if (!row.has (mapx)) continue; data::map::cell const &cell = row[mapx]; u32 const face = select_face (cell.face, layer); data::glyph const *glyph; int const winy = y * 1; int const winx = x * 2; if (x == playerx && y == playery) glyph = &player; else if (face && face < data::glyphs.size ()) // TODO: warn about face >= size glyph = &data::glyphs[face]; else glyph = &space; return_unless (winy >= 0); return_unless (winx >= 0); return_unless (winy < int (array_size ( win))); return_unless (winx < int (array_size (*win))); win[winy][winx + 0] = (*glyph)[0].text; win[winy][winx + 1] = (*glyph)[1].text; } } }
/*> In the consuming function we do the heavy lifting, if the capacity is exceeded. Then we double the capacity until we grow so big, that we switch to a linear growth. We reallocate the buffer for the new size, adjust the pointers and add the element. If we can't reallocate the buffer, nothing will be changed. <*/ bool str_lst_add_and_consume(str_lst *sl, char *str) { return_unless(sl, false, "no list"); if (sl->end == sl->capacity) { int old_count = sl->capacity - sl->begin; int new_count = old_count + MIN(old_count, 1024); void *newBuffer = realloc(sl->begin, new_count * sizeof(char **)); return_unless(newBuffer, false, "can't expand buffer"); sl->begin = newBuffer; sl->end = sl->begin + old_count; sl->capacity = sl->begin + new_count; } *sl->end++ = str; return true; }
void inventory_manager::upditem (u08 flags, u32 location, data::item const &item) { data::item *current = get (item.tag); return_unless (current != NULL); if (flags & UPD_LOCATION) { data::item save = *current; delitem ({ item.tag }); current = &merge (inventories[location], save); } if (flags & UPD_ANIM) current->anim = item.anim; if (flags & UPD_ANIMSPEED) current->animspeed = item.animspeed; if (flags & UPD_FACE) current->face = item.face; if (flags & UPD_FLAGS) current->flags = item.flags; if (flags & UPD_NROF) current->nrof = item.nrof; if (flags & UPD_WEIGHT) current->weight = item.weight; if (flags & UPD_NAME) { current->singular = item.singular; current->plural = item.plural; } update (); }
static void render_rusage (ndk::window &widget, int row = 8) { static timeval start; ndk::pen pen (widget); return_unless (pen.move (2, row)); if (!start.tv_sec) gettimeofday (&start, NULL); timeval now, diff; gettimeofday (&now, NULL); timersub (&now, &start, &diff); struct rusage usage; getrusage (RUSAGE_SELF, &usage); pen.write ( "[CPU: %ld.%02lds" , usage.ru_utime.tv_sec + usage.ru_stime.tv_sec , (usage.ru_utime.tv_usec + usage.ru_stime.tv_usec) / 10000 ); pen.write ( " Cells: %d (%dKiB)" , data::cell_count , data::cell_count * sizeof (data::map::cell) / 1024 ); pen.write ( " RES: %ldKiB" , usage.ru_maxrss ); pen.write ( " RT: %ld:%02ld]" , diff.tv_sec / 60 , diff.tv_sec % 60 ); }
char *str_cons(int count, ...) { return_unless(count >= 0, empty, "count must not be negative"); if (!count) { return empty; } va_list args1; va_list args2; va_start(args1, count); va_copy(args2, args1); /*> The calculation of the length is straight forward. We only have to watch out for `NULL` strings, that will be silently ignored. <*/ size_t length = 0; for (int i = count; i; --i) { const char *current = va_arg(args1, const char *); if (current) length += strlen(current); } va_end(args1); /*> The result buffer must be one byte bigger to store the terminating null byte. <*/ char *result = malloc(length + 1); /*> The `copy_args` function may throw an error. We put it in a different function, so we can free the second argument list, even, if an error is raised. <*/ copy_args(result, count, args2); va_end(args2); return result ? : empty; }
gc_node *find_node(void *ptr) { return_unless(NULL, ptr); for (gc_node *cur = all_nodes; cur; cur = cur->next) { if (cur->ptr == ptr) return cur; } return NULL; }
void *rc_false() { static void *_singleton = NULL; if (!_singleton) { _singleton = rc_alloc(0, rc_type_false, NULL); return_unless(NULL, _singleton); } return rc_retain(_singleton); }
str_lst *str_lst_create(int min_capacity) { int capacity = MAX(min_capacity, 8); str_lst *sl = malloc(sizeof(str_lst)); return_unless(sl, NULL, "no memory for struct"); sl->begin = malloc(sizeof(char **) * capacity); if (!str_lst_adjust_pointers(sl, capacity)) { free(sl); sl = NULL; } return sl; }
void *rc_alloc(size_t size, rc_type type, dealloc_fn *dealloc) { const size_t data_size = padded_rc_size(); void *result = NULL; if (size <= SIZE_MAX - data_size) { size += data_size; result = malloc(size); return_unless(NULL, result); struct rc *r = result; r->dealloc = dealloc; r->count = 1; r->type = type; result += data_size; } else { log_error("can't alloc %lu bytes (too big)", size); } return result; }
static bool mark_decendents(void *ptr) { return_unless(false, ptr); bool something_changed = false; for (gc_dispatcher *dispatcher = dispatchers; dispatcher; dispatcher = dispatcher->next) { if (dispatcher->is_matching(ptr)) { int count = dispatcher->number_of_references(ptr); for (int i = 0; i < count; ++i) { void *ref = dispatcher->reference_number(ptr, i); if (ref) { gc_node *ref_node = find_node(ref); if (ref_node && ref_node->marked == UNMARKED) { ref_node->marked = MARKED; something_changed = true; } } } break; } } return something_changed; }
void map_widget::draw () { frame::draw (); if (!map) return; static int const layer = -1; int const W = this->width () / 2; int const H = this->height (); ndk::pen pen (*this); static data::glyph const space = { { { 0, 0, L' ' }, { 0, 0, L' ' } } }; #if HIGHLIGHT_PLAYER static data::glyph const player = { { { 0, 0, L'@' }, { 13, 13, L'@' } } }; #endif #if HIGHLIGHT_PLAYER int const playerx = (W - !(W % 2)) / 2; int const playery = (H - !(H % 2)) / 2; #endif int const offx = (map->w - W) / 2; int const offy = (map->h - H) / 2; return_unless (!data::glyphs.empty ()); for (int y = 1; y < H - 1; y++) { int const mapy = y + map->y + offy; if (!map->rows.has (mapy)) continue; auto const &row = map->rows[mapy]; for (int x = 1; x < W - 1; x++) { int const mapx = x + map->x + offx; if (!row.has (mapx)) continue; data::map::cell const &cell = row[mapx]; u32 const face = select_face (cell.face, layer); data::glyph const *glyph; int const winy = y * 1; int const winx = x * 2; #if HIGHLIGHT_PLAYER if (x == playerx && y == playery) glyph = &player; #else if (0) ; #endif else if (face && face < data::glyphs.size ()) // TODO: warn about face >= size glyph = &data::glyphs[face]; else glyph = &space; return_unless (winy >= 0); return_unless (winx >= 0); return_unless (winy < H); return_unless (winx < W * 2); return_unless (pen.move (winx, winy)); write (pen, *glyph, cell.darkness); } } #if HIGHLIGHT_PLAYER // 19:15 < n0nsense> pippijn: kannst du nethack-mäßig noch den cursor auf den player setzen? if (active ()) { pen.move (playerx, playery); ndk::app->cursor_on (); } else ndk::app->cursor_off (); #endif if (getenv ("DCLIENT_ONESHOT")) { delete ndk::app; exit (0); } pen.set_color ({ }); // reset }
void stats_widget::draw () { frame::draw (); if (!stats) return; ndk::pen pen (*this); int const margin = 2; return_unless (pen.move (margin - 1, 1)); pen.write (stats->s_range); return_unless (pen.move (margin, 2)); pen.write (stats->s_title); return_unless (pen.move (margin, 3)); if (stats->s_exp64) pen.write ("Exp: %'ld", stats->s_exp64); else if (stats->s_exp) pen.write ("Exp: %d", stats->s_exp); else pen.write ("Exp: 0"); int row = 4; { int const shift = 12; int col = 0; return_unless (pen.move (margin + shift * col++, row)); pen.write ("HP: %d/%d", stats->s_hp, stats->s_maxhp); return_unless (pen.move (margin + shift * col++, row)); pen.write ("SP: %d/%d", stats->s_sp, stats->s_maxsp); return_unless (pen.move (margin + shift * col++, row)); pen.write ("GP: %d/%d", stats->s_grace, stats->s_maxgrace); return_unless (pen.move (margin + shift * col++, row)); pen.write ("Food: %d/%d", stats->s_food, 999); } row++; { int const shift = 12; int col = 0; return_unless (pen.move (margin + shift * col++, row)); pen.write ("WC: %d", stats->s_wc); return_unless (pen.move (margin + shift * col++, row)); pen.write ("AC: %d", stats->s_ac); return_unless (pen.move (margin + shift * col++, row)); pen.write ("Dam: %d", stats->s_dam); return_unless (pen.move (margin + shift * col++, row)); pen.write ("Speed: %d", stats->s_speed); return_unless (pen.move (margin + shift * col++, row)); pen.write ("Weapon speed: %d", stats->s_weap_sp); } row++; { int const shift = 8; int col = 0; return_unless (pen.move (margin + shift * col++, row)); pen.write ("Str: %d", stats->s_str); return_unless (pen.move (margin + shift * col++, row)); pen.write ("Dex: %d", stats->s_dex); return_unless (pen.move (margin + shift * col++, row)); pen.write ("Con: %d", stats->s_con); return_unless (pen.move (margin + shift * col++, row)); pen.write ("Int: %d", stats->s_int); return_unless (pen.move (margin + shift * col++, row)); pen.write ("Wis: %d", stats->s_wis); return_unless (pen.move (margin + shift * col++, row)); pen.write ("Pow: %d", stats->s_pow); return_unless (pen.move (margin + shift * col++, row)); pen.write ("Cha: %d", stats->s_cha); } render_rusage (*this); }
/*> The execution of the buffer is trivial, but can still fail. <*/ static bool execute_buffer(char *buffer) { return_unless(buffer, false, "no buffer"); return_unless(!system(buffer), false, "can't execute '%s'", buffer); return true; }
rc_type rc_get_type(void *rc) { return_unless(rc_type_unknown, rc); struct rc *r = rc - padded_rc_size(); return r->type; }