POSIX conformance:
authorSascha Wildner <swildner@dragonflybsd.org>
Mon, 6 Oct 2008 21:01:37 +0000 (21:01 +0000)
committerSascha Wildner <swildner@dragonflybsd.org>
Mon, 6 Oct 2008 21:01:37 +0000 (21:01 +0000)
Add fmtmsg(3), posix_madvise(3), strfmon(3) and wordexp(3).

Taken-from: FreeBSD

16 files changed:
include/Makefile
include/fmtmsg.h [new file with mode: 0644]
include/monetary.h [new file with mode: 0644]
include/wordexp.h [new file with mode: 0644]
lib/libc/gen/Makefile.inc
lib/libc/gen/fmtmsg.3 [new file with mode: 0644]
lib/libc/gen/fmtmsg.c [new file with mode: 0644]
lib/libc/gen/pmadvise.c [new file with mode: 0644]
lib/libc/gen/wordexp.3 [new file with mode: 0644]
lib/libc/gen/wordexp.c [new file with mode: 0644]
lib/libc/stdlib/Makefile.inc
lib/libc/stdlib/strfmon.3 [new file with mode: 0644]
lib/libc/stdlib/strfmon.c [new file with mode: 0644]
lib/libc/sys/Makefile.inc
lib/libc/sys/madvise.2
sys/sys/mman.h

index 9603f3a..e913814 100644 (file)
@@ -1,6 +1,6 @@
 #      @(#)Makefile    8.2 (Berkeley) 1/4/94
 # $FreeBSD: src/include/Makefile,v 1.109.2.27 2003/01/24 05:12:29 sam Exp $
-# $DragonFly: src/include/Makefile,v 1.39 2008/07/07 22:02:09 nant Exp $
+# $DragonFly: src/include/Makefile,v 1.40 2008/10/06 21:01:37 swildner Exp $
 #
 # Doing a make install builds /usr/include
 #
@@ -11,18 +11,18 @@ CLEANFILES= osreldate.h version vers.c
 SUBDIR= arpa protocols rpc rpcsvc
 INCS=  a.out.h ar.h assert.h bitstring.h complex.h cpio.h ctype.h db.h \
        dirent.h disktab.h \
-       dlfcn.h elf.h elf-hints.h err.h fnmatch.h fstab.h \
+       dlfcn.h elf.h elf-hints.h err.h fmtmsg.h fnmatch.h fstab.h \
        fts.h getopt.h glob.h grp.h histedit.h iconv.h ieeefp.h ifaddrs.h \
        iso646.h inttypes.h \
        langinfo.h libgen.h limits.h link.h locale.h malloc.h math.h memory.h \
-       mpool.h ndbm.h netdb.h nl_types.h nlist.h objformat.h \
+       mpool.h monetary.h ndbm.h netdb.h nl_types.h nlist.h objformat.h \
        paths.h pthread.h pthread_np.h pwd.h \
        ranlib.h readpassphrase.h regex.h regexp.h resolv.h re_comp.h rmd160.h \
        search.h setjmp.h sgtty.h \
        signal.h stab.h stdarg.h stdbool.h stddef.h stdint.h stdio.h stdlib.h \
        string.h stringlist.h strings.h struct.h sysexits.h tar.h time.h \
        timers.h ttyent.h unistd.h ulimit.h utime.h utmp.h uuid.h vis.h \
-       wchar.h wctype.h
+       wchar.h wctype.h wordexp.h
 
 MHDRS= float.h floatingpoint.h varargs.h
 
diff --git a/include/fmtmsg.h b/include/fmtmsg.h
new file mode 100644 (file)
index 0000000..de2244a
--- /dev/null
@@ -0,0 +1,74 @@
+/*-
+ * Copyright (c) 2002 Mike Barcroft <mike@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/include/fmtmsg.h,v 1.2 2002/08/05 16:37:05 mike Exp $
+ * $DragonFly: src/include/fmtmsg.h,v 1.1 2008/10/06 21:01:37 swildner Exp $
+ */
+
+#ifndef _FMTMSG_H_
+#define        _FMTMSG_H_
+
+/* Source of condition is... */
+#define        MM_HARD         0x0001  /* ...hardware. */
+#define        MM_SOFT         0x0002  /* ...software. */
+#define        MM_FIRM         0x0004  /* ...fireware. */
+
+/* Condition detected by... */
+#define        MM_APPL         0x0010  /* ...application. */
+#define        MM_UTIL         0x0020  /* ...utility. */
+#define        MM_OPSYS        0x0040  /* ...operating system. */
+
+/* Display on... */
+#define        MM_PRINT        0x0100  /* ...standard error. */
+#define        MM_CONSOLE      0x0200  /* ...system console. */
+
+#define        MM_RECOVER      0x1000  /* Recoverable error. */
+#define        MM_NRECOV       0x2000  /* Non-recoverable error. */
+
+/* Severity levels. */
+#define        MM_NOSEV        0       /* No severity level provided. */
+#define        MM_HALT         1       /* Error causing application to halt. */
+#define        MM_ERROR        2       /* Non-fault fault. */
+#define        MM_WARNING      3       /* Unusual non-error condition. */
+#define        MM_INFO         4       /* Informative message. */
+
+/* Null options. */
+#define        MM_NULLLBL      (char *)0
+#define        MM_NULLSEV      0
+#define        MM_NULLMC       0L
+#define        MM_NULLTXT      (char *)0
+#define        MM_NULLACT      (char *)0
+#define        MM_NULLTAG      (char *)0
+
+/* Return values. */
+#define        MM_OK           0       /* Success. */
+#define        MM_NOMSG        1       /* Failed to output to stderr. */
+#define        MM_NOCON        2       /* Failed to output to console. */
+#define        MM_NOTOK        3       /* Failed to output anything. */
+
+int    fmtmsg(long, const char *, int, const char *, const char *,
+           const char *);
+
+#endif /* !_FMTMSG_H_ */
diff --git a/include/monetary.h b/include/monetary.h
new file mode 100644 (file)
index 0000000..2fb6dff
--- /dev/null
@@ -0,0 +1,50 @@
+/*-
+ * Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/include/monetary.h,v 1.7 2002/09/20 08:22:48 mike Exp $
+ * $DragonFly: src/include/monetary.h,v 1.1 2008/10/06 21:01:37 swildner Exp $
+ */
+
+#ifndef _MONETARY_H_
+#define        _MONETARY_H_
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#ifndef _SIZE_T_DECLARED
+typedef        __size_t        size_t;
+#define        _SIZE_T_DECLARED
+#endif
+
+#ifndef _SSIZE_T_DECLARED
+typedef        __ssize_t       ssize_t;
+#define        _SSIZE_T_DECLARED
+#endif
+
+__BEGIN_DECLS
+ssize_t        strfmon(char * __restrict, size_t, const char * __restrict, ...);
+__END_DECLS
+
+#endif /* !_MONETARY_H_ */
diff --git a/include/wordexp.h b/include/wordexp.h
new file mode 100644 (file)
index 0000000..b286e61
--- /dev/null
@@ -0,0 +1,76 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/include/wordexp.h,v 1.5 2004/06/30 13:55:08 tjr Exp $
+ * $DragonFly: src/include/wordexp.h,v 1.1 2008/10/06 21:01:37 swildner Exp $
+ */
+
+#ifndef _WORDEXP_H_
+#define        _WORDEXP_H_
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#if __XSI_VISIBLE && !defined(_SIZE_T_DECLARED)
+typedef        __size_t        size_t;
+#define        _SIZE_T_DECLARED
+#endif
+
+typedef struct {
+       __size_t        we_wordc;       /* count of words matched */
+       char            **we_wordv;     /* pointer to list of words */
+       __size_t        we_offs;        /* slots to reserve in we_wordv */
+       char            *we_strings;    /* storage for wordv strings */
+       __size_t        we_nbytes;      /* size of we_strings */
+} wordexp_t;
+
+/*
+ * Flags for wordexp().
+ */
+#define        WRDE_APPEND     0x1             /* append to previously generated */
+#define        WRDE_DOOFFS     0x2             /* we_offs member is valid */
+#define        WRDE_NOCMD      0x4             /* disallow command substitution */
+#define        WRDE_REUSE      0x8             /* reuse wordexp_t */
+#define        WRDE_SHOWERR    0x10            /* don't redirect stderr to /dev/null */
+#define        WRDE_UNDEF      0x20            /* disallow undefined shell vars */
+
+/*
+ * Return values from wordexp().
+ */
+#define        WRDE_BADCHAR    1               /* unquoted special character */
+#define        WRDE_BADVAL     2               /* undefined variable */
+#define        WRDE_CMDSUB     3               /* command substitution not allowed */
+#define        WRDE_NOSPACE    4               /* no memory for result */
+#if __XSI_VISIBLE
+#define        WRDE_NOSYS      5               /* obsolete, reserved */
+#endif
+#define        WRDE_SYNTAX     6               /* shell syntax error */
+
+__BEGIN_DECLS
+int    wordexp(const char * __restrict, wordexp_t * __restrict, int);
+void   wordfree(wordexp_t *);
+__END_DECLS
+
+#endif /* !_WORDEXP_H_ */
index 025d7c5..82263c6 100644 (file)
@@ -1,6 +1,6 @@
 #      @(#)Makefile.inc        8.6 (Berkeley) 5/4/95
 # $FreeBSD: src/lib/libc/gen/Makefile.inc,v 1.62.2.19 2003/02/21 13:46:16 phantom Exp $
