]> git.saurik.com Git - apple/libc.git/blobdiff - gen/getttyent.c
Libc-498.1.5.tar.gz
[apple/libc.git] / gen / getttyent.c
index 723077bb79323d0c025ea57d5ba146d3902678d6..def6fa3930dfe04f916badff4655d80a854f49b4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1999, 2005 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  * SUCH DAMAGE.
  */
 
+#include "xlocale_private.h"
 
 #include <ttyent.h>
 #include <stdio.h>
 #include <ctype.h>
 #include <string.h>
 #include <stdlib.h>
+#include <regex.h>
+#include <limits.h>
 
 static char zapchar;
 static FILE *tf;
@@ -70,22 +73,61 @@ getttynam(tty)
        register struct ttyent *t;
 
        setttyent();
-       while (t = getttyent())
+       while ((t = getttyent()) != NULL)
                if (!strcmp(tty, t->ty_name))
                        break;
        endttyent();
        return (t);
 }
 
+static char *skip(), *value();
+
+/*
+ * 4372480: Support for sequences in the tty name.  Expressions like [000-999]
+ * for decimal sequences and [0x0-0xf] for hexidecimal sequences causes a
+ * sequence of all combinations of names to be returned by getttyent().
+ *
+ * There is also a slot=nn option, which will cause getttyent() to return
+ * non-existent ttyent structs until the slot number nn is reached.  Note, slot
+ * numbers begin at 1.
+ */
+struct seq {
+       int first;
+       int count;
+       int index;
+       char fmt[NAME_MAX + 17];
+};
+
+static char brapat[] = "\\[(.*)]";
+static regex_t brapreg;
+static char decpat[] = "^([0-9]+)-([0-9]+)$";
+static regex_t decpreg;
+static char hexpat[] = "^0x([0-9a-f]+)-0x([0-9a-f]+)$";
+static regex_t hexpreg;
+static struct seq *seq = NULL;
+static int slot;
+
 struct ttyent *
 getttyent()
 {
        static struct ttyent tty;
+       static struct ttyent nonexistent = {
+               "\01",  /* this shouldn't match anything */
+               NULL,
+               NULL,
+               0,
+               NULL,
+               NULL,
+               NULL
+       };
        register int c;
        register char *p;
 #define        MAXLINELENGTH   1024
        static char *line = NULL;
-       static char *skip(), *value();
+       locale_t loc = __current_locale();
+       int newslot, hex;
+       long b, e;
+       regmatch_t match[3], save, bracket;
 
        if ( line == NULL ) {
                line = malloc(MAXLINELENGTH);
@@ -95,6 +137,36 @@ getttyent()
 
        if (!tf && !setttyent())
                return (NULL);
+
+restart:
+       if (slot < seq->first) {
+               /*
+                * the slot= option was set, and we are returning non-existent
+                * entries until we catch up.
+                */
+               slot++;
+               return &nonexistent;
+       }
+
+       if (seq->count > 0) {
+               /*
+                * generate the next tty name; the rest of the tty entries
+                * is the same.
+                */
+               sprintf(tty.ty_name, seq->fmt, seq->index++);
+               slot++;
+               seq->count--;
+               return &tty;
+       }
+
+       if (slot == seq->first) {
+               /*
+                * this was a regular entry with slot=
+                */
+               slot++;
+               return &tty;
+       }
+
        for (;;) {
                if (!fgets(p = line, MAXLINELENGTH, tf))
                        return (NULL);
@@ -104,7 +176,7 @@ getttyent()
                                ;
                        continue;
                }
-               while (isspace(*p))
+               while (isspace_l(*p, loc))
                        ++p;
                if (*p && *p != '#')
                        break;
@@ -127,8 +199,9 @@ getttyent()
        tty.ty_onerror = NULL;
        tty.ty_onoption = NULL;
 
-#define        scmp(e) !strncmp(p, e, sizeof(e) - 1) && isspace(p[sizeof(e) - 1])
+#define        scmp(e) !strncmp(p, e, sizeof(e) - 1) && isspace_l(p[sizeof(e) - 1], loc)
 #define        vcmp(e) !strncmp(p, e, sizeof(e) - 1) && p[sizeof(e) - 1] == '='
+       newslot = -1;
        for (; *p; p = skip(p)) {
                if (scmp(_TTYS_OFF))
                        tty.ty_status &= ~TTY_ON;
@@ -142,7 +215,11 @@ getttyent()
                        tty.ty_onerror = value(p);
                else if (vcmp(_TTYS_ONOPTION))
                        tty.ty_onoption = value(p);
-               else
+               else if (vcmp(_TTYS_SLOT)) {
+                       char *slotstr = value(p);
+                       if (slotstr)
+                               newslot = atoi(slotstr);
+               } else
                        break;
        }
 
@@ -152,8 +229,64 @@ getttyent()
        tty.ty_comment = p;
        if (*p == 0)
                tty.ty_comment = 0;
-       if (p = index(p, '\n'))
+       if ((p = index(p, '\n')) != NULL)
                *p = '\0';
+
+       /* check if tty.tyname has a sequence */
+       if (regexec(&brapreg, tty.ty_name, 3, match, 0) != 0)
+               goto out;
+
+       /*
+        * save the range of the bracketed range, so we can find the strings
+        * before and after
+        */
+       bracket = match[0];
+       /* use REG_STARTEND to limit matching with the bracketed range */
+       match[0] = save = match[1];
+       if (regexec(&decpreg, tty.ty_name, 3, match, REG_STARTEND) == 0) {
+               /* a decimal range */
+               b = strtol(tty.ty_name + match[1].rm_so, NULL, 10);
+               e = strtol(tty.ty_name + match[2].rm_so, NULL, 10);
+               hex = 0;
+       } else {
+               match[0] = save;
+               if (regexec(&hexpreg, tty.ty_name, 3, match, REG_STARTEND) == 0) {
+                       /* a hexidecimal range */
+                       b = strtol(tty.ty_name + match[1].rm_so, NULL, 16);
+                       e = strtol(tty.ty_name + match[2].rm_so, NULL, 16);
+                       hex = 1;
+               } else
+                       goto out;
+       }
+       if (b > e)      /* skip */
+               goto restart;
+
+       /* seq->first is already less than slot, so just leave it */
+       seq->count = e - b + 1;
+       seq->index = b;
+       /*
+        * The fmt string contains the characters before the bracket, the
+        * a format specifier (either decimal or hex) and any characters
+        * after the bracket.  Note that the length of the lower range is
+        * use as a minimum digit length, with zero fill, so the format
+        * specifier will look something like %03d.
+        */
+       sprintf(seq->fmt, "%.*s%%0%d%c%s",
+               (int)bracket.rm_so, tty.ty_name,
+               (int)(match[1].rm_eo - match[1].rm_so),
+               hex ? 'x' : 'd',
+               tty.ty_name + bracket.rm_eo);
+
+out:
+       if (newslot > slot) {
+               /* set up to skip until newslot */
+               seq->first = newslot;
+               goto restart;
+       }
+       if (seq->count > 0)     /* restart if we are doing a sequence */
+               goto restart;
+       /* regular single value return */
+       slot++;
        return (&tty);
 }
 
@@ -209,10 +342,33 @@ int
 setttyent()
 {
 
+       /* initialize seq and the three regexp patterns */
+       if (!seq) {
+               if (regcomp(&brapreg, brapat, REG_EXTENDED) != 0)
+                       return 0;
+               if (regcomp(&decpreg, decpat, REG_EXTENDED) != 0) {
+                       regfree(&brapreg);
+                       return 0;
+               }
+               if (regcomp(&hexpreg, hexpat, REG_EXTENDED | REG_ICASE) != 0) {
+                       regfree(&decpreg);
+                       regfree(&brapreg);
+                       return 0;
+               }
+               if ((seq = malloc(sizeof(struct seq))) == NULL) {
+                       regfree(&hexpreg);
+                       regfree(&decpreg);
+                       regfree(&brapreg);
+                       return 0;
+               }
+       }
+       seq->first = seq->count = 0;
+       slot = 1;
+
        if (tf) {
                (void)rewind(tf);
                return (1);
-       } else if (tf = fopen(_PATH_TTYS, "r"))
+       } else if ((tf = fopen(_PATH_TTYS, "r")) != NULL)
                return (1);
        return (0);
 }