?
Solved

Is PrintScreen possible on Linux?

Posted on 1998-10-19
3
Medium Priority
?
608 Views
Last Modified: 2008-03-10

Is it possible to use the printscreen-key to dump the text on the page to default printer?

If possible - how do you do it?

0
Comment
Question by:jonnybe
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
3 Comments
 

Expert Comment

by:shivinder_jit
ID: 2007496
are you using a terminal or a pc  to connect to the server?
0
 

Author Comment

by:jonnybe
ID: 2007497

I am running a 486 PC as a workstation with RedHat Linux 5.1 and want to use printscreen from a text-based telnet-session.


0
 
LVL 2

Accepted Solution

by:
JYoungman earned 200 total points
ID: 2007498
To dump a virtual console to a graphic file, run this program:-

/* vcdump
 *
 *    Copyright (C) 1998,  James A Youngman <jay@gnu.org>
 *
 *    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 2 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with this program; if not, write to the Free Software
 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *
 * Utility which generates a screendump of a Linux console,
 * in full colour, as a PPM or PNG file.
 *
 *  Output file sizes:-
 *   (the input is an 80x25 VC containing the Red Hat "cabaret" filesystem
 *    administration tool)
 *  Plain PPM             2321189 bytes
 *  Raw   PPM           768014 bytes
 *        PNG             9076 bytes (About 2K of which is text data, etc.)
 *
 * TODO list:-
 *      1. Do the right thing for a monochrome display.
 *
 *      2. Test with differently-sized screen modes, and differently-
 *         sized fonts cells.
 *    
 *      3. Find out if it is possible to use console fonts with widths
 *         other than 8; if so, fix this program since it assumes that
 *         it is not.
 */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#include <getopt.h>
#include <unistd.h>

#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/kd.h>

#include <ppm.h>            /* we need libppm for writing the output. */

#ifdef USE_PNG
#include <png.h>            /* PNG support is optional. */
#endif

#define PROGNAME "vcdump"


#define FONT_BYTES           (8192)
#define FONT_LINES_PER_CHAR  (32)
#define VGA_PALDEPTH         (63)
#define VGA_COLOURS          (16) /* Number of colours in the VGA palette */
#define EFFECTS_PALETTE_SIZE (VGA_COLOURS * 2)
#define BG_COLOUR_BANK       (EFFECTS_PALETTE_SIZE / 2)

struct tagVcsaScreenInfo
{
  unsigned char lines, cols;      /* screen size */
  unsigned char x,     y;      /* cursor position */
};


static char rcs_id[] = "$Id: vcdump.c,v 1.6 1998/04/06 07:54:01 james Exp $";


/* colour_translations[] is an array; the on-screen colour is looked up in
 * this table before deciding which colour to use in the output file; this
 * allows us to make any given colour a copy of something else.  Typically,
 * this allows us to change a grey background into a white one.
 *
 * For output files which contain palettes, this is all done by palette
 * manipulation; for non-palette output files (PPM) this is done by modifying
 * the output for the relevant pixels.
 *
 * The first sixteen entries of the palette are used for the foreground
 * colours, and the second sixteen for the backgound colours.
 */
static unsigned colour_translations[EFFECTS_PALETTE_SIZE];

static int
screen_rows_to_font_height(int rr)
{
  /* This table is from the resizecons.c file in the Linux kbd package.
   */
  switch (rr)
    {
    case 25 : return 16;
    case 28 : return 14;
    case 30 : return 16;
    case 34 : return 14;
    case 36 : return 12;
    case 40 : return 12;
    case 44 : return 9;  
    case 50 : return 8;  
    case 60 : return 8;  
    default : return 8;  
    }
}

/* in_textmode()
 *
 * Returns nonzero if the VC to which the passed in fd refers is in
 * text mode.
 */
static int
in_textmode(int fd)
{
  long lmode;
  if (0 == ioctl(fd, KDGETMODE, &lmode))
    {
      return (lmode == KD_TEXT) ? 1 : 0;
    }
  else
    {
      perror("ioctl(KDGETMODE)");
      return 0;
    }
}

/* capture_vca
 *
 * Capture the text and attribute data from the vcsa device to which
 * fd refers.
 */