-# $DragonFly: src/lib/libc/gen/Makefile.inc,v 1.28 2008/08/09 20:12:20 swildner Exp $
+# $DragonFly: src/lib/libc/gen/Makefile.inc,v 1.29 2008/10/06 21:01:37 swildner Exp $
 
 # machine-independent gen sources
 .PATH: ${.CURDIR}/../libc/${MACHINE_ARCH}/gen ${.CURDIR}/../libc/gen
@@ -10,8 +10,8 @@ SRCS+=  _pthread_stubs.c _rand48.c _spinlock_stub.c _thread_init.c \
        clock.c closedir.c confstr.c \
        ctermid.c ctype.c daemon.c devname.c dirname.c disklabel.c disktab.c \
        dlfcn.c drand48.c erand48.c err.c errlst.c \
-       exec.c fmtcheck.c fnmatch.c fpclassifyd.c fpclassifyf.c fstab.c \
-       ftok.c fts.c getbootfile.c getbsize.c \
+       exec.c fmtcheck.c fmtmsg.c fnmatch.c fpclassifyd.c fpclassifyf.c \
+       fstab.c ftok.c fts.c getbootfile.c getbsize.c \
        getcap.c getcwd.c getdomainname.c getgrent.c getgrouplist.c \
        gethostname.c getloadavg.c getlogin.c getmntinfo.c getmntvinfo.c \
        getnetgrent.c getobjformat.c getosreldate.c getpagesize.c \
@@ -23,7 +23,8 @@ SRCS+=  _pthread_stubs.c _rand48.c _spinlock_stub.c _thread_init.c \
        lockf.c lrand48.c mrand48.c msgctl.c \
        msgget.c msgrcv.c msgsnd.c nice.c \
        nlist.c nrand48.c ntp_gettime.c opendir.c \
-       pause.c popen.c posixshm.c psignal.c pthread_fake.c pwcache.c \
+       pause.c pmadvise.c popen.c posixshm.c \
+       psignal.c pthread_fake.c pwcache.c \
        raise.c readdir.c readpassphrase.c rewinddir.c \
        scandir.c seed48.c seekdir.c semconfig.c semctl.c semget.c semop.c \
        setdomainname.c sethostname.c setjmperr.c setmode.c setprogname.c \
@@ -34,7 +35,7 @@ SRCS+=  _pthread_stubs.c _rand48.c _spinlock_stub.c _thread_init.c \
        sysctlnametomib.c syslog.c telldir.c termios.c time.c times.c \
        timezone.c toascii.c tolower.c toupper.c ttyname.c ttyslot.c \
        ualarm.c ucontext.c ulimit.c uname.c unvis.c usleep.c utime.c \
-       valloc.c vis.c wait.c wait3.c waitpid.c
+       valloc.c vis.c wait.c wait3.c waitpid.c wordexp.c
 
 .if ${LIB} != {c_rtld}
 SRCS+= tls.c
@@ -49,7 +50,8 @@ MAN+= alarm.3 arc4random.3 clock.3 \
        confstr.3 ctermid.3 ctype.3 daemon.3 \
        devname.3 directory.3 dirname.3 \
        dladdr.3 dlinfo.3 dlopen.3 \
-       err.3 exec.3 fmtcheck.3 fnmatch.3 fpclassify.3 frexp.3 ftok.3 fts.3 \
+       err.3 exec.3 \
+       fmtcheck.3 fmtmsg.3 fnmatch.3 fpclassify.3 frexp.3 ftok.3 fts.3 \
        getbootfile.3 getbsize.3 getcap.3 getcontext.3 getcwd.3 \
        getdiskbyname.3 getdisktabbyname.3 getdomainname.3 getfsent.3 \
        getgrent.3 getgrouplist.3 gethostname.3 getloadavg.3 \
@@ -68,7 +70,7 @@ MAN+= alarm.3 arc4random.3 clock.3 \
        tcsendbreak.3 tcsetattr.3 tcsetpgrp.3 time.3 times.3 timezone.3 \
        toascii.3 tolower.3 toupper.3 ttyname.3 tzset.3 ualarm.3 \
        ucontext.3 ulimit.3 uname.3 unvis.3 usleep.3 utime.3 \
-       valloc.3 vis.3
+       valloc.3 vis.3 wordexp.3
 
 MLINKS+=arc4random.3 arc4random_addrandom.3 arc4random.3 arc4random_stir.3
 MLINKS+=ctermid.3 ctermid_r.3
@@ -143,4 +145,5 @@ MLINKS+=ttyname.3 isatty.3 ttyname.3 ttyslot.3 ttyname.3 ttyname_r.3
 MLINKS+=tzset.3 tzsetwall.3
 MLINKS+=unvis.3 strunvis.3 unvis.3 strunvisx.3
 MLINKS+=vis.3 strnvis.3 vis.3 strvis.3 vis.3 strvisx.3
+MLINKS+=wordexp.3 wordfree.3
 .endif
