/* Function nano_realloc * Implement realloc by malloc + memcpy */ void * nano_realloc(RARG void * ptr, malloc_size_t size) { void * mem; chunk * p_to_realloc; if (ptr == NULL) return nano_malloc(RCALL size); if (size == 0) { nano_free(RCALL ptr); return NULL; } /* TODO: There is chance to shrink the chunk if newly requested * size is much small */ if (nano_malloc_usable_size(RCALL ptr) >= size) return ptr; mem = nano_malloc(RCALL size); if (mem != NULL) { memcpy(mem, ptr, size); nano_free(RCALL ptr); } return mem; }
/* * Initialize a graphics window. */ void nanoglk_wingraphics_init(winid_t win) { win->data = nano_malloc(sizeof(struct graphics)); struct graphics *g = (struct graphics*)win->data; g->bg = nanoglk_buffer_font[style_Normal]->bg; // To have one background. nanoglk_wingraphics_clear(win); }
/* * Create a file reference with a given name, given flags, and a given * rock. Called by all other functions, which return a new file * reference. */ frefid_t create_by_name(glui32 usage, char *name, glui32 rock) { frefid_t fref = (frefid_t)nano_malloc(sizeof(struct glk_fileref_struct)); fref->usage = usage; fref->rock = rock; fref->name = strdup(name); ADD(fref); return fref; }
/* Function nano_memalign * Allocate memory block aligned at specific boundary. * align: required alignment. Must be power of 2. Return NULL * if not power of 2. Undefined behavior is bigger than * pointer value range. * s: required size. * Return: allocated memory pointer aligned to align * Algorithm: Malloc a big enough block, padding pointer to aligned * address, then truncate and free the tail if too big. * Record the offset of align pointer and original pointer * in the padding area. */ void * nano_memalign(RARG size_t align, size_t s) { chunk * chunk_p; malloc_size_t size_allocated, offset, ma_size, size_with_padding; char * allocated, * aligned_p; /* Return NULL if align isn't power of 2 */ if ((align & (align-1)) != 0) return NULL; align = MAX(align, MALLOC_ALIGN); ma_size = ALIGN_TO(MAX(s, MALLOC_MINSIZE), CHUNK_ALIGN); size_with_padding = ma_size + align - MALLOC_ALIGN; allocated = nano_malloc(RCALL size_with_padding); if (allocated == NULL) return NULL; chunk_p = get_chunk_from_ptr(allocated); aligned_p = (char *)ALIGN_TO( (unsigned long)((char *)chunk_p + CHUNK_OFFSET), (unsigned long)align); offset = aligned_p - ((char *)chunk_p + CHUNK_OFFSET); if (offset) { if (offset >= MALLOC_MINCHUNK) { /* Padding is too large, free it */ chunk * front_chunk = chunk_p; chunk_p = (chunk *)((char *)chunk_p + offset); chunk_p->size = front_chunk->size - offset; front_chunk->size = offset; nano_free(RCALL (char *)front_chunk + CHUNK_OFFSET); } else { /* Padding is used. Need to set a jump offset for aligned pointer * to get back to chunk head */ assert(offset >= sizeof(int)); *(int *)((char *)chunk_p + offset) = -offset; } } size_allocated = chunk_p->size; if ((char *)chunk_p + size_allocated > (aligned_p + ma_size + MALLOC_MINCHUNK)) { /* allocated much more than what's required for padding, free * tail part */ chunk * tail_chunk = (chunk *)(aligned_p + ma_size); chunk_p->size = aligned_p + ma_size - (char *)chunk_p; tail_chunk->size = size_allocated - chunk_p->size; nano_free(RCALL (char *)tail_chunk + CHUNK_OFFSET); } return aligned_p; }
/* * Read a Unicode line from a window. Called when the respective event * has been requested and is read. * * - win the window the user must input the text * - buf the buffer to store the input; may already contain text; *not* * 0-terminated * - maxlen the lenght of the buffer * - initlen the lenght of the initial text */ glui32 nanoglk_window_get_line_uni(winid_t win, glui32 *buf, glui32 maxlen, glui32 initlen) { nano_trace("nanoglk_window_get_line_uni(%p, %p, %d, %d)", win, buf, maxlen, initlen); // Convert glui32* to Uint16* ... Uint16 *text = (Uint16*)nano_malloc((maxlen + 1) * sizeof(Uint16*)); int i; for(i = 0; i < initlen; i++) text[i] = buf[i]; text[initlen] = 0; // ... read Uint16* ... int len = get_line16(win, text, maxlen, 0xffff); // ... and convert it back to glui32*. for(i = 0; text[i]; i++) buf[i] = text[i]; return len; }
/* Function nano_calloc * Implement calloc simply by calling malloc and set zero */ void * nano_calloc(RARG malloc_size_t n, malloc_size_t elem) { void * mem = nano_malloc(RCALL n * elem); if (mem != NULL) memset(mem, 0, n * elem); return mem; }
frefid_t glk_fileref_create_by_prompt(glui32 usage, glui32 fmode, glui32 rock) { int must_exist = 0, warn_replace = 0, warn_modify = 0, warn_append = 0; char title8[128]; switch(fmode) { case filemode_Read: strcpy(title8, "Read "); must_exist = 1; break; case filemode_Write: strcpy(title8, "Write (or replace) "); warn_replace = 1; break; case filemode_ReadWrite: strcpy(title8, "Write (or modify) "); warn_modify = 1; break; case filemode_WriteAppend: strcpy(title8, "Write (or append to) "); warn_append = 1; break; } switch(usage & fileusage_TypeMask) { case fileusage_Data: strcat(title8, "data"); break; case fileusage_SavedGame: strcat(title8, "saved game"); break; case fileusage_Transcript: strcat(title8, "transscript"); break; case fileusage_InputRecord: strcat(title8, "input record file"); break; } char cwd[FILENAME_MAX + 1]; getcwd(cwd, FILENAME_MAX + 1); Uint16 *title16 = strdup16fromutf8(title8); char *name = nano_input_file(cwd, title16, nanoglk_surface, nanoglk_ui_font->font, nanoglk_ui_font->text_height, nanoglk_ui_font->fg, nanoglk_ui_font->bg, nanoglk_ui_list_i_fg_color, nanoglk_ui_list_i_bg_color, nanoglk_ui_list_a_fg_color, nanoglk_ui_list_a_bg_color, nanoglk_ui_input_fg_color, nanoglk_ui_input_bg_color, (nanoglk_screen_width - nanoglk_filesel_width) / 2, (nanoglk_screen_height - nanoglk_filesel_height) / 2, nanoglk_filesel_width, nanoglk_filesel_height, must_exist, warn_replace, warn_modify, warn_append); free(title16); // TODO change directory depending on the result? frefid_t fref = NULL; if(name) { fref = (frefid_t)nano_malloc(sizeof(struct glk_fileref_struct)); fref->usage = usage; fref->rock = rock; fref->name = name; ADD(fref); } nanoglk_log("glk_fileref_create_by_prompt(%d, %d, %d) => %p", usage, fmode, rock, fref); if(fref) fref->disprock = nanoglk_call_regi_obj(fref, gidisp_Class_Fileref); return fref; }
winid_t glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype, glui32 rock) { winid_t win = (winid_t)nano_malloc(sizeof(struct glk_window_struct)); nanoglk_log("glk_window_open(%p, %d, %d, %d, %d) => %p", split, method, size, wintype, rock, win); win->stream = nanoglk_stream_new(streamtype_Window, 0); win->stream->x.window = win; win->method = method; win->size = size; win->wintype = wintype; win->rock = rock; win->left = win->right = NULL; win->cur_styl = style_Normal; // Colors for styles. See comment at the beginning of this file. int i; switch(win->wintype) { case wintype_TextBuffer: for(i = 0; i < style_NUMSTYLES; i++) { win->fg[i] = next_buffer_fg[i]; win->bg[i] = next_buffer_bg[i]; } break; case wintype_TextGrid: for(i = 0; i < style_NUMSTYLES; i++) { win->fg[i] = next_grid_fg[i]; win->bg[i] = next_grid_bg[i]; } break; } winid_t pair; if(split == NULL) { // parent is NULL => new root window nano_failunless(root == NULL, "two root windows"); win->parent = NULL; win->area.x = win->area.y = 0; win->area.w = nanoglk_surface->w; win->area.h = nanoglk_surface->h; root = win; pair = NULL; // no pair window created nano_trace("[glk_window_open] root %p: (%d, %d, %d x %d)", win, win->area.x, win->area.y, win->area.w, win->area.h); } else { // Create a pair window. The old parent "split" becomes the left // child, the newly created becomes the right child. (See also // comment on these members in "nanoglk.h".) pair = (winid_t)nano_malloc(sizeof(struct glk_window_struct)); pair->stream = NULL; pair->wintype = wintype_Pair; pair->rock = 0; pair->left = split; pair->right = win; pair->area = split->area; pair->method = split->method; pair->size = split->size; pair->parent = split->parent; // Rearrange tree: "pair" takes over the place of "split". if(pair->parent == NULL) root = pair; else { if(pair->parent->left == split) pair->parent->left = pair; else if(pair->parent->right == split) pair->parent->right = pair; else nano_fail("split not child of parent?"); } split->parent = win->parent = pair; pair->left = split; pair->right = win; win->area = split->area; SDL_Rect split_area, win_area; window_calc_sizes(pair, &split_area, &win_area); window_resize(split, &split_area); win->area = win_area; window_draw_border(pair); nano_trace("split %p: (%d, %d, %d x %d)", split, split->area.x, split->area.y, split->area.w, split->area.h); nano_trace("new win %p: (%d, %d, %d x %d)", win, win->area.x, win->area.y, win->area.w, win->area.h); } // Further initialization depending on the type. switch(win->wintype) { case wintype_TextBuffer: nanoglk_wintextbuffer_init(win); break; case wintype_TextGrid: nanoglk_wintextgrid_init(win); break; case wintype_Graphics: nanoglk_wingraphics_init(win); break; } if(pair) pair->disprock = nanoglk_call_regi_obj(pair, gidisp_Class_Window); win->stream->disprock = nanoglk_call_regi_obj(win->stream, gidisp_Class_Stream); win->disprock = nanoglk_call_regi_obj(win, gidisp_Class_Window); return win; }