Exemplo n.º 1
0
static void print_all_signals(FILE *fp, int pretty)
{
	size_t n, lth, lpos = 0, width;

	if (!pretty) {
		for (n = 0; n < ARRAY_SIZE(sys_signame); n++) {
			lth = 1 + strlen(sys_signame[n].name);
			if (KILL_OUTPUT_WIDTH < lpos + lth) {
				fputc('\n', fp);
				lpos = 0;
			} else if (lpos)
				fputc(' ', fp);
			lpos += lth;
			fputs(sys_signame[n].name, fp);
		}
#ifdef SIGRTMIN
		fputs(" RT<N> RTMIN+<N> RTMAX-<N>", fp);
#endif
		fputc('\n', fp);
		return;
	}

	/* pretty print */
	width = get_terminal_width(KILL_OUTPUT_WIDTH + 1) - 1;
	for (n = 0; n < ARRAY_SIZE(sys_signame); n++)
		pretty_print_signal(fp, width, &lpos,
				    sys_signame[n].val, sys_signame[n].name);
#ifdef SIGRTMIN
	pretty_print_signal(fp, width, &lpos, SIGRTMIN, "RTMIN");
	pretty_print_signal(fp, width, &lpos, SIGRTMAX, "RTMAX");
#endif
	fputc('\n', fp);
}
Exemplo n.º 2
0
static void pretty_print_line(const char *device, const char *fs_type,
			      const char *label, const char *mtpt,
			      const char *uuid)
{
	static int device_len = 10, fs_type_len = 7;
	static int label_len = 8, mtpt_len = 14;
	static int term_width = -1;
	int len, w;

	if (term_width < 0)
		term_width = get_terminal_width();

	if (term_width > 80) {
		term_width -= 80;
		w = term_width / 10;
		if (w > 8)
			w = 8;
		term_width -= 2*w;
		label_len += w;
		fs_type_len += w;
		w = term_width/2;
		device_len += w;
		mtpt_len +=w;
	}

	len = pretty_print_word(device, device_len, 0, 1);
	len = pretty_print_word(fs_type, fs_type_len, len, 0);
	len = pretty_print_word(label, label_len, len, 0);
	len = pretty_print_word(mtpt, mtpt_len, len, 0);
	fputs(uuid, stdout);
	fputc('\n', stdout);
}
Exemplo n.º 3
0
void hash_printing_accept_byte_count(progress_op_t op, off64_t bytes_written,
                                     off64_t total_size)
{
	static char *output;
	static size_t max_output_size;
	int width;

	switch( op) {
	case progress_set:
		width = get_terminal_width();

		if( width >= max_output_size) {
			max_output_size = width+1;
			output = realloc( output, max_output_size);
		}

		build_output(output, width, bytes_written, total_size);
		append_spaces_if_shrunk(output, width);
		printf( "%s\r", output);
		fflush(stdout);
		break;

	case progress_finished:
		free(output);
		output = NULL;
		max_output_size = 0;
		printf( "\n");
		break;
	}
}
Exemplo n.º 4
0
void
gfc_error_init_1 (void)
{
  terminal_width = get_terminal_width ();
  errors = 0;
  warnings = 0;
  buffer_flag = 0;
}
Exemplo n.º 5
0
void
Xboxdrv::run_list_enums(uint32_t enums)
{
  const int terminal_width = get_terminal_width();

  WordWrap wrap(terminal_width);

  if (enums & Options::LIST_ABS)
  {
    wrap.println("EV_ABS:");
    wrap.para("  ", boost::algorithm::join(evdev_abs_names.get_names(), ", "));
    wrap.newline();
  }
  
  if (enums & Options::LIST_REL)
  {
    wrap.println("EV_REL:");
    wrap.para("  ", boost::algorithm::join(evdev_rel_names.get_names(), ", "));
    wrap.newline();
  }
  
  if (enums & Options::LIST_KEY)
  {
    wrap.println("EV_KEY:");
    wrap.para("  ", boost::algorithm::join(evdev_key_names.get_names(), ", "));
    wrap.newline();
  }
  
  if (enums & Options::LIST_X11KEYSYM)
  {
    std::vector<std::string> lst;  
    for(X11KeysymEnum::const_iterator i = get_x11keysym_names().begin();
        i != get_x11keysym_names().end(); ++i)
    {
      lst.push_back(i->second);
    }
    wrap.println("X11Keysym:");
    wrap.para("  ", boost::algorithm::join(lst, ", "));
    wrap.newline();
  }
  
  if (enums & Options::LIST_AXIS)
  {
    wrap.println("XboxAxis:");
    // BROKEN
    wrap.newline();
  }
  
  if (enums & Options::LIST_BUTTON)
  {
    wrap.println("XboxButton:");
    // BROKEN
    wrap.newline();
  }
}
Exemplo n.º 6
0
void
Xboxdrv::print_copyright() const
{
  WordWrap wrap(get_terminal_width());
  wrap.para("xboxdrv " PACKAGE_VERSION " - http://pingus.seul.org/~grumbel/xboxdrv/");
  wrap.para("Copyright © 2008-2011 Ingo Ruhnke <*****@*****.**>");
  wrap.para("Licensed under GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>");
  wrap.para("This program comes with ABSOLUTELY NO WARRANTY.");
  wrap.para("This is free software, and you are welcome to redistribute it under certain "
            "conditions; see the file COPYING for details.");
  wrap.newline();
}
Exemplo n.º 7
0
/* Set caret_max_width to value.  */
void
diagnostic_set_caret_max_width (diagnostic_context *context, int value)
{
  /* One minus to account for the leading empty space.  */
  value = value ? value - 1 
    : (isatty (fileno (pp_buffer (context->printer)->stream))
       ? get_terminal_width () - 1: INT_MAX);
  
  if (value <= 0) 
    value = INT_MAX;

  context->caret_max_width = value;
}
Exemplo n.º 8
0
static void pretty_print_dev(blkid_dev dev)
{
	blkid_tag_iterate	iter;
	const char		*type, *value, *devname;
	const char		*uuid = "", *fs_type = "", *label = "";
	int			len, mount_flags;
	char			mtpt[80];
	errcode_t		retval;

	if (dev == NULL) {
		pretty_print_line("device", "fs_type", "label",
				  "mount point", "UUID");
		for (len=get_terminal_width()-1; len > 0; len--)
			fputc('-', stdout);
		fputc('\n', stdout);
		return;
	}

	devname = blkid_dev_devname(dev);
	if (access(devname, F_OK))
		return;

	/* Get the uuid, label, type */
	iter = blkid_tag_iterate_begin(dev);
	while (blkid_tag_next(iter, &type, &value) == 0) {
		if (!strcmp(type, "UUID"))
			uuid = value;
		if (!strcmp(type, "TYPE"))
			fs_type = value;
		if (!strcmp(type, "LABEL"))
			label = value;
	}
	blkid_tag_iterate_end(iter);

	/* Get the mount point */
	mtpt[0] = 0;
	retval = ext2fs_check_mount_point(devname, &mount_flags,
					  mtpt, sizeof(mtpt));
	if (retval == 0) {
		if (mount_flags & EXT2_MF_MOUNTED) {
			if (!mtpt[0])
				strcpy(mtpt, "(mounted, mtpt unknown)");
		} else if (mount_flags & EXT2_MF_BUSY)
			strcpy(mtpt, "(in use)");
		else
			strcpy(mtpt, "(not mounted)");
	}

	pretty_print_line(devname, fs_type, label, mtpt, uuid);
}
Exemplo n.º 9
0
int main(int argc, char** argv)
{
  PrettyPrinter printer(16, get_terminal_width() - 16);

  printer.print(" -h, --help",
                "This program is free software: you can redistribute it and/or modify "
                "it under the terms of the GNU General Public License as published by "
                "the Free Software Foundation, either version 3 of the License, or "
                "(at your option) any later version.\n"
                "\n"
                "\n"
                "You should have received a copy of the GNU General Public License "
                "along with this program.");
  return 0;
}
Exemplo n.º 10
0
void blink_square(Square * square) {
	char i;
	Location location = get_square_location(square);
	ansi_set_position(1 + 2 + location.row, (get_terminal_width() - g_maze->size) / 2 + location.column);
	for (i = 0 ; i < 4 ; i++) {
		set_background_color(square);
		putchar(' ');
		fflush(stdout);
		usleep(150000);
		ansi_left(1);
		print_foreground(square);
		fflush(stdout);
		usleep(150000);
		ansi_left(1);
	}
}
Exemplo n.º 11
0
/**
 * scols_new_table:
 *
 * Returns: A newly allocated table.
 */