diff --git a/lib/libc/gen/fmtmsg.3 b/lib/libc/gen/fmtmsg.3
new file mode 100644 (file)
index 0000000..8c34092
--- /dev/null
@@ -0,0 +1,263 @@
+.\"
+.\" Copyright (c) 2002 Mike Barcroft <mike@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc/gen/fmtmsg.3,v 1.4 2002/12/04 18:57:44 ru Exp $
+.\" $DragonFly: src/lib/libc/gen/fmtmsg.3,v 1.1 2008/10/06 21:01:37 swildner Exp $
+.\"
+.Dd October 6, 2008
+.Dt FMTMSG 3
+.Os
+.Sh NAME
+.Nm fmtmsg
+.Nd display a detailed diagnostic message
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In fmtmsg.h
+.Ft int
+.Fo fmtmsg
+.Fa "long classification" "const char *label" "int severity"
+.Fa "const char *text" "const char *action" "const char *tag"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn fmtmsg
+function displays a detailed diagnostic message, based on
+the supplied arguments, to
+.Dv stderr
+and/or the system console.
+.Pp
+The
+.Fa classification
+argument is the bitwise inclusive
+.Tn OR
+of zero or one of the manifest constants from
+each of the classification groups below.
+The Output classification group is an exception since both
+.Dv MM_PRINT
+and
+.Dv MM_CONSOLE
+may be specified.
+.Bl -tag -width indent
+.It Output
+.Bl -tag -width ".Dv MM_CONSOLE"
+.It Dv MM_PRINT
+Output should take place on
+.Dv stderr .
+.It Dv MM_CONSOLE
+Output should take place on the system console.
+.El
+.It "Source of Condition (Major)"
+.Bl -tag -width ".Dv MM_CONSOLE"
+.It Dv MM_HARD
+The source of the condition is hardware related.
+.It Dv MM_SOFT
+The source of the condition is software related.
+.It Dv MM_FIRM
+The source of the condition is firmware related.
+.El
+.It "Source of Condition (Minor)"
+.Bl -tag -width ".Dv MM_CONSOLE"
+.It Dv MM_APPL
+The condition was detected at the application level.
+.It Dv MM_UTIL
+The condition was detected at the utility level.
+.It Dv MM_OPSYS
+The condition was detected at the operating system level.
+.El
+.It Status
+.Bl -tag -width ".Dv MM_CONSOLE"
+.It Dv MM_RECOVER
+The application can recover from the condition.
+.It Dv MM_NRECOV
+The application is unable to recover from the condition.
+.El
+.El
+.Pp
+Alternatively, the
+.Dv MM_NULLMC
+manifest constant may be used to specify no classification.
+.Pp
+The
+.Fa label
+argument indicates the source of the message.
+It is made up of two fields separated by a colon
+.Pq Ql \&: .
+The first field can be up to 10 bytes,
+and the second field can be up to 14 bytes.
+The
+.Dv MM_NULLLBL
+manifest constant may be used to specify no label.
+.Pp
+The
+.Fa severity
+argument identifies the importance of the condition.
+One of the following manifest constants should be used for this argument.
+.Bl -tag -offset indent -width ".Dv MM_WARNING"
+.It Dv MM_HALT
+The application has confronted a serious fault and is halting.
+.It Dv MM_ERROR
+The application has detected a fault.
+.It Dv MM_WARNING
+The application has detected an unusual condition,
+that could be indicative of a problem.
+.It Dv MM_INFO
+The application is providing information about a non-error condition.
+.It Dv MM_NOSEV
+No severity level supplied.
+.El
+.Pp
+The
+.Fa text
+argument details the error condition that caused the message.
+There is no limit on the size of this character string.
+The
+.Dv MM_NULLTXT
+manifest constant may be used to specify no text.
+.Pp
+The
+.Fa action
+argument details how the error-recovery process should begin.
+Upon output,
+.Fn fmtmsg
+will prefix
+.Qq Li "TO FIX:"
+to the beginning of the
+.Fa action
+argument.
+The
+.Dv MM_NULLACT
+manifest constant may be used to specify no action.
+.Pp
+The
+.Fa tag
+argument should reference online documentation for the message.
+This usually includes the
+.Fa label
+and a unique identifying number.
+An example tag is
+.Qq Li BSD:ls:168 .
+The
+.Dv MM_NULLTAG
+manifest constant may be used to specify no tag.
+.Sh RETURN VALUES
+The
+.Fn fmtmsg
+function returns
+.Dv MM_OK
+upon success,
+.Dv MM_NOMSG
+to indicate output to
+.Dv stderr
+failed,
+.Dv MM_NOCON
+to indicate output to the system console failed, or
+.Dv MM_NOTOK
+to indicate output to
+.Dv stderr
+and the system console failed.
+.Sh ENVIRONMENT
+The
+.Ev MSGVERB
+(message verbosity)
+environment variable specifies which arguments to
+.Fn fmtmsg
+will be output to
+.Dv stderr ,
+and in which order.
+.Ev MSGVERB
+should be a colon
+.Pq Ql \&:
+separated list of identifiers.
+Valid identifiers include:
+.Li label , severity , text , action ,
+and
+.Li tag .
+If invalid identifiers are specified or incorrectly separated,
+the default message verbosity and ordering will be used.
+The default ordering is equivalent to a
+.Ev MSGVERB
+with a value of
+.Qq Li label:severity:text:action:tag .
+.Sh EXAMPLES
+The code:
+.Bd -literal -offset indent
+fmtmsg(MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR,
+    "illegal option -- z", "refer to manual", "BSD:ls:001");
+.Ed
+.Pp
+will output:
+.Bd -literal -offset indent
+BSD:ls: ERROR: illegal option -- z
+TO FIX: refer to manual BSD:ls:001
+.Ed
+.Pp
+to
+.Dv stderr .
+.Pp
+The same code, with
+.Ev MSGVERB
+set to
+.Qq Li "text:severity:action:tag" ,
+produces:
+.Bd -literal -offset indent
+illegal option -- z: ERROR
+TO FIX: refer to manual BSD:ls:001
+.Ed
+.Sh SEE ALSO
+.Xr err 3 ,
+.Xr exit 3 ,
+.Xr strerror 3
+.Sh STANDARDS
+The
+.Fn fmtmsg
+function conforms to
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Fn fmtmsg
+function first appeared in
+.Fx 5.0 .
+It was imported into
+.Dx 2.1 .
+.Sh BUGS
+Specifying
+.Dv MM_NULLMC
+for the
+.Fa classification
+argument makes little sense, since without an output specified,
+.Fn fmtmsg
+is unable to do anything useful.
+.Pp
+In order for
+.Fn fmtmsg
+to output to the system console, the effective
+user must have appropriate permission to write to
+.Pa /dev/console .
+This means that on most systems
+.Fn fmtmsg
+will return
+.Dv MM_NOCON
+unless the effective user is root.
diff --git a/lib/libc/gen/fmtmsg.c b/lib/libc/gen/fmtmsg.c
new file mode 100644 (file)
index 0000000..74aeb2a
--- /dev/null
@@ -0,0 +1,220 @@
+/*-
+ * Copyright (c) 2002 Mike Barcroft <mike@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libc/gen/fmtmsg.c,v 1.5 2003/05/01 19:03:13 nectar Exp $
+ * $DragonFly: src/lib/libc/gen/fmtmsg.c,v 1.1 2008/10/06 21:01:37 swildner Exp $
+ */
+
+#include <fmtmsg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Default value for MSGVERB. */
+#define        DFLT_MSGVERB    "label:severity:text:action:tag"
+
+/* Maximum valid size for a MSGVERB. */
+#define        MAX_MSGVERB     sizeof(DFLT_MSGVERB)
+
+static char    *printfmt(char *, long, const char *, int, const char *,
+                   const char *, const char *);
+static char    *nextcomp(const char *);
+static const char
+               *sevinfo(int);
+static int      validmsgverb(const char *);
+
+static const char *validlist[] = {
+       "label", "severity", "text", "action", "tag", NULL
+};
+
+int
+fmtmsg(long class, const char *label, int sev, const char *text,
+    const char *action, const char *tag)
+{
+       FILE *fp;
+       char *env, *msgverb, *output;
+
+       if (class & MM_PRINT) {
+               if ((env = getenv("MSGVERB")) != NULL && *env != '\0' &&
+                   strlen(env) <= strlen(DFLT_MSGVERB)) {
+                       if ((msgverb = strdup(env)) == NULL)
+                               return (MM_NOTOK);
+                       else if (validmsgverb(msgverb) == 0) {
+                               free(msgverb);
+                               goto def;
+                       }
+               } else {
+def:
+                       if ((msgverb = strdup(DFLT_MSGVERB)) == NULL)
+                               return (MM_NOTOK);
+               }
+               output = printfmt(msgverb, class, label, sev, text, action,
+                   tag);
+               if (output == NULL) {
+                       free(msgverb);
+                       return (MM_NOTOK);
+               }
+               if (*output != '\0')
+                       fprintf(stderr, "%s", output);
+               free(msgverb);
+               free(output);
+       }
+       if (class & MM_CONSOLE) {
+               output = printfmt(DFLT_MSGVERB, class, label, sev, text,
+                   action, tag);
+               if (output == NULL)
+                       return (MM_NOCON);
+               if (*output != '\0') {
+                       if ((fp = fopen("/dev/console", "a")) == NULL) {
+                               free(output);
+                               return (MM_NOCON);
+                       }
+                       fprintf(fp, "%s", output);
+                       fclose(fp);
+               }
+               free(output);
+       }
+       return (MM_OK);
+}
+
+#define INSERT_COLON                                                   \
+       if (*output != '\0')                                            \
+               strlcat(output, ": ", size)
+#define INSERT_NEWLINE                                                 \
+       if (*output != '\0')                                            \
+               strlcat(output, "\n", size)
+#define INSERT_SPACE                                                   \
+       if (*output != '\0')                                            \
+               strlcat(output, " ", size)
+
+/*
+ * Returns NULL on memory allocation failure, otherwise returns a pointer to
+ * a newly malloc()'d output buffer.
+ */
+static char *
+printfmt(char *msgverb, long class, const char *label, int sev,
+    const char *text, const char *act, const char *tag)
+{
+       size_t size;
+       char *comp, *output;
+       const char *sevname;
+
+       size = 32;
+       if (label != MM_NULLLBL)
+               size += strlen(label);
+       if ((sevname = sevinfo(sev)) != NULL)
+               size += strlen(sevname);
+       if (text != MM_NULLTXT)
+               size += strlen(text);
+       if (text != MM_NULLACT)
+               size += strlen(act);
+       if (tag != MM_NULLTAG)
+               size += strlen(tag);
+
+       if ((output = malloc(size)) == NULL)
+               return (NULL);
+       *output = '\0';
+       while ((comp = nextcomp(msgverb)) != NULL) {
+               if (strcmp(comp, "label") == 0 && label != MM_NULLLBL) {
+                       INSERT_COLON;
+                       strlcat(output, label, size);
+               } else if (strcmp(comp, "severity") == 0 && sevname != NULL) {
+                       INSERT_COLON;
+                       strlcat(output, sevinfo(sev), size);
+               } else if (strcmp(comp, "text") == 0 && text != MM_NULLTXT) {
+                       INSERT_COLON;
+                       strlcat(output, text, size);
+               } else if (strcmp(comp, "action") == 0 && act != MM_NULLACT) {
+                       INSERT_NEWLINE;
+                       strlcat(output, "TO FIX: ", size);
+                       strlcat(output, act, size);
+               } else if (strcmp(comp, "tag") == 0 && tag != MM_NULLTAG) {
+                       INSERT_SPACE;
+                       strlcat(output, tag, size);
+               }
+       }
+       INSERT_NEWLINE;
+       return (output);
+}
+
+/*
+ * Returns a component of a colon delimited string.  NULL is returned to
+ * indicate that there are no remaining components.  This function must be
+ * called until it returns NULL in order for the local state to be cleared.
+ */
+static char *
+nextcomp(const char *msgverb)
+{
+       static char lmsgverb[MAX_MSGVERB], *state;
+       char *retval;
+       
+       if (*lmsgverb == '\0') {
+               strlcpy(lmsgverb, msgverb, sizeof(lmsgverb));
+               retval = strtok_r(lmsgverb, ":", &state);
+       } else {
+               retval = strtok_r(NULL, ":", &state);
+       }
+       if (retval == NULL)
+               *lmsgverb = '\0';
+       return (retval);
+}
+
+static const char *
+sevinfo(int sev)
+{
+
+       switch (sev) {
+       case MM_HALT:
+               return ("HALT");
+       case MM_ERROR:
+               return ("ERROR");
+       case MM_WARNING:
+               return ("WARNING");
+       case MM_INFO:
+               return ("INFO");
+       default:
+               return (NULL);
+       }
+}
+
+/*
+ * Returns 1 if the msgverb list is valid, otherwise 0.
+ */
+static int
+validmsgverb(const char *msgverb)
+{
+       char *msgcomp;
+       int i, equality;
+
+       equality = 0;
+       while ((msgcomp = nextcomp(msgverb)) != NULL) {
+               equality--;
+               for (i = 0; validlist[i] != NULL; i++) {
+                       if (strcmp(msgcomp, validlist[i]) == 0)
+                               equality++;
+               }
+       }
+       return (!equality);
+}
diff --git a/lib/libc/gen/pmadvise.c b/lib/libc/gen/pmadvise.c
new file mode 100644 (file)
index 0000000..bb76967
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * The contents of this file are in the public domain.
+ * Written by Garrett A. Wollman, 2000-10-07.
+ *
+ * $FreeBSD: src/lib/libc/gen/pmadvise.c,v 1.3 2003/08/09 03:23:24 bms Exp $
+ * $DragonFly: src/lib/libc/gen/pmadvise.c,v 1.1 2008/10/06 21:01:37 swildner Exp $
+ */
+
+#include <sys/mman.h>
+
+int
+posix_madvise(void *address, size_t size, int how)
+{
+       return madvise(address, size, how);
+}
diff --git a/lib/libc/gen/wordexp.3 b/lib/libc/gen/wordexp.3
new file mode 100644 (file)
index 0000000..1780be4
--- /dev/null
@@ -0,0 +1,207 @@
+.\"
+.\" Copyright (c) 2002 Tim J. Robbins
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc/gen/wordexp.3,v 1.9 2006/04/18 21:37:24 ceri Exp $
+.\" $DragonFly: src/lib/libc/gen/wordexp.3,v 1.1 2008/10/06 21:01:37 swildner Exp $
+.\"
+.Dd October 6, 2008
+.Dt WORDEXP 3
+.Os
+.Sh NAME
+.Nm wordexp
+.Nd "perform shell-style word expansions"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In wordexp.h
+.Ft int
+.Fn wordexp "const char * restrict words" "wordexp_t * restrict we" "int flags"
+.Ft void
+.Fn wordfree "wordexp_t *we"
+.Sh DESCRIPTION
+The
+.Fn wordexp
+function performs shell-style word expansion on
+.Fa words
+and places the list of words into the
+.Va we_wordv
+member of
+.Fa we ,
+and the number of words into
+.Va we_wordc .
+.Pp
+The
+.Fa flags
+argument is the bitwise inclusive OR of any of the following constants:
+.Bl -tag -width ".Dv WRDE_SHOWERR"
+.It Dv WRDE_APPEND
+Append the words to those generated by a previous call to
+.Fn wordexp .
+.It Dv WRDE_DOOFFS
+As many
+.Dv NULL
+pointers as are specified by the
+.Va we_offs
+member of
+.Fa we
+are added to the front of
+.Va we_wordv .
+.It Dv WRDE_NOCMD
+Disallow command substitution in
+.Fa words .
+See the note in
+.Sx BUGS
+before using this.
+.It Dv WRDE_REUSE
+The
+.Fa we
+argument was passed to a previous successful call to
+.Fn wordexp
+but has not been passed to
+.Fn wordfree .
+The implementation may reuse the space allocated to it.
+.It Dv WRDE_SHOWERR
+Do not redirect shell error messages to
+.Pa /dev/null .
+.It Dv WRDE_UNDEF
+Report error on an attempt to expand an undefined shell variable.
+.El
+.Pp
+The
+.Vt wordexp_t
+structure is defined in
+.In wordexp.h
+as:
+.Bd -literal -offset indent
+typedef struct {
+       size_t  we_wordc;       /* count of words matched */
+       char    **we_wordv;     /* pointer to list of words */
+       size_t  we_offs;        /* slots to reserve in we_wordv */
+} wordexp_t;
+.Ed
+.Pp
+The
+.Fn wordfree
+function frees the memory allocated by
+.Fn wordexp .
+.Sh IMPLEMENTATION NOTES
+The
+.Fn wordexp
+function is implemented as a wrapper around the undocumented
+.Ic wordexp
+shell built-in command.
+.Sh RETURN VALUES
+The
+.Fn wordexp
+function returns zero if successful, otherwise it returns one of the following
+error codes:
+.Bl -tag -width ".Dv WRDE_NOSPACE"
+.It Dv WRDE_BADCHAR
+The
+.Fa words
+argument contains one of the following unquoted characters:
+.Aq newline ,
+.Ql | ,
+.Ql & ,
+.Ql \&; ,
+.Ql < ,
+.Ql > ,
+.Ql \&( ,
+.Ql \&) ,
+.Ql { ,
+.Ql } .
+.It Dv WRDE_BADVAL
+An attempt was made to expand an undefined shell variable and
+.Dv WRDE_UNDEF
+is set in
+.Fa flags .
+.It Dv WRDE_CMDSUB
+An attempt was made to use command substitution and
+.Dv WRDE_NOCMD
+is set in
+.Fa flags .
+.It Dv WRDE_NOSPACE
+Not enough memory to store the result.
+.It Dv WRDE_SYNTAX
+Shell syntax error in
+.Fa words .
+.El
+.Pp
+The
+.Fn wordfree
+function returns no value.
+.Sh ENVIRONMENT
+.Bl -tag -width ".Ev IFS"
+.It Ev IFS
+Field separator.
+.El
+.Sh EXAMPLES
+Invoke the editor on all
+.Pa .c
+files in the current directory
+and
+.Pa /etc/motd
+(error checking omitted):
+.Bd -literal -offset indent
+wordexp_t we;
+
+wordexp("${EDITOR:-vi} *.c /etc/motd", &we, 0);
+execvp(we.we_wordv[0], we.we_wordv);
+.Ed
+.Sh DIAGNOSTICS
+Diagnostic messages from the shell are written to the standard error output
+if
+.Dv WRDE_SHOWERR
+is set in
+.Fa flags .
+.Sh SEE ALSO
+.Xr sh 1 ,
+.Xr fnmatch 3 ,
+.Xr glob 3 ,
+.Xr popen 3 ,
+.Xr system 3
+.Sh STANDARDS
+The
+.Fn wordexp
+and
+.Fn wordfree
+functions conform to
+.St -p1003.1-2001 .
+.Sh BUGS
+Do not pass untrusted user data to
+.Fn wordexp ,
+regardless of whether the
+.Dv WRDE_NOCMD
+flag is set.
+The
+.Fn wordexp
+function attempts to detect input that would cause commands to be
+executed before passing it to the shell
+but it does not use the same parser so it may be fooled.
+.Pp
+The current
+.Fn wordexp
+implementation does not recognize multibyte characters, since the
+shell (which it invokes to perform expansions) does not.
diff --git a/lib/libc/gen/wordexp.c b/lib/libc/gen/wordexp.c
new file mode 100644 (file)
index 0000000..8d098b6
--- /dev/null
@@ -0,0 +1,314 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libc/gen/wordexp.c,v 1.6 2004/06/30 13:55:08 tjr Exp $
+ * $DragonFly: src/lib/libc/gen/wordexp.c,v 1.1 2008/10/06 21:01:37 swildner Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wordexp.h>
+
+static int     we_askshell(const char *, wordexp_t *, int);
+static int     we_check(const char *, int);
+
+/*
+ * wordexp --
+ *     Perform shell word expansion on `words' and place the resulting list
+ *     of words in `we'. See wordexp(3).
+ *
+ *     Specified by IEEE Std. 1003.1-2001.
+ */
+int
+wordexp(const char * __restrict words, wordexp_t * __restrict we, int flags)
+{
+       int error;
+
+       if (flags & WRDE_REUSE)
+               wordfree(we);
+       if ((flags & WRDE_APPEND) == 0) {
+               we->we_wordc = 0;
+               we->we_wordv = NULL;
+               we->we_strings = NULL;
+               we->we_nbytes = 0;
+       }
+       if ((error = we_check(words, flags)) != 0) {
+               wordfree(we);
+               return (error);
+       }
+       if ((error = we_askshell(words, we, flags)) != 0) {
+               wordfree(we);
+               return (error);
+       }
+       return (0);
+}
+
+/*
+ * we_askshell --
+ *     Use the `wordexp' /bin/sh builtin function to do most of the work
+ *     in expanding the word string. This function is complicated by
+ *     memory management.
+ */
+static int
+we_askshell(const char *words, wordexp_t *we, int flags)
+{
+       int pdes[2];                    /* Pipe to child */
+       char bbuf[9];                   /* Buffer for byte count */
+       char wbuf[9];                   /* Buffer for word count */
+       long nwords, nbytes;            /* Number of words, bytes from child */
+       long i;                         /* Handy integer */
+       size_t sofs;                    /* Offset into we->we_strings */
+       size_t vofs;                    /* Offset into we->we_wordv */
+       pid_t pid;                      /* Process ID of child */
+       int status;                     /* Child exit status */
+       char *ifs;                      /* IFS env. var. */
+       char *np, *p;                   /* Handy pointers */
+       char *nstrings;                 /* Temporary for realloc() */
+       char **nwv;                     /* Temporary for realloc() */
+
+       if ((ifs = getenv("IFS")) == NULL)
+               ifs = " \t\n";
+
+       if (pipe(pdes) < 0)
+               return (WRDE_NOSPACE);  /* XXX */
+       if ((pid = fork()) < 0) {
+               _close(pdes[0]);
+               _close(pdes[1]);
+               return (WRDE_NOSPACE);  /* XXX */
+       }
+       else if (pid == 0) {
+               /*
+                * We are the child; just get /bin/sh to run the wordexp
+                * builtin on `words'.
+                */
+               int devnull;
+               char *cmd;
+
+               _close(pdes[0]);
+               if (_dup2(pdes[1], STDOUT_FILENO) < 0)
+                       _exit(1);
+               _close(pdes[1]);
+               if (asprintf(&cmd, "wordexp%c%s\n", *ifs, words) < 0)
+                       _exit(1);
+               if ((flags & WRDE_SHOWERR) == 0) {
+                       if ((devnull = _open(_PATH_DEVNULL, O_RDWR, 0666)) < 0)
+                               _exit(1);
+                       if (_dup2(devnull, STDERR_FILENO) < 0)
+                               _exit(1);
+                       _close(devnull);
+               }
+               execl(_PATH_BSHELL, "sh", flags & WRDE_UNDEF ? "-u" : "+u",
+                   "-c", cmd, (char *)NULL);
+               _exit(1);
+       }
+
+       /*
+        * We are the parent; read the output of the shell wordexp function,
+        * which is a 32-bit hexadecimal word count, a 32-bit hexadecimal
+        * byte count (not including terminating null bytes), followed by
+        * the expanded words separated by nulls.
+        */
+       _close(pdes[1]);
+       if (_read(pdes[0], wbuf, 8) != 8 || _read(pdes[0], bbuf, 8) != 8) {
+               _close(pdes[0]);
+               _waitpid(pid, &status, 0);
+               return (flags & WRDE_UNDEF ? WRDE_BADVAL : WRDE_SYNTAX);
+       }
+       wbuf[8] = bbuf[8] = '\0';
+       nwords = strtol(wbuf, NULL, 16);
+       nbytes = strtol(bbuf, NULL, 16) + nwords;
+
+       /*
+        * Allocate or reallocate (when flags & WRDE_APPEND) the word vector
+        * and string storage buffers for the expanded words we're about to
+        * read from the child.
+        */
+       sofs = we->we_nbytes;
+       vofs = we->we_wordc;
+       if ((flags & (WRDE_DOOFFS|WRDE_APPEND)) == (WRDE_DOOFFS|WRDE_APPEND))
+               vofs += we->we_offs;
+       we->we_wordc += nwords;
+       we->we_nbytes += nbytes;
+       if ((nwv = realloc(we->we_wordv, (we->we_wordc + 1 +
+           (flags & WRDE_DOOFFS ?  we->we_offs : 0)) *
+           sizeof(char *))) == NULL) {
+               _close(pdes[0]);
+               _waitpid(pid, &status, 0);
+               return (WRDE_NOSPACE);
+       }
+       we->we_wordv = nwv;
+       if ((nstrings = realloc(we->we_strings, we->we_nbytes)) == NULL) {
+               _close(pdes[0]);
+               _waitpid(pid, &status, 0);
+               return (WRDE_NOSPACE);
+       }
+       for (i = 0; i < vofs; i++)
+               if (we->we_wordv[i] != NULL)
+                       we->we_wordv[i] += nstrings - we->we_strings;
+       we->we_strings = nstrings;
+
+       if (_read(pdes[0], we->we_strings + sofs, nbytes) != nbytes) {
+               _close(pdes[0]);
+               _waitpid(pid, &status, 0);
+               return (flags & WRDE_UNDEF ? WRDE_BADVAL : WRDE_SYNTAX);
+       }
+
+       if (_waitpid(pid, &status, 0) < 0 || !WIFEXITED(status) ||
+           WEXITSTATUS(status) != 0) {
+               _close(pdes[0]);
+               return (flags & WRDE_UNDEF ? WRDE_BADVAL : WRDE_SYNTAX);
+       }
+       _close(pdes[0]);
+
+       /*
+        * Break the null-terminated expanded word strings out into
+        * the vector.
+        */
+       if (vofs == 0 && flags & WRDE_DOOFFS)
+               while (vofs < we->we_offs)
+                       we->we_wordv[vofs++] = NULL;
+       p = we->we_strings + sofs;
+       while (nwords-- != 0) {
+               we->we_wordv[vofs++] = p;
+               if ((np = memchr(p, '\0', nbytes)) == NULL)
+                       return (WRDE_NOSPACE);  /* XXX */
+               nbytes -= np - p + 1;
+               p = np + 1;
+       }
+       we->we_wordv[vofs] = NULL;
+
+       return (0);
+}
+
+/*
+ * we_check --
+ *     Check that the string contains none of the following unquoted
+ *     special characters: <newline> |&;<>(){}
+ *     or command substitutions when WRDE_NOCMD is set in flags.
+ */
+static int
+we_check(const char *words, int flags)
+{
+       char c;
+       int dquote, level, quote, squote;
+
+       quote = squote = dquote = 0;
+       while ((c = *words++) != '\0') {
+               switch (c) {
+               case '\\':
+                       quote ^= 1;
+                       continue;
+               case '\'':
+                       if (quote + dquote == 0)
+                               squote ^= 1;
+                       break;
+               case '"':
+                       if (quote + squote == 0)
+                               dquote ^= 1;
+                       break;
+               case '`':
+                       if (quote + squote == 0 && flags & WRDE_NOCMD)
+                               return (WRDE_CMDSUB);
+                       while ((c = *words++) != '\0' && c != '`')
+                               if (c == '\\' && (c = *words++) == '\0')
+                                       break;
+                       if (c == '\0')
+                               return (WRDE_SYNTAX);
+                       break;
+               case '|': case '&': case ';': case '<': case '>':
+               case '{': case '}': case '(': case ')': case '\n':
+                       if (quote + squote + dquote == 0)
+                               return (WRDE_BADCHAR);
+                       break;
+               case '$':
+                       if ((c = *words++) == '\0')
+                               break;
+                       else if (quote + squote == 0 && c == '(') {
+                               if (flags & WRDE_NOCMD && *words != '(')
+                                       return (WRDE_CMDSUB);
+                               level = 1;
+                               while ((c = *words++) != '\0') {
+                                       if (c == '\\') {
+                                               if ((c = *words++) == '\0')
+                                                       break;
+                                       } else if (c == '(')
+                                               level++;
+                                       else if (c == ')' && --level == 0)
+                                               break;
+                               }
+                               if (c == '\0' || level != 0)
+                                       return (WRDE_SYNTAX);
+                       } else if (quote + squote == 0 && c == '{') {
+                               level = 1;
+                               while ((c = *words++) != '\0') {
+                                       if (c == '\\') {
+                                               if ((c = *words++) == '\0')
+                                                       break;
+                                       } else if (c == '{')
+                                               level++;
+                                       else if (c == '}' && --level == 0)
+                                               break;
+                               }
+                               if (c == '\0' || level != 0)
+                                       return (WRDE_SYNTAX);
+                       } else
+                               c = *--words;
+                       break;
+               default:
+                       break;
+               }
+               quote = 0;
+       }
+       if (quote + squote + dquote != 0)
+               return (WRDE_SYNTAX);
+
+       return (0);
+}
+
+/*
+ * wordfree --
+ *     Free the result of wordexp(). See wordexp(3).
+ *
+ *     Specified by IEEE Std. 1003.1-2001.
+ */
+void
+wordfree(wordexp_t *we)
+{
+
+       if (we == NULL)
+               return;
+       free(we->we_wordv);
+       free(we->we_strings);
+       we->we_wordv = NULL;
+       we->we_strings = NULL;
+       we->we_nbytes = 0;
+       we->we_wordc = 0;
+}
index 70dcaaa..d8c5cf0 100644 (file)
@@ -1,6 +1,6 @@
 #      from @(#)Makefile.inc   8.3 (Berkeley) 2/4/95
 # $FreeBSD: src/lib/libc/stdlib/Makefile.inc,v 1.19.2.4 2001/10/02 11:15:38 ru Exp $