unsigned char *
capture_vca(int fd, struct tagVcsaScreenInfo *ps)
{
  void *p;
  size_t slen = sizeof(*ps);
  size_t ncells;

  /* Rewind to the start of the screen data */
  if (-1 == lseek(fd, 0, SEEK_SET))
    {
      perror("lseek (vcsa)");
      return NULL;
    }

  /* Read the header information, which contains the size */
  if (slen != read(fd, ps, slen))
    {
      perror("short read of header from vcsa device");
      return NULL;
    }
 
  /* Allocate a buffer for the screen data. */
  ncells = ps->lines * ps->cols;
  slen = 2u * ncells;
  p = malloc(slen);
  if (p)
    {
      /* Read in the screen data. */
      if (slen != read(fd, p, slen))
      {
        perror("short read of screen data from vcsa device");
        return NULL;
      }
      return p;                  /* done. */
    }
  else
    {
      perror("out of memory for screen data");
      return NULL;
    }
}

/* get_font()
 *
 * Capture the font information for the VC to which fd refers.
 */
int
get_font(int fd, unsigned char buf[FONT_BYTES])
{
  int i;
  i = ioctl(fd,GIO_FONT,buf);
  if (i)
    {
      perror("GIO_FONT ioctl error");
      return 0;
    }
  return 1;
}

/* get_vc_fds()
 *
 * Given a VC number, open the /dev/tty* and /dev/vcsa* devices
 * corresponding to it.
 */
int
get_vc_fds(int vcnum, int *vca_fd, int *tty_fd)
{
  char name[20];

  sprintf(name, "/dev/vcsa%d", vcnum);
  *vca_fd = open(name, O_RDONLY);
  if (*vca_fd < 0)
    perror(name);
 
  sprintf(name, "/dev/tty%d", vcnum);
  *tty_fd = open(name, O_RDONLY);
  if (*tty_fd < 0)
    perror(name);

  return (vca_fd >= 0) && (tty_fd >= 0);
}


/* Palette entries for the default VGA palette.  These are from table
 * 8.14 "Initial Values in the Color Registers", from "Programmer's
 * Guide to the EGA and VGA cards", by Richard E. Ferraro, 2nd Edn.,
 * Addison-Wesley, ISBN 0-201-57025-4.
 *
 * The VGA palette is 6-bit, and 2^6=64, so 63 is full-scale.
 */
struct tagPal { unsigned  r, g, b; };
const struct tagPal initial_vga_palette[VGA_COLOURS] =
{
  { 0,  0,  0}, { 0,  0, 42},      /* black,               blue, */
  { 0, 42,  0}, { 0, 42, 42},      /* green,               cyan, */
  {42,  0,  0}, {42,  0, 42},      /* red,                 magenta */
  {42, 21,  0}, {42, 42, 42},      /* brown,               white */
  {21, 21, 21}, {21, 21, 63},      /* gray,                light blue,  */
  {21, 63, 21}, {21, 63, 63},      /* light green,         light cyan  */
  {63, 21, 21}, {63, 21, 63},      /* light red,               light magenta,*/
  {63, 63, 21}, {63, 63, 63}      /* light brown (=yellow), bright white. */
};


/* decode_pixel()
 *
 * Select the background or foreground colour for a given pixel,
 * according to wether it is a foreground or background pixel.  Decode
 * the attribute into a libppm "pixel" value.
 */
void ppm_decode_pixel(pixel *pix, int is_on, int full_attrib)
{
  struct tagPal tp;
  int colour;
 
  if (!is_on)
    {
      full_attrib >>= 4;      /* select the background portion. */
      full_attrib &= 0x0F;
      colour = colour_translations[full_attrib+BG_COLOUR_BANK];
    }
  else
    {
      full_attrib &= 0x0F;
      colour = colour_translations[full_attrib];
    }

  /* The effects palette has 32 entries composed of two lots of
   * the same set of 16 colours.  Using (colour % 16) as the
   * lookup index then does the right thing.
   */
  tp = initial_vga_palette[colour % VGA_COLOURS];
  PPM_ASSIGN(*pix, tp.r, tp.g, tp.b);
}



/* get_font_row()
 *
 * Extract one scan row of the font information for a particular character.
 */
int get_font_row(int ascii, int charline, unsigned char font_buf[FONT_BYTES])
{
  return font_buf[ascii*FONT_LINES_PER_CHAR + charline];
}

static void oom(void)
{
  fprintf(stderr, "Fatal error: Out of memory.\n");
  exit(EXIT_FAILURE);
}

/* dump_to_ppm_file()
 *
 * Given the screen and font data, generate a PPM output file from it.
 */
