(file) Return to util.c CVS log (file) (dir) Up to [RizwankCVS] / testProject / src

   1 rizwank 1.1 /*
   2              * Help utilities.
   3              * Copyright (c) 1995-1999 Markku Rossi.
   4              *
   5              * Author: Markku Rossi <mtr@iki.fi>
   6              */
   7             
   8             /*
   9              * This file is part of GNU enscript.
  10              *
  11              * This program is free software; you can redistribute it and/or modify
  12              * it under the terms of the GNU General Public License as published by
  13              * the Free Software Foundation; either version 2, or (at your option)
  14              * any later version.
  15              *
  16              * This program is distributed in the hope that it will be useful,
  17              * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18              * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19              * GNU General Public License for more details.
  20              *
  21              * You should have received a copy of the GNU General Public License
  22 rizwank 1.1  * along with this program; see the file COPYING.  If not, write to
  23              * the Free Software Foundation, 59 Temple Place - Suite 330,
  24              * Boston, MA 02111-1307, USA.
  25              */
  26             
  27             #include "gsint.h"
  28             
  29             /*
  30              * Types and definitions.
  31              */
  32             
  33             #define CFG_FATAL(body)						\
  34               do {								\
  35                 fprintf (stderr, "%s:%s:%d: ", program, fname, line);	\
  36                 fprintf body;						\
  37                 fprintf (stderr, "\n");					\
  38                 fflush (stderr);						\
  39                 exit (1);							\
  40               } while (0)
  41             
  42             
  43 rizwank 1.1 /*
  44              * Static variables.
  45              */
  46             
  47             /*
  48              * 7bit ASCII fi(nland), se (sweden) scand encodings (additions to 7bit ASCII
  49              * enc).
  50              */
  51             static struct
  52             {
  53               int code;
  54               char *name;
  55             } enc_7bit_ascii_fise[] =
  56             {
  57               {'{',		"adieresis"},
  58               {'|',		"odieresis"},
  59               {'}',		"aring"},
  60               {'[',		"Adieresis"},
  61               {'\\',	"Odieresis"},
  62               {']',		"Aring"},
  63               {0, NULL},
  64 rizwank 1.1 };
  65             
  66             /*
  67              * 7bit ASCII dk (denmark), no(rway) scand encodings (additions to 7bit ASCII
  68              * enc).
  69              */
  70             static struct
  71             {
  72               int code;
  73               char *name;
  74             } enc_7bit_ascii_dkno[] =
  75             {
  76               {'{',		"ae"},
  77               {'|',		"oslash"},
  78               {'}',		"aring"},
  79               {'[',		"AE"},
  80               {'\\',	"Oslash"},
  81               {']',		"Aring"},
  82               {0, NULL},
  83             };
  84             
  85 rizwank 1.1 
  86             /*
  87              * Global functions.
  88              */
  89             
  90             #define GET_TOKEN(from) (strtok ((from), " \t\n"))
  91             #define GET_LINE_TOKEN(from) (strtok ((from), "\n"))
  92             
  93             #define CHECK_TOKEN() 							\
  94               if (token2 == NULL) 							\
  95                 CFG_FATAL ((stderr, _("missing argument: %s"), token));
  96             
  97             int
  98             read_config (char *path, char *file)
  99             {
 100               FILE *fp;
 101               Buffer fname;
 102               char buf[4096];
 103               char *token, *token2;
 104               int line = 0;
 105             
 106 rizwank 1.1   buffer_init (&fname);
 107               buffer_append (&fname, path);
 108               buffer_append (&fname, "/");
 109               buffer_append (&fname, file);
 110             
 111               fp = fopen (buffer_ptr (&fname), "r");
 112             
 113               buffer_uninit (&fname);
 114             
 115               if (fp == NULL)
 116                 return 0;
 117             
 118               while (fgets (buf, sizeof (buf), fp))
 119                 {
 120                   line++;
 121             
 122                   if (buf[0] == '#')
 123             	continue;
 124             
 125                   token = GET_TOKEN (buf);
 126                   if (token == NULL)
 127 rizwank 1.1 	/* Empty line. */
 128             	continue;
 129             
 130                   if (MATCH (token, "AcceptCompositeCharacters:"))
 131             	{
 132             	  token2 = GET_TOKEN (NULL);
 133             	  CHECK_TOKEN ();
 134             	  accept_composites = atoi (token2);
 135             	}
 136                   else if (MATCH (token, "AFMPath:"))
 137             	{
 138             	  token2 = GET_TOKEN (NULL);
 139             	  CHECK_TOKEN ();
 140             	  xfree (afm_path);
 141             	  afm_path = xstrdup (token2);
 142             	}
 143                   else if (MATCH (token, "AppendCtrlD:"))
 144             	{
 145             	  token2 = GET_TOKEN (NULL);
 146             	  CHECK_TOKEN ();
 147             	  append_ctrl_D = atoi (token2);
 148 rizwank 1.1 	}
 149                   else if (MATCH (token, "Clean7Bit:"))
 150             	{
 151             	  token2 = GET_TOKEN (NULL);
 152             	  CHECK_TOKEN ();
 153             	  clean_7bit = atoi (token2);
 154             	}
 155                   else if (MATCH (token, "DefaultEncoding:"))
 156             	{
 157             	  token2 = GET_TOKEN (NULL);
 158             	  CHECK_TOKEN ();
 159             	  xfree (encoding_name);
 160             	  encoding_name = xstrdup (token2);
 161             	}
 162                   else if (MATCH (token, "DefaultFancyHeader:"))
 163             	{
 164             	  token2 = GET_TOKEN (NULL);
 165             	  CHECK_TOKEN ();
 166             	  xfree (fancy_header_default);
 167             	  fancy_header_default = xstrdup (token2);
 168             	}
 169 rizwank 1.1       else if (MATCH (token, "DefaultMedia:"))
 170             	{
 171             	  token2 = GET_TOKEN (NULL);
 172             	  CHECK_TOKEN ();
 173             	  xfree (media_name);
 174             	  media_name = xstrdup (token2);
 175             	}
 176                   else if (MATCH (token, "DefaultOutputMethod:"))
 177             	{
 178             	  token2 = GET_TOKEN (NULL);
 179             	  CHECK_TOKEN ();
 180             	  if (MATCH (token2, "printer"))
 181             	    output_file = OUTPUT_FILE_NONE;
 182             	  else if (MATCH (token2, "stdout"))
 183             	    output_file = OUTPUT_FILE_STDOUT;
 184             	  else
 185             	    CFG_FATAL ((stderr, _("illegal value \"%s\" for option %s"),
 186             			token2, token));
 187             	}
 188                   else if (MATCH (token, "DownloadFont:"))
 189             	{
 190 rizwank 1.1 	  token2 = GET_TOKEN (NULL);
 191             	  CHECK_TOKEN ();
 192             	  strhash_put (download_fonts, token2, strlen (token2) + 1, NULL,
 193             		       NULL);
 194             	}
 195                   else if (MATCH (token, "EscapeChar:"))
 196             	{
 197             	  token2 = GET_TOKEN (NULL);
 198             	  CHECK_TOKEN ();
 199             	  escape_char = atoi (token2);
 200             	  if (escape_char < 0 || escape_char > 255)
 201             	    CFG_FATAL ((stderr, _("invalid value \"%s\" for option %s"),
 202             			token2, token));
 203             	}
 204                   else if (MATCH (token, "FormFeedType:"))
 205             	{
 206             	  token2 = GET_TOKEN (NULL);
 207             	  CHECK_TOKEN ();
 208             	  if (MATCH (token2, "column"))
 209             	    formfeed_type = FORMFEED_COLUMN;
 210             	  else if (MATCH (token2, "page"))
 211 rizwank 1.1 	    formfeed_type = FORMFEED_PAGE;
 212             	  else
 213             	    CFG_FATAL ((stderr, _("illegal value \"%s\" for option %s"),
 214             			token2, token));
 215             	}
 216                   else if (MATCH (token, "GeneratePageSize:"))
 217             	{
 218             	  token2 = GET_TOKEN (NULL);
 219             	  CHECK_TOKEN ();
 220             	  generate_PageSize = atoi (token2);
 221             	}
 222                   else if (MATCH (token, "HighlightBarGray:"))
 223             	{
 224             	  token2 = GET_TOKEN (NULL);
 225             	  CHECK_TOKEN ();
 226             	  highlight_bar_gray = atof (token2);
 227             	}
 228                   else if (MATCH (token, "HighlightBars:"))
 229             	{
 230             	  token2 = GET_TOKEN (NULL);
 231             	  CHECK_TOKEN ();
 232 rizwank 1.1 	  highlight_bars = atoi (token2);
 233             	}
 234                   else if (MATCH (token, "LibraryPath:"))
 235             	{
 236             	  token2 = GET_TOKEN (NULL);
 237             	  CHECK_TOKEN ();
 238             	  xfree (libpath);
 239             	  libpath = xstrdup (token2);
 240             	}
 241                   else if (MATCH (token, "MarkWrappedLines:"))
 242             	{
 243             	  token2 = GET_TOKEN (NULL);
 244             	  CHECK_TOKEN ();
 245             	  xfree (mark_wrapped_lines_style_name);
 246             	  mark_wrapped_lines_style_name = xstrdup (token2);
 247             	}
 248                   else if (MATCH (token, "Media:"))
 249             	{
 250             	  char *name;
 251             	  int w, h, llx, lly, urx, ury;
 252             
 253 rizwank 1.1 	  token2 = GET_TOKEN (NULL);
 254             	  CHECK_TOKEN ();
 255             	  name = token2;
 256             
 257             	  token2 = GET_TOKEN (NULL);
 258             	  CHECK_TOKEN ();
 259             	  w = atoi (token2);
 260             
 261             	  token2 = GET_TOKEN (NULL);
 262             	  CHECK_TOKEN ();
 263             	  h = atoi (token2);
 264             
 265             	  token2 = GET_TOKEN (NULL);
 266             	  CHECK_TOKEN ();
 267             	  llx = atoi (token2);
 268             
 269             	  token2 = GET_TOKEN (NULL);
 270             	  CHECK_TOKEN ();
 271             	  lly = atoi (token2);
 272             
 273             	  token2 = GET_TOKEN (NULL);
 274 rizwank 1.1 	  CHECK_TOKEN ();
 275             	  urx = atoi (token2);
 276             
 277             	  token2 = GET_TOKEN (NULL);
 278             	  CHECK_TOKEN ();
 279             	  ury = atoi (token2);
 280             
 281             	  add_media (name, w, h, llx, lly, urx, ury);
 282             	}
 283                   else if (MATCH (token, "NoJobHeaderSwitch:"))
 284             	{
 285             	  token2 = GET_LINE_TOKEN (NULL);
 286             	  CHECK_TOKEN ();
 287             	  xfree (no_job_header_switch);
 288             	  no_job_header_switch = xstrdup (token2);
 289             	}
 290                   else if (MATCH (token, "NonPrintableFormat:"))
 291             	{
 292             	  token2 = GET_TOKEN (NULL);
 293             	  CHECK_TOKEN ();
 294             	  xfree (npf_name);
 295 rizwank 1.1 	  npf_name = xstrdup (token2);
 296             	}
 297                   else if (MATCH (token, "OutputFirstLine:"))
 298             	{
 299             	  token2 = GET_LINE_TOKEN (NULL);
 300             	  CHECK_TOKEN ();
 301             	  xfree (output_first_line);
 302             	  output_first_line = xstrdup (token2);
 303             	}
 304                   else if (MATCH (token, "PageLabelFormat:"))
 305             	{
 306             	  token2 = GET_TOKEN (NULL);
 307             	  CHECK_TOKEN ();
 308             	  xfree (page_label_format);
 309             	  page_label_format = xstrdup (token2);
 310             	}
 311                   else if (MATCH (token, "PagePrefeed:"))
 312             	{
 313             	  token2 = GET_TOKEN (NULL);
 314             	  CHECK_TOKEN ();
 315             	  page_prefeed = atoi (token2);
 316 rizwank 1.1 	}
 317                   else if (MATCH (token, "PostScriptLevel:"))
 318             	{
 319             	  token2 = GET_TOKEN (NULL);
 320             	  CHECK_TOKEN ();
 321             	  pslevel = atoi (token2);
 322             	}
 323                   else if (MATCH (token, "Printer:"))
 324             	{
 325             	  token2 = GET_TOKEN (NULL);
 326             	  CHECK_TOKEN ();
 327             	  xfree (printer);
 328             	  printer = xstrdup (token2);
 329             	}
 330                   else if (MATCH (token, "QueueParam:"))
 331             	{
 332             	  token2 = GET_LINE_TOKEN (NULL);
 333             	  CHECK_TOKEN ();
 334             	  xfree (queue_param);
 335             	  queue_param = xstrdup (token2);
 336             	}
 337 rizwank 1.1       else if (MATCH (token, "SetPageDevice:"))
 338             	{
 339             	  token2 = GET_LINE_TOKEN (NULL);
 340             	  CHECK_TOKEN ();
 341             	  parse_key_value_pair (pagedevice, token2);
 342             	}
 343                   else if (MATCH (token, "Spooler:"))
 344             	{
 345             	  token2 = GET_TOKEN (NULL);
 346             	  CHECK_TOKEN ();
 347             	  xfree (spooler_command);
 348             	  spooler_command = xstrdup (token2);
 349             	}
 350                   else if (MATCH (token, "StatesBinary:"))
 351             	{
 352             	  token2 = GET_TOKEN (NULL);
 353             	  CHECK_TOKEN ();
 354             	  xfree (states_binary);
 355             	  states_binary = xstrdup (token2);
 356             	}
 357                   else if (MATCH (token, "StatesColor:"))
 358 rizwank 1.1 	{
 359             	  token2 = GET_TOKEN (NULL);
 360             	  CHECK_TOKEN ();
 361             	  states_color = atoi (token2);
 362             	}
 363                   else if (MATCH (token, "StatesConfigFile:"))
 364             	{
 365             	  token2 = GET_LINE_TOKEN (NULL);
 366             	  CHECK_TOKEN ();
 367             	  xfree (states_config_file);
 368             	  states_config_file = xstrdup (token2);
 369             	}
 370                   else if (MATCH (token, "StatesHighlightStyle:"))
 371             	{
 372             	  token2 = GET_TOKEN (NULL);
 373             	  CHECK_TOKEN ();
 374             	  xfree (states_highlight_style);
 375             	  states_highlight_style = xstrdup (token2);
 376             	}
 377                   else if (MATCH (token, "StatesPath:"))
 378             	{
 379 rizwank 1.1 	  token2 = GET_LINE_TOKEN (NULL);
 380             	  CHECK_TOKEN ();
 381             	  xfree (states_path);
 382             	  states_path = xstrdup (token2);
 383             	}
 384                   else if (MATCH (token, "StatusDict:"))
 385             	{
 386             	  token2 = GET_TOKEN (NULL);
 387             	  CHECK_TOKEN ();
 388             	  parse_key_value_pair (statusdict, token2);
 389             	}
 390                   else if (MATCH (token, "TOCFormat:"))
 391             	{
 392             	  token2 = GET_LINE_TOKEN (NULL);
 393             	  CHECK_TOKEN ();
 394             	  toc_fmt_string = xstrdup (token2);
 395             	}
 396                   else if (MATCH (token, "Underlay:"))
 397             	{
 398             	  token2 = GET_LINE_TOKEN (NULL);
 399             	  CHECK_TOKEN ();
 400 rizwank 1.1 	  underlay = xmalloc (strlen (token2) + 1);
 401             	  strcpy (underlay, token2);
 402             	}
 403                   else if (MATCH (token, "UnderlayAngle:"))
 404             	{
 405             	  token2 = GET_TOKEN (NULL);
 406             	  CHECK_TOKEN ();
 407             	  ul_angle = atof (token2);
 408             	  ul_angle_p = 1;
 409             	}
 410                   else if (MATCH (token, "UnderlayFont:"))
 411             	{
 412             	  token2 = GET_TOKEN (NULL);
 413             	  CHECK_TOKEN ();
 414             	  if (!parse_font_spec (token2, &ul_font, &ul_ptsize, NULL))
 415             	    CFG_FATAL ((stderr, _("malformed font spec: %s"), token2));
 416             	}
 417                   else if (MATCH (token, "UnderlayGray:"))
 418             	{
 419             	  token2 = GET_TOKEN (NULL);
 420             	  CHECK_TOKEN ();
 421 rizwank 1.1 	  ul_gray = atof (token2);
 422             	}
 423                   else if (MATCH (token, "UnderlayPosition:"))
 424             	{
 425             	  token2 = GET_TOKEN (NULL);
 426             	  CHECK_TOKEN ();
 427             	  xfree (ul_position);
 428             	  ul_position = xstrdup (token2);
 429             	  ul_position_p = 1;
 430             	}
 431                   else if (MATCH (token, "UnderlayStyle:"))
 432             	{
 433             	  token2 = GET_TOKEN (NULL);
 434             	  CHECK_TOKEN ();
 435             	  xfree (ul_style_str);
 436             	  ul_style_str = xstrdup (token2);
 437             	}
 438                   else
 439             	CFG_FATAL ((stderr, _("illegal option: %s"), token));
 440                 }
 441               return 1;
 442 rizwank 1.1 }
 443             
 444             
 445             void
 446             add_media (char *name, int w, int h, int llx, int lly, int urx, int ury)
 447             {
 448               MediaEntry *entry;
 449             
 450               MESSAGE (2,
 451             	   (stderr,
 452             	    "add_media: name=%s, w=%d, h=%d, llx=%d, lly=%d, urx=%d, ury=%d\n",
 453             	    name, w, h, llx, lly, urx, ury));
 454             
 455               entry = xcalloc (1, sizeof (*entry));
 456               entry->name = xmalloc (strlen (name) + 1);
 457             
 458               strcpy (entry->name, name);
 459               entry->w = w;
 460               entry->h = h;
 461               entry->llx = llx;
 462               entry->lly = lly;
 463 rizwank 1.1   entry->urx = urx;
 464               entry->ury = ury;
 465             
 466               entry->next = media_names;
 467               media_names = entry;
 468             }
 469             
 470             
 471             void
 472             do_list_missing_characters (int *array)
 473             {
 474               int i;
 475               int count = 0;
 476             
 477               for (i = 0; i < 256; i++)
 478                 if (array[i])
 479                   {
 480             	fprintf (stderr, "%3d ", i);
 481             	count++;
 482             	if (count % 15 == 0)
 483             	  fprintf (stderr, "\n");
 484 rizwank 1.1       }
 485             
 486               if (count % 15 != 0)
 487                 fprintf (stderr, "\n");
 488             }
 489             
 490             
 491             int
 492             file_existsp (char *name, char *suffix)
 493             {
 494               FileLookupCtx ctx;
 495               int result;
 496             
 497               ctx.name = name;
 498               ctx.suffix =  suffix ? suffix : "";
 499               ctx.fullname = buffer_alloc ();
 500             
 501               result = pathwalk (libpath, file_lookup, &ctx);
 502             
 503               buffer_free (ctx.fullname);
 504             
 505 rizwank 1.1   return result;
 506             }
 507             
 508             
 509             int
 510             paste_file (char *name, char *suffix)
 511             {
 512               char buf[512];
 513               char resources[512];
 514               FILE *fp;
 515               FileLookupCtx ctx;
 516               int pending_comment = 0;
 517               int line = 0;
 518             
 519               ctx.name = name;
 520               ctx.suffix = suffix ? suffix : "";
 521               ctx.fullname = buffer_alloc ();
 522             
 523               if (!pathwalk (libpath, file_lookup, &ctx))
 524                 {
 525                   buffer_free (ctx.fullname);
 526 rizwank 1.1       return 0;
 527                 }
 528               fp = fopen (buffer_ptr (ctx.fullname), "r");
 529               if (fp == NULL)
 530                 {
 531                   buffer_free (ctx.fullname);
 532                   return 0;
 533                 }
 534             
 535               /* Find the end of the header. */
 536             #define HDR_TAG "% -- code follows this line --"
 537               while ((fgets (buf, sizeof (buf), fp)))
 538                 {
 539                   line++;
 540                   if (strncmp (buf, HDR_TAG, strlen (HDR_TAG)) == 0)
 541             	break;
 542                 }
 543             
 544               /* Dump rest of file. */
 545               while ((fgets (buf, sizeof (buf), fp)))
 546                 {
 547 rizwank 1.1       line++;
 548             
 549                   /*
 550                    * Document needed resources?
 551                    */
 552             #define RESOURCE_DSC 	"%%DocumentNeededResources:"
 553             #define CONT_DSC 	"%%+"
 554                   if (strncmp (buf, RESOURCE_DSC, strlen (RESOURCE_DSC)) == 0)
 555             	{
 556             	  char *cp, *cp2;
 557             
 558             	  strcpy (resources, buf + strlen (RESOURCE_DSC));
 559             	  pending_comment = 1;
 560             
 561             	parse_resources:
 562             	  /* Register needed resources. */
 563             	  cp = GET_TOKEN (resources);
 564             	  if (cp == NULL)
 565             	    /* Get the next line. */
 566             	    continue;
 567             
 568 rizwank 1.1 	  if (MATCH (cp, "font"))
 569             	    {
 570             	      for (cp = GET_TOKEN (NULL); cp; cp = GET_TOKEN (NULL))
 571             		/* Is this font already known? */
 572             		if (!strhash_get (res_fonts, cp, strlen (cp) + 1,
 573             				  (void **) &cp2))
 574             		  {
 575             		    /* Not it is not,  we must include this resource. */
 576             		    fprintf (ofp, "%%%%IncludeResource: font %s\n", cp);
 577             
 578             		    /*
 579             		     * And register that this resource is needed in
 580             		     * this document.
 581             		     */
 582             		    strhash_put (res_fonts, cp, strlen (cp) + 1, NULL, NULL);
 583             		  }
 584             
 585             	      /* Do not pass this DSC row to the output. */
 586             	      continue;
 587             	    }
 588             	  else
 589 rizwank 1.1 	    /* Unknown resource, ignore. */
 590             	    continue;
 591             	}
 592                   else if (pending_comment
 593             	       && strncmp (buf, CONT_DSC, strlen (CONT_DSC)) == 0)
 594             	{
 595             	  strcpy (resources, buf + strlen (CONT_DSC));
 596             	  goto parse_resources;
 597             	}
 598                   else
 599             	pending_comment = 0;
 600             
 601                   /*
 602                    * `%Format' directive?
 603                    */
 604             #define DIRECTIVE_FORMAT "%Format:"
 605                   if (strncmp (buf, DIRECTIVE_FORMAT, strlen (DIRECTIVE_FORMAT)) == 0)
 606             	{
 607             	  int i, j;
 608             	  char name[256];
 609             	  char *cp, *cp2;
 610 rizwank 1.1 	  errno = 0;
 611             
 612             	  /* Skip the leading whitespace. */
 613             	  for (i = strlen (DIRECTIVE_FORMAT); buf[i] && isspace (buf[i]); i++)
 614             	    ;
 615             	  if (!buf[i])
 616             	    FATAL ((stderr, _("%s:%d: %%Format: no name"),
 617             		    buffer_ptr (ctx.fullname), line));
 618             
 619             	  /* Copy name. */
 620             	  for (j = 0;
 621             	       j < sizeof (name) - 1 && buf[i] && !isspace (buf[i]);
 622             	       i++)
 623             	    name[j++] = buf[i];
 624             	  name[j] = '\0';
 625             
 626             	  if (j >= sizeof (name) - 1)
 627             	    FATAL ((stderr, _("%s:%d: %%Format: too long name, maxlen=%d"),
 628             		    buffer_ptr (ctx.fullname), line, sizeof (name) - 1));
 629             
 630             	  /* Find the start of the format string. */
 631 rizwank 1.1 	  for (; buf[i] && isspace (buf[i]); i++)
 632             	    ;
 633             
 634             	  /* Find the end. */
 635             	  j = strlen (buf);
 636             	  for (j--; isspace (buf[j]) && j > i; j--)
 637             	    ;
 638             	  j++;
 639             
 640             	  MESSAGE (2, (stderr, "%%Format: %s %.*s\n", name, j - i, buf + i));
 641             
 642             	  cp = xmalloc (j - i + 1);
 643             	  memcpy (cp, buf + i, j - i);
 644             	  cp[j - i] = '\0';
 645             
 646             	  strhash_put (user_strings, name, strlen (name) + 1, cp,
 647             		       (void **) &cp2);
 648             	  if (cp2)
 649             	    FATAL ((stderr,
 650             		    _("%s:%d: %%Format: name \"%s\" is already defined"),
 651             		    buffer_ptr (ctx.fullname), line, name));
 652 rizwank 1.1 
 653             	  /* All done with the `%Format' directive. */
 654             	  continue;
 655             	}
 656             
 657                   /*
 658                    * `%HeaderHeight' directive?
 659                    */
 660             #define DIRECTIVE_HEADERHEIGHT "%HeaderHeight:"
 661                   if (strncmp (buf, DIRECTIVE_HEADERHEIGHT,
 662             		   strlen (DIRECTIVE_HEADERHEIGHT)) == 0)
 663             	  {
 664             	    int i;
 665             
 666             	    /* Find the start of the pts argument. */
 667             	    for (i = strlen (DIRECTIVE_HEADERHEIGHT);
 668             		 buf[i] && !isspace (buf[i]); i++)
 669             	      ;
 670             	    if (!buf[i])
 671             	      FATAL ((stderr, _("%s:%d: %%HeaderHeight: no argument"),
 672             		      buffer_ptr (ctx.fullname), line));
 673 rizwank 1.1 
 674             	    d_header_h = atoi (buf + i);
 675             	    MESSAGE (2, (stderr, "%%HeaderHeight: %d\n", d_header_h));
 676             	    continue;
 677             	  }
 678             
 679                   /*
 680                    * `%FooterHeight' directive?
 681                    */
 682             #define DIRECTIVE_FOOTERHEIGHT "%FooterHeight:"
 683                   if (strncmp (buf, DIRECTIVE_FOOTERHEIGHT,
 684             		   strlen (DIRECTIVE_FOOTERHEIGHT)) == 0)
 685             	{
 686             	  int i;
 687             
 688             	  /* Find the start of the pts argument. */
 689             	  for (i = strlen (DIRECTIVE_FOOTERHEIGHT);
 690             	       buf[i] && !isspace (buf[i]); i++)
 691             	    ;
 692             	  if (!buf[i])
 693             	    FATAL ((stderr, _("%s:%d: %%FooterHeight: no argument"),
 694 rizwank 1.1 		    buffer_ptr (ctx.fullname), line));
 695             
 696             	  d_footer_h = atoi (buf + i);
 697             	  MESSAGE (2, (stderr, "%%FooterHeight: %d\n", d_footer_h));
 698             	  continue;
 699             	}
 700             
 701                   /* Nothing special, just copy it to the output. */
 702                   fputs (buf, ofp);
 703                 }
 704             
 705               fclose (fp);
 706               buffer_free (ctx.fullname);
 707             
 708               return 1;
 709             }
 710             
 711             
 712             int
 713             parse_font_spec (char *spec_a, char **name_return, FontPoint *size_return,
 714             		 InputEncoding *encoding_return)
 715 rizwank 1.1 {
 716               int i, j;
 717               char *cp, *cp2;
 718               char *spec;
 719               char *encp;
 720             
 721               spec = xstrdup (spec_a);
 722             
 723               /* Check for the `namesize:encoding' format. */
 724               encp = strrchr (spec, ':');
 725               if (encp)
 726                 {
 727                   *encp = '\0';
 728                   encp++;
 729                 }
 730             
 731               /* The `name@ptsize' format? */
 732               cp = strchr (spec, '@');
 733               if (cp)
 734                 {
 735                   i = cp - spec;
 736 rizwank 1.1       if (cp[1] == '\0')
 737             	{
 738             	  /* No ptsize after '@'. */
 739             	  xfree (spec);
 740             	  return 0;
 741             	}
 742                   cp++;
 743                 }
 744               else
 745                 {
 746                   /* The old `nameptsize' format. */
 747                   i = strlen (spec) - 1;
 748                   if (i <= 0 || !ISNUMBERDIGIT (spec[i]))
 749             	{
 750             	  xfree (spec);
 751             	  return 0;
 752             	}
 753             
 754                   for (i--; i >= 0 && ISNUMBERDIGIT (spec[i]); i--)
 755             	;
 756                   if (i < 0)
 757 rizwank 1.1 	{
 758             	  xfree (spec);
 759             	  return 0;
 760             	}
 761                   if (spec[i] == '/')
 762             	{
 763             	  /* We accept one slash for the `pt/pt' format. */
 764             	  for (i--; i >= 0 && ISNUMBERDIGIT (spec[i]); i--)
 765             	    ;
 766             	  if (i < 0)
 767             	    {
 768             	      xfree (spec);
 769             	      return 0;
 770             	    }
 771             	}
 772                   i++;
 773             
 774                   /* Now, <i> points to the end of the name.  Let's set the <cp>
 775                      to the beginning of the point size and share a little code
 776                      with the other format. */
 777                   cp = spec + i;
 778 rizwank 1.1     }
 779             
 780               /* Check the font point size. */
 781               cp2 = strchr (cp, '/');
 782               if (cp2)
 783                 {
 784                   *cp2++ = '\0';
 785                   size_return->w = atof (cp);
 786                   size_return->h = atof (cp2);
 787                 }
 788               else
 789                 size_return->w = size_return->h = atof (cp);
 790             
 791               /* Extract the font name. */
 792               *name_return = (char *) xcalloc (1, i + 1);
 793               strncpy (*name_return, spec, i);
 794             
 795               /* Check the input encoding. */
 796               if (encp)
 797                 {
 798                   int found = 0;
 799 rizwank 1.1 
 800                   if (encoding_return == NULL)
 801             	{
 802             	  /* We don't allow it here. */
 803             	  xfree (spec);
 804             	  return 0;
 805             	}
 806             
 807                   for (i = 0; !found && encodings[i].names[0]; i++)
 808             	for (j = 0; j < 3; j++)
 809             	  if (encodings[i].names[j] != NULL && MATCH (encodings[i].names[j],
 810             						      encp))
 811             	    {
 812             	      /* Found a match. */
 813             	      *encoding_return = encodings[i].encoding;
 814             	      encp = encodings[i].names[0];
 815             	      found = 1;
 816             	      break;
 817             	    }
 818             
 819                   if (!found)
 820 rizwank 1.1 	{
 821             	  xfree (spec);
 822             	  return 0;
 823             	}
 824                 }
 825               else
 826                 {
 827                   /* The spec didn't contain the encoding part.  Use our global default. */
 828                   encp = encoding_name;
 829                   if (encoding_return)
 830             	*encoding_return = encoding;
 831                 }
 832               xfree (spec);
 833             
 834               MESSAGE (2, (stderr,
 835             	       "parse_font_spec(): name=%.*s, size=%g/%g, encoding=%s\n", i,
 836             	       *name_return, size_return->w, size_return->h,
 837             	       encp));
 838             
 839               if (size_return->w < 0.0 && size_return->h < 0.0)
 840                 MESSAGE (0, (stderr, _("%s: warning: font size is negative\n"), program));
 841 rizwank 1.1   else if (size_return->w < 0.0)
 842                 MESSAGE (0, (stderr, _("%s: warning: font width is negative\n"), program));
 843               else if (size_return->h < 0.0)
 844                 MESSAGE (0, (stderr, _("%s: warning: font height is negative\n"),
 845             		 program));
 846             
 847               return 1;
 848             }
 849             
 850             
 851             void
 852             read_font_info (void)
 853             {
 854               CachedFontInfo *font_info;
 855               AFMFont font;
 856               int font_info_cached = 1;
 857               int font_cached = 1;
 858               int i;
 859               unsigned int enc_flags = 0;
 860               char buf[256];
 861               Buffer fkey;
 862 rizwank 1.1 
 863               MESSAGE (2, (stderr, _("reading AFM info for font \"%s\"\n"), Fname));
 864             
 865               if (accept_composites)
 866                 enc_flags = AFM_ENCODE_ACCEPT_COMPOSITES;
 867             
 868               /* Open font */
 869             
 870               buffer_init (&fkey);
 871             
 872               buffer_append (&fkey, Fname);
 873               sprintf (buf, "@%f:%d", Fpt.w, encoding);
 874               buffer_append (&fkey, buf);
 875             
 876               if (!strhash_get (afm_info_cache, buffer_ptr (&fkey),
 877             		    strlen (buffer_ptr (&fkey)), (void **) &font_info))
 878                 {
 879                   AFMError error;
 880             
 881                   /* Couldn't find it from our cache, open open AFM file. */
 882                   if (!strhash_get (afm_cache, Fname, strlen (Fname), (void **) &font))
 883 rizwank 1.1 	{
 884             	  /* AFM file was not cached, open it from disk. */
 885             	  error = afm_open_font (afm, AFM_I_COMPOSITES, Fname, &font);
 886             	  if (error != AFM_SUCCESS)
 887             	    {
 888             #define COUR "Courier"
 889             	      /*
 890             	       * Do not report failures for "Courier*" fonts because
 891             	       * AFM library's default font will fix them.
 892             	       */
 893             	      if (strncmp (Fname, COUR, strlen (COUR)) != 0)
 894             		MESSAGE (0,
 895             			 (stderr,
 896             			  _("couldn't open AFM file for font \"%s\", using default\n"),
 897             			  Fname));
 898             	      error = afm_open_default_font (afm, &font);
 899             	      if (error != AFM_SUCCESS)
 900             		{
 901             		  afm_error_to_string (error, buf);
 902             		  FATAL ((stderr,
 903             			  _("couldn't open AFM file for the default font: %s"),
 904 rizwank 1.1 			  buf));
 905             		}
 906             	    }
 907             
 908             	  /* Apply encoding. */
 909             	  switch (encoding)
 910             	    {
 911             	    case ENC_ISO_8859_1:
 912             	      (void) afm_font_encoding (font, AFM_ENCODING_ISO_8859_1,
 913             					enc_flags);
 914             	      break;
 915             
 916             	    case ENC_ISO_8859_2:
 917             	      (void) afm_font_encoding (font, AFM_ENCODING_ISO_8859_2,
 918             					enc_flags);
 919             	      break;
 920             
 921             	    case ENC_ISO_8859_3:
 922             	      (void) afm_font_encoding (font, AFM_ENCODING_ISO_8859_3,
 923             					enc_flags);
 924             	      break;
 925 rizwank 1.1 
 926             	    case ENC_ISO_8859_4:
 927             	      (void) afm_font_encoding (font, AFM_ENCODING_ISO_8859_4,
 928             					enc_flags);
 929             	      break;
 930             
 931             	    case ENC_ISO_8859_5:
 932             	      (void) afm_font_encoding (font, AFM_ENCODING_ISO_8859_5,
 933             					enc_flags);
 934             	      break;
 935             
 936             	    case ENC_ISO_8859_7:
 937             	      (void) afm_font_encoding (font, AFM_ENCODING_ISO_8859_7,
 938             					enc_flags);
 939             	      break;
 940             
 941             	    case ENC_ISO_8859_9:
 942             	      (void) afm_font_encoding (font, AFM_ENCODING_ISO_8859_9,
 943             					enc_flags);
 944             	      break;
 945             
 946 rizwank 1.1 	    case ENC_ISO_8859_10:
 947             	      (void) afm_font_encoding (font, AFM_ENCODING_ISO_8859_10,
 948             					enc_flags);
 949             	      break;
 950             
 951             	    case ENC_ASCII:
 952             	      (void) afm_font_encoding (font, AFM_ENCODING_ASCII, enc_flags);
 953             	      break;
 954             
 955             	    case ENC_ASCII_FISE:
 956             	      /* First apply standard 7bit ASCII encoding. */
 957             	      (void) afm_font_encoding (font, AFM_ENCODING_ASCII, enc_flags);
 958             
 959             	      /* Then add those scand characters. */
 960             	      for (i = 0; enc_7bit_ascii_fise[i].name; i++)
 961             		(void) afm_font_encode (font, enc_7bit_ascii_fise[i].code,
 962             					enc_7bit_ascii_fise[i].name,
 963             					enc_flags);
 964             	      break;
 965             
 966             	    case ENC_ASCII_DKNO:
 967 rizwank 1.1 	      /* First apply standard 7bit ASCII encoding. */
 968             	      (void) afm_font_encoding (font, AFM_ENCODING_ASCII, enc_flags);
 969             
 970             	      /* Then add those scand characters. */
 971             	      for (i = 0; enc_7bit_ascii_dkno[i].name; i++)
 972             		(void) afm_font_encode (font, enc_7bit_ascii_dkno[i].code,
 973             					enc_7bit_ascii_dkno[i].name,
 974             					enc_flags);
 975             	      break;
 976             
 977             	    case ENC_IBMPC:
 978             	      (void) afm_font_encoding (font, AFM_ENCODING_IBMPC, enc_flags);
 979             	      break;
 980             
 981             	    case ENC_MAC:
 982             	      (void) afm_font_encoding (font, AFM_ENCODING_MAC, enc_flags);
 983             	      break;
 984             
 985             	    case ENC_VMS:
 986             	      (void) afm_font_encoding (font, AFM_ENCODING_VMS, enc_flags);
 987             	      break;
 988 rizwank 1.1 
 989             	    case ENC_HP8:
 990             	      (void) afm_font_encoding (font, AFM_ENCODING_HP8, enc_flags);
 991             	      break;
 992             
 993             	    case ENC_KOI8:
 994             	      (void) afm_font_encoding (font, AFM_ENCODING_KOI8, enc_flags);
 995             	      break;
 996             
 997             	    case ENC_PS:
 998             	      /* Let's use font's default encoding -- nothing here. */
 999             	      break;
1000             	    }
1001             
1002             	  /* Put it to the AFM cache. */
1003             	  if (!strhash_put (afm_cache, Fname, strlen (Fname), font, NULL))
1004             	    font_cached = 0;
1005             	}
1006             
1007                   font_info = (CachedFontInfo *) xcalloc (1, sizeof (*font_info));
1008                   /* Read character widths and types. */
1009 rizwank 1.1       for (i = 0; i < 256; i++)
1010             	{
1011             	  AFMNumber w0x, w0y;
1012             
1013             	  (void) afm_font_charwidth (font, Fpt.w, i, &w0x, &w0y);
1014             	  font_info->font_widths[i] = w0x;
1015             
1016             	  if (font->encoding[i] == AFM_ENC_NONE)
1017             	    font_info->font_ctype[i] = ' ';
1018             	  else if (font->encoding[i] == AFM_ENC_NON_EXISTENT)
1019             	    font_info->font_ctype[i] = '.';
1020             	  else
1021             	    font_info->font_ctype[i] = '*';
1022             	}
1023             
1024                   font_info->font_is_fixed
1025             	= font->writing_direction_metrics[0].IsFixedPitch;
1026                   font_info->font_bbox_lly = font->global_info.FontBBox_lly;
1027             
1028                   if (!font_cached)
1029             	(void) afm_close_font (font);
1030 rizwank 1.1 
1031                   /* Store font information to the AFM information cache. */
1032                   if (!strhash_put (afm_info_cache, buffer_ptr (&fkey),
1033             			strlen (buffer_ptr (&fkey)), font_info, NULL))
1034             	font_info_cached = 0;
1035                 }
1036             
1037               /* Select character widths and types. */
1038               memcpy (font_widths, font_info->font_widths, 256 * sizeof (double));
1039               memcpy (font_ctype, font_info->font_ctype, 256);
1040             
1041               font_is_fixed = font_info->font_is_fixed;
1042               font_bbox_lly = font_info->font_bbox_lly;
1043             
1044               if (!font_info_cached)
1045                 xfree (font_info);
1046             
1047               buffer_uninit (&fkey);
1048             }
1049             
1050             
1051 rizwank 1.1 void
1052             download_font (char *name)
1053             {
1054               AFMError error;
1055               const char *prefix;
1056               struct stat stat_st;
1057               Buffer fname;
1058               unsigned char buf[4096];
1059               FILE *fp;
1060               int i;
1061               char *cp;
1062             
1063               /* Get font prefix. */
1064               error = afm_font_prefix (afm, name, &prefix);
1065               if (error != AFM_SUCCESS)
1066                 /* Font is unknown, nothing to download. */
1067                 return;
1068             
1069               /* Check if we have a font description file. */
1070             
1071               buffer_init (&fname);
1072 rizwank 1.1 
1073               /* .pfa */
1074               buffer_append (&fname, prefix);
1075               buffer_append (&fname, ".pfa");
1076               if (stat (buffer_ptr (&fname), &stat_st) != 0)
1077                 {
1078                   /* .pfb */
1079                   buffer_clear (&fname);
1080                   buffer_append (&fname, prefix);
1081                   buffer_append (&fname, ".pfb");
1082                   if (stat (buffer_ptr (&fname), &stat_st) != 0)
1083             	{
1084             	  /* Couldn't find font description file, nothing to download. */
1085             	  buffer_uninit (&fname);
1086             	  return;
1087             	}
1088                 }
1089             
1090               /* Ok, fine.  Font was found. */
1091             
1092               MESSAGE (1, (stderr, _("downloading font \"%s\"\n"), name));
1093 rizwank 1.1   fp = fopen (buffer_ptr (&fname), "rb");
1094               if (fp == NULL)
1095                 {
1096                   MESSAGE (0, (stderr,
1097             		   _("couldn't open font description file \"%s\": %s\n"),
1098             		   buffer_ptr (&fname), strerror (errno)));
1099                   buffer_uninit (&fname);
1100                   return;
1101                 }
1102               buffer_uninit (&fname);
1103             
1104               /* Dump file. */
1105               fprintf (ofp, "%%%%BeginResource: font %s\n", name);
1106             
1107               /* Check file type. */
1108               i = fgetc (fp);
1109               if (i == EOF)
1110                 {
1111                   /* Not much to do here. */
1112                   ;
1113                 }
1114 rizwank 1.1   else if (i == 128)
1115                 {
1116                   int done = 0;
1117                   unsigned int chunk;
1118                   unsigned int to_read;
1119                   int last_was_cr;
1120                   int j;
1121             
1122                   /* IBM PC Format */
1123             
1124                   ungetc (i, fp);
1125             
1126                   while (!done)
1127             	{
1128             	  /* Read 6-byte long header. */
1129             	  i = fread (buf, 1, 6, fp);
1130             	  if (i != 6)
1131             	    break;
1132             
1133             	  chunk = buf[2] | (buf[3] << 8) | (buf[4] << 16) | (buf[5] << 24);
1134             
1135 rizwank 1.1 	  /* Check chunk type. */
1136             	  switch (buf[1])
1137             	    {
1138             	    case 1:		/* ASCII */
1139             	      last_was_cr = 0;
1140             	      while (chunk > 0)
1141             		{
1142             		  to_read = sizeof (buf) < chunk ? sizeof (buf) : chunk;
1143             		  i = fread (buf, 1, to_read, fp);
1144             		  if (i == 0)
1145             		    {
1146             		      done = 1;
1147             		      break;
1148             		    }
1149             
1150             		  /* Check and fix Mac-newlines. */
1151             		  for (j = 0; j < i; j++)
1152             		    {
1153             		      if (j == 0 && last_was_cr && buf[0] != '\n')
1154             			{
1155             			  fputc ('\n', ofp);
1156 rizwank 1.1 			  fputc (buf[0], ofp);
1157             			}
1158             		      else if (buf[j] == '\r' && j + 1 < i
1159             			       && buf[j + 1] != '\n')
1160             			{
1161             			  fputc ('\n', ofp);
1162             			}
1163             		      else if (buf[j] != '\r')
1164             			fputc (buf[j], ofp);
1165             		    }
1166             
1167             		  chunk -= i;
1168             		  last_was_cr = (buf[i - 1] == '\r');
1169             		}
1170             	      break;
1171             
1172             	    case 2:		/* binary data */
1173             	      while (chunk > 0)
1174             		{
1175             		  to_read = sizeof (buf) < chunk ? sizeof (buf) : chunk;
1176             		  i = fread (buf, 1, to_read, fp);
1177 rizwank 1.1 		  if (i == 0)
1178             		    {
1179             		      done = 1;
1180             		      break;
1181             		    }
1182             
1183             		  for (j = 0; j < i; j++)
1184             		    {
1185             		      fprintf (ofp, "%02X", buf[j]);
1186             		      if ((j + 1) % 32 == 0)
1187             			fprintf (ofp, "\n");
1188             		    }
1189             		  chunk -= i;
1190             		}
1191             	      break;
1192             
1193             	    case 3:		/* EOF */
1194             	      done = 1;
1195             	      break;
1196             	    }
1197             
1198 rizwank 1.1 	  /* Force a linebreak after each chunk. */
1199             	  fprintf (ofp, "\n");
1200             	}
1201                 }
1202               else
1203                 {
1204                   /* Plain ASCII. */
1205                   ungetc (i, fp);
1206                   while ((i = fread (buf, 1, sizeof (buf), fp)) != 0)
1207             	fwrite (buf, 1, i, ofp);
1208                 }
1209             
1210               fprintf (ofp, "%%%%EndResource\n");
1211             
1212               /* Remove font from needed resources. */
1213               (void) strhash_delete (res_fonts, name, strlen (name) + 1, (void **) &cp);
1214             
1215               fclose (fp);
1216             }
1217             
1218             
1219 rizwank 1.1 char *
1220             escape_string (char *string)
1221             {
1222               int i, j;
1223               int len;
1224               char *cp;
1225             
1226               /* Count the length of the result string. */
1227               for (len = 0, i = 0; string[i]; i++)
1228                 switch (string[i])
1229                   {
1230                   case '(':
1231                   case ')':
1232                   case '\\':
1233             	len += 2;
1234             	break;
1235             
1236                   default:
1237             	len++;
1238                   }
1239             
1240 rizwank 1.1   /* Create result. */
1241               cp = xmalloc (len + 1);
1242               for (i = 0, j = 0; string[i]; i++)
1243                 switch (string[i])
1244                   {
1245                   case '(':
1246                   case ')':
1247                   case '\\':
1248             	cp[j++] = '\\';
1249             	/* FALLTHROUGH */
1250             
1251                   default:
1252             	cp[j++] = string[i];
1253             	break;
1254                   }
1255               cp[j++] = '\0';
1256             
1257               return cp;
1258             }
1259             
1260             
1261 rizwank 1.1 
1262             /*
1263              * Help macros for the format_user_string() function.
1264              */
1265             
1266             #define NEED_NBYTES(n) 				\
1267               do {						\
1268                 if (rbufpos + (n) >= rbuflen)		\
1269                   {						\
1270                     rbuflen += (n) + 1024;			\
1271                     rbuf = xrealloc (rbuf, rbuflen);	\
1272                   }						\
1273               } while (0)
1274             
1275             #define APPEND_CH(ch)				\
1276               do {						\
1277                 int a;					\
1278                 NEED_NBYTES (width);			\
1279                 if (width && justification < 0)		\
1280                   rbuf[rbufpos++] = (ch);			\
1281                 for (a = 0; a < width - 1; a++)		\
1282 rizwank 1.1       rbuf[rbufpos++] = ' ';			\
1283                 if (!width || justification > 0)		\
1284                   rbuf[rbufpos++] = (ch);			\
1285               } while (0)
1286             
1287             #define APPEND_STR(str)				\
1288               do {						\
1289                 int len = strlen ((str));			\
1290                 int nspace;					\
1291             						\
1292                 if (len > width)				\
1293                   nspace = 0;				\
1294                 else					\
1295                   nspace = width - len;			\
1296             						\
1297                 NEED_NBYTES (nspace + len);			\
1298                 if (width && justification > 0)		\
1299                   for (; nspace; nspace--)			\
1300             	rbuf[rbufpos++] = ' ';			\
1301             						\
1302                 memcpy (rbuf + rbufpos, str, len);		\
1303 rizwank 1.1     rbufpos += len;				\
1304             						\
1305                 if (width && justification < 0)		\
1306                   for (; nspace; nspace--)			\
1307             	rbuf[rbufpos++] = ' ';			\
1308               } while (0)
1309             
1310             char *
1311             format_user_string (char *context_name, char *str)
1312             {
1313               char *cp;
1314               char *rbuf = NULL;
1315               int rbuflen = 0;
1316               int rbufpos = 0;
1317               int i = 0;
1318               int j;
1319               char buf[512];
1320               char buf2[512];
1321               int width = 0;
1322               int justification = 1;
1323             
1324 rizwank 1.1   /* Format string. */
1325               for (i = 0; str[i] != '\0'; i++)
1326                 {
1327                   int type;
1328             
1329                   type = str[i];
1330             
1331                   if (type == '%' || type == '$')
1332             	{
1333             	  i++;
1334             	  width = 0;
1335             	  justification = 1;
1336             
1337             	  /* Get optional width and justification. */
1338             	  if (str[i] == '-')
1339             	    {
1340             	      i++;
1341             	      justification = -1;
1342             	    }
1343             	  while (isdigit (str[i]))
1344             	    width = width * 10 + str[i++] - '0';
1345 rizwank 1.1 
1346             	  /* Handle escapes. */
1347             	  if (type == '%')
1348             	    {
1349             	      /* General state related %-escapes. */
1350             	      switch (str[i])
1351             		{
1352             		case '%':	/* `%%' character `%' */
1353             		  APPEND_CH ('%');
1354             		  break;
1355             
1356             		case 'c':	/* `%c' trailing component of pwd. */
1357             		  getcwd (buf, sizeof (buf));
1358             		  cp = strrchr (buf, '/');
1359             		  if (cp)
1360             		    cp++;
1361             		  else
1362             		    cp = buf;
1363             		  APPEND_STR (cp);
1364             		  break;
1365             
1366 rizwank 1.1 		case 'C':	/* `%C' runtime in `hh:mm:ss' format */
1367             		  sprintf (buf, "%02d:%02d:%02d", run_tm.tm_hour,
1368             			   run_tm.tm_min, run_tm.tm_sec);
1369             		  APPEND_STR (buf);
1370             		  break;
1371             
1372             		case 'd':	/* `%d' current working directory */
1373             		  getcwd (buf, sizeof (buf));
1374             		  APPEND_STR (buf);
1375             		  break;
1376             
1377             		case 'D':
1378             		  if (str[i + 1] == '{')
1379             		    {
1380             		      /* `%D{}' format run date with strftime() */
1381             		      for (j = 0, i += 2;
1382             			   j < sizeof (buf2) && str[i] && str[i] != '}';
1383             			   i++, j++)
1384             			buf2[j] = str[i];
1385             		      if (str[i] != '}')
1386             			FATAL ((stderr,
1387 rizwank 1.1 				_("%s: too long format for %%D{} escape"),
1388             				context_name));
1389             
1390             		      buf2[j] = '\0';
1391             		      strftime (buf, sizeof (buf), buf2, &run_tm);
1392             		    }
1393             		  else
1394             		    {
1395             		      /* `%D' run date in `yy-mm-dd' format */
1396             		      sprintf (buf, "%02d-%02d-%02d", run_tm.tm_year % 100,
1397             			       run_tm.tm_mon + 1, run_tm.tm_mday);
1398             		    }
1399             		  APPEND_STR (buf);
1400             		  break;
1401             
1402             		case 'E':	/* `%E' run date in `yy/mm/dd' format */
1403             		  sprintf (buf, "%02d/%02d/%02d", run_tm.tm_year % 100,
1404             			   run_tm.tm_mon + 1, run_tm.tm_mday);
1405             		  APPEND_STR (buf);
1406             		  break;
1407             
1408 rizwank 1.1 		case 'F':	/* `%F' run date in `dd.mm.yyyy' format */
1409             		  sprintf (buf, "%d.%d.%d",
1410             			   run_tm.tm_mday,
1411             			   run_tm.tm_mon + 1,
1412             			   run_tm.tm_year + 1900);
1413             		  APPEND_STR (buf);
1414             		  break;
1415             
1416             		case 'H':	/* `%H' document title */
1417             		  APPEND_STR (title);
1418             		  break;
1419             
1420             		case 'm':	/* `%m' the hostname up to the first `.' */
1421             		  (void) gethostname (buf, sizeof (buf));
1422             		  cp = strchr (buf, '.');
1423             		  if (cp)
1424             		    *cp = '\0';
1425             		  APPEND_STR (buf);
1426             		  break;
1427             
1428             		case 'M':	/* `%M' the full hostname */
1429 rizwank 1.1 		  (void) gethostname (buf, sizeof (buf));
1430             		  APPEND_STR (buf);
1431             		  break;
1432             
1433             		case 'n':	/* `%n' username */
1434             		  APPEND_STR (passwd->pw_name);
1435             		  break;
1436             
1437             		case 'N':	/* `%N' pw_gecos up to the first `,' char */
1438             		  strcpy (buf, passwd->pw_gecos);
1439             		  cp = strchr (buf, ',');
1440             		  if (cp)
1441             		    *cp = '\0';
1442             		  APPEND_STR (buf);
1443             		  break;
1444             
1445             		case 't':	/* `%t' runtime in 12-hour am/pm format */
1446             		  sprintf (buf, "%d:%d%s",
1447             			   run_tm.tm_hour > 12
1448             			   ? run_tm.tm_hour - 12 : run_tm.tm_hour,
1449             			   run_tm.tm_min,
1450 rizwank 1.1 			   run_tm.tm_hour > 12 ? "pm" : "am");
1451             		  APPEND_STR (buf);
1452             		  break;
1453             
1454             		case 'T':	/* `%T' runtime in 24-hour format */
1455             		  sprintf (buf, "%d:%d", run_tm.tm_hour, run_tm.tm_min);
1456             		  APPEND_STR (buf);
1457             		  break;
1458             
1459             		case '*':	/* `%*' runtime in 24-hour format with secs */
1460             		  sprintf (buf, "%d:%d:%d", run_tm.tm_hour, run_tm.tm_min,
1461             			   run_tm.tm_sec);
1462             		  APPEND_STR (buf);
1463             		  break;
1464             
1465             		case 'W':	/* `%W' run date in `mm/dd/yy' format */
1466             		  sprintf (buf, "%02d/%02d/%02d", run_tm.tm_mon + 1,
1467             			   run_tm.tm_mday, run_tm.tm_year % 100);
1468             		  APPEND_STR (buf);
1469             		  break;
1470             
1471 rizwank 1.1 		default:
1472             		  FATAL ((stderr, _("%s: unknown `%%' escape `%c' (%d)"),
1473             			  context_name, str[i], str[i]));
1474             		  break;
1475             		}
1476             	    }
1477             	  else
1478             	    {
1479             	      /* Input file related $-escapes. */
1480             	      switch (str[i])
1481             		{
1482             		case '$':	/* `$$' character `$' */
1483             		  APPEND_CH ('$');
1484             		  break;
1485             
1486             		case '%':	/* `$%' current page number */
1487             		  if (slicing)
1488             		    sprintf (buf, "%d%c", current_pagenum, slice - 1 + 'A');
1489             		  else
1490             		    sprintf (buf, "%d", current_pagenum);
1491             		  APPEND_STR (buf);
1492 rizwank 1.1 		  break;
1493             
1494             		case '=':	/* `$=' number of pages in this file */
1495             		  APPEND_CH ('\001');
1496             		  break;
1497             
1498             		case 'p':	/* `$p' number of pages processed so far */
1499             		  sprintf (buf, "%d", total_pages);
1500             		  APPEND_STR (buf);
1501             		  break;
1502             
1503             		case '(':	/* $(ENVVAR)  */
1504             		  for (j = 0, i++;
1505             		       str[i] && str[i] != ')' && j < sizeof (buf) - 1;
1506             		       i++)
1507             		    buf[j++] = str[i];
1508             
1509             		  if (str[i] == '\0')
1510             		    FATAL ((stderr, _("%s: no closing ')' for $() escape"),
1511             			    context_name));
1512             		  if (str[i] != ')')
1513 rizwank 1.1 		    FATAL ((stderr, _("%s: too long variable name for $() escape"),
1514             			    context_name));
1515             
1516             		  buf[j] = '\0';
1517             
1518             		  cp = getenv (buf);
1519             		  if (cp == NULL)
1520             		    cp = "";
1521             		  APPEND_STR (cp);
1522             		  break;
1523             
1524             		case 'C':	/* `$C' modtime in `hh:mm:ss' format */
1525             		  sprintf (buf, "%02d:%02d:%02d", mod_tm.tm_hour,
1526             			   mod_tm.tm_min, mod_tm.tm_sec);
1527             		  APPEND_STR (buf);
1528             		  break;
1529             
1530             		case 'D':
1531             		  if (str[i + 1] == '{')
1532             		    {
1533             		      /* `$D{}' format modification date with strftime() */
1534 rizwank 1.1 		      for (j = 0, i += 2;
1535             			   j < sizeof (buf2) && str[i] && str[i] != '}';
1536             			   i++, j++)
1537             			buf2[j] = str[i];
1538             		      if (str[i] != '}')
1539             			FATAL ((stderr,
1540             				_("%s: too long format for $D{} escape"),
1541             				context_name));
1542             
1543             		      buf2[j] = '\0';
1544             		      strftime (buf, sizeof (buf), buf2, &mod_tm);
1545             		    }
1546             		  else
1547             		    {
1548             		      /* `$D' mod date in `yy-mm-dd' format */
1549             		      sprintf (buf, "%02d-%02d-%02d", mod_tm.tm_year % 100,
1550             			       mod_tm.tm_mon + 1, mod_tm.tm_mday);
1551             		    }
1552             		  APPEND_STR (buf);
1553             		  break;
1554             
1555 rizwank 1.1 		case 'E':	/* `$E' mod date in `yy/mm/dd' format */
1556             		  sprintf (buf, "%02d/%02d/%02d", mod_tm.tm_year % 100,
1557             			   mod_tm.tm_mon + 1, mod_tm.tm_mday);
1558             		  APPEND_STR (buf);
1559             		  break;
1560             
1561             		case 'F':	/* `$F' run date in `dd.mm.yyyy' format */
1562             		  sprintf (buf, "%d.%d.%d",
1563             			   mod_tm.tm_mday,
1564             			   mod_tm.tm_mon + 1,
1565             			   mod_tm.tm_year + 1900);
1566             		  APPEND_STR (buf);
1567             		  break;
1568             
1569             		case 't':	/* `$t' runtime in 12-hour am/pm format */
1570             		  sprintf (buf, "%d:%d%s",
1571             			   mod_tm.tm_hour > 12
1572             			   ? mod_tm.tm_hour - 12 : mod_tm.tm_hour,
1573             			   mod_tm.tm_min,
1574             			   mod_tm.tm_hour > 12 ? "pm" : "am");
1575             		  APPEND_STR (buf);
1576 rizwank 1.1 		  break;
1577             
1578             		case 'T':	/* `$T' runtime in 24-hour format */
1579             		  sprintf (buf, "%d:%d", mod_tm.tm_hour, mod_tm.tm_min);
1580             		  APPEND_STR (buf);
1581             		  break;
1582             
1583             		case '*':	/* `$*' runtime in 24-hour format with secs */
1584             		  sprintf (buf, "%d:%d:%d", mod_tm.tm_hour, mod_tm.tm_min,
1585             			   mod_tm.tm_sec);
1586             		  APPEND_STR (buf);
1587             		  break;
1588             
1589             		case 'v':	/* `$v': input file number */
1590             		  sprintf (buf, "%d", input_filenum);
1591             		  APPEND_STR (buf);
1592             		  break;
1593             
1594             		case 'V':	/* `$V': input file number in --toc format */
1595             		  if (toc)
1596             		    {
1597 rizwank 1.1 		      sprintf (buf, "%d-", input_filenum);
1598             		      APPEND_STR (buf);
1599             		    }
1600             		  break;
1601             
1602             		case 'W':	/* `$W' run date in `mm/dd/yy' format */
1603             		  sprintf (buf, "%02d/%02d/%02d", mod_tm.tm_mon + 1,
1604             			   mod_tm.tm_mday, mod_tm.tm_year % 100);
1605             		  APPEND_STR (buf);
1606             		  break;
1607             
1608             		case 'N':	/* `$N' the full name of the printed file */
1609             		  APPEND_STR (fname);
1610             		  break;
1611             
1612             		case 'n':	/* `$n' input file name without directory */
1613             		  cp = strrchr (fname, '/');
1614             		  if (cp)
1615             		    cp++;
1616             		  else
1617             		    cp = fname;
1618 rizwank 1.1 		  APPEND_STR (cp);
1619             		  break;
1620             
1621             		case 'L':	/* `$L' number of lines in this file. */
1622             		  /* This is valid only for TOC-strings. */
1623             		  sprintf (buf, "%d", current_file_linenum - 1);
1624             		  APPEND_STR (buf);
1625             		  break;
1626             
1627             		default:
1628             		  FATAL ((stderr, _("%s: unknown `$' escape `%c' (%d)"),
1629             			  context_name, str[i], str[i]));
1630             		  break;
1631             		}
1632             	    }
1633             	  /* Reset width so the else-arm goes ok at the next round. */
1634             	  width = 0;
1635             	  justification = 1;
1636             	}
1637                   else
1638             	APPEND_CH (str[i]);
1639 rizwank 1.1     }
1640               APPEND_CH ('\0');
1641             
1642               /* Escape PS specials. */
1643               cp = escape_string (rbuf);
1644               xfree (rbuf);
1645             
1646               return cp;
1647             }
1648             
1649             
1650             void
1651             parse_key_value_pair (StringHashPtr set, char *kv)
1652             {
1653               char *cp;
1654               Buffer key;
1655             
1656               cp = strchr (kv, ':');
1657               if (cp == NULL)
1658                 {
1659                   if (strhash_delete (set, kv, strlen (kv) + 1, (void **) &cp))
1660 rizwank 1.1 	xfree (cp);
1661                 }
1662               else
1663                 {
1664                   buffer_init (&key);
1665                   buffer_append_len (&key, kv, cp - kv);
1666             
1667                   strhash_put (set, buffer_ptr (&key), strlen (buffer_ptr (&key)) + 1,
1668             		   xstrdup (cp + 1), (void **) &cp);
1669                   if (cp)
1670             	xfree (cp);
1671             
1672                   buffer_uninit (&key);
1673                 }
1674             }
1675             
1676             
1677             int
1678             count_key_value_set (StringHashPtr set)
1679             {
1680               int i = 0, got, j;
1681 rizwank 1.1   char *cp;
1682               void *value;
1683             
1684               for (got = strhash_get_first (set, &cp, &j, &value); got;
1685                    got = strhash_get_next (set, &cp, &j, &value))
1686                 i++;
1687             
1688               return i;
1689             }
1690             
1691             
1692             int
1693             pathwalk (char *path, PathWalkProc proc, void *context)
1694             {
1695               char buf[512];
1696               char *cp;
1697               char *cp2;
1698               int len, i;
1699             
1700               for (cp = path; cp; cp = strchr (cp, PATH_SEPARATOR))
1701                 {
1702 rizwank 1.1       if (cp != path)
1703             	cp++;
1704             
1705                   cp2 = strchr (cp, PATH_SEPARATOR);
1706                   if (cp2)
1707             	len = cp2 - cp;
1708                   else
1709             	len = strlen (cp);
1710             
1711                   memcpy (buf, cp, len);
1712                   buf[len] = '\0';
1713             
1714                   i = (*proc) (buf, context);
1715                   if (i != 0)
1716             	return i;
1717                 }
1718             
1719               return 0;
1720             }
1721             
1722             
1723 rizwank 1.1 int
1724             file_lookup (char *path, void *context)
1725             {
1726               int len;
1727               FileLookupCtx *ctx = context;
1728               struct stat stat_st;
1729               int i;
1730             
1731               MESSAGE (2, (stderr, "file_lookup(): %s/%s%s\t", path, ctx->name,
1732             	       ctx->suffix));
1733             
1734               len = strlen (path);
1735               if (len && path[len - 1] == '/')
1736                 len--;
1737             
1738               buffer_clear (ctx->fullname);
1739               buffer_append_len (ctx->fullname, path, len);
1740               buffer_append (ctx->fullname, "/");
1741               buffer_append (ctx->fullname, ctx->name);
1742               buffer_append (ctx->fullname, ctx->suffix);
1743             
1744 rizwank 1.1   i = stat (buffer_ptr (ctx->fullname), &stat_st) == 0;
1745             
1746               MESSAGE (2, (stderr, "#%c\n", i ? 't' : 'f'));
1747             
1748               return i;
1749             }
1750             
1751             
1752             char *
1753             tilde_subst (char *fname)
1754             {
1755               char *cp;
1756               int i;
1757               struct passwd *pswd;
1758               Buffer buffer;
1759               char *result;
1760             
1761               if (fname[0] != '~')
1762                 return xstrdup (fname);
1763             
1764               if (fname[1] == '/' || fname[1] == '\0')
1765 rizwank 1.1     {
1766                   /* The the user's home directory from the `HOME' environment
1767                      variable. */
1768                   cp = getenv ("HOME");
1769                   if (cp == NULL)
1770             	return xstrdup (fname);
1771             
1772                   buffer_init (&buffer);
1773                   buffer_append (&buffer, cp);
1774                   buffer_append (&buffer, fname + 1);
1775             
1776                   result = buffer_copy (&buffer);
1777                   buffer_uninit (&buffer);
1778             
1779                   return result;
1780                 }
1781             
1782               /* Get user's login name. */
1783               for (i = 1; fname[i] && fname[i] != '/'; i++)
1784                 ;
1785             
1786 rizwank 1.1   buffer_init (&buffer);
1787               buffer_append_len (&buffer, fname + 1, i - 1);
1788             
1789               pswd = getpwnam (buffer_ptr (&buffer));
1790               buffer_uninit (&buffer);
1791             
1792               if (pswd)
1793                 {
1794                   /* Found passwd entry. */
1795                   buffer_init (&buffer);
1796                   buffer_append (&buffer, pswd->pw_dir);
1797                   buffer_append (&buffer, fname + i);
1798             
1799                   result = buffer_copy (&buffer);
1800                   buffer_uninit (&buffer);
1801             
1802                   return result;
1803                 }
1804             
1805               /* No match found. */
1806               return xstrdup (fname);
1807 rizwank 1.1 }
1808             
1809             
1810             double
1811             parse_float (char *string, int units, int horizontal)
1812             {
1813               double val;
1814               char *end;
1815             
1816               val = strtod (string, &end);
1817               if (end == string)
1818               malformed_float:
1819                 ERROR ((stderr, _("malformed float dimension: \"%s\""), string));
1820             
1821               if (units)
1822                 {
1823                   switch (*end)
1824             	{
1825             	case 'c':
1826             	  val *= 72 / 2.54;
1827             	  break;
1828 rizwank 1.1 
1829             	case 'p':
1830             	  break;
1831             
1832             	case 'i':
1833             	  val *= 72;
1834             	  break;
1835             
1836             	case '\0':
1837             	  /* FALLTHROUGH */
1838             
1839             	case 'l':
1840             	  if (horizontal)
1841             	    val *= CHAR_WIDTH ('m');
1842             	  else
1843             	    val *= LINESKIP;
1844             	  break;
1845             
1846             	default:
1847             	  goto malformed_float;
1848             	  break;
1849 rizwank 1.1 	}
1850                 }
1851               else
1852                 {
1853                   if (*end != '\0')
1854             	goto malformed_float;
1855                 }
1856             
1857               return val;
1858             }
1859             
1860             
1861             /*
1862              * InputStream functions.
1863              */
1864             
1865             int
1866             is_open (InputStream *is, FILE *fp, char *fname, char *input_filter)
1867             {
1868               /* Init stream variables. */
1869               is->data_in_buf = 0;
1870 rizwank 1.1   is->bufpos = 0;
1871               is->nreads = 0;
1872               is->unget_ch = NULL;
1873               is->unget_pos = 0;
1874               is->unget_alloc = 0;
1875             
1876               /* Input filter? */
1877               if (input_filter)
1878                 {
1879                   char *cmd = NULL;
1880                   int cmdlen;
1881                   int i, pos;
1882             
1883                   is->is_pipe = 1;
1884             
1885                   if (fname == NULL)
1886             	fname = input_filter_stdin;
1887             
1888                   /*
1889                    * Count the initial command length, this will grow dynamically
1890                    * when file specifier `%s' is encountered from <input_filter>.
1891 rizwank 1.1        */
1892                   cmdlen = strlen (input_filter) + 1;
1893                   cmd = xmalloc (cmdlen);
1894             
1895                   /* Create filter command. */
1896                   pos = 0;
1897                   for (i = 0; input_filter[i]; i++)
1898             	{
1899             	  if (input_filter[i] == '%')
1900             	    {
1901             	      switch (input_filter[i + 1])
1902             		{
1903             		case 's':
1904             		  /* Expand cmd-buffer. */
1905             		  cmdlen += strlen (fname);
1906             		  cmd = xrealloc (cmd, cmdlen);
1907             
1908             		  /* Paste filename. */
1909             		  strcpy (cmd + pos, fname);
1910             		  pos += strlen (fname);
1911             
1912 rizwank 1.1 		  i++;
1913             		  break;
1914             
1915             		case '%':
1916             		  cmd[pos++] = '%';
1917             		  i++;
1918             		  break;
1919             
1920             		default:
1921             		  cmd[pos++] = input_filter[i];
1922             		  break;
1923             		}
1924             	    }
1925             	  else
1926             	    cmd[pos++] = input_filter[i];
1927             	}
1928                   cmd[pos++] = '\0';
1929             
1930                   is->fp = popen (cmd, "r");
1931                   xfree (cmd);
1932             
1933 rizwank 1.1       if (is->fp == NULL)
1934             	{
1935             	  ERROR ((stderr,
1936             		  _("couldn't open input filter \"%s\" for file \"%s\": %s"),
1937             		  input_filter, fname ? fname : "(stdin)",
1938             		  strerror (errno)));
1939             	  return 0;
1940             	}
1941                 }
1942               else
1943                 {
1944                   /* Just open the stream. */
1945                   is->is_pipe = 0;
1946                   if (fp)
1947             	is->fp = fp;
1948                   else
1949             	{
1950             	  is->fp = fopen (fname, "rb");
1951             	  if (is->fp == NULL)
1952             	    {
1953             	      ERROR ((stderr, _("couldn't open input file \"%s\": %s"), fname,
1954 rizwank 1.1 		      strerror (errno)));
1955             	      return 0;
1956             	    }
1957             	}
1958                 }
1959             
1960               return 1;
1961             }
1962             
1963             
1964             void
1965             is_close (InputStream *is)
1966             {
1967               if (is->is_pipe)
1968                 pclose (is->fp);
1969               else
1970                 fclose (is->fp);
1971             
1972               if (is->unget_ch)
1973                 xfree (is->unget_ch);
1974             }
1975 rizwank 1.1 
1976             
1977             int
1978             is_getc (InputStream *is)
1979             {
1980               int ch;
1981             
1982               if (is->unget_pos > 0)
1983                 {
1984                   ch = is->unget_ch[--is->unget_pos];
1985                   return ch;
1986                 }
1987             
1988              retry:
1989             
1990               /* Do we have any data left? */
1991               if (is->bufpos >= is->data_in_buf)
1992                 {
1993                   /* At the EOF? */
1994                   if (is->nreads > 0 && is->data_in_buf < sizeof (is->buf))
1995             	/* Yes. */
1996 rizwank 1.1 	return EOF;
1997             
1998                   /* Read more data. */
1999                   is->data_in_buf = fread (is->buf, 1, sizeof (is->buf), is->fp);
2000                   is->bufpos = 0;
2001                   is->nreads++;
2002             
2003                   goto retry;
2004                 }
2005             
2006               return is->buf[is->bufpos++];
2007             }
2008             
2009             
2010             int
2011             is_ungetc (int ch, InputStream *is)
2012             {
2013               if (is->unget_pos >= is->unget_alloc)
2014                 {
2015                   is->unget_alloc += 1024;
2016                   is->unget_ch = xrealloc (is->unget_ch, is->unget_alloc);
2017 rizwank 1.1     }
2018             
2019               is->unget_ch[is->unget_pos++] = ch;
2020             
2021               return 1;
2022             }
2023             
2024             
2025             /*
2026              * Buffer Functions.
2027              */
2028             
2029             void
2030             buffer_init (Buffer *buffer)
2031             {
2032               buffer->allocated = 128;
2033               buffer->data = xmalloc (buffer->allocated);
2034               buffer->data[0] = '\0';
2035               buffer->len = 0;
2036             }
2037             
2038 rizwank 1.1 
2039             void
2040             buffer_uninit (Buffer *buffer)
2041             {
2042               xfree (buffer->data);
2043             }
2044             
2045             
2046             Buffer *
2047             buffer_alloc ()
2048             {
2049               Buffer *buffer = (Buffer *) xcalloc (1, sizeof (Buffer));
2050             
2051               buffer_init (buffer);
2052             
2053               return buffer;
2054             }
2055             
2056             
2057             void
2058             buffer_free (Buffer *buffer)
2059 rizwank 1.1 {
2060               buffer_uninit (buffer);
2061               xfree (buffer);
2062             }
2063             
2064             
2065             void
2066             buffer_append (Buffer *buffer, const char *data)
2067             {
2068               buffer_append_len (buffer, data, strlen (data));
2069             }
2070             
2071             
2072             void
2073             buffer_append_len (Buffer *buffer, const char *data, size_t len)
2074             {
2075               if (buffer->len + len + 1 >= buffer->allocated)
2076                 {
2077                   buffer->allocated = buffer->len + len + 1024;
2078                   buffer->data = xrealloc (buffer->data, buffer->allocated);
2079                 }
2080 rizwank 1.1 
2081               memcpy (buffer->data + buffer->len, data, len);
2082               buffer->len += len;
2083             
2084               buffer->data[buffer->len] = '\0';
2085             }
2086             
2087             
2088             char *
2089             buffer_copy (Buffer *buffer)
2090             {
2091               char *copy = xmalloc (buffer->len + 1);
2092             
2093               memcpy (copy, buffer->data, buffer->len + 1);
2094             
2095               return copy;
2096             }
2097             
2098             
2099             void
2100             buffer_clear (Buffer *buffer)
2101 rizwank 1.1 {
2102               buffer->len = 0;
2103               buffer->data[0] = '\0';
2104             }
2105             
2106             
2107             char *
2108             buffer_ptr (Buffer *buffer)
2109             {
2110               return buffer->data;
2111             }
2112             
2113             
2114             size_t
2115             buffer_len (Buffer *buffer)
2116             {
2117               return buffer->len;
2118             }

Rizwan Kassim
Powered by
ViewCVS 0.9.2