-# $DragonFly: src/lib/libc/stdlib/Makefile.inc,v 1.23 2008/08/09 21:55:59 swildner Exp $
+# $DragonFly: src/lib/libc/stdlib/Makefile.inc,v 1.24 2008/10/06 21:01:37 swildner Exp $
 
 # machine-independent stdlib sources
 .PATH: ${.CURDIR}/../libc/${MACHINE_ARCH}/stdlib ${.CURDIR}/../libc/stdlib
@@ -10,7 +10,8 @@ MISRCS+=abort.c abs.c atexit.c atof.c atoi.c atol.c atoll.c bsearch.c calloc.c d
        imaxabs.c imaxdiv.c \
        labs.c ldiv.c llabs.c lldiv.c lsearch.c malloc.c merge.c putenv.c \
        qsort.c radixsort.c rand.c \
-       random.c reallocf.c realpath.c setenv.c strtod.c strtoimax.c strtol.c \
+       random.c reallocf.c realpath.c \
+       setenv.c strfmon.c strtod.c strtoimax.c strtol.c \
        strtoll.c strtonum.c strtoq.c strtoul.c strtoull.c strtoumax.c \
        strtouq.c system.c tdelete.c tfind.c tsearch.c twalk.c
 
@@ -24,8 +25,8 @@ MAN+= abort.3 abs.3 alloca.3 atexit.3 atof.3 atoi.3 atol.3 bsearch.3 \
        div.3 exit.3 getenv.3 getopt.3 getopt_long.3 getsubopt.3 hcreate.3 \
        imaxabs.3 imaxdiv.3 \
        labs.3 ldiv.3 llabs.3 lldiv.3 lsearch.3 malloc.3 memory.3 \
