]> git.cameronkatri.com Git - mandoc.git/blobdiff - preconv.c
fix the two manual links on the index page
[mandoc.git] / preconv.c
index da5af9b4f5ead994acf16f12e0772c6749ccc55b..7595887dd26f1a042f82523d9857293f89834457 100644 (file)
--- a/preconv.c
+++ b/preconv.c
@@ -1,4 +1,4 @@
-/*     $Id: preconv.c,v 1.2 2011/05/26 12:01:14 kristaps Exp $ */
+/*     $Id: preconv.c,v 1.6 2013/06/02 03:52:21 schwarze Exp $ */
 /*
  * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  *
 #include "config.h"
 #endif
 
+#ifdef HAVE_MMAP
 #include <sys/stat.h>
 #include <sys/mman.h>
+#endif
 
 #include <assert.h>
 #include <fcntl.h>
 
 /* 
  * The read_whole_file() and resize_buf() functions are copied from
- * read.c, including all dependency code (MAP_FILE, etc.).
+ * read.c, including all dependency code.
  */
 
-#ifndef MAP_FILE
-#define        MAP_FILE        0
-#endif
-
 enum   enc {
        ENC_UTF_8, /* UTF-8 */
        ENC_US_ASCII, /* US-ASCII */
@@ -55,6 +53,7 @@ struct        encode {
        int             (*conv)(const struct buf *);
 };
 
+static int      cue_enc(const struct buf *, size_t *, enum enc *);
 static int      conv_latin_1(const struct buf *);
 static int      conv_us_ascii(const struct buf *);
 static int      conv_utf_8(const struct buf *);
@@ -94,11 +93,13 @@ conv_latin_1(const struct buf *b)
         * Latin-1 falls into the first 256 code-points of Unicode, so
         * there's no need for any sort of translation.  Just make the
         * 8-bit characters use the Unicode escape.
+        * Note that binary values 128 < v < 160 are passed through
+        * unmodified to mandoc.
         */
 
        for (i = b->offs; i < b->sz; i++) {
                cu = (unsigned char)*cp++;
-               cu < 128U ? putchar(cu) : printf("\\[u%.4X]", cu);
+               cu < 160U ? putchar(cu) : printf("\\[u%.4X]", cu);
        }
 
        return(1);
@@ -134,7 +135,7 @@ conv_utf_8(const struct buf *b)
 
        /* Quick test for big-endian value. */
 
-       if ( ! (*((char *)(&one))))
+       if ( ! (*((const char *)(&one))))
                be = 1;
 
        for (i = b->offs; i < b->sz; i++) {
@@ -241,10 +242,11 @@ static int
 read_whole_file(const char *f, int fd, 
                struct buf *fb, int *with_mmap)
 {
-       struct stat      st;
        size_t           off;
        ssize_t          ssz;
 
+#ifdef HAVE_MMAP
+       struct stat      st;
        if (-1 == fstat(fd, &st)) {
                perror(f);
                return(0);
@@ -265,11 +267,11 @@ read_whole_file(const char *f, int fd,
        if (S_ISREG(st.st_mode)) {
                *with_mmap = 1;
                fb->sz = (size_t)st.st_size;
-               fb->buf = mmap(NULL, fb->sz, PROT_READ, 
-                               MAP_FILE|MAP_SHARED, fd, 0);
+               fb->buf = mmap(NULL, fb->sz, PROT_READ, MAP_SHARED, fd, 0);
                if (fb->buf != MAP_FAILED)
                        return(1);
        }
+#endif
 
        /*
         * If this isn't a regular file (like, say, stdin), then we must
@@ -306,6 +308,93 @@ read_whole_file(const char *f, int fd,
        return(0);
 }
 
+static int
+cue_enc(const struct buf *b, size_t *offs, enum enc *enc)
+{
+       const char      *ln, *eoln, *eoph;
+       size_t           sz, phsz, nsz;
+       int              i;
+
+       ln = b->buf + (int)*offs;
+       sz = b->sz - *offs;
+
+       /* Look for the end-of-line. */
+
+       if (NULL == (eoln = memchr(ln, '\n', sz)))
+               return(-1);
+
+       /* Set next-line marker. */
+
+       *offs = (size_t)((eoln + 1) - b->buf);
+
+       /* Check if we have the correct header/trailer. */
+
+       if ((sz = (size_t)(eoln - ln)) < 10 || 
+                       memcmp(ln, ".\\\" -*-", 7) ||
+                       memcmp(eoln - 3, "-*-", 3))
+               return(0);
+
+       /* Move after the header and adjust for the trailer. */
+
+       ln += 7;
+       sz -= 10;
+
+       while (sz > 0) {
+               while (sz > 0 && ' ' == *ln) {
+                       ln++;
+                       sz--;
+               }
+               if (0 == sz)
+                       break;
+
+               /* Find the end-of-phrase marker (or eoln). */
+
+               if (NULL == (eoph = memchr(ln, ';', sz)))
+                       eoph = eoln - 3;
+               else
+                       eoph++;
+
+               /* Only account for the "coding" phrase. */
+
+               if ((phsz = (size_t)(eoph - ln)) < 7 ||
+                               strncasecmp(ln, "coding:", 7)) {
+                       sz -= phsz;
+                       ln += phsz;
+                       continue;
+               } 
+
+               sz -= 7;
+               ln += 7;
+
+               while (sz > 0 && ' ' == *ln) {
+                       ln++;
+                       sz--;
+               }
+               if (0 == sz)
+                       break;
+
+               /* Check us against known encodings. */
+
+               for (i = 0; i < (int)ENC__MAX; i++) {
+                       nsz = strlen(encs[i].name);
+                       if (phsz < nsz)
+                               continue;
+                       if (strncasecmp(ln, encs[i].name, nsz))
+                               continue;
+
+                       *enc = (enum enc)i;
+                       return(1);
+               }
+
+               /* Unknown encoding. */
+
+               *enc = ENC__MAX;
+               return(1);
+       }
+
+       return(0);
+}
+
 int
 main(int argc, char *argv[])
 {
@@ -313,7 +402,8 @@ main(int argc, char *argv[])
        struct buf       b;
        const char      *fn;
        enum enc         enc, def;
-       const char       bom[3] = { 0xEF, 0xBB, 0xBF };
+       unsigned char    bom[3] = { 0xEF, 0xBB, 0xBF };
+       size_t           offs;
        extern int       optind;
        extern char     *optarg;
 
@@ -336,12 +426,12 @@ main(int argc, char *argv[])
                case ('D'):
                        /* FALLTHROUGH */
                case ('e'):
-                       for (i = 0; i < ENC__MAX; i++) {
+                       for (i = 0; i < (int)ENC__MAX; i++) {
                                if (strcasecmp(optarg, encs[i].name))
                                        continue;
                                break;
                        }
-                       if (i < ENC__MAX) {
+                       if (i < (int)ENC__MAX) {
                                if ('D' == ch)
                                        def = (enum enc)i;
                                else
@@ -394,6 +484,15 @@ main(int argc, char *argv[])
                        enc = ENC_UTF_8;
                }
 
+       /* Try reading from the "-*-" cue. */
+
+       if (ENC__MAX == enc) {
+               offs = b.offs;
+               ch = cue_enc(&b, &offs, &enc);
+               if (0 == ch)
+                       ch = cue_enc(&b, &offs, &enc);
+       }
+
        /*
         * No encoding has been detected.
         * Thus, we either fall into our default encoder, if specified,
@@ -403,14 +502,18 @@ main(int argc, char *argv[])
        if (ENC__MAX == enc) 
                enc = ENC__MAX == def ? ENC_LATIN_1 : def;
 
-       if ( ! (*encs[(int)enc].conv)(&b)) 
+       if ( ! (*encs[(int)enc].conv)(&b)) {
+               fprintf(stderr, "%s: Bad encoding\n", fn);
                goto out;
+       }
 
        rc = EXIT_SUCCESS;
 out:
+#ifdef HAVE_MMAP
        if (map)
                munmap(b.buf, b.sz);
        else 
+#endif
                free(b.buf);
 
        if (fd > STDIN_FILENO)