struct libscols_table *scols_new_table(void)
{
	struct libscols_table *tb;

	tb = calloc(1, sizeof(struct libscols_table));
	if (!tb)
		return NULL;

	tb->refcount = 1;
	tb->out = stdout;
	tb->termwidth = get_terminal_width(80);

	INIT_LIST_HEAD(&tb->tb_lines);
	INIT_LIST_HEAD(&tb->tb_columns);

	DBG(TAB, ul_debugobj(tb, "alloc"));
	ON_DBG(INIT, check_padding_debug(tb));

	return tb;
}
Exemplo n.º 12
0
void display_maze() {
	int i, j, width;
	ansi_set_position(3, 1);
	if (g_maze != NULL) {
		ansi_clear_screen_after();
		width = get_terminal_width();
		for (i = 0 ; i < g_maze->size ; i++) {
			ansi_set_column((width - g_maze->size) / 2);
			for (j = 0 ; j < g_maze->size ; j++) {
				print_square(g_maze->squares + (i * g_maze->size + j));
			}
			ansi_set_bg_color(ANSI_BLACK);
			putchar('\n');
		}
		g_maze_height = g_maze->size + 2;
	} else {
		ansi_clear_screen_after();
		g_maze_height = 0;
	}
	fflush(stdout);
}
Exemplo n.º 13
0
/* usable for example in usage() */
void list_available_columns(FILE *out)
{
	size_t i;
	int termwidth;
	struct fdisk_label *lb = NULL;
	struct fdisk_context *cxt = fdisk_new_context();

	if (!cxt)
		return;

	termwidth = get_terminal_width();
	if (termwidth <= 0)
		termwidth = 80;

	fprintf(out, _("\nAvailable columns (for -o):\n"));

	while (fdisk_next_label(cxt, &lb) == 0) {
		size_t width = 6;	/* label name and separators */

		fprintf(out, " %s:", fdisk_label_get_name(lb));
		for (i = 1; i < FDISK_NFIELDS; i++) {
			const struct fdisk_field *fl = fdisk_label_get_field(lb, i);
			const char *name = fl ? fdisk_field_get_name(fl) : NULL;
			size_t len;

			if (!name)
				continue;
			len = strlen(name) + 1;
			if (width + len > (size_t) termwidth) {
				fputs("\n     ", out);
				width = 6;
			}
			fprintf(out, " %s", name);
			width += len;
		}
		fputc('\n', out);
	}

	fdisk_unref_context(cxt);
}
Exemplo n.º 14
0
static int
gfc_get_terminal_width (void)
{
  return isatty (STDERR_FILENO) ? get_terminal_width () : INT_MAX;
}
Exemplo n.º 15
0
CLIOPTS_API
int
cliopts_parse_options(cliopts_entry *entries,
                      int argc,
                      char **argv,
                      int *lastidx,
                      struct cliopts_extra_settings *settings)
{
    /**
     * Now let's build ourselves a
     */
    int curmode;
    int ii, ret = 0, lastidx_s = 0;
    struct cliopts_priv ctx = { 0 };
    struct cliopts_extra_settings default_settings = { 0 };

    if (!lastidx) {
        lastidx = &lastidx_s;
    }

    ctx.entries = entries;

    if (!settings) {
        settings = &default_settings;
        settings->show_defaults = 1;
    }
    if (!settings->progname) {
        settings->progname = argv[0];
    }
    if (!settings->argstring) {
        settings->argstring = "[OPTIONS...]";
    }
    settings->nrestargs = 0;

    if (!settings->line_max) {
        settings->line_max = get_terminal_width() - 3;
    }

    ii = (settings->argv_noskip) ? 0 : 1;

    if (ii >= argc) {
        *lastidx = 0;
        ret = 0;
        goto GT_CHECK_REQ;
        return 0;
    }

    curmode = WANT_OPTION;
    ctx.wanted = curmode;
    ctx.settings = settings;

    for (; ii < argc; ii++) {

        if (curmode == WANT_OPTION) {
            curmode = parse_option(&ctx, argv[ii]);
        } else if (curmode == WANT_VALUE) {
            curmode = parse_value(&ctx, argv[ii]);
        }

        if (curmode == MODE_ERROR) {
            if (settings->error_nohelp == 0) {
                dump_error(&ctx);
            }
            ret = -1;
            break;
        } else if (curmode == MODE_HELP) {
            if (settings->help_noflag) {
                /* ignore it ? */
                continue;
            }

            print_help(&ctx, settings);
            exit(0);

        } else if (curmode == MODE_RESTARGS) {
            ii++;
            break;
        } else {
            ctx.wanted = curmode;
        }
    }

    *lastidx = ii;

    if (curmode == WANT_VALUE) {
        ret = -1;

        if (settings->error_nohelp == 0) {
            fprintf(stderr,
                    "Option %s requires argument\n",
                    ctx.current_key);
        }
        goto GT_RET;
    }

    GT_CHECK_REQ:
    {
        cliopts_entry *cur_ent;
        for (cur_ent = entries; cur_ent->dest; cur_ent++) {
            char entbuf[128] = { 0 };
            if (cur_ent->found || cur_ent->required == 0) {
                continue;
            }

            ret = -1;
            if (settings->error_nohelp) {
                goto GT_RET;
            }

            fprintf(stderr, "Required option %s missing\n",
                    get_option_name(cur_ent, entbuf));
        }
    }

    GT_RET:
    if (ret == -1) {
        if (settings->error_nohelp == 0) {
            print_help(&ctx, settings);
        }
        if (settings->error_noexit == 0) {
            exit(EXIT_FAILURE);
        }
    }
    return ret;
}
Exemplo n.º 16
0
/* File already had beg_size bytes.
 * Then we started downloading.
 * We downloaded "transferred" bytes so far.
 * Download is expected to stop when total size (beg_size + transferred)
 * will be "totalsize" bytes.
 * If totalsize == 0, then it is unknown.
 */