static int
dump_to_ppm_file(FILE *fp,
             struct tagVcsaScreenInfo *psi,
             unsigned char *text_data,
             unsigned char font_buf[FONT_BYTES],
             int forceplain)
{
  int x, y, charline, nlines;
  const unsigned char *row;
  unsigned char ascii, attr;
  pixel *prow, *pixptr;

  nlines = screen_rows_to_font_height(psi->lines);

  prow = ppm_allocrow(psi->cols * 8);
  if (NULL == prow)
    {
      oom();
      return 0;
    }

  ppm_writeppminit(fp,
               psi->cols*8, psi->lines*nlines,
               VGA_PALDEPTH, forceplain);

  /* Work from top to bottom of the screen.
   */
  for (y=0; y < psi->lines; ++y)
    {
      /* Within each row, work from top to bottom of the character definitions.
       */
      for (charline=0; charline<nlines; ++charline)
      {
        row = text_data + y*(psi->cols * 2);
        pixptr = prow;

        /* Within the given scanline for this row, work from left to right.
         */
        for (x=0; x < psi->cols; ++x)
          {
            int i, fontline;
            
            ascii = *row++;
            attr = *row++;

            /* Extract the pixels for this row of this character,
             * working left to right.  
             * (TODO: maybe optimise fontline==0 or fontline==0xFF)
             */
            fontline = get_font_row(ascii, charline, font_buf);
            for (i=0; i<8; i++)
            {
              int mask = 1 << (7-i);
              ppm_decode_pixel(pixptr++, fontline & mask, attr );
            }
          }
        /* Write out the pixel row...
         */
        ppm_writeppmrow(fp, prow, psi->cols*8, VGA_PALDEPTH, forceplain);
      }
    }
 
  ppm_freerow(prow);
  return EXIT_SUCCESS;
}

#ifdef USE_PNG



/* dump_to_png_file
 *
 * Dump a VC to a PNG file; we dump the data as an image with a
 * palette with 8-bit depth.  The least significant two bits of the
 * intensities in the palette are zero (VGA palette range is 0...63).
 * Instead of a 16-entry palette, we produce as 32 entry one, the
 * first and second sixteen colours being dumped as the same colour.
 * The first set is used for the foreground colours, the second
 * sixteen for the background colours.  A typical use for this is to
 * brichten the grey background to bright white for greater clearness
 * when printed.
 */
