groff
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Groff] Re: groff 1.17: pre-grohtml's unsafe temporary file handling & o


From: Gaius Mulley
Subject: [Groff] Re: groff 1.17: pre-grohtml's unsafe temporary file handling & other improvements
Date: Mon, 18 Jun 2001 13:38:09 +0100

ok so here we go again :-)
This time vsnprintf has been removed to make it more portable,
calls to index have been replaced with strchr, return values
from malloc/strdup are checked..
Looking forward to 1.17.1..

Gaius

--- groff-cvs/src/devices/grohtml/grohtml.man   Fri Apr 13 10:03:53 2001
+++ groff-html/src/devices/grohtml/grohtml.man  Sat Jun 16 00:11:22 2001
@@ -37,8 +37,10 @@
 .el .RB "[\ " "\\$1" "\ ]"
 ..
 .OP \-v?lrn
+.OP \-D dir
 .OP \-F dir
 .OP \-i resolution
+.OP \-I image stem
 .OP \-o image vertical offset
 .RI "[\ " files\|.\|.\|. "\ ]"
 .br
@@ -104,6 +106,18 @@
 select the resolution for all images.
 By default this is 80 pixels per inch.
 Example: -i100 indicates 100 pixels per inch.
+.TP
+.BI \-I stem
+determine the image stem name. If omitted grohtml uses
+.BR grohtml-<pid> .
+.TP
+.BI \-D dir
+informs
+.B grohtml
+to place all image files into directory,
+.BR dir .
+.I dir
+for all images.
 .TP
 .B \-v
 Print the version number.
--- groff-cvs/src/devices/grohtml/post-html.cc  Mon Jun  4 11:17:31 2001
+++ groff-html/src/devices/grohtml/post-html.cc Tue Jun  5 19:48:02 2001
@@ -2879,7 +2879,7 @@
     { "version", no_argument, 0, 'v' },
     { NULL, 0, 0, 0 }
   };