-       qsort.3 radixsort.3 rand.3 random.3 \
-       realpath.3 strtod.3 strtol.3 strtonum.3 strtoul.3 system.3 tsearch.3
+       qsort.3 radixsort.3 rand.3 random.3 realpath.3 \
+       strfmon.3 strtod.3 strtol.3 strtonum.3 strtoul.3 system.3 tsearch.3
 
 MLINKS+=atol.3 atoll.3
 MLINKS+=exit.3 _Exit.3
diff --git a/lib/libc/stdlib/strfmon.3 b/lib/libc/stdlib/strfmon.3
new file mode 100644 (file)
index 0000000..02835c2
--- /dev/null
@@ -0,0 +1,169 @@
+.\" Copyright (c) 2001 Jeroen Ruigrok van der Werven <asmodai@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc/stdlib/strfmon.3,v 1.7 2003/01/06 06:21:25 tjr Exp $
+.\" $NetBSD: strfmon.3,v 1.3 2005/04/04 08:19:00 wiz Exp $
+.\" $DragonFly: src/lib/libc/stdlib/strfmon.3,v 1.1 2008/10/06 21:01:37 swildner Exp $
+.\"
+.Dd October 6, 2008
+.Dt STRFMON 3
+.Os
+.Sh NAME
+.Nm strfmon
+.Nd convert monetary value to string
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In monetary.h
+.Ft ssize_t
+.Fn strfmon "char * restrict s" "size_t maxsize" "const char * restrict format" "..."
+.Sh DESCRIPTION
+The
+.Fn strfmon
+function places characters into the array pointed to by
+.Fa s
+as controlled by the string pointed to by
+.Fa format .
+No more than
+.Fa maxsize
+bytes are placed into the array.
+.Pp
+The format string is composed of zero or more directives:
+ordinary characters (not
+.Cm % ) ,
+which are copied unchanged to the output stream; and conversion
+specifications, each of which results in fetching zero or more subsequent
+arguments.
+Each conversion specification is introduced by the
+.Cm %
+character.
+After the
+.Cm % ,
+the following appear in sequence:
+.Bl -bullet
+.It
+Zero or more of the following flags:
+.Bl -tag -width "XXX"
+.It Cm = Ns Ar f
+A
+.Sq Cm =
+character followed by another character
+.Ar f
+which is used as the numeric fill character.
+.It Cm ^
+Do not use grouping characters, regardless of the current locale default.
+.It Cm +
+Represent positive values by prefixing them with a positive sign,
+and negative values by prefixing them with a negative sign.
+This is the default.
+.It Cm \&(
+Enclose negative values in parentheses.
+.It Cm \&!
+Do not include a currency symbol in the output.
+.It Cm \-
+Left justify the result.
+Only valid when a field width is specified.
+.El
+.It
+An optional minimum field width as a decimal number.
+By default, there is no minimum width.
+.It
+A
+.Sq Cm #
+sign followed by a decimal number specifying the maximum
+expected number of digits after the radix character.
+.It
+A
+.Sq Cm \&.
+character followed by a decimal number specifying the number
+of digits after the radix character.
+.It
+One of the following conversion specifiers:
+.Bl -tag -width "XXX"
+.It Cm i
+The
+.Vt double
+argument is formatted as an international monetary amount.
+.It Cm n
+The
+.Vt double
+argument is formatted as a national monetary amount.
+.It Cm %
+A
+.Sq Li %
+character is written.
+.El
+.El
+.Sh RETURN VALUES
+If the total number of resulting bytes including the terminating
+.Dv NULL
+byte is not more than
+.Fa maxsize ,
+.Fn strfmon
+returns the number of bytes placed into the array pointed to by
+.Fa s ,
+not including the terminating
+.Dv NULL
+byte.
+Otherwise, \-1 is returned,
+the contents of the array are indeterminate,
+and
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The
+.Fn strfmon
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er E2BIG
+Conversion stopped due to lack of space in the buffer.
+.It Bq Er EINVAL
+The format string is invalid.
+.It Bq Er ENOMEM
+Not enough memory for temporary buffers.
+.El
+.Sh SEE ALSO
+.Xr localeconv 3
+.Sh STANDARDS
+The
+.Fn strfmon
+function
+conforms to
+.St -p1003.1-2001 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Fn strfmon
+function was implemented by
+.An Alexey Zelkin Aq phantom@FreeBSD.org .
+.Pp
+This manual page was written by
+.An Jeroen Ruigrok van der Werven Aq asmodai@FreeBSD.org
+based on the standard's text.
+.Sh BUGS
+The
+.Fn strfmon
+function does not correctly handle multibyte characters in the
+.Fa format
+argument.
diff --git a/lib/libc/stdlib/strfmon.c b/lib/libc/stdlib/strfmon.c
new file mode 100644 (file)
index 0000000..1194ba4
--- /dev/null
@@ -0,0 +1,615 @@
+/*-
+ * Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libc/stdlib/strfmon.c,v 1.19 2008/04/24 07:49:00 ru Exp $
+ * $NetBSD: strfmon.c,v 1.3 2005/12/02 14:19:43 yamt Exp $
+ * $DragonFly: src/lib/libc/stdlib/strfmon.c,v 1.1 2008/10/06 21:01:37 swildner Exp $
+ */
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <monetary.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* internal flags */
+#define        NEED_GROUPING           0x01    /* print digits grouped (default) */
+#define        SIGN_POSN_USED          0x02    /* '+' or '(' usage flag */
+#define        LOCALE_POSN             0x04    /* use locale defined +/- (default) */
+#define        PARENTH_POSN            0x08    /* enclose negative amount in () */
+#define        SUPRESS_CURR_SYMBOL     0x10    /* supress the currency from output */
+#define        LEFT_JUSTIFY            0x20    /* left justify */
+#define        USE_INTL_CURRENCY       0x40    /* use international currency symbol */
+#define IS_NEGATIVE            0x80    /* is argument value negative ? */
+
+/* internal macros */
+#define PRINT(CH) do {                                         \
+       if (dst >= s + maxsize)                                 \
+               goto e2big_error;                               \
+       *dst++ = CH;                                            \
+} while (0)
+
+#define PRINTS(STR) do {                                       \
+       const char *tmps = STR;                                 \
+       while (*tmps != '\0')                                   \
+               PRINT(*tmps++);                                 \
+} while (0)
+
+#define GET_NUMBER(VAR)        do {                                    \
+       VAR = 0;                                                \
+       while (isdigit((unsigned char)*fmt)) {                  \
+               if (VAR > INT_MAX / 10)                         \
+                       goto e2big_error;                       \
+               VAR *= 10;                                      \
+               VAR += *fmt - '0';                              \
+               if (VAR < 0)                                    \
+                       goto e2big_error;                       \
+               fmt++;                                          \
+       }                                                       \
+} while (0)
+
+#define GRPCPY(howmany) do {                                   \
+       int i = howmany;                                        \
+       while (i-- > 0) {                                       \
+               avalue_size--;                                  \
+               *--bufend = *(avalue+avalue_size+padded);       \
+       }                                                       \
+} while (0)
+
+#define GRPSEP do {                                            \
+       *--bufend = thousands_sep;                              \
+       groups++;                                               \
+} while (0)
+
+static void __setup_vars(int, char *, char *, char *, const char **);
+static int __calc_left_pad(int, char *);
+static char *__format_grouped_double(double, int *, int, int, int);
+
+ssize_t
+strfmon(char * __restrict s, size_t maxsize, const char * __restrict format,
+    ...)
+{
+       va_list         ap;
+       char            *dst;           /* output destination pointer */
+       const char      *fmt;           /* current format poistion pointer */
+       struct lconv    *lc;            /* pointer to lconv structure */
+       char            *asciivalue;    /* formatted double pointer */
+
+       int             flags;          /* formatting options */
+       int             pad_char;       /* padding character */
+       int             pad_size;       /* pad size */
+       int             width;          /* field width */
+       int             left_prec;      /* left precision */
+       int             right_prec;     /* right precision */
+       double          value;          /* just value */
+       char            space_char = ' '; /* space after currency */
+
+       char            cs_precedes,    /* values gathered from struct lconv */
+                       sep_by_space,
+                       sign_posn,
+                       *currency_symbol;
+       const char      *signstr;
+       char            *tmpptr;        /* temporary vars */
+       int             sverrno;
+
+        va_start(ap, format);
+
+       lc = localeconv();
+       dst = s;
+       fmt = format;
+       asciivalue = NULL;
+       currency_symbol = NULL;
+       pad_size = 0;
+
+       while (*fmt) {
+               /* pass nonformating characters AS IS */
+               if (*fmt != '%')
+                       goto literal;
+
+               /* '%' found ! */
+
+               /* "%%" mean just '%' */
+               if (*(fmt+1) == '%') {
+                       fmt++;
+       literal:
+                       PRINT(*fmt++);
+                       continue;
+               }
+
+               /* set up initial values */
+               flags = (NEED_GROUPING|LOCALE_POSN);
+               pad_char = ' ';         /* padding character is "space" */
+               left_prec = -1;         /* no left precision specified */
+               right_prec = -1;        /* no right precision specified */
+               width = -1;             /* no width specified */
+               value = 0;              /* we have no value to print now */
+
+               /* Flags */
+               while (1) {
+                       switch (*++fmt) {
+                               case '=':       /* fill character */
+                                       pad_char = *++fmt;
+                                       if (pad_char == '\0')
+                                               goto format_error;
+                                       continue;
+                               case '^':       /* not group currency  */
+                                       flags &= ~(NEED_GROUPING);
+                                       continue;
+                               case '+':       /* use locale defined signs */
+                                       if (flags & SIGN_POSN_USED)
+                                               goto format_error;
+                                       flags |= (SIGN_POSN_USED|LOCALE_POSN);
+                                       continue;
+                               case '(':       /* enclose negatives with () */
+                                       if (flags & SIGN_POSN_USED)
+                                               goto format_error;
+                                       flags |= (SIGN_POSN_USED|PARENTH_POSN);
+                                       continue;
+                               case '!':       /* suppress currency symbol */
+                                       flags |= SUPRESS_CURR_SYMBOL;
+                                       continue;
+                               case '-':       /* alignment (left)  */
+                                       flags |= LEFT_JUSTIFY;
+                                       continue;
+                               default:
+                                       break;
+                       }
+                       break;
+               }
+
+               /* field Width */
+               if (isdigit((unsigned char)*fmt)) {
+                       GET_NUMBER(width);
+                       /* Do we have enough space to put number with
+                        * required width ?
+                        */
+                       if ((unsigned int)width >= maxsize - (dst - s))
+                               goto e2big_error;
+               }
+
+               /* Left precision */
+               if (*fmt == '#') {
+                       if (!isdigit((unsigned char)*++fmt))
+                               goto format_error;
+                       GET_NUMBER(left_prec);
+                       if ((unsigned int)left_prec >= maxsize - (dst - s))
+                               goto e2big_error;
+               }
+
+               /* Right precision */
+               if (*fmt == '.') {
+                       if (!isdigit((unsigned char)*++fmt))
+                               goto format_error;
+                       GET_NUMBER(right_prec);
+                       if ((unsigned int)right_prec >= maxsize - (dst - s) -
+                           left_prec)
+                               goto e2big_error;
+               }
+
+               /* Conversion Characters */
+               switch (*fmt++) {
+                       case 'i':       /* use internaltion currency format */
+                               flags |= USE_INTL_CURRENCY;
+                               break;
+                       case 'n':       /* use national currency format */
+                               flags &= ~(USE_INTL_CURRENCY);
+                               break;
+                       default:        /* required character is missing or
+                                          premature EOS */
+                               goto format_error;
+               }
+
+               if (currency_symbol != NULL)
+                       free(currency_symbol);
+               if (flags & USE_INTL_CURRENCY) {
+                       currency_symbol = strdup(lc->int_curr_symbol);
+                       if (currency_symbol != NULL)
+                               space_char = *(currency_symbol+3);
+               } else
+                       currency_symbol = strdup(lc->currency_symbol);
+
+               if (currency_symbol == NULL)
+                       goto end_error;                 /* ENOMEM. */
+
+               /* value itself */
+               value = va_arg(ap, double);
+
+               /* detect sign */
+               if (value < 0) {
+                       flags |= IS_NEGATIVE;
+                       value = -value;
+               }
+
+               /* fill left_prec with amount of padding chars */
+               if (left_prec >= 0) {
+                       pad_size = __calc_left_pad((flags ^ IS_NEGATIVE),
+                                                       currency_symbol) -
+                                  __calc_left_pad(flags, currency_symbol);
+                       if (pad_size < 0)
+                               pad_size = 0;
+               }
+
+               if (asciivalue != NULL)
+                       free(asciivalue);
+               asciivalue = __format_grouped_double(value, &flags,
+                               left_prec, right_prec, pad_char);
+               if (asciivalue == NULL)
+                       goto end_error;         /* errno already set     */
+                                               /* to ENOMEM by malloc() */
+
+               /* set some variables for later use */
+               __setup_vars(flags, &cs_precedes, &sep_by_space,
+                               &sign_posn, &signstr);
+
+               /*
+                * Description of some LC_MONETARY's values:
+                *
+                * p_cs_precedes & n_cs_precedes
+                *
+                * = 1 - $currency_symbol precedes the value
+                *       for a monetary quantity with a non-negative value
+                * = 0 - symbol succeeds the value
+                *
+                * p_sep_by_space & n_sep_by_space
+                 *
+                * = 0 - no space separates $currency_symbol
+                *       from the value for a monetary quantity with a
+                *       non-negative value
+                * = 1 - space separates the symbol from the value
+                * = 2 - space separates the symbol and the sign string,
+                *       if adjacent.
+                 *
+                * p_sign_posn & n_sign_posn
+                 *
+                * = 0 - parentheses enclose the quantity and the
+                *       $currency_symbol
+                * = 1 - the sign string precedes the quantity and the 
+                *       $currency_symbol
+                * = 2 - the sign string succeeds the quantity and the 
+                *       $currency_symbol
+                * = 3 - the sign string precedes the $currency_symbol
+                * = 4 - the sign string succeeds the $currency_symbol
+                 *
+                */
+
+               tmpptr = dst;
+
+               while (pad_size-- > 0)
+                       PRINT(' ');
+
+               if (sign_posn == 0 && (flags & IS_NEGATIVE))
+                       PRINT('(');
+
+               if (cs_precedes == 1) {
+                       if (sign_posn == 1 || sign_posn == 3) {
+                               PRINTS(signstr);
+                               if (sep_by_space == 2)          /* XXX: ? */
+                                       PRINT(' ');
+                       }
+
+                       if (!(flags & SUPRESS_CURR_SYMBOL)) {
+                               PRINTS(currency_symbol);
+
+                               if (sign_posn == 4) {
+                                       if (sep_by_space == 2)
+                                               PRINT(space_char);
+                                       PRINTS(signstr);
+                                       if (sep_by_space == 1)
+                                               PRINT(' ');
+                               } else if (sep_by_space == 1)
+                                       PRINT(space_char);
+                       }
+               } else if (sign_posn == 1)
+                       PRINTS(signstr);
+
+               PRINTS(asciivalue);
+
+               if (cs_precedes == 0) {
+                       if (sign_posn == 3) {
+                               if (sep_by_space == 1)
+                                       PRINT(' ');
+                               PRINTS(signstr);
+                       }
+
+                       if (!(flags & SUPRESS_CURR_SYMBOL)) {
+                               if ((sign_posn == 3 && sep_by_space == 2)
+                                   || (sep_by_space == 1
+                                   && (sign_posn == 0
+                                   || sign_posn == 1
+                                   || sign_posn == 2
+                                   || sign_posn == 4)))
+                                       PRINT(space_char);
+                               PRINTS(currency_symbol); /* XXX: len */
+                               if (sign_posn == 4) {
+                                       if (sep_by_space == 2)
+                                               PRINT(' ');
+                                       PRINTS(signstr);
+                               }
+                       }
+               }
+
+               if (sign_posn == 2) {
+                       if (sep_by_space == 2)
+                               PRINT(' ');
+                       PRINTS(signstr);
+               }
+
+               if (sign_posn == 0 && (flags & IS_NEGATIVE))
+                       PRINT(')');
+
+               if (dst - tmpptr < width) {
+                       if (flags & LEFT_JUSTIFY) {
+                               while (dst - tmpptr < width)
+                                       PRINT(' ');
+                       } else {
+                               pad_size = dst-tmpptr;
+                               memmove(tmpptr + width-pad_size, tmpptr,
+                                   pad_size);
+                               memset(tmpptr, ' ', width-pad_size);
+                               dst += width-pad_size;
+                       }
+               }
+       }
+
+       PRINT('\0');
+       va_end(ap);
+       free(asciivalue);
+       free(currency_symbol);
+       return (dst - s - 1);   /* return size of put data except trailing '\0' */
+
+e2big_error:
+       errno = E2BIG;
+       goto end_error;
+
+format_error:
+       errno = EINVAL;
+
+end_error:
+       sverrno = errno;
+       if (asciivalue != NULL)
+               free(asciivalue);
+       if (currency_symbol != NULL)
+               free(currency_symbol);
+       errno = sverrno;
+       va_end(ap);
+       return (-1);
+}
+
+static void
+__setup_vars(int flags, char *cs_precedes, char *sep_by_space,
+               char *sign_posn, const char **signstr) {
+       struct lconv *lc = localeconv();
+
+       if ((flags & IS_NEGATIVE) && (flags & USE_INTL_CURRENCY)) {
+               *cs_precedes = lc->int_n_cs_precedes;
+               *sep_by_space = lc->int_n_sep_by_space;
+               *sign_posn = (flags & PARENTH_POSN) ? 0 : lc->int_n_sign_posn;
+               *signstr = (lc->negative_sign == '\0') ? "-"
+                   : lc->negative_sign;
+       } else if (flags & USE_INTL_CURRENCY) {
+               *cs_precedes = lc->int_p_cs_precedes;
+               *sep_by_space = lc->int_p_sep_by_space;
+               *sign_posn = (flags & PARENTH_POSN) ? 0 : lc->int_p_sign_posn;
+               *signstr = lc->positive_sign;
+       } else if (flags & IS_NEGATIVE) {
+               *cs_precedes = lc->n_cs_precedes;
+               *sep_by_space = lc->n_sep_by_space;
+               *sign_posn = (flags & PARENTH_POSN) ? 0 : lc->n_sign_posn;
+               *signstr = (lc->negative_sign == '\0') ? "-"
+                   : lc->negative_sign;
+       } else {
+               *cs_precedes = lc->p_cs_precedes;
+               *sep_by_space = lc->p_sep_by_space;
+               *sign_posn = (flags & PARENTH_POSN) ? 0 : lc->p_sign_posn;
+               *signstr = lc->positive_sign;
+       }
+
+       /* Set defult values for unspecified information. */
+       if (*cs_precedes != 0)
+               *cs_precedes = 1;
+       if (*sep_by_space == CHAR_MAX)
+               *sep_by_space = 0;
+       if (*sign_posn == CHAR_MAX)
+               *sign_posn = 0;
+}
+
+static int
+__calc_left_pad(int flags, char *cur_symb) {
+
+       char cs_precedes, sep_by_space, sign_posn;
+       const char *signstr;
+       int left_chars = 0;
+
+       __setup_vars(flags, &cs_precedes, &sep_by_space, &sign_posn, &signstr);
+
+       if (cs_precedes != 0) {
+               left_chars += strlen(cur_symb);
+               if (sep_by_space != 0)
+                       left_chars++;
+       }
+
+       switch (sign_posn) {
+               case 1:
+                       left_chars += strlen(signstr);
+                       break;
+               case 3:
+               case 4:
+                       if (cs_precedes != 0)
+                               left_chars += strlen(signstr);
+       }
+       return (left_chars);
+}
+
+static int
+get_groups(int size, char *grouping) {
+
+       int     chars = 0;
+
+       if (*grouping == CHAR_MAX || *grouping <= 0)    /* no grouping ? */
+               return (0);
+
+       while (size > (int)*grouping) {
+               chars++;
+               size -= (int)*grouping++;
+               /* no more grouping ? */
+               if (*grouping == CHAR_MAX)
+                       break;
+               /* rest grouping with same value ? */
+               if (*grouping == 0) {
+                       chars += (size - 1) / *(grouping - 1);
+                       break;
+               }
+       }
+       return (chars);
+}
+
+/* convert double to ASCII */
+static char *
+__format_grouped_double(double value, int *flags,
+                       int left_prec, int right_prec, int pad_char) {
+
+       char            *rslt;
+       char            *avalue;
+       int             avalue_size;
+       char            fmt[32];
+
+       size_t          bufsize;
+       char            *bufend;
+
+       int             padded;
+
+       struct lconv    *lc = localeconv();
+       char            *grouping;
+       char            decimal_point;
+       char            thousands_sep;
+
+       int groups = 0;
+
+       grouping = lc->mon_grouping;
+       decimal_point = *lc->mon_decimal_point;
+       if (decimal_point == '\0')
+               decimal_point = *lc->decimal_point;
+       thousands_sep = *lc->mon_thousands_sep;
+       if (thousands_sep == '\0')
+               thousands_sep = *lc->thousands_sep;
+
+       /* fill left_prec with default value */
+       if (left_prec == -1)
+               left_prec = 0;
+
+       /* fill right_prec with default value */
+       if (right_prec == -1) {
+                if (*flags & USE_INTL_CURRENCY)
+                        right_prec = lc->int_frac_digits;
+                else
+                        right_prec = lc->frac_digits;
+
+               if (right_prec == CHAR_MAX)     /* POSIX locale ? */
+                       right_prec = 2;
+       }
+
+       if (*flags & NEED_GROUPING)
+               left_prec += get_groups(left_prec, grouping);
+
+       /* convert to string */
+       snprintf(fmt, sizeof(fmt), "%%%d.%df", left_prec + right_prec + 1,
+           right_prec);
+       avalue_size = asprintf(&avalue, fmt, value);
+       if (avalue_size < 0)
+               return (NULL);
+
+       /* make sure that we've enough space for result string */
+       bufsize = strlen(avalue)*2+1;
+       rslt = calloc(1, bufsize);
+       if (rslt == NULL) {
+               free(avalue);
+               return (NULL);
+       }
+       bufend = rslt + bufsize - 1;    /* reserve space for trailing '\0' */
+
+       /* skip spaces at beggining */
+       padded = 0;
+       while (avalue[padded] == ' ') {
+               padded++;
+               avalue_size--;
+       }
+
+       if (right_prec > 0) {
+               bufend -= right_prec;
+               memcpy(bufend, avalue + avalue_size+padded-right_prec,
+                   right_prec);
+               *--bufend = decimal_point;
+               avalue_size -= (right_prec + 1);
+       }
+
+       if ((*flags & NEED_GROUPING) &&
+           thousands_sep != '\0' &&    /* XXX: need investigation */
+           *grouping != CHAR_MAX &&
+           *grouping > 0) {
+               while (avalue_size > (int)*grouping) {
+                       GRPCPY(*grouping);
+                       GRPSEP;
+                       grouping++;
+
+                       /* no more grouping ? */
+                       if (*grouping == CHAR_MAX)
+                               break;
+
+                       /* rest grouping with same value ? */
+                       if (*grouping == 0) {
+                               grouping--;
+                               while (avalue_size > *grouping) {
+                                       GRPCPY(*grouping);
+                                       GRPSEP;
+                               }
+                       }
+               }
+               if (avalue_size != 0)
+                       GRPCPY(avalue_size);
+               padded -= groups;
+
+       } else {
+               bufend -= avalue_size;
+               memcpy(bufend, avalue+padded, avalue_size);
+               if (right_prec == 0)
+                       padded--;       /* decrease assumed $decimal_point */
+       }
+
+       /* do padding with pad_char */
+       if (padded > 0) {
+               bufend -= padded;
+               memset(bufend, pad_char, padded);
+       }
+
+       bufsize = bufsize - (bufend - rslt) + 1;
+       memmove(rslt, bufend, bufsize);
+       free(avalue);
+       return (rslt);
+}
index 19ee1b2..4409412 100644 (file)
@@ -1,6 +1,6 @@
 #      @(#)Makefile.inc        8.3 (Berkeley) 10/24/94
 # $FreeBSD: src/lib/libc/sys/Makefile.inc,v 1.75.2.7 2003/04/22 17:31:18 trhodes Exp $