static int
dump_to_png_file(FILE *fp,
             struct tagVcsaScreenInfo *psi,
             unsigned char *screen_text_data,
             unsigned char font_buf[FONT_BYTES],
             int forceplain)
{
  int x, y, charline, nlines, i;
  const unsigned char *row, *q;
  char *timestr;
  unsigned char ascii, attr;
  png_structp png_ptr;
  png_infop info_ptr;
  png_color my_png_palette[EFFECTS_PALETTE_SIZE];
  png_color output_palette[EFFECTS_PALETTE_SIZE];
  png_color_8 six_sig_bits;
  png_byte *pngimage_row, *pixptr;
  png_time conversion_time;
  time_t ttnow;
  png_text tentry[5];
  int colchars;
  char *p, *txt;

 
  /* The 6-bit VGA palette in initial_vga_palette needs
   * to be scaled up by 2 bit positions to look like an
   * 8-bit palette.
   */
  for (i=0; i<VGA_COLOURS; ++i)
    {
      /* foreground entries. */
      my_png_palette[i].red   = initial_vga_palette[i].r << 2;
      my_png_palette[i].green = initial_vga_palette[i].g << 2;
      my_png_palette[i].blue  = initial_vga_palette[i].b << 2;

      /* background entries. */
      my_png_palette[BG_COLOUR_BANK + i].red   = my_png_palette[i].red;  
      my_png_palette[BG_COLOUR_BANK + i].green = my_png_palette[i].green;
      my_png_palette[BG_COLOUR_BANK + i].blue  = my_png_palette[i].blue;  
    }

  /* The palette we actually output consists of this scaled palette
   * modified by the effects of colour_translations[] (see the -e
   * option).
   */
  for (i=0; i<32; ++i)
      output_palette[i] = my_png_palette[colour_translations[i]];
 
  six_sig_bits.red = six_sig_bits.green = six_sig_bits.blue = 6;
 
  nlines = screen_rows_to_font_height(psi->lines);

  pngimage_row = malloc(psi->cols * 8);
  if (!pngimage_row)
    oom();
 
  /* Init the png stuff */
  png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if (NULL == png_ptr)
    return EXIT_FAILURE;      /* TODO: make verbose */
     
  info_ptr = png_create_info_struct(png_ptr);
  if (!info_ptr)
    {
      png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
      return EXIT_FAILURE;
    }
  if (setjmp(png_ptr->jmpbuf))
    {
      png_destroy_write_struct(&png_ptr, &info_ptr);
      return EXIT_FAILURE;
    }
  png_init_io(png_ptr, fp);
  png_set_IHDR(png_ptr, info_ptr, psi->cols*8, psi->lines*nlines,
             8,            /* color depth */
             PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,
             PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
  png_set_PLTE(png_ptr, info_ptr, output_palette, 32);
  png_set_sBIT(png_ptr, info_ptr, &six_sig_bits);
  ttnow = time(NULL);
  png_convert_from_time_t(&conversion_time, ttnow);
  png_set_tIME(png_ptr, info_ptr, &conversion_time);
  png_write_info(png_ptr, info_ptr);
 

 

  /* Work from top to bottom of the screen.
   */
  for (y=0; y < psi->lines; ++y)
    {
      /* Within each row, work from top to bottom of the character definitions.
       */
      for (charline=0; charline<nlines; ++charline)
      {
        row = screen_text_data + y*(psi->cols * 2);
        pixptr = pngimage_row;

        /* Within the given scanline for this row, work from left to right.
         */
        for (x=0; x < psi->cols; ++x)
          {
            int i, fontline;
            
            ascii = *row++;
            attr = *row++;

            /* Extract the pixels for this row of this character,
             * working left to right.
             */
            fontline = get_font_row(ascii, charline, font_buf);
            for (i=0; i<8; i++)
            {
              int mask = 1 << (7-i);
              int nclr;
              if (fontline & mask)
                {
                  nclr = attr & 0x0F; /* fg pixel. */
                }
              else
                {
                  nclr = (attr & 0xF0) >> 4; /* bg pixel. */
                  nclr += BG_COLOUR_BANK; /* second palette group for bg. */
                }

              *pixptr++ = nclr;
            }
          }
        /* Write out the pixel row...
         */
        png_write_rows(png_ptr, &pngimage_row, 1);
      }
    }
 
  colchars = psi->cols + 1;      /* +1 for '\n' */


  /* Write out the ASCII text into the Comments section of the PNG file.
   */
  if ( NULL ==  (txt = malloc(sizeof(png_textp) * psi->lines * colchars + 1)) )
    oom();
  p = txt;
 
  q = screen_text_data;
  for (i=0; i<psi->lines; ++i)
    {
      int j = psi->cols;
      while (j--)
      {
        int ch = *q;

        if (ch >= 128 || ch < 0) /* keep only 7-bit characters. */
          ch = ' ';

        *p++ = ch;
        q += 2;
      }
      *p++ = '\n';
    }
  *p++ = '\0';
  tentry[0].compression = PNG_TEXT_COMPRESSION_NONE;
  tentry[0].key = "Comment";
  tentry[0].text = txt;

  tentry[1].compression = PNG_TEXT_COMPRESSION_NONE;
  tentry[1].key = "Software";
  tentry[1].text = PROGNAME " $Revision: 1.6 $ (C) 1998, James Youngman";

  tentry[2].compression = PNG_TEXT_COMPRESSION_NONE;
  tentry[2].key = "Description";
  tentry[2].text = "Image dumped from a Linux Virtual Console";

  tentry[3].compression = PNG_TEXT_COMPRESSION_NONE;
  tentry[3].key = "Creation Time";
  if ( (time_t)-1 == ttnow )      /* call failed */
    timestr = "4004 BC";
  else
    timestr = ctime(&ttnow);
  tentry[3].text = timestr;

  /* The output of ctime() doesn't indicate that it is in UTC.
   * I don't want to faff around with arbitrary length buffers
   * and certainly don't want to have a fixed-size one.  So I'll
   * put another text string in that makes this plain.
   */
  tentry[4].compression = PNG_TEXT_COMPRESSION_NONE;
  tentry[4].key = "UTC Creation Time";
  tentry[4].text = timestr;


  png_set_text(png_ptr, info_ptr, tentry, 5);

 
  png_write_end(png_ptr, info_ptr);
 
  free(pngimage_row);
  free(txt);
 
  png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
 
  return EXIT_SUCCESS;
 
}
#endif


typedef int (*dumper)(FILE *fp,
                 struct tagVcsaScreenInfo *psi,
                 unsigned char *text_data,
                 unsigned char font_buf[FONT_BYTES],
                 int forceplain);


struct tagDumpDefs
{
  const char *name;
  int plainflag;
  dumper dumpfn;
} dumpers[ ] =
{
  { "ppm",     0, dump_to_ppm_file },    
  { "ppmraw",  0, dump_to_ppm_file },    
  { "ppmtext", 1, dump_to_ppm_file },
#ifdef USE_PNG  
  { "png",     0, dump_to_png_file }
#endif
};
#define NDUMPERS (sizeof(dumpers)/sizeof(dumpers[0]))


dumper
set_output_type(const char *name, int *plain)
{
  int i;
  for (i=0; i<NDUMPERS; ++i)
    {
      if (0 == strcmp(name, dumpers[i].name))
      {
        *plain = dumpers[i].plainflag;
        return dumpers[i].dumpfn;
      }
    }
  return (dumper)0;
}

void
show_output_types(FILE *f)
{
  int i;
  for (i=0; i<NDUMPERS; ++i)
    fprintf(f, "%s%s", dumpers[i].name, i<(NDUMPERS-1) ? ", " : "");
}


/* Colour names.
 */
enum
{
  Black=0,
  Blue, Green, Cyan, Red, Magenta, Brown, White, Grey, LightBlue,
  LightGreen, LightCyan, LightRed, LightMagenta, Yellow, BrightWhite,

  FgBlack=0,
  FgBlue,         FgGreen,  FgCyan,      FgRed,        FgMagenta,  FgBrown,
  FgWhite,        FgGrey,   FgLightBlue, FgLightGreen, FgLightCyan, FgLightRed,
  FgLightMagenta, FgYellow, FgBrightWhite,

  BgBlack=16,
  BgBlue,         BgGreen,  BgCyan,      BgRed,        BgMagenta,   BgBrown,
  BgWhite,        BgGrey,   BgLightBlue, BgLightGreen, BgLightCyan, BgLightRed,
  BgLightMagenta, BgYellow, BgBrightWhite

};

static void
init_colour_translations(void)
{
  unsigned i;
  for (i=0; i<EFFECTS_PALETTE_SIZE; ++i)
    colour_translations[i] = i;      /* normal one-to-one mapping.*/
}


/* Colour effect -- convert white background to bright white.
 *
 * This is useful when the output is going to be printed.
 */
static void effect_bright_white_bg(void)
{
  colour_translations[BgWhite] = BgBrightWhite;
  colour_translations[BgGrey] = BgWhite;
}

/* Colour effect -- convert white foreground to bright white.
 *
 * This is useful when the output is going to be printed.
 */
static void effect_bright_white_fg(void)
{
  colour_translations[FgWhite] = FgBrightWhite;
  colour_translations[FgGrey] = FgWhite;
}

struct tagColourEffects
{
  const char *name;
  void (*fn)(void);
}
effect_table[] =
{
  { "brighten-white-bg", effect_bright_white_bg },
  { "brighten-white-fg", effect_bright_white_fg }
};
#define NEFFECTS (sizeof(effect_table)/sizeof(effect_table[0]))


void show_effects(FILE *f)
{
  int i;
  for (i=0; i<NEFFECTS; ++i)
    fprintf(stderr, "%s%s", effect_table[i].name, i<(NEFFECTS-1) ? ", " : "");
}

int
do_effect(const char *what)
{
  int i;
  for (i=0; i<NEFFECTS; ++i)
    {
      if (0 == strcmp(what, effect_table[i].name))
      {
        (effect_table[i].fn)();
        return 1;            /* OK. */
      }
    }
  return 0;                  /* fail. */
}


/* capture()
 *
 * Capture a specific VC to the given FILE.
 */
static int
capture(int vc, FILE *f, dumper dumpfunc, int plain)
{
  int vcsa_fd, tty_fd;
  struct tagVcsaScreenInfo si;
  unsigned char font_buf[FONT_BYTES];
  unsigned char * text_data;
 
  if (get_vc_fds(vc, &vcsa_fd, &tty_fd))
    {
      if (in_textmode(tty_fd))
      {
        if ( NULL != (text_data = capture_vca(vcsa_fd, &si)) )
          {
            if (get_font(tty_fd, font_buf))
            {
              return (dumpfunc)(f, &si, text_data, font_buf, plain);
            }
          }
      }
      else
      {
        fprintf(stderr, "tty%d is not in text mode.\n", vc);
      }
    }
  return EXIT_FAILURE;
}

void
usage(const char *prog)
{
  fprintf(stderr, "%s: [-o output-file] [-t TYPE] [-e EFFECT] VC-number\n",
        prog);
  fprintf(stderr, "TYPE can be one of ");
  show_output_types(stderr);
  fprintf(stderr, "\n");
  fprintf(stderr, "EFFECT can be one of ");
  show_effects(stderr);
  fprintf(stderr, "\n");
 
}

int main(int argc, char *argv[])
{
  int opt, vc_num;
  const char *output_file_name = NULL;
  FILE *output_file;
  int ret;
  dumper dumpfunc = dump_to_ppm_file;
  int plain_flag = 0;
 
  init_colour_translations();
   
  /* Options:
   * -o output-file-name
   * -t ppm|ppmraw|ppmtext|png
   * -e effect-name
   */
  while ( (opt = getopt(argc, argv, "o:t:e:")) != EOF )
    {
      if ('?' == opt)
      {
        fprintf(stderr, "Unknown option -%c\n", opt);
        usage(argv[0]);
        exit(EXIT_FAILURE);
      }
      else if (':' == opt)
      {
        fprintf(stderr, "-%c: Missing argument\n", opt);
        usage(argv[0]);
        exit(EXIT_FAILURE);
      }
      else if ('o' == opt)
      {
        output_file_name = optarg;
      }
      else if ('e' == opt)
      {
        if (0 == do_effect(optarg))
          {
            fprintf(stderr, "Unkown effect type \"%s\"."
                  "  Known types are:-\n", optarg);
            show_effects(stderr);
            fprintf(stderr, "\n");
            return (EXIT_FAILURE);
          }
      }
      else if ('t' == opt)
      {
        dumpfunc = set_output_type(optarg, &plain_flag);
        if (0 == dumpfunc)
          {
            usage(argv[0]);
            exit(EXIT_FAILURE);
          }
      }
      else
      {
        fprintf(stderr, "getopt() returned %d, weird.\n", opt);
      }
    }
 
  /* Sole non-option argument should be the VC number.
   */
  if (optind < argc)
    {
      if (optind == argc-1)
      {
        const char *vc_arg = argv[optind];
        vc_num = atoi(vc_arg);
        if (0 == vc_arg)
          {
            fprintf(stderr, "Invalid VC number \"%s\"\n", vc_arg);
            usage(argv[0]);
            return EXIT_FAILURE;
          }
      }
      else
      {
        fprintf(stderr, "Too many arguments.\n");
        usage(argv[0]);
        return EXIT_FAILURE;
      }
    }
  else
    {
      fprintf(stderr, "Not enough arguments.\n");
      usage(argv[0]);
      return EXIT_FAILURE;
    }

  /* Actually do the VC capture...
   */
  if (output_file_name)
    {
      output_file = fopen(output_file_name, "wb");
      if (NULL == output_file)
      {
        perror(output_file_name);
        return EXIT_FAILURE;
      }
    }
  else
    {
      output_file = stdout;
    }
  ret = capture(vc_num, output_file, dumpfunc, plain_flag);
  if (output_file_name)
    fclose(output_file);
  exit(ret);
}

/*
 * Local Variables: !
 * compile-command: "make vcdump CPPFLAGS='-DUSE_PNG=1' LDLIBS='-lppm -lpbm -lpgm -lpng -lz' CFLAGS='-g'" !
 * End: !
 */


0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In tuning file systems on the Solaris Operating System, changing some parameters of a file system usually destroys the data on it. For instance, changing the cache segment block size in the volume of a T3 requires that you delete the existing volu…
I have been running these systems for a few years now and I am just very happy with them.   I just wanted to share the manual that I have created for upgrades and other things.  Oooh yes! FreeBSD makes me happy (as a server), no maintenance and I al…
Learn how to navigate the file tree with the shell. Use pwd to print the current working directory: Use ls to list a directory's contents: Use cd to change to a new directory: Use wildcards instead of typing out long directory names: Use ../ to move…
This video shows how to set up a shell script to accept a positional parameter when called, pass that to a SQL script, accept the output from the statement back and then manipulate it in the Shell.
Suggested Courses
Course of the Month10 days, 6 hours left to enroll

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question