00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #ifndef ENVISION_ENV_STDIO_INTERFACE_C_DEFINED
00039 #define ENVISION_ENV_STDIO_INTERFACE_C_DEFINED
00040
00041 #include "Envision/env_stdio_interface.h"
00042
00043 #include "Envision/env_alloc.h"
00044 #include "Envision/env_image.h"
00045 #include "Envision/env_log.h"
00046
00047 #include <ctype.h>
00048 #include <errno.h>
00049 #include <stdarg.h>
00050 #include <stdio.h>
00051 #include <stdlib.h>
00052 #include <string.h>
00053
00054
00055 static void lfatal(const char *msg, ...)
00056 __attribute__((format(__printf__,1,2)));
00057
00058 static void lfatal(const char *msg, ...)
00059 {
00060 va_list args;
00061 va_start(args, msg);
00062
00063 vfprintf(stderr, msg, args);
00064
00065 va_end(args);
00066
00067 fprintf(stderr, "\n");
00068 fflush(stderr);
00069
00070 abort();
00071 }
00072
00073
00074 static void div2(const env_size_t numer, const env_size_t denom,
00075 const env_size_t ndigits,
00076 env_size_t* const whole, env_size_t* const fract)
00077 {
00078 *whole = numer / denom;
00079 *fract = 0;
00080 env_size_t rem = numer - (*whole * denom);
00081 for (env_size_t i = 0; i < ndigits; ++i)
00082 {
00083 rem *= 10;
00084 const env_size_t newwhole = rem / denom;
00085 ENV_ASSERT(newwhole < 10);
00086 rem = rem - (newwhole * denom);
00087 *fract *= 10;
00088 *fract += newwhole;
00089 }
00090 }
00091
00092
00093 void env_stdio_assert_handler(const char* what, int custom_msg,
00094 const char* where, int line_no)
00095 {
00096 if (custom_msg)
00097 fprintf(stderr, "Assertion failed (%s:%d):\n\t%s\n\n",
00098 where, line_no, what);
00099 else
00100 fprintf(stderr, "Assertion failed (%s:%d):\n\texpected '%s'\n\n",
00101 where, line_no, what);
00102 abort();
00103 }
00104
00105
00106 void env_stdio_print_alloc_stats(const struct env_alloc_stats* p,
00107 const env_size_t block_size)
00108 {
00109 env_size_t kiB_block_size_whole, kiB_block_size_fract;
00110 div2(block_size, 1024, 2,
00111 &kiB_block_size_whole, &kiB_block_size_fract);
00112
00113 ENV_ASSERT(block_size > 0);
00114
00115 env_size_t n_cache_blocks = 0;
00116
00117 for (env_size_t i = 0; i < p->ncache_used; ++i)
00118 {
00119 const env_size_t nb =
00120 (p->cache[i].num_allocations
00121 * p->cache[i].alloc_size);
00122
00123 n_cache_blocks += p->cache[i].num_allocations;
00124
00125 env_size_t kiB_alloc_whole, kiB_alloc_fract;
00126 div2(nb, 1024, 2,
00127 &kiB_alloc_whole, &kiB_alloc_fract);
00128
00129 env_size_t kiB_alloc_size_whole, kiB_alloc_size_fract;
00130 div2(p->cache[i].alloc_size, 1024, 4,
00131 &kiB_alloc_size_whole, &kiB_alloc_size_fract);
00132
00133 env_size_t alloc_percent_whole, alloc_percent_fract;
00134 div2(nb*100, p->bytes_allocated, 2,
00135 &alloc_percent_whole, &alloc_percent_fract);
00136
00137 env_size_t block_ratio_whole, block_ratio_fract;
00138 char symbol;
00139
00140 if (p->cache[i].alloc_size - p->overhead >= block_size
00141 || p->cache[i].alloc_size - p->overhead <= 1)
00142 {
00143 div2(p->cache[i].alloc_size - p->overhead,
00144 block_size, 1,
00145 &block_ratio_whole, &block_ratio_fract);
00146 symbol = '*';
00147 }
00148 else
00149 {
00150 div2(block_size,
00151 p->cache[i].alloc_size - p->overhead, 1,
00152 &block_ratio_whole, &block_ratio_fract);
00153 symbol = '/';
00154 }
00155
00156 fprintf(stderr,
00157 "memstats: cache[%02lu/%02lu]: "
00158 "%5lu.%02lukiB (%3lu.%02lu%%) "
00159 "in %4lu allocations "
00160 "(%2lu active) of %5lu.%04lukiB"
00161 " (%lu.%02lukiB %c %5lu.%01lu + %2luB)\n",
00162 i, ENV_NCACHE,
00163 kiB_alloc_whole, kiB_alloc_fract,
00164 alloc_percent_whole, alloc_percent_fract,
00165 p->cache[i].num_allocations,
00166 p->cache[i].num_active,
00167 kiB_alloc_size_whole, kiB_alloc_size_fract,
00168 kiB_block_size_whole, kiB_block_size_fract,
00169 (int) symbol,
00170 block_ratio_whole, block_ratio_fract,
00171 p->overhead);
00172 }
00173
00174 env_size_t kiB_alloc_whole, kiB_alloc_fract;
00175 div2(p->bytes_allocated, 1024, 2,
00176 &kiB_alloc_whole, &kiB_alloc_fract);
00177
00178 env_size_t n_blocks_whole, n_blocks_fract;
00179 div2(p->bytes_allocated, block_size, 1,
00180 &n_blocks_whole, &n_blocks_fract);
00181
00182 fprintf(stderr,
00183 "memstats: =====[TOTAL]: "
00184 "%5lu.%02lukiB (100.00%%) "
00185 "in %4lu allocations "
00186 "(%2lu active) ================"
00187 " (%lu.%02lukiB * %5lu.%01lu )\n",
00188 kiB_alloc_whole, kiB_alloc_fract,
00189 n_cache_blocks,
00190 p->nallocations_current,
00191 kiB_block_size_whole, kiB_block_size_fract,
00192 n_blocks_whole, n_blocks_fract);
00193
00194 fprintf(stderr,
00195 "memstats: %lu/%lu cache table entries in use\n",
00196 p->ncache_used, ENV_NCACHE);
00197
00198 fprintf(stderr,
00199 "memstats: block alignment: %lu bytes\n", p->nalign);
00200
00201 fprintf(stderr,
00202 "memstats: all-time: %llukiB in %lu requested allocations\n",
00203 p->nbytes_alltime/1024, p->nallocations_alltime);
00204
00205 fprintf(stderr,
00206 "memstats: current: %lukiB in %lu active allocations\n",
00207 (unsigned long)(p->nbytes_current/1024),
00208 p->nallocations_current);
00209 }
00210
00211
00212 struct env_rgb_pixel* env_stdio_parse_rgb(const char* fname,
00213 struct env_dims* outdims)
00214 {
00215 FILE* f = fopen(fname, "rb");
00216
00217 if (f == 0)
00218 lfatal("Couldn't open file '%s' for reading.", fname);
00219
00220 int c = getc(f);
00221 if (c != 'P')
00222 lfatal("Missing magic number in pnm file '%s'"
00223 "(got '%c' [%d], expected '%c' [%d]).",
00224 fname, c, c, 'P', 'P');
00225
00226 int mode = -1;
00227 int ret = fscanf(f, "%d", &mode);
00228 if (ret > 0 && mode != 6)
00229 lfatal("Wrong pnm mode (got 'P%d', expected 'P6')",
00230 mode);
00231
00232 while (1)
00233 {
00234 const int c = getc(f);
00235 if (!isspace(c))
00236 { ungetc(c, f); break; }
00237 }
00238
00239
00240
00241
00242 while (1)
00243 {
00244 const int c = getc(f);
00245 if (c != '#')
00246 { ungetc(c, f); break; }
00247 else
00248 {
00249 while (getc(f) != '\n')
00250 { }
00251 }
00252 }
00253
00254 int w = -1;
00255 int h = -1;
00256 int maxGrey = -1;
00257 ret = fscanf(f, "%d %d %d", &w, &h, &maxGrey);
00258 ENV_ASSERT(ret > 0);
00259 ENV_ASSERT(w > 0);
00260 ENV_ASSERT(h > 0);
00261 ENV_ASSERT(maxGrey > 0);
00262
00263
00264 c = getc(f);
00265 if ( !isspace(c) )
00266 lfatal("Missing whitespace after maxGrey in pbm file '%s'.", fname);
00267
00268 struct env_rgb_pixel* result = (struct env_rgb_pixel*)
00269 env_allocate(w * h * sizeof(struct env_rgb_pixel));
00270 if (fread((char*) result, 3, w*h, f) != ((env_size_t)(w*h)))
00271 lfatal("%s: fread() failed", fname);
00272 outdims->w = w;
00273 outdims->h = h;
00274 return result;
00275 }
00276
00277
00278 void env_stdio_write_gray(const struct env_image* iimage,
00279 const char* outstem, const char* name, int c)
00280 {
00281 if (!env_img_initialized(iimage))
00282 return;
00283
00284
00285
00286 if (outstem[0] == '\0')
00287 return;
00288
00289 char fname[256];
00290 snprintf(fname, sizeof(fname),
00291 "%s-%s%06d.pnm", outstem, name, c);
00292
00293 FILE* const f = fopen(fname, "wb");
00294 if (f == 0)
00295 lfatal("%s: couldn't open PNM file for writing (errno=%d, %s)",
00296 fname, errno, strerror(errno));
00297
00298 if (fprintf(f, "P5\n%d %d\n255\n",
00299 (int) iimage->dims.w, (int) iimage->dims.h) < 0)
00300 lfatal("%s: fprintf() failed (errno=%d, %s)",
00301 fname, errno, strerror(errno));
00302
00303 const intg32* const src = env_img_pixels(iimage);
00304 const env_size_t sz = env_img_size(iimage);
00305 byte* bimage =
00306 (byte*) env_allocate(sz * sizeof(byte));
00307
00308 for (env_size_t i = 0; i < sz; ++i)
00309 {
00310
00311
00312
00313 ENV_ASSERT(src[i] >= 0 && src[i] <= 255);
00314 bimage[i] = (byte) src[i];
00315 }
00316
00317 if (fwrite(bimage, 1, sz, f) != sz)
00318 {
00319 env_deallocate(bimage);
00320 lfatal("%s: fwrite() failed (errno=%d, %s)",
00321 fname, errno, strerror(errno));
00322 }
00323
00324 env_deallocate(bimage);
00325
00326 if (fclose(f) != 0)
00327 lfatal("%s: fclose() failed (errno=%d, %s)",
00328 fname, errno, strerror(errno));
00329 }
00330
00331
00332
00333
00334
00335
00336
00337
00338 #endif // ENVISION_ENV_STDIO_INTERFACE_C_DEFINED