-# $DragonFly: src/lib/libc/sys/Makefile.inc,v 1.36 2008/09/28 16:33:35 swildner Exp $
+# $DragonFly: src/lib/libc/sys/Makefile.inc,v 1.37 2008/10/06 21:01:37 swildner Exp $
 
 # sys sources
 .PATH: ${.CURDIR}/../libc/${MACHINE_ARCH}/sys ${.CURDIR}/../libc/sys
@@ -126,7 +126,8 @@ MLINKS+=intro.2 errno.2
 MLINKS+=kqueue.2 EV_SET.2 \
        kqueue.2 kevent.2
 MLINKS+=lseek.2 seek.2
-MLINKS+=madvise.2 mcontrol.2
+MLINKS+=madvise.2 mcontrol.2 \
+       madvise.2 posix_madvise.3
 MLINKS+=mlock.2 munlock.2
 MLINKS+=modnext.2 modfnext.2
 MLINKS+=mount.2 unmount.2
index 629ba85..e1070e5 100644 (file)
 .\"
 .\"    @(#)madvise.2   8.1 (Berkeley) 6/9/93
 .\" $FreeBSD: src/lib/libc/sys/madvise.2,v 1.17.2.8 2003/01/06 23:33:59 trhodes Exp $
-.\" $DragonFly: src/lib/libc/sys/madvise.2,v 1.6 2007/07/30 22:11:33 swildner Exp $
+.\" $DragonFly: src/lib/libc/sys/madvise.2,v 1.7 2008/10/06 21:01:37 swildner Exp $
 .\"