void FAST_FUNC bb_progress_update(bb_progress_t *p,
		uoff_t beg_size,
		uoff_t transferred,
		uoff_t totalsize)
{
	char numbuf5[6]; /* 5 + 1 for NUL */
	unsigned since_last_update, elapsed;
	int notty;

	//transferred = 1234; /* use for stall detection testing */
	//totalsize = 0; /* use for unknown size download testing */

	elapsed = monotonic_sec();
	since_last_update = elapsed - p->last_update_sec;
	p->last_update_sec = elapsed;

	if (totalsize != 0 && transferred >= totalsize - beg_size) {
		/* Last call. Do not skip this update */
		transferred = totalsize - beg_size; /* sanitize just in case */
	}
	else if (since_last_update == 0) {
		/*
		 * Do not update on every call
		 * (we can be called on every network read!)
		 */
		return;
	}

	/* Before we lose real, unscaled sizes, produce human-readable size string */
	smart_ulltoa5(beg_size + transferred, numbuf5, " kMGTPEZY")[0] = '\0';

	/*
	 * Scale sizes down if they are close to overflowing.
	 * This allows calculations like (100 * transferred / totalsize)
	 * without risking overflow: we guarantee 10 highest bits to be 0.
	 * Introduced error is less than 1 / 2^12 ~= 0.025%
	 */
	while (totalsize >= (1 << 20)) {
		totalsize >>= 8;
		beg_size >>= 8;
		transferred >>= 8;
	}
	/* If they were huge, now they are scaled down to [1048575,4096] range.
	 * (N * totalsize) won't overflow 32 bits for N up to 4096.
	 */
#if ULONG_MAX == 0xffffffff
/* 32-bit CPU, uoff_t arithmetic is complex on it, cast variables to narrower types */
# define totalsize   ((unsigned)totalsize)
# define beg_size    ((unsigned)beg_size)
# define transferred ((unsigned)transferred)
#endif

	notty = !isatty(STDERR_FILENO);

	if (ENABLE_UNICODE_SUPPORT)
		fprintf(stderr, "\r%s " + notty, p->curfile);
	else
		fprintf(stderr, "\r%-20.20s " + notty, p->curfile);

	if (totalsize != 0) {
		int barlength;
		unsigned beg_and_transferred; /* does not need uoff_t, see scaling code */
		unsigned ratio;

		beg_and_transferred = beg_size + transferred;
		ratio = 100 * beg_and_transferred / totalsize;
		/* can't overflow ^^^^^^^^^^^^^^^ */
		fprintf(stderr, "%3u%% ", ratio);

		barlength = get_terminal_width(2) - 48;
		/*
		 * Must reject barlength <= 0 (terminal too narrow). While at it,
		 * also reject: 1-char bar (useless), 2-char bar (ridiculous).
		 */
		if (barlength > 2) {
			if (barlength > 999)
				barlength = 999;
			{
				/* god bless gcc for variable arrays :) */
				char buf[barlength + 1];
				unsigned stars = (unsigned)barlength * beg_and_transferred / totalsize;
				/* can't overflow ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
				memset(buf, ' ', barlength);
				buf[barlength] = '\0';
				memset(buf, '*', stars);
				fprintf(stderr, "|%s| ", buf);
			}
		}
	}

	fputs(numbuf5, stderr); /* "NNNNk" */

	since_last_update = elapsed - p->last_change_sec;
	if ((unsigned)transferred != p->last_size) {
		p->last_change_sec = elapsed;
		p->last_size = (unsigned)transferred;
		if (since_last_update >= STALLTIME) {
			/* We "cut out" these seconds from elapsed time
			 * by adjusting start time */
			p->start_sec += since_last_update;
		}
		since_last_update = 0; /* we are un-stalled now */
	}

	elapsed -= p->start_sec; /* now it's "elapsed since start" */

	if (since_last_update >= STALLTIME) {
		fprintf(stderr, "  - stalled -");
	} else if (!totalsize || !transferred || (int)elapsed < 0) {
		fprintf(stderr, " --:--:-- ETA");
	} else {
		unsigned eta, secs, hours;
		unsigned bytes;

		bytes = totalsize - beg_size;

		/* Estimated remaining time =
		 * estimated_sec_to_dl_bytes - elapsed_sec =
		 * bytes / average_bytes_sec_so_far - elapsed =
		 * bytes / (transferred/elapsed) - elapsed =
		 * bytes * elapsed / transferred - elapsed
		 */
		eta = (unsigned long)bytes * elapsed / transferred - elapsed;
		/* if 32bit, can overflow ^^^^^^^^^^, but this would only show bad ETA */
		if (eta >= 1000*60*60)
			eta = 1000*60*60 - 1;
#if 0
		/* To prevent annoying "back-and-forth" estimation jitter,
		 * if new ETA is larger than the last just by a few seconds,
		 * disregard it, and show last one. The end result is that
		 * ETA usually only decreases, unless download slows down a lot.
		 */
		if ((unsigned)(eta - p->last_eta) < 10)
			eta = p->last_eta;
		p->last_eta = eta;
#endif
		secs = eta % 3600;
		hours = eta / 3600;
		fprintf(stderr, "%3u:%02u:%02u ETA", hours, secs / 60, secs % 60);
	}
	if (notty)
		fputc('\n', stderr);
}
Exemplo n.º 17
0
void update_square(Square * square) {
	Location location = get_square_location(square);
	ansi_set_position(1 + 2 + location.row, (get_terminal_width() - g_maze->size) / 2 + location.column);
	print_square(square);
	fflush(stdout);
}
Exemplo n.º 18
0
//Basic Init, create the font, backbuffer, etc
WINDOW *curses_init(void)
{
    lastchar = -1;
    inputdelay = -1;

    std::string typeface = "Terminus";
    std::string blending = "solid";
    std::ifstream fin;
    int faceIndex = 0;
    int fontsize = 0; //actuall size
    fin.open("data/FONTDATA");
    if (!fin.is_open()){
        fontwidth = 8;
        fontheight = 16;
        std::ofstream fout;//create data/FONDATA file
        fout.open("data/FONTDATA");
        if(fout.is_open()) {
            fout << typeface << "\n";
            fout << fontwidth << "\n";
            fout << fontheight;
            fout.close();
        }
    } else {
        getline(fin, typeface);
        fin >> fontwidth;
        fin >> fontheight;
        fin >> fontsize;
        fin >> blending;
        if ((fontwidth <= 4) || (fontheight <= 4)) {
            fontheight = 16;
            fontwidth = 8;
        }
        fin.close();
    }

    fontblending = (blending=="blended");

    halfwidth=fontwidth / 2;
    halfheight=fontheight / 2;

    if(!InitSDL()) {
        DebugLog() << "Failed to initialize SDL: " << SDL_GetError() << "\n";
        return NULL;
    }

    TERMINAL_WIDTH = OPTIONS["TERMINAL_X"];
    TERMINAL_HEIGHT = OPTIONS["TERMINAL_Y"];

    if(OPTIONS["FULLSCREEN"]) {
        // Fullscreen mode overrides terminal width/height
        SDL_DisplayMode display_mode;
        SDL_GetDesktopDisplayMode(0, &display_mode);

        TERMINAL_WIDTH = display_mode.w / fontwidth;
        TERMINAL_HEIGHT = display_mode.h / fontheight;

        WindowWidth  = display_mode.w;
        WindowHeight = display_mode.h;
    } else {
        WindowWidth= OPTIONS["TERMINAL_X"];
        if (WindowWidth < FULL_SCREEN_WIDTH) WindowWidth = FULL_SCREEN_WIDTH;
        WindowWidth *= fontwidth;
        WindowHeight = OPTIONS["TERMINAL_Y"] * fontheight;
    }

    if(!WinCreate()) {
        DebugLog() << "Failed to create game window: " << SDL_GetError() << "\n";
        return NULL;
    }

    #ifdef SDLTILES
    DebugLog() << "Initializing SDL Tiles context\n";
    tilecontext = new cata_tiles(renderer);
    try {
        tilecontext->init("gfx");
        DebugLog() << "Tiles initialized successfully.\n";
    } catch(std::string err) {
        // use_tiles is the cached value of the USE_TILES option.
        // most (all?) code refers to this to see if cata_tiles should be used.
        // Setting it to false disables this from getting used.
        use_tiles = false;
    }
    #endif // SDLTILES

    #ifdef SDLTILES
    while(!strcasecmp(typeface.substr(typeface.length()-4).c_str(),".bmp") ||
          !strcasecmp(typeface.substr(typeface.length()-4).c_str(),".png")) {
        DebugLog() << "Loading bitmap font [" + typeface + "].\n" ;
        typeface = "data/font/" + typeface;
        SDL_Surface *asciiload = IMG_Load(typeface.c_str());
        if(!asciiload || asciiload->w*asciiload->h < (fontwidth * fontheight * 256)) {
            DebugLog() << "Failed to load bitmap font: " << IMG_GetError() << "\n";
            SDL_FreeSurface(asciiload);
            break;
        }
        Uint32 key = SDL_MapRGB(asciiload->format, 0xFF, 0, 0xFF);
        SDL_SetColorKey(asciiload,SDL_TRUE,key);
        SDL_Surface *ascii_surf[16];
        ascii_surf[0] = SDL_ConvertSurface(asciiload,format,0);
        SDL_SetSurfaceRLE(ascii_surf[0], true);
        SDL_FreeSurface(asciiload);

        for(int a = 1; a < 16; ++a) {
            ascii_surf[a] = SDL_ConvertSurface(ascii_surf[0],format,0);
            SDL_SetSurfaceRLE(ascii_surf[a], true);
        }

        init_colors();
        for(int a = 0; a < 15; ++a) {
            SDL_LockSurface(ascii_surf[a]);
            int size = ascii_surf[a]->h * ascii_surf[a]->w;
            Uint32 *pixels = (Uint32 *)ascii_surf[a]->pixels;
            Uint32 color = (windowsPalette[a].r << 16) | (windowsPalette[a].g << 8) | windowsPalette[a].b;
            for(int i=0;i<size;i++) {
                if(pixels[i] == 0xFFFFFF)
                    pixels[i] = color;
            }
            SDL_UnlockSurface(ascii_surf[a]);
        }

        if(fontwidth)
            tilewidth = ascii_surf[0]->w / fontwidth;

        OutputChar = &OutputImageChar;

        //convert ascii_surf to SDL_Texture
        for(int a = 0; a < 16; ++a) {
            ascii[a] = SDL_CreateTextureFromSurface(renderer,ascii_surf[a]);
            SDL_FreeSurface(ascii_surf[a]);
        }

        mainwin = newwin(get_terminal_height(), get_terminal_width(),0,0);
        return mainwin;
    }
    #endif // SDLTILES

    std::string sysfnt = find_system_font(typeface, faceIndex);
    if(sysfnt != "") typeface = sysfnt;

    //make fontdata compatible with wincurse
    if(!fexists(typeface.c_str())) {
        faceIndex = 0;
        typeface = "data/font/" + typeface + ".ttf";
    }

    //different default font with wincurse
    if(!fexists(typeface.c_str())) {
        faceIndex = 0;
        typeface = "data/font/fixedsys.ttf";
    }

    DebugLog() << "Loading truetype font [" + typeface + "].\n" ;

    if(fontsize <= 0) fontsize = fontheight - 1;

    // SDL_ttf handles bitmap fonts size incorrectly
    if(0 == strcasecmp(typeface.substr(typeface.length() - 4).c_str(), ".fon"))
        faceIndex = test_face_size(typeface, fontsize, faceIndex);

    font = TTF_OpenFontIndex(typeface.c_str(), fontsize, faceIndex);
    if (font == NULL) {
        DebugLog() << "Failed to load truetype font: " << TTF_GetError() << "\n";
        return NULL;
    }

    TTF_SetFontStyle(font, TTF_STYLE_NORMAL);

    // glyph height hack by utunnels
    // SDL_ttf doesn't use FT_HAS_VERTICAL for function TTF_GlyphMetrics
    // this causes baseline problems for certain fonts
    // I can only guess by check a certain tall character...
    cache_glyphs();
    init_colors();

    OutputChar = &OutputFontChar;

    mainwin = newwin(get_terminal_height(), get_terminal_width(),0,0);
    return mainwin;   //create the 'stdscr' window and return its ref
}
Exemplo n.º 19
0
static int run_pipe(char *man_filename, int man, int level)
{
	char *cmd;

	/* Prevent man page link loops */
	if (level > 10)
		return 0;

	if (access(man_filename, R_OK) != 0)
		return 0;

	if (option_mask32 & OPT_w) {
		puts(man_filename);
		return 1;
	}

	if (man) { /* man page, not cat page */
		/* Is this a link to another manpage? */
		/* The link has the following on the first line: */
		/* ".so another_man_page" */

		struct stat sb;
		char *line;
		char *linkname, *p;

		/* On my system:
		 * man1/genhostid.1.gz: 203 bytes - smallest real manpage
		 * man2/path_resolution.2.gz: 114 bytes - largest link
		 */
		xstat(man_filename, &sb);
		if (sb.st_size > 300) /* err on the safe side */
			goto ordinary_manpage;

		line = xmalloc_open_zipped_read_close(man_filename, NULL);
		if (!line || !is_prefixed_with(line, ".so ")) {
			free(line);
			goto ordinary_manpage;
		}
		/* Example: man2/path_resolution.2.gz contains
		 * ".so man7/path_resolution.7\n<junk>"
		 */
		*strchrnul(line, '\n') = '\0';
		linkname = skip_whitespace(&line[4]);

		/* If link has no slashes, we just replace man page name.
		 * If link has slashes (however many), we go back *once*.
		 * ".so zzz/ggg/page.3" does NOT go back two levels. */
		p = strrchr(man_filename, '/');
		if (!p)
			goto ordinary_manpage;
		*p = '\0';
		if (strchr(linkname, '/')) {
			p = strrchr(man_filename, '/');
			if (!p)
				goto ordinary_manpage;
			*p = '\0';
		}

		/* Links do not have .gz extensions, even if manpage
		 * is compressed */
		man_filename = xasprintf("%s/%s", man_filename, linkname);
		free(line);
		/* Note: we leak "new" man_filename string as well... */
		if (show_manpage(man_filename, man, level + 1))
			return 1;
		/* else: show the link, it's better than nothing */
	}

 ordinary_manpage:
	close(STDIN_FILENO);
	open_zipped(man_filename, /*fail_if_not_compressed:*/ 0); /* guaranteed to use fd 0 (STDIN_FILENO) */
	if (man) {
		int w = get_terminal_width(-1);
		if (w > 10)
			w -= 2;
		/* "2>&1" is added so that nroff errors are shown in pager too.
		 * Otherwise it may show just empty screen.
		 */
		cmd = xasprintf("%s | %s -rLL=%un -rLT=%un 2>&1 | %s",
				G.tbl, G.nroff, w, w,
				G.pager);
	} else {
		cmd = xstrdup(G.pager);
	}
	system(cmd);
	free(cmd);
	return 1;
}
Exemplo n.º 20
0
int stty_main(int argc UNUSED_PARAM, char **argv)
{
	struct termios mode;
	void (*output_func)(const struct termios *, int);
	const char *file_name = NULL;
	int display_all = 0;
	int stty_state;
	int k;

	INIT_G();

	stty_state = STTY_noargs;
	output_func = do_display;

	/* First pass: only parse/verify command line params */
	k = 0;
	while (argv[++k]) {
		const struct mode_info *mp;
		const struct control_info *cp;
		const char *arg = argv[k];
		const char *argnext = argv[k+1];
		int param;

		if (arg[0] == '-') {
			int i;
			mp = find_mode(arg+1);
			if (mp) {
				if (!(mp->flags & REV))
					goto invalid_argument;
				stty_state &= ~STTY_noargs;
				continue;
			}
			/* It is an option - parse it */
			i = 0;
			while (arg[++i]) {
				switch (arg[i]) {
				case 'a':
					stty_state |= STTY_verbose_output;
					output_func = do_display;
					display_all = 1;
					break;
				case 'g':
					stty_state |= STTY_recoverable_output;
					output_func = display_recoverable;
					break;
				case 'F':
					if (file_name)
						bb_error_msg_and_die("only one device may be specified");
					file_name = &arg[i+1]; /* "-Fdevice" ? */
					if (!file_name[0]) { /* nope, "-F device" */
						int p = k+1; /* argv[p] is argnext */
						file_name = argnext;
						if (!file_name)
							bb_error_msg_and_die(bb_msg_requires_arg, "-F");
						/* remove -F param from arg[vc] */
						while (argv[p]) {
							argv[p] = argv[p+1];
							++p;
						}
					}
					goto end_option;
				default:
					goto invalid_argument;
				}
			}
 end_option:
			continue;
		}

		mp = find_mode(arg);
		if (mp) {
			stty_state &= ~STTY_noargs;
			continue;
		}

		cp = find_control(arg);
		if (cp) {
			if (!argnext)
				bb_error_msg_and_die(bb_msg_requires_arg, arg);
			/* called for the side effect of xfunc death only */
			set_control_char_or_die(cp, argnext, &mode);
			stty_state &= ~STTY_noargs;
			++k;
			continue;
		}

		param = find_param(arg);
		if (param & param_need_arg) {
			if (!argnext)
				bb_error_msg_and_die(bb_msg_requires_arg, arg);
			++k;
		}

		switch (param) {
#ifdef __linux__
		case param_line:
# ifndef TIOCGWINSZ
			xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
			break;
# endif /* else fall-through */
#endif
#ifdef TIOCGWINSZ
		case param_rows:
		case param_cols:
		case param_columns:
			xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
			break;
		case param_size:
#endif
		case param_speed:
			break;
		case param_ispeed:
			/* called for the side effect of xfunc death only */
			set_speed_or_die(input_speed, argnext, &mode);
			break;
		case param_ospeed:
			/* called for the side effect of xfunc death only */
			set_speed_or_die(output_speed, argnext, &mode);
			break;
		default:
			if (recover_mode(arg, &mode) == 1) break;
			if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) break;
 invalid_argument:
			bb_error_msg_and_die("invalid argument '%s'", arg);
		}
		stty_state &= ~STTY_noargs;
	}

	/* Specifying both -a and -g is an error */
	if ((stty_state & (STTY_verbose_output | STTY_recoverable_output)) ==
		(STTY_verbose_output | STTY_recoverable_output)
	) {
		bb_error_msg_and_die("-a and -g are mutually exclusive");
	}
	/* Specifying -a or -g with non-options is an error */
	if ((stty_state & (STTY_verbose_output | STTY_recoverable_output))
	 && !(stty_state & STTY_noargs)
	) {
		bb_error_msg_and_die("modes may not be set when -a or -g is used");
	}

	/* Now it is safe to start doing things */
	if (file_name) {
		G.device_name = file_name;
		xmove_fd(xopen_nonblocking(G.device_name), STDIN_FILENO);
		ndelay_off(STDIN_FILENO);
	}

	/* Initialize to all zeroes so there is no risk memcmp will report a
	   spurious difference in an uninitialized portion of the structure */
	memset(&mode, 0, sizeof(mode));
	if (tcgetattr(STDIN_FILENO, &mode))
		perror_on_device_and_die("%s");

	if (stty_state & (STTY_verbose_output | STTY_recoverable_output | STTY_noargs)) {
		G.max_col = get_terminal_width(STDOUT_FILENO);
		output_func(&mode, display_all);
		return EXIT_SUCCESS;
	}

	/* Second pass: perform actions */
	k = 0;
	while (argv[++k]) {
		const struct mode_info *mp;
		const struct control_info *cp;
		const char *arg = argv[k];
		const char *argnext = argv[k+1];
		int param;

		if (arg[0] == '-') {
			mp = find_mode(arg+1);
			if (mp) {
				set_mode(mp, 1 /* reversed */, &mode);
				stty_state |= STTY_require_set_attr;
			}
			/* It is an option - already parsed. Skip it */
			continue;
		}

		mp = find_mode(arg);
		if (mp) {
			set_mode(mp, 0 /* non-reversed */, &mode);
			stty_state |= STTY_require_set_attr;
			continue;
		}

		cp = find_control(arg);
		if (cp) {
			++k;
			set_control_char_or_die(cp, argnext, &mode);
			stty_state |= STTY_require_set_attr;
			continue;
		}

		param = find_param(arg);
		if (param & param_need_arg) {
			++k;
		}

		switch (param) {
#ifdef __linux__
		case param_line:
			mode.c_line = xatoul_sfx(argnext, stty_suffixes);
			stty_state |= STTY_require_set_attr;
			break;
#endif
#ifdef TIOCGWINSZ
		case param_cols:
		case param_columns:
			set_window_size(-1, xatoul_sfx(argnext, stty_suffixes));
			break;
		case param_size:
			display_window_size(0);
			break;
		case param_rows:
			set_window_size(xatoul_sfx(argnext, stty_suffixes), -1);
			break;
#endif
		case param_speed:
			display_speed(&mode, 0);
			break;
		case param_ispeed:
			set_speed_or_die(input_speed, argnext, &mode);
			stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
			break;
		case param_ospeed:
			set_speed_or_die(output_speed, argnext, &mode);
			stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
			break;
		default:
			if (recover_mode(arg, &mode) == 1)
				stty_state |= STTY_require_set_attr;
			else /* true: if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) */{
				set_speed_or_die(both_speeds, arg, &mode);
				stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
			} /* else - impossible (caught in the first pass):
				bb_error_msg_and_die("invalid argument '%s'", arg); */
		}
	}

	if (stty_state & STTY_require_set_attr) {
		struct termios new_mode;

		if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode))
			perror_on_device_and_die("%s");

		/* POSIX (according to Zlotnick's book) tcsetattr returns zero if
		   it performs *any* of the requested operations.  This means it
		   can report 'success' when it has actually failed to perform
		   some proper subset of the requested operations.  To detect
		   this partial failure, get the current terminal attributes and
		   compare them to the requested ones */

		/* Initialize to all zeroes so there is no risk memcmp will report a
		   spurious difference in an uninitialized portion of the structure */
		memset(&new_mode, 0, sizeof(new_mode));
		if (tcgetattr(STDIN_FILENO, &new_mode))
			perror_on_device_and_die("%s");

		if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
/*
 * I think the below chunk is not necessary on Linux.
 * If you are deleting it, also delete STTY_speed_was_set bit -
 * it is only ever checked here.
 */
#if 0 /* was "if CIBAUD" */
			/* SunOS 4.1.3 (at least) has the problem that after this sequence,
			   tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
			   sometimes (m1 != m2).  The only difference is in the four bits
			   of the c_cflag field corresponding to the baud rate.  To save
			   Sun users a little confusion, don't report an error if this
			   happens.  But suppress the error only if we haven't tried to
			   set the baud rate explicitly -- otherwise we'd never give an
			   error for a true failure to set the baud rate */

			new_mode.c_cflag &= (~CIBAUD);
			if ((stty_state & STTY_speed_was_set)
			 || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
#endif
				perror_on_device_and_die("%s: cannot perform all requested operations");
		}
	}

	return EXIT_SUCCESS;
}
Exemplo n.º 21
0
int
main(int argc,
     char ** argv)
{
/// @section csv_segmentation Chan-Sandberg-Vese segmentation
///
/// @subsection csv_theory Theory
/// Since the routine contains too many free parameters which makes it unreasonable to place it into a separate
/// function, all the code is kept in main(). Here's a rough explanation of what's Chan-Sandberg-Vese all about,
/// which is based on paper @cite Getreuer2012.
///
/// The Chan-Vese method seeks a contour @f$\mathcal{C}@f$ which minimizes the functional
/// @f[
///    \mathcal{F}[I;\,\mathcal{C},\,c_{1},\,c_{2}]=
///        \mu\mathrm{Length}(\mathcal{C})+
///        \nu\mathrm{Area}(\mathcal{C})+
///        \lambda_{1}\int_{\mathcal{C}}|I-c_{1}|^{2}\,\mathrm{d}x\mathrm{d}y+
///        \lambda_{2}\int_{\Omega\setminus\mathcal{C}}|I-c_{2}|^{2}\,\mathrm{d}x\mathrm{d}y\,,
/// @f]
/// where
///    - the single-channel image @f$I=I(x,\,y)@f$ is defined on the region @f$\Omega=[0,\,a]\times[0,\,b]@f$;
///         - regions in the integral limits, @f$\mathcal{C}@f$ and @f$\Omega\setminus\mathcal{C}@f$,
///           denote the region enclosed by the contour and the region outside the contour, respectively;
///    -  @f$\mu(=0.5)@f$, @f$\nu(=0)@f$, @f$\lambda_{1}(=1)@f$ and @f$\lambda_{2}(=1)@f$ are free parameters,
///       whereby only @f$\nu@f$ can be negative (default values in parentheses);
///    - @f$c_{1}@f$ and @f$c_{2}@f$ are constants that depend on the information of the regions enclosed by and
///      outside of the contour.
///
/// Instead of dealing with @f$\mathcal{C}@f$ explicitly, it's custom to define a level set function @f$u(x,\,y;\,t)@f$
/// so that its zero-level iso-surface (also: zero level set) coincides with the contour:
/// @f$\mathcal{C}=\{\Omega\ni(x,\,y)\,:\,u(x,\,y;\,t)=0\forall t\}@f$. This in turn leads us to a new definition
/// of the functional:
/// @f[
///      \mathcal{F}[I;\,u,\,c_{1},\,c_{2}] =
///             \mu\left(\int_{\Omega}|\nabla H(u)|\,\mathrm{d}x\mathrm{d}y\right)^{p}+
///             \nu\int_{\Omega}H(u)\,\mathrm{d}x\mathrm{d}y+
///             \lambda_{1}\int_{\Omega}|I-c_{1}|^{2}H(u)\,\mathrm{d}x\mathrm{d}y+
///             \lambda_{2}\int_{\Omega}|I-c_{2}|^{2}(1-H(u))\,\mathrm{d}x\mathrm{d}y\,.
/// @f]
/// In our implementation we've picked @f$p=1@f$, so that the first integral reduces to
/// @f[
///      \left.\mu\left(\int_{\Omega}|\nabla H(u)|\,\mathrm{d}x\mathrm{d}y\right)^{p}\right|_{p=1}=
///       \mu\int_{\Omega}\delta(u)|\nabla u|\,\mathrm{d}x\mathrm{d}y\,,
/// @f]
/// where @f$H(x)@f$ and @f$\delta(x)=H'(x)@f$ are Heaviside's step and Dirac's delta functions.
/// In this prescription @f$c_{1}@f$ and @f$c_{2}@f$ are now region averages and take the following form:
/// @f[
///      c_{1}=\frac{\int_{\Omega}IH(u)\mathrm{d}x\mathrm{d}y}{\int_{\Omega}H(u)\,\mathrm{d}x\mathrm{d}y}\,,\quad
///      c_{2}=\frac{\int_{\Omega}I(1-H(u))\mathrm{d}x\mathrm{d}y}{\int_{\Omega}(1 - H(u))\,\mathrm{d}x\mathrm{d}y}\,.
/// @f]
/// For practical reasons the functions are replaced by smooth/regularized versions (see regularized_heaviside() and
/// regularized_delta()):
/// @f[
///      H_{\epsilon}(x)=\frac{1}{2}\left[1+\frac{2}{\pi}\arctan\left(\frac{x}{\epsilon}\right)\right]\,,\quad
///      \delta_{\epsilon}(x)=\frac{\epsilon}{\pi\left(\epsilon^{2}+x^{2}\right)}\,,
/// @f]
/// with @f$\epsilon=1@f$ by default.
/// The interpretation of the functional @f$\mathcal{F}@f$ is the following:
///     - the first term penalizes the length of @f$\mathcal{C}@f$;
///     - the second term penalizes the area enclosed by the curve;
///     - the 3rd and 4th term penalize region averages inside and outside of the contour; in other words
///       it keeps track of the discrepancy between the two regions.
///
/// A stationary solution to @f$\mathcal{F}@f$, or equivalently the equation of motion (e.o.m) for the contour,
/// can be found by solving it with Euler-Lagrange equation, which results in
/// @f[
///    u_{t} = \delta_{\epsilon}(u)\left[\mu\kappa-\nu-\lambda_{1}(I-c_{1})^{2}+\lambda_{2}(I-c_{2})^{2}\right]\,,
/// @f]
/// where @f$\kappa=\nabla\cdot\left(\frac{\nabla u}{|\nabla u|}\right)@f$ is curvature of @f$u@f$.
///
/// If the (still 2D) image has @f$I@f$ has @f$N@f$ channels @f$\{I_{i}(x,\,y)\}_{i=1}^{N}@f$, there should still
/// be a single level set @f$u@f$, which leads us the following functional:
/// @f[
///    \mathcal{F}[I;\,u,\,\mathbf{c_{1}},\,\mathbf{c}_{2}]=
///      \mu\int_{\Omega}|\nabla H(u)|\mathrm{d}x\mathrm{d}y+
///      \nu\int_{\Omega}H(u)\mathrm{d}x\mathrm{d}y+
///      \int_{\Omega}\frac{1}{N}\sum_{i=1}^{N}\lambda_{1}^{(i)}|I_{i}-c_{1}^{(i)}|^{2}H(u)\mathrm{d}x\mathrm{d}y+
///      \int_{\Omega}\frac{1}{N}\sum_{i=1}^{N}\lambda_{2}^{(i)}|I_{i}-c_{2}^{(i)}|^{2}(1-H(u))\mathrm{d}x\mathrm{d}y\,.
/// @f]
/// Variables @f$\{c_{1}^{(i)},\,c_{2}^{(i)}\}_{i=1}^{N}@f$ retain their original meaning,
/// @f[
///     c_{1}^{(i)}=\frac{\int_{\Omega}I_{i}H(u)\mathrm{d}x\mathrm{d}y}{\int_{\Omega}H(u)\mathrm{d}x\mathrm{d}y}\,,\quad
///     c_{2}^{(i)}=\frac{\int_{\Omega}I_{i}(1-H(u))\mathrm{d}x\mathrm{d}y}{\int_{\Omega}(1-H(u))\mathrm{d}x\mathrm{d}y}
///     \quad\forall i=\{1,\,\ldots,\,N\}\,;
/// @f]
/// the constants @f$\{\lambda_{1}^{(i)},\,\lambda_{2}^{(i)}\}_{i=1}^{N}@f$ are defined for each channel separately.
/// This implementation consider only grayscale (@f$N=1@f$) and RGB (@f$N=3@f$) images, for which @f$\lambda_{i}=1@f$
/// by default for any @f$i@f$-th channel.
/// The corresponding e.o.m reads
/// @f[
///      u_{t}=\delta_{\epsilon}(u)\left[\mu\kappa-\nu-
///            \frac{1}{N}\sum_{i=1}^{N}\lambda_{1}^{(i)}\left(I_{i}-c_{1}^{(i)}\right)^{2}+
///            \frac{1}{N}\sum_{i=1}^{N}\lambda_{2}^{(i)}\left(I_{i}-c_{2}^{(i)}\right)^{2}\right]\,.
/// @f]
///
/// @subsection csv_numsch Numerical scheme
///
/// Finite difference expression for the curvature @f$\kappa@f$ is explained in curvature(). The advantage of this scheme
/// is that we only need nearest neighbouring points at current point while keeping the derivative centered at current point,
/// whereas naive implementation would use more distant points. Since we're dealing with a finite domain and therefore
/// boundaries, we don't have to "extend" the region by two pixels each direction. Instead, we just duplicate border pixels.
///
/// Rest of the calculation is actually quite straightforward -- the zero level set is iteratively updated with
/// @f[
///      u_{i,j}^{n+1}=u_{i,j}^{n}+\mathrm{d}t\;\delta_{\epsilon}(u_{i,j}^{n})\left[\kappa_{i,j}^{n}-\nu-
///      \frac{1}{N}\sum_{k=1}^N\lambda_{1}^{(k)}\left(I_{i,j}-c_{1}^{n,(k)}\right)+
///      \frac{1}{N}\sum_{k=1}^N\lambda_{2}^{(k)}\left(I_{i,j}-c_{2}^{n,(k)}\right)\right]\,.
/// @f]
/// The method is inherently implicit and is implemented with ordinary matrix operations. The first term in the brackets
/// has already been discussed; the second term is trivial; the final two terms are explained in region_variance() and
/// variance_penalty().
///
/// There are various ways to initialize the level set, and since we're solving a differential equation, different initial
/// conditions lead to different outcome. The simplest way is to let the user draw either rectangular or circular contour.
/// The level set will be evaluated with @f$+1@f$'s inside the contour and with @f$-1@f$'s outside of it.
/// A more optimal (here the default) contour would be checkerboard
/// @f[
///      u(i,\,j;\,0)=\sin\left(\frac{\pi}{5}i\right)\sin\left(\frac{\pi}{5}j\right)\,,
/// @f]
/// because it converges faster to a solution (see levelset_checkerboard()). The solution is reached when the maximum number
/// of iterations, @f$T_\max@f$, is reached or when @f$||u_{i,j}^{n+1}-u_{i,j}^{n}||_{2}\leqslant\delta ||\bar{I}||_{2}@f$,
/// where the subscript denotes @f$L_{2}@f$-norm, @f$\delta=(10^{-3})@f$ is tolerance parameter and @f$\bar{I}@f$ is
/// the intensity average in the image (averaged across the channels).
///
/// @subsection csv_summary Summary
///
/// The main logic described above starts with a timestep loop (look for the comment below); everything else preciding
/// that is actually sugar coating just to make the program usable for anyone.
///
/// If it isn't clear from above text or the code below, here is the list of variables which the user can pass as an argument
/// (the default values in the parentheses): @f$\mu(=0.5)@f$, @f$\nu(=0)@f$, @f$\mathrm{d}t(=1)@f$,
/// @f$\lambda_{1}^{(i)}(=1)@f$ and @f$\lambda_{1}^{(i)}(=1)@f$ @f$\forall i=1\ldots N@f$, @f$\epsilon(=1)@f$,
/// @f$\delta(=10^{-3})@f$, @f$T_\max@f$(=INT_MAX), @f$N(=1\;\mbox{or}\;3)@f$ (number of channels).
///
/// Other general options include:
///    - object selection (-s) -- the region enclosed by the contour will be cut out and placed onto white canvas and saved;
///    - region inversion (-I) -- sometimes the ROI is inverted; there's an option to circumvent that (goes with -s option);
///    - video output (-V) -- see contour evolution in a video (*.avi, the same filename as the image; see VideoWriterManager);
///    - overlay text (-O) -- puts overlay text (timesteps) on the video (goes with the previous option);
///    - frame rate (-f) -- frame rate of the video;
///    - line color (-l) -- color of the contour line (see Colors);
///    - rectangular (-R) or circular (-C) contour -- lets the user draw it on the image (see InteractiveData and its subclasses);
///    - grayscale image (-g) -- sometimes we just want do perform it on a black-white image, but the original source is RGB.
///
/// For Perona-Malik-specific parameters @f$K@f$, @f$L@f$, @f$T@f$, see perona_malik().
///
/// @sa curvature, region_variance, variance_penalty, levelset_checkerboard, VideoWriterManager, InteractiveData, Colors, perona_malik

  double mu, nu, eps, tol, dt, fps, K, L, T;
  int max_steps;
  std::vector<double> lambda1,
                      lambda2;
  std::string input_filename,
              text_position,
              line_color_str;
  bool grayscale         = false,
       write_video       = false,
       overlay_text      = false,
       object_selection  = false,
       invert            = false,
       segment           = false,
       rectangle_contour = false,
       circle_contour    = false;
  ChanVese::TextPosition pos = ChanVese::TextPosition::TopLeft;
  cv::Scalar contour_color = ChanVese::Colors::blue;

//-- Parse command line arguments
//   Negative values in multitoken are not an issue, b/c it doesn't make much sense
//   to use negative values for lambda1 and lambda2
  try
  {
    namespace po = boost::program_options;
    po::options_description desc("Allowed options", get_terminal_width());
    desc.add_options()
      ("help,h",                                                                               "this message")
      ("input,i",            po::value<std::string>(&input_filename),                          "input image")
      ("mu",                 po::value<double>(&mu) -> default_value(0.5),                     "length penalty parameter (must be positive or zero)")
      ("nu",                 po::value<double>(&nu) -> default_value(0),                       "area penalty parameter")
      ("dt",                 po::value<double>(&dt) -> default_value(1),                       "timestep")
      ("lambda1",            po::value<std::vector<double>>(&lambda1) -> multitoken(),         "penalty of variance inside the contour (default: 1's)")
      ("lambda2",            po::value<std::vector<double>>(&lambda2) -> multitoken(),         "penalty of variance outside the contour (default: 1's)")
      ("epsilon,e",          po::value<double>(&eps) -> default_value(1),                      "smoothing parameter in Heaviside/delta")
      ("tolerance,t",        po::value<double>(&tol) -> default_value(0.001),                  "tolerance in stopping condition")
      ("max-steps,N",        po::value<int>(&max_steps) -> default_value(-1),                  "maximum nof iterations (negative means unlimited)")
      ("fps,f",              po::value<double>(&fps) -> default_value(10),                     "video fps")
      ("overlay-pos,P",      po::value<std::string>(&text_position) -> default_value("TL"),    "overlay tex position; allowed only: TL, BL, TR, BR")
      ("line-color,l",       po::value<std::string>(&line_color_str) -> default_value("blue"), "contour color (allowed only: black, white, R, G, B, Y, M, C")
      ("edge-coef,K",        po::value<double>(&K) -> default_value(10),                       "coefficient for enhancing edge detection in Perona-Malik")
      ("laplacian-coef,L",   po::value<double>(&L) -> default_value(0.25),                     "coefficient in the gradient FD scheme of Perona-Malik (must be [0, 1/4])")
      ("segment-time,T",     po::value<double>(&T) -> default_value(20),                       "number of smoothing steps in Perona-Malik")
      ("segment,S",          po::bool_switch(&segment),                                        "segment the image with Perona-Malik beforehand")
      ("grayscale,g",        po::bool_switch(&grayscale),                                      "read in as grayscale")
      ("video,V",            po::bool_switch(&write_video),                                    "enable video output (changes the extension to '.avi')")
      ("overlay-text,O",     po::bool_switch(&overlay_text),                                   "add overlay text")
      ("invert-selection,I", po::bool_switch(&invert),                                         "invert selected region (see: select)")
      ("select,s",           po::bool_switch(&object_selection),                               "separate the region encolosed by the contour (adds suffix '_selection')")
      ("rectangle,R",        po::bool_switch(&rectangle_contour),                              "select rectangular contour interactively")
      ("circle,C",           po::bool_switch(&circle_contour),                                 "select circular contour interactively")
    ;
    po::variables_map vm;
    po::store(po::command_line_parser(argc, argv).options(desc).run(), vm);
    po::notify(vm);

    if(vm.count("help"))
    {
      std::cout << desc << "\n";
      return EXIT_SUCCESS;
    }
    if(! vm.count("input"))
      msg_exit("Error: you have to specify input file name!");
    else if(vm.count("input") && ! boost::filesystem::exists(input_filename))
      msg_exit("Error: file \"" + input_filename + "\" does not exists!");
    if(vm.count("dt") && dt <= 0)
      msg_exit("Cannot have negative or zero timestep: " + std::to_string(dt) + ".");
    if(vm.count("mu") && mu < 0)
      msg_exit("Length penalty parameter cannot be negative: " + std::to_string(mu) + ".");
    if(vm.count("lambda1"))
    {
      if(grayscale && lambda1.size() != 1)
        msg_exit("Too many lambda1 values for a grayscale image.");
      else if(! grayscale && lambda1.size() != 3)
        msg_exit("Number of lambda1 values must be 3 for a colored input image.");
      else if(grayscale && lambda1[0] < 0)
        msg_exit("The value of lambda1 cannot be negative.");
      else if(! grayscale && (lambda1[0] < 0 || lambda1[1] < 0 || lambda1[2] < 0))
        msg_exit("Any value of lambda1 cannot be negative.");
    }
    else if(! vm.count("lambda1"))
    {
      if(grayscale) lambda1 = {1};
      else          lambda1 = {1, 1, 1};
    }
    if(vm.count("lambda2"))
    {
      if(grayscale && lambda2.size() != 1)
        msg_exit("Too many lambda2 values for a grayscale image.");
      else if(! grayscale && lambda2.size() != 3)
        msg_exit("Number of lambda2 values must be 3 for a colored input image.");
      else if(grayscale && lambda2[0] < 0)
        msg_exit("The value of lambda2 cannot be negative.");
      else if(! grayscale && (lambda2[0] < 0 || lambda2[1] < 0 || lambda2[2] < 0))
        msg_exit("Any value of lambda2 cannot be negative.");
    }
    else if(! vm.count("lambda2"))
    {
      if(grayscale) lambda2 = {1};
      else          lambda2 = {1, 1, 1};
    }
    if(vm.count("eps") && eps < 0)
      msg_exit("Cannot have negative smoothing parameter: " + std::to_string(eps) + ".");
    if(vm.count("tol") && tol < 0)
      msg_exit("Cannot have negative tolerance: " + std::to_string(tol) + ".");
    if(vm.count("overlay-pos"))
    {
      if     (boost::iequals(text_position, "TL")) pos = ChanVese::TextPosition::TopLeft;
      else if(boost::iequals(text_position, "BL")) pos = ChanVese::TextPosition::BottomLeft;
      else if(boost::iequals(text_position, "TR")) pos = ChanVese::TextPosition::TopRight;
      else if(boost::iequals(text_position, "BR")) pos = ChanVese::TextPosition::BottomRight;
      else
        msg_exit("Invalid text position requested.\n"\
                 "Correct values are: TL -- top left\n"\
                 "                    BL -- bottom left\n"\
                 "                    TR -- top right\n"\
                 "                    BR -- bottom right"\
                );
    }
    if(vm.count("line-color"))
    {
      if     (boost::iequals(line_color_str, "red"))     contour_color = ChanVese::Colors::red;
      else if(boost::iequals(line_color_str, "green"))   contour_color = ChanVese::Colors::green;
      else if(boost::iequals(line_color_str, "blue"))    contour_color = ChanVese::Colors::blue;
      else if(boost::iequals(line_color_str, "black"))   contour_color = ChanVese::Colors::black;
      else if(boost::iequals(line_color_str, "white"))   contour_color = ChanVese::Colors::white;
      else if(boost::iequals(line_color_str, "magenta")) contour_color = ChanVese::Colors::magenta;
      else if(boost::iequals(line_color_str, "yellow"))  contour_color = ChanVese::Colors::yellow;
      else if(boost::iequals(line_color_str, "cyan"))    contour_color = ChanVese::Colors::cyan;
      else
        msg_exit("Invalid contour color requested.\n"\
                 "Correct values are: red, green, blue, black, white, magenta, yellow, cyan.");
    }
    if(vm.count("laplacian-coef") && (L > 0.25 || L < 0))
      msg_exit("The Laplacian coefficient in Perona-Malik segmentation must be between 0 and 0.25.");
    if(vm.count("segment-time") && (T < L))
      msg_exit("The segmentation duration must exceed the value of Laplacian coefficient, " +
               std::to_string(L) + ".");
    if(rectangle_contour && circle_contour)
      msg_exit("Cannot initialize with both rectangular and circular contour");
  }
  catch(std::exception & e)
  {
    msg_exit("error: " + std::string(e.what()));
  }

//-- Read the image (grayscale or BGR? RGB? BGR? help)
  cv::Mat _img;
  if(grayscale) _img = cv::imread(input_filename, CV_LOAD_IMAGE_GRAYSCALE);
  else          _img = cv::imread(input_filename, CV_LOAD_IMAGE_COLOR);
  if(! _img.data)
    msg_exit("Error on opening \"" + input_filename + "\" (probably not an image)!");

//-- Second conversion needed since we want to display a colored contour on a grayscale image
  cv::Mat img;
  if(grayscale) cv::cvtColor(_img, img, CV_GRAY2RGB);
  else          img = _img;
  _img.release();

//-- Determine the constants and define functionals
  max_steps = max_steps < 0 ? std::numeric_limits<int>::max() : max_steps;
  const int h = img.rows;
  const int w = img.cols;
  const int nof_channels = grayscale ? 1 : img.channels();
  const auto heaviside = std::bind(regularized_heaviside, std::placeholders::_1, eps);
  const auto delta = std::bind(regularized_delta, std::placeholders::_1, eps);

//-- Construct the level set
  cv::Mat u;
  if(rectangle_contour || circle_contour)
  {
    std::unique_ptr<InteractiveData> id;
    cv::startWindowThread();
    cv::namedWindow(WINDOW_TITLE, cv::WINDOW_NORMAL);

    if     (rectangle_contour)
      id = std::unique_ptr<InteractiveDataRect>(new InteractiveDataRect(&img, contour_color));
    else if(circle_contour)
      id = std::unique_ptr<InteractiveDataCirc>(new InteractiveDataCirc(&img, contour_color));

    if(id) cv::setMouseCallback(WINDOW_TITLE, on_mouse, id.get());
    cv::imshow(WINDOW_TITLE, img);
    cv::waitKey();
    cv::destroyWindow(WINDOW_TITLE);

    if(id)
    {
      if(! id -> is_ok())
        msg_exit("You must specify the contour with non-zero dimensions");
      u = id -> get_levelset(h, w);
    }
  }
  else
    u = levelset_checkerboard(h, w);

//-- Set up the video writer (and save the first frame)
  VideoWriterManager vwm;
  if(write_video)
  {
    vwm = VideoWriterManager(input_filename, img, contour_color, fps, pos, overlay_text);
    vwm.write_frame(u, overlay_text ? "t = 0" : "");
  }

//-- Split the channels
  std::vector<cv::Mat> channels;
  channels.reserve(nof_channels);
  cv::split(img, channels);
  if(grayscale) channels.erase(channels.begin() + 1, channels.end());

//-- Smooth the image with Perona-Malik
  cv::Mat smoothed_img;
  if(segment)
  {
    smoothed_img = perona_malik(channels, h, w, K, L, T);
    channels.clear();
    cv::split(smoothed_img, channels);
    cv::imwrite(add_suffix(input_filename, "pm"), smoothed_img);
  }

//-- Find intensity sum and derive the stopping condition
  cv::Mat intensity_avg = cv::Mat(h, w, CV_64FC1);
#pragma omp parallel for num_threads(nof_channels)
  for(int k = 0; k < nof_channels; ++k)
  {
    cv::Mat channel(h, w, intensity_avg.type());
    channels[k].convertTo(channel, channel.type());
    intensity_avg += channel;
  }
  intensity_avg /= nof_channels;
  double stop_cond = tol * cv::norm(intensity_avg, cv::NORM_L2);
  intensity_avg.release();

//-- Timestep loop
  for(int t = 1; t <= max_steps; ++t)
  {
    cv::Mat u_diff(cv::Mat::zeros(h, w, CV_64FC1));

//-- Channel loop
#pragma omp parallel for num_threads(nof_channels)
    for(int k = 0; k < nof_channels; ++k)
    {
      cv::Mat channel = channels[k];
//-- Find the average regional variances
      const double c1 = region_variance(channel, u, h, w, ChanVese::Region::Inside, heaviside);
      const double c2 = region_variance(channel, u, h, w, ChanVese::Region::Outside, heaviside);

//-- Calculate the contribution of one channel to the level set
      const cv::Mat variance_inside = variance_penalty(channel, h, w, c1, lambda1[k]);
      const cv::Mat variance_outside = variance_penalty(channel, h, w, c2, lambda2[k]);
      u_diff += -variance_inside + variance_outside;
    }
//-- Calculate the curvature (divergence of normalized gradient)
    const cv::Mat kappa = curvature(u, h, w);

//-- Mash the terms together
    u_diff = dt * (mu * kappa - nu + u_diff / nof_channels);

//-- Run delta function on the level set
    cv::Mat u_cp = u.clone();
    cv::parallel_for_(cv::Range(0, h * w), ParallelPixelFunction(u_cp, w, delta));

//-- Shift the level set
    cv::multiply(u_diff, u_cp, u_diff);
    const double u_diff_norm = cv::norm(u_diff, cv::NORM_L2);
    u += u_diff;

//-- Save the frame
    if(write_video) vwm.write_frame(u, overlay_text ? "t = " + std::to_string(t) : "");

//-- Check if we have achieved the desired precision
    if(u_diff_norm <= stop_cond) break;
  }

//-- Select the region enclosed by the contour and save it to the disk
  if(object_selection)
    cv::imwrite(add_suffix(input_filename, "selection"), separate(img, u, h, w, invert));

  return EXIT_SUCCESS;
}