-  while ((c = getopt_long(argc, argv, "o:i:F:vd?lrn", long_options, NULL))
+  while ((c = getopt_long(argc, argv, "o:i:I:D:F:vd?lrn", long_options, NULL))
         != EOF)
     switch(c) {
     case 'v':
@@ -2903,6 +2903,12 @@
     case 'i':
       /* handled by pre-html */
       break;
+    case 'I':
+      /* handled by pre-html */
+      break;
+    case 'D':
+      /* handled by pre-html */
+      break;
     case 'n':
       simple_anchors = TRUE;
       break;
@@ -2929,6 +2935,6 @@
 
 static void usage(FILE *stream)
 {
-  fprintf(stream, "usage: %s [-vld?n] [-F dir] [files ...]\n",
+  fprintf(stream, "usage: %s [-vld?n] [-D dir] [-I image_stem] [-F dir] [files 
...]\n",
          program_name);
 }
--- groff-cvs/src/preproc/html/pre-html.cc      Fri Apr 20 14:35:01 2001
+++ groff-html/src/preproc/html/pre-html.cc     Mon Jun 18 13:26:02 2001
@@ -46,6 +46,8 @@
 #define PID_T int
 #endif /* not _POSIX_VERSION */
 
+#include <stdarg.h>
+
 extern "C" const char *Version_string;
 
 #include "pre-html.h"
@@ -58,6 +60,7 @@
 #define IMAGE_BOARDER_PIXELS       0
 #define MAX_WIDTH                  8   // inches
 #define INLINE_LEADER_CHAR      '\\'
+#define MAX_RETRIES             4096   // number of different page directory 
names to try before giving up
 
 #define TRANSPARENT  "-background \"#FFF\" -transparent \"#FFF\""
 
@@ -81,20 +84,21 @@
                                                 // -1 means closed
 static int   copyofstdoutfd =-1;                // a copy of stdout, so we can 
restore stdout when
                                                 // writing to post-html
-static char *psFileName     = 0;                // name of postscript file
-static char *regionFileName = 0;                // name of file containing all 
image regions
-static char *imagePageStem  = 0;                // stem of all files 
containing page images
+static char *psFileName     = NULL;             // name of postscript file
+static char *regionFileName = NULL;             // name of file containing all 
image regions
+static char *imagePageStem  = NULL;             // stem of all files 
containing page images
 static char *image_device   = "pnmraw";
 static int   image_res      = DEFAULT_IMAGE_RES;
 static int   vertical_offset= DEFAULT_VERTICAL_OFFSET;
-static char *image_template = 0;                // image template filename
+static char *image_template = NULL;             // image template filename
 static int   troff_arg      = 0;                // troff arg index
-static char *command_prefix = 0;                // optional prefix for some 
installations.
-static char *troff_command  = 0;
+static char *command_prefix = NULL;             // optional prefix for some 
installations.
+static char *troff_command  = NULL;
+static char *image_dir      = NULL;             // user specified image 
directory
 #if defined(DEBUGGING)
 static int   debug          = FALSE;
-static char *troffFileName  = 0;                // output of pre-html output 
which is sent to troff -Tps
-static char *htmlFileName   = 0;                // output of pre-html output 
which is sent to troff -Thtml
+static char *troffFileName  = NULL;             // output of pre-html output 
which is sent to troff -Tps
+static char *htmlFileName   = NULL;             // output of pre-html output 
which is sent to troff -Thtml
 #endif
 
 
@@ -118,6 +122,196 @@
   fprintf(stderr, "%s: %s: %s", program_name, s, strerror(errno));
 }
 
+
+#if 0
+
+/*
+ *  if/when vsnprintf becomes available on all *NIX machines we can use this 
function,
+ *  until then we must use the more complex function below which performs hand 
built
+ *  %d, %s and %%.
+ */
+
+/*
+ *  make_message - taken from man printf(3), creates a string via malloc
+ *                 and places the result of the va args into string.
+ *                 Finally the new string is returned.
+ */
+
+char *
+make_message (const char *fmt, ...)
+{
+  /* Guess we need no more than 100 bytes. */
+  int n, size = 100;
+  char *p;
+  char *np;
+  va_list ap;
+  if ((p = (char *)malloc (size)) == NULL)
+    return NULL;
+  while (1) {
+    /* Try to print in the allocated space. */
+    va_start(ap, fmt);
+    n = vsnprintf (p, size, fmt, ap);
+    va_end(ap);
+    /* If that worked, return the string. */
+    if (n > -1 && n < size) {
+      if (size > n+1) {
+       np = strdup(p);
+       if (np == NULL)
+         sys_fatal("strdup");
+       free(p);
+       return np;
+      }
+      return p;
+    }
+    /* Else try again with more space. */
+    if (n > -1)    /* glibc 2.1 */
+      size = n+1; /* precisely what is needed */
+    else           /* glibc 2.0 */
+      size *= 2;  /* twice the old size */
+    if ((np = (char *)realloc (p, size)) == NULL) {
+      free(p);  /* realloc failed, free old, p. */
+      return NULL;
+    }
+    p = np;  /* use realloc'ed, p */
+  }
+}
+#else
+
+/*
+ *  lengthOfintToStr - returns the length of the proposed string value of i.
+ *                     Hand built log10.
+ */
+
+int
+lengthOfintToStr (int i)
+{
+  int n=0;
+
+  if (i < 0)
+    sys_fatal("expecting positive integer value");
+
+  do {
+    i /= 10;
+    n++;
+  } while (i > 0);
+  return n;
+}
+
+/*
+ *  intToStr - returns a string containing the positive value of, i.
+ *             (int i is assumed to be positive).
+ */
+
+char *
+intToStr (int i)
+{
+  int n=lengthOfintToStr(i)+1;
+  char *p = (char *)malloc(n);
+
+  if (p == NULL)
+    sys_fatal("malloc");
+
+  if (i < 0)
+    sys_fatal("expecting positive integer value");
+
+  n--;
+  p[n] = (char)0;
+  do {
+    n--;
+    p[n] = (char)((i % 10) + (int)'0');
+    i /= 10;
+  } while (i > 0);
+  return( p );
+}
+
+/*
+ *  make_message - returns a string built from a format specifier.
+ *                 This function is does not vsnprintf and only
+ *                 understands primitive %% %s and %d specifiers.
+ */
+
+char *
+make_message (const char *fmt, ...)
+{
+  char *p = strdup(fmt);  /* so we can splat a nul anywhere in the string */
+  char *np;
+  char *l;
+  char *s;
+  char *num;
+  int   search=0;
+  va_list ap;
+
+  if (p == NULL)
+    sys_fatal("strdup");
+  
+  va_start(ap, fmt);
+  while (p) {
+    int   lenp=strlen(p);
+    char *f   = strchr(p+search, '%');
+
+    search = f-p;
+    np = p;
+
+    if (f == NULL) {
+      va_end(ap);
+      return p;
+    }
+    switch (*(f+1)) {
+
+    case 'd':
+      l = strdup(f+2);
+      if (l == NULL)
+       sys_fatal("strdup");
+      *f = (char)0;
+      num = intToStr(va_arg(ap, int));
+      np = (char *)malloc(strlen(p)+strlen(num)+strlen(l)+1);
+      if (np == NULL)
+       sys_fatal("malloc");
+      strcpy(np, p);
+      strcat(np, num);
+      strcat(np, l);
+      search += strlen(np)-lenp;
+      free(num);
+      free(l);
+      break;
+    case 's':
+      /* concat */
+      l = f+2;
+      if (l == NULL)
+       sys_fatal("strdup");
+      s = va_arg(ap, char *);
+      *f = (char)0;
+      np = (char *)malloc(strlen(l)+1+strlen(p)+strlen(s));
+      if (np == NULL)
+       sys_fatal("malloc");
+      strcpy(np, p);
+      strcat(np, s);
+      strcat(np, l);
+      search += strlen(s)-2;
+      break;
+    case '%':
+      /* remove one of the two % that we have seen */
+      *f = (char)0;
+      l = f+1;
+      np = (char *)malloc(strlen(l)+1+strlen(p));
+      if (np == NULL)
+       sys_fatal("malloc");
+      strcpy(np, p);
+      strcat(np, l);
+      search++;
+      break;
+    default:
+      sys_fatal("unexpected format specifier");
+      return NULL;
+    }
+    free(p);
+    p = np;
+  }
+  va_end(ap);
+  return NULL;
+}
+#endif
+
 /*
  *  the class and methods for retaining ascii text
  */
@@ -173,7 +367,7 @@
 
 char_buffer::~char_buffer()
 {
-  while (head != 0) {
+  while (head != NULL) {
     char_block *temp = head;
     head = head->next;
     delete temp;
@@ -189,7 +383,7 @@
   int n;
 
   while (! feof(fp)) {
-    if (tail == 0) {
+    if (tail == NULL) {
       tail = new char_block;
       head = tail;
     } else {
@@ -243,14 +437,55 @@
  *  makeFileName - creates the image filename template.
  */
 
-void makeFileName ()
+static void makeFileName (void)
 {
-  char buffer[8192];
+  char *s;
+
+  if ((image_dir != NULL) && (strchr(image_dir, '%') != NULL)) {
+    error("cannot use a `%%' within the image directory name");
+    exit(1);
+  }
 
-  sprintf(buffer, "grohtml-%d", (int)getpid());
-  strcat(buffer, "-%d");
-  image_template = (char *)malloc(strlen(buffer)+1);
-  strcpy(image_template, buffer);
+  if ((image_template != NULL) && (strchr(image_template, '%') != NULL)) {
+    error("cannot use a `%%' within the image template");
+    exit(1);
+  }
+
+  if (image_dir == NULL) {
+    image_dir = "";
+  } else if ((strlen(image_dir)>0) && (image_dir[strlen(image_dir)-1] != '/')) 
{
+    image_dir = make_message("%s/", image_dir);
+    if (image_dir == NULL)
+      sys_fatal("make_message");
+  }
+  
+  if (image_template == NULL)
+    s = make_message("%sgrohtml-%d", image_dir, (int)getpid());
+  else {
+    s = make_message("%s%s", image_dir, image_template);
+  }
+  if (s == NULL)
+    sys_fatal("make_message");
+
+  image_template = (char *)malloc(strlen("-%d")+strlen(s)+1);
+  if (image_template == NULL)
+    sys_fatal("malloc");
+  strcpy(image_template, s);
+  strcat(image_template, "-%d");
+  free(s);
+}
+
+/*
+ *  checkImageDir - checks to see whether the image directory is available.
+ */
+
+static void checkImageDir (void)
+{
+  if ((image_dir != NULL) && (strcmp(image_dir, "") != 0))
+    if (! ((mkdir(image_dir, 0700) == 0) || (errno == EEXIST))) {
+      error("cannot create directory `%1'", image_dir);
+      exit(1);
+    }
 }
 
 /*
@@ -263,12 +498,12 @@
     /*
      *  emit image name and enable output
      */
-    writeString("\\O2\\O1\\O4\n");
+    writeString("\\O[2]\\O[1]\\O[4]\n");
   } else {
     /*
      *  postscript, therefore emit image boundaries
      */
-    writeString("\\O2\\O4\n");
+    writeString("\\O[2]\\O[4]\n");
   }
 }
 
@@ -283,8 +518,8 @@
 static void write_start_image (IMAGE_ALIGNMENT pos, int is_html)
 {
   if (pos == INLINE) {
-    writeString("\\O3\\O5'");
-    writeString(image_template); writeString(".png'");
+    writeString("\\O[3]\\O[5 ");
+    writeString(image_template); writeString(".png]");
   } else {
     writeString(".begin \\{\\\n");
     switch (pos) {
@@ -307,10 +542,10 @@
     writeString("\\}\n");
   }
   if (is_html) {
-    writeString("\\O0\n");
+    writeString("\\O[0]\n");
   } else {
     // reset min/max registers
-    writeString("\\O0\\O1\n");
+    writeString("\\O[0]\\O[1]\n");
   }
 }
 
@@ -455,7 +690,7 @@
   char_block *t=head;
   int         i=0;
 
-  if (t != 0) {
+  if (t != NULL) {
     do {
       /*
        *  remember to check the shortest string last
@@ -475,7 +710,7 @@
       } else {
        write_upto_newline(&t, &i, FALSE);
       }
-    } while (t != 0);
+    } while (t != NULL);
   }
   if (close(stdoutfd) < 0)
     sys_fatal("close");
@@ -522,7 +757,7 @@
   resolution = res;
   maxx       = max_width;
   imageName  = name;
-  next       = 0;
+  next       = NULL;
 }
 
 /*
@@ -563,7 +798,7 @@
 
 imageList::~imageList ()
 {
-  while (head != 0) {
+  while (head != NULL) {
     imageItem *i = head;
     head = head->next;
     delete i;
@@ -574,21 +809,51 @@
  *  createAllPages - creates a set of images, one per page.
  */
 
-static void createAllPages (void)
+static int createAllPages (void)
 {
   char buffer[4096];
+  char *s;
+  int retries = MAX_RETRIES;
 
-  sprintf(buffer,
-         "echo showpage | gs -q -dSAFER -sDEVICE=%s -r%d -sOutputFile=%s%%d %s 
- > /dev/null 2>&1 \n",
-         image_device,
-         image_res,
-         imagePageStem,
-         psFileName);
+  imagePageStem = xtmptemplate("-page-");
+  strcpy(buffer, imagePageStem);
+
+  do {
+    if (mktemp(imagePageStem) == NULL) {
+      sys_fatal("mktemp");
+      return -1;
+    }
+    if (mkdir(imagePageStem, 0700) == 0) break;
+    if (errno == EEXIST) {
+      // directory already exists, try another name
+      retries--;
+      if (retries == 0) {
+       // time to give up
+       sys_fatal("mkdir");
+       return -1;
+      }
+    } else {
+      // another error, quit
+      sys_fatal("mkdir");
+      return -1;
+    }      
+    strcpy(imagePageStem, buffer);
+  } while (1);
+
+  s = make_message("echo showpage | gs -q -dSAFER -sDEVICE=%s -r%d 
-sOutputFile=%s/%%d %s - > /dev/null 2>&1 \n",
+                  image_device,
+                  image_res,
+                  imagePageStem,
+                  psFileName);
+  if (s == NULL)
+    sys_fatal("make_message");
 #if defined(DEBUGGING)
-  fwrite(buffer, sizeof(char), strlen(buffer), stderr);
+  fwrite(s, sizeof(char), strlen(s), stderr);
   fflush(stderr);
 #endif
-  system(buffer);
+  system(s);
+  free(s);
+  return 0;
 }
 
 /*
@@ -598,13 +863,18 @@
 static void removeAllPages (void)
 {
 #if !defined(DEBUGGING)
-  char buffer[4096];
+  char *s=NULL;
   int  i=1;
 
   do {
-    sprintf(buffer, "%s%d", imagePageStem, i);
+    if (s)
+      free(s);
+    s = make_message("%s/%d", imagePageStem, i);
+    if (s == NULL)
+      sys_fatal("make_message");
     i++;
-  } while (remove(buffer) == 0);
+  } while (unlink(s) == 0);
+  rmdir(imagePageStem);
 #endif
 }
 
@@ -641,23 +911,26 @@
 static void createImage (imageItem *i)
 {
   if (i->X1 != -1) {
-    char buffer[4096];
+    char *s;
     int  x1 = max(min(i->X1, 
i->X2)*image_res/POSTSCRIPTRES-1*IMAGE_BOARDER_PIXELS, 0);
     int  y1 = max((image_res*vertical_offset/72)+min(i->Y1, 
i->Y2)*image_res/POSTSCRIPTRES-IMAGE_BOARDER_PIXELS, 0);
     int  x2 = max(i->X1, i->X2)*image_res/POSTSCRIPTRES+1*IMAGE_BOARDER_PIXELS;
     int  y2 = (image_res*vertical_offset/72)+max(i->Y1, 
i->Y2)*image_res/POSTSCRIPTRES+1*IMAGE_BOARDER_PIXELS;
 
-    sprintf(buffer,
-           "pnmcut %d %d %d %d < %s%d | pnmtopng %s > %s \n",
-           x1, y1, x2-x1+1, y2-y1+1,
-           imagePageStem,
-           i->pageNo,
-           TRANSPARENT,
-           i->imageName);
+    s = make_message("pnmcut %d %d %d %d < %s/%d | pnmtopng %s > %s \n",
+                    x1, y1, x2-x1+1, y2-y1+1,
+                    imagePageStem,
+                    i->pageNo,
+                    TRANSPARENT,
+                    i->imageName);
+    if (s == NULL)
+      sys_fatal("make_message");
+
 #if defined(DEBUGGING)
-    fprintf(stderr, buffer);
+    fprintf(stderr, s);
 #endif
-    system(buffer);
+    system(s);
+    free(s);
 #if defined(DEBUGGING)
   } else {
     fprintf(stderr, "ignoring image as x1 coord is -1\n");
@@ -674,7 +947,7 @@
 {
   imageItem *i = new imageItem(x1, y1, x2, y2, page, res, maxx, name);
 
-  if (head == 0) {
+  if (head == NULL) {
     head = i;
     tail = i;
   } else {
@@ -697,7 +970,7 @@
   char_block *t      =head;
   int         i=0;
 
-  if (t != 0) {
+  if (t != NULL) {
     stop();
     do {
       /*
@@ -719,7 +992,7 @@
       } else {
        write_upto_newline(&t, &i, TRUE);
       }
-    } while (t != 0);
+    } while (t != NULL);
   }
   if (close(stdoutfd) < 0)
     sys_fatal("close");
@@ -912,6 +1185,9 @@
   char **new_argv = (char **)malloc((argc+2)*sizeof(char *));
   int   i=0;
 
+  if (new_argv == NULL)
+    sys_fatal("malloc");
+
   while (i<argc) {
     new_argv[i] = argv[i];
     i++;
@@ -987,13 +1263,15 @@
 
 void usage(FILE *stream)
 {
-  fprintf(stream, "usage: %s troffname [-P-o vertical_image_offset] [-P-i 
image_resolution] [troff flags] [files]\n", program_name);
+  fprintf(stream, "usage: %s troffname [-Iimage_name] [-Dimage_directory] 
[-P-o vertical_image_offset] [-P-i image_resolution] [troff flags] [files]\n", 
program_name);
   fprintf(stream, "    vertical_image_offset (default %d/72 of an inch)\n", 
vertical_offset);
   fprintf(stream, "    image_resolution (default %d) pixels per inch\n", 
image_res);
+  fprintf(stream, "    image_name is the name of the stem for all images 
(default is grohtml-<pid>)\n");
+  fprintf(stream, "    place all png files into image_directory\n");
 }
 
 /*
- *  scanArguments - scans for -P-i and -P-o arguments.
+ *  scanArguments - scans for -P-i, -P-o, -P-D and -P-I arguments.
  */
 
 int scanArguments (int argc, char **argv)
@@ -1001,7 +1279,11 @@
   int i=1;
 
   while (i<argc) {
-    if (strncmp(argv[i], "-i", 2) == 0) {
+    if (strncmp(argv[i], "-D", 2) == 0) {
+      image_dir = (char *)(argv[i]+2);
+    } else if (strncmp(argv[i], "-I", 2) == 0) {
+      image_template = (char *)(argv[i]+2);
+    } else if (strncmp(argv[i], "-i", 2) == 0) {
       image_res = atoi((char *)(argv[i]+2));
     } else if (strncmp(argv[i], "-o", 2) == 0) {
       vertical_offset = atoi((char *)(argv[i]+2));
@@ -1033,7 +1315,7 @@
  *  makeTempFiles - name the temporary files
  */
 
-static void makeTempFiles (void)
+static int makeTempFiles (void)
 {
 #if defined(DEBUGGING)
   psFileName     = "/tmp/prehtml-ps";
@@ -1042,10 +1324,21 @@
   troffFileName  = "/tmp/prehtml-troff";
   htmlFileName   = "/tmp/prehtml-html";
 #else
-  psFileName     = mktemp(xtmptemplate("-ps-"));
-  regionFileName = mktemp(xtmptemplate("-regions-"));
-  imagePageStem  = mktemp(xtmptemplate("-page-"));
+  int fd;
+
+  if ((fd = mkstemp(psFileName = xtmptemplate("-ps-"))) == -1) {
+    sys_fatal("mkstemp");
+    return -1;
+  }
+  close(fd);
+  if ((fd = mkstemp(regionFileName = xtmptemplate("-regions-"))) == -1) {
+    sys_fatal("mkstemp");
+    unlink(psFileName);
+    return -1;
+  }
+  close(fd);
 #endif
+  return 0;
 }
 
 /*
@@ -1055,8 +1348,8 @@
 static void removeTempFiles (void)
 {
 #if !defined(DEBUGGING)
-  remove(psFileName);
-  remove(regionFileName);
+  unlink(psFileName);
+  unlink(regionFileName);
 #endif
 }
 
@@ -1071,6 +1364,9 @@
   if (!command_prefix)
     command_prefix = PROG_PREFIX;
   troff_command = (char *)malloc(strlen("troff")+strlen(command_prefix)+1);
+  if (troff_command == NULL)
+    sys_fatal("malloc");
+
   strcpy(troff_command, command_prefix);
   strcat(troff_command, "troff");
 }
@@ -1084,8 +1380,9 @@
   int ok=1;
 
   findPrefix();
-  makeFileName();
   i = scanArguments(argc, argv);
+  checkImageDir();
+  makeFileName();
   while (i < argc) {
     if (argv[i][0] != '-') {
       /* found source file */
@@ -1103,13 +1400,16 @@
   if (! found) {
     do_file("-");
   }
-  makeTempFiles();
+  if (makeTempFiles())
+    return 1;
   ok = inputFile.do_image(argc, argv);
   if (ok == 0) {
-    createAllPages();
-    generateImages(regionFileName);
-    ok = inputFile.do_html(argc, argv);
-    removeAllPages();
+    ok = createAllPages();
+    if (ok == 0) {
+      generateImages(regionFileName);
+      ok = inputFile.do_html(argc, argv);
+      removeAllPages();
+    }
   }
   removeTempFiles();
   return ok;
@@ -1135,6 +1435,6 @@
 
   if (fp != stdin)
     fclose(fp);
-  current_filename = 0;
+  current_filename = NULL;
   return 1;
 }
--- groff-cvs/src/roff/troff/input.cc   Mon Jun  4 11:17:50 2001
+++ groff-html/src/roff/troff/input.cc  Mon Jun  4 16:03:26 2001
@@ -135,6 +135,7 @@
 static request_or_macro *lookup_request(symbol);
 static int get_delim_number(units *, int);
 static int get_delim_number(units *, int, units);
+static symbol get_delim_file_name();
 static int get_line_arg(units *res, int si, charinfo **cp);
 static int read_size(int *);
 static symbol get_delim_name();
@@ -4084,6 +4085,66 @@
   }
 }
 
+static symbol get_delim_file_name()
+{
+  token start;
+  start.next();
+  if (start.eof()) {
+    error("end of input at start of delimited file name");
+    return NULL_SYMBOL;
+  }
+  if (start.newline()) {
+    error("can't delimit file name with a newline");
+    return NULL_SYMBOL;
+  }
+  int start_level = input_stack::get_level();
+  char abuf[ABUF_SIZE];
+  char *buf = abuf;
+  int buf_size = ABUF_SIZE;
+  int i = 0;
+  for (;;) {
+    if (i + 1 > buf_size) {
+      if (buf == abuf) {
+       buf = new char[ABUF_SIZE*2];
+       memcpy(buf, abuf, buf_size);
+       buf_size = ABUF_SIZE*2;
+      }
+      else {
+       char *old_buf = buf;
+       buf = new char[buf_size*2];
+       memcpy(buf, old_buf, buf_size);
+       buf_size *= 2;
+       a_delete old_buf;
+      }
+    }
+    tok.next();
+    if (tok.ch() == ']' && input_stack::get_level() == start_level)
+      break;
+
+    if ((buf[i] = tok.ch()) == 0) {
+      error("missing delimiter (got %1)", tok.description());
+      if (buf != abuf)
+       a_delete buf;
+      return NULL_SYMBOL;
+    }
+    i++;
+  }
+  buf[i] = '\0';
+  if (buf == abuf) {
+    if (i == 0) {
+      error("empty delimited file name");
+      return NULL_SYMBOL;
+    }
+    else
+      return symbol(buf);
+  }
+  else {
+    symbol s(buf);
+    a_delete buf;
+    return s;
+  }
+}
+
 // Implement \R
 
 static void do_register()
@@ -4324,6 +4385,13 @@
 {
   tok.next();
   int c = tok.ch();
+  if (c != '[') {
+    error("`\\O%1' is incorrect syntax, use `\\O[%1]'", char(c), char(c));
+    return 0;
+  }
+  tok.next();
+  c = tok.ch();
+  tok.next();
   switch (c) {
   case '0':
     if (begin_level == 1)
@@ -4344,14 +4412,19 @@
     begin_level--;
     break;
   case '5': {
-    symbol filename = get_delim_name();
+    symbol filename = get_delim_file_name();
+    tok.next();
+    if (filename.is_null()) {
+      error("\\O[5 requires a filename");
+      return 0;
+    }
     if (begin_level == 1)
       return new suppress_node(filename, 'i');
     return 0;
     break;
   }
   default:
-    error("`%1' is an invalid argument to \\O", char(c));
+    error("`%1' is an invalid argument to \\O[", char(c));
   }
   return 0;
 }
--- groff-cvs/tmac/www.tmac     Sat Apr 14 15:25:15 2001
+++ groff-html/tmac/www.tmac    Mon Jun  4 12:13:27 2001
@@ -159,19 +159,19 @@
 .         image \\$2 \\$1.png
 .         bp
 .         tl ''''
-\O0\O1
+\O[0]\O[1]
 .  \}
 .  if \\n[www-html] .begin \{
 .         image \\$2 \\$1.png
-\O0
+\O[0]
 .  \}
 ..
 .\"
 .\" HTML-IMAGE-END - terminates an image for html
 .\"
 .de HTML-IMAGE-END
-.  if r ps4html    \O2\O1\O4
-.  if \\n[www-html] \O2\O1\O4
+.  if r ps4html    \O[2]\O[1]\O[4]
+.  if \\n[www-html] \O[2]\O[1]\O[4]
 ..
 .nr png-no 0
 .\"

reply via email to

[Prev in Thread] Current Thread [Next in Thread]