-.Dd December 12, 2006
+.Dd October 6, 2008
 .Dt MADVISE 2
 .Os
 .Sh NAME
 .Nm madvise ,
+.Nm posix_madvise ,
 .Nm mcontrol
 .Nd give advice about use of memory
 .Sh LIBRARY
@@ -48,6 +49,8 @@
 .Ft int
 .Fn madvise "void *addr" "size_t len" "int behav"
 .Ft int
+.Fn posix_madvise "void *addr" "size_t len" "int behav"
+.Ft int
 .Fn mcontrol "void *addr" "size_t len" "int behav" "off_t value"
 .Sh DESCRIPTION
 The
@@ -56,6 +59,9 @@ system call
 allows a process that has knowledge of its memory behavior
 to describe it to the system.
 The
+.Fn posix_madvise
+interface is identical and is provided for standards conformance.
+The
 .Fn mcontrol
 system call is an extension of
 .Fn madvise
@@ -147,17 +153,29 @@ the specified area of memory.  The entire memory area under virtual page table
 management should be specified.  You may encounter unexpected effects
 if you only set the page directory page for part of the mapping.
 .El
+.Pp
+Portable programs that call the
+.Fn posix_madvise
+interface should use the aliases
+.Dv POSIX_MADV_NORMAL , POSIX_MADV_SEQUENTIAL ,
+.Dv POSIX_MADV_RANDOM , POSIX_MADV_WILLNEED ,
+and
+.Dv POSIX_MADV_DONTNEED
+rather than the flags described above.
 .Sh RETURN VALUES
-.Rv -std madvise mcontrol
+.Rv -std madvise posix_madvise mcontrol
 .Sh ERRORS
 The
-.Fn madvise
+.Fn madvise ,
+.Fn posix_madvise ,
 and
 .Fn mcontrol
 functions will fail if:
 .Bl -tag -width Er
 .It Bq Er EINVAL
-The virtual address range specified by the
+The
+.Fa behav
+argument is not valid or the virtual address range specified by the
 .Fa addr
 and
 .Fa len
@@ -168,6 +186,11 @@ arguments is not valid.
 .Xr mprotect 2 ,
 .Xr msync 2 ,
 .Xr munmap 2
+.Sh STANDARDS
+The
+.Fn posix_madvise
+interface conforms to
+.St -p1003.1-2001 .
 .Sh HISTORY
 The
 .Fn madvise
index e3f6d80..805d5a2 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)mman.h      8.2 (Berkeley) 1/9/95
  * $FreeBSD: src/sys/sys/mman.h,v 1.29.2.1 2001/08/25 07:25:43 dillon Exp $
- * $DragonFly: src/sys/sys/mman.h,v 1.9 2008/07/23 17:22:33 dillon Exp $
+ * $DragonFly: src/sys/sys/mman.h,v 1.10 2008/10/06 21:01:37 swildner Exp $
  */
 
 #ifndef _SYS_MMAN_H_
 #ifndef _SYS__POSIX_H_
 #include <sys/_posix.h>
 #endif
+#ifndef _SYS_TYPES_H_
+#include <sys/types.h>
+#endif
+#ifndef _SYS_CDEFS_H_
+#include <sys/cdefs.h>
+#endif
 
 /*
  * Inheritance for minherit()
 #define MADV_INVAL     10      /* virt page tables have changed, inval pmap */
 #define MADV_SETMAP    11      /* set page table directory page for map */
 
+/*
+ * Advice to posix_madvise()
+ */
+#if __POSIX_VISIBLE >= 200112
+#define        POSIX_MADV_NORMAL       MADV_NORMAL
+#define        POSIX_MADV_RANDOM       MADV_RANDOM
+#define        POSIX_MADV_SEQUENTIAL   MADV_SEQUENTIAL
+#define        POSIX_MADV_WILLNEED     MADV_WILLNEED
+#define        POSIX_MADV_DONTNEED     MADV_DONTNEED
+#endif
+
 /*
  * mcontrol() must be used for these functions instead of madvise()
  */
 #define        MINCORE_MODIFIED_OTHER  0x10 /* Page has been modified */
 #define        MINCORE_SUPER           0x20 /* Page is a "super" page */
 
-#ifndef _SYS_TYPES_H_
-#include <sys/types.h>
-#endif
-#ifndef _SYS_CDEFS_H_
-#include <sys/cdefs.h>
-#endif
-
 __BEGIN_DECLS
 #ifdef _P1003_1B_VISIBLE
 int    mlockall (int);
@@ -166,6 +176,9 @@ int mprotect (const void *, size_t, int);
 int    msync (void *, size_t, int);
 int    munlock (const void *, size_t);
 int    munmap (void *, size_t);
+#if __POSIX_VISIBLE >= 200112
+int    posix_madvise(void *, size_t, int);
+#endif
 #ifndef _POSIX_SOURCE
 int    madvise (void *, size_t, int);
 int    mcontrol (void *, size_t, int, off_t);