CHANGES-1.4.txt
---------------
+CHANGES IN CUPS V1.4.4
+
+ - The scheduler did not update the classes.conf file when deleting a
+ printer belonging to a class (STR #3505)
+ - The lppasswd command did not use localized password prompts
+ (STR #3492)
+ - The socket backend no longer waits for back-channel data on platforms
+ other than Mac OS X (STR #3495)
+ - The scheduler didn't send events when a printer started accepting or
+ rejecting jobs (STR #3480)
+ - The web interface now includes additional CSRF protection (STR #3498)
+
+
CHANGES IN CUPS V1.4.3
- SECURITY: The scheduler could try responding on a closed client
connection, leading to a crash (STR #3200)
- Localization updates (STR #3352, STR #3409, STR #3422, STR #3452,
- STR #3473)
- - Documentation update (STR #3451)
+ STR #3473, STR #3502)
+ - Documentation updates (STR #3451, STR #3504)
- The IPP backend now sets the printer-state-message to "Ready to
print." at the end of a successful job (STR #3460)
- The PPD compiler did not correctly add the manufacturer to the output
-CHANGES.txt - 2009-11-19
+CHANGES.txt - 2010-02-12
------------------------
CHANGES IN CUPS V1.5b1
+ - The ipptest tool is now a first-class user program and has several
+ improvements along with new documentation (STR #3484)
- The cupstestppd tool now warns about non-unique filenames and
provides a way to ignore all filename warnings.
- Dropped support for the recoverable: and recovered: message prefixes.
permissions disabled.
- The PPD compiler now checks for overlapping filenames when writing
PPD files.
+ - The HP-GL/2 filter is no longer included with CUPS (STR #3322)
+ - The SCSI backend is no longer included with CUPS (STR #3500)
#
# "$Id: Makedefs.in 7900 2008-09-03 13:47:57Z mike $"
#
-# Common makefile definitions for the Common UNIX Printing System (CUPS).
+# Common makefile definitions for CUPS.
#
-# Copyright 2007-2009 by Apple Inc.
+# Copyright 2007-2010 by Apple Inc.
# Copyright 1997-2007 by Easy Software Products, all rights reserved.
#
# These coded instructions, statements, and computer programs are the
LIBCUPSIMAGE = @LIBCUPSIMAGE@
LIBCUPSMIME = @LIBCUPSMIME@
LIBCUPSPPDC = @LIBCUPSPPDC@
+LIBCUPSSTATIC = @LIBCUPSSTATIC@
LIBJPEG = @LIBJPEG@
LIBLDAP = @LIBLDAP@
LIBMALLOC = @LIBMALLOC@
#
# "$Id: Makefile 7961 2008-09-17 19:52:46Z mike $"
#
-# Top-level Makefile for the Common UNIX Printing System (CUPS).
+# Top-level Makefile for CUPS.
#
-# Copyright 2007-2009 by Apple Inc.
+# Copyright 2007-2010 by Apple Inc.
# Copyright 1997-2007 by Easy Software Products, all rights reserved.
#
# These coded instructions, statements, and computer programs are the
# (at least checker-231 is required for scan-build to work this way)
#
-.PHONY: clang
+.PHONY: clang clang-changes
clang:
$(RM) -r clang
scan-build -V -k -o `pwd`/clang $(MAKE) $(MFLAGS) clean all
+clang-changes:
+ scan-build -V -k -o `pwd`/clang $(MAKE) $(MFLAGS) all
#
#
-# Make software distributions using EPM (http://www.easysw.com/epm/)...
+# Make software distributions using EPM (http://www.epmhome.org/)...
#
EPMFLAGS = -v --output-dir dist $(EPMARCH)
parallel.o: ../cups/file.h ../cups/language.h ../cups/debug.h ../cups/i18n.h
parallel.o: ../cups/transcode.h ../cups/snmp-private.h ../cups/string.h
parallel.o: ../config.h
-scsi.o: ../cups/backend.h ../cups/versioning.h ../cups/cups.h ../cups/ipp.h
-scsi.o: ../cups/http.h ../cups/ppd.h ../cups/array.h ../cups/file.h
-scsi.o: ../cups/language.h ../cups/i18n.h ../cups/transcode.h
-scsi.o: ../cups/string.h ../config.h
serial.o: backend-private.h ../cups/backend.h ../cups/versioning.h
serial.o: ../cups/sidechannel.h ../cups/ppd-private.h ../cups/cups.h
serial.o: ../cups/ipp.h ../cups/http.h ../cups/ppd.h ../cups/array.h
test1284.o: ../cups/ppd-private.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
test1284.o: ../cups/ppd.h ../cups/array.h ../cups/file.h ../cups/language.h
test1284.o: ../cups/debug.h ../cups/i18n.h ../cups/transcode.h
-test1284.o: ../cups/snmp-private.h
+test1284.o: ../cups/snmp-private.h ../cups/globals.h ../cups/string.h
+test1284.o: ../cups/http-private.h ../cups/md5.h ../cups/ipp-private.h
+test1284.o: ../cups/i18n.h
testbackend.o: ../cups/string.h ../config.h ../cups/cups.h ../cups/ipp.h
testbackend.o: ../cups/http.h ../cups/versioning.h ../cups/ppd.h
testbackend.o: ../cups/array.h ../cups/file.h ../cups/language.h
#
# "$Id: Makefile 7924 2008-09-10 17:36:13Z mike $"
#
-# Backend makefile for the Common UNIX Printing System (CUPS).
+# Backend makefile for CUPS.
#
-# Copyright 2007-2009 by Apple Inc.
+# Copyright 2007-2010 by Apple Inc.
# Copyright 1997-2007 by Easy Software Products, all rights reserved.
#
# These coded instructions, statements, and computer programs are the
include ../Makedefs
+#
+# Object files...
+#
+
RBACKENDS = ipp lpd $(DNSSD_BACKEND)
UBACKENDS = $(PAP) $(LEGACY_BACKENDS) serial snmp socket usb
UNITTESTS = test1284 testbackend testsupplies
TARGETS = libbackend.a $(RBACKENDS) $(UBACKENDS)
LIBOBJS = ieee1284.o network.o runloop.o snmp-supplies.o
-OBJS = ipp.o lpd.o dnssd.o pap.o parallel.o scsi.o serial.o snmp.o \
+OBJS = ipp.o lpd.o dnssd.o pap.o parallel.o serial.o snmp.o \
socket.o test1284.o testbackend.o testsupplies.o usb.o
# test1284
#
-test1284: test1284.o ../cups/libcups.a
+test1284: test1284.o ../cups/$(LIBCUPSSTATIC)
echo Linking $@...
- $(CC) $(LDFLAGS) -o test1284 test1284.o ../cups/libcups.a \
+ $(CC) $(LDFLAGS) -o test1284 test1284.o ../cups/$(LIBCUPSSTATIC) \
$(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
# testbackend
#
-testbackend: testbackend.o ../cups/libcups.a
+testbackend: testbackend.o ../cups/$(LIBCUPSSTATIC)
echo Linking $@...
- $(CC) $(LDFLAGS) -o testbackend testbackend.o ../cups/libcups.a \
+ $(CC) $(LDFLAGS) -o testbackend testbackend.o ../cups/$(LIBCUPSSTATIC) \
$(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
# testsupplies
#
-testsupplies: testsupplies.o libbackend.a ../cups/libcups.a
+testsupplies: testsupplies.o libbackend.a ../cups/$(LIBCUPSSTATIC)
echo Linking $@...
$(CC) $(LDFLAGS) -o testsupplies testsupplies.o libbackend.a \
- ../cups/libcups.a $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) \
+ ../cups/$(LIBCUPSSTATIC) $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) \
$(COMMONLIBS) $(LIBZ)
$(CC) $(LDFLAGS) -o parallel parallel.o libbackend.a $(LIBS)
-#
-# scsi
-#
-
-scsi: scsi.o ../cups/$(LIBCUPS)
- echo Linking $@...
- $(CC) $(LDFLAGS) -o scsi scsi.o $(LIBS)
-
-scsi.o: scsi.c scsi-irix.c scsi-linux.c
-
-
#
# serial
#
*/
#include "backend-private.h"
+#include <cups/globals.h>
/*
* Get the make, model, and serial numbers...
*/
- num_values = _ppdGet1284Values(device_id, &values);
+ num_values = _cupsGet1284Values(device_id, &values);
if ((sern = cupsGetOption("SERIALNUMBER", num_values, values)) == NULL)
if ((sern = cupsGetOption("SERN", num_values, values)) == NULL)
* Look for the description field...
*/
- num_values = _ppdGet1284Values(device_id, &values);
+ num_values = _cupsGet1284Values(device_id, &values);
if ((mdl = cupsGetOption("MODEL", num_values, values)) == NULL)
mdl = cupsGetOption("MDL", num_values, values);
+++ /dev/null
-/*
- * "$Id: scsi-irix.c 6834 2007-08-22 18:29:25Z mike $"
- *
- * IRIX SCSI printer support for the Common UNIX Printing System (CUPS).
- *
- * Copyright 2007-2009 by Apple Inc.
- * Copyright 2003-2005 by Easy Software Products, 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.
- *
- * 3. All advertising materials mentioning features or use
- * of this software must display the following
- * acknowledgement:
- *
- * This product includes software developed by Easy
- * Software Products.
- *
- * 4. The name of Easy Software Products may not be used to
- * endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * 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.
- *
- * Contents:
- *
- * list_devices() - List the available SCSI printer devices.
- * print_device() - Print a file to a SCSI device.
- */
-
-/*
- * Include necessary headers.
- */
-
-#include <bstring.h> /* memcpy() and friends */
-#include <sys/dsreq.h> /* SCSI interface stuff */
-
-
-/*
- * 'list_devices()' - List the available SCSI printer devices.
- */
-
-void
-list_devices(void)
-{
- printf("direct scsi \"Unknown\" \"%s\"\n",
- _cupsLangString(cupsLangDefault(), _("SCSI Printer")));
-}
-
-
-/*
- * 'print_device()' - Print a file to a SCSI device.
- */
-
-int /* O - Print status */
-print_device(const char *resource, /* I - SCSI device */
- int fd, /* I - File to print */
- int copies) /* I - Number of copies to print */
-{
- int scsi_fd; /* SCSI file descriptor */
- char buffer[8192]; /* Data buffer */
- int bytes; /* Number of bytes */
- int try; /* Current try */
- dsreq_t scsi_req; /* SCSI request */
- char scsi_cmd[6]; /* SCSI command data */
-#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
- struct sigaction action; /* Actions for POSIX signals */
-#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
-
-
- /*
- * Make sure we have a valid resource name...
- */
-
- if (strncmp(resource, "/dev/scsi/", 10) != 0)
- {
- _cupsLangPrintf(stderr, _("ERROR: Bad SCSI device file \"%s\"\n"),
- resource);
- return (CUPS_BACKEND_STOP);
- }
-
- /*
- * Open the SCSI device file...
- */
-
- fputs("STATE: +connecting-to-device\n", stderr);
-
- do
- {
- if ((scsi_fd = open(resource, O_RDWR | O_EXCL)) == -1)
- {
- if (getenv("CLASS") != NULL)
- {
- /*
- * If the CLASS environment variable is set, the job was submitted
- * to a class and not to a specific queue. In this case, we want
- * to abort immediately so that the job can be requeued on the next
- * available printer in the class.
- */
-
- _cupsLangPuts(stderr,
- _("INFO: Unable to contact printer, queuing on next "
- "printer in class...\n"));
-
- /*
- * Sleep 5 seconds to keep the job from requeuing too rapidly...
- */
-
- sleep(5);
-
- return (1);
- }
-
- if (errno != EAGAIN && errno != EBUSY)
- {
- _cupsLangPrintf(stderr,
- _("ERROR: Unable to open device file \"%s\": %s\n"),
- resource, strerror(errno));
- return (CUPS_BACKEND_FAILED);
- }
- else
- {
- _cupsLangPuts(stderr,
- _("INFO: Printer busy; will retry in 30 seconds...\n"));
- sleep(30);
- }
- }
- }
- while (scsi_fd == -1);
-
- fputs("STATE: -connecting-to-device\n", stderr);
-
- /*
- * Now that we are "connected" to the port, ignore SIGTERM so that we
- * can finish out any page data the driver sends (e.g. to eject the
- * current page... Only ignore SIGTERM if we are printing data from
- * stdin (otherwise you can't cancel raw jobs...)
- */
-
- if (fd != 0)
- {
-#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
- sigset(SIGTERM, SIG_IGN);
-#elif defined(HAVE_SIGACTION)
- memset(&action, 0, sizeof(action));
-
- sigemptyset(&action.sa_mask);
- action.sa_handler = SIG_IGN;
- sigaction(SIGTERM, &action, NULL);
-#else
- signal(SIGTERM, SIG_IGN);
-#endif /* HAVE_SIGSET */
- }
-
- /*
- * Copy the print file to the device...
- */
-
- while (copies > 0)
- {
- if (fd != 0)
- lseek(fd, 0, SEEK_SET);
-
- while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
- {
- memset(&scsi_req, 0, sizeof(scsi_req));
-
- scsi_req.ds_flags = DSRQ_WRITE;
- scsi_req.ds_time = 60 * 1000;
- scsi_req.ds_cmdbuf = scsi_cmd;
- scsi_req.ds_cmdlen = 6;
- scsi_req.ds_databuf = buffer;
- scsi_req.ds_datalen = bytes;
-
- scsi_cmd[0] = 0x0a; /* Group 0 print command */
- scsi_cmd[1] = 0x00;
- scsi_cmd[2] = bytes / 65536;
- scsi_cmd[3] = bytes / 256;
- scsi_cmd[4] = bytes;
- scsi_cmd[5] = 0x00;
-
- for (try = 0; try < 10; try ++)
- if (ioctl(scsi_fd, DS_ENTER, &scsi_req) < 0 ||
- scsi_req.ds_status != 0)
- {
- _cupsLangPrintf(stderr,
- _("WARNING: SCSI command timed out (%d); "
- "retrying...\n"), scsi_req.ds_status);
- sleep(try + 1);
- }
- else
- break;
-
- if (try >= 10)
- {
- _cupsLangPrintf(stderr, _("ERROR: Unable to send print data (%d)\n"),
- scsi_req.ds_status);
- close(scsi_fd);
- return (CUPS_BACKEND_FAILED);
- }
- }
-
- copies --;
- }
-
- /*
- * Close the device and return...
- */
-
- close(fd);
-
- return (CUPS_BACKEND_OK);
-}
-
-
-/*
- * End of "$Id: scsi-irix.c 6834 2007-08-22 18:29:25Z mike $".
- */
+++ /dev/null
-/*
- * "$Id: scsi-linux.c 6834 2007-08-22 18:29:25Z mike $"
- *
- * Linux SCSI printer support for the Common UNIX Printing System (CUPS).
- *
- * Copyright 2007-2009 by Apple Inc.
- * Copyright 2003-2005 by Easy Software Products, 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.
- *
- * 3. All advertising materials mentioning features or use
- * of this software must display the following
- * acknowledgement:
- *
- * This product includes software developed by Easy
- * Software Products.
- *
- * 4. The name of Easy Software Products may not be used to
- * endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * 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.
- *
- * Contents:
- *
- * list_devices() - List the available SCSI printer devices.
- * print_device() - Print a file to a SCSI device.
- */
-
-/*
- * Include necessary headers.
- */
-
-#include <scsi/sg.h>
-#include <cups/i18n.h>
-
-
-/*
- * We currently only support the Linux 2.4 generic SCSI interface.
- */
-
-#ifndef SG_DXFER_TO_DEV
-/*
- * Dummy functions that do nothing on unsupported platforms...
- */
-void list_devices(void) {}
-int print_device(const char *resource, int fd, int copies) { return (1); }
-#else
-
-
-/*
- * 'list_devices()' - List the available SCSI printer devices.
- */
-
-void
-list_devices(void)
-{
- printf("direct scsi \"Unknown\" \"%s\"\n",
- _cupsLangString(cupsLangDefault(), _("SCSI Printer")));
-}
-
-
-/*
- * 'print_device()' - Print a file to a SCSI device.
- */
-
-int /* O - Print status */
-print_device(const char *resource, /* I - SCSI device */
- int fd, /* I - File to print */
- int copies) /* I - Number of copies to print */
-{
- int scsi_fd; /* SCSI file descriptor */
- char buffer[8192]; /* Data buffer */
- int bytes; /* Number of bytes */
- int try; /* Current try */
- sg_io_hdr_t scsi_req; /* SCSI request */
- unsigned char scsi_cmd[6], /* SCSI command data */
- scsi_sense[32]; /* SCSI sense data */
-# if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
- struct sigaction action; /* Actions for POSIX signals */
-# endif /* HAVE_SIGACTION && !HAVE_SIGSET */
-
-
- /*
- * Make sure we have a valid resource name...
- */
-
- if (strncmp(resource, "/dev/sg", 7) != 0)
- {
- _cupsLangPrintf(stderr, _("ERROR: Bad SCSI device file \"%s\"\n"),
- resource);
- return (CUPS_BACKEND_STOP);
- }
-
- /*
- * Open the SCSI device file...
- */
-
- fputs("STATE: +connecting-to-device\n", stderr);
-
- do
- {
- if ((scsi_fd = open(resource, O_RDWR | O_EXCL)) == -1)
- {
- if (getenv("CLASS") != NULL)
- {
- /*
- * If the CLASS environment variable is set, the job was submitted
- * to a class and not to a specific queue. In this case, we want
- * to abort immediately so that the job can be requeued on the next
- * available printer in the class.
- */
-
- _cupsLangPuts(stderr,
- _("INFO: Unable to contact printer, queuing on next "
- "printer in class...\n"));
-
- /*
- * Sleep 5 seconds to keep the job from requeuing too rapidly...
- */
-
- sleep(5);
-
- return (CUPS_BACKEND_FAILED);
- }
-
- if (errno != EAGAIN && errno != EBUSY)
- {
- _cupsLangPrintf(stderr,
- _("ERROR: Unable to open device file \"%s\": %s\n"),
- resource, strerror(errno));
- return (CUPS_BACKEND_FAILED);
- }
- else
- {
- _cupsLangPuts(stderr,
- _("INFO: Printer busy; will retry in 30 seconds...\n"));
- sleep(30);
- }
- }
- }
- while (scsi_fd == -1);
-
- fputs("STATE: -connecting-to-device\n", stderr);
-
- /*
- * Now that we are "connected" to the port, ignore SIGTERM so that we
- * can finish out any page data the driver sends (e.g. to eject the
- * current page... Only ignore SIGTERM if we are printing data from
- * stdin (otherwise you can't cancel raw jobs...)
- */
-
- if (fd != 0)
- {
-# ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
- sigset(SIGTERM, SIG_IGN);
-# elif defined(HAVE_SIGACTION)
- memset(&action, 0, sizeof(action));
-
- sigemptyset(&action.sa_mask);
- action.sa_handler = SIG_IGN;
- sigaction(SIGTERM, &action, NULL);
-# else
- signal(SIGTERM, SIG_IGN);
-# endif /* HAVE_SIGSET */
- }
-
- /*
- * Copy the print file to the device...
- */
-
- while (copies > 0)
- {
- if (fd != 0)
- lseek(fd, 0, SEEK_SET);
-
- while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
- {
- memset(&scsi_req, 0, sizeof(scsi_req));
-
- scsi_req.interface_id = 'S';
- scsi_req.dxfer_direction = SG_DXFER_TO_DEV;
- scsi_req.cmd_len = 6;
- scsi_req.mx_sb_len = sizeof(scsi_sense);
- scsi_req.iovec_count = 0;
- scsi_req.dxfer_len = bytes;
- scsi_req.dxferp = buffer;
- scsi_req.cmdp = scsi_cmd;
- scsi_req.sbp = scsi_sense;
- scsi_req.timeout = 60 * 1000;
-
- scsi_cmd[0] = 0x0a; /* Group 0 print command */
- scsi_cmd[1] = 0x00;
- scsi_cmd[2] = bytes / 65536;
- scsi_cmd[3] = bytes / 256;
- scsi_cmd[4] = bytes;
- scsi_cmd[5] = 0x00;
-
- for (try = 0; try < 10; try ++)
- if (ioctl(scsi_fd, SG_IO, &scsi_req) < 0 ||
- scsi_req.status != 0)
- {
- _cupsLangPrintf(stderr,
- _("WARNING: SCSI command timed out (%d); "
- "retrying...\n"), scsi_req.status);
- sleep(try + 1);
- }
- else
- break;
-
- if (try >= 10)
- {
- _cupsLangPrintf(stderr, _("ERROR: Unable to send print data (%d)\n"),
- scsi_req.status);
- close(scsi_fd);
- return (CUPS_BACKEND_FAILED);
- }
- }
-
- copies --;
- }
-
- /*
- * Close the device and return...
- */
-
- close(fd);
-
- return (CUPS_BACKEND_OK);
-}
-#endif /* !SG_DXFER_TO_DEV */
-
-
-/*
- * End of "$Id: scsi-linux.c 6834 2007-08-22 18:29:25Z mike $".
- */
+++ /dev/null
-/*
- * "$Id: scsi.c 7193 2008-01-07 23:01:40Z mike $"
- *
- * SCSI printer backend for the Common UNIX Printing System (CUPS).
- *
- * Copyright 2007 by Apple Inc.
- * Copyright 2003-2006 by Easy Software Products, 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.
- *
- * 3. All advertising materials mentioning features or use
- * of this software must display the following
- * acknowledgement:
- *
- * This product includes software developed by Easy
- * Software Products.
- *
- * 4. The name of Easy Software Products may not be used to
- * endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * 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.
- *
- * Contents:
- *
- * main() - Send a file to the specified SCSI printer.
- */
-
-/*
- * Include necessary headers.
- */
-
-#include <cups/backend.h>
-#include <cups/cups.h>
-#include <cups/i18n.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <cups/string.h>
-#include <cups/i18n.h>
-#include <signal.h>
-
-#ifdef WIN32
-# include <io.h>
-#else
-# include <unistd.h>
-# include <fcntl.h>
-# ifdef HAVE_SYS_IOCTL_H
-# include <sys/ioctl.h>
-# endif /* HAVE_SYS_IOCTL_H */
-#endif /* WIN32 */
-
-
-/*
- * Local functions...
- */
-
-void list_devices(void);
-int print_device(const char *resource, int fd, int copies);
-
-
-#if defined(__linux__) && defined(HAVE_SCSI_SG_H)
-# include "scsi-linux.c"
-#elif defined(__sgi)
-# include "scsi-irix.c"
-#else
-/*
- * Dummy functions that do nothing on unsupported platforms...
- */
-void list_devices(void) {}
-int print_device(const char *resource, int fd, int copies) { return (CUPS_BACKEND_FAILED); }
-#endif /* __linux && HAVE_SCSI_SG_H */
-
-
-/*
- * 'main()' - Send a file to the specified SCSI printer.
- *
- * Usage:
- *
- * printer-uri job-id user title copies options [file]
- */
-
-int /* O - Exit status */
-main(int argc, /* I - Number of command-line arguments (6 or 7) */
- char *argv[]) /* I - Command-line arguments */
-{
- char method[255], /* Method in URI */
- hostname[1024], /* Hostname */
- username[255], /* Username info (not used) */
- resource[1024], /* Resource info (device and options) */
- *options; /* Pointer to options */
- int port; /* Port number (not used) */
- int fp; /* Print file */
- int copies; /* Number of copies to print */
- int status; /* Exit status */
-#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
- struct sigaction action; /* Actions for POSIX signals */
-#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
-
-
- /*
- * Make sure status messages are not buffered...
- */
-
- setbuf(stderr, NULL);
-
- /*
- * Ignore SIGPIPE signals...
- */
-
-#ifdef HAVE_SIGSET
- sigset(SIGPIPE, SIG_IGN);
-#elif defined(HAVE_SIGACTION)
- memset(&action, 0, sizeof(action));
- action.sa_handler = SIG_IGN;
- sigaction(SIGPIPE, &action, NULL);
-#else
- signal(SIGPIPE, SIG_IGN);
-#endif /* HAVE_SIGSET */
-
- /*
- * Check command-line...
- */
-
- if (argc == 1)
- {
- list_devices();
- return (CUPS_BACKEND_OK);
- }
- else if (argc < 6 || argc > 7)
- {
- _cupsLangPrintf(stderr,
- _("Usage: %s job-id user title copies options [file]\n"),
- argv[0]);
- return (CUPS_BACKEND_FAILED);
- }
-
- /*
- * If we have 7 arguments, print the file named on the command-line.
- * Otherwise, send stdin instead...
- */
-
- if (argc == 6)
- {
- fp = 0;
- copies = 1;
- }
- else
- {
- /*
- * Try to open the print file...
- */
-
- if ((fp = open(argv[6], O_RDONLY)) < 0)
- {
- _cupsLangPrintf(stderr,
- _("ERROR: Unable to open print file \"%s\": %s\n"),
- argv[6], strerror(errno));
- return (CUPS_BACKEND_FAILED);
- }
-
- copies = atoi(argv[4]);
- }
-
- /*
- * Extract the device name and options from the URI...
- */
-
- httpSeparateURI(HTTP_URI_CODING_ALL, cupsBackendDeviceURI(argv),
- method, sizeof(method), username, sizeof(username),
- hostname, sizeof(hostname), &port,
- resource, sizeof(resource));
-
- /*
- * See if there are any options...
- */
-
- if ((options = strchr(resource, '?')) != NULL)
- {
- /*
- * Yup, terminate the device name string and move to the first
- * character of the options...
- */
-
- *options++ = '\0';
- }
-
- /*
- * Finally, send the print file...
- */
-
- status = print_device(resource, fp, copies);
-
- /*
- * Close input file and return...
- */
-
- if (fp != 0)
- close(fp);
-
- return (status);
-}
-
-
-/*
- * End of "$Id: scsi.c 7193 2008-01-07 23:01:40Z mike $".
- */
*
* AppSocket backend for the Common UNIX Printing System (CUPS).
*
- * Copyright 2007-2009 by Apple Inc.
+ * Copyright 2007-2010 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
sep; /* Option separator */
int print_fd; /* Print file */
int copies; /* Number of copies to print */
- time_t start_time, /* Time of first connect */
- current_time, /* Current time */
+ time_t start_time; /* Time of first connect */
+#ifdef __APPLE__
+ time_t current_time, /* Current time */
wait_time; /* Time to wait before shutting down socket */
+#endif /* __APPLE__ */
int contimeout; /* Connection timeout */
int waiteof; /* Wait for end-of-file? */
int port; /* Port number */
CUPS_LLCAST tbytes);
}
+#ifdef __APPLE__
/*
* Wait up to 5 seconds to get any pending back-channel data...
*/
while (wait_time >= time(¤t_time))
if (wait_bc(device_fd, wait_time - current_time) <= 0)
break;
+#endif /* __APPLE__ */
if (waiteof)
{
#include <usb.h>
#include <poll.h>
+#include <cups/globals.h>
/*
* Get the make, model, and serial numbers...
*/
- num_values = _ppdGet1284Values(device_id, &values);
+ num_values = _cupsGet1284Values(device_id, &values);
if ((sern = cupsGetOption("SERIALNUMBER", num_values, values)) == NULL)
if ((sern = cupsGetOption("SERN", num_values, values)) == NULL)
var.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h ../cups/file.h
var.o: ../cups/language.h ../cups/array.h help-index.h ../cups/debug.h
var.o: ../cups/i18n.h ../cups/transcode.h ../cups/string.h ../config.h
+var.o: ../cups/http.h ../cups/md5.h
admin.o: cgi-private.h cgi.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
admin.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h ../cups/file.h
admin.o: ../cups/language.h ../cups/array.h help-index.h ../cups/debug.h
#
# "$Id: Makefile 7871 2008-08-27 21:12:43Z mike $"
#
-# CGI makefile for the Common UNIX Printing System (CUPS).
+# CGI makefile for CUPS.
#
-# Copyright 2007-2009 by Apple Inc.
+# Copyright 2007-2010 by Apple Inc.
# Copyright 1997-2006 by Easy Software Products.
#
# These coded instructions, statements, and computer programs are the
done
if test "x$(SYMROOT)" != "x"; then \
$(INSTALL_DIR) $(SYMROOT); \
- for file in $(TARGETS); do \
+ for file in $(CGIS); do \
cp $$file $(SYMROOT); \
done \
fi
# makedocset
#
-makedocset: makedocset.o ../Makedefs libcupscgi.a ../cups/libcups.a
+makedocset: makedocset.o ../Makedefs libcupscgi.a ../cups/$(LIBCUPSSTATIC)
echo Linking $@...
$(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ makedocset.o libcupscgi.a \
- ../cups/libcups.a $(COMMONLIBS) $(SSLLIBS) $(DNSSDLIBS) \
+ ../cups/$(LIBCUPSSTATIC) $(COMMONLIBS) $(SSLLIBS) $(DNSSDLIBS) \
$(LIBZ) $(LIBGSSAPI)
# testcgi
#
-testcgi: testcgi.o ../Makedefs libcupscgi.a ../cups/libcups.a
+testcgi: testcgi.o ../Makedefs libcupscgi.a ../cups/$(LIBCUPSSTATIC)
echo Linking $@...
$(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testcgi.o libcupscgi.a \
- ../cups/libcups.a $(COMMONLIBS) $(SSLLIBS) $(DNSSDLIBS) \
+ ../cups/$(LIBCUPSSTATIC) $(COMMONLIBS) $(SSLLIBS) $(DNSSDLIBS) \
$(LIBZ) $(LIBGSSAPI)
echo Testing CGI API...
./testcgi
# testhi
#
-testhi: testhi.o ../Makedefs libcupscgi.a ../cups/libcups.a
+testhi: testhi.o ../Makedefs libcupscgi.a ../cups/$(LIBCUPSSTATIC)
echo Linking $@...
$(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testhi.o libcupscgi.a \
- ../cups/libcups.a $(COMMONLIBS) $(SSLLIBS) $(DNSSDLIBS) \
+ ../cups/$(LIBCUPSSTATIC) $(COMMONLIBS) $(SSLLIBS) $(DNSSDLIBS) \
$(LIBZ) $(LIBGSSAPI)
echo Testing help index API...
./testhi
# testtemplate
#
-testtemplate: testtemplate.o ../Makedefs libcupscgi.a ../cups/libcups.a
+testtemplate: testtemplate.o ../Makedefs libcupscgi.a ../cups/$(LIBCUPSSTATIC)
echo Linking $@...
- $(CC) $(LDFLAGS) -o $@ testtemplate.o libcupscgi.a ../cups/libcups.a \
+ $(CC) $(LDFLAGS) -o $@ testtemplate.o libcupscgi.a ../cups/$(LIBCUPSSTATIC) \
$(COMMONLIBS) $(SSLLIBS) $(DNSSDLIBS) $(LIBZ) $(LIBGSSAPI)
# websearch
#
-websearch: websearch.o ../Makedefs libcupscgi.a ../cups/libcups.a
+websearch: websearch.o ../Makedefs libcupscgi.a ../cups/$(LIBCUPSSTATIC)
echo Linking $@...
$(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ websearch.o libcupscgi.a \
- ../cups/libcups.a $(COMMONLIBS) $(SSLLIBS) $(DNSSDLIBS) \
+ ../cups/$(LIBCUPSSTATIC) $(COMMONLIBS) $(SSLLIBS) $(DNSSDLIBS) \
$(LIBZ) $(LIBGSSAPI)
*
* Administration CGI for the Common UNIX Printing System (CUPS).
*
- * Copyright 2007-2009 by Apple Inc.
+ * Copyright 2007-2010 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products.
*
* These coded instructions, statements, and computer programs are the
#include <limits.h>
+/*
+ * Local globals...
+ */
+
+static int current_device = 0; /* Current device shown */
+
+
/*
* Local functions...
*/
const char *device_make_and_model,
const char *device_uri,
const char *device_location,
- int *current_device);
+ const char *title);
static void do_add_rss_subscription(http_t *http);
static void do_am_class(http_t *http, int modify);
static void do_am_printer(http_t *http, int modify);
const char *device_make_and_model, /* I - Make and model */
const char *device_uri, /* I - Device URI */
const char *device_location, /* I - Location */
- int *current_device) /* I - Current device index */
+ const char *title) /* I - Page title */
{
+ /*
+ * For modern browsers, start a multi-part page so we can show that something
+ * is happening. Non-modern browsers just get everything at the end...
+ */
+
+ if (current_device == 0 && cgiSupportsMultipart())
+ {
+ cgiStartMultipart();
+ cgiStartHTML(title);
+ cgiCopyTemplateLang("choose-device.tmpl");
+ cgiEndHTML();
+ fflush(stdout);
+ }
+
+
/*
* Add the device to the array...
*/
- cgiSetArray("device_class", *current_device, device_class);
- cgiSetArray("device_id", *current_device, device_id);
- cgiSetArray("device_info", *current_device, device_info);
- cgiSetArray("device_make_and_model", *current_device, device_make_and_model);
- cgiSetArray("device_uri", *current_device, device_uri);
- cgiSetArray("device_location", *current_device, device_location);
+ cgiSetArray("device_class", current_device, device_class);
+ cgiSetArray("device_id", current_device, device_id);
+ cgiSetArray("device_info", current_device, device_info);
+ cgiSetArray("device_make_and_model", current_device, device_make_and_model);
+ cgiSetArray("device_uri", current_device, device_uri);
+ cgiSetArray("device_location", current_device, device_location);
- (*current_device) ++;
+ current_device ++;
}
const char *name, /* Pointer to class name */
*ptr; /* Pointer to CGI variable */
const char *title; /* Title of page */
- int current_device; /* Index of current device */
static int baudrates[] = /* Baud rates */
{
1200,
cgiSetVariable("CURRENT_DEVICE_SCHEME", uri);
}
- /*
- * For modern browsers, start a multi-part page so we can show that something
- * is happening. Non-modern browsers just get everything at the end...
- */
-
- if (cgiSupportsMultipart())
- {
- cgiStartMultipart();
- cgiStartHTML(title);
- cgiCopyTemplateLang("choose-device.tmpl");
- cgiEndHTML();
- fflush(stdout);
- }
-
/*
* Scan for devices for up to 30 seconds...
*/
current_device = 0;
if (cupsGetDevices(http, 30, CUPS_INCLUDE_ALL, CUPS_EXCLUDE_NONE,
(cups_device_cb_t)choose_device_cb,
- ¤t_device) == IPP_OK)
+ (void *)title) == IPP_OK)
{
fputs("DEBUG: Got device list!\n", stderr);
/*
* "$Id: cgi.h 6649 2007-07-11 21:46:42Z mike $"
*
- * CGI support library definitions.
+ * CGI support library definitions for CUPS.
*
- * Copyright 2007-2009 by Apple Inc.
+ * Copyright 2007-2010 by Apple Inc.
* Copyright 1997-2006 by Easy Software Products.
*
* These coded instructions, statements, and computer programs are the
extern int cgiDoSearch(void *search, const char *text);
extern void cgiEndHTML(void);
extern void cgiEndMultipart(void);
-extern char *cgiFormEncode(char *dst, const char *src, size_t dstsize);
+extern char *cgiFormEncode(char *dst, const char *src,
+ size_t dstsize);
extern void cgiFreeSearch(void *search);
extern const char *cgiGetArray(const char *name, int element);
extern void cgiGetAttributes(ipp_t *request, const char *tmpl);
-extern char *cgiGetCookie(const char *name, char *buf, int buflen);
+extern const char *cgiGetCookie(const char *name);
extern const cgi_file_t *cgiGetFile(void);
extern cups_array_t *cgiGetIPPObjects(ipp_t *response, void *search);
extern int cgiGetSize(const char *name);
_cgiFreeSearch
_cgiGetArray
_cgiGetAttributes
+_cgiGetCookie
_cgiGetFile
_cgiGetIPPObjects
_cgiGetSize
_cgiSetArray
_cgiSetIPPObjectVars
_cgiSetIPPVars
+_cgiSetCookie
_cgiSetServerVersion
_cgiSetSize
_cgiSetVariable
*
* CGI template function.
*
- * Copyright 2007-2008 by Apple Inc.
+ * Copyright 2007-2010 by Apple Inc.
* Copyright 1997-2006 by Easy Software Products.
*
* These coded instructions, statements, and computer programs are the
continue;
}
+ else if (name[0] == '$')
+ {
+ /*
+ * Insert cookie value or nothing if not defined.
+ */
+
+ if ((value = cgiGetCookie(name + 1)) != NULL)
+ outptr = value;
+ else
+ {
+ outval[0] = '\0';
+ outptr = outval;
+ }
+ }
else
{
/*
* Test for existance...
*/
- result = cgiGetArray(name, element) != NULL && outptr[0];
+ if (name[0] == '?')
+ result = cgiGetArray(name + 1, element) != NULL;
+ else if (name[0] == '#')
+ result = cgiGetVariable(name + 1) != NULL;
+ else
+ result = cgiGetArray(name, element) != NULL;
+
+ result = result && outptr[0];
compare[0] = '\0';
}
else
/*
* "$Id: var.c 7460 2008-04-16 02:19:54Z mike $"
*
- * CGI form variable and array functions.
+ * CGI form variable and array functions for CUPS.
*
- * Copyright 2007-2009 by Apple Inc.
+ * Copyright 2007-2010 by Apple Inc.
* Copyright 1997-2005 by Easy Software Products.
*
* These coded instructions, statements, and computer programs are the
*
* Contents:
*
- * cgiCheckVariables() - Check for the presence of "required" variables.
+ * cgiCheckVariables() - Check for the presence of "required"
+ * variables.
* cgiClearVariables() - Clear all form variables.
- * cgiGetArray() - Get an element from a form array...
- * cgiGetFile() - Get the file (if any) that was submitted in the form.
+ * cgiGetArray() - Get an element from a form array.
+ * cgiGetCookie() - Get a cookie value.
+ * cgiGetFile() - Get the file (if any) that was submitted in
+ * the form.
* cgiGetSize() - Get the size of a form array value.
- * cgiGetVariable() - Get a CGI variable from the database...
- * cgiInitialize() - Initialize the CGI variable "database"...
+ * cgiGetVariable() - Get a CGI variable from the database.
+ * cgiInitialize() - Initialize the CGI variable "database".
* cgiIsPOST() - Determine whether this page was POSTed.
* cgiSetArray() - Set array element N to the specified string.
+ * cgiSetCookie() - Set a cookie value.
* cgiSetSize() - Set the array size.
- * cgiSetVariable() - Set a CGI variable in the database...
+ * cgiSetVariable() - Set a CGI variable in the database.
* cgi_add_variable() - Add a form variable.
* cgi_compare_variables() - Compare two variables.
- * cgi_find_variable() - Find a variable...
- * cgi_initialize_get() - Initialize form variables using the GET method.
- * cgi_initialize_multipart() - Initialize variables and file using the POST method.
+ * cgi_find_variable() - Find a variable.
+ * cgi_initialize_cookies() - Initialize cookies.
+ * cgi_initialize_get() - Initialize form variables using the GET
+ * method.
+ * cgi_initialize_multipart() - Initialize variables and file using the POST
+ * method.
* cgi_initialize_post() - Initialize variables using the POST method.
* cgi_initialize_string() - Initialize form variables from a string.
- * cgi_passwd() - Catch authentication requests and notify the server.
+ * cgi_passwd() - Catch authentication requests and notify the
+ * server.
+ * cgi_set_sid() - Set the CUPS session ID.
* cgi_sort_variables() - Sort all form variables for faster lookup.
* cgi_unlink_file() - Remove the uploaded form.
*/
/*#define DEBUG*/
#include "cgi-private.h"
#include <errno.h>
+#include <cups/http.h>
+#include <cups/md5.h>
+
+
+/*
+ * Session ID name
+ */
+
+#define CUPS_SID "org.cups.sid"
/*
* Local globals...
*/
+static int num_cookies = 0;/* Number of cookies */
+static cups_option_t *cookies = NULL;/* Cookies */
static int form_count = 0, /* Form variable count */
form_alloc = 0; /* Number of variables allocated */
static _cgi_var_t *form_vars = NULL;
static int cgi_compare_variables(const _cgi_var_t *v1,
const _cgi_var_t *v2);
static _cgi_var_t *cgi_find_variable(const char *name);
+static void cgi_initialize_cookies(void);
static int cgi_initialize_get(void);
static int cgi_initialize_multipart(const char *boundary);
static int cgi_initialize_post(void);
static int cgi_initialize_string(const char *data);
static const char *cgi_passwd(const char *prompt);
+static const char *cgi_set_sid(void);
static void cgi_sort_variables(void);
static void cgi_unlink_file(void);
/*
- * 'cgiGetArray()' - Get an element from a form array...
+ * 'cgiGetArray()' - Get an element from a form array.
*/
const char * /* O - Element value or NULL */
}
+/*
+ * 'cgiGetCookie()' - Get a cookie value.
+ */
+
+const char * /* O - Value or NULL */
+cgiGetCookie(const char *name) /* I - Name of cookie */
+{
+ return (cupsGetOption(name, num_cookies, cookies));
+}
+
+
/*
* 'cgiGetFile()' - Get the file (if any) that was submitted in the form.
*/
/*
- * 'cgiGetVariable()' - Get a CGI variable from the database...
+ * 'cgiGetVariable()' - Get a CGI variable from the database.
*
* Returns NULL if the variable doesn't exist. If the variable is an
- * array of values, returns the last element...
+ * array of values, returns the last element.
*/
const char * /* O - Value of variable */
/*
- * 'cgiInitialize()' - Initialize the CGI variable "database"...
+ * 'cgiInitialize()' - Initialize the CGI variable "database".
*/
int /* O - Non-zero if there was form data */
cgiInitialize(void)
{
- const char *method; /* Form posting method */
- const char *content_type; /* Content-Type of post data */
+ const char *method, /* Form posting method */
+ *content_type, /* Content-Type of post data */
+ *cups_sid_cookie, /* SID cookie */
+ *cups_sid_form; /* SID form variable */
/*
setbuf(stdout, NULL);
#endif /* DEBUG */
+ /*
+ * Get cookies...
+ */
+
+ cgi_initialize_cookies();
+
+ if ((cups_sid_cookie = cgiGetCookie(CUPS_SID)) == NULL)
+ {
+ fputs("DEBUG: " CUPS_SID " cookie not found, initializing!\n", stderr);
+ cups_sid_cookie = cgi_set_sid();
+ }
+
+ fprintf(stderr, "DEBUG: " CUPS_SID " cookie is \"%s\"\n", cups_sid_cookie);
+
/*
* Get the request method (GET or POST)...
*/
boundary += 9;
if (content_type && !strncmp(content_type, "multipart/form-data; ", 21))
- return (cgi_initialize_multipart(boundary));
+ {
+ if (!cgi_initialize_multipart(boundary))
+ return (0);
+ }
+ else if (!cgi_initialize_post())
+ return (0);
+
+ if ((cups_sid_form = cgiGetVariable(CUPS_SID)) == NULL ||
+ strcmp(cups_sid_cookie, cups_sid_form))
+ {
+ if (cups_sid_form)
+ fprintf(stderr, "DEBUG: " CUPS_SID " form variable is \"%s\"\n",
+ cups_sid_form);
+ else
+ fputs("DEBUG: " CUPS_SID " form variable is not present.\n", stderr);
+
+ cgiClearVariables();
+ return (0);
+ }
else
- return (cgi_initialize_post());
+ return (1);
}
else
return (0);
}
+/*
+ * 'cgiSetCookie()' - Set a cookie value.
+ */
+
+void
+cgiSetCookie(const char *name, /* I - Name */
+ const char *value, /* I - Value */
+ const char *path, /* I - Path (typically "/") */
+ const char *domain, /* I - Domain name */
+ time_t expires, /* I - Expiration date (0 for session) */
+ int secure) /* I - Require SSL */
+{
+ num_cookies = cupsAddOption(name, value, num_cookies, &cookies);
+
+ printf("Set-Cookie: %s=%s;", name, value);
+ if (path)
+ printf("; path=%s", path);
+ if (domain)
+ printf("; domain=%s", domain);
+ if (expires)
+ {
+ char date[256]; /* Date string */
+
+ printf("; expires=%s", httpGetDateString2(expires, date, sizeof(date)));
+ }
+ if (secure)
+ puts("; secure;");
+ else
+ puts(";");
+}
+
+
/*
* 'cgiSetSize()' - Set the array size.
*/
/*
- * 'cgiSetVariable()' - Set a CGI variable in the database...
+ * 'cgiSetVariable()' - Set a CGI variable in the database.
*
* If the variable is an array, this truncates the array to a single element.
*/
/*
- * 'cgi_find_variable()' - Find a variable...
+ * 'cgi_find_variable()' - Find a variable.
*/
static _cgi_var_t * /* O - Variable pointer or NULL */
}
+/*
+ * 'cgi_initialize_cookies()' - Initialize cookies.
+ */
+
+static void
+cgi_initialize_cookies(void)
+{
+ const char *cookie; /* HTTP_COOKIE environment variable */
+ char name[128], /* Name string */
+ value[512], /* Value string */
+ *ptr; /* Pointer into name/value */
+
+
+ if ((cookie = getenv("HTTP_COOKIE")) == NULL)
+ return;
+
+ while (*cookie)
+ {
+ /*
+ * Skip leading whitespace...
+ */
+
+ while (isspace(*cookie & 255))
+ cookie ++;
+ if (!*cookie)
+ break;
+
+ /*
+ * Copy the name...
+ */
+
+ for (ptr = name; *cookie && *cookie != '=';)
+ if (ptr < (name + sizeof(name) - 1))
+ *ptr++ = *cookie++;
+ else
+ break;
+
+ if (*cookie != '=')
+ break;
+
+ *ptr = '\0';
+ cookie ++;
+
+ /*
+ * Then the value...
+ */
+
+ if (*cookie == '\"')
+ {
+ for (cookie ++, ptr = value; *cookie && *cookie != '\"';)
+ if (ptr < (value + sizeof(value) - 1))
+ *ptr++ = *cookie++;
+ else
+ break;
+
+ if (*cookie == '\"')
+ cookie ++;
+ }
+ else
+ {
+ for (ptr = value; *cookie && *cookie != ';';)
+ if (ptr < (value + sizeof(value) - 1))
+ *ptr++ = *cookie++;
+ else
+ break;
+ }
+
+ if (*cookie == ';')
+ cookie ++;
+ else if (*cookie)
+ break;
+
+ *ptr = '\0';
+
+ /*
+ * Then add the cookie to an array as long as the name doesn't start with
+ * "$"...
+ */
+
+ if (name[0] != '$')
+ num_cookies = cupsAddOption(name, value, num_cookies, &cookies);
+ }
+}
+
+
/*
* 'cgi_initialize_get()' - Initialize form variables using the GET method.
*/
/*
- * 'cgi_initialize_multipart()' - Initialize variables and file using the POST method.
+ * 'cgi_initialize_multipart()' - Initialize variables and file using the POST
+ * method.
*
* TODO: Update to support files > 2GB.
*/
char *s, /* Pointer to current form string */
ch, /* Temporary character */
name[255], /* Name of form variable */
- value[65536]; /* Variable value... */
+ value[65536]; /* Variable value */
/*
}
+/*
+ * 'cgi_set_sid()' - Set the CUPS session ID.
+ */
+
+static const char * /* O - New session ID */
+cgi_set_sid(void)
+{
+ char buffer[512], /* SID data */
+ sid[33]; /* SID string */
+ _cups_md5_state_t md5; /* MD5 state */
+ unsigned char sum[16]; /* MD5 sum */
+ const char *remote_addr, /* REMOTE_ADDR */
+ *server_name, /* SERVER_NAME */
+ *server_port; /* SERVER_PORT */
+
+
+ if ((remote_addr = getenv("REMOTE_ADDR")) == NULL)
+ remote_addr = "REMOTE_ADDR";
+ if ((server_name = getenv("SERVER_NAME")) == NULL)
+ server_name = "SERVER_NAME";
+ if ((server_port = getenv("SERVER_PORT")) == NULL)
+ server_port = "SERVER_PORT";
+
+ CUPS_SRAND(time(NULL));
+ snprintf(buffer, sizeof(buffer), "%s:%s:%s:%02X%02X%02X%02X%02X%02X%02X%02X",
+ remote_addr, server_name, server_port,
+ (unsigned)CUPS_RAND() & 255, (unsigned)CUPS_RAND() & 255,
+ (unsigned)CUPS_RAND() & 255, (unsigned)CUPS_RAND() & 255,
+ (unsigned)CUPS_RAND() & 255, (unsigned)CUPS_RAND() & 255,
+ (unsigned)CUPS_RAND() & 255, (unsigned)CUPS_RAND() & 255);
+ _cupsMD5Init(&md5);
+ _cupsMD5Append(&md5, (unsigned char *)buffer, (int)strlen(buffer));
+ _cupsMD5Finish(&md5, sum);
+
+ cgiSetCookie(CUPS_SID, httpMD5String(sum, sid), "/", server_name, 0, 0);
+
+ return (cupsGetOption(CUPS_SID, num_cookies, cookies));
+}
+
+
/*
* 'cgi_sort_variables()' - Sort all form variables for faster lookup.
*/
#
# MIME converts file for the Common UNIX Printing System (CUPS).
#
-# Copyright 2007-2009 by Apple Inc.
+# Copyright 2007-2010 by Apple Inc.
# Copyright 1997-2007 by Easy Software Products.
#
# These coded instructions, statements, and computer programs are the
application/pdf application/vnd.cups-postscript 66 pdftops
application/postscript application/vnd.cups-postscript 66 pstops
-application/vnd.hp-HPGL application/postscript 66 hpgltops
application/x-cshell application/postscript 33 texttops
application/x-csource application/postscript 33 texttops
application/x-perl application/postscript 33 texttops
# VERSIONS OF CUPS. Instead, create a "local.types" file that
# reflects your local configuration changes.
#
-# Copyright 2007-2009 by Apple Inc.
+# Copyright 2007-2010 by Apple Inc.
# Copyright 1997-2007 by Easy Software Products.
#
# These coded instructions, statements, and computer programs are the
contains(0,4096,"LANGUAGE = POSTSCRIPT") \
(contains(0,4096,<0a>%!) + \
!contains(0,4096,"ENTER LANGUAGE")))
-application/vnd.hp-HPGL hpgl \
- string(0,<1B>E<1B>%0B) \
- string(0,<1B>%-1B) string(0,<201B>)\
- string(0,BP;) string(0,IN;) string(0,DF;) \
- string(0,BPINPS;) \
- (contains(0,128,<1B>%-12345X) + \
- (contains(0,4096,"LANGUAGE=HPGL") \
- contains(0,4096,"LANGUAGE = HPGL")))
########################################################################
#
dnl Extra platform-specific libraries...
CUPS_DEFAULT_PRINTOPERATOR_AUTH="@SYSTEM"
CUPS_SYSTEM_AUTHKEY=""
-FONTS="fonts"
-LEGACY_BACKENDS="parallel scsi"
+LEGACY_BACKENDS="parallel"
case $uname in
Darwin*)
LEGACY_BACKENDS=""
BACKLIBS="$BACKLIBS -framework IOKit"
- CUPSDLIBS="$CUPSDLIBS -sectorder __TEXT __text cupsd.order -e start -framework IOKit -framework SystemConfiguration -weak_framework ApplicationServices"
- LIBS="-framework SystemConfiguration -framework CoreFoundation $LIBS"
+ CUPSDLIBS="$CUPSDLIBS -sectorder __TEXT __text cupsd.order -e start -framework IOKit -weak_framework ApplicationServices"
+ LIBS="-framework SystemConfiguration -framework CoreFoundation -framework Security $LIBS"
dnl Check for framework headers...
AC_CHECK_HEADER(CoreFoundation/CoreFoundation.h,AC_DEFINE(HAVE_COREFOUNDATION_H))
AC_SUBST(CUPS_DEFAULT_PRINTOPERATOR_AUTH)
AC_DEFINE_UNQUOTED(CUPS_DEFAULT_PRINTOPERATOR_AUTH, "$CUPS_DEFAULT_PRINTOPERATOR_AUTH")
AC_SUBST(CUPS_SYSTEM_AUTHKEY)
-AC_SUBST(FONTS)
AC_SUBST(LEGACY_BACKENDS)
dnl
AC_SUBST(BANNERTOPS)
AC_SUBST(TEXTTOPS)
+dnl Fonts
+if test "x$BANNERTOPS" = x -a "x$TEXTTOPS" = x; then
+ FONTS=""
+else
+ FONTS="fonts"
+fi
+
+AC_SUBST(FONTS)
+
dnl
dnl End of "$Id: cups-defaults.m4 7959 2008-09-17 19:30:58Z mike $".
dnl
dnl
dnl "$Id: cups-launchd.m4 6649 2007-07-11 21:46:42Z mike $"
dnl
-dnl launchd stuff for the Common UNIX Printing System (CUPS).
+dnl launchd stuff for CUPS.
dnl
-dnl Copyright 2007-2009 by Apple Inc.
+dnl Copyright 2007-2010 by Apple Inc.
dnl Copyright 1997-2005 by Easy Software Products, all rights reserved.
dnl
dnl These coded instructions, statements, and computer programs are the
esac
fi
-AC_DEFINE_UNQUOTED(CUPS_DEFAULT_LAUNCHD_CONF, "$DEFAULT_LAUNCHD_CONF")
AC_SUBST(DEFAULT_LAUNCHD_CONF)
AC_SUBST(LAUNCHDLIBS)
dnl
dnl "$Id: cups-sharedlibs.m4 7630 2008-06-09 22:31:44Z mike $"
dnl
-dnl Shared library support for the Common UNIX Printing System (CUPS).
+dnl Shared library support for CUPS.
dnl
-dnl Copyright 2007-2009 by Apple Inc.
+dnl Copyright 2007-2010 by Apple Inc.
dnl Copyright 1997-2005 by Easy Software Products, all rights reserved.
dnl
dnl These coded instructions, statements, and computer programs are the
AC_ARG_ENABLE(shared, [ --disable-shared do not create shared libraries])
+cupsbase="cups"
+LIBCUPSBASE="lib$cupsbase"
+LIBCUPSSTATIC="lib$cupsbase.a"
+
if test x$enable_shared != xno; then
case "$uname" in
SunOS*)
- LIBCUPS="libcups.so.2"
+ LIBCUPS="lib$cupsbase.so.2"
LIBCUPSCGI="libcupscgi.so.1"
LIBCUPSDRIVER="libcupsdriver.so.1"
LIBCUPSIMAGE="libcupsimage.so.2"
DSOFLAGS="$DSOFLAGS -Wl,-h\`basename \$@\` -G \$(OPTIM)"
;;
UNIX_S*)
- LIBCUPS="libcups.so.2"
+ LIBCUPS="lib$cupsbase.so.2"
LIBCUPSCGI="libcupscgi.so.1"
LIBCUPSDRIVER="libcupsdriver.so.1"
LIBCUPSIMAGE="libcupsimage.so.2"
HP-UX*)
case "$uarch" in
ia64)
- LIBCUPS="libcups.so.2"
+ LIBCUPS="lib$cupsbase.so.2"
LIBCUPSCGI="libcupscgi.so.1"
LIBCUPSDRIVER="libcupsdriver.so.1"
LIBCUPSIMAGE="libcupsimage.so.2"
DSOFLAGS="$DSOFLAGS -Wl,-b,-z,+h,\`basename \$@\`"
;;
*)
- LIBCUPS="libcups.sl.2"
+ LIBCUPS="lib$cupsbase.sl.2"
LIBCUPSCGI="libcupscgi.sl.1"
LIBCUPSDRIVER="libcupsdriver.sl.1"
LIBCUPSIMAGE="libcupsimage.sl.2"
esac
;;
IRIX)
- LIBCUPS="libcups.so.2"
+ LIBCUPS="lib$cupsbase.so.2"
LIBCUPSCGI="libcupscgi.so.1"
LIBCUPSDRIVER="libcupsdriver.so.1"
LIBCUPSIMAGE="libcupsimage.so.2"
DSOFLAGS="$DSOFLAGS -set_version,sgi2.6,-soname,\`basename \$@\` -shared \$(OPTIM)"
;;
OSF1* | Linux | GNU | *BSD*)
- LIBCUPS="libcups.so.2"
+ LIBCUPS="lib$cupsbase.so.2"
LIBCUPSCGI="libcupscgi.so.1"
LIBCUPSDRIVER="libcupsdriver.so.1"
LIBCUPSIMAGE="libcupsimage.so.2"
DSOFLAGS="$DSOFLAGS -Wl,-soname,\`basename \$@\` -shared \$(OPTIM)"
;;
Darwin*)
- LIBCUPS="libcups.2.dylib"
+ LIBCUPS="lib$cupsbase.2.dylib"
LIBCUPSCGI="libcupscgi.1.dylib"
LIBCUPSDRIVER="libcupsdriver.1.dylib"
LIBCUPSIMAGE="libcupsimage.2.dylib"
DSOFLAGS="$DSOFLAGS -dynamiclib -single_module -lc"
;;
AIX*)
- LIBCUPS="libcups_s.a"
+ LIBCUPS="lib${cupsbase}_s.a"
+ LIBCUPSBASE="${cupsbase}_s"
LIBCUPSCGI="libcupscgi_s.a"
LIBCUPSDRIVER="libcupsdriver_s.a"
LIBCUPSIMAGE="libcupsimage_s.a"
*)
echo "Warning: shared libraries may not be supported. Trying -shared"
echo " option with compiler."
- LIBCUPS="libcups.so.2"
+ LIBCUPS="lib$cupsbase.so.2"
LIBCUPSCGI="libcupscgi.so.1"
LIBCUPSDRIVER="libcupsdriver.so.1"
LIBCUPSIMAGE="libcupsimage.so.2"
esac
else
PICFLAG=0
- LIBCUPS="libcups.a"
+ LIBCUPS="lib$cupsbase.a"
LIBCUPSCGI="libcupscgi.a"
LIBCUPSDRIVER="libcupsdriver.a"
LIBCUPSIMAGE="libcupsimage.a"
AC_SUBST(DSO32FLAGS)
AC_SUBST(DSO64FLAGS)
AC_SUBST(LIBCUPS)
+AC_SUBST(LIBCUPSBASE)
AC_SUBST(LIBCUPSCGI)
AC_SUBST(LIBCUPSDRIVER)
AC_SUBST(LIBCUPSIMAGE)
AC_SUBST(LIBCUPSMIME)
AC_SUBST(LIBCUPSPPDC)
+AC_SUBST(LIBCUPSSTATIC)
if test x$enable_shared = xno; then
- LINKCUPS="../cups/libcups.a"
+ LINKCUPS="../cups/lib$cupsbase.a"
LINKCUPSIMAGE="../filter/libcupsimage.a"
else
if test $uname = AIX; then
- LINKCUPS="-lcups_s"
+ LINKCUPS="-l${cupsbase}_s"
LINKCUPSIMAGE="-lcupsimage_s"
else
- LINKCUPS="-lcups"
+ LINKCUPS="-l${cupsbase}"
LINKCUPSIMAGE="-lcupsimage"
fi
fi
dnl
dnl "$Id: cups-ssl.m4 7241 2008-01-22 22:34:52Z mike $"
dnl
-dnl OpenSSL/GNUTLS stuff for the Common UNIX Printing System (CUPS).
+dnl OpenSSL/GNUTLS stuff for CUPS.
dnl
-dnl Copyright 2007-2009 by Apple Inc.
+dnl Copyright 2007-2010 by Apple Inc.
dnl Copyright 1997-2007 by Easy Software Products, all rights reserved.
dnl
dnl These coded instructions, statements, and computer programs are the
SSLFLAGS=""
SSLLIBS=""
+have_ssl=0
if test x$enable_ssl != xno; then
dnl Look for CDSA...
- if test "x${SSLLIBS}" = "x" -a "x${enable_cdsassl}" != "xno"; then
+ if test $have_ssl = 0 -a "x${enable_cdsassl}" != "xno"; then
if test $uname = Darwin; then
AC_CHECK_HEADER(Security/SecureTransport.h, [
- SSLLIBS="-framework CoreFoundation -framework Security"
+ have_ssl=1
AC_DEFINE(HAVE_SSL)
AC_DEFINE(HAVE_CDSASSL)
fi
dnl Then look for GNU TLS...
- if test "x${SSLLIBS}" = "x" -a "x${enable_gnutls}" != "xno" -a "x$PKGCONFIG" != x; then
+ if test $have_ssl = 0 -a "x${enable_gnutls}" != "xno" -a "x$PKGCONFIG" != x; then
AC_PATH_PROG(LIBGNUTLSCONFIG,libgnutls-config)
if $PKGCONFIG --exists gnutls; then
+ have_ssl=1
SSLLIBS=`$PKGCONFIG --libs gnutls`
SSLFLAGS=`$PKGCONFIG --cflags gnutls`
AC_DEFINE(HAVE_SSL)
fi
dnl Check for the OpenSSL library last...
- if test "x${SSLLIBS}" = "x" -a "x${enable_openssl}" != "xno"; then
+ if test $have_ssl = 0 -a "x${enable_openssl}" != "xno"; then
AC_CHECK_HEADER(openssl/ssl.h,
dnl Save the current libraries so the crypto stuff isn't always
dnl included...
"-lcrypto -lRSAglue -lrsaref"
do
AC_CHECK_LIB(ssl,SSL_new,
- [SSLFLAGS="-DOPENSSL_DISABLE_OLD_DES_SUPPORT"
+ [have_ssl=1
+ SSLFLAGS="-DOPENSSL_DISABLE_OLD_DES_SUPPORT"
SSLLIBS="-lssl $libcrypto"
AC_DEFINE(HAVE_SSL)
AC_DEFINE(HAVE_LIBSSL)],,
fi
fi
-if test "x$SSLLIBS" != x; then
+if test $have_ssl = 1; then
AC_MSG_RESULT([ Using SSLLIBS="$SSLLIBS"])
AC_MSG_RESULT([ Using SSLFLAGS="$SSLFLAGS"])
fi
dnl
dnl "$Id: configure.in 7833 2008-08-04 20:55:13Z mike $"
dnl
-dnl Configuration script for the Common UNIX Printing System (CUPS).
+dnl Configuration script for CUPS.
dnl
-dnl Copyright 2007 by Apple Inc.
+dnl Copyright 2007-2010 by Apple Inc.
dnl Copyright 1997-2007 by Easy Software Products, all rights reserved.
dnl
dnl These coded instructions, statements, and computer programs are the
#
# "$Id: Makefile 7871 2008-08-27 21:12:43Z mike $"
#
-# API library Makefile for the Common UNIX Printing System (CUPS).
+# API library Makefile for CUPS.
#
-# Copyright 2007-2009 by Apple Inc.
+# Copyright 2007-2010 by Apple Inc.
# Copyright 1997-2006 by Easy Software Products, all rights reserved.
#
# These coded instructions, statements, and computer programs are the
#
LIBTARGETS = \
+ $(LIBCUPSSTATIC) \
$(LIBCUPS) \
$(LIB32CUPS) \
- $(LIB64CUPS) \
- libcups.a
+ $(LIB64CUPS)
UNITTARGETS = \
testadmin \
# Make all targets...
#
-all: $(TARGETS)
+all: $(TARGETS)
#
installstatic:
$(INSTALL_DIR) -m 755 $(LIBDIR)
- $(INSTALL_LIB) -m 755 libcups.a $(LIBDIR)
- $(RANLIB) $(LIBDIR)/libcups.a
- $(CHMOD) 555 $(LIBDIR)/libcups.a
+ $(INSTALL_LIB) -m 755 $(LIBCUPSSTATIC) $(LIBDIR)
+ $(RANLIB) $(LIBDIR)/$(LIBCUPSSTATIC)
+ $(CHMOD) 555 $(LIBDIR)/$(LIBCUPSSTATIC)
install32bit:
echo Installing libraries in $(LIB32DIR)...
# libcups.2.dylib
#
-libcups.2.dylib: $(LIBOBJS) $(LIBCUPSORDER) libcups.exp
+libcups.2.dylib: $(LIBOBJS) $(LIBCUPSORDER)
+ echo Creating export list for $@...
+ nm $(LIBOBJS) 2>/dev/null | grep "T _" | awk '{print $$3}' | \
+ grep -v -e '^(_cupsConnect|_cupsSetDefaults|_cupsSetHTTPError|_cupsUserDefault|_httpWait)$$' | \
+ sort >t.exp
echo Linking $@...
$(DSO) $(ARCHFLAGS) $(DSOFLAGS) -o $@ \
-install_name $(libdir)/$@ \
-current_version 2.8.0 \
-compatibility_version 2.0.0 \
- -exported_symbols_list libcups.exp \
+ -exported_symbols_list t.exp \
-sectorder __TEXT __text $(LIBCUPSORDER) \
$(LIBOBJS) $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) \
$(COMMONLIBS) $(LIBZ)
- $(RM) libcups.dylib
+ $(RM) libcups.dylib t.exp
$(LN) $@ libcups.dylib
$(RANLIB) $@
-#
-# CUPS language bindings for various scripting languages...
-#
-# NOTE: Not currently used or functional - see the scripting/php directory
-# for the hand-written bindings...
-#
-
-phpcups.so: $(LIBCUPS) php_cups_wrap.o
- echo Linking $@...
- if test `uname` = Darwin; then \
- DSOFLAGS="-bundle -flat_namespace -undefined suppress"; \
- else \
- DSOFLAGS="$(DSOFLAGS)"; \
- fi; \
- $(DSO) $$DSOFLAGS -o $@ php_cups_wrap.o $(LIBS) `php-config --ldflags --libs`
-
-php_cups_wrap.o: php_cups_wrap.c
- echo Compiling $<...
- $(CC) $(CFLAGS) `php-config --includes` -c $<
-php_cups_wrap.c: cups.h
- echo Creating $< using SWIG...
- swig -php -o $@ -module cups cups.h
-
-
#
# testadmin (dependency on static CUPS library is intentional)
#
-testadmin: testadmin.o libcups.a
+testadmin: testadmin.o $(LIBCUPSSTATIC)
echo Linking $@...
- $(CC) $(LDFLAGS) -o $@ testadmin.o libcups.a \
+ $(CC) $(LDFLAGS) -o $@ testadmin.o $(LIBCUPSSTATIC) \
$(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
# testarray (dependency on static CUPS library is intentional)
#
-testarray: testarray.o libcups.a
+testarray: testarray.o $(LIBCUPSSTATIC)
echo Linking $@...
- $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testarray.o libcups.a \
+ $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testarray.o $(LIBCUPSSTATIC) \
$(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
echo Running array API tests...
./testarray
# testconflicts (dependency on static CUPS library is intentional)
#
-testconflicts: testconflicts.o libcups.a
+testconflicts: testconflicts.o $(LIBCUPSSTATIC)
echo Linking $@...
- $(CC) $(LDFLAGS) -o $@ testconflicts.o libcups.a \
+ $(CC) $(LDFLAGS) -o $@ testconflicts.o $(LIBCUPSSTATIC) \
$(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
# testcups (dependency on static CUPS library is intentional)
#
-testcups: testcups.o libcups.a
+testcups: testcups.o $(LIBCUPSSTATIC)
echo Linking $@...
- $(CC) $(LDFLAGS) -o $@ testcups.o libcups.a \
+ $(CC) $(LDFLAGS) -o $@ testcups.o $(LIBCUPSSTATIC) \
$(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
# testfile (dependency on static CUPS library is intentional)
#
-testfile: testfile.o libcups.a
+testfile: testfile.o $(LIBCUPSSTATIC)
echo Linking $@...
- $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testfile.o libcups.a \
+ $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testfile.o $(LIBCUPSSTATIC) \
$(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
echo Running file API tests...
./testfile
# testhttp (dependency on static CUPS library is intentional)
#
-testhttp: testhttp.o libcups.a
+testhttp: testhttp.o $(LIBCUPSSTATIC)
echo Linking $@...
- $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testhttp.o libcups.a \
+ $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testhttp.o $(LIBCUPSSTATIC) \
$(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
echo Running HTTP API tests...
./testhttp
# testipp (dependency on static CUPS library is intentional)
#
-testipp: testipp.o libcups.a
+testipp: testipp.o $(LIBCUPSSTATIC)
echo Linking $@...
- $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testipp.o libcups.a \
+ $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testipp.o $(LIBCUPSSTATIC) \
$(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
echo Running IPP API tests...
./testipp
# testi18n (dependency on static CUPS library is intentional)
#
-testi18n: testi18n.o libcups.a
+testi18n: testi18n.o $(LIBCUPSSTATIC)
echo Linking $@...
- $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testi18n.o libcups.a \
+ $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testi18n.o $(LIBCUPSSTATIC) \
$(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
echo Running internationalization API tests...
./testi18n
# testlang (dependency on static CUPS library is intentional)
#
-testlang: testlang.o libcups.a
+testlang: testlang.o $(LIBCUPSSTATIC)
echo Linking $@...
- $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testlang.o libcups.a \
+ $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testlang.o $(LIBCUPSSTATIC) \
$(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
echo Running language API tests...
./testlang
# testoptions (dependency on static CUPS library is intentional)
#
-testoptions: testoptions.o libcups.a
+testoptions: testoptions.o $(LIBCUPSSTATIC)
echo Linking $@...
- $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testoptions.o libcups.a \
+ $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testoptions.o $(LIBCUPSSTATIC) \
$(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
echo Running option API tests...
./testoptions
# testppd (dependency on static CUPS library is intentional)
#
-testppd: testppd.o libcups.a test.ppd test2.ppd
+testppd: testppd.o $(LIBCUPSSTATIC) test.ppd test2.ppd
echo Linking $@...
- $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testppd.o libcups.a \
+ $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testppd.o $(LIBCUPSSTATIC) \
$(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
echo Running PPD API tests...
./testppd
# testsnmp (dependency on static CUPS library is intentional)
#
-testsnmp: testsnmp.o libcups.a
+testsnmp: testsnmp.o $(LIBCUPSSTATIC)
echo Linking $@...
- $(CC) $(LDFLAGS) -o $@ testsnmp.o libcups.a \
+ $(CC) $(LDFLAGS) -o $@ testsnmp.o $(LIBCUPSSTATIC) \
$(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
/*
* "$Id: attr.c 7584 2008-05-16 22:55:53Z mike $"
*
- * PPD model-specific attribute routines for the Common UNIX Printing System
- * (CUPS).
+ * PPD model-specific attribute routines for CUPS.
*
- * Copyright 2007-2009 by Apple Inc.
+ * Copyright 2007-2010 by Apple Inc.
* Copyright 1997-2006 by Easy Software Products.
*
* These coded instructions, statements, and computer programs are the
*
* Contents:
*
- * ppdFindAttr() - Find the first matching attribute.
- * ppdFindNextAttr() - Find the next matching attribute.
+ * ppdFindAttr() - Find the first matching attribute.
+ * ppdFindNextAttr() - Find the next matching attribute.
+ * _ppdNormalizeMakeAndModel() - Normalize a product/make-and-model string.
*/
/*
}
-/*
- * '_ppdGet1284Values()' - Get 1284 device ID keys and values.
- *
- * The returned dictionary is a CUPS option array that can be queried with
- * cupsGetOption and freed with cupsFreeOptions.
- */
-
-int /* O - Number of key/value pairs */
-_ppdGet1284Values(
- const char *device_id, /* I - IEEE-1284 device ID string */
- cups_option_t **values) /* O - Array of key/value pairs */
-{
- int num_values; /* Number of values */
- char key[256], /* Key string */
- value[256], /* Value string */
- *ptr; /* Pointer into key/value */
-
-
- /*
- * Range check input...
- */
-
- if (values)
- *values = NULL;
-
- if (!device_id || !values)
- return (0);
-
- /*
- * Parse the 1284 device ID value into keys and values. The format is
- * repeating sequences of:
- *
- * [whitespace]key:value[whitespace];
- */
-
- num_values = 0;
- while (*device_id)
- {
- while (isspace(*device_id & 255))
- device_id ++;
-
- if (!*device_id)
- break;
-
- for (ptr = key; *device_id && *device_id != ':'; device_id ++)
- if (ptr < (key + sizeof(key) - 1))
- *ptr++ = *device_id;
-
- if (!*device_id)
- break;
-
- while (ptr > key && isspace(ptr[-1] & 255))
- ptr --;
-
- *ptr = '\0';
- device_id ++;
-
- while (isspace(*device_id & 255))
- device_id ++;
-
- if (!*device_id)
- break;
-
- for (ptr = value; *device_id && *device_id != ';'; device_id ++)
- if (ptr < (value + sizeof(value) - 1))
- *ptr++ = *device_id;
-
- if (!*device_id)
- break;
-
- while (ptr > value && isspace(ptr[-1] & 255))
- ptr --;
-
- *ptr = '\0';
- device_id ++;
-
- num_values = cupsAddOption(key, value, num_values, values);
- }
-
- return (num_values);
-}
-
-
/*
* '_ppdNormalizeMakeAndModel()' - Normalize a product/make-and-model string.
*
* 'debug_vsnprintf()' - Format a string into a fixed size buffer.
*/
-int /* O - Number of bytes formatted */
+static int /* O - Number of bytes formatted */
debug_vsnprintf(char *buffer, /* O - Output buffer */
size_t bufsize, /* O - Size of output buffer */
const char *format, /* I - printf-style format string */
static void
cups_env_init(_cups_globals_t *g) /* I - Global data */
{
+#ifdef WIN32
+ HKEY key; /* Registry key */
+ DWORD size; /* Size of string */
+ static char installdir[1024], /* Install directory */
+ confdir[1024], /* Server root directory */
+ localedir[1024]; /* Locale directory */
+
+
+ /*
+ * Open the registry...
+ */
+
+ strcpy(installdir, "C:/Program Files/cups.org");
+
+ if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\cups.org", 0, KEY_READ,
+ &key))
+ {
+ /*
+ * Grab the installation directory...
+ */
+
+ size = sizeof(installdir);
+ RegQueryValueEx(key, "installdir", NULL, NULL, installdir, &size);
+ RegCloseKey(key);
+ }
+
+ snprintf(confdir, sizeof(confdir), "%s/conf", installdir);
+ snprintf(localedir, sizeof(localedir), "%s/locale", installdir);
+
+ if ((g->cups_datadir = getenv("CUPS_DATADIR")) == NULL)
+ g->cups_datadir = installdir;
+
+ if ((g->cups_serverbin = getenv("CUPS_SERVERBIN")) == NULL)
+ g->cups_serverbin = installdir;
+
+ if ((g->cups_serverroot = getenv("CUPS_SERVERROOT")) == NULL)
+ g->cups_serverroot = confdir;
+
+ if ((g->cups_statedir = getenv("CUPS_STATEDIR")) == NULL)
+ g->cups_statedir = confdir;
+
+ if ((g->localedir = getenv("LOCALEDIR")) == NULL)
+ g->localedir = localedir;
+
+#else
if ((g->cups_datadir = getenv("CUPS_DATADIR")) == NULL)
g->cups_datadir = CUPS_DATADIR;
if ((g->localedir = getenv("LOCALEDIR")) == NULL)
g->localedir = CUPS_LOCALEDIR;
+#endif /* WIN32 */
}
*/
extern http_t *_cupsConnect(void);
+extern int _cupsGet1284Values(const char *device_id,
+ cups_option_t **values);
extern const char *_cupsGetPassword(const char *prompt);
extern _cups_globals_t *_cupsGlobals(void);
extern void _cupsSetDefaults(void);
void
httpFlush(http_t *http) /* I - Connection to server */
{
- char buffer[8192]; /* Junk buffer */
- int blocking; /* To block or not to block */
+ char buffer[8192]; /* Junk buffer */
+ int blocking; /* To block or not to block */
+ http_state_t oldstate; /* Old state */
DEBUG_printf(("httpFlush(http=%p), state=%s", http,
* Read any data we can...
*/
+ oldstate = http->state;
while (httpRead2(http, buffer, sizeof(buffer)) > 0);
/*
http->blocking = blocking;
- if (http->state != HTTP_WAITING && http->fd >= 0)
+ if (http->state == oldstate && http->fd >= 0)
{
/*
* Didn't get the data back, so close the current connection.
DEBUG_printf(("httpFlushWrite(http=%p)", http));
if (!http || !http->wused)
+ {
+ DEBUG_puts(http ? "1httpFlushWrite: Write buffer is empty." :
+ "1httpFlushWrite: No connection.");
return (0);
+ }
if (http->data_encoding == HTTP_ENCODE_CHUNKED)
bytes = http_write_chunk(http, http->wbuffer, http->wused);
http->wused = 0;
+ DEBUG_printf(("1httpFlushWrite: Returning %d.", bytes));
+
return (bytes);
}
DEBUG_printf(("4_httpWait(http=%p, msec=%d, usessl=%d)", http, msec, usessl));
if (http->fd < 0)
+ {
+ DEBUG_printf(("5_httpWait: Returning 0 since fd=%d", http->fd));
return (0);
+ }
/*
* Check the SSL/TLS buffers for data first...
{
# ifdef HAVE_LIBSSL
if (SSL_pending((SSL *)(http->tls)))
+ {
+ DEBUG_puts("5_httpWait: Return 1 since there is pending SSL data.");
return (1);
+ }
+
# elif defined(HAVE_GNUTLS)
if (gnutls_record_check_pending(((http_tls_t *)(http->tls))->session))
+ {
+ DEBUG_puts("5_httpWait: Return 1 since there is pending SSL data.");
return (1);
+ }
+
# elif defined(HAVE_CDSASSL)
size_t bytes; /* Bytes that are available */
if (!SSLGetBufferedReadSize(((http_tls_t *)(http->tls))->session, &bytes) &&
bytes > 0)
+ {
+ DEBUG_puts("5_httpWait: Return 1 since there is pending SSL data.");
return (1);
+ }
# endif /* HAVE_LIBSSL */
}
#endif /* HAVE_SSL */
# endif /* WIN32 */
#endif /* HAVE_POLL */
- DEBUG_printf(("5_httpWait: returning with nfds=%d...", nfds));
+ DEBUG_printf(("5_httpWait: returning with nfds=%d, errno=%d...", nfds,
+ errno));
return (nfds > 0);
}
bytes; /* Bytes sent */
+ DEBUG_printf(("2http_write(http=%p, buffer=%p, length=%d)", http, buffer,
+ length));
http->error = 0;
tbytes = 0;
}
#endif /* WIN32 */
- DEBUG_puts("8http_write: error writing data...");
+ DEBUG_printf(("3http_write: error writing data (%s).",
+ strerror(http->error)));
return (-1);
}
http_debug_hex("http_write", buffer - tbytes, tbytes);
#endif /* DEBUG */
+ DEBUG_printf(("3http_write: Returning %d.", tbytes));
+
return (tbytes);
}
const char *buf, /* I - Buffer holding data */
int len) /* I - Length of buffer */
{
+ ssize_t result; /* Return value */
+
+
+ DEBUG_printf(("2http_write_ssl(http=%p, buf=%p, len=%d)", http, buf, len));
+
# if defined(HAVE_LIBSSL)
- return (SSL_write((SSL *)(http->tls), buf, len));
+ result = SSL_write((SSL *)(http->tls), buf, len);
# elif defined(HAVE_GNUTLS)
- ssize_t result; /* Return value */
-
result = gnutls_record_send(((http_tls_t *)(http->tls))->session, buf, len);
if (result < 0 && !errno)
result = -1;
}
- return ((int)result);
-
# elif defined(HAVE_CDSASSL)
- int result; /* Return value */
OSStatus error; /* Error info */
size_t processed; /* Number of bytes processed */
result = -1;
break;
}
-
- return (result);
# endif /* HAVE_LIBSSL */
+
+ DEBUG_printf(("3http_write_ssl: Returning %d.", (int)result));
+
+ return ((int)result);
}
#endif /* HAVE_SSL */
* Prototypes...
*/
-#ifdef __APPLE__
+# ifdef __APPLE__
extern const char *_cupsAppleLanguage(const char *locale, char *language,
size_t langsize);
-#endif /* __APPLE__ */
+# endif /* __APPLE__ */
extern void _cupsCharmapFlush(void);
extern void _cupsCharmapFree(const cups_encoding_t encoding);
extern void *_cupsCharmapGet(const cups_encoding_t encoding);
extern const char *_cupsEncodingName(cups_encoding_t encoding);
extern void _cupsLangPrintError(const char *message);
extern int _cupsLangPrintf(FILE *fp, const char *message, ...)
-# ifdef __GNUC__
+# ifdef __GNUC__
__attribute__ ((__format__ (__printf__, 2, 3)))
-# endif /* __GNUC__ */
+# endif /* __GNUC__ */
;
extern int _cupsLangPuts(FILE *fp, const char *message);
extern const char *_cupsLangString(cups_lang_t *lang, const char *message);
"dateTime", /* 0x31 */
"resolution", /* 0x32 */
"rangeOfInteger", /* 0x33 */
- "begCollection", /* 0x34 */
+ "collection", /* 0x34 */
"textWithLanguage", /* 0x35 */
"nameWithLanguage", /* 0x36 */
"endCollection", /* 0x37 */
value = "en";
/*
- * Convert language values to lowercase and change _ to - as needed...
+ * Convert language and charset values to lowercase and change _ to - as
+ * needed...
*/
if ((type == IPP_TAG_LANGUAGE || type == IPP_TAG_CHARSET) && value)
int i; /* Looping var */
ipp_attribute_t *attr; /* New attribute */
ipp_value_t *value; /* Current value */
+ char buffer[1024], /* Language/charset value buffer */
+ *bufptr; /* Pointer into buffer */
DEBUG_printf(("ippAddStrings(ipp=%p, group=%02x(%s), type=%02x(%s), "
if (values != NULL)
{
- /*
- * Force language to be English for the POSIX locale...
- */
+ if ((int)type & IPP_TAG_COPY)
+ value->string.text = (char *)values[i];
+ else if (type == IPP_TAG_LANGUAGE && !strcasecmp(values[i], "C"))
+ {
+ /*
+ * Force language to be English for the POSIX locale...
+ */
- if (type == IPP_TAG_LANGUAGE && !strcasecmp(values[i], "C"))
value->string.text = ((int)type & IPP_TAG_COPY) ? "en" :
_cupsStrAlloc("en");
+ }
+ else if (type == IPP_TAG_LANGUAGE || type == IPP_TAG_CHARSET)
+ {
+ /*
+ * Convert language values to lowercase and change _ to - as needed...
+ */
+
+ strlcpy(buffer, values[i], sizeof(buffer));
+
+ for (bufptr = buffer; *bufptr; bufptr ++)
+ if (*bufptr == '_')
+ *bufptr = '-';
+ else
+ *bufptr = tolower(*bufptr & 255);
+
+ value->string.text = _cupsStrAlloc(buffer);
+ }
else
- value->string.text = ((int)type & IPP_TAG_COPY) ? (char *)values[i] :
- _cupsStrAlloc(values[i]);
+ value->string.text = _cupsStrAlloc(values[i]);
+
}
}
-__cups_debug_fd
-__cups_debug_printf
-__cups_debug_puts
-__cups_strcpy
-__cupsAdminGetServerSettings
-__cupsAdminSetServerSettings
-__cupsAppleLanguage
-__cupsCharmapFlush
-__cupsCharmapFree
-__cupsCharmapGet
-__cupsEncodingName
-__cupsGetPassword
-__cupsGlobals
-__cupsLangPrintError
-__cupsLangPrintf
-__cupsLangPuts
-__cupsLangString
-__cupsMD5Append
-__cupsMD5Finish
-__cupsMD5Init
-__cupsMessageFree
-__cupsMessageLoad
-__cupsMessageLookup
-__cupsPWGMediaByName
-__cupsPWGMediaByLegacy
-__cupsPWGMediaBySize
-__cupsSetError
-__cupsSetLocale
-__cupsSNMPClose
-__cupsSNMPCopyOID
-__cupsSNMPDefaultCommunity
-__cupsSNMPIsOID
-__cupsSNMPIsOIDPrefixed
-__cupsSNMPOIDToString
-__cupsSNMPOpen
-__cupsSNMPRead
-__cupsSNMPSetDebug
-__cupsSNMPStringToOID
-__cupsSNMPWalk
-__cupsSNMPWrite
-__cupsStrAlloc
-__cupsStrFlush
-__cupsStrFormatd
-__cupsStrFree
-__cupsStrRetain
-__cupsStrScand
-__cupsStrStatistics
-__httpAddrPort
-__httpCreate
-__httpEncodeURI
-__httpReadCDSA
-__httpResolveURI
-__httpWriteCDSA
-__ippAddAttr
-__ippFindOption
-__ippFreeAttr
-__ppdFreeLanguages
-__ppdGet1284Values
-__ppdGetEncoding
-__ppdGetLanguages
-__ppdHashName
-__ppdLocalizedAttr
-__ppdNormalizeMakeAndModel
-__ppdParseOptions
-_cupsAddDest
-_cupsAddOption
-_cupsAdminCreateWindowsPPD
-_cupsAdminExportSamba
-_cupsAdminGetServerSettings
-_cupsAdminSetServerSettings
-_cupsArrayAdd
-_cupsArrayClear
-_cupsArrayCount
-_cupsArrayCurrent
-_cupsArrayDelete
-_cupsArrayDup
-_cupsArrayFind
-_cupsArrayFirst
-_cupsArrayGetIndex
-_cupsArrayGetInsert
-_cupsArrayIndex
-_cupsArrayInsert
-_cupsArrayLast
-_cupsArrayNew
-_cupsArrayNew2
-_cupsArrayNext
-_cupsArrayPrev
-_cupsArrayRemove
-_cupsArrayRestore
-_cupsArraySave
-_cupsArrayUserData
-_cupsBackChannelRead
-_cupsBackChannelWrite
-_cupsBackendDeviceURI
-_cupsBackendReport
-_cupsCancelJob
-_cupsCancelJob2
-_cupsCharsetToUTF8
-_cupsCreateJob
-_cupsDirClose
-_cupsDirOpen
-_cupsDirRead
-_cupsDirRewind
-_cupsDoAuthentication
-_cupsDoFileRequest
-_cupsDoIORequest
-_cupsDoRequest
-_cupsEncodeOptions
-_cupsEncodeOptions2
-_cupsEncryption
-_cupsFileClose
-_cupsFileCompression
-_cupsFileEOF
-_cupsFileFind
-_cupsFileFlush
-_cupsFileGetChar
-_cupsFileGetConf
-_cupsFileGetLine
-_cupsFileGets
-_cupsFileLock
-_cupsFileNumber
-_cupsFileOpen
-_cupsFileOpenFd
-_cupsFilePeekChar
-_cupsFilePrintf
-_cupsFilePutChar
-_cupsFilePutConf
-_cupsFilePuts
-_cupsFileRead
-_cupsFileRewind
-_cupsFileSeek
-_cupsFileStderr
-_cupsFileStdin
-_cupsFileStdout
-_cupsFileTell
-_cupsFileUnlock
-_cupsFileWrite
-_cupsFinishDocument
-_cupsFreeDests
-_cupsFreeJobs
-_cupsFreeOptions
-_cupsGetClasses
-_cupsGetConflicts
-_cupsGetDefault
-_cupsGetDefault2
-_cupsGetDest
-_cupsGetDests
-_cupsGetDests2
-_cupsGetDevices
-_cupsGetFd
-_cupsGetFile
-_cupsGetJobs
-_cupsGetJobs2
-_cupsGetNamedDest
-_cupsGetOption
-_cupsGetPassword
-_cupsGetPassword2
-_cupsGetPPD
-_cupsGetPPD2
-_cupsGetPPD3
-_cupsGetPrinters
-_cupsGetResponse
-_cupsGetServerPPD
-_cupsLangDefault
-_cupsLangEncoding
-_cupsLangFlush
-_cupsLangFree
-_cupsLangGet
-_cupsLastError
-_cupsLastErrorString
-_cupsMarkOptions
-_cupsNotifySubject
-_cupsNotifyText
-_cupsParseOptions
-_cupsPrintFile
-_cupsPrintFile2
-_cupsPrintFiles
-_cupsPrintFiles2
-_cupsPutFd
-_cupsPutFile
-_cupsReadResponseData
-_cupsRemoveDest
-_cupsRemoveOption
-_cupsResolveConflicts
-_cupsSendRequest
-_cupsServer
-_cupsSetDefaultDest
-_cupsSetDests
-_cupsSetDests2
-_cupsSetEncryption
-_cupsSetPasswordCB
-_cupsSetPasswordCB2
-_cupsSetServer
-_cupsSetUser
-_cupsSideChannelDoRequest
-_cupsSideChannelRead
-_cupsSideChannelWrite
-_cupsSideChannelSNMPGet
-_cupsSideChannelSNMPWalk
-_cupsStartDocument
-_cupsTempFd
-_cupsTempFile
-_cupsTempFile2
-_cupsUser
-_cupsUTF32ToUTF8
-_cupsUTF8ToCharset
-_cupsUTF8ToUTF32
-_cupsWriteRequestData
-_httpAddrAny
-_httpAddrConnect
-_httpAddrEqual
-_httpAddrFreeList
-_httpAddrGetList
-_httpAddrLength
-_httpAddrLocalhost
-_httpAddrLookup
-_httpAddrString
-_httpAssembleURI
-_httpAssembleURIf
-_httpBlocking
-_httpCheck
-_httpClearCookie
-_httpClearFields
-_httpClose
-_httpConnect
-_httpConnectEncrypt
-_httpDecode64
-_httpDecode64_2
-_httpDelete
-_httpEncode64
-_httpEncode64_2
-_httpEncryption
-_httpError
-_httpFlush
-_httpFlushWrite
-_httpGet
-_httpGetAuthString
-_httpGetBlocking
-_httpGetCookie
-_httpGetDateString
-_httpGetDateString2
-_httpGetDateTime
-_httpGetFd
-_httpGetField
-_httpGetHostByName
-_httpGetHostname
-_httpGetLength
-_httpGetLength2
-_httpGets
-_httpGetStatus
-_httpGetSubField
-_httpGetSubField2
-_httpHead
-_httpInitialize
-_httpMD5
-_httpMD5Final
-_httpMD5String
-_httpOptions
-_httpPost
-_httpPrintf
-_httpPut
-_httpRead
-_httpRead2
-_httpReconnect
-_httpSeparate
-_httpSeparate2
-_httpSeparateURI
-_httpSetAuthString
-_httpSetCookie
-_httpSetExpect
-_httpSetField
-_httpSetLength
-_httpStatus
-_httpTrace
-_httpUpdate
-_httpWait
-_httpWrite
-_httpWrite2
-_ippAddBoolean
-_ippAddBooleans
-_ippAddCollection
-_ippAddCollections
-_ippAddDate
-_ippAddInteger
-_ippAddIntegers
-_ippAddOctetString
-_ippAddRange
-_ippAddRanges
-_ippAddResolution
-_ippAddResolutions
-_ippAddSeparator
-_ippAddString
-_ippAddStrings
-_ippDateToTime
-_ippDelete
-_ippDeleteAttribute
-_ippErrorString
-_ippErrorValue
-_ippFindAttribute
-_ippFindNextAttribute
-_ippLength
-_ippNew
-_ippNewRequest
-_ippOpString
-_ippOpValue
-_ippPort
-_ippRead
-_ippReadFile
-_ippReadIO
-_ippSetPort
-_ippTagString
-_ippTagValue
-_ippTimeToDate
-_ippWrite
-_ippWriteFile
-_ippWriteIO
-_ppdClose
-_ppdCollect
-_ppdCollect2
-_ppdConflicts
-_ppdEmit
-_ppdEmitAfterOrder
-_ppdEmitFd
-_ppdEmitJCL
-_ppdEmitJCLEnd
-_ppdEmitString
-_ppdErrorString
-_ppdFindAttr
-_ppdFindChoice
-_ppdFindCustomOption
-_ppdFindCustomParam
-_ppdFindMarkedChoice
-_ppdFindNextAttr
-_ppdFindOption
-_ppdFirstCustomParam
-_ppdFirstOption
-_ppdInstallableConflict
-_ppdIsMarked
-_ppdLastError
-_ppdLocalize
-_ppdLocalizeAttr
-_ppdLocalizeIPPReason
-_ppdLocalizeMarkerName
-_ppdMarkDefaults
-_ppdMarkOption
-_ppdNextCustomParam
-_ppdNextOption
-_ppdOpen
-_ppdOpen2
-_ppdOpenFd
-_ppdOpenFile
-_ppdPageLength
-_ppdPageSize
-_ppdPageSizeLimits
-_ppdPageWidth
-_ppdSetConformance
LIBRARY libcups2
-VERSION 2.7
+VERSION 2.8
EXPORTS
_cupsAdminGetServerSettings
_cupsAdminSetServerSettings
cupsDirRewind
cupsDoAuthentication
cupsDoFileRequest
+cupsDoIORequest
cupsDoRequest
cupsEncodeOptions
cupsEncodeOptions2
cupsGetPPD2
cupsGetPassword
cupsGetPrinters
+cupsGetResponse
cupsLangDefault
cupsLangEncoding
cupsLangFlush
cupsPutFile
cupsRemoveOption
cupsResolveConflicts
+cupsSendRequest
cupsServer
cupsSetDests
cupsSetDests2
cupsUTF8ToCharset
cupsUTF8ToUTF32
cupsUser
+cupsWriteRequestData
httpAddrAny
httpAddrConnect
httpAddrEqual
ippReadFile
ippReadIO
ippSetPort
+ippTagString
+ippTagValue
ippTimeToDate
ippWrite
ippWriteFile
_cupsCharmapFree
_cupsCharmapGet
_cupsEncodingName
+_cupsGet1284Values
_cupsGetPassword
_cupsGlobals
_cupsLangPrintf
_ippAddAttr
_ippFreeAttr
_ppdFreeLanguages
-_ppdGet1284Values
_ppdGetEncoding
_ppdGetLanguages
_ppdHashName
/*
* "$Id: options.c 8181 2008-12-10 17:29:57Z mike $"
*
- * Option routines for the Common UNIX Printing System (CUPS).
+ * Option routines for CUPS.
*
- * Copyright 2007-2009 by Apple Inc.
+ * Copyright 2007-2010 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products.
*
* These coded instructions, statements, and computer programs are the
*
* Contents:
*
- * cupsAddOption() - Add an option to an option array.
- * cupsFreeOptions() - Free all memory used by options.
- * cupsGetOption() - Get an option value.
- * cupsParseOptions() - Parse options from a command-line argument.
- * cupsRemoveOption() - Remove an option from an option array.
+ * cupsAddOption() - Add an option to an option array.
+ * cupsFreeOptions() - Free all memory used by options.
+ * cupsGetOption() - Get an option value.
+ * cupsParseOptions() - Parse options from a command-line argument.
+ * cupsRemoveOption() - Remove an option from an option array.
+ * _cupsGet1284Values() - Get 1284 device ID keys and values.
+ * cups_compare_options() - Compare two options.
+ * cups_find_option() - Find an option using a binary search.
*/
/*
}
+/*
+ * '_cupsGet1284Values()' - Get 1284 device ID keys and values.
+ *
+ * The returned dictionary is a CUPS option array that can be queried with
+ * cupsGetOption and freed with cupsFreeOptions.
+ */
+
+int /* O - Number of key/value pairs */
+_cupsGet1284Values(
+ const char *device_id, /* I - IEEE-1284 device ID string */
+ cups_option_t **values) /* O - Array of key/value pairs */
+{
+ int num_values; /* Number of values */
+ char key[256], /* Key string */
+ value[256], /* Value string */
+ *ptr; /* Pointer into key/value */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (values)
+ *values = NULL;
+
+ if (!device_id || !values)
+ return (0);
+
+ /*
+ * Parse the 1284 device ID value into keys and values. The format is
+ * repeating sequences of:
+ *
+ * [whitespace]key:value[whitespace];
+ */
+
+ num_values = 0;
+ while (*device_id)
+ {
+ while (isspace(*device_id & 255))
+ device_id ++;
+
+ if (!*device_id)
+ break;
+
+ for (ptr = key; *device_id && *device_id != ':'; device_id ++)
+ if (ptr < (key + sizeof(key) - 1))
+ *ptr++ = *device_id;
+
+ if (!*device_id)
+ break;
+
+ while (ptr > key && isspace(ptr[-1] & 255))
+ ptr --;
+
+ *ptr = '\0';
+ device_id ++;
+
+ while (isspace(*device_id & 255))
+ device_id ++;
+
+ if (!*device_id)
+ break;
+
+ for (ptr = value; *device_id && *device_id != ';'; device_id ++)
+ if (ptr < (value + sizeof(value) - 1))
+ *ptr++ = *device_id;
+
+ if (!*device_id)
+ break;
+
+ while (ptr > value && isspace(ptr[-1] & 255))
+ ptr --;
+
+ *ptr = '\0';
+ device_id ++;
+
+ num_values = cupsAddOption(key, value, num_values, values);
+ }
+
+ return (num_values);
+}
+
+
/*
* 'cups_compare_options()' - Compare two options.
*/
*
* Page size functions for the Common UNIX Printing System (CUPS).
*
- * Copyright 2007-2009 by Apple Inc.
+ * Copyright 2007-2010 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
* Figure out the current minimum width and length...
*/
+ width = ppd->custom_min[0];
+ length = ppd->custom_min[1];
+
if (qualifier2)
{
/*
length = ppd->custom_min[1];
}
}
- else
- {
- width = ppd->custom_min[0];
- length = ppd->custom_min[1];
- }
minimum->width = width;
minimum->length = length;
* Figure out the current maximum width and length...
*/
+ width = ppd->custom_max[0];
+ length = ppd->custom_max[1];
+
if (qualifier2)
{
/*
length = ppd->custom_max[1];
}
}
- else
- {
- width = ppd->custom_max[0];
- length = ppd->custom_max[1];
- }
maximum->width = width;
maximum->length = length;
/*
* "$Id$"
*
- * Private PPD definitions for the Common UNIX Printing System (CUPS).
+ * Private PPD definitions for CUPS.
*
- * Copyright 2007-2008 by Apple Inc.
+ * Copyright 2007-2010 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
*/
extern void _ppdFreeLanguages(cups_array_t *languages);
-extern int _ppdGet1284Values(const char *device_id,
- cups_option_t **values);
extern cups_encoding_t _ppdGetEncoding(const char *name);
extern cups_array_t *_ppdGetLanguages(ppd_file_t *ppd);
extern unsigned _ppdHashName(const char *name);
* Format a string using the hex time values...
*/
- snprintf(filename, len - 1, "%s/%05x%08lx", tmpdir, (unsigned)getpid(),
- (unsigned long)(curtime.tv_sec + curtime.tv_usec + tries));
+ snprintf(filename, len - 1, "%s/%05x%08x", tmpdir, (unsigned)getpid(),
+ (unsigned)(curtime.tv_sec + curtime.tv_usec + tries));
#endif /* WIN32 */
/*
+++ /dev/null
-%%BeginResource: procset hpgltops 1.1 0
-%
-% "$Id: HPGLprolog 6649 2007-07-11 21:46:42Z mike $"
-%
-% HP-GL/2 filter procset for the Common UNIX Printing System (CUPS).
-%
-% This procset contains the basic drawing commands that are used to
-% reduce output size. Note the 'MP' (make newpath) definition - this
-% should be called 'NP' (newpath), but GhostScript uses the 'NP' name
-% for 'noaccess put' in some of its font files...
-%
-% Copyright 2007 by Apple Inc.
-% Copyright 1993-2005 by Easy Software Products
-%
-% These coded instructions, statements, and computer programs are the
-% property of Apple Inc. and are protected by Federal copyright law.
-% Distribution and use rights are outlined in the file "LICENSE.txt"
-% which is included with the CUPS source distribution.
-%
-/MO { moveto } bind def
-/LI { lineto } bind def
-/FI { fill } bind def
-/ST { stroke } bind def
-/CP { closepath } bind def
-/MP { newpath } bind def
-/SP { setlinewidth setrgbcolor } bind def
-%%EndResource
#
# Datafile makefile for the Common UNIX Printing System (CUPS).
#
-# Copyright 2007-2008 by Apple Inc.
+# Copyright 2007-2010 by Apple Inc.
# Copyright 1993-2006 by Easy Software Products.
#
# These coded instructions, statements, and computer programs are the
utf-8
DATAFILES = \
- HPGLprolog \
psglyphs \
testprint
username. The default is <CODE>Basic</CODE>.</P>
-<H2 CLASS="title"><A NAME="DefaultCharset">DefaultCharset</A></H2>
-
-<H3>Examples</H3>
-
-<PRE CLASS="command">
-DefaultCharset utf-8
-DefaultCharset iso-8859-1
-DefaultCharset windows-1251
-</PRE>
-
-<H3>Description</H3>
-
-<P>The <CODE>DefaultCharset</CODE> directive sets the default
-character set to use for client connections. The default
-character set is <CODE>utf-8</CODE> but is overridden by the
-character set for the language specified by the client or the
-<CODE>DefaultLanguage</CODE> directive.</P>
-
-
<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.2/Mac OS X 10.5</SPAN><A NAME="DefaultEncryption">DefaultEncryption</A></H2>
<H3>Examples</H3>
to the <I>data-time</I> field in the <VAR>access_log</VAR>
file.</P>
-<P>The <I>page-number</I> and <I>num-pages</I> fields contain the
+<P>The <I>page-number</I> and <I>num-copies</I> fields contain the
page number and number of copies being printed of that page. For
printers that cannot produce copies on their own, the
-<I>num-pages</I> field will always be 1.</P>
+<I>num-copies</I> field will always be 1.</P>
<P>The <I>job-billing</I> field contains a copy of the
<CODE>job-billing</CODE> attribute provided with the IPP
in their entirety, however that may delay the adoption of your
changes.</P>
-<BLOCKQUOTE>Patches and files must conform to the standards
-outlined in the "<A HREF="#CODING">Coding Guidelines</A>" and "<A
-HREF="#MAKEFILES">Makefile Guidelines</A>" sections in this
-document. In addition, since Apple Inc. provides CUPS
-under multiple licenses, we require that you assign the copyright
-for your changes and files to us for inclusion in
-CUPS.</BLOCKQUOTE>
+<BLOCKQUOTE>Patches and files must conform to the standards outlined in the
+"<A HREF="#CODING">Coding Guidelines</A>" and "<A HREF="#MAKEFILES">Makefile
+Guidelines</A>" sections in this document. In addition, since Apple Inc.
+provides CUPS under multiple licenses, we require that you assign the copyright
+for your changes and files to us for inclusion in CUPS.</BLOCKQUOTE>
<H2 CLASS="title"><A NAME="PRACTICES">Software Development Practices</A></H2>
2.0.0
</PRE>
-<P>The first production release in a MAJOR.MINOR series
-(MAJOR.MINOR.0) is called a feature release. Feature releases are
-the only releases that may contain new features. Subsequent
-production releases in a MAJOR.MINOR series may only contain bug
-fixes.</P>
+<P>The first production release in a MAJOR.MINOR series (MAJOR.MINOR.0) is
+called a feature release. Feature releases are the only releases that may
+contain new features. Subsequent production releases in a MAJOR.MINOR series may
+only contain bug fixes.</P>
-<BLOCKQUOTE>We did not hold to this limitation in the CUPS 1.1
-series for a variety of reasons. Starting with CUPS 1.2, the "no
-new features in a patch release" policy will be strictly
-enforced. This should yield more frequent minor releases with
-fewer new features (and interactions!) to
-validate/test.</BLOCKQUOTE>
+<BLOCKQUOTE>We did not hold to this limitation in the CUPS 1.1 series for a
+variety of reasons. Starting with CUPS 1.2, the "no new features in a patch
+release" policy has been strictly enforced. The policy has also resulted in
+fewer new features (and interactions!) to validate/test in the subsequence
+feature releases.</BLOCKQUOTE>
-<P>Beta-test releases are identified by appending the letter B
-to the major and minor version numbers followed by the beta
-release number:</P>
+<P>Beta-test releases are identified by appending the letter B to the major and
+minor version numbers followed by the beta release number:</P>
<PRE CLASS="command">
MAJOR.MINORbNUMBER
1.2b1
</PRE>
-<P>Release candidates are identified by appending the letters RC
-to the major and minor version numbers followed by the release
-candidate number:</P>
+<P>Release candidates are identified by appending the letters RC to the major
+and minor version numbers followed by the release candidate number:</P>
<PRE CLASS="command">
MAJOR.MINORrcNUMBER
1.2rc1
</PRE>
-<P>Developer snapshots are identified by appending the letters
-SVN-R to the major and minor version numbers followed by the
-revision number:</P>
+<P>Developer snapshots are identified by appending the letters SVN-R to the
+major and minor version numbers followed by the revision number:</P>
<PRE CLASS="command">
MAJOR.MINORsvn-rREV
1.2svn-r1234
</PRE>
-<P>Beta-test releases, release candidates, and developer
-snapshots are only created for new minor releases. Once a
-production release has been made (MAJOR.MINOR.0), subsequent
-patch releases are issues without preliminary beta or release
-testing.</P>
+<P>Beta-test releases, release candidates, and developer snapshots are only
+created for new minor releases. Once a production release has been made
+(MAJOR.MINOR.0), subsequent patch releases are issues without preliminary beta
+or release testing.</P>
<H3>Version Control (Subversion)</H3>
commit log messages:</P>
<PRE CLASS="command">
-Summary of the change ("fix PostScript printing bug") along
-with corresponding STRs ("STR #1, STR #6")
+Summary of the change on one line followed by bug number (STR #NNNN)
-foo.cxx:
- - function(): Detailed list of changes
- - function2(): Detailed list of changes
- - Summary of design changes ("added new foo struct")
-
-bar.h:
- - More detailed changes
+Detailed list of changes.
</PRE>
<P>Primary development occurs on the <var>trunk</var> branch,
*
* Description of file contents.
*
- * Copyright 2007 by Apple Inc.
+ * Copyright 2010 by Apple Inc.
*
* These coded instructions, statements, and computer programs are the
* property of Apple Inc. and are protected by Federal copyright
<UL>
- <LI><CODE>@since CUPS <I>version</I>@</CODE> - Marks the
- function as new in the specified version of CUPS.</LI>
-
<LI><CODE>@deprecated@</CODE> - Marks the function as
deprecated (not recommended for new development and
scheduled for removal)</LI>
+ <LI><CODE>@since CUPS <I>version</I>@</CODE> - Marks the
+ function as new in the specified version of CUPS.</LI>
+
+ <LI><CODE>@private@</CODE> - Marks the function as private.</LI>
+
</UL>
<H3>Variables</H3>
cmyk.o: ../cups/language.h ../cups/raster.h ../cups/string.h ../config.h
dither.o: driver.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
dither.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h ../cups/file.h
-dither.o: ../cups/language.h ../cups/raster.h
+dither.o: ../cups/language.h ../cups/raster.h ../config.h
lut.o: driver.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
lut.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h ../cups/file.h
lut.o: ../cups/language.h ../cups/raster.h
#
# Makefile for the CUPS base drivers.
#
-# Copyright 2007-2009 by Apple Inc.
+# Copyright 2007-2010 by Apple Inc.
# Copyright 2002-2005 by Easy Software Products.
#
# These coded instructions, statements, and computer programs are the
testcmyk \
testdither \
testrgb
-TARGETS = \
- $(LIBTARGETS) \
+FILTERS = \
commandtoescpx \
commandtopclx \
rastertoescpx \
rastertopclx
+TARGETS = \
+ $(LIBTARGETS) \
+ $(FILTERS)
#
install-exec:
$(INSTALL_DIR) $(SERVERBIN)/filter
- for file in commandtoescpx commandtopclx rastertoescpx rastertopclx; do \
+ for file in $(FILTERS); do \
$(INSTALL_BIN) $$file $(SERVERBIN)/filter; \
done
if test "x$(SYMROOT)" != "x"; then \
$(INSTALL_DIR) $(SYMROOT); \
- for file in commandtoescpx commandtopclx rastertoescpx rastertopclx; do \
+ for file in $(FILTERS); do \
cp $$file $(SYMROOT); \
done \
fi
# DO NOT DELETE
-hpgl-attr.o: hpgltops.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
-hpgl-attr.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h
-hpgl-attr.o: ../cups/file.h ../cups/language.h ../cups/language.h
-hpgl-attr.o: ../cups/string.h ../config.h
-hpgl-config.o: hpgltops.h common.h ../cups/cups.h ../cups/ipp.h
-hpgl-config.o: ../cups/http.h ../cups/versioning.h ../cups/ppd.h
-hpgl-config.o: ../cups/array.h ../cups/file.h ../cups/language.h
-hpgl-config.o: ../cups/language.h ../cups/string.h ../config.h
-hpgl-main.o: hpgltops.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
-hpgl-main.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h
-hpgl-main.o: ../cups/file.h ../cups/language.h ../cups/language.h
-hpgl-main.o: ../cups/string.h ../config.h ../cups/i18n.h ../cups/transcode.h
-hpgl-prolog.o: hpgltops.h common.h ../cups/cups.h ../cups/ipp.h
-hpgl-prolog.o: ../cups/http.h ../cups/versioning.h ../cups/ppd.h
-hpgl-prolog.o: ../cups/array.h ../cups/file.h ../cups/language.h
-hpgl-prolog.o: ../cups/language.h ../cups/string.h ../config.h
-hpgl-char.o: hpgltops.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
-hpgl-char.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h
-hpgl-char.o: ../cups/file.h ../cups/language.h ../cups/language.h
-hpgl-char.o: ../cups/string.h ../config.h
-hpgl-input.o: hpgltops.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
-hpgl-input.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h
-hpgl-input.o: ../cups/file.h ../cups/language.h ../cups/language.h
-hpgl-input.o: ../cups/string.h ../config.h ../cups/i18n.h ../cups/transcode.h
-hpgl-polygon.o: hpgltops.h common.h ../cups/cups.h ../cups/ipp.h
-hpgl-polygon.o: ../cups/http.h ../cups/versioning.h ../cups/ppd.h
-hpgl-polygon.o: ../cups/array.h ../cups/file.h ../cups/language.h
-hpgl-polygon.o: ../cups/language.h ../cups/string.h ../config.h
-hpgl-vector.o: hpgltops.h common.h ../cups/cups.h ../cups/ipp.h
-hpgl-vector.o: ../cups/http.h ../cups/versioning.h ../cups/ppd.h
-hpgl-vector.o: ../cups/array.h ../cups/file.h ../cups/language.h
-hpgl-vector.o: ../cups/language.h ../cups/string.h ../config.h
image-bmp.o: image-private.h image.h ../cups/raster.h ../cups/cups.h
image-bmp.o: ../cups/ipp.h ../cups/http.h ../cups/versioning.h ../cups/ppd.h
image-bmp.o: ../cups/array.h ../cups/file.h ../cups/language.h
raster.o: ../cups/ipp.h ../cups/http.h ../cups/versioning.h ../cups/ppd.h
raster.o: ../cups/array.h ../cups/file.h ../cups/language.h ../cups/debug.h
raster.o: ../cups/string.h ../config.h
-form-main.o: form.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
-form-main.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h
-form-main.o: ../cups/file.h ../cups/language.h ../cups/language.h
-form-main.o: ../cups/string.h ../config.h
-form-ps.o: form.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
-form-ps.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h ../cups/file.h
-form-ps.o: ../cups/language.h ../cups/language.h ../cups/string.h ../config.h
-form-tree.o: form.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
-form-tree.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h
-form-tree.o: ../cups/file.h ../cups/language.h ../cups/language.h
-form-tree.o: ../cups/string.h ../config.h
bannertops.o: pstext.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
bannertops.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h
bannertops.o: ../cups/file.h ../cups/language.h ../cups/language.h
commandtops.o: ../cups/file.h ../cups/language.h ../cups/string.h ../config.h
commandtops.o: ../cups/sidechannel.h
gziptoany.o: ../cups/file.h ../cups/versioning.h ../cups/string.h ../config.h
-gziptoany.o: ../cups/i18n.h ../cups/transcode.h ../cups/language.h
-gziptoany.o: ../cups/array.h
+gziptoany.o: ../cups/i18n.h ../cups/transcode.h
imagetops.o: common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
imagetops.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h
imagetops.o: ../cups/file.h ../cups/language.h ../cups/language.h
pstops.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h ../cups/file.h
pstops.o: ../cups/language.h ../cups/language.h ../cups/string.h ../config.h
pstops.o: ../cups/file.h ../cups/array.h ../cups/i18n.h ../cups/transcode.h
-rasterbench.o: ../cups/raster.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
-rasterbench.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h
-rasterbench.o: ../cups/file.h ../cups/language.h
+rasterbench.o: ../config.h ../cups/raster.h ../cups/cups.h ../cups/ipp.h
+rasterbench.o: ../cups/http.h ../cups/versioning.h ../cups/ppd.h
+rasterbench.o: ../cups/array.h ../cups/file.h ../cups/language.h
rastertoepson.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h
rastertoepson.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h
rastertoepson.o: ../cups/file.h ../cups/language.h ../cups/ppd.h
texttops.o: ../config.h ../cups/i18n.h ../cups/transcode.h
# DO NOT DELETE
-hpgl-attr.32.o: hpgl-attr.c hpgltops.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
-hpgl-attr.32.o: hpgl-attr.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h
-hpgl-attr.32.o: hpgl-attr.c ../cups/file.h ../cups/language.h ../cups/language.h
-hpgl-attr.32.o: hpgl-attr.c ../cups/string.h ../config.h
-hpgl-config.32.o: hpgl-config.c hpgltops.h common.h ../cups/cups.h ../cups/ipp.h
-hpgl-config.32.o: hpgl-config.c ../cups/http.h ../cups/versioning.h ../cups/ppd.h
-hpgl-config.32.o: hpgl-config.c ../cups/array.h ../cups/file.h ../cups/language.h
-hpgl-config.32.o: hpgl-config.c ../cups/language.h ../cups/string.h ../config.h
-hpgl-main.32.o: hpgl-main.c hpgltops.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
-hpgl-main.32.o: hpgl-main.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h
-hpgl-main.32.o: hpgl-main.c ../cups/file.h ../cups/language.h ../cups/language.h
-hpgl-main.32.o: hpgl-main.c ../cups/string.h ../config.h ../cups/i18n.h ../cups/transcode.h
-hpgl-prolog.32.o: hpgl-prolog.c hpgltops.h common.h ../cups/cups.h ../cups/ipp.h
-hpgl-prolog.32.o: hpgl-prolog.c ../cups/http.h ../cups/versioning.h ../cups/ppd.h
-hpgl-prolog.32.o: hpgl-prolog.c ../cups/array.h ../cups/file.h ../cups/language.h
-hpgl-prolog.32.o: hpgl-prolog.c ../cups/language.h ../cups/string.h ../config.h
-hpgl-char.32.o: hpgl-char.c hpgltops.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
-hpgl-char.32.o: hpgl-char.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h
-hpgl-char.32.o: hpgl-char.c ../cups/file.h ../cups/language.h ../cups/language.h
-hpgl-char.32.o: hpgl-char.c ../cups/string.h ../config.h
-hpgl-input.32.o: hpgl-input.c hpgltops.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
-hpgl-input.32.o: hpgl-input.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h
-hpgl-input.32.o: hpgl-input.c ../cups/file.h ../cups/language.h ../cups/language.h
-hpgl-input.32.o: hpgl-input.c ../cups/string.h ../config.h ../cups/i18n.h ../cups/transcode.h
-hpgl-polygon.32.o: hpgl-polygon.c hpgltops.h common.h ../cups/cups.h ../cups/ipp.h
-hpgl-polygon.32.o: hpgl-polygon.c ../cups/http.h ../cups/versioning.h ../cups/ppd.h
-hpgl-polygon.32.o: hpgl-polygon.c ../cups/array.h ../cups/file.h ../cups/language.h
-hpgl-polygon.32.o: hpgl-polygon.c ../cups/language.h ../cups/string.h ../config.h
-hpgl-vector.32.o: hpgl-vector.c hpgltops.h common.h ../cups/cups.h ../cups/ipp.h
-hpgl-vector.32.o: hpgl-vector.c ../cups/http.h ../cups/versioning.h ../cups/ppd.h
-hpgl-vector.32.o: hpgl-vector.c ../cups/array.h ../cups/file.h ../cups/language.h
-hpgl-vector.32.o: hpgl-vector.c ../cups/language.h ../cups/string.h ../config.h
image-bmp.32.o: image-bmp.c image-private.h image.h ../cups/raster.h ../cups/cups.h
image-bmp.32.o: image-bmp.c ../cups/ipp.h ../cups/http.h ../cups/versioning.h ../cups/ppd.h
image-bmp.32.o: image-bmp.c ../cups/array.h ../cups/file.h ../cups/language.h
raster.32.o: raster.c ../cups/ipp.h ../cups/http.h ../cups/versioning.h ../cups/ppd.h
raster.32.o: raster.c ../cups/array.h ../cups/file.h ../cups/language.h ../cups/debug.h
raster.32.o: raster.c ../cups/string.h ../config.h
-form-main.32.o: form-main.c form.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
-form-main.32.o: form-main.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h
-form-main.32.o: form-main.c ../cups/file.h ../cups/language.h ../cups/language.h
-form-main.32.o: form-main.c ../cups/string.h ../config.h
-form-ps.32.o: form-ps.c form.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
-form-ps.32.o: form-ps.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h ../cups/file.h
-form-ps.32.o: form-ps.c ../cups/language.h ../cups/language.h ../cups/string.h ../config.h
-form-tree.32.o: form-tree.c form.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
-form-tree.32.o: form-tree.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h
-form-tree.32.o: form-tree.c ../cups/file.h ../cups/language.h ../cups/language.h
-form-tree.32.o: form-tree.c ../cups/string.h ../config.h
bannertops.32.o: bannertops.c pstext.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
bannertops.32.o: bannertops.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h
bannertops.32.o: bannertops.c ../cups/file.h ../cups/language.h ../cups/language.h
commandtops.32.o: commandtops.c ../cups/file.h ../cups/language.h ../cups/string.h ../config.h
commandtops.32.o: commandtops.c ../cups/sidechannel.h
gziptoany.32.o: gziptoany.c ../cups/file.h ../cups/versioning.h ../cups/string.h ../config.h
-gziptoany.32.o: gziptoany.c ../cups/i18n.h ../cups/transcode.h ../cups/language.h
-gziptoany.32.o: gziptoany.c ../cups/array.h
+gziptoany.32.o: gziptoany.c ../cups/i18n.h ../cups/transcode.h
imagetops.32.o: imagetops.c common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
imagetops.32.o: imagetops.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h
imagetops.32.o: imagetops.c ../cups/file.h ../cups/language.h ../cups/language.h
pstops.32.o: pstops.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h ../cups/file.h
pstops.32.o: pstops.c ../cups/language.h ../cups/language.h ../cups/string.h ../config.h
pstops.32.o: pstops.c ../cups/file.h ../cups/array.h ../cups/i18n.h ../cups/transcode.h
-rasterbench.32.o: rasterbench.c ../cups/raster.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
-rasterbench.32.o: rasterbench.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h
-rasterbench.32.o: rasterbench.c ../cups/file.h ../cups/language.h
+rasterbench.32.o: rasterbench.c ../config.h ../cups/raster.h ../cups/cups.h ../cups/ipp.h
+rasterbench.32.o: rasterbench.c ../cups/http.h ../cups/versioning.h ../cups/ppd.h
+rasterbench.32.o: rasterbench.c ../cups/array.h ../cups/file.h ../cups/language.h
rastertoepson.32.o: rastertoepson.c ../cups/cups.h ../cups/ipp.h ../cups/http.h
rastertoepson.32.o: rastertoepson.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h
rastertoepson.32.o: rastertoepson.c ../cups/file.h ../cups/language.h ../cups/ppd.h
texttops.32.o: texttops.c ../config.h ../cups/i18n.h ../cups/transcode.h
# DO NOT DELETE
-hpgl-attr.64.o: hpgl-attr.c hpgltops.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
-hpgl-attr.64.o: hpgl-attr.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h
-hpgl-attr.64.o: hpgl-attr.c ../cups/file.h ../cups/language.h ../cups/language.h
-hpgl-attr.64.o: hpgl-attr.c ../cups/string.h ../config.h
-hpgl-config.64.o: hpgl-config.c hpgltops.h common.h ../cups/cups.h ../cups/ipp.h
-hpgl-config.64.o: hpgl-config.c ../cups/http.h ../cups/versioning.h ../cups/ppd.h
-hpgl-config.64.o: hpgl-config.c ../cups/array.h ../cups/file.h ../cups/language.h
-hpgl-config.64.o: hpgl-config.c ../cups/language.h ../cups/string.h ../config.h
-hpgl-main.64.o: hpgl-main.c hpgltops.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
-hpgl-main.64.o: hpgl-main.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h
-hpgl-main.64.o: hpgl-main.c ../cups/file.h ../cups/language.h ../cups/language.h
-hpgl-main.64.o: hpgl-main.c ../cups/string.h ../config.h ../cups/i18n.h ../cups/transcode.h
-hpgl-prolog.64.o: hpgl-prolog.c hpgltops.h common.h ../cups/cups.h ../cups/ipp.h
-hpgl-prolog.64.o: hpgl-prolog.c ../cups/http.h ../cups/versioning.h ../cups/ppd.h
-hpgl-prolog.64.o: hpgl-prolog.c ../cups/array.h ../cups/file.h ../cups/language.h
-hpgl-prolog.64.o: hpgl-prolog.c ../cups/language.h ../cups/string.h ../config.h
-hpgl-char.64.o: hpgl-char.c hpgltops.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
-hpgl-char.64.o: hpgl-char.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h
-hpgl-char.64.o: hpgl-char.c ../cups/file.h ../cups/language.h ../cups/language.h
-hpgl-char.64.o: hpgl-char.c ../cups/string.h ../config.h
-hpgl-input.64.o: hpgl-input.c hpgltops.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
-hpgl-input.64.o: hpgl-input.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h
-hpgl-input.64.o: hpgl-input.c ../cups/file.h ../cups/language.h ../cups/language.h
-hpgl-input.64.o: hpgl-input.c ../cups/string.h ../config.h ../cups/i18n.h ../cups/transcode.h
-hpgl-polygon.64.o: hpgl-polygon.c hpgltops.h common.h ../cups/cups.h ../cups/ipp.h
-hpgl-polygon.64.o: hpgl-polygon.c ../cups/http.h ../cups/versioning.h ../cups/ppd.h
-hpgl-polygon.64.o: hpgl-polygon.c ../cups/array.h ../cups/file.h ../cups/language.h
-hpgl-polygon.64.o: hpgl-polygon.c ../cups/language.h ../cups/string.h ../config.h
-hpgl-vector.64.o: hpgl-vector.c hpgltops.h common.h ../cups/cups.h ../cups/ipp.h
-hpgl-vector.64.o: hpgl-vector.c ../cups/http.h ../cups/versioning.h ../cups/ppd.h
-hpgl-vector.64.o: hpgl-vector.c ../cups/array.h ../cups/file.h ../cups/language.h
-hpgl-vector.64.o: hpgl-vector.c ../cups/language.h ../cups/string.h ../config.h
image-bmp.64.o: image-bmp.c image-private.h image.h ../cups/raster.h ../cups/cups.h
image-bmp.64.o: image-bmp.c ../cups/ipp.h ../cups/http.h ../cups/versioning.h ../cups/ppd.h
image-bmp.64.o: image-bmp.c ../cups/array.h ../cups/file.h ../cups/language.h
raster.64.o: raster.c ../cups/ipp.h ../cups/http.h ../cups/versioning.h ../cups/ppd.h
raster.64.o: raster.c ../cups/array.h ../cups/file.h ../cups/language.h ../cups/debug.h
raster.64.o: raster.c ../cups/string.h ../config.h
-form-main.64.o: form-main.c form.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
-form-main.64.o: form-main.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h
-form-main.64.o: form-main.c ../cups/file.h ../cups/language.h ../cups/language.h
-form-main.64.o: form-main.c ../cups/string.h ../config.h
-form-ps.64.o: form-ps.c form.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
-form-ps.64.o: form-ps.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h ../cups/file.h
-form-ps.64.o: form-ps.c ../cups/language.h ../cups/language.h ../cups/string.h ../config.h
-form-tree.64.o: form-tree.c form.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
-form-tree.64.o: form-tree.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h
-form-tree.64.o: form-tree.c ../cups/file.h ../cups/language.h ../cups/language.h
-form-tree.64.o: form-tree.c ../cups/string.h ../config.h
bannertops.64.o: bannertops.c pstext.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
bannertops.64.o: bannertops.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h
bannertops.64.o: bannertops.c ../cups/file.h ../cups/language.h ../cups/language.h
commandtops.64.o: commandtops.c ../cups/file.h ../cups/language.h ../cups/string.h ../config.h
commandtops.64.o: commandtops.c ../cups/sidechannel.h
gziptoany.64.o: gziptoany.c ../cups/file.h ../cups/versioning.h ../cups/string.h ../config.h
-gziptoany.64.o: gziptoany.c ../cups/i18n.h ../cups/transcode.h ../cups/language.h
-gziptoany.64.o: gziptoany.c ../cups/array.h
+gziptoany.64.o: gziptoany.c ../cups/i18n.h ../cups/transcode.h
imagetops.64.o: imagetops.c common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
imagetops.64.o: imagetops.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h
imagetops.64.o: imagetops.c ../cups/file.h ../cups/language.h ../cups/language.h
pstops.64.o: pstops.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h ../cups/file.h
pstops.64.o: pstops.c ../cups/language.h ../cups/language.h ../cups/string.h ../config.h
pstops.64.o: pstops.c ../cups/file.h ../cups/array.h ../cups/i18n.h ../cups/transcode.h
-rasterbench.64.o: rasterbench.c ../cups/raster.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
-rasterbench.64.o: rasterbench.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h
-rasterbench.64.o: rasterbench.c ../cups/file.h ../cups/language.h
+rasterbench.64.o: rasterbench.c ../config.h ../cups/raster.h ../cups/cups.h ../cups/ipp.h
+rasterbench.64.o: rasterbench.c ../cups/http.h ../cups/versioning.h ../cups/ppd.h
+rasterbench.64.o: rasterbench.c ../cups/array.h ../cups/file.h ../cups/language.h
rastertoepson.64.o: rastertoepson.c ../cups/cups.h ../cups/ipp.h ../cups/http.h
rastertoepson.64.o: rastertoepson.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h
rastertoepson.64.o: rastertoepson.c ../cups/file.h ../cups/language.h ../cups/ppd.h
#
# Filter makefile for the Common UNIX Printing System (CUPS).
#
-# Copyright 2007-2009 by Apple Inc.
+# Copyright 2007-2010 by Apple Inc.
# Copyright 1997-2006 by Easy Software Products.
#
# These coded instructions, statements, and computer programs are the
$(BANNERTOPS) \
commandtops \
gziptoany \
- hpgltops \
$(TEXTTOPS) \
pstops \
$(IMGFILTERS) \
$(LIBTARGETS) \
$(FILTERS)
-HPGLOBJS = hpgl-attr.o hpgl-config.o hpgl-main.o hpgl-prolog.o \
- hpgl-char.o hpgl-input.o hpgl-polygon.o hpgl-vector.o
IMAGEOBJS = image-bmp.o image-colorspace.o image-gif.o image-jpeg.o \
image-photocd.o image-pix.o image-png.o image-pnm.o \
image-sgi.o image-sgilib.o image-sun.o image-tiff.o \
image-zoom.o image.o error.o interpret.o raster.o
IMAGE32OBJS = $(IMAGEOBJS:.o=.32.o)
IMAGE64OBJS = $(IMAGEOBJS:.o=.64.o)
-FORMOBJS = form-attr.o form-main.o form-ps.o form-text.o form-tree.o
-OBJS = $(HPGLOBJS) $(IMAGEOBJS) $(FORMOBJS) \
+OBJS = $(IMAGEOBJS) \
bannertops.o commandtops.o gziptoany.o imagetops.o \
imagetoraster.o common.o pdftops.o pstext.o pstops.o \
rasterbench.o rastertoepson.o rastertohp.o rastertolabel.o \
$(LN) rastertolabel $(SERVERBIN)/filter/rastertodymo
if test "x$(SYMROOT)" != "x"; then \
$(INSTALL_DIR) $(SYMROOT); \
- for file in $(TARGETS); do \
+ for file in $(FILTERS); do \
cp $$file $(SYMROOT); \
done \
fi
$(RM) $(LIBDIR)/libcupsimage.dylib; \
$(LN) $(LIBCUPSIMAGE) $(LIBDIR)/libcupsimage.dylib; \
fi
+ if test "x$(SYMROOT)" != "x"; then \
+ $(INSTALL_DIR) $(SYMROOT); \
+ cp $(LIBCUPSIMAGE) $(SYMROOT); \
+ fi
installstatic:
$(INSTALL_DIR) -m 755 $(LIBDIR)
$(CC) $(LDFLAGS) -o $@ commandtops.o $(LIBS)
-#
-# formtops
-#
-
-formtops: $(FORMOBJS) common.o ../cups/$(LIBCUPS)
- echo Linking $@...
- $(CC) $(LDFLAGS) -o $@ $(FORMOBJS) common.o $(LIBS) -lm
-
-
#
# gziptoany
#
$(CC) $(LDFLAGS) -o $@ gziptoany.o $(LIBZ) $(LIBS)
-#
-# hpgltops
-#
-
-hpgltops: $(HPGLOBJS) common.o ../cups/$(LIBCUPS)
- echo Linking $@...
- $(CC) $(LDFLAGS) -o $@ $(HPGLOBJS) common.o $(LIBS) -lm
-
-
#
# libcupsimage.so.2, libcupsimage.sl.2
#
+++ /dev/null
-/*
- * "$Id: form-main.c 6649 2007-07-11 21:46:42Z mike $"
- *
- * CUPS form main entry for the Common UNIX Printing System (CUPS).
- *
- * Copyright 2007 by Apple Inc.
- * Copyright 1997-2005 by Easy Software Products.
- *
- * These coded instructions, statements, and computer programs are the
- * property of Apple Inc. and are protected by Federal copyright
- * law. Distribution and use rights are outlined in the file "LICENSE.txt"
- * which should have been included with this file. If this file is
- * file is missing or damaged, see the license at "http://www.cups.org/".
- *
- * This file is subject to the Apple OS-Developed Software exception.
- *
- * Contents:
- *
- * main() - Load the specified form file and output PostScript.
- */
-
-/*
- * Include necessary headers...
- */
-
-#include "form.h"
-
-
-/*
- * Globals...
- */
-
-int NumOptions; /* Number of command-line options */
-cups_option_t *Options; /* Command-line options */
-ppd_file_t *PPD; /* PPD file */
-
-
-/*
- * 'main()' - Load the specified form file and output PostScript.
- */
-
-int /* O - Exit status */
-main(int argc, /* I - Number of command-line arguments */
- char *argv[]) /* I - Command-line arguments */
-{
-
- return (0);
-}
-
-
-/*
- * End of "$Id: form-main.c 6649 2007-07-11 21:46:42Z mike $".
- */
+++ /dev/null
-/*
- * "$Id: form-ps.c 6649 2007-07-11 21:46:42Z mike $"
- *
- * CUPS form PostScript routines for the Common UNIX Printing System (CUPS).
- *
- * Copyright 2007 by Apple Inc.
- * Copyright 1997-2005 by Easy Software Products.
- *
- * These coded instructions, statements, and computer programs are the
- * property of Apple Inc. and are protected by Federal copyright
- * law. Distribution and use rights are outlined in the file "LICENSE.txt"
- * which should have been included with this file. If this file is
- * file is missing or damaged, see the license at "http://www.cups.org/".
- *
- * This file is subject to the Apple OS-Developed Software exception.
- *
- * Contents:
- *
- */
-
-/*
- * Include necessary headers...
- */
-
-#include "form.h"
-
-
-/*
- * 'formWrite()' - Write PostScript output for the given form document.
- */
-
-void
-formWrite(tree_t *t) /* I - Document tree to write */
-{
-}
-
-
-/*
- * End of "$Id: form-ps.c 6649 2007-07-11 21:46:42Z mike $".
- */
+++ /dev/null
-/*
- * "$Id: form-tree.c 6649 2007-07-11 21:46:42Z mike $"
- *
- * CUPS form document tree routines for the Common UNIX Printing
- * System (CUPS).
- *
- * Copyright 2007 by Apple Inc.
- * Copyright 1997-2005 by Easy Software Products.
- *
- * These coded instructions, statements, and computer programs are the
- * property of Apple Inc. and are protected by Federal copyright
- * law. Distribution and use rights are outlined in the file "LICENSE.txt"
- * which should have been included with this file. If this file is
- * file is missing or damaged, see the license at "http://www.cups.org/".
- *
- * This file is subject to the Apple OS-Developed Software exception.
- *
- * Contents:
- *
- */
-
-/*
- * Include necessary headers...
- */
-
-#include "form.h"
-
-
-/*
- * Local functions...
- */
-
-static int compare_attr(attr_t *a0, attr_t *a1);
-static int compare_elements(char **e0, char **e1);
-static int parse_attr(tree_t *t, FILE *fp);
-static int parse_element(tree_t *t, FILE *fp);
-
-
-/*
- * Local globals...
- */
-
-static char *elements[] =
- {
- "",
- "!--",
- "ARC",
- "BOX",
- "BR",
- "B",
- "CUPSFORM",
- "DEFVAR",
- "FONT",
- "H1",
- "H2",
- "H3",
- "H4",
- "H5",
- "H6",
- "HEAD",
- "IMG",
- "I",
- "LINE",
- "PAGE",
- "PIE",
- "POLY",
- "PRE",
- "P",
- "RECT",
- "TEXT",
- "TT",
- "VAR"
- };
-
-
-/*
- * 'formDelete()' - Delete a node and its children.
- */
-
-void
-formDelete(tree_t *t) /* I - Tree node */
-{
-}
-
-
-/*
- * 'formGetAttr()' - Get a node attribute value.
- */
-
-char * /* O - Value or NULL */
-formGetAttr(tree_t *t, /* I - Tree node */
- const char *name) /* I - Name of attribute */
-{
-}
-
-
-/*
- * 'formNew()' - Create a new form node.
- */
-
-tree_t * /* O - New tree node */
-formNew(tree_t *p) /* I - Parent node */
-{
- tree_t *t; /* New tree node */
-
-
- /*
- * Allocate the new node...
- */
-
- if ((t = (tree_t *)calloc(sizeof(tree_t), 1)) == NULL)
- return (NULL);
-
- /*
- * Set/copy attributes...
- */
-
- if (p == NULL)
- {
- t->bg[0] = 1.0;
- t->bg[1] = 1.0;
- t->bg[2] = 1.0;
- t->halign = HALIGN_LEFT;
- t->valign = VALIGN_MIDDLE;
- t->typeface = "Courier";
- t->size = 12.0;
- }
- else
- {
- memcpy(t, p, sizeof(tree_t));
-
- t->prev = NULL;
- t->next = NULL;
- t->child = NULL;
- t->last_child = NULL;
- t->parent = NULL;
- t->num_attrs = 0;
- t->attrs = NULL;
- t->data = NULL;
- }
-
- /*
- * Return the new node...
- */
-
- return (t);
-}
-
-
-/*
- * 'formRead()' - Read a form tree from a file.
- */
-
-tree_t * /* O - New form tree */
-formRead(FILE *fp, /* I - File to read from */
- tree_t *p) /* I - Parent node */
-{
- int ch, /* Character from file */
- closech, /* Closing character */
- have_whitespace; /* Leading whitespace? */
- static char s[10240]; /* String from file */
- uchar *ptr, /* Pointer in string */
- glyph[16], /* Glyph name (&#nnn;) */
- *glyphptr; /* Pointer in glyph string */
- tree_t *tree, /* "top" of this tree */
- *t, /* New tree node */
- *prev, /* Previous tree node */
- *temp; /* Temporary looping var */
- uchar *face, /* Typeface for FONT tag */
- *color, /* Color for FONT tag */
- *size; /* Size for FONT tag */
-
-
- /*
- * Start off with no previous tree node...
- */
-
- prev = NULL;
- tree = NULL;
-
- /*
- * Parse data until we hit end-of-file...
- */
-
- while ((ch = getc(fp)) != EOF)
- {
- /*
- * Ignore leading whitespace...
- */
-
- have_whitespace = 0;
- closech = '/';
-
- if (p == NULL || !p->preformatted)
- {
- while (isspace(ch & 255))
- {
- have_whitespace = 1;
- ch = getc(fp);
- }
-
- if (ch == EOF)
- break;
- }
-
- /*
- * Allocate a new tree node - use calloc() to get zeroed data...
- */
-
- t = formNew(p);
-
- /*
- * See what the character was...
- */
-
- if (ch == '<')
- {
- /*
- * Markup char; grab the next char to see if this is a /...
- */
-
- ch = getc(fp);
- if (ch == ' ')
- {
- /*
- * Illegal lone "<"! Ignore it...
- */
-
- free(t);
- continue;
- }
-
- if (ch != '/')
- ungetc(ch, fp);
-
- if (parse_element(t, fp) < 0)
- {
- free(t);
- break;
- }
-
- if ((closech = getc(fp)) == '/')
- getc(fp);
-
- /*
- * If this is the matching close mark, or if we are starting the same
- * element, or if we've completed a list, we're done!
- */
-
- if (ch == '/')
- {
- /*
- * Close element; find matching element...
- */
-
- for (temp = p; temp != NULL; temp = temp->p)
- if (temp->element == t->element)
- break;
-
- free(t);
-
- if (temp != NULL)
- break;
- else
- continue;
- }
- }
- else if (t->preformatted)
- {
- /*
- * Read a pre-formatted string into the current tree node...
- */
-
- ptr = s;
- while (ch != '<' && ch != EOF && ptr < (s + sizeof(s) - 1))
- {
- if (ch == '&')
- {
- for (glyphptr = glyph;
- (ch = getc(fp)) != EOF && (glyphptr - glyph) < 15;
- glyphptr ++)
- if (!isalnum(ch & 255))
- break;
- else
- *glyphptr = ch;
-
- *glyphptr = '\0';
- if (atoi(glyph) > 0)
- ch = atoi(glyph);
- else if (strcmp(glyph, "lt") == 0)
- ch = '<';
- else if (strcmp(glyph, "gt") == 0)
- ch = '>';
- else if (strcmp(glyph, "quot") == 0)
- ch = '\'';
- else if (strcmp(glyph, "nbsp") == 0)
- ch = ' ';
- else
- ch = '&';
- }
-
- if (ch != 0)
- *ptr++ = ch;
-
- if (ch == '\n')
- break;
-
- ch = getc(fp);
- }
-
- *ptr = '\0';
-
- if (ch == '<')
- ungetc(ch, fp);
-
- t->element = ELEMENT_FRAGMENT;
- t->data = strdup(s);
- }
- else
- {
- /*
- * Read the next string fragment...
- */
-
- ptr = s;
- if (have_whitespace)
- *ptr++ = ' ';
-
- while (!isspace(ch & 255) && ch != '<' && ch != EOF && ptr < (s + sizeof(s) - 1))
- {
- if (ch == '&')
- {
- for (glyphptr = glyph;
- (ch = getc(fp)) != EOF && (glyphptr - glyph) < 15;
- glyphptr ++)
- if (!isalnum(ch & 255))
- break;
- else
- *glyphptr = ch;
-
- *glyphptr = '\0';
- if (atoi(glyph) > 0)
- ch = atoi(glyph);
- else if (strcmp(glyph, "lt") == 0)
- ch = '<';
- else if (strcmp(glyph, "gt") == 0)
- ch = '>';
- else if (strcmp(glyph, "quot") == 0)
- ch = '\'';
- else if (strcmp(glyph, "nbsp") == 0)
- ch = ' ';
- else
- ch = '&';
- }
-
- if (ch != 0)
- *ptr++ = ch;
-
- ch = getc(fp);
- }
-
- if (isspace(ch & 255))
- *ptr++ = ' ';
-
- *ptr = '\0';
-
- if (ch == '<')
- ungetc(ch, fp);
-
- t->element = ELEMENT_FRAGMENT;
- t->data = strdup(s);
- }
-
- /*
- * If the p tree pointer is not NULL and this is the first
- * entry we've read, set the child pointer...
- */
-
- if (p != NULL && prev == NULL)
- p->child = t;
-
- if (p != NULL)
- p->last_child = t;
-
- /*
- * Do the prev/next links...
- */
-
- t->parent = p;
- t->prev = prev;
- if (prev != NULL)
- prev->next = t;
- else
- tree = t;
-
- prev = t;
-
- /*
- * Do child stuff as needed...
- */
-
- if (closech == '>')
- t->child = formRead(t, fp);
- }
-
- return (tree);
-}
-
-
-/*
- * 'formSetAttr()' - Set a node attribute.
- */
-
-void
-formSetAttr(tree_t *t, /* I - Tree node */
- const char *name, /* I - Attribute name */
- const char *value) /* I - Attribute value */
-{
-}
-
-
-/*
- * 'compare_attr()' - Compare two attributes.
- */
-
-static int /* O - -1 if a0 < a1, etc. */
-compare_attr(attr_t *a0, /* I - First attribute */
- attr_t *a1) /* I - Second attribute */
-{
- return (strcasecmp(a0->name, a1->name));
-}
-
-
-/*
- * 'compare_elements()' - Compare two elements.
- */
-
-static int /* O - -1 if e0 < e1, etc. */
-compare_elements(char **e0, /* I - First element */
- char **e1) /* I - Second element */
-{
- return (strcasecmp(*e0, *e1));
-}
-
-
-/*
- * 'parse_attr()' - Parse an element attribute string.
- */
-
-static int /* O - -1 on error, 0 on success */
-parse_attr(tree_t *t, /* I - Current tree node */
- FILE *fp) /* I - Input file */
-{
- char name[1024], /* Name of attr */
- value[10240], /* Value of attr */
- *ptr; /* Temporary pointer */
- int ch; /* Character from file */
-
-
- ptr = name;
- while ((ch = getc(fp)) != EOF)
- if (isalnum(ch & 255))
- {
- if (ptr < (name + sizeof(name) - 1))
- *ptr++ = ch;
- }
- else
- break;
-
- *ptr = '\0';
-
- while (isspace(ch & 255) || ch == '\r')
- ch = getc(fp);
-
- switch (ch)
- {
- default :
- ungetc(ch, fp);
- return (formSetAttr(t, name, NULL));
- case EOF :
- return (-1);
- case '=' :
- ptr = value;
- ch = getc(fp);
-
- while (isspace(ch & 255) || ch == '\r')
- ch = getc(fp);
-
- if (ch == EOF)
- return (-1);
-
- if (ch == '\'')
- {
- while ((ch = getc(fp)) != EOF)
- if (ch == '\'')
- break;
- else if (ptr < (value + sizeof(value) - 1))
- *ptr++ = ch;
-
- *ptr = '\0';
- }
- else if (ch == '\"')
- {
- while ((ch = getc(fp)) != EOF)
- if (ch == '\"')
- break;
- else if (ptr < (value + sizeof(value) - 1))
- *ptr++ = ch;
-
- *ptr = '\0';
- }
- else
- {
- *ptr++ = ch;
- while ((ch = getc(fp)) != EOF)
- if (isspace(ch & 255) || ch == '>' || ch == '/' || ch == '\r')
- break;
- else if (ptr < (value + sizeof(value) - 1))
- *ptr++ = ch;
-
- *ptr = '\0';
- if (ch == '>' || ch == '/')
- ungetc(ch, fp);
- }
-
- return (formSetAttr(t, name, value));
- }
-}
-
-
-/*
- * 'parse_element()' - Parse an element.
- */
-
-static int /* O - -1 on error or ELEMENT_nnnn */
-parse_element(tree_t *t, /* I - Current tree node */
- FILE *fp) /* I - Input file */
-{
- int ch; /* Character from file */
- char element[255], /* Element string... */
- *eptr, /* Current character... */
- comment[10240], /* Comment string */
- *cptr, /* Current char... */
- **temp; /* Element variable entry */
-
-
- eptr = element;
-
- while ((ch = getc(fp)) != EOF && eptr < (element + sizeof(element) - 1))
- if (ch == '>' || ch == '/' || isspace(ch & 255))
- break;
- else
- *eptr++ = ch;
-
- *eptr = '\0';
-
- if (ch == EOF)
- return (ELEMENT_ERROR);
-
- eptr = element;
- temp = bsearch(&mptr, elements, sizeof(elements) / sizeof(elements[0]),
- sizeof(elements[0]),
- (int (*)(const void *, const void *))compare_elements);
-
- if (temp == NULL)
- {
- /*
- * Unrecognized element stuff...
- */
-
- t->element = ELEMENT_COMMENT;
- strcpy(comment, element);
- cptr = comment + strlen(comment);
- }
- else
- {
- t->element = (element_t)((char **)temp - elements);
- cptr = comment;
- }
-
- if (t->element == ELEMENT_COMMENT)
- {
- while (ch != EOF && ch != '>' && cptr < (comment + sizeof(comment) - 1))
- {
- *cptr++ = ch;
- ch = getc(fp);
- }
-
- *cptr = '\0';
- t->data = strdup(comment);
- }
- else
- {
- while (ch != EOF && ch != '>' && ch != '/')
- {
- if (!isspace(ch & 255))
- {
- ungetc(ch, fp);
- parse_variable(t, fp);
- }
-
- ch = getc(fp);
- }
-
- if (ch != EOF)
- ungetc(ch, fp);
- }
-
- return (t->element);
-}
-
-
-/*
- * End of "$Id: form-tree.c 6649 2007-07-11 21:46:42Z mike $".
- */
+++ /dev/null
-/*
- * "$Id: form.h 6649 2007-07-11 21:46:42Z mike $"
- *
- * CUPS form header file for the Common UNIX Printing System (CUPS).
- *
- * Copyright 2007 by Apple Inc.
- * Copyright 1997-2005 by Easy Software Products.
- *
- * These coded instructions, statements, and computer programs are the
- * property of Apple Inc. and are protected by Federal copyright
- * law. Distribution and use rights are outlined in the file "LICENSE.txt"
- * which should have been included with this file. If this file is
- * file is missing or damaged, see the license at "http://www.cups.org/".
- *
- * This file is subject to the Apple OS-Developed Software exception.
- */
-
-/*
- * Include necessary headers...
- */
-
-#include "common.h"
-
-
-/*
- * Form elements...
- */
-
-typedef enum
-{
- ELEMENT_FILE = -1, /* Pseudo element, not in file, but above */
- ELEMENT_FRAGMENT, /* Text fragment */
- ELEMENT_COMMENT, /* <!-- .... --> */
- ELEMENT_ARC,
- ELEMENT_BOX,
- ELEMENT_BR,
- ELEMENT_B,
- ELEMENT_CUPSFORM,
- ELEMENT_DEFVAR,
- ELEMENT_FONT,
- ELEMENT_H1,
- ELEMENT_H2,
- ELEMENT_H3,
- ELEMENT_H4,
- ELEMENT_H5,
- ELEMENT_H6,
- ELEMENT_HEAD,
- ELEMENT_IMG,
- ELEMENT_I,
- ELEMENT_LINE,
- ELEMENT_PAGE,
- ELEMENT_PIE,
- ELEMENT_POLY,
- ELEMENT_PRE,
- ELEMENT_P,
- ELEMENT_RECT,
- ELEMENT_TEXT,
- ELEMENT_TT,
- ELEMENT_VAR
-} element_t;
-
-
-/*
- * Font styles...
- */
-
-typedef enum
-{
- STYLE_NORMAL,
- STYLE_BOLD,
- STYLE_ITALIC,
- STYLE_BOLD_ITALIC
-} style_t;
-
-
-/*
- * Text alignments...
- */
-
-typedef enum
-{
- HALIGN_LEFT,
- HALIGN_CENTER,
- HALIGN_RIGHT
-} halign_t;
-
-typedef enum
-{
- VALIGN_BOTTOM,
- VALIGN_CENTER,
- VALIGN_TOP
-} valign_t;
-
-
-/*
- * Text directions...
- */
-
-typedef enun
-{
- DIR_LEFT_TO_RIGHT,
- DIR_RIGHT_TO_LEFT
-} dir_t;
-
-
-/*
- * Attribute structure...
- */
-
-typedef struct
-{
- char *name, /* Name of attribute */
- *value; /* Value of attribute */
-} attr_t;
-
-
-/*
- * Form document tree structure...
- */
-
-typedef struct tree_str
-{
- struct tree_str *prev, /* Previous tree node */
- *next, /* Next tree node */
- *parent, /* Parent tree node */
- *child, /* First child node */
- *last_child; /* Last child node */
- element_t element; /* Element type */
- float x, y, w, h; /* Position and size in points */
- float bg[3], fg[3]; /* Colors of element */
- float thickness; /* Thickness of lines */
- int preformatted; /* Preformatted text? */
- float size; /* Height of text in points */
- char *typeface; /* Typeface of text */
- style_t style; /* Style of text */
- halign_t halign; /* Horizontal alignment */
- valign_t valign; /* Vertical alignment */
- dir_t dir; /* Direction of text */
- int num_attrs; /* Number of attributes */
- attr_t *attrs; /* Attributes */
- void *data; /* Text fragment data */
-} tree_t;
-
-
-/*
- * Globals...
- */
-
-extern int NumOptions; /* Number of command-line options */
-extern cups_option_t *Options; /* Command-line options */
-extern ppd_file_t *PPD; /* PPD file */
-
-
-/*
- * Prototypes...
- */
-
-extern void formDelete(tree_t *t);
-extern char *formGetAttr(tree_t *t, const char *name);
-extern tree_t *formNew(tree_t *p);
-extern tree_t *formRead(FILE *fp, tree_t *p);
-extern void formSetAttr(tree_t *t, const char *name, const char *value);
-extern void formWrite(tree_t *p);
-
-
-/*
- * End of "$Id: form.h 6649 2007-07-11 21:46:42Z mike $".
- */
+++ /dev/null
-/*
- * "$Id: hpgl-attr.c 6649 2007-07-11 21:46:42Z mike $"
- *
- * HP-GL/2 attribute processing for the Common UNIX Printing System (CUPS).
- *
- * Copyright 2007-2008 by Apple Inc.
- * Copyright 1993-2007 by Easy Software Products.
- *
- * These coded instructions, statements, and computer programs are the
- * property of Apple Inc. and are protected by Federal copyright
- * law. Distribution and use rights are outlined in the file "LICENSE.txt"
- * which should have been included with this file. If this file is
- * file is missing or damaged, see the license at "http://www.cups.org/".
- *
- * This file is subject to the Apple OS-Developed Software exception.
- *
- * Contents:
- *
- * CR_color_range() - Set the range for color values.
- * AC_anchor_corner() - Set the anchor corner.
- * FT_fill_type() - Set the fill type or pattern.
- * LA_line_attributes() - Set the line drawing attributes.
- * LT_line_type() - Set the line type (style)...
- * NP_number_pens() - Set the number of pens to be used.
- * PC_pen_color() - Set the pen color...
- * PW_pen_width() - Set the pen width.
- * RF_raster_fill() - Set the raster fill pattern.
- * SM_symbol_mode() - Set where symbols are drawn.
- * SP_select_pen() - Select a pen for drawing.
- * UL_user_line_type() - Set a user-defined line type.
- * WU_width_units() - Set the units used for pen widths.
- */
-
-/*
- * Include necessary headers...
- */
-
-#include "hpgltops.h"
-
-
-/*
- * 'CR_color_range()' - Set the range for color values.
- */
-
-void
-CR_color_range(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- if (num_params == 0)
- {
- /*
- * Default to 0 to 255 for all color values.
- */
-
- ColorRange[0][0] = 0.0;
- ColorRange[0][1] = 255.0;
- ColorRange[1][0] = 0.0;
- ColorRange[1][1] = 255.0;
- ColorRange[2][0] = 0.0;
- ColorRange[2][1] = 255.0;
- }
- else if (num_params == 6)
- {
- /*
- * Set the range based on the parameters...
- */
-
- ColorRange[0][0] = params[0].value.number;
- ColorRange[0][1] = params[1].value.number - params[0].value.number;
- ColorRange[1][0] = params[2].value.number;
- ColorRange[1][1] = params[3].value.number - params[2].value.number;
- ColorRange[2][0] = params[4].value.number;
- ColorRange[2][1] = params[5].value.number - params[4].value.number;
- }
- else
- fprintf(stderr,
- "DEBUG: HP-GL/2 \'CR\' command with invalid number of "
- "parameters (%d)!\n", num_params);
-}
-
-
-/*
- * 'AC_anchor_corner()' - Set the anchor corner.
- */
-
-void
-AC_anchor_corner(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- (void)num_params;
- (void)params;
-}
-
-
-/*
- * 'FT_fill_type()' - Set the fill type or pattern.
- *
- * Note:
- *
- * This needs to be updated to support non-solid fill.
- */
-
-void
-FT_fill_type(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- if (num_params == 0 ||
- params[0].value.number == 1 ||
- params[0].value.number == 2)
- {
- /**** SOLID PATTERN ****/
- }
-}
-
-
-/*
- * 'LA_line_attributes()' - Set the line drawing attributes.
- */
-
-void
-LA_line_attributes(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- int i; /* Looping var */
-
-
- if (num_params == 0)
- {
- MiterLimit = 3.0f;
- LineCap = 0;
- LineJoin = 0;
- }
- else for (i = 0; i < (num_params - 1); i += 2)
- switch ((int)params[i].value.number)
- {
- case 1 :
- LineCap = params[i + 1].value.number == 1 ? 0 :
- params[i + 1].value.number == 4 ? 1 : 2;
- break;
- case 2 :
- switch ((int)params[i + 1].value.number)
- {
- case 1 :
- case 2 :
- case 3 :
- LineJoin = 0;
- break;
- case 5 :
- LineJoin = 2;
- break;
- default :
- LineJoin = 1;
- break;
- }
- break;
- case 3 :
- MiterLimit = 1.0 + 0.5 * (params[i + 1].value.number - 1.0);
- break;
- }
-
- if (PageDirty)
- {
- printf("%.1f setmiterlimit\n", MiterLimit);
- printf("%d setlinecap\n", LineCap);
- printf("%d setlinejoin\n", LineJoin);
- }
-}
-
-
-/*
- * 'LT_line_type()' - Set the line type (style)...
- *
- * Note:
- *
- * This needs to be updated to support line types.
- */
-
-void
-LT_line_type(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- (void)num_params;
- (void)params;
-}
-
-
-/*
- * 'NP_number_pens()' - Set the number of pens to be used.
- */
-
-void
-NP_number_pens(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- int i; /* Looping var */
-
-
- if (num_params == 0)
- PenCount = 8;
- else if (num_params == 1)
- {
- if (params[0].value.number < 1 || params[0].value.number > MAX_PENS)
- {
- fprintf(stderr,
- "DEBUG: HP-GL/2 \'NP\' command with invalid number of "
- "pens (%d)!\n", (int)params[0].value.number);
- PenCount = 8;
- }
- else
- PenCount = (int)params[0].value.number;
- }
- else
- fprintf(stderr,
- "DEBUG: HP-GL/2 \'NP\' command with invalid number of "
- "parameters (%d)!\n", num_params);
-
- for (i = 0; i < PenCount; i ++)
- Pens[i].width = PenWidth;
-
- PC_pen_color(0, NULL);
-}
-
-
-/*
- * 'PC_pen_color()' - Set the pen color...
- */
-
-void
-PC_pen_color(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- int i; /* Looping var */
- static float standard_colors[8][3] = /* Standard colors for first 8 pens */
- {
- { 0.0, 0.0, 0.0 }, /* Black */
- { 1.0, 0.0, 0.0 }, /* Red */
- { 0.0, 1.0, 0.0 }, /* Green */
- { 1.0, 1.0, 0.0 }, /* Yellow */
- { 0.0, 0.0, 1.0 }, /* Blue */
- { 1.0, 0.0, 1.0 }, /* Magenta */
- { 0.0, 1.0, 1.0 }, /* Cyan */
- { 1.0, 1.0, 1.0 } /* White */
- };
-
-
- if (num_params == 0)
- {
- for (i = 0; i < PenCount; i ++)
- if (i < 8)
- {
- Pens[i].rgb[0] = standard_colors[i][0];
- Pens[i].rgb[1] = standard_colors[i][1];
- Pens[i].rgb[2] = standard_colors[i][2];
- }
- else
- {
- Pens[i].rgb[0] = 0.0f;
- Pens[i].rgb[1] = 0.0f;
- Pens[i].rgb[2] = 0.0f;
- }
-
- if (PageDirty)
- printf("%.3f %.3f %.3f %.2f SP\n", Pens[PenNumber].rgb[0],
- Pens[PenNumber].rgb[1], Pens[PenNumber].rgb[2],
- Pens[PenNumber].width * PenScaling);
- }
- else if (num_params == 1 || num_params == 4)
- {
- i = (int)params[0].value.number - 1;
-
- if (i < 0 || i >= PenCount)
- {
- fprintf(stderr,
- "DEBUG: HP-GL/2 \'PC\' command with invalid pen (%d)!\n", i + 1);
- return;
- }
-
- if (num_params == 1)
- {
- Pens[i].rgb[0] = standard_colors[i & 7][0];
- Pens[i].rgb[1] = standard_colors[i & 7][1];
- Pens[i].rgb[2] = standard_colors[i & 7][2];
- }
- else
- {
- Pens[i].rgb[0] = (params[1].value.number - ColorRange[0][0]) /
- (ColorRange[0][1] - ColorRange[0][0]);
- Pens[i].rgb[1] = (params[2].value.number - ColorRange[1][0]) /
- (ColorRange[1][1] - ColorRange[1][0]);
- Pens[i].rgb[2] = (params[3].value.number - ColorRange[2][0]) /
- (ColorRange[2][1] - ColorRange[2][0]);
-
- fprintf(stderr, "DEBUG: Pen %d %.0f %.0f %.0f = %.3f %.3f %.3f\n",
- i, params[1].value.number, params[2].value.number,
- params[3].value.number, Pens[i].rgb[0], Pens[i].rgb[1],
- Pens[i].rgb[2]);
- }
-
- if (PageDirty && i == PenNumber)
- printf("%.3f %.3f %.3f %.2f SP\n", Pens[PenNumber].rgb[0],
- Pens[PenNumber].rgb[1], Pens[PenNumber].rgb[2],
- Pens[PenNumber].width * PenScaling);
- }
- else
- fprintf(stderr,
- "DEBUG: HP-GL/2 \'PC\' command with invalid number of "
- "parameters (%d)!\n", num_params);
-}
-
-
-/*
- * 'PW_pen_width()' - Set the pen width.
- */
-
-void
-PW_pen_width(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- int pen; /* Pen number */
- float w; /* Width value */
-
-
- if (WidthUnits == 0)
- {
- /*
- * Metric...
- */
-
- if (num_params == 0)
- w = 0.35f / 25.4f * 72.0f;
- else
- w = params[0].value.number / 25.4f * 72.0f;
- }
- else
- {
- /*
- * Relative...
- */
-
- w = (float)hypot(PlotSize[0], PlotSize[1]) / 1016.0f * 72.0f;
-
- if (num_params == 0)
- w *= 0.01f;
- else
- w *= params[0].value.number;
- }
-
- if (num_params == 2)
- {
- pen = (int)params[1].value.number - 1;
-
- if (pen < 0 || pen >= PenCount)
- {
- fprintf(stderr,
- "DEBUG: HP-GL/2 \'PW\' command with invalid pen (%d)!\n",
- pen + 1);
- return;
- }
-
- Pens[pen].width = w;
-
- if (PageDirty && pen == PenNumber)
- printf("%.3f %.3f %.3f %.2f SP\n", Pens[PenNumber].rgb[0],
- Pens[PenNumber].rgb[1], Pens[PenNumber].rgb[2],
- Pens[PenNumber].width * PenScaling);
- }
- else if (num_params < 2)
- {
- /*
- * Set width for all pens...
- */
-
- for (pen = 0; pen < PenCount; pen ++)
- Pens[pen].width = w;
-
- if (PageDirty)
- printf("%.3f %.3f %.3f %.2f SP\n", Pens[PenNumber].rgb[0],
- Pens[PenNumber].rgb[1], Pens[PenNumber].rgb[2],
- Pens[PenNumber].width * PenScaling);
- }
- else
- fprintf(stderr,
- "DEBUG: HP-GL/2 \'PW\' command with invalid number of "
- "parameters (%d)!\n", num_params);
-}
-
-
-/*
- * 'RF_raster_fill()' - Set the raster fill pattern.
- *
- * Note:
- *
- * This needs to be implemented.
- */
-
-void
-RF_raster_fill(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- (void)num_params;
- (void)params;
-}
-
-
-/*
- * 'SM_symbol_mode()' - Set where symbols are drawn.
- */
-
-void
-SM_symbol_mode(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- (void)num_params;
- (void)params;
-}
-
-
-/*
- * 'SP_select_pen()' - Select a pen for drawing.
- */
-
-void
-SP_select_pen(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- if (num_params == 0)
- PenNumber = 0;
- else if (num_params > 1)
- fprintf(stderr,
- "DEBUG: HP-GL/2 \'SP\' command with invalid number of parameters "
- "(%d)!\n", num_params);
- else if (params[0].value.number <= 0 || params[0].value.number >= PenCount)
- fprintf(stderr, "DEBUG: HP-GL/2 \'SP\' command with invalid pen (%d)!\n",
- (int)params[0].value.number);
- else
- PenNumber = (int)params[0].value.number - 1;
-
- if (PageDirty)
- printf("%.3f %.3f %.3f %.2f SP\n", Pens[PenNumber].rgb[0],
- Pens[PenNumber].rgb[1], Pens[PenNumber].rgb[2],
- Pens[PenNumber].width * PenScaling);
-}
-
-
-/*
- * 'UL_user_line_type()' - Set a user-defined line type.
- */
-
-void
-UL_user_line_type(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- (void)num_params;
- (void)params;
-}
-
-
-/*
- * 'WU_width_units()' - Set the units used for pen widths.
- */
-
-void
-WU_width_units(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- if (num_params == 0)
- WidthUnits = 0;
- else if (num_params == 1)
- WidthUnits = (int)params[0].value.number;
- else
- fprintf(stderr,
- "DEBUG: HP-GL/2 \'WU\' command with invalid number of "
- "parameters (%d)!\n", num_params);
-}
-
-
-/*
- * End of "$Id: hpgl-attr.c 6649 2007-07-11 21:46:42Z mike $".
- */
+++ /dev/null
-/*
- * "$Id: hpgl-char.c 6649 2007-07-11 21:46:42Z mike $"
- *
- * HP-GL/2 character processing for the Common UNIX Printing System (CUPS).
- *
- * Copyright 2007 by Apple Inc.
- * Copyright 1993-2005 by Easy Software Products.
- *
- * These coded instructions, statements, and computer programs are the
- * property of Apple Inc. and are protected by Federal copyright
- * law. Distribution and use rights are outlined in the file "LICENSE.txt"
- * which should have been included with this file. If this file is
- * file is missing or damaged, see the license at "http://www.cups.org/".
- *
- * This file is subject to the Apple OS-Developed Software exception.
- *
- * Contents:
- *
- * AD_define_alternate() - Define the alternate font.
- * CF_character_fill() - Set whether or not to fill or outline
- * characters.
- * CP_character_plot() - Move the current pen position for the given
- * number of columns and rows.
- * DI_absolute_direction() - Set the direction vector for text.
- * DR_relative_direction() - Set the relative direction vector for text.
- * DT_define_label_term() - Set the label string terminator.
- * DV_define_variable_path() - Define a path for text.
- * ES_extra_space() - Set extra spacing (kerning) between characters.
- * LB_label() - Display a label string.
- * LO_label_origin() - Set the label origin.
- * SA_select_alternate() - Select the alternate font.
- * SD_define_standard() - Define the standard font...
- * SI_absolute_size() - Set the absolute size of text.
- * SL_character_slant() - Set the slant of text.
- * SR_relative_size() - Set the relative size of text.
- * SS_select_standard() - Select the standard font for text.
- * TD_transparent_data() - Send transparent print data.
- *
- */
-
-/*
- * Include necessary headers...
- */
-
-#include "hpgltops.h"
-
-
-/*
- * 'define_font()' - Define the specified font...
- */
-
-void
-define_font(int f) /* I - Font number */
-{
- font_t *font; /* Font */
- const char *fstring; /* Font string - SA or SS */
- float xform[2][2]; /* Transform matrix */
-
-
- /*
- * Get the correct font data...
- */
-
- if (f)
- {
- font = &AlternateFont;
- fstring = "SA";
- }
- else
- {
- font = &StandardFont;
- fstring = "SS";
- }
-
- /*
- * Compute the font matrix, accounting for any rotation...
- */
-
- switch (Rotation)
- {
- default :
- case 0 :
- xform[0][0] = font->xpitch * font->x * font->height;
- xform[0][1] = font->xpitch * font->y * font->height;
- xform[1][0] = -font->y * font->height;
- xform[1][1] = font->x * font->height;
- break;
-
- case 90 :
- xform[0][0] = -font->xpitch * font->y * font->height;
- xform[0][1] = font->xpitch * font->x * font->height;
- xform[1][0] = -font->x * font->height;
- xform[1][1] = -font->y * font->height;
- break;
-
- case 180 :
- xform[0][0] = -font->xpitch * font->x * font->height;
- xform[0][1] = -font->xpitch * font->y * font->height;
- xform[1][0] = font->y * font->height;
- xform[1][1] = -font->x * font->height;
- break;
-
- case 270 :
- xform[0][0] = font->xpitch * font->y * font->height;
- xform[0][1] = -font->xpitch * font->x * font->height;
- xform[1][0] = font->x * font->height;
- xform[1][1] = font->y * font->height;
- break;
- }
-
- /*
- * Send the font definition...
- */
-
- printf("/%s {\n"
- " /%s%s%s%s findfont\n"
- " [ %f %f %f %f 0.0 0.0 ] makefont\n"
- " setfont\n"
- "} bind def\n",
- fstring, font->spacing ? "Helvetica" : "Courier",
- (font->weight > 0 || font->posture) ? "-" : "",
- font->weight > 0 ? "Bold" : "",
- font->posture ? "Oblique" : "",
- xform[0][0], xform[0][1], xform[1][0], xform[1][1]);
-
- if (f == CharFont)
- printf("%s\n", fstring);
-}
-
-
-/*
- * 'AD_define_alternate()' - Define the alternate font.
- */
-
-void
-AD_define_alternate(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- int i; /* Looping var */
-
-
- /*
- * Set default font attributes...
- */
-
- AlternateFont.symbol_set = 277;
- AlternateFont.spacing = 0;
- AlternateFont.pitch = 9;
- AlternateFont.height = 11.5;
- AlternateFont.posture = 0;
- AlternateFont.weight = 0;
- AlternateFont.typeface = 48;
- AlternateFont.x = 1.0;
- AlternateFont.y = 0.0;
-
- /*
- * Loop through parameter value pairs...
- */
-
- for (i = 0; i < (num_params - 1); i += 2)
- switch ((int)params[i].value.number)
- {
- case 1 : /* Symbol Set */
- AlternateFont.symbol_set = (int)params[i + 1].value.number;
- break;
- case 2 : /* Font Spacing */
- AlternateFont.spacing = (int)params[i + 1].value.number;
- break;
- case 3 : /* Pitch */
- AlternateFont.pitch = params[i + 1].value.number;
- break;
- case 4 : /* Height */
- AlternateFont.height = params[i + 1].value.number;
- break;
- case 5 : /* Posture */
- AlternateFont.posture = (int)params[i + 1].value.number;
- break;
- case 6 : /* Stroke Weight */
- AlternateFont.weight = (int)params[i + 1].value.number;
- break;
- case 7 : /* Typeface */
- AlternateFont.typeface = (int)params[i + 1].value.number;
- break;
- }
-
- if (AlternateFont.spacing)
- {
- /*
- * Set proportional spacing font...
- */
-
- AlternateFont.xpitch = 1.0f;
- }
- else
- {
- /*
- * Set fixed-spaced font...
- */
-
- AlternateFont.xpitch = 0.6f * AlternateFont.height / AlternateFont.pitch;
- }
-
- /*
- * Define the font...
- */
-
- if (PageDirty)
- {
- printf("%% AD");
- for (i = 0; i < num_params; i ++)
- if (i)
- printf(",%g", params[i].value.number);
- else
- printf("%g", params[i].value.number);
- puts(";");
-
- define_font(1);
- }
-
- CharHeight[1] = AlternateFont.height;
-}
-
-
-/*
- * 'CF_character_fill()' - Set whether or not to fill or outline characters.
- */
-
-void
-CF_character_fill(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- if (num_params == 0)
- CharFillMode = 0;
- else
- CharFillMode = (int)params[0].value.number;
-
- if (num_params == 2)
- CharPen = (int)params[1].value.number;
-}
-
-
-/*
- * 'CP_character_plot()' - Move the current pen position for the given number
- * of columns and rows.
- */
-
-void
-CP_character_plot(int num_params,
- param_t *params)
-{
- if (num_params < 2)
- return;
-
- switch (Rotation)
- {
- case 0:
- PenPosition[0] += params[0].value.number * 1.2f / CharHeight[CharFont];
- PenPosition[1] += params[1].value.number * CharHeight[CharFont];
- break;
- case 90:
- PenPosition[0] -= params[1].value.number * 1.2f / CharHeight[CharFont];
- PenPosition[1] += params[0].value.number * CharHeight[CharFont];
- break;
- case 180:
- PenPosition[0] -= params[0].value.number * 1.2f / CharHeight[CharFont];
- PenPosition[1] -= params[1].value.number * CharHeight[CharFont];
- break;
- case 270:
- PenPosition[0] += params[1].value.number * 1.2f / CharHeight[CharFont];
- PenPosition[1] -= params[0].value.number * CharHeight[CharFont];
- break;
- }
-}
-
-
-/*
- * 'DI_absolute_direction()' - Set the direction vector for text.
- */
-
-void
-DI_absolute_direction(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- if (num_params != 2)
- return;
-
- if (CharFont)
- {
- AlternateFont.x = params[0].value.number;
- AlternateFont.y = params[1].value.number;
- }
- else
- {
- StandardFont.x = params[0].value.number;
- StandardFont.y = params[1].value.number;
- }
-
- if (PageDirty)
- {
- printf("%% DI%g,%g\n", params[0].value.number, params[1].value.number);
-
- define_font(CharFont);
- }
-}
-
-
-/*
- * 'DR_relative_direction()' - Set the relative direction vector for text.
- */
-
-void
-DR_relative_direction(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- (void)num_params;
- (void)params;
-}
-
-
-/*
- * 'DT_define_label_term()' - Set the label string terminator.
- */
-
-void
-DT_define_label_term(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- if (num_params == 0)
- StringTerminator = '\003';
- else
- StringTerminator = params[0].value.string[0];
-}
-
-
-/*
- * 'DV_define_variable_path()' - Define a path for text.
- */
-
-void
-DV_define_variable_path(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- (void)num_params;
- (void)params;
-}
-
-
-/*
- * 'ES_extra_space()' - Set extra spacing (kerning) between characters.
- */
-
-void
-ES_extra_space(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- (void)num_params;
- (void)params;
-}
-
-
-/*
- * 'LB_label()' - Display a label string.
- */
-
-void
-LB_label(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- char *s; /* Pointer into string */
-
-
- if (num_params == 0)
- return;
-
- Outputf("gsave\n");
- Outputf("currentmiterlimit 1.0 setmiterlimit\n");
- Outputf("MP\n");
- Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]);
- PenValid = 1;
-
- Outputf("(");
- for (s = params[0].value.string; *s != '\0'; s ++)
- if (strchr("()\\", *s) != NULL)
- Outputf("\\%c", *s);
- else
- Outputf("%c", *s);
- Outputf(") true charpath\n");
-
- if (CharFillMode != 1)
- Outputf("FI\n");
- if (CharFillMode == 1 || CharFillMode == 3)
- {
- Outputf("%.3f %.3f %.3f %.2f SP ST\n", Pens[CharPen].rgb[0],
- Pens[CharPen].rgb[CharPen], Pens[CharPen].rgb[2],
- Pens[CharPen].width * PenScaling);
- Outputf("%.3f %.3f %.3f %.2f SP\n", Pens[PenNumber].rgb[0],
- Pens[PenNumber].rgb[1], Pens[PenNumber].rgb[2],
- Pens[PenNumber].width * PenScaling);
- }
-
- Outputf("setmiterlimit\n");
- Outputf("grestore\n");
-}
-
-
-/*
- * 'LO_label_origin()' - Set the label origin.
- */
-
-void
-LO_label_origin(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- (void)num_params;
- (void)params;
-}
-
-
-/*
- * 'SA_select_alternate()' - Select the alternate font.
- */
-
-void
-SA_select_alternate(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- (void)num_params;
- (void)params;
-
- if (PageDirty)
- puts("SA");
-
- CharFont = 1;
-}
-
-
-/*
- * 'SD_define_standard()' - Define the standard font...
- */
-
-void
-SD_define_standard(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- int i; /* Looping var */
-
-
- /*
- * Set default font attributes...
- */
-
- StandardFont.symbol_set = 277;
- StandardFont.spacing = 0;
- StandardFont.pitch = 9;
- StandardFont.height = 11.5;
- StandardFont.posture = 0;
- StandardFont.weight = 0;
- StandardFont.typeface = 48;
- StandardFont.x = 1.0;
- StandardFont.y = 0.0;
-
- /*
- * Loop through parameter value pairs...
- */
-
- for (i = 0; i < (num_params - 1); i += 2)
- switch ((int)params[i].value.number)
- {
- case 1 : /* Symbol Set */
- StandardFont.symbol_set = (int)params[i + 1].value.number;
- break;
- case 2 : /* Font Spacing */
- StandardFont.spacing = (int)params[i + 1].value.number;
- break;
- case 3 : /* Pitch */
- StandardFont.pitch = params[i + 1].value.number;
- break;
- case 4 : /* Height */
- StandardFont.height = params[i + 1].value.number;
- break;
- case 5 : /* Posture */
- StandardFont.posture = (int)params[i + 1].value.number;
- break;
- case 6 : /* Stroke Weight */
- StandardFont.weight = (int)params[i + 1].value.number;
- break;
- case 7 : /* Typeface */
- StandardFont.typeface = (int)params[i + 1].value.number;
- break;
- }
-
- if (StandardFont.spacing || StandardFont.pitch <= 0.0)
- {
- /*
- * Set proportional spacing font...
- */
-
- StandardFont.xpitch = 1.0f;
- }
- else
- {
- /*
- * Set fixed-spaced font...
- */
-
- StandardFont.xpitch = 0.6f * StandardFont.height / StandardFont.pitch;
- }
-
- /*
- * Define the font...
- */
-
- if (PageDirty)
- {
- printf("%% SD");
- for (i = 0; i < num_params; i ++)
- if (i)
- printf(",%g", params[i].value.number);
- else
- printf("%g", params[i].value.number);
- puts(";");
-
- define_font(0);
- }
-
- CharHeight[0] = StandardFont.height;
-}
-
-
-/*
- * 'SI_absolute_size()' - Set the absolute size of text.
- */
-
-void
-SI_absolute_size(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- float xsize, ysize; /* Font size... */
-
-
- if (num_params != 2)
- return;
-
- /*
- * The "SI" values are supposed to be cm, but they appear to be inches
- * when tested on real HP devices...
- */
-
- xsize = params[0].value.number * 72.0f;
- ysize = params[1].value.number * 72.0f * 0.6f;
-
- if (CharFont)
- {
- AlternateFont.xpitch = xsize / ysize;
- AlternateFont.height = ysize;
- }
- else
- {
- StandardFont.xpitch = xsize / ysize;
- StandardFont.height = ysize;
- }
-
- if (PageDirty)
- {
- printf("%% SI%g,%g\n", params[0].value.number, params[1].value.number);
-
- define_font(CharFont);
- }
-}
-
-
-/*
- * 'SL_character_slant()' - Set the slant of text.
- */
-
-void
-SL_character_slant(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- (void)num_params;
- (void)params;
-}
-
-
-/*
- * 'SR_relative_size()' - Set the relative size of text.
- */
-
-void
-SR_relative_size(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- (void)num_params;
- (void)params;
-}
-
-
-/*
- * 'SS_select_standard()' - Select the standard font for text.
- */
-
-void
-SS_select_standard(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- (void)num_params;
- (void)params;
-
- if (PageDirty)
- puts("SS");
-
- CharFont = 0;
-}
-
-
-/*
- * 'TD_transparent_data()' - Send transparent print data.
- */
-
-void
-TD_transparent_data(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- (void)num_params;
- (void)params;
-}
-
-
-/*
- * End of "$Id: hpgl-char.c 6649 2007-07-11 21:46:42Z mike $".
- */
+++ /dev/null
-/*
- * "$Id: hpgl-config.c 6649 2007-07-11 21:46:42Z mike $"
- *
- * HP-GL/2 configuration routines for the Common UNIX Printing System (CUPS).
- *
- * Copyright 2007 by Apple Inc.
- * Copyright 1993-2005 by Easy Software Products.
- *
- * These coded instructions, statements, and computer programs are the
- * property of Apple Inc. and are protected by Federal copyright
- * law. Distribution and use rights are outlined in the file "LICENSE.txt"
- * which should have been included with this file. If this file is
- * file is missing or damaged, see the license at "http://www.cups.org/".
- *
- * This file is subject to the Apple OS-Developed Software exception.
- *
- * Contents:
- *
- * update_transform() - Update the page transformation matrix as needed.
- * BP_begin_plot() - Start a plot...
- * DF_default_values() - Set all state info to the default values.
- * IN_initialize() - Initialize the plotter.
- * IP_input_absolute() - Set P1 and P2 values for the plot.
- * IR_input_relative() - Update P1 and P2.
- * IW_input_window() - Setup an input window.
- * PG_advance_page() - Eject the current page.
- * PS_plot_size() - Set the plot size.
- * RO_rotate() - Rotate the plot.
- * RP_replot() - Replot the current page.
- * SC_scale() - Set user-defined scaling.
- */
-
-/*
- * Include necessary headers...
- */
-
-#include "hpgltops.h"
-
-#define max(a,b) ((a) < (b) ? (b) : (a))
-
-
-/*
- * 'update_transform()' - Update the page transformation matrix as needed.
- */
-
-void
-update_transform(void)
-{
- float page_width, /* Actual page width */
- page_height; /* Actual page height */
- float scaling; /* Scaling factor */
- float left, right, /* Scaling window */
- bottom, top;
- float width, height; /* Scaling width and height */
- float iw1[2], iw2[2]; /* Clipping window */
-
-
- /*
- * Get the page and input window sizes...
- */
-
- if (FitPlot)
- {
- page_width = PageRight - PageLeft;
- page_height = PageTop - PageBottom;
- }
- else
- {
- page_width = (P2[0] - P1[0]) * 72.0f / 1016.0f;
- page_height = (P2[1] - P1[1]) * 72.0f / 1016.0f;
- }
-
- fprintf(stderr, "DEBUG: page_width = %.0f, page_height = %.0f\n",
- page_width, page_height);
-
- if (page_width == 0 || page_height == 0)
- return;
-
- /*
- * Set the scaling window...
- */
-
- switch (ScalingType)
- {
- default : /* No user scaling */
- left = P1[0];
- bottom = P1[1];
- right = P2[0];
- top = P2[1];
- break;
-
- case 0 : /* Anisotropic (non-uniform) scaling */
- left = Scaling1[0];
- bottom = Scaling1[1];
- right = Scaling2[0];
- top = Scaling2[1];
- break;
-
- case 1 : /* Isotropic (uniform) scaling */
- left = Scaling1[0];
- bottom = Scaling1[1];
- right = Scaling2[0];
- top = Scaling2[1];
-
- width = right - left;
- height = top - bottom;
-
- if (width == 0 || height == 0)
- return;
-
- if ((width * page_height) != (height * page_width))
- {
- scaling = height * page_width / page_height;
- if (width < scaling)
- {
- width = scaling;
- left = 0.5f * (left + right - width);
- right = left + width;
- }
- else
- {
- height = width * page_height / page_width;
- bottom = 0.5f * (bottom + top - height);
- top = bottom + height;
- }
- }
- break;
-
- case 2 :
- left = Scaling1[0];
- bottom = Scaling1[1];
- right = left + page_width * Scaling2[0] * 1016.0f / 72.0f;
- top = bottom + page_height * Scaling2[1] * 1016.0f / 72.0f;
- break;
- }
-
- width = right - left;
- height = top - bottom;
-
- if (width == 0 || height == 0)
- return;
-
- /*
- * Scale the plot as needed...
- */
-
- if (Rotation == 0 || Rotation == 180)
- scaling = page_width / width;
- else
- scaling = page_width / height;
-
- if (FitPlot)
- scaling *= max(page_width, page_height) / max(PlotSize[1], PlotSize[0]);
-
- /*
- * Offset for the current P1 location...
- */
-
- if (FitPlot)
- {
- left = 0;
- bottom = 0;
- }
- else
- {
- left = P1[0] * 72.0f / 1016.0f;
- bottom = P1[1] * 72.0f / 1016.0f;
- }
-
- /*
- * Generate a new transformation matrix...
- */
-
- switch (Rotation)
- {
- default :
- case 0 :
- Transform[0][0] = scaling;
- Transform[0][1] = 0.0;
- Transform[0][2] = -left;
- Transform[1][0] = 0.0;
- Transform[1][1] = scaling;
- Transform[1][2] = -bottom;
- break;
-
- case 90 :
- Transform[0][0] = 0.0;
- Transform[0][1] = -scaling;
- Transform[0][2] = PageLength - left;
- Transform[1][0] = scaling;
- Transform[1][1] = 0.0;
- Transform[1][2] = -bottom;
- break;
-
- case 180 :
- Transform[0][0] = -scaling;
- Transform[0][1] = 0.0;
- Transform[0][2] = PageLength - left;
- Transform[1][0] = 0.0;
- Transform[1][1] = -scaling;
- Transform[1][2] = PageWidth - bottom;
- break;
-
- case 270 :
- Transform[0][0] = 0.0;
- Transform[0][1] = scaling;
- Transform[0][2] = -left;
- Transform[1][0] = -scaling;
- Transform[1][1] = 0.0;
- Transform[1][2] = PageWidth - bottom;
- break;
- }
-
- fprintf(stderr, "DEBUG: Transform = [ %.3f %.3f\n"
- "DEBUG: %.3f %.3f\n"
- "DEBUG: %.3f %.3f ]\n",
- Transform[0][0], Transform[1][0], Transform[0][1],
- Transform[1][1], Transform[0][2], Transform[1][2]);
-
- if (FitPlot)
- {
- if (Rotation == 0 || Rotation == 180)
- PenScaling = page_width / PlotSize[1];
- else
- PenScaling = page_width / PlotSize[0];
- }
- else
- PenScaling = 1.0;
-
- if (PenScaling < 0.0)
- PenScaling = -PenScaling;
-
- if (PageDirty)
- {
- printf("%.2f setlinewidth\n", Pens[PenNumber].width * PenScaling);
-
- if (IW1[0] != IW2[0] && IW1[1] != IW2[1])
- {
- iw1[0] = IW1[0] * 72.0f / 1016.0f;
- iw1[1] = IW1[1] * 72.0f / 1016.0f;
- iw2[0] = IW2[0] * 72.0f / 1016.0f;
- iw2[1] = IW2[1] * 72.0f / 1016.0f;
-
- printf("initclip MP %.3f %.3f MO %.3f %.3f LI %.3f %.3f LI %.3f %.3f LI CP clip\n",
- iw1[0], iw1[1], iw1[0], iw2[1], iw2[0], iw2[1], iw2[0], iw1[1]);
- }
- }
-}
-
-
-/*
- * 'BP_begin_plot()' - Start a plot...
- */
-
-void
-BP_begin_plot(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- (void)num_params;
- (void)params;
-}
-
-
-/*
- * 'DF_default_values()' - Set all state info to the default values.
- */
-
-void
-DF_default_values(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- (void)num_params;
- (void)params;
-
- NP_number_pens(0, NULL);
- AC_anchor_corner(0, NULL);
- AD_define_alternate(0, NULL);
- SD_define_standard(0, NULL);
- CF_character_fill(0, NULL);
- DI_absolute_direction(0, NULL);
- DT_define_label_term(0, NULL);
- DV_define_variable_path(0, NULL);
- ES_extra_space(0, NULL);
- FT_fill_type(0, NULL);
- IW_input_window(0, NULL);
- LA_line_attributes(0, NULL);
- LO_label_origin(0, NULL);
- LT_line_type(0, NULL);
- PA_plot_absolute(0, NULL);
- PolygonMode = 0;
- RF_raster_fill(0, NULL);
- SC_scale(0, NULL);
- SM_symbol_mode(0, NULL);
- SS_select_standard(0, NULL);
- TD_transparent_data(0, NULL);
- UL_user_line_type(0, NULL);
-}
-
-
-/*
- * 'IN_initialize()' - Initialize the plotter.
- */
-
-void
-IN_initialize(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- (void)num_params;
- (void)params;
-
- DF_default_values(0, NULL);
- PU_pen_up(0, NULL);
- RO_rotate(0, NULL);
- PS_plot_size(0, NULL);
- WU_width_units(0, NULL);
- PW_pen_width(0, NULL);
-
- PenWidth = 1;
-
- PenPosition[0] = PenPosition[1] = 0.0;
-}
-
-
-/*
- * 'IP_input_absolute()' - Set P1 and P2 values for the plot.
- */
-
-void
-IP_input_absolute(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- if (num_params == 0)
- {
- P1[0] = PageLeft / 72.0f * 1016.0f;
- P1[1] = PageBottom / 72.0f * 1016.0f;
- P2[0] = PageRight / 72.0f * 1016.0f;
- P2[1] = PageTop / 72.0f * 1016.0f;
- }
- else if (num_params == 2)
- {
- P2[0] -= P1[0];
- P2[1] -= P1[1];
- P1[0] = params[0].value.number;
- P1[1] = params[1].value.number;
- P2[0] += P1[0];
- P2[1] += P1[1];
- }
- else if (num_params == 4)
- {
- P1[0] = params[0].value.number;
- P1[1] = params[1].value.number;
- P2[0] = params[2].value.number;
- P2[1] = params[3].value.number;
- }
-
- IW1[0] = 0.0;
- IW1[1] = 0.0;
- IW2[0] = 0.0;
- IW2[1] = 0.0;
-
- if (ScalingType < 0)
- {
- Scaling1[0] = P1[0];
- Scaling1[0] = P1[1];
- Scaling2[0] = P2[0];
- Scaling2[1] = P2[1];
- }
-
- update_transform();
-}
-
-
-/*
- * 'IR_input_relative()' - Update P1 and P2.
- */
-
-void
-IR_input_relative(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- if (num_params == 0)
- {
- P1[0] = PageLeft / 72.0f * 1016.0f;
- P1[1] = PageBottom / 72.0f * 1016.0f;
- P2[0] = PageRight / 72.0f * 1016.0f;
- P2[1] = PageTop / 72.0f * 1016.0f;
- }
- else if (num_params == 2)
- {
- P2[0] -= P1[0];
- P2[1] -= P1[1];
- P1[0] = params[0].value.number * PlotSize[0] / 72.0f * 1016.0f / 100.0f;
- P1[1] = params[1].value.number * PlotSize[1] / 72.0f * 1016.0f / 100.0f;
- P2[0] += P1[0];
- P2[1] += P1[1];
- }
- else if (num_params == 4)
- {
- P1[0] = params[0].value.number * PlotSize[0] / 72.0f * 1016.0f / 100.0f;
- P1[1] = params[1].value.number * PlotSize[1] / 72.0f * 1016.0f / 100.0f;
- P2[0] = params[2].value.number * PlotSize[0] / 72.0f * 1016.0f / 100.0f;
- P2[1] = params[3].value.number * PlotSize[1] / 72.0f * 1016.0f / 100.0f;
- }
-
- IW1[0] = 0.0;
- IW1[1] = 0.0;
- IW2[0] = 0.0;
- IW2[1] = 0.0;
-
- if (ScalingType < 0)
- {
- Scaling1[0] = P1[0];
- Scaling1[0] = P1[1];
- Scaling2[0] = P2[0];
- Scaling2[1] = P2[1];
- }
-
- update_transform();
-}
-
-
-/*
- * 'IW_input_window()' - Setup an input window.
- */
-
-void
-IW_input_window(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- if (num_params == 0)
- {
- IW1[0] = PageLeft / 72.0f * 1016.0f;
- IW1[1] = PageBottom / 72.0f * 1016.0f;
- IW2[0] = PageRight / 72.0f * 1016.0f;
- IW2[1] = PageTop / 72.0f * 1016.0f;
- }
- else if (num_params == 4)
- {
-
- if (ScalingType < 0)
- {
- IW1[0] = params[0].value.number;
- IW1[1] = params[1].value.number;
- IW2[0] = params[2].value.number;
- IW2[1] = params[3].value.number;
- }
- else
- {
- IW1[0] = (Transform[0][0] * params[0].value.number +
- Transform[0][1] * params[1].value.number +
- Transform[0][2]) / 72.0f * 1016.0f;
- IW1[1] = (Transform[1][0] * params[0].value.number +
- Transform[1][1] * params[1].value.number +
- Transform[1][2]) / 72.0f * 1016.0f;
- IW2[0] = (Transform[0][0] * params[2].value.number +
- Transform[0][1] * params[3].value.number +
- Transform[0][2]) / 72.0f * 1016.0f;
- IW2[1] = (Transform[1][0] * params[2].value.number +
- Transform[1][1] * params[3].value.number +
- Transform[1][2]) / 72.0f * 1016.0f;
- }
-
- fprintf(stderr, "DEBUG: IW%.0f,%.0f,%.0f,%.0f = [ %.0f %.0f %.0f %.0f ]\n",
- params[0].value.number, params[1].value.number,
- params[2].value.number, params[3].value.number,
- IW1[0], IW1[1], IW2[0], IW2[1]);
- }
-
-
- update_transform();
-}
-
-
-/*
- * 'PG_advance_page()' - Eject the current page.
- */
-
-void
-PG_advance_page(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- (void)num_params;
- (void)params;
-
- if (PageDirty)
- {
- puts("grestore");
- puts("showpage");
-
- PageDirty = 0;
- }
-}
-
-
-/*
- * 'PS_plot_size()' - Set the plot size.
- */
-
-void
-PS_plot_size(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- switch (num_params)
- {
- case 0 : /* PS ; */
- if (Rotation == 0 || Rotation == 180)
- {
- PlotSize[0] = PageWidth;
- PlotSize[1] = PageLength;
- }
- else
- {
- PlotSize[0] = PageLength;
- PlotSize[1] = PageWidth;
- }
-
- PlotSizeSet = 0;
- break;
- case 1 : /* PS length ; */
- if (Rotation == 0 || Rotation == 180)
- {
- PlotSize[1] = 72.0f * params[0].value.number / 1016.0f;
- PlotSize[0] = 0.75f * PlotSize[1];
- }
- else
- {
- PlotSize[0] = 72.0f * params[0].value.number / 1016.0f;
- PlotSize[1] = 0.75f * PlotSize[0];
- }
-
- PlotSizeSet = 1;
- break;
- case 2 : /* PS length, width ; */
- /*
- * Unfortunately, it appears that NO application correctly
- * sends a two-argument PS command as documented in the
- * HP-GL/2 Reference Manual from HP. Instead, applications
- * send the width before the length, which causes all sorts
- * of problems when scaling.
- *
- * Rather than fight it, we now look for them as width,length
- * instead of length,width.
- *
- * Don't like it? Send mail to the folks that make Ideas, Pro/E,
- * AutoCAD, etc.
- */
-
- if (Rotation == 0 || Rotation == 180)
- {
- PlotSize[0] = 72.0f * params[0].value.number / 1016.0f;
- PlotSize[1] = 72.0f * params[1].value.number / 1016.0f;
- }
- else
- {
- PlotSize[0] = 72.0f * params[1].value.number / 1016.0f;
- PlotSize[1] = 72.0f * params[0].value.number / 1016.0f;
- }
-
- PlotSizeSet = 1;
- break;
- }
-
- /*
- * This is required for buggy files that don't set the input window.
- */
-
- IP_input_absolute(0, NULL);
-}
-
-
-/*
- * 'RO_rotate()' - Rotate the plot.
- */
-
-void
-RO_rotate(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- if (num_params == 0)
- Rotation = 0;
- else
- Rotation = (int)params[0].value.number;
-
- update_transform();
-}
-
-
-/*
- * 'RP_replot()' - Replot the current page.
- */
-
-void
-RP_replot(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- (void)num_params;
- (void)params;
-}
-
-
-/*
- * 'SC_scale()' - Set user-defined scaling.
- */
-
-void
-SC_scale(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- if (num_params == 0)
- {
- ScalingType = -1;
- Scaling1[0] = P1[0];
- Scaling1[0] = P1[1];
- Scaling2[0] = P2[0];
- Scaling2[1] = P2[1];
- }
- else if (num_params > 3)
- {
- Scaling1[0] = params[0].value.number;
- Scaling2[0] = params[1].value.number;
- Scaling1[1] = params[2].value.number;
- Scaling2[1] = params[3].value.number;
-
- if (num_params > 4)
- ScalingType = (int)params[4].value.number;
- else
- ScalingType = 1;
- }
-
- update_transform();
-}
-
-
-/*
- * End of "$Id: hpgl-config.c 6649 2007-07-11 21:46:42Z mike $".
- */
+++ /dev/null
-/*
- * "$Id: hpgl-input.c 7219 2008-01-14 22:00:02Z mike $"
- *
- * HP-GL/2 input processing for the Common UNIX Printing System (CUPS).
- *
- * Copyright 2007-2009 by Apple Inc.
- * Copyright 1993-2006 by Easy Software Products.
- *
- * These coded instructions, statements, and computer programs are the
- * property of Apple Inc. and are protected by Federal copyright
- * law. Distribution and use rights are outlined in the file "LICENSE.txt"
- * which should have been included with this file. If this file is
- * file is missing or damaged, see the license at "http://www.cups.org/".
- *
- * This file is subject to the Apple OS-Developed Software exception.
- *
- * Contents:
- *
- * ParseCommand() - Parse an HPGL/2 command.
- * FreeParameters() - Free all string parameter values.
- */
-
-/*
- * Include necessary headers...
- */
-
-#include "hpgltops.h"
-#include <ctype.h>
-#include <cups/i18n.h>
-
-#define MAX_PARAMS 16384
-
-
-/*
- * 'ParseCommand()' - Parse an HPGL/2 command.
- *
- * Returns the number of parameters seen or -1 on EOF.
- */
-
-int /* O - -1 on EOF, # params otherwise */
-ParseCommand(FILE *fp, /* I - File to read from */
- char *name, /* O - Name of command */
- param_t **params) /* O - Parameter list */
-{
- int num_params, /* Number of parameters seen */
- ch, /* Current char */
- done, /* Non-zero when the current command is read */
- i; /* Looping var */
- char buf[262144], /* String buffer */
- *bufptr; /* Pointer into buffer */
- float temp; /* Temporary parameter value */
- static param_t p[MAX_PARAMS]; /* Parameter buffer */
-
-
- num_params = 0;
- done = 0;
-
- do
- {
- while ((ch = getc(fp)) != EOF)
- if (strchr(" \t\r\n,;", ch) == NULL)
- break;
-
- if (ch == EOF)
- {
- return (-1);
- }
-
- if (ch == 0x1b)
- switch (getc(fp))
- {
- case '.' : /* HP-GL/2 job control */
- i = getc(fp);
-
- if (strchr(")Z", i) != NULL)
- {
- /*
- * 'Printer Off' command - look for next 'Printer On' command...
- */
-
- for (;;)
- {
- while ((i = getc(fp)) != EOF && i != 0x1b);
-
- if (i == EOF)
- return (-1);
-
- if (getc(fp) != '.')
- continue;
-
- if ((i = getc(fp)) == '(' ||
- i == 'Y')
- break;
- }
- }
- else if (strchr("@HIMNTI\003", i) != NULL)
- {
- while ((i = getc(fp)) != EOF && i != ':');
- }
- break;
-
- case '%' : /* PJL command? */
- if ((i = getc(fp)) == '-')
- if ((i = getc(fp)) == '1')
- if ((i = getc(fp)) == '2')
- {
- /*
- * Yes, dump everything up to the "ENTER LANGUAGE" line...
- */
-
- while (fgets(buf, sizeof(buf), fp) != NULL)
- if (strstr(buf, "ENTER") && strstr(buf, "LANGUAGE"))
- break;
- break;
- }
-
- ungetc(i, fp);
-
- default : /* HP RTL/PCL control */
- while ((i = getc(fp)) != EOF && !isupper(i & 255));
-
- if (i == EOF)
- return (-1);
- break;
- }
- } while (ch < ' ');
-
- name[0] = ch;
- name[1] = getc(fp);
- name[2] = '\0';
-
- if (name[1] < ' ')
- {
- /*
- * If we get here, then more than likely we are faced with a raw PCL
- * file which we can't handle - abort!
- */
-
- fputs(_("ERROR: Invalid HP-GL/2 command seen, unable to print file\n"),
- stderr);
- return (-1);
- }
-
- if (!strcasecmp(name, "LB"))
- {
- bufptr = buf;
- while ((ch = getc(fp)) != StringTerminator && ch != EOF)
- if (bufptr < (buf + sizeof(buf) - 1))
- *bufptr++ = ch;
- *bufptr = '\0';
-
- p[num_params].type = PARAM_STRING;
- p[num_params].value.string = strdup(buf);
- num_params ++;
- }
- else if (!strcasecmp(name, "SM"))
- {
- buf[0] = getc(fp);
- buf[1] = '\0';
- p[num_params].type = PARAM_STRING;
- p[num_params].value.string = strdup(buf);
- num_params ++;
- }
- else if (!strcasecmp(name, "DT"))
- {
- if ((buf[0] = getc(fp)) != ';')
- {
- buf[1] = '\0';
- p[num_params].type = PARAM_STRING;
- p[num_params].value.string = strdup(buf);
- num_params ++;
- }
- }
- else if (!strcasecmp(name, "PE"))
- {
- bufptr = buf;
- while ((ch = getc(fp)) != ';')
- if (ch == EOF)
- break;
- else if (bufptr < (buf + sizeof(buf) - 1))
- *bufptr++ = ch;
- *bufptr = '\0';
-
- p[num_params].type = PARAM_STRING;
- p[num_params].value.string = strdup(buf);
- num_params ++;
- }
-
- while (!done)
- switch (ch = getc(fp))
- {
- case EOF :
- done = 1;
- break;
-
- case ',' :
- case ' ' :
- case '\n' :
- case '\r' :
- case '\t' :
- break;
-
- case '\"' :
- fscanf(fp, "%262143[^\"]\"", buf);
- if (num_params < MAX_PARAMS)
- {
- p[num_params].type = PARAM_STRING;
- p[num_params].value.string = strdup(buf);
- num_params ++;
- };
- break;
-
- case '-' :
- case '+' :
- ungetc(ch, fp);
- if (fscanf(fp, "%f", &temp) == 1 && num_params < MAX_PARAMS)
- {
- p[num_params].type = PARAM_RELATIVE;
- p[num_params].value.number = temp;
- num_params ++;
- }
- break;
- case '0' :
- case '1' :
- case '2' :
- case '3' :
- case '4' :
- case '5' :
- case '6' :
- case '7' :
- case '8' :
- case '9' :
- case '.' :
- ungetc(ch, fp);
- if (fscanf(fp, "%f", &temp) == 1 && num_params < MAX_PARAMS)
- {
- p[num_params].type = PARAM_ABSOLUTE;
- p[num_params].value.number = temp;
- num_params ++;
- }
- break;
- default :
- ungetc(ch, fp);
- done = 1;
- break;
- }
-
- *params = p;
- return (num_params);
-}
-
-
-/*
- * 'FreeParameters()' - Free all string parameter values.
- */
-
-void
-FreeParameters(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameter values */
-{
- int i; /* Looping var */
-
-
- for (i = 0; i < num_params; i ++)
- if (params[i].type == PARAM_STRING)
- free(params[i].value.string);
-}
-
-
-/*
- * End of "$Id: hpgl-input.c 7219 2008-01-14 22:00:02Z mike $".
- */
+++ /dev/null
-/*
- * "$Id: hpgl-main.c 6649 2007-07-11 21:46:42Z mike $"
- *
- * HP-GL/2 filter main entry for the Common UNIX Printing System (CUPS).
- *
- * Copyright 2007-2008 by Apple Inc.
- * Copyright 1993-2007 by Easy Software Products.
- *
- * These coded instructions, statements, and computer programs are the
- * property of Apple Inc. and are protected by Federal copyright
- * law. Distribution and use rights are outlined in the file "LICENSE.txt"
- * which should have been included with this file. If this file is
- * file is missing or damaged, see the license at "http://www.cups.org/".
- *
- * This file is subject to the Apple OS-Developed Software exception.
- *
- * Contents:
- *
- * main() - Main entry for HP-GL/2 filter.
- * compare_names() - Compare two command names.
- */
-
-/*
- * Include necessary headers...
- */
-
-/*#define DEBUG*/
-#define _HPGL_MAIN_C_
-#include "hpgltops.h"
-#include <cups/i18n.h>
-
-
-/*
- * HP-GL/2 command table...
- */
-
-typedef struct
-{
- char name[4]; /* Name of command */
- void (*func)(int, param_t *); /* Function to call */
-} name_t;
-
-static name_t commands[] =
-{
- { "BP", BP_begin_plot },
- { "DF", DF_default_values },
- { "IN", IN_initialize },
- { "IP", IP_input_absolute },
- { "IR", IR_input_relative },
- { "IW", IW_input_window },
- { "PG", PG_advance_page },
- { "RO", RO_rotate },
- { "RP", RP_replot },
- { "SC", SC_scale },
- { "AA", AA_arc_absolute },
- { "AR", AR_arc_relative },
- { "AT", AT_arc_absolute3 },
- { "CI", CI_circle },
- { "PA", PA_plot_absolute },
- { "PD", PD_pen_down },
- { "PE", PE_polyline_encoded },
- { "PR", PR_plot_relative },
- { "PS", PS_plot_size },
- { "PU", PU_pen_up },
- { "RT", RT_arc_relative3 },
- { "EA", EA_edge_rect_absolute },
- { "EP", EP_edge_polygon },
- { "ER", ER_edge_rect_relative },
- { "EW", EW_edge_wedge },
- { "FP", FP_fill_polygon },
- { "PM", PM_polygon_mode },
- { "RA", RA_fill_rect_absolute },
- { "RR", RR_fill_rect_relative },
- { "WG", WG_fill_wedge },
- { "AD", AD_define_alternate },
- { "CF", CF_character_fill },
- { "CP", CP_character_plot },
- { "DI", DI_absolute_direction },
- { "DR", DR_relative_direction },
- { "DT", DT_define_label_term },
- { "DV", DV_define_variable_path },
- { "ES", ES_extra_space },
- { "LB", LB_label },
- { "LO", LO_label_origin },
- { "SA", SA_select_alternate },
- { "SD", SD_define_standard },
- { "SI", SI_absolute_size },
- { "SL", SL_character_slant },
- { "SR", SR_relative_size },
- { "SS", SS_select_standard },
- { "TD", TD_transparent_data },
- { "AC", AC_anchor_corner },
- { "FT", FT_fill_type },
- { "LA", LA_line_attributes },
- { "LT", LT_line_type },
- { "NP", NP_number_pens },
- { "PC", PC_pen_color },
- { "CR", CR_color_range },
- { "PW", PW_pen_width },
- { "RF", RF_raster_fill },
- { "SM", SM_symbol_mode },
- { "SP", SP_select_pen },
- { "UL", UL_user_line_type },
- { "WU", WU_width_units }
-};
-#define NUM_COMMANDS (sizeof(commands) / sizeof(name_t))
-
-
-/*
- * Local functions...
- */
-
-static int compare_names(const void *p1, const void *p2);
-
-
-/*
- * 'main()' - Main entry for HP-GL/2 filter.
- */
-
-int /* O - Exit status */
-main(int argc, /* I - Number of command-line arguments */
- char *argv[]) /* I - Command-line arguments */
-{
- FILE *fp; /* Input file */
- int num_params; /* Number of parameters */
- param_t *params; /* Command parameters */
- name_t *command, /* Command */
- name; /* Name of command */
- int num_options; /* Number of print options */
- cups_option_t *options; /* Print options */
- const char *val; /* Option value */
- int shading; /* -1 = black, 0 = grey, 1 = color */
-
-
- /*
- * Make sure status messages are not buffered...
- */
-
- setbuf(stdout, NULL);
- setbuf(stderr, NULL);
-
- /*
- * Check command-line...
- */
-
- if (argc < 6 || argc > 7)
- {
- fprintf(stderr, _("Usage: %s job-id user title copies options [file]\n"),
- argv[0]);
- return (1);
- }
-
- /*
- * If we have 7 arguments, print the file named on the command-line.
- * Otherwise, send stdin instead...
- */
-
- if (argc == 6)
- fp = stdin;
- else
- {
- /*
- * Try to open the print file...
- */
-
- if ((fp = fopen(argv[6], "rb")) == NULL)
- {
- perror("DEBUG: unable to open print file - ");
- return (1);
- }
- }
-
- /*
- * Process command-line options and write the prolog...
- */
-
- options = NULL;
- num_options = cupsParseOptions(argv[5], 0, &options);
-
- PPD = SetCommonOptions(num_options, options, 1);
-
- PlotSize[0] = PageWidth;
- PlotSize[1] = PageLength;
-
- shading = 1;
- PenWidth = 1.0;
-
- if ((val = cupsGetOption("blackplot", num_options, options)) != NULL &&
- strcasecmp(val, "no") && strcasecmp(val, "off") &&
- strcasecmp(val, "false"))
- shading = 0;
-
- if ((val = cupsGetOption("fitplot", num_options, options)) != NULL &&
- !strcasecmp(val, "true"))
- FitPlot = 1;
- else if ((val = cupsGetOption("fit-to-page", num_options, options)) != NULL &&
- !strcasecmp(val, "true"))
- FitPlot = 1;
-
- if ((val = cupsGetOption("penwidth", num_options, options)) != NULL)
- PenWidth = (float)atoi(val) * 0.001f;
-
- /*
- * Write the PostScript prolog and initialize the plotting "engine"...
- */
-
- OutputProlog(argv[3], argv[2], shading);
-
- IP_input_absolute(0, NULL);
-
- /*
- * Sort the command array...
- */
-
- qsort(commands, NUM_COMMANDS, sizeof(name_t),
- (int (*)(const void *, const void *))compare_names);
-
- /*
- * Read commands until we reach the end of file.
- */
-
- while ((num_params = ParseCommand(fp, name.name, ¶ms)) >= 0)
- {
- Outputf("%% %s(%d)\n", name.name, num_params);
-
-#ifdef DEBUG
- {
- int i;
- fprintf(stderr, "DEBUG: %s(%d)", name.name, num_params);
- for (i = 0; i < num_params; i ++)
- if (params[i].type == PARAM_STRING)
- fprintf(stderr, " \'%s\'", params[i].value.string);
- else
- fprintf(stderr, " %f", params[i].value.number);
- fputs("\n", stderr);
- }
-#endif /* DEBUG */
-
- if ((command = bsearch(&name, commands, NUM_COMMANDS, sizeof(name_t),
- (int (*)(const void *, const void *))compare_names)) != NULL)
- (*command->func)(num_params, params);
-
- FreeParameters(num_params, params);
- }
-
- OutputTrailer();
-
- if (fp != stdin)
- fclose(fp);
-
- return (0);
-}
-
-
-/*
- * 'compare_names()' - Compare two command names.
- */
-
-static int /* O - Result of strcasecmp() on names */
-compare_names(const void *p1, /* I - First name */
- const void *p2) /* I - Second name */
-{
- return (strcasecmp(((name_t *)p1)->name, ((name_t *)p2)->name));
-}
-
-
-/*
- * End of "$Id: hpgl-main.c 6649 2007-07-11 21:46:42Z mike $".
- */
+++ /dev/null
-/*
- * "$Id: hpgl-polygon.c 6649 2007-07-11 21:46:42Z mike $"
- *
- * HP-GL/2 polygon routines for the Common UNIX Printing System (CUPS).
- *
- * Copyright 2007 by Apple Inc.
- * Copyright 1993-2005 by Easy Software Products.
- *
- * These coded instructions, statements, and computer programs are the
- * property of Apple Inc. and are protected by Federal copyright
- * law. Distribution and use rights are outlined in the file "LICENSE.txt"
- * which should have been included with this file. If this file is
- * file is missing or damaged, see the license at "http://www.cups.org/".
- *
- * This file is subject to the Apple OS-Developed Software exception.
- *
- * Contents:
- *
- * EA_edge_rect_absolute() - Draw a rectangle.
- * EP_edge_polygon() - Stroke the edges of a polygon.
- * ER_edge_rect_relative() - Draw a rectangle relative to the current
- * EW_edge_wedge() - Draw a pie wedge.
- * FP_fill_polygon() - Fill a polygon.
- * PM_polygon_mode() - Set the polygon drawing mode.
- * RA_fill_rect_absolute() - Fill a rectangle.
- * RR_fill_rect_relative() - Fill a rectangle relative to the current
- * WG_fill_wedge() - Fill a pie wedge.
- */
-
-/*
- * Include necessary headers...
- */
-
-#include "hpgltops.h"
-
-
-/*
- * 'EA_edge_rect_absolute()' - Draw a rectangle.
- */
-
-void
-EA_edge_rect_absolute(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- float x, y; /* Transformed coordinates */
-
-
- if (num_params < 2)
- return;
-
- x = Transform[0][0] * params[0].value.number +
- Transform[0][1] * params[1].value.number +
- Transform[0][2];
- y = Transform[1][0] * params[0].value.number +
- Transform[1][1] * params[1].value.number +
- Transform[1][2];
-
- if (!PolygonMode)
- Outputf("MP\n");
-
- PenValid = 1;
-
- Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]);
- Outputf("%.3f %.3f LI\n", PenPosition[0], y);
- Outputf("%.3f %.3f LI\n", x, y);
- Outputf("%.3f %.3f LI\n", x, PenPosition[1]);
-
- Outputf("CP\n");
- if (!PolygonMode)
- Outputf("ST\n");
-}
-
-
-/*
- * 'EP_edge_polygon()' - Stroke the edges of a polygon.
- */
-
-void
-EP_edge_polygon(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- (void)num_params;
- (void)params;
-
- Outputf("ST\n");
-}
-
-
-/*
- * 'ER_edge_rect_relative()' - Draw a rectangle relative to the current
- * pen position.
- */
-
-void
-ER_edge_rect_relative(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- float x, y; /* Transformed coordinates */
-
-
- if (num_params < 2)
- return;
-
- x = Transform[0][0] * params[0].value.number +
- Transform[0][1] * params[1].value.number +
- PenPosition[0];
- y = Transform[1][0] * params[0].value.number +
- Transform[1][1] * params[1].value.number +
- PenPosition[1];
-
- if (!PolygonMode)
- Outputf("MP\n");
-
- PenValid = 1;
-
- Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]);
- Outputf("%.3f %.3f LI\n", PenPosition[0], y);
- Outputf("%.3f %.3f LI\n", x, y);
- Outputf("%.3f %.3f LI\n", x, PenPosition[1]);
-
- Outputf("CP\n");
- if (!PolygonMode)
- Outputf("ST\n");
-}
-
-
-/*
- * 'EW_edge_wedge()' - Draw a pie wedge.
- */
-
-void
-EW_edge_wedge(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- float x, y; /* Transformed coordinates */
- float start, end, /* Start and end of arc */
- theta, /* Current angle */
- dt, /* Step between points */
- radius; /* Radius of arc */
-
-
- if (num_params < 3)
- return;
-
- radius = params[0].value.number;
- start = params[1].value.number;
- end = start + params[2].value.number;
-
- if (num_params > 3)
- dt = (float)fabs(params[3].value.number);
- else
- dt = 5.0f;
-
- if (!PolygonMode)
- Outputf("MP\n");
-
- PenValid = 1;
-
- Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]);
-
- if (start < end)
- for (theta = start + dt; theta < end; theta += dt)
- {
- x = (float)(PenPosition[0] +
- radius * cos(M_PI * theta / 180.0) * Transform[0][0] +
- radius * sin(M_PI * theta / 180.0) * Transform[0][1]);
- y = (float)(PenPosition[1] +
- radius * cos(M_PI * theta / 180.0) * Transform[1][0] +
- radius * sin(M_PI * theta / 180.0) * Transform[1][1]);
-
- Outputf("%.3f %.3f LI\n", x, y);
- }
- else
- for (theta = start - dt; theta > end; theta -= dt)
- {
- x = (float)(PenPosition[0] +
- radius * cos(M_PI * theta / 180.0) * Transform[0][0] +
- radius * sin(M_PI * theta / 180.0) * Transform[0][1]);
- y = (float)(PenPosition[1] +
- radius * cos(M_PI * theta / 180.0) * Transform[1][0] +
- radius * sin(M_PI * theta / 180.0) * Transform[1][1]);
-
- Outputf("%.3f %.3f LI\n", x, y);
- }
-
- x = (float)(PenPosition[0] +
- radius * cos(M_PI * end / 180.0) * Transform[0][0] +
- radius * sin(M_PI * end / 180.0) * Transform[0][1]);
- y = (float)(PenPosition[1] +
- radius * cos(M_PI * end / 180.0) * Transform[1][0] +
- radius * sin(M_PI * end / 180.0) * Transform[1][1]);
- Outputf("%.3f %.3f LI\n", x, y);
-
- Outputf("CP\n");
- if (!PolygonMode)
- Outputf("ST\n");
-}
-
-
-/*
- * 'FP_fill_polygon()' - Fill a polygon.
- */
-
-void
-FP_fill_polygon(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- (void)num_params;
- (void)params;
-
- Outputf("FI\n");
-}
-
-
-/*
- * 'PM_polygon_mode()' - Set the polygon drawing mode.
- */
-
-void
-PM_polygon_mode(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- if (num_params == 0 ||
- params[0].value.number == 0)
- {
- Outputf("MP\n");
- PenValid = 0;
- PolygonMode = 1;
- }
- else if (params[0].value.number == 2)
- PolygonMode = 0;
-}
-
-
-/*
- * 'RA_fill_rect_absolute()' - Fill a rectangle.
- */
-
-void
-RA_fill_rect_absolute(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- float x, y; /* Transformed coordinates */
-
-
- if (num_params < 2)
- return;
-
- x = Transform[0][0] * params[0].value.number +
- Transform[0][1] * params[1].value.number +
- Transform[0][2];
- y = Transform[1][0] * params[0].value.number +
- Transform[1][1] * params[1].value.number +
- Transform[1][2];
-
- if (!PolygonMode)
- Outputf("MP\n");
-
- PenValid = 1;
-
- Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]);
- Outputf("%.3f %.3f LI\n", PenPosition[0], y);
- Outputf("%.3f %.3f LI\n", x, y);
- Outputf("%.3f %.3f LI\n", x, PenPosition[1]);
-
- Outputf("CP\n");
- if (!PolygonMode)
- Outputf("FI\n");
-}
-
-
-/*
- * 'RR_fill_rect_relative()' - Fill a rectangle relative to the current
- * pen position.
- */
-
-void
-RR_fill_rect_relative(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- float x, y; /* Transformed coordinates */
-
-
- if (num_params < 2)
- return;
-
- x = Transform[0][0] * params[0].value.number +
- Transform[0][1] * params[1].value.number +
- PenPosition[0];
- y = Transform[1][0] * params[0].value.number +
- Transform[1][1] * params[1].value.number +
- PenPosition[1];
-
- if (!PolygonMode)
- Outputf("MP\n");
-
- PenValid = 1;
-
- Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]);
- Outputf("%.3f %.3f LI\n", PenPosition[0], y);
- Outputf("%.3f %.3f LI\n", x, y);
- Outputf("%.3f %.3f LI\n", x, PenPosition[1]);
-
- Outputf("CP\n");
- if (!PolygonMode)
- Outputf("FI\n");
-}
-
-
-/*
- * 'WG_fill_wedge()' - Fill a pie wedge.
- */
-
-void
-WG_fill_wedge(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- float x, y; /* Transformed coordinates */
- float start, end, /* Start and end angles */
- theta, /* Current angle */
- dt, /* Step between points */
- radius; /* Radius of arc */
-
-
- if (num_params < 3)
- return;
-
- radius = params[0].value.number;
- start = params[1].value.number;
- end = start + params[2].value.number;
-
- if (num_params > 3)
- dt = (float)fabs(params[3].value.number);
- else
- dt = 5.0;
-
- if (!PolygonMode)
- Outputf("MP\n");
-
- PenValid = 1;
-
- Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]);
-
- if (start < end)
- for (theta = start + dt; theta < end; theta += dt)
- {
- x = (float)(PenPosition[0] +
- radius * cos(M_PI * theta / 180.0) * Transform[0][0] +
- radius * sin(M_PI * theta / 180.0) * Transform[0][1]);
- y = (float)(PenPosition[1] +
- radius * cos(M_PI * theta / 180.0) * Transform[1][0] +
- radius * sin(M_PI * theta / 180.0) * Transform[1][1]);
-
- Outputf("%.3f %.3f LI\n", x, y);
- }
- else
- for (theta = start - dt; theta > end; theta -= dt)
- {
- x = (float)(PenPosition[0] +
- radius * cos(M_PI * theta / 180.0) * Transform[0][0] +
- radius * sin(M_PI * theta / 180.0) * Transform[0][1]);
- y = (float)(PenPosition[1] +
- radius * cos(M_PI * theta / 180.0) * Transform[1][0] +
- radius * sin(M_PI * theta / 180.0) * Transform[1][1]);
-
- Outputf("%.3f %.3f LI\n", x, y);
- }
-
- x = (float)(PenPosition[0] +
- radius * cos(M_PI * end / 180.0) * Transform[0][0] +
- radius * sin(M_PI * end / 180.0) * Transform[0][1]);
- y = (float)(PenPosition[1] +
- radius * cos(M_PI * end / 180.0) * Transform[1][0] +
- radius * sin(M_PI * end / 180.0) * Transform[1][1]);
- Outputf("%.3f %.3f LI\n", x, y);
-
- Outputf("CP\n");
- if (!PolygonMode)
- Outputf("FI\n");
-}
-
-
-/*
- * End of "$Id: hpgl-polygon.c 6649 2007-07-11 21:46:42Z mike $".
- */
+++ /dev/null
-/*
- * "$Id: hpgl-prolog.c 6649 2007-07-11 21:46:42Z mike $"
- *
- * HP-GL/2 prolog routines for for the Common UNIX Printing System (CUPS).
- *
- * Copyright 2007 by Apple Inc.
- * Copyright 1993-2007 by Easy Software Products.
- *
- * These coded instructions, statements, and computer programs are the
- * property of Apple Inc. and are protected by Federal copyright
- * law. Distribution and use rights are outlined in the file "LICENSE.txt"
- * which should have been included with this file. If this file is
- * file is missing or damaged, see the license at "http://www.cups.org/".
- *
- * This file is subject to the Apple OS-Developed Software exception.
- *
- * Contents:
- *
- * OutputProlog() - Output the PostScript prolog...
- * OutputTrailer() - Output the PostScript trailer...
- * Outputf() - Write a formatted string to the output file, creating the
- * page header as needed...
- */
-
-/*
- * Include necessary headers...
- */
-
-#include "hpgltops.h"
-#include <stdarg.h>
-
-
-/*
- * 'OutputProlog()' - Output the PostScript prolog...
- */
-
-void
-OutputProlog(char *title, /* I - Job title */
- char *user, /* I - Username */
- int shading) /* I - Type of shading */
-{
- FILE *prolog; /* Prolog file */
- char line[255]; /* Line from prolog file */
- const char *datadir; /* CUPS_DATADIR environment variable */
- char filename[1024]; /* Name of prolog file */
- time_t curtime; /* Current time */
- struct tm *curtm; /* Current date */
-
-
- curtime = time(NULL);
- curtm = localtime(&curtime);
-
- puts("%!PS-Adobe-3.0");
- printf("%%%%BoundingBox: %.0f %.0f %.0f %.0f\n",
- PageLeft, PageBottom, PageRight, PageTop);
- puts("%%Pages: (atend)");
- printf("%%%%LanguageLevel: %d\n", LanguageLevel);
- puts("%%DocumentData: Clean7Bit");
- puts("%%DocumentSuppliedResources: procset hpgltops 1.1 0");
- puts("%%DocumentNeededResources: font Courier Helvetica");
- puts("%%Creator: hpgltops/" CUPS_SVERSION);
- strftime(line, sizeof(line), "%c", curtm);
- printf("%%%%CreationDate: %s\n", line);
- WriteTextComment("Title", title);
- WriteTextComment("For", user);
- printf("%%cupsRotation: %d\n", (Orientation & 3) * 90);
- puts("%%EndComments");
- puts("%%BeginProlog");
- printf("/DefaultPenWidth %.2f def\n", PenWidth * 72.0 / 25.4);
- if (!shading) /* Black only */
- puts("/setrgbcolor { pop pop pop } bind def");
- else if (!ColorDevice) /* Greyscale */
- puts("/setrgbcolor { 0.08 mul exch 0.61 mul add exch 0.31 mul add setgray } bind def\n");
-
- if ((datadir = getenv("CUPS_DATADIR")) == NULL)
- datadir = CUPS_DATADIR;
-
- snprintf(filename, sizeof(filename), "%s/data/HPGLprolog", datadir);
-
- if ((prolog = fopen(filename, "r")) == NULL)
- {
- fprintf(stderr,
- "DEBUG: Unable to open HPGL prolog \"%s\" for reading - %s\n",
- filename, strerror(errno));
- exit(1);
- }
-
- while (fgets(line, sizeof(line), prolog) != NULL)
- fputs(line, stdout);
-
- fclose(prolog);
-
- puts("%%EndProlog");
-
- IN_initialize(0, NULL);
-}
-
-
-/*
- * 'OutputTrailer()' - Output the PostScript trailer...
- */
-
-void
-OutputTrailer(void)
-{
- if (PageDirty)
- PG_advance_page(0, NULL);
-
- puts("%%Trailer");
- printf("%%%%Pages: %d\n", PageCount);
- puts("%%EOF");
-}
-
-
-/*
- * 'Outputf()' - Write a formatted string to the output file, creating the
- * page header as needed...
- */
-
-int /* O - Number of bytes written */
-Outputf(const char *format, /* I - Printf-style string */
- ...) /* I - Additional args as needed */
-{
- va_list ap; /* Argument pointer */
- int bytes; /* Number of bytes written */
- float iw1[2], iw2[2]; /* Clipping window */
- int i; /* Looping var */
- ppd_size_t *size; /* Page size */
- ppd_option_t *option; /* Page size option */
- ppd_choice_t *choice; /* Page size choice */
- float width, length; /* Page dimensions */
- int landscape; /* Rotate for landscape orientation? */
-
-
- /*
- * Write the page header as needed...
- */
-
- if (!PageDirty)
- {
- PageDirty = 1;
- PageCount ++;
-
- printf("%%%%Page: %d %d\n", PageCount, PageCount);
-
- landscape = 0;
-
- if (!FitPlot && PlotSizeSet)
- {
- /*
- * Set the page size for this page...
- */
-
- if (PageRotation == 0 || PageRotation == 180)
- {
- width = PlotSize[0];
- length = PlotSize[1];
- }
- else
- {
- width = PlotSize[1];
- length = PlotSize[0];
- }
-
- fprintf(stderr, "DEBUG: hpgltops setting page size (%.0f x %.0f)\n",
- width, length);
-
- if (PPD != NULL)
- {
- fputs("DEBUG: hpgltops has a PPD file!\n", stderr);
-
- /*
- * Lookup the closest PageSize and set it...
- */
-
- for (i = PPD->num_sizes, size = PPD->sizes; i > 0; i --, size ++)
- if ((fabs(length - size->length) < 36.0 && size->width >= width) ||
- (fabs(length - size->width) < 36.0 && size->length >= width))
- break;
-
- if (i == 0 && PPD->variable_sizes)
- {
- for (i = PPD->num_sizes, size = PPD->sizes; i > 0; i --, size ++)
- if (strcasecmp(size->name, "custom") == 0)
- break;
- }
-
- if (i > 0)
- {
- /*
- * Found a matching size...
- */
-
- option = ppdFindOption(PPD, "PageSize");
- choice = ppdFindChoice(option, size->name);
-
- puts("%%BeginPageSetup");
- printf("%%%%BeginFeature: PageSize %s\n", size->name);
-
- if (strcasecmp(size->name, "custom") == 0)
- {
- PageLeft = PPD->custom_margins[0];
- PageRight = width - PPD->custom_margins[2];
- PageWidth = width;
- PageBottom = PPD->custom_margins[1];
- PageTop = length - PPD->custom_margins[3];
- PageLength = length;
-
- printf("%.0f %.0f 0 0 0\n", width, length);
-
- if (choice->code == NULL)
- {
- /*
- * This can happen with certain buggy PPD files that don't include
- * a CustomPageSize command sequence... We just use a generic
- * Level 2 command sequence...
- */
-
- puts("pop pop pop");
- puts("<</PageSize[5 -2 roll]/ImagingBBox null>>setpagedevice\n");
- }
- else
- {
- /*
- * Use the vendor-supplied command...
- */
-
- printf("%s\n", choice->code);
- }
- }
- else
- {
- if (choice->code)
- printf("%s\n", choice->code);
-
- if (fabs(length - size->width) < 36.0)
- {
- /*
- * Do landscape orientation...
- */
-
- PageLeft = size->bottom;
- PageRight = size->top;
- PageWidth = size->length;
- PageBottom = size->left;
- PageTop = size->right;
- PageLength = size->width;
-
- landscape = 1;
- }
- else
- {
- /*
- * Do portrait orientation...
- */
-
- PageLeft = size->left;
- PageRight = size->right;
- PageWidth = size->width;
- PageBottom = size->bottom;
- PageTop = size->top;
- PageLength = size->length;
- }
- }
-
- puts("%%EndFeature");
- puts("%%EndPageSetup");
- }
- }
- else
- {
- fputs("DEBUG: hpgltops does not have a PPD file!\n", stderr);
-
- puts("%%BeginPageSetup");
- printf("%%%%BeginFeature: PageSize w%.0fh%.0f\n", width, length);
- printf("<</PageSize[%.0f %.0f]/ImageBBox null>>setpagedevice\n",
- width, length);
- puts("%%EndFeature");
- puts("%%EndPageSetup");
-
- PageLeft = 0.0;
- PageRight = width;
- PageWidth = width;
- PageBottom = 0.0;
- PageTop = length;
- PageLength = length;
- }
- }
-
- define_font(0);
- define_font(1);
-
- printf("%.1f setmiterlimit\n", MiterLimit);
- printf("%d setlinecap\n", LineCap);
- printf("%d setlinejoin\n", LineJoin);
-
- printf("%.3f %.3f %.3f %.2f SP\n", Pens[1].rgb[0], Pens[1].rgb[1],
- Pens[1].rgb[2], Pens[1].width * PenScaling);
-
- puts("gsave");
-
- if (Duplex && (PageCount & 1) == 0)
- switch ((PageRotation / 90 + landscape) & 3)
- {
- case 0 :
- printf("%.1f %.1f translate\n", PageWidth - PageRight, PageBottom);
- break;
- case 1 :
- printf("%.0f 0 translate 90 rotate\n", PageLength);
- printf("%.1f %.1f translate\n", PageLength - PageTop,
- PageWidth - PageRight);
- break;
- case 2 :
- printf("%.0f %.0f translate 180 rotate\n", PageWidth, PageLength);
- printf("%.1f %.1f translate\n", PageLeft, PageLength - PageTop);
- break;
- case 3 :
- printf("0 %.0f translate -90 rotate\n", PageWidth);
- printf("%.1f %.1f translate\n", PageBottom, PageLeft);
- break;
- }
- else
- switch ((PageRotation / 90 + landscape) & 3)
- {
- case 0 :
- printf("%.1f %.1f translate\n", PageLeft, PageBottom);
- break;
- case 1 :
- printf("%.0f 0 translate 90 rotate\n", PageLength);
- printf("%.1f %.1f translate\n", PageBottom, PageWidth - PageRight);
- break;
- case 2 :
- printf("%.0f %.0f translate 180 rotate\n", PageWidth, PageLength);
- printf("%.1f %.1f translate\n", PageWidth - PageRight,
- PageLength - PageTop);
- break;
- case 3 :
- printf("0 %.0f translate -90 rotate\n", PageWidth);
- printf("%.1f %.1f translate\n", PageLength - PageTop, PageLeft);
- break;
- }
-
- if (IW1[0] != IW2[0] && IW1[1] != IW2[1])
- {
- iw1[0] = IW1[0] * 72.0f / 1016.0f;
- iw1[1] = IW1[1] * 72.0f / 1016.0f;
- iw2[0] = IW2[0] * 72.0f / 1016.0f;
- iw2[1] = IW2[1] * 72.0f / 1016.0f;
-
- printf("initclip MP %.3f %.3f MO %.3f %.3f LI %.3f %.3f LI %.3f %.3f LI CP clip\n",
- iw1[0], iw1[1], iw1[0], iw2[1], iw2[0], iw2[1], iw2[0], iw1[1]);
- }
- }
-
- /*
- * Write the string to the output file...
- */
-
- va_start(ap, format);
- bytes = vprintf(format, ap);
- va_end(ap);
-
- return (bytes);
-}
-
-
-/*
- * End of "$Id: hpgl-prolog.c 6649 2007-07-11 21:46:42Z mike $".
- */
+++ /dev/null
-/*
- * "$Id: hpgl-vector.c 6649 2007-07-11 21:46:42Z mike $"
- *
- * HP-GL/2 vector routines for the Common UNIX Printing System (CUPS).
- *
- * Copyright 2007-2008 by Apple Inc.
- * Copyright 1993-2007 by Easy Software Products.
- *
- * These coded instructions, statements, and computer programs are the
- * property of Apple Inc. and are protected by Federal copyright
- * law. Distribution and use rights are outlined in the file "LICENSE.txt"
- * which should have been included with this file. If this file is
- * file is missing or damaged, see the license at "http://www.cups.org/".
- *
- * This file is subject to the Apple OS-Developed Software exception.
- *
- * Contents:
- *
- * AA_arc_absolute() - Draw an arc.
- * AR_arc_relative() - Draw an arc relative to the current pen
- * AT_arc_absolute3() - Draw an arc using 3 points.
- * CI_circle() - Draw a circle.
- * PA_plot_absolute() - Plot a line using absolute coordinates.
- * PD_pen_down() - Start drawing.
- * PE_polygon_encoded() - Draw an encoded polyline.
- * PR_plot_relative() - Plot a line using relative coordinates.
- * PU_pen_up() - Stop drawing.
- * RT_arc_relative3() - Draw an arc through 3 points relative to the
- * decode_number() - Decode an encoded number.
- * plot_points() - Plot the specified points.
- */
-
-/*
- * Include necessary headers...
- */
-
-#include "hpgltops.h"
-
-
-/*
- * Local functions...
- */
-
-static double decode_number(unsigned char **, int, double);
-static void plot_points(int, param_t *);
-
-
-/*
- * 'AA_arc_absolute()' - Draw an arc.
- */
-
-void
-AA_arc_absolute(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- float x, y, /* Transformed coordinates */
- dx, dy; /* Distance from current pen */
- float start, end, /* Start and end angles */
- theta, /* Current angle */
- dt, /* Step between points */
- radius; /* Radius of arc */
-
-
- if (num_params < 3)
- return;
-
- x = Transform[0][0] * params[0].value.number +
- Transform[0][1] * params[1].value.number +
- Transform[0][2];
- y = Transform[1][0] * params[0].value.number +
- Transform[1][1] * params[1].value.number +
- Transform[1][2];
-
- dx = PenPosition[0] - x;
- dy = PenPosition[1] - y;
-
- start = (float)(180.0 * atan2(dy, dx) / M_PI);
- if (start < 0.0)
- start += 360.0f;
-
- end = start + params[2].value.number;
- radius = (float)hypot(dx, dy);
-
- if (PenDown)
- {
- if (num_params > 3 && params[3].value.number > 0.0)
- dt = (float)fabs(params[3].value.number);
- else
- dt = 5.0;
-
- if (!PolygonMode)
- Outputf("MP\n");
-
- PenValid = 1;
-
- Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]);
-
- if (start < end)
- for (theta = start + dt; theta < end; theta += dt)
- {
- PenPosition[0] = (float)(x + radius * cos(M_PI * theta / 180.0));
- PenPosition[1] = (float)(y + radius * sin(M_PI * theta / 180.0));
-
- Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]);
- }
- else
- for (theta = start - dt; theta > end; theta -= dt)
- {
- PenPosition[0] = (float)(x + radius * cos(M_PI * theta / 180.0));
- PenPosition[1] = (float)(y + radius * sin(M_PI * theta / 180.0));
-
- Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]);
- }
- }
-
- PenPosition[0] = (float)(x + radius * cos(M_PI * end / 180.0));
- PenPosition[1] = (float)(y + radius * sin(M_PI * end / 180.0));
-
- if (PenDown)
- {
- Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]);
-
- if (!PolygonMode)
- Outputf("ST\n");
- }
-}
-
-
-/*
- * 'AR_arc_relative()' - Draw an arc relative to the current pen
- * position.
- */
-
-void
-AR_arc_relative(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- float x, y, /* Transformed coordinates */
- dx, dy; /* Distance from current pen */
- float start, end, /* Start and end angles */
- theta, /* Current angle */
- dt, /* Step between points */
- radius; /* Radius of arc */
-
-
- if (num_params < 3)
- return;
-
- x = Transform[0][0] * params[0].value.number +
- Transform[0][1] * params[1].value.number +
- PenPosition[0];
- y = Transform[1][0] * params[0].value.number +
- Transform[1][1] * params[1].value.number +
- PenPosition[1];
-
- dx = PenPosition[0] - x;
- dy = PenPosition[1] - y;
-
- start = (float)(180.0 * atan2(dy, dx) / M_PI);
- if (start < 0.0)
- start += 360.0f;
-
- end = start + params[2].value.number;
- radius = (float)hypot(dx, dy);
-
- if (PenDown)
- {
- if (num_params > 3 && params[3].value.number > 0.0)
- dt = (float)fabs(params[3].value.number);
- else
- dt = 5.0;
-
- if (!PolygonMode)
- Outputf("MP\n");
-
- PenValid = 1;
-
- Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]);
-
- if (start < end)
- for (theta = start + dt; theta < end; theta += dt)
- {
- PenPosition[0] = (float)(x + radius * cos(M_PI * theta / 180.0));
- PenPosition[1] = (float)(y + radius * sin(M_PI * theta / 180.0));
-
- Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]);
- }
- else
- for (theta = start - dt; theta > end; theta -= dt)
- {
- PenPosition[0] = (float)(x + radius * cos(M_PI * theta / 180.0));
- PenPosition[1] = (float)(y + radius * sin(M_PI * theta / 180.0));
-
- Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]);
- }
- }
-
- PenPosition[0] = (float)(x + radius * cos(M_PI * end / 180.0));
- PenPosition[1] = (float)(y + radius * sin(M_PI * end / 180.0));
-
- if (PenDown)
- {
- Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]);
-
- if (!PolygonMode)
- Outputf("ST\n");
- }
-}
-
-
-/*
- * 'AT_arc_absolute3()' - Draw an arc using 3 points.
- *
- * Note:
- *
- * Currently this only draws two line segments through the
- * specified points.
- */
-
-void
-AT_arc_absolute3(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- if (num_params < 4)
- return;
-
- if (PenDown)
- {
- if (!PolygonMode)
- Outputf("MP\n");
-
- PenValid = 1;
-
- Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]);
-
- PenPosition[0] = Transform[0][0] * params[0].value.number +
- Transform[0][1] * params[1].value.number +
- Transform[0][2];
- PenPosition[1] = Transform[1][0] * params[0].value.number +
- Transform[1][1] * params[1].value.number +
- Transform[1][2];
-
- Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]);
- }
-
- PenPosition[0] = Transform[0][0] * params[2].value.number +
- Transform[0][1] * params[3].value.number +
- Transform[0][2];
- PenPosition[1] = Transform[1][0] * params[2].value.number +
- Transform[1][1] * params[3].value.number +
- Transform[1][2];
-
- if (PenDown)
- {
- Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]);
-
- if (!PolygonMode)
- Outputf("ST\n");
- }
-}
-
-
-/*
- * 'CI_circle()' - Draw a circle.
- */
-
-void
-CI_circle(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- float x, y; /* Transformed coordinates */
- float theta, /* Current angle */
- dt, /* Step between points */
- radius; /* Radius of circle */
-
-
- if (num_params < 1)
- return;
-
- if (!PenDown)
- return;
-
- radius = params[0].value.number;
-
- if (num_params > 1)
- dt = (float)fabs(params[1].value.number);
- else
- dt = 5.0;
-
- if (!PolygonMode)
- Outputf("MP\n");
-
- PenValid = 1;
-
- for (theta = 0.0; theta < 360.0; theta += dt)
- {
- x = (float)(PenPosition[0] +
- radius * cos(M_PI * theta / 180.0) * Transform[0][0] +
- radius * sin(M_PI * theta / 180.0) * Transform[0][1]);
- y = (float)(PenPosition[1] +
- radius * cos(M_PI * theta / 180.0) * Transform[1][0] +
- radius * sin(M_PI * theta / 180.0) * Transform[1][1]);
-
- Outputf("%.3f %.3f %s\n", x, y, theta == 0.0 ? "MO" : "LI");
- }
-
- Outputf("CP\n");
- if (!PolygonMode)
- Outputf("ST\n");
-}
-
-
-/*
- * 'PA_plot_absolute()' - Plot a line using absolute coordinates.
- */
-
-void
-PA_plot_absolute(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- PenMotion = 0;
-
- if (num_params > 1)
- plot_points(num_params, params);
-}
-
-
-/*
- * 'PD_pen_down()' - Start drawing.
- */
-
-void
-PD_pen_down(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- PenDown = 1;
-
- if (num_params > 1)
- plot_points(num_params, params);
-}
-
-
-/*
- * 'PE_polygon_encoded()' - Draw an encoded polyline.
- */
-
-void
-PE_polyline_encoded(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- unsigned char *s; /* Pointer into string */
- int temp, /* Temporary value */
- base_bits, /* Data bits per byte */
- draw, /* Draw or move */
- abscoords; /* Use absolute coordinates */
- double tx, ty, /* Transformed coordinates */
- x, y, /* Raw coordinates */
- frac_bits; /* Multiplier for encoded number */
-
-
- base_bits = 6;
- frac_bits = 1.0;
- draw = PenDown;
- abscoords = 0;
-
- if (num_params == 0)
- return;
-
- if (!PolygonMode)
- {
- Outputf("MP\n");
- PenValid = 0;
- }
-
- if (!PenValid)
- {
- Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]);
- PenValid = 1;
- }
-
- for (s = (unsigned char *)params[0].value.string; *s != '\0';)
- switch (*s)
- {
- case '7' :
- s ++;
- base_bits = 5;
-
-#ifdef DEBUG
- fputs("DEBUG: 7-bit\n", stderr);
-#endif /* DEBUG */
-
- Outputf("%% PE: 7-bit\n");
- break;
- case ':' : /* Select pen */
- s ++;
- temp = (int)decode_number(&s, base_bits, 1.0) - 1;
- if (temp < 0 || temp >= PenCount)
- {
- fprintf(stderr, "DEBUG: Bad pen number %d in PE\n", temp + 1);
- return;
- }
-
- PenNumber = temp;
-
-#ifdef DEBUG
- fprintf(stderr, "DEBUG: set pen #%d\n", PenNumber + 1);
-#endif /* DEBUG */
-
- Outputf("%% PE: set pen #%d\n", PenNumber + 1);
-
- if (PageDirty)
- printf("%.3f %.3f %.3f %.2f SP\n", Pens[PenNumber].rgb[0],
- Pens[PenNumber].rgb[1], Pens[PenNumber].rgb[2],
- Pens[PenNumber].width * PenScaling);
- break;
- case '<' : /* Next coords are a move-to */
- draw = 0;
- s ++;
-
-#ifdef DEBUG
- fputs("DEBUG: moveto\n", stderr);
-#endif /* DEBUG */
-
- Outputf("%% PE: moveto\n");
- break;
- case '>' : /* Set fractional bits */
- s ++;
- temp = (int)decode_number(&s, base_bits, 1.0);
- frac_bits = 1.0 / (1 << temp);
-
-#ifdef DEBUG
- fprintf(stderr, "DEBUG: set fractional bits %d\n", temp);
-#endif /* DEBUG */
-
- Outputf("%% PE: set fractional bits %d\n", temp);
- break;
- case '=' : /* Next coords are absolute */
- s ++;
- abscoords = 1;
-
-#ifdef DEBUG
- fputs("DEBUG: absolute\n", stderr);
-#endif /* DEBUG */
-
- Outputf("%% PE: absolute\n");
- break;
- default :
- if (*s >= 63)
- {
- /*
- * Coordinate...
- */
-
- x = decode_number(&s, base_bits, frac_bits);
- y = decode_number(&s, base_bits, frac_bits);
-
-#ifdef DEBUG
- fprintf(stderr, "DEBUG: coords %.3f %.3f\n", x, y);
-#endif /* DEBUG */
-
- Outputf("%% PE: coords %.3f %.3f\n", x, y);
-
- if (abscoords)
- {
- tx = Transform[0][0] * x + Transform[0][1] * y +
- Transform[0][2];
- ty = Transform[1][0] * x + Transform[1][1] * y +
- Transform[1][2];
- }
- else if (x == 0.0 && y == 0.0)
- {
- draw = 1;
- continue;
- }
- else
- {
- tx = Transform[0][0] * x + Transform[0][1] * y +
- PenPosition[0];
- ty = Transform[1][0] * x + Transform[1][1] * y +
- PenPosition[1];
- }
-
- if (draw)
- {
- if (fabs(PenPosition[0] - tx) > 0.001 ||
- fabs(PenPosition[1] - ty) > 0.001)
- Outputf("%.3f %.3f LI\n", tx, ty);
- }
- else
- Outputf("%.3f %.3f MO\n", tx, ty);
-
- PenPosition[0] = (float)tx;
- PenPosition[1] = (float)ty;
-
- draw = 1;
- abscoords = 0;
- }
- else
- {
- /*
- * Junk - ignore...
- */
-
- if (*s != '\n' && *s != '\r')
- fprintf(stderr, "WARNING: ignoring illegal PE char \'%c\'...\n", *s);
- s ++;
- }
- break;
- }
-
- if (!PolygonMode)
- Outputf("ST\n");
-}
-
-
-/*
- * 'PR_plot_relative()' - Plot a line using relative coordinates.
- */
-
-void
-PR_plot_relative(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- PenMotion = 1;
-
- if (num_params > 1)
- plot_points(num_params, params);
-}
-
-
-/*
- * 'PU_pen_up()' - Stop drawing.
- */
-
-void
-PU_pen_up(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- PenDown = 0;
-
- if (num_params > 1)
- plot_points(num_params, params);
-}
-
-
-/*
- * 'RT_arc_relative3()' - Draw an arc through 3 points relative to the
- * current pen position.
- *
- * Note:
- *
- * This currently only draws two line segments through the specified
- * points.
- */
-
-void
-RT_arc_relative3(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- if (num_params < 4)
- return;
-
- if (PenDown)
- {
- if (!PolygonMode)
- Outputf("MP\n");
-
- PenValid = 1;
-
- Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]);
-
- PenPosition[0] = Transform[0][0] * params[0].value.number +
- Transform[0][1] * params[1].value.number +
- PenPosition[0];
- PenPosition[1] = Transform[1][0] * params[0].value.number +
- Transform[1][1] * params[1].value.number +
- PenPosition[1];
-
- Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]);
- }
-
- PenPosition[0] = Transform[0][0] * params[2].value.number +
- Transform[0][1] * params[3].value.number +
- PenPosition[0];
- PenPosition[1] = Transform[1][0] * params[2].value.number +
- Transform[1][1] * params[3].value.number +
- PenPosition[1];
-
- if (PenDown)
- {
- Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]);
-
- if (!PolygonMode)
- Outputf("ST\n");
- }
-}
-
-
-/*
- * 'decode_number()' - Decode an encoded number.
- */
-
-static double /* O - Value */
-decode_number(unsigned char **s, /* IO - String to decode */
- int base_bits, /* I - Number of data bits per byte */
- double frac_bits) /* I - Multiplier for fractional data */
-{
- double temp, /* Current value */
- shift; /* Multiplier */
- int sign; /* Sign of result */
-
-
- sign = 0;
-
- if (base_bits == 5)
- {
- for (temp = 0.0, shift = frac_bits * 0.5; **s != '\0'; (*s) ++)
- if (**s >= 95 && **s < 127)
- {
- if (sign == 0)
- {
- if ((**s - 95) & 1)
- sign = -1;
- else
- sign = 1;
-
- temp += ((**s - 95) & ~1) * shift;
- }
- else
- temp += (**s - 95) * shift;
- break;
- }
- else if (**s < 63)
- {
- if (**s != '\r' && **s != '\n')
- fprintf(stderr, "DEBUG: Bad PE character 0x%02X!\n", **s);
-
- continue;
- }
- else
- {
- if (sign == 0)
- {
- if ((**s - 63) & 1)
- sign = -1;
- else
- sign = 1;
-
- temp += ((**s - 63) & ~1) * shift;
- }
- else
- temp += (**s - 63) * shift;
-
- shift *= 32.0;
- }
- }
- else
- {
- for (temp = 0.0, shift = frac_bits * 0.5; **s != '\0'; (*s) ++)
- if (**s >= 191 && **s < 255)
- {
- if (sign == 0)
- {
- if ((**s - 191) & 1)
- sign = -1;
- else
- sign = 1;
-
- temp += ((**s - 191) & ~1) * shift;
- }
- else
- temp += (**s - 191) * shift;
- break;
- }
- else if (**s < 63)
- {
- if (**s != '\r' && **s != '\n')
- fprintf(stderr, "DEBUG: Bad PE character 0x%02X!\n", **s);
-
- continue;
- }
- else
- {
- if (sign == 0)
- {
- if ((**s - 63) & 1)
- sign = -1;
- else
- sign = 1;
-
- temp += ((**s - 63) & ~1) * shift;
- }
- else
- temp += (**s - 63) * shift;
-
- shift *= 64.0;
- }
- }
-
- (*s) ++;
-
- return (temp * sign);
-}
-
-
-/*
- * 'plot_points()' - Plot the specified points.
- */
-
-static void
-plot_points(int num_params, /* I - Number of parameters */
- param_t *params) /* I - Parameters */
-{
- int i; /* Looping var */
- float x, y; /* Transformed coordinates */
-
-
- if (PenDown)
- {
- if (!PolygonMode)
- {
- Outputf("MP\n");
- Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]);
-
- PenValid = 1;
- }
- }
-
- for (i = 0; i < num_params; i += 2)
- {
- if (PenMotion == 0)
- {
- x = Transform[0][0] * params[i + 0].value.number +
- Transform[0][1] * params[i + 1].value.number +
- Transform[0][2];
- y = Transform[1][0] * params[i + 0].value.number +
- Transform[1][1] * params[i + 1].value.number +
- Transform[1][2];
- }
- else
- {
- x = Transform[0][0] * params[i + 0].value.number +
- Transform[0][1] * params[i + 1].value.number +
- PenPosition[0];
- y = Transform[1][0] * params[i + 0].value.number +
- Transform[1][1] * params[i + 1].value.number +
- PenPosition[1];
- }
-
- if (PenDown)
- {
- if (PolygonMode && i == 0)
- Outputf("%.3f %.3f MO\n", x, y);
- else if (fabs(PenPosition[0] - x) > 0.001 ||
- fabs(PenPosition[1] - y) > 0.001)
- Outputf("%.3f %.3f LI\n", x, y);
- }
-
- PenPosition[0] = x;
- PenPosition[1] = y;
- }
-
- if (PenDown)
- {
- if (!PolygonMode)
- Outputf("ST\n");
- }
-}
-
-
-/*
- * End of "$Id: hpgl-vector.c 6649 2007-07-11 21:46:42Z mike $".
- */
+++ /dev/null
-/*
- * "$Id: hpgltops.h 6649 2007-07-11 21:46:42Z mike $"
- *
- * HP-GL/2 to PostScript filter for the Common UNIX Printing System (CUPS).
- *
- * Copyright 2007 by Apple Inc.
- * Copyright 1993-2005 by Easy Software Products.
- *
- * These coded instructions, statements, and computer programs are the
- * property of Apple Inc. and are protected by Federal copyright
- * law. Distribution and use rights are outlined in the file "LICENSE.txt"
- * which should have been included with this file. If this file is
- * file is missing or damaged, see the license at "http://www.cups.org/".
- *
- * This file is subject to the Apple OS-Developed Software exception.
- */
-
-/*
- * Include necessary headers...
- */
-
-#include "common.h"
-#include <math.h>
-
-#ifndef M_PI
-# define M_PI 3.14159265358979323846
-#endif /* M_PI */
-
-
-/*
- * Maximum number of pens we emulate...
- */
-
-#define MAX_PENS 1024
-
-
-/*
- * Parameter value structure...
- */
-
-typedef struct
-{
- int type;
- union
- {
- float number;
- char *string;
- } value;
-} param_t;
-
-#define PARAM_ABSOLUTE 0
-#define PARAM_RELATIVE 1
-#define PARAM_STRING 2
-
-
-/*
- * Font information...
- */
-
-typedef struct
-{
- int symbol_set, /* Symbol set */
- spacing, /* Spacing (0 = fixed, 1 = proportional) */
- posture, /* Posture number */
- weight, /* Weight number */
- typeface; /* Typeface number */
- float pitch, /* Characters per inch */
- height, /* Height/size of font */
- xpitch; /* X pitch scaling value */
- float x, y; /* X and Y direction/scaling */
-} font_t;
-
-
-/*
- * Pen information...
- */
-
-typedef struct
-{
- float rgb[3]; /* Pen color */
- float width; /* Pen width */
-} pen_t;
-
-
-/*
- * Globals...
- */
-
-#ifdef _HPGL_MAIN_C_
-# define VAR
-# define VALUE(x) =x
-# define VALUE2(x,y) ={x,y}
-#else
-# define VAR extern
-# define VALUE(x)
-# define VALUE2(x,y)
-#endif /* _HPGL_MAIN_C_ */
-
-VAR ppd_file_t *PPD VALUE(NULL); /* PPD file */
-
-VAR float P1[2], /* Lower-lefthand physical limit */
- P2[2], /* Upper-righthand physical limit */
- IW1[2], /* Window lower-lefthand limit */
- IW2[2]; /* Window upper-righthand limit */
-VAR int Rotation VALUE(0); /* Page rotation */
-VAR int ScalingType VALUE(-1); /* Type of scaling (-1 for none) */
-VAR float Scaling1[2], /* Lower-lefthand user limit */
- Scaling2[2]; /* Upper-righthand user limit */
-VAR float Transform[2][3]; /* Transform matrix */
-VAR int PageRotation VALUE(0); /* Page/plot rotation */
-
-VAR char StringTerminator VALUE('\003'); /* Terminator for labels */
-VAR font_t StandardFont, /* Standard font */
- AlternateFont; /* Alternate font */
-VAR float PenPosition[2] VALUE2(0.0f, 0.0f),
- /* Current pen position */
- PenScaling VALUE(1.0f), /* Pen width scaling factor */
- PenWidth VALUE(1.0f); /* Default pen width */
-VAR pen_t Pens[MAX_PENS]; /* State of each pen */
-VAR int PenMotion VALUE(0), /* 0 = absolute, 1 = relative */
- PenValid VALUE(0), /* 1 = valid position, 0 = undefined */
- PenNumber VALUE(0), /* Current pen number */
- PenCount VALUE(8), /* Number of pens */
- PenDown VALUE(0), /* 0 = pen up, 1 = pen down */
- PolygonMode VALUE(0), /* Drawing polygons? */
- PageCount VALUE(0), /* Number of pages in plot */
- PageDirty VALUE(0), /* Current page written on? */
- WidthUnits VALUE(0); /* 0 = mm, 1 = proportionate */
-VAR float PlotSize[2] VALUE2(2592.0f, 3456.0f);
- /* Plot size */
-VAR int PlotSizeSet VALUE(0); /* Plot size set? */
-VAR int CharFillMode VALUE(0), /* Where to draw labels */
- CharPen VALUE(0), /* Pen to use for labels */
- CharFont VALUE(0); /* Font to use for labels */
-VAR float CharHeight[2] VALUE2(11.5f,11.5f);
- /* Size of font for labels */
-VAR int FitPlot VALUE(0); /* 1 = fit to page */
-VAR float ColorRange[3][2] /* Range of color values */
-#ifdef _HPGL_MAIN_C_
- = {
- { 0.0, 255.0 },
- { 0.0, 255.0 },
- { 0.0, 255.0 }
- }
-#endif /* _HPGL_MAIN_C_ */
-;
-
-VAR int LineCap VALUE(0); /* Line capping */
-VAR int LineJoin VALUE(0); /* Line joining */
-VAR float MiterLimit VALUE(3.0f); /* Miter limit at joints */
-
-
-/*
- * Prototypes...
- */
-
-/* hpgl-input.c */
-extern int ParseCommand(FILE *fp, char *name, param_t **params);
-extern void FreeParameters(int num_params, param_t *params);
-
-/* hpgl-config.c */
-extern void update_transform(void);
-extern void BP_begin_plot(int num_params, param_t *params);
-extern void DF_default_values(int num_params, param_t *params);
-extern void IN_initialize(int num_params, param_t *params);
-extern void IP_input_absolute(int num_params, param_t *params);
-extern void IR_input_relative(int num_params, param_t *params);
-extern void IW_input_window(int num_params, param_t *params);
-extern void PG_advance_page(int num_params, param_t *params);
-extern void PS_plot_size(int num_params, param_t *params);
-extern void RO_rotate(int num_params, param_t *params);
-extern void RP_replot(int num_params, param_t *params);
-extern void SC_scale(int num_params, param_t *params);
-
-/* hpgl-vector.c */
-extern void AA_arc_absolute(int num_params, param_t *params);
-extern void AR_arc_relative(int num_params, param_t *params);
-extern void AT_arc_absolute3(int num_params, param_t *params);
-extern void CI_circle(int num_params, param_t *params);
-extern void PA_plot_absolute(int num_params, param_t *params);
-extern void PD_pen_down(int num_params, param_t *params);
-extern void PE_polyline_encoded(int num_params, param_t *params);
-extern void PR_plot_relative(int num_params, param_t *params);
-extern void PU_pen_up(int num_params, param_t *params);
-extern void RT_arc_relative3(int num_params, param_t *params);
-
-/* hpgl-polygon.c */
-extern void EA_edge_rect_absolute(int num_params, param_t *params);
-extern void EP_edge_polygon(int num_params, param_t *params);
-extern void ER_edge_rect_relative(int num_params, param_t *params);
-extern void EW_edge_wedge(int num_params, param_t *params);
-extern void FP_fill_polygon(int num_params, param_t *params);
-extern void PM_polygon_mode(int num_params, param_t *params);
-extern void RA_fill_rect_absolute(int num_params, param_t *params);
-extern void RR_fill_rect_relative(int num_params, param_t *params);
-extern void WG_fill_wedge(int num_params, param_t *params);
-
-/* hpgl-char.c */
-extern void define_font(int f);
-extern void AD_define_alternate(int num_params, param_t *params);
-extern void CF_character_fill(int num_params, param_t *params);
-extern void CP_character_plot(int num_params, param_t *params);
-extern void DI_absolute_direction(int num_params, param_t *params);
-extern void DR_relative_direction(int num_params, param_t *params);
-extern void DT_define_label_term(int num_params, param_t *params);
-extern void DV_define_variable_path(int num_params, param_t *params);
-extern void ES_extra_space(int num_params, param_t *params);
-extern void LB_label(int num_params, param_t *params);
-extern void LO_label_origin(int num_params, param_t *params);
-extern void SA_select_alternate(int num_params, param_t *params);
-extern void SD_define_standard(int num_params, param_t *params);
-extern void SI_absolute_size(int num_params, param_t *params);
-extern void SL_character_slant(int num_params, param_t *params);
-extern void SR_relative_size(int num_params, param_t *params);
-extern void SS_select_standard(int num_params, param_t *params);
-extern void TD_transparent_data(int num_params, param_t *params);
-
-/* hpgl-attr.c */
-extern void AC_anchor_corner(int num_params, param_t *params);
-extern void CR_color_range(int num_params, param_t *params);
-extern void FT_fill_type(int num_params, param_t *params);
-extern void LA_line_attributes(int num_params, param_t *params);
-extern void LT_line_type(int num_params, param_t *params);
-extern void NP_number_pens(int num_params, param_t *params);
-extern void PC_pen_color(int num_params, param_t *params);
-extern void PW_pen_width(int num_params, param_t *params);
-extern void RF_raster_fill(int num_params, param_t *params);
-extern void SM_symbol_mode(int num_params, param_t *params);
-extern void SP_select_pen(int num_params, param_t *params);
-extern void UL_user_line_type(int num_params, param_t *params);
-extern void WU_width_units(int num_params, param_t *params);
-
-/* hpgl-prolog.c */
-extern void OutputProlog(char *title, char *user, int shading);
-extern void OutputTrailer(void);
-extern int Outputf(const char *format, ...);
-
-/*
- * End of "$Id: hpgltops.h 6649 2007-07-11 21:46:42Z mike $".
- */
#
# Man page makefile for the Common UNIX Printing System (CUPS).
#
-# Copyright 2007-2008 by Apple Inc.
+# Copyright 2007-2010 by Apple Inc.
# Copyright 1993-2006 by Easy Software Products.
#
# These coded instructions, statements, and computer programs are the
cups-config.$(MAN1EXT) \
cupstestdsc.$(MAN1EXT) \
cupstestppd.$(MAN1EXT) \
+ ipptest.$(MAN1EXT) \
lp.$(MAN1EXT) \
lpoptions.$(MAN1EXT) \
lppasswd.$(MAN1EXT) \
client.conf.$(MAN5EXT) \
cups-snmp.conf.$(MAN5EXT) \
cupsd.conf.$(MAN5EXT) \
+ ipp.test.$(MAN5EXT) \
mailto.conf.$(MAN5EXT) \
mime.convs.$(MAN5EXT) \
mime.types.$(MAN5EXT) \
.\"
.\" cupsd.conf man page for the Common UNIX Printing System (CUPS).
.\"
-.\" Copyright 2007-2009 by Apple Inc.
+.\" Copyright 2007-2010 by Apple Inc.
.\" Copyright 1997-2006 by Easy Software Products.
.\"
.\" These coded instructions, statements, and computer programs are the
.\" which should have been included with this file. If this file is
.\" file is missing or damaged, see the license at "http://www.cups.org/".
.\"
-.TH cupsd.conf 5 "CUPS" "14 July 2009" "Apple Inc."
+.TH cupsd.conf 5 "CUPS" "28 January 2010" "Apple Inc."
.SH NAME
cupsd.conf \- server configuration file for cups
.SH DESCRIPTION
.br
Specifies the default type of authentication to use.
.TP 5
-DefaultCharset charset
-.br
-Specifies the default character set to use for text.
-.TP 5
DefaultEncryption Never
.TP 5
DefaultEncryption IfRequested
--- /dev/null
+.\"
+.\" "$Id$"
+.\"
+.\" ipp.test man page for CUPS.
+.\"
+.\" Copyright 2010 by Apple Inc.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. and are protected by Federal copyright
+.\" law. Distribution and use rights are outlined in the file "LICENSE.txt"
+.\" which should have been included with this file. If this file is
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH ipp.test 5 "CUPS" "23 February 2010" "Apple Inc."
+.SH NAME
+ipp.test \- ipptest test file format
+
+.SH DESCRIPTION
+The \fIipptest(1)\fR program accepts free-form plain text files that describe
+one or more IPP operation tests. Comments start with the "#" character and
+continue to the end of the line. Each test is enclosed by curley braces, for
+example:
+.nf
+
+ # This is a comment
+ {
+ # The name of the test
+ NAME "Print PostScript Job"
+
+ # The request to send
+ OPERATION Print-Job
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ FILE testfile.ps
+
+ # The response to expect
+ STATUS successful-ok
+ EXPECT attributes-charset OF-TYPE charset
+ EXPECT attributes-natural-language OF-TYPE naturalLanguage
+ EXPECT job-id OF-TYPE integer
+ EXPECT job-uri OF-TYPE uri
+ }
+ {
+ # The name of the test
+ NAME "Get Attributes of PostScript Job"
+
+ # The request to send
+ OPERATION Get-Job-Attributes
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR integer job-id $job-id
+ ATTR name requesting-user-name $user
+
+ # The response to expect
+ STATUS successful-ok
+ EXPECT attributes-charset OF-TYPE charset
+ EXPECT attributes-natural-language OF-TYPE naturalLanguage
+ EXPECT job-id OF-TYPE integer
+ EXPECT job-uri OF-TYPE uri
+ EXPECT job-state OF-TYPE enum
+ EXPECT job-originating-user-name OF-TYPE name WITH-VALUE "$user"
+ }
+.fi
+
+.SH TOP-LEVEL DIRECTIVES
+The following directives can be used outside of a test:
+.TP 5
+{ test }
+Defines a test.
+.TP 5
+DEFINE variable-name value
+Defines the named variable to the given value. This is equivalent to specifying
+"-d variable-name=value" on the \fIipptest\fR command-line.
+.TP 5
+INCLUDE "filename"
+.TP 5
+INCLUDE <filename>
+Includes another test file. The first form includes a file relative to the
+current test file, while the second form includes a file from the \fIipptest\fR
+include directory.
+.TP 5
+TRANSFER auto
+Specifies that tests will, by default, use "Transfer-Encoding: chunked" for
+requests with attached files and "Content-Length:" for requests without attached
+files.
+.TP 5
+TRANSFER chunked
+Specifies that tests will, by default, use the HTTP/1.1 "Transfer-Encoding:
+chunked" header. This is the default and is equivalent to specifying "-c" on the
+\fIipptest\fR command-line. Support for chunked requests is required for
+conformance with all versions of IPP.
+.TP 5
+TRANSFER length
+Specifies that tests will, by default, use the HTTP/1.0 "Content-Length:"
+header. This is equivalent to specifying "-l" on the \fIipptest\fR command-line.
+Support for content length requests is required for conformance with all
+versions of IPP.
+.TP 5
+VERSION 1.0
+.TP 5
+VERSION 1.1
+.TP 5
+VERSION 2.0
+.TP 5
+VERSION 2.1
+.TP 5
+VERSION 2.2
+Specifies the default IPP version number to use for the tests that follow.
+
+.SH TEST DIRECTIVES
+The following directives are understood in a test:
+.TP 5
+ATTR tag attribute-name value(s)
+Adds an attribute to the test request. Values are separated by the comma (",")
+character - escape commas using the "\" character.
+.TP 5
+ATTR collection attribute-name { MEMBER tag member-name value(s) ... } [ ... { ... } ]
+Adds a collection attribute to the test request. Member attributes follow the
+same syntax as regular attributes and can themselves be nested collections.
+Multiple collection values can be supplied as needed.
+.TP 5
+DELAY seconds
+Specifies a delay before this test will be run.
+.TP 5
+DISPLAY attribute-name
+Specifies that value of the named attribute should be output as part of the
+test report.
+.TP 5
+EXPECT attribute-name [ predicate(s) ]
+.TP 5
+EXPECT ?attribute-name predicate(s)
+.TP 5
+EXPECT !attribute-name
+Specifies that the response must/may/must not include the named attribute.
+Additional requirements can be added as predicates - see the "EXPECT PREDICATES"
+section for more information on predicates.
+.TP 5
+FILE filename
+Specifies a file to include at the end of the request. This is typically used
+when sending a test print file.
+.TP 5
+GROUP tag
+Specifies the group tag for subsequent attributes in the request.
+.TP 5
+NAME "literal string"
+Specifies the human-readable name of the test.
+.TP 5
+OPERATION operation-code
+Specifies the operation to be performed.
+.TP 5
+REQUEST-ID number
+.TP 5
+REQUEST-ID random
+Specifies the request-id value to use in the request, either an integer or the
+word "random" to use a randomly generated value (the default).
+.TP 5
+RESOURCE path
+Specifies an alternate resource path that is used for the HTTP POST request.
+The default is the resource from the URI provided to the \fIipptest\fR program.
+.TP 5
+STATUS status-code [ predicate ]
+Specifies an expected response status-code value. Additional requirements can be
+added as predicates - see the "STATUS PREDICATES" section for more information
+on predicates.
+.TP 5
+TRANSFER auto
+Specifies that this test will use "Transfer-Encoding: chunked" if it has an
+attached file or "Content-Length:" otherwise.
+.TP 5
+TRANSFER chunked
+Specifies that this test will use the HTTP/1.1 "Transfer-Encoding: chunked"
+header.
+.TP 5
+TRANSFER length
+Specifies that this test will use the HTTP/1.0 "Content-Length:" header.
+.TP 5
+VERSION 1.0
+.TP 5
+VERSION 1.1
+.TP 5
+VERSION 2.0
+.TP 5
+VERSION 2.1
+.TP 5
+VERSION 2.2
+Specifies the IPP version number to use for this test.
+
+.SH EXPECT PREDICATES
+The following predicates are understood following the EXPECT test directive:
+.TP 5
+COUNT number
+Requires the EXPECT attribute to have the specified number of values.
+.TP 5
+IF-DEFINED variable-name
+Makes the EXPECT conditions apply only if the specified variable is defined.
+.TP 5
+IF-UNDEFINED variable-name
+Makes the EXPECT conditions apply only if the specified variable is not
+defined.
+.TP 5
+IN-GROUP tag
+Requires the EXPECT attribute to be in the specified group tag.
+.TP 5
+OF-TYPE tag[,tag,...]
+Requires the EXPECT attribute to use the specified value tag(s).
+.TP 5
+SAME-COUNT-AS attribute-name
+Requires the EXPECT attribute to have the same number of values as the specified
+parallel attribute.
+.TP 5
+WITH-VALUE "literal string"
+Requires at least one value of the EXPECT attribute to match the literal string.
+Comparisons are case-sensitive.
+.TP 5
+WITH-VALUE "/regular expression/"
+Requires that all values of the EXPECT attribute match the regular expression,
+which must conform to the POSIX regular expression syntax.
+Comparisons are case-sensitive.
+
+.SH STATUS PREDICATES
+The following predicates are understood following the STATUS test directive:
+.TP 5
+IF-DEFINED variable-name
+Makes the STATUS apply only if the specified variable is defined.
+.TP 5
+IF-UNDEFINED variable-name
+Makes the STATUS apply only if the specified variable is not defined.
+
+.SH OPERATION CODES
+Operation codes correspond to the names from RFC 2911 and other IPP extension
+specifications. Here is a complete list:
+.nf
+ Activate-Printer
+ CUPS-Accept-Jobs
+ CUPS-Add-Modify-Class
+ CUPS-Add-Modify-Printer
+ CUPS-Authenticate-Job
+ CUPS-Delete-Class
+ CUPS-Delete-Printer
+ CUPS-Get-Classes
+ CUPS-Get-Default
+ CUPS-Get-Devices
+ CUPS-Get-Document
+ CUPS-Get-PPD
+ CUPS-Get-PPDs
+ CUPS-Get-Printers
+ CUPS-Move-Job
+ CUPS-Reject-Jobs
+ CUPS-Set-Default
+ Cancel-Current-Job
+ Cancel-Job
+ Cancel-Subscription
+ Create-Job
+ Create-Job-Subscription
+ Create-Printer-Subscription
+ Deactivate-Printer
+ Disable-Printer
+ Enable-Printer
+ Get-Job-Attributes
+ Get-Jobs
+ Get-Notifications
+ Get-Printer-Attributes
+ Get-Printer-Support-Files
+ Get-Printer-Supported-Values
+ Get-Subscription-Attributes
+ Get-Subscriptions
+ Hold-Job
+ Hold-New-Jobs
+ Pause-Printer
+ Pause-Printer-After-Current-Job
+ Print-Job
+ Print-URI
+ Promote-Job
+ Purge-Jobs
+ Release-Held-New-Jobs
+ Release-Job
+ Renew-Subscription
+ Reprocess-Job
+ Restart-Job
+ Restart-Printer
+ Resume-Job
+ Resume-Printer
+ Schedule-Job-After
+ Send-Document
+ Send-Notifications
+ Send-URI
+ Set-Job-Attributes
+ Set-Printer-Attributes
+ Shutdown-Printer
+ Startup-Printer
+ Suspend-Current-Job
+ Validate-Job
+.fi
+
+.SH STATUS CODES
+Status codes correspond to the names from RFC 2911 and other IPP extension
+specifications. Here is a complete list:
+.nf
+ client-error-attributes-not-settable
+ client-error-attributes-or-values-not-supported
+ client-error-bad-request
+ client-error-charset-not-supported
+ client-error-compression-error
+ client-error-compression-not-supported
+ client-error-conflicting-attributes
+ client-error-document-access-error
+ client-error-document-format-error
+ client-error-document-format-not-supported
+ client-error-forbidden
+ client-error-gone
+ client-error-ignored-all-notifications
+ client-error-ignored-all-subscriptions
+ client-error-not-authenticated
+ client-error-not-authorized
+ client-error-not-found
+ client-error-not-possible
+ client-error-print-support-file-not-found
+ client-error-request-entity-too-large
+ client-error-request-value-too-long
+ client-error-timeout
+ client-error-too-many-subscriptions
+ client-error-uri-scheme-not-supported
+ cups-see-other
+ redirection-other-site
+ server-error-busy
+ server-error-device-error
+ server-error-internal-error
+ server-error-job-canceled
+ server-error-multiple-document-jobs-not-supported
+ server-error-not-accepting-jobs
+ server-error-operation-not-supported
+ server-error-printer-is-deactivated
+ server-error-service-unavailable
+ server-error-temporary-error
+ server-error-version-not-supported
+ successful-ok
+ successful-ok-but-cancel-subscription
+ successful-ok-conflicting-attributes
+ successful-ok-events-complete
+ successful-ok-ignored-notifications
+ successful-ok-ignored-or-substituted-attributes
+ successful-ok-ignored-subscriptions
+ successful-ok-too-many-events
+.fi
+
+.SH TAGS
+Value and group tags correspond to the names from RFC 2911 and other IPP
+extension specifications. Here are the group tags:
+.nf
+ event-notification-attributes-tag
+ job-attributes-tag
+ operation-attributes-tag
+ printer-attributes-tag
+ subscription-attributes-tag
+ unsupported-attributes-tag
+.fi
+.LP
+Here are the value tags:
+.nf
+ admin-define
+ boolean
+ charset
+ collection
+ dateTime
+ default
+ delete-attribute
+ enum
+ integer
+ keyword
+ mimeMediaType
+ nameWithLanguage
+ nameWithoutLanguage
+ naturalLanguage
+ no-value
+ not-settable
+ octetString
+ rangeOfInteger
+ resolution
+ textWithLanguage
+ textWithoutLanguage
+ unknown
+ unsupported
+ uri
+ uriScheme
+.fi
+
+.SH VARIABLES
+The \fIipptest\fR program maintains a list of variables that can be used in any
+literal string or attribute value by specifying "$variable-name". Aside from
+variables defined using the "-d" option or "DEFINE" directive, the following
+pre-defined variables are available:
+.TP 5
+$$
+Inserts a single "$" character.
+.TP 5
+$ENV[name]
+Inserts the value of the named environment variable, or an empty string if the
+environment variable is not defined.
+.TP 5
+$filename
+Inserts the filename provided to \fIipptest\fR with the "-f" option.
+.TP 5
+$hostname
+Inserts the hostname from the URI provided to \fIipptest\fR.
+.TP 5
+$job-id
+Inserts the last job-id value returned in a test response or 0 if no job-id has
+been seen.
+.TP 5
+$job-uri
+Inserts the last job-uri value returned in a test response or an empty string if
+no job-uri has been seen.
+.TP 5
+$scheme
+Inserts the scheme from the URI provided to \fIipptest\fR.
+.TP 5
+$notify-subscription-id
+Inserts the last notify-subscription-id value returnd in a test response or 0 if
+no notify-subscription-id has been seen.
+.TP 5
+$port
+Inserts the port number from the URI provided to \fIipptest\fR.
+.TP 5
+$resource
+Inserts the resource path from the URI provided to \fIipptest\fR.
+.TP 5
+$uri
+Inserts the URI provided to \fIipptest\fR.
+.TP 5
+$user
+Inserts the current user's login name.
+.TP 5
+$username
+Inserts the username from the URI provided to \fIipptest\fR, if any.
+
+.SH SEE ALSO
+\fIipptest(1)\fR,
+.br
+http://localhost:631/help
+
+.SH COPYRIGHT
+Copyright 2007-2010 by Apple Inc.
+.\"
+.\" End of "$Id$".
+.\"
--- /dev/null
+.\"
+.\" "$Id$"
+.\"
+.\" ipptest man page for CUPS.
+.\"
+.\" Copyright 2010 by Apple Inc.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. and are protected by Federal copyright
+.\" law. Distribution and use rights are outlined in the file "LICENSE.txt"
+.\" which should have been included with this file. If this file is
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH ipptest 1 "CUPS" "15 February 2010" "Apple Inc."
+.SH NAME
+ipptest - perform internet printing protocol tests
+.SH SYNOPSIS
+.B ipptest
+[ -E ] [ -V
+.I version
+] [ -X ] [ -c ] [ -d
+.I name=value
+] [ -f
+.I filename
+] [ -i
+.I seconds
+] [ -l ] [ -v ]
+.I URI
+.I filename.test
+[
+.I ... filenameN.test
+]
+.SH DESCRIPTION
+\fIipptest\fR sends IPP requests to the specified URI and tests the results.
+Each test file contains one or more test requests, including the expected
+response status, attributes, and values. Output is either a plain text or XML
+report on the standard output, with a non-zero exit status indicating that one
+or more tests have failed. The test file format is described in
+\fIipp.test(5)\fR.
+.SH OPTIONS
+The following options are recognized by \fIipptest\fR:
+.TP 5
+-E
+Forces encryption when connecting to the server.
+.TP 5
+-V version
+Specifies the default IPP version to use: 1.0, 1.1, 2.0, 2.1, or 2.2. If not
+specified, version 1.1 is used.
+.TP 5
+-X
+Specifies that XML (Apple plist) output is desired instead of the plain text
+report. This option is incompatible with the \fI-i\fR (interval) option.
+.TP 5
+-c
+Specifies that requests should be sent using the HTTP/1.1 "Transfer-Encoding:
+chunked" header, which is required for conformance by all versions of IPP. The
+default is to use "Transfer-Encoding: chunked" for requests with attached files
+and "Content-Length:" for requests without attached files.
+.TP 5
+-d name=value
+Defines the named variable.
+.TP 5
+-f filename
+Defines the default request filename for tests.
+.TP 5
+-i seconds
+Specifies that the (last) test should be repeated at the specified interval.
+This option is incompatible with the \fI-X\fR (XML output) option.
+.TP 5
+-l
+Specifies that requests should be sent using the HTTP/1.0 "Content-Length:"
+header, which is required for conformance by all versions of IPP. The
+default is to use "Transfer-Encoding: chunked" for requests with attached files
+and "Content-Length:" for requests without attached files.
+.TP 5
+-v
+Specifies that all request and response attributes should be output. This is the
+default for XML output.
+.SH COMPATIBILITY
+The \fIipptest\fR program is unique to CUPS.
+.SH SEE ALSO
+\fIipp.test(5)\fR,
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2010 by Apple Inc.
+.\"
+.\" End of "$Id$".
+.\"
#
# ESP Package Manager (EPM) file list for CUPS.
#
-# Copyright 2007-2009 by Apple Inc.
+# Copyright 2007-2010 by Apple Inc.
# Copyright 1997-2007 by Easy Software Products, all rights reserved.
#
# These coded instructions, statements, and computer programs are the
# Product information
%product CUPS
-%copyright 2007-2009 by Apple Inc.
+%copyright 2007-2010 by Apple Inc.
%vendor Apple Inc.
#%license LICENSE.txt
%readme LICENSE.txt
%endif
%system !darwin
f 0555 root sys $SERVERBIN/backend/parallel backend/parallel
-f 0555 root sys $SERVERBIN/backend/scsi backend/scsi
%system all
f 0555 root sys $SERVERBIN/backend/serial backend/serial
f 0555 root sys $SERVERBIN/backend/snmp backend/snmp
f 0555 root sys $SERVERBIN/filter/commandtopclx driver/commandtopclx
f 0555 root sys $SERVERBIN/filter/commandtops filter/commandtops
f 0555 root sys $SERVERBIN/filter/gziptoany filter/gziptoany
-f 0555 root sys $SERVERBIN/filter/hpgltops filter/hpgltops
%if IMGFILTERS
f 0555 root sys $SERVERBIN/filter/imagetops filter/imagetops
f 0555 root sys $SERVERBIN/filter/imagetoraster filter/imagetoraster
f 0555 root sys $BINDIR/cancel systemv/cancel
f 0555 root sys $BINDIR/cupstestdsc systemv/cupstestdsc
f 0555 root sys $BINDIR/cupstestppd systemv/cupstestppd
+f 0555 root sys $BINDIR/ipptest test/ipptest
f 0555 root sys $BINDIR/lp systemv/lp
f 0555 root sys $BINDIR/lpoptions systemv/lpoptions
f 0555 root sys $BINDIR/lppasswd systemv/lppasswd
d 0511 root $CUPS_PRIMARY_SYSTEM_GROUP $STATEDIR/certs -
# Data files
-#f 0444 root sys $LOCALEDIR/da/cups_da.po locale/cups_da.po
-#f 0444 root sys $LOCALEDIR/de/cups_de.po locale/cups_de.po
+f 0444 root sys $LOCALEDIR/da/cups_da.po locale/cups_da.po
+f 0444 root sys $LOCALEDIR/de/cups_de.po locale/cups_de.po
f 0444 root sys $LOCALEDIR/es/cups_es.po locale/cups_es.po
#f 0444 root sys $LOCALEDIR/et/cups_et.po locale/cups_et.po
f 0444 root sys $LOCALEDIR/eu/cups_eu.po locale/cups_eu.po
-#f 0444 root sys $LOCALEDIR/fi/cups_fi.po locale/cups_fi.po
-#f 0444 root sys $LOCALEDIR/fr/cups_fr.po locale/cups_fr.po
+f 0444 root sys $LOCALEDIR/fi/cups_fi.po locale/cups_fi.po
+f 0444 root sys $LOCALEDIR/fr/cups_fr.po locale/cups_fr.po
#f 0444 root sys $LOCALEDIR/he/cups_he.po locale/cups_he.po
-#f 0444 root sys $LOCALEDIR/it/cups_it.po locale/cups_it.po
-#f 0444 root sys $LOCALEDIR/ja/cups_ja.po locale/cups_ja.po
-#f 0444 root sys $LOCALEDIR/ko/cups_ko.po locale/cups_ko.po
-#f 0444 root sys $LOCALEDIR/nl/cups_nl.po locale/cups_nl.po
-#f 0444 root sys $LOCALEDIR/no/cups_no.po locale/cups_no.po
-#f 0444 root sys $LOCALEDIR/pl/cups_pl.po locale/cups_pl.po
-#f 0444 root sys $LOCALEDIR/pt/cups_pt.po locale/cups_pt.po
-#f 0444 root sys $LOCALEDIR/pt_BR/cups_pt_BR.po locale/cups_pt_BR.po
-#f 0444 root sys $LOCALEDIR/ru/cups_ru.po locale/cups_ru.po
-#f 0444 root sys $LOCALEDIR/sv/cups_sv.po locale/cups_sv.po
-#f 0444 root sys $LOCALEDIR/zh/cups_zh.po locale/cups_zh.po
-#f 0444 root sys $LOCALEDIR/zh_TW/cups_zh_TW.po locale/cups_zh_TW.po
+f 0444 root sys $LOCALEDIR/id/cups_id.po locale/cups_id.po
+f 0444 root sys $LOCALEDIR/it/cups_it.po locale/cups_it.po
+f 0444 root sys $LOCALEDIR/ja/cups_ja.po locale/cups_ja.po
+f 0444 root sys $LOCALEDIR/ko/cups_ko.po locale/cups_ko.po
+f 0444 root sys $LOCALEDIR/nl/cups_nl.po locale/cups_nl.po
+f 0444 root sys $LOCALEDIR/no/cups_no.po locale/cups_no.po
+f 0444 root sys $LOCALEDIR/pl/cups_pl.po locale/cups_pl.po
+f 0444 root sys $LOCALEDIR/pt/cups_pt.po locale/cups_pt.po
+f 0444 root sys $LOCALEDIR/pt_BR/cups_pt_BR.po locale/cups_pt_BR.po
+f 0444 root sys $LOCALEDIR/ru/cups_ru.po locale/cups_ru.po
+f 0444 root sys $LOCALEDIR/sv/cups_sv.po locale/cups_sv.po
+f 0444 root sys $LOCALEDIR/zh/cups_zh.po locale/cups_zh.po
+f 0444 root sys $LOCALEDIR/zh_TW/cups_zh_TW.po locale/cups_zh_TW.po
d 0755 root sys $DATADIR -
f 0444 root sys $DATADIR/charsets/utf-8 data/utf-8
d 0755 root sys $DATADIR/data -
-f 0444 root sys $DATADIR/data/HPGLprolog data/HPGLprolog
f 0444 root sys $DATADIR/data/psglyphs data/psglyphs
f 0444 root sys $DATADIR/data/testprint data/testprint
d 0755 root sys $DATADIR/fonts -
f 0444 root sys $DATADIR/fonts fonts/Monospace*
+d 0755 root sys $DATADIR/ipptest -
+f 0444 root sys $DATADIR/ipptest test/ipp-*.test
+f 0444 root sys $DATADIR/ipptest test/testfile.*
+
d 0755 root sys $DATADIR/mime -
f 0444 root sys $DATADIR/mime/mime.convs conf/mime.convs
f 0444 root sys $DATADIR/mime/mime.types conf/mime.types
f 0444 root sys $DATADIR/templates templates/*.tmpl
## Template files
-#d 0755 root sys $DATADIR/templates/de
-#f 0444 root sys $DATADIR/templates/de templates/de/*.tmpl
+d 0755 root sys $DATADIR/templates/de
+f 0444 root sys $DATADIR/templates/de templates/de/*.tmpl
d 0755 root sys $DATADIR/templates/es
f 0444 root sys $DATADIR/templates/es templates/es/*.tmpl
#d 0755 root sys $DATADIR/templates/he
#f 0444 root sys $DATADIR/templates/he templates/he/*.tmpl
-#d 0755 root sys $DATADIR/templates/it
-#f 0444 root sys $DATADIR/templates/it templates/it/*.tmpl
+d 0755 root sys $DATADIR/templates/id
+f 0444 root sys $DATADIR/templates/id templates/id/*.tmpl
+
+d 0755 root sys $DATADIR/templates/it
+f 0444 root sys $DATADIR/templates/it templates/it/*.tmpl
d 0755 root sys $DATADIR/templates/ja
f 0444 root sys $DATADIR/templates/ja templates/ja/*.tmpl
f 0444 root sys $DOCDIR/robots.txt doc/robots.txt
# Localized documentation files
-#d 0755 root sys $DOCDIR/de
-#f 0444 root sys $DOCDIR/de doc/de/*.html
+d 0755 root sys $DOCDIR/de
+f 0444 root sys $DOCDIR/de doc/de/*.html
d 0755 root sys $DOCDIR/es
f 0444 root sys $DOCDIR/es doc/es/*.html
#f 0444 root sys $DOCDIR/he doc/he/*.html
#f 0444 root sys $DOCDIR/he/cups.css doc/he/cups.css
-#d 0755 root sys $DOCDIR/it
-#f 0444 root sys $DOCDIR/it doc/it/*.html
+d 0755 root sys $DOCDIR/id
+f 0444 root sys $DOCDIR/id doc/id/*.html
+
+d 0755 root sys $DOCDIR/it
+f 0444 root sys $DOCDIR/it doc/it/*.html
d 0755 root sys $DOCDIR/ja
f 0444 root sys $DOCDIR/ja doc/ja/*.html
f 0444 root sys $MANDIR/man1/cancel.$MAN1EXT man/cancel.$MAN1EXT
f 0444 root sys $MANDIR/man1/cupstestdsc.$MAN1EXT man/cupstestdsc.$MAN1EXT
f 0444 root sys $MANDIR/man1/cupstestppd.$MAN1EXT man/cupstestppd.$MAN1EXT
+f 0444 root sys $MANDIR/man1/ipptest.$MAN1EXT man/ipptest.$MAN1EXT
f 0444 root sys $MANDIR/man1/lpoptions.$MAN1EXT man/lpoptions.$MAN1EXT
f 0444 root sys $MANDIR/man1/lppasswd.$MAN1EXT man/lppasswd.$MAN1EXT
f 0444 root sys $MANDIR/man1/lpq.$MAN1EXT man/lpq.$MAN1EXT
f 0444 root sys $MANDIR/man5/classes.conf.$MAN5EXT man/classes.conf.$MAN5EXT
f 0444 root sys $MANDIR/man5/cupsd.conf.$MAN5EXT man/cupsd.conf.$MAN5EXT
+f 0444 root sys $MANDIR/man5/ipp.test.$MAN5EXT man/ipp.test.$MAN5EXT
f 0444 root sys $MANDIR/man5/mailto.conf.$MAN5EXT man/mailto.conf.$MAN5EXT
f 0444 root sys $MANDIR/man5/mime.convs.$MAN5EXT man/mime.convs.$MAN5EXT
f 0444 root sys $MANDIR/man5/mime.types.$MAN5EXT man/mime.types.$MAN5EXT
#
# Original version by Jason McMullan <jmcc@ontv.com>.
#
-# Copyright 2007-2009 by Apple Inc.
+# Copyright 2007-2010 by Apple Inc.
# Copyright 1999-2007 by Easy Software Products, all rights reserved.
#
# These coded instructions, statements, and computer programs are the
/usr/bin/cancel
/usr/bin/cupstestdsc
/usr/bin/cupstestppd
+/usr/bin/ipptest
/usr/bin/lp*
%dir /usr/lib/cups
%dir /usr/lib/cups/backend
/usr/share/cups/drv/*
%dir /usr/share/cups/fonts
/usr/share/cups/fonts/*
+%dir /usr/share/cups/ipptest
+/usr/share/cups/ipptest/*
%dir /usr/share/cups/mime
/usr/share/cups/mime/*
%dir /usr/share/cups/model
/usr/share/doc/cups/es/*
%dir /usr/share/doc/cups/eu
/usr/share/doc/cups/eu/*
+%dir /usr/share/doc/cups/id
+/usr/share/doc/cups/id/*
%dir /usr/share/doc/cups/ja
/usr/share/doc/cups/ja/*
%dir /usr/share/doc/cups/pl
/usr/share/man/man1/cancel.1.gz
/usr/share/man/man1/cupstestdsc.1.gz
/usr/share/man/man1/cupstestppd.1.gz
+/usr/share/man/man1/ipptest.1.gz
/usr/share/man/man1/lp.1.gz
/usr/share/man/man1/lpoptions.1.gz
/usr/share/man/man1/lppasswd.1.gz
/usr/share/man/man1/lpstat.1.gz
%dir /usr/share/man/man5
/usr/share/man/man5/*.conf.5.gz
+/usr/share/man/man5/ipp.test.5.gz
/usr/share/man/man5/mime.*.5.gz
%dir /usr/share/man/man7
/usr/share/man/man7/drv*
#
# Makefile for the CUPS PPD Compiler.
#
-# Copyright 2007-2009 by Apple Inc.
+# Copyright 2007-2010 by Apple Inc.
# Copyright 2002-2006 by Easy Software Products.
#
# These coded instructions, statements, and computer programs are the
done
if test "x$(SYMROOT)" != "x"; then \
$(INSTALL_DIR) $(SYMROOT); \
- for file in $(EXECTARGETS) $(LIBTARGETS); do \
+ for file in $(EXECTARGETS); do \
cp $$file $(SYMROOT); \
done \
fi
# genstrings - generate GNU gettext strings.
#
-genstrings: genstrings.o libcupsppdc.a ../cups/libcups.a \
+genstrings: genstrings.o libcupsppdc.a ../cups/$(LIBCUPSSTATIC) \
sample.drv ../data/media.defs
echo Linking $@...
$(CXX) $(ARCHFLAGS) $(LDFLAGS) -o genstrings genstrings.o \
- libcupsppdc.a ../cups/libcups.a $(LIBGSSAPI) $(SSLLIBS) \
+ libcupsppdc.a ../cups/$(LIBCUPSSTATIC) $(LIBGSSAPI) $(SSLLIBS) \
$(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
echo Generating localization strings...
./genstrings >sample.c
$(CXX) $(LDFLAGS) -o $@ ppdc.o -L. -lcupsppdc $(LIBS)
-ppdc-static: ppdc.o libcupsppdc.a ../cups/libcups.a foo.drv foo-fr.po
+ppdc-static: ppdc.o libcupsppdc.a ../cups/$(LIBCUPSSTATIC) foo.drv foo-fr.po
echo Linking $@...
$(CXX) $(ARCHFLAGS) $(LDFLAGS) -o ppdc-static ppdc.o libcupsppdc.a \
- ../cups/libcups.a $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) \
+ ../cups/$(LIBCUPSSTATIC) $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) \
$(COMMONLIBS) $(LIBZ)
echo Testing PPD compiler...
./ppdc-static -l en,fr -I ../data foo.drv
$(CXX) $(LDFLAGS) -o $@ ppdi.o -L. -lcupsppdc $(LIBS)
-ppdi-static: ppdc-static ppdi.o libcupsppdc.a ../cups/libcups.a
+ppdi-static: ppdc-static ppdi.o libcupsppdc.a ../cups/$(LIBCUPSSTATIC)
echo Linking $@...
$(CXX) $(ARCHFLAGS) $(LDFLAGS) -o ppdi-static ppdi.o libcupsppdc.a \
- ../cups/libcups.a $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) \
+ ../cups/$(LIBCUPSSTATIC) $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) \
$(COMMONLIBS) $(LIBZ)
echo Testing PPD importer...
$(RM) -r ppd ppd2 sample-import.drv
# testcatalog, test ppdcCatalog class.
#
-testcatalog: testcatalog.o libcupsppdc.a ../cups/libcups.a
+testcatalog: testcatalog.o libcupsppdc.a ../cups/$(LIBCUPSSTATIC)
echo Linking $@...
$(CXX) $(LDFLAGS) -o $@ testcatalog.o libcupsppdc.a \
- ../cups/libcups.a $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) \
+ ../cups/$(LIBCUPSSTATIC) $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) \
$(COMMONLIBS) $(LIBZ)
cups-driverd.o: ../cups/string.h ../cups/cups.h ../cups/i18n.h
cups-driverd.o: ../cups/transcode.h ../cups/language.h ../cups/array.h
cups-driverd.o: ../cups/debug.h ../cups/dir.h ../cups/transcode.h
-cups-driverd.o: ../cups/ppd-private.h ../ppdc/ppdc.h ../cups/string.h
-cups-driverd.o: ../cups/file.h
+cups-driverd.o: ../cups/ppd-private.h ../ppdc/ppdc.h ../cups/file.h
#
# "$Id: Makefile 7875 2008-08-27 22:53:31Z mike $"
#
-# Scheduler Makefile for the Common UNIX Printing System (CUPS).
+# Scheduler Makefile for CUPS.
#
-# Copyright 2007-2009 by Apple Inc.
+# Copyright 2007-2010 by Apple Inc.
# Copyright 1997-2007 by Easy Software Products, all rights reserved.
#
# These coded instructions, statements, and computer programs are the
testspeed \
testsub
-TARGETS = \
- $(LIBTARGETS) \
+DAEMONS = \
cupsd \
cupsfilter \
cups-deviced \
cups-driverd \
cups-lpd \
- cups-polld \
+ cups-polld
+
+TARGETS = \
+ $(LIBTARGETS) \
+ $(DAEMONS)
#
$(INSTALL_BIN) cups-polld $(SERVERBIN)/daemon
if test "x$(SYMROOT)" != "x"; then \
$(INSTALL_DIR) $(SYMROOT); \
- for file in $(TARGETS); do \
+ for file in $(DAEMONS); do \
cp $$file $(SYMROOT); \
done \
fi
$(LIBPAPER) $(LIBMALLOC) $(CUPSDLIBS) $(DNSSDLIBS) $(LIBS) \
$(LIBGSSAPI) $(LIBWRAP)
-cupsd-static: $(CUPSDOBJS) libcupsmime.a ../cups/libcups.a
+cupsd-static: $(CUPSDOBJS) libcupsmime.a ../cups/$(LIBCUPSSTATIC)
echo Linking $@...
$(CC) $(LDFLAGS) -o cupsd-static $(CUPSDOBJS) libcupsmime.a \
$(LIBZ) $(SSLLIBS) $(LIBSLP) $(LIBLDAP) $(PAMLIBS) \
- ../cups/libcups.a $(COMMONLIBS) $(LIBZ) $(LIBPAPER) \
+ ../cups/$(LIBCUPSSTATIC) $(COMMONLIBS) $(LIBZ) $(LIBPAPER) \
$(LIBMALLOC) $(CUPSDLIBS) $(DNSSDLIBS) $(LIBGSSAPI) \
$(LIBWRAP)
# Make the test program, "testlpd".
#
-testlpd: testlpd.o ../cups/libcups.a cups-lpd
+testlpd: testlpd.o ../cups/$(LIBCUPSSTATIC) cups-lpd
echo Linking $@...
- $(CC) $(LDFLAGS) -o testlpd testlpd.o ../cups/libcups.a \
+ $(CC) $(LDFLAGS) -o testlpd testlpd.o ../cups/$(LIBCUPSSTATIC) \
$(COMMONLIBS) $(LIBZ) $(SSLLIBS) $(DNSSDLIBS) $(LIBGSSAPI)
# testmime
#
-testmime: testmime.o libcupsmime.a ../cups/libcups.a
+testmime: testmime.o libcupsmime.a ../cups/$(LIBCUPSSTATIC)
echo Linking $@...
$(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testmime.o libcupsmime.a \
- ../cups/libcups.a $(COMMONLIBS) $(LIBZ) $(SSLLIBS) \
+ ../cups/$(LIBCUPSSTATIC) $(COMMONLIBS) $(LIBZ) $(SSLLIBS) \
$(DNSSDLIBS) $(LIBGSSAPI)
echo Running MIME tests...
./testmime
# Make the test program, "testspeed".
#
-testspeed: testspeed.o ../cups/libcups.a
+testspeed: testspeed.o ../cups/$(LIBCUPSSTATIC)
echo Linking $@...
- $(CC) $(LDFLAGS) -o testspeed testspeed.o ../cups/libcups.a \
+ $(CC) $(LDFLAGS) -o testspeed testspeed.o ../cups/$(LIBCUPSSTATIC) \
$(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) $(LIBGSSAPI)
# Make the test program, "testsub".
#
-testsub: testsub.o ../cups/libcups.a
+testsub: testsub.o ../cups/$(LIBCUPSSTATIC)
echo Linking $@...
- $(CC) $(LDFLAGS) -o testsub testsub.o ../cups/libcups.a \
+ $(CC) $(LDFLAGS) -o testsub testsub.o ../cups/$(LIBCUPSSTATIC) \
$(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) $(LIBGSSAPI)
/*
* "$Id: cert.c 7673 2008-06-18 22:31:26Z mike $"
*
- * Authentication certificate routines for the Common UNIX
- * Printing System (CUPS).
+ * Authentication certificate routines for CUPS.
*
- * Copyright 2007-2009 by Apple Inc.
+ * Copyright 2007-2010 by Apple Inc.
* Copyright 1997-2006 by Easy Software Products.
*
* These coded instructions, statements, and computer programs are the
void
cupsdInitCerts(void)
{
+#ifndef HAVE_ARC4RANDOM
cups_file_t *fp; /* /dev/random file */
- unsigned seed; /* Seed for random number generator */
- struct timeval tod; /* Time of day */
/*
if ((fp = cupsFileOpen("/dev/urandom", "rb")) == NULL)
{
+ struct timeval tod; /* Time of day */
+
/*
* Get the time in usecs and use it as the initial seed...
*/
gettimeofday(&tod, NULL);
- seed = (unsigned)(tod.tv_sec + tod.tv_usec);
+ CUPS_SRAND((unsigned)(tod.tv_sec + tod.tv_usec));
}
else
{
+ unsigned seed; /* Seed for random number generator */
+
/*
* Read 4 random characters from the random device and use
* them as the seed...
seed = cupsFileGetChar(fp);
seed = (seed << 8) | cupsFileGetChar(fp);
seed = (seed << 8) | cupsFileGetChar(fp);
- seed = (seed << 8) | cupsFileGetChar(fp);
+ CUPS_SRAND((seed << 8) | cupsFileGetChar(fp));
cupsFileClose(fp);
}
-
- CUPS_SRAND(seed);
+#endif /* !HAVE_ARC4RANDOM */
/*
* Create a root certificate and return...
*
* Printer class routines for the Common UNIX Printing System (CUPS).
*
- * Copyright 2007-2009 by Apple Inc.
+ * Copyright 2007-2010 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
* 'cupsdDeletePrinterFromClass()' - Delete a printer from a class.
*/
-void
+int /* O - 1 if class changed, 0 otherwise */
cupsdDeletePrinterFromClass(
cupsd_printer_t *c, /* I - Class to delete from */
cupsd_printer_t *p) /* I - Printer to delete */
(c->num_printers - i) * sizeof(cupsd_printer_t *));
}
else
- return;
+ return (0);
/*
* Update the IPP attributes (have to do this for member-names)...
*/
cupsdSetPrinterAttrs(c);
+
+ return (1);
}
* 'cupsdDeletePrinterFromClasses()' - Delete a printer from all classes.
*/
-void
+int /* O - 1 if class changed, 0 otherwise */
cupsdDeletePrinterFromClasses(
cupsd_printer_t *p) /* I - Printer to delete */
{
+ int changed = 0; /* Any class changed? */
cupsd_printer_t *c; /* Pointer to current class */
c;
c = (cupsd_printer_t *)cupsArrayNext(Printers))
if (c->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
- cupsdDeletePrinterFromClass(c, p);
+ changed |= cupsdDeletePrinterFromClass(c, p);
/*
* Then clean out any empty implicit classes...
cupsdLogMessage(CUPSD_LOG_DEBUG, "Deleting implicit class \"%s\"...",
c->name);
cupsdDeletePrinter(c, 0);
+ changed = 1;
}
+
+ return (changed);
}
*
* Printer class definitions for the Common UNIX Printing System (CUPS).
*
- * Copyright 2007-2008 by Apple Inc.
+ * Copyright 2007-2010 by Apple Inc.
* Copyright 1997-2005 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
extern cupsd_printer_t *cupsdAddClass(const char *name);
extern void cupsdAddPrinterToClass(cupsd_printer_t *c,
cupsd_printer_t *p);
-extern void cupsdDeletePrinterFromClass(cupsd_printer_t *c,
+extern int cupsdDeletePrinterFromClass(cupsd_printer_t *c,
cupsd_printer_t *p);
-extern void cupsdDeletePrinterFromClasses(cupsd_printer_t *p);
+extern int cupsdDeletePrinterFromClasses(cupsd_printer_t *p);
extern cupsd_printer_t *cupsdFindAvailablePrinter(const char *name);
extern cupsd_printer_t *cupsdFindClass(const char *name);
extern void cupsdLoadAllClasses(void);
*
* Client routines for the Common UNIX Printing System (CUPS) scheduler.
*
- * Copyright 2007-2009 by Apple Inc.
+ * Copyright 2007-2010 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products, all rights reserved.
*
* This file contains Kerberos support code, copyright 2006 by
*ptr = '\0';
}
else
- snprintf(locale, sizeof(locale), "%s.%s",
- con->http.fields[HTTP_FIELD_ACCEPT_LANGUAGE], DefaultCharset);
+ snprintf(locale, sizeof(locale), "%s.UTF-8",
+ con->http.fields[HTTP_FIELD_ACCEPT_LANGUAGE]);
con->language = cupsLangGet(locale);
}
return;
}
}
+ else if (filestats.st_size == 0)
+ {
+ /*
+ * Don't allow empty file...
+ */
+
+ unlink(con->filename);
+ cupsdClearString(&con->filename);
+ }
if (con->command)
{
*
* Configuration routines for the Common UNIX Printing System (CUPS).
*
- * Copyright 2007-2009 by Apple Inc.
+ * Copyright 2007-2010 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
{ "ClassifyOverride", &ClassifyOverride, CUPSD_VARTYPE_BOOLEAN },
{ "ConfigFilePerm", &ConfigFilePerm, CUPSD_VARTYPE_INTEGER },
{ "DataDir", &DataDir, CUPSD_VARTYPE_STRING },
- { "DefaultCharset", &DefaultCharset, CUPSD_VARTYPE_STRING },
{ "DefaultLanguage", &DefaultLanguage, CUPSD_VARTYPE_STRING },
{ "DefaultLeaseDuration", &DefaultLeaseDuration, CUPSD_VARTYPE_INTEGER },
{ "DefaultPaperSize", &DefaultPaperSize, CUPSD_VARTYPE_STRING },
{ "KeepAlive", &KeepAlive, CUPSD_VARTYPE_BOOLEAN },
#ifdef HAVE_LAUNCHD
{ "LaunchdTimeout", &LaunchdTimeout, CUPSD_VARTYPE_INTEGER },
- { "LaunchdConf", &LaunchdConf, CUPSD_VARTYPE_STRING },
#endif /* HAVE_LAUNCHD */
{ "LimitRequestBody", &MaxRequestSize, CUPSD_VARTYPE_INTEGER },
{ "ListenBackLog", &ListenBackLog, CUPSD_VARTYPE_INTEGER },
else
cupsdSetString(&DefaultLanguage, language->language);
- cupsdSetString(&DefaultCharset, _cupsEncodingName(language->encoding));
-
cupsdClearString(&DefaultPaperSize);
cupsdSetString(&RIPCache, "8m");
#ifdef HAVE_LAUNCHD
LaunchdTimeout = DEFAULT_TIMEOUT + 10;
- cupsdSetString(&LaunchdConf, CUPS_DEFAULT_LAUNCHD_CONF);
#endif /* HAVE_LAUNCHD */
#ifdef __APPLE__
* Set the default locale using the language and charset...
*/
- cupsdSetStringf(&DefaultLocale, "%s.%s", DefaultLanguage, DefaultCharset);
+ cupsdSetStringf(&DefaultLocale, "%s.UTF-8", DefaultLanguage);
/*
* Update all relative filenames to include the full path from ServerRoot...
/*
* "$Id: conf.h 7935 2008-09-11 01:54:11Z mike $"
*
- * Configuration file definitions for the Common UNIX Printing System (CUPS)
- * scheduler.
+ * Configuration file definitions for CUPS.
*
* Copyright 2007-2009 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products, all rights reserved.
/* Data file directory */
*DefaultLanguage VALUE(NULL),
/* Default language encoding */
- *DefaultCharset VALUE(NULL),
- /* Default charset */
*DefaultLocale VALUE(NULL),
/* Default locale */
*DefaultPaperSize VALUE(NULL),
#ifdef HAVE_LAUNCHD
VAR int LaunchdTimeout VALUE(DEFAULT_KEEPALIVE);
/* Time after which an idle cupsd will exit */
-VAR char *LaunchdConf VALUE(NULL);
- /* launchd(8) configuration file */
#endif /* HAVE_LAUNCHD */
#ifdef __APPLE__
type = PPD_TYPE_PDF;
}
- for (product = (ppdcAttr *)d->attrs->first(), products_found = 0;
+ for (product = (ppdcAttr *)d->attrs->first(), products_found = 0,
+ ppd = NULL;
product;
product = (ppdcAttr *)d->attrs->next())
if (!strcmp(product->name->value, "Product"))
*
* IPP routines for the Common UNIX Printing System (CUPS) scheduler.
*
- * Copyright 2007-2009 by Apple Inc.
+ * Copyright 2007-2010 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products, all rights reserved.
*
* This file contains Kerberos support code, copyright 2006 by
charset->values[0].string.text);
else
ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
- "attributes-charset", NULL, DefaultCharset);
+ "attributes-charset", NULL, "utf-8");
if (language)
ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
cupsdAddPrinterHistory(printer);
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, printer, NULL,
+ "Now accepting jobs.");
+
if (dtype & CUPS_PRINTER_CLASS)
{
cupsdMarkDirty(CUPSD_DIRTY_CLASSES);
cupsdSetString(&pclass->info, attr->values[0].string.text);
if ((attr = ippFindAttribute(con->request, "printer-is-accepting-jobs",
- IPP_TAG_BOOLEAN)) != NULL)
+ IPP_TAG_BOOLEAN)) != NULL &&
+ attr->values[0].boolean != pclass->accepting)
{
cupsdLogMessage(CUPSD_LOG_INFO,
"Setting %s printer-is-accepting-jobs to %d (was %d.)",
pclass->accepting = attr->values[0].boolean;
cupsdAddPrinterHistory(pclass);
+
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, pclass, NULL, "%s accepting jobs.",
+ pclass->accepting ? "Now" : "No longer");
}
if ((attr = ippFindAttribute(con->request, "printer-is-shared",
strlcpy(pclass->state_message, attr->values[0].string.text,
sizeof(pclass->state_message));
cupsdAddPrinterHistory(pclass);
+
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, pclass, NULL, "%s",
+ pclass->state_message);
}
if ((attr = ippFindAttribute(con->request, "member-uris",
IPP_TAG_URI)) != NULL)
if (modify)
{
- cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED, pclass, NULL,
- "Class \"%s\" modified by \"%s\".", pclass->name,
- get_username(con));
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED | CUPSD_EVENT_PRINTER_CONFIG,
+ pclass, NULL, "Class \"%s\" modified by \"%s\".",
+ pclass->name, get_username(con));
cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" modified by \"%s\".",
pclass->name, get_username(con));
{
cupsdAddPrinterHistory(pclass);
- cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, pclass, NULL,
- "New class \"%s\" added by \"%s\".", pclass->name,
- get_username(con));
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED | CUPSD_EVENT_PRINTER_CONFIG,
+ pclass, NULL, "New class \"%s\" added by \"%s\".",
+ pclass->name, get_username(con));
cupsdLogMessage(CUPSD_LOG_INFO, "New class \"%s\" added by \"%s\".",
pclass->name, get_username(con));
*auth_info; /* auth-info attribute */
const char *val; /* Default option value */
int priority; /* Job priority */
- char *title; /* Job name/title */
cupsd_job_t *job; /* Current job */
char job_uri[HTTP_MAX_URI]; /* Job URI */
int kbytes; /* Size of print file */
ippAddSeparator(con->response);
ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
"notify-subscription-id", sub->id);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Added subscription %d for job %d",
+ sub->id, job->id);
}
if (attr)
}
if ((attr = ippFindAttribute(con->request, "printer-is-accepting-jobs",
- IPP_TAG_BOOLEAN)) != NULL)
+ IPP_TAG_BOOLEAN)) != NULL &&
+ attr->values[0].boolean != printer->accepting)
{
cupsdLogMessage(CUPSD_LOG_INFO,
"Setting %s printer-is-accepting-jobs to %d (was %d.)",
printer->accepting = attr->values[0].boolean;
cupsdAddPrinterHistory(printer);
+
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, printer, NULL,
+ "%s accepting jobs.",
+ printer->accepting ? "Now" : "No longer");
}
if ((attr = ippFindAttribute(con->request, "printer-is-shared",
strlcpy(printer->state_message, attr->values[0].string.text,
sizeof(printer->state_message));
cupsdAddPrinterHistory(printer);
+
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, printer, NULL, "%s",
+ printer->state_message);
}
if ((attr = ippFindAttribute(con->request, "printer-state-reasons",
if (PrintcapFormat == PRINTCAP_PLIST)
cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
+
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, printer, NULL,
+ "Printer \"%s\" state changed.", printer->name);
}
set_printer_defaults(con, printer);
if (modify)
{
- cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED, printer, NULL,
- "Printer \"%s\" modified by \"%s\".", printer->name,
- get_username(con));
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED | CUPSD_EVENT_PRINTER_CONFIG,
+ printer, NULL, "Printer \"%s\" modified by \"%s\".",
+ printer->name, get_username(con));
cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" modified by \"%s\".",
printer->name, get_username(con));
{
cupsdAddPrinterHistory(printer);
- cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, printer, NULL,
- "New printer \"%s\" added by \"%s\".", printer->name,
- get_username(con));
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED | CUPSD_EVENT_PRINTER_CONFIG,
+ printer, NULL, "New printer \"%s\" added by \"%s\".",
+ printer->name, get_username(con));
cupsdLogMessage(CUPSD_LOG_INFO, "New printer \"%s\" added by \"%s\".",
printer->name, get_username(con));
cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" deleted by \"%s\".",
printer->name, get_username(con));
- cupsdDeletePrinter(printer, 0);
+ if (cupsdDeletePrinter(printer, 0))
+ cupsdMarkDirty(CUPSD_DIRTY_CLASSES);
+
cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
}
cupsdAddPrinterHistory(printer);
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, printer, NULL,
+ "No longer accepting jobs.");
+
if (dtype & CUPS_PRINTER_CLASS)
{
cupsdMarkDirty(CUPSD_DIRTY_CLASSES);
if (ippFindAttribute(con->response, "attributes-charset",
IPP_TAG_ZERO) == NULL)
ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
- "attributes-charset", NULL, DefaultCharset);
+ "attributes-charset", NULL, "utf-8");
if (ippFindAttribute(con->response, "attributes-natural-language",
IPP_TAG_ZERO) == NULL)
break;
}
- if (event & CUPSD_EVENT_PRINTER_STATE)
+ if (event & CUPSD_EVENT_JOB_PROGRESS)
+ cupsdAddEvent(CUPSD_EVENT_JOB_PROGRESS, job->printer, job,
+ "%s", job->printer->state_message);
+ else if (event & CUPSD_EVENT_PRINTER_STATE)
cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, job->printer, NULL,
(job->printer->type & CUPS_PRINTER_CLASS) ?
"Class \"%s\" state changed." :
"Printer \"%s\" state changed.",
job->printer->name);
- if (event & CUPSD_EVENT_JOB_PROGRESS)
- cupsdAddEvent(CUPSD_EVENT_JOB_PROGRESS, job->printer, job,
- "%s", job->printer->state_message);
if (ptr == NULL && !job->status_buffer->bufused)
{
unlink(lis->address.un.sun_path);
/*
- * Save the curent umask and set it to 0...
+ * Save the current umask and set it to 0 so that all users can access
+ * the domain socket...
*/
mask = umask(0);
launchd_checkin(void)
{
size_t i, /* Looping var */
- count; /* Numebr of listeners */
+ count; /* Number of listeners */
int portnum; /* Port number */
launch_data_t ld_msg, /* Launch data message */
ld_resp, /* Launch data response */
*
* Printer routines for the Common UNIX Printing System (CUPS).
*
- * Copyright 2007-2009 by Apple Inc.
+ * Copyright 2007-2010 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
/* charset-configured */
ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_CHARSET | IPP_TAG_COPY,
- "charset-configured", NULL, DefaultCharset);
+ "charset-configured", NULL, "utf-8");
/* charset-supported */
ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_CHARSET | IPP_TAG_COPY,
ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_TEXT | IPP_TAG_COPY,
"cups-version", NULL, CUPS_SVERSION + 6);
- /* generated-natural-language-supported */
- ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE | IPP_TAG_COPY,
+ /* generated-natural-language-supported (no IPP_TAG_COPY) */
+ ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
"generated-natural-language-supported", NULL, DefaultLanguage);
/* ipp-versions-supported */
ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"multiple-operation-time-out", MultipleOperationTimeout);
- /* natural-language-configured */
- ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE | IPP_TAG_COPY,
+ /* natural-language-configured (no IPP_TAG_COPY) */
+ ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
"natural-language-configured", NULL, DefaultLanguage);
/* notify-attributes-supported */
* 'cupsdDeletePrinter()' - Delete a printer from the system.
*/
-void
+int /* O - 1 if classes affected, 0 otherwise */
cupsdDeletePrinter(
cupsd_printer_t *p, /* I - Printer to delete */
int update) /* I - Update printers.conf? */
{
- int i; /* Looping var */
+ int i, /* Looping var */
+ changed = 0; /* Class changed? */
#ifdef __sgi
char filename[1024]; /* Interface script filename */
#endif /* __sgi */
if (!(p->type & CUPS_PRINTER_IMPLICIT))
{
- cupsdDeletePrinterFromClasses(p);
+ changed = cupsdDeletePrinterFromClasses(p);
/*
* Deregister from any browse protocols...
*/
cupsArrayRestore(Printers);
+
+ return (changed);
}
int update) /* I - Update printers.conf? */
{
ipp_pstate_t old_state; /* Old printer state */
+ static const char * const printer_states[] =
+ { /* State strings */
+ "idle",
+ "processing",
+ "stopped"
+ };
/*
{
cupsdAddEvent(s == IPP_PRINTER_STOPPED ? CUPSD_EVENT_PRINTER_STOPPED :
CUPSD_EVENT_PRINTER_STATE, p, NULL,
- "%s \"%s\" state changed.",
+ "%s \"%s\" state changed to %s.",
(p->type & CUPS_PRINTER_CLASS) ? "Class" : "Printer",
- p->name);
+ p->name, printer_states[p->state]);
/*
* Let the browse code know this needs to be updated...
const char *username);
extern void cupsdCreateCommonData(void);
extern void cupsdDeleteAllPrinters(void);
-extern void cupsdDeletePrinter(cupsd_printer_t *p, int update);
+extern int cupsdDeletePrinter(cupsd_printer_t *p, int update);
extern cupsd_printer_t *cupsdFindDest(const char *name);
extern cupsd_printer_t *cupsdFindPrinter(const char *name);
extern cupsd_quota_t *cupsdFindQuota(cupsd_printer_t *p,
#
# "$Id: Makefile 7871 2008-08-27 21:12:43Z mike $"
#
-# Standards makefile for the Common UNIX Printing System (CUPS).
+# Standards makefile for CUPS.
#
-# Copyright 2007-2009 by Apple Inc.
+# Copyright 2007-2010 by Apple Inc.
# Copyright 2006 by Easy Software Products.
#
# These coded instructions, statements, and computer programs are the
# rfctohtml - make html versions of RFCs...
#
-rfctohtml: rfctohtml.o ../cups/libcups.a
- $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ rfctohtml.o ../cups/libcups.a \
+rfctohtml: rfctohtml.o ../cups/$(LIBCUPSSTATIC)
+ $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ rfctohtml.o ../cups/$(LIBCUPSSTATIC) \
$(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
--- /dev/null
+
+
+
+
+
+
+Network Working Group N. Freed
+Request for Comments: 2046 Innosoft
+Obsoletes: 1521, 1522, 1590 N. Borenstein
+Category: Standards Track First Virtual
+ November 1996
+
+
+ Multipurpose Internet Mail Extensions
+ (MIME) Part Two:
+ Media Types
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Abstract
+
+ STD 11, RFC 822 defines a message representation protocol specifying
+ considerable detail about US-ASCII message headers, but which leaves
+ the message content, or message body, as flat US-ASCII text. This
+ set of documents, collectively called the Multipurpose Internet Mail
+ Extensions, or MIME, redefines the format of messages to allow for
+
+ (1) textual message bodies in character sets other than
+ US-ASCII,
+
+ (2) an extensible set of different formats for non-textual
+ message bodies,
+
+ (3) multi-part message bodies, and
+
+ (4) textual header information in character sets other than
+ US-ASCII.
+
+ These documents are based on earlier work documented in RFC 934, STD
+ 11, and RFC 1049, but extends and revises them. Because RFC 822 said
+ so little about message bodies, these documents are largely
+ orthogonal to (rather than a revision of) RFC 822.
+
+ The initial document in this set, RFC 2045, specifies the various
+ headers used to describe the structure of MIME messages. This second
+ document defines the general structure of the MIME media typing
+ system and defines an initial set of media types. The third document,
+ RFC 2047, describes extensions to RFC 822 to allow non-US-ASCII text
+
+
+
+Freed & Borenstein Standards Track [Page 1]
+\f
+RFC 2046 Media Types November 1996
+
+
+ data in Internet mail header fields. The fourth document, RFC 2048,
+ specifies various IANA registration procedures for MIME-related
+ facilities. The fifth and final document, RFC 2049, describes MIME
+ conformance criteria as well as providing some illustrative examples
+ of MIME message formats, acknowledgements, and the bibliography.
+
+ These documents are revisions of RFCs 1521 and 1522, which themselves
+ were revisions of RFCs 1341 and 1342. An appendix in RFC 2049
+ describes differences and changes from previous versions.
+
+Table of Contents
+
+ 1. Introduction ......................................... 3
+ 2. Definition of a Top-Level Media Type ................. 4
+ 3. Overview Of The Initial Top-Level Media Types ........ 4
+ 4. Discrete Media Type Values ........................... 6
+ 4.1 Text Media Type ..................................... 6
+ 4.1.1 Representation of Line Breaks ..................... 7
+ 4.1.2 Charset Parameter ................................. 7
+ 4.1.3 Plain Subtype ..................................... 11
+ 4.1.4 Unrecognized Subtypes ............................. 11
+ 4.2 Image Media Type .................................... 11
+ 4.3 Audio Media Type .................................... 11
+ 4.4 Video Media Type .................................... 12
+ 4.5 Application Media Type .............................. 12
+ 4.5.1 Octet-Stream Subtype .............................. 13
+ 4.5.2 PostScript Subtype ................................ 14
+ 4.5.3 Other Application Subtypes ........................ 17
+ 5. Composite Media Type Values .......................... 17
+ 5.1 Multipart Media Type ................................ 17
+ 5.1.1 Common Syntax ..................................... 19
+ 5.1.2 Handling Nested Messages and Multiparts ........... 24
+ 5.1.3 Mixed Subtype ..................................... 24
+ 5.1.4 Alternative Subtype ............................... 24
+ 5.1.5 Digest Subtype .................................... 26
+ 5.1.6 Parallel Subtype .................................. 27
+ 5.1.7 Other Multipart Subtypes .......................... 28
+ 5.2 Message Media Type .................................. 28
+ 5.2.1 RFC822 Subtype .................................... 28
+ 5.2.2 Partial Subtype ................................... 29
+ 5.2.2.1 Message Fragmentation and Reassembly ............ 30
+ 5.2.2.2 Fragmentation and Reassembly Example ............ 31
+ 5.2.3 External-Body Subtype ............................. 33
+ 5.2.4 Other Message Subtypes ............................ 40
+ 6. Experimental Media Type Values ....................... 40
+ 7. Summary .............................................. 41
+ 8. Security Considerations .............................. 41
+ 9. Authors' Addresses ................................... 42
+
+
+
+Freed & Borenstein Standards Track [Page 2]
+\f
+RFC 2046 Media Types November 1996
+
+
+ A. Collected Grammar .................................... 43
+
+1. Introduction
+
+ The first document in this set, RFC 2045, defines a number of header
+ fields, including Content-Type. The Content-Type field is used to
+ specify the nature of the data in the body of a MIME entity, by
+ giving media type and subtype identifiers, and by providing auxiliary
+ information that may be required for certain media types. After the
+ type and subtype names, the remainder of the header field is simply a
+ set of parameters, specified in an attribute/value notation. The
+ ordering of parameters is not significant.
+
+ In general, the top-level media type is used to declare the general
+ type of data, while the subtype specifies a specific format for that
+ type of data. Thus, a media type of "image/xyz" is enough to tell a
+ user agent that the data is an image, even if the user agent has no
+ knowledge of the specific image format "xyz". Such information can
+ be used, for example, to decide whether or not to show a user the raw
+ data from an unrecognized subtype -- such an action might be
+ reasonable for unrecognized subtypes of "text", but not for
+ unrecognized subtypes of "image" or "audio". For this reason,
+ registered subtypes of "text", "image", "audio", and "video" should
+ not contain embedded information that is really of a different type.
+ Such compound formats should be represented using the "multipart" or
+ "application" types.
+
+ Parameters are modifiers of the media subtype, and as such do not
+ fundamentally affect the nature of the content. The set of
+ meaningful parameters depends on the media type and subtype. Most
+ parameters are associated with a single specific subtype. However, a
+ given top-level media type may define parameters which are applicable
+ to any subtype of that type. Parameters may be required by their
+ defining media type or subtype or they may be optional. MIME
+ implementations must also ignore any parameters whose names they do
+ not recognize.
+
+ MIME's Content-Type header field and media type mechanism has been
+ carefully designed to be extensible, and it is expected that the set
+ of media type/subtype pairs and their associated parameters will grow
+ significantly over time. Several other MIME facilities, such as
+ transfer encodings and "message/external-body" access types, are
+ likely to have new values defined over time. In order to ensure that
+ the set of such values is developed in an orderly, well-specified,
+ and public manner, MIME sets up a registration process which uses the
+ Internet Assigned Numbers Authority (IANA) as a central registry for
+ MIME's various areas of extensibility. The registration process for
+ these areas is described in a companion document, RFC 2048.
+
+
+
+Freed & Borenstein Standards Track [Page 3]
+\f
+RFC 2046 Media Types November 1996
+
+
+ The initial seven standard top-level media type are defined and
+ described in the remainder of this document.
+
+2. Definition of a Top-Level Media Type
+
+ The definition of a top-level media type consists of:
+
+ (1) a name and a description of the type, including
+ criteria for whether a particular type would qualify
+ under that type,
+
+ (2) the names and definitions of parameters, if any, which
+ are defined for all subtypes of that type (including
+ whether such parameters are required or optional),
+
+ (3) how a user agent and/or gateway should handle unknown
+ subtypes of this type,
+
+ (4) general considerations on gatewaying entities of this
+ top-level type, if any, and
+
+ (5) any restrictions on content-transfer-encodings for
+ entities of this top-level type.
+
+3. Overview Of The Initial Top-Level Media Types
+
+ The five discrete top-level media types are:
+
+ (1) text -- textual information. The subtype "plain" in
+ particular indicates plain text containing no
+ formatting commands or directives of any sort. Plain
+ text is intended to be displayed "as-is". No special
+ software is required to get the full meaning of the
+ text, aside from support for the indicated character
+ set. Other subtypes are to be used for enriched text in
+ forms where application software may enhance the
+ appearance of the text, but such software must not be
+ required in order to get the general idea of the
+ content. Possible subtypes of "text" thus include any
+ word processor format that can be read without
+ resorting to software that understands the format. In
+ particular, formats that employ embeddded binary
+ formatting information are not considered directly
+ readable. A very simple and portable subtype,
+ "richtext", was defined in RFC 1341, with a further
+ revision in RFC 1896 under the name "enriched".
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 4]
+\f
+RFC 2046 Media Types November 1996
+
+
+ (2) image -- image data. "Image" requires a display device
+ (such as a graphical display, a graphics printer, or a
+ FAX machine) to view the information. An initial
+ subtype is defined for the widely-used image format
+ JPEG. . subtypes are defined for two widely-used image
+ formats, jpeg and gif.
+
+ (3) audio -- audio data. "Audio" requires an audio output
+ device (such as a speaker or a telephone) to "display"
+ the contents. An initial subtype "basic" is defined in
+ this document.
+
+ (4) video -- video data. "Video" requires the capability
+ to display moving images, typically including
+ specialized hardware and software. An initial subtype
+ "mpeg" is defined in this document.
+
+ (5) application -- some other kind of data, typically
+ either uninterpreted binary data or information to be
+ processed by an application. The subtype "octet-
+ stream" is to be used in the case of uninterpreted
+ binary data, in which case the simplest recommended
+ action is to offer to write the information into a file
+ for the user. The "PostScript" subtype is also defined
+ for the transport of PostScript material. Other
+ expected uses for "application" include spreadsheets,
+ data for mail-based scheduling systems, and languages
+ for "active" (computational) messaging, and word
+ processing formats that are not directly readable.
+ Note that security considerations may exist for some
+ types of application data, most notably
+ "application/PostScript" and any form of active
+ messaging. These issues are discussed later in this
+ document.
+
+ The two composite top-level media types are:
+
+ (1) multipart -- data consisting of multiple entities of
+ independent data types. Four subtypes are initially
+ defined, including the basic "mixed" subtype specifying
+ a generic mixed set of parts, "alternative" for
+ representing the same data in multiple formats,
+ "parallel" for parts intended to be viewed
+ simultaneously, and "digest" for multipart entities in
+ which each part has a default type of "message/rfc822".
+
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 5]
+\f
+RFC 2046 Media Types November 1996
+
+
+ (2) message -- an encapsulated message. A body of media
+ type "message" is itself all or a portion of some kind
+ of message object. Such objects may or may not in turn
+ contain other entities. The "rfc822" subtype is used
+ when the encapsulated content is itself an RFC 822
+ message. The "partial" subtype is defined for partial
+ RFC 822 messages, to permit the fragmented transmission
+ of bodies that are thought to be too large to be passed
+ through transport facilities in one piece. Another
+ subtype, "external-body", is defined for specifying
+ large bodies by reference to an external data source.
+
+ It should be noted that the list of media type values given here may
+ be augmented in time, via the mechanisms described above, and that
+ the set of subtypes is expected to grow substantially.
+
+4. Discrete Media Type Values
+
+ Five of the seven initial media type values refer to discrete bodies.
+ The content of these types must be handled by non-MIME mechanisms;
+ they are opaque to MIME processors.
+
+4.1. Text Media Type
+
+ The "text" media type is intended for sending material which is
+ principally textual in form. A "charset" parameter may be used to
+ indicate the character set of the body text for "text" subtypes,
+ notably including the subtype "text/plain", which is a generic
+ subtype for plain text. Plain text does not provide for or allow
+ formatting commands, font attribute specifications, processing
+ instructions, interpretation directives, or content markup. Plain
+ text is seen simply as a linear sequence of characters, possibly
+ interrupted by line breaks or page breaks. Plain text may allow the
+ stacking of several characters in the same position in the text.
+ Plain text in scripts like Arabic and Hebrew may also include
+ facilitites that allow the arbitrary mixing of text segments with
+ opposite writing directions.
+
+ Beyond plain text, there are many formats for representing what might
+ be known as "rich text". An interesting characteristic of many such
+ representations is that they are to some extent readable even without
+ the software that interprets them. It is useful, then, to
+ distinguish them, at the highest level, from such unreadable data as
+ images, audio, or text represented in an unreadable form. In the
+ absence of appropriate interpretation software, it is reasonable to
+ show subtypes of "text" to the user, while it is not reasonable to do
+ so with most nontextual data. Such formatted textual data should be
+ represented using subtypes of "text".
+
+
+
+Freed & Borenstein Standards Track [Page 6]
+\f
+RFC 2046 Media Types November 1996
+
+
+4.1.1. Representation of Line Breaks
+
+ The canonical form of any MIME "text" subtype MUST always represent a
+ line break as a CRLF sequence. Similarly, any occurrence of CRLF in
+ MIME "text" MUST represent a line break. Use of CR and LF outside of
+ line break sequences is also forbidden.
+
+ This rule applies regardless of format or character set or sets
+ involved.
+
+ NOTE: The proper interpretation of line breaks when a body is
+ displayed depends on the media type. In particular, while it is
+ appropriate to treat a line break as a transition to a new line when
+ displaying a "text/plain" body, this treatment is actually incorrect
+ for other subtypes of "text" like "text/enriched" [RFC-1896].
+ Similarly, whether or not line breaks should be added during display
+ operations is also a function of the media type. It should not be
+ necessary to add any line breaks to display "text/plain" correctly,
+ whereas proper display of "text/enriched" requires the appropriate
+ addition of line breaks.
+
+ NOTE: Some protocols defines a maximum line length. E.g. SMTP [RFC-
+ 821] allows a maximum of 998 octets before the next CRLF sequence.
+ To be transported by such protocols, data which includes too long
+ segments without CRLF sequences must be encoded with a suitable
+ content-transfer-encoding.
+
+4.1.2. Charset Parameter
+
+ A critical parameter that may be specified in the Content-Type field
+ for "text/plain" data is the character set. This is specified with a
+ "charset" parameter, as in:
+
+ Content-type: text/plain; charset=iso-8859-1
+
+ Unlike some other parameter values, the values of the charset
+ parameter are NOT case sensitive. The default character set, which
+ must be assumed in the absence of a charset parameter, is US-ASCII.
+
+ The specification for any future subtypes of "text" must specify
+ whether or not they will also utilize a "charset" parameter, and may
+ possibly restrict its values as well. For other subtypes of "text"
+ than "text/plain", the semantics of the "charset" parameter should be
+ defined to be identical to those specified here for "text/plain",
+ i.e., the body consists entirely of characters in the given charset.
+ In particular, definers of future "text" subtypes should pay close
+ attention to the implications of multioctet character sets for their
+ subtype definitions.
+
+
+
+Freed & Borenstein Standards Track [Page 7]
+\f
+RFC 2046 Media Types November 1996
+
+
+ The charset parameter for subtypes of "text" gives a name of a
+ character set, as "character set" is defined in RFC 2045. The rules
+ regarding line breaks detailed in the previous section must also be
+ observed -- a character set whose definition does not conform to
+ these rules cannot be used in a MIME "text" subtype.
+
+ An initial list of predefined character set names can be found at the
+ end of this section. Additional character sets may be registered
+ with IANA.
+
+ Other media types than subtypes of "text" might choose to employ the
+ charset parameter as defined here, but with the CRLF/line break
+ restriction removed. Therefore, all character sets that conform to
+ the general definition of "character set" in RFC 2045 can be
+ registered for MIME use.
+
+ Note that if the specified character set includes 8-bit characters
+ and such characters are used in the body, a Content-Transfer-Encoding
+ header field and a corresponding encoding on the data are required in
+ order to transmit the body via some mail transfer protocols, such as
+ SMTP [RFC-821].
+
+ The default character set, US-ASCII, has been the subject of some
+ confusion and ambiguity in the past. Not only were there some
+ ambiguities in the definition, there have been wide variations in
+ practice. In order to eliminate such ambiguity and variations in the
+ future, it is strongly recommended that new user agents explicitly
+ specify a character set as a media type parameter in the Content-Type
+ header field. "US-ASCII" does not indicate an arbitrary 7-bit
+ character set, but specifies that all octets in the body must be
+ interpreted as characters according to the US-ASCII character set.
+ National and application-oriented versions of ISO 646 [ISO-646] are
+ usually NOT identical to US-ASCII, and in that case their use in
+ Internet mail is explicitly discouraged. The omission of the ISO 646
+ character set from this document is deliberate in this regard. The
+ character set name of "US-ASCII" explicitly refers to the character
+ set defined in ANSI X3.4-1986 [US- ASCII]. The new international
+ reference version (IRV) of the 1991 edition of ISO 646 is identical
+ to US-ASCII. The character set name "ASCII" is reserved and must not
+ be used for any purpose.
+
+ NOTE: RFC 821 explicitly specifies "ASCII", and references an earlier
+ version of the American Standard. Insofar as one of the purposes of
+ specifying a media type and character set is to permit the receiver
+ to unambiguously determine how the sender intended the coded message
+ to be interpreted, assuming anything other than "strict ASCII" as the
+ default would risk unintentional and incompatible changes to the
+ semantics of messages now being transmitted. This also implies that
+
+
+
+Freed & Borenstein Standards Track [Page 8]
+\f
+RFC 2046 Media Types November 1996
+
+
+ messages containing characters coded according to other versions of
+ ISO 646 than US-ASCII and the 1991 IRV, or using code-switching
+ procedures (e.g., those of ISO 2022), as well as 8bit or multiple
+ octet character encodings MUST use an appropriate character set
+ specification to be consistent with MIME.
+
+ The complete US-ASCII character set is listed in ANSI X3.4- 1986.
+ Note that the control characters including DEL (0-31, 127) have no
+ defined meaning in apart from the combination CRLF (US-ASCII values
+ 13 and 10) indicating a new line. Two of the characters have de
+ facto meanings in wide use: FF (12) often means "start subsequent
+ text on the beginning of a new page"; and TAB or HT (9) often (though
+ not always) means "move the cursor to the next available column after
+ the current position where the column number is a multiple of 8
+ (counting the first column as column 0)." Aside from these
+ conventions, any use of the control characters or DEL in a body must
+ either occur
+
+ (1) because a subtype of text other than "plain"
+ specifically assigns some additional meaning, or
+
+ (2) within the context of a private agreement between the
+ sender and recipient. Such private agreements are
+ discouraged and should be replaced by the other
+ capabilities of this document.
+
+ NOTE: An enormous proliferation of character sets exist beyond US-
+ ASCII. A large number of partially or totally overlapping character
+ sets is NOT a good thing. A SINGLE character set that can be used
+ universally for representing all of the world's languages in Internet
+ mail would be preferrable. Unfortunately, existing practice in
+ several communities seems to point to the continued use of multiple
+ character sets in the near future. A small number of standard
+ character sets are, therefore, defined for Internet use in this
+ document.
+
+ The defined charset values are:
+
+ (1) US-ASCII -- as defined in ANSI X3.4-1986 [US-ASCII].
+
+ (2) ISO-8859-X -- where "X" is to be replaced, as
+ necessary, for the parts of ISO-8859 [ISO-8859]. Note
+ that the ISO 646 character sets have deliberately been
+ omitted in favor of their 8859 replacements, which are
+ the designated character sets for Internet mail. As of
+ the publication of this document, the legitimate values
+ for "X" are the digits 1 through 10.
+
+
+
+
+Freed & Borenstein Standards Track [Page 9]
+\f
+RFC 2046 Media Types November 1996
+
+
+ Characters in the range 128-159 has no assigned meaning in ISO-8859-
+ X. Characters with values below 128 in ISO-8859-X have the same
+ assigned meaning as they do in US-ASCII.
+
+ Part 6 of ISO 8859 (Latin/Arabic alphabet) and part 8 (Latin/Hebrew
+ alphabet) includes both characters for which the normal writing
+ direction is right to left and characters for which it is left to
+ right, but do not define a canonical ordering method for representing
+ bi-directional text. The charset values "ISO-8859-6" and "ISO-8859-
+ 8", however, specify that the visual method is used [RFC-1556].
+
+ All of these character sets are used as pure 7bit or 8bit sets
+ without any shift or escape functions. The meaning of shift and
+ escape sequences in these character sets is not defined.
+
+ The character sets specified above are the ones that were relatively
+ uncontroversial during the drafting of MIME. This document does not
+ endorse the use of any particular character set other than US-ASCII,
+ and recognizes that the future evolution of world character sets
+ remains unclear.
+
+ Note that the character set used, if anything other than US- ASCII,
+ must always be explicitly specified in the Content-Type field.
+
+ No character set name other than those defined above may be used in
+ Internet mail without the publication of a formal specification and
+ its registration with IANA, or by private agreement, in which case
+ the character set name must begin with "X-".
+
+ Implementors are discouraged from defining new character sets unless
+ absolutely necessary.
+
+ The "charset" parameter has been defined primarily for the purpose of
+ textual data, and is described in this section for that reason.
+ However, it is conceivable that non-textual data might also wish to
+ specify a charset value for some purpose, in which case the same
+ syntax and values should be used.
+
+ In general, composition software should always use the "lowest common
+ denominator" character set possible. For example, if a body contains
+ only US-ASCII characters, it SHOULD be marked as being in the US-
+ ASCII character set, not ISO-8859-1, which, like all the ISO-8859
+ family of character sets, is a superset of US-ASCII. More generally,
+ if a widely-used character set is a subset of another character set,
+ and a body contains only characters in the widely-used subset, it
+ should be labelled as being in that subset. This will increase the
+ chances that the recipient will be able to view the resulting entity
+ correctly.
+
+
+
+Freed & Borenstein Standards Track [Page 10]
+\f
+RFC 2046 Media Types November 1996
+
+
+4.1.3. Plain Subtype
+
+ The simplest and most important subtype of "text" is "plain". This
+ indicates plain text that does not contain any formatting commands or
+ directives. Plain text is intended to be displayed "as-is", that is,
+ no interpretation of embedded formatting commands, font attribute
+ specifications, processing instructions, interpretation directives,
+ or content markup should be necessary for proper display. The
+ default media type of "text/plain; charset=us-ascii" for Internet
+ mail describes existing Internet practice. That is, it is the type
+ of body defined by RFC 822.
+
+ No other "text" subtype is defined by this document.
+
+4.1.4. Unrecognized Subtypes
+
+ Unrecognized subtypes of "text" should be treated as subtype "plain"
+ as long as the MIME implementation knows how to handle the charset.
+ Unrecognized subtypes which also specify an unrecognized charset
+ should be treated as "application/octet- stream".
+
+4.2. Image Media Type
+
+ A media type of "image" indicates that the body contains an image.
+ The subtype names the specific image format. These names are not
+ case sensitive. An initial subtype is "jpeg" for the JPEG format
+ using JFIF encoding [JPEG].
+
+ The list of "image" subtypes given here is neither exclusive nor
+ exhaustive, and is expected to grow as more types are registered with
+ IANA, as described in RFC 2048.
+
+ Unrecognized subtypes of "image" should at a miniumum be treated as
+ "application/octet-stream". Implementations may optionally elect to
+ pass subtypes of "image" that they do not specifically recognize to a
+ secure and robust general-purpose image viewing application, if such
+ an application is available.
+
+ NOTE: Using of a generic-purpose image viewing application this way
+ inherits the security problems of the most dangerous type supported
+ by the application.
+
+4.3. Audio Media Type
+
+ A media type of "audio" indicates that the body contains audio data.
+ Although there is not yet a consensus on an "ideal" audio format for
+ use with computers, there is a pressing need for a format capable of
+ providing interoperable behavior.
+
+
+
+Freed & Borenstein Standards Track [Page 11]
+\f
+RFC 2046 Media Types November 1996
+
+
+ The initial subtype of "basic" is specified to meet this requirement
+ by providing an absolutely minimal lowest common denominator audio
+ format. It is expected that richer formats for higher quality and/or
+ lower bandwidth audio will be defined by a later document.
+
+ The content of the "audio/basic" subtype is single channel audio
+ encoded using 8bit ISDN mu-law [PCM] at a sample rate of 8000 Hz.
+
+ Unrecognized subtypes of "audio" should at a miniumum be treated as
+ "application/octet-stream". Implementations may optionally elect to
+ pass subtypes of "audio" that they do not specifically recognize to a
+ robust general-purpose audio playing application, if such an
+ application is available.
+
+4.4. Video Media Type
+
+ A media type of "video" indicates that the body contains a time-
+ varying-picture image, possibly with color and coordinated sound.
+ The term 'video' is used in its most generic sense, rather than with
+ reference to any particular technology or format, and is not meant to
+ preclude subtypes such as animated drawings encoded compactly. The
+ subtype "mpeg" refers to video coded according to the MPEG standard
+ [MPEG].
+
+ Note that although in general this document strongly discourages the
+ mixing of multiple media in a single body, it is recognized that many
+ so-called video formats include a representation for synchronized
+ audio, and this is explicitly permitted for subtypes of "video".
+
+ Unrecognized subtypes of "video" should at a minumum be treated as
+ "application/octet-stream". Implementations may optionally elect to
+ pass subtypes of "video" that they do not specifically recognize to a
+ robust general-purpose video display application, if such an
+ application is available.
+
+4.5. Application Media Type
+
+ The "application" media type is to be used for discrete data which do
+ not fit in any of the other categories, and particularly for data to
+ be processed by some type of application program. This is
+ information which must be processed by an application before it is
+ viewable or usable by a user. Expected uses for the "application"
+ media type include file transfer, spreadsheets, data for mail-based
+ scheduling systems, and languages for "active" (computational)
+ material. (The latter, in particular, can pose security problems
+ which must be understood by implementors, and are considered in
+ detail in the discussion of the "application/PostScript" media type.)
+
+
+
+
+Freed & Borenstein Standards Track [Page 12]
+\f
+RFC 2046 Media Types November 1996
+
+
+ For example, a meeting scheduler might define a standard
+ representation for information about proposed meeting dates. An
+ intelligent user agent would use this information to conduct a dialog
+ with the user, and might then send additional material based on that
+ dialog. More generally, there have been several "active" messaging
+ languages developed in which programs in a suitably specialized
+ language are transported to a remote location and automatically run
+ in the recipient's environment.
+
+ Such applications may be defined as subtypes of the "application"
+ media type. This document defines two subtypes:
+
+ octet-stream, and PostScript.
+
+ The subtype of "application" will often be either the name or include
+ part of the name of the application for which the data are intended.
+ This does not mean, however, that any application program name may be
+ used freely as a subtype of "application".
+
+4.5.1. Octet-Stream Subtype
+
+ The "octet-stream" subtype is used to indicate that a body contains
+ arbitrary binary data. The set of currently defined parameters is:
+
+ (1) TYPE -- the general type or category of binary data.
+ This is intended as information for the human recipient
+ rather than for any automatic processing.
+
+ (2) PADDING -- the number of bits of padding that were
+ appended to the bit-stream comprising the actual
+ contents to produce the enclosed 8bit byte-oriented
+ data. This is useful for enclosing a bit-stream in a
+ body when the total number of bits is not a multiple of
+ 8.
+
+ Both of these parameters are optional.
+
+ An additional parameter, "CONVERSIONS", was defined in RFC 1341 but
+ has since been removed. RFC 1341 also defined the use of a "NAME"
+ parameter which gave a suggested file name to be used if the data
+ were to be written to a file. This has been deprecated in
+ anticipation of a separate Content-Disposition header field, to be
+ defined in a subsequent RFC.
+
+ The recommended action for an implementation that receives an
+ "application/octet-stream" entity is to simply offer to put the data
+ in a file, with any Content-Transfer-Encoding undone, or perhaps to
+ use it as input to a user-specified process.
+
+
+
+Freed & Borenstein Standards Track [Page 13]
+\f
+RFC 2046 Media Types November 1996
+
+
+ To reduce the danger of transmitting rogue programs, it is strongly
+ recommended that implementations NOT implement a path-search
+ mechanism whereby an arbitrary program named in the Content-Type
+ parameter (e.g., an "interpreter=" parameter) is found and executed
+ using the message body as input.
+
+4.5.2. PostScript Subtype
+
+ A media type of "application/postscript" indicates a PostScript
+ program. Currently two variants of the PostScript language are
+ allowed; the original level 1 variant is described in [POSTSCRIPT]
+ and the more recent level 2 variant is described in [POSTSCRIPT2].
+
+ PostScript is a registered trademark of Adobe Systems, Inc. Use of
+ the MIME media type "application/postscript" implies recognition of
+ that trademark and all the rights it entails.
+
+ The PostScript language definition provides facilities for internal
+ labelling of the specific language features a given program uses.
+ This labelling, called the PostScript document structuring
+ conventions, or DSC, is very general and provides substantially more
+ information than just the language level. The use of document
+ structuring conventions, while not required, is strongly recommended
+ as an aid to interoperability. Documents which lack proper
+ structuring conventions cannot be tested to see whether or not they
+ will work in a given environment. As such, some systems may assume
+ the worst and refuse to process unstructured documents.
+
+ The execution of general-purpose PostScript interpreters entails
+ serious security risks, and implementors are discouraged from simply
+ sending PostScript bodies to "off- the-shelf" interpreters. While it
+ is usually safe to send PostScript to a printer, where the potential
+ for harm is greatly constrained by typical printer environments,
+ implementors should consider all of the following before they add
+ interactive display of PostScript bodies to their MIME readers.
+
+ The remainder of this section outlines some, though probably not all,
+ of the possible problems with the transport of PostScript entities.
+
+ (1) Dangerous operations in the PostScript language
+ include, but may not be limited to, the PostScript
+ operators "deletefile", "renamefile", "filenameforall",
+ and "file". "File" is only dangerous when applied to
+ something other than standard input or output.
+ Implementations may also define additional nonstandard
+ file operators; these may also pose a threat to
+ security. "Filenameforall", the wildcard file search
+ operator, may appear at first glance to be harmless.
+
+
+
+Freed & Borenstein Standards Track [Page 14]
+\f
+RFC 2046 Media Types November 1996
+
+
+ Note, however, that this operator has the potential to
+ reveal information about what files the recipient has
+ access to, and this information may itself be
+ sensitive. Message senders should avoid the use of
+ potentially dangerous file operators, since these
+ operators are quite likely to be unavailable in secure
+ PostScript implementations. Message receiving and
+ displaying software should either completely disable
+ all potentially dangerous file operators or take
+ special care not to delegate any special authority to
+ their operation. These operators should be viewed as
+ being done by an outside agency when interpreting
+ PostScript documents. Such disabling and/or checking
+ should be done completely outside of the reach of the
+ PostScript language itself; care should be taken to
+ insure that no method exists for re-enabling full-
+ function versions of these operators.
+
+ (2) The PostScript language provides facilities for exiting
+ the normal interpreter, or server, loop. Changes made
+ in this "outer" environment are customarily retained
+ across documents, and may in some cases be retained
+ semipermanently in nonvolatile memory. The operators
+ associated with exiting the interpreter loop have the
+ potential to interfere with subsequent document
+ processing. As such, their unrestrained use
+ constitutes a threat of service denial. PostScript
+ operators that exit the interpreter loop include, but
+ may not be limited to, the exitserver and startjob
+ operators. Message sending software should not
+ generate PostScript that depends on exiting the
+ interpreter loop to operate, since the ability to exit
+ will probably be unavailable in secure PostScript
+ implementations. Message receiving and displaying
+ software should completely disable the ability to make
+ retained changes to the PostScript environment by
+ eliminating or disabling the "startjob" and
+ "exitserver" operations. If these operations cannot be
+ eliminated or completely disabled the password
+ associated with them should at least be set to a hard-
+ to-guess value.
+
+ (3) PostScript provides operators for setting system-wide
+ and device-specific parameters. These parameter
+ settings may be retained across jobs and may
+ potentially pose a threat to the correct operation of
+ the interpreter. The PostScript operators that set
+ system and device parameters include, but may not be
+
+
+
+Freed & Borenstein Standards Track [Page 15]
+\f
+RFC 2046 Media Types November 1996
+
+
+ limited to, the "setsystemparams" and "setdevparams"
+ operators. Message sending software should not
+ generate PostScript that depends on the setting of
+ system or device parameters to operate correctly. The
+ ability to set these parameters will probably be
+ unavailable in secure PostScript implementations.
+ Message receiving and displaying software should
+ disable the ability to change system and device
+ parameters. If these operators cannot be completely
+ disabled the password associated with them should at
+ least be set to a hard-to-guess value.
+
+ (4) Some PostScript implementations provide nonstandard
+ facilities for the direct loading and execution of
+ machine code. Such facilities are quite obviously open
+ to substantial abuse. Message sending software should
+ not make use of such features. Besides being totally
+ hardware-specific, they are also likely to be
+ unavailable in secure implementations of PostScript.
+ Message receiving and displaying software should not
+ allow such operators to be used if they exist.
+
+ (5) PostScript is an extensible language, and many, if not
+ most, implementations of it provide a number of their
+ own extensions. This document does not deal with such
+ extensions explicitly since they constitute an unknown
+ factor. Message sending software should not make use
+ of nonstandard extensions; they are likely to be
+ missing from some implementations. Message receiving
+ and displaying software should make sure that any
+ nonstandard PostScript operators are secure and don't
+ present any kind of threat.
+
+ (6) It is possible to write PostScript that consumes huge
+ amounts of various system resources. It is also
+ possible to write PostScript programs that loop
+ indefinitely. Both types of programs have the
+ potential to cause damage if sent to unsuspecting
+ recipients. Message-sending software should avoid the
+ construction and dissemination of such programs, which
+ is antisocial. Message receiving and displaying
+ software should provide appropriate mechanisms to abort
+ processing after a reasonable amount of time has
+ elapsed. In addition, PostScript interpreters should be
+ limited to the consumption of only a reasonable amount
+ of any given system resource.
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 16]
+\f
+RFC 2046 Media Types November 1996
+
+
+ (7) It is possible to include raw binary information inside
+ PostScript in various forms. This is not recommended
+ for use in Internet mail, both because it is not
+ supported by all PostScript interpreters and because it
+ significantly complicates the use of a MIME Content-
+ Transfer-Encoding. (Without such binary, PostScript
+ may typically be viewed as line-oriented data. The
+ treatment of CRLF sequences becomes extremely
+ problematic if binary and line-oriented data are mixed
+ in a single Postscript data stream.)
+
+ (8) Finally, bugs may exist in some PostScript interpreters
+ which could possibly be exploited to gain unauthorized
+ access to a recipient's system. Apart from noting this
+ possibility, there is no specific action to take to
+ prevent this, apart from the timely correction of such
+ bugs if any are found.
+
+4.5.3. Other Application Subtypes
+
+ It is expected that many other subtypes of "application" will be
+ defined in the future. MIME implementations must at a minimum treat
+ any unrecognized subtypes as being equivalent to "application/octet-
+ stream".
+
+5. Composite Media Type Values
+
+ The remaining two of the seven initial Content-Type values refer to
+ composite entities. Composite entities are handled using MIME
+ mechanisms -- a MIME processor typically handles the body directly.
+
+5.1. Multipart Media Type
+
+ In the case of multipart entities, in which one or more different
+ sets of data are combined in a single body, a "multipart" media type
+ field must appear in the entity's header. The body must then contain
+ one or more body parts, each preceded by a boundary delimiter line,
+ and the last one followed by a closing boundary delimiter line.
+ After its boundary delimiter line, each body part then consists of a
+ header area, a blank line, and a body area. Thus a body part is
+ similar to an RFC 822 message in syntax, but different in meaning.
+
+ A body part is an entity and hence is NOT to be interpreted as
+ actually being an RFC 822 message. To begin with, NO header fields
+ are actually required in body parts. A body part that starts with a
+ blank line, therefore, is allowed and is a body part for which all
+ default values are to be assumed. In such a case, the absence of a
+ Content-Type header usually indicates that the corresponding body has
+
+
+
+Freed & Borenstein Standards Track [Page 17]
+\f
+RFC 2046 Media Types November 1996
+
+
+ a content-type of "text/plain; charset=US-ASCII".
+
+ The only header fields that have defined meaning for body parts are
+ those the names of which begin with "Content-". All other header
+ fields may be ignored in body parts. Although they should generally
+ be retained if at all possible, they may be discarded by gateways if
+ necessary. Such other fields are permitted to appear in body parts
+ but must not be depended on. "X-" fields may be created for
+ experimental or private purposes, with the recognition that the
+ information they contain may be lost at some gateways.
+
+ NOTE: The distinction between an RFC 822 message and a body part is
+ subtle, but important. A gateway between Internet and X.400 mail,
+ for example, must be able to tell the difference between a body part
+ that contains an image and a body part that contains an encapsulated
+ message, the body of which is a JPEG image. In order to represent
+ the latter, the body part must have "Content-Type: message/rfc822",
+ and its body (after the blank line) must be the encapsulated message,
+ with its own "Content-Type: image/jpeg" header field. The use of
+ similar syntax facilitates the conversion of messages to body parts,
+ and vice versa, but the distinction between the two must be
+ understood by implementors. (For the special case in which parts
+ actually are messages, a "digest" subtype is also defined.)
+
+ As stated previously, each body part is preceded by a boundary
+ delimiter line that contains the boundary delimiter. The boundary
+ delimiter MUST NOT appear inside any of the encapsulated parts, on a
+ line by itself or as the prefix of any line. This implies that it is
+ crucial that the composing agent be able to choose and specify a
+ unique boundary parameter value that does not contain the boundary
+ parameter value of an enclosing multipart as a prefix.
+
+ All present and future subtypes of the "multipart" type must use an
+ identical syntax. Subtypes may differ in their semantics, and may
+ impose additional restrictions on syntax, but must conform to the
+ required syntax for the "multipart" type. This requirement ensures
+ that all conformant user agents will at least be able to recognize
+ and separate the parts of any multipart entity, even those of an
+ unrecognized subtype.
+
+ As stated in the definition of the Content-Transfer-Encoding field
+ [RFC 2045], no encoding other than "7bit", "8bit", or "binary" is
+ permitted for entities of type "multipart". The "multipart" boundary
+ delimiters and header fields are always represented as 7bit US-ASCII
+ in any case (though the header fields may encode non-US-ASCII header
+ text as per RFC 2047) and data within the body parts can be encoded
+ on a part-by-part basis, with Content-Transfer-Encoding fields for
+ each appropriate body part.
+
+
+
+Freed & Borenstein Standards Track [Page 18]
+\f
+RFC 2046 Media Types November 1996
+
+
+5.1.1. Common Syntax
+
+ This section defines a common syntax for subtypes of "multipart".
+ All subtypes of "multipart" must use this syntax. A simple example
+ of a multipart message also appears in this section. An example of a
+ more complex multipart message is given in RFC 2049.
+
+ The Content-Type field for multipart entities requires one parameter,
+ "boundary". The boundary delimiter line is then defined as a line
+ consisting entirely of two hyphen characters ("-", decimal value 45)
+ followed by the boundary parameter value from the Content-Type header
+ field, optional linear whitespace, and a terminating CRLF.
+
+ NOTE: The hyphens are for rough compatibility with the earlier RFC
+ 934 method of message encapsulation, and for ease of searching for
+ the boundaries in some implementations. However, it should be noted
+ that multipart messages are NOT completely compatible with RFC 934
+ encapsulations; in particular, they do not obey RFC 934 quoting
+ conventions for embedded lines that begin with hyphens. This
+ mechanism was chosen over the RFC 934 mechanism because the latter
+ causes lines to grow with each level of quoting. The combination of
+ this growth with the fact that SMTP implementations sometimes wrap
+ long lines made the RFC 934 mechanism unsuitable for use in the event
+ that deeply-nested multipart structuring is ever desired.
+
+ WARNING TO IMPLEMENTORS: The grammar for parameters on the Content-
+ type field is such that it is often necessary to enclose the boundary
+ parameter values in quotes on the Content-type line. This is not
+ always necessary, but never hurts. Implementors should be sure to
+ study the grammar carefully in order to avoid producing invalid
+ Content-type fields. Thus, a typical "multipart" Content-Type header
+ field might look like this:
+
+ Content-Type: multipart/mixed; boundary=gc0p4Jq0M2Yt08j34c0p
+
+ But the following is not valid:
+
+ Content-Type: multipart/mixed; boundary=gc0pJq0M:08jU534c0p
+
+ (because of the colon) and must instead be represented as
+
+ Content-Type: multipart/mixed; boundary="gc0pJq0M:08jU534c0p"
+
+ This Content-Type value indicates that the content consists of one or
+ more parts, each with a structure that is syntactically identical to
+ an RFC 822 message, except that the header area is allowed to be
+ completely empty, and that the parts are each preceded by the line
+
+
+
+
+Freed & Borenstein Standards Track [Page 19]
+\f
+RFC 2046 Media Types November 1996
+
+
+ --gc0pJq0M:08jU534c0p
+
+ The boundary delimiter MUST occur at the beginning of a line, i.e.,
+ following a CRLF, and the initial CRLF is considered to be attached
+ to the boundary delimiter line rather than part of the preceding
+ part. The boundary may be followed by zero or more characters of
+ linear whitespace. It is then terminated by either another CRLF and
+ the header fields for the next part, or by two CRLFs, in which case
+ there are no header fields for the next part. If no Content-Type
+ field is present it is assumed to be "message/rfc822" in a
+ "multipart/digest" and "text/plain" otherwise.
+
+ NOTE: The CRLF preceding the boundary delimiter line is conceptually
+ attached to the boundary so that it is possible to have a part that
+ does not end with a CRLF (line break). Body parts that must be
+ considered to end with line breaks, therefore, must have two CRLFs
+ preceding the boundary delimiter line, the first of which is part of
+ the preceding body part, and the second of which is part of the
+ encapsulation boundary.
+
+ Boundary delimiters must not appear within the encapsulated material,
+ and must be no longer than 70 characters, not counting the two
+ leading hyphens.
+
+ The boundary delimiter line following the last body part is a
+ distinguished delimiter that indicates that no further body parts
+ will follow. Such a delimiter line is identical to the previous
+ delimiter lines, with the addition of two more hyphens after the
+ boundary parameter value.
+
+ --gc0pJq0M:08jU534c0p--
+
+ NOTE TO IMPLEMENTORS: Boundary string comparisons must compare the
+ boundary value with the beginning of each candidate line. An exact
+ match of the entire candidate line is not required; it is sufficient
+ that the boundary appear in its entirety following the CRLF.
+
+ There appears to be room for additional information prior to the
+ first boundary delimiter line and following the final boundary
+ delimiter line. These areas should generally be left blank, and
+ implementations must ignore anything that appears before the first
+ boundary delimiter line or after the last one.
+
+ NOTE: These "preamble" and "epilogue" areas are generally not used
+ because of the lack of proper typing of these parts and the lack of
+ clear semantics for handling these areas at gateways, particularly
+ X.400 gateways. However, rather than leaving the preamble area
+ blank, many MIME implementations have found this to be a convenient
+
+
+
+Freed & Borenstein Standards Track [Page 20]
+\f
+RFC 2046 Media Types November 1996
+
+
+ place to insert an explanatory note for recipients who read the
+ message with pre-MIME software, since such notes will be ignored by
+ MIME-compliant software.
+
+ NOTE: Because boundary delimiters must not appear in the body parts
+ being encapsulated, a user agent must exercise care to choose a
+ unique boundary parameter value. The boundary parameter value in the
+ example above could have been the result of an algorithm designed to
+ produce boundary delimiters with a very low probability of already
+ existing in the data to be encapsulated without having to prescan the
+ data. Alternate algorithms might result in more "readable" boundary
+ delimiters for a recipient with an old user agent, but would require
+ more attention to the possibility that the boundary delimiter might
+ appear at the beginning of some line in the encapsulated part. The
+ simplest boundary delimiter line possible is something like "---",
+ with a closing boundary delimiter line of "-----".
+
+ As a very simple example, the following multipart message has two
+ parts, both of them plain text, one of them explicitly typed and one
+ of them implicitly typed:
+
+ From: Nathaniel Borenstein <nsb@bellcore.com>
+ To: Ned Freed <ned@innosoft.com>
+ Date: Sun, 21 Mar 1993 23:56:48 -0800 (PST)
+ Subject: Sample message
+ MIME-Version: 1.0
+ Content-type: multipart/mixed; boundary="simple boundary"
+
+ This is the preamble. It is to be ignored, though it
+ is a handy place for composition agents to include an
+ explanatory note to non-MIME conformant readers.
+
+ --simple boundary
+
+ This is implicitly typed plain US-ASCII text.
+ It does NOT end with a linebreak.
+ --simple boundary
+ Content-type: text/plain; charset=us-ascii
+
+ This is explicitly typed plain US-ASCII text.
+ It DOES end with a linebreak.
+
+ --simple boundary--
+
+ This is the epilogue. It is also to be ignored.
+
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 21]
+\f
+RFC 2046 Media Types November 1996
+
+
+ The use of a media type of "multipart" in a body part within another
+ "multipart" entity is explicitly allowed. In such cases, for obvious
+ reasons, care must be taken to ensure that each nested "multipart"
+ entity uses a different boundary delimiter. See RFC 2049 for an
+ example of nested "multipart" entities.
+
+ The use of the "multipart" media type with only a single body part
+ may be useful in certain contexts, and is explicitly permitted.
+
+ NOTE: Experience has shown that a "multipart" media type with a
+ single body part is useful for sending non-text media types. It has
+ the advantage of providing the preamble as a place to include
+ decoding instructions. In addition, a number of SMTP gateways move
+ or remove the MIME headers, and a clever MIME decoder can take a good
+ guess at multipart boundaries even in the absence of the Content-Type
+ header and thereby successfully decode the message.
+
+ The only mandatory global parameter for the "multipart" media type is
+ the boundary parameter, which consists of 1 to 70 characters from a
+ set of characters known to be very robust through mail gateways, and
+ NOT ending with white space. (If a boundary delimiter line appears to
+ end with white space, the white space must be presumed to have been
+ added by a gateway, and must be deleted.) It is formally specified
+ by the following BNF:
+
+ boundary := 0*69<bchars> bcharsnospace
+
+ bchars := bcharsnospace / " "
+
+ bcharsnospace := DIGIT / ALPHA / "'" / "(" / ")" /
+ "+" / "_" / "," / "-" / "." /
+ "/" / ":" / "=" / "?"
+
+ Overall, the body of a "multipart" entity may be specified as
+ follows:
+
+ dash-boundary := "--" boundary
+ ; boundary taken from the value of
+ ; boundary parameter of the
+ ; Content-Type field.
+
+ multipart-body := [preamble CRLF]
+ dash-boundary transport-padding CRLF
+ body-part *encapsulation
+ close-delimiter transport-padding
+ [CRLF epilogue]
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 22]
+\f
+RFC 2046 Media Types November 1996
+
+
+ transport-padding := *LWSP-char
+ ; Composers MUST NOT generate
+ ; non-zero length transport
+ ; padding, but receivers MUST
+ ; be able to handle padding
+ ; added by message transports.
+
+ encapsulation := delimiter transport-padding
+ CRLF body-part
+
+ delimiter := CRLF dash-boundary
+
+ close-delimiter := delimiter "--"
+
+ preamble := discard-text
+
+ epilogue := discard-text
+
+ discard-text := *(*text CRLF) *text
+ ; May be ignored or discarded.
+
+ body-part := MIME-part-headers [CRLF *OCTET]
+ ; Lines in a body-part must not start
+ ; with the specified dash-boundary and
+ ; the delimiter must not appear anywhere
+ ; in the body part. Note that the
+ ; semantics of a body-part differ from
+ ; the semantics of a message, as
+ ; described in the text.
+
+ OCTET := <any 0-255 octet value>
+
+ IMPORTANT: The free insertion of linear-white-space and RFC 822
+ comments between the elements shown in this BNF is NOT allowed since
+ this BNF does not specify a structured header field.
+
+ NOTE: In certain transport enclaves, RFC 822 restrictions such as
+ the one that limits bodies to printable US-ASCII characters may not
+ be in force. (That is, the transport domains may exist that resemble
+ standard Internet mail transport as specified in RFC 821 and assumed
+ by RFC 822, but without certain restrictions.) The relaxation of
+ these restrictions should be construed as locally extending the
+ definition of bodies, for example to include octets outside of the
+ US-ASCII range, as long as these extensions are supported by the
+ transport and adequately documented in the Content- Transfer-Encoding
+ header field. However, in no event are headers (either message
+ headers or body part headers) allowed to contain anything other than
+ US-ASCII characters.
+
+
+
+Freed & Borenstein Standards Track [Page 23]
+\f
+RFC 2046 Media Types November 1996
+
+
+ NOTE: Conspicuously missing from the "multipart" type is a notion of
+ structured, related body parts. It is recommended that those wishing
+ to provide more structured or integrated multipart messaging
+ facilities should define subtypes of multipart that are syntactically
+ identical but define relationships between the various parts. For
+ example, subtypes of multipart could be defined that include a
+ distinguished part which in turn is used to specify the relationships
+ between the other parts, probably referring to them by their
+ Content-ID field. Old implementations will not recognize the new
+ subtype if this approach is used, but will treat it as
+ multipart/mixed and will thus be able to show the user the parts that
+ are recognized.
+
+5.1.2. Handling Nested Messages and Multiparts
+
+ The "message/rfc822" subtype defined in a subsequent section of this
+ document has no terminating condition other than running out of data.
+ Similarly, an improperly truncated "multipart" entity may not have
+ any terminating boundary marker, and can turn up operationally due to
+ mail system malfunctions.
+
+ It is essential that such entities be handled correctly when they are
+ themselves imbedded inside of another "multipart" structure. MIME
+ implementations are therefore required to recognize outer level
+ boundary markers at ANY level of inner nesting. It is not sufficient
+ to only check for the next expected marker or other terminating
+ condition.
+
+5.1.3. Mixed Subtype
+
+ The "mixed" subtype of "multipart" is intended for use when the body
+ parts are independent and need to be bundled in a particular order.
+ Any "multipart" subtypes that an implementation does not recognize
+ must be treated as being of subtype "mixed".
+
+5.1.4. Alternative Subtype
+
+ The "multipart/alternative" type is syntactically identical to
+ "multipart/mixed", but the semantics are different. In particular,
+ each of the body parts is an "alternative" version of the same
+ information.
+
+ Systems should recognize that the content of the various parts are
+ interchangeable. Systems should choose the "best" type based on the
+ local environment and references, in some cases even through user
+ interaction. As with "multipart/mixed", the order of body parts is
+ significant. In this case, the alternatives appear in an order of
+ increasing faithfulness to the original content. In general, the
+
+
+
+Freed & Borenstein Standards Track [Page 24]
+\f
+RFC 2046 Media Types November 1996
+
+
+ best choice is the LAST part of a type supported by the recipient
+ system's local environment.
+
+ "Multipart/alternative" may be used, for example, to send a message
+ in a fancy text format in such a way that it can easily be displayed
+ anywhere:
+
+ From: Nathaniel Borenstein <nsb@bellcore.com>
+ To: Ned Freed <ned@innosoft.com>
+ Date: Mon, 22 Mar 1993 09:41:09 -0800 (PST)
+ Subject: Formatted text mail
+ MIME-Version: 1.0
+ Content-Type: multipart/alternative; boundary=boundary42
+
+ --boundary42
+ Content-Type: text/plain; charset=us-ascii
+
+ ... plain text version of message goes here ...
+
+ --boundary42
+ Content-Type: text/enriched
+
+ ... RFC 1896 text/enriched version of same message
+ goes here ...
+
+ --boundary42
+ Content-Type: application/x-whatever
+
+ ... fanciest version of same message goes here ...
+
+ --boundary42--
+
+ In this example, users whose mail systems understood the
+ "application/x-whatever" format would see only the fancy version,
+ while other users would see only the enriched or plain text version,
+ depending on the capabilities of their system.
+
+ In general, user agents that compose "multipart/alternative" entities
+ must place the body parts in increasing order of preference, that is,
+ with the preferred format last. For fancy text, the sending user
+ agent should put the plainest format first and the richest format
+ last. Receiving user agents should pick and display the last format
+ they are capable of displaying. In the case where one of the
+ alternatives is itself of type "multipart" and contains unrecognized
+ sub-parts, the user agent may choose either to show that alternative,
+ an earlier alternative, or both.
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 25]
+\f
+RFC 2046 Media Types November 1996
+
+
+ NOTE: From an implementor's perspective, it might seem more sensible
+ to reverse this ordering, and have the plainest alternative last.
+ However, placing the plainest alternative first is the friendliest
+ possible option when "multipart/alternative" entities are viewed
+ using a non-MIME-conformant viewer. While this approach does impose
+ some burden on conformant MIME viewers, interoperability with older
+ mail readers was deemed to be more important in this case.
+
+ It may be the case that some user agents, if they can recognize more
+ than one of the formats, will prefer to offer the user the choice of
+ which format to view. This makes sense, for example, if a message
+ includes both a nicely- formatted image version and an easily-edited
+ text version. What is most critical, however, is that the user not
+ automatically be shown multiple versions of the same data. Either
+ the user should be shown the last recognized version or should be
+ given the choice.
+
+ THE SEMANTICS OF CONTENT-ID IN MULTIPART/ALTERNATIVE: Each part of a
+ "multipart/alternative" entity represents the same data, but the
+ mappings between the two are not necessarily without information
+ loss. For example, information is lost when translating ODA to
+ PostScript or plain text. It is recommended that each part should
+ have a different Content-ID value in the case where the information
+ content of the two parts is not identical. And when the information
+ content is identical -- for example, where several parts of type
+ "message/external-body" specify alternate ways to access the
+ identical data -- the same Content-ID field value should be used, to
+ optimize any caching mechanisms that might be present on the
+ recipient's end. However, the Content-ID values used by the parts
+ should NOT be the same Content-ID value that describes the
+ "multipart/alternative" as a whole, if there is any such Content-ID
+ field. That is, one Content-ID value will refer to the
+ "multipart/alternative" entity, while one or more other Content-ID
+ values will refer to the parts inside it.
+
+5.1.5. Digest Subtype
+
+ This document defines a "digest" subtype of the "multipart" Content-
+ Type. This type is syntactically identical to "multipart/mixed", but
+ the semantics are different. In particular, in a digest, the default
+ Content-Type value for a body part is changed from "text/plain" to
+ "message/rfc822". This is done to allow a more readable digest
+ format that is largely compatible (except for the quoting convention)
+ with RFC 934.
+
+ Note: Though it is possible to specify a Content-Type value for a
+ body part in a digest which is other than "message/rfc822", such as a
+ "text/plain" part containing a description of the material in the
+
+
+
+Freed & Borenstein Standards Track [Page 26]
+\f
+RFC 2046 Media Types November 1996
+
+
+ digest, actually doing so is undesireble. The "multipart/digest"
+ Content-Type is intended to be used to send collections of messages.
+ If a "text/plain" part is needed, it should be included as a seperate
+ part of a "multipart/mixed" message.
+
+ A digest in this format might, then, look something like this:
+
+ From: Moderator-Address
+ To: Recipient-List
+ Date: Mon, 22 Mar 1994 13:34:51 +0000
+ Subject: Internet Digest, volume 42
+ MIME-Version: 1.0
+ Content-Type: multipart/mixed;
+ boundary="---- main boundary ----"
+
+ ------ main boundary ----
+
+ ...Introductory text or table of contents...
+
+ ------ main boundary ----
+ Content-Type: multipart/digest;
+ boundary="---- next message ----"
+
+ ------ next message ----
+
+ From: someone-else
+ Date: Fri, 26 Mar 1993 11:13:32 +0200
+ Subject: my opinion
+
+ ...body goes here ...
+
+ ------ next message ----
+
+ From: someone-else-again
+ Date: Fri, 26 Mar 1993 10:07:13 -0500
+ Subject: my different opinion
+
+ ... another body goes here ...
+
+ ------ next message ------
+
+ ------ main boundary ------
+
+5.1.6. Parallel Subtype
+
+ This document defines a "parallel" subtype of the "multipart"
+ Content-Type. This type is syntactically identical to
+ "multipart/mixed", but the semantics are different. In particular,
+
+
+
+Freed & Borenstein Standards Track [Page 27]
+\f
+RFC 2046 Media Types November 1996
+
+
+ in a parallel entity, the order of body parts is not significant.
+
+ A common presentation of this type is to display all of the parts
+ simultaneously on hardware and software that are capable of doing so.
+ However, composing agents should be aware that many mail readers will
+ lack this capability and will show the parts serially in any event.
+
+5.1.7. Other Multipart Subtypes
+
+ Other "multipart" subtypes are expected in the future. MIME
+ implementations must in general treat unrecognized subtypes of
+ "multipart" as being equivalent to "multipart/mixed".
+
+5.2. Message Media Type
+
+ It is frequently desirable, in sending mail, to encapsulate another
+ mail message. A special media type, "message", is defined to
+ facilitate this. In particular, the "rfc822" subtype of "message" is
+ used to encapsulate RFC 822 messages.
+
+ NOTE: It has been suggested that subtypes of "message" might be
+ defined for forwarded or rejected messages. However, forwarded and
+ rejected messages can be handled as multipart messages in which the
+ first part contains any control or descriptive information, and a
+ second part, of type "message/rfc822", is the forwarded or rejected
+ message. Composing rejection and forwarding messages in this manner
+ will preserve the type information on the original message and allow
+ it to be correctly presented to the recipient, and hence is strongly
+ encouraged.
+
+ Subtypes of "message" often impose restrictions on what encodings are
+ allowed. These restrictions are described in conjunction with each
+ specific subtype.
+
+ Mail gateways, relays, and other mail handling agents are commonly
+ known to alter the top-level header of an RFC 822 message. In
+ particular, they frequently add, remove, or reorder header fields.
+ These operations are explicitly forbidden for the encapsulated
+ headers embedded in the bodies of messages of type "message."
+
+5.2.1. RFC822 Subtype
+
+ A media type of "message/rfc822" indicates that the body contains an
+ encapsulated message, with the syntax of an RFC 822 message.
+ However, unlike top-level RFC 822 messages, the restriction that each
+ "message/rfc822" body must include a "From", "Date", and at least one
+ destination header is removed and replaced with the requirement that
+ at least one of "From", "Subject", or "Date" must be present.
+
+
+
+Freed & Borenstein Standards Track [Page 28]
+\f
+RFC 2046 Media Types November 1996
+
+
+ It should be noted that, despite the use of the numbers "822", a
+ "message/rfc822" entity isn't restricted to material in strict
+ conformance to RFC822, nor are the semantics of "message/rfc822"
+ objects restricted to the semantics defined in RFC822. More
+ specifically, a "message/rfc822" message could well be a News article
+ or a MIME message.
+
+ No encoding other than "7bit", "8bit", or "binary" is permitted for
+ the body of a "message/rfc822" entity. The message header fields are
+ always US-ASCII in any case, and data within the body can still be
+ encoded, in which case the Content-Transfer-Encoding header field in
+ the encapsulated message will reflect this. Non-US-ASCII text in the
+ headers of an encapsulated message can be specified using the
+ mechanisms described in RFC 2047.
+
+5.2.2. Partial Subtype
+
+ The "partial" subtype is defined to allow large entities to be
+ delivered as several separate pieces of mail and automatically
+ reassembled by a receiving user agent. (The concept is similar to IP
+ fragmentation and reassembly in the basic Internet Protocols.) This
+ mechanism can be used when intermediate transport agents limit the
+ size of individual messages that can be sent. The media type
+ "message/partial" thus indicates that the body contains a fragment of
+ a larger entity.
+
+ Because data of type "message" may never be encoded in base64 or
+ quoted-printable, a problem might arise if "message/partial" entities
+ are constructed in an environment that supports binary or 8bit
+ transport. The problem is that the binary data would be split into
+ multiple "message/partial" messages, each of them requiring binary
+ transport. If such messages were encountered at a gateway into a
+ 7bit transport environment, there would be no way to properly encode
+ them for the 7bit world, aside from waiting for all of the fragments,
+ reassembling the inner message, and then encoding the reassembled
+ data in base64 or quoted-printable. Since it is possible that
+ different fragments might go through different gateways, even this is
+ not an acceptable solution. For this reason, it is specified that
+ entities of type "message/partial" must always have a content-
+ transfer-encoding of 7bit (the default). In particular, even in
+ environments that support binary or 8bit transport, the use of a
+ content- transfer-encoding of "8bit" or "binary" is explicitly
+ prohibited for MIME entities of type "message/partial". This in turn
+ implies that the inner message must not use "8bit" or "binary"
+ encoding.
+
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 29]
+\f
+RFC 2046 Media Types November 1996
+
+
+ Because some message transfer agents may choose to automatically
+ fragment large messages, and because such agents may use very
+ different fragmentation thresholds, it is possible that the pieces of
+ a partial message, upon reassembly, may prove themselves to comprise
+ a partial message. This is explicitly permitted.
+
+ Three parameters must be specified in the Content-Type field of type
+ "message/partial": The first, "id", is a unique identifier, as close
+ to a world-unique identifier as possible, to be used to match the
+ fragments together. (In general, the identifier is essentially a
+ message-id; if placed in double quotes, it can be ANY message-id, in
+ accordance with the BNF for "parameter" given in RFC 2045.) The
+ second, "number", an integer, is the fragment number, which indicates
+ where this fragment fits into the sequence of fragments. The third,
+ "total", another integer, is the total number of fragments. This
+ third subfield is required on the final fragment, and is optional
+ (though encouraged) on the earlier fragments. Note also that these
+ parameters may be given in any order.
+
+ Thus, the second piece of a 3-piece message may have either of the
+ following header fields:
+
+ Content-Type: Message/Partial; number=2; total=3;
+ id="oc=jpbe0M2Yt4s@thumper.bellcore.com"
+
+ Content-Type: Message/Partial;
+ id="oc=jpbe0M2Yt4s@thumper.bellcore.com";
+ number=2
+
+ But the third piece MUST specify the total number of fragments:
+
+ Content-Type: Message/Partial; number=3; total=3;
+ id="oc=jpbe0M2Yt4s@thumper.bellcore.com"
+
+ Note that fragment numbering begins with 1, not 0.
+
+ When the fragments of an entity broken up in this manner are put
+ together, the result is always a complete MIME entity, which may have
+ its own Content-Type header field, and thus may contain any other
+ data type.
+
+5.2.2.1. Message Fragmentation and Reassembly
+
+ The semantics of a reassembled partial message must be those of the
+ "inner" message, rather than of a message containing the inner
+ message. This makes it possible, for example, to send a large audio
+ message as several partial messages, and still have it appear to the
+ recipient as a simple audio message rather than as an encapsulated
+
+
+
+Freed & Borenstein Standards Track [Page 30]
+\f
+RFC 2046 Media Types November 1996
+
+
+ message containing an audio message. That is, the encapsulation of
+ the message is considered to be "transparent".
+
+ When generating and reassembling the pieces of a "message/partial"
+ message, the headers of the encapsulated message must be merged with
+ the headers of the enclosing entities. In this process the following
+ rules must be observed:
+
+ (1) Fragmentation agents must split messages at line
+ boundaries only. This restriction is imposed because
+ splits at points other than the ends of lines in turn
+ depends on message transports being able to preserve
+ the semantics of messages that don't end with a CRLF
+ sequence. Many transports are incapable of preserving
+ such semantics.
+
+ (2) All of the header fields from the initial enclosing
+ message, except those that start with "Content-" and
+ the specific header fields "Subject", "Message-ID",
+ "Encrypted", and "MIME-Version", must be copied, in
+ order, to the new message.
+
+ (3) The header fields in the enclosed message which start
+ with "Content-", plus the "Subject", "Message-ID",
+ "Encrypted", and "MIME-Version" fields, must be
+ appended, in order, to the header fields of the new
+ message. Any header fields in the enclosed message
+ which do not start with "Content-" (except for the
+ "Subject", "Message-ID", "Encrypted", and "MIME-
+ Version" fields) will be ignored and dropped.
+
+ (4) All of the header fields from the second and any
+ subsequent enclosing messages are discarded by the
+ reassembly process.
+
+5.2.2.2. Fragmentation and Reassembly Example
+
+ If an audio message is broken into two pieces, the first piece might
+ look something like this:
+
+ X-Weird-Header-1: Foo
+ From: Bill@host.com
+ To: joe@otherhost.com
+ Date: Fri, 26 Mar 1993 12:59:38 -0500 (EST)
+ Subject: Audio mail (part 1 of 2)
+ Message-ID: <id1@host.com>
+ MIME-Version: 1.0
+ Content-type: message/partial; id="ABC@host.com";
+
+
+
+Freed & Borenstein Standards Track [Page 31]
+\f
+RFC 2046 Media Types November 1996
+
+
+ number=1; total=2
+
+ X-Weird-Header-1: Bar
+ X-Weird-Header-2: Hello
+ Message-ID: <anotherid@foo.com>
+ Subject: Audio mail
+ MIME-Version: 1.0
+ Content-type: audio/basic
+ Content-transfer-encoding: base64
+
+ ... first half of encoded audio data goes here ...
+
+ and the second half might look something like this:
+
+ From: Bill@host.com
+ To: joe@otherhost.com
+ Date: Fri, 26 Mar 1993 12:59:38 -0500 (EST)
+ Subject: Audio mail (part 2 of 2)
+ MIME-Version: 1.0
+ Message-ID: <id2@host.com>
+ Content-type: message/partial;
+ id="ABC@host.com"; number=2; total=2
+
+ ... second half of encoded audio data goes here ...
+
+ Then, when the fragmented message is reassembled, the resulting
+ message to be displayed to the user should look something like this:
+
+ X-Weird-Header-1: Foo
+ From: Bill@host.com
+ To: joe@otherhost.com
+ Date: Fri, 26 Mar 1993 12:59:38 -0500 (EST)
+ Subject: Audio mail
+ Message-ID: <anotherid@foo.com>
+ MIME-Version: 1.0
+ Content-type: audio/basic
+ Content-transfer-encoding: base64
+
+ ... first half of encoded audio data goes here ...
+ ... second half of encoded audio data goes here ...
+
+ The inclusion of a "References" field in the headers of the second
+ and subsequent pieces of a fragmented message that references the
+ Message-Id on the previous piece may be of benefit to mail readers
+ that understand and track references. However, the generation of
+ such "References" fields is entirely optional.
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 32]
+\f
+RFC 2046 Media Types November 1996
+
+
+ Finally, it should be noted that the "Encrypted" header field has
+ been made obsolete by Privacy Enhanced Messaging (PEM) [RFC-1421,
+ RFC-1422, RFC-1423, RFC-1424], but the rules above are nevertheless
+ believed to describe the correct way to treat it if it is encountered
+ in the context of conversion to and from "message/partial" fragments.
+
+5.2.3. External-Body Subtype
+
+ The external-body subtype indicates that the actual body data are not
+ included, but merely referenced. In this case, the parameters
+ describe a mechanism for accessing the external data.
+
+ When a MIME entity is of type "message/external-body", it consists of
+ a header, two consecutive CRLFs, and the message header for the
+ encapsulated message. If another pair of consecutive CRLFs appears,
+ this of course ends the message header for the encapsulated message.
+ However, since the encapsulated message's body is itself external, it
+ does NOT appear in the area that follows. For example, consider the
+ following message:
+
+ Content-type: message/external-body;
+ access-type=local-file;
+ name="/u/nsb/Me.jpeg"
+
+ Content-type: image/jpeg
+ Content-ID: <id42@guppylake.bellcore.com>
+ Content-Transfer-Encoding: binary
+
+ THIS IS NOT REALLY THE BODY!
+
+ The area at the end, which might be called the "phantom body", is
+ ignored for most external-body messages. However, it may be used to
+ contain auxiliary information for some such messages, as indeed it is
+ when the access-type is "mail- server". The only access-type defined
+ in this document that uses the phantom body is "mail-server", but
+ other access-types may be defined in the future in other
+ specifications that use this area.
+
+ The encapsulated headers in ALL "message/external-body" entities MUST
+ include a Content-ID header field to give a unique identifier by
+ which to reference the data. This identifier may be used for caching
+ mechanisms, and for recognizing the receipt of the data when the
+ access-type is "mail-server".
+
+ Note that, as specified here, the tokens that describe external-body
+ data, such as file names and mail server commands, are required to be
+ in the US-ASCII character set.
+
+
+
+
+Freed & Borenstein Standards Track [Page 33]
+\f
+RFC 2046 Media Types November 1996
+
+
+ If this proves problematic in practice, a new mechanism may be
+ required as a future extension to MIME, either as newly defined
+ access-types for "message/external-body" or by some other mechanism.
+
+ As with "message/partial", MIME entities of type "message/external-
+ body" MUST have a content-transfer-encoding of 7bit (the default).
+ In particular, even in environments that support binary or 8bit
+ transport, the use of a content- transfer-encoding of "8bit" or
+ "binary" is explicitly prohibited for entities of type
+ "message/external-body".
+
+5.2.3.1. General External-Body Parameters
+
+ The parameters that may be used with any "message/external- body"
+ are:
+
+ (1) ACCESS-TYPE -- A word indicating the supported access
+ mechanism by which the file or data may be obtained.
+ This word is not case sensitive. Values include, but
+ are not limited to, "FTP", "ANON-FTP", "TFTP", "LOCAL-
+ FILE", and "MAIL-SERVER". Future values, except for
+ experimental values beginning with "X-", must be
+ registered with IANA, as described in RFC 2048.
+ This parameter is unconditionally mandatory and MUST be
+ present on EVERY "message/external-body".
+
+ (2) EXPIRATION -- The date (in the RFC 822 "date-time"
+ syntax, as extended by RFC 1123 to permit 4 digits in
+ the year field) after which the existence of the
+ external data is not guaranteed. This parameter may be
+ used with ANY access-type and is ALWAYS optional.
+
+ (3) SIZE -- The size (in octets) of the data. The intent
+ of this parameter is to help the recipient decide
+ whether or not to expend the necessary resources to
+ retrieve the external data. Note that this describes
+ the size of the data in its canonical form, that is,
+ before any Content-Transfer-Encoding has been applied
+ or after the data have been decoded. This parameter
+ may be used with ANY access-type and is ALWAYS
+ optional.
+
+ (4) PERMISSION -- A case-insensitive field that indicates
+ whether or not it is expected that clients might also
+ attempt to overwrite the data. By default, or if
+ permission is "read", the assumption is that they are
+ not, and that if the data is retrieved once, it is
+ never needed again. If PERMISSION is "read-write",
+
+
+
+Freed & Borenstein Standards Track [Page 34]
+\f
+RFC 2046 Media Types November 1996
+
+
+ this assumption is invalid, and any local copy must be
+ considered no more than a cache. "Read" and "Read-
+ write" are the only defined values of permission. This
+ parameter may be used with ANY access-type and is
+ ALWAYS optional.
+
+ The precise semantics of the access-types defined here are described
+ in the sections that follow.
+
+5.2.3.2. The 'ftp' and 'tftp' Access-Types
+
+ An access-type of FTP or TFTP indicates that the message body is
+ accessible as a file using the FTP [RFC-959] or TFTP [RFC- 783]
+ protocols, respectively. For these access-types, the following
+ additional parameters are mandatory:
+
+ (1) NAME -- The name of the file that contains the actual
+ body data.
+
+ (2) SITE -- A machine from which the file may be obtained,
+ using the given protocol. This must be a fully
+ qualified domain name, not a nickname.
+
+ (3) Before any data are retrieved, using FTP, the user will
+ generally need to be asked to provide a login id and a
+ password for the machine named by the site parameter.
+ For security reasons, such an id and password are not
+ specified as content-type parameters, but must be
+ obtained from the user.
+
+ In addition, the following parameters are optional:
+
+ (1) DIRECTORY -- A directory from which the data named by
+ NAME should be retrieved.
+
+ (2) MODE -- A case-insensitive string indicating the mode
+ to be used when retrieving the information. The valid
+ values for access-type "TFTP" are "NETASCII", "OCTET",
+ and "MAIL", as specified by the TFTP protocol [RFC-
+ 783]. The valid values for access-type "FTP" are
+ "ASCII", "EBCDIC", "IMAGE", and "LOCALn" where "n" is a
+ decimal integer, typically 8. These correspond to the
+ representation types "A" "E" "I" and "L n" as specified
+ by the FTP protocol [RFC-959]. Note that "BINARY" and
+ "TENEX" are not valid values for MODE and that "OCTET"
+ or "IMAGE" or "LOCAL8" should be used instead. IF MODE
+ is not specified, the default value is "NETASCII" for
+ TFTP and "ASCII" otherwise.
+
+
+
+Freed & Borenstein Standards Track [Page 35]
+\f
+RFC 2046 Media Types November 1996
+
+
+5.2.3.3. The 'anon-ftp' Access-Type
+
+ The "anon-ftp" access-type is identical to the "ftp" access type,
+ except that the user need not be asked to provide a name and password
+ for the specified site. Instead, the ftp protocol will be used with
+ login "anonymous" and a password that corresponds to the user's mail
+ address.
+
+5.2.3.4. The 'local-file' Access-Type
+
+ An access-type of "local-file" indicates that the actual body is
+ accessible as a file on the local machine. Two additional parameters
+ are defined for this access type:
+
+ (1) NAME -- The name of the file that contains the actual
+ body data. This parameter is mandatory for the
+ "local-file" access-type.
+
+ (2) SITE -- A domain specifier for a machine or set of
+ machines that are known to have access to the data
+ file. This optional parameter is used to describe the
+ locality of reference for the data, that is, the site
+ or sites at which the file is expected to be visible.
+ Asterisks may be used for wildcard matching to a part
+ of a domain name, such as "*.bellcore.com", to indicate
+ a set of machines on which the data should be directly
+ visible, while a single asterisk may be used to
+ indicate a file that is expected to be universally
+ available, e.g., via a global file system.
+
+5.2.3.5. The 'mail-server' Access-Type
+
+ The "mail-server" access-type indicates that the actual body is
+ available from a mail server. Two additional parameters are defined
+ for this access-type:
+
+ (1) SERVER -- The addr-spec of the mail server from which
+ the actual body data can be obtained. This parameter
+ is mandatory for the "mail-server" access-type.
+
+ (2) SUBJECT -- The subject that is to be used in the mail
+ that is sent to obtain the data. Note that keying mail
+ servers on Subject lines is NOT recommended, but such
+ mail servers are known to exist. This is an optional
+ parameter.
+
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 36]
+\f
+RFC 2046 Media Types November 1996
+
+
+ Because mail servers accept a variety of syntaxes, some of which is
+ multiline, the full command to be sent to a mail server is not
+ included as a parameter in the content-type header field. Instead,
+ it is provided as the "phantom body" when the media type is
+ "message/external-body" and the access-type is mail-server.
+
+ Note that MIME does not define a mail server syntax. Rather, it
+ allows the inclusion of arbitrary mail server commands in the phantom
+ body. Implementations must include the phantom body in the body of
+ the message it sends to the mail server address to retrieve the
+ relevant data.
+
+ Unlike other access-types, mail-server access is asynchronous and
+ will happen at an unpredictable time in the future. For this reason,
+ it is important that there be a mechanism by which the returned data
+ can be matched up with the original "message/external-body" entity.
+ MIME mail servers must use the same Content-ID field on the returned
+ message that was used in the original "message/external-body"
+ entities, to facilitate such matching.
+
+5.2.3.6. External-Body Security Issues
+
+ "Message/external-body" entities give rise to two important security
+ issues:
+
+ (1) Accessing data via a "message/external-body" reference
+ effectively results in the message recipient performing
+ an operation that was specified by the message
+ originator. It is therefore possible for the message
+ originator to trick a recipient into doing something
+ they would not have done otherwise. For example, an
+ originator could specify a action that attempts
+ retrieval of material that the recipient is not
+ authorized to obtain, causing the recipient to
+ unwittingly violate some security policy. For this
+ reason, user agents capable of resolving external
+ references must always take steps to describe the
+ action they are to take to the recipient and ask for
+ explicit permisssion prior to performing it.
+
+ The 'mail-server' access-type is particularly
+ vulnerable, in that it causes the recipient to send a
+ new message whose contents are specified by the
+ original message's originator. Given the potential for
+ abuse, any such request messages that are constructed
+ should contain a clear indication that they were
+ generated automatically (e.g. in a Comments: header
+ field) in an attempt to resolve a MIME
+
+
+
+Freed & Borenstein Standards Track [Page 37]
+\f
+RFC 2046 Media Types November 1996
+
+
+ "message/external-body" reference.
+
+ (2) MIME will sometimes be used in environments that
+ provide some guarantee of message integrity and
+ authenticity. If present, such guarantees may apply
+ only to the actual direct content of messages -- they
+ may or may not apply to data accessed through MIME's
+ "message/external-body" mechanism. In particular, it
+ may be possible to subvert certain access mechanisms
+ even when the messaging system itself is secure.
+
+ It should be noted that this problem exists either with
+ or without the availabilty of MIME mechanisms. A
+ casual reference to an FTP site containing a document
+ in the text of a secure message brings up similar
+ issues -- the only difference is that MIME provides for
+ automatic retrieval of such material, and users may
+ place unwarranted trust is such automatic retrieval
+ mechanisms.
+
+5.2.3.7. Examples and Further Explanations
+
+ When the external-body mechanism is used in conjunction with the
+ "multipart/alternative" media type it extends the functionality of
+ "multipart/alternative" to include the case where the same entity is
+ provided in the same format but via different accces mechanisms.
+ When this is done the originator of the message must order the parts
+ first in terms of preferred formats and then by preferred access
+ mechanisms. The recipient's viewer should then evaluate the list
+ both in terms of format and access mechanisms.
+
+ With the emerging possibility of very wide-area file systems, it
+ becomes very hard to know in advance the set of machines where a file
+ will and will not be accessible directly from the file system.
+ Therefore it may make sense to provide both a file name, to be tried
+ directly, and the name of one or more sites from which the file is
+ known to be accessible. An implementation can try to retrieve remote
+ files using FTP or any other protocol, using anonymous file retrieval
+ or prompting the user for the necessary name and password. If an
+ external body is accessible via multiple mechanisms, the sender may
+ include multiple entities of type "message/external-body" within the
+ body parts of an enclosing "multipart/alternative" entity.
+
+ However, the external-body mechanism is not intended to be limited to
+ file retrieval, as shown by the mail-server access-type. Beyond
+ this, one can imagine, for example, using a video server for external
+ references to video clips.
+
+
+
+
+Freed & Borenstein Standards Track [Page 38]
+\f
+RFC 2046 Media Types November 1996
+
+
+ The embedded message header fields which appear in the body of the
+ "message/external-body" data must be used to declare the media type
+ of the external body if it is anything other than plain US-ASCII
+ text, since the external body does not have a header section to
+ declare its type. Similarly, any Content-transfer-encoding other
+ than "7bit" must also be declared here. Thus a complete
+ "message/external-body" message, referring to an object in PostScript
+ format, might look like this:
+
+ From: Whomever
+ To: Someone
+ Date: Whenever
+ Subject: whatever
+ MIME-Version: 1.0
+ Message-ID: <id1@host.com>
+ Content-Type: multipart/alternative; boundary=42
+ Content-ID: <id001@guppylake.bellcore.com>
+
+ --42
+ Content-Type: message/external-body; name="BodyFormats.ps";
+ site="thumper.bellcore.com"; mode="image";
+ access-type=ANON-FTP; directory="pub";
+ expiration="Fri, 14 Jun 1991 19:13:14 -0400 (EDT)"
+
+ Content-type: application/postscript
+ Content-ID: <id42@guppylake.bellcore.com>
+
+ --42
+ Content-Type: message/external-body; access-type=local-file;
+ name="/u/nsb/writing/rfcs/RFC-MIME.ps";
+ site="thumper.bellcore.com";
+ expiration="Fri, 14 Jun 1991 19:13:14 -0400 (EDT)"
+
+ Content-type: application/postscript
+ Content-ID: <id42@guppylake.bellcore.com>
+
+ --42
+ Content-Type: message/external-body;
+ access-type=mail-server
+ server="listserv@bogus.bitnet";
+ expiration="Fri, 14 Jun 1991 19:13:14 -0400 (EDT)"
+
+ Content-type: application/postscript
+ Content-ID: <id42@guppylake.bellcore.com>
+
+ get RFC-MIME.DOC
+
+ --42--
+
+
+
+Freed & Borenstein Standards Track [Page 39]
+\f
+RFC 2046 Media Types November 1996
+
+
+ Note that in the above examples, the default Content-transfer-
+ encoding of "7bit" is assumed for the external postscript data.
+
+ Like the "message/partial" type, the "message/external-body" media
+ type is intended to be transparent, that is, to convey the data type
+ in the external body rather than to convey a message with a body of
+ that type. Thus the headers on the outer and inner parts must be
+ merged using the same rules as for "message/partial". In particular,
+ this means that the Content-type and Subject fields are overridden,
+ but the From field is preserved.
+
+ Note that since the external bodies are not transported along with
+ the external body reference, they need not conform to transport
+ limitations that apply to the reference itself. In particular,
+ Internet mail transports may impose 7bit and line length limits, but
+ these do not automatically apply to binary external body references.
+ Thus a Content-Transfer-Encoding is not generally necessary, though
+ it is permitted.
+
+ Note that the body of a message of type "message/external-body" is
+ governed by the basic syntax for an RFC 822 message. In particular,
+ anything before the first consecutive pair of CRLFs is header
+ information, while anything after it is body information, which is
+ ignored for most access-types.
+
+5.2.4. Other Message Subtypes
+
+ MIME implementations must in general treat unrecognized subtypes of
+ "message" as being equivalent to "application/octet-stream".
+
+ Future subtypes of "message" intended for use with email should be
+ restricted to "7bit" encoding. A type other than "message" should be
+ used if restriction to "7bit" is not possible.
+
+6. Experimental Media Type Values
+
+ A media type value beginning with the characters "X-" is a private
+ value, to be used by consenting systems by mutual agreement. Any
+ format without a rigorous and public definition must be named with an
+ "X-" prefix, and publicly specified values shall never begin with
+ "X-". (Older versions of the widely used Andrew system use the "X-
+ BE2" name, so new systems should probably choose a different name.)
+
+ In general, the use of "X-" top-level types is strongly discouraged.
+ Implementors should invent subtypes of the existing types whenever
+ possible. In many cases, a subtype of "application" will be more
+ appropriate than a new top-level type.
+
+
+
+
+Freed & Borenstein Standards Track [Page 40]
+\f
+RFC 2046 Media Types November 1996
+
+
+7. Summary
+
+ The five discrete media types provide provide a standardized
+ mechanism for tagging entities as "audio", "image", or several other
+ kinds of data. The composite "multipart" and "message" media types
+ allow mixing and hierarchical structuring of entities of different
+ types in a single message. A distinguished parameter syntax allows
+ further specification of data format details, particularly the
+ specification of alternate character sets. Additional optional
+ header fields provide mechanisms for certain extensions deemed
+ desirable by many implementors. Finally, a number of useful media
+ types are defined for general use by consenting user agents, notably
+ "message/partial" and "message/external-body".
+
+9. Security Considerations
+
+ Security issues are discussed in the context of the
+ "application/postscript" type, the "message/external-body" type, and
+ in RFC 2048. Implementors should pay special attention to the
+ security implications of any media types that can cause the remote
+ execution of any actions in the recipient's environment. In such
+ cases, the discussion of the "application/postscript" type may serve
+ as a model for considering other media types with remote execution
+ capabilities.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 41]
+\f
+RFC 2046 Media Types November 1996
+
+
+9. Authors' Addresses
+
+ For more information, the authors of this document are best contacted
+ via Internet mail:
+
+ Ned Freed
+ Innosoft International, Inc.
+ 1050 East Garvey Avenue South
+ West Covina, CA 91790
+ USA
+
+ Phone: +1 818 919 3600
+ Fax: +1 818 919 3614
+ EMail: ned@innosoft.com
+
+
+ Nathaniel S. Borenstein
+ First Virtual Holdings
+ 25 Washington Avenue
+ Morristown, NJ 07960
+ USA
+
+ Phone: +1 201 540 8967
+ Fax: +1 201 993 3032
+ EMail: nsb@nsb.fv.com
+
+
+ MIME is a result of the work of the Internet Engineering Task Force
+ Working Group on RFC 822 Extensions. The chairman of that group,
+ Greg Vaudreuil, may be reached at:
+
+ Gregory M. Vaudreuil
+ Octel Network Services
+ 17080 Dallas Parkway
+ Dallas, TX 75248-1905
+ USA
+
+ EMail: Greg.Vaudreuil@Octel.Com
+
+
+
+
+
+
+
+
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 42]
+\f
+RFC 2046 Media Types November 1996
+
+
+Appendix A -- Collected Grammar
+
+ This appendix contains the complete BNF grammar for all the syntax
+ specified by this document.
+
+ By itself, however, this grammar is incomplete. It refers by name to
+ several syntax rules that are defined by RFC 822. Rather than
+ reproduce those definitions here, and risk unintentional differences
+ between the two, this document simply refers the reader to RFC 822
+ for the remaining definitions. Wherever a term is undefined, it
+ refers to the RFC 822 definition.
+
+ boundary := 0*69<bchars> bcharsnospace
+
+ bchars := bcharsnospace / " "
+
+ bcharsnospace := DIGIT / ALPHA / "'" / "(" / ")" /
+ "+" / "_" / "," / "-" / "." /
+ "/" / ":" / "=" / "?"
+
+ body-part := <"message" as defined in RFC 822, with all
+ header fields optional, not starting with the
+ specified dash-boundary, and with the
+ delimiter not occurring anywhere in the
+ body part. Note that the semantics of a
+ part differ from the semantics of a message,
+ as described in the text.>
+
+ close-delimiter := delimiter "--"
+
+ dash-boundary := "--" boundary
+ ; boundary taken from the value of
+ ; boundary parameter of the
+ ; Content-Type field.
+
+ delimiter := CRLF dash-boundary
+
+ discard-text := *(*text CRLF)
+ ; May be ignored or discarded.
+
+ encapsulation := delimiter transport-padding
+ CRLF body-part
+
+ epilogue := discard-text
+
+ multipart-body := [preamble CRLF]
+ dash-boundary transport-padding CRLF
+ body-part *encapsulation
+
+
+
+Freed & Borenstein Standards Track [Page 43]
+\f
+RFC 2046 Media Types November 1996
+
+
+ close-delimiter transport-padding
+ [CRLF epilogue]
+
+ preamble := discard-text
+
+ transport-padding := *LWSP-char
+ ; Composers MUST NOT generate
+ ; non-zero length transport
+ ; padding, but receivers MUST
+ ; be able to handle padding
+ ; added by message transports.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 44]
+\f
--- /dev/null
+
+
+
+
+
+
+Network Working Group H. Alvestrand
+Request for Comments: 3282 Cisco Systems
+Obsoletes: 1766 May 2002
+Category: Standards Track
+
+
+ Content Language Headers
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2002). All Rights Reserved.
+
+Abstract
+
+ This document defines a "Content-language:" header, for use in cases
+ where one desires to indicate the language of something that has RFC
+ 822-like headers, like MIME body parts or Web documents, and an
+ "Accept-Language:" header for use in cases where one wishes to
+ indicate one's preferences with regard to language.
+
+1. Introduction
+
+ There are a number of languages presently or previously used by human
+ beings in this world.
+
+ A great number of these people would prefer to have information
+ presented in a language which they understand.
+
+ In some contexts, it is possible to have information available in
+ more than one language, or it might be possible to provide tools
+ (such as dictionaries) to assist in the understanding of a language.
+
+ In other cases, it may be desirable to use a computer program to
+ convert information from one format (such as plaintext) into another
+ (such as computer-synthesized speech, or Braille, or high-quality
+ print renderings).
+
+
+
+
+
+
+
+Alvestrand Standards Track [Page 1]
+\f
+RFC 3282 Content Language Headers May 2002
+
+
+ A prerequisite for any such function is a means of labelling the
+ information content with an identifier for the language that is used
+ in this information content, such as is defined by [TAGS]. This
+ document specifies a protocol element for use with protocols that use
+ RFC 822-like headers for carrying language tags as defined in [TAGS].
+
+ The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in [RFC 2119].
+
+2. The Content-language header
+
+ The "Content-Language" header is intended for use in the case where
+ one desires to indicate the language(s) of something that has RFC
+ 822-like headers, such as MIME body parts or Web documents.
+
+ The RFC 822 EBNF of the Content-Language header is:
+
+ Content-Language = "Content-Language" ":" 1#Language-tag
+
+ In the more strict RFC 2234 ABNF:
+
+ Content-Language = "Content-Language" ":" [CFWS] Language-List
+ Language-List = Language-Tag [CFWS]
+ *("," [CFWS] Language-Tag [CFWS])
+
+ The Content-Language header may list several languages in a comma-
+ separated list.
+
+ The CFWS construct is intended to function like the whitespace
+ convention in RFC 822, which means also that one can place
+ parenthesized comments anywhere in the language sequence, or use
+ continuation lines. A formal definition is given in RFC 2822
+ [RFC2822].
+
+ In keeping with the tradition of RFC 2822, a more liberal "obsolete"
+ grammar is also given:
+
+ obs-content-language = "Content-Language" *WSP ":"
+ [CFWS] Language-List
+
+ Like RFC 2822, this specification says that conforming
+ implementations MUST accept the obs-content-language syntax, but MUST
+ NOT generate it; all generated headers MUST conform to the Content-
+ Language syntax.
+
+
+
+
+
+
+Alvestrand Standards Track [Page 2]
+\f
+RFC 3282 Content Language Headers May 2002
+
+
+2.1 Examples of Content-language values
+
+ Voice recording from Liverpool downtown
+
+ Content-type: audio/basic
+ Content-Language: en-scouse
+
+ Document in Mingo, an American Indian language which does not have an
+ ISO 639 code:
+
+ Content-type: text/plain
+ Content-Language: i-mingo
+
+ A English-French dictionary
+
+ Content-type: application/dictionary
+ Content-Language: en, fr (This is a dictionary)
+
+ An official European Commission document (in a few of its official
+ languages):
+
+ Content-type: multipart/alternative
+ Content-Language: da, de, el, en, fr, it
+
+ An excerpt from Star Trek
+
+ Content-type: video/mpeg
+ Content-Language: i-klingon
+
+3. The Accept-Language header
+
+ The "Accept-Language" header is intended for use in cases where a
+ user or a process desires to identify the preferred language(s) when
+ RFC 822-like headers, such as MIME body parts or Web documents, are
+ used.
+
+ The RFC 822 EBNF of the Accept-Language header is:
+
+ Accept-Language = "Accept-Language" ":"
+ 1#( language-range [ ";" "q" "=" qvalue ] )
+
+ A slightly more restrictive RFC 2234 ABNF definition is:
+
+ Accept-Language = "Accept-Language:" [CFWS] language-q
+ *( "," [CFWS] language-q )
+ language-q = language-range [";" [CFWS] "q=" qvalue ] [CFWS]
+ qvalue = ( "0" [ "." 0*3DIGIT ] )
+ / ( "1" [ "." 0*3("0") ] )
+
+
+
+Alvestrand Standards Track [Page 3]
+\f
+RFC 3282 Content Language Headers May 2002
+
+
+
+ A more liberal RFC 2234 ABNF definition is:
+
+ Obs-accept-language = "Accept-Language" *WSP ":" [CFWS]
+ obs-language-q *( "," [CFWS] obs-language-q ) [CFWS]
+ obs-language-q = language-range
+ [ [CFWS] ";" [CFWS] "q" [CFWS] "=" qvalue ]
+
+ Like RFC 2822, this specification says that conforming
+ implementations MUST accept the obs-accept-language syntax, but MUST
+ NOT generate it; all generated messages MUST conform to the Accept-
+ Language syntax.
+
+ The syntax and semantics of language-range is defined in [TAGS]. The
+ Accept-Language header may list several language-ranges in a comma-
+ separated list, and each may include a quality value Q. If no Q
+ values are given, the language-ranges are given in priority order,
+ with the leftmost language-range being the most preferred language;
+ this is an extension to the HTTP/1.1 rules, but matches current
+ practice.
+
+ If Q values are given, refer to HTTP/1.1 [RFC 2616] for the details
+ on how to evaluate it.
+
+4. Security Considerations
+
+ The only security issue that has been raised with language tags since
+ the publication of RFC 1766, which stated that "Security issues are
+ believed to be irrelevant to this memo", is a concern with language
+ ranges used in content negotiation - that they may be used to infer
+ the nationality of the sender, and thus identify potential targets
+ for surveillance.
+
+ This is a special case of the general problem that anything you send
+ is visible to the receiving party; it is useful to be aware that such
+ concerns can exist in some cases.
+
+ The exact magnitude of the threat, and any possible countermeasures,
+ is left to each application protocol.
+
+5. Character set considerations
+
+ This document adds no new considerations beyond what is mentioned in
+ [TAGS].
+
+
+
+
+
+
+
+Alvestrand Standards Track [Page 4]
+\f
+RFC 3282 Content Language Headers May 2002
+
+
+6. Acknowledgements
+
+ This document has benefited from many rounds of review and comments
+ in various fora of the IETF and the Internet working groups.
+
+ Any list of contributors is bound to be incomplete; please regard the
+ following as only a selection from the group of people who have
+ contributed to make this document what it is today.
+
+ In alphabetical order:
+
+ Tim Berners-Lee, Nathaniel Borenstein, Sean M. Burke, John Clews, Jim
+ Conklin, John Cowan, Dave Crocker, Martin Duerst, Michael Everson,
+ Ned Freed, Tim Goodwin, Dirk-Willem van Gulik, Marion Gunn, Paul
+ Hoffman, Olle Jarnefors, John Klensin, Bruce Lilly, Keith Moore,
+ Chris Newman, Masataka Ohta, Keld Jorn Simonsen, Rhys Weatherley,
+ Misha Wolf, Francois Yergeau and many, many others.
+
+ Special thanks must go to Michael Everson, who has served as language
+ tag reviewer for almost the entire period, since the publication of
+ RFC 1766, and has provided a great deal of input to this revision.
+ Bruce Lilly did a special job of reading and commenting on my ABNF
+ definitions.
+
+7. References
+
+ [TAGS] Alvestrand, H., "Tags for the Identification of
+ Languages", BCP 47, RFC 3066
+
+ [ISO 639] ISO 639:1988 (E/F) - Code for the representation of names
+ of languages - The International Organization for
+ Standardization, 1st edition, 1988-04-01 Prepared by
+ ISO/TC 37 - Terminology (principles and coordination).
+ Note that a new version (ISO 639-1:2000) is in
+ preparation at the time of this writing.
+
+ [ISO 639-2] ISO 639-2:1998 - Codes for the representation of names of
+ languages -- Part 2: Alpha-3 code - edition 1, 1998-11-
+ 01, 66 pages, prepared by ISO/TC 37/SC 2
+
+ [ISO 3166] ISO 3166:1988 (E/F) - Codes for the representation of
+ names of countries - The International Organization for
+ Standardization, 3rd edition, 1988-08-15.
+
+ [ISO 15924] ISO/DIS 15924 - Codes for the representation of names of
+ scripts (under development by ISO TC46/SC2)
+
+
+
+
+
+Alvestrand Standards Track [Page 5]
+\f
+RFC 3282 Content Language Headers May 2002
+
+
+ [RFC 2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+ Extensions (MIME) Part One: Format of Internet Message
+ Bodies", RFC 2045, November 1996.
+
+ [RFC 2046] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+ Extensions (MIME) Part Two: Media Types", RFC 2046,
+ November 1996.
+
+ [RFC 2047] Moore, K., "MIME (Multipurpose Internet Mail Extensions)
+ Part Three: Message Header Extensions for Non-ASCII
+ Text", RFC 2047, November 1996.
+
+ [RFC 2048] Freed, N., Klensin, J. and J. Postel, "Multipurpose
+ Internet Mail Extensions (MIME) Part Four: Registration
+ Procedures", RFC 2048, November 1996.
+
+ [RFC 2049] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+ Extensions (MIME) Part Five: Conformance Criteria and
+ Examples", RFC 2049, November 1996.
+
+ [RFC 2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [RFC 2234] Crocker, D. and P. Overell, "Augmented BNF for Syntax
+ Specifications: ABNF", RFC 2234, November 1997.
+
+ [RFC 2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H.,
+ Masinter, L., Leach, P. and T. Berners-Lee, "Hypertext
+ Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999.
+
+ [RFC 2822] Resnick, P., "Internet Message Format", RFC 2822, April
+ 2001.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Alvestrand Standards Track [Page 6]
+\f
+RFC 3282 Content Language Headers May 2002
+
+
+Appendix A: Changes from RFC 1766
+
+ The definition of the language tags has been split, and is now RFC
+ 3066. The differences parameter to multipart/alternative is no
+ longer part of this standard, because no implementations of the
+ function were ever found. Consult RFC 1766 if you need the
+ information.
+
+ The ABNF for content-language has been updated to use the RFC 2234
+ ABNF.
+
+Author's Address
+
+ Harald Tveit Alvestrand
+ Cisco Systems
+ Weidemanns vei 27
+ 7043 Trondheim
+ NORWAY
+
+ EMail: Harald@Alvestrand.no
+ Phone: +47 73 50 33 52
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Alvestrand Standards Track [Page 7]
+\f
+RFC 3282 Content Language Headers May 2002
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2002). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Alvestrand Standards Track [Page 8]
+\f
--- /dev/null
+
+
+
+
+
+
+Network Working Group A. Phillips, Ed.
+Request for Comments: 4646 Yahoo! Inc.
+BCP: 47 M. Davis, Ed.
+Obsoletes: 3066 Google
+Category: Best Current Practice September 2006
+
+
+ Tags for Identifying Languages
+
+Status of This Memo
+
+ This document specifies an Internet Best Current Practices for the
+ Internet Community, and requests discussion and suggestions for
+ improvements. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2005).
+
+Abstract
+
+ This document describes the structure, content, construction, and
+ semantics of language tags for use in cases where it is desirable to
+ indicate the language used in an information object. It also
+ describes how to register values for use in language tags and the
+ creation of user-defined extensions for private interchange. This
+ document, in combination with RFC 4647, replaces RFC 3066, which
+ replaced RFC 1766.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 1]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+Table of Contents
+
+ 1. Introduction ....................................................3
+ 2. The Language Tag ................................................4
+ 2.1. Syntax .....................................................4
+ 2.2. Language Subtag Sources and Interpretation .................7
+ 2.2.1. Primary Language Subtag .............................8
+ 2.2.2. Extended Language Subtags ..........................10
+ 2.2.3. Script Subtag ......................................11
+ 2.2.4. Region Subtag ......................................11
+ 2.2.5. Variant Subtags ....................................13
+ 2.2.6. Extension Subtags ..................................14
+ 2.2.7. Private Use Subtags ................................16
+ 2.2.8. Preexisting RFC 3066 Registrations .................16
+ 2.2.9. Classes of Conformance .............................17
+ 3. Registry Format and Maintenance ................................18
+ 3.1. Format of the IANA Language Subtag Registry ...............18
+ 3.2. Language Subtag Reviewer ..................................24
+ 3.3. Maintenance of the Registry ...............................24
+ 3.4. Stability of IANA Registry Entries ........................25
+ 3.5. Registration Procedure for Subtags ........................29
+ 3.6. Possibilities for Registration ............................32
+ 3.7. Extensions and Extensions Registry ........................34
+ 3.8. Initialization of the Registries ..........................37
+ 4. Formation and Processing of Language Tags ......................38
+ 4.1. Choice of Language Tag ....................................38
+ 4.2. Meaning of the Language Tag ...............................40
+ 4.3. Length Considerations .....................................41
+ 4.3.1. Working with Limited Buffer Sizes ..................42
+ 4.3.2. Truncation of Language Tags ........................43
+ 4.4. Canonicalization of Language Tags .........................44
+ 4.5. Considerations for Private Use Subtags ....................45
+ 5. IANA Considerations ............................................46
+ 5.1. Language Subtag Registry ..................................46
+ 5.2. Extensions Registry .......................................47
+ 6. Security Considerations ........................................48
+ 7. Character Set Considerations ...................................48
+ 8. Changes from RFC 3066 ..........................................49
+ 9. References .....................................................52
+ 9.1. Normative References ......................................52
+ 9.2. Informative References ....................................53
+ Appendix A. Acknowledgements ......................................55
+ Appendix B. Examples of Language Tags (Informative) ...............56
+
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 2]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+1. Introduction
+
+ Human beings on our planet have, past and present, used a number of
+ languages. There are many reasons why one would want to identify the
+ language used when presenting or requesting information.
+
+ A user's language preferences often need to be identified so that
+ appropriate processing can be applied. For example, the user's
+ language preferences in a Web browser can be used to select Web pages
+ appropriately. Language preferences can also be used to select among
+ tools (such as dictionaries) to assist in the processing or
+ understanding of content in different languages.
+
+ In addition, knowledge about the particular language used by some
+ piece of information content might be useful or even required by some
+ types of processing; for example, spell-checking, computer-
+ synthesized speech, Braille transcription, or high-quality print
+ renderings.
+
+ One means of indicating the language used is by labeling the
+ information content with an identifier or "tag". These tags can be
+ used to specify user preferences when selecting information content,
+ or for labeling additional attributes of content and associated
+ resources.
+
+ Tags can also be used to indicate additional language attributes of
+ content. For example, indicating specific information about the
+ dialect, writing system, or orthography used in a document or
+ resource may enable the user to obtain information in a form that
+ they can understand, or it can be important in processing or
+ rendering the given content into an appropriate form or style.
+
+ This document specifies a particular identifier mechanism (the
+ language tag) and a registration function for values to be used to
+ form tags. It also defines a mechanism for private use values and
+ future extension.
+
+ This document, in combination with [RFC4647], replaces [RFC3066],
+ which replaced [RFC1766]. For a list of changes in this document,
+ see Section 8.
+
+ The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in [RFC2119].
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 3]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+2. The Language Tag
+
+ Language tags are used to help identify languages, whether spoken,
+ written, signed, or otherwise signaled, for the purpose of
+ communication. This includes constructed and artificial languages,
+ but excludes languages not intended primarily for human
+ communication, such as programming languages.
+
+2.1. Syntax
+
+ The language tag is composed of one or more parts, known as
+ "subtags". Each subtag consists of a sequence of alphanumeric
+ characters. Subtags are distinguished and separated from one another
+ by a hyphen ("-", ABNF [RFC4234] %x2D). A language tag consists of a
+ "primary language" subtag and a (possibly empty) series of subsequent
+ subtags, each of which refines or narrows the range of languages
+ identified by the overall tag.
+
+ Usually, each type of subtag is distinguished by length, position in
+ the tag, and content: subtags can be recognized solely by these
+ features. The only exception to this is a fixed list of
+ grandfathered tags registered under RFC 3066 [RFC3066]. This makes
+ it possible to construct a parser that can extract and assign some
+ semantic information to the subtags, even if the specific subtag
+ values are not recognized. Thus, a parser need not have an up-to-
+ date copy (or any copy at all) of the subtag registry to perform most
+ searching and matching operations.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 4]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ The syntax of the language tag in ABNF [RFC4234] is:
+
+ Language-Tag = langtag
+ / privateuse ; private use tag
+ / grandfathered ; grandfathered registrations
+
+ langtag = (language
+ ["-" script]
+ ["-" region]
+ *("-" variant)
+ *("-" extension)
+ ["-" privateuse])
+
+ language = (2*3ALPHA [ extlang ]) ; shortest ISO 639 code
+ / 4ALPHA ; reserved for future use
+ / 5*8ALPHA ; registered language subtag
+
+ extlang = *3("-" 3ALPHA) ; reserved for future use
+
+ script = 4ALPHA ; ISO 15924 code
+
+ region = 2ALPHA ; ISO 3166 code
+ / 3DIGIT ; UN M.49 code
+
+ variant = 5*8alphanum ; registered variants
+ / (DIGIT 3alphanum)
+
+ extension = singleton 1*("-" (2*8alphanum))
+
+ singleton = %x41-57 / %x59-5A / %x61-77 / %x79-7A / DIGIT
+ ; "a"-"w" / "y"-"z" / "A"-"W" / "Y"-"Z" / "0"-"9"
+ ; Single letters: x/X is reserved for private use
+
+ privateuse = ("x"/"X") 1*("-" (1*8alphanum))
+
+ grandfathered = 1*3ALPHA 1*2("-" (2*8alphanum))
+ ; grandfathered registration
+ ; Note: i is the only singleton
+ ; that starts a grandfathered tag
+
+ alphanum = (ALPHA / DIGIT) ; letters and numbers
+
+ Figure 1: Language Tag ABNF
+
+ Note: There is a subtlety in the ABNF for 'variant': variants
+ starting with a digit MAY be four characters long, while those
+ starting with a letter MUST be at least five characters long.
+
+
+
+
+Phillips & Davis Best Current Practice [Page 5]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ All subtags have a maximum length of eight characters and whitespace
+ is not permitted in a language tag. For examples of language tags,
+ see Appendix B.
+
+ Note that although [RFC4234] refers to octets, the language tags
+ described in this document are sequences of characters from the
+ US-ASCII [ISO646] repertoire. Language tags MAY be used in documents
+ and applications that use other encodings, so long as these encompass
+ the US-ASCII repertoire. An example of this would be an XML document
+ that uses the UTF-16LE [RFC2781] encoding of [Unicode].
+
+ The tags and their subtags, including private use and extensions, are
+ to be treated as case insensitive: there exist conventions for the
+ capitalization of some of the subtags, but these MUST NOT be taken to
+ carry meaning.
+
+ For example:
+
+ o [ISO639-1] recommends that language codes be written in lowercase
+ ('mn' Mongolian).
+
+ o [ISO3166-1] recommends that country codes be capitalized ('MN'
+ Mongolia).
+
+ o [ISO15924] recommends that script codes use lowercase with the
+ initial letter capitalized ('Cyrl' Cyrillic).
+
+ However, in the tags defined by this document, the uppercase US-ASCII
+ letters in the range 'A' through 'Z' are considered equivalent and
+ mapped directly to their US-ASCII lowercase equivalents in the range
+ 'a' through 'z'. Thus, the tag "mn-Cyrl-MN" is not distinct from
+ "MN-cYRL-mn" or "mN-cYrL-Mn" (or any other combination), and each of
+ these variations conveys the same meaning: Mongolian written in the
+ Cyrillic script as used in Mongolia.
+
+ Although case distinctions do not carry meaning in language tags,
+ consistent formatting and presentation of the tags will aid users.
+ The format of the tags and subtags in the registry is RECOMMENDED.
+ In this format, all non-initial two-letter subtags are uppercase, all
+ non-initial four-letter subtags are titlecase, and all other subtags
+ are lowercase.
+
+
+
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 6]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+2.2. Language Subtag Sources and Interpretation
+
+ The namespace of language tags and their subtags is administered by
+ the Internet Assigned Numbers Authority (IANA) [RFC2860] according to
+ the rules in Section 5 of this document. The Language Subtag
+ Registry maintained by IANA is the source for valid subtags: other
+ standards referenced in this section provide the source material for
+ that registry.
+
+ Terminology in this section:
+
+ o Tag or tags refers to a complete language tag, such as
+ "fr-Latn-CA". Examples of tags in this document are enclosed in
+ double-quotes ("en-US").
+
+ o Subtag refers to a specific section of a tag, delimited by hyphen,
+ such as the subtag 'Latn' in "fr-Latn-CA". Examples of subtags in
+ this document are enclosed in single quotes ('Latn').
+
+ o Code or codes refers to values defined in external standards (and
+ that are used as subtags in this document). For example, 'Latn'
+ is an [ISO15924] script code that was used to define the 'Latn'
+ script subtag for use in a language tag. Examples of codes in
+ this document are enclosed in single quotes ('en', 'Latn').
+
+ The definitions in this section apply to the various subtags within
+ the language tags defined by this document, excepting those
+ "grandfathered" tags defined in Section 2.2.8.
+
+ Language tags are designed so that each subtag type has unique length
+ and content restrictions. These make identification of the subtag's
+ type possible, even if the content of the subtag itself is
+ unrecognized. This allows tags to be parsed and processed without
+ reference to the latest version of the underlying standards or the
+ IANA registry and makes the associated exception handling when
+ parsing tags simpler.
+
+ Subtags in the IANA registry that do not come from an underlying
+ standard can only appear in specific positions in a tag.
+ Specifically, they can only occur as primary language subtags or as
+ variant subtags.
+
+ Note that sequences of private use and extension subtags MUST occur
+ at the end of the sequence of subtags and MUST NOT be interspersed
+ with subtags defined elsewhere in this document.
+
+ Single-letter and single-digit subtags are reserved for current or
+ future use. These include the following current uses:
+
+
+
+Phillips & Davis Best Current Practice [Page 7]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ o The single-letter subtag 'x' is reserved to introduce a sequence
+ of private use subtags. The interpretation of any private use
+ subtags is defined solely by private agreement and is not defined
+ by the rules in this section or in any standard or registry
+ defined in this document.
+
+ o All other single-letter subtags are reserved to introduce
+ standardized extension subtag sequences as described in
+ Section 3.7.
+
+ The single-letter subtag 'i' is used by some grandfathered tags, such
+ as "i-enochian", where it always appears in the first position and
+ cannot be confused with an extension.
+
+2.2.1. Primary Language Subtag
+
+ The primary language subtag is the first subtag in a language tag
+ (with the exception of private use and certain grandfathered tags)
+ and cannot be omitted. The following rules apply to the primary
+ language subtag:
+
+ 1. All two-character language subtags were defined in the IANA
+ registry according to the assignments found in the standard ISO
+ 639 Part 1, "ISO 639-1:2002, Codes for the representation of
+ names of languages -- Part 1: Alpha-2 code" [ISO639-1], or using
+ assignments subsequently made by the ISO 639 Part 1 maintenance
+ agency or governing standardization bodies.
+
+ 2. All three-character language subtags were defined in the IANA
+ registry according to the assignments found in ISO 639 Part 2,
+ "ISO 639-2:1998 - Codes for the representation of names of
+ languages -- Part 2: Alpha-3 code - edition 1" [ISO639-2], or
+ assignments subsequently made by the ISO 639 Part 2 maintenance
+ agency or governing standardization bodies.
+
+ 3. The subtags in the range 'qaa' through 'qtz' are reserved for
+ private use in language tags. These subtags correspond to codes
+ reserved by ISO 639-2 for private use. These codes MAY be used
+ for non-registered primary language subtags (instead of using
+ private use subtags following 'x-'). Please refer to Section 4.5
+ for more information on private use subtags.
+
+ 4. All four-character language subtags are reserved for possible
+ future standardization.
+
+ 5. All language subtags of 5 to 8 characters in length in the IANA
+ registry were defined via the registration process in Section 3.5
+ and MAY be used to form the primary language subtag. At the time
+
+
+
+Phillips & Davis Best Current Practice [Page 8]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ this document was created, there were no examples of this kind of
+ subtag and future registrations of this type will be discouraged:
+ primary languages are strongly RECOMMENDED for registration with
+ ISO 639, and proposals rejected by ISO 639/RA will be closely
+ scrutinized before they are registered with IANA.
+
+ 6. The single-character subtag 'x' as the primary subtag indicates
+ that the language tag consists solely of subtags whose meaning is
+ defined by private agreement. For example, in the tag "x-fr-CH",
+ the subtags 'fr' and 'CH' SHOULD NOT be taken to represent the
+ French language or the country of Switzerland (or any other value
+ in the IANA registry) unless there is a private agreement in
+ place to do so. See Section 4.5.
+
+ 7. The single-character subtag 'i' is used by some grandfathered
+ tags (see Section 2.2.8) such as "i-klingon" and "i-bnn". (Other
+ grandfathered tags have a primary language subtag in their first
+ position.)
+
+ 8. Other values MUST NOT be assigned to the primary subtag except by
+ revision or update of this document.
+
+ Note: For languages that have both an ISO 639-1 two-character code
+ and an ISO 639-2 three-character code, only the ISO 639-1 two-
+ character code is defined in the IANA registry.
+
+ Note: For languages that have no ISO 639-1 two-character code and for
+ which the ISO 639-2/T (Terminology) code and the ISO 639-2/B
+ (Bibliographic) codes differ, only the Terminology code is defined in
+ the IANA registry. At the time this document was created, all
+ languages that had both kinds of three-character code were also
+ assigned a two-character code; it is not expected that future
+ assignments of this nature will occur.
+
+ Note: To avoid problems with versioning and subtag choice as
+ experienced during the transition between RFC 1766 and RFC 3066, as
+ well as the canonical nature of subtags defined by this document, the
+ ISO 639 Registration Authority Joint Advisory Committee (ISO 639/
+ RA-JAC) has included the following statement in [iso639.prin]:
+
+ "A language code already in ISO 639-2 at the point of freezing ISO
+ 639-1 shall not later be added to ISO 639-1. This is to ensure
+ consistency in usage over time, since users are directed in Internet
+ applications to employ the alpha-3 code when an alpha-2 code for that
+ language is not available."
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 9]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ In order to avoid instability in the canonical form of tags, if a
+ two-character code is added to ISO 639-1 for a language for which a
+ three-character code was already included in ISO 639-2, the two-
+ character code MUST NOT be registered. See Section 3.4.
+
+ For example, if some content were tagged with 'haw' (Hawaiian), which
+ currently has no two-character code, the tag would not be invalidated
+ if ISO 639-1 were to assign a two-character code to the Hawaiian
+ language at a later date.
+
+ For example, one of the grandfathered IANA registrations is
+ "i-enochian". The subtag 'enochian' could be registered in the IANA
+ registry as a primary language subtag (assuming that ISO 639 does not
+ register this language first), making tags such as "enochian-AQ" and
+ "enochian-Latn" valid.
+
+2.2.2. Extended Language Subtags
+
+ The following rules apply to the extended language subtags:
+
+ 1. Three-letter subtags immediately following the primary subtag are
+ reserved for future standardization, anticipating work that is
+ currently under way on ISO 639.
+
+ 2. Extended language subtags MUST follow the primary subtag and
+ precede any other subtags.
+
+ 3. There MAY be up to three extended language subtags.
+
+ 4. Extended language subtags MUST NOT be registered or used to form
+ language tags. Their syntax is described here so that
+ implementations can be compatible with any future revision of
+ this document that does provide for their registration.
+
+ Extended language subtag records, once they appear in the registry,
+ MUST include exactly one 'Prefix' field indicating an appropriate
+ language subtag or sequence of subtags that MUST always appear as a
+ prefix to the extended language subtag.
+
+ Example: In a future revision or update of this document, the tag
+ "zh-gan" (registered under RFC 3066) might become a valid non-
+ grandfathered (that is, redundant) tag in which the subtag 'gan'
+ might represent the Chinese dialect 'Gan'.
+
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 10]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+2.2.3. Script Subtag
+
+ Script subtags are used to indicate the script or writing system
+ variations that distinguish the written forms of a language or its
+ dialects. The following rules apply to the script subtags:
+
+ 1. All four-character subtags were defined according to
+ [ISO15924]--"Codes for the representation of names of scripts":
+ alpha-4 script codes, or subsequently assigned by the ISO 15924
+ maintenance agency or governing standardization bodies, denoting
+ the script or writing system used in conjunction with this
+ language.
+
+ 2. Script subtags MUST immediately follow the primary language
+ subtag and all extended language subtags and MUST occur before
+ any other type of subtag described below.
+
+ 3. The script subtags 'Qaaa' through 'Qabx' are reserved for private
+ use in language tags. These subtags correspond to codes reserved
+ by ISO 15924 for private use. These codes MAY be used for non-
+ registered script values. Please refer to Section 4.5 for more
+ information on private use subtags.
+
+ 4. Script subtags MUST NOT be registered using the process in
+ Section 3.5 of this document. Variant subtags MAY be considered
+ for registration for that purpose.
+
+ 5. There MUST be at most one script subtag in a language tag, and
+ the script subtag SHOULD be omitted when it adds no
+ distinguishing value to the tag or when the primary language
+ subtag's record includes a Suppress-Script field listing the
+ applicable script subtag.
+
+ Example: "sr-Latn" represents Serbian written using the Latin script.
+
+2.2.4. Region Subtag
+
+ Region subtags are used to indicate linguistic variations associated
+ with or appropriate to a specific country, territory, or region.
+ Typically, a region subtag is used to indicate regional dialects or
+ usage, or region-specific spelling conventions. A region subtag can
+ also be used to indicate that content is expressed in a way that is
+ appropriate for use throughout a region, for instance, Spanish
+ content tailored to be useful throughout Latin America.
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 11]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ The following rules apply to the region subtags:
+
+ 1. Region subtags MUST follow any language, extended language, or
+ script subtags and MUST precede all other subtags.
+
+ 2. All two-character subtags following the primary subtag were
+ defined in the IANA registry according to the assignments found
+ in [ISO3166-1] ("Codes for the representation of names of
+ countries and their subdivisions -- Part 1: Country codes") using
+ the list of alpha-2 country codes, or using assignments
+ subsequently made by the ISO 3166 maintenance agency or governing
+ standardization bodies.
+
+ 3. All three-character subtags consisting of digit (numeric)
+ characters following the primary subtag were defined in the IANA
+ registry according to the assignments found in UN Standard
+ Country or Area Codes for Statistical Use [UN_M.49] or
+ assignments subsequently made by the governing standards body.
+ Note that not all of the UN M.49 codes are defined in the IANA
+ registry. The following rules define which codes are entered
+ into the registry as valid subtags:
+
+ A. UN numeric codes assigned to 'macro-geographical
+ (continental)' or sub-regions MUST be registered in the
+ registry. These codes are not associated with an assigned
+ ISO 3166 alpha-2 code and represent supra-national areas,
+ usually covering more than one nation, state, province, or
+ territory.
+
+ B. UN numeric codes for 'economic groupings' or 'other
+ groupings' MUST NOT be registered in the IANA registry and
+ MUST NOT be used to form language tags.
+
+ C. UN numeric codes for countries or areas with ambiguous ISO
+ 3166 alpha-2 codes, when entered into the registry, MUST be
+ defined according to the rules in Section 3.4 and MUST be
+ used to form language tags that represent the country or
+ region for which they are defined.
+
+ D. UN numeric codes for countries or areas for which there is an
+ associated ISO 3166 alpha-2 code in the registry MUST NOT be
+ entered into the registry and MUST NOT be used to form
+ language tags. Note that the ISO 3166-based subtag in the
+ registry MUST actually be associated with the UN M.49 code in
+ question.
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 12]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ E. UN numeric codes and ISO 3166 alpha-2 codes for countries or
+ areas listed as eligible for registration in [RFC4645] but
+ not presently registered MAY be entered into the IANA
+ registry via the process described in Section 3.5. Once
+ registered, these codes MAY be used to form language tags.
+
+ F. All other UN numeric codes for countries or areas that do not
+ have an associated ISO 3166 alpha-2 code MUST NOT be entered
+ into the registry and MUST NOT be used to form language tags.
+ For more information about these codes, see Section 3.4.
+
+ 4. Note: The alphanumeric codes in Appendix X of the UN document
+ MUST NOT be entered into the registry and MUST NOT be used to
+ form language tags. (At the time this document was created,
+ these values matched the ISO 3166 alpha-2 codes.)
+
+ 5. There MUST be at most one region subtag in a language tag and the
+ region subtag MAY be omitted, as when it adds no distinguishing
+ value to the tag.
+
+ 6. The region subtags 'AA', 'QM'-'QZ', 'XA'-'XZ', and 'ZZ' are
+ reserved for private use in language tags. These subtags
+ correspond to codes reserved by ISO 3166 for private use. These
+ codes MAY be used for private use region subtags (instead of
+ using a private use subtag sequence). Please refer to
+ Section 4.5 for more information on private use subtags.
+
+ "de-CH" represents German ('de') as used in Switzerland ('CH').
+
+ "sr-Latn-CS" represents Serbian ('sr') written using Latin script
+ ('Latn') as used in Serbia and Montenegro ('CS').
+
+ "es-419" represents Spanish ('es') appropriate to the UN-defined
+ Latin America and Caribbean region ('419').
+
+2.2.5. Variant Subtags
+
+ Variant subtags are used to indicate additional, well-recognized
+ variations that define a language or its dialects that are not
+ covered by other available subtags. The following rules apply to the
+ variant subtags:
+
+ 1. Variant subtags are not associated with any external standard.
+ Variant subtags and their meanings are defined by the
+ registration process defined in Section 3.5.
+
+ 2. Variant subtags MUST follow all of the other defined subtags, but
+ precede any extension or private use subtag sequences.
+
+
+
+Phillips & Davis Best Current Practice [Page 13]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ 3. More than one variant MAY be used to form the language tag.
+
+ 4. Variant subtags MUST be registered with IANA according to the
+ rules in Section 3.5 of this document before being used to form
+ language tags. In order to distinguish variants from other types
+ of subtags, registrations MUST meet the following length and
+ content restrictions:
+
+ 1. Variant subtags that begin with a letter (a-z, A-Z) MUST be
+ at least five characters long.
+
+ 2. Variant subtags that begin with a digit (0-9) MUST be at
+ least four characters long.
+
+ Variant subtag records in the language subtag registry MAY include
+ one or more 'Prefix' fields, which indicate the language tag or tags
+ that would make a suitable prefix (with other subtags, as
+ appropriate) in forming a language tag with the variant. For
+ example, the subtag 'nedis' has a Prefix of "sl", making it suitable
+ to form language tags such as "sl-nedis" and "sl-IT-nedis", but not
+ suitable for use in a tag such as "zh-nedis" or "it-IT-nedis".
+
+ "sl-nedis" represents the Natisone or Nadiza dialect of Slovenian.
+
+ "de-CH-1996" represents German as used in Switzerland and as written
+ using the spelling reform beginning in the year 1996 C.E.
+
+ Most variants that share a prefix are mutually exclusive. For
+ example, the German orthographic variations '1996' and '1901' SHOULD
+ NOT be used in the same tag, as they represent the dates of different
+ spelling reforms. A variant that can meaningfully be used in
+ combination with another variant SHOULD include a 'Prefix' field in
+ its registry record that lists that other variant. For example, if
+ another German variant 'example' were created that made sense to use
+ with '1996', then 'example' should include two Prefix fields: "de"
+ and "de-1996".
+
+2.2.6. Extension Subtags
+
+ Extensions provide a mechanism for extending language tags for use in
+ various applications. See Section 3.7. The following rules apply to
+ extensions:
+
+ 1. Extension subtags are separated from the other subtags defined
+ in this document by a single-character subtag ("singleton").
+ The singleton MUST be one allocated to a registration authority
+ via the mechanism described in Section 3.7 and MUST NOT be the
+ letter 'x', which is reserved for private use subtag sequences.
+
+
+
+Phillips & Davis Best Current Practice [Page 14]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ 2. Note: Private use subtag sequences starting with the singleton
+ subtag 'x' are described in Section 2.2.7 below.
+
+ 3. An extension MUST follow at least a primary language subtag.
+ That is, a language tag cannot begin with an extension.
+ Extensions extend language tags, they do not override or replace
+ them. For example, "a-value" is not a well-formed language tag,
+ while "de-a-value" is.
+
+ 4. Each singleton subtag MUST appear at most one time in each tag
+ (other than as a private use subtag). That is, singleton
+ subtags MUST NOT be repeated. For example, the tag
+ "en-a-bbb-a-ccc" is invalid because the subtag 'a' appears
+ twice. Note that the tag "en-a-bbb-x-a-ccc" is valid because
+ the second appearance of the singleton 'a' is in a private use
+ sequence.
+
+ 5. Extension subtags MUST meet all of the requirements for the
+ content and format of subtags defined in this document.
+
+ 6. Extension subtags MUST meet whatever requirements are set by the
+ document that defines their singleton prefix and whatever
+ requirements are provided by the maintaining authority.
+
+ 7. Each extension subtag MUST be from two to eight characters long
+ and consist solely of letters or digits, with each subtag
+ separated by a single '-'.
+
+ 8. Each singleton MUST be followed by at least one extension
+ subtag. For example, the tag "tlh-a-b-foo" is invalid because
+ the first singleton 'a' is followed immediately by another
+ singleton 'b'.
+
+ 9. Extension subtags MUST follow all language, extended language,
+ script, region, and variant subtags in a tag.
+
+ 10. All subtags following the singleton and before another singleton
+ are part of the extension. Example: In the tag "fr-a-Latn", the
+ subtag 'Latn' does not represent the script subtag 'Latn'
+ defined in the IANA Language Subtag Registry. Its meaning is
+ defined by the extension 'a'.
+
+ 11. In the event that more than one extension appears in a single
+ tag, the tag SHOULD be canonicalized as described in
+ Section 4.4.
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 15]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ For example, if the prefix singleton 'r' and the shown subtags were
+ defined, then the following tag would be a valid example:
+ "en-Latn-GB-boont-r-extended-sequence-x-private".
+
+2.2.7. Private Use Subtags
+
+ Private use subtags are used to indicate distinctions in language
+ important in a given context by private agreement. The following
+ rules apply to private use subtags:
+
+ 1. Private use subtags are separated from the other subtags defined
+ in this document by the reserved single-character subtag 'x'.
+
+ 2. Private use subtags MUST conform to the format and content
+ constraints defined in the ABNF for all subtags.
+
+ 3. Private use subtags MUST follow all language, extended language,
+ script, region, variant, and extension subtags in the tag.
+ Another way of saying this is that all subtags following the
+ singleton 'x' MUST be considered private use. Example: The
+ subtag 'US' in the tag "en-x-US" is a private use subtag.
+
+ 4. A tag MAY consist entirely of private use subtags.
+
+ 5. No source is defined for private use subtags. Use of private use
+ subtags is by private agreement only.
+
+ 6. Private use subtags are NOT RECOMMENDED where alternatives exist
+ or for general interchange. See Section 4.5 for more information
+ on private use subtag choice.
+
+ For example: Users who wished to utilize codes from the Ethnologue
+ publication of SIL International for language identification might
+ agree to exchange tags such as "az-Arab-x-AZE-derbend". This example
+ contains two private use subtags. The first is 'AZE' and the second
+ is 'derbend'.
+
+2.2.8. Preexisting RFC 3066 Registrations
+
+ Existing IANA-registered language tags from RFC 1766 and/or RFC 3066
+ maintain their validity. These tags will be maintained in the
+ registry in records of either the "grandfathered" or "redundant"
+ type. Grandfathered tags contain one or more subtags that are not
+ defined in the Language Subtag Registry (see Section 3). Redundant
+ tags consist entirely of subtags defined above and whose independent
+ registration is superseded by this document. For more information,
+ see Section 3.8.
+
+
+
+
+Phillips & Davis Best Current Practice [Page 16]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ It is important to note that all language tags formed under the
+ guidelines in this document were either legal, well-formed tags or
+ could have been registered under RFC 3066.
+
+2.2.9. Classes of Conformance
+
+ Implementations sometimes need to describe their capabilities with
+ regard to the rules and practices described in this document. There
+ are two classes of conforming implementations described by this
+ document: "well-formed" processors and "validating" processors.
+ Claims of conformance SHOULD explicitly reference one of these
+ definitions.
+
+ An implementation that claims to check for well-formed language tags
+ MUST:
+
+ o Check that the tag and all of its subtags, including extension and
+ private use subtags, conform to the ABNF or that the tag is on the
+ list of grandfathered tags.
+
+ o Check that singleton subtags that identify extensions do not
+ repeat. For example, the tag "en-a-xx-b-yy-a-zz" is not well-
+ formed.
+
+ Well-formed processors are strongly encouraged to implement the
+ canonicalization rules contained in Section 4.4.
+
+ An implementation that claims to be validating MUST:
+
+ o Check that the tag is well-formed.
+
+ o Specify the particular registry date for which the implementation
+ performs validation of subtags.
+
+ o Check that either the tag is a grandfathered tag, or that all
+ language, script, region, and variant subtags consist of valid
+ codes for use in language tags according to the IANA registry as
+ of the particular date specified by the implementation.
+
+ o Specify which, if any, extension RFCs as defined in Section 3.7
+ are supported, including version, revision, and date.
+
+ o For any such extensions supported, check that all subtags used in
+ that extension are valid.
+
+ o For variant and extended language subtags, if the registry
+ contains one or more 'Prefix' fields for that subtag, check that
+ the tag matches at least one prefix. The tag matches if all the
+
+
+
+Phillips & Davis Best Current Practice [Page 17]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ subtags in the 'Prefix' also appear in the tag. For example, the
+ prefix "es-CO" matches the tag "es-Latn-CO-x-private" because both
+ the 'es' language subtag and 'CO' region subtag appear in the tag.
+
+3. Registry Format and Maintenance
+
+ This section defines the Language Subtag Registry and the maintenance
+ and update procedures associated with it, as well as a registry for
+ extensions to language tags (Section 3.7).
+
+ The Language Subtag Registry contains a comprehensive list of all of
+ the subtags valid in language tags. This allows implementers a
+ straightforward and reliable way to validate language tags. The
+ Language Subtag Registry will be maintained so that, except for
+ extension subtags, it is possible to validate all of the subtags that
+ appear in a language tag under the provisions of this document or its
+ revisions or successors. In addition, the meaning of the various
+ subtags will be unambiguous and stable over time. (The meaning of
+ private use subtags, of course, is not defined by the IANA registry.)
+
+3.1. Format of the IANA Language Subtag Registry
+
+ The IANA Language Subtag Registry ("the registry") consists of a text
+ file that is machine readable in the format described in this
+ section, plus copies of the registration forms approved in accordance
+ with the process described in Section 3.5. The existing registration
+ forms for grandfathered and redundant tags taken from RFC 3066 will
+ be maintained as part of the obsolete RFC 3066 registry. The
+ remaining set of initial subtags will not have registration forms
+ created for them.
+
+ The registry is in the text format described below. This format was
+ based on the record-jar format described in [record-jar].
+
+ Each line of text is limited to 72 characters, including all
+ whitespace. Records are separated by lines containing only the
+ sequence "%%" (%x25.25).
+
+ Each field can be viewed as a single, logical line of ASCII
+ characters, comprising a field-name and a field-body separated by a
+ COLON character (%x3A). For convenience, the field-body portion of
+ this conceptual entity can be split into a multiple-line
+ representation; this is called "folding". The format of the registry
+ is described by the following ABNF (per [RFC4234]):
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 18]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ registry = record *("%%" CRLF record)
+ record = 1*( field-name *SP ":" *SP field-body CRLF )
+ field-name = (ALPHA / DIGIT) [*(ALPHA / DIGIT / "-") (ALPHA / DIGIT)]
+ field-body = *(ASCCHAR/LWSP)
+ ASCCHAR = %x21-25 / %x27-7E / UNICHAR ; Note: AMPERSAND is %x26
+ UNICHAR = "&#x" 2*6HEXDIG ";"
+
+ Figure 2: Registry Format ABNF
+
+ The sequence '..' (%x2E.2E) in a field-body denotes a range of
+ values. Such a range represents all subtags of the same length that
+ are in alphabetic or numeric order within that range, including the
+ values explicitly mentioned. For example 'a..c' denotes the values
+ 'a', 'b', and 'c' and '11..13' denotes the values '11', '12', and
+ '13'.
+
+ Characters from outside the US-ASCII [ISO646] repertoire, as well as
+ the AMPERSAND character ("&", %x26) when it occurs in a field-body,
+ are represented by a "Numeric Character Reference" using hexadecimal
+ notation in the style used by [XML10] (see
+ <http://www.w3.org/TR/REC-xml/#dt-charref>). This consists of the
+ sequence "&#x" (%x26.23.78) followed by a hexadecimal representation
+ of the character's code point in [ISO10646] followed by a closing
+ semicolon (%x3B). For example, the EURO SIGN, U+20AC, would be
+ represented by the sequence "€". Note that the hexadecimal
+ notation MAY have between two and six digits.
+
+ All fields whose field-body contains a date value use the "full-date"
+ format specified in [RFC3339]. For example: "2004-06-28" represents
+ June 28, 2004, in the Gregorian calendar.
+
+ The first record in the file contains the single field whose field-
+ name is "File-Date" (see Figure 3). The field-body of this record
+ contains the last modification date of this copy of the registry,
+ making it possible to compare different versions of the registry.
+ The registry on the IANA website is the most current. Versions with
+ an older date than that one are not up-to-date.
+
+ File-Date: 2004-06-28
+ %%
+
+ Figure 3: Example of the File-Date Record
+
+ Subsequent records represent subtags in the registry. Each of the
+ fields in each record MUST occur no more than once, unless otherwise
+ noted below. Each record MUST contain the following fields:
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 19]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ o 'Type'
+
+ * Type's field-value MUST consist of one of the following
+ strings: "language", "extlang", "script", "region", "variant",
+ "grandfathered", and "redundant" and denotes the type of tag or
+ subtag.
+
+ o Either 'Subtag' or 'Tag'
+
+ * Subtag's field-value contains the subtag being defined. This
+ field MUST only appear in records of whose 'Type' has one of
+ these values: "language", "extlang", "script", "region", or
+ "variant".
+
+ * Tag's field-value contains a complete language tag. This field
+ MUST only appear in records whose 'Type' has one of these
+ values: "grandfathered" or "redundant". Note that the field-
+ value will always follow the 'grandfathered' production in the
+ ABNF in Section 2.1
+
+ o Description
+
+ * Description's field-value contains a non-normative description
+ of the subtag or tag.
+
+ o Added
+
+ * Added's field-value contains the date the record was added to
+ the registry.
+
+ The 'Subtag' or 'Tag' field MUST use lowercase letters to form the
+ subtag or tag, with two exceptions. Subtags whose 'Type' field is
+ 'script' (in other words, subtags defined by ISO 15924) MUST use
+ titlecase. Subtags whose 'Type' field is 'region' (in other words,
+ subtags defined by ISO 3166) MUST use uppercase. These exceptions
+ mirror the use of case in the underlying standards.
+
+ The field 'Description' MAY appear more than one time and contains a
+ description of the tag or subtag in the record. At least one of the
+ 'Description' fields MUST be written or transcribed into the Latin
+ script; the same or additional fields MAY also include a description
+ in a non-Latin script. The 'Description' field is used for
+ identification purposes and SHOULD NOT be taken to represent the
+ actual native name of the language or variation or to be in any
+ particular language. Most descriptions are taken directly from
+ source standards such as ISO 639 or ISO 3166.
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 20]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ Note: Descriptions in registry entries that correspond to ISO 639,
+ ISO 15924, ISO 3166, or UN M.49 codes are intended only to indicate
+ the meaning of that identifier as defined in the source standard at
+ the time it was added to the registry. The description does not
+ replace the content of the source standard itself. The descriptions
+ are not intended to be the English localized names for the subtags.
+ Localization or translation of language tag and subtag descriptions
+ is out of scope of this document.
+
+ Each record MAY also contain the following fields:
+
+ o Preferred-Value
+
+ * For fields of type 'language', 'extlang', 'script', 'region',
+ and 'variant', 'Preferred-Value' contains the subtag of the
+ same 'Type' that is preferred for forming the language tag.
+
+ * For fields of type 'grandfathered' and 'redundant', a canonical
+ mapping to a complete language tag.
+
+ o Deprecated
+
+ * Deprecated's field-value contains the date the record was
+ deprecated.
+
+ o Prefix
+
+ * Prefix's field-value contains a language tag with which this
+ subtag MAY be used to form a new language tag, perhaps with
+ other subtags as well. This field MUST only appear in records
+ whose 'Type' field-value is 'variant' or 'extlang'. For
+ example, the 'Prefix' for the variant 'nedis' is 'sl', meaning
+ that the tags "sl-nedis" and "sl-IT-nedis" might be appropriate
+ while the tag "is-nedis" is not.
+
+ o Comments
+
+ * Comments contains additional information about the subtag, as
+ deemed appropriate for understanding the registry and
+ implementing language tags using the subtag or tag.
+
+ o Suppress-Script
+
+ * Suppress-Script contains a script subtag that SHOULD NOT be
+ used to form language tags with the associated primary language
+ subtag. This field MUST only appear in records whose 'Type'
+ field-value is 'language'. See Section 4.1.
+
+
+
+
+Phillips & Davis Best Current Practice [Page 21]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ The field 'Deprecated' MAY be added to any record via the maintenance
+ process described in Section 3.3 or via the registration process
+ described in Section 3.5. Usually, the addition of a 'Deprecated'
+ field is due to the action of one of the standards bodies, such as
+ ISO 3166, withdrawing a code. In some historical cases, it might not
+ have been possible to reconstruct the original deprecation date. For
+ these cases, an approximate date appears in the registry. Although
+ valid in language tags, subtags and tags with a 'Deprecated' field
+ are deprecated and validating processors SHOULD NOT generate these
+ subtags. Note that a record that contains a 'Deprecated' field and
+ no corresponding 'Preferred-Value' field has no replacement mapping.
+
+ The field 'Preferred-Value' contains a mapping between the record in
+ which it appears and another tag or subtag. The value in this field
+ is STRONGLY RECOMMENDED as the best choice to represent the value of
+ this record when selecting a language tag. These values form three
+ groups:
+
+ 1. ISO 639 language codes that were later withdrawn in favor of
+ other codes. These values are mostly a historical curiosity.
+
+ 2. ISO 3166 region codes that have been withdrawn in favor of a new
+ code. This sometimes happens when a country changes its name or
+ administration in such a way that warrants a new region code.
+
+ 3. Tags grandfathered from RFC 3066. In many cases, these tags have
+ become obsolete because the values they represent were later
+ encoded by ISO 639.
+
+ Records that contain a 'Preferred-Value' field MUST also have a
+ 'Deprecated' field. This field contains a date of deprecation.
+ Thus, a language tag processor can use the registry to construct the
+ valid, non-deprecated set of subtags for a given date. In addition,
+ for any given tag, a processor can construct the set of valid
+ language tags that correspond to that tag for all dates up to the
+ date of the registry. The ability to do these mappings MAY be
+ beneficial to applications that are matching, selecting, for
+ filtering content based on its language tags.
+
+ Note that 'Preferred-Value' mappings in records of type 'region'
+ sometimes do not represent exactly the same meaning as the original
+ value. There are many reasons for a country code to be changed, and
+ the effect this has on the formation of language tags will depend on
+ the nature of the change in question.
+
+ In particular, the 'Preferred-Value' field does not imply retagging
+ content that uses the affected subtag.
+
+
+
+
+Phillips & Davis Best Current Practice [Page 22]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ The field 'Preferred-Value' MUST NOT be modified once created in the
+ registry. The field MAY be added to records of type "grandfathered"
+ and "region" according to the rules in Section 3.3. Otherwise the
+ field MUST NOT be added to any record already in the registry.
+
+ The 'Preferred-Value' field in records of type "grandfathered" and
+ "redundant" contains whole language tags that are strongly
+ RECOMMENDED for use in place of the record's value. In many cases,
+ the mappings were created by deprecation of the tags during the
+ period before this document was adopted. For example, the tag
+ "no-nyn" was deprecated in favor of the ISO 639-1-defined language
+ code 'nn'.
+
+ Records of type 'variant' MAY have more than one field of type
+ 'Prefix'. Additional fields of this type MAY be added to a 'variant'
+ record via the registration process.
+
+ Records of type 'extlang' MUST have _exactly_ one 'Prefix' field.
+
+ The field-value of the 'Prefix' field consists of a language tag
+ whose subtags are appropriate to use with this subtag. For example,
+ the variant subtag '1996' has a 'Prefix' field of "de". This means
+ that tags starting with the sequence "de-" are appropriate with this
+ subtag, so "de-Latg-1996" and "de-CH-1996" are both acceptable, while
+ the tag "fr-1996" is an inappropriate choice.
+
+ The field of type 'Prefix' MUST NOT be removed from any record. The
+ field-value for this type of field MUST NOT be modified.
+
+ The field 'Comments' MAY appear more than once per record. This
+ field MAY be inserted or changed via the registration process and no
+ guarantee of stability is provided. The content of this field is not
+ restricted, except by the need to register the information, the
+ suitability of the request, and by reasonable practical size
+ limitations.
+
+ The field 'Suppress-Script' MUST only appear in records whose 'Type'
+ field-value is 'language'. This field MUST NOT appear more than one
+ time in a record. This field indicates a script used to write the
+ overwhelming majority of documents for the given language and that
+ therefore adds no distinguishing information to a language tag. It
+ helps ensure greater compatibility between the language tags
+ generated according to the rules in this document and language tags
+ and tag processors or consumers based on RFC 3066. For example,
+ virtually all Icelandic documents are written in the Latin script,
+ making the subtag 'Latn' redundant in the tag "is-Latn".
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 23]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+3.2. Language Subtag Reviewer
+
+ The Language Subtag Reviewer is appointed by the IESG for an
+ indefinite term, subject to removal or replacement at the IESG's
+ discretion. The Language Subtag Reviewer moderates the ietf-
+ languages mailing list, responds to requests for registration, and
+ performs the other registry maintenance duties described in
+ Section 3.3. Only the Language Subtag Reviewer is permitted to
+ request IANA to change, update, or add records to the Language Subtag
+ Registry.
+
+ The performance or decisions of the Language Subtag Reviewer MAY be
+ appealed to the IESG under the same rules as other IETF decisions
+ (see [RFC2026]). The IESG can reverse or overturn the decision of
+ the Language Subtag Reviewer, provide guidance, or take other
+ appropriate actions.
+
+3.3. Maintenance of the Registry
+
+ Maintenance of the registry requires that as codes are assigned or
+ withdrawn by ISO 639, ISO 15924, ISO 3166, and UN M.49, the Language
+ Subtag Reviewer MUST evaluate each change, determine whether it
+ conflicts with existing registry entries, and submit the information
+ to IANA for inclusion in the registry. If a change takes place and
+ the Language Subtag Reviewer does not do this in a timely manner,
+ then any interested party MAY use the procedure in Section 3.5 to
+ register the appropriate update.
+
+ Note: The redundant and grandfathered entries together are the
+ complete list of tags registered under [RFC3066]. The redundant tags
+ are those that can now be formed using the subtags defined in the
+ registry together with the rules of Section 2.2. The grandfathered
+ entries include those that can never be legal under those same
+ provisions.
+
+ The set of redundant and grandfathered tags is permanent and stable:
+ new entries in this section MUST NOT be added and existing entries
+ MUST NOT be removed. Records of type 'grandfathered' MAY have their
+ type converted to 'redundant'; see item 12 in Section 3.6 for more
+ information. The decision-making process about which tags were
+ initially grandfathered and which were made redundant is described in
+ [RFC4645].
+
+ RFC 3066 tags that were deprecated prior to the adoption of this
+ document are part of the list of grandfathered tags, and their
+ component subtags were not included as registered variants (although
+ they remain eligible for registration). For example, the tag
+ "art-lojban" was deprecated in favor of the language subtag 'jbo'.
+
+
+
+Phillips & Davis Best Current Practice [Page 24]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ The Language Subtag Reviewer MUST ensure that new subtags meet the
+ requirements in Section 4.1 or submit an appropriate alternate subtag
+ as described in that section. When either a change or addition to
+ the registry is needed, the Language Subtag Reviewer MUST prepare the
+ complete record, including all fields, and forward it to IANA for
+ insertion into the registry. Each record being modified or inserted
+ MUST be forwarded in a separate message.
+
+ If a record represents a new subtag that does not currently exist in
+ the registry, then the message's subject line MUST include the word
+ "INSERT". If the record represents a change to an existing subtag,
+ then the subject line of the message MUST include the word "MODIFY".
+ The message MUST contain both the record for the subtag being
+ inserted or modified and the new File-Date record. Here is an
+ example of what the body of the message might contain:
+
+ LANGUAGE SUBTAG MODIFICATION
+ File-Date: 2005-01-02
+ %%
+ Type: variant
+ Subtag: nedis
+ Description: Natisone dialect
+ Description: Nadiza dialect
+ Added: 2003-10-09
+ Prefix: sl
+ Comments: This is a comment shown
+ as an example.
+ %%
+
+ Figure 4: Example of a Language Subtag Modification Form
+
+ Whenever an entry is created or modified in the registry, the
+ 'File-Date' record at the start of the registry is updated to reflect
+ the most recent modification date in the [RFC3339] "full-date"
+ format.
+
+ Before forwarding a new registration to IANA, the Language Subtag
+ Reviewer MUST ensure that values in the 'Subtag' field match case
+ according to the description in Section 3.1.
+
+3.4. Stability of IANA Registry Entries
+
+ The stability of entries and their meaning in the registry is
+ critical to the long-term stability of language tags. The rules in
+ this section guarantee that a specific language tag's meaning is
+ stable over time and will not change.
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 25]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ These rules specifically deal with how changes to codes (including
+ withdrawal and deprecation of codes) maintained by ISO 639, ISO
+ 15924, ISO 3166, and UN M.49 are reflected in the IANA Language
+ Subtag Registry. Assignments to the IANA Language Subtag Registry
+ MUST follow the following stability rules:
+
+ 1. Values in the fields 'Type', 'Subtag', 'Tag', 'Added',
+ 'Deprecated' and 'Preferred-Value' MUST NOT be changed and are
+ guaranteed to be stable over time.
+
+ 2. Values in the 'Description' field MUST NOT be changed in a way
+ that would invalidate previously-existing tags. They MAY be
+ broadened somewhat in scope, changed to add information, or
+ adapted to the most common modern usage. For example, countries
+ occasionally change their official names; a historical example
+ of this would be "Upper Volta" changing to "Burkina Faso".
+
+ 3. Values in the field 'Prefix' MAY be added to records of type
+ 'variant' via the registration process.
+
+ 4. Values in the field 'Prefix' MAY be modified, so long as the
+ modifications broaden the set of prefixes. That is, a prefix
+ MAY be replaced by one of its own prefixes. For example, the
+ prefix "en-US" could be replaced by "en", but not by the
+ prefixes "en-Latn", "fr", or "en-US-boont". If one of those
+ prefixes were needed, a new Prefix SHOULD be registered.
+
+ 5. Values in the field 'Prefix' MUST NOT be removed.
+
+ 6. The field 'Comments' MAY be added, changed, modified, or removed
+ via the registration process or any of the processes or
+ considerations described in this section.
+
+ 7. The field 'Suppress-Script' MAY be added or removed via the
+ registration process.
+
+ 8. Codes assigned by ISO 639, ISO 15924, and ISO 3166 that do not
+ conflict with existing subtags of the associated type and whose
+ meaning is not the same as an existing subtag of the same type
+ are entered into the IANA registry as new records.
+
+ 9. Codes assigned by ISO 639, ISO 15924, or ISO 3166 that are
+ withdrawn by their respective maintenance or registration
+ authority remain valid in language tags. A 'Deprecated' field
+ containing the date of withdrawal is added to the record. If a
+ new record of the same type is added that represents a
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 26]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ replacement value, then a 'Preferred-Value' field MAY also be
+ added. The registration process MAY be used to add comments
+ about the withdrawal of the code by the respective standard.
+
+ Example
+ The region code 'TL' was assigned to the country 'Timor-
+ Leste', replacing the code 'TP' (which was assigned to 'East
+ Timor' when it was under administration by Portugal). The
+ subtag 'TP' remains valid in language tags, but its record
+ contains the a 'Preferred-Value' of 'TL' and its field
+ 'Deprecated' contains the date the new code was assigned
+ ('2004-07-06').
+
+ 10. Codes assigned by ISO 639, ISO 15924, or ISO 3166 that conflict
+ with existing subtags of the associated type, including subtags
+ that are deprecated, MUST NOT be entered into the registry. The
+ following additional considerations apply to subtag values that
+ are reassigned:
+
+ A. For ISO 639 codes, if the newly assigned code's meaning is
+ not represented by a subtag in the IANA registry, the
+ Language Subtag Reviewer, as described in Section 3.5, SHALL
+ prepare a proposal for entering in the IANA registry as soon
+ as practical a registered language subtag as an alternate
+ value for the new code. The form of the registered language
+ subtag will be at the discretion of the Language Subtag
+ Reviewer and MUST conform to other restrictions on language
+ subtags in this document.
+
+ B. For all subtags whose meaning is derived from an external
+ standard (i.e., ISO 639, ISO 15924, ISO 3166, or UN M.49),
+ if a new meaning is assigned to an existing code and the new
+ meaning broadens the meaning of that code, then the meaning
+ for the associated subtag MAY be changed to match. The
+ meaning of a subtag MUST NOT be narrowed, however, as this
+ can result in an unknown proportion of the existing uses of
+ a subtag becoming invalid. Note: ISO 639 maintenance
+ agency/registration authority (MA/RA) has adopted a similar
+ stability policy.
+
+ C. For ISO 15924 codes, if the newly assigned code's meaning is
+ not represented by a subtag in the IANA registry, the
+ Language Subtag Reviewer, as described in Section 3.5, SHALL
+ prepare a proposal for entering in the IANA registry as soon
+ as practical a registered variant subtag as an alternate
+ value for the new code. The form of the registered variant
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 27]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ subtag will be at the discretion of the Language Subtag
+ Reviewer and MUST conform to other restrictions on variant
+ subtags in this document.
+
+ D. For ISO 3166 codes, if the newly assigned code's meaning is
+ associated with the same UN M.49 code as another 'region'
+ subtag, then the existing region subtag remains as the
+ preferred value for that region and no new entry is created.
+ A comment MAY be added to the existing region subtag
+ indicating the relationship to the new ISO 3166 code.
+
+ E. For ISO 3166 codes, if the newly assigned code's meaning is
+ associated with a UN M.49 code that is not represented by an
+ existing region subtag, then the Language Subtag Reviewer,
+ as described in Section 3.5, SHALL prepare a proposal for
+ entering the appropriate UN M.49 country code as an entry in
+ the IANA registry.
+
+ F. For ISO 3166 codes, if there is no associated UN numeric
+ code, then the Language Subtag Reviewer SHALL petition the
+ UN to create one. If there is no response from the UN
+ within ninety days of the request being sent, the Language
+ Subtag Reviewer SHALL prepare a proposal for entering in the
+ IANA registry as soon as practical a registered variant
+ subtag as an alternate value for the new code. The form of
+ the registered variant subtag will be at the discretion of
+ the Language Subtag Reviewer and MUST conform to other
+ restrictions on variant subtags in this document. This
+ situation is very unlikely to ever occur.
+
+ 11. UN M.49 has codes for both countries and areas (such as '276'
+ for Germany) and geographical regions and sub-regions (such as
+ '150' for Europe). UN M.49 country or area codes for which
+ there is no corresponding ISO 3166 code SHOULD NOT be
+ registered, except as a surrogate for an ISO 3166 code that is
+ blocked from registration by an existing subtag. If such a code
+ becomes necessary, then the registration authority for ISO 3166
+ SHOULD first be petitioned to assign a code to the region. If
+ the petition for a code assignment by ISO 3166 is refused or not
+ acted on in a timely manner, the registration process described
+ in Section 3.5 MAY then be used to register the corresponding UN
+ M.49 code. At the time this document was written, there were
+ only four such codes: 830 (Channel Islands), 831 (Guernsey), 832
+ (Jersey), and 833 (Isle of Man). This way, UN M.49 codes remain
+ available as the value of last resort in cases where ISO 3166
+ reassigns a deprecated value in the registry.
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 28]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ 12. Stability provisions apply to grandfathered tags with this
+ exception: should all of the subtags in a grandfathered tag
+ become valid subtags in the IANA registry, then the field 'Type'
+ in that record is changed from 'grandfathered' to 'redundant'.
+ Note that this will not affect language tags that match the
+ grandfathered tag, since these tags will now match valid
+ generative subtag sequences. For example, if the subtag 'gan'
+ in the language tag "zh-gan" were to be registered as an
+ extended language subtag, then the grandfathered tag "zh-gan"
+ would be deprecated (but existing content or implementations
+ that use "zh-gan" would remain valid).
+
+3.5. Registration Procedure for Subtags
+
+ The procedure given here MUST be used by anyone who wants to use a
+ subtag not currently in the IANA Language Subtag Registry.
+
+ Only subtags of type 'language' and 'variant' will be considered for
+ independent registration of new subtags. Handling of subtags needed
+ for stability and subtags necessary to keep the registry synchronized
+ with ISO 639, ISO 15924, ISO 3166, and UN M.49 within the limits
+ defined by this document are described in Section 3.3. Stability
+ provisions are described in Section 3.4.
+
+ This procedure MAY also be used to register or alter the information
+ for the 'Description', 'Comments', 'Deprecated', or 'Prefix' fields
+ in a subtag's record as described in Section 3.4. Changes to all
+ other fields in the IANA registry are NOT permitted.
+
+ Registering a new subtag or requesting modifications to an existing
+ tag or subtag starts with the requester filling out the registration
+ form reproduced below. Note that each response is not limited in
+ size so that the request can adequately describe the registration.
+ The fields in the "Record Requested" section SHOULD follow the
+ requirements in Section 3.1.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 29]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ LANGUAGE SUBTAG REGISTRATION FORM
+ 1. Name of requester:
+ 2. E-mail address of requester:
+ 3. Record Requested:
+
+ Type:
+ Subtag:
+ Description:
+ Prefix:
+ Preferred-Value:
+ Deprecated:
+ Suppress-Script:
+ Comments:
+
+ 4. Intended meaning of the subtag:
+ 5. Reference to published description
+ of the language (book or article):
+ 6. Any other relevant information:
+
+ Figure 5: The Language Subtag Registration Form
+
+ The subtag registration form MUST be sent to
+ <ietf-languages@iana.org> for a two-week review period before it can
+ be submitted to IANA. (This is an open list and can be joined by
+ sending a request to <ietf-languages-request@iana.org>.)
+
+ Variant subtags are usually registered for use with a particular
+ range of language tags. For example, the subtag 'rozaj' is intended
+ for use with language tags that start with the primary language
+ subtag "sl", since Resian is a dialect of Slovenian. Thus, the
+ subtag 'rozaj' would be appropriate in tags such as "sl-Latn-rozaj"
+ or "sl-IT-rozaj". This information is stored in the 'Prefix' field
+ in the registry. Variant registration requests SHOULD include at
+ least one 'Prefix' field in the registration form.
+
+ Extended language subtags are reserved for future standardization.
+ These subtags will be REQUIRED to include exactly one 'Prefix' field
+ once they are allowed for registration.
+
+ The 'Prefix' field for a given registered subtag exists in the IANA
+ registry as a guide to usage. Additional prefixes MAY be added by
+ filing an additional registration form. In that form, the "Any other
+ relevant information:" field MUST indicate that it is the addition of
+ a prefix.
+
+ Requests to add a prefix to a variant subtag that imply a different
+ semantic meaning will probably be rejected. For example, a request
+ to add the prefix "de" to the subtag 'nedis' so that the tag
+
+
+
+Phillips & Davis Best Current Practice [Page 30]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ "de-nedis" represented some German dialect would be rejected. The
+ 'nedis' subtag represents a particular Slovenian dialect and the
+ additional registration would change the semantic meaning assigned to
+ the subtag. A separate subtag SHOULD be proposed instead.
+
+ The 'Description' field MUST contain a description of the tag being
+ registered written or transcribed into the Latin script; it MAY also
+ include a description in a non-Latin script. Non-ASCII characters
+ MUST be escaped using the syntax described in Section 3.1. The
+ 'Description' field is used for identification purposes and doesn't
+ necessarily represent the actual native name of the language or
+ variation or to be in any particular language.
+
+ While the 'Description' field itself is not guaranteed to be stable
+ and errata corrections MAY be undertaken from time to time, attempts
+ to provide translations or transcriptions of entries in the registry
+ itself will probably be frowned upon by the community or rejected
+ outright, as changes of this nature have an impact on the provisions
+ in Section 3.4.
+
+ When the two-week period has passed, the Language Subtag Reviewer
+ either forwards the record to be inserted or modified to
+ iana@iana.org according to the procedure described in Section 3.3, or
+ rejects the request because of significant objections raised on the
+ list or due to problems with constraints in this document (which MUST
+ be explicitly cited). The Language Subtag Reviewer MAY also extend
+ the review period in two-week increments to permit further
+ discussion. The Language Subtag Reviewer MUST indicate on the list
+ whether the registration has been accepted, rejected, or extended
+ following each two-week period.
+
+ Note that the Language Subtag Reviewer MAY raise objections on the
+ list if he or she so desires. The important thing is that the
+ objection MUST be made publicly.
+
+ The applicant is free to modify a rejected application with
+ additional information and submit it again; this restarts the two-
+ week comment period.
+
+ Decisions made by the Language Subtag Reviewer MAY be appealed to the
+ IESG [RFC2028] under the same rules as other IETF decisions
+ [RFC2026].
+
+ All approved registration forms are available online in the directory
+ http://www.iana.org/numbers.html under "languages".
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 31]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ Updates or changes to existing records follow the same procedure as
+ new registrations. The Language Subtag Reviewer decides whether
+ there is consensus to update the registration following the two-week
+ review period; normally, objections by the original registrant will
+ carry extra weight in forming such a consensus.
+
+ Registrations are permanent and stable. Once registered, subtags
+ will not be removed from the registry and will remain a valid way in
+ which to specify a specific language or variant.
+
+ Note: The purpose of the "Description" in the registration form is to
+ aid people trying to verify whether a language is registered or what
+ language or language variation a particular subtag refers to. In
+ most cases, reference to an authoritative grammar or dictionary of
+ that language will be useful; in cases where no such work exists,
+ other well-known works describing that language or in that language
+ MAY be appropriate. The Language Subtag Reviewer decides what
+ constitutes "good enough" reference material. This requirement is
+ not intended to exclude particular languages or dialects due to the
+ size of the speaker population or lack of a standardized orthography.
+ Minority languages will be considered equally on their own merits.
+
+3.6. Possibilities for Registration
+
+ Possibilities for registration of subtags or information about
+ subtags include:
+
+ o Primary language subtags for languages not listed in ISO 639 that
+ are not variants of any listed or registered language MAY be
+ registered. At the time this document was created, there were no
+ examples of this form of subtag. Before attempting to register a
+ language subtag, there MUST be an attempt to register the language
+ with ISO 639. Subtags MUST NOT be registered for codes that exist
+ in ISO 639-1 or ISO 639-2, that are under consideration by the ISO
+ 639 maintenance or registration authorities, or that have never
+ been attempted for registration with those authorities. If ISO
+ 639 has previously rejected a language for registration, it is
+ reasonable to assume that there must be additional, very
+ compelling evidence of need before it will be registered in the
+ IANA registry (to the extent that it is very unlikely that any
+ subtags will be registered of this type).
+
+ o Dialect or other divisions or variations within a language, its
+ orthography, writing system, regional or historical usage,
+ transliteration or other transformation, or distinguishing
+ variation MAY be registered as variant subtags. An example is the
+ 'rozaj' subtag (the Resian dialect of Slovenian).
+
+
+
+
+Phillips & Davis Best Current Practice [Page 32]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ o The addition or maintenance of fields (generally of an
+ informational nature) in Tag or Subtag records as described in
+ Section 3.1 and subject to the stability provisions in
+ Section 3.4. This includes descriptions, comments, deprecation
+ and preferred values for obsolete or withdrawn codes, or the
+ addition of script or extlang information to primary language
+ subtags.
+
+ o The addition of records and related field value changes necessary
+ to reflect assignments made by ISO 639, ISO 15924, ISO 3166, and
+ UN M.49 as described in Section 3.4.
+
+ Subtags proposed for registration that would cause all or part of a
+ grandfathered tag to become redundant but whose meaning conflicts
+ with or alters the meaning of the grandfathered tag MUST be rejected.
+
+ This document leaves the decision on what subtags or changes to
+ subtags are appropriate (or not) to the registration process
+ described in Section 3.5.
+
+ Note: four-character primary language subtags are reserved to allow
+ for the possibility of alpha4 codes in some future addition to the
+ ISO 639 family of standards.
+
+ ISO 639 defines a maintenance agency for additions to and changes in
+ the list of languages in ISO 639. This agency is:
+
+ International Information Centre for Terminology (Infoterm)
+ Aichholzgasse 6/12, AT-1120
+ Wien, Austria
+ Phone: +43 1 26 75 35 Ext. 312 Fax: +43 1 216 32 72
+
+ ISO 639-2 defines a maintenance agency for additions to and changes
+ in the list of languages in ISO 639-2. This agency is:
+
+ Library of Congress
+ Network Development and MARC Standards Office
+ Washington, D.C. 20540 USA
+ Phone: +1 202 707 6237 Fax: +1 202 707 0115
+ URL: http://www.loc.gov/standards/iso639-2
+
+
+
+
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 33]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ The maintenance agency for ISO 3166 (country codes) is:
+
+ ISO 3166 Maintenance Agency
+ c/o International Organization for Standardization
+ Case postale 56
+ CH-1211 Geneva 20 Switzerland
+ Phone: +41 22 749 72 33 Fax: +41 22 749 73 49
+ URL: http://www.iso.org/iso/en/prods-services/iso3166ma/index.html
+
+ The registration authority for ISO 15924 (script codes) is:
+
+ Unicode Consortium Box 391476
+ Mountain View, CA 94039-1476, USA
+ URL: http://www.unicode.org/iso15924
+
+ The Statistics Division of the United Nations Secretariat maintains
+ the Standard Country or Area Codes for Statistical Use and can be
+ reached at:
+
+ Statistical Services Branch
+ Statistics Division
+ United Nations, Room DC2-1620
+ New York, NY 10017, USA
+
+ Fax: +1-212-963-0623
+ E-mail: statistics@un.org
+ URL: http://unstats.un.org/unsd/methods/m49/m49alpha.htm
+
+3.7. Extensions and Extensions Registry
+
+ Extension subtags are those introduced by single-character subtags
+ ("singletons") other than 'x'. They are reserved for the generation
+ of identifiers that contain a language component and are compatible
+ with applications that understand language tags.
+
+ The structure and form of extensions are defined by this document so
+ that implementations can be created that are forward compatible with
+ applications that might be created using singletons in the future.
+ In addition, defining a mechanism for maintaining singletons will
+ lend stability to this document by reducing the likely need for
+ future revisions or updates.
+
+ Single-character subtags are assigned by IANA using the "IETF
+ Consensus" policy defined by [RFC2434]. This policy requires the
+ development of an RFC, which SHALL define the name, purpose,
+ processes, and procedures for maintaining the subtags. The
+ maintaining or registering authority, including name, contact email,
+
+
+
+
+Phillips & Davis Best Current Practice [Page 34]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ discussion list email, and URL location of the registry, MUST be
+ indicated clearly in the RFC. The RFC MUST specify or include each
+ of the following:
+
+ o The specification MUST reference the specific version or revision
+ of this document that governs its creation and MUST reference this
+ section of this document.
+
+ o The specification and all subtags defined by the specification
+ MUST follow the ABNF and other rules for the formation of tags and
+ subtags as defined in this document. In particular, it MUST
+ specify that case is not significant and that subtags MUST NOT
+ exceed eight characters in length.
+
+ o The specification MUST specify a canonical representation.
+
+ o The specification of valid subtags MUST be available over the
+ Internet and at no cost.
+
+ o The specification MUST be in the public domain or available via a
+ royalty-free license acceptable to the IETF and specified in the
+ RFC.
+
+ o The specification MUST be versioned, and each version of the
+ specification MUST be numbered, dated, and stable.
+
+ o The specification MUST be stable. That is, extension subtags,
+ once defined by a specification, MUST NOT be retracted or change
+ in meaning in any substantial way.
+
+ o The specification MUST include in a separate section the
+ registration form reproduced in this section (below) to be used in
+ registering the extension upon publication as an RFC.
+
+ o IANA MUST be informed of changes to the contact information and
+ URL for the specification.
+
+ IANA will maintain a registry of allocated single-character
+ (singleton) subtags. This registry MUST use the record-jar format
+ described by the ABNF in Section 3.1. Upon publication of an
+ extension as an RFC, the maintaining authority defined in the RFC
+ MUST forward this registration form to iesg@ietf.org, who MUST
+ forward the request to iana@iana.org. The maintaining authority of
+ the extension MUST maintain the accuracy of the record by sending an
+ updated full copy of the record to iana@iana.org with the subject
+ line "LANGUAGE TAG EXTENSION UPDATE" whenever content changes. Only
+ the 'Comments', 'Contact_Email', 'Mailing_List', and 'URL' fields MAY
+ be modified in these updates.
+
+
+
+Phillips & Davis Best Current Practice [Page 35]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ Failure to maintain this record, maintain the corresponding registry,
+ or meet other conditions imposed by this section of this document MAY
+ be appealed to the IESG [RFC2028] under the same rules as other IETF
+ decisions (see [RFC2026]) and MAY result in the authority to maintain
+ the extension being withdrawn or reassigned by the IESG.
+
+ %%
+ Identifier:
+ Description:
+ Comments:
+ Added:
+ RFC:
+ Authority:
+ Contact_Email:
+ Mailing_List:
+ URL:
+ %%
+
+ Figure 6: Format of Records in the Language Tag Extensions Registry
+
+ 'Identifier' contains the single-character subtag (singleton)
+ assigned to the extension. The Internet-Draft submitted to define
+ the extension SHOULD specify which letter or digit to use, although
+ the IESG MAY change the assignment when approving the RFC.
+
+ 'Description' contains the name and description of the extension.
+
+ 'Comments' is an OPTIONAL field and MAY contain a broader description
+ of the extension.
+
+ 'Added' contains the date the RFC was published in the "full-date"
+ format specified in [RFC3339]. For example: 2004-06-28 represents
+ June 28, 2004, in the Gregorian calendar.
+
+ 'RFC' contains the RFC number assigned to the extension.
+
+ 'Authority' contains the name of the maintaining authority for the
+ extension.
+
+ 'Contact_Email' contains the email address used to contact the
+ maintaining authority.
+
+ 'Mailing_List' contains the URL or subscription email address of the
+ mailing list used by the maintaining authority.
+
+ 'URL' contains the URL of the registry for this extension.
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 36]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ The determination of whether an Internet-Draft meets the above
+ conditions and the decision to grant or withhold such authority rests
+ solely with the IESG and is subject to the normal review and appeals
+ process associated with the RFC process.
+
+ Extension authors are strongly cautioned that many (including most
+ well-formed) processors will be unaware of any special relationships
+ or meaning inherent in the order of extension subtags. Extension
+ authors SHOULD avoid subtag relationships or canonicalization
+ mechanisms that interfere with matching or with length restrictions
+ that sometimes exist in common protocols where the extension is used.
+ In particular, applications MAY truncate the subtags in doing
+ matching or in fitting into limited lengths, so it is RECOMMENDED
+ that the most significant information be in the most significant
+ (left-most) subtags and that the specification gracefully handle
+ truncated subtags.
+
+ When a language tag is to be used in a specific, known, protocol, it
+ is RECOMMENDED that the language tag not contain extensions not
+ supported by that protocol. In addition, note that some protocols
+ MAY impose upper limits on the length of the strings used to store or
+ transport the language tag.
+
+3.8. Initialization of the Registries
+
+ Upon adoption of this document, an initial version of the Language
+ Subtag Registry containing the various subtags initially valid in a
+ language tag is necessary. This collection of subtags, along with a
+ description of the process used to create it, is described by
+ [RFC4645]. IANA SHALL publish the initial version of the registry
+ described by this document from the content of [RFC4645]. Once
+ published by IANA, the maintenance procedures, rules, and
+ registration processes described in this document will be available
+ for new registrations or updates.
+
+ Registrations that are in process under the rules defined in
+ [RFC3066] when this document is adopted MAY be completed under the
+ former rules, at the discretion of the Language Tag Reviewer (as
+ described in [RFC3066]). Until the IESG officially appoints a
+ Language Subtag Reviewer, the existing Language Tag Reviewer SHALL
+ serve as the Language Subtag Reviewer.
+
+ Any new registrations submitted using the RFC 3066 forms or format
+ after the adoption of this document and publication of the registry
+ by IANA MUST be rejected.
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 37]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ An initial version of the Language Tag Extensions Registry described
+ in Section 3.7 is also needed. The Language Tag Extensions Registry
+ SHALL be initialized with a single record containing a single field
+ of type "File-Date" as a placeholder for future assignments.
+
+4. Formation and Processing of Language Tags
+
+ This section addresses how to use the information in the registry
+ with the tag syntax to choose, form, and process language tags.
+
+4.1. Choice of Language Tag
+
+ One is sometimes faced with the choice between several possible tags
+ for the same body of text.
+
+ Interoperability is best served when all users use the same language
+ tag in order to represent the same language. If an application has
+ requirements that make the rules here inapplicable, then that
+ application risks damaging interoperability. It is strongly
+ RECOMMENDED that users not define their own rules for language tag
+ choice.
+
+ Subtags SHOULD only be used where they add useful distinguishing
+ information; extraneous subtags interfere with the meaning,
+ understanding, and processing of language tags. In particular, users
+ and implementations SHOULD follow the 'Prefix' and 'Suppress-Script'
+ fields in the registry (defined in Section 3.1): these fields provide
+ guidance on when specific additional subtags SHOULD (and SHOULD NOT)
+ be used in a language tag.
+
+ Of particular note, many applications can benefit from the use of
+ script subtags in language tags, as long as the use is consistent for
+ a given context. Script subtags were not formally defined in RFC
+ 3066 and their use can affect matching and subtag identification by
+ implementations of RFC 3066, as these subtags appear between the
+ primary language and region subtags. For example, if a user requests
+ content in an implementation of Section 2.5 of [RFC3066] using the
+ language range "en-US", content labeled "en-Latn-US" will not match
+ the request. Therefore, it is important to know when script subtags
+ will customarily be used and when they ought not be used. In the
+ registry, the Suppress-Script field helps ensure greater
+ compatibility between the language tags generated according to the
+ rules in this document and language tags and tag processors or
+ consumers based on RFC 3066 by defining when users SHOULD NOT include
+ a script subtag with a particular primary language subtag.
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 38]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ Extended language subtags (type 'extlang' in the registry; see
+ Section 3.1) also appear between the primary language and region
+ subtags and are reserved for future standardization. Applications
+ might benefit from their judicious use in forming language tags in
+ the future. Similar recommendations are expected to apply to their
+ use as apply to script subtags.
+
+ Standards, protocols, and applications that reference this document
+ normatively but apply different rules to the ones given in this
+ section MUST specify how the procedure varies from the one given
+ here.
+
+ The choice of subtags used to form a language tag SHOULD be guided by
+ the following rules:
+
+ 1. Use as precise a tag as possible, but no more specific than is
+ justified. Avoid using subtags that are not important for
+ distinguishing content in an application.
+
+ * For example, 'de' might suffice for tagging an email written
+ in German, while "de-CH-1996" is probably unnecessarily
+ precise for such a task.
+
+ 2. The script subtag SHOULD NOT be used to form language tags unless
+ the script adds some distinguishing information to the tag. The
+ field 'Suppress-Script' in the primary language record in the
+ registry indicates which script subtags do not add distinguishing
+ information for most applications.
+
+ * For example, the subtag 'Latn' should not be used with the
+ primary language 'en' because nearly all English documents are
+ written in the Latin script and it adds no distinguishing
+ information. However, if a document were written in English
+ mixing Latin script with another script such as Braille
+ ('Brai'), then it might be appropriate to choose to indicate
+ both scripts to aid in content selection, such as the
+ application of a style sheet.
+
+ 3. If a tag or subtag has a 'Preferred-Value' field in its registry
+ entry, then the value of that field SHOULD be used to form the
+ language tag in preference to the tag or subtag in which the
+ preferred value appears.
+
+ * For example, use 'he' for Hebrew in preference to 'iw'.
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 39]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ 4. The 'und' (Undetermined) primary language subtag SHOULD NOT be
+ used to label content, even if the language is unknown. Omitting
+ the language tag altogether is preferred to using a tag with a
+ primary language subtag of 'und'. The 'und' subtag MAY be useful
+ for protocols that require a language tag to be provided. The
+ 'und' subtag MAY also be useful when matching language tags in
+ certain situations.
+
+ 5. The 'mul' (Multiple) primary language subtag SHOULD NOT be used
+ whenever the protocol allows the separate tags for multiple
+ languages, as is the case for the Content-Language header in
+ HTTP. The 'mul' subtag conveys little useful information:
+ content in multiple languages SHOULD individually tag the
+ languages where they appear or otherwise indicate the actual
+ language in preference to the 'mul' subtag.
+
+ 6. The same variant subtag SHOULD NOT be used more than once within
+ a language tag.
+
+ * For example, do not use "de-DE-1901-1901".
+
+ To ensure consistent backward compatibility, this document contains
+ several provisions to account for potential instability in the
+ standards used to define the subtags that make up language tags.
+ These provisions mean that no language tag created under the rules in
+ this document will become obsolete.
+
+4.2. Meaning of the Language Tag
+
+ The relationship between the tag and the information it relates to is
+ defined by the context in which the tag appears. Accordingly, this
+ section gives only possible examples of its usage.
+
+ o For a single information object, the associated language tags
+ might be interpreted as the set of languages that is necessary for
+ a complete comprehension of the complete object. Example: Plain
+ text documents.
+
+ o For an aggregation of information objects, the associated language
+ tags could be taken as the set of languages used inside components
+ of that aggregation. Examples: Document stores and libraries.
+
+ o For information objects whose purpose is to provide alternatives,
+ the associated language tags could be regarded as a hint that the
+ content is provided in several languages and that one has to
+ inspect each of the alternatives in order to find its language or
+ languages. In this case, the presence of multiple tags might not
+ mean that one needs to be multi-lingual to get complete
+
+
+
+Phillips & Davis Best Current Practice [Page 40]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ understanding of the document. Example: MIME multipart/
+ alternative.
+
+ o In markup languages, such as HTML and XML, language information
+ can be added to each part of the document identified by the markup
+ structure (including the whole document itself). For example, one
+ could write <span lang="fr">C'est la vie.</span> inside a
+ Norwegian document; the Norwegian-speaking user could then access
+ a French-Norwegian dictionary to find out what the marked section
+ meant. If the user were listening to that document through a
+ speech synthesis interface, this formation could be used to signal
+ the synthesizer to appropriately apply French text-to-speech
+ pronunciation rules to that span of text, instead of applying the
+ inappropriate Norwegian rules.
+
+ Language tags are related when they contain a similar sequence of
+ subtags. For example, if a language tag B contains language tag A as
+ a prefix, then B is typically "narrower" or "more specific" than A.
+ Thus, "zh-Hant-TW" is more specific than "zh-Hant".
+
+ This relationship is not guaranteed in all cases: specifically,
+ languages that begin with the same sequence of subtags are NOT
+ guaranteed to be mutually intelligible, although they might be. For
+ example, the tag "az" shares a prefix with both "az-Latn"
+ (Azerbaijani written using the Latin script) and "az-Cyrl"
+ (Azerbaijani written using the Cyrillic script). A person fluent in
+ one script might not be able to read the other, even though the text
+ might be identical. Content tagged as "az" most probably is written
+ in just one script and thus might not be intelligible to a reader
+ familiar with the other script.
+
+4.3. Length Considerations
+
+ [RFC3066] did not provide an upper limit on the size of language
+ tags. While RFC 3066 did define the semantics of particular subtags
+ in such a way that most language tags consisted of language and
+ region subtags with a combined total length of up to six characters,
+ larger registered tags were not only possible but were actually
+ registered.
+
+ Neither the language tag syntax nor other requirements in this
+ document impose a fixed upper limit on the number of subtags in a
+ language tag (and thus an upper bound on the size of a tag). The
+ language tag syntax suggests that, depending on the specific
+ language, more subtags (and thus a longer tag) are sometimes
+ necessary to completely identify the language for certain
+ applications; thus, it is possible to envision long or complex subtag
+ sequences.
+
+
+
+Phillips & Davis Best Current Practice [Page 41]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+4.3.1. Working with Limited Buffer Sizes
+
+ Some applications and protocols are forced to allocate fixed buffer
+ sizes or otherwise limit the length of a language tag. A conformant
+ implementation or specification MAY refuse to support the storage of
+ language tags that exceed a specified length. Any such limitation
+ SHOULD be clearly documented, and such documentation SHOULD include
+ what happens to longer tags (for example, whether an error value is
+ generated or the language tag is truncated). A protocol that allows
+ tags to be truncated at an arbitrary limit, without giving any
+ indication of what that limit is, has the potential for causing harm
+ by changing the meaning of tags in substantial ways.
+
+ In practice, most language tags do not require more than a few
+ subtags and will not approach reasonably sized buffer limitations;
+ see Section 4.1.
+
+ Some specifications or protocols have limits on tag length but do not
+ have a fixed length limitation. For example, [RFC2231] has no
+ explicit length limitation: the length available for the language tag
+ is constrained by the length of other header components (such as the
+ charset's name) coupled with the 76-character limit in [RFC2047].
+ Thus, the "limit" might be 50 or more characters, but it could
+ potentially be quite small.
+
+ The considerations for assigning a buffer limit are:
+
+ Implementations SHOULD NOT truncate language tags unless the
+ meaning of the tag is purposefully being changed, or unless the
+ tag does not fit into a limited buffer size specified by a
+ protocol for storage or transmission.
+
+ Implementations SHOULD warn the user when a tag is truncated since
+ truncation changes the semantic meaning of the tag.
+
+ Implementations of protocols or specifications that are space
+ constrained but do not have a fixed limit SHOULD use the longest
+ possible tag in preference to truncation.
+
+ Protocols or specifications that specify limited buffer sizes for
+ language tags MUST allow for language tags of up to 33 characters.
+
+ Protocols or specifications that specify limited buffer sizes for
+ language tags SHOULD allow for language tags of at least 42
+ characters.
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 42]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ The following illustration shows how the 42-character recommendation
+ was derived. The combination of language and extended language
+ subtags was chosen for future compatibility. At up to 15 characters,
+ this combination is longer than the longest possible primary language
+ subtag (8 characters):
+
+ language = 3 (ISO 639-2; ISO 639-1 requires 2)
+ extlang1 = 4 (each subsequent subtag includes '-')
+ extlang2 = 4 (unlikely: needs prefix="language-extlang1")
+ extlang3 = 4 (extremely unlikely)
+ script = 5 (if not suppressed: see Section 4.1)
+ region = 4 (UN M.49; ISO 3166 requires 3)
+ variant1 = 9 (MUST have language as a prefix)
+ variant2 = 9 (MUST have language-variant1 as a prefix)
+
+ total = 42 characters
+
+ Figure 7: Derivation of the Limit on Tag Length
+
+4.3.2. Truncation of Language Tags
+
+ Truncation of a language tag alters the meaning of the tag, and thus
+ SHOULD be avoided. However, truncation of language tags is sometimes
+ necessary due to limited buffer sizes. Such truncation MUST NOT
+ permit a subtag to be chopped off in the middle or the formation of
+ invalid tags (for example, one ending with the "-" character).
+
+ This means that applications or protocols that truncate tags MUST do
+ so by progressively removing subtags along with their preceding "-"
+ from the right side of the language tag until the tag is short enough
+ for the given buffer. If the resulting tag ends with a single-
+ character subtag, that subtag and its preceding "-" MUST also be
+ removed. For example:
+
+ Tag to truncate: zh-Latn-CN-variant1-a-extend1-x-wadegile-private1
+ 1. zh-Latn-CN-variant1-a-extend1-x-wadegile
+ 2. zh-Latn-CN-variant1-a-extend1
+ 3. zh-Latn-CN-variant1
+ 4. zh-Latn-CN
+ 5. zh-Latn
+ 6. zh
+
+ Figure 8: Example of Tag Truncation
+
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 43]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+4.4. Canonicalization of Language Tags
+
+ Since a particular language tag is sometimes used by many processes,
+ language tags SHOULD always be created or generated in a canonical
+ form.
+
+ A language tag is in canonical form when:
+
+ 1. The tag is well-formed according the rules in Section 2.1 and
+ Section 2.2.
+
+ 2. Subtags of type 'Region' that have a Preferred-Value mapping in
+ the IANA registry (see Section 3.1) SHOULD be replaced with their
+ mapped value. Note: In rare cases, the mapped value will also
+ have a Preferred-Value.
+
+ 3. Redundant or grandfathered tags that have a Preferred-Value
+ mapping in the IANA registry (see Section 3.1) MUST be replaced
+ with their mapped value. These items either are deprecated
+ mappings created before the adoption of this document (such as
+ the mapping of "no-nyn" to "nn" or "i-klingon" to "tlh") or are
+ the result of later registrations or additions to this document
+ (for example, "zh-guoyu" might be mapped to a language-extlang
+ combination such as "zh-cmn" by some future update of this
+ document).
+
+ 4. Other subtags that have a Preferred-Value mapping in the IANA
+ registry (see Section 3.1) MUST be replaced with their mapped
+ value. These items consist entirely of clerical corrections to
+ ISO 639-1 in which the deprecated subtags have been maintained
+ for compatibility purposes.
+
+ 5. If more than one extension subtag sequence exists, the extension
+ sequences are ordered into case-insensitive ASCII order by
+ singleton subtag.
+
+ Example: The language tag "en-A-aaa-B-ccc-bbb-x-xyz" is in canonical
+ form, while "en-B-ccc-bbb-A-aaa-X-xyz" is well-formed but not in
+ canonical form.
+
+ Example: The language tag "en-BU" (English as used in Burma) is not
+ canonical because the 'BU' subtag has a canonical mapping to 'MM'
+ (Myanmar), although the tag "en-BU" maintains its validity.
+
+ Canonicalization of language tags does not imply anything about the
+ use of upper or lowercase letters when processing or comparing
+ subtags (and as described in Section 2.1). All comparisons MUST be
+ performed in a case-insensitive manner.
+
+
+
+Phillips & Davis Best Current Practice [Page 44]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ When performing canonicalization of language tags, processors MAY
+ regularize the case of the subtags (that is, this process is
+ OPTIONAL), following the case used in the registry. Note that this
+ corresponds to the following casing rules: uppercase all non-initial
+ two-letter subtags; titlecase all non-initial four-letter subtags;
+ lowercase everything else.
+
+ Note: Case folding of ASCII letters in certain locales, unless
+ carefully handled, sometimes produces non-ASCII character values.
+ The Unicode Character Database file "SpecialCasing.txt" defines the
+ specific cases that are known to cause problems with this. In
+ particular, the letter 'i' (U+0069) in Turkish and Azerbaijani is
+ uppercased to U+0130 (LATIN CAPITAL LETTER I WITH DOT ABOVE).
+ Implementers SHOULD specify a locale-neutral casing operation to
+ ensure that case folding of subtags does not produce this value,
+ which is illegal in language tags. For example, if one were to
+ uppercase the region subtag 'in' using Turkish locale rules, the
+ sequence U+0130 U+004E would result instead of the expected 'IN'.
+
+ Note: if the field 'Deprecated' appears in a registry record without
+ an accompanying 'Preferred-Value' field, then that tag or subtag is
+ deprecated without a replacement. Validating processors SHOULD NOT
+ generate tags that include these values, although the values are
+ canonical when they appear in a language tag.
+
+ An extension MUST define any relationships that exist between the
+ various subtags in the extension and thus MAY define an alternate
+ canonicalization scheme for the extension's subtags. Extensions MAY
+ define how the order of the extension's subtags are interpreted. For
+ example, an extension could define that its subtags are in canonical
+ order when the subtags are placed into ASCII order: that is,
+ "en-a-aaa-bbb-ccc" instead of "en-a-ccc-bbb-aaa". Another extension
+ might define that the order of the subtags influences their semantic
+ meaning (so that "en-b-ccc-bbb-aaa" has a different value from
+ "en-b-aaa-bbb-ccc"). However, extension specifications SHOULD be
+ designed so that they are tolerant of the typical processes described
+ in Section 3.7.
+
+4.5. Considerations for Private Use Subtags
+
+ Private use subtags, like all other subtags, MUST conform to the
+ format and content constraints in the ABNF. Private use subtags have
+ no meaning outside the private agreement between the parties that
+ intend to use or exchange language tags that employ them. The same
+ subtags MAY be used with a different meaning under a separate private
+ agreement. They SHOULD NOT be used where alternatives exist and
+ SHOULD NOT be used in content or protocols intended for general use.
+
+
+
+
+Phillips & Davis Best Current Practice [Page 45]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ Private use subtags are simply useless for information exchange
+ without prior arrangement. The value and semantic meaning of private
+ use tags and of the subtags used within such a language tag are not
+ defined by this document.
+
+ Subtags defined in the IANA registry as having a specific private use
+ meaning convey more information that a purely private use tag
+ prefixed by the singleton subtag 'x'. For applications, this
+ additional information MAY be useful.
+
+ For example, the region subtags 'AA', 'ZZ', and in the ranges
+ 'QM'-'QZ' and 'XA'-'XZ' (derived from ISO 3166 private use codes) MAY
+ be used to form a language tag. A tag such as "zh-Hans-XQ" conveys a
+ great deal of public, interchangeable information about the language
+ material (that it is Chinese in the simplified Chinese script and is
+ suitable for some geographic region 'XQ'). While the precise
+ geographic region is not known outside of private agreement, the tag
+ conveys far more information than an opaque tag such as "x-someLang",
+ which contains no information about the language subtag or script
+ subtag outside of the private agreement.
+
+ However, in some cases content tagged with private use subtags MAY
+ interact with other systems in a different and possibly unsuitable
+ manner compared to tags that use opaque, privately defined subtags,
+ so the choice of the best approach sometimes depends on the
+ particular domain in question.
+
+5. IANA Considerations
+
+ This section deals with the processes and requirements necessary for
+ IANA to undertake to maintain the subtag and extension registries as
+ defined by this document and in accordance with the requirements of
+ [RFC2434].
+
+ The impact on the IANA maintainers of the two registries defined by
+ this document will be a small increase in the frequency of new
+ entries or updates.
+
+5.1. Language Subtag Registry
+
+ Upon adoption of this document, the registry will be initialized by a
+ companion document: [RFC4645]. The criteria and process for
+ selecting the initial set of records are described in that document.
+ The initial set of records represents no impact on IANA, since the
+ work to create it will be performed externally.
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 46]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ The new registry MUST be listed under "Language Tags" at
+ <http://www.iana.org/numbers.html>, replacing the existing
+ registrations defined by [RFC3066]. The existing set of registration
+ forms and RFC 3066 registrations MUST be relabeled as "Language Tags
+ (Obsolete)" and maintained (but not added to or modified).
+
+ Future work on the Language Subtag Registry SHALL be limited to
+ inserting or replacing whole records preformatted for IANA by the
+ Language Subtag Reviewer as described in Section 3.3 of this document
+ and archiving the forwarded registration form.
+
+ Each record MUST be sent to iana@iana.org with a subject line
+ indicating whether the enclosed record is an insertion of a new
+ record (indicated by the word "INSERT" in the subject line) or a
+ replacement of an existing record (indicated by the word "MODIFY" in
+ the subject line). Records MUST NOT be deleted from the registry.
+ IANA MUST place any inserted or modified records into the appropriate
+ section of the language subtag registry, grouping the records by
+ their 'Type' field. Inserted records MAY be placed anywhere in the
+ appropriate section; there is no guarantee of the order of the
+ records beyond grouping them together by 'Type'. Modified records
+ MUST overwrite the record they replace.
+
+ Included in any request to insert or modify records MUST be a new
+ File-Date record. This record MUST be placed first in the registry.
+ In the event that the File-Date record present in the registry has a
+ later date than the record being inserted or modified, the existing
+ record MUST be preserved.
+
+5.2. Extensions Registry
+
+ The Language Tag Extensions Registry will also be generated and sent
+ to IANA as described in Section 3.7. This registry can contain at
+ most 35 records, and thus changes to this registry are expected to be
+ very infrequent.
+
+ Future work by IANA on the Language Tag Extensions Registry is
+ limited to two cases. First, the IESG MAY request that new records
+ be inserted into this registry from time to time. These requests
+ MUST include the record to insert in the exact format described in
+ Section 3.7. In addition, there MAY be occasional requests from the
+ maintaining authority for a specific extension to update the contact
+ information or URLs in the record. These requests MUST include the
+ complete, updated record. IANA is not responsible for validating the
+ information provided, only that it is properly formatted. It should
+ reasonably be seen to come from the maintaining authority named in
+ the record present in the registry.
+
+
+
+
+Phillips & Davis Best Current Practice [Page 47]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+6. Security Considerations
+
+ Language tags used in content negotiation, like any other information
+ exchanged on the Internet, might be a source of concern because they
+ might be used to infer the nationality of the sender, and thus
+ identify potential targets for surveillance.
+
+ This is a special case of the general problem that anything sent is
+ visible to the receiving party and possibly to third parties as well.
+ It is useful to be aware that such concerns can exist in some cases.
+
+ The evaluation of the exact magnitude of the threat, and any possible
+ countermeasures, is left to each application protocol (see BCP 72
+ [RFC3552] for best current practice guidance on security threats and
+ defenses).
+
+ The language tag associated with a particular information item is of
+ no consequence whatsoever in determining whether that content might
+ contain possible homographs. The fact that a text is tagged as being
+ in one language or using a particular script subtag provides no
+ assurance whatsoever that it does not contain characters from scripts
+ other than the one(s) associated with or specified by that language
+ tag.
+
+ Since there is no limit to the number of variant, private use, and
+ extension subtags, and consequently no limit on the possible length
+ of a tag, implementations need to guard against buffer overflow
+ attacks. See Section 4.3 for details on language tag truncation,
+ which can occur as a consequence of defenses against buffer overflow.
+
+ Although the specification of valid subtags for an extension (see
+ Section 3.7) MUST be available over the Internet, implementations
+ SHOULD NOT mechanically depend on it being always accessible, to
+ prevent denial-of-service attacks.
+
+7. Character Set Considerations
+
+ The syntax in this document requires that language tags use only the
+ characters A-Z, a-z, 0-9, and HYPHEN-MINUS, which are present in most
+ character sets, so the composition of language tags should not have
+ any character set issues.
+
+ Rendering of characters based on the content of a language tag is not
+ addressed in this memo. Historically, some languages have relied on
+ the use of specific character sets or other information in order to
+ infer how a specific character should be rendered (notably this
+ applies to language- and culture-specific variations of Han
+ ideographs as used in Japanese, Chinese, and Korean). When language
+
+
+
+Phillips & Davis Best Current Practice [Page 48]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ tags are applied to spans of text, rendering engines sometimes use
+ that information in deciding which font to use in the absence of
+ other information, particularly where languages with distinct writing
+ traditions use the same characters.
+
+8. Changes from RFC 3066
+
+ The main goals for this revision of language tags were the following:
+
+ *Compatibility.* All RFC 3066 language tags (including those in the
+ IANA registry) remain valid in this specification. The changes in
+ this document represent additional constraints on language tags.
+ That is, in no case is the syntax more permissive and processors
+ based on the ABNF and other provisions of RFC 3066 (such as those
+ described in [XMLSchema]) will be able to process the tags described
+ by this document. In addition, this document defines language tags
+ in such as way as to ensure future compatibility.
+
+ *Stability.* Because of changes in the past in the underlying ISO
+ standards, a valid RFC 3066 language tag could become invalid or have
+ its meaning change. This has the potential of invalidating content
+ that may have an extensive shelf-life. In this specification, once a
+ language tag is valid, it remains valid forever.
+
+ *Validity.* The structure of language tags defined by this document
+ makes it possible to determine if a particular tag is well-formed
+ without regard for the actual content or "meaning" of the tag as a
+ whole. This is important because the registry grows and underlying
+ standards change over time. In addition, it must be possible to
+ determine if a tag is valid (or not) for a given point in time in
+ order to provide reproducible, testable results. This process must
+ not be error-prone; otherwise implementations might give different
+ results. By having an authoritative registry with specific
+ versioning information, the validity of language tags at any point in
+ time can be precisely determined (instead of interpolating values
+ from many separate sources).
+
+ *Utility.* It is sometimes important to be able to differentiate
+ between written forms of a language -- for many implementations this
+ is more important than distinguishing between the spoken variants of
+ a language. Languages are written in a wide variety of different
+ scripts, so this document provides for the generative use of ISO
+ 15924 script codes. Like the generative use of ISO language and
+ country codes in RFC 3066, this allows combinations to be produced
+ without resorting to the registration process. The addition of UN
+ M.49 codes provides for the generation of language tags with regional
+ scope, which is also required by some applications.
+
+
+
+
+Phillips & Davis Best Current Practice [Page 49]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ The recast of the registry from containing whole language tags to
+ subtags is a key part of this. An important feature of RFC 3066 was
+ that it allowed generative use of subtags. This allows people to
+ meaningfully use generated tags, without the delays in registering
+ whole tags or the need to register all of the combinations that might
+ be useful.
+
+ The choice of placing the extended language and script subtags
+ between the primary language and region subtags was widely debated.
+ This design was chosen because the prevalent matching and content
+ negotiation schemes rely on the subtags being arranged in order of
+ increasing specificity. That is, the subtags that mark a greater
+ barrier to mutual intelligibility appear left-most in a tag. For
+ example, when selecting content written in Azerbaijani, the script
+ (Arabic, Cyrillic, or Latin) represents a greater barrier to
+ understanding than any regional variations (those associated with
+ Azerbaijan or Iran, for example). Individuals who prefer documents
+ in a particular script, but can deal with the minor regional
+ differences, can therefore select appropriate content. Applications
+ that do not deal with written content will continue to omit these
+ subtags.
+
+ *Extensibility.* Because of the widespread use of language tags, it
+ is disruptive to have periodic revisions of the core specification,
+ even in the face of demonstrated need. The extension mechanism
+ provides for a way for independent RFCs to define extensions to
+ language tags. These extensions have a very constrained, well-
+ defined structure that prevents extensions from interfering with
+ implementations of language tags defined in this document.
+
+ The document also anticipates features of ISO 639-3 with the addition
+ of the extended language subtags, as well as the possibility of other
+ ISO 639 parts becoming useful for the formation of language tags in
+ the future.
+
+ The use and definition of private use tags have also been modified,
+ to allow people to use private use subtags to extend or modify
+ defined tags and to move as much information as possible out of
+ private use and into the regular structure.
+
+ The goal for each of these modifications is to reduce or eliminate
+ the need for future revisions of this document.
+
+
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 50]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ The specific changes in this document to meet these goals are:
+
+ o Defines the ABNF and rules for subtags so that the category of all
+ subtags can be determined without reference to the registry.
+
+ o Adds the concept of well-formed vs. validating processors,
+ defining the rules by which an implementation can claim to be one
+ or the other.
+
+ o Replaces the IANA language tag registry with a language subtag
+ registry that provides a complete list of valid subtags in the
+ IANA registry. This allows for robust implementation and ease of
+ maintenance. The language subtag registry becomes the canonical
+ source for forming language tags.
+
+ o Provides a process that guarantees stability of language tags, by
+ handling reuse of values by ISO 639, ISO 15924, and ISO 3166 in
+ the event that they register a previously used value for a new
+ purpose.
+
+ o Allows ISO 15924 script code subtags and allows them to be used
+ generatively. Defines a method for indicating in the registry
+ when script subtags are necessary for a given language tag.
+
+ o Adds the concept of a variant subtag and allows variants to be
+ used generatively.
+
+ o Adds the ability to use a class of UN M.49 tags for supra-national
+ regions and to resolve conflicts in the assignment of ISO 3166
+ codes.
+
+ o Defines the private use tags in ISO 639, ISO 15924, and ISO 3166
+ as the mechanism for creating private use language, script, and
+ region subtags, respectively.
+
+ o Adds a well-defined extension mechanism.
+
+ o Defines an extended language subtag, possibly for use with certain
+ anticipated features of ISO 639-3.
+
+
+
+
+
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 51]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+9. References
+
+9.1. Normative References
+
+ [ISO10646] International Organization for Standardization,
+ "ISO/IEC 10646:2003. Information technology --
+ Universal Multiple-Octet Coded Character Set (UCS)",
+ 2003.
+
+ [ISO15924] International Organization for Standardization, "ISO
+ 15924:2004. Information and documentation -- Codes for
+ the representation of names of scripts", January 2004.
+
+ [ISO3166-1] International Organization for Standardization, "ISO
+ 3166-1:1997. Codes for the representation of names of
+ countries and their subdivisions -- Part 1: Country
+ codes", 1997.
+
+ [ISO639-1] International Organization for Standardization, "ISO
+ 639-1:2002. Codes for the representation of names of
+ languages -- Part 1: Alpha-2 code", 2002.
+
+ [ISO639-2] International Organization for Standardization, "ISO
+ 639-2:1998. Codes for the representation of names of
+ languages -- Part 2: Alpha-3 code, first edition",
+ 1998.
+
+ [ISO646] International Organization for Standardization,
+ "ISO/IEC 646:1991, Information technology -- ISO 7-bit
+ coded character set for information interchange.",
+ 1991.
+
+ [RFC2026] Bradner, S., "The Internet Standards Process --
+ Revision 3", BCP 9, RFC 2026, October 1996.
+
+ [RFC2028] Hovey, R. and S. Bradner, "The Organizations Involved
+ in the IETF Standards Process", BCP 11, RFC 2028,
+ October 1996.
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [RFC2434] Narten, T. and H. Alvestrand, "Guidelines for Writing
+ an IANA Considerations Section in RFCs", BCP 26,
+ RFC 2434, October 1998.
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 52]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ [RFC2860] Carpenter, B., Baker, F., and M. Roberts, "Memorandum
+ of Understanding Concerning the Technical Work of the
+ Internet Assigned Numbers Authority", RFC 2860,
+ June 2000.
+
+ [RFC3339] Klyne, G., Ed. and C. Newman, "Date and Time on the
+ Internet: Timestamps", RFC 3339, July 2002.
+
+ [RFC4234] Crocker, D., Ed. and P. Overell, "Augmented BNF for
+ Syntax Specifications: ABNF", RFC 4234, October 2005.
+
+ [UN_M.49] Statistics Division, United Nations, "Standard Country
+ or Area Codes for Statistical Use", UN Standard
+ Country or Area Codes for Statistical Use, Revision 4
+ (United Nations publication, Sales No. 98.XVII.9,
+ June 1999.
+
+9.2. Informative References
+
+ [RFC1766] Alvestrand, H., "Tags for the Identification of
+ Languages", RFC 1766, March 1995.
+
+ [RFC2047] Moore, K., "MIME (Multipurpose Internet Mail
+ Extensions) Part Three: Message Header Extensions for
+ Non-ASCII Text", RFC 2047, November 1996.
+
+ [RFC2231] Freed, N. and K. Moore, "MIME Parameter Value and
+ Encoded Word Extensions: Character Sets, Languages,
+ and Continuations", RFC 2231, November 1997.
+
+ [RFC2781] Hoffman, P. and F. Yergeau, "UTF-16, an encoding of
+ ISO 10646", RFC 2781, February 2000.
+
+ [RFC3066] Alvestrand, H., "Tags for the Identification of
+ Languages", BCP 47, RFC 3066, January 2001.
+
+ [RFC3552] Rescorla, E. and B. Korver, "Guidelines for Writing
+ RFC Text on Security Considerations", BCP 72,
+ RFC 3552, July 2003.
+
+ [RFC4645] Ewell, D., Ed., "Initial Language Subtag Registry",
+ RFC 4645, September 2006.
+
+ [RFC4647] Phillips, A., Ed. and M. Davis, Ed., "Matching of
+ Language Tags", BCP 47, RFC 4647, September 2006.
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 53]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ [Unicode] Unicode Consortium, "The Unicode Standard, Version
+ 5.0", Boston, MA, Addison-Wesley, 2007. ISBN 0-321-
+ 48091-0.
+
+ [XML10] Bray (et al), T., "Extensible Markup Language (XML)
+ 1.0", 02 2004.
+
+ [XMLSchema] Biron, P., Ed. and A. Malhotra, Ed., "XML Schema Part
+ 2: Datatypes Second Edition", 10 2004, <
+ http://www.w3.org/TR/xmlschema-2/>.
+
+ [iso639.prin] ISO 639 Joint Advisory Committee, "ISO 639 Joint
+ Advisory Committee: Working principles for ISO 639
+ maintenance", March 2000, <http://www.loc.gov/
+ standards/iso639-2/iso639jac_n3r.html>.
+
+ [record-jar] Raymond, E., "The Art of Unix Programming", 2003,
+ <urn:isbn:0-13-142901-9>.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 54]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+Appendix A. Acknowledgements
+
+ Any list of contributors is bound to be incomplete; please regard the
+ following as only a selection from the group of people who have
+ contributed to make this document what it is today.
+
+ The contributors to RFC 3066 and RFC 1766, the precursors of this
+ document, made enormous contributions directly or indirectly to this
+ document and are generally responsible for the success of language
+ tags.
+
+ The following people (in alphabetical order) contributed to this
+ document or to RFCs 1766 and 3066:
+
+ Glenn Adams, Harald Tveit Alvestrand, Tim Berners-Lee, Marc Blanchet,
+ Nathaniel Borenstein, Karen Broome, Eric Brunner, Sean M. Burke, M.T.
+ Carrasco Benitez, Jeremy Carroll, John Clews, Jim Conklin, Peter
+ Constable, John Cowan, Mark Crispin, Dave Crocker, Elwyn Davies,
+ Martin Duerst, Frank Ellerman, Michael Everson, Doug Ewell, Ned
+ Freed, Tim Goodwin, Dirk-Willem van Gulik, Marion Gunn, Joel Halpren,
+ Elliotte Rusty Harold, Paul Hoffman, Scott Hollenbeck, Richard
+ Ishida, Olle Jarnefors, Kent Karlsson, John Klensin, Erkki
+ Kolehmainen, Alain LaBonte, Eric Mader, Ira McDonald, Keith Moore,
+ Chris Newman, Masataka Ohta, Dylan Pierce, Randy Presuhn, George
+ Rhoten, Felix Sasaki, Markus Scherer, Keld Jorn Simonsen, Thierry
+ Sourbier, Otto Stolz, Tex Texin, Andrea Vine, Rhys Weatherley, Misha
+ Wolf, Francois Yergeau and many, many others.
+
+ Very special thanks must go to Harald Tveit Alvestrand, who
+ originated RFCs 1766 and 3066, and without whom this document would
+ not have been possible. Special thanks must go to Michael Everson,
+ who has served as Language Tag Reviewer for almost the complete
+ period since the publication of RFC 1766. Special thanks to Doug
+ Ewell, for his production of the first complete subtag registry, and
+ his work in producing a test parser for verifying language tags.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 55]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+Appendix B. Examples of Language Tags (Informative)
+
+ Simple language subtag:
+
+ de (German)
+
+ fr (French)
+
+ ja (Japanese)
+
+ i-enochian (example of a grandfathered tag)
+
+ Language subtag plus Script subtag:
+
+ zh-Hant (Chinese written using the Traditional Chinese script)
+
+ zh-Hans (Chinese written using the Simplified Chinese script)
+
+ sr-Cyrl (Serbian written using the Cyrillic script)
+
+ sr-Latn (Serbian written using the Latin script)
+
+ Language-Script-Region:
+
+ zh-Hans-CN (Chinese written using the Simplified script as used in
+ mainland China)
+
+ sr-Latn-CS (Serbian written using the Latin script as used in
+ Serbia and Montenegro)
+
+ Language-Variant:
+
+ sl-rozaj (Resian dialect of Slovenian
+
+ sl-nedis (Nadiza dialect of Slovenian)
+
+ Language-Region-Variant:
+
+ de-CH-1901 (German as used in Switzerland using the 1901 variant
+ [orthography])
+
+ sl-IT-nedis (Slovenian as used in Italy, Nadiza dialect)
+
+
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 56]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ Language-Script-Region-Variant:
+
+ sl-Latn-IT-nedis (Nadiza dialect of Slovenian written using the
+ Latin script as used in Italy. Note that this tag is NOT
+ RECOMMENDED because subtag 'sl' has a Suppress-Script value of
+ 'Latn')
+
+ Language-Region:
+
+ de-DE (German for Germany)
+
+ en-US (English as used in the United States)
+
+ es-419 (Spanish appropriate for the Latin America and Caribbean
+ region using the UN region code)
+
+ Private use subtags:
+
+ de-CH-x-phonebk
+
+ az-Arab-x-AZE-derbend
+
+ Extended language subtags (examples ONLY: extended languages MUST be
+ defined by revision or update to this document):
+
+ zh-min
+
+ zh-min-nan-Hant-CN
+
+ Private use registry values:
+
+ x-whatever (private use using the singleton 'x')
+
+ qaa-Qaaa-QM-x-southern (all private tags)
+
+ de-Qaaa (German, with a private script)
+
+ sr-Latn-QM (Serbian, Latin-script, private region)
+
+ sr-Qaaa-CS (Serbian, private script, for Serbia and Montenegro)
+
+ Tags that use extensions (examples ONLY: extensions MUST be defined
+ by revision or update to this document or by RFC):
+
+ en-US-u-islamCal
+
+ zh-CN-a-myExt-x-private
+
+
+
+
+Phillips & Davis Best Current Practice [Page 57]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ en-a-myExt-b-another
+
+ Some Invalid Tags:
+
+ de-419-DE (two region tags)
+
+ a-DE (use of a single-character subtag in primary position; note
+ that there are a few grandfathered tags that start with "i-" that
+ are valid)
+
+ ar-a-aaa-b-bbb-a-ccc (two extensions with same single-letter
+ prefix)
+
+Authors' Addresses
+
+ Addison Phillips (Editor)
+ Yahoo! Inc.
+
+ EMail: addison@inter-locale.com
+
+
+ Mark Davis (Editor)
+ Google
+
+ EMail: mark.davis@macchiato.com or mark.davis@google.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 58]
+\f
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2006).
+
+ This document is subject to the rights, licenses and restrictions
+ contained in BCP 78, and except as set forth therein, the authors
+ retain all their rights.
+
+ This document and the information contained herein are provided on an
+ "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+ OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
+ ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
+ INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
+ INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+ WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+ The IETF takes no position regarding the validity or scope of any
+ Intellectual Property Rights or other rights that might be claimed to
+ pertain to the implementation or use of the technology described in
+ this document or the extent to which any license under such rights
+ might or might not be available; nor does it represent that it has
+ made any independent effort to identify any such rights. Information
+ on the procedures with respect to rights in RFC documents can be
+ found in BCP 78 and BCP 79.
+
+ Copies of IPR disclosures made to the IETF Secretariat and any
+ assurances of licenses to be made available, or the result of an
+ attempt made to obtain a general license or permission for the use of
+ such proprietary rights by implementers or users of this
+ specification can be obtained from the IETF on-line IPR repository at
+ http://www.ietf.org/ipr.
+
+ The IETF invites any interested party to bring to its attention any
+ copyrights, patents or patent applications, or other proprietary
+ rights that may cover technology that may be required to implement
+ this standard. Please address the information to the IETF at
+ ietf-ipr@ietf.org.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is provided by the IETF
+ Administrative Support Activity (IASA).
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 59]
+\f
lpoptions.o: ../cups/http.h ../cups/versioning.h ../cups/ppd.h
lpoptions.o: ../cups/array.h ../cups/file.h ../cups/language.h ../cups/i18n.h
lpoptions.o: ../cups/transcode.h
-lppasswd.o: ../cups/string.h ../config.h ../cups/cups.h ../cups/ipp.h
-lppasswd.o: ../cups/http.h ../cups/versioning.h ../cups/ppd.h ../cups/array.h
-lppasswd.o: ../cups/file.h ../cups/language.h ../cups/i18n.h
-lppasswd.o: ../cups/transcode.h ../cups/md5.h
-lpstat.o: ../cups/http-private.h ../config.h ../cups/http.h
-lpstat.o: ../cups/versioning.h ../cups/md5.h ../cups/ipp-private.h
-lpstat.o: ../cups/ipp.h ../cups/string.h ../cups/cups.h ../cups/ppd.h
-lpstat.o: ../cups/array.h ../cups/file.h ../cups/language.h ../cups/i18n.h
-lpstat.o: ../cups/transcode.h ../cups/debug.h
+lppasswd.o: ../cups/globals.h ../cups/string.h ../config.h
+lppasswd.o: ../cups/http-private.h ../cups/http.h ../cups/versioning.h
+lppasswd.o: ../cups/md5.h ../cups/ipp-private.h ../cups/ipp.h ../cups/cups.h
+lppasswd.o: ../cups/ppd.h ../cups/array.h ../cups/file.h ../cups/language.h
+lppasswd.o: ../cups/i18n.h ../cups/transcode.h ../cups/md5.h
+lpstat.o: ../cups/globals.h ../cups/string.h ../config.h
+lpstat.o: ../cups/http-private.h ../cups/http.h ../cups/versioning.h
+lpstat.o: ../cups/md5.h ../cups/ipp-private.h ../cups/ipp.h ../cups/cups.h
+lpstat.o: ../cups/ppd.h ../cups/array.h ../cups/file.h ../cups/language.h
+lpstat.o: ../cups/i18n.h ../cups/transcode.h ../cups/debug.h
#
# "$Id: Makefile 7929 2008-09-10 22:23:59Z mike $"
#
-# System V commands makefile for the Common UNIX Printing System (CUPS).
+# System V commands makefile for CUPS.
#
-# Copyright 2007-2009 by Apple Inc.
+# Copyright 2007-2010 by Apple Inc.
# Copyright 1997-2006 by Easy Software Products, all rights reserved.
#
# These coded instructions, statements, and computer programs are the
echo Linking $@...
$(CC) $(LDFLAGS) -o $@ cupstestppd.o $(LINKCUPSIMAGE) $(IMGLIBS) $(LIBS)
-cupstestppd-static: cupstestppd.o ../cups/libcups.a ../filter/libcupsimage.a
+cupstestppd-static: cupstestppd.o ../cups/$(LIBCUPSSTATIC) ../filter/libcupsimage.a
echo Linking $@...
$(CC) $(LDFLAGS) -o $@ cupstestppd.o ../filter/libcupsimage.a \
- ../cups/libcups.a $(IMGLIBS) $(LIBGSSAPI) $(LIBS) $(LIBZ)
+ ../cups/$(LIBCUPSSTATIC) $(IMGLIBS) $(LIBGSSAPI) $(LIBS) $(LIBZ)
#
/*
* "$Id: lppasswd.c 6649 2007-07-11 21:46:42Z mike $"
*
- * MD5 password program for the Common UNIX Printing System (CUPS).
+ * MD5 password program for CUPS.
*
- * Copyright 2007-2009 by Apple Inc.
+ * Copyright 2007-2010 by Apple Inc.
* Copyright 1997-2006 by Easy Software Products.
*
* These coded instructions, statements, and computer programs are the
#include <sys/types.h>
#include <sys/stat.h>
-#include <cups/string.h>
-#include <cups/cups.h>
-#include <cups/i18n.h>
+#include <cups/globals.h>
#include <cups/md5.h>
#ifndef WIN32
groupline[17], /* Group from line */
md5line[33], /* MD5-sum from line */
md5new[33]; /* New MD5 sum */
- const char *root; /* CUPS server root directory */
char passwdmd5[1024], /* passwd.md5 file */
passwdold[1024], /* passwd.old file */
passwdnew[1024]; /* passwd.tmp file */
int flag; /* Password check flags... */
int fd; /* Password file descriptor */
int error; /* Write error */
+ _cups_globals_t *cg = _cupsGlobals(); /* Global data */
+ cups_lang_t *lang; /* Language info */
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
struct sigaction action; /* Signal action */
#endif /* HAVE_SIGACTION && !HAVE_SIGSET*/
_cupsSetLocale(argv);
+ lang = cupsLangDefault();
/*
* Check to see if stdin, stdout, and stderr are still open...
/*
* Find the server directory...
- *
- * We use the CUPS_SERVERROOT environment variable when we are running
- * as root or when lppasswd is not setuid...
*/
- if ((root = getenv("CUPS_SERVERROOT")) == NULL ||
- (getuid() != geteuid() && getuid()))
- root = CUPS_SERVERROOT;
-
- snprintf(passwdmd5, sizeof(passwdmd5), "%s/passwd.md5", root);
- snprintf(passwdold, sizeof(passwdold), "%s/passwd.old", root);
- snprintf(passwdnew, sizeof(passwdnew), "%s/passwd.new", root);
+ snprintf(passwdmd5, sizeof(passwdmd5), "%s/passwd.md5", cg->cups_serverroot);
+ snprintf(passwdold, sizeof(passwdold), "%s/passwd.old", cg->cups_serverroot);
+ snprintf(passwdnew, sizeof(passwdnew), "%s/passwd.new", cg->cups_serverroot);
/*
* Find the default system group...
if (op != DELETE)
{
- if ((passwd = cupsGetPassword(_("Enter password:"))) == NULL)
+ if ((passwd = cupsGetPassword(
+ _cupsLangString(lang, _("Enter password:")))) == NULL)
return (1);
if ((newpass = strdup(passwd)) == NULL)
return (1);
}
- if ((passwd = cupsGetPassword(_("Enter password again:"))) == NULL)
+ if ((passwd = cupsGetPassword(
+ _cupsLangString(lang, _("Enter password again:")))) == NULL)
return (1);
if (strcmp(passwd, newpass) != 0)
/*
* "$Id: lpstat.c 7921 2008-09-10 15:42:24Z mike $"
*
- * "lpstat" command for the Common UNIX Printing System (CUPS).
+ * "lpstat" command for CUPS.
*
- * Copyright 2007-2009 by Apple Inc.
+ * Copyright 2007-2010 by Apple Inc.
* Copyright 1997-2006 by Easy Software Products.
*
* These coded instructions, statements, and computer programs are the
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
-#include <cups/http-private.h>
-#include <cups/string.h>
-#include <cups/cups.h>
-#include <cups/i18n.h>
+#include <cups/globals.h>
#include <cups/debug.h>
char printer_uri[HTTP_MAX_URI],
/* Printer URI */
printer_state_time[255];/* Printer state time */
- const char *root; /* Server root directory... */
+ _cups_globals_t *cg = _cupsGlobals(); /* Global data */
static const char *pattrs[] = /* Attributes we need for printers... */
{
"printer-name",
DEBUG_printf(("show_printers(printers=\"%s\", num_dests=%d, dests=%p, "
"long_status=%d)\n", printers, num_dests, dests, long_status));
- if ((root = getenv("CUPS_SERVERROOT")) == NULL)
- root = CUPS_SERVERROOT;
-
if (printers != NULL && !strcmp(printers, "all"))
printers = NULL;
if (make_model && strstr(make_model, "System V Printer"))
_cupsLangPrintf(stdout,
_("\tInterface: %s/interfaces/%s\n"),
- root, printer);
+ cg->cups_serverroot, printer);
else if (make_model && !strstr(make_model, "Raw Printer"))
_cupsLangPrintf(stdout,
- _("\tInterface: %s/ppd/%s.ppd\n"), root, printer);
+ _("\tInterface: %s/ppd/%s.ppd\n"),
+ cg->cups_serverroot, printer);
}
_cupsLangPuts(stdout, _("\tOn fault: no alert\n"));
_cupsLangPuts(stdout, _("\tAfter fault: continue\n"));
if (make_model && strstr(make_model, "System V Printer"))
_cupsLangPrintf(stdout,
_("\tInterface: %s/interfaces/%s\n"),
- root, printer);
+ cg->cups_serverroot, printer);
else if (make_model && !strstr(make_model, "Raw Printer"))
_cupsLangPrintf(stdout,
- _("\tInterface: %s/ppd/%s.ppd\n"), root, printer);
+ _("\tInterface: %s/ppd/%s.ppd\n"),
+ cg->cups_serverroot, printer);
}
_cupsLangPuts(stdout, _("\tOn fault: no alert\n"));
_cupsLangPuts(stdout, _("\tAfter fault: continue\n"));
<H2 CLASS="title">Add Class</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
<TABLE>
<H2 CLASS="title">Add Printer</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription">
<H2 CLASS="title">Add RSS Subscription</H2>
<H2 CLASS="title">Printers</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="SUBMIT" VALUE="Add Printer"></FORM>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="find-new-printers"><INPUT TYPE="SUBMIT" VALUE="Find New Printers"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="SUBMIT" VALUE="Add Printer"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="find-new-printers"><INPUT TYPE="SUBMIT" VALUE="Find New Printers"></FORM>
<FORM ACTION="/printers/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Manage Printers"></FORM>
-{have_samba?<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba"><INPUT TYPE="SUBMIT" VALUE="Export Printers to Samba"></FORM>:}
+{have_samba?<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba"><INPUT TYPE="SUBMIT" VALUE="Export Printers to Samba"></FORM>:}
</P>
<H2 CLASS="title">Classes</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-class"><INPUT TYPE="SUBMIT" VALUE="Add Class"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-class"><INPUT TYPE="SUBMIT" VALUE="Add Class"></FORM>
<FORM ACTION="/classes/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Manage Classes"></FORM>
</P>
<H2 CLASS="title">Server</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server"><INPUT TYPE="SUBMIT" VALUE="Edit Configuration File"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server"><INPUT TYPE="SUBMIT" VALUE="Edit Configuration File"></FORM>
<FORM ACTION="/admin/log/access_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="View Access Log"></FORM>
<FORM ACTION="/admin/log/error_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="View Error Log"></FORM>
<FORM ACTION="/admin/log/page_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="View Page Log"></FORM>
<BLOCKQUOTE>{SETTINGS_ERROR}</BLOCKQUOTE>:
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
{ADVANCEDSETTINGS?<P><B>Server Settings\:</B></P>
<H2 CLASS="title">RSS Subscriptions</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription"><INPUT TYPE="SUBMIT" VALUE="Add RSS Subscription"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription"><INPUT TYPE="SUBMIT" VALUE="Add RSS Subscription"></FORM>
</P>
</DIV>
<H2 CLASS="title">{op=modify-printer?Modify {printer_name}:Add Printer}</H2>
{CUPS_GET_DEVICES_DONE?<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<H2 CLASS="title">{op=modify-printer?Modify {printer_name}:Add Printer}</H2>
<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
<H2 CLASS="title">{op=modify-printer?Modify {printer_name}:Add Printer}</H2>
<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
<H2 CLASS="title">{op=modify-printer?Modify {printer_name}:Add Printer}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<H2 CLASS="title">{op=modify-printer?Modify {printer_name}:Add Printer}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{?current_make_and_model}">
<P><B>Warning:</B> Are you sure you want to delete class
{printer_name}?</P>
-<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="op" VALUE="delete-class"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Delete Class"></FORM></P>
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="op" VALUE="delete-class"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Delete Class"></FORM></P>
</DIV>
{server_is_sharing_printers=0?Not:{printer_is_shared=0?Not:}} Shared{default_name={printer_name}?, Server Default:})</H2>
<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
<OPTION VALUE="">Maintenance</OPTION>
<OPTION VALUE="print-test-page">Print Test Page</OPTION>
</FORM>
<FORM METHOD="POST" ACTION="{admin_uri}" NAME="administration">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
<OPTION VALUE="">Administration</OPTION>
<H2 CLASS="title">>Klasse hinzufügen</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
<TABLE>
<H2 CLASS="title">Drucker hinzufügen</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription">
<H2 CLASS="title">>RSS Subskription hinzufügen</H2>
<H2 CLASS="title">Drucker</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="SUBMIT" VALUE="Drucker hinzufügen"></FORM>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="find-new-printers"><INPUT TYPE="SUBMIT" VALUE="Verfügbare Drucker auflisten"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="SUBMIT" VALUE="Drucker hinzufügen"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="find-new-printers"><INPUT TYPE="SUBMIT" VALUE="Verfügbare Drucker auflisten"></FORM>
<FORM ACTION="/printers/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Drucker verwalten"></FORM>
-{have_samba?<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba"><INPUT TYPE="SUBMIT" VALUE="Drucker für Samba freigeben"></FORM>:}
+{have_samba?<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba"><INPUT TYPE="SUBMIT" VALUE="Drucker für Samba freigeben"></FORM>:}
</P>
<H2 CLASS="title">Klassen</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-class"><INPUT TYPE="SUBMIT" VALUE="Klasse hinzufügen"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-class"><INPUT TYPE="SUBMIT" VALUE="Klasse hinzufügen"></FORM>
<FORM ACTION="/classes/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Klassen verwalten"></FORM>
</P>
<H2 CLASS="title">Server</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server"><INPUT TYPE="SUBMIT" VALUE="Konfigurationsdatei bearbeiten"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server"><INPUT TYPE="SUBMIT" VALUE="Konfigurationsdatei bearbeiten"></FORM>
<FORM ACTION="/admin/log/access_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Zugriffsprotokoll betrachten"></FORM>
<FORM ACTION="/admin/log/error_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Fehlerprotokoll betrachten"></FORM>
<FORM ACTION="/admin/log/page_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Seitenprotokoll betrachten"></FORM>
<BLOCKQUOTE>{SETTINGS_ERROR}</BLOCKQUOTE>:
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
{ADVANCEDSETTINGS?<P><B>Erweiterte Servereinstellungen\:</B></P>
<H2 CLASS="title">RSS Subskriptionen</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription"><INPUT TYPE="SUBMIT" VALUE="RSS Subskription hinzufügen"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription"><INPUT TYPE="SUBMIT" VALUE="RSS Subskription hinzufügen"></FORM>
</P>
</DIV>
<THEAD><TR><TH>Name</TH><TH>Ereignis</TH><TH>Warteschlange</TH></TR></THEAD>
<TBODY>{[notify_subscription_id]
<TR><TD><A HREF="{notify_recipient_uri}">{notify_recipient_name}</A><BR>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-subscription"><INPUT TYPE="HIDDEN" NAME="notify_subscription_id" VALUE="{notify_subscription_id}"><INPUT TYPE="SUBMIT" VALUE="RSS Subskription kündigen"></FORM> </TD><TD>{notify_events}</TD><TD NOWRAP> {notify_printer_name?{notify_printer_name}:Alle Warteschlangen}</TD></TR>}
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-subscription"><INPUT TYPE="HIDDEN" NAME="notify_subscription_id" VALUE="{notify_subscription_id}"><INPUT TYPE="SUBMIT" VALUE="RSS Subskription kündigen"></FORM> </TD><TD>{notify_events}</TD><TD NOWRAP> {notify_printer_name?{notify_printer_name}:Alle Warteschlangen}</TD></TR>}
</TBODY>
</TABLE>:}
ALT="Busy Indicator"> Suche nach Druckern...</P>}
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<H2 CLASS="title">{op=modify-printer?{printer_name} ändern:Drucker hinzufügen}</H2>
<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
<H2 CLASS="title">{op=modify-printer?{printer_name} ändern:Drucker hinzufügen}</H2>
<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
</TD>
</TR>
<TR>
-<TH CLASS="label">>Oder stellen Sie eine PPD Datei bereit:</TH>
+<TH CLASS="label">Oder stellen Sie eine PPD Datei bereit:</TH>
<TD><INPUT TYPE="HIDDEN" NAME="MAX_FILE_SIZE" VALUE="262144"><INPUT
TYPE="FILE" NAME="PPD_FILE"></TD>
</TR>
<H2 CLASS="title">{op=modify-printer?{printer_name} ändern:Drucker hinzufügen}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<H2 CLASS="title">{op=modify-printer?{printer_name} ändern:Drucker hinzufügen}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{?current_make_and_model}">
<P><B>Warnung:</B> Sind Sie sicher, dass Sie die Klasse
{printer_name} löschen wollen?</P>
-<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="op" VALUE="delete-class"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Klasse löschen"></FORM></P>
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="op" VALUE="delete-class"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Klasse löschen"></FORM></P>
</DIV>
{server_is_sharing_printers=0?Nicht:{printer_is_shared=0?Nicht:}} Freigegeben{default_name={printer_name}?, Standarddrucker:})</H2>
<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
<OPTION VALUE="">Wartung</OPTION>
<OPTION VALUE="print-test-page">Drucke Testseite</OPTION>
</FORM>
<FORM METHOD="POST" ACTION="{admin_uri}" NAME="administration">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
<OPTION VALUE="">Administration</OPTION>
<H2 CLASS="title">Konfigurationsdatei ändern</H2>
<FORM NAME="cups" METHOD="POST" ACTION="/admin/">
-
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
<TEXTAREA NAME="CUPSDCONF" COLS="80" ROWS="25">{CUPSDCONF}</TEXTAREA>
<DIV CLASS="indent">
<FORM METHOD="POST" ACTION="/{SECTION}/{job_id?:{printer_name}}">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{job_id?<INPUT TYPE="HIDDEN" NAME="JOB_ID" VALUE="{job_id}">:}
<EM>"{job_printer_state_message}"</EM>:}</TD>
<TD>
{job_preserved>0?{job_state>5?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="restart-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="restart-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
<INPUT TYPE="SUBMIT" VALUE="Auftrag neu drucken"></FORM>:}:}
{job_state=4?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="release-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="release-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
<INPUT TYPE="SUBMIT" VALUE="Auftrag freigeben"></FORM>:}
{job_state=3?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="hold-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="hold-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
<INPUT TYPE="SUBMIT" VALUE="Auftrag anhalten"></FORM>:}
{job_state<7?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
<INPUT TYPE="SUBMIT" VALUE="Auftrag löschen"></FORM>
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="move-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="SUBMIT" VALUE="Auftrag verschieben"></FORM>:}
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="move-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="SUBMIT" VALUE="Auftrag verschieben"></FORM>:}
</TD>
</TR>
}
{#device_uri=0?<P>Keine Drucker gefunden.</P>
:<UL>{[device_uri]
-<LI><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="HIDDEN" NAME="TEMPLATE_NAME" VALUE="{template_name}"><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="Local Printer"><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{device_make_and_model}"><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}"><INPUT TYPE="SUBMIT" VALUE="Diesen Drucker hinzufügen"></FORM>
+<LI><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="HIDDEN" NAME="TEMPLATE_NAME" VALUE="{template_name}"><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="Local Printer"><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{device_make_and_model}"><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}"><INPUT TYPE="SUBMIT" VALUE="Diesen Drucker hinzufügen"></FORM>
{device_make_and_model} ({device_info})</LI>
}</UL>}
<H2 CLASS="title">Klasse {printer_name} ändern</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
<H2 CLASS="title">{printer_name} ändern</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
<P><B>Warnung:</B> Sind Sie sicher, dass Sie den Drucker
{printer_name} löschen wollen?</P>
-<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="delete-printer"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Drucker löschen"></FORM></P>
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="delete-printer"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Drucker löschen"></FORM></P>
</DIV>
{server_is_sharing_printers=0?Nicht:{printer_is_shared=0?Nicht:}} freigegeben{default_name={printer_name}?, Standarddrucker:})</H2>
<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
<OPTION VALUE="">Wartung</OPTION>
<OPTION VALUE="print-test-page">Testseite drucken</OPTION>
</FORM>
<FORM METHOD="POST" ACTION="{admin_uri}" NAME="administration">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
<OPTION VALUE="">Administration</OPTION>
--></SCRIPT>
<FORM METHOD="POST" ACTION="/admin/" NAME="export_samba">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba">
<H2 CLASS="title">Drucker für Samba freigeben</H2>
<H2 CLASS="title">Standardeinstellungen für {printer_name} festlegen</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{HAVE_AUTOCONFIGURE?<INPUT TYPE="SUBMIT" NAME="AUTOCONFIGURE" VALUE="Drucker nach Standardeinstellungen fragen">:}
<DIV CLASS="indent">
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{OP}">
<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
{IS_CLASS?<INPUT TYPE="HIDDEN" NAME="IS_CLASS" VALUE="{IS_CLASS}">:}
<H2 CLASS="title">Edit Configuration File</H2>
<FORM NAME="cups" METHOD="POST" ACTION="/admin/">
-
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
<TEXTAREA NAME="CUPSDCONF" COLS="80" ROWS="25">{CUPSDCONF}</TEXTAREA>
<H2 CLASS="title">Añadir clase</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
<TABLE>
<H2 CLASS="title">Añadir impresora</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription">
<H2 CLASS="title">Añadir subscripción RSS</H2>
<H2 CLASS="title">Impresoras</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="SUBMIT" VALUE="Añadir impresora"></FORM>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="find-new-printers"><INPUT TYPE="SUBMIT" VALUE="Encontrar nuevas impresoras"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="SUBMIT" VALUE="Añadir impresora"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="find-new-printers"><INPUT TYPE="SUBMIT" VALUE="Encontrar nuevas impresoras"></FORM>
<FORM ACTION="/printers/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Administrar impresoras"></FORM>
-{have_samba?<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba"><INPUT TYPE="SUBMIT" VALUE="Exportar impresoras a Samba"></FORM>:}
+{have_samba?<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba"><INPUT TYPE="SUBMIT" VALUE="Exportar impresoras a Samba"></FORM>:}
</P>
<H2 CLASS="title">Clases</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-class"><INPUT TYPE="SUBMIT" VALUE="Añadir clase"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-class"><INPUT TYPE="SUBMIT" VALUE="Añadir clase"></FORM>
<FORM ACTION="/classes/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Administrar clases"></FORM>
</P>
<H2 CLASS="title">Servidor</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server"><INPUT TYPE="SUBMIT" VALUE="Editar archivo configuración"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server"><INPUT TYPE="SUBMIT" VALUE="Editar archivo configuración"></FORM>
<FORM ACTION="/admin/log/access_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Ver archivo de registro de accesos"></FORM>
<FORM ACTION="/admin/log/error_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Ver archivo de registro de errores"></FORM>
<FORM ACTION="/admin/log/page_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Ver archivo de registro de páginas"></FORM>
<BLOCKQUOTE>{SETTINGS_ERROR}</BLOCKQUOTE>:
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
{ADVANCEDSETTINGS?<P><B>Configuración del servidor\:</B></P>
<H2 CLASS="title">Subscripciones RSS</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription"><INPUT TYPE="SUBMIT" VALUE="Añadir subscripción RSS"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription"><INPUT TYPE="SUBMIT" VALUE="Añadir subscripción RSS"></FORM>
</P>
</DIV>
<THEAD><TR><TH>Nombre</TH><TH>Eventos</TH><TH>Nombre de la cola</TH></TR></THEAD>
<TBODY>{[notify_subscription_id]
<TR><TD><A HREF="{notify_recipient_uri}">{notify_recipient_name}</A><BR>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-subscription"><INPUT TYPE="HIDDEN" NAME="notify_subscription_id" VALUE="{notify_subscription_id}"><INPUT TYPE="SUBMIT" VALUE="Cancelar subscripción RSS"></FORM> </TD><TD>{notify_events}</TD><TD NOWRAP> {notify_printer_name?{notify_printer_name}:Todas las colas}</TD></TR>}
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-subscription"><INPUT TYPE="HIDDEN" NAME="notify_subscription_id" VALUE="{notify_subscription_id}"><INPUT TYPE="SUBMIT" VALUE="Cancelar subscripción RSS"></FORM> </TD><TD>{notify_events}</TD><TD NOWRAP> {notify_printer_name?{notify_printer_name}:Todas las colas}</TD></TR>}
</TBODY>
</TABLE>:}
ALT="Busy Indicator"> Buscando impresoras...</P>}
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<H2 CLASS="title">{op=modify-printer?Modificar {printer_name}:Añadir impresora}</H2>
<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
<H2 CLASS="title">{op=modify-printer?Modificar {printer_name}:Añadir impresora}</H2>
<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
<H2 CLASS="title">{op=modify-printer?Modificar {printer_name}:Añadir impresora}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<H2 CLASS="title">{op=modify-printer?Modificar {printer_name}:Añadir impresora}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{?current_make_and_model}">
<P><B>Advertencia:</B> ¿Está seguro de querer borrar la clase
{printer_name}?</P>
-<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="op" VALUE="delete-class"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Borrar clase"></FORM></P>
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="op" VALUE="delete-class"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Borrar clase"></FORM></P>
</DIV>
{server_is_sharing_printers=0?no:{printer_is_shared=0?no:}} compartida{default_name={printer_name}?, predeterminada del servidor:})</H2>
<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
<OPTION VALUE="">Mantenimiento</OPTION>
<OPTION VALUE="print-test-page">Imprimir página de prueba</OPTION>
</FORM>
<FORM METHOD="POST" ACTION="{admin_uri}" NAME="administration">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
<OPTION VALUE="">Administración</OPTION>
<H2 CLASS="title">Editar archivo de configuración</H2>
<FORM NAME="cups" METHOD="POST" ACTION="/admin/">
-
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
<TEXTAREA NAME="CUPSDCONF" COLS="80" ROWS="25">{CUPSDCONF}</TEXTAREA>
<DIV CLASS="indent">
<FORM METHOD="POST" ACTION="/{SECTION}/{job_id?:{printer_name}}">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{job_id?<INPUT TYPE="HIDDEN" NAME="JOB_ID" VALUE="{job_id}">:}
<EM>"{job_printer_state_message}"</EM>:}</TD>
<TD>
{job_preserved>0?{job_state>5?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="restart-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="restart-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
<INPUT TYPE="SUBMIT" VALUE="Reimprimir trabajo"></FORM>:}:}
{job_state=4?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="release-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="release-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
<INPUT TYPE="SUBMIT" VALUE="Liberar trabajo"></FORM>:}
{job_state=3?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="hold-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="hold-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
<INPUT TYPE="SUBMIT" VALUE="Retener trabajo"></FORM>:}
{job_state<7?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
<INPUT TYPE="SUBMIT" VALUE="Cancelar trabajo"></FORM>
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="move-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="SUBMIT" VALUE="Mover trabajo"></FORM>:}
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="move-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="SUBMIT" VALUE="Mover trabajo"></FORM>:}
</TD>
</TR>
}
{#device_uri=0?<P>No se encuentran impresoras.</P>
:<UL>{[device_uri]
-<LI><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="HIDDEN" NAME="TEMPLATE_NAME" VALUE="{template_name}"><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="Local Printer"><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{device_make_and_model}"><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}"><INPUT TYPE="SUBMIT" VALUE="Añadir esta impresora"></FORM>
+<LI><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="HIDDEN" NAME="TEMPLATE_NAME" VALUE="{template_name}"><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="Local Printer"><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{device_make_and_model}"><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}"><INPUT TYPE="SUBMIT" VALUE="Añadir esta impresora"></FORM>
{device_make_and_model} ({device_info})</LI>
}</UL>}
<H2 CLASS="title">Modificar clase {printer_name}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
<H2 CLASS="title">Modificar {printer_name}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
<P><B>Advertencia:</B> ¿Está seguro de querer borrar la impresora
{printer_name}?</P>
-<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="delete-printer"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Borrar impresora"></FORM></P>
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="delete-printer"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Borrar impresora"></FORM></P>
</DIV>
{server_is_sharing_printers=0?no:{printer_is_shared=0?no:}} compartida{default_name={printer_name}?, predeterminada del servidor:})</H2>
<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
<OPTION VALUE="">Mantenimiento</OPTION>
<OPTION VALUE="print-test-page">Imprimir página de prueba</OPTION>
</FORM>
<FORM METHOD="POST" ACTION="{admin_uri}" NAME="administration">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
<OPTION VALUE="">Administración</OPTION>
--></SCRIPT>
<FORM METHOD="POST" ACTION="/admin/" NAME="export_samba">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba">
<H2 CLASS="title">Exportar impresoras a Samba</H2>
<H2 CLASS="title">Establecer opciones predeterminadas de {printer_name}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{HAVE_AUTOCONFIGURE?<INPUT TYPE="SUBMIT" NAME="AUTOCONFIGURE" VALUE="Consultar a la impresora las opciones predeterminadas">:}
<DIV CLASS="indent">
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{OP}">
<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
{IS_CLASS?<INPUT TYPE="HIDDEN" NAME="IS_CLASS" VALUE="{IS_CLASS}">:}
<H2 CLASS="title">Gehitu klasea</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
<TABLE>
<H2 CLASS="title">Gehitu inprimagailua</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription">
<H2 CLASS="title">Gehitu RSS harpidetza</H2>
<H2 CLASS="title">Inprimagailuak</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="SUBMIT" VALUE="Gehitu inprimagailua"></FORM>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="find-new-printers"><INPUT TYPE="SUBMIT" VALUE="Bilatu inprimagailu berriak"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="SUBMIT" VALUE="Gehitu inprimagailua"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="find-new-printers"><INPUT TYPE="SUBMIT" VALUE="Bilatu inprimagailu berriak"></FORM>
<FORM ACTION="/printers/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Kudeatu inprimagailuak"></FORM>
-{have_samba?<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba"><INPUT TYPE="SUBMIT" VALUE="Esportatu inprimagailuak Samba-ra"></FORM>:}
+{have_samba?<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba"><INPUT TYPE="SUBMIT" VALUE="Esportatu inprimagailuak Samba-ra"></FORM>:}
</P>
<H2 CLASS="title">Klaseak</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-class"><INPUT TYPE="SUBMIT" VALUE="Gehitu klasea"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-class"><INPUT TYPE="SUBMIT" VALUE="Gehitu klasea"></FORM>
<FORM ACTION="/classes/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Kudeatu klaseak"></FORM>
</P>
<H2 CLASS="title">Zerbitzaria</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server"><INPUT TYPE="SUBMIT" VALUE="Editatu konfigurazioko fitxategia"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server"><INPUT TYPE="SUBMIT" VALUE="Editatu konfigurazioko fitxategia"></FORM>
<FORM ACTION="/admin/log/access_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Ikusi atzipenen egunkaria"></FORM>
<FORM ACTION="/admin/log/error_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Ikusi erroreen egunkaria"></FORM>
<FORM ACTION="/admin/log/page_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Ikusi orrialdeen egunkaria"></FORM>
<BLOCKQUOTE>{SETTINGS_ERROR}</BLOCKQUOTE>:
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
{ADVANCEDSETTINGS?<P><B>Zerbitzariaren ezarpenak\:</B></P>
<H2 CLASS="title">RSS harpidetzak</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription"><INPUT TYPE="SUBMIT" VALUE="Gehitu RSS harpidetza"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription"><INPUT TYPE="SUBMIT" VALUE="Gehitu RSS harpidetza"></FORM>
</P>
</DIV>
<THEAD><TR><TH>Izena</TH><TH>Gertaerak</TH><TH>Ilararen izena</TH></TR></THEAD>
<TBODY>{[notify_subscription_id]
<TR><TD><A HREF="{notify_recipient_uri}">{notify_recipient_name}</A><BR>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-subscription"><INPUT TYPE="HIDDEN" NAME="notify_subscription_id" VALUE="{notify_subscription_id}"><INPUT TYPE="SUBMIT" VALUE="Utzi RSS harpidetza"></FORM> </TD><TD>{notify_events}</TD><TD NOWRAP> {notify_printer_name?{notify_printer_name}:Ilara guztiak}</TD></TR>}
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-subscription"><INPUT TYPE="HIDDEN" NAME="notify_subscription_id" VALUE="{notify_subscription_id}"><INPUT TYPE="SUBMIT" VALUE="Utzi RSS harpidetza"></FORM> </TD><TD>{notify_events}</TD><TD NOWRAP> {notify_printer_name?{notify_printer_name}:Ilara guztiak}</TD></TR>}
</TBODY>
</TABLE>:}
ALT="Busy Indicator"> Inprimagailuak bilatzen...</P>}
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<H2 CLASS="title">{op=modify-printer?Aldatu {printer_name}:Gehitu inprimagailua}</H2>
<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
<H2 CLASS="title">{op=modify-printer?Aldatu {printer_name}:Gehitu inprimagailua}</H2>
<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
<H2 CLASS="title">{op=modify-printer?Aldatu {printer_name}:Gehitu inprimagailua}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<H2 CLASS="title">{op=modify-printer?Aldatu {printer_name}:Gehitu inprimagailua}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{?current_make_and_model}">
<P><B>Abisua:</B> ziur zaude {printer_name} klasea ezabatu nahi duzula?</P>
-<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="op" VALUE="delete-class"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Ezabatu klasea"></FORM></P>
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="op" VALUE="delete-class"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Ezabatu klasea"></FORM></P>
</DIV>
{default_name={printer_name}?, zerbitzariaren lehenetsiak:} partekatuta {server_is_sharing_printers=0?ez:{printer_is_shared=0?ez:}} daude)</H2>
<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
<OPTION VALUE="">Mantenimendua</OPTION>
<OPTION VALUE="print-test-page">Inprimatu probako orrialdea</OPTION>
</FORM>
<FORM METHOD="POST" ACTION="{admin_uri}" NAME="administration">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
<OPTION VALUE="">Administrazioa</OPTION>
<H2 CLASS="title">Editatu konfigurazioko fitxategia</H2>
<FORM NAME="cups" METHOD="POST" ACTION="/admin/">
-
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
<TEXTAREA NAME="CUPSDCONF" COLS="80" ROWS="25">{CUPSDCONF}</TEXTAREA>
<DIV CLASS="indent">
<FORM METHOD="POST" ACTION="/{SECTION}/{job_id?:{printer_name}}">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{job_id?<INPUT TYPE="HIDDEN" NAME="JOB_ID" VALUE="{job_id}">:}
<EM>"{job_printer_state_message}"</EM>:}</TD>
<TD>
{job_preserved>0?{job_state>5?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="restart-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="restart-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
<INPUT TYPE="SUBMIT" VALUE="Inprimatu berriro lana"></FORM>:}:}
{job_state=4?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="release-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="release-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
<INPUT TYPE="SUBMIT" VALUE="Askatu lana"></FORM>:}
{job_state=3?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="hold-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="hold-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
<INPUT TYPE="SUBMIT" VALUE="Eutsi lana"></FORM>:}
{job_state<7?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
<INPUT TYPE="SUBMIT" VALUE="Utzi lana"></FORM>
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="move-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="SUBMIT" VALUE="Aldatu lana lekuz"></FORM>:}
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="move-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="SUBMIT" VALUE="Aldatu lana lekuz"></FORM>:}
</TD>
</TR>
}
{#device_uri=0?<P>Ez da inprimagailurik aurkitu.</P>
:<UL>{[device_uri]
-<LI><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="HIDDEN" NAME="TEMPLATE_NAME" VALUE="{template_name}"><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="Local Printer"><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{device_make_and_model}"><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}"><INPUT TYPE="SUBMIT" VALUE="Gehitu inprimagailu hau"></FORM>
+<LI><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="HIDDEN" NAME="TEMPLATE_NAME" VALUE="{template_name}"><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="Local Printer"><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{device_make_and_model}"><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}"><INPUT TYPE="SUBMIT" VALUE="Gehitu inprimagailu hau"></FORM>
{device_make_and_model} ({device_info})</LI>
}</UL>}
<H2 CLASS="title">Aldatu {printer_name} klasea</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
<H2 CLASS="title">Aldatu {printer_name}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
<P><B>Abisua:</B> ziur zaude {printer_name} inprimagailua ezabatzea nahi duzula?</P>
-<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="delete-printer"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Ezabatu inprimagailua"></FORM></P>
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="delete-printer"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Ezabatu inprimagailua"></FORM></P>
</DIV>
{default_name={printer_name}?, Zerbitzariaren lehenetsia:} partekatuta {server_is_sharing_printers=0?ez:{printer_is_shared=0?ez:}} dago)</H2>
<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
<OPTION VALUE="">Mantenimendua</OPTION>
<OPTION VALUE="print-test-page">Inprimatu probako orrialdea</OPTION>
</FORM>
<FORM METHOD="POST" ACTION="{admin_uri}" NAME="administration">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
<OPTION VALUE="">Administrazioa</OPTION>
--></SCRIPT>
<FORM METHOD="POST" ACTION="/admin/" NAME="export_samba">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba">
<H2 CLASS="title">Esportatu inprimagailuak Samba-ra</H2>
<H2 CLASS="title">Ezarri {printer_name}(r)en aukera lehenetsiak</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{HAVE_AUTOCONFIGURE?<INPUT TYPE="SUBMIT" NAME="AUTOCONFIGURE" VALUE="Kontsultatu inprimagailuaren aukera lehenetsiei buruz">:}
<DIV CLASS="indent">
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{OP}">
<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
{IS_CLASS?<INPUT TYPE="HIDDEN" NAME="IS_CLASS" VALUE="{IS_CLASS}">:}
<H2 CLASS="title">Tambah Kelas</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
<TABLE>
<H2 CLASS="title">Add Printer</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{?current_make!?<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE" VALUE="{current_make}">:}
{?current_make_and_model!?<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{current_make_and_model}">:}
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription">
<H2 CLASS="title">Tambah Subskripsi RSS</H2>
<H2 CLASS="title">Pencetak</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="SUBMIT" VALUE="Tambah Pencetak"></FORM>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="find-new-printers"><INPUT TYPE="SUBMIT" VALUE="Cari Pencetak Baru"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="SUBMIT" VALUE="Tambah Pencetak"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="find-new-printers"><INPUT TYPE="SUBMIT" VALUE="Cari Pencetak Baru"></FORM>
<FORM ACTION="/printers/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Atur Pencetak"></FORM>
-{have_samba?<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba"><INPUT TYPE="SUBMIT" VALUE="Ekspor Pencetak ke Samba"></FORM>:}
+{have_samba?<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba"><INPUT TYPE="SUBMIT" VALUE="Ekspor Pencetak ke Samba"></FORM>:}
</P>
<H2 CLASS="title">Kelas</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-class"><INPUT TYPE="SUBMIT" VALUE="Tambah Kelas"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-class"><INPUT TYPE="SUBMIT" VALUE="Tambah Kelas"></FORM>
<FORM ACTION="/classes/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Atur Kelas"></FORM>
</P>
<H2 CLASS="title">Server</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server"><INPUT TYPE="SUBMIT" VALUE="Sunting Berkas Konfigurasi"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server"><INPUT TYPE="SUBMIT" VALUE="Sunting Berkas Konfigurasi"></FORM>
<FORM ACTION="/admin/log/access_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Lihat Log Akses"></FORM>
<FORM ACTION="/admin/log/error_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Lihat Log Kesalahan"></FORM>
<FORM ACTION="/admin/log/page_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Lihat Log Halaman"></FORM>
<BLOCKQUOTE>{SETTINGS_ERROR}</BLOCKQUOTE>:
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
{ADVANCEDSETTINGS?<P><B>Pengaturan Server\:</B></P>
<H2 CLASS="title">Subskripsi RSS</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription"><INPUT TYPE="SUBMIT" VALUE="Tambah Subskripsi RSS"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription"><INPUT TYPE="SUBMIT" VALUE="Tambah Subskripsi RSS"></FORM>
</P>
</DIV>
<THEAD><TR><TH>Nama</TH><TH>Kejadian</TH><TH>Nama Antrian</TH></TR></THEAD>
<TBODY>{[notify_subscription_id]
<TR><TD><A HREF="{notify_recipient_uri}">{notify_recipient_name}</A><BR>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-subscription"><INPUT TYPE="HIDDEN" NAME="notify_subscription_id" VALUE="{notify_subscription_id}"><INPUT TYPE="SUBMIT" VALUE="Cancel RSS Subscription"></FORM> </TD><TD>{notify_events}</TD><TD NOWRAP> {notify_printer_name?{notify_printer_name}:Semua Antrian}</TD></TR>}
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-subscription"><INPUT TYPE="HIDDEN" NAME="notify_subscription_id" VALUE="{notify_subscription_id}"><INPUT TYPE="SUBMIT" VALUE="Cancel RSS Subscription"></FORM> </TD><TD>{notify_events}</TD><TD NOWRAP> {notify_printer_name?{notify_printer_name}:Semua Antrian}</TD></TR>}
</TBODY>
</TABLE>:}
ALT="Busy Indicator"> Mencari pencetak...</P>}
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<H2 CLASS="title">{op=modify-printer?Ubah {printer_name}:Tambah Pencetak}</H2>
<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
<H2 CLASS="title">{op=modify-printer?Modify {printer_name}:Tambah Pencetak}</H2>
<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
<H2 CLASS="title">{op=modify-printer?Modify {printer_name}:Tambah Pencetak}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<H2 CLASS="title">{op=modify-printer?Modify {printer_name}:Tambah Pencetak}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{?current_make_and_model}">
<P><B>Peringatan:</B> Anda yakin untuk menghapus kelas
{printer_name}?</P>
-<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="op" VALUE="delete-class"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Hapus Kelas"></FORM></P>
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="op" VALUE="delete-class"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Hapus Kelas"></FORM></P>
</DIV>
{server_is_sharing_printers=0?Jangan:{printer_is_shared=0?Jangan:}} Berbagi{default_name={printer_name}?, Server Baku:})</H2>
<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
<OPTION VALUE="">Perawatan</OPTION>
<OPTION VALUE="print-test-page">Halaman Uji Cetak</OPTION>
</FORM>
<FORM METHOD="POST" ACTION="{admin_uri}" NAME="administration">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
<OPTION VALUE="">Administrasi</OPTION>
<H2 CLASS="title">Sunting Berkas Konfigurasi</H2>
<FORM NAME="cups" METHOD="POST" ACTION="/admin/">
-
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
<TEXTAREA NAME="CUPSDCONF" COLS="80" ROWS="25">{CUPSDCONF}</TEXTAREA>
<DIV CLASS="indent">
<FORM METHOD="POST" ACTION="/{SECTION}/{job_id?:{printer_name}}">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{job_id?<INPUT TYPE="HIDDEN" NAME="JOB_ID" VALUE="{job_id}">:}
<EM>"{job_printer_state_message}"</EM>:}</TD>
<TD>
{job_preserved>0?{job_state>5?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="restart-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
-<INPUT TYPE="SUBMIT" VALUE="Reprint Job"></FORM>:}:}
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="restart-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}"><INPUT TYPE="SUBMIT" VALUE="Reprint Job"></FORM>:}:}
{job_state=4?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="release-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="release-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
<INPUT TYPE="SUBMIT" VALUE="Release Job"></FORM>:}
{job_state=3?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="hold-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="hold-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
<INPUT TYPE="SUBMIT" VALUE="Hold Job"></FORM>:}
{job_state<7?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
<INPUT TYPE="SUBMIT" VALUE="Cancel Job"></FORM>
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="move-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="SUBMIT" VALUE="Move Job"></FORM>:}
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="move-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="SUBMIT" VALUE="Move Job"></FORM>:}
</TD>
</TR>
}
{#device_uri=0?<P>Tidak ada pencetak.</P>
:<UL>{[device_uri]
-<LI><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="HIDDEN" NAME="TEMPLATE_NAME" VALUE="{template_name}"><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="Local Printer"><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{device_make_and_model}"><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}"><INPUT TYPE="SUBMIT" VALUE="Tambah Pencetak Ini"></FORM>
+<LI><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="HIDDEN" NAME="TEMPLATE_NAME" VALUE="{template_name}"><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="Local Printer"><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{device_make_and_model}"><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}"><INPUT TYPE="SUBMIT" VALUE="Tambah Pencetak Ini"></FORM>
{device_make_and_model} ({device_info})</LI>
}</UL>}
<H2 CLASS="title">Ubah Kelas {printer_name}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
<H2 CLASS="title">Ubah {printer_name}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
<P><B>Peringatan:</B> Anda yakin untuk menghapus
{printer_name}?</P>
-<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="delete-printer"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Hapus Pencetak"></FORM></P>
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="delete-printer"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Hapus Pencetak"></FORM></P>
</DIV>
{server_is_sharing_printers=0?Tidak:{printer_is_shared=0?Tidak:}} Berbagi{default_name={printer_name}?, Server Baku:})</H2>
<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
<OPTION VALUE="">Perawatan</OPTION>
<OPTION VALUE="print-test-page">Cetak Halaman Uji</OPTION>
</FORM>
<FORM METHOD="POST" ACTION="{admin_uri}" NAME="administration">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
<OPTION VALUE="">Administrasi</OPTION>
--></SCRIPT>
<FORM METHOD="POST" ACTION="/admin/" NAME="export_samba">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba">
<H2 CLASS="title">Ekspor Pencetak ke Samba</H2>
<H2 CLASS="title">Atur Opsi Baku untuk {printer_name}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{HAVE_AUTOCONFIGURE?<INPUT TYPE="SUBMIT" NAME="AUTOCONFIGURE" VALUE="Kuiri Pencetak untuk Opsi Baku">:}
<DIV CLASS="indent">
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{OP}">
<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
{IS_CLASS?<INPUT TYPE="HIDDEN" NAME="IS_CLASS" VALUE="{IS_CLASS}">:}
<H2 CLASS="title">Aggiungi classe</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
<TABLE>
<H2 CLASS="title">Aggiungi stampante</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{?current_make!?<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE" VALUE="{current_make}">:}
{?current_make_and_model!?<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{current_make_and_model}">:}
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription">
<H2 CLASS="title">Aggiungi iscrizione RSS</H2>
<H2 CLASS="title">Stampanti</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="SUBMIT" VALUE="Aggiungi stampante"></FORM>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="find-new-printers"><INPUT TYPE="SUBMIT" VALUE="Trova nuove stampanti"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="SUBMIT" VALUE="Aggiungi stampante"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="find-new-printers"><INPUT TYPE="SUBMIT" VALUE="Trova nuove stampanti"></FORM>
<FORM ACTION="/printers/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Gestisci stampanti"></FORM>
-{have_samba?<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba"><INPUT TYPE="SUBMIT" VALUE="Esporta stampanti a Samba"></FORM>:}
+{have_samba?<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba"><INPUT TYPE="SUBMIT" VALUE="Esporta stampanti a Samba"></FORM>:}
</P>
<H2 CLASS="title">Classi</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-class"><INPUT TYPE="SUBMIT" VALUE="Aggiungi classe"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-class"><INPUT TYPE="SUBMIT" VALUE="Aggiungi classe"></FORM>
<FORM ACTION="/classes/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Gestisci classi"></FORM>
</P>
<H2 CLASS="title">Server</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server"><INPUT TYPE="SUBMIT" VALUE="Modifica file di configurazione"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server"><INPUT TYPE="SUBMIT" VALUE="Modifica file di configurazione"></FORM>
<FORM ACTION="/admin/log/access_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Mostra registro degli accessi"></FORM>
<FORM ACTION="/admin/log/error_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Visualizza registro di errore"></FORM>
<FORM ACTION="/admin/log/page_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Visualizza registro delle pagine"></FORM>
<BLOCKQUOTE>{SETTINGS_ERROR}</BLOCKQUOTE>:
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
{ADVANCEDSETTINGS?<P><B>Impostazioni del server\:</B></P>
<H2 CLASS="title">Iscrizioni RSS</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription"><INPUT TYPE="SUBMIT" VALUE="Aggiungi iscrizione RSS"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription"><INPUT TYPE="SUBMIT" VALUE="Aggiungi iscrizione RSS"></FORM>
</P>
</DIV>
<THEAD><TR><TH>Nome</TH><TH>Eventi</TH><TH>Nome coda</TH></TR></THEAD>
<TBODY>{[notify_subscription_id]
<TR><TD><A HREF="{notify_recipient_uri}">{notify_recipient_name}</A><BR>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-subscription"><INPUT TYPE="HIDDEN" NAME="notify_subscription_id" VALUE="{notify_subscription_id}"><INPUT TYPE="SUBMIT" VALUE="Annulla iscrizione RSS"></FORM> </TD><TD>{notify_events}</TD><TD NOWRAP> {notify_printer_name?{notify_printer_name}:Tutte le code}</TD></TR>}
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-subscription"><INPUT TYPE="HIDDEN" NAME="notify_subscription_id" VALUE="{notify_subscription_id}"><INPUT TYPE="SUBMIT" VALUE="Annulla iscrizione RSS"></FORM> </TD><TD>{notify_events}</TD><TD NOWRAP> {notify_printer_name?{notify_printer_name}:Tutte le code}</TD></TR>}
</TBODY>
</TABLE>:}
ALT="Busy Indicator"> Ricerca stampanti...</P>}
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<H2 CLASS="title">{op=modify-printer?Modify {printer_name}:Aggiungi stampante}</H2>
<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
<H2 CLASS="title">{op=modify-printer?Modify {printer_name}:Aggiungi stampante}</H2>
<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
<H2 CLASS="title">{op=modify-printer?Modifica {printer_name}:Aggiungi stampante}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<H2 CLASS="title">{op=modify-printer?Modifica {printer_name}:Aggiungi stampante}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{?current_make_and_model}">
<P><B>Warning:</B> Sei sicuro di voler eliminare la classe
{printer_name}?</P>
-<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="op" VALUE="delete-class"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Elimina classe"></FORM></P>
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="op" VALUE="delete-class"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Elimina classe"></FORM></P>
</DIV>
{server_is_sharing_printers=0?Not:{printer_is_shared=0?Not:}} Shared{default_name={printer_name}?, Server Default:})</H2>
<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
<OPTION VALUE="">Manutenzione</OPTION>
<OPTION VALUE="print-test-page">Stampa pagina di prova</OPTION>
</FORM>
<FORM METHOD="POST" ACTION="{admin_uri}" NAME="administration">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
<OPTION VALUE="">Amministrazione</OPTION>
<H2 CLASS="title">Modifica file di configurazione</H2>
<FORM NAME="cups" METHOD="POST" ACTION="/admin/">
-
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
<TEXTAREA NAME="CUPSDCONF" COLS="80" ROWS="25">{CUPSDCONF}</TEXTAREA>
<DIV CLASS="indent">
<FORM METHOD="POST" ACTION="/{SECTION}/{job_id?:{printer_name}}">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{job_id?<INPUT TYPE="HIDDEN" NAME="JOB_ID" VALUE="{job_id}">:}
<EM>"{job_printer_state_message}"</EM>:}</TD>
<TD>
{job_preserved>0?{job_state>5?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="restart-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="restart-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
<INPUT TYPE="SUBMIT" VALUE="Ripeti stampa"></FORM>:}:}
{job_state=4?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="release-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="release-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
<INPUT TYPE="SUBMIT" VALUE="Release Job"></FORM>:}
{job_state=3?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="hold-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="hold-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
<INPUT TYPE="SUBMIT" VALUE="Hold Job"></FORM>:}
{job_state<7?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
<INPUT TYPE="SUBMIT" VALUE="Annulla stampa"></FORM>
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="move-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="SUBMIT" VALUE="Sposta stampa"></FORM>:}
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="move-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="SUBMIT" VALUE="Sposta stampa"></FORM>:}
</TD>
</TR>
}
{#device_uri=0?<P>Nessuna stampante trovata.</P>
:<UL>{[device_uri]
-<LI><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="HIDDEN" NAME="TEMPLATE_NAME" VALUE="{template_name}"><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="Stampante locale"><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{device_make_and_model}"><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}"><INPUT TYPE="SUBMIT" VALUE="Aggiungi stampante"></FORM>
+<LI><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="HIDDEN" NAME="TEMPLATE_NAME" VALUE="{template_name}"><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="Stampante locale"><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{device_make_and_model}"><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}"><INPUT TYPE="SUBMIT" VALUE="Aggiungi stampante"></FORM>
{device_make_and_model} ({device_info})</LI>
}</UL>}
<H2 CLASS="title">Modifica classe {printer_name}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
<H2 CLASS="title">Modifica {printer_name}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
<P><B>Avviso:</B> Sei sicuro di voler eliminare la stampante
{printer_name}?</P>
-<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="delete-printer"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Elimina stampante"></FORM></P>
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="delete-printer"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Elimina stampante"></FORM></P>
</DIV>
{server_is_sharing_printers=0?Not:{printer_is_shared=0?Not:}} Shared{default_name={printer_name}?, Server Default:})</H2>
<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
<OPTION VALUE="">Maintenance</OPTION>
<OPTION VALUE="print-test-page">Print Test Page</OPTION>
</FORM>
<FORM METHOD="POST" ACTION="{admin_uri}" NAME="administration">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
<OPTION VALUE="">Administration</OPTION>
--></SCRIPT>
<FORM METHOD="POST" ACTION="/admin/" NAME="export_samba">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba">
<H2 CLASS="title">Esporta stampanti a Samba</H2>
<H2 CLASS="title">Imposta opzioni predefinite per {printer_name}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{HAVE_AUTOCONFIGURE?<INPUT TYPE="SUBMIT" NAME="AUTOCONFIGURE" VALUE="Interroga stampante per opzioni predefinite">:}
<DIV CLASS="indent">
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{OP}">
<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
{IS_CLASS?<INPUT TYPE="HIDDEN" NAME="IS_CLASS" VALUE="{IS_CLASS}">:}
<H2 CLASS="title">クラスの追加</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
<TABLE>
<H2 CLASS="title">新しいプリンターの追加</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription">
<H2 CLASS="title">RSS 購読を追加</H2>
<H2 CLASS="title">プリンター</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="SUBMIT" VALUE="プリンターの追加"></FORM>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="find-new-printers"><INPUT TYPE="SUBMIT" VALUE="新しいプリンターの検索"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="SUBMIT" VALUE="プリンターの追加"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="find-new-printers"><INPUT TYPE="SUBMIT" VALUE="新しいプリンターの検索"></FORM>
<FORM ACTION="/printers/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="プリンターの管理"></FORM>
-{have_samba?<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba"><INPUT TYPE="SUBMIT" VALUE="プリンターを Samba にエクスポート"></FORM>:}
+{have_samba?<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba"><INPUT TYPE="SUBMIT" VALUE="プリンターを Samba にエクスポート"></FORM>:}
</P>
<H2 CLASS="title">クラス</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-class"><INPUT TYPE="SUBMIT" VALUE="クラスの追加"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-class"><INPUT TYPE="SUBMIT" VALUE="クラスの追加"></FORM>
<FORM ACTION="/classes/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="クラスの管理"></FORM>
</P>
<H2 CLASS="title">サーバー</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server"><INPUT TYPE="SUBMIT" VALUE="設定ファイルの編集"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server"><INPUT TYPE="SUBMIT" VALUE="設定ファイルの編集"></FORM>
<FORM ACTION="/admin/log/access_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="アクセスログの表示"></FORM>
<FORM ACTION="/admin/log/error_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="エラーログの表示"></FORM>
<FORM ACTION="/admin/log/page_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="ページログの表示"></FORM>
<BLOCKQUOTE>{SETTINGS_ERROR}</BLOCKQUOTE>:
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
{ADVANCEDSETTINGS?<P><B>サーバー設定\:</B></P>
<H2 CLASS="title">RSS 購読</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription"><INPUT TYPE="SUBMIT" VALUE="RSS 購読の追加"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription"><INPUT TYPE="SUBMIT" VALUE="RSS 購読の追加"></FORM>
</P>
</DIV>
<THEAD><TR><TH>名前</TH><TH>イベント</TH><TH>キュー名</TH></TR></THEAD>
<TBODY>{[notify_subscription_id]
<TR><TD><A HREF="{notify_recipient_uri}">{notify_recipient_name}</A><BR>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-subscription"><INPUT TYPE="HIDDEN" NAME="notify_subscription_id" VALUE="{notify_subscription_id}"><INPUT TYPE="SUBMIT" VALUE="RSS 購読のキャンセル"></FORM> </TD><TD>{notify_events}</TD><TD NOWRAP> {notify_printer_name?{notify_printer_name}:すべてのキュー}</TD></TR>}
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-subscription"><INPUT TYPE="HIDDEN" NAME="notify_subscription_id" VALUE="{notify_subscription_id}"><INPUT TYPE="SUBMIT" VALUE="RSS 購読のキャンセル"></FORM> </TD><TD>{notify_events}</TD><TD NOWRAP> {notify_printer_name?{notify_printer_name}:すべてのキュー}</TD></TR>}
</TBODY>
</TABLE>:}
ALT="Busy Indicator"> プリンターを探しています...</P>}
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<H2 CLASS="title">{op=modify-printer?{printer_name}の変更:プリンターの追加}</H2>
<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
<H2 CLASS="title">{op=modify-printer?{printer_name}の追加:プリンターの追加}</H2>
<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
<H2 CLASS="title">{op=modify-printer?{printer_name}の変更:プリンターの追加}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<H2 CLASS="title">{op=modify-printer?{printer_name}の変更:プリンターの追加}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{?current_make_and_model}">
<P><B>警告:</B> 本当にクラス
{printer_name} を削除しても良いですか?</P>
-<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="op" VALUE="delete-class"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="クラスの削除"></FORM></P>
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="op" VALUE="delete-class"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="クラスの削除"></FORM></P>
</DIV>
{server_is_sharing_printers=0?非:{printer_is_shared=0?非:}}共有{default_name={printer_name}?, デフォルトプリンター:})</H2>
<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
<OPTION VALUE="">メンテナンス</OPTION>
<OPTION VALUE="print-test-page">テストページの印刷</OPTION>
</FORM>
<FORM METHOD="POST" ACTION="{admin_uri}" NAME="administration">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
<OPTION VALUE="">管理</OPTION>
<H2 CLASS="title">設定ファイルの設定</H2>
<FORM NAME="cups" METHOD="POST" ACTION="/admin/">
-
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
<TEXTAREA NAME="CUPSDCONF" COLS="80" ROWS="25">{CUPSDCONF}</TEXTAREA>
<DIV CLASS="indent">
<FORM METHOD="POST" ACTION="/{SECTION}/{job_id?:{printer_name}}">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{job_id?<INPUT TYPE="HIDDEN" NAME="JOB_ID" VALUE="{job_id}">:}
<EM>"{job_printer_state_message}"</EM>:}</TD>
<TD>
{job_preserved>0?{job_state>5?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="restart-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="restart-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
<INPUT TYPE="SUBMIT" VALUE="ジョブの再印刷"></FORM>:}:}
{job_state=4?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="release-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="release-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
<INPUT TYPE="SUBMIT" VALUE="ジョブを解放"></FORM>:}
{job_state=3?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="hold-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="hold-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
<INPUT TYPE="SUBMIT" VALUE="ジョブを保留"></FORM>:}
{job_state<7?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
<INPUT TYPE="SUBMIT" VALUE="ジョブをキャンセル"></FORM>
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="move-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="SUBMIT" VALUE="ジョブを移動"></FORM>:}
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="move-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="SUBMIT" VALUE="ジョブを移動"></FORM>:}
</TD>
</TR>
}
{#device_uri=0?<P>プリンターが見つかりません。</P>
:<UL>{[device_uri]
-<LI><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="HIDDEN" NAME="TEMPLATE_NAME" VALUE="{template_name}"><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="Local Printer"><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{device_make_and_model}"><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}"><INPUT TYPE="SUBMIT" VALUE="このプリンターを追加"></FORM>
+<LI><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="HIDDEN" NAME="TEMPLATE_NAME" VALUE="{template_name}"><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="Local Printer"><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{device_make_and_model}"><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}"><INPUT TYPE="SUBMIT" VALUE="このプリンターを追加"></FORM>
{device_make_and_model} ({device_info})</LI>
}</UL>}
<H2 CLASS="title">クラス {printer_name} の変更</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
<H2 CLASS="title">プリンター {printer_name} の変更</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
<P><B>警告:</B> 本当にプリンター {printer_name} を削除してよいですか?</P>
-<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="delete-printer"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="プリンターの削除"></FORM></P>
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="delete-printer"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="プリンターの削除"></FORM></P>
</DIV>
{server_is_sharing_printers=0?非:{printer_is_shared=0?非:}}共有{default_name={printer_name}?, デフォルトプリンター:})</H2>
<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
<OPTION VALUE="">メンテナンス</OPTION>
<OPTION VALUE="print-test-page">テストページの印刷</OPTION>
</FORM>
<FORM METHOD="POST" ACTION="{admin_uri}" NAME="administration">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
<OPTION VALUE="">管理</OPTION>
--></SCRIPT>
<FORM METHOD="POST" ACTION="/admin/" NAME="export_samba">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba">
<H2 CLASS="title">プリンターを Samba にエクスポート</H2>
<H2 CLASS="title">{printer_name} のデフォルトオプション変更</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{HAVE_AUTOCONFIGURE?<INPUT TYPE="SUBMIT" NAME="AUTOCONFIGURE" VALUE="プリンターにデフォルトオプションを問い合わせる">:}
<DIV CLASS="indent">
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{OP}">
<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
{IS_CLASS?<INPUT TYPE="HIDDEN" NAME="IS_CLASS" VALUE="{IS_CLASS}">:}
<DIV CLASS="indent">
<FORM METHOD="POST" ACTION="/{SECTION}/{job_id?:{printer_name}}">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{job_id?<INPUT TYPE="HIDDEN" NAME="JOB_ID" VALUE="{job_id}">:}
<EM>"{job_printer_state_message}"</EM>:}</TD>
<TD>
{job_preserved>0?{job_state>5?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="restart-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
-<INPUT TYPE="SUBMIT" VALUE="Reprint Job"></FORM>:}:}
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="restart-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}"><INPUT TYPE="SUBMIT" VALUE="Reprint Job"></FORM>:}:}
{job_state=4?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="release-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="release-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
<INPUT TYPE="SUBMIT" VALUE="Release Job"></FORM>:}
{job_state=3?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="hold-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="hold-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
<INPUT TYPE="SUBMIT" VALUE="Hold Job"></FORM>:}
{job_state<7?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
<INPUT TYPE="SUBMIT" VALUE="Cancel Job"></FORM>
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="move-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="SUBMIT" VALUE="Move Job"></FORM>:}
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="move-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="SUBMIT" VALUE="Move Job"></FORM>:}
</TD>
</TR>
}
{#device_uri=0?<P>No printers found.</P>
:<UL>{[device_uri]
-<LI><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="HIDDEN" NAME="TEMPLATE_NAME" VALUE="{template_name}"><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="Local Printer"><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{device_make_and_model}"><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}"><INPUT TYPE="SUBMIT" VALUE="Add This Printer"></FORM>
+<LI><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="HIDDEN" NAME="TEMPLATE_NAME" VALUE="{template_name}"><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="Local Printer"><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{device_make_and_model}"><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}"><INPUT TYPE="SUBMIT" VALUE="Add This Printer"></FORM>
{device_make_and_model} ({device_info})</LI>
}</UL>}
<H2 CLASS="title">Modify Class {printer_name}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
<H2 CLASS="title">Modify {printer_name}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
<H2 CLASS="title">Dodawanie klasy</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
<TABLE>
<H2 CLASS="title">Dodawanie drukarki</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription">
<H2 CLASS="title">Dodawanie subskrypcji RSS</H2>
<H2 CLASS="title">Drukarki</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="SUBMIT" VALUE="Dodawanie drukarki"></FORM>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="find-new-printers"><INPUT TYPE="SUBMIT" VALUE="Wyszukiwanie nowych drukarek"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="SUBMIT" VALUE="Dodawanie drukarki"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="find-new-printers"><INPUT TYPE="SUBMIT" VALUE="Wyszukiwanie nowych drukarek"></FORM>
<FORM ACTION="/printers/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Zarządzanie drukarkami"></FORM>
-{have_samba?<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba"><INPUT TYPE="SUBMIT" VALUE="Eksportowanie drukarek do Samby"></FORM>:}
+{have_samba?<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba"><INPUT TYPE="SUBMIT" VALUE="Eksportowanie drukarek do Samby"></FORM>:}
</P>
<H2 CLASS="title">Klasy</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-class"><INPUT TYPE="SUBMIT" VALUE="Dodawanie klasy"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-class"><INPUT TYPE="SUBMIT" VALUE="Dodawanie klasy"></FORM>
<FORM ACTION="/classes/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Zarządzanie klasami"></FORM>
</P>
<H2 CLASS="title">Serwery</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server"><INPUT TYPE="SUBMIT" VALUE="Modyfikowanie pliku konfiguracji"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server"><INPUT TYPE="SUBMIT" VALUE="Modyfikowanie pliku konfiguracji"></FORM>
<FORM ACTION="/admin/log/access_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Przeglądanie dziennika dostępu"></FORM>
<FORM ACTION="/admin/log/error_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Przeglądanie dziennika błędów"></FORM>
<FORM ACTION="/admin/log/page_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Przeglądanie dziennika stron"></FORM>
<BLOCKQUOTE>{SETTINGS_ERROR}</BLOCKQUOTE>:
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
{ADVANCEDSETTINGS?<P><B>Ustawienia serwera\:</B></P>
<H2 CLASS="title">Subskrypcje RSS</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription"><INPUT TYPE="SUBMIT" VALUE="Dodawanie subskrypcji RSS"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription"><INPUT TYPE="SUBMIT" VALUE="Dodawanie subskrypcji RSS"></FORM>
</P>
</DIV>
<THEAD><TR><TH>Name</TH><TH>Zdarzenia</TH><TH>Nazwa kolejki</TH></TR></THEAD>
<TBODY>{[notify_subscription_id]
<TR><TD><A HREF="{notify_recipient_uri}">{notify_recipient_name}</A><BR>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-subscription"><INPUT TYPE="HIDDEN" NAME="notify_subscription_id" VALUE="{notify_subscription_id}"><INPUT TYPE="SUBMIT" VALUE="Anuluj subskrypcję RSS"></FORM> </TD><TD>{notify_events}</TD><TD NOWRAP> {notify_printer_name?{notify_printer_name}:Wszystkie kolejki}</TD></TR>}
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-subscription"><INPUT TYPE="HIDDEN" NAME="notify_subscription_id" VALUE="{notify_subscription_id}"><INPUT TYPE="SUBMIT" VALUE="Anuluj subskrypcję RSS"></FORM> </TD><TD>{notify_events}</TD><TD NOWRAP> {notify_printer_name?{notify_printer_name}:Wszystkie kolejki}</TD></TR>}
</TBODY>
</TABLE>:}
ALT="Busy Indicator"> Wyszukiwanie drukarek...</P>}
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<H2 CLASS="title">{op=modify-printer?Modify {printer_name}:Dodawanie drukarki}</H2>
<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
<H2 CLASS="title">{op=modify-printer?Modyfikowanie {printer_name}:Dodawanie drukarki}</H2>
<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
<H2 CLASS="title">{op=modify-printer?Modyfikowanie {printer_name}:Dodawanie drukarki}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<H2 CLASS="title">{op=modify-printer?Modyfikowanie {printer_name}:Dodawanie drukarki}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{?current_make_and_model}">
<P><B>Ostrzeżenie:</B> Usunąć klasę
{printer_name}?</P>
-<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="op" VALUE="delete-class"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Usuń klasę"></FORM></P>
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="op" VALUE="delete-class"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Usuń klasę"></FORM></P>
</DIV>
{server_is_sharing_printers=0?Nie:{printer_is_shared=0?Nie:}} Współdzielona{default_name={printer_name}?, Domyślne serwera:})</H2>
<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
<OPTION VALUE="">Konserwacja</OPTION>
<OPTION VALUE="print-test-page">Drukowanie strony próbnej</OPTION>
</FORM>
<FORM METHOD="POST" ACTION="{admin_uri}" NAME="administration">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
<OPTION VALUE="">Administracja</OPTION>
<H2 CLASS="title">Modyfikowanie pliku konfiguracji</H2>
<FORM NAME="cups" METHOD="POST" ACTION="/admin/">
-
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
<TEXTAREA NAME="CUPSDCONF" COLS="80" ROWS="25">{CUPSDCONF}</TEXTAREA>
<DIV CLASS="indent">
<FORM METHOD="POST" ACTION="/{SECTION}/{job_id?:{printer_name}}">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{job_id?<INPUT TYPE="HIDDEN" NAME="JOB_ID" VALUE="{job_id}">:}
<EM>"{job_printer_state_message}"</EM>:}</TD>
<TD>
{job_preserved>0?{job_state>5?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="restart-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="restart-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
<INPUT TYPE="SUBMIT" VALUE="Ponownie wydrukuj zadanie"></FORM>:}:}
{job_state=4?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="release-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="release-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
<INPUT TYPE="SUBMIT" VALUE="Zwolnij zadanie"></FORM>:}
{job_state=3?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="hold-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="hold-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
<INPUT TYPE="SUBMIT" VALUE="Wstrzymaj zadanie"></FORM>:}
{job_state<7?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
<INPUT TYPE="SUBMIT" VALUE="Anuluj zadanie"></FORM>
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="move-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="SUBMIT" VALUE="Przenieś zadanie"></FORM>:}
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="move-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="SUBMIT" VALUE="Przenieś zadanie"></FORM>:}
</TD>
</TR>
}
{#device_uri=0?<P>Nie znaleziono drukarek.</P>
:<UL>{[device_uri]
-<LI><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="HIDDEN" NAME="TEMPLATE_NAME" VALUE="{template_name}"><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="Lokalna drukarka"><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{device_make_and_model}"><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}"><INPUT TYPE="SUBMIT" VALUE="Dodaj tę drukarkę"></FORM>
+<LI><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="HIDDEN" NAME="TEMPLATE_NAME" VALUE="{template_name}"><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="Lokalna drukarka"><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{device_make_and_model}"><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}"><INPUT TYPE="SUBMIT" VALUE="Dodaj tę drukarkę"></FORM>
{device_make_and_model} ({device_info})</LI>
}</UL>}
<H2 CLASS="title">Modyfikowanie klasy {printer_name}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
<H2 CLASS="title">Modyfikowanie {printer_name}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
<P><B>Ostrzeżenie:</B> usunąć drukarkę
{printer_name}?</P>
-<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="delete-printer"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Usuń drukarkę"></FORM></P>
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="delete-printer"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Usuń drukarkę"></FORM></P>
</DIV>
{server_is_sharing_printers=0?Nie:{printer_is_shared=0?Nie:}} Współdzielona{default_name={printer_name}?, Domyślne serwera:})</H2>
<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
<OPTION VALUE="">Konserwacja</OPTION>
<OPTION VALUE="print-test-page">Wydrukuj stronę próbną</OPTION>
</FORM>
<FORM METHOD="POST" ACTION="{admin_uri}" NAME="administration">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
<OPTION VALUE="">Administracja</OPTION>
--></SCRIPT>
<FORM METHOD="POST" ACTION="/admin/" NAME="export_samba">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba">
<H2 CLASS="title">Eksportowanie drukarek do Samby</H2>
<H2 CLASS="title">Ustawianie domyślnych opcji dla {printer_name}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{HAVE_AUTOCONFIGURE?<INPUT TYPE="SUBMIT" NAME="AUTOCONFIGURE" VALUE="Zakolejkuj drukarkę do domyślnych opcji">:}
<DIV CLASS="indent">
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{OP}">
<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
{IS_CLASS?<INPUT TYPE="HIDDEN" NAME="IS_CLASS" VALUE="{IS_CLASS}">:}
<P><B>Warning:</B> Are you sure you want to delete printer
{printer_name}?</P>
-<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="delete-printer"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Delete Printer"></FORM></P>
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="delete-printer"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Delete Printer"></FORM></P>
</DIV>
{server_is_sharing_printers=0?Not:{printer_is_shared=0?Not:}} Shared{default_name={printer_name}?, Server Default:})</H2>
<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
<OPTION VALUE="">Maintenance</OPTION>
<OPTION VALUE="print-test-page">Print Test Page</OPTION>
</FORM>
<FORM METHOD="POST" ACTION="{admin_uri}" NAME="administration">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
<OPTION VALUE="">Administration</OPTION>
<H2 CLASS="title">Новая группа</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
<TABLE>
<H2 CLASS="title">Добавление принтера</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription">
<H2 CLASS="title">Добавление подписки по RSS</H2>
<H2 CLASS="title">Принтеры</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="SUBMIT" VALUE="Добавить принтер"></FORM>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="find-new-printers"><INPUT TYPE="SUBMIT" VALUE="Найти новый принтер"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="SUBMIT" VALUE="Добавить принтер"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="find-new-printers"><INPUT TYPE="SUBMIT" VALUE="Найти новый принтер"></FORM>
<FORM ACTION="/printers/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Управление принтерами"></FORM>
-{have_samba?<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba"><INPUT TYPE="SUBMIT" VALUE="Экспортировать принтер в Samba"></FORM>:}
+{have_samba?<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba"><INPUT TYPE="SUBMIT" VALUE="Экспортировать принтер в Samba"></FORM>:}
</P>
<H2 CLASS="title">Группы</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-class"><INPUT TYPE="SUBMIT" VALUE="Добавить группу"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-class"><INPUT TYPE="SUBMIT" VALUE="Добавить группу"></FORM>
<FORM ACTION="/classes/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Управление группами"></FORM>
</P>
<H2 CLASS="title">Сервер</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server"><INPUT TYPE="SUBMIT" VALUE="Редактировать конфигурационный файл"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server"><INPUT TYPE="SUBMIT" VALUE="Редактировать конфигурационный файл"></FORM>
<FORM ACTION="/admin/log/access_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Показать журнал заданий"></FORM>
<FORM ACTION="/admin/log/error_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Показать журнал ошибок"></FORM>
<FORM ACTION="/admin/log/page_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Показать журнал страниц"></FORM>
<BLOCKQUOTE>{SETTINGS_ERROR}</BLOCKQUOTE>:
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
{ADVANCEDSETTINGS?<P><B>Параметры сервера\:</B></P>
<H2 CLASS="title">Подписка по RSS</H2>
<P>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription"><INPUT TYPE="SUBMIT" VALUE="Добавить подписку по RSS"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription"><INPUT TYPE="SUBMIT" VALUE="Добавить подписку по RSS"></FORM>
</P>
</DIV>
<THEAD><TR><TH>Название</TH><TH>События</TH><TH>Очередь</TH></TR></THEAD>
<TBODY>{[notify_subscription_id]
<TR><TD><A HREF="{notify_recipient_uri}">{notify_recipient_name}</A><BR>
-<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-subscription"><INPUT TYPE="HIDDEN" NAME="notify_subscription_id" VALUE="{notify_subscription_id}"><INPUT TYPE="SUBMIT" VALUE="Отменить подписку по RSS"></FORM> </TD><TD>{notify_events}</TD><TD NOWRAP> {notify_printer_name?{notify_printer_name}:Все очереди}</TD></TR>}
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-subscription"><INPUT TYPE="HIDDEN" NAME="notify_subscription_id" VALUE="{notify_subscription_id}"><INPUT TYPE="SUBMIT" VALUE="Отменить подписку по RSS"></FORM> </TD><TD>{notify_events}</TD><TD NOWRAP> {notify_printer_name?{notify_printer_name}:Все очереди}</TD></TR>}
</TBODY>
</TABLE>:}
ALT="Busy Indicator"> Поиск принтеров...</P>}
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<H2 CLASS="title">{op=modify-printer?Изменение {printer_name}:Добавление принтера}</H2>
<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
<H2 CLASS="title">{op=modify-printer?Изменение {printer_name}:Добавление принтера}</H2>
<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
<H2 CLASS="title">{op=modify-printer?Изменение {printer_name}:Добавление принтера}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<H2 CLASS="title">{op=modify-printer?Изменение {printer_name}:Добавление принтера}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{?current_make_and_model}">
<P><B>Предупреждение:</B> вы действительно хотите удалить группу
«{printer_name}»?</P>
-<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="op" VALUE="delete-class"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Удалить группу"></FORM></P>
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="op" VALUE="delete-class"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Удалить группу"></FORM></P>
</DIV>
{server_is_sharing_printers=0?нет совместного доступа:{printer_is_shared=0?нет совместного доступа:разрешен совместный доступ}})</H2>
<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
<OPTION VALUE="">Обслуживание</OPTION>
<OPTION VALUE="print-test-page">Печать пробной страницы</OPTION>
</FORM>
<FORM METHOD="POST" ACTION="{admin_uri}" NAME="Администрирование">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
<OPTION VALUE="">Администрирование</OPTION>
<H2 CLASS="title">Редактирование конфигурационного файла</H2>
<FORM NAME="cups" METHOD="POST" ACTION="/admin/">
-
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
<TEXTAREA NAME="CUPSDCONF" COLS="80" ROWS="25">{CUPSDCONF}</TEXTAREA>
<DIV CLASS="indent">
<FORM METHOD="POST" ACTION="/{SECTION}/{job_id?:{printer_name}}">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{job_id?<INPUT TYPE="HIDDEN" NAME="JOB_ID" VALUE="{job_id}">:}
<EM>"{job_printer_state_message}"</EM>:}</TD>
<TD>
{job_preserved>0?{job_state>5?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="restart-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="restart-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
<INPUT TYPE="SUBMIT" VALUE="Перезапустить"></FORM>:}:}
{job_state=4?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="release-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="release-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
<INPUT TYPE="SUBMIT" VALUE="Продолжить"></FORM>:}
{job_state=3?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="hold-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="hold-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
<INPUT TYPE="SUBMIT" VALUE="Приостановить"></FORM>:}
{job_state<7?
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
<INPUT TYPE="SUBMIT" VALUE="Отменить"></FORM>
-<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="move-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="SUBMIT" VALUE="Переместить"></FORM>:}
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="move-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="SUBMIT" VALUE="Переместить"></FORM>:}
</TD>
</TR>
}
{#device_uri=0?<P>Не обнаружено ни одного принтера.</P>
:<UL>{[device_uri]
-<LI><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="HIDDEN" NAME="TEMPLATE_NAME" VALUE="{template_name}"><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="Сетевой принтер"><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{device_make_and_model}"><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}"><INPUT TYPE="SUBMIT" VALUE="Добавить этот принтер"></FORM>
+<LI><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="HIDDEN" NAME="TEMPLATE_NAME" VALUE="{template_name}"><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="Сетевой принтер"><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{device_make_and_model}"><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}"><INPUT TYPE="SUBMIT" VALUE="Добавить этот принтер"></FORM>
{device_make_and_model} ({device_info})</LI>
}</UL>}
<H2 CLASS="title">Изменение группы {printer_name}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
<H2 CLASS="title">Изменение принтера {printer_name}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
<P><B>Предупреждение:</B> вы действительно хотите удалить принтер
«{printer_name}»?</P>
-<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="delete-printer"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Удалить принтер"></FORM></P>
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="delete-printer"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Удалить принтер"></FORM></P>
</DIV>
{server_is_sharing_printers=0?нет совместного доступа:{printer_is_shared=0?нет совместного доступа:разрешен совместный доступ}})</H2>
<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
<OPTION VALUE="">Обслуживание</OPTION>
<OPTION VALUE="print-test-page">Печать пробной страницы</OPTION>
</FORM>
<FORM METHOD="POST" ACTION="{admin_uri}" NAME="administration">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
<OPTION VALUE="">Администрирование</OPTION>
--></SCRIPT>
<FORM METHOD="POST" ACTION="/admin/" NAME="export_samba">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba">
<H2 CLASS="title">Экспорт принтеров в Samba</H2>
<H2 CLASS="title">Установить параметры по умолчанию для {printer_name}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{HAVE_AUTOCONFIGURE?<INPUT TYPE="SUBMIT" NAME="AUTOCONFIGURE" VALUE="Запрос принтера для параметров по умолчанию">:}
<DIV CLASS="indent">
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{OP}">
<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
{IS_CLASS?<INPUT TYPE="HIDDEN" NAME="IS_CLASS" VALUE="{IS_CLASS}">:}
--></SCRIPT>
<FORM METHOD="POST" ACTION="/admin/" NAME="export_samba">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba">
<H2 CLASS="title">Export Printers to Samba</H2>
<H2 CLASS="title">Set Default Options for {printer_name}</H2>
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
{HAVE_AUTOCONFIGURE?<INPUT TYPE="SUBMIT" NAME="AUTOCONFIGURE" VALUE="Query Printer for Default Options">:}
<DIV CLASS="indent">
<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{OP}">
<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
{IS_CLASS?<INPUT TYPE="HIDDEN" NAME="IS_CLASS" VALUE="{IS_CLASS}">:}
# DO NOT DELETE THIS LINE -- make depend depends on it.
-ipptest.o: ../cups/string.h ../config.h ../cups/cups.h ../cups/ipp.h
-ipptest.o: ../cups/http.h ../cups/versioning.h ../cups/ppd.h ../cups/array.h
-ipptest.o: ../cups/file.h ../cups/language.h ../cups/language.h
-ipptest.o: ../cups/http-private.h ../cups/md5.h ../cups/ipp-private.h
+ipptest.o: ../cups/globals.h ../cups/string.h ../config.h
+ipptest.o: ../cups/http-private.h ../cups/http.h ../cups/versioning.h
+ipptest.o: ../cups/md5.h ../cups/ipp-private.h ../cups/ipp.h ../cups/cups.h
+ipptest.o: ../cups/ppd.h ../cups/array.h ../cups/file.h ../cups/language.h
+ipptest.o: ../cups/i18n.h ../cups/transcode.h
#
# "$Id: Makefile 7871 2008-08-27 21:12:43Z mike $"
#
-# IPP test makefile for the Common UNIX Printing System (CUPS).
+# IPP test makefile for CUPS.
#
-# Copyright 2007-2009 by Apple Inc.
+# Copyright 2007-2010 by Apple Inc.
# Copyright 1997-2006 by Easy Software Products, all rights reserved.
#
# These coded instructions, statements, and computer programs are the
include ../Makedefs
+#
+# Sample test files.
+#
+
+TESTFILES = \
+ ipp-1.1.test \
+ ipp-2.0.test \
+ ipp-2.1.test \
+ testfile.jpg \
+ testfile.pdf \
+ testfile.ps \
+ testfile.txt
+
+
#
# Make all targets...
#
-all: ipptest
+all: ipptest ipptest-static
#
#
clean:
- $(RM) ipptest ipptest.o
+ $(RM) ipptest ipptest.o ipptest-static
#
#
install-data:
+ echo Installing sample ipptest files in $(DATADIR)/ipptest...
+ $(INSTALL_DIR) -m 755 $(DATADIR)/ipptest
+ for file in $(TESTFILES); do \
+ $(INSTALL_DATA) $$file $(DATADIR)/ipptest; \
+ done
#
#
install-exec:
+ echo Installing ipptest in $(BINDIR)...
+ $(INSTALL_DIR) -m 755 $(BINDIR)
+ $(INSTALL_BIN) ipptest $(BINDIR)
+ if test "x$(SYMROOT)" != "x"; then \
+ $(INSTALL_DIR) $(SYMROOT); \
+ cp ipptest $(SYMROOT); \
+ fi
#
# ipptest
#
-ipptest: ipptest.o ../cups/libcups.a
+ipptest: ipptest.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ ipptest.o $(LIBS)
+
+
+#
+# ipptest-static
+#
+
+ipptest-static: ipptest.o ../cups/$(LIBCUPSSTATIC)
echo Linking $@...
- $(CC) $(LDFLAGS) -o ipptest ipptest.o ../cups/libcups.a \
+ $(CC) $(LDFLAGS) -o $@ ipptest.o ../cups/$(LIBCUPSSTATIC) \
$(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
--- /dev/null
+#
+# "$Id$"
+#
+# IPP/1.1 test suite.
+#
+# Copyright 2007-2010 by Apple Inc.
+# Copyright 2001-2006 by Easy Software Products. All rights reserved.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. and are protected by Federal copyright
+# law. Distribution and use rights are outlined in the file "LICENSE.txt"
+# which should have been included with this file. If this file is
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+# Usage:
+#
+# ./ipptest -f filename printer-uri ipp-1.1.test
+#
+
+# Test that a request-id value of 0 is not accepted.
+#
+# Required by: RFC 2911 section 3.1.1
+{
+ NAME "3.1.1: Bad request-id value 0"
+ REQUEST-ID 0
+ OPERATION Get-Printer-Attributes
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+
+ STATUS client-error-bad-request
+ EXPECT !printer-uri-supported
+}
+
+
+# Test that the first two attributes must be attributes-charset and
+# attributes-natural-language.
+#
+# Required by: RFC 2911 section 3.1.4
+{
+ NAME "3.1.4: No Operation Attributes"
+ REQUEST-ID random
+ OPERATION Get-Printer-Attributes
+ GROUP operation-attributes-tag
+
+ STATUS client-error-bad-request
+ EXPECT !printer-uri-supported
+}
+{
+ NAME "3.1.4: attributes-charset"
+ OPERATION Get-Printer-Attributes
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR uri printer-uri $uri
+
+ STATUS client-error-bad-request
+ EXPECT !printer-uri-supported
+}
+{
+ NAME "3.1.4: attributes-natural-language"
+ OPERATION Get-Printer-Attributes
+ GROUP operation-attributes-tag
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+
+ STATUS client-error-bad-request
+ EXPECT !printer-uri-supported
+}
+{
+ NAME "3.1.4: attributes-natural-language + attributes-charset"
+ OPERATION Get-Printer-Attributes
+ GROUP operation-attributes-tag
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR charset attributes-charset utf-8
+ ATTR uri printer-uri $uri
+
+ STATUS client-error-bad-request
+ EXPECT !printer-uri-supported
+}
+{
+ NAME "3.1.4: attributes-charset + attributes-natural-language"
+ OPERATION Get-Printer-Attributes
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+
+ STATUS successful-ok
+ EXPECT printer-uri-supported OF-TYPE uri
+}
+
+
+# Test that bad IPP versions are not supported.
+#
+# Required by: RFC 2911 section 3.1.8
+{
+ # The name of the test...
+ NAME "3.1.8: Unsupported IPP version 0.0"
+ VERSION 0.0
+ OPERATION Get-Printer-Attributes
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+
+ STATUS server-error-version-not-supported
+ EXPECT !printer-uri-supported
+}
+
+
+# Test that printer operations require the printer-uri operation attribute.
+#
+# Required by: RFC 2911 section 3.2
+{
+ NAME "3.2: No printer-uri operation attribute"
+ OPERATION Get-Printer-Attributes
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+
+ STATUS client-error-bad-request
+ EXPECT !printer-uri-supported
+}
+
+
+# Test Print-Job operation
+#
+# Required by: RFC 2911 section 3.2.1
+{
+ NAME "3.2.1: Print-Job Operation"
+ OPERATION Print-Job
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR name job-name $filename
+ ATTR boolean ipp-attribute-fidelity false
+ ATTR name document-name $filename
+ ATTR keyword compression none
+ ATTR mimeMediaType document-format application/octet-stream
+ FILE $filename
+
+ STATUS successful-ok
+ STATUS client-error-document-format-not-supported
+ EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag
+ EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
+ WITH-VALUE >0
+ EXPECT job-state OF-TYPE enum COUNT 1 IN-GROUP job-attributes-tag
+ WITH-VALUE 3,4,5,6,7,8,9
+ EXPECT job-state-reasons OF-TYPE keyword IN-GROUP job-attributes-tag
+ EXPECT ?job-state-message OF-TYPE text IN-GROUP job-attributes-tag
+ EXPECT ?number-of-intervening-jobs OF-TYPE integer
+ IN-GROUP job-attributes-tag WITH-VALUE >-1
+}
+
+# Test Get-Printer-Attributes operation
+#
+# Required by: RFC 2911 section 3.2.5
+{
+ NAME "3.2.5: Get-Printer-Attributes Operation (default)"
+ OPERATION Get-Printer-Attributes
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR mimeMediaType document-format application/octet-stream
+
+ STATUS successful-ok
+
+ # Job template attributes
+ EXPECT ?copies-default OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT ?copies-supported OF-TYPE rangeOfInteger IN-GROUP printer-attributes-tag
+ EXPECT ?finishings-default OF-TYPE enum IN-GROUP printer-attributes-tag
+ EXPECT ?finishings-supported OF-TYPE enum IN-GROUP printer-attributes-tag WITH-VALUE 3
+ EXPECT ?job-hold-until-default OF-TYPE keyword|name IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?job-hold-until-supported OF-TYPE keyword|name IN-GROUP printer-attributes-tag WITH-VALUE no-hold
+ EXPECT ?job-priority-default OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE >0,<101
+ EXPECT ?job-priority-supported OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE >0,<101
+ EXPECT ?job-sheets-default OF-TYPE keyword|name IN-GROUP printer-attributes-tag
+ EXPECT ?job-sheets-supported OF-TYPE keyword|name IN-GROUP printer-attributes-tag WITH-VALUE none
+ EXPECT ?media-default OF-TYPE keyword|name IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?media-ready OF-TYPE keyword|name IN-GROUP printer-attributes-tag
+ EXPECT ?media-supported OF-TYPE keyword|name IN-GROUP printer-attributes-tag
+ EXPECT ?multiple-document-handling-default OF-TYPE keyword IN-GROUP printer-attributes-tag WITH-VALUE "/^(single-document|separate-documents-uncollated-copies|separate-documents-collated-copies|single-document-new-sheet)$$/"
+ EXPECT ?multiple-document-handling-supported OF-TYPE keyword IN-GROUP printer-attributes-tag WITH-VALUE "/^(single-document|separate-documents-uncollated-copies|separate-documents-collated-copies|single-document-new-sheet)$$/"
+ EXPECT ?number-up-default OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT ?number-up-supported OF-TYPE integer|rangeOfInteger IN-GROUP printer-attributes-tag WITH-VALUE >0
+ EXPECT ?number-up-supported WITH-VALUE 1
+ EXPECT ?orientation-requested-default OF-TYPE enum,no-value IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE no-value,3,4,5,6
+ EXPECT ?orientation-requested-supported OF-TYPE enum IN-GROUP printer-attributes-tag WITH-VALUE 3,4,5,6
+ EXPECT ?pages-ranges-supported OF-TYPE boolean IN-GROUP printer-attributes-tag
+ EXPECT ?print-quality-default OF-TYPE enum IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE 3,4,5
+ EXPECT ?print-quality-supported OF-TYPE enum IN-GROUP printer-attributes-tag WITH-VALUE 3,4,5
+ EXPECT ?printer-resolution-default OF-TYPE resolution IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?printer-resolution-supported OF-TYPE resolution IN-GROUP printer-attributes-tag
+ EXPECT ?sides-default OF-TYPE keyword IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "/^(one-sided|two-sided-long-edge|two-sided-short-edge)$$/"
+ EXPECT ?sides-supported OF-TYPE keyword IN-GROUP printer-attributes-tag WITH-VALUE "/^(one-sided|two-sided-long-edge|two-sided-short-edge)$$/"
+
+ # Printer description attributes
+ EXPECT ?color-supported OF-TYPE boolean IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?job-impressions-supported OF-TYPE rangeOfInteger IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?job-k-octets-supported OF-TYPE rangeOfInteger IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?job-media-sheets-supported OF-TYPE rangeOfInteger IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?multiple-document-jobs-supported OF-TYPE boolean IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?multiple-operation-time-out OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT ?pages-per-minute OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?pages-per-minute-color OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?printer-driver-installer OF-TYPE uri IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?printer-info OF-TYPE text IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "/^.{0,127}$$/"
+ EXPECT ?printer-location OF-TYPE text IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "/^.{0,127}$$/"
+ EXPECT ?printer-make-and-model OF-TYPE text IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "/^.{0,127}$$/"
+ EXPECT ?printer-message-from-operator OF-TYPE text IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "/^.{0,127}$$/"
+ EXPECT ?printer-more-info OF-TYPE uri IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?printer-more-info-manufacturer OF-TYPE uri IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?printer-state-message OF-TYPE text IN-GROUP printer-attributes-tag
+ EXPECT ?reference-uri-schemes-supported OF-TYPE uriScheme IN-GROUP printer-attributes-tag
+ EXPECT charset-configured OF-TYPE charset IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT charset-supported OF-TYPE charset IN-GROUP printer-attributes-tag WITH-VALUE utf-8
+ EXPECT compression-supported OF-TYPE keyword IN-GROUP printer-attributes-tag WITH-VALUE none
+ EXPECT document-format-default OF-TYPE mimeMediaType IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT document-format-supported OF-TYPE mimeMediaType IN-GROUP printer-attributes-tag
+ EXPECT generated-natural-language-supported OF-TYPE naturalLanguage IN-GROUP printer-attributes-tag
+ EXPECT ipp-versions-supported OF-TYPE keyword IN-GROUP printer-attributes-tag WITH-VALUE 1.1
+ EXPECT natural-language-configured OF-TYPE naturalLanguage IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT operations-supported OF-TYPE enum IN-GROUP printer-attributes-tag WITH-VALUE 0x0002 # Print-Job
+ # Not requiring 0x0004 Validate-Job since it is deprecated
+ EXPECT operations-supported WITH-VALUE 0x0008 # Cancel-Job
+ EXPECT operations-supported WITH-VALUE 0x0009 # Get-Job-Attributes
+ EXPECT operations-supported WITH-VALUE 0x000a # Get-Jobs
+ EXPECT operations-supported WITH-VALUE 0x000b # Get-Printer-Attributes
+ EXPECT pdl-override-supported OF-TYPE keyword IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT printer-is-accepting-jobs OF-TYPE boolean IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT printer-name OF-TYPE name IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "/^.{1,127}$$/"
+ EXPECT printer-state OF-TYPE enum IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE 3,4,5
+ EXPECT printer-state-reasons OF-TYPE keyword IN-GROUP printer-attributes-tag
+ EXPECT printer-up-time OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT printer-uri-supported OF-TYPE uri IN-GROUP printer-attributes-tag SAME-COUNT-AS uri-security-supported
+ EXPECT queued-job-count OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT uri-authentication-supported OF-TYPE keyword IN-GROUP printer-attributes-tag
+ EXPECT uri-security-supported OF-TYPE keyword IN-GROUP printer-attributes-tag SAME-COUNT-AS uri-authentication-supported
+}
+
+
+# Test Get-Printer-Attributes operation with requested-attributes
+#
+# Required by: RFC 2911 section 3.2.5
+{
+ NAME "3.2.5: Get-Printer-Attributes Operation (requested-attributes)"
+ OPERATION Get-Printer-Attributes
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR mimeMediaType document-format application/octet-stream
+ ATTR keyword requested-attributes printer-uri-supported
+
+ STATUS successful-ok
+
+ EXPECT printer-uri-supported OF-TYPE uri IN-GROUP printer-attributes-tag
+ EXPECT !printer-name
+}
+
+
+# Test Get-Jobs operation
+#
+# Required by: RFC 2911 section 3.2.6
+{
+ NAME "3.2.6: Get-Jobs Operation (default)"
+ OPERATION Get-Jobs
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+
+ STATUS successful-ok
+ EXPECT job-id OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT job-uri OF-TYPE uri IN-GROUP job-attributes-tag COUNT 1
+ EXPECT !job-printer-uri
+ EXPECT !job-more-info
+ EXPECT !job-name
+ EXPECT !job-originating-user-name
+ EXPECT !job-state
+ EXPECT !job-state-reasons
+ EXPECT !job-state-message
+ EXPECT !job-detailed-status-messages
+ EXPECT !number-of-documents
+ EXPECT !output-device-assigned
+ EXPECT !time-at-creation
+ EXPECT !time-at-processing
+ EXPECT !time-at-completed
+ EXPECT !job-printer-up-time
+ EXPECT !date-time-at-creation
+ EXPECT !date-time-at-processing
+ EXPECT !date-time-at-completed
+ EXPECT !number-of-intervening-jobs
+ EXPECT !job-message-from-operator
+ EXPECT !job-k-octets
+ EXPECT !job-impressions
+ EXPECT !job-media-sheets
+ EXPECT !job-k-octets-processed
+ EXPECT !job-impressions-completed
+ EXPECT !job-media-sheets-completed
+
+ EXPECT !copies
+ EXPECT !finishings
+ EXPECT !job-hold-until
+ EXPECT !job-priority
+ EXPECT !job-sheets
+ EXPECT !media
+ EXPECT !multiple-document-handling
+ EXPECT !number-up
+ EXPECT !orientation-requested
+ EXPECT !pages-ranges
+ EXPECT !print-quality
+ EXPECT !printer-resolution
+ EXPECT !sides
+}
+
+
+# Test Get-Jobs operation
+#
+# Required by: RFC 2911 section 3.2.6
+{
+ NAME "3.2.6: Get-Jobs Operation (requested-attributes)"
+ OPERATION Get-Jobs
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR keyword requested-attributes all
+
+ STATUS successful-ok
+ EXPECT job-id OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT job-uri OF-TYPE uri IN-GROUP job-attributes-tag COUNT 1
+ EXPECT job-printer-uri OF-TYPE uri IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-more-info OF-TYPE uri IN-GROUP job-attributes-tag COUNT 1
+ EXPECT job-name OF-TYPE name IN-GROUP job-attributes-tag COUNT 1
+ EXPECT job-originating-user-name OF-TYPE name IN-GROUP job-attributes-tag COUNT 1
+ EXPECT job-state OF-TYPE enum IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE >2,<10
+ EXPECT job-state-reasons OF-TYPE keyword IN-GROUP job-attributes-tag
+ EXPECT ?job-state-message OF-TYPE text IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-detailed-status-messages OF-TYPE text IN-GROUP job-attributes-tag
+ EXPECT ?number-of-documents OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?output-device-assigned OF-TYPE name IN-GROUP job-attributes-tag COUNT 1
+ EXPECT time-at-creation OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE no-value,>-1
+ EXPECT time-at-processing OF-TYPE no-value,integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE no-value,>-1
+ EXPECT time-at-completed OF-TYPE no-value,integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE no-value,>-1
+ EXPECT job-printer-up-time OF-TYPE no-value,integer IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?date-time-at-creation OF-TYPE no-value,dateTime IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?date-time-at-processing OF-TYPE no-value,dateTime IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?date-time-at-completed OF-TYPE no-value,dateTime IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?number-of-intervening-jobs OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-message-from-operator OF-TYPE text IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-k-octets OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-impressions OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-media-sheets OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-k-octets-processed OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-impressions-completed OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-media-sheets-completed OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1
+
+ EXPECT ?copies OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT ?finishings OF-TYPE enum IN-GROUP job-attributes-tag
+ EXPECT ?job-hold-until OF-TYPE keyword|name IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-priority OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE >0,<101
+ EXPECT ?job-sheets OF-TYPE keyword|name IN-GROUP job-attributes-tag
+ EXPECT ?media OF-TYPE keyword|name IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?multiple-document-handling OF-TYPE keyword IN-GROUP job-attributes-tag WITH-VALUE "/^(single-document|separate-documents-uncollated-copies|separate-documents-collated-copies|single-document-new-sheet)$$/"
+ EXPECT ?number-up OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT ?orientation-requested OF-TYPE enum IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE 3,4,5,6
+ EXPECT ?pages-ranges OF-TYPE rangeOfInteger IN-GROUP job-attributes-tag
+ EXPECT ?print-quality OF-TYPE enum IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE 3,4,5
+ EXPECT ?printer-resolution OF-TYPE resolution IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?sides OF-TYPE keyword IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE "/^(one-sided|two-sided-long-edge|two-sided-short-edge)$$/"
+}
+
+
+# Test Get-Jobs operation
+#
+# Required by: RFC 2911 section 3.2.6
+{
+ NAME "3.2.6: Get-Jobs Operation (my-jobs)"
+ OPERATION Get-Jobs
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR boolean my-jobs true
+
+ STATUS successful-ok
+ EXPECT job-id OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT job-uri OF-TYPE uri IN-GROUP job-attributes-tag COUNT 1
+ EXPECT !job-printer-uri
+ EXPECT !job-more-info
+ EXPECT !job-name
+ EXPECT !job-originating-user-name
+ EXPECT !job-state
+ EXPECT !job-state-reasons
+ EXPECT !job-state-message
+ EXPECT !job-detailed-status-messages
+ EXPECT !number-of-documents
+ EXPECT !output-device-assigned
+ EXPECT !time-at-creation
+ EXPECT !time-at-processing
+ EXPECT !time-at-completed
+ EXPECT !job-printer-up-time
+ EXPECT !date-time-at-creation
+ EXPECT !date-time-at-processing
+ EXPECT !date-time-at-completed
+ EXPECT !number-of-intervening-jobs
+ EXPECT !job-message-from-operator
+ EXPECT !job-k-octets
+ EXPECT !job-impressions
+ EXPECT !job-media-sheets
+ EXPECT !job-k-octets-processed
+ EXPECT !job-impressions-completed
+ EXPECT !job-media-sheets-completed
+
+ EXPECT !copies
+ EXPECT !finishings
+ EXPECT !job-hold-until
+ EXPECT !job-priority
+ EXPECT !job-sheets
+ EXPECT !media
+ EXPECT !multiple-document-handling
+ EXPECT !number-up
+ EXPECT !orientation-requested
+ EXPECT !pages-ranges
+ EXPECT !print-quality
+ EXPECT !printer-resolution
+ EXPECT !sides
+}
+
+
+# Test Get-Jobs operation
+#
+# Required by: RFC 2911 section 3.2.6
+{
+ NAME "3.2.6: Get-Jobs Operation (my-jobs different user)"
+ OPERATION Get-Jobs
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name not-$user
+ ATTR boolean my-jobs true
+
+ STATUS successful-ok
+ EXPECT !job-id
+ EXPECT !job-uri
+ EXPECT !job-printer-uri
+ EXPECT !job-more-info
+ EXPECT !job-name
+ EXPECT !job-originating-user-name
+ EXPECT !job-state
+ EXPECT !job-state-reasons
+ EXPECT !job-state-message
+ EXPECT !job-detailed-status-messages
+ EXPECT !number-of-documents
+ EXPECT !output-device-assigned
+ EXPECT !time-at-creation
+ EXPECT !time-at-processing
+ EXPECT !time-at-completed
+ EXPECT !job-printer-up-time
+ EXPECT !date-time-at-creation
+ EXPECT !date-time-at-processing
+ EXPECT !date-time-at-completed
+ EXPECT !number-of-intervening-jobs
+ EXPECT !job-message-from-operator
+ EXPECT !job-k-octets
+ EXPECT !job-impressions
+ EXPECT !job-media-sheets
+ EXPECT !job-k-octets-processed
+ EXPECT !job-impressions-completed
+ EXPECT !job-media-sheets-completed
+
+ EXPECT !copies
+ EXPECT !finishings
+ EXPECT !job-hold-until
+ EXPECT !job-priority
+ EXPECT !job-sheets
+ EXPECT !media
+ EXPECT !multiple-document-handling
+ EXPECT !number-up
+ EXPECT !orientation-requested
+ EXPECT !pages-ranges
+ EXPECT !print-quality
+ EXPECT !printer-resolution
+ EXPECT !sides
+}
+
+
+# Test Get-Jobs operation
+#
+# Required by: RFC 2911 section 3.2.6
+{
+ NAME "3.2.6: Get-Jobs Operation (which-jobs=not-completed)"
+ OPERATION Get-Jobs
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR keyword which-jobs not-completed
+
+ STATUS successful-ok
+ EXPECT job-id OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT job-uri OF-TYPE uri IN-GROUP job-attributes-tag COUNT 1
+ EXPECT !job-printer-uri
+ EXPECT !job-more-info
+ EXPECT !job-name
+ EXPECT !job-originating-user-name
+ EXPECT !job-state
+ EXPECT !job-state-reasons
+ EXPECT !job-state-message
+ EXPECT !job-detailed-status-messages
+ EXPECT !number-of-documents
+ EXPECT !output-device-assigned
+ EXPECT !time-at-creation
+ EXPECT !time-at-processing
+ EXPECT !time-at-completed
+ EXPECT !job-printer-up-time
+ EXPECT !date-time-at-creation
+ EXPECT !date-time-at-processing
+ EXPECT !date-time-at-completed
+ EXPECT !number-of-intervening-jobs
+ EXPECT !job-message-from-operator
+ EXPECT !job-k-octets
+ EXPECT !job-impressions
+ EXPECT !job-media-sheets
+ EXPECT !job-k-octets-processed
+ EXPECT !job-impressions-completed
+ EXPECT !job-media-sheets-completed
+
+ EXPECT !copies
+ EXPECT !finishings
+ EXPECT !job-hold-until
+ EXPECT !job-priority
+ EXPECT !job-sheets
+ EXPECT !media
+ EXPECT !multiple-document-handling
+ EXPECT !number-up
+ EXPECT !orientation-requested
+ EXPECT !pages-ranges
+ EXPECT !print-quality
+ EXPECT !printer-resolution
+ EXPECT !sides
+}
+
+
+
+# Test Get-Jobs operation
+#
+# Required by: RFC 2911 section 3.2.6
+{
+ NAME "3.2.6: Get-Jobs Operation (which-jobs=completed)"
+ OPERATION Get-Jobs
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR keyword which-jobs completed
+ DELAY 10
+
+ STATUS successful-ok
+ EXPECT job-id OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT job-uri OF-TYPE uri IN-GROUP job-attributes-tag COUNT 1
+ EXPECT !job-printer-uri
+ EXPECT !job-more-info
+ EXPECT !job-name
+ EXPECT !job-originating-user-name
+ EXPECT !job-state
+ EXPECT !job-state-reasons
+ EXPECT !job-state-message
+ EXPECT !job-detailed-status-messages
+ EXPECT !number-of-documents
+ EXPECT !output-device-assigned
+ EXPECT !time-at-creation
+ EXPECT !time-at-processing
+ EXPECT !time-at-completed
+ EXPECT !job-printer-up-time
+ EXPECT !date-time-at-creation
+ EXPECT !date-time-at-processing
+ EXPECT !date-time-at-completed
+ EXPECT !number-of-intervening-jobs
+ EXPECT !job-message-from-operator
+ EXPECT !job-k-octets
+ EXPECT !job-impressions
+ EXPECT !job-media-sheets
+ EXPECT !job-k-octets-processed
+ EXPECT !job-impressions-completed
+ EXPECT !job-media-sheets-completed
+
+ EXPECT !copies
+ EXPECT !finishings
+ EXPECT !job-hold-until
+ EXPECT !job-priority
+ EXPECT !job-sheets
+ EXPECT !media
+ EXPECT !multiple-document-handling
+ EXPECT !number-up
+ EXPECT !orientation-requested
+ EXPECT !pages-ranges
+ EXPECT !print-quality
+ EXPECT !printer-resolution
+ EXPECT !sides
+}
+
+
+# Test Cancel-Job operation
+#
+# Required by: RFC 2911 section 3.3.3
+{
+ NAME "3.3.3: Cancel-Job Operation (completed job)"
+ OPERATION Cancel-Job
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR integer job-id $job-id
+ ATTR name requesting-user-name $user
+
+ STATUS client-error-not-possible
+}
+
+
+# Test Print-Job operation
+#
+# Required by: RFC 2911 section 3.2.1
+{
+ NAME "3.2.1: Print-Job Operation"
+ OPERATION Print-Job
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR name job-name $filename
+ ATTR boolean ipp-attribute-fidelity false
+ ATTR name document-name $filename
+ ATTR keyword compression none
+ ATTR mimeMediaType document-format application/octet-stream
+ FILE $filename
+
+ STATUS successful-ok
+ STATUS client-error-document-format-not-supported
+ EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag
+ EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
+ WITH-VALUE >0
+ EXPECT job-state OF-TYPE enum COUNT 1 IN-GROUP job-attributes-tag
+ WITH-VALUE 3,4,5,6,7,8,9
+ EXPECT job-state-reasons OF-TYPE keyword IN-GROUP job-attributes-tag
+ EXPECT ?job-state-message OF-TYPE text IN-GROUP job-attributes-tag
+ EXPECT ?number-of-intervening-jobs OF-TYPE integer
+ IN-GROUP job-attributes-tag WITH-VALUE >-1
+}
+
+
+# Test Cancel-Job operation
+#
+# Required by: RFC 2911 section 3.3.3
+{
+ NAME "3.3.3: Cancel-Job Operation (pending/processing job)"
+ OPERATION Cancel-Job
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR integer job-id $job-id
+ ATTR name requesting-user-name $user
+
+ STATUS successful-ok
+}
+
+
+# Test Get-Job-Attributes operation
+#
+# Required by: RFC 2911 section 3.3.4
+{
+ NAME "3.3.4: Get-Job-Attributes Operation"
+ OPERATION Get-Job-Attributes
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR integer job-id $job-id
+ ATTR name requesting-user-name $user
+
+ STATUS successful-ok
+ EXPECT job-id OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT job-uri OF-TYPE uri IN-GROUP job-attributes-tag COUNT 1
+ EXPECT job-printer-uri OF-TYPE uri IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-more-info OF-TYPE uri IN-GROUP job-attributes-tag COUNT 1
+ EXPECT job-name OF-TYPE name IN-GROUP job-attributes-tag COUNT 1
+ EXPECT job-originating-user-name OF-TYPE name IN-GROUP job-attributes-tag COUNT 1
+ EXPECT job-state OF-TYPE enum IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE >2,<10
+ EXPECT job-state-reasons OF-TYPE keyword IN-GROUP job-attributes-tag
+ EXPECT ?job-state-message OF-TYPE text IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-detailed-status-messages OF-TYPE text IN-GROUP job-attributes-tag
+ EXPECT ?number-of-documents OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?output-device-assigned OF-TYPE name IN-GROUP job-attributes-tag COUNT 1
+ EXPECT time-at-creation OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE no-value,>-1
+ EXPECT time-at-processing OF-TYPE no-value,integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE no-value,>-1
+ EXPECT time-at-completed OF-TYPE no-value,integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE no-value,>-1
+ EXPECT job-printer-up-time OF-TYPE no-value,integer IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?date-time-at-creation OF-TYPE no-value,dateTime IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?date-time-at-processing OF-TYPE no-value,dateTime IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?date-time-at-completed OF-TYPE no-value,dateTime IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?number-of-intervening-jobs OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-message-from-operator OF-TYPE text IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-k-octets OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-impressions OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-media-sheets OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-k-octets-processed OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-impressions-completed OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-media-sheets-completed OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1
+
+ EXPECT ?copies OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT ?finishings OF-TYPE enum IN-GROUP job-attributes-tag
+ EXPECT ?job-hold-until OF-TYPE keyword|name IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-priority OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE >0,<101
+ EXPECT ?job-sheets OF-TYPE keyword|name IN-GROUP job-attributes-tag
+ EXPECT ?media OF-TYPE keyword|name IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?multiple-document-handling OF-TYPE keyword IN-GROUP job-attributes-tag WITH-VALUE "/^(single-document|separate-documents-uncollated-copies|separate-documents-collated-copies|single-document-new-sheet)$$/"
+ EXPECT ?number-up OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT ?orientation-requested OF-TYPE enum IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE 3,4,5,6
+ EXPECT ?pages-ranges OF-TYPE rangeOfInteger IN-GROUP job-attributes-tag
+ EXPECT ?print-quality OF-TYPE enum IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE 3,4,5
+ EXPECT ?printer-resolution OF-TYPE resolution IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?sides OF-TYPE keyword IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE "/^(one-sided|two-sided-long-edge|two-sided-short-edge)$$/"
+}
+
+
+#
+# End of "$Id$".
+#
--- /dev/null
+#
+# "$Id$"
+#
+# IPP/2.0 test suite.
+#
+# Copyright 2007-2010 by Apple Inc.
+# Copyright 2001-2006 by Easy Software Products. All rights reserved.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. and are protected by Federal copyright
+# law. Distribution and use rights are outlined in the file "LICENSE.txt"
+# which should have been included with this file. If this file is
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+# Usage:
+#
+# ./ipptest -V 2.0 -f filename printer-uri ipp-2.0.test
+#
+
+# Do all of the IPP/1.1 tests as an IPP/2.0 client
+#
+# Required by: PWG 5100.10 section 4.3
+INCLUDE "ipp-1.1.test"
+
+
+# Test required printer description attribute support.
+#
+# Required by: PWG 5100.10 section 6.2
+{
+ NAME "PWG 5100.10 section 6.2 - Required Printer Description Attributes"
+ OPERATION Get-Printer-Attributes
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR mimeMediaType document-format application/octet-stream
+
+ STATUS successful-ok
+
+ # Job template attributes
+ EXPECT ?media-default OF-TYPE keyword|name IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?media-ready OF-TYPE keyword|name IN-GROUP printer-attributes-tag
+ EXPECT ?media-supported OF-TYPE keyword|name IN-GROUP printer-attributes-tag
+ EXPECT ?multiple-document-handling-default OF-TYPE keyword IN-GROUP printer-attributes-tag WITH-VALUE "/^(single-document|separate-documents-uncollated-copies|separate-documents-collated-copies|single-document-new-sheet)$$/"
+ EXPECT ?multiple-document-handling-supported OF-TYPE keyword IN-GROUP printer-attributes-tag WITH-VALUE "/^(single-document|separate-documents-uncollated-copies|separate-documents-collated-copies|single-document-new-sheet)$$/"
+ EXPECT ?number-up-default OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT ?number-up-supported OF-TYPE integer|rangeOfInteger IN-GROUP printer-attributes-tag WITH-VALUE >0
+ EXPECT ?number-up-supported WITH-VALUE 1
+ EXPECT ?orientation-requested-default OF-TYPE enum IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE 3,4,5,6
+ EXPECT ?orientation-requested-supported OF-TYPE enum IN-GROUP printer-attributes-tag WITH-VALUE 3,4,5,6
+ EXPECT ?pages-ranges-supported OF-TYPE boolean IN-GROUP printer-attributes-tag
+ EXPECT ?print-quality-default OF-TYPE enum IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE 3,4,5
+ EXPECT ?print-quality-supported OF-TYPE enum IN-GROUP printer-attributes-tag WITH-VALUE 3,4,5
+ EXPECT ?printer-resolution-default OF-TYPE resolution IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?printer-resolution-supported OF-TYPE resolution IN-GROUP printer-attributes-tag
+ EXPECT ?sides-default OF-TYPE keyword IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "/^(one-sided|two-sided-long-edge|two-sided-short-edge)$$/"
+ EXPECT ?sides-supported OF-TYPE keyword IN-GROUP printer-attributes-tag WITH-VALUE "/^(one-sided|two-sided-long-edge|two-sided-short-edge)$$/"
+
+ # Printer description attributes
+ EXPECT ?color-supported OF-TYPE boolean IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?job-impressions-supported OF-TYPE rangeOfInteger IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?job-k-octets-supported OF-TYPE rangeOfInteger IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?job-media-sheets-supported OF-TYPE rangeOfInteger IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?multiple-document-jobs-supported OF-TYPE boolean IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?multiple-operation-time-out OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT ?pages-per-minute OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?pages-per-minute-color OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?printer-driver-installer OF-TYPE uri IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?printer-info OF-TYPE text IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "/^.{0,127}$$/"
+ EXPECT ?printer-location OF-TYPE text IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "/^.{0,127}$$/"
+ EXPECT ?printer-make-and-model OF-TYPE text IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "/^.{0,127}$$/"
+ EXPECT ?printer-message-from-operator OF-TYPE text IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "/^.{0,127}$$/"
+ EXPECT ?printer-more-info OF-TYPE uri IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?printer-more-info-manufacturer OF-TYPE uri IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?printer-state-message OF-TYPE text IN-GROUP printer-attributes-tag
+ EXPECT ?reference-uri-schemes-supported OF-TYPE uriScheme IN-GROUP printer-attributes-tag
+ EXPECT charset-configured OF-TYPE charset IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT charset-supported OF-TYPE charset IN-GROUP printer-attributes-tag WITH-VALUE utf-8
+ EXPECT compression-supported OF-TYPE keyword IN-GROUP printer-attributes-tag WITH-VALUE none
+ EXPECT document-format-default OF-TYPE mimeMediaType IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT document-format-supported OF-TYPE mimeMediaType IN-GROUP printer-attributes-tag
+ EXPECT generated-natural-language-supported OF-TYPE naturalLanguage IN-GROUP printer-attributes-tag
+ EXPECT ipp-versions-supported OF-TYPE keyword IN-GROUP printer-attributes-tag WITH-VALUE 1.1
+ EXPECT natural-language-configured OF-TYPE naturalLanguage IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT operations-supported OF-TYPE enum IN-GROUP printer-attributes-tag WITH-VALUE 0x0002 # Print-Job
+ # Not requiring 0x0004 Validate-Job since it is deprecated
+ EXPECT operations-supported WITH-VALUE 0x0008 # Cancel-Job
+ EXPECT operations-supported WITH-VALUE 0x0009 # Get-Job-Attributes
+ EXPECT operations-supported WITH-VALUE 0x000A # Get-Jobs
+ EXPECT operations-supported WITH-VALUE 0x000B # Get-Printer-Attributes
+ EXPECT pdl-override-supported OF-TYPE keyword IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT printer-is-accepting-jobs OF-TYPE boolean IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT printer-name OF-TYPE name IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "/^.{1,127}$$/"
+ EXPECT printer-state OF-TYPE enum IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE 3,4,5
+ EXPECT printer-state-reasons OF-TYPE keyword IN-GROUP printer-attributes-tag
+ EXPECT printer-up-time OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT printer-uri-supported OF-TYPE uri IN-GROUP printer-attributes-tag SAME-COUNT-AS uri-security-supported
+ EXPECT queued-job-count OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT uri-authentication-supported OF-TYPE keyword IN-GROUP printer-attributes-tag
+ EXPECT uri-security-supported OF-TYPE keyword IN-GROUP printer-attributes-tag SAME-COUNT-AS uri-authentication-supported
+}
+
+
+#
+# End of "$Id$".
+#
--- /dev/null
+#
+# "$Id$"
+#
+# IPP/2.1 test suite.
+#
+# Copyright 2007-2010 by Apple Inc.
+# Copyright 2001-2006 by Easy Software Products. All rights reserved.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. and are protected by Federal copyright
+# law. Distribution and use rights are outlined in the file "LICENSE.txt"
+# which should have been included with this file. If this file is
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+# Usage:
+#
+# ./ipptest -V 2.1 -f filename printer-uri ipp-2.0.test
+#
+
+# Do all of the IPP/1.1 and IPP/2.0 tests as an IPP/2.1 client
+INCLUDE "ipp-2.0.test"
+
+
+# Test required printer description attribute support.
+#
+# Required by: PWG 5100.10 section 6.3
+{
+ NAME "PWG 5100.10 section 6.3 - Required Printer Description Attributes"
+ OPERATION Get-Printer-Attributes
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR mimeMediaType document-format application/octet-stream
+
+ STATUS successful-ok
+
+ # Job template attributes
+ EXPECT ?media-default OF-TYPE keyword|name IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?media-ready OF-TYPE keyword|name IN-GROUP printer-attributes-tag
+ EXPECT ?media-supported OF-TYPE keyword|name IN-GROUP printer-attributes-tag
+ EXPECT ?multiple-document-handling-default OF-TYPE keyword IN-GROUP printer-attributes-tag WITH-VALUE "/^(single-document|separate-documents-uncollated-copies|separate-documents-collated-copies|single-document-new-sheet)$$/"
+ EXPECT ?multiple-document-handling-supported OF-TYPE keyword IN-GROUP printer-attributes-tag WITH-VALUE "/^(single-document|separate-documents-uncollated-copies|separate-documents-collated-copies|single-document-new-sheet)$$/"
+ EXPECT ?number-up-default OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT ?number-up-supported OF-TYPE integer|rangeOfInteger IN-GROUP printer-attributes-tag WITH-VALUE >0
+ EXPECT ?number-up-supported WITH-VALUE 1
+ EXPECT ?orientation-requested-default OF-TYPE enum IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE 3,4,5,6
+ EXPECT ?orientation-requested-supported OF-TYPE enum IN-GROUP printer-attributes-tag WITH-VALUE 3,4,5,6
+ EXPECT ?pages-ranges-supported OF-TYPE boolean IN-GROUP printer-attributes-tag
+ EXPECT ?print-quality-default OF-TYPE enum IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE 3,4,5
+ EXPECT ?print-quality-supported OF-TYPE enum IN-GROUP printer-attributes-tag WITH-VALUE 3,4,5
+ EXPECT ?printer-resolution-default OF-TYPE resolution IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?printer-resolution-supported OF-TYPE resolution IN-GROUP printer-attributes-tag
+ EXPECT ?sides-default OF-TYPE keyword IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "/^(one-sided|two-sided-long-edge|two-sided-short-edge)$$/"
+ EXPECT ?sides-supported OF-TYPE keyword IN-GROUP printer-attributes-tag WITH-VALUE "/^(one-sided|two-sided-long-edge|two-sided-short-edge)$$/"
+
+ # Printer description attributes
+ EXPECT ?color-supported OF-TYPE boolean IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?job-impressions-supported OF-TYPE rangeOfInteger IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?job-k-octets-supported OF-TYPE rangeOfInteger IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?job-media-sheets-supported OF-TYPE rangeOfInteger IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?multiple-document-jobs-supported OF-TYPE boolean IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?multiple-operation-time-out OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT ?pages-per-minute OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?pages-per-minute-color OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?printer-driver-installer OF-TYPE uri IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?printer-info OF-TYPE text IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "/^.{0,127}$$/"
+ EXPECT ?printer-location OF-TYPE text IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "/^.{0,127}$$/"
+ EXPECT ?printer-make-and-model OF-TYPE text IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "/^.{0,127}$$/"
+ EXPECT ?printer-message-from-operator OF-TYPE text IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "/^.{0,127}$$/"
+ EXPECT ?printer-more-info OF-TYPE uri IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?printer-more-info-manufacturer OF-TYPE uri IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?printer-state-message OF-TYPE text IN-GROUP printer-attributes-tag
+ EXPECT ?reference-uri-schemes-supported OF-TYPE uriScheme IN-GROUP printer-attributes-tag
+ EXPECT charset-configured OF-TYPE charset IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT charset-supported OF-TYPE charset IN-GROUP printer-attributes-tag WITH-VALUE utf-8
+ EXPECT compression-supported OF-TYPE keyword IN-GROUP printer-attributes-tag WITH-VALUE none
+ EXPECT document-format-default OF-TYPE mimeMediaType IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT document-format-supported OF-TYPE mimeMediaType IN-GROUP printer-attributes-tag
+ EXPECT generated-natural-language-supported OF-TYPE naturalLanguage IN-GROUP printer-attributes-tag
+ EXPECT ipp-versions-supported OF-TYPE keyword IN-GROUP printer-attributes-tag WITH-VALUE 1.1
+ EXPECT natural-language-configured OF-TYPE naturalLanguage IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT operations-supported OF-TYPE enum IN-GROUP printer-attributes-tag WITH-VALUE 0x0002 # Print-Job
+ # Not requiring 0x0004 Validate-Job since it is deprecated
+ EXPECT operations-supported WITH-VALUE 0x0008 # Cancel-Job
+ EXPECT operations-supported WITH-VALUE 0x0009 # Get-Job-Attributes
+ EXPECT operations-supported WITH-VALUE 0x000A # Get-Jobs
+ EXPECT operations-supported WITH-VALUE 0x000B # Get-Printer-Attributes
+ EXPECT pdl-override-supported OF-TYPE keyword IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT printer-is-accepting-jobs OF-TYPE boolean IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT printer-name OF-TYPE name IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "/^.{1,127}$$/"
+ EXPECT printer-state OF-TYPE enum IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE 3,4,5
+ EXPECT printer-state-reasons OF-TYPE keyword IN-GROUP printer-attributes-tag
+ EXPECT printer-up-time OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT printer-uri-supported OF-TYPE uri IN-GROUP printer-attributes-tag SAME-COUNT-AS uri-security-supported
+ EXPECT queued-job-count OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT uri-authentication-supported OF-TYPE keyword IN-GROUP printer-attributes-tag
+ EXPECT uri-security-supported OF-TYPE keyword IN-GROUP printer-attributes-tag SAME-COUNT-AS uri-authentication-supported
+}
+
+
+#
+# End of "$Id$".
+#
/*
- * "$Id: ipptest.c 7847 2008-08-19 04:22:14Z mike $"
+ * "$Id: ipptest.c 9000 2010-02-24 06:29:38Z mike $"
*
* IPP test command for the Common UNIX Printing System (CUPS).
*
- * Copyright 2007-2009 by Apple Inc.
+ * Copyright 2007-2010 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products.
*
* These coded instructions, statements, and computer programs are the
*
* Contents:
*
- * main() - Parse options and do tests.
- * do_tests() - Do tests as specified in the test file.
- * expect_matches() - Return true if the tag matches the specification.
- * get_token() - Get a token from a file.
- * print_attr() - Print an attribute on the screen.
- * print_col() - Print a collection attribute on the screen.
- * usage() - Show program usage.
+ * main() - Parse options and do tests.
+ * compare_vars() - Compare two variables.
+ * do_tests() - Do tests as specified in the test file.
+ * expand_variables() - Expand variables in a string.
+ * expect_matches() - Return true if the tag matches the specification.
+ * get_collection() - Get a collection value from the current test file.
+ * get_filename() - Get a filename based on the current test file.
+ * get_token() - Get a token from a file.
+ * get_variable() - Get the value of a variable.
+ * iso_date() - Return an ISO 8601 date/time string for the given IPP
+ * dateTime value.
+ * print_attr() - Print an attribute on the screen.
+ * print_col() - Print a collection attribute on the screen.
+ * print_fatal_error() - Print a fatal error message.
+ * print_test_error() - Print a test error message.
+ * print_xml_header() - Print a standard XML plist header.
+ * print_xml_string() - Print an XML string with escaping.
+ * print_xml_trailer() - Print the XML trailer with success/fail value.
+ * set_variable() - Set a variable value.
+ * usage() - Show program usage.
+ * validate_attr() - Determine whether an attribute is valid.
+ * with_value() - Test a WITH-VALUE predicate.
*/
/*
#include <stdio.h>
#include <stdlib.h>
-#include <cups/string.h>
#include <errno.h>
#include <ctype.h>
+#include <regex.h>
-#include <cups/cups.h>
-#include <cups/language.h>
-#include <cups/http-private.h>
+#include <cups/globals.h>
#ifndef O_BINARY
# define O_BINARY 0
#endif /* !O_BINARY */
* Types...
*/
+typedef enum /**** How to send request data ****/
+{
+ _CUPS_TRANSFER_AUTO, /* Chunk for files, length for static */
+ _CUPS_TRANSFER_CHUNKED, /* Chunk always */
+ _CUPS_TRANSFER_LENGTH /* Length always */
+} _cups_transfer_t;
+
typedef struct _cups_expect_s /**** Expected attribute info ****/
{
- int not_expect; /* Don't expect attribute? */
- char *name, /* Attribute name */
- *of_type, /* Type name */
- *same_count_as, /* Parallel attribute name */
- *if_defined; /* Only required if variable defined */
+ int optional, /* Optional attribute? */
+ not_expect; /* Don't expect attribute? */
+ char *name, /* Attribute name */
+ *of_type, /* Type name */
+ *same_count_as, /* Parallel attribute name */
+ *if_defined, /* Only required if variable defined */
+ *if_undefined, /* Only required if variable is not defined */
+ *with_value; /* Attribute must include this value */
+ int with_regex, /* WITH-VALUE is a regular expression */
+ count; /* Expected count if > 0 */
+ ipp_tag_t in_group; /* IN-GROUP value */
} _cups_expect_t;
+typedef struct _cups_status_s /**** Status info ****/
+{
+ ipp_status_t status; /* Expected status code */
+ char *if_defined, /* Only if variable is defined */
+ *if_undefined; /* Only if variable is not defined */
+} _cups_status_t;
+
+typedef struct _cups_var_s /**** Variable ****/
+{
+ char *name, /* Name of variable */
+ *value; /* Value of variable */
+} _cups_var_t;
+
+typedef struct _cups_vars_s /**** Set of variables ****/
+{
+ const char *uri, /* URI for printer */
+ *filename; /* Filename */
+ char scheme[64], /* Scheme from URI */
+ userpass[256], /* Username/password from URI */
+ hostname[256], /* Hostname from URI */
+ resource[1024]; /* Resource path from URI */
+ int port; /* Port number from URI */
+ http_encryption_t encryption; /* Encryption for connection? */
+ cups_array_t *vars; /* Array of variables */
+} _cups_vars_t;
+
/*
* Globals...
*/
-int Chunking = 0; /* Use chunked requests */
-int Verbosity = 0; /* Show all attributes? */
+_cups_transfer_t Transfer = _CUPS_TRANSFER_AUTO;
+ /* How to transfer requests */
+int Verbosity = 0, /* Show all attributes? */
+ Version = 11, /* Default IPP version */
+ XML = 0, /* Produce XML output? */
+ XMLHeader = 0; /* 1 if header is written */
+const char * const URIStatusStrings[] = /* URI status strings */
+{
+ "URI too large",
+ "Bad arguments to function",
+ "Bad resource in URI",
+ "Bad port number in URI",
+ "Bad hostname/address in URI",
+ "Bad username in URI",
+ "Bad scheme in URI",
+ "Bad/empty URI",
+ "OK",
+ "Missing scheme in URI",
+ "Unknown scheme in URI",
+ "Missing resource in URI"
+};
/*
* Local functions...
*/
-static int do_tests(const char *uri, const char *testfile);
+static int compare_vars(_cups_var_t *a, _cups_var_t *b);
+static int do_tests(_cups_vars_t *vars, const char *testfile);
+static void expand_variables(_cups_vars_t *vars, char *dst, const char *src,
+ size_t dstsize)
+#ifdef __GNUC__
+__attribute((nonnull(1,2,3)))
+#endif /* __GNUC__ */
+;
static int expect_matches(_cups_expect_t *expect, ipp_tag_t value_tag);
+static ipp_t *get_collection(_cups_vars_t *vars, FILE *fp, int *linenum);
+static char *get_filename(const char *testfile, char *dst, const char *src,
+ size_t dstsize);
static char *get_token(FILE *fp, char *buf, int buflen,
int *linenum);
+static char *get_variable(_cups_vars_t *vars, const char *name);
+static char *iso_date(ipp_uchar_t *date);
static void print_attr(ipp_attribute_t *attr);
static void print_col(ipp_t *col);
+static void print_fatal_error(const char *s, ...)
+#ifdef __GNUC__
+__attribute__ ((__format__ (__printf__, 1, 2)))
+#endif /* __GNUC__ */
+;
+static void print_test_error(const char *s, ...)
+#ifdef __GNUC__
+__attribute__ ((__format__ (__printf__, 1, 2)))
+#endif /* __GNUC__ */
+;
+static void print_xml_header(void);
+static void print_xml_string(const char *element, const char *s);
+static void print_xml_trailer(int success, const char *message);
+static void set_variable(_cups_vars_t *vars, const char *name,
+ const char *value);
static void usage(void);
+static int validate_attr(ipp_attribute_t *attr, int print);
+static int with_value(char *value, int regex, ipp_attribute_t *attr);
/*
main(int argc, /* I - Number of command-line args */
char *argv[]) /* I - Command-line arguments */
{
- int i; /* Looping var */
- int status; /* Status of tests... */
- char *opt; /* Current option */
- const char *uri, /* URI to use */
- *testfile; /* Test file to use */
- int interval; /* Test interval */
+ int i; /* Looping var */
+ int status; /* Status of tests... */
+ char *opt, /* Current option */
+ name[1024], /* Name/value buffer */
+ *value; /* Pointer to value */
+ const char *testfile; /* Test file to use */
+ int interval; /* Test interval */
+ _cups_vars_t vars; /* Variables */
+ http_uri_status_t uri_status; /* URI separation status */
+
+
+ /*
+ * Initialize the locale and variables...
+ */
+
+ _cupsSetLocale(argv);
+ memset(&vars, 0, sizeof(vars));
+ vars.vars = cupsArrayNew((cups_array_func_t)compare_vars, NULL);
/*
* We need at least:
*
- * testipp URL testfile
+ * ipptest URI testfile
*/
- uri = NULL;
testfile = NULL;
status = 0;
interval = 0;
{
switch (*opt)
{
+ case 'E' : /* Encrypt */
+#ifdef HAVE_SSL
+ vars.encryption = HTTP_ENCRYPT_REQUIRED;
+#else
+ _cupsLangPrintf(stderr,
+ _("%s: Sorry, no encryption support compiled in\n"),
+ argv[0]);
+#endif /* HAVE_SSL */
+ break;
+
+ case 'V' : /* Set IPP version */
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPuts(stderr,
+ _("ipptest: Missing version for \"-V\".\n"));
+ usage();
+ }
+
+ if (!strcmp(argv[i], "1.0"))
+ Version = 10;
+ else if (!strcmp(argv[i], "1.1"))
+ Version = 11;
+ else if (!strcmp(argv[i], "2.0"))
+ Version = 20;
+ else if (!strcmp(argv[i], "2.1"))
+ Version = 21;
+ else if (!strcmp(argv[i], "2.2"))
+ Version = 22;
+ else
+ {
+ _cupsLangPrintf(stderr,
+ _("ipptest: Bad version %s for \"-V\".\n"),
+ argv[i]);
+ usage();
+ }
+ break;
+
+ case 'X' : /* Produce XML output */
+ XML = 1;
+
+ if (interval)
+ {
+ _cupsLangPuts(stderr, _("ipptest: \"-i\" is incompatible with "
+ "\"-x\".\n"));
+ usage();
+ }
+ break;
+
case 'c' : /* Enable HTTP chunking */
- Chunking = 1;
+ Transfer = _CUPS_TRANSFER_CHUNKED;
break;
case 'd' : /* Define a variable */
if (i >= argc)
{
- fputs("ipptest: Missing name=value for \"-d\"!\n", stderr);
+ _cupsLangPuts(stderr,
+ _("ipptest: Missing name=value for \"-d\".\n"));
usage();
}
+
+ strlcpy(name, argv[i], sizeof(name));
+ if ((value = strchr(name, '=')) != NULL)
+ *value++ = '\0';
else
- putenv(argv[i]);
+ value = name + strlen(name);
+
+ set_variable(&vars, name, value);
+ break;
+
+ case 'f' : /* Set the default test filename */
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPuts(stderr,
+ _("ipptest: Missing filename for \"-f\".\n"));
+ usage();
+ }
+
+ vars.filename = argv[i];
break;
case 'i' : /* Test every N seconds */
if (i >= argc)
{
- fputs("ipptest: Missing seconds for \"-i\"!\n", stderr);
+ _cupsLangPuts(stderr,
+ _("ipptest: Missing seconds for \"-i\".\n"));
usage();
}
else
interval = atoi(argv[i]);
+
+ if (XML && interval)
+ {
+ _cupsLangPuts(stderr, _("ipptest: \"-i\" is incompatible with "
+ "\"-x\".\n"));
+ usage();
+ }
break;
+ case 'l' : /* Disable HTTP chunking */
+ Transfer = _CUPS_TRANSFER_LENGTH;
+ break;
+
case 'v' : /* Be verbose */
Verbosity ++;
break;
default :
- fprintf(stderr, "ipptest: Unknown option \"-%c\"!\n", *opt);
+ _cupsLangPrintf(stderr, _("ipptest: Unknown option \"-%c\".\n"),
+ *opt);
usage();
break;
}
* Set URI...
*/
- if (!testfile && uri)
+ if (vars.uri)
{
- fputs("ipptest: May only specify a single URI before a test!\n",
- stderr);
+ _cupsLangPuts(stderr, _("ipptest: May only specify a single URI.\n"));
usage();
}
- uri = argv[i];
- testfile = NULL;
+ vars.uri = argv[i];
+ uri_status = httpSeparateURI(HTTP_URI_CODING_ALL, vars.uri,
+ vars.scheme, sizeof(vars.scheme),
+ vars.userpass, sizeof(vars.userpass),
+ vars.hostname, sizeof(vars.hostname),
+ &(vars.port),
+ vars.resource, sizeof(vars.resource));
+
+ if (uri_status != HTTP_URI_OK)
+ {
+ _cupsLangPrintf(stderr, _("ipptest: Bad URI - %s.\n"),
+ URIStatusStrings[uri_status - HTTP_URI_OVERFLOW]);
+ return (1);
+ }
+
+ if (strcmp(vars.scheme, "http") && strcmp(vars.scheme, "https") &&
+ strcmp(vars.scheme, "ipp"))
+ {
+ _cupsLangPuts(stderr, _("ipptest: Only http, https, and ipp URIs are "
+ "supported."));
+ return (1);
+ }
}
else
{
* Run test...
*/
+ if (!vars.uri)
+ {
+ _cupsLangPuts(stderr, _("ipptest: URI required before test file."));
+ usage();
+ }
+
testfile = argv[i];
- if (!do_tests(uri, testfile))
- status ++;
+ if (!do_tests(&vars, testfile))
+ status = 1;
}
}
- if (!uri || !testfile)
+ if (!vars.uri || !testfile)
usage();
/*
* Loop if the interval is set...
*/
- if (interval)
+ if (XML)
+ print_xml_trailer(!status, NULL);
+ else if (interval)
{
for (;;)
{
sleep(interval);
- do_tests(uri, testfile);
+ do_tests(&vars, testfile);
}
}
return (status);
}
-
+
+/*
+ * 'compare_vars()' - Compare two variables.
+ */
+
+static int /* O - Result of comparison */
+compare_vars(_cups_var_t *a, /* I - First variable */
+ _cups_var_t *b) /* I - Second variable */
+{
+ return (strcasecmp(a->name, b->name));
+}
+
+
/*
* 'do_tests()' - Do tests as specified in the test file.
*/
static int /* 1 = success, 0 = failure */
-do_tests(const char *uri, /* I - URI to connect on */
- const char *testfile) /* I - Test file to use */
+do_tests(_cups_vars_t *vars, /* I - Variables */
+ const char *testfile) /* I - Test file to use */
{
- int i; /* Looping var */
- int linenum; /* Current line number */
- int version; /* IPP version number to use */
- http_t *http; /* HTTP connection to server */
- char scheme[HTTP_MAX_URI], /* URI scheme */
- userpass[HTTP_MAX_URI], /* username:password */
- server[HTTP_MAX_URI], /* Server */
- resource[HTTP_MAX_URI]; /* Resource path */
- int port; /* Port number */
- FILE *fp; /* Test file */
- char token[1024], /* Token from file */
+ int i, /* Looping var */
+ linenum, /* Current line number */
+ pass, /* Did we pass the test? */
+ request_id; /* Current request ID */
+ http_t *http = NULL; /* HTTP connection to server */
+ FILE *fp = NULL; /* Test file */
+ char resource[512], /* Resource for request */
+ token[1024], /* Token from file */
*tokenptr, /* Pointer into token */
- temp[1024], /* Temporary string */
- *tempptr; /* Pointer into temp string */
- ipp_t *request; /* IPP request */
- ipp_t *response; /* IPP response */
+ temp[1024]; /* Temporary string */
+ ipp_t *request = NULL; /* IPP request */
+ ipp_t *response = NULL; /* IPP response */
+ char attr[128]; /* Attribute name */
ipp_op_t op; /* Operation */
ipp_tag_t group; /* Current group */
ipp_tag_t value; /* Current value type */
ipp_attribute_t *attrptr, /* Attribute pointer */
- *found; /* Found attribute */
- char attr[128]; /* Attribute name */
- int num_statuses; /* Number of valid status codes */
- ipp_status_t statuses[100]; /* Valid status codes */
- int num_expects; /* Number of expected attributes */
- _cups_expect_t expects[100], /* Expected attributes */
+ *found, /* Found attribute */
+ *lastcol = NULL; /* Last collection attribute */
+ char name[1024]; /* Name of test */
+ char filename[1024]; /* Filename */
+ _cups_transfer_t transfer; /* To chunk or not to chunk */
+ int version; /* IPP version number to use */
+ int num_statuses = 0; /* Number of valid status codes */
+ _cups_status_t statuses[100], /* Valid status codes */
+ *last_status; /* Last STATUS (for predicates) */
+ int num_expects = 0; /* Number of expected attributes */
+ _cups_expect_t expects[200], /* Expected attributes */
*expect, /* Current expected attribute */
*last_expect; /* Last EXPECT (for predicates) */
- int num_displayed; /* Number of displayed attributes */
+ int num_displayed = 0; /* Number of displayed attributes */
char *displayed[100]; /* Displayed attributes */
- char name[1024]; /* Name of test */
- char filename[1024]; /* Filename */
- int pass; /* Did we pass the test? */
- int job_id; /* Job ID from last operation */
- int subscription_id; /* Subscription ID from last operation */
/*
if ((fp = fopen(testfile, "r")) == NULL)
{
- printf("Unable to open test file %s - %s\n", testfile, strerror(errno));
- return (0);
+ print_fatal_error("Unable to open test file %s - %s", testfile,
+ strerror(errno));
+ goto test_error;
}
/*
* Connect to the server...
*/
- httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), userpass,
- sizeof(userpass), server, sizeof(server), &port, resource,
- sizeof(resource));
- if ((http = httpConnect(server, port)) == NULL)
+ if ((http = httpConnectEncrypt(vars->hostname, vars->port,
+ vars->encryption)) == NULL)
{
- printf("Unable to connect to %s on port %d - %s\n", server, port,
- strerror(errno));
- fclose(fp);
- return (0);
+ print_fatal_error("Unable to connect to %s on port %d - %s", vars->hostname,
+ vars->port, strerror(errno));
+ goto test_error;
}
/*
* Loop on tests...
*/
- printf("\"%s\":\n", testfile);
- pass = 1;
- job_id = 0;
- subscription_id = 0;
- version = 11;
- linenum = 1;
+ if (XML)
+ print_xml_header();
+ else
+ printf("\"%s\":\n", testfile);
+
+ CUPS_SRAND(time(NULL));
+
+ pass = 1;
+ linenum = 1;
+ request_id = (CUPS_RAND() % 1000) * 137 + 1;
while (get_token(fp, token, sizeof(token), &linenum) != NULL)
{
* Expect an open brace...
*/
- if (strcmp(token, "{"))
+ if (!strcmp(token, "DEFINE"))
+ {
+ /*
+ * DEFINE name value
+ */
+
+ if (get_token(fp, attr, sizeof(attr), &linenum) &&
+ get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ expand_variables(vars, token, temp, sizeof(token));
+ set_variable(vars, attr, token);
+ }
+ else
+ {
+ print_fatal_error("Missing DEFINE name and/or value on line %d.",
+ linenum);
+ goto test_error;
+ }
+
+ continue;
+ }
+ else if (!strcmp(token, "INCLUDE"))
+ {
+ /*
+ * INCLUDE "filename"
+ * INCLUDE <filename>
+ */
+
+ if (get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ /*
+ * Map the filename to and then run the tests...
+ */
+
+ if (!do_tests(vars, get_filename(testfile, filename, temp,
+ sizeof(filename))))
+ goto test_error;
+ }
+ else
+ {
+ print_fatal_error("Missing INCLUDE filename on line %d.", linenum);
+ goto test_error;
+ }
+
+ continue;
+ }
+ else if (!strcmp(token, "TRANSFER"))
+ {
+ /*
+ * TRANSFER auto
+ * TRANSFER chunked
+ * TRANSFER length
+ */
+
+ if (get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ if (!strcmp(temp, "auto"))
+ Transfer = _CUPS_TRANSFER_AUTO;
+ else if (!strcmp(temp, "chunked"))
+ Transfer = _CUPS_TRANSFER_CHUNKED;
+ else if (!strcmp(temp, "length"))
+ Transfer = _CUPS_TRANSFER_LENGTH;
+ else
+ {
+ print_fatal_error("Bad TRANSFER value \"%s\" on line %d.", temp,
+ linenum);
+ goto test_error;
+ }
+ }
+ else
+ {
+ print_fatal_error("Missing TRANSFER value on line %d.", linenum);
+ goto test_error;
+ }
+
+ continue;
+ }
+ else if (!strcmp(token, "VERSION"))
+ {
+ if (get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ if (!strcmp(temp, "1.0"))
+ Version = 10;
+ else if (!strcmp(temp, "1.1"))
+ Version = 11;
+ else if (!strcmp(temp, "2.0"))
+ Version = 20;
+ else if (!strcmp(temp, "2.1"))
+ Version = 21;
+ else if (!strcmp(temp, "2.2"))
+ Version = 22;
+ else
+ {
+ print_fatal_error("Bad VERSION \"%s\" on line %d.", temp, linenum);
+ goto test_error;
+ }
+ }
+ else
+ {
+ print_fatal_error("Missing VERSION number on line %d.", linenum);
+ goto test_error;
+ }
+
+ continue;
+ }
+ else if (strcmp(token, "{"))
{
- printf("Unexpected token %s seen on line %d - aborting test!\n", token,
- linenum);
- httpClose(http);
- return (0);
+ print_fatal_error("Unexpected token %s seen on line %d.", token, linenum);
+ goto test_error;
}
/*
* Initialize things...
*/
- httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), userpass,
- sizeof(userpass), server, sizeof(server), &port, resource,
- sizeof(resource));
+ strlcpy(resource, vars->resource, sizeof(resource));
+ request_id ++;
request = ippNew();
op = (ipp_op_t)0;
group = IPP_TAG_ZERO;
- num_statuses = 0;
- num_expects = 0;
- num_displayed = 0;
last_expect = NULL;
+ last_status = NULL;
filename[0] = '\0';
+ version = Version;
+ transfer = Transfer;
- strcpy(name, testfile);
+ strlcpy(name, testfile, sizeof(name));
if (strrchr(name, '.') != NULL)
*strrchr(name, '.') = '\0';
while (get_token(fp, token, sizeof(token), &linenum) != NULL)
{
- if (strcasecmp(token, "EXPECT") &&
+ if (strcasecmp(token, "COUNT") &&
strcasecmp(token, "IF-DEFINED") &&
+ strcasecmp(token, "IF-UNDEFINED") &&
+ strcasecmp(token, "IN-GROUP") &&
strcasecmp(token, "OF-TYPE") &&
- strcasecmp(token, "SAME-COUNT-AS"))
+ strcasecmp(token, "SAME-COUNT-AS") &&
+ strcasecmp(token, "WITH-VALUE"))
last_expect = NULL;
+ if (strcasecmp(token, "IF-DEFINED") &&
+ strcasecmp(token, "IF-UNDEFINED"))
+ last_status = NULL;
+
if (!strcmp(token, "}"))
break;
+ else if (!strcmp(token, "{") && lastcol)
+ {
+ /*
+ * Another collection value
+ */
+
+ ipp_t *col = get_collection(vars, fp, &linenum);
+ /* Collection value */
+
+ if (col)
+ {
+ ipp_attribute_t *tempcol; /* Pointer to new buffer */
+
+
+ /*
+ * Reallocate memory...
+ */
+
+ if ((tempcol = realloc(lastcol, sizeof(ipp_attribute_t) +
+ (lastcol->num_values + 1) *
+ sizeof(ipp_value_t))) == NULL)
+ {
+ print_fatal_error("Unable to allocate memory on line %d.", linenum);
+ goto test_error;
+ }
+
+ if (tempcol != lastcol)
+ {
+ /*
+ * Reset pointers in the list...
+ */
+
+ if (request->prev)
+ request->prev->next = tempcol;
+ else
+ request->attrs = tempcol;
+
+ lastcol = request->current = request->last = tempcol;
+ }
+
+ lastcol->values[lastcol->num_values].collection = col;
+ lastcol->num_values ++;
+ }
+ else
+ goto test_error;
+ }
+ else if (!strcmp(token, "DEFINE"))
+ {
+ /*
+ * DEFINE name value
+ */
+
+ if (get_token(fp, attr, sizeof(attr), &linenum) &&
+ get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ expand_variables(vars, token, temp, sizeof(token));
+ set_variable(vars, attr, token);
+ }
+ else
+ {
+ print_fatal_error("Missing DEFINE name and/or value on line %d.",
+ linenum);
+ goto test_error;
+ }
+ }
else if (!strcasecmp(token, "NAME"))
{
/*
get_token(fp, name, sizeof(name), &linenum);
}
- else if (!strcasecmp(token, "VERSION"))
+ else if (!strcmp(token, "REQUEST-ID"))
{
/*
- * IPP version number for test...
+ * REQUEST-ID #
+ * REQUEST-ID random
*/
- int major, minor; /* Major/minor IPP version */
-
+ if (get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ if (isdigit(temp[0] & 255))
+ request_id = atoi(temp);
+ else if (!strcasecmp(temp, "random"))
+ request_id = (CUPS_RAND() % 1000) * 137 + 1;
+ else
+ {
+ print_fatal_error("Bad REQUEST-ID value \"%s\" on line %d.", temp,
+ linenum);
+ goto test_error;
+ }
+ }
+ else
+ {
+ print_fatal_error("Missing REQUEST-ID value on line %d.", linenum);
+ goto test_error;
+ }
+ }
+ else if (!strcmp(token, "TRANSFER"))
+ {
+ /*
+ * TRANSFER auto
+ * TRANSFER chunked
+ * TRANSFER length
+ */
- get_token(fp, temp, sizeof(temp), &linenum);
- if (sscanf(temp, "%d.%d", &major, &minor) == 2 &&
- major >= 0 && minor >= 0 && minor < 10)
- version = major * 10 + minor;
+ if (get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ if (!strcmp(temp, "auto"))
+ transfer = _CUPS_TRANSFER_AUTO;
+ else if (!strcmp(temp, "chunked"))
+ transfer = _CUPS_TRANSFER_CHUNKED;
+ else if (!strcmp(temp, "length"))
+ transfer = _CUPS_TRANSFER_LENGTH;
+ else
+ {
+ print_fatal_error("Bad TRANSFER value \"%s\" on line %d.", temp,
+ linenum);
+ goto test_error;
+ }
+ }
+ else
+ {
+ print_fatal_error("Missing TRANSFER value on line %d.", linenum);
+ goto test_error;
+ }
+ }
+ else if (!strcasecmp(token, "VERSION"))
+ {
+ if (get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ if (!strcmp(temp, "0.0"))
+ version = 0;
+ else if (!strcmp(temp, "1.0"))
+ version = 10;
+ else if (!strcmp(temp, "1.1"))
+ version = 11;
+ else if (!strcmp(temp, "2.0"))
+ version = 20;
+ else if (!strcmp(temp, "2.1"))
+ version = 21;
+ else if (!strcmp(temp, "2.2"))
+ version = 22;
+ else
+ {
+ print_fatal_error("Bad VERSION \"%s\" on line %d.", temp, linenum);
+ goto test_error;
+ }
+ }
else
{
- printf("Bad version %s seen on line %d - aborting test!\n", token,
- linenum);
- httpClose(http);
- ippDelete(request);
- return (0);
+ print_fatal_error("Missing VERSION number on line %d.", linenum);
+ goto test_error;
}
}
else if (!strcasecmp(token, "RESOURCE"))
* Resource name...
*/
- get_token(fp, resource, sizeof(resource), &linenum);
+ if (!get_token(fp, resource, sizeof(resource), &linenum))
+ {
+ print_fatal_error("Missing RESOURCE path on line %d.", linenum);
+ goto test_error;
+ }
}
else if (!strcasecmp(token, "OPERATION"))
{
* Operation...
*/
- get_token(fp, token, sizeof(token), &linenum);
- op = ippOpValue(token);
+ if (!get_token(fp, token, sizeof(token), &linenum))
+ {
+ print_fatal_error("Missing OPERATION code on line %d.", linenum);
+ goto test_error;
+ }
+
+ if ((op = ippOpValue(token)) < 0)
+ {
+ print_fatal_error("Bad OPERATION code \"%s\" on line %d.", token,
+ linenum);
+ goto test_error;
+ }
}
else if (!strcasecmp(token, "GROUP"))
{
* Attribute group...
*/
- get_token(fp, token, sizeof(token), &linenum);
- value = ippTagValue(token);
+ if (!get_token(fp, token, sizeof(token), &linenum))
+ {
+ print_fatal_error("Missing GROUP tag on line %d.", linenum);
+ goto test_error;
+ }
+
+ if ((value = ippTagValue(token)) < 0)
+ {
+ print_fatal_error("Bad GROUP tag \"%s\" on line %d.", token, linenum);
+ goto test_error;
+ }
if (value == group)
ippAddSeparator(request);
int delay;
- get_token(fp, token, sizeof(token), &linenum);
- if ((delay = atoi(token)) > 0)
+ if (!get_token(fp, token, sizeof(token), &linenum))
+ {
+ print_fatal_error("Missing DELAY value on line %d.", linenum);
+ goto test_error;
+ }
+
+ if ((delay = atoi(token)) <= 0)
+ {
+ print_fatal_error("Bad DELAY value \"%s\" on line %d.", token,
+ linenum);
+ goto test_error;
+ }
+ else
sleep(delay);
}
else if (!strcasecmp(token, "ATTR"))
* Attribute...
*/
- get_token(fp, token, sizeof(token), &linenum);
- value = ippTagValue(token);
- get_token(fp, attr, sizeof(attr), &linenum);
- get_token(fp, temp, sizeof(temp), &linenum);
+ if (!get_token(fp, token, sizeof(token), &linenum))
+ {
+ print_fatal_error("Missing ATTR value tag on line %d.", linenum);
+ goto test_error;
+ }
- token[sizeof(token) - 1] = '\0';
+ if ((value = ippTagValue(token)) < 0)
+ {
+ print_fatal_error("Bad ATTR value tag \"%s\" on line %d.", token,
+ linenum);
+ goto test_error;
+ }
- for (tempptr = temp, tokenptr = token;
- *tempptr && tokenptr < (token + sizeof(token) - 1);)
- if (*tempptr == '$')
- {
- /*
- * Substitute a string/number...
- */
+ printf("%d: value=%s\n", linenum, ippTagString(value));
- if (!strncasecmp(tempptr + 1, "uri", 3))
- {
- strlcpy(tokenptr, uri, sizeof(token) - (tokenptr - token));
- tempptr += 4;
- }
- else if (!strncasecmp(tempptr + 1, "scheme", 6) ||
- !strncasecmp(tempptr + 1, "method", 6))
- {
- strlcpy(tokenptr, scheme, sizeof(token) - (tokenptr - token));
- tempptr += 7;
- }
- else if (!strncasecmp(tempptr + 1, "username", 8))
- {
- strlcpy(tokenptr, userpass, sizeof(token) - (tokenptr - token));
- tempptr += 9;
- }
- else if (!strncasecmp(tempptr + 1, "hostname", 8))
- {
- strlcpy(tokenptr, server, sizeof(token) - (tokenptr - token));
- tempptr += 9;
- }
- else if (!strncasecmp(tempptr + 1, "port", 4))
- {
- snprintf(tokenptr, sizeof(token) - (tokenptr - token),
- "%d", port);
- tempptr += 5;
- }
- else if (!strncasecmp(tempptr + 1, "resource", 8))
- {
- strlcpy(tokenptr, resource, sizeof(token) - (tokenptr - token));
- tempptr += 9;
- }
- else if (!strncasecmp(tempptr + 1, "job-id", 6))
- {
- snprintf(tokenptr, sizeof(token) - (tokenptr - token),
- "%d", job_id);
- tempptr += 7;
- }
- else if (!strncasecmp(tempptr + 1, "notify-subscription-id", 22))
- {
- snprintf(tokenptr, sizeof(token) - (tokenptr - token),
- "%d", subscription_id);
- tempptr += 23;
- }
- else if (!strncasecmp(tempptr + 1, "user", 4))
- {
- strlcpy(tokenptr, cupsUser(), sizeof(token) - (tokenptr - token));
- tempptr += 5;
- }
- else if (!strncasecmp(tempptr + 1, "ENV[", 4))
- {
- char *end; /* End of $ENV[name] */
+ if (!get_token(fp, attr, sizeof(attr), &linenum))
+ {
+ print_fatal_error("Missing ATTR name on line %d.", linenum);
+ goto test_error;
+ }
+ if (!get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ print_fatal_error("Missing ATTR value on line %d.", linenum);
+ goto test_error;
+ }
- if ((end = strchr(tempptr + 5, ']')) != NULL)
- {
- *end++ = '\0';
- strlcpy(tokenptr,
- getenv(tempptr + 5) ? getenv(tempptr + 5) : tempptr + 5,
- sizeof(token) - (tokenptr - token));
- tempptr = end;
- }
- else
- {
- *tokenptr++ = *tempptr++;
- *tokenptr = '\0';
- }
- }
- else
- {
- *tokenptr++ = *tempptr++;
- *tokenptr = '\0';
- }
-
- tokenptr += strlen(tokenptr);
- }
- else
- {
- *tokenptr++ = *tempptr++;
- *tokenptr = '\0';
- }
+ expand_variables(vars, token, temp, sizeof(token));
switch (value)
{
break;
case IPP_TAG_RESOLUTION :
- puts(" ERROR: resolution tag not yet supported!");
+ {
+ int xres, /* X resolution */
+ yres; /* Y resolution */
+ char units[6]; /* Units */
+
+ if (sscanf(token, "%dx%d%5s", &xres, &yres, units) != 3 ||
+ (strcasecmp(units, "dpi") && strcasecmp(units, "dpc") &&
+ strcasecmp(units, "other")))
+ {
+ print_fatal_error("Bad resolution value \"%s\" on line %d.",
+ token, linenum);
+ goto test_error;
+ }
+
+ if (!strcasecmp(units, "dpi"))
+ ippAddResolution(request, group, attr, xres, yres,
+ IPP_RES_PER_INCH);
+ else if (!strcasecmp(units, "dpc"))
+ ippAddResolution(request, group, attr, xres, yres,
+ IPP_RES_PER_CM);
+ else
+ ippAddResolution(request, group, attr, xres, yres,
+ (ipp_res_t)0);
+ }
break;
case IPP_TAG_RANGE :
- puts(" ERROR: range tag not yet supported!");
+ {
+ int lowers[4], /* Lower value */
+ uppers[4], /* Upper values */
+ num_vals; /* Number of values */
+
+
+ num_vals = sscanf(token, "%d-%d,%d-%d,%d-%d,%d-%d",
+ lowers + 0, uppers + 0,
+ lowers + 1, uppers + 1,
+ lowers + 2, uppers + 2,
+ lowers + 3, uppers + 3);
+
+ if ((num_vals & 1) || num_vals == 0)
+ {
+ print_fatal_error("Bad rangeOfInteger value \"%s\" on line "
+ "%d.", token, linenum);
+ goto test_error;
+ }
+
+ ippAddRanges(request, group, attr, num_vals / 2, lowers,
+ uppers);
+ }
+ break;
+
+ case IPP_TAG_BEGIN_COLLECTION :
+ if (!strcmp(token, "{"))
+ {
+ ipp_t *col = get_collection(vars, fp, &linenum);
+ /* Collection value */
+
+ if (col)
+ lastcol = ippAddCollection(request, group, attr, col);
+ else
+ goto test_error;
+ }
+ else
+ {
+ print_fatal_error("Bad ATTR collection value on line %d.",
+ linenum);
+ goto test_error;
+ }
break;
default :
* File...
*/
- get_token(fp, filename, sizeof(filename), &linenum);
+ if (!get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ print_fatal_error("Missing FILE filename on line %d.", linenum);
+ goto test_error;
+ }
+
+ expand_variables(vars, token, temp, sizeof(token));
+ get_filename(testfile, filename, token, sizeof(filename));
}
- else if (!strcasecmp(token, "STATUS") &&
- num_statuses < (int)(sizeof(statuses) / sizeof(statuses[0])))
+ else if (!strcasecmp(token, "STATUS"))
{
/*
* Status...
*/
- get_token(fp, token, sizeof(token), &linenum);
- statuses[num_statuses] = ippErrorValue(token);
+ if (num_statuses >= (int)(sizeof(statuses) / sizeof(statuses[0])))
+ {
+ print_fatal_error("Too many STATUS's on line %d.", linenum);
+ goto test_error;
+ }
+
+ if (!get_token(fp, token, sizeof(token), &linenum))
+ {
+ print_fatal_error("Missing STATUS code on line %d.", linenum);
+ goto test_error;
+ }
+
+ if ((statuses[num_statuses].status = ippErrorValue(token)) < 0)
+ {
+ print_fatal_error("Bad STATUS code \"%s\" on line %d.", token,
+ linenum);
+ goto test_error;
+ }
+
+ last_status = statuses + num_statuses;
num_statuses ++;
+
+ last_status->if_defined = NULL;
+ last_status->if_undefined = NULL;
}
else if (!strcasecmp(token, "EXPECT"))
{
if (num_expects >= (int)(sizeof(expects) / sizeof(expects[0])))
{
- fprintf(stderr, "ipptest: Too many EXPECT's on line %d\n", linenum);
- httpClose(http);
- ippDelete(request);
- return (0);
+ print_fatal_error("Too many EXPECT's on line %d.", linenum);
+ goto test_error;
}
- get_token(fp, token, sizeof(token), &linenum);
+ if (!get_token(fp, token, sizeof(token), &linenum))
+ {
+ print_fatal_error("Missing EXPECT name on line %d.", linenum);
+ goto test_error;
+ }
last_expect = expects + num_expects;
num_expects ++;
+ memset(last_expect, 0, sizeof(_cups_expect_t));
+
if (token[0] == '!')
{
last_expect->not_expect = 1;
last_expect->name = strdup(token + 1);
}
- else
+ else if (token[0] == '?')
{
- last_expect->not_expect = 0;
- last_expect->name = strdup(token);
+ last_expect->optional = 1;
+ last_expect->name = strdup(token + 1);
+ }
+ else
+ last_expect->name = strdup(token);
+ }
+ else if (!strcasecmp(token, "COUNT"))
+ {
+ if (!get_token(fp, token, sizeof(token), &linenum))
+ {
+ print_fatal_error("Missing COUNT number on line %d.", linenum);
+ goto test_error;
+ }
+
+ if ((i = atoi(token)) <= 0)
+ {
+ print_fatal_error("Bad COUNT \"%s\" on line %d.", token, linenum);
+ goto test_error;
}
- last_expect->of_type = NULL;
- last_expect->same_count_as = NULL;
- last_expect->if_defined = NULL;
+ if (last_expect)
+ last_expect->count = i;
+ else
+ {
+ print_fatal_error("COUNT without a preceding EXPECT on line %d.",
+ linenum);
+ goto test_error;
+ }
}
else if (!strcasecmp(token, "OF-TYPE"))
{
- get_token(fp, token, sizeof(token), &linenum);
+ if (!get_token(fp, token, sizeof(token), &linenum))
+ {
+ print_fatal_error("Missing OF-TYPE value tag(s) on line %d.",
+ linenum);
+ goto test_error;
+ }
if (last_expect)
last_expect->of_type = strdup(token);
else
{
- fprintf(stderr,
- "ipptest: OF-TYPE without a preceding EXPECT on line %d\n",
- linenum);
- httpClose(http);
- ippDelete(request);
- return (0);
+ print_fatal_error("OF-TYPE without a preceding EXPECT on line %d.",
+ linenum);
+ goto test_error;
+ }
+ }
+ else if (!strcasecmp(token, "IN-GROUP"))
+ {
+ ipp_tag_t in_group; /* IN-GROUP value */
+
+
+ if (!get_token(fp, token, sizeof(token), &linenum))
+ {
+ print_fatal_error("Missing IN-GROUP group tag on line %d.", linenum);
+ goto test_error;
+ }
+
+ if ((in_group = ippTagValue(token)) == (ipp_tag_t)-1)
+ {
+ }
+ else if (last_expect)
+ last_expect->in_group = in_group;
+ else
+ {
+ print_fatal_error("IN-GROUP without a preceding EXPECT on line %d.",
+ linenum);
+ goto test_error;
}
}
else if (!strcasecmp(token, "SAME-COUNT-AS"))
{
- get_token(fp, token, sizeof(token), &linenum);
+ if (!get_token(fp, token, sizeof(token), &linenum))
+ {
+ print_fatal_error("Missing SAME-COUNT-AS name on line %d.", linenum);
+ goto test_error;
+ }
if (last_expect)
last_expect->same_count_as = strdup(token);
else
{
- fprintf(stderr,
- "ipptest: SAME-COUNT-AS without a preceding EXPECT on line "
- "%d\n", linenum);
- httpClose(http);
- ippDelete(request);
- return (0);
+ print_fatal_error("SAME-COUNT-AS without a preceding EXPECT on line "
+ "%d.", linenum);
+ goto test_error;
}
}
else if (!strcasecmp(token, "IF-DEFINED"))
{
- get_token(fp, token, sizeof(token), &linenum);
+ if (!get_token(fp, token, sizeof(token), &linenum))
+ {
+ print_fatal_error("Missing IF-DEFINED name on line %d.", linenum);
+ goto test_error;
+ }
if (last_expect)
last_expect->if_defined = strdup(token);
+ else if (last_status)
+ last_status->if_defined = strdup(token);
+ else
+ {
+ print_fatal_error("IF-DEFINED without a preceding EXPECT or STATUS "
+ "on line %d.", linenum);
+ goto test_error;
+ }
+ }
+ else if (!strcasecmp(token, "IF-UNDEFINED"))
+ {
+ if (!get_token(fp, token, sizeof(token), &linenum))
+ {
+ print_fatal_error("Missing IF-UNDEFINED name on line %d.", linenum);
+ goto test_error;
+ }
+
+ if (last_expect)
+ last_expect->if_undefined = strdup(token);
+ else if (last_status)
+ last_status->if_undefined = strdup(token);
+ else
+ {
+ print_fatal_error("IF-UNDEFINED without a preceding EXPECT or STATUS "
+ "on line %d.", linenum);
+ goto test_error;
+ }
+ }
+ else if (!strcasecmp(token, "WITH-VALUE"))
+ {
+ if (!get_token(fp, token, sizeof(token), &linenum))
+ {
+ print_fatal_error("Missing WITH-VALUE value on line %d.", linenum);
+ goto test_error;
+ }
+
+ if (last_expect)
+ {
+ tokenptr = token + strlen(token) - 1;
+ if (token[0] == '/' && tokenptr > token && *tokenptr == '/')
+ {
+ /*
+ * WITH-VALUE is a POSIX extended regular expression.
+ */
+
+ last_expect->with_value = calloc(1, tokenptr - token);
+ last_expect->with_regex = 1;
+
+ if (last_expect->with_value)
+ memcpy(last_expect->with_value, token + 1, tokenptr - token - 1);
+ }
+ else
+ {
+ /*
+ * WITH-VALUE is a literal value...
+ */
+
+ last_expect->with_value = strdup(token);
+ }
+ }
else
{
- fprintf(stderr,
- "ipptest: IF-DEFINED without a preceding EXPECT on line %d\n",
- linenum);
- httpClose(http);
- ippDelete(request);
- return (0);
+ print_fatal_error("WITH-VALUE without a preceding EXPECT on line %d.",
+ linenum);
+ goto test_error;
}
}
- else if (!strcasecmp(token, "DISPLAY") &&
- num_displayed < (int)(sizeof(displayed) / sizeof(displayed[0])))
+ else if (!strcasecmp(token, "DISPLAY"))
{
/*
* Display attributes...
*/
- get_token(fp, token, sizeof(token), &linenum);
+ if (num_displayed >= (int)(sizeof(displayed) / sizeof(displayed[0])))
+ {
+ print_fatal_error("Too many DISPLAY's on line %d", linenum);
+ goto test_error;
+ }
+
+ if (!get_token(fp, token, sizeof(token), &linenum))
+ {
+ print_fatal_error("Missing DISPLAY name on line %d.", linenum);
+ goto test_error;
+ }
+
displayed[num_displayed] = strdup(token);
num_displayed ++;
}
else
{
- fprintf(stderr,
- "ipptest: Unexpected token %s seen on line %d - aborting "
- "test!\n", token, linenum);
- httpClose(http);
- ippDelete(request);
- return (0);
+ print_fatal_error("Unexpected token %s seen on line %d.", token,
+ linenum);
+ goto test_error;
}
}
request->request.op.version[0] = version / 10;
request->request.op.version[1] = version % 10;
request->request.op.operation_id = op;
- request->request.op.request_id = 1;
+ request->request.op.request_id = request_id;
- if (Verbosity)
+ if (XML)
{
- printf(" %s:\n", ippOpString(op));
-
+ puts("<dict>");
+ puts("<key>Name</key>");
+ print_xml_string("string", name);
+ puts("<key>Operation</key>");
+ print_xml_string("string", ippOpString(op));
+ puts("<key>RequestAttributes</key>");
+ puts("<dict>");
for (attrptr = request->attrs; attrptr; attrptr = attrptr->next)
print_attr(attrptr);
+ puts("</dict>");
}
+ else
+ {
+ if (Verbosity)
+ {
+ printf(" %s:\n", ippOpString(op));
+
+ for (attrptr = request->attrs; attrptr; attrptr = attrptr->next)
+ print_attr(attrptr);
+ }
- printf(" %-60.60s [", name);
- fflush(stdout);
+ printf(" %-69.69s [", name);
+ fflush(stdout);
+ }
- if (Chunking)
+ if (transfer == _CUPS_TRANSFER_CHUNKED ||
+ (transfer == _CUPS_TRANSFER_AUTO && filename[0]))
{
+ /*
+ * Send request using chunking...
+ */
+
http_status_t status = cupsSendRequest(http, request, resource, 0);
if (status == HTTP_CONTINUE && filename[0])
char buffer[8192]; /* Copy buffer */
ssize_t bytes; /* Bytes read/written */
-
if ((fd = open(filename, O_RDONLY | O_BINARY)) >= 0)
{
while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
break;
}
else
+ {
+ snprintf(buffer, sizeof(buffer), "%s: %s", filename, strerror(errno));
+ _cupsSetError(IPP_INTERNAL_ERROR, buffer, 0);
+
status = HTTP_ERROR;
+ }
}
ippDelete(request);
else if (filename[0])
response = cupsDoFileRequest(http, request, resource, filename);
else
- response = cupsDoIORequest(http, request, resource, -1,
- Verbosity ? 1 : -1);
-
- if (response == NULL)
- {
- time_t curtime;
+ response = cupsDoRequest(http, request, resource);
- curtime = time(NULL);
+ request = NULL;
- puts("FAIL]");
- printf(" ERROR %04x (%s) @ %s\n", cupsLastError(),
- cupsLastErrorString(), ctime(&curtime));
+ if (!response)
pass = 0;
- }
else
{
if (http->version != HTTP_1_1)
pass = 0;
+ if (response->request.status.version[0] != (version / 10) ||
+ response->request.status.version[1] != (version % 10) ||
+ response->request.status.request_id != request_id)
+ pass = 0;
+
if ((attrptr = ippFindAttribute(response, "job-id",
IPP_TAG_INTEGER)) != NULL)
- job_id = attrptr->values[0].integer;
+ {
+ snprintf(temp, sizeof(temp), "%d", attrptr->values[0].integer);
+ set_variable(vars, "job-id", temp);
+ }
+
+ if ((attrptr = ippFindAttribute(response, "job-uri",
+ IPP_TAG_URI)) != NULL)
+ set_variable(vars, "job-uri", attrptr->values[0].string.text);
if ((attrptr = ippFindAttribute(response, "notify-subscription-id",
IPP_TAG_INTEGER)) != NULL)
- subscription_id = attrptr->values[0].integer;
+ {
+ snprintf(temp, sizeof(temp), "%d", attrptr->values[0].integer);
+ set_variable(vars, "notify-subscription-id", temp);
+ }
+
+ attrptr = response->attrs;
+ if (!attrptr || !attrptr->name ||
+ attrptr->value_tag != IPP_TAG_CHARSET ||
+ attrptr->group_tag != IPP_TAG_OPERATION ||
+ attrptr->num_values != 1 ||
+ strcmp(attrptr->name, "attributes-charset"))
+ pass = 0;
+
+ if (attrptr)
+ {
+ attrptr = attrptr->next;
+ if (!attrptr || !attrptr->name ||
+ attrptr->value_tag != IPP_TAG_LANGUAGE ||
+ attrptr->group_tag != IPP_TAG_OPERATION ||
+ attrptr->num_values != 1 ||
+ strcmp(attrptr->name, "attributes-natural-language"))
+ pass = 0;
+ }
+
+ if ((attrptr = ippFindAttribute(response, "status-message",
+ IPP_TAG_ZERO)) != NULL &&
+ (attrptr->value_tag != IPP_TAG_TEXT ||
+ attrptr->group_tag != IPP_TAG_OPERATION ||
+ attrptr->num_values != 1 ||
+ (attrptr->value_tag == IPP_TAG_TEXT &&
+ strlen(attrptr->values[0].string.text) > 255)))
+ pass = 0;
+
+ if ((attrptr = ippFindAttribute(response, "detailed-status-message",
+ IPP_TAG_ZERO)) != NULL &&
+ (attrptr->value_tag != IPP_TAG_TEXT ||
+ attrptr->group_tag != IPP_TAG_OPERATION ||
+ attrptr->num_values != 1 ||
+ (attrptr->value_tag == IPP_TAG_TEXT &&
+ strlen(attrptr->values[0].string.text) > 1023)))
+ pass = 0;
+
+ for (attrptr = response->attrs, group = attrptr->group_tag;
+ attrptr;
+ attrptr = attrptr->next)
+ {
+ if (attrptr->group_tag < group && attrptr->group_tag != IPP_TAG_ZERO)
+ {
+ pass = 0;
+ break;
+ }
+
+ if (!validate_attr(attrptr, 0))
+ {
+ pass = 0;
+ break;
+ }
+ }
for (i = 0; i < num_statuses; i ++)
- if (response->request.status.status_code == statuses[i])
+ {
+ if (statuses[i].if_defined &&
+ !get_variable(vars, statuses[i].if_defined))
+ continue;
+
+ if (statuses[i].if_undefined &&
+ get_variable(vars, statuses[i].if_undefined))
+ continue;
+
+ if (response->request.status.status_code == statuses[i].status)
break;
+ }
if (i == num_statuses && num_statuses > 0)
pass = 0;
{
for (i = num_expects, expect = expects; i > 0; i --, expect ++)
{
- if (expect->if_defined && !getenv(expect->if_defined))
+ if (expect->if_defined && !get_variable(vars, expect->if_defined))
+ continue;
+
+ if (expect->if_undefined && get_variable(vars, expect->if_undefined))
continue;
found = ippFindAttribute(response, expect->name, IPP_TAG_ZERO);
- if ((found == NULL) != expect->not_expect ||
- (found && !expect_matches(expect, found->value_tag)))
+ if ((found && expect->not_expect) ||
+ (!found && !(expect->not_expect || expect->optional)) ||
+ (found && !expect_matches(expect, found->value_tag)) ||
+ (found && expect->in_group &&
+ found->group_tag != expect->in_group))
{
pass = 0;
break;
}
+ if (found &&
+ !with_value(expect->with_value, expect->with_regex, found))
+ {
+ pass = 0;
+ break;
+ }
+
+ if (found && expect->count > 0 && found->num_values != expect->count)
+ {
+ pass = 0;
+ break;
+ }
+
if (found && expect->same_count_as)
{
attrptr = ippFindAttribute(response, expect->same_count_as,
}
}
}
+ }
+
+ if (XML)
+ {
+ puts("<key>Successful</key>");
+ puts(pass ? "<true />" : "<false />");
+ puts("<key>StatusCode</key>");
+ print_xml_string("string", ippErrorString(cupsLastError()));
+ puts("<key>ResponseAttributes</key>");
+ puts("<dict>");
+ for (attrptr = response ? response->attrs : NULL;
+ attrptr;
+ attrptr = attrptr->next)
+ print_attr(attrptr);
+ puts("</dict>");
+ }
+ else
+ {
+ puts(pass ? "PASS]" : "FAIL]");
- if (pass)
+ if (Verbosity && response)
{
- puts("PASS]");
printf(" RECEIVED: %lu bytes in response\n",
(unsigned long)ippLength(response));
+ printf(" status-code = %x (%s)\n", cupsLastError(),
+ ippErrorString(cupsLastError()));
- if (Verbosity)
- {
- for (attrptr = response->attrs;
- attrptr != NULL;
- attrptr = attrptr->next)
- {
- print_attr(attrptr);
- }
- }
- else if (num_displayed > 0)
+ for (attrptr = response->attrs;
+ attrptr != NULL;
+ attrptr = attrptr->next)
{
- for (attrptr = response->attrs;
- attrptr != NULL;
- attrptr = attrptr->next)
- {
- if (attrptr->name)
+ print_attr(attrptr);
+ }
+ }
+ }
+
+ if (pass && !XML && !Verbosity && num_displayed > 0)
+ {
+ for (attrptr = response->attrs;
+ attrptr != NULL;
+ attrptr = attrptr->next)
+ if (attrptr->name)
+ for (i = 0; i < num_displayed; i ++)
+ if (!strcmp(displayed[i], attrptr->name))
{
- for (i = 0; i < num_displayed; i ++)
- {
- if (!strcmp(displayed[i], attrptr->name))
- {
- print_attr(attrptr);
- break;
- }
- }
+ print_attr(attrptr);
+ break;
}
- }
- }
+ }
+ else if (!pass)
+ {
+ if (XML)
+ {
+ puts("<key>Errors</key>");
+ puts("<array>");
}
+
+ if (http->version != HTTP_1_1)
+ print_test_error("Bad HTTP version (%d.%d)", http->version / 100,
+ http->version % 100);
+
+ if (!response)
+ print_test_error("IPP request failed with status %s (%s)",
+ ippErrorString(cupsLastError()),
+ cupsLastErrorString());
else
{
- puts("FAIL]");
- printf(" RECEIVED: %lu bytes in response\n",
- (unsigned long)ippLength(response));
+ if (response->request.status.version[0] != (version / 10) ||
+ response->request.status.version[1] != (version % 10))
+ print_test_error("Bad version %d.%d in response - expected %d.%d "
+ "(RFC 2911 section 3.1.8).",
+ response->request.status.version[0],
+ response->request.status.version[1],
+ version / 10, version % 10);
+
+ if (response->request.status.request_id != request_id)
+ print_test_error("Bad request ID %d in response - expected %d "
+ "(RFC 2911 section 3.1.1)",
+ response->request.status.request_id, request_id);
+
+ attrptr = response->attrs;
+ if (!attrptr)
+ print_test_error("Missing first attribute \"attributes-charset "
+ "(charset)\" in group operation-attributes-tag "
+ "(RFC 2911 section 3.1.4).");
+ else
+ {
+ if (!attrptr->name ||
+ attrptr->value_tag != IPP_TAG_CHARSET ||
+ attrptr->group_tag != IPP_TAG_OPERATION ||
+ attrptr->num_values != 1 ||
+ strcmp(attrptr->name, "attributes-charset"))
+ print_test_error("Bad first attribute \"%s (%s%s)\" in group %s, "
+ "expected \"attributes-charset (charset)\" in "
+ "group operation-attributes-tag (RFC 2911 section "
+ "3.1.4).",
+ attrptr->name ? attrptr->name : "(null)",
+ attrptr->num_values > 1 ? "1setOf " : "",
+ ippTagString(attrptr->value_tag),
+ ippTagString(attrptr->group_tag));
+
+ attrptr = attrptr->next;
+ if (!attrptr)
+ print_test_error("Missing second attribute \"attributes-natural-"
+ "language (naturalLanguage)\" in group "
+ "operation-attributes-tag (RFC 2911 section "
+ "3.1.4).");
+ else if (!attrptr->name ||
+ attrptr->value_tag != IPP_TAG_LANGUAGE ||
+ attrptr->group_tag != IPP_TAG_OPERATION ||
+ attrptr->num_values != 1 ||
+ strcmp(attrptr->name, "attributes-natural-language"))
+ print_test_error("Bad first attribute \"%s (%s%s)\" in group %s, "
+ "expected \"attributes-natural-language "
+ "(naturalLanguage)\" in group "
+ "operation-attributes-tag (RFC 2911 section "
+ "3.1.4).",
+ attrptr->name ? attrptr->name : "(null)",
+ attrptr->num_values > 1 ? "1setOf " : "",
+ ippTagString(attrptr->value_tag),
+ ippTagString(attrptr->group_tag));
+ }
+
+ if ((attrptr = ippFindAttribute(response, "status-message",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ if (attrptr->value_tag != IPP_TAG_TEXT)
+ print_test_error("status-message (text(255)) has wrong value tag "
+ "%s (RFC 2911 section 3.1.6.2).",
+ ippTagString(attrptr->value_tag));
+ if (attrptr->group_tag != IPP_TAG_OPERATION)
+ print_test_error("status-message (text(255)) has wrong group tag "
+ "%s (RFC 2911 section 3.1.6.2).",
+ ippTagString(attrptr->group_tag));
+ if (attrptr->num_values != 1)
+ print_test_error("status-message (text(255)) has %d values "
+ "(RFC 2911 section 3.1.6.2).",
+ attrptr->num_values);
+ if (attrptr->value_tag == IPP_TAG_TEXT &&
+ strlen(attrptr->values[0].string.text) > 255)
+ print_test_error("status-message (text(255)) has bad length %d"
+ " (RFC 2911 section 3.1.6.2).",
+ (int)strlen(attrptr->values[0].string.text));
+ }
- if (http->version != HTTP_1_1)
- printf(" BAD HTTP VERSION (%d.%d)\n", http->version / 100,
- http->version % 100);
+ if ((attrptr = ippFindAttribute(response, "detailed-status-message",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ if (attrptr->value_tag != IPP_TAG_TEXT)
+ print_test_error("detailed-status-message (text(MAX)) has wrong "
+ "value tag %s (RFC 2911 section 3.1.6.3).",
+ ippTagString(attrptr->value_tag));
+ if (attrptr->group_tag != IPP_TAG_OPERATION)
+ print_test_error("detailed-status-message (text(MAX)) has wrong "
+ "group tag %s (RFC 2911 section 3.1.6.3).",
+ ippTagString(attrptr->group_tag));
+ if (attrptr->num_values != 1)
+ print_test_error("detailed-status-message (text(MAX)) has %d values"
+ " (RFC 2911 section 3.1.6.3).",
+ attrptr->num_values);
+ if (attrptr->value_tag == IPP_TAG_TEXT &&
+ strlen(attrptr->values[0].string.text) > 1023)
+ print_test_error("detailed-status-message (text(MAX)) has bad "
+ "length %d (RFC 2911 section 3.1.6.3).",
+ (int)strlen(attrptr->values[0].string.text));
+ }
+
+ for (attrptr = response->attrs, group = attrptr->group_tag;
+ attrptr;
+ attrptr = attrptr->next)
+ {
+ if (attrptr->group_tag < group && attrptr->group_tag != IPP_TAG_ZERO)
+ print_test_error("Attribute groups out of order (%s < %s)",
+ ippTagString(attrptr->group_tag),
+ ippTagString(group));
+
+ validate_attr(attrptr, 1);
+ }
for (i = 0; i < num_statuses; i ++)
- if (response->request.status.status_code == statuses[i])
+ {
+ if (statuses[i].if_defined &&
+ !get_variable(vars, statuses[i].if_defined))
+ continue;
+
+ if (statuses[i].if_undefined &&
+ get_variable(vars, statuses[i].if_undefined))
+ continue;
+
+ if (response->request.status.status_code == statuses[i].status)
break;
+ }
if (i == num_statuses && num_statuses > 0)
- puts(" BAD STATUS");
+ {
+ print_test_error("Bad status-code (%s)",
+ ippErrorString(cupsLastError()));
+ print_test_error("status-message=\"%s\"", cupsLastErrorString());
+ }
- printf(" status-code = %04x (%s)\n",
- cupsLastError(), ippErrorString(cupsLastError()));
+ for (i = num_expects, expect = expects; i > 0; i --, expect ++)
+ {
+ if (expect->if_defined && !get_variable(vars, expect->if_defined))
+ continue;
+
+ if (expect->if_undefined && get_variable(vars, expect->if_undefined))
+ continue;
+
+ found = ippFindAttribute(response, expect->name, IPP_TAG_ZERO);
+
+ if (found && expect->not_expect)
+ print_test_error("NOT EXPECTED: %s", expect->name);
+ else if (!found && !(expect->not_expect || expect->optional))
+ print_test_error("EXPECTED: %s", expect->name);
+ else if (found)
+ {
+ if (!expect_matches(expect, found->value_tag))
+ print_test_error("EXPECTED: %s OF-TYPE %s (got %s)",
+ expect->name, expect->of_type,
+ ippTagString(found->value_tag));
- for (i = num_expects, expect = expects; i > 0; i --, expect ++)
- {
- if (expect->if_defined && !getenv(expect->if_defined))
- continue;
+ if (expect->in_group && found->group_tag != expect->in_group)
+ print_test_error("EXPECTED: %s IN-GROUP %s (got %s).",
+ expect->name, ippTagString(expect->in_group),
+ ippTagString(found->group_tag));
- found = ippFindAttribute(response, expect->name, IPP_TAG_ZERO);
+ if (!with_value(expect->with_value, expect->with_regex, found))
+ {
+ if (expect->with_regex)
+ print_test_error("EXPECTED: %s WITH-VALUE /%s/",
+ expect->name, expect->with_value);
+ else
+ print_test_error("EXPECTED: %s WITH-VALUE \"%s\"",
+ expect->name, expect->with_value);
+ }
- if ((found == NULL) != expect->not_expect)
- {
- if (expect->not_expect)
- printf(" NOT EXPECTED: %s\n", expect->name);
- else
- printf(" EXPECTED: %s\n", expect->name);
- }
- else if (found)
- {
- if (!expect_matches(expect, found->value_tag))
- printf(" EXPECTED: %s of type %s but got %s\n",
- expect->name, expect->of_type,
- ippTagString(found->value_tag));
- else if (expect->same_count_as)
+ if (expect->count > 0 && found->num_values != expect->count)
+ {
+ print_test_error("EXPECTED: %s COUNT %d (got %d)", expect->name,
+ expect->count, found->num_values);
+ }
+
+ if (expect->same_count_as)
{
attrptr = ippFindAttribute(response, expect->same_count_as,
IPP_TAG_ZERO);
-
+
if (!attrptr)
- printf(" EXPECTED: %s (%d values) same count as %s "
- "(not returned)\n",
- expect->name, found->num_values, expect->same_count_as);
+ print_test_error("EXPECTED: %s (%d values) SAME-COUNT-AS %s "
+ "(not returned)", expect->name,
+ found->num_values, expect->same_count_as);
else if (attrptr->num_values != found->num_values)
- printf(" EXPECTED: %s (%d values) same count as %s "
- "(%d values)\n",
- expect->name, found->num_values, expect->same_count_as,
- attrptr->num_values);
+ print_test_error("EXPECTED: %s (%d values) SAME-COUNT-AS %s "
+ "(%d values)", expect->name, found->num_values,
+ expect->same_count_as, attrptr->num_values);
}
}
- }
-
- for (attrptr = response->attrs; attrptr != NULL; attrptr = attrptr->next)
- print_attr(attrptr);
+ }
}
- ippDelete(response);
+ if (XML)
+ puts("</array>");
+ }
+
+ if (XML)
+ puts("</dict>");
+
+ ippDelete(response);
+ response = NULL;
+
+ for (i = 0; i < num_statuses; i ++)
+ {
+ if (statuses[i].if_defined)
+ free(statuses[i].if_defined);
+ if (statuses[i].if_undefined)
+ free(statuses[i].if_undefined);
}
+ num_statuses = 0;
for (i = num_expects, expect = expects; i > 0; i --, expect ++)
{
free(expect->same_count_as);
if (expect->if_defined)
free(expect->if_defined);
+ if (expect->if_undefined)
+ free(expect->if_undefined);
+ if (expect->with_value)
+ free(expect->with_value);
}
+ num_expects = 0;
+
+ for (i = 0; i < num_displayed; i ++)
+ free(displayed[i]);
+ num_displayed = 0;
+
if (!pass)
break;
}
httpClose(http);
return (pass);
-}
+ /*
+ * If we get here there was a fatal test error...
+ */
-/*
- * 'expect_matches()' - Return true if the tag matches the specification.
- */
+ test_error:
+
+ if (fp)
+ fclose(fp);
+
+ httpClose(http);
+ ippDelete(request);
+ ippDelete(response);
+
+ for (i = 0; i < num_statuses; i ++)
+ {
+ if (statuses[i].if_defined)
+ free(statuses[i].if_defined);
+ if (statuses[i].if_undefined)
+ free(statuses[i].if_undefined);
+ }
+
+ for (i = num_expects, expect = expects; i > 0; i --, expect ++)
+ {
+ free(expect->name);
+ if (expect->of_type)
+ free(expect->of_type);
+ if (expect->same_count_as)
+ free(expect->same_count_as);
+ if (expect->if_defined)
+ free(expect->if_defined);
+ if (expect->if_undefined)
+ free(expect->if_undefined);
+ if (expect->with_value)
+ free(expect->with_value);
+ }
+
+ for (i = 0; i < num_displayed; i ++)
+ free(displayed[i]);
+
+ return (0);
+}
+
+
+/*
+ * 'expand_variables()' - Expand variables in a string.
+ */
+
+static void
+expand_variables(_cups_vars_t *vars, /* I - Variables */
+ char *dst, /* I - Destination string buffer */
+ const char *src, /* I - Source string */
+ size_t dstsize) /* I - Size of destination buffer */
+{
+ char *dstptr, /* Pointer into destination */
+ *dstend, /* End of destination */
+ temp[256], /* Temporary string */
+ *tempptr; /* Pointer into temporary string */
+ const char *value; /* Value to substitute */
+
+
+ dstptr = dst;
+ dstend = dst + dstsize - 1;
+
+ while (*src && dstptr < dstend)
+ {
+ if (*src == '$')
+ {
+ /*
+ * Substitute a string/number...
+ */
+
+ if (!strncmp(src, "$$", 2))
+ {
+ value = "$";
+ src += 2;
+ }
+ else if (!strncmp(src, "$ENV[", 5))
+ {
+ strlcpy(temp, src + 5, sizeof(temp));
+
+ for (tempptr = temp; *tempptr; tempptr ++)
+ if (*tempptr == ']')
+ break;
+
+ if (*tempptr)
+ *tempptr++ = '\0';
+
+ value = getenv(temp);
+ src += tempptr - temp + 5;
+ }
+ else if (vars)
+ {
+ strlcpy(temp, src + 1, sizeof(temp));
+
+ for (tempptr = temp; *tempptr; tempptr ++)
+ if (!isalnum(*tempptr & 255) && *tempptr != '-' && *tempptr != '_')
+ break;
+
+ if (*tempptr)
+ *tempptr = '\0';
+
+ if (!strcmp(temp, "uri"))
+ value = vars->uri;
+ else if (!strcmp(temp, "filename"))
+ value = vars->filename;
+ else if (!strcmp(temp, "scheme") || !strcmp(temp, "method"))
+ value = vars->scheme;
+ else if (!strcmp(temp, "username"))
+ value = vars->userpass;
+ else if (!strcmp(temp, "hostname"))
+ value = vars->hostname;
+ else if (!strcmp(temp, "port"))
+ {
+ snprintf(temp, sizeof(temp), "%d", vars->port);
+ value = temp;
+ }
+ else if (!strcmp(temp, "resource"))
+ value = vars->resource;
+ else if (!strcmp(temp, "user"))
+ value = cupsUser();
+ else
+ value = get_variable(vars, temp);
+
+ src += tempptr - temp + 1;
+ }
+ else
+ {
+ value = "$";
+ src ++;
+ }
+
+ if (value)
+ {
+ strlcpy(dstptr, value, dstend - dstptr + 1);
+ dstptr += strlen(dstptr);
+ }
+ }
+ else
+ *dstptr++ = *src++;
+ }
+
+ *dstptr = '\0';
+}
+
+
+/*
+ * 'expect_matches()' - Return true if the tag matches the specification.
+ */
static int /* O - 1 if matches, 0 otherwise */
expect_matches(
{
int match; /* Match? */
char *of_type, /* Type name to match */
- *next; /* Next name to match */
+ *next, /* Next name to match */
+ sep; /* Separator character */
/*
/*
* Parse the "of_type" value since the string can contain multiple attribute
- * types separated by "|"...
+ * types separated by "," or "|"...
*/
for (of_type = expect->of_type, match = 0; !match && of_type; of_type = next)
* Find the next separator, and set it (temporarily) to nul if present.
*/
- if ((next = strchr(of_type, '|')) != NULL)
+ for (next = of_type; *next && *next != '|' && *next != ','; next ++);
+
+ if ((sep = *next) != '\0')
*next = '\0';
/*
* Restore the separator if we have one...
*/
- if (next)
- *next++ = '|';
+ if (sep)
+ *next++ = sep;
}
return (match);
}
+/*
+ * 'get_collection()' - Get a collection value from the current test file.
+ */
+
+static ipp_t * /* O - Collection value */
+get_collection(_cups_vars_t *vars, /* I - Variables */
+ FILE *fp, /* I - File to read from */
+ int *linenum) /* IO - Line number */
+{
+ char token[1024], /* Token from file */
+ temp[1024], /* Temporary string */
+ attr[128]; /* Attribute name */
+ ipp_tag_t value; /* Current value type */
+ ipp_t *col = ippNew(); /* Collection value */
+ ipp_attribute_t *lastcol = NULL; /* Last collection attribute */
+
+
+ while (get_token(fp, token, sizeof(token), linenum) != NULL)
+ {
+ if (!strcmp(token, "}"))
+ break;
+ else if (!strcmp(token, "{") && lastcol)
+ {
+ /*
+ * Another collection value
+ */
+
+ ipp_t *subcol = get_collection(vars, fp, linenum);
+ /* Collection value */
+
+ if (subcol)
+ {
+ ipp_attribute_t *tempcol; /* Pointer to new buffer */
+
+
+ /*
+ * Reallocate memory...
+ */
+
+ if ((tempcol = realloc(lastcol, sizeof(ipp_attribute_t) +
+ (lastcol->num_values + 1) *
+ sizeof(ipp_value_t))) == NULL)
+ {
+ print_fatal_error("Unable to allocate memory on line %d.", *linenum);
+ goto col_error;
+ }
+
+ if (tempcol != lastcol)
+ {
+ /*
+ * Reset pointers in the list...
+ */
+
+ if (col->prev)
+ col->prev->next = tempcol;
+ else
+ col->attrs = tempcol;
+
+ lastcol = col->current = col->last = tempcol;
+ }
+
+ lastcol->values[lastcol->num_values].collection = subcol;
+ lastcol->num_values ++;
+ }
+ else
+ goto col_error;
+ }
+ else if (!strcasecmp(token, "MEMBER"))
+ {
+ /*
+ * Attribute...
+ */
+
+ lastcol = NULL;
+
+ if (!get_token(fp, token, sizeof(token), linenum))
+ {
+ print_fatal_error("Missing MEMBER value tag on line %d.", *linenum);
+ goto col_error;
+ }
+
+ if ((value = ippTagValue(token)) < 0)
+ {
+ print_fatal_error("Bad MEMBER value tag \"%s\" on line %d.", token,
+ *linenum);
+ goto col_error;
+ }
+
+ if (!get_token(fp, attr, sizeof(attr), linenum))
+ {
+ print_fatal_error("Missing MEMBER name on line %d.", *linenum);
+ goto col_error;
+ }
+
+ if (!get_token(fp, temp, sizeof(temp), linenum))
+ {
+ print_fatal_error("Missing MEMBER value on line %d.", *linenum);
+ goto col_error;
+ }
+
+ expand_variables(vars, token, temp, sizeof(token));
+
+ switch (value)
+ {
+ case IPP_TAG_BOOLEAN :
+ if (!strcasecmp(token, "true"))
+ ippAddBoolean(col, IPP_TAG_ZERO, attr, 1);
+ else
+ ippAddBoolean(col, IPP_TAG_ZERO, attr, atoi(token));
+ break;
+
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ ippAddInteger(col, IPP_TAG_ZERO, value, attr, atoi(token));
+ break;
+
+ case IPP_TAG_RESOLUTION :
+ {
+ int xres, /* X resolution */
+ yres; /* Y resolution */
+ char units[6]; /* Units */
+
+ if (sscanf(token, "%dx%d%5s", &xres, &yres, units) != 3 ||
+ (strcasecmp(units, "dpi") && strcasecmp(units, "dpc") &&
+ strcasecmp(units, "other")))
+ {
+ print_fatal_error("Bad resolution value \"%s\" on line %d.",
+ token, *linenum);
+ goto col_error;
+ }
+
+ if (!strcasecmp(units, "dpi"))
+ ippAddResolution(col, IPP_TAG_ZERO, attr, xres, yres,
+ IPP_RES_PER_INCH);
+ else if (!strcasecmp(units, "dpc"))
+ ippAddResolution(col, IPP_TAG_ZERO, attr, xres, yres,
+ IPP_RES_PER_CM);
+ else
+ ippAddResolution(col, IPP_TAG_ZERO, attr, xres, yres,
+ (ipp_res_t)0);
+ }
+ break;
+
+ case IPP_TAG_RANGE :
+ {
+ int lowers[4], /* Lower value */
+ uppers[4], /* Upper values */
+ num_vals; /* Number of values */
+
+
+ num_vals = sscanf(token, "%d-%d,%d-%d,%d-%d,%d-%d",
+ lowers + 0, uppers + 0,
+ lowers + 1, uppers + 1,
+ lowers + 2, uppers + 2,
+ lowers + 3, uppers + 3);
+
+ if ((num_vals & 1) || num_vals == 0)
+ {
+ print_fatal_error("Bad rangeOfInteger value \"%s\" on line %d.",
+ token, *linenum);
+ goto col_error;
+ }
+
+ ippAddRanges(col, IPP_TAG_ZERO, attr, num_vals / 2, lowers,
+ uppers);
+ }
+ break;
+
+ case IPP_TAG_BEGIN_COLLECTION :
+ if (!strcmp(token, "{"))
+ {
+ ipp_t *subcol = get_collection(vars, fp, linenum);
+ /* Collection value */
+
+ if (subcol)
+ lastcol = ippAddCollection(col, IPP_TAG_ZERO, attr, subcol);
+ else
+ goto col_error;
+ }
+ else
+ {
+ print_fatal_error("Bad collection value on line %d.", *linenum);
+ goto col_error;
+ }
+ break;
+
+ default :
+ if (!strchr(token, ','))
+ ippAddString(col, IPP_TAG_ZERO, value, attr, NULL, token);
+ else
+ {
+ /*
+ * Multiple string values...
+ */
+
+ int num_values; /* Number of values */
+ char *values[100], /* Values */
+ *ptr; /* Pointer to next value */
+
+
+ values[0] = token;
+ num_values = 1;
+
+ for (ptr = strchr(token, ','); ptr; ptr = strchr(ptr, ','))
+ {
+ *ptr++ = '\0';
+ values[num_values] = ptr;
+ num_values ++;
+ }
+
+ ippAddStrings(col, IPP_TAG_ZERO, value, attr, num_values,
+ NULL, (const char **)values);
+ }
+ break;
+ }
+ }
+ }
+
+ return (col);
+
+ /*
+ * If we get here there was a parse error; free memory and return.
+ */
+
+ col_error:
+
+ ippDelete(col);
+
+ return (NULL);
+}
+
+
+/*
+ * 'get_filename()' - Get a filename based on the current test file.
+ */
+
+static char * /* O - Filename */
+get_filename(const char *testfile, /* I - Current test file */
+ char *dst, /* I - Destination filename */
+ const char *src, /* I - Source filename */
+ size_t dstsize) /* I - Size of destination buffer */
+{
+ char *dstptr; /* Pointer into destination */
+ _cups_globals_t *cg = _cupsGlobals();
+ /* Global data */
+
+
+ if (*src == '<' && src[strlen(src) - 1] == '>')
+ {
+ /*
+ * Map <filename> to CUPS_DATADIR/ipptest/filename...
+ */
+
+ snprintf(dst, dstsize, "%s/ipptest/%s", cg->cups_datadir, src + 1);
+ dstptr = dst + strlen(dst) - 1;
+ if (*dstptr == '>')
+ *dstptr = '\0';
+ }
+ else if (*src == '/' || !strchr(testfile, '/'))
+ {
+ /*
+ * Use the path as-is...
+ */
+
+ strlcpy(dst, src, dstsize);
+ }
+ else
+ {
+ /*
+ * Make path relative to testfile...
+ */
+
+ strlcpy(dst, testfile, dstsize);
+ if ((dstptr = strrchr(dst, '/')) != NULL)
+ dstptr ++;
+ else
+ dstptr = dst; /* Should never happen */
+
+ strlcpy(dstptr, src, dstsize - (dstptr - dst));
+ }
+
+ return (dst);
+}
+
+
/*
* 'get_token()' - Get a token from a file.
*/
else if (ch == '\'' || ch == '\"')
{
/*
- * Quoted text...
+ * Quoted text or regular expression...
*/
quote = ch;
bufend = buf + buflen - 1;
while ((ch = getc(fp)) != EOF)
- if (ch == quote)
+ {
+ if (ch == '\\')
+ {
+ /*
+ * Escape next character...
+ */
+
+ if (bufptr < bufend)
+ *bufptr++ = ch;
+
+ if ((ch = getc(fp)) != EOF && bufptr < bufend)
+ *bufptr++ = ch;
+ }
+ else if (ch == quote)
break;
else if (bufptr < bufend)
*bufptr++ = ch;
+ }
*bufptr = '\0';
+
return (buf);
}
else if (ch == '#')
if (ch == '#')
ungetc(ch, fp);
-
+ else if (ch == '\n')
+ (*linenum) ++;
+
*bufptr = '\0';
+
return (buf);
}
}
}
+/*
+ * 'get_variable()' - Get the value of a variable.
+ */
+
+static char * /* O - Value or NULL */
+get_variable(_cups_vars_t *vars, /* I - Variables */
+ const char *name) /* I - Variable name */
+{
+ _cups_var_t key, /* Search key */
+ *match; /* Matching variable, if any */
+
+
+ key.name = (char *)name;
+ match = cupsArrayFind(vars->vars, &key);
+
+ return (match ? match->value : NULL);
+}
+
+
+/*
+ * 'iso_date()' - Return an ISO 8601 date/time string for the given IPP dateTime
+ * value.
+ */
+
+static char * /* O - ISO 8601 date/time string */
+iso_date(ipp_uchar_t *date) /* I - IPP (RFC 1903) date/time value */
+{
+ unsigned year = (date[0] << 8) + date[1];
+ /* Year */
+ static char buffer[255]; /* String buffer */
+
+
+ if (date[9] == 0 && date[10] == 0)
+ snprintf(buffer, sizeof(buffer), "%04u-%02u-%02uT%02u:%02u:%02uZ",
+ year, date[2], date[3], date[4], date[5], date[6]);
+ else
+ snprintf(buffer, sizeof(buffer), "%04u-%02u-%02uT%02u:%02u:%02u%c%02u%02u",
+ year, date[2], date[3], date[4], date[5], date[6],
+ date[8], date[9], date[10]);
+
+ return (buffer);
+}
+
+
/*
* 'print_attr()' - Print an attribute on the screen.
*/
static void
print_attr(ipp_attribute_t *attr) /* I - Attribute to print */
{
- int i; /* Looping var */
+ int i; /* Looping var */
+ ipp_attribute_t *colattr; /* Collection attribute */
- if (attr->name == NULL)
+ if (XML)
{
- puts(" -- separator --");
- return;
+ if (!attr->name)
+ {
+ printf("<key>%s</key>\n<true />\n", ippTagString(attr->group_tag));
+ return;
+ }
+
+ print_xml_string("key", attr->name);
+ if (attr->num_values > 1)
+ puts("<array>");
}
+ else
+ {
+ if (!attr->name)
+ {
+ puts(" -- separator --");
+ return;
+ }
- printf(" %s (%s%s) = ", attr->name,
- attr->num_values > 1 ? "1setOf " : "",
- ippTagString(attr->value_tag));
+ printf(" %s (%s%s) = ", attr->name,
+ attr->num_values > 1 ? "1setOf " : "",
+ ippTagString(attr->value_tag));
+ }
switch (attr->value_tag)
{
case IPP_TAG_INTEGER :
case IPP_TAG_ENUM :
for (i = 0; i < attr->num_values; i ++)
- printf("%d ", attr->values[i].integer);
+ if (XML)
+ printf("<integer>%d</integer>\n", attr->values[i].integer);
+ else
+ printf("%d ", attr->values[i].integer);
break;
case IPP_TAG_BOOLEAN :
for (i = 0; i < attr->num_values; i ++)
- if (attr->values[i].boolean)
- printf("true ");
+ if (XML)
+ puts(attr->values[i].boolean ? "<true />" : "<false />");
+ else if (attr->values[i].boolean)
+ fputs("true ", stdout);
else
- printf("false ");
- break;
-
- case IPP_TAG_NOVALUE :
- printf("novalue");
+ fputs("false ", stdout);
break;
case IPP_TAG_RANGE :
for (i = 0; i < attr->num_values; i ++)
- printf("%d-%d ", attr->values[i].range.lower,
- attr->values[i].range.upper);
+ if (XML)
+ printf("<dict><key>lower</key><integer>%d</integer>"
+ "<key>upper</key><integer>%d</integer></dict>\n",
+ attr->values[i].range.lower, attr->values[i].range.upper);
+ else
+ printf("%d-%d ", attr->values[i].range.lower,
+ attr->values[i].range.upper);
break;
case IPP_TAG_RESOLUTION :
for (i = 0; i < attr->num_values; i ++)
- printf("%dx%d%s ", attr->values[i].resolution.xres,
- attr->values[i].resolution.yres,
- attr->values[i].resolution.units == IPP_RES_PER_INCH ?
- "dpi" : "dpc");
- break;
-
- case IPP_TAG_STRING :
- case IPP_TAG_TEXT :
- case IPP_TAG_NAME :
- case IPP_TAG_KEYWORD :
- case IPP_TAG_CHARSET :
+ if (XML)
+ printf("<dict><key>xres</key><integer>%d</integer>"
+ "<key>yres</key><integer>%d</integer>"
+ "<key>units</key><string>%s</string></dict>\n",
+ attr->values[i].resolution.xres,
+ attr->values[i].resolution.yres,
+ attr->values[i].resolution.units == IPP_RES_PER_INCH ?
+ "dpi" : "dpc");
+ else
+ printf("%dx%d%s ", attr->values[i].resolution.xres,
+ attr->values[i].resolution.yres,
+ attr->values[i].resolution.units == IPP_RES_PER_INCH ?
+ "dpi" : "dpc");
+ break;
+
+ case IPP_TAG_DATE :
+ for (i = 0; i < attr->num_values; i ++)
+ if (XML)
+ printf("<date>%s</date>\n", iso_date(attr->values[i].date));
+ else
+ printf("%s ", iso_date(attr->values[i].date));
+ break;
+
+ case IPP_TAG_STRING :
+ case IPP_TAG_TEXT :
+ case IPP_TAG_NAME :
+ case IPP_TAG_KEYWORD :
+ case IPP_TAG_CHARSET :
case IPP_TAG_URI :
case IPP_TAG_MIMETYPE :
case IPP_TAG_LANGUAGE :
for (i = 0; i < attr->num_values; i ++)
- printf("\"%s\" ", attr->values[i].string.text);
+ if (XML)
+ print_xml_string("string", attr->values[i].string.text);
+ else
+ printf("\"%s\" ", attr->values[i].string.text);
break;
case IPP_TAG_TEXTLANG :
case IPP_TAG_NAMELANG :
for (i = 0; i < attr->num_values; i ++)
- printf("\"%s\",%s ", attr->values[i].string.text,
- attr->values[i].string.charset);
+ if (XML)
+ {
+ fputs("<dict><key>language</key><string>", stdout);
+ print_xml_string(NULL, attr->values[i].string.charset);
+ fputs("</string><key>string</key><string>", stdout);
+ print_xml_string(NULL, attr->values[i].string.text);
+ puts("</string></dict>");
+ }
+ else
+ printf("\"%s\",%s ", attr->values[i].string.text,
+ attr->values[i].string.charset);
break;
case IPP_TAG_BEGIN_COLLECTION :
for (i = 0; i < attr->num_values; i ++)
{
- if (i)
- putchar(' ');
+ if (XML)
+ {
+ puts("<dict>");
+ for (colattr = attr->values[i].collection->attrs;
+ colattr;
+ colattr = colattr->next)
+ print_attr(colattr);
+ puts("</dict>");
+ }
+ else
+ {
+ if (i)
+ putchar(' ');
- print_col(attr->values[i].collection);
+ print_col(attr->values[i].collection);
+ }
}
break;
default :
- break; /* anti-compiler-warning-code */
+ if (XML)
+ printf("<string><<%s>></string>\n",
+ ippTagString(attr->value_tag));
+ else
+ fputs(ippTagString(attr->value_tag), stdout);
+ break;
}
- putchar('\n');
+ if (XML)
+ {
+ if (attr->num_values > 1)
+ puts("</array>");
+ }
+ else
+ putchar('\n');
}
ipp_attribute_t *attr; /* Current attribute in collection */
- putchar('{');
+ fputs("{ ", stdout);
for (attr = col->attrs; attr; attr = attr->next)
{
- printf("%s(%s%s)=", attr->name, attr->num_values > 1 ? "1setOf " : "",
+ printf("%s (%s%s) = ", attr->name, attr->num_values > 1 ? "1setOf " : "",
ippTagString(attr->value_tag));
switch (attr->value_tag)
}
+/*
+ * 'print_fatal_error()' - Print a fatal error message.
+ */
+
+static void
+print_fatal_error(const char *s, /* I - Printf-style format string */
+ ...) /* I - Additional arguments as needed */
+{
+ char buffer[10240]; /* Format buffer */
+ va_list ap; /* Pointer to arguments */
+
+
+ /*
+ * Format the error message...
+ */
+
+ va_start(ap, s);
+ vsnprintf(buffer, sizeof(buffer), s, ap);
+ va_end(ap);
+
+ /*
+ * Then output it...
+ */
+
+ if (XML)
+ {
+ print_xml_header();
+ print_xml_trailer(0, buffer);
+ }
+ else
+ _cupsLangPrintf(stderr, "ipptest: %s\n", buffer);
+}
+
+
+/*
+ * 'print_test_error()' - Print a test error message.
+ */
+
+static void
+print_test_error(const char *s, /* I - Printf-style format string */
+ ...) /* I - Additional arguments as needed */
+{
+ char buffer[10240]; /* Format buffer */
+ va_list ap; /* Pointer to arguments */
+
+
+ /*
+ * Format the error message...
+ */
+
+ va_start(ap, s);
+ vsnprintf(buffer, sizeof(buffer), s, ap);
+ va_end(ap);
+
+ /*
+ * Then output it...
+ */
+
+ if (XML)
+ print_xml_string("string", buffer);
+ else
+ printf(" %s\n", buffer);
+}
+
+
+/*
+ * 'print_xml_header()' - Print a standard XML plist header.
+ */
+
+static void
+print_xml_header(void)
+{
+ if (!XMLHeader)
+ {
+ puts("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+ puts("<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" "
+ "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">");
+ puts("<plist version=\"1.0\">");
+ puts("<dict>");
+ puts("<key>Transfer</key>");
+ printf("<string>%s</string>\n",
+ Transfer == _CUPS_TRANSFER_AUTO ? "auto" :
+ Transfer == _CUPS_TRANSFER_CHUNKED ? "chunked" : "length");
+ puts("<key>Tests</key>");
+ puts("<array>");
+
+ XMLHeader = 1;
+ }
+}
+
+
+/*
+ * 'print_xml_string()' - Print an XML string with escaping.
+ */
+
+static void
+print_xml_string(const char *element, /* I - Element name or NULL */
+ const char *s) /* I - String to print */
+{
+ if (element)
+ printf("<%s>", element);
+
+ while (*s)
+ {
+ if (*s == '&')
+ fputs("&", stdout);
+ else if (*s == '<')
+ fputs("<", stdout);
+ else if (*s == '>')
+ fputs(">", stdout);
+ else
+ putchar(*s);
+
+ s ++;
+ }
+
+ if (element)
+ printf("</%s>\n", element);
+}
+
+
+/*
+ * 'print_xml_trailer()' - Print the XML trailer with success/fail value.
+ */
+
+static void
+print_xml_trailer(int success, /* I - 1 on success, 0 on failure */
+ const char *message) /* I - Error message or NULL */
+{
+ if (XMLHeader)
+ {
+ puts("</array>");
+ puts("<key>Successful</key>");
+ puts(success ? "<true />" : "<false />");
+ if (message)
+ {
+ puts("<key>ErrorMessage</key>");
+ print_xml_string("string", message);
+ }
+ puts("</dict>");
+ puts("</plist>");
+
+ XMLHeader = 0;
+ }
+}
+
+
+/*
+ * 'set_variable()' - Set a variable value.
+ */
+
+static void
+set_variable(_cups_vars_t *vars, /* I - Variables */
+ const char *name, /* I - Variable name */
+ const char *value) /* I - Value string */
+{
+ _cups_var_t key, /* Search key */
+ *var; /* New variable */
+
+
+ key.name = (char *)name;
+ if ((var = cupsArrayFind(vars->vars, &key)) != NULL)
+ {
+ free(var->value);
+ var->value = strdup(value);
+ }
+ else if ((var = malloc(sizeof(_cups_var_t))) == NULL)
+ {
+ print_fatal_error("Unable to allocate memory for variable \"%s\".", name);
+ exit(1);
+ }
+ else
+ {
+ var->name = strdup(name);
+ var->value = strdup(value);
+
+ cupsArrayAdd(vars->vars, var);
+ }
+}
+
+
/*
* 'usage()' - Show program usage.
*/
static void
usage(void)
{
- fputs("Usage: ipptest [options] URL testfile [ ... testfileN ]\n", stderr);
- fputs("Options:\n", stderr);
- fputs("\n", stderr);
- fputs("-c Send requests using chunking.\n", stderr);
- fputs("-d name=value Define variable.\n", stderr);
- fputs("-i seconds Repeat the last test file with the given interval.\n",
- stderr);
- fputs("-v Show all attributes in response, even on success.\n",
- stderr);
+ _cupsLangPuts(stderr,
+ _("Usage: ipptest [options] URI filename.test [ ... "
+ "filenameN.test ]\n"
+ "\n"
+ "Options:\n"
+ "\n"
+ "-E Test with encryption.\n"
+ "-V version Set default IPP version.\n"
+ "-X Produce XML instead of plain text.\n"
+ "-c Send requests using chunking (default)\n"
+ "-d name=value Define variable.\n"
+ "-f filename Set default test file.\n"
+ "-i seconds Repeat the last test file with the given "
+ "interval.\n"
+ "-l Send requests using content-length\n"
+ "-v Show all attributes sent and received.\n"));
exit(1);
}
/*
- * End of "$Id: ipptest.c 7847 2008-08-19 04:22:14Z mike $".
+ * 'validate_attr()' - Determine whether an attribute is valid.
+ */
+
+static int /* O - 1 if valid, 0 otherwise */
+validate_attr(ipp_attribute_t *attr, /* I - Attribute to validate */
+ int print) /* I - 1 = report issues to stdout */
+{
+ int i; /* Looping var */
+ char scheme[64], /* Scheme from URI */
+ userpass[256], /* Username/password from URI */
+ hostname[256], /* Hostname from URI */
+ resource[1024]; /* Resource from URI */
+ int port, /* Port number from URI */
+ uri_status, /* URI separation status */
+ valid = 1; /* Is the attribute valid? */
+ const char *ptr; /* Pointer into string */
+ ipp_attribute_t *colattr; /* Collection attribute */
+ regex_t re; /* Regular expression */
+ ipp_uchar_t *date; /* Current date value */
+
+
+ /*
+ * Skip separators.
+ */
+
+ if (!attr->name)
+ return (1);
+
+ /*
+ * Validate the attribute name.
+ */
+
+ for (ptr = attr->name; *ptr; ptr ++)
+ if (!isalnum(*ptr & 255) && *ptr != '-' && *ptr != '.' && *ptr != '_')
+ break;
+
+ if (*ptr || ptr == attr->name)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad attribute name - invalid character (RFC "
+ "2911 section 4.1.3).", attr->name);
+ }
+
+ if ((ptr - attr->name) > 255)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad attribute name - bad length (RFC 2911 "
+ "section 4.1.3).", attr->name);
+ }
+
+ switch (attr->value_tag)
+ {
+ case IPP_TAG_INTEGER :
+ break;
+
+ case IPP_TAG_BOOLEAN :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (attr->values[i].boolean != 0 &&
+ attr->values[i].boolean != 1)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad boolen value %d (RFC 2911 section "
+ "4.1.10).", attr->name, attr->values[i].boolean);
+ else
+ break;
+ }
+ }
+ break;
+
+ case IPP_TAG_ENUM :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (attr->values[i].integer < 1)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad enum value %d - out of range "
+ "(RFC 2911 section 4.1.4).", attr->name,
+ attr->values[i].integer);
+ else
+ break;
+ }
+ }
+ break;
+
+ case IPP_TAG_STRING :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (attr->values[i].unknown.length > 1023)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad octetString value - bad length %d "
+ "(RFC 2911 section 4.1.10).", attr->name,
+ attr->values[i].unknown.length);
+ else
+ break;
+ }
+ }
+ break;
+
+ case IPP_TAG_DATE :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ date = attr->values[i].date;
+
+ if (date[2] < 1 || date[2] > 12)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad dateTime month %u (RFC 2911 "
+ "section 4.1.13).", attr->name, date[2]);
+ else
+ break;
+ }
+
+ if (date[3] < 1 || date[3] > 31)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad dateTime day %u (RFC 2911 "
+ "section 4.1.13).", attr->name, date[3]);
+ else
+ break;
+ }
+
+ if (date[4] > 23)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad dateTime hours %u (RFC 2911 "
+ "section 4.1.13).", attr->name, date[4]);
+ else
+ break;
+ }
+
+ if (date[5] > 59)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad dateTime minutes %u (RFC 2911 "
+ "section 4.1.13).", attr->name, date[5]);
+ else
+ break;
+ }
+
+ if (date[6] > 60)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad dateTime seconds %u (RFC 2911 "
+ "section 4.1.13).", attr->name, date[6]);
+ else
+ break;
+ }
+
+ if (date[7] > 9)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad dateTime deciseconds %u (RFC 2911 "
+ "section 4.1.13).", attr->name, date[7]);
+ else
+ break;
+ }
+
+ if (date[8] != '-' && date[8] != '+')
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad dateTime UTC sign '%c' (RFC 2911 "
+ "section 4.1.13).", attr->name, date[8]);
+ else
+ break;
+ }
+
+ if (date[9] > 11)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad dateTime UTC hours %u (RFC 2911 "
+ "section 4.1.13).", attr->name, date[9]);
+ else
+ break;
+ }
+
+ if (date[10] > 59)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad dateTime UTC minutes %u (RFC 2911 "
+ "section 4.1.13).", attr->name, date[10]);
+ else
+ break;
+ }
+ }
+ break;
+
+ case IPP_TAG_RESOLUTION :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (attr->values[i].resolution.xres <= 0)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad resolution value %dx%d%s - cross "
+ "feed resolution must be positive (RFC 2911 "
+ "section 4.1.13).", attr->name,
+ attr->values[i].resolution.xres,
+ attr->values[i].resolution.yres,
+ attr->values[i].resolution.units ==
+ IPP_RES_PER_INCH ? "dpi" :
+ attr->values[i].resolution.units ==
+ IPP_RES_PER_CM ? "dpc" : "unknown");
+ else
+ break;
+ }
+
+ if (attr->values[i].resolution.yres <= 0)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad resolution value %dx%d%s - feed "
+ "resolution must be positive (RFC 2911 section "
+ "4.1.13).", attr->name,
+ attr->values[i].resolution.xres,
+ attr->values[i].resolution.yres,
+ attr->values[i].resolution.units ==
+ IPP_RES_PER_INCH ? "dpi" :
+ attr->values[i].resolution.units ==
+ IPP_RES_PER_CM ? "dpc" : "unknown");
+ else
+ break;
+ }
+
+ if (attr->values[i].resolution.units != IPP_RES_PER_INCH &&
+ attr->values[i].resolution.units != IPP_RES_PER_CM)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad resolution value %dx%d%s - bad "
+ "units value (RFC 2911 section 4.1.13).",
+ attr->name, attr->values[i].resolution.xres,
+ attr->values[i].resolution.yres,
+ attr->values[i].resolution.units ==
+ IPP_RES_PER_INCH ? "dpi" :
+ attr->values[i].resolution.units ==
+ IPP_RES_PER_CM ? "dpc" : "unknown");
+ else
+ break;
+ }
+ }
+ break;
+
+ case IPP_TAG_RANGE :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (attr->values[i].range.lower > attr->values[i].range.upper)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad rangeOfInteger value %d-%d - lower "
+ "greater than upper (RFC 2911 section 4.1.13).",
+ attr->name, attr->values[i].range.lower,
+ attr->values[i].range.upper);
+ else
+ break;
+ }
+ }
+ break;
+
+ case IPP_TAG_BEGIN_COLLECTION :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ for (colattr = attr->values[i].collection->attrs;
+ colattr;
+ colattr = colattr->next)
+ {
+ if (!validate_attr(colattr, 0))
+ {
+ valid = 0;
+ break;
+ }
+ }
+
+ if (colattr && print)
+ {
+ print_test_error("\"%s\": Bad collection value.", attr->name);
+
+ while (colattr)
+ {
+ validate_attr(colattr, print);
+ colattr = colattr->next;
+ }
+ }
+ }
+ break;
+
+ case IPP_TAG_TEXT :
+ case IPP_TAG_TEXTLANG :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ for (ptr = attr->values[i].string.text; *ptr; ptr ++)
+ {
+ if ((*ptr & 0xe0) == 0xc0)
+ {
+ ptr ++;
+ if ((*ptr & 0xc0) != 0x80)
+ break;
+ }
+ else if ((*ptr & 0xf0) == 0xe0)
+ {
+ ptr ++;
+ if ((*ptr & 0xc0) != 0x80)
+ break;
+ ptr ++;
+ if ((*ptr & 0xc0) != 0x80)
+ break;
+ }
+ else if ((*ptr & 0xf8) == 0xf0)
+ {
+ ptr ++;
+ if ((*ptr & 0xc0) != 0x80)
+ break;
+ ptr ++;
+ if ((*ptr & 0xc0) != 0x80)
+ break;
+ ptr ++;
+ if ((*ptr & 0xc0) != 0x80)
+ break;
+ }
+ else if (*ptr & 0x80)
+ break;
+ }
+
+ if (*ptr)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad text value \"%s\" - bad UTF-8 "
+ "sequence (RFC 2911 section 4.1.1).", attr->name,
+ attr->values[i].string.text);
+ else
+ break;
+ }
+
+ if ((ptr - attr->values[i].string.text) > 1023)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad text value \"%s\" - bad length %d "
+ "(RFC 2911 section 4.1.1).", attr->name,
+ attr->values[i].string.text,
+ (int)strlen(attr->values[i].string.text));
+ else
+ break;
+ }
+ }
+ break;
+
+ case IPP_TAG_NAME :
+ case IPP_TAG_NAMELANG :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ for (ptr = attr->values[i].string.text; *ptr; ptr ++)
+ {
+ if ((*ptr & 0xe0) == 0xc0)
+ {
+ ptr ++;
+ if ((*ptr & 0xc0) != 0x80)
+ break;
+ }
+ else if ((*ptr & 0xf0) == 0xe0)
+ {
+ ptr ++;
+ if ((*ptr & 0xc0) != 0x80)
+ break;
+ ptr ++;
+ if ((*ptr & 0xc0) != 0x80)
+ break;
+ }
+ else if ((*ptr & 0xf8) == 0xf0)
+ {
+ ptr ++;
+ if ((*ptr & 0xc0) != 0x80)
+ break;
+ ptr ++;
+ if ((*ptr & 0xc0) != 0x80)
+ break;
+ ptr ++;
+ if ((*ptr & 0xc0) != 0x80)
+ break;
+ }
+ else if (*ptr & 0x80)
+ break;
+ }
+
+ if (*ptr)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad name value \"%s\" - bad UTF-8 "
+ "sequence (RFC 2911 section 4.1.2).", attr->name,
+ attr->values[i].string.text);
+ else
+ break;
+ }
+
+ if ((ptr - attr->values[i].string.text) > 1023)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad name value \"%s\" - bad length %d "
+ "(RFC 2911 section 4.1.2).", attr->name,
+ attr->values[i].string.text,
+ (int)strlen(attr->values[i].string.text));
+ else
+ break;
+ }
+ }
+ break;
+
+ case IPP_TAG_KEYWORD :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ for (ptr = attr->values[i].string.text; *ptr; ptr ++)
+ if (!isalnum(*ptr & 255) && *ptr != '-' && *ptr != '.' &&
+ *ptr != '_')
+ break;
+
+ if (*ptr || ptr == attr->values[i].string.text)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad keyword value \"%s\" - invalid "
+ "character (RFC 2911 section 4.1.3).",
+ attr->name, attr->values[i].string.text);
+ else
+ break;
+ }
+
+ if ((ptr - attr->values[i].string.text) > 255)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad keyword value \"%s\" - bad "
+ "length %d (RFC 2911 section 4.1.3).",
+ attr->name, attr->values[i].string.text,
+ (int)strlen(attr->values[i].string.text));
+ else
+ break;
+ }
+ }
+ break;
+
+ case IPP_TAG_URI :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ uri_status = httpSeparateURI(HTTP_URI_CODING_ALL,
+ attr->values[i].string.text,
+ scheme, sizeof(scheme),
+ userpass, sizeof(userpass),
+ hostname, sizeof(hostname),
+ &port, resource, sizeof(resource));
+
+ if (uri_status < HTTP_URI_OK)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad URI value \"%s\" - %s "
+ "(RFC 2911 section 4.1.5).", attr->name,
+ attr->values[i].string.text,
+ URIStatusStrings[uri_status -
+ HTTP_URI_OVERFLOW]);
+ else
+ break;
+ }
+
+ if (strlen(attr->values[i].string.text) > 1023)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad URI value \"%s\" - bad length %d "
+ "(RFC 2911 section 4.1.5).", attr->name,
+ attr->values[i].string.text,
+ (int)strlen(attr->values[i].string.text));
+ else
+ break;
+ }
+ }
+ break;
+
+ case IPP_TAG_URISCHEME :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ ptr = attr->values[i].string.text;
+ if (islower(*ptr & 255))
+ {
+ for (ptr ++; *ptr; ptr ++)
+ if (!islower(*ptr & 255) && !isdigit(*ptr & 255) &&
+ *ptr != '+' && *ptr != '-' && *ptr != '.')
+ break;
+ }
+
+ if (*ptr || ptr == attr->values[i].string.text)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad uriScheme value \"%s\" - bad "
+ "characters (RFC 2911 section 4.1.6).",
+ attr->name, attr->values[i].string.text);
+ else
+ break;
+ }
+
+ if ((ptr - attr->values[i].string.text) > 63)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad uriScheme value \"%s\" - bad "
+ "length %d (RFC 2911 section 4.1.6).",
+ attr->name, attr->values[i].string.text,
+ (int)strlen(attr->values[i].string.text));
+ else
+ break;
+ }
+ }
+ break;
+
+ case IPP_TAG_CHARSET :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ for (ptr = attr->values[i].string.text; *ptr; ptr ++)
+ if (!isprint(*ptr & 255) || isupper(*ptr & 255) ||
+ isspace(*ptr & 255))
+ break;
+
+ if (*ptr || ptr == attr->values[i].string.text)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad charset value \"%s\" - bad "
+ "characters (RFC 2911 section 4.1.7).",
+ attr->name, attr->values[i].string.text);
+ else
+ break;
+ }
+
+ if ((ptr - attr->values[i].string.text) > 40)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad charset value \"%s\" - bad "
+ "length %d (RFC 2911 section 4.1.7).",
+ attr->name, attr->values[i].string.text,
+ (int)strlen(attr->values[i].string.text));
+ else
+ break;
+ }
+ }
+ break;
+
+ case IPP_TAG_LANGUAGE :
+ /*
+ * The following regular expression is derived from the ABNF for
+ * language tags in RFC 4646. All I can say is that this is the
+ * easiest way to check the values...
+ */
+
+ if ((i = regcomp(&re,
+ "^("
+ "(([a-z]{2,3}(-[a-z][a-z][a-z]){0,3})|[a-z]{4,8})"
+ /* language */
+ "(-[a-z][a-z][a-z][a-z]){0,1}" /* script */
+ "(-([a-z][a-z]|[0-9][0-9][0-9])){0,1}" /* region */
+ "(-([a-z]{5,8}|[0-9][0-9][0-9]))*" /* variant */
+ "(-[a-wy-z](-[a-z0-9]{2,8})+)*" /* extension */
+ "(-x(-[a-z0-9]{1,8})+)*" /* privateuse */
+ "|"
+ "x(-[a-z0-9]{1,8})+" /* privateuse */
+ "|"
+ "[a-z]{1,3}(-[a-z][0-9]{2,8}){1,2}" /* grandfathered */
+ ")$",
+ REG_NOSUB | REG_EXTENDED)) != 0)
+ {
+ char temp[256]; /* Temporary error string */
+
+ regerror(i, &re, temp, sizeof(temp));
+ print_fatal_error("Unable to compile naturalLanguage regular "
+ "expression: %s.", temp);
+ }
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (regexec(&re, attr->values[i].string.text, 0, NULL, 0))
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad naturalLanguage value \"%s\" - bad "
+ "characters (RFC 2911 section 4.1.8).",
+ attr->name, attr->values[i].string.text);
+ else
+ break;
+ }
+
+ if (strlen(attr->values[i].string.text) > 63)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad naturalLanguage value \"%s\" - bad "
+ "length %d (RFC 2911 section 4.1.8).",
+ attr->name, attr->values[i].string.text,
+ (int)strlen(attr->values[i].string.text));
+ else
+ break;
+ }
+ }
+
+ regfree(&re);
+ break;
+
+ case IPP_TAG_MIMETYPE :
+ /*
+ * The following regular expression is derived from the ABNF for
+ * language tags in RFC 2045 and 4288. All I can say is that this is
+ * the easiest way to check the values...
+ */
+
+ if ((i = regcomp(&re,
+ "^"
+ "[-a-zA-Z0-9!#$&.+^_]{1,127}" /* type-name */
+ "/"
+ "[-a-zA-Z0-9!#$&.+^_]{1,127}" /* subtype-name */
+ "(;[-a-zA-Z0-9!#$&.+^_]{1,127}=" /* parameter= */
+ "([-a-zA-Z0-9!#$&.+^_]{1,127}|\"[^\"]*\"))*"
+ /* value */
+ "$",
+ REG_NOSUB | REG_EXTENDED)) != 0)
+ {
+ char temp[256]; /* Temporary error string */
+
+ regerror(i, &re, temp, sizeof(temp));
+ print_fatal_error("Unable to compile mimeMediaType regular "
+ "expression: %s.", temp);
+ }
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (regexec(&re, attr->values[i].string.text, 0, NULL, 0))
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad mimeMediaType value \"%s\" - bad "
+ "characters (RFC 2911 section 4.1.9).",
+ attr->name, attr->values[i].string.text);
+ else
+ break;
+ }
+
+ if (strlen(attr->values[i].string.text) > 255)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad mimeMediaType value \"%s\" - bad "
+ "length %d (RFC 2911 section 4.1.9).",
+ attr->name, attr->values[i].string.text,
+ (int)strlen(attr->values[i].string.text));
+ else
+ break;
+ }
+ }
+ break;
+
+ default :
+ break;
+ }
+
+ return (valid);
+}
+
+
+/*
+ * 'with_value()' - Test a WITH-VALUE predicate.
+ */
+
+static int /* O - 1 on match, 0 on non-match */
+with_value(char *value, /* I - Value string */
+ int regex, /* I - Value is a regular expression */
+ ipp_attribute_t *attr) /* I - Attribute to compare */
+{
+ int i; /* Looping var */
+ char *valptr; /* Pointer into value */
+
+
+ /*
+ * NULL matches everything.
+ */
+
+ if (!value || !*value)
+ return (1);
+
+ /*
+ * Compare the value string to the attribute value.
+ */
+
+ switch (attr->value_tag)
+ {
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ char op, /* Comparison operator */
+ *nextptr; /* Next pointer */
+ int intvalue; /* Integer value */
+
+
+ valptr = value;
+ if (!strncmp(valptr, "no-value,", 9))
+ valptr += 9;
+
+ while (isspace(*valptr & 255) || isdigit(*valptr & 255) ||
+ *valptr == '-' || *valptr == ',' || *valptr == '<' ||
+ *valptr == '=' || *valptr == '>')
+ {
+ op = '=';
+ while (*valptr && !isdigit(*valptr & 255) && *valptr != '-')
+ {
+ if (*valptr == '<' || *valptr == '>' || *valptr == '=')
+ op = *valptr;
+ valptr ++;
+ }
+
+ if (!*valptr)
+ break;
+
+ intvalue = strtol(valptr, &nextptr, 0);
+ if (nextptr == valptr)
+ break;
+ valptr = nextptr;
+
+ switch (op)
+ {
+ case '=' :
+ if (attr->values[i].integer == intvalue)
+ return (1);
+ break;
+ case '<' :
+ if (attr->values[i].integer < intvalue)
+ return (1);
+ break;
+ case '>' :
+ if (attr->values[i].integer > intvalue)
+ return (1);
+ break;
+ }
+ }
+ }
+ break;
+
+ case IPP_TAG_BOOLEAN :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (!strcmp(value, "true") == attr->values[i].boolean)
+ return (1);
+ }
+ break;
+
+ case IPP_TAG_NOVALUE :
+ return (!strcmp(value, "no-value") || !strncmp(value, "no-value,", 9));
+
+ case IPP_TAG_CHARSET :
+ case IPP_TAG_KEYWORD :
+ case IPP_TAG_LANGUAGE :
+ case IPP_TAG_MIMETYPE :
+ case IPP_TAG_NAME :
+ case IPP_TAG_NAMELANG :
+ case IPP_TAG_TEXT :
+ case IPP_TAG_TEXTLANG :
+ case IPP_TAG_URI :
+ case IPP_TAG_URISCHEME :
+ if (regex)
+ {
+ /*
+ * Value is an extended, case-sensitive POSIX regular expression...
+ */
+
+ regex_t re; /* Regular expression */
+
+ if ((i = regcomp(&re, value, REG_EXTENDED | REG_NOSUB)) != 0)
+ {
+ char temp[256]; /* Temporary string */
+
+ regerror(i, &re, temp, sizeof(temp));
+
+ print_fatal_error("Unable to compile WITH-VALUE regular expression "
+ "\"%s\" - %s", value, temp);
+ return (0);
+ }
+
+ /*
+ * See if ALL of the values match the given regular expression.
+ */
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (regexec(&re, attr->values[i].string.text, 0, NULL, 0))
+ break;
+ }
+
+ regfree(&re);
+
+ return (i == attr->num_values);
+ }
+ else
+ {
+ /*
+ * Value is a literal string, see if at least one value matches the
+ * literal string...
+ */
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (!strcmp(value, attr->values[i].string.text))
+ return (1);
+ }
+ }
+ break;
+
+ default :
+ break;
+ }
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id: ipptest.c 9000 2010-02-24 06:29:38Z mike $".
*/
--- /dev/null
+# Print a test page using Print-Job + media-col
+#
+# Usage:
+#
+# ./ipptest -f filename ipp://... print-job-media-col.test
+{
+ # The name of the test...
+ NAME "Print test page using Print-Job + media-col"
+
+ # The operation to use
+ OPERATION Print-Job
+
+ # Attributes, starting in the operation group...
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR mimetype document-format application/octet-stream
+
+ GROUP job-attributes-tag
+ ATTR collection media-col {
+ MEMBER collection media-size {
+ # 4x6
+ MEMBER integer media-x-dimension 10160
+ MEMBER integer media-y-dimension 15240
+ }
+ }
+
+ FILE $filename
+
+ # What statuses are OK?
+ STATUS successful-ok
+ STATUS successful-ok-ignored-or-substituted-attributes
+
+ # What attributes do we expect?
+ EXPECT job-id OF-TYPE integer WITH-VALUE >0
+ EXPECT job-uri OF-TYPE uri
+}
<HTML>
<HEAD>
- <META NAME="Description" CONTENT="Common UNIX Printing System Software Test Report">
- <META NAME="COPYRIGHT" CONTENT="Copyright 2007-2008, All Rights Reserved">
- <META NAME="DOCNUMBER" CONTENT="CUPS-STR-1.4">
+ <META NAME="Description" CONTENT="CUPS Test Report">
+ <META NAME="COPYRIGHT" CONTENT="Copyright 2007-2010, All Rights Reserved">
+ <META NAME="DOCNUMBER" CONTENT="CUPS-STR-1.5">
<META NAME="Author" CONTENT="Apple Inc.">
- <TITLE>CUPS 1.4 Software Test Report</TITLE>
+ <TITLE>CUPS 1.5 Software Test Report</TITLE>
<STYLE TYPE="text/css"><!--
PRE {
font-size: 80%;
</HEAD>
<BODY>
-<H1>CUPS 1.4 Software Test Report</H1>
+<H1>CUPS 1.5 Software Test Report</H1>
<P>This software test report provides detailed test results that
-are used to evaluate the stability and compliance of the Common
-UNIX Printing System ("CUPS") Version 1.4.
+are used to evaluate the stability and compliance of CUPS Version 1.5.
<H2>Document Overview</H2>
--- /dev/null
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+ ProjectType="Visual C++"\r
+ Version="8.00"\r
+ Name="cupstestppd"\r
+ ProjectGUID="{B246D91E-61F2-4433-BFD2-6C2A96FBD4D4}"\r
+ RootNamespace="ipptest"\r
+ Keyword="Win32Proj"\r
+ >\r
+ <Platforms>\r
+ <Platform\r
+ Name="Win32"\r
+ />\r
+ </Platforms>\r
+ <ToolFiles>\r
+ </ToolFiles>\r
+ <Configurations>\r
+ <Configuration\r
+ Name="Debug|Win32"\r
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"\r
+ IntermediateDirectory="$(ConfigurationName)"\r
+ ConfigurationType="1"\r
+ CharacterSet="1"\r
+ >\r
+ <Tool\r
+ Name="VCPreBuildEventTool"\r
+ />\r
+ <Tool\r
+ Name="VCCustomBuildTool"\r
+ />\r
+ <Tool\r
+ Name="VCXMLDataGeneratorTool"\r
+ />\r
+ <Tool\r
+ Name="VCWebServiceProxyGeneratorTool"\r
+ />\r
+ <Tool\r
+ Name="VCMIDLTool"\r
+ />\r
+ <Tool\r
+ Name="VCCLCompilerTool"\r
+ Optimization="0"\r
+ AdditionalIncludeDirectories="..\vcnet;.."\r
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"\r
+ MinimalRebuild="true"\r
+ BasicRuntimeChecks="3"\r
+ RuntimeLibrary="3"\r
+ UsePrecompiledHeader="0"\r
+ WarningLevel="1"\r
+ Detect64BitPortabilityProblems="true"\r
+ DebugInformationFormat="4"\r
+ />\r
+ <Tool\r
+ Name="VCManagedResourceCompilerTool"\r
+ />\r
+ <Tool\r
+ Name="VCResourceCompilerTool"\r
+ />\r
+ <Tool\r
+ Name="VCPreLinkEventTool"\r
+ />\r
+ <Tool\r
+ Name="VCLinkerTool"\r
+ LinkIncremental="2"\r
+ GenerateDebugInformation="true"\r
+ SubSystem="1"\r
+ TargetMachine="1"\r
+ />\r
+ <Tool\r
+ Name="VCALinkTool"\r
+ />\r
+ <Tool\r
+ Name="VCManifestTool"\r
+ />\r
+ <Tool\r
+ Name="VCXDCMakeTool"\r
+ />\r
+ <Tool\r
+ Name="VCBscMakeTool"\r
+ />\r
+ <Tool\r
+ Name="VCFxCopTool"\r
+ />\r
+ <Tool\r
+ Name="VCAppVerifierTool"\r
+ />\r
+ <Tool\r
+ Name="VCWebDeploymentTool"\r
+ />\r
+ <Tool\r
+ Name="VCPostBuildEventTool"\r
+ />\r
+ </Configuration>\r
+ <Configuration\r
+ Name="Release|Win32"\r
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"\r
+ IntermediateDirectory="$(ConfigurationName)"\r
+ ConfigurationType="1"\r
+ CharacterSet="1"\r
+ WholeProgramOptimization="1"\r
+ >\r
+ <Tool\r
+ Name="VCPreBuildEventTool"\r
+ />\r
+ <Tool\r
+ Name="VCCustomBuildTool"\r
+ />\r
+ <Tool\r
+ Name="VCXMLDataGeneratorTool"\r
+ />\r
+ <Tool\r
+ Name="VCWebServiceProxyGeneratorTool"\r
+ />\r
+ <Tool\r
+ Name="VCMIDLTool"\r
+ />\r
+ <Tool\r
+ Name="VCCLCompilerTool"\r
+ AdditionalIncludeDirectories="..\vcnet;.."\r
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"\r
+ RuntimeLibrary="2"\r
+ UsePrecompiledHeader="0"\r
+ WarningLevel="1"\r
+ Detect64BitPortabilityProblems="true"\r
+ DebugInformationFormat="3"\r
+ />\r
+ <Tool\r
+ Name="VCManagedResourceCompilerTool"\r
+ />\r
+ <Tool\r
+ Name="VCResourceCompilerTool"\r
+ />\r
+ <Tool\r
+ Name="VCPreLinkEventTool"\r
+ />\r
+ <Tool\r
+ Name="VCLinkerTool"\r
+ LinkIncremental="1"\r
+ GenerateDebugInformation="true"\r
+ SubSystem="1"\r
+ OptimizeReferences="2"\r
+ EnableCOMDATFolding="2"\r
+ TargetMachine="1"\r
+ />\r
+ <Tool\r
+ Name="VCALinkTool"\r
+ />\r
+ <Tool\r
+ Name="VCManifestTool"\r
+ />\r
+ <Tool\r
+ Name="VCXDCMakeTool"\r
+ />\r
+ <Tool\r
+ Name="VCBscMakeTool"\r
+ />\r
+ <Tool\r
+ Name="VCFxCopTool"\r
+ />\r
+ <Tool\r
+ Name="VCAppVerifierTool"\r
+ />\r
+ <Tool\r
+ Name="VCWebDeploymentTool"\r
+ />\r
+ <Tool\r
+ Name="VCPostBuildEventTool"\r
+ />\r
+ </Configuration>\r
+ </Configurations>\r
+ <References>\r
+ </References>\r
+ <Files>\r
+ <Filter\r
+ Name="Source Files"\r
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+ >\r
+ <File\r
+ RelativePath="..\test\ipptest.c"\r
+ >\r
+ </File>\r
+ </Filter>\r
+ <Filter\r
+ Name="Header Files"\r
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+ >\r
+ </Filter>\r
+ <Filter\r
+ Name="Resource Files"\r
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"\r
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
+ >\r
+ </Filter>\r
+ </Files>\r
+ <Globals>\r
+ </Globals>\r
+</VisualStudioProject>\r
* Version of software...
*/
-#define CUPS_SVERSION "CUPS v1.4.0"
-#define CUPS_MINIMAL "CUPS/1.4.0"
+#define CUPS_SVERSION "CUPS v1.5svn"
+#define CUPS_MINIMAL "CUPS/1.5svn"
/*
/* #undef HAVE_CRYPT_H */
+/*
+ * Do we have <scsi/sg.h>?
+ */
+
+/* #undef HAVE_SCSI_SG_H */
+
+
/*
* Use <string.h>, <strings.h>, and/or <bstring.h>?
*/
* Default GSS service name...
*/
-#define CUPS_DEFAULT_GSSSERVICENAME "ipp"
+#define CUPS_DEFAULT_GSSSERVICENAME "host"
/*
* Which random number generator function to use...
*/
+/* #undef HAVE_ARC4RANDOM */
/* #undef HAVE_RANDOM */
-/* #undef HAVE_MRAND48 */
/* #undef HAVE_LRAND48 */
+#ifdef HAVE_ARC4RANDOM
+# define CUPS_RAND() arc4random()
+# define CUPS_SRAND(v) arc4random_stir()
+#elif defined(HAVE_RANDOM)
+# define CUPS_RAND() random()
+# define CUPS_SRAND(v) srandom(v)
+#elif defined(HAVE_LRAND48)
+# define CUPS_RAND() lrand48()
+# define CUPS_SRAND(v) srand48(v)
+#else
+# define CUPS_RAND() rand()
+# define CUPS_SRAND(v) srand(v)
+#endif /* HAVE_ARC4RANDOM */
+
/*
* Do we have vproc_transaction_begin/end?
Microsoft Visual Studio Solution File, Format Version 10.00\r
-# Visual C++ Express 2008\r
+# Visual Studio 2008\r
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcups2", "libcups2.vcproj", "{CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}"\r
EndProject\r
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testfile", "testfile.vcproj", "{CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}"\r
{CB4AA6F2-3E84-45BE-B505-95CD375E8BE3} = {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}\r
EndProjectSection\r
EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ipptest", "ipptest.vcproj", "{B246D91E-61F2-4433-BFD2-6C2A96FBD4D4}"\r
+ ProjectSection(ProjectDependencies) = postProject\r
+ {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3} = {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}\r
+ EndProjectSection\r
+EndProject\r
Global\r
GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
Debug|Win32 = Debug|Win32\r
{CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Debug|Win32.Build.0 = Debug|Win32\r
{CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Debug|x64.ActiveCfg = Debug|x64\r
{CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Debug|x64.Build.0 = Debug|x64\r
- {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Release|Win32.ActiveCfg = Debug|Win32\r
- {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Release|Win32.Build.0 = Debug|Win32\r
+ {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Release|Win32.ActiveCfg = Release|Win32\r
+ {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Release|Win32.Build.0 = Release|Win32\r
{CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Release|x64.ActiveCfg = Debug|x64\r
{CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Release|x64.Build.0 = Debug|x64\r
{CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}.Debug|Win32.ActiveCfg = Debug|Win32\r
{CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}.Debug|Win32.Build.0 = Debug|Win32\r
{CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}.Debug|x64.ActiveCfg = Debug|x64\r
{CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}.Debug|x64.Build.0 = Debug|x64\r
- {CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}.Release|Win32.ActiveCfg = Debug|Win32\r
- {CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}.Release|Win32.Build.0 = Debug|Win32\r
+ {CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}.Release|Win32.ActiveCfg = Release|Win32\r
+ {CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}.Release|Win32.Build.0 = Release|Win32\r
{CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}.Release|x64.ActiveCfg = Debug|x64\r
{CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}.Release|x64.Build.0 = Debug|x64\r
{90B0058C-8393-411F-BD3B-E2C831D4E883}.Debug|Win32.ActiveCfg = Debug|Win32\r
{90B0058C-8393-411F-BD3B-E2C831D4E883}.Debug|Win32.Build.0 = Debug|Win32\r
{90B0058C-8393-411F-BD3B-E2C831D4E883}.Debug|x64.ActiveCfg = Debug|x64\r
{90B0058C-8393-411F-BD3B-E2C831D4E883}.Debug|x64.Build.0 = Debug|x64\r
- {90B0058C-8393-411F-BD3B-E2C831D4E883}.Release|Win32.ActiveCfg = Debug|Win32\r
- {90B0058C-8393-411F-BD3B-E2C831D4E883}.Release|Win32.Build.0 = Debug|Win32\r
+ {90B0058C-8393-411F-BD3B-E2C831D4E883}.Release|Win32.ActiveCfg = Release|Win32\r
+ {90B0058C-8393-411F-BD3B-E2C831D4E883}.Release|Win32.Build.0 = Release|Win32\r
{90B0058C-8393-411F-BD3B-E2C831D4E883}.Release|x64.ActiveCfg = Debug|x64\r
{90B0058C-8393-411F-BD3B-E2C831D4E883}.Release|x64.Build.0 = Debug|x64\r
{6BE0CDD3-4ED7-409C-A80F-19DF73664B1F}.Debug|Win32.ActiveCfg = Debug|Win32\r
{6BE0CDD3-4ED7-409C-A80F-19DF73664B1F}.Release|Win32.ActiveCfg = Release|Win32\r
{6BE0CDD3-4ED7-409C-A80F-19DF73664B1F}.Release|Win32.Build.0 = Release|Win32\r
{6BE0CDD3-4ED7-409C-A80F-19DF73664B1F}.Release|x64.ActiveCfg = Release|Win32\r
+ {6BE0CDD3-4ED7-409C-A80F-19DF73664B1F}.Release|x64.Build.0 = Release|Win32\r
+ {B246D91E-61F2-4433-BFD2-6C2A96FBD4D4}.Debug|Win32.ActiveCfg = Debug|Win32\r
+ {B246D91E-61F2-4433-BFD2-6C2A96FBD4D4}.Debug|Win32.Build.0 = Debug|Win32\r
+ {B246D91E-61F2-4433-BFD2-6C2A96FBD4D4}.Debug|x64.ActiveCfg = Debug|Win32\r
+ {B246D91E-61F2-4433-BFD2-6C2A96FBD4D4}.Release|Win32.ActiveCfg = Release|Win32\r
+ {B246D91E-61F2-4433-BFD2-6C2A96FBD4D4}.Release|Win32.Build.0 = Release|Win32\r
+ {B246D91E-61F2-4433-BFD2-6C2A96FBD4D4}.Release|x64.ActiveCfg = Release|Win32\r
+ {B246D91E-61F2-4433-BFD2-6C2A96FBD4D4}.Release|x64.Build.0 = Release|Win32\r
EndGlobalSection\r
GlobalSection(SolutionProperties) = preSolution\r
HideSolutionNode = FALSE\r
--- /dev/null
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+ ProjectType="Visual C++"\r
+ Version="9.00"\r
+ Name="ipptest"\r
+ ProjectGUID="{B246D91E-61F2-4433-BFD2-6C2A96FBD4D4}"\r
+ RootNamespace="ipptest"\r
+ Keyword="Win32Proj"\r
+ TargetFrameworkVersion="131072"\r
+ >\r
+ <Platforms>\r
+ <Platform\r
+ Name="Win32"\r
+ />\r
+ </Platforms>\r
+ <ToolFiles>\r
+ </ToolFiles>\r
+ <Configurations>\r
+ <Configuration\r
+ Name="Debug|Win32"\r
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"\r
+ IntermediateDirectory="$(ConfigurationName)"\r
+ ConfigurationType="1"\r
+ CharacterSet="1"\r
+ >\r
+ <Tool\r
+ Name="VCPreBuildEventTool"\r
+ />\r
+ <Tool\r
+ Name="VCCustomBuildTool"\r
+ />\r
+ <Tool\r
+ Name="VCXMLDataGeneratorTool"\r
+ />\r
+ <Tool\r
+ Name="VCWebServiceProxyGeneratorTool"\r
+ />\r
+ <Tool\r
+ Name="VCMIDLTool"\r
+ />\r
+ <Tool\r
+ Name="VCCLCompilerTool"\r
+ Optimization="0"\r
+ AdditionalIncludeDirectories="..\vcnet;..;..\vcnet\regex"\r
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"\r
+ MinimalRebuild="true"\r
+ BasicRuntimeChecks="3"\r
+ RuntimeLibrary="3"\r
+ UsePrecompiledHeader="0"\r
+ WarningLevel="1"\r
+ Detect64BitPortabilityProblems="false"\r
+ DebugInformationFormat="4"\r
+ />\r
+ <Tool\r
+ Name="VCManagedResourceCompilerTool"\r
+ />\r
+ <Tool\r
+ Name="VCResourceCompilerTool"\r
+ />\r
+ <Tool\r
+ Name="VCPreLinkEventTool"\r
+ />\r
+ <Tool\r
+ Name="VCLinkerTool"\r
+ LinkIncremental="2"\r
+ GenerateDebugInformation="true"\r
+ SubSystem="1"\r
+ RandomizedBaseAddress="1"\r
+ DataExecutionPrevention="0"\r
+ TargetMachine="1"\r
+ />\r
+ <Tool\r
+ Name="VCALinkTool"\r
+ />\r
+ <Tool\r
+ Name="VCManifestTool"\r
+ />\r
+ <Tool\r
+ Name="VCXDCMakeTool"\r
+ />\r
+ <Tool\r
+ Name="VCBscMakeTool"\r
+ />\r
+ <Tool\r
+ Name="VCFxCopTool"\r
+ />\r
+ <Tool\r
+ Name="VCAppVerifierTool"\r
+ />\r
+ <Tool\r
+ Name="VCPostBuildEventTool"\r
+ />\r
+ </Configuration>\r
+ <Configuration\r
+ Name="Release|Win32"\r
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"\r
+ IntermediateDirectory="$(ConfigurationName)"\r
+ ConfigurationType="1"\r
+ CharacterSet="1"\r
+ WholeProgramOptimization="1"\r
+ >\r
+ <Tool\r
+ Name="VCPreBuildEventTool"\r
+ />\r
+ <Tool\r
+ Name="VCCustomBuildTool"\r
+ />\r
+ <Tool\r
+ Name="VCXMLDataGeneratorTool"\r
+ />\r
+ <Tool\r
+ Name="VCWebServiceProxyGeneratorTool"\r
+ />\r
+ <Tool\r
+ Name="VCMIDLTool"\r
+ />\r
+ <Tool\r
+ Name="VCCLCompilerTool"\r
+ AdditionalIncludeDirectories="..\vcnet;..;..\vcnet\regex"\r
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"\r
+ RuntimeLibrary="2"\r
+ UsePrecompiledHeader="0"\r
+ WarningLevel="1"\r
+ Detect64BitPortabilityProblems="false"\r
+ DebugInformationFormat="3"\r
+ />\r
+ <Tool\r
+ Name="VCManagedResourceCompilerTool"\r
+ />\r
+ <Tool\r
+ Name="VCResourceCompilerTool"\r
+ />\r
+ <Tool\r
+ Name="VCPreLinkEventTool"\r
+ />\r
+ <Tool\r
+ Name="VCLinkerTool"\r
+ LinkIncremental="1"\r
+ GenerateDebugInformation="true"\r
+ SubSystem="1"\r
+ OptimizeReferences="2"\r
+ EnableCOMDATFolding="2"\r
+ RandomizedBaseAddress="1"\r
+ DataExecutionPrevention="0"\r
+ TargetMachine="1"\r
+ />\r
+ <Tool\r
+ Name="VCALinkTool"\r
+ />\r
+ <Tool\r
+ Name="VCManifestTool"\r
+ />\r
+ <Tool\r
+ Name="VCXDCMakeTool"\r
+ />\r
+ <Tool\r
+ Name="VCBscMakeTool"\r
+ />\r
+ <Tool\r
+ Name="VCFxCopTool"\r
+ />\r
+ <Tool\r
+ Name="VCAppVerifierTool"\r
+ />\r
+ <Tool\r
+ Name="VCPostBuildEventTool"\r
+ />\r
+ </Configuration>\r
+ </Configurations>\r
+ <References>\r
+ </References>\r
+ <Files>\r
+ <Filter\r
+ Name="Source Files"\r
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+ >\r
+ <File\r
+ RelativePath=".\regex\debug.c"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath="..\test\ipptest.c"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\regex\regcomp.c"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\regex\regerror.c"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\regex\regexec.c"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\regex\regfree.c"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\regex\split.c"\r
+ >\r
+ </File>\r
+ </Filter>\r
+ <Filter\r
+ Name="Header Files"\r
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+ >\r
+ <File\r
+ RelativePath=".\regex\regex.h"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\regex\regex2.h"\r
+ >\r
+ </File>\r
+ </Filter>\r
+ <Filter\r
+ Name="Resource Files"\r
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"\r
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
+ >\r
+ </Filter>\r
+ </Files>\r
+ <Globals>\r
+ </Globals>\r
+</VisualStudioProject>\r
--- /dev/null
+Copyright 1992, 1993, 1994, 1997 Henry Spencer. All rights reserved.
+This software is not subject to any license of the American Telephone
+and Telegraph Company or of the Regents of the University of California.
+
+Permission is granted to anyone to use this software for any purpose on
+any computer system, and to alter it and redistribute it, subject
+to the following restrictions:
+
+1. The author is not responsible for the consequences of use of this
+ software, no matter how awful, even if they arise from flaws in it.
+
+2. The origin of this software must not be misrepresented, either by
+ explicit claim or by omission. Since few users ever read sources,
+ credits must appear in the documentation.
+
+3. Altered versions must be plainly marked as such, and must not be
+ misrepresented as being the original software. Since few users
+ ever read sources, credits must appear in the documentation.
+
+4. This notice may not be removed or altered.
--- /dev/null
+# You probably want to take -DREDEBUG out of CFLAGS, and put something like
+# -O in, *after* testing (-DREDEBUG strengthens testing by enabling a lot of
+# internal assertion checking and some debugging facilities).
+# Put -Dconst= in for a pre-ANSI compiler.
+# Do not take -DPOSIX_MISTAKE out.
+# REGCFLAGS isn't important to you (it's for my use in some special contexts).
+CFLAGS=-I. -DPOSIX_MISTAKE -DREDEBUG $(REGCFLAGS)
+
+# If you have a pre-ANSI compiler, put -o into MKHFLAGS. If you want
+# the Berkeley __P macro, put -b in.
+MKHFLAGS=
+
+# Flags for linking but not compiling, if any.
+LDFLAGS=
+
+# Extra libraries for linking, if any.
+LIBS=
+
+# Internal stuff, should not need changing.
+OBJPRODN=regcomp.o regexec.o regerror.o regfree.o
+OBJS=$(OBJPRODN) split.o debug.o main.o
+H=cclass.h cname.h regex2.h utils.h
+REGSRC=regcomp.c regerror.c regexec.c regfree.c
+ALLSRC=$(REGSRC) engine.c debug.c main.c split.c
+
+# Stuff that matters only if you're trying to lint the package.
+LINTFLAGS=-I. -Dstatic= -Dconst= -DREDEBUG
+LINTC=regcomp.c regexec.c regerror.c regfree.c debug.c main.c
+JUNKLINT=possible pointer alignment|null effect
+
+# arrangements to build forward-reference header files
+.SUFFIXES: .ih .h
+.c.ih:
+ sh ./mkh $(MKHFLAGS) -p $< >$@
+
+default: r
+
+lib: purge $(OBJPRODN)
+ rm -f libregex.a
+ ar crv libregex.a $(OBJPRODN)
+
+purge:
+ rm -f *.o
+
+# stuff to build regex.h
+REGEXH=regex.h
+REGEXHSRC=regex2.h $(REGSRC)
+$(REGEXH): $(REGEXHSRC) mkh
+ sh ./mkh $(MKHFLAGS) -i _REGEX_H_ $(REGEXHSRC) >regex.tmp
+ cmp -s regex.tmp regex.h 2>/dev/null || cp regex.tmp regex.h
+ rm -f regex.tmp
+
+# dependencies
+$(OBJPRODN) debug.o: utils.h regex.h regex2.h
+regcomp.o: cclass.h cname.h regcomp.ih
+regexec.o: engine.c engine.ih
+regerror.o: regerror.ih
+debug.o: debug.ih
+main.o: main.ih
+
+# tester
+re: $(OBJS)
+ $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) -o $@
+
+# regression test
+r: re tests
+ ./re <tests
+ ./re -el <tests
+ ./re -er <tests
+
+# 57 variants, and other stuff, for development use -- not useful to you
+ra: ./re tests
+ -./re <tests
+ -./re -el <tests
+ -./re -er <tests
+
+rx: ./re tests
+ ./re -x <tests
+ ./re -x -el <tests
+ ./re -x -er <tests
+
+t: ./re tests
+ -time ./re <tests
+ -time ./re -cs <tests
+ -time ./re -el <tests
+ -time ./re -cs -el <tests
+
+l: $(LINTC)
+ lint $(LINTFLAGS) -h $(LINTC) 2>&1 | egrep -v '$(JUNKLINT)' | tee lint
+
+fullprint:
+ ti README WHATSNEW notes todo | list
+ ti *.h | list
+ list *.c
+ list regex.3 regex.7
+
+print:
+ ti README WHATSNEW notes todo | list
+ ti *.h | list
+ list reg*.c engine.c
+
+
+mf.tmp: Makefile
+ sed '/^REGEXH=/s/=.*/=regex.h/' Makefile | sed '/#DEL$$/d' >$@
+
+DTRH=cclass.h cname.h regex2.h utils.h
+PRE=COPYRIGHT README WHATSNEW
+POST=mkh regex.3 regex.7 tests $(DTRH) $(ALLSRC) fake/*.[ch]
+FILES=$(PRE) Makefile $(POST)
+DTR=$(PRE) Makefile=mf.tmp $(POST)
+dtr: $(FILES) mf.tmp
+ makedtr $(DTR) >$@
+ rm mf.tmp
+
+cio: $(FILES)
+ cio $(FILES)
+
+rdf: $(FILES)
+ rcsdiff -c $(FILES) 2>&1 | p
+
+# various forms of cleanup
+tidy:
+ rm -f junk* core core.* *.core dtr *.tmp lint
+
+clean: tidy
+ rm -f *.o *.s *.ih re libregex.a
+
+# don't do this one unless you know what you're doing
+spotless: clean
+ rm -f mkh regex.h
--- /dev/null
+alpha3.8 release.
+Tue Aug 10 15:51:48 EDT 1999
+henry@spsystems.net (formerly henry@zoo.toronto.edu)
+
+See WHATSNEW for change listing.
+
+installation notes:
+--------
+Read the comments at the beginning of Makefile before running.
+
+Utils.h contains some things that just might have to be modified on
+some systems, as well as a nested include (ugh) of <assert.h>.
+
+The "fake" directory contains quick-and-dirty fakes for some header
+files and routines that old systems may not have. Note also that
+-DUSEBCOPY will make utils.h substitute bcopy() for memmove().
+
+After that, "make r" will build regcomp.o, regexec.o, regfree.o,
+and regerror.o (the actual routines), bundle them together into a test
+program, and run regression tests on them. No output is good output.
+
+"make lib" builds just the .o files for the actual routines (when
+you're happy with testing and have adjusted CFLAGS for production),
+and puts them together into libregex.a. You can pick up either the
+library or *.o ("make lib" makes sure there are no other .o files left
+around to confuse things).
+
+Main.c, debug.c, split.c are used for regression testing but are not part
+of the RE routines themselves.
+
+Regex.h goes in /usr/include. All other .h files are internal only.
+--------
--- /dev/null
+New in alpha3.8: Bug fix for signed/unsigned mixup, found and fixed
+by the FreeBSD folks.
+
+New in alpha3.7: A bit of cleanup aimed at maximizing portability,
+possibly at slight cost in efficiency. "ul" suffixes and "unsigned long"
+no longer appear, in particular.
+
+New in alpha3.6: A couple more portability glitches fixed.
+
+New in alpha3.5: Active development of this code has been stopped --
+I'm working on a complete reimplementation -- but folks have found some
+minor portability glitches and the like, hence this release to fix them.
+One penalty: slightly reduced compatibility with old compilers, because
+the ANSI C `unsigned long' type and `ul' constant suffix are used in a
+few places (I could avoid this but it would be considerably more work).
+
+New in alpha3.4: The complex bug alluded to below has been fixed (in a
+slightly kludgey temporary way that may hurt efficiency a bit; this is
+another "get it out the door for 4.4" release). The tests at the end of
+the tests file have accordingly been uncommented. The primary sign of
+the bug was that something like a?b matching ab matched b rather than ab.
+(The bug was essentially specific to this exact situation, else it would
+have shown up earlier.)
+
+New in alpha3.3: The definition of word boundaries has been altered
+slightly, to more closely match the usual programming notion that "_"
+is an alphabetic. Stuff used for pre-ANSI systems is now in a subdir,
+and the makefile no longer alludes to it in mysterious ways. The
+makefile has generally been cleaned up some. Fixes have been made
+(again!) so that the regression test will run without -DREDEBUG, at
+the cost of weaker checking. A workaround for a bug in some folks'
+<assert.h> has been added. And some more things have been added to
+tests, including a couple right at the end which are commented out
+because the code currently flunks them (complex bug; fix coming).
+Plus the usual minor cleanup.
+
+New in alpha3.2: Assorted bits of cleanup and portability improvement
+(the development base is now a BSDI system using GCC instead of an ancient
+Sun system, and the newer compiler exposed some glitches). Fix for a
+serious bug that affected REs using many [] (including REG_ICASE REs
+because of the way they are implemented), *sometimes*, depending on
+memory-allocation patterns. The header-file prototypes no longer name
+the parameters, avoiding possible name conflicts. The possibility that
+some clot has defined CHAR_MIN as (say) `-128' instead of `(-128)' is
+now handled gracefully. "uchar" is no longer used as an internal type
+name (too many people have the same idea). Still the same old lousy
+performance, alas.
+
+New in alpha3.1: Basically nothing, this release is just a bookkeeping
+convenience. Stay tuned.
+
+New in alpha3.0: Performance is no better, alas, but some fixes have been
+made and some functionality has been added. (This is basically the "get
+it out the door in time for 4.4" release.) One bug fix: regfree() didn't
+free the main internal structure (how embarrassing). It is now possible
+to put NULs in either the RE or the target string, using (resp.) a new
+REG_PEND flag and the old REG_STARTEND flag. The REG_NOSPEC flag to
+regcomp() makes all characters ordinary, so you can match a literal
+string easily (this will become more useful when performance improves!).
+There are now primitives to match beginnings and ends of words, although
+the syntax is disgusting and so is the implementation. The REG_ATOI
+debugging interface has changed a bit. And there has been considerable
+internal cleanup of various kinds.
+
+New in alpha2.3: Split change list out of README, and moved flags notes
+into Makefile. Macro-ized the name of regex(7) in regex(3), since it has
+to change for 4.4BSD. Cleanup work in engine.c, and some new regression
+tests to catch tricky cases thereof.
+
+New in alpha2.2: Out-of-date manpages updated. Regerror() acquires two
+small extensions -- REG_ITOA and REG_ATOI -- which avoid debugging kludges
+in my own test program and might be useful to others for similar purposes.
+The regression test will now compile (and run) without REDEBUG. The
+BRE \$ bug is fixed. Most uses of "uchar" are gone; it's all chars now.
+Char/uchar parameters are now written int/unsigned, to avoid possible
+portability problems with unpromoted parameters. Some unsigned casts have
+been introduced to minimize portability problems with shifting into sign
+bits.
+
+New in alpha2.1: Lots of little stuff, cleanup and fixes. The one big
+thing is that regex.h is now generated, using mkh, rather than being
+supplied in the distribution; due to circularities in dependencies,
+you have to build regex.h explicitly by "make h". The two known bugs
+have been fixed (and the regression test now checks for them), as has a
+problem with assertions not being suppressed in the absence of REDEBUG.
+No performance work yet.
+
+New in alpha2: Backslash-anything is an ordinary character, not an
+error (except, of course, for the handful of backslashed metacharacters
+in BREs), which should reduce script breakage. The regression test
+checks *where* null strings are supposed to match, and has generally
+been tightened up somewhat. Small bug fixes in parameter passing (not
+harmful, but technically errors) and some other areas. Debugging
+invoked by defining REDEBUG rather than not defining NDEBUG.
+
+New in alpha+3: full prototyping for internal routines, using a little
+helper program, mkh, which extracts prototypes given in stylized comments.
+More minor cleanup. Buglet fix: it's CHAR_BIT, not CHAR_BITS. Simple
+pre-screening of input when a literal string is known to be part of the
+RE; this does wonders for performance.
+
+New in alpha+2: minor bits of cleanup. Notably, the number "32" for the
+word width isn't hardwired into regexec.c any more, the public header
+file prototypes the functions if __STDC__ is defined, and some small typos
+in the manpages have been fixed.
+
+New in alpha+1: improvements to the manual pages, and an important
+extension, the REG_STARTEND option to regexec().
--- /dev/null
+/* character-class table */
+static struct cclass {
+ char *name;
+ char *chars;
+ char *multis;
+} cclasses[] = {
+ "alnum", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\
+0123456789", "",
+ "alpha", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
+ "",
+ "blank", " \t", "",
+ "cntrl", "\007\b\t\n\v\f\r\1\2\3\4\5\6\16\17\20\21\22\23\24\
+\25\26\27\30\31\32\33\34\35\36\37\177", "",
+ "digit", "0123456789", "",
+ "graph", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\
+0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+ "",
+ "lower", "abcdefghijklmnopqrstuvwxyz",
+ "",
+ "print", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\
+0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ ",
+ "",
+ "punct", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+ "",
+ "space", "\t\n\v\f\r ", "",
+ "upper", "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
+ "",
+ "xdigit", "0123456789ABCDEFabcdef",
+ "",
+ NULL, 0, ""
+};
--- /dev/null
+/* character-name table */
+static struct cname {
+ char *name;
+ char code;
+} cnames[] = {
+ "NUL", '\0',
+ "SOH", '\001',
+ "STX", '\002',
+ "ETX", '\003',
+ "EOT", '\004',
+ "ENQ", '\005',
+ "ACK", '\006',
+ "BEL", '\007',
+ "alert", '\007',
+ "BS", '\010',
+ "backspace", '\b',
+ "HT", '\011',
+ "tab", '\t',
+ "LF", '\012',
+ "newline", '\n',
+ "VT", '\013',
+ "vertical-tab", '\v',
+ "FF", '\014',
+ "form-feed", '\f',
+ "CR", '\015',
+ "carriage-return", '\r',
+ "SO", '\016',
+ "SI", '\017',
+ "DLE", '\020',
+ "DC1", '\021',
+ "DC2", '\022',
+ "DC3", '\023',
+ "DC4", '\024',
+ "NAK", '\025',
+ "SYN", '\026',
+ "ETB", '\027',
+ "CAN", '\030',
+ "EM", '\031',
+ "SUB", '\032',
+ "ESC", '\033',
+ "IS4", '\034',
+ "FS", '\034',
+ "IS3", '\035',
+ "GS", '\035',
+ "IS2", '\036',
+ "RS", '\036',
+ "IS1", '\037',
+ "US", '\037',
+ "space", ' ',
+ "exclamation-mark", '!',
+ "quotation-mark", '"',
+ "number-sign", '#',
+ "dollar-sign", '$',
+ "percent-sign", '%',
+ "ampersand", '&',
+ "apostrophe", '\'',
+ "left-parenthesis", '(',
+ "right-parenthesis", ')',
+ "asterisk", '*',
+ "plus-sign", '+',
+ "comma", ',',
+ "hyphen", '-',
+ "hyphen-minus", '-',
+ "period", '.',
+ "full-stop", '.',
+ "slash", '/',
+ "solidus", '/',
+ "zero", '0',
+ "one", '1',
+ "two", '2',
+ "three", '3',
+ "four", '4',
+ "five", '5',
+ "six", '6',
+ "seven", '7',
+ "eight", '8',
+ "nine", '9',
+ "colon", ':',
+ "semicolon", ';',
+ "less-than-sign", '<',
+ "equals-sign", '=',
+ "greater-than-sign", '>',
+ "question-mark", '?',
+ "commercial-at", '@',
+ "left-square-bracket", '[',
+ "backslash", '\\',
+ "reverse-solidus", '\\',
+ "right-square-bracket", ']',
+ "circumflex", '^',
+ "circumflex-accent", '^',
+ "underscore", '_',
+ "low-line", '_',
+ "grave-accent", '`',
+ "left-brace", '{',
+ "left-curly-bracket", '{',
+ "vertical-line", '|',
+ "right-brace", '}',
+ "right-curly-bracket", '}',
+ "tilde", '~',
+ "DEL", '\177',
+ NULL, 0,
+};
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <regex.h>
+
+#include "utils.h"
+#include "regex2.h"
+#include "debug.ih"
+
+/*
+ - regprint - print a regexp for debugging
+ == void regprint(regex_t *r, FILE *d);
+ */
+void
+regprint(r, d)
+regex_t *r;
+FILE *d;
+{
+ register struct re_guts *g = r->re_g;
+ register int i;
+ register int c;
+ register int last;
+ int nincat[NC];
+
+ fprintf(d, "%ld states, %d categories", (long)g->nstates,
+ g->ncategories);
+ fprintf(d, ", first %ld last %ld", (long)g->firststate,
+ (long)g->laststate);
+ if (g->iflags&USEBOL)
+ fprintf(d, ", USEBOL");
+ if (g->iflags&USEEOL)
+ fprintf(d, ", USEEOL");
+ if (g->iflags&BAD)
+ fprintf(d, ", BAD");
+ if (g->nsub > 0)
+ fprintf(d, ", nsub=%ld", (long)g->nsub);
+ if (g->must != NULL)
+ fprintf(d, ", must(%ld) `%*s'", (long)g->mlen, (int)g->mlen,
+ g->must);
+ if (g->backrefs)
+ fprintf(d, ", backrefs");
+ if (g->nplus > 0)
+ fprintf(d, ", nplus %ld", (long)g->nplus);
+ fprintf(d, "\n");
+ s_print(g, d);
+ for (i = 0; i < g->ncategories; i++) {
+ nincat[i] = 0;
+ for (c = CHAR_MIN; c <= CHAR_MAX; c++)
+ if (g->categories[c] == i)
+ nincat[i]++;
+ }
+ fprintf(d, "cc0#%d", nincat[0]);
+ for (i = 1; i < g->ncategories; i++)
+ if (nincat[i] == 1) {
+ for (c = CHAR_MIN; c <= CHAR_MAX; c++)
+ if (g->categories[c] == i)
+ break;
+ fprintf(d, ", %d=%s", i, regchar(c));
+ }
+ fprintf(d, "\n");
+ for (i = 1; i < g->ncategories; i++)
+ if (nincat[i] != 1) {
+ fprintf(d, "cc%d\t", i);
+ last = -1;
+ for (c = CHAR_MIN; c <= CHAR_MAX+1; c++) /* +1 does flush */
+ if (c <= CHAR_MAX && g->categories[c] == i) {
+ if (last < 0) {
+ fprintf(d, "%s", regchar(c));
+ last = c;
+ }
+ } else {
+ if (last >= 0) {
+ if (last != c-1)
+ fprintf(d, "-%s",
+ regchar(c-1));
+ last = -1;
+ }
+ }
+ fprintf(d, "\n");
+ }
+}
+
+/*
+ - s_print - print the strip for debugging
+ == static void s_print(register struct re_guts *g, FILE *d);
+ */
+static void
+s_print(g, d)
+register struct re_guts *g;
+FILE *d;
+{
+ register sop *s;
+ register cset *cs;
+ register int i;
+ register int done = 0;
+ register sop opnd;
+ register int col = 0;
+ register int last;
+ register sopno offset = 2;
+# define GAP() { if (offset % 5 == 0) { \
+ if (col > 40) { \
+ fprintf(d, "\n\t"); \
+ col = 0; \
+ } else { \
+ fprintf(d, " "); \
+ col++; \
+ } \
+ } else \
+ col++; \
+ offset++; \
+ }
+
+ if (OP(g->strip[0]) != OEND)
+ fprintf(d, "missing initial OEND!\n");
+ for (s = &g->strip[1]; !done; s++) {
+ opnd = OPND(*s);
+ switch (OP(*s)) {
+ case OEND:
+ fprintf(d, "\n");
+ done = 1;
+ break;
+ case OCHAR:
+ if (strchr("\\|()^$.[+*?{}!<> ", (char)opnd) != NULL)
+ fprintf(d, "\\%c", (char)opnd);
+ else
+ fprintf(d, "%s", regchar((char)opnd));
+ break;
+ case OBOL:
+ fprintf(d, "^");
+ break;
+ case OEOL:
+ fprintf(d, "$");
+ break;
+ case OBOW:
+ fprintf(d, "\\{");
+ break;
+ case OEOW:
+ fprintf(d, "\\}");
+ break;
+ case OANY:
+ fprintf(d, ".");
+ break;
+ case OANYOF:
+ fprintf(d, "[(%ld)", (long)opnd);
+ cs = &g->sets[opnd];
+ last = -1;
+ for (i = 0; i < g->csetsize+1; i++) /* +1 flushes */
+ if (CHIN(cs, i) && i < g->csetsize) {
+ if (last < 0) {
+ fprintf(d, "%s", regchar(i));
+ last = i;
+ }
+ } else {
+ if (last >= 0) {
+ if (last != i-1)
+ fprintf(d, "-%s",
+ regchar(i-1));
+ last = -1;
+ }
+ }
+ fprintf(d, "]");
+ break;
+ case OBACK_:
+ fprintf(d, "(\\<%ld>", (long)opnd);
+ break;
+ case O_BACK:
+ fprintf(d, "<%ld>\\)", (long)opnd);
+ break;
+ case OPLUS_:
+ fprintf(d, "(+");
+ if (OP(*(s+opnd)) != O_PLUS)
+ fprintf(d, "<%ld>", (long)opnd);
+ break;
+ case O_PLUS:
+ if (OP(*(s-opnd)) != OPLUS_)
+ fprintf(d, "<%ld>", (long)opnd);
+ fprintf(d, "+)");
+ break;
+ case OQUEST_:
+ fprintf(d, "(?");
+ if (OP(*(s+opnd)) != O_QUEST)
+ fprintf(d, "<%ld>", (long)opnd);
+ break;
+ case O_QUEST:
+ if (OP(*(s-opnd)) != OQUEST_)
+ fprintf(d, "<%ld>", (long)opnd);
+ fprintf(d, "?)");
+ break;
+ case OLPAREN:
+ fprintf(d, "((<%ld>", (long)opnd);
+ break;
+ case ORPAREN:
+ fprintf(d, "<%ld>))", (long)opnd);
+ break;
+ case OCH_:
+ fprintf(d, "<");
+ if (OP(*(s+opnd)) != OOR2)
+ fprintf(d, "<%ld>", (long)opnd);
+ break;
+ case OOR1:
+ if (OP(*(s-opnd)) != OOR1 && OP(*(s-opnd)) != OCH_)
+ fprintf(d, "<%ld>", (long)opnd);
+ fprintf(d, "|");
+ break;
+ case OOR2:
+ fprintf(d, "|");
+ if (OP(*(s+opnd)) != OOR2 && OP(*(s+opnd)) != O_CH)
+ fprintf(d, "<%ld>", (long)opnd);
+ break;
+ case O_CH:
+ if (OP(*(s-opnd)) != OOR1)
+ fprintf(d, "<%ld>", (long)opnd);
+ fprintf(d, ">");
+ break;
+ default:
+ fprintf(d, "!%d(%d)!", OP(*s), opnd);
+ break;
+ }
+ if (!done)
+ GAP();
+ }
+}
+
+/*
+ - regchar - make a character printable
+ == static char *regchar(int ch);
+ */
+static char * /* -> representation */
+regchar(ch)
+int ch;
+{
+ static char buf[10];
+
+ if (isprint(ch) || ch == ' ')
+ sprintf(buf, "%c", ch);
+ else
+ sprintf(buf, "\\%o", ch);
+ return(buf);
+}
--- /dev/null
+/* ========= begin header generated by ./mkh ========= */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* === debug.c === */
+void regprint(regex_t *r, FILE *d);
+static void s_print(register struct re_guts *g, FILE *d);
+static char *regchar(int ch);
+
+#ifdef __cplusplus
+}
+#endif
+/* ========= end header generated by ./mkh ========= */
--- /dev/null
+/*
+ * The matching engine and friends. This file is #included by regexec.c
+ * after suitable #defines of a variety of macros used herein, so that
+ * different state representations can be used without duplicating masses
+ * of code.
+ */
+
+#ifdef SNAMES
+#define matcher smatcher
+#define fast sfast
+#define slow sslow
+#define dissect sdissect
+#define backref sbackref
+#define step sstep
+#define print sprint
+#define at sat
+#define match smat
+#endif
+#ifdef LNAMES
+#define matcher lmatcher
+#define fast lfast
+#define slow lslow
+#define dissect ldissect
+#define backref lbackref
+#define step lstep
+#define print lprint
+#define at lat
+#define match lmat
+#endif
+
+/* another structure passed up and down to avoid zillions of parameters */
+struct match {
+ struct re_guts *g;
+ int eflags;
+ regmatch_t *pmatch; /* [nsub+1] (0 element unused) */
+ char *offp; /* offsets work from here */
+ char *beginp; /* start of string -- virtual NUL precedes */
+ char *endp; /* end of string -- virtual NUL here */
+ char *coldp; /* can be no match starting before here */
+ char **lastpos; /* [nplus+1] */
+ STATEVARS;
+ states st; /* current states */
+ states fresh; /* states for a fresh start */
+ states tmp; /* temporary */
+ states empty; /* empty set of states */
+};
+
+#include "engine.ih"
+
+#ifdef REDEBUG
+#define SP(t, s, c) print(m, t, s, c, stdout)
+#define AT(t, p1, p2, s1, s2) at(m, t, p1, p2, s1, s2)
+#define NOTE(str) { if (m->eflags®_TRACE) printf("=%s\n", (str)); }
+#else
+#define SP(t, s, c) /* nothing */
+#define AT(t, p1, p2, s1, s2) /* nothing */
+#define NOTE(s) /* nothing */
+#endif
+
+/*
+ - matcher - the actual matching engine
+ == static int matcher(register struct re_guts *g, char *string, \
+ == size_t nmatch, regmatch_t pmatch[], int eflags);
+ */
+static int /* 0 success, REG_NOMATCH failure */
+matcher(g, string, nmatch, pmatch, eflags)
+register struct re_guts *g;
+char *string;
+size_t nmatch;
+regmatch_t pmatch[];
+int eflags;
+{
+ register char *endp;
+ register int i;
+ struct match mv;
+ register struct match *m = &mv;
+ register char *dp;
+ const register sopno gf = g->firststate+1; /* +1 for OEND */
+ const register sopno gl = g->laststate;
+ char *start;
+ char *stop;
+
+ /* simplify the situation where possible */
+ if (g->cflags®_NOSUB)
+ nmatch = 0;
+ if (eflags®_STARTEND) {
+ start = string + pmatch[0].rm_so;
+ stop = string + pmatch[0].rm_eo;
+ } else {
+ start = string;
+ stop = start + strlen(start);
+ }
+ if (stop < start)
+ return(REG_INVARG);
+
+ /* prescreening; this does wonders for this rather slow code */
+ if (g->must != NULL) {
+ for (dp = start; dp < stop; dp++)
+ if (*dp == g->must[0] && stop - dp >= g->mlen &&
+ memcmp(dp, g->must, (size_t)g->mlen) == 0)
+ break;
+ if (dp == stop) /* we didn't find g->must */
+ return(REG_NOMATCH);
+ }
+
+ /* match struct setup */
+ m->g = g;
+ m->eflags = eflags;
+ m->pmatch = NULL;
+ m->lastpos = NULL;
+ m->offp = string;
+ m->beginp = start;
+ m->endp = stop;
+ STATESETUP(m, 4);
+ SETUP(m->st);
+ SETUP(m->fresh);
+ SETUP(m->tmp);
+ SETUP(m->empty);
+ CLEAR(m->empty);
+
+ /* this loop does only one repetition except for backrefs */
+ for (;;) {
+ endp = fast(m, start, stop, gf, gl);
+ if (endp == NULL) { /* a miss */
+ STATETEARDOWN(m);
+ return(REG_NOMATCH);
+ }
+ if (nmatch == 0 && !g->backrefs)
+ break; /* no further info needed */
+
+ /* where? */
+ assert(m->coldp != NULL);
+ for (;;) {
+ NOTE("finding start");
+ endp = slow(m, m->coldp, stop, gf, gl);
+ if (endp != NULL)
+ break;
+ assert(m->coldp < m->endp);
+ m->coldp++;
+ }
+ if (nmatch == 1 && !g->backrefs)
+ break; /* no further info needed */
+
+ /* oh my, he wants the subexpressions... */
+ if (m->pmatch == NULL)
+ m->pmatch = (regmatch_t *)malloc((m->g->nsub + 1) *
+ sizeof(regmatch_t));
+ if (m->pmatch == NULL) {
+ STATETEARDOWN(m);
+ return(REG_ESPACE);
+ }
+ for (i = 1; i <= m->g->nsub; i++)
+ m->pmatch[i].rm_so = m->pmatch[i].rm_eo = -1;
+ if (!g->backrefs && !(m->eflags®_BACKR)) {
+ NOTE("dissecting");
+ dp = dissect(m, m->coldp, endp, gf, gl);
+ } else {
+ if (g->nplus > 0 && m->lastpos == NULL)
+ m->lastpos = (char **)malloc((g->nplus+1) *
+ sizeof(char *));
+ if (g->nplus > 0 && m->lastpos == NULL) {
+ free(m->pmatch);
+ STATETEARDOWN(m);
+ return(REG_ESPACE);
+ }
+ NOTE("backref dissect");
+ dp = backref(m, m->coldp, endp, gf, gl, (sopno)0);
+ }
+ if (dp != NULL)
+ break;
+
+ /* uh-oh... we couldn't find a subexpression-level match */
+ assert(g->backrefs); /* must be back references doing it */
+ assert(g->nplus == 0 || m->lastpos != NULL);
+ for (;;) {
+ if (dp != NULL || endp <= m->coldp)
+ break; /* defeat */
+ NOTE("backoff");
+ endp = slow(m, m->coldp, endp-1, gf, gl);
+ if (endp == NULL)
+ break; /* defeat */
+ /* try it on a shorter possibility */
+#ifndef NDEBUG
+ for (i = 1; i <= m->g->nsub; i++) {
+ assert(m->pmatch[i].rm_so == -1);
+ assert(m->pmatch[i].rm_eo == -1);
+ }
+#endif
+ NOTE("backoff dissect");
+ dp = backref(m, m->coldp, endp, gf, gl, (sopno)0);
+ }
+ assert(dp == NULL || dp == endp);
+ if (dp != NULL) /* found a shorter one */
+ break;
+
+ /* despite initial appearances, there is no match here */
+ NOTE("false alarm");
+ start = m->coldp + 1; /* recycle starting later */
+ assert(start <= stop);
+ }
+
+ /* fill in the details if requested */
+ if (nmatch > 0) {
+ pmatch[0].rm_so = m->coldp - m->offp;
+ pmatch[0].rm_eo = endp - m->offp;
+ }
+ if (nmatch > 1) {
+ assert(m->pmatch != NULL);
+ for (i = 1; i < nmatch; i++)
+ if (i <= m->g->nsub)
+ pmatch[i] = m->pmatch[i];
+ else {
+ pmatch[i].rm_so = -1;
+ pmatch[i].rm_eo = -1;
+ }
+ }
+
+ if (m->pmatch != NULL)
+ free((char *)m->pmatch);
+ if (m->lastpos != NULL)
+ free((char *)m->lastpos);
+ STATETEARDOWN(m);
+ return(0);
+}
+
+/*
+ - dissect - figure out what matched what, no back references
+ == static char *dissect(register struct match *m, char *start, \
+ == char *stop, sopno startst, sopno stopst);
+ */
+static char * /* == stop (success) always */
+dissect(m, start, stop, startst, stopst)
+register struct match *m;
+char *start;
+char *stop;
+sopno startst;
+sopno stopst;
+{
+ register int i;
+ register sopno ss; /* start sop of current subRE */
+ register sopno es; /* end sop of current subRE */
+ register char *sp; /* start of string matched by it */
+ register char *stp; /* string matched by it cannot pass here */
+ register char *rest; /* start of rest of string */
+ register char *tail; /* string unmatched by rest of RE */
+ register sopno ssub; /* start sop of subsubRE */
+ register sopno esub; /* end sop of subsubRE */
+ register char *ssp; /* start of string matched by subsubRE */
+ register char *sep; /* end of string matched by subsubRE */
+ register char *oldssp; /* previous ssp */
+ register char *dp;
+
+ AT("diss", start, stop, startst, stopst);
+ sp = start;
+ for (ss = startst; ss < stopst; ss = es) {
+ /* identify end of subRE */
+ es = ss;
+ switch (OP(m->g->strip[es])) {
+ case OPLUS_:
+ case OQUEST_:
+ es += OPND(m->g->strip[es]);
+ break;
+ case OCH_:
+ while (OP(m->g->strip[es]) != O_CH)
+ es += OPND(m->g->strip[es]);
+ break;
+ }
+ es++;
+
+ /* figure out what it matched */
+ switch (OP(m->g->strip[ss])) {
+ case OEND:
+ assert(nope);
+ break;
+ case OCHAR:
+ sp++;
+ break;
+ case OBOL:
+ case OEOL:
+ case OBOW:
+ case OEOW:
+ break;
+ case OANY:
+ case OANYOF:
+ sp++;
+ break;
+ case OBACK_:
+ case O_BACK:
+ assert(nope);
+ break;
+ /* cases where length of match is hard to find */
+ case OQUEST_:
+ stp = stop;
+ for (;;) {
+ /* how long could this one be? */
+ rest = slow(m, sp, stp, ss, es);
+ assert(rest != NULL); /* it did match */
+ /* could the rest match the rest? */
+ tail = slow(m, rest, stop, es, stopst);
+ if (tail == stop)
+ break; /* yes! */
+ /* no -- try a shorter match for this one */
+ stp = rest - 1;
+ assert(stp >= sp); /* it did work */
+ }
+ ssub = ss + 1;
+ esub = es - 1;
+ /* did innards match? */
+ if (slow(m, sp, rest, ssub, esub) != NULL) {
+ dp = dissect(m, sp, rest, ssub, esub);
+ assert(dp == rest);
+ } else /* no */
+ assert(sp == rest);
+ sp = rest;
+ break;
+ case OPLUS_:
+ stp = stop;
+ for (;;) {
+ /* how long could this one be? */
+ rest = slow(m, sp, stp, ss, es);
+ assert(rest != NULL); /* it did match */
+ /* could the rest match the rest? */
+ tail = slow(m, rest, stop, es, stopst);
+ if (tail == stop)
+ break; /* yes! */
+ /* no -- try a shorter match for this one */
+ stp = rest - 1;
+ assert(stp >= sp); /* it did work */
+ }
+ ssub = ss + 1;
+ esub = es - 1;
+ ssp = sp;
+ oldssp = ssp;
+ for (;;) { /* find last match of innards */
+ sep = slow(m, ssp, rest, ssub, esub);
+ if (sep == NULL || sep == ssp)
+ break; /* failed or matched null */
+ oldssp = ssp; /* on to next try */
+ ssp = sep;
+ }
+ if (sep == NULL) {
+ /* last successful match */
+ sep = ssp;
+ ssp = oldssp;
+ }
+ assert(sep == rest); /* must exhaust substring */
+ assert(slow(m, ssp, sep, ssub, esub) == rest);
+ dp = dissect(m, ssp, sep, ssub, esub);
+ assert(dp == sep);
+ sp = rest;
+ break;
+ case OCH_:
+ stp = stop;
+ for (;;) {
+ /* how long could this one be? */
+ rest = slow(m, sp, stp, ss, es);
+ assert(rest != NULL); /* it did match */
+ /* could the rest match the rest? */
+ tail = slow(m, rest, stop, es, stopst);
+ if (tail == stop)
+ break; /* yes! */
+ /* no -- try a shorter match for this one */
+ stp = rest - 1;
+ assert(stp >= sp); /* it did work */
+ }
+ ssub = ss + 1;
+ esub = ss + OPND(m->g->strip[ss]) - 1;
+ assert(OP(m->g->strip[esub]) == OOR1);
+ for (;;) { /* find first matching branch */
+ if (slow(m, sp, rest, ssub, esub) == rest)
+ break; /* it matched all of it */
+ /* that one missed, try next one */
+ assert(OP(m->g->strip[esub]) == OOR1);
+ esub++;
+ assert(OP(m->g->strip[esub]) == OOR2);
+ ssub = esub + 1;
+ esub += OPND(m->g->strip[esub]);
+ if (OP(m->g->strip[esub]) == OOR2)
+ esub--;
+ else
+ assert(OP(m->g->strip[esub]) == O_CH);
+ }
+ dp = dissect(m, sp, rest, ssub, esub);
+ assert(dp == rest);
+ sp = rest;
+ break;
+ case O_PLUS:
+ case O_QUEST:
+ case OOR1:
+ case OOR2:
+ case O_CH:
+ assert(nope);
+ break;
+ case OLPAREN:
+ i = OPND(m->g->strip[ss]);
+ assert(0 < i && i <= m->g->nsub);
+ m->pmatch[i].rm_so = sp - m->offp;
+ break;
+ case ORPAREN:
+ i = OPND(m->g->strip[ss]);
+ assert(0 < i && i <= m->g->nsub);
+ m->pmatch[i].rm_eo = sp - m->offp;
+ break;
+ default: /* uh oh */
+ assert(nope);
+ break;
+ }
+ }
+
+ assert(sp == stop);
+ return(sp);
+}
+
+/*
+ - backref - figure out what matched what, figuring in back references
+ == static char *backref(register struct match *m, char *start, \
+ == char *stop, sopno startst, sopno stopst, sopno lev);
+ */
+static char * /* == stop (success) or NULL (failure) */
+backref(m, start, stop, startst, stopst, lev)
+register struct match *m;
+char *start;
+char *stop;
+sopno startst;
+sopno stopst;
+sopno lev; /* PLUS nesting level */
+{
+ register int i;
+ register sopno ss; /* start sop of current subRE */
+ register char *sp; /* start of string matched by it */
+ register sopno ssub; /* start sop of subsubRE */
+ register sopno esub; /* end sop of subsubRE */
+ register char *ssp; /* start of string matched by subsubRE */
+ register char *dp;
+ register size_t len;
+ register int hard;
+ register sop s;
+ register regoff_t offsave;
+ register cset *cs;
+
+ AT("back", start, stop, startst, stopst);
+ sp = start;
+
+ /* get as far as we can with easy stuff */
+ hard = 0;
+ for (ss = startst; !hard && ss < stopst; ss++)
+ switch (OP(s = m->g->strip[ss])) {
+ case OCHAR:
+ if (sp == stop || *sp++ != (char)OPND(s))
+ return(NULL);
+ break;
+ case OANY:
+ if (sp == stop)
+ return(NULL);
+ sp++;
+ break;
+ case OANYOF:
+ cs = &m->g->sets[OPND(s)];
+ if (sp == stop || !CHIN(cs, *sp++))
+ return(NULL);
+ break;
+ case OBOL:
+ if ( (sp == m->beginp && !(m->eflags®_NOTBOL)) ||
+ (sp < m->endp && *(sp-1) == '\n' &&
+ (m->g->cflags®_NEWLINE)) )
+ { /* yes */ }
+ else
+ return(NULL);
+ break;
+ case OEOL:
+ if ( (sp == m->endp && !(m->eflags®_NOTEOL)) ||
+ (sp < m->endp && *sp == '\n' &&
+ (m->g->cflags®_NEWLINE)) )
+ { /* yes */ }
+ else
+ return(NULL);
+ break;
+ case OBOW:
+ if (( (sp == m->beginp && !(m->eflags®_NOTBOL)) ||
+ (sp < m->endp && *(sp-1) == '\n' &&
+ (m->g->cflags®_NEWLINE)) ||
+ (sp > m->beginp &&
+ !ISWORD(*(sp-1))) ) &&
+ (sp < m->endp && ISWORD(*sp)) )
+ { /* yes */ }
+ else
+ return(NULL);
+ break;
+ case OEOW:
+ if (( (sp == m->endp && !(m->eflags®_NOTEOL)) ||
+ (sp < m->endp && *sp == '\n' &&
+ (m->g->cflags®_NEWLINE)) ||
+ (sp < m->endp && !ISWORD(*sp)) ) &&
+ (sp > m->beginp && ISWORD(*(sp-1))) )
+ { /* yes */ }
+ else
+ return(NULL);
+ break;
+ case O_QUEST:
+ break;
+ case OOR1: /* matches null but needs to skip */
+ ss++;
+ s = m->g->strip[ss];
+ do {
+ assert(OP(s) == OOR2);
+ ss += OPND(s);
+ } while (OP(s = m->g->strip[ss]) != O_CH);
+ /* note that the ss++ gets us past the O_CH */
+ break;
+ default: /* have to make a choice */
+ hard = 1;
+ break;
+ }
+ if (!hard) { /* that was it! */
+ if (sp != stop)
+ return(NULL);
+ return(sp);
+ }
+ ss--; /* adjust for the for's final increment */
+
+ /* the hard stuff */
+ AT("hard", sp, stop, ss, stopst);
+ s = m->g->strip[ss];
+ switch (OP(s)) {
+ case OBACK_: /* the vilest depths */
+ i = OPND(s);
+ assert(0 < i && i <= m->g->nsub);
+ if (m->pmatch[i].rm_eo == -1)
+ return(NULL);
+ assert(m->pmatch[i].rm_so != -1);
+ len = m->pmatch[i].rm_eo - m->pmatch[i].rm_so;
+ assert(stop - m->beginp >= len);
+ if (sp > stop - len)
+ return(NULL); /* not enough left to match */
+ ssp = m->offp + m->pmatch[i].rm_so;
+ if (memcmp(sp, ssp, len) != 0)
+ return(NULL);
+ while (m->g->strip[ss] != SOP(O_BACK, i))
+ ss++;
+ return(backref(m, sp+len, stop, ss+1, stopst, lev));
+ break;
+ case OQUEST_: /* to null or not */
+ dp = backref(m, sp, stop, ss+1, stopst, lev);
+ if (dp != NULL)
+ return(dp); /* not */
+ return(backref(m, sp, stop, ss+OPND(s)+1, stopst, lev));
+ break;
+ case OPLUS_:
+ assert(m->lastpos != NULL);
+ assert(lev+1 <= m->g->nplus);
+ m->lastpos[lev+1] = sp;
+ return(backref(m, sp, stop, ss+1, stopst, lev+1));
+ break;
+ case O_PLUS:
+ if (sp == m->lastpos[lev]) /* last pass matched null */
+ return(backref(m, sp, stop, ss+1, stopst, lev-1));
+ /* try another pass */
+ m->lastpos[lev] = sp;
+ dp = backref(m, sp, stop, ss-OPND(s)+1, stopst, lev);
+ if (dp == NULL)
+ return(backref(m, sp, stop, ss+1, stopst, lev-1));
+ else
+ return(dp);
+ break;
+ case OCH_: /* find the right one, if any */
+ ssub = ss + 1;
+ esub = ss + OPND(s) - 1;
+ assert(OP(m->g->strip[esub]) == OOR1);
+ for (;;) { /* find first matching branch */
+ dp = backref(m, sp, stop, ssub, esub, lev);
+ if (dp != NULL)
+ return(dp);
+ /* that one missed, try next one */
+ if (OP(m->g->strip[esub]) == O_CH)
+ return(NULL); /* there is none */
+ esub++;
+ assert(OP(m->g->strip[esub]) == OOR2);
+ ssub = esub + 1;
+ esub += OPND(m->g->strip[esub]);
+ if (OP(m->g->strip[esub]) == OOR2)
+ esub--;
+ else
+ assert(OP(m->g->strip[esub]) == O_CH);
+ }
+ break;
+ case OLPAREN: /* must undo assignment if rest fails */
+ i = OPND(s);
+ assert(0 < i && i <= m->g->nsub);
+ offsave = m->pmatch[i].rm_so;
+ m->pmatch[i].rm_so = sp - m->offp;
+ dp = backref(m, sp, stop, ss+1, stopst, lev);
+ if (dp != NULL)
+ return(dp);
+ m->pmatch[i].rm_so = offsave;
+ return(NULL);
+ break;
+ case ORPAREN: /* must undo assignment if rest fails */
+ i = OPND(s);
+ assert(0 < i && i <= m->g->nsub);
+ offsave = m->pmatch[i].rm_eo;
+ m->pmatch[i].rm_eo = sp - m->offp;
+ dp = backref(m, sp, stop, ss+1, stopst, lev);
+ if (dp != NULL)
+ return(dp);
+ m->pmatch[i].rm_eo = offsave;
+ return(NULL);
+ break;
+ default: /* uh oh */
+ assert(nope);
+ break;
+ }
+
+ /* "can't happen" */
+ assert(nope);
+ /* NOTREACHED */
+ return((char *)NULL); /* dummy */
+}
+
+/*
+ - fast - step through the string at top speed
+ == static char *fast(register struct match *m, char *start, \
+ == char *stop, sopno startst, sopno stopst);
+ */
+static char * /* where tentative match ended, or NULL */
+fast(m, start, stop, startst, stopst)
+register struct match *m;
+char *start;
+char *stop;
+sopno startst;
+sopno stopst;
+{
+ register states st = m->st;
+ register states fresh = m->fresh;
+ register states tmp = m->tmp;
+ register char *p = start;
+ register int c = (start == m->beginp) ? OUT : *(start-1);
+ register int lastc; /* previous c */
+ register int flagch;
+ register int i;
+ register char *coldp; /* last p after which no match was underway */
+
+ CLEAR(st);
+ SET1(st, startst);
+ st = step(m->g, startst, stopst, st, NOTHING, st);
+ ASSIGN(fresh, st);
+ SP("start", st, *p);
+ coldp = NULL;
+ for (;;) {
+ /* next character */
+ lastc = c;
+ c = (p == m->endp) ? OUT : *p;
+ if (EQ(st, fresh))
+ coldp = p;
+
+ /* is there an EOL and/or BOL between lastc and c? */
+ flagch = '\0';
+ i = 0;
+ if ( (lastc == '\n' && m->g->cflags®_NEWLINE) ||
+ (lastc == OUT && !(m->eflags®_NOTBOL)) ) {
+ flagch = BOL;
+ i = m->g->nbol;
+ }
+ if ( (c == '\n' && m->g->cflags®_NEWLINE) ||
+ (c == OUT && !(m->eflags®_NOTEOL)) ) {
+ flagch = (flagch == BOL) ? BOLEOL : EOL;
+ i += m->g->neol;
+ }
+ if (i != 0) {
+ for (; i > 0; i--)
+ st = step(m->g, startst, stopst, st, flagch, st);
+ SP("boleol", st, c);
+ }
+
+ /* how about a word boundary? */
+ if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) &&
+ (c != OUT && ISWORD(c)) ) {
+ flagch = BOW;
+ }
+ if ( (lastc != OUT && ISWORD(lastc)) &&
+ (flagch == EOL || (c != OUT && !ISWORD(c))) ) {
+ flagch = EOW;
+ }
+ if (flagch == BOW || flagch == EOW) {
+ st = step(m->g, startst, stopst, st, flagch, st);
+ SP("boweow", st, c);
+ }
+
+ /* are we done? */
+ if (ISSET(st, stopst) || p == stop)
+ break; /* NOTE BREAK OUT */
+
+ /* no, we must deal with this character */
+ ASSIGN(tmp, st);
+ ASSIGN(st, fresh);
+ assert(c != OUT);
+ st = step(m->g, startst, stopst, tmp, c, st);
+ SP("aft", st, c);
+ assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st));
+ p++;
+ }
+
+ assert(coldp != NULL);
+ m->coldp = coldp;
+ if (ISSET(st, stopst))
+ return(p+1);
+ else
+ return(NULL);
+}
+
+/*
+ - slow - step through the string more deliberately
+ == static char *slow(register struct match *m, char *start, \
+ == char *stop, sopno startst, sopno stopst);
+ */
+static char * /* where it ended */
+slow(m, start, stop, startst, stopst)
+register struct match *m;
+char *start;
+char *stop;
+sopno startst;
+sopno stopst;
+{
+ register states st = m->st;
+ register states empty = m->empty;
+ register states tmp = m->tmp;
+ register char *p = start;
+ register int c = (start == m->beginp) ? OUT : *(start-1);
+ register int lastc; /* previous c */
+ register int flagch;
+ register int i;
+ register char *matchp; /* last p at which a match ended */
+
+ AT("slow", start, stop, startst, stopst);
+ CLEAR(st);
+ SET1(st, startst);
+ SP("sstart", st, *p);
+ st = step(m->g, startst, stopst, st, NOTHING, st);
+ matchp = NULL;
+ for (;;) {
+ /* next character */
+ lastc = c;
+ c = (p == m->endp) ? OUT : *p;
+
+ /* is there an EOL and/or BOL between lastc and c? */
+ flagch = '\0';
+ i = 0;
+ if ( (lastc == '\n' && m->g->cflags®_NEWLINE) ||
+ (lastc == OUT && !(m->eflags®_NOTBOL)) ) {
+ flagch = BOL;
+ i = m->g->nbol;
+ }
+ if ( (c == '\n' && m->g->cflags®_NEWLINE) ||
+ (c == OUT && !(m->eflags®_NOTEOL)) ) {
+ flagch = (flagch == BOL) ? BOLEOL : EOL;
+ i += m->g->neol;
+ }
+ if (i != 0) {
+ for (; i > 0; i--)
+ st = step(m->g, startst, stopst, st, flagch, st);
+ SP("sboleol", st, c);
+ }
+
+ /* how about a word boundary? */
+ if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) &&
+ (c != OUT && ISWORD(c)) ) {
+ flagch = BOW;
+ }
+ if ( (lastc != OUT && ISWORD(lastc)) &&
+ (flagch == EOL || (c != OUT && !ISWORD(c))) ) {
+ flagch = EOW;
+ }
+ if (flagch == BOW || flagch == EOW) {
+ st = step(m->g, startst, stopst, st, flagch, st);
+ SP("sboweow", st, c);
+ }
+
+ /* are we done? */
+ if (ISSET(st, stopst))
+ matchp = p;
+ if (EQ(st, empty) || p == stop)
+ break; /* NOTE BREAK OUT */
+
+ /* no, we must deal with this character */
+ ASSIGN(tmp, st);
+ ASSIGN(st, empty);
+ assert(c != OUT);
+ st = step(m->g, startst, stopst, tmp, c, st);
+ SP("saft", st, c);
+ assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st));
+ p++;
+ }
+
+ return(matchp);
+}
+
+
+/*
+ - step - map set of states reachable before char to set reachable after
+ == static states step(register struct re_guts *g, sopno start, sopno stop, \
+ == register states bef, int ch, register states aft);
+ == #define BOL (OUT+1)
+ == #define EOL (BOL+1)
+ == #define BOLEOL (BOL+2)
+ == #define NOTHING (BOL+3)
+ == #define BOW (BOL+4)
+ == #define EOW (BOL+5)
+ == #define CODEMAX (BOL+5) // highest code used
+ == #define NONCHAR(c) ((c) > CHAR_MAX)
+ == #define NNONCHAR (CODEMAX-CHAR_MAX)
+ */
+static states
+step(g, start, stop, bef, ch, aft)
+register struct re_guts *g;
+sopno start; /* start state within strip */
+sopno stop; /* state after stop state within strip */
+register states bef; /* states reachable before */
+int ch; /* character or NONCHAR code */
+register states aft; /* states already known reachable after */
+{
+ register cset *cs;
+ register sop s;
+ register sopno pc;
+ register onestate here; /* note, macros know this name */
+ register sopno look;
+ register long i;
+
+ for (pc = start, INIT(here, pc); pc != stop; pc++, INC(here)) {
+ s = g->strip[pc];
+ switch (OP(s)) {
+ case OEND:
+ assert(pc == stop-1);
+ break;
+ case OCHAR:
+ /* only characters can match */
+ assert(!NONCHAR(ch) || ch != (char)OPND(s));
+ if (ch == (char)OPND(s))
+ FWD(aft, bef, 1);
+ break;
+ case OBOL:
+ if (ch == BOL || ch == BOLEOL)
+ FWD(aft, bef, 1);
+ break;
+ case OEOL:
+ if (ch == EOL || ch == BOLEOL)
+ FWD(aft, bef, 1);
+ break;
+ case OBOW:
+ if (ch == BOW)
+ FWD(aft, bef, 1);
+ break;
+ case OEOW:
+ if (ch == EOW)
+ FWD(aft, bef, 1);
+ break;
+ case OANY:
+ if (!NONCHAR(ch))
+ FWD(aft, bef, 1);
+ break;
+ case OANYOF:
+ cs = &g->sets[OPND(s)];
+ if (!NONCHAR(ch) && CHIN(cs, ch))
+ FWD(aft, bef, 1);
+ break;
+ case OBACK_: /* ignored here */
+ case O_BACK:
+ FWD(aft, aft, 1);
+ break;
+ case OPLUS_: /* forward, this is just an empty */
+ FWD(aft, aft, 1);
+ break;
+ case O_PLUS: /* both forward and back */
+ FWD(aft, aft, 1);
+ i = ISSETBACK(aft, OPND(s));
+ BACK(aft, aft, OPND(s));
+ if (!i && ISSETBACK(aft, OPND(s))) {
+ /* oho, must reconsider loop body */
+ pc -= OPND(s) + 1;
+ INIT(here, pc);
+ }
+ break;
+ case OQUEST_: /* two branches, both forward */
+ FWD(aft, aft, 1);
+ FWD(aft, aft, OPND(s));
+ break;
+ case O_QUEST: /* just an empty */
+ FWD(aft, aft, 1);
+ break;
+ case OLPAREN: /* not significant here */
+ case ORPAREN:
+ FWD(aft, aft, 1);
+ break;
+ case OCH_: /* mark the first two branches */
+ FWD(aft, aft, 1);
+ assert(OP(g->strip[pc+OPND(s)]) == OOR2);
+ FWD(aft, aft, OPND(s));
+ break;
+ case OOR1: /* done a branch, find the O_CH */
+ if (ISSTATEIN(aft, here)) {
+ for (look = 1;
+ OP(s = g->strip[pc+look]) != O_CH;
+ look += OPND(s))
+ assert(OP(s) == OOR2);
+ FWD(aft, aft, look);
+ }
+ break;
+ case OOR2: /* propagate OCH_'s marking */
+ FWD(aft, aft, 1);
+ if (OP(g->strip[pc+OPND(s)]) != O_CH) {
+ assert(OP(g->strip[pc+OPND(s)]) == OOR2);
+ FWD(aft, aft, OPND(s));
+ }
+ break;
+ case O_CH: /* just empty */
+ FWD(aft, aft, 1);
+ break;
+ default: /* ooooops... */
+ assert(nope);
+ break;
+ }
+ }
+
+ return(aft);
+}
+
+#ifdef REDEBUG
+/*
+ - print - print a set of states
+ == #ifdef REDEBUG
+ == static void print(struct match *m, char *caption, states st, \
+ == int ch, FILE *d);
+ == #endif
+ */
+static void
+print(m, caption, st, ch, d)
+struct match *m;
+char *caption;
+states st;
+int ch;
+FILE *d;
+{
+ register struct re_guts *g = m->g;
+ register int i;
+ register int first = 1;
+
+ if (!(m->eflags®_TRACE))
+ return;
+
+ fprintf(d, "%s", caption);
+ if (ch != '\0')
+ fprintf(d, " %s", pchar(ch));
+ for (i = 0; i < g->nstates; i++)
+ if (ISSET(st, i)) {
+ fprintf(d, "%s%d", (first) ? "\t" : ", ", i);
+ first = 0;
+ }
+ fprintf(d, "\n");
+}
+
+/*
+ - at - print current situation
+ == #ifdef REDEBUG
+ == static void at(struct match *m, char *title, char *start, char *stop, \
+ == sopno startst, sopno stopst);
+ == #endif
+ */
+static void
+at(m, title, start, stop, startst, stopst)
+struct match *m;
+char *title;
+char *start;
+char *stop;
+sopno startst;
+sopno stopst;
+{
+ if (!(m->eflags®_TRACE))
+ return;
+
+ printf("%s %s-", title, pchar(*start));
+ printf("%s ", pchar(*stop));
+ printf("%ld-%ld\n", (long)startst, (long)stopst);
+}
+
+#ifndef PCHARDONE
+#define PCHARDONE /* never again */
+/*
+ - pchar - make a character printable
+ == #ifdef REDEBUG
+ == static char *pchar(int ch);
+ == #endif
+ *
+ * Is this identical to regchar() over in debug.c? Well, yes. But a
+ * duplicate here avoids having a debugging-capable regexec.o tied to
+ * a matching debug.o, and this is convenient. It all disappears in
+ * the non-debug compilation anyway, so it doesn't matter much.
+ */
+static char * /* -> representation */
+pchar(ch)
+int ch;
+{
+ static char pbuf[10];
+
+ if (isprint(ch) || ch == ' ')
+ sprintf(pbuf, "%c", ch);
+ else
+ sprintf(pbuf, "\\%o", ch);
+ return(pbuf);
+}
+#endif
+#endif
+
+#undef matcher
+#undef fast
+#undef slow
+#undef dissect
+#undef backref
+#undef step
+#undef print
+#undef at
+#undef match
--- /dev/null
+/* ========= begin header generated by ./mkh ========= */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* === engine.c === */
+static int matcher(register struct re_guts *g, char *string, size_t nmatch, regmatch_t pmatch[], int eflags);
+static char *dissect(register struct match *m, char *start, char *stop, sopno startst, sopno stopst);
+static char *backref(register struct match *m, char *start, char *stop, sopno startst, sopno stopst, sopno lev);
+static char *fast(register struct match *m, char *start, char *stop, sopno startst, sopno stopst);
+static char *slow(register struct match *m, char *start, char *stop, sopno startst, sopno stopst);
+static states step(register struct re_guts *g, sopno start, sopno stop, register states bef, int ch, register states aft);
+#define BOL (OUT+1)
+#define EOL (BOL+1)
+#define BOLEOL (BOL+2)
+#define NOTHING (BOL+3)
+#define BOW (BOL+4)
+#define EOW (BOL+5)
+#define CODEMAX (BOL+5) /* highest code used */
+#define NONCHAR(c) ((c) > CHAR_MAX)
+#define NNONCHAR (CODEMAX-CHAR_MAX)
+#ifdef REDEBUG
+static void print(struct match *m, char *caption, states st, int ch, FILE *d);
+#endif
+#ifdef REDEBUG
+static void at(struct match *m, char *title, char *start, char *stop, sopno startst, sopno stopst);
+#endif
+#ifdef REDEBUG
+static char *pchar(int ch);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+/* ========= end header generated by ./mkh ========= */
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <regex.h>
+#include <assert.h>
+
+#include "main.ih"
+
+char *progname;
+int debug = 0;
+int line = 0;
+int status = 0;
+
+int copts = REG_EXTENDED;
+int eopts = 0;
+regoff_t startoff = 0;
+regoff_t endoff = 0;
+
+
+extern int split();
+extern void regprint();
+
+/*
+ - main - do the simple case, hand off to regress() for regression
+ */
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ regex_t re;
+# define NS 10
+ regmatch_t subs[NS];
+ char erbuf[100];
+ int err;
+ size_t len;
+ int c;
+ int errflg = 0;
+ register int i;
+ extern int optind;
+ extern char *optarg;
+
+ progname = argv[0];
+
+ while ((c = getopt(argc, argv, "c:e:S:E:x")) != EOF)
+ switch (c) {
+ case 'c': /* compile options */
+ copts = options('c', optarg);
+ break;
+ case 'e': /* execute options */
+ eopts = options('e', optarg);
+ break;
+ case 'S': /* start offset */
+ startoff = (regoff_t)atoi(optarg);
+ break;
+ case 'E': /* end offset */
+ endoff = (regoff_t)atoi(optarg);
+ break;
+ case 'x': /* Debugging. */
+ debug++;
+ break;
+ case '?':
+ default:
+ errflg++;
+ break;
+ }
+ if (errflg) {
+ fprintf(stderr, "usage: %s ", progname);
+ fprintf(stderr, "[-c copt][-C][-d] [re]\n");
+ exit(2);
+ }
+
+ if (optind >= argc) {
+ regress(stdin);
+ exit(status);
+ }
+
+ err = regcomp(&re, argv[optind++], copts);
+ if (err) {
+ len = regerror(err, &re, erbuf, sizeof(erbuf));
+ fprintf(stderr, "error %s, %d/%d `%s'\n",
+ eprint(err), len, sizeof(erbuf), erbuf);
+ exit(status);
+ }
+ regprint(&re, stdout);
+
+ if (optind >= argc) {
+ regfree(&re);
+ exit(status);
+ }
+
+ if (eopts®_STARTEND) {
+ subs[0].rm_so = startoff;
+ subs[0].rm_eo = strlen(argv[optind]) - endoff;
+ }
+ err = regexec(&re, argv[optind], (size_t)NS, subs, eopts);
+ if (err) {
+ len = regerror(err, &re, erbuf, sizeof(erbuf));
+ fprintf(stderr, "error %s, %d/%d `%s'\n",
+ eprint(err), len, sizeof(erbuf), erbuf);
+ exit(status);
+ }
+ if (!(copts®_NOSUB)) {
+ len = (int)(subs[0].rm_eo - subs[0].rm_so);
+ if (subs[0].rm_so != -1) {
+ if (len != 0)
+ printf("match `%.*s'\n", len,
+ argv[optind] + subs[0].rm_so);
+ else
+ printf("match `'@%.1s\n",
+ argv[optind] + subs[0].rm_so);
+ }
+ for (i = 1; i < NS; i++)
+ if (subs[i].rm_so != -1)
+ printf("(%d) `%.*s'\n", i,
+ (int)(subs[i].rm_eo - subs[i].rm_so),
+ argv[optind] + subs[i].rm_so);
+ }
+ exit(status);
+}
+
+/*
+ - regress - main loop of regression test
+ == void regress(FILE *in);
+ */
+void
+regress(in)
+FILE *in;
+{
+ char inbuf[1000];
+# define MAXF 10
+ char *f[MAXF];
+ int nf;
+ int i;
+ char erbuf[100];
+ size_t ne;
+ char *badpat = "invalid regular expression";
+# define SHORT 10
+ char *bpname = "REG_BADPAT";
+ regex_t re;
+
+ while (fgets(inbuf, sizeof(inbuf), in) != NULL) {
+ line++;
+ if (inbuf[0] == '#' || inbuf[0] == '\n')
+ continue; /* NOTE CONTINUE */
+ inbuf[strlen(inbuf)-1] = '\0'; /* get rid of stupid \n */
+ if (debug)
+ fprintf(stdout, "%d:\n", line);
+ nf = split(inbuf, f, MAXF, "\t\t");
+ if (nf < 3) {
+ fprintf(stderr, "bad input, line %d\n", line);
+ exit(1);
+ }
+ for (i = 0; i < nf; i++)
+ if (strcmp(f[i], "\"\"") == 0)
+ f[i] = "";
+ if (nf <= 3)
+ f[3] = NULL;
+ if (nf <= 4)
+ f[4] = NULL;
+ try(f[0], f[1], f[2], f[3], f[4], options('c', f[1]));
+ if (opt('&', f[1])) /* try with either type of RE */
+ try(f[0], f[1], f[2], f[3], f[4],
+ options('c', f[1]) &~ REG_EXTENDED);
+ }
+
+ ne = regerror(REG_BADPAT, (regex_t *)NULL, erbuf, sizeof(erbuf));
+ if (strcmp(erbuf, badpat) != 0 || ne != strlen(badpat)+1) {
+ fprintf(stderr, "end: regerror() test gave `%s' not `%s'\n",
+ erbuf, badpat);
+ status = 1;
+ }
+ ne = regerror(REG_BADPAT, (regex_t *)NULL, erbuf, (size_t)SHORT);
+ if (strncmp(erbuf, badpat, SHORT-1) != 0 || erbuf[SHORT-1] != '\0' ||
+ ne != strlen(badpat)+1) {
+ fprintf(stderr, "end: regerror() short test gave `%s' not `%.*s'\n",
+ erbuf, SHORT-1, badpat);
+ status = 1;
+ }
+ ne = regerror(REG_ITOA|REG_BADPAT, (regex_t *)NULL, erbuf, sizeof(erbuf));
+ if (strcmp(erbuf, bpname) != 0 || ne != strlen(bpname)+1) {
+ fprintf(stderr, "end: regerror() ITOA test gave `%s' not `%s'\n",
+ erbuf, bpname);
+ status = 1;
+ }
+ re.re_endp = bpname;
+ ne = regerror(REG_ATOI, &re, erbuf, sizeof(erbuf));
+ if (atoi(erbuf) != (int)REG_BADPAT) {
+ fprintf(stderr, "end: regerror() ATOI test gave `%s' not `%ld'\n",
+ erbuf, (long)REG_BADPAT);
+ status = 1;
+ } else if (ne != strlen(erbuf)+1) {
+ fprintf(stderr, "end: regerror() ATOI test len(`%s') = %ld\n",
+ erbuf, (long)REG_BADPAT);
+ status = 1;
+ }
+}
+
+/*
+ - try - try it, and report on problems
+ == void try(char *f0, char *f1, char *f2, char *f3, char *f4, int opts);
+ */
+void
+try(f0, f1, f2, f3, f4, opts)
+char *f0;
+char *f1;
+char *f2;
+char *f3;
+char *f4;
+int opts; /* may not match f1 */
+{
+ regex_t re;
+# define NSUBS 10
+ regmatch_t subs[NSUBS];
+# define NSHOULD 15
+ char *should[NSHOULD];
+ int nshould;
+ char erbuf[100];
+ int err;
+ int len;
+ char *type = (opts & REG_EXTENDED) ? "ERE" : "BRE";
+ register int i;
+ char *grump;
+ char f0copy[1000];
+ char f2copy[1000];
+
+ strcpy(f0copy, f0);
+ re.re_endp = (opts®_PEND) ? f0copy + strlen(f0copy) : NULL;
+ fixstr(f0copy);
+ err = regcomp(&re, f0copy, opts);
+ if (err != 0 && (!opt('C', f1) || err != efind(f2))) {
+ /* unexpected error or wrong error */
+ len = regerror(err, &re, erbuf, sizeof(erbuf));
+ fprintf(stderr, "%d: %s error %s, %d/%d `%s'\n",
+ line, type, eprint(err), len,
+ sizeof(erbuf), erbuf);
+ status = 1;
+ } else if (err == 0 && opt('C', f1)) {
+ /* unexpected success */
+ fprintf(stderr, "%d: %s should have given REG_%s\n",
+ line, type, f2);
+ status = 1;
+ err = 1; /* so we won't try regexec */
+ }
+
+ if (err != 0) {
+ regfree(&re);
+ return;
+ }
+
+ strcpy(f2copy, f2);
+ fixstr(f2copy);
+
+ if (options('e', f1)®_STARTEND) {
+ if (strchr(f2, '(') == NULL || strchr(f2, ')') == NULL)
+ fprintf(stderr, "%d: bad STARTEND syntax\n", line);
+ subs[0].rm_so = strchr(f2, '(') - f2 + 1;
+ subs[0].rm_eo = strchr(f2, ')') - f2;
+ }
+ err = regexec(&re, f2copy, NSUBS, subs, options('e', f1));
+
+ if (err != 0 && (f3 != NULL || err != REG_NOMATCH)) {
+ /* unexpected error or wrong error */
+ len = regerror(err, &re, erbuf, sizeof(erbuf));
+ fprintf(stderr, "%d: %s exec error %s, %d/%d `%s'\n",
+ line, type, eprint(err), len,
+ sizeof(erbuf), erbuf);
+ status = 1;
+ } else if (err != 0) {
+ /* nothing more to check */
+ } else if (f3 == NULL) {
+ /* unexpected success */
+ fprintf(stderr, "%d: %s exec should have failed\n",
+ line, type);
+ status = 1;
+ err = 1; /* just on principle */
+ } else if (opts®_NOSUB) {
+ /* nothing more to check */
+ } else if ((grump = check(f2, subs[0], f3)) != NULL) {
+ fprintf(stderr, "%d: %s %s\n", line, type, grump);
+ status = 1;
+ err = 1;
+ }
+
+ if (err != 0 || f4 == NULL) {
+ regfree(&re);
+ return;
+ }
+
+ for (i = 1; i < NSHOULD; i++)
+ should[i] = NULL;
+ nshould = split(f4, should+1, NSHOULD-1, ",");
+ if (nshould == 0) {
+ nshould = 1;
+ should[1] = "";
+ }
+ for (i = 1; i < NSUBS; i++) {
+ grump = check(f2, subs[i], should[i]);
+ if (grump != NULL) {
+ fprintf(stderr, "%d: %s $%d %s\n", line,
+ type, i, grump);
+ status = 1;
+ err = 1;
+ }
+ }
+
+ regfree(&re);
+}
+
+/*
+ - options - pick options out of a regression-test string
+ == int options(int type, char *s);
+ */
+int
+options(type, s)
+int type; /* 'c' compile, 'e' exec */
+char *s;
+{
+ register char *p;
+ register int o = (type == 'c') ? copts : eopts;
+ register char *legal = (type == 'c') ? "bisnmp" : "^$#tl";
+
+ for (p = s; *p != '\0'; p++)
+ if (strchr(legal, *p) != NULL)
+ switch (*p) {
+ case 'b':
+ o &= ~REG_EXTENDED;
+ break;
+ case 'i':
+ o |= REG_ICASE;
+ break;
+ case 's':
+ o |= REG_NOSUB;
+ break;
+ case 'n':
+ o |= REG_NEWLINE;
+ break;
+ case 'm':
+ o &= ~REG_EXTENDED;
+ o |= REG_NOSPEC;
+ break;
+ case 'p':
+ o |= REG_PEND;
+ break;
+ case '^':
+ o |= REG_NOTBOL;
+ break;
+ case '$':
+ o |= REG_NOTEOL;
+ break;
+ case '#':
+ o |= REG_STARTEND;
+ break;
+ case 't': /* trace */
+ o |= REG_TRACE;
+ break;
+ case 'l': /* force long representation */
+ o |= REG_LARGE;
+ break;
+ case 'r': /* force backref use */
+ o |= REG_BACKR;
+ break;
+ }
+ return(o);
+}
+
+/*
+ - opt - is a particular option in a regression string?
+ == int opt(int c, char *s);
+ */
+int /* predicate */
+opt(c, s)
+int c;
+char *s;
+{
+ return(strchr(s, c) != NULL);
+}
+
+/*
+ - fixstr - transform magic characters in strings
+ == void fixstr(register char *p);
+ */
+void
+fixstr(p)
+register char *p;
+{
+ if (p == NULL)
+ return;
+
+ for (; *p != '\0'; p++)
+ if (*p == 'N')
+ *p = '\n';
+ else if (*p == 'T')
+ *p = '\t';
+ else if (*p == 'S')
+ *p = ' ';
+ else if (*p == 'Z')
+ *p = '\0';
+}
+
+/*
+ - check - check a substring match
+ == char *check(char *str, regmatch_t sub, char *should);
+ */
+char * /* NULL or complaint */
+check(str, sub, should)
+char *str;
+regmatch_t sub;
+char *should;
+{
+ register int len;
+ register int shlen;
+ register char *p;
+ static char grump[500];
+ register char *at = NULL;
+
+ if (should != NULL && strcmp(should, "-") == 0)
+ should = NULL;
+ if (should != NULL && should[0] == '@') {
+ at = should + 1;
+ should = "";
+ }
+
+ /* check rm_so and rm_eo for consistency */
+ if (sub.rm_so > sub.rm_eo || (sub.rm_so == -1 && sub.rm_eo != -1) ||
+ (sub.rm_so != -1 && sub.rm_eo == -1) ||
+ (sub.rm_so != -1 && sub.rm_so < 0) ||
+ (sub.rm_eo != -1 && sub.rm_eo < 0) ) {
+ sprintf(grump, "start %ld end %ld", (long)sub.rm_so,
+ (long)sub.rm_eo);
+ return(grump);
+ }
+
+ /* check for no match */
+ if (sub.rm_so == -1 && should == NULL)
+ return(NULL);
+ if (sub.rm_so == -1)
+ return("did not match");
+
+ /* check for in range */
+ if (sub.rm_eo > strlen(str)) {
+ sprintf(grump, "start %ld end %ld, past end of string",
+ (long)sub.rm_so, (long)sub.rm_eo);
+ return(grump);
+ }
+
+ len = (int)(sub.rm_eo - sub.rm_so);
+ shlen = (int)strlen(should);
+ p = str + sub.rm_so;
+
+ /* check for not supposed to match */
+ if (should == NULL) {
+ sprintf(grump, "matched `%.*s'", len, p);
+ return(grump);
+ }
+
+ /* check for wrong match */
+ if (len != shlen || strncmp(p, should, (size_t)shlen) != 0) {
+ sprintf(grump, "matched `%.*s' instead", len, p);
+ return(grump);
+ }
+ if (shlen > 0)
+ return(NULL);
+
+ /* check null match in right place */
+ if (at == NULL)
+ return(NULL);
+ shlen = strlen(at);
+ if (shlen == 0)
+ shlen = 1; /* force check for end-of-string */
+ if (strncmp(p, at, shlen) != 0) {
+ sprintf(grump, "matched null at `%.20s'", p);
+ return(grump);
+ }
+ return(NULL);
+}
+
+/*
+ - eprint - convert error number to name
+ == static char *eprint(int err);
+ */
+static char *
+eprint(err)
+int err;
+{
+ static char epbuf[100];
+ size_t len;
+
+ len = regerror(REG_ITOA|err, (regex_t *)NULL, epbuf, sizeof(epbuf));
+ assert(len <= sizeof(epbuf));
+ return(epbuf);
+}
+
+/*
+ - efind - convert error name to number
+ == static int efind(char *name);
+ */
+static int
+efind(name)
+char *name;
+{
+ static char efbuf[100];
+ size_t n;
+ regex_t re;
+
+ sprintf(efbuf, "REG_%s", name);
+ assert(strlen(efbuf) < sizeof(efbuf));
+ re.re_endp = efbuf;
+ (void) regerror(REG_ATOI, &re, efbuf, sizeof(efbuf));
+ return(atoi(efbuf));
+}
--- /dev/null
+/* ========= begin header generated by ./mkh ========= */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* === main.c === */
+void regress(FILE *in);
+void try(char *f0, char *f1, char *f2, char *f3, char *f4, int opts);
+int options(int type, char *s);
+int opt(int c, char *s);
+void fixstr(register char *p);
+char *check(char *str, regmatch_t sub, char *should);
+static char *eprint(int err);
+static int efind(char *name);
+
+#ifdef __cplusplus
+}
+#endif
+/* ========= end header generated by ./mkh ========= */
--- /dev/null
+#! /bin/sh
+# mkh - pull headers out of C source
+PATH=/bin:/usr/bin ; export PATH
+
+# egrep pattern to pick out marked lines
+egrep='^ =([ ]|$)'
+
+# Sed program to process marked lines into lines for the header file.
+# The markers have already been removed. Two things are done here: removal
+# of backslashed newlines, and some fudging of comments. The first is done
+# because -o needs to have prototypes on one line to strip them down.
+# Getting comments into the output is tricky; we turn C++-style // comments
+# into /* */ comments, after altering any existing */'s to avoid trouble.
+peel=' /\\$/N
+ /\\\n[ ]*/s///g
+ /\/\//s;\*/;* /;g
+ /\/\//s;//\(.*\);/*\1 */;'
+
+for a
+do
+ case "$a" in
+ -o) # old (pre-function-prototype) compiler
+ # add code to comment out argument lists
+ peel="$peel
+ "'/^\([^#\/][^\/]*[a-zA-Z0-9_)]\)(\(.*\))/s;;\1(/*\2*/);'
+ shift
+ ;;
+ -b) # funny Berkeley __P macro
+ peel="$peel
+ "'/^\([^#\/][^\/]*[a-zA-Z0-9_)]\)(\(.*\))/s;;\1 __P((\2));'
+ shift
+ ;;
+ -s) # compiler doesn't like `static foo();'
+ # add code to get rid of the `static'
+ peel="$peel
+ "'/^static[ ][^\/]*[a-zA-Z0-9_)](.*)/s;static.;;'
+ shift
+ ;;
+ -p) # private declarations
+ egrep='^ ==([ ]|$)'
+ shift
+ ;;
+ -i) # wrap in #ifndef, argument is name
+ ifndef="$2"
+ shift ; shift
+ ;;
+ *) break
+ ;;
+ esac
+done
+
+if test " $ifndef" != " "
+then
+ echo "#ifndef $ifndef"
+ echo "#define $ifndef /* never again */"
+fi
+echo "/* ========= begin header generated by $0 ========= */"
+echo '#ifdef __cplusplus'
+echo 'extern "C" {'
+echo '#endif'
+for f
+do
+ echo
+ echo "/* === $f === */"
+ egrep "$egrep" $f | sed 's/^ ==*[ ]//;s/^ ==*$//' | sed "$peel"
+ echo
+done
+echo '#ifdef __cplusplus'
+echo '}'
+echo '#endif'
+echo "/* ========= end header generated by $0 ========= */"
+if test " $ifndef" != " "
+then
+ echo "#endif"
+fi
+exit 0
--- /dev/null
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <regex.h>
+
+#include "utils.h"
+#include "regex2.h"
+
+#include "cclass.h"
+#include "cname.h"
+
+/*
+ * parse structure, passed up and down to avoid global variables and
+ * other clumsinesses
+ */
+struct parse {
+ char *next; /* next character in RE */
+ char *end; /* end of string (-> NUL normally) */
+ int error; /* has an error been seen? */
+ sop *strip; /* malloced strip */
+ sopno ssize; /* malloced strip size (allocated) */
+ sopno slen; /* malloced strip length (used) */
+ int ncsalloc; /* number of csets allocated */
+ struct re_guts *g;
+# define NPAREN 10 /* we need to remember () 1-9 for back refs */
+ sopno pbegin[NPAREN]; /* -> ( ([0] unused) */
+ sopno pend[NPAREN]; /* -> ) ([0] unused) */
+};
+
+#include "regcomp.ih"
+
+static char nuls[10]; /* place to point scanner in event of error */
+
+/*
+ * macros for use with parse structure
+ * BEWARE: these know that the parse structure is named `p' !!!
+ */
+#define PEEK() (*p->next)
+#define PEEK2() (*(p->next+1))
+#define MORE() (p->next < p->end)
+#define MORE2() (p->next+1 < p->end)
+#define SEE(c) (MORE() && PEEK() == (c))
+#define SEETWO(a, b) (MORE() && MORE2() && PEEK() == (a) && PEEK2() == (b))
+#define EAT(c) ((SEE(c)) ? (NEXT(), 1) : 0)
+#define EATTWO(a, b) ((SEETWO(a, b)) ? (NEXT2(), 1) : 0)
+#define NEXT() (p->next++)
+#define NEXT2() (p->next += 2)
+#define NEXTn(n) (p->next += (n))
+#define GETNEXT() (*p->next++)
+#define SETERROR(e) seterr(p, (e))
+#define REQUIRE(co, e) ((co) || SETERROR(e))
+#define MUSTSEE(c, e) (REQUIRE(MORE() && PEEK() == (c), e))
+#define MUSTEAT(c, e) (REQUIRE(MORE() && GETNEXT() == (c), e))
+#define MUSTNOTSEE(c, e) (REQUIRE(!MORE() || PEEK() != (c), e))
+#define EMIT(op, sopnd) doemit(p, (sop)(op), (size_t)(sopnd))
+#define INSERT(op, pos) doinsert(p, (sop)(op), HERE()-(pos)+1, pos)
+#define AHEAD(pos) dofwd(p, pos, HERE()-(pos))
+#define ASTERN(sop, pos) EMIT(sop, HERE()-pos)
+#define HERE() (p->slen)
+#define THERE() (p->slen - 1)
+#define THERETHERE() (p->slen - 2)
+#define DROP(n) (p->slen -= (n))
+
+#ifndef NDEBUG
+static int never = 0; /* for use in asserts; shuts lint up */
+#else
+#define never 0 /* some <assert.h>s have bugs too */
+#endif
+
+/*
+ - regcomp - interface for parser and compilation
+ = extern int regcomp(regex_t *, const char *, int);
+ = #define REG_BASIC 0000
+ = #define REG_EXTENDED 0001
+ = #define REG_ICASE 0002
+ = #define REG_NOSUB 0004
+ = #define REG_NEWLINE 0010
+ = #define REG_NOSPEC 0020
+ = #define REG_PEND 0040
+ = #define REG_DUMP 0200
+ */
+int /* 0 success, otherwise REG_something */
+regcomp(preg, pattern, cflags)
+regex_t *preg;
+const char *pattern;
+int cflags;
+{
+ struct parse pa;
+ register struct re_guts *g;
+ register struct parse *p = &pa;
+ register int i;
+ register size_t len;
+#ifdef REDEBUG
+# define GOODFLAGS(f) (f)
+#else
+# define GOODFLAGS(f) ((f)&~REG_DUMP)
+#endif
+
+ cflags = GOODFLAGS(cflags);
+ if ((cflags®_EXTENDED) && (cflags®_NOSPEC))
+ return(REG_INVARG);
+
+ if (cflags®_PEND) {
+ if (preg->re_endp < pattern)
+ return(REG_INVARG);
+ len = preg->re_endp - pattern;
+ } else
+ len = strlen((char *)pattern);
+
+ /* do the mallocs early so failure handling is easy */
+ g = (struct re_guts *)malloc(sizeof(struct re_guts) +
+ (NC-1)*sizeof(cat_t));
+ if (g == NULL)
+ return(REG_ESPACE);
+ p->ssize = len/(size_t)2*(size_t)3 + (size_t)1; /* ugh */
+ p->strip = (sop *)malloc(p->ssize * sizeof(sop));
+ p->slen = 0;
+ if (p->strip == NULL) {
+ free((char *)g);
+ return(REG_ESPACE);
+ }
+
+ /* set things up */
+ p->g = g;
+ p->next = (char *)pattern; /* convenience; we do not modify it */
+ p->end = p->next + len;
+ p->error = 0;
+ p->ncsalloc = 0;
+ for (i = 0; i < NPAREN; i++) {
+ p->pbegin[i] = 0;
+ p->pend[i] = 0;
+ }
+ g->csetsize = NC;
+ g->sets = NULL;
+ g->setbits = NULL;
+ g->ncsets = 0;
+ g->cflags = cflags;
+ g->iflags = 0;
+ g->nbol = 0;
+ g->neol = 0;
+ g->must = NULL;
+ g->mlen = 0;
+ g->nsub = 0;
+ g->ncategories = 1; /* category 0 is "everything else" */
+ g->categories = &g->catspace[-(CHAR_MIN)];
+ (void) memset((char *)g->catspace, 0, NC*sizeof(cat_t));
+ g->backrefs = 0;
+
+ /* do it */
+ EMIT(OEND, 0);
+ g->firststate = THERE();
+ if (cflags®_EXTENDED)
+ p_ere(p, OUT);
+ else if (cflags®_NOSPEC)
+ p_str(p);
+ else
+ p_bre(p, OUT, OUT);
+ EMIT(OEND, 0);
+ g->laststate = THERE();
+
+ /* tidy up loose ends and fill things in */
+ categorize(p, g);
+ stripsnug(p, g);
+ findmust(p, g);
+ g->nplus = pluscount(p, g);
+ g->magic = MAGIC2;
+ preg->re_nsub = g->nsub;
+ preg->re_g = g;
+ preg->re_magic = MAGIC1;
+#ifndef REDEBUG
+ /* not debugging, so can't rely on the assert() in regexec() */
+ if (g->iflags&BAD)
+ SETERROR(REG_ASSERT);
+#endif
+
+ /* win or lose, we're done */
+ if (p->error != 0) /* lose */
+ regfree(preg);
+ return(p->error);
+}
+
+/*
+ - p_ere - ERE parser top level, concatenation and alternation
+ == static void p_ere(register struct parse *p, int stop);
+ */
+static void
+p_ere(p, stop)
+register struct parse *p;
+int stop; /* character this ERE should end at */
+{
+ register char c;
+ register sopno prevback;
+ register sopno prevfwd;
+ register sopno conc;
+ register int first = 1; /* is this the first alternative? */
+
+ for (;;) {
+ /* do a bunch of concatenated expressions */
+ conc = HERE();
+ while (MORE() && (c = PEEK()) != '|' && c != stop)
+ p_ere_exp(p);
+ REQUIRE(HERE() != conc, REG_EMPTY); /* require nonempty */
+
+ if (!EAT('|'))
+ break; /* NOTE BREAK OUT */
+
+ if (first) {
+ INSERT(OCH_, conc); /* offset is wrong */
+ prevfwd = conc;
+ prevback = conc;
+ first = 0;
+ }
+ ASTERN(OOR1, prevback);
+ prevback = THERE();
+ AHEAD(prevfwd); /* fix previous offset */
+ prevfwd = HERE();
+ EMIT(OOR2, 0); /* offset is very wrong */
+ }
+
+ if (!first) { /* tail-end fixups */
+ AHEAD(prevfwd);
+ ASTERN(O_CH, prevback);
+ }
+
+ assert(!MORE() || SEE(stop));
+}
+
+/*
+ - p_ere_exp - parse one subERE, an atom possibly followed by a repetition op
+ == static void p_ere_exp(register struct parse *p);
+ */
+static void
+p_ere_exp(p)
+register struct parse *p;
+{
+ register char c;
+ register sopno pos;
+ register int count;
+ register int count2;
+ register sopno subno;
+ int wascaret = 0;
+
+ assert(MORE()); /* caller should have ensured this */
+ c = GETNEXT();
+
+ pos = HERE();
+ switch (c) {
+ case '(':
+ REQUIRE(MORE(), REG_EPAREN);
+ p->g->nsub++;
+ subno = p->g->nsub;
+ if (subno < NPAREN)
+ p->pbegin[subno] = HERE();
+ EMIT(OLPAREN, subno);
+ if (!SEE(')'))
+ p_ere(p, ')');
+ if (subno < NPAREN) {
+ p->pend[subno] = HERE();
+ assert(p->pend[subno] != 0);
+ }
+ EMIT(ORPAREN, subno);
+ MUSTEAT(')', REG_EPAREN);
+ break;
+#ifndef POSIX_MISTAKE
+ case ')': /* happens only if no current unmatched ( */
+ /*
+ * You may ask, why the ifndef? Because I didn't notice
+ * this until slightly too late for 1003.2, and none of the
+ * other 1003.2 regular-expression reviewers noticed it at
+ * all. So an unmatched ) is legal POSIX, at least until
+ * we can get it fixed.
+ */
+ SETERROR(REG_EPAREN);
+ break;
+#endif
+ case '^':
+ EMIT(OBOL, 0);
+ p->g->iflags |= USEBOL;
+ p->g->nbol++;
+ wascaret = 1;
+ break;
+ case '$':
+ EMIT(OEOL, 0);
+ p->g->iflags |= USEEOL;
+ p->g->neol++;
+ break;
+ case '|':
+ SETERROR(REG_EMPTY);
+ break;
+ case '*':
+ case '+':
+ case '?':
+ SETERROR(REG_BADRPT);
+ break;
+ case '.':
+ if (p->g->cflags®_NEWLINE)
+ nonnewline(p);
+ else
+ EMIT(OANY, 0);
+ break;
+ case '[':
+ p_bracket(p);
+ break;
+ case '\\':
+ REQUIRE(MORE(), REG_EESCAPE);
+ c = GETNEXT();
+ ordinary(p, c);
+ break;
+ case '{': /* okay as ordinary except if digit follows */
+ REQUIRE(!MORE() || !isdigit(PEEK()), REG_BADRPT);
+ /* FALLTHROUGH */
+ default:
+ ordinary(p, c);
+ break;
+ }
+
+ if (!MORE())
+ return;
+ c = PEEK();
+ /* we call { a repetition if followed by a digit */
+ if (!( c == '*' || c == '+' || c == '?' ||
+ (c == '{' && MORE2() && isdigit(PEEK2())) ))
+ return; /* no repetition, we're done */
+ NEXT();
+
+ REQUIRE(!wascaret, REG_BADRPT);
+ switch (c) {
+ case '*': /* implemented as +? */
+ /* this case does not require the (y|) trick, noKLUDGE */
+ INSERT(OPLUS_, pos);
+ ASTERN(O_PLUS, pos);
+ INSERT(OQUEST_, pos);
+ ASTERN(O_QUEST, pos);
+ break;
+ case '+':
+ INSERT(OPLUS_, pos);
+ ASTERN(O_PLUS, pos);
+ break;
+ case '?':
+ /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
+ INSERT(OCH_, pos); /* offset slightly wrong */
+ ASTERN(OOR1, pos); /* this one's right */
+ AHEAD(pos); /* fix the OCH_ */
+ EMIT(OOR2, 0); /* offset very wrong... */
+ AHEAD(THERE()); /* ...so fix it */
+ ASTERN(O_CH, THERETHERE());
+ break;
+ case '{':
+ count = p_count(p);
+ if (EAT(',')) {
+ if (isdigit(PEEK())) {
+ count2 = p_count(p);
+ REQUIRE(count <= count2, REG_BADBR);
+ } else /* single number with comma */
+ count2 = INFINITY;
+ } else /* just a single number */
+ count2 = count;
+ repeat(p, pos, count, count2);
+ if (!EAT('}')) { /* error heuristics */
+ while (MORE() && PEEK() != '}')
+ NEXT();
+ REQUIRE(MORE(), REG_EBRACE);
+ SETERROR(REG_BADBR);
+ }
+ break;
+ }
+
+ if (!MORE())
+ return;
+ c = PEEK();
+ if (!( c == '*' || c == '+' || c == '?' ||
+ (c == '{' && MORE2() && isdigit(PEEK2())) ) )
+ return;
+ SETERROR(REG_BADRPT);
+}
+
+/*
+ - p_str - string (no metacharacters) "parser"
+ == static void p_str(register struct parse *p);
+ */
+static void
+p_str(p)
+register struct parse *p;
+{
+ REQUIRE(MORE(), REG_EMPTY);
+ while (MORE())
+ ordinary(p, GETNEXT());
+}
+
+/*
+ - p_bre - BRE parser top level, anchoring and concatenation
+ == static void p_bre(register struct parse *p, register int end1, \
+ == register int end2);
+ * Giving end1 as OUT essentially eliminates the end1/end2 check.
+ *
+ * This implementation is a bit of a kludge, in that a trailing $ is first
+ * taken as an ordinary character and then revised to be an anchor. The
+ * only undesirable side effect is that '$' gets included as a character
+ * category in such cases. This is fairly harmless; not worth fixing.
+ * The amount of lookahead needed to avoid this kludge is excessive.
+ */
+static void
+p_bre(p, end1, end2)
+register struct parse *p;
+register int end1; /* first terminating character */
+register int end2; /* second terminating character */
+{
+ register sopno start = HERE();
+ register int first = 1; /* first subexpression? */
+ register int wasdollar = 0;
+
+ if (EAT('^')) {
+ EMIT(OBOL, 0);
+ p->g->iflags |= USEBOL;
+ p->g->nbol++;
+ }
+ while (MORE() && !SEETWO(end1, end2)) {
+ wasdollar = p_simp_re(p, first);
+ first = 0;
+ }
+ if (wasdollar) { /* oops, that was a trailing anchor */
+ DROP(1);
+ EMIT(OEOL, 0);
+ p->g->iflags |= USEEOL;
+ p->g->neol++;
+ }
+
+ REQUIRE(HERE() != start, REG_EMPTY); /* require nonempty */
+}
+
+/*
+ - p_simp_re - parse a simple RE, an atom possibly followed by a repetition
+ == static int p_simp_re(register struct parse *p, int starordinary);
+ */
+static int /* was the simple RE an unbackslashed $? */
+p_simp_re(p, starordinary)
+register struct parse *p;
+int starordinary; /* is a leading * an ordinary character? */
+{
+ register int c;
+ register int count;
+ register int count2;
+ register sopno pos;
+ register int i;
+ register sopno subno;
+# define BACKSL (1<<CHAR_BIT)
+
+ pos = HERE(); /* repetion op, if any, covers from here */
+
+ assert(MORE()); /* caller should have ensured this */
+ c = GETNEXT();
+ if (c == '\\') {
+ REQUIRE(MORE(), REG_EESCAPE);
+ c = BACKSL | (unsigned char)GETNEXT();
+ }
+ switch (c) {
+ case '.':
+ if (p->g->cflags®_NEWLINE)
+ nonnewline(p);
+ else
+ EMIT(OANY, 0);
+ break;
+ case '[':
+ p_bracket(p);
+ break;
+ case BACKSL|'{':
+ SETERROR(REG_BADRPT);
+ break;
+ case BACKSL|'(':
+ p->g->nsub++;
+ subno = p->g->nsub;
+ if (subno < NPAREN)
+ p->pbegin[subno] = HERE();
+ EMIT(OLPAREN, subno);
+ /* the MORE here is an error heuristic */
+ if (MORE() && !SEETWO('\\', ')'))
+ p_bre(p, '\\', ')');
+ if (subno < NPAREN) {
+ p->pend[subno] = HERE();
+ assert(p->pend[subno] != 0);
+ }
+ EMIT(ORPAREN, subno);
+ REQUIRE(EATTWO('\\', ')'), REG_EPAREN);
+ break;
+ case BACKSL|')': /* should not get here -- must be user */
+ case BACKSL|'}':
+ SETERROR(REG_EPAREN);
+ break;
+ case BACKSL|'1':
+ case BACKSL|'2':
+ case BACKSL|'3':
+ case BACKSL|'4':
+ case BACKSL|'5':
+ case BACKSL|'6':
+ case BACKSL|'7':
+ case BACKSL|'8':
+ case BACKSL|'9':
+ i = (c&~BACKSL) - '0';
+ assert(i < NPAREN);
+ if (p->pend[i] != 0) {
+ assert(i <= p->g->nsub);
+ EMIT(OBACK_, i);
+ assert(p->pbegin[i] != 0);
+ assert(OP(p->strip[p->pbegin[i]]) == OLPAREN);
+ assert(OP(p->strip[p->pend[i]]) == ORPAREN);
+ (void) dupl(p, p->pbegin[i]+1, p->pend[i]);
+ EMIT(O_BACK, i);
+ } else
+ SETERROR(REG_ESUBREG);
+ p->g->backrefs = 1;
+ break;
+ case '*':
+ REQUIRE(starordinary, REG_BADRPT);
+ /* FALLTHROUGH */
+ default:
+ ordinary(p, (char)c); /* takes off BACKSL, if any */
+ break;
+ }
+
+ if (EAT('*')) { /* implemented as +? */
+ /* this case does not require the (y|) trick, noKLUDGE */
+ INSERT(OPLUS_, pos);
+ ASTERN(O_PLUS, pos);
+ INSERT(OQUEST_, pos);
+ ASTERN(O_QUEST, pos);
+ } else if (EATTWO('\\', '{')) {
+ count = p_count(p);
+ if (EAT(',')) {
+ if (MORE() && isdigit(PEEK())) {
+ count2 = p_count(p);
+ REQUIRE(count <= count2, REG_BADBR);
+ } else /* single number with comma */
+ count2 = INFINITY;
+ } else /* just a single number */
+ count2 = count;
+ repeat(p, pos, count, count2);
+ if (!EATTWO('\\', '}')) { /* error heuristics */
+ while (MORE() && !SEETWO('\\', '}'))
+ NEXT();
+ REQUIRE(MORE(), REG_EBRACE);
+ SETERROR(REG_BADBR);
+ }
+ } else if (c == (unsigned char)'$') /* $ (but not \$) ends it */
+ return(1);
+
+ return(0);
+}
+
+/*
+ - p_count - parse a repetition count
+ == static int p_count(register struct parse *p);
+ */
+static int /* the value */
+p_count(p)
+register struct parse *p;
+{
+ register int count = 0;
+ register int ndigits = 0;
+
+ while (MORE() && isdigit(PEEK()) && count <= DUPMAX) {
+ count = count*10 + (GETNEXT() - '0');
+ ndigits++;
+ }
+
+ REQUIRE(ndigits > 0 && count <= DUPMAX, REG_BADBR);
+ return(count);
+}
+
+/*
+ - p_bracket - parse a bracketed character list
+ == static void p_bracket(register struct parse *p);
+ *
+ * Note a significant property of this code: if the allocset() did SETERROR,
+ * no set operations are done.
+ */
+static void
+p_bracket(p)
+register struct parse *p;
+{
+ register cset *cs = allocset(p);
+ register int invert = 0;
+
+ /* Dept of Truly Sickening Special-Case Kludges */
+ if (p->next + 5 < p->end && strncmp(p->next, "[:<:]]", 6) == 0) {
+ EMIT(OBOW, 0);
+ NEXTn(6);
+ return;
+ }
+ if (p->next + 5 < p->end && strncmp(p->next, "[:>:]]", 6) == 0) {
+ EMIT(OEOW, 0);
+ NEXTn(6);
+ return;
+ }
+
+ if (EAT('^'))
+ invert++; /* make note to invert set at end */
+ if (EAT(']'))
+ CHadd(cs, ']');
+ else if (EAT('-'))
+ CHadd(cs, '-');
+ while (MORE() && PEEK() != ']' && !SEETWO('-', ']'))
+ p_b_term(p, cs);
+ if (EAT('-'))
+ CHadd(cs, '-');
+ MUSTEAT(']', REG_EBRACK);
+
+ if (p->error != 0) /* don't mess things up further */
+ return;
+
+ if (p->g->cflags®_ICASE) {
+ register int i;
+ register int ci;
+
+ for (i = p->g->csetsize - 1; i >= 0; i--)
+ if (CHIN(cs, i) && isalpha(i)) {
+ ci = othercase(i);
+ if (ci != i)
+ CHadd(cs, ci);
+ }
+ if (cs->multis != NULL)
+ mccase(p, cs);
+ }
+ if (invert) {
+ register int i;
+
+ for (i = p->g->csetsize - 1; i >= 0; i--)
+ if (CHIN(cs, i))
+ CHsub(cs, i);
+ else
+ CHadd(cs, i);
+ if (p->g->cflags®_NEWLINE)
+ CHsub(cs, '\n');
+ if (cs->multis != NULL)
+ mcinvert(p, cs);
+ }
+
+ assert(cs->multis == NULL); /* xxx */
+
+ if (nch(p, cs) == 1) { /* optimize singleton sets */
+ ordinary(p, firstch(p, cs));
+ freeset(p, cs);
+ } else
+ EMIT(OANYOF, freezeset(p, cs));
+}
+
+/*
+ - p_b_term - parse one term of a bracketed character list
+ == static void p_b_term(register struct parse *p, register cset *cs);
+ */
+static void
+p_b_term(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+ register char c;
+ register char start, finish;
+ register int i;
+
+ /* classify what we've got */
+ switch ((MORE()) ? PEEK() : '\0') {
+ case '[':
+ c = (MORE2()) ? PEEK2() : '\0';
+ break;
+ case '-':
+ SETERROR(REG_ERANGE);
+ return; /* NOTE RETURN */
+ break;
+ default:
+ c = '\0';
+ break;
+ }
+
+ switch (c) {
+ case ':': /* character class */
+ NEXT2();
+ REQUIRE(MORE(), REG_EBRACK);
+ c = PEEK();
+ REQUIRE(c != '-' && c != ']', REG_ECTYPE);
+ p_b_cclass(p, cs);
+ REQUIRE(MORE(), REG_EBRACK);
+ REQUIRE(EATTWO(':', ']'), REG_ECTYPE);
+ break;
+ case '=': /* equivalence class */
+ NEXT2();
+ REQUIRE(MORE(), REG_EBRACK);
+ c = PEEK();
+ REQUIRE(c != '-' && c != ']', REG_ECOLLATE);
+ p_b_eclass(p, cs);
+ REQUIRE(MORE(), REG_EBRACK);
+ REQUIRE(EATTWO('=', ']'), REG_ECOLLATE);
+ break;
+ default: /* symbol, ordinary character, or range */
+/* xxx revision needed for multichar stuff */
+ start = p_b_symbol(p);
+ if (SEE('-') && MORE2() && PEEK2() != ']') {
+ /* range */
+ NEXT();
+ if (EAT('-'))
+ finish = '-';
+ else
+ finish = p_b_symbol(p);
+ } else
+ finish = start;
+/* xxx what about signed chars here... */
+ REQUIRE(start <= finish, REG_ERANGE);
+ for (i = start; i <= finish; i++)
+ CHadd(cs, i);
+ break;
+ }
+}
+
+/*
+ - p_b_cclass - parse a character-class name and deal with it
+ == static void p_b_cclass(register struct parse *p, register cset *cs);
+ */
+static void
+p_b_cclass(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+ register char *sp = p->next;
+ register struct cclass *cp;
+ register size_t len;
+ register char *u;
+ register char c;
+
+ while (MORE() && isalpha(PEEK()))
+ NEXT();
+ len = p->next - sp;
+ for (cp = cclasses; cp->name != NULL; cp++)
+ if (strncmp(cp->name, sp, len) == 0 && cp->name[len] == '\0')
+ break;
+ if (cp->name == NULL) {
+ /* oops, didn't find it */
+ SETERROR(REG_ECTYPE);
+ return;
+ }
+
+ u = cp->chars;
+ while ((c = *u++) != '\0')
+ CHadd(cs, c);
+ for (u = cp->multis; *u != '\0'; u += strlen(u) + 1)
+ MCadd(p, cs, u);
+}
+
+/*
+ - p_b_eclass - parse an equivalence-class name and deal with it
+ == static void p_b_eclass(register struct parse *p, register cset *cs);
+ *
+ * This implementation is incomplete. xxx
+ */
+static void
+p_b_eclass(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+ register char c;
+
+ c = p_b_coll_elem(p, '=');
+ CHadd(cs, c);
+}
+
+/*
+ - p_b_symbol - parse a character or [..]ed multicharacter collating symbol
+ == static char p_b_symbol(register struct parse *p);
+ */
+static char /* value of symbol */
+p_b_symbol(p)
+register struct parse *p;
+{
+ register char value;
+
+ REQUIRE(MORE(), REG_EBRACK);
+ if (!EATTWO('[', '.'))
+ return(GETNEXT());
+
+ /* collating symbol */
+ value = p_b_coll_elem(p, '.');
+ REQUIRE(EATTWO('.', ']'), REG_ECOLLATE);
+ return(value);
+}
+
+/*
+ - p_b_coll_elem - parse a collating-element name and look it up
+ == static char p_b_coll_elem(register struct parse *p, int endc);
+ */
+static char /* value of collating element */
+p_b_coll_elem(p, endc)
+register struct parse *p;
+int endc; /* name ended by endc,']' */
+{
+ register char *sp = p->next;
+ register struct cname *cp;
+ register int len;
+
+ while (MORE() && !SEETWO(endc, ']'))
+ NEXT();
+ if (!MORE()) {
+ SETERROR(REG_EBRACK);
+ return(0);
+ }
+ len = p->next - sp;
+ for (cp = cnames; cp->name != NULL; cp++)
+ if (strncmp(cp->name, sp, len) == 0 && cp->name[len] == '\0')
+ return(cp->code); /* known name */
+ if (len == 1)
+ return(*sp); /* single character */
+ SETERROR(REG_ECOLLATE); /* neither */
+ return(0);
+}
+
+/*
+ - othercase - return the case counterpart of an alphabetic
+ == static char othercase(int ch);
+ */
+static char /* if no counterpart, return ch */
+othercase(ch)
+int ch;
+{
+ assert(isalpha(ch));
+ if (isupper(ch))
+ return(tolower(ch));
+ else if (islower(ch))
+ return(toupper(ch));
+ else /* peculiar, but could happen */
+ return(ch);
+}
+
+/*
+ - bothcases - emit a dualcase version of a two-case character
+ == static void bothcases(register struct parse *p, int ch);
+ *
+ * Boy, is this implementation ever a kludge...
+ */
+static void
+bothcases(p, ch)
+register struct parse *p;
+int ch;
+{
+ register char *oldnext = p->next;
+ register char *oldend = p->end;
+ char bracket[3];
+
+ assert(othercase(ch) != ch); /* p_bracket() would recurse */
+ p->next = bracket;
+ p->end = bracket+2;
+ bracket[0] = ch;
+ bracket[1] = ']';
+ bracket[2] = '\0';
+ p_bracket(p);
+ assert(p->next == bracket+2);
+ p->next = oldnext;
+ p->end = oldend;
+}
+
+/*
+ - ordinary - emit an ordinary character
+ == static void ordinary(register struct parse *p, register int ch);
+ */
+static void
+ordinary(p, ch)
+register struct parse *p;
+register int ch;
+{
+ register cat_t *cap = p->g->categories;
+
+ if ((p->g->cflags®_ICASE) && isalpha(ch) && othercase(ch) != ch)
+ bothcases(p, ch);
+ else {
+ EMIT(OCHAR, (unsigned char)ch);
+ if (cap[ch] == 0)
+ cap[ch] = p->g->ncategories++;
+ }
+}
+
+/*
+ - nonnewline - emit REG_NEWLINE version of OANY
+ == static void nonnewline(register struct parse *p);
+ *
+ * Boy, is this implementation ever a kludge...
+ */
+static void
+nonnewline(p)
+register struct parse *p;
+{
+ register char *oldnext = p->next;
+ register char *oldend = p->end;
+ char bracket[4];
+
+ p->next = bracket;
+ p->end = bracket+3;
+ bracket[0] = '^';
+ bracket[1] = '\n';
+ bracket[2] = ']';
+ bracket[3] = '\0';
+ p_bracket(p);
+ assert(p->next == bracket+3);
+ p->next = oldnext;
+ p->end = oldend;
+}
+
+/*
+ - repeat - generate code for a bounded repetition, recursively if needed
+ == static void repeat(register struct parse *p, sopno start, int from, int to);
+ */
+static void
+repeat(p, start, from, to)
+register struct parse *p;
+sopno start; /* operand from here to end of strip */
+int from; /* repeated from this number */
+int to; /* to this number of times (maybe INFINITY) */
+{
+ register sopno finish = HERE();
+# define N 2
+# define INF 3
+# define REP(f, t) ((f)*8 + (t))
+# define MAP(n) (((n) <= 1) ? (n) : ((n) == INFINITY) ? INF : N)
+ register sopno copy;
+
+ if (p->error != 0) /* head off possible runaway recursion */
+ return;
+
+ assert(from <= to);
+
+ switch (REP(MAP(from), MAP(to))) {
+ case REP(0, 0): /* must be user doing this */
+ DROP(finish-start); /* drop the operand */
+ break;
+ case REP(0, 1): /* as x{1,1}? */
+ case REP(0, N): /* as x{1,n}? */
+ case REP(0, INF): /* as x{1,}? */
+ /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
+ INSERT(OCH_, start); /* offset is wrong... */
+ repeat(p, start+1, 1, to);
+ ASTERN(OOR1, start);
+ AHEAD(start); /* ... fix it */
+ EMIT(OOR2, 0);
+ AHEAD(THERE());
+ ASTERN(O_CH, THERETHERE());
+ break;
+ case REP(1, 1): /* trivial case */
+ /* done */
+ break;
+ case REP(1, N): /* as x?x{1,n-1} */
+ /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
+ INSERT(OCH_, start);
+ ASTERN(OOR1, start);
+ AHEAD(start);
+ EMIT(OOR2, 0); /* offset very wrong... */
+ AHEAD(THERE()); /* ...so fix it */
+ ASTERN(O_CH, THERETHERE());
+ copy = dupl(p, start+1, finish+1);
+ assert(copy == finish+4);
+ repeat(p, copy, 1, to-1);
+ break;
+ case REP(1, INF): /* as x+ */
+ INSERT(OPLUS_, start);
+ ASTERN(O_PLUS, start);
+ break;
+ case REP(N, N): /* as xx{m-1,n-1} */
+ copy = dupl(p, start, finish);
+ repeat(p, copy, from-1, to-1);
+ break;
+ case REP(N, INF): /* as xx{n-1,INF} */
+ copy = dupl(p, start, finish);
+ repeat(p, copy, from-1, to);
+ break;
+ default: /* "can't happen" */
+ SETERROR(REG_ASSERT); /* just in case */
+ break;
+ }
+}
+
+/*
+ - seterr - set an error condition
+ == static int seterr(register struct parse *p, int e);
+ */
+static int /* useless but makes type checking happy */
+seterr(p, e)
+register struct parse *p;
+int e;
+{
+ if (p->error == 0) /* keep earliest error condition */
+ p->error = e;
+ p->next = nuls; /* try to bring things to a halt */
+ p->end = nuls;
+ return(0); /* make the return value well-defined */
+}
+
+/*
+ - allocset - allocate a set of characters for []
+ == static cset *allocset(register struct parse *p);
+ */
+static cset *
+allocset(p)
+register struct parse *p;
+{
+ register int no = p->g->ncsets++;
+ register size_t nc;
+ register size_t nbytes;
+ register cset *cs;
+ register size_t css = (size_t)p->g->csetsize;
+ register int i;
+
+ if (no >= p->ncsalloc) { /* need another column of space */
+ p->ncsalloc += CHAR_BIT;
+ nc = p->ncsalloc;
+ assert(nc % CHAR_BIT == 0);
+ nbytes = nc / CHAR_BIT * css;
+ if (p->g->sets == NULL)
+ p->g->sets = (cset *)malloc(nc * sizeof(cset));
+ else
+ p->g->sets = (cset *)realloc((char *)p->g->sets,
+ nc * sizeof(cset));
+ if (p->g->setbits == NULL)
+ p->g->setbits = (uch *)malloc(nbytes);
+ else {
+ p->g->setbits = (uch *)realloc((char *)p->g->setbits,
+ nbytes);
+ /* xxx this isn't right if setbits is now NULL */
+ for (i = 0; i < no; i++)
+ p->g->sets[i].ptr = p->g->setbits + css*(i/CHAR_BIT);
+ }
+ if (p->g->sets != NULL && p->g->setbits != NULL)
+ (void) memset((char *)p->g->setbits + (nbytes - css),
+ 0, css);
+ else {
+ no = 0;
+ SETERROR(REG_ESPACE);
+ /* caller's responsibility not to do set ops */
+ }
+ }
+
+ assert(p->g->sets != NULL); /* xxx */
+ cs = &p->g->sets[no];
+ cs->ptr = p->g->setbits + css*((no)/CHAR_BIT);
+ cs->mask = 1 << ((no) % CHAR_BIT);
+ cs->hash = 0;
+ cs->smultis = 0;
+ cs->multis = NULL;
+
+ return(cs);
+}
+
+/*
+ - freeset - free a now-unused set
+ == static void freeset(register struct parse *p, register cset *cs);
+ */
+static void
+freeset(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+ register int i;
+ register cset *top = &p->g->sets[p->g->ncsets];
+ register size_t css = (size_t)p->g->csetsize;
+
+ for (i = 0; i < css; i++)
+ CHsub(cs, i);
+ if (cs == top-1) /* recover only the easy case */
+ p->g->ncsets--;
+}
+
+/*
+ - freezeset - final processing on a set of characters
+ == static int freezeset(register struct parse *p, register cset *cs);
+ *
+ * The main task here is merging identical sets. This is usually a waste
+ * of time (although the hash code minimizes the overhead), but can win
+ * big if REG_ICASE is being used. REG_ICASE, by the way, is why the hash
+ * is done using addition rather than xor -- all ASCII [aA] sets xor to
+ * the same value!
+ */
+static int /* set number */
+freezeset(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+ register uch h = cs->hash;
+ register int i;
+ register cset *top = &p->g->sets[p->g->ncsets];
+ register cset *cs2;
+ register size_t css = (size_t)p->g->csetsize;
+
+ /* look for an earlier one which is the same */
+ for (cs2 = &p->g->sets[0]; cs2 < top; cs2++)
+ if (cs2->hash == h && cs2 != cs) {
+ /* maybe */
+ for (i = 0; i < css; i++)
+ if (!!CHIN(cs2, i) != !!CHIN(cs, i))
+ break; /* no */
+ if (i == css)
+ break; /* yes */
+ }
+
+ if (cs2 < top) { /* found one */
+ freeset(p, cs);
+ cs = cs2;
+ }
+
+ return((int)(cs - p->g->sets));
+}
+
+/*
+ - firstch - return first character in a set (which must have at least one)
+ == static int firstch(register struct parse *p, register cset *cs);
+ */
+static int /* character; there is no "none" value */
+firstch(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+ register int i;
+ register size_t css = (size_t)p->g->csetsize;
+
+ for (i = 0; i < css; i++)
+ if (CHIN(cs, i))
+ return((char)i);
+ assert(never);
+ return(0); /* arbitrary */
+}
+
+/*
+ - nch - number of characters in a set
+ == static int nch(register struct parse *p, register cset *cs);
+ */
+static int
+nch(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+ register int i;
+ register size_t css = (size_t)p->g->csetsize;
+ register int n = 0;
+
+ for (i = 0; i < css; i++)
+ if (CHIN(cs, i))
+ n++;
+ return(n);
+}
+
+/*
+ - mcadd - add a collating element to a cset
+ == static void mcadd(register struct parse *p, register cset *cs, \
+ == register char *cp);
+ */
+static void
+mcadd(p, cs, cp)
+register struct parse *p;
+register cset *cs;
+register char *cp;
+{
+ register size_t oldend = cs->smultis;
+
+ cs->smultis += strlen(cp) + 1;
+ if (cs->multis == NULL)
+ cs->multis = malloc(cs->smultis);
+ else
+ cs->multis = realloc(cs->multis, cs->smultis);
+ if (cs->multis == NULL) {
+ SETERROR(REG_ESPACE);
+ return;
+ }
+
+ (void) strcpy(cs->multis + oldend - 1, cp);
+ cs->multis[cs->smultis - 1] = '\0';
+}
+
+/*
+ - mcsub - subtract a collating element from a cset
+ == static void mcsub(register cset *cs, register char *cp);
+ */
+static void
+mcsub(cs, cp)
+register cset *cs;
+register char *cp;
+{
+ register char *fp = mcfind(cs, cp);
+ register size_t len = strlen(fp);
+
+ assert(fp != NULL);
+ (void) memmove(fp, fp + len + 1,
+ cs->smultis - (fp + len + 1 - cs->multis));
+ cs->smultis -= len;
+
+ if (cs->smultis == 0) {
+ free(cs->multis);
+ cs->multis = NULL;
+ return;
+ }
+
+ cs->multis = realloc(cs->multis, cs->smultis);
+ assert(cs->multis != NULL);
+}
+
+/*
+ - mcin - is a collating element in a cset?
+ == static int mcin(register cset *cs, register char *cp);
+ */
+static int
+mcin(cs, cp)
+register cset *cs;
+register char *cp;
+{
+ return(mcfind(cs, cp) != NULL);
+}
+
+/*
+ - mcfind - find a collating element in a cset
+ == static char *mcfind(register cset *cs, register char *cp);
+ */
+static char *
+mcfind(cs, cp)
+register cset *cs;
+register char *cp;
+{
+ register char *p;
+
+ if (cs->multis == NULL)
+ return(NULL);
+ for (p = cs->multis; *p != '\0'; p += strlen(p) + 1)
+ if (strcmp(cp, p) == 0)
+ return(p);
+ return(NULL);
+}
+
+/*
+ - mcinvert - invert the list of collating elements in a cset
+ == static void mcinvert(register struct parse *p, register cset *cs);
+ *
+ * This would have to know the set of possibilities. Implementation
+ * is deferred.
+ */
+static void
+mcinvert(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+ assert(cs->multis == NULL); /* xxx */
+}
+
+/*
+ - mccase - add case counterparts of the list of collating elements in a cset
+ == static void mccase(register struct parse *p, register cset *cs);
+ *
+ * This would have to know the set of possibilities. Implementation
+ * is deferred.
+ */
+static void
+mccase(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+ assert(cs->multis == NULL); /* xxx */
+}
+
+/*
+ - isinsets - is this character in any sets?
+ == static int isinsets(register struct re_guts *g, int c);
+ */
+static int /* predicate */
+isinsets(g, c)
+register struct re_guts *g;
+int c;
+{
+ register uch *col;
+ register int i;
+ register int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT;
+ register unsigned uc = (unsigned char)c;
+
+ for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize)
+ if (col[uc] != 0)
+ return(1);
+ return(0);
+}
+
+/*
+ - samesets - are these two characters in exactly the same sets?
+ == static int samesets(register struct re_guts *g, int c1, int c2);
+ */
+static int /* predicate */
+samesets(g, c1, c2)
+register struct re_guts *g;
+int c1;
+int c2;
+{
+ register uch *col;
+ register int i;
+ register int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT;
+ register unsigned uc1 = (unsigned char)c1;
+ register unsigned uc2 = (unsigned char)c2;
+
+ for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize)
+ if (col[uc1] != col[uc2])
+ return(0);
+ return(1);
+}
+
+/*
+ - categorize - sort out character categories
+ == static void categorize(struct parse *p, register struct re_guts *g);
+ */
+static void
+categorize(p, g)
+struct parse *p;
+register struct re_guts *g;
+{
+ register cat_t *cats = g->categories;
+ register int c;
+ register int c2;
+ register cat_t cat;
+
+ /* avoid making error situations worse */
+ if (p->error != 0)
+ return;
+
+ for (c = CHAR_MIN; c <= CHAR_MAX; c++)
+ if (cats[c] == 0 && isinsets(g, c)) {
+ cat = g->ncategories++;
+ cats[c] = cat;
+ for (c2 = c+1; c2 <= CHAR_MAX; c2++)
+ if (cats[c2] == 0 && samesets(g, c, c2))
+ cats[c2] = cat;
+ }
+}
+
+/*
+ - dupl - emit a duplicate of a bunch of sops
+ == static sopno dupl(register struct parse *p, sopno start, sopno finish);
+ */
+static sopno /* start of duplicate */
+dupl(p, start, finish)
+register struct parse *p;
+sopno start; /* from here */
+sopno finish; /* to this less one */
+{
+ register sopno ret = HERE();
+ register sopno len = finish - start;
+
+ assert(finish >= start);
+ if (len == 0)
+ return(ret);
+ enlarge(p, p->ssize + len); /* this many unexpected additions */
+ assert(p->ssize >= p->slen + len);
+ (void) memcpy((char *)(p->strip + p->slen),
+ (char *)(p->strip + start), (size_t)len*sizeof(sop));
+ p->slen += len;
+ return(ret);
+}
+
+/*
+ - doemit - emit a strip operator
+ == static void doemit(register struct parse *p, sop op, size_t opnd);
+ *
+ * It might seem better to implement this as a macro with a function as
+ * hard-case backup, but it's just too big and messy unless there are
+ * some changes to the data structures. Maybe later.
+ */
+static void
+doemit(p, op, opnd)
+register struct parse *p;
+sop op;
+size_t opnd;
+{
+ /* avoid making error situations worse */
+ if (p->error != 0)
+ return;
+
+ /* deal with oversize operands ("can't happen", more or less) */
+ assert(opnd < 1<<OPSHIFT);
+
+ /* deal with undersized strip */
+ if (p->slen >= p->ssize)
+ enlarge(p, (p->ssize+1) / 2 * 3); /* +50% */
+ assert(p->slen < p->ssize);
+
+ /* finally, it's all reduced to the easy case */
+ p->strip[p->slen++] = SOP(op, opnd);
+}
+
+/*
+ - doinsert - insert a sop into the strip
+ == static void doinsert(register struct parse *p, sop op, size_t opnd, sopno pos);
+ */
+static void
+doinsert(p, op, opnd, pos)
+register struct parse *p;
+sop op;
+size_t opnd;
+sopno pos;
+{
+ register sopno sn;
+ register sop s;
+ register int i;
+
+ /* avoid making error situations worse */
+ if (p->error != 0)
+ return;
+
+ sn = HERE();
+ EMIT(op, opnd); /* do checks, ensure space */
+ assert(HERE() == sn+1);
+ s = p->strip[sn];
+
+ /* adjust paren pointers */
+ assert(pos > 0);
+ for (i = 1; i < NPAREN; i++) {
+ if (p->pbegin[i] >= pos) {
+ p->pbegin[i]++;
+ }
+ if (p->pend[i] >= pos) {
+ p->pend[i]++;
+ }
+ }
+
+ memmove((char *)&p->strip[pos+1], (char *)&p->strip[pos],
+ (HERE()-pos-1)*sizeof(sop));
+ p->strip[pos] = s;
+}
+
+/*
+ - dofwd - complete a forward reference
+ == static void dofwd(register struct parse *p, sopno pos, sop value);
+ */
+static void
+dofwd(p, pos, value)
+register struct parse *p;
+register sopno pos;
+sop value;
+{
+ /* avoid making error situations worse */
+ if (p->error != 0)
+ return;
+
+ assert(value < 1<<OPSHIFT);
+ p->strip[pos] = OP(p->strip[pos]) | value;
+}
+
+/*
+ - enlarge - enlarge the strip
+ == static void enlarge(register struct parse *p, sopno size);
+ */
+static void
+enlarge(p, size)
+register struct parse *p;
+register sopno size;
+{
+ register sop *sp;
+
+ if (p->ssize >= size)
+ return;
+
+ sp = (sop *)realloc(p->strip, size*sizeof(sop));
+ if (sp == NULL) {
+ SETERROR(REG_ESPACE);
+ return;
+ }
+ p->strip = sp;
+ p->ssize = size;
+}
+
+/*
+ - stripsnug - compact the strip
+ == static void stripsnug(register struct parse *p, register struct re_guts *g);
+ */
+static void
+stripsnug(p, g)
+register struct parse *p;
+register struct re_guts *g;
+{
+ g->nstates = p->slen;
+ g->strip = (sop *)realloc((char *)p->strip, p->slen * sizeof(sop));
+ if (g->strip == NULL) {
+ SETERROR(REG_ESPACE);
+ g->strip = p->strip;
+ }
+}
+
+/*
+ - findmust - fill in must and mlen with longest mandatory literal string
+ == static void findmust(register struct parse *p, register struct re_guts *g);
+ *
+ * This algorithm could do fancy things like analyzing the operands of |
+ * for common subsequences. Someday. This code is simple and finds most
+ * of the interesting cases.
+ *
+ * Note that must and mlen got initialized during setup.
+ */
+static void
+findmust(p, g)
+struct parse *p;
+register struct re_guts *g;
+{
+ register sop *scan;
+ sop *start;
+ register sop *newstart;
+ register sopno newlen;
+ register sop s;
+ register char *cp;
+ register sopno i;
+
+ /* avoid making error situations worse */
+ if (p->error != 0)
+ return;
+
+ /* find the longest OCHAR sequence in strip */
+ newlen = 0;
+ scan = g->strip + 1;
+ do {
+ s = *scan++;
+ switch (OP(s)) {
+ case OCHAR: /* sequence member */
+ if (newlen == 0) /* new sequence */
+ newstart = scan - 1;
+ newlen++;
+ break;
+ case OPLUS_: /* things that don't break one */
+ case OLPAREN:
+ case ORPAREN:
+ break;
+ case OQUEST_: /* things that must be skipped */
+ case OCH_:
+ scan--;
+ do {
+ scan += OPND(s);
+ s = *scan;
+ /* assert() interferes w debug printouts */
+ if (OP(s) != O_QUEST && OP(s) != O_CH &&
+ OP(s) != OOR2) {
+ g->iflags |= BAD;
+ return;
+ }
+ } while (OP(s) != O_QUEST && OP(s) != O_CH);
+ /* fallthrough */
+ default: /* things that break a sequence */
+ if (newlen > g->mlen) { /* ends one */
+ start = newstart;
+ g->mlen = newlen;
+ }
+ newlen = 0;
+ break;
+ }
+ } while (OP(s) != OEND);
+
+ if (g->mlen == 0) /* there isn't one */
+ return;
+
+ /* turn it into a character string */
+ g->must = malloc((size_t)g->mlen + 1);
+ if (g->must == NULL) { /* argh; just forget it */
+ g->mlen = 0;
+ return;
+ }
+ cp = g->must;
+ scan = start;
+ for (i = g->mlen; i > 0; i--) {
+ while (OP(s = *scan++) != OCHAR)
+ continue;
+ assert(cp < g->must + g->mlen);
+ *cp++ = (char)OPND(s);
+ }
+ assert(cp == g->must + g->mlen);
+ *cp++ = '\0'; /* just on general principles */
+}
+
+/*
+ - pluscount - count + nesting
+ == static sopno pluscount(register struct parse *p, register struct re_guts *g);
+ */
+static sopno /* nesting depth */
+pluscount(p, g)
+struct parse *p;
+register struct re_guts *g;
+{
+ register sop *scan;
+ register sop s;
+ register sopno plusnest = 0;
+ register sopno maxnest = 0;
+
+ if (p->error != 0)
+ return(0); /* there may not be an OEND */
+
+ scan = g->strip + 1;
+ do {
+ s = *scan++;
+ switch (OP(s)) {
+ case OPLUS_:
+ plusnest++;
+ break;
+ case O_PLUS:
+ if (plusnest > maxnest)
+ maxnest = plusnest;
+ plusnest--;
+ break;
+ }
+ } while (OP(s) != OEND);
+ if (plusnest != 0)
+ g->iflags |= BAD;
+ return(maxnest);
+}
--- /dev/null
+/* ========= begin header generated by ./mkh ========= */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* === regcomp.c === */
+static void p_ere(register struct parse *p, int stop);
+static void p_ere_exp(register struct parse *p);
+static void p_str(register struct parse *p);
+static void p_bre(register struct parse *p, register int end1, register int end2);
+static int p_simp_re(register struct parse *p, int starordinary);
+static int p_count(register struct parse *p);
+static void p_bracket(register struct parse *p);
+static void p_b_term(register struct parse *p, register cset *cs);
+static void p_b_cclass(register struct parse *p, register cset *cs);
+static void p_b_eclass(register struct parse *p, register cset *cs);
+static char p_b_symbol(register struct parse *p);
+static char p_b_coll_elem(register struct parse *p, int endc);
+static char othercase(int ch);
+static void bothcases(register struct parse *p, int ch);
+static void ordinary(register struct parse *p, register int ch);
+static void nonnewline(register struct parse *p);
+static void repeat(register struct parse *p, sopno start, int from, int to);
+static int seterr(register struct parse *p, int e);
+static cset *allocset(register struct parse *p);
+static void freeset(register struct parse *p, register cset *cs);
+static int freezeset(register struct parse *p, register cset *cs);
+static int firstch(register struct parse *p, register cset *cs);
+static int nch(register struct parse *p, register cset *cs);
+static void mcadd(register struct parse *p, register cset *cs, register char *cp);
+static void mcsub(register cset *cs, register char *cp);
+static int mcin(register cset *cs, register char *cp);
+static char *mcfind(register cset *cs, register char *cp);
+static void mcinvert(register struct parse *p, register cset *cs);
+static void mccase(register struct parse *p, register cset *cs);
+static int isinsets(register struct re_guts *g, int c);
+static int samesets(register struct re_guts *g, int c1, int c2);
+static void categorize(struct parse *p, register struct re_guts *g);
+static sopno dupl(register struct parse *p, sopno start, sopno finish);
+static void doemit(register struct parse *p, sop op, size_t opnd);
+static void doinsert(register struct parse *p, sop op, size_t opnd, sopno pos);
+static void dofwd(register struct parse *p, sopno pos, sop value);
+static void enlarge(register struct parse *p, sopno size);
+static void stripsnug(register struct parse *p, register struct re_guts *g);
+static void findmust(register struct parse *p, register struct re_guts *g);
+static sopno pluscount(register struct parse *p, register struct re_guts *g);
+
+#ifdef __cplusplus
+}
+#endif
+/* ========= end header generated by ./mkh ========= */
--- /dev/null
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <regex.h>
+
+#include "utils.h"
+#include "regerror.ih"
+
+/*
+ = #define REG_OKAY 0
+ = #define REG_NOMATCH 1
+ = #define REG_BADPAT 2
+ = #define REG_ECOLLATE 3
+ = #define REG_ECTYPE 4
+ = #define REG_EESCAPE 5
+ = #define REG_ESUBREG 6
+ = #define REG_EBRACK 7
+ = #define REG_EPAREN 8
+ = #define REG_EBRACE 9
+ = #define REG_BADBR 10
+ = #define REG_ERANGE 11
+ = #define REG_ESPACE 12
+ = #define REG_BADRPT 13
+ = #define REG_EMPTY 14
+ = #define REG_ASSERT 15
+ = #define REG_INVARG 16
+ = #define REG_ATOI 255 // convert name to number (!)
+ = #define REG_ITOA 0400 // convert number to name (!)
+ */
+static struct rerr {
+ int code;
+ char *name;
+ char *explain;
+} rerrs[] = {
+ REG_OKAY, "REG_OKAY", "no errors detected",
+ REG_NOMATCH, "REG_NOMATCH", "regexec() failed to match",
+ REG_BADPAT, "REG_BADPAT", "invalid regular expression",
+ REG_ECOLLATE, "REG_ECOLLATE", "invalid collating element",
+ REG_ECTYPE, "REG_ECTYPE", "invalid character class",
+ REG_EESCAPE, "REG_EESCAPE", "trailing backslash (\\)",
+ REG_ESUBREG, "REG_ESUBREG", "invalid backreference number",
+ REG_EBRACK, "REG_EBRACK", "brackets ([ ]) not balanced",
+ REG_EPAREN, "REG_EPAREN", "parentheses not balanced",
+ REG_EBRACE, "REG_EBRACE", "braces not balanced",
+ REG_BADBR, "REG_BADBR", "invalid repetition count(s)",
+ REG_ERANGE, "REG_ERANGE", "invalid character range",
+ REG_ESPACE, "REG_ESPACE", "out of memory",
+ REG_BADRPT, "REG_BADRPT", "repetition-operator operand invalid",
+ REG_EMPTY, "REG_EMPTY", "empty (sub)expression",
+ REG_ASSERT, "REG_ASSERT", "\"can't happen\" -- you found a bug",
+ REG_INVARG, "REG_INVARG", "invalid argument to regex routine",
+ -1, "", "*** unknown regexp error code ***",
+};
+
+/*
+ - regerror - the interface to error numbers
+ = extern size_t regerror(int, const regex_t *, char *, size_t);
+ */
+/* ARGSUSED */
+size_t
+regerror(
+int errcode,
+const regex_t *preg,
+char *errbuf,
+size_t errbuf_size)
+{
+ register struct rerr *r;
+ register size_t len;
+ register int target = errcode &~ REG_ITOA;
+ register char *s;
+ char convbuf[50];
+
+ if (errcode == REG_ATOI)
+ s = regatoi(preg, convbuf);
+ else {
+ for (r = rerrs; r->code >= 0; r++)
+ if (r->code == target)
+ break;
+
+ if (errcode®_ITOA) {
+ if (r->code >= 0)
+ (void) strcpy(convbuf, r->name);
+ else
+ sprintf(convbuf, "REG_0x%x", target);
+ assert(strlen(convbuf) < sizeof(convbuf));
+ s = convbuf;
+ } else
+ s = r->explain;
+ }
+
+ len = strlen(s) + 1;
+ if (errbuf_size > 0) {
+ if (errbuf_size > len)
+ (void) strcpy(errbuf, s);
+ else {
+ (void) strncpy(errbuf, s, errbuf_size-1);
+ errbuf[errbuf_size-1] = '\0';
+ }
+ }
+
+ return(len);
+}
+
+/*
+ - regatoi - internal routine to implement REG_ATOI
+ == static char *regatoi(const regex_t *preg, char *localbuf);
+ */
+static char *
+regatoi(preg, localbuf)
+const regex_t *preg;
+char *localbuf;
+{
+ register struct rerr *r;
+
+ for (r = rerrs; r->code >= 0; r++)
+ if (strcmp(r->name, preg->re_endp) == 0)
+ break;
+ if (r->code < 0)
+ return("0");
+
+ sprintf(localbuf, "%d", r->code);
+ return(localbuf);
+}
--- /dev/null
+/* ========= begin header generated by ./mkh ========= */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* === regerror.c === */
+static char *regatoi(const regex_t *preg, char *localbuf);
+
+#ifdef __cplusplus
+}
+#endif
+/* ========= end header generated by ./mkh ========= */
--- /dev/null
+.TH REGEX 3 "25 Sept 1997"
+.BY "Henry Spencer"
+.de ZR
+.\" one other place knows this name: the SEE ALSO section
+.IR regex (7) \\$1
+..
+.SH NAME
+regcomp, regexec, regerror, regfree \- regular-expression library
+.SH SYNOPSIS
+.ft B
+.\".na
+#include <sys/types.h>
+.br
+#include <regex.h>
+.HP 10
+int regcomp(regex_t\ *preg, const\ char\ *pattern, int\ cflags);
+.HP
+int\ regexec(const\ regex_t\ *preg, const\ char\ *string,
+size_t\ nmatch, regmatch_t\ pmatch[], int\ eflags);
+.HP
+size_t\ regerror(int\ errcode, const\ regex_t\ *preg,
+char\ *errbuf, size_t\ errbuf_size);
+.HP
+void\ regfree(regex_t\ *preg);
+.\".ad
+.ft
+.SH DESCRIPTION
+These routines implement POSIX 1003.2 regular expressions (``RE''s);
+see
+.ZR .
+.I Regcomp
+compiles an RE written as a string into an internal form,
+.I regexec
+matches that internal form against a string and reports results,
+.I regerror
+transforms error codes from either into human-readable messages,
+and
+.I regfree
+frees any dynamically-allocated storage used by the internal form
+of an RE.
+.PP
+The header
+.I <regex.h>
+declares two structure types,
+.I regex_t
+and
+.IR regmatch_t ,
+the former for compiled internal forms and the latter for match reporting.
+It also declares the four functions,
+a type
+.IR regoff_t ,
+and a number of constants with names starting with ``REG_''.
+.PP
+.I Regcomp
+compiles the regular expression contained in the
+.I pattern
+string,
+subject to the flags in
+.IR cflags ,
+and places the results in the
+.I regex_t
+structure pointed to by
+.IR preg .
+.I Cflags
+is the bitwise OR of zero or more of the following flags:
+.IP REG_EXTENDED \w'REG_EXTENDED'u+2n
+Compile modern (``extended'') REs,
+rather than the obsolete (``basic'') REs that
+are the default.
+.IP REG_BASIC
+This is a synonym for 0,
+provided as a counterpart to REG_EXTENDED to improve readability.
+This is an extension,
+compatible with but not specified by POSIX 1003.2,
+and should be used with
+caution in software intended to be portable to other systems.
+.IP REG_NOSPEC
+Compile with recognition of all special characters turned off.
+All characters are thus considered ordinary,
+so the ``RE'' is a literal string.
+This is an extension,
+compatible with but not specified by POSIX 1003.2,
+and should be used with
+caution in software intended to be portable to other systems.
+REG_EXTENDED and REG_NOSPEC may not be used
+in the same call to
+.IR regcomp .
+.IP REG_ICASE
+Compile for matching that ignores upper/lower case distinctions.
+See
+.ZR .
+.IP REG_NOSUB
+Compile for matching that need only report success or failure,
+not what was matched.
+.IP REG_NEWLINE
+Compile for newline-sensitive matching.
+By default, newline is a completely ordinary character with no special
+meaning in either REs or strings.
+With this flag,
+`[^' bracket expressions and `.' never match newline,
+a `^' anchor matches the null string after any newline in the string
+in addition to its normal function,
+and the `$' anchor matches the null string before any newline in the
+string in addition to its normal function.
+.IP REG_PEND
+The regular expression ends,
+not at the first NUL,
+but just before the character pointed to by the
+.I re_endp
+member of the structure pointed to by
+.IR preg .
+The
+.I re_endp
+member is of type
+.IR const\ char\ * .
+This flag permits inclusion of NULs in the RE;
+they are considered ordinary characters.
+This is an extension,
+compatible with but not specified by POSIX 1003.2,
+and should be used with
+caution in software intended to be portable to other systems.
+.PP
+When successful,
+.I regcomp
+returns 0 and fills in the structure pointed to by
+.IR preg .
+One member of that structure
+(other than
+.IR re_endp )
+is publicized:
+.IR re_nsub ,
+of type
+.IR size_t ,
+contains the number of parenthesized subexpressions within the RE
+(except that the value of this member is undefined if the
+REG_NOSUB flag was used).
+If
+.I regcomp
+fails, it returns a non-zero error code;
+see DIAGNOSTICS.
+.PP
+.I Regexec
+matches the compiled RE pointed to by
+.I preg
+against the
+.IR string ,
+subject to the flags in
+.IR eflags ,
+and reports results using
+.IR nmatch ,
+.IR pmatch ,
+and the returned value.
+The RE must have been compiled by a previous invocation of
+.IR regcomp .
+The compiled form is not altered during execution of
+.IR regexec ,
+so a single compiled RE can be used simultaneously by multiple threads.
+.PP
+By default,
+the NUL-terminated string pointed to by
+.I string
+is considered to be the text of an entire line,
+with the NUL indicating the end of the line.
+(That is,
+any other end-of-line marker is considered to have been removed
+and replaced by the NUL.)
+The
+.I eflags
+argument is the bitwise OR of zero or more of the following flags:
+.IP REG_NOTBOL \w'REG_STARTEND'u+2n
+The first character of
+the string
+is not the beginning of a line, so the `^' anchor should not match before it.
+This does not affect the behavior of newlines under REG_NEWLINE.
+.IP REG_NOTEOL
+The NUL terminating
+the string
+does not end a line, so the `$' anchor should not match before it.
+This does not affect the behavior of newlines under REG_NEWLINE.
+.IP REG_STARTEND
+The string is considered to start at
+\fIstring\fR\ + \fIpmatch\fR[0].\fIrm_so\fR
+and to have a terminating NUL located at
+\fIstring\fR\ + \fIpmatch\fR[0].\fIrm_eo\fR
+(there need not actually be a NUL at that location),
+regardless of the value of
+.IR nmatch .
+See below for the definition of
+.IR pmatch
+and
+.IR nmatch .
+This is an extension,
+compatible with but not specified by POSIX 1003.2,
+and should be used with
+caution in software intended to be portable to other systems.
+Note that a non-zero \fIrm_so\fR does not imply REG_NOTBOL;
+REG_STARTEND affects only the location of the string,
+not how it is matched.
+.PP
+See
+.ZR
+for a discussion of what is matched in situations where an RE or a
+portion thereof could match any of several substrings of
+.IR string .
+.PP
+Normally,
+.I regexec
+returns 0 for success and the non-zero code REG_NOMATCH for failure.
+Other non-zero error codes may be returned in exceptional situations;
+see DIAGNOSTICS.
+.PP
+If REG_NOSUB was specified in the compilation of the RE,
+or if
+.I nmatch
+is 0,
+.I regexec
+ignores the
+.I pmatch
+argument (but see below for the case where REG_STARTEND is specified).
+Otherwise,
+.I pmatch
+points to an array of
+.I nmatch
+structures of type
+.IR regmatch_t .
+Such a structure has at least the members
+.I rm_so
+and
+.IR rm_eo ,
+both of type
+.I regoff_t
+(a signed arithmetic type at least as large as an
+.I off_t
+and a
+.IR ssize_t ),
+containing respectively the offset of the first character of a substring
+and the offset of the first character after the end of the substring.
+Offsets are measured from the beginning of the
+.I string
+argument given to
+.IR regexec .
+An empty substring is denoted by equal offsets,
+both indicating the character following the empty substring.
+.PP
+The 0th member of the
+.I pmatch
+array is filled in to indicate what substring of
+.I string
+was matched by the entire RE.
+Remaining members report what substring was matched by parenthesized
+subexpressions within the RE;
+member
+.I i
+reports subexpression
+.IR i ,
+with subexpressions counted (starting at 1) by the order of their opening
+parentheses in the RE, left to right.
+Unused entries in the array\(emcorresponding either to subexpressions that
+did not participate in the match at all, or to subexpressions that do not
+exist in the RE (that is, \fIi\fR\ > \fIpreg\fR\->\fIre_nsub\fR)\(emhave both
+.I rm_so
+and
+.I rm_eo
+set to \-1.
+If a subexpression participated in the match several times,
+the reported substring is the last one it matched.
+(Note, as an example in particular, that when the RE `(b*)+' matches `bbb',
+the parenthesized subexpression matches the three `b's and then
+an infinite number of empty strings following the last `b',
+so the reported substring is one of the empties.)
+.PP
+If REG_STARTEND is specified,
+.I pmatch
+must point to at least one
+.I regmatch_t
+(even if
+.I nmatch
+is 0 or REG_NOSUB was specified),
+to hold the input offsets for REG_STARTEND.
+Use for output is still entirely controlled by
+.IR nmatch ;
+if
+.I nmatch
+is 0 or REG_NOSUB was specified,
+the value of
+.IR pmatch [0]
+will not be changed by a successful
+.IR regexec .
+.PP
+.I Regerror
+maps a non-zero
+.I errcode
+from either
+.I regcomp
+or
+.I regexec
+to a human-readable, printable message.
+If
+.I preg
+is non-NULL,
+the error code should have arisen from use of
+the
+.I regex_t
+pointed to by
+.IR preg ,
+and if the error code came from
+.IR regcomp ,
+it should have been the result from the most recent
+.I regcomp
+using that
+.IR regex_t .
+.RI ( Regerror
+may be able to supply a more detailed message using information
+from the
+.IR regex_t .)
+.I Regerror
+places the NUL-terminated message into the buffer pointed to by
+.IR errbuf ,
+limiting the length (including the NUL) to at most
+.I errbuf_size
+bytes.
+If the whole message won't fit,
+as much of it as will fit before the terminating NUL is supplied.
+In any case,
+the returned value is the size of buffer needed to hold the whole
+message (including terminating NUL).
+If
+.I errbuf_size
+is 0,
+.I errbuf
+is ignored but the return value is still correct.
+.PP
+If the
+.I errcode
+given to
+.I regerror
+is first ORed with REG_ITOA,
+the ``message'' that results is the printable name of the error code,
+e.g. ``REG_NOMATCH'',
+rather than an explanation thereof.
+If
+.I errcode
+is REG_ATOI,
+then
+.I preg
+shall be non-NULL and the
+.I re_endp
+member of the structure it points to
+must point to the printable name of an error code;
+in this case, the result in
+.I errbuf
+is the decimal digits of
+the numeric value of the error code
+(0 if the name is not recognized).
+REG_ITOA and REG_ATOI are intended primarily as debugging facilities;
+they are extensions,
+compatible with but not specified by POSIX 1003.2,
+and should be used with
+caution in software intended to be portable to other systems.
+Be warned also that they are considered experimental and changes are possible.
+.PP
+.I Regfree
+frees any dynamically-allocated storage associated with the compiled RE
+pointed to by
+.IR preg .
+The remaining
+.I regex_t
+is no longer a valid compiled RE
+and the effect of supplying it to
+.I regexec
+or
+.I regerror
+is undefined.
+.PP
+None of these functions references global variables except for tables
+of constants;
+all are safe for use from multiple threads if the arguments are safe.
+.SH IMPLEMENTATION CHOICES
+There are a number of decisions that 1003.2 leaves up to the implementor,
+either by explicitly saying ``undefined'' or by virtue of them being
+forbidden by the RE grammar.
+This implementation treats them as follows.
+.PP
+See
+.ZR
+for a discussion of the definition of case-independent matching.
+.PP
+There is no particular limit on the length of REs,
+except insofar as memory is limited.
+Memory usage is approximately linear in RE size, and largely insensitive
+to RE complexity, except for bounded repetitions.
+See BUGS for one short RE using them
+that will run almost any system out of memory.
+.PP
+A backslashed character other than one specifically given a magic meaning
+by 1003.2 (such magic meanings occur only in obsolete [``basic''] REs)
+is taken as an ordinary character.
+.PP
+Any unmatched [ is a REG_EBRACK error.
+.PP
+Equivalence classes cannot begin or end bracket-expression ranges.
+The endpoint of one range cannot begin another.
+.PP
+RE_DUP_MAX, the limit on repetition counts in bounded repetitions, is 255.
+.PP
+A repetition operator (?, *, +, or bounds) cannot follow another
+repetition operator.
+A repetition operator cannot begin an expression or subexpression
+or follow `^' or `|'.
+.PP
+`|' cannot appear first or last in a (sub)expression or after another `|',
+i.e. an operand of `|' cannot be an empty subexpression.
+An empty parenthesized subexpression, `()', is legal and matches an
+empty (sub)string.
+An empty string is not a legal RE.
+.PP
+A `{' followed by a digit is considered the beginning of bounds for a
+bounded repetition, which must then follow the syntax for bounds.
+A `{' \fInot\fR followed by a digit is considered an ordinary character.
+.PP
+`^' and `$' beginning and ending subexpressions in obsolete (``basic'')
+REs are anchors, not ordinary characters.
+.SH SEE ALSO
+grep(1), regex(7)
+.PP
+POSIX 1003.2, sections 2.8 (Regular Expression Notation)
+and
+B.5 (C Binding for Regular Expression Matching).
+.SH DIAGNOSTICS
+Non-zero error codes from
+.I regcomp
+and
+.I regexec
+include the following:
+.PP
+.nf
+.ta \w'REG_ECOLLATE'u+3n
+REG_NOMATCH regexec() failed to match
+REG_BADPAT invalid regular expression
+REG_ECOLLATE invalid collating element
+REG_ECTYPE invalid character class
+REG_EESCAPE \e applied to unescapable character
+REG_ESUBREG invalid backreference number
+REG_EBRACK brackets [ ] not balanced
+REG_EPAREN parentheses ( ) not balanced
+REG_EBRACE braces { } not balanced
+REG_BADBR invalid repetition count(s) in { }
+REG_ERANGE invalid character range in [ ]
+REG_ESPACE ran out of memory
+REG_BADRPT ?, *, or + operand invalid
+REG_EMPTY empty (sub)expression
+REG_ASSERT ``can't happen''\(emyou found a bug
+REG_INVARG invalid argument, e.g. negative-length string
+.fi
+.SH HISTORY
+Written by Henry Spencer,
+henry@zoo.toronto.edu.
+.SH BUGS
+This is an alpha release with known defects.
+Please report problems.
+.PP
+There is one known functionality bug.
+The implementation of internationalization is incomplete:
+the locale is always assumed to be the default one of 1003.2,
+and only the collating elements etc. of that locale are available.
+.PP
+The back-reference code is subtle and doubts linger about its correctness
+in complex cases.
+.PP
+.I Regexec
+performance is poor.
+This will improve with later releases.
+.I Nmatch
+exceeding 0 is expensive;
+.I nmatch
+exceeding 1 is worse.
+.I Regexec
+is largely insensitive to RE complexity \fIexcept\fR that back
+references are massively expensive.
+RE length does matter; in particular, there is a strong speed bonus
+for keeping RE length under about 30 characters,
+with most special characters counting roughly double.
+.PP
+.I Regcomp
+implements bounded repetitions by macro expansion,
+which is costly in time and space if counts are large
+or bounded repetitions are nested.
+An RE like, say,
+`((((a{1,100}){1,100}){1,100}){1,100}){1,100}'
+will (eventually) run almost any existing machine out of swap space.
+.PP
+There are suspected problems with response to obscure error conditions.
+Notably,
+certain kinds of internal overflow,
+produced only by truly enormous REs or by multiply nested bounded repetitions,
+are probably not handled well.
+.PP
+Due to a mistake in 1003.2, things like `a)b' are legal REs because `)' is
+a special character only in the presence of a previous unmatched `('.
+This can't be fixed until the spec is fixed.
+.PP
+The standard's definition of back references is vague.
+For example, does
+`a\e(\e(b\e)*\e2\e)*d' match `abbbd'?
+Until the standard is clarified,
+behavior in such cases should not be relied on.
+.PP
+The implementation of word-boundary matching is a bit of a kludge,
+and bugs may lurk in combinations of word-boundary matching and anchoring.
--- /dev/null
+.TH REGEX 7 "25 Oct 1995"
+.BY "Henry Spencer"
+.SH NAME
+regex \- POSIX 1003.2 regular expressions
+.SH DESCRIPTION
+Regular expressions (``RE''s),
+as defined in POSIX 1003.2, come in two forms:
+modern REs (roughly those of
+.IR egrep ;
+1003.2 calls these ``extended'' REs)
+and obsolete REs (roughly those of
+.IR ed ;
+1003.2 ``basic'' REs).
+Obsolete REs mostly exist for backward compatibility in some old programs;
+they will be discussed at the end.
+1003.2 leaves some aspects of RE syntax and semantics open;
+`\(dg' marks decisions on these aspects that
+may not be fully portable to other 1003.2 implementations.
+.PP
+A (modern) RE is one\(dg or more non-empty\(dg \fIbranches\fR,
+separated by `|'.
+It matches anything that matches one of the branches.
+.PP
+A branch is one\(dg or more \fIpieces\fR, concatenated.
+It matches a match for the first, followed by a match for the second, etc.
+.PP
+A piece is an \fIatom\fR possibly followed
+by a single\(dg `*', `+', `?', or \fIbound\fR.
+An atom followed by `*' matches a sequence of 0 or more matches of the atom.
+An atom followed by `+' matches a sequence of 1 or more matches of the atom.
+An atom followed by `?' matches a sequence of 0 or 1 matches of the atom.
+.PP
+A \fIbound\fR is `{' followed by an unsigned decimal integer,
+possibly followed by `,'
+possibly followed by another unsigned decimal integer,
+always followed by `}'.
+The integers must lie between 0 and RE_DUP_MAX (255\(dg) inclusive,
+and if there are two of them, the first may not exceed the second.
+An atom followed by a bound containing one integer \fIi\fR
+and no comma matches
+a sequence of exactly \fIi\fR matches of the atom.
+An atom followed by a bound
+containing one integer \fIi\fR and a comma matches
+a sequence of \fIi\fR or more matches of the atom.
+An atom followed by a bound
+containing two integers \fIi\fR and \fIj\fR matches
+a sequence of \fIi\fR through \fIj\fR (inclusive) matches of the atom.
+.PP
+An atom is a regular expression enclosed in `()' (matching a match for the
+regular expression),
+an empty set of `()' (matching the null string)\(dg,
+a \fIbracket expression\fR (see below), `.'
+(matching any single character), `^' (matching the null string at the
+beginning of a line), `$' (matching the null string at the
+end of a line), a `\e' followed by one of the characters
+`^.[$()|*+?{\e'
+(matching that character taken as an ordinary character),
+a `\e' followed by any other character\(dg
+(matching that character taken as an ordinary character,
+as if the `\e' had not been present\(dg),
+or a single character with no other significance (matching that character).
+A `{' followed by a character other than a digit is an ordinary
+character, not the beginning of a bound\(dg.
+It is illegal to end an RE with `\e'.
+.PP
+A \fIbracket expression\fR is a list of characters enclosed in `[]'.
+It normally matches any single character from the list (but see below).
+If the list begins with `^',
+it matches any single character
+(but see below) \fInot\fR from the rest of the list.
+If two characters in the list are separated by `\-', this is shorthand
+for the full \fIrange\fR of characters between those two (inclusive) in the
+collating sequence,
+e.g. `[0\-9]' in ASCII matches any decimal digit.
+It is illegal\(dg for two ranges to share an
+endpoint, e.g. `a\-c\-e'.
+Ranges are very collating-sequence-dependent,
+and portable programs should avoid relying on them.
+.PP
+To include a literal `]' in the list, make it the first character
+(following a possible `^').
+To include a literal `\-', make it the first or last character,
+or the second endpoint of a range.
+To use a literal `\-' as the first endpoint of a range,
+enclose it in `[.' and `.]' to make it a collating element (see below).
+With the exception of these and some combinations using `[' (see next
+paragraphs), all other special characters, including `\e', lose their
+special significance within a bracket expression.
+.PP
+Within a bracket expression, a collating element (a character,
+a multi-character sequence that collates as if it were a single character,
+or a collating-sequence name for either)
+enclosed in `[.' and `.]' stands for the
+sequence of characters of that collating element.
+The sequence is a single element of the bracket expression's list.
+A bracket expression containing a multi-character collating element
+can thus match more than one character,
+e.g. if the collating sequence includes a `ch' collating element,
+then the RE `[[.ch.]]*c' matches the first five characters
+of `chchcc'.
+.PP
+Within a bracket expression, a collating element enclosed in `[=' and
+`=]' is an equivalence class, standing for the sequences of characters
+of all collating elements equivalent to that one, including itself.
+(If there are no other equivalent collating elements,
+the treatment is as if the enclosing delimiters were `[.' and `.]'.)
+For example, if o and \o'o^' are the members of an equivalence class,
+then `[[=o=]]', `[[=\o'o^'=]]', and `[o\o'o^']' are all synonymous.
+An equivalence class may not\(dg be an endpoint
+of a range.
+.PP
+Within a bracket expression, the name of a \fIcharacter class\fR enclosed
+in `[:' and `:]' stands for the list of all characters belonging to that
+class.
+Standard character class names are:
+.PP
+.RS
+.nf
+.ta 3c 6c 9c
+alnum digit punct
+alpha graph space
+blank lower upper
+cntrl print xdigit
+.fi
+.RE
+.PP
+These stand for the character classes defined in
+.IR ctype (3).
+A locale may provide others.
+A character class may not be used as an endpoint of a range.
+.PP
+There are two special cases\(dg of bracket expressions:
+the bracket expressions `[[:<:]]' and `[[:>:]]' match the null string at
+the beginning and end of a word respectively.
+A word is defined as a sequence of
+word characters
+which is neither preceded nor followed by
+word characters.
+A word character is an
+.I alnum
+character (as defined by
+.IR ctype (3))
+or an underscore.
+This is an extension,
+compatible with but not specified by POSIX 1003.2,
+and should be used with
+caution in software intended to be portable to other systems.
+.PP
+In the event that an RE could match more than one substring of a given
+string,
+the RE matches the one starting earliest in the string.
+If the RE could match more than one substring starting at that point,
+it matches the longest.
+Subexpressions also match the longest possible substrings, subject to
+the constraint that the whole match be as long as possible,
+with subexpressions starting earlier in the RE taking priority over
+ones starting later.
+Note that higher-level subexpressions thus take priority over
+their lower-level component subexpressions.
+.PP
+Match lengths are measured in characters, not collating elements.
+A null string is considered longer than no match at all.
+For example,
+`bb*' matches the three middle characters of `abbbc',
+`(wee|week)(knights|nights)' matches all ten characters of `weeknights',
+when `(.*).*' is matched against `abc' the parenthesized subexpression
+matches all three characters, and
+when `(a*)*' is matched against `bc' both the whole RE and the parenthesized
+subexpression match the null string.
+.PP
+If case-independent matching is specified,
+the effect is much as if all case distinctions had vanished from the
+alphabet.
+When an alphabetic that exists in multiple cases appears as an
+ordinary character outside a bracket expression, it is effectively
+transformed into a bracket expression containing both cases,
+e.g. `x' becomes `[xX]'.
+When it appears inside a bracket expression, all case counterparts
+of it are added to the bracket expression, so that (e.g.) `[x]'
+becomes `[xX]' and `[^x]' becomes `[^xX]'.
+.PP
+No particular limit is imposed on the length of REs\(dg.
+Programs intended to be portable should not employ REs longer
+than 256 bytes,
+as an implementation can refuse to accept such REs and remain
+POSIX-compliant.
+.PP
+Obsolete (``basic'') regular expressions differ in several respects.
+`|', `+', and `?' are ordinary characters and there is no equivalent
+for their functionality.
+The delimiters for bounds are `\e{' and `\e}',
+with `{' and `}' by themselves ordinary characters.
+The parentheses for nested subexpressions are `\e(' and `\e)',
+with `(' and `)' by themselves ordinary characters.
+`^' is an ordinary character except at the beginning of the
+RE or\(dg the beginning of a parenthesized subexpression,
+`$' is an ordinary character except at the end of the
+RE or\(dg the end of a parenthesized subexpression,
+and `*' is an ordinary character if it appears at the beginning of the
+RE or the beginning of a parenthesized subexpression
+(after a possible leading `^').
+Finally, there is one new type of atom, a \fIback reference\fR:
+`\e' followed by a non-zero decimal digit \fId\fR
+matches the same sequence of characters
+matched by the \fId\fRth parenthesized subexpression
+(numbering subexpressions by the positions of their opening parentheses,
+left to right),
+so that (e.g.) `\e([bc]\e)\e1' matches `bb' or `cc' but not `bc'.
+.SH SEE ALSO
+regex(3)
+.PP
+POSIX 1003.2, section 2.8 (Regular Expression Notation).
+.SH HISTORY
+Written by Henry Spencer, based on the 1003.2 spec.
+.SH BUGS
+Having two kinds of REs is a botch.
+.PP
+The current 1003.2 spec says that `)' is an ordinary character in
+the absence of an unmatched `(';
+this was an unintentional result of a wording error,
+and change is likely.
+Avoid relying on it.
+.PP
+Back references are a dreadful botch,
+posing major problems for efficient implementations.
+They are also somewhat vaguely defined
+(does
+`a\e(\e(b\e)*\e2\e)*d' match `abbbd'?).
+Avoid using them.
+.PP
+1003.2's specification of case-independent matching is vague.
+The ``one case implies all cases'' definition given above
+is current consensus among implementors as to the right interpretation.
+.PP
+The syntax for word boundaries is incredibly ugly.
--- /dev/null
+#ifndef _REGEX_H_
+#define _REGEX_H_ /* never again */
+/* ========= begin header generated by ./mkh ========= */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* === regex2.h === */
+typedef long regoff_t;
+typedef struct {
+ int re_magic;
+ size_t re_nsub; /* number of parenthesized subexpressions */
+ const char *re_endp; /* end pointer for REG_PEND */
+ struct re_guts *re_g; /* none of your business :-) */
+} regex_t;
+typedef struct {
+ regoff_t rm_so; /* start of match */
+ regoff_t rm_eo; /* end of match */
+} regmatch_t;
+
+
+/* === regcomp.c === */
+extern int regcomp(regex_t *, const char *, int);
+#define REG_BASIC 0000
+#define REG_EXTENDED 0001
+#define REG_ICASE 0002
+#define REG_NOSUB 0004
+#define REG_NEWLINE 0010
+#define REG_NOSPEC 0020
+#define REG_PEND 0040
+#define REG_DUMP 0200
+
+
+/* === regerror.c === */
+#define REG_OKAY 0
+#define REG_NOMATCH 1
+#define REG_BADPAT 2
+#define REG_ECOLLATE 3
+#define REG_ECTYPE 4
+#define REG_EESCAPE 5
+#define REG_ESUBREG 6
+#define REG_EBRACK 7
+#define REG_EPAREN 8
+#define REG_EBRACE 9
+#define REG_BADBR 10
+#define REG_ERANGE 11
+#define REG_ESPACE 12
+#define REG_BADRPT 13
+#define REG_EMPTY 14
+#define REG_ASSERT 15
+#define REG_INVARG 16
+#define REG_ATOI 255 /* convert name to number (!) */
+#define REG_ITOA 0400 /* convert number to name (!) */
+extern size_t regerror(int, const regex_t *, char *, size_t);
+
+
+/* === regexec.c === */
+extern int regexec(const regex_t *, const char *, size_t, regmatch_t [], int);
+#define REG_NOTBOL 00001
+#define REG_NOTEOL 00002
+#define REG_STARTEND 00004
+#define REG_TRACE 00400 /* tracing of execution */
+#define REG_LARGE 01000 /* force large representation */
+#define REG_BACKR 02000 /* force use of backref code */
+
+
+/* === regfree.c === */
+extern void regfree(regex_t *);
+
+#ifdef __cplusplus
+}
+#endif
+/* ========= end header generated by ./mkh ========= */
+#endif
--- /dev/null
+/*
+ * First, the stuff that ends up in the outside-world include file
+ = typedef off_t regoff_t;
+ = typedef struct {
+ = int re_magic;
+ = size_t re_nsub; // number of parenthesized subexpressions
+ = const char *re_endp; // end pointer for REG_PEND
+ = struct re_guts *re_g; // none of your business :-)
+ = } regex_t;
+ = typedef struct {
+ = regoff_t rm_so; // start of match
+ = regoff_t rm_eo; // end of match
+ = } regmatch_t;
+ */
+/*
+ * internals of regex_t
+ */
+#define MAGIC1 ((('r'^0200)<<8) | 'e')
+
+/*
+ * The internal representation is a *strip*, a sequence of
+ * operators ending with an endmarker. (Some terminology etc. is a
+ * historical relic of earlier versions which used multiple strips.)
+ * Certain oddities in the representation are there to permit running
+ * the machinery backwards; in particular, any deviation from sequential
+ * flow must be marked at both its source and its destination. Some
+ * fine points:
+ *
+ * - OPLUS_ and O_PLUS are *inside* the loop they create.
+ * - OQUEST_ and O_QUEST are *outside* the bypass they create.
+ * - OCH_ and O_CH are *outside* the multi-way branch they create, while
+ * OOR1 and OOR2 are respectively the end and the beginning of one of
+ * the branches. Note that there is an implicit OOR2 following OCH_
+ * and an implicit OOR1 preceding O_CH.
+ *
+ * In state representations, an operator's bit is on to signify a state
+ * immediately *preceding* "execution" of that operator.
+ */
+typedef long sop; /* strip operator */
+typedef long sopno;
+#define OPRMASK 0x7c000000
+#define OPDMASK 0x03ffffff
+#define OPSHIFT (26)
+#define OP(n) ((n)&OPRMASK)
+#define OPND(n) ((n)&OPDMASK)
+#define SOP(op, opnd) ((op)|(opnd))
+/* operators meaning operand */
+/* (back, fwd are offsets) */
+#define OEND (1<<OPSHIFT) /* endmarker - */
+#define OCHAR (2<<OPSHIFT) /* character unsigned char */
+#define OBOL (3<<OPSHIFT) /* left anchor - */
+#define OEOL (4<<OPSHIFT) /* right anchor - */
+#define OANY (5<<OPSHIFT) /* . - */
+#define OANYOF (6<<OPSHIFT) /* [...] set number */
+#define OBACK_ (7<<OPSHIFT) /* begin \d paren number */
+#define O_BACK (8<<OPSHIFT) /* end \d paren number */
+#define OPLUS_ (9<<OPSHIFT) /* + prefix fwd to suffix */
+#define O_PLUS (10<<OPSHIFT) /* + suffix back to prefix */
+#define OQUEST_ (11<<OPSHIFT) /* ? prefix fwd to suffix */
+#define O_QUEST (12<<OPSHIFT) /* ? suffix back to prefix */
+#define OLPAREN (13<<OPSHIFT) /* ( fwd to ) */
+#define ORPAREN (14<<OPSHIFT) /* ) back to ( */
+#define OCH_ (15<<OPSHIFT) /* begin choice fwd to OOR2 */
+#define OOR1 (16<<OPSHIFT) /* | pt. 1 back to OOR1 or OCH_ */
+#define OOR2 (17<<OPSHIFT) /* | pt. 2 fwd to OOR2 or O_CH */
+#define O_CH (18<<OPSHIFT) /* end choice back to OOR1 */
+#define OBOW (19<<OPSHIFT) /* begin word - */
+#define OEOW (20<<OPSHIFT) /* end word - */
+
+/*
+ * Structure for [] character-set representation. Character sets are
+ * done as bit vectors, grouped 8 to a byte vector for compactness.
+ * The individual set therefore has both a pointer to the byte vector
+ * and a mask to pick out the relevant bit of each byte. A hash code
+ * simplifies testing whether two sets could be identical.
+ *
+ * This will get trickier for multicharacter collating elements. As
+ * preliminary hooks for dealing with such things, we also carry along
+ * a string of multi-character elements, and decide the size of the
+ * vectors at run time.
+ */
+typedef struct {
+ uch *ptr; /* -> uch [csetsize] */
+ uch mask; /* bit within array */
+ uch hash; /* hash code */
+ size_t smultis;
+ char *multis; /* -> char[smulti] ab\0cd\0ef\0\0 */
+} cset;
+/* note that CHadd and CHsub are unsafe, and CHIN doesn't yield 0/1 */
+#define CHadd(cs, c) ((cs)->ptr[(uch)(c)] |= (cs)->mask, (cs)->hash += (c))
+#define CHsub(cs, c) ((cs)->ptr[(uch)(c)] &= ~(cs)->mask, (cs)->hash -= (c))
+#define CHIN(cs, c) ((cs)->ptr[(uch)(c)] & (cs)->mask)
+#define MCadd(p, cs, cp) mcadd(p, cs, cp) /* regcomp() internal fns */
+#define MCsub(p, cs, cp) mcsub(p, cs, cp)
+#define MCin(p, cs, cp) mcin(p, cs, cp)
+
+/* stuff for character categories */
+typedef unsigned char cat_t;
+
+/*
+ * main compiled-expression structure
+ */
+struct re_guts {
+ int magic;
+# define MAGIC2 ((('R'^0200)<<8)|'E')
+ sop *strip; /* malloced area for strip */
+ int csetsize; /* number of bits in a cset vector */
+ int ncsets; /* number of csets in use */
+ cset *sets; /* -> cset [ncsets] */
+ uch *setbits; /* -> uch[csetsize][ncsets/CHAR_BIT] */
+ int cflags; /* copy of regcomp() cflags argument */
+ sopno nstates; /* = number of sops */
+ sopno firststate; /* the initial OEND (normally 0) */
+ sopno laststate; /* the final OEND */
+ int iflags; /* internal flags */
+# define USEBOL 01 /* used ^ */
+# define USEEOL 02 /* used $ */
+# define BAD 04 /* something wrong */
+ int nbol; /* number of ^ used */
+ int neol; /* number of $ used */
+ int ncategories; /* how many character categories */
+ cat_t *categories; /* ->catspace[-CHAR_MIN] */
+ char *must; /* match must contain this string */
+ int mlen; /* length of must */
+ size_t nsub; /* copy of re_nsub */
+ int backrefs; /* does it use back references? */
+ sopno nplus; /* how deep does it nest +s? */
+ /* catspace must be last */
+ cat_t catspace[1]; /* actually [NC] */
+};
+
+/* misc utilities */
+#define OUT (CHAR_MAX+1) /* a non-character value */
+#define ISWORD(c) (isalnum(c) || (c) == '_')
--- /dev/null
+/*
+ * the outer shell of regexec()
+ *
+ * This file includes engine.c *twice*, after muchos fiddling with the
+ * macros that code uses. This lets the same code operate on two different
+ * representations for state sets.
+ */
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <ctype.h>
+#include <regex.h>
+
+#include "utils.h"
+#include "regex2.h"
+
+static int nope = 0; /* for use in asserts; shuts lint up */
+
+/* macros for manipulating states, small version */
+#define states unsigned
+#define states1 unsigned /* for later use in regexec() decision */
+#define CLEAR(v) ((v) = 0)
+#define SET0(v, n) ((v) &= ~((unsigned)1 << (n)))
+#define SET1(v, n) ((v) |= (unsigned)1 << (n))
+#define ISSET(v, n) ((v) & ((unsigned)1 << (n)))
+#define ASSIGN(d, s) ((d) = (s))
+#define EQ(a, b) ((a) == (b))
+#define STATEVARS int dummy /* dummy version */
+#define STATESETUP(m, n) /* nothing */
+#define STATETEARDOWN(m) /* nothing */
+#define SETUP(v) ((v) = 0)
+#define onestate unsigned
+#define INIT(o, n) ((o) = (unsigned)1 << (n))
+#define INC(o) ((o) <<= 1)
+#define ISSTATEIN(v, o) ((v) & (o))
+/* some abbreviations; note that some of these know variable names! */
+/* do "if I'm here, I can also be there" etc without branches */
+#define FWD(dst, src, n) ((dst) |= ((unsigned)(src)&(here)) << (n))
+#define BACK(dst, src, n) ((dst) |= ((unsigned)(src)&(here)) >> (n))
+#define ISSETBACK(v, n) ((v) & ((unsigned)here >> (n)))
+/* function names */
+#define SNAMES /* engine.c looks after details */
+
+#include "engine.c"
+
+/* now undo things */
+#undef states
+#undef CLEAR
+#undef SET0
+#undef SET1
+#undef ISSET
+#undef ASSIGN
+#undef EQ
+#undef STATEVARS
+#undef STATESETUP
+#undef STATETEARDOWN
+#undef SETUP
+#undef onestate
+#undef INIT
+#undef INC
+#undef ISSTATEIN
+#undef FWD
+#undef BACK
+#undef ISSETBACK
+#undef SNAMES
+
+/* macros for manipulating states, large version */
+#define states char *
+#define CLEAR(v) memset(v, 0, m->g->nstates)
+#define SET0(v, n) ((v)[n] = 0)
+#define SET1(v, n) ((v)[n] = 1)
+#define ISSET(v, n) ((v)[n])
+#define ASSIGN(d, s) memcpy(d, s, m->g->nstates)
+#define EQ(a, b) (memcmp(a, b, m->g->nstates) == 0)
+#define STATEVARS int vn; char *space
+#define STATESETUP(m, nv) { (m)->space = malloc((nv)*(m)->g->nstates); \
+ if ((m)->space == NULL) return(REG_ESPACE); \
+ (m)->vn = 0; }
+#define STATETEARDOWN(m) { free((m)->space); }
+#define SETUP(v) ((v) = &m->space[m->vn++ * m->g->nstates])
+#define onestate int
+#define INIT(o, n) ((o) = (n))
+#define INC(o) ((o)++)
+#define ISSTATEIN(v, o) ((v)[o])
+/* some abbreviations; note that some of these know variable names! */
+/* do "if I'm here, I can also be there" etc without branches */
+#define FWD(dst, src, n) ((dst)[here+(n)] |= (src)[here])
+#define BACK(dst, src, n) ((dst)[here-(n)] |= (src)[here])
+#define ISSETBACK(v, n) ((v)[here - (n)])
+/* function names */
+#define LNAMES /* flag */
+
+#include "engine.c"
+
+/*
+ - regexec - interface for matching
+ = extern int regexec(const regex_t *, const char *, size_t, \
+ = regmatch_t [], int);
+ = #define REG_NOTBOL 00001
+ = #define REG_NOTEOL 00002
+ = #define REG_STARTEND 00004
+ = #define REG_TRACE 00400 // tracing of execution
+ = #define REG_LARGE 01000 // force large representation
+ = #define REG_BACKR 02000 // force use of backref code
+ *
+ * We put this here so we can exploit knowledge of the state representation
+ * when choosing which matcher to call. Also, by this point the matchers
+ * have been prototyped.
+ */
+int /* 0 success, REG_NOMATCH failure */
+regexec(preg, string, nmatch, pmatch, eflags)
+const regex_t *preg;
+const char *string;
+size_t nmatch;
+regmatch_t pmatch[];
+int eflags;
+{
+ register struct re_guts *g = preg->re_g;
+#ifdef REDEBUG
+# define GOODFLAGS(f) (f)
+#else
+# define GOODFLAGS(f) ((f)&(REG_NOTBOL|REG_NOTEOL|REG_STARTEND))
+#endif
+
+ if (preg->re_magic != MAGIC1 || g->magic != MAGIC2)
+ return(REG_BADPAT);
+ assert(!(g->iflags&BAD));
+ if (g->iflags&BAD) /* backstop for no-debug case */
+ return(REG_BADPAT);
+ eflags = GOODFLAGS(eflags);
+
+ if (g->nstates <= CHAR_BIT*sizeof(states1) && !(eflags®_LARGE))
+ return(smatcher(g, (char *)string, nmatch, pmatch, eflags));
+ else
+ return(lmatcher(g, (char *)string, nmatch, pmatch, eflags));
+}
--- /dev/null
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <regex.h>
+
+#include "utils.h"
+#include "regex2.h"
+
+/*
+ - regfree - free everything
+ = extern void regfree(regex_t *);
+ */
+void
+regfree(preg)
+regex_t *preg;
+{
+ register struct re_guts *g;
+
+ if (preg->re_magic != MAGIC1) /* oops */
+ return; /* nice to complain, but hard */
+
+ g = preg->re_g;
+ if (g == NULL || g->magic != MAGIC2) /* oops again */
+ return;
+ preg->re_magic = 0; /* mark it invalid */
+ g->magic = 0; /* mark it invalid */
+
+ if (g->strip != NULL)
+ free((char *)g->strip);
+ if (g->sets != NULL)
+ free((char *)g->sets);
+ if (g->setbits != NULL)
+ free((char *)g->setbits);
+ if (g->must != NULL)
+ free(g->must);
+ free((char *)g);
+}
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+
+/*
+ - split - divide a string into fields, like awk split()
+ = int split(char *string, char *fields[], int nfields, char *sep);
+ */
+int /* number of fields, including overflow */
+split(string, fields, nfields, sep)
+char *string;
+char *fields[]; /* list is not NULL-terminated */
+int nfields; /* number of entries available in fields[] */
+char *sep; /* "" white, "c" single char, "ab" [ab]+ */
+{
+ register char *p = string;
+ register char c; /* latest character */
+ register char sepc = sep[0];
+ register char sepc2;
+ register int fn;
+ register char **fp = fields;
+ register char *sepp;
+ register int trimtrail;
+
+ /* white space */
+ if (sepc == '\0') {
+ while ((c = *p++) == ' ' || c == '\t')
+ continue;
+ p--;
+ trimtrail = 1;
+ sep = " \t"; /* note, code below knows this is 2 long */
+ sepc = ' ';
+ } else
+ trimtrail = 0;
+ sepc2 = sep[1]; /* now we can safely pick this up */
+
+ /* catch empties */
+ if (*p == '\0')
+ return(0);
+
+ /* single separator */
+ if (sepc2 == '\0') {
+ fn = nfields;
+ for (;;) {
+ *fp++ = p;
+ fn--;
+ if (fn == 0)
+ break;
+ while ((c = *p++) != sepc)
+ if (c == '\0')
+ return(nfields - fn);
+ *(p-1) = '\0';
+ }
+ /* we have overflowed the fields vector -- just count them */
+ fn = nfields;
+ for (;;) {
+ while ((c = *p++) != sepc)
+ if (c == '\0')
+ return(fn);
+ fn++;
+ }
+ /* not reached */
+ }
+
+ /* two separators */
+ if (sep[2] == '\0') {
+ fn = nfields;
+ for (;;) {
+ *fp++ = p;
+ fn--;
+ while ((c = *p++) != sepc && c != sepc2)
+ if (c == '\0') {
+ if (trimtrail && **(fp-1) == '\0')
+ fn++;
+ return(nfields - fn);
+ }
+ if (fn == 0)
+ break;
+ *(p-1) = '\0';
+ while ((c = *p++) == sepc || c == sepc2)
+ continue;
+ p--;
+ }
+ /* we have overflowed the fields vector -- just count them */
+ fn = nfields;
+ while (c != '\0') {
+ while ((c = *p++) == sepc || c == sepc2)
+ continue;
+ p--;
+ fn++;
+ while ((c = *p++) != '\0' && c != sepc && c != sepc2)
+ continue;
+ }
+ /* might have to trim trailing white space */
+ if (trimtrail) {
+ p--;
+ while ((c = *--p) == sepc || c == sepc2)
+ continue;
+ p++;
+ if (*p != '\0') {
+ if (fn == nfields+1)
+ *p = '\0';
+ fn--;
+ }
+ }
+ return(fn);
+ }
+
+ /* n separators */
+ fn = 0;
+ for (;;) {
+ if (fn < nfields)
+ *fp++ = p;
+ fn++;
+ for (;;) {
+ c = *p++;
+ if (c == '\0')
+ return(fn);
+ sepp = sep;
+ while ((sepc = *sepp++) != '\0' && sepc != c)
+ continue;
+ if (sepc != '\0') /* it was a separator */
+ break;
+ }
+ if (fn < nfields)
+ *(p-1) = '\0';
+ for (;;) {
+ c = *p++;
+ sepp = sep;
+ while ((sepc = *sepp++) != '\0' && sepc != c)
+ continue;
+ if (sepc == '\0') /* it wasn't a separator */
+ break;
+ }
+ p--;
+ }
+
+ /* not reached */
+}
+
+#ifdef TEST_SPLIT
+
+
+/*
+ * test program
+ * pgm runs regression
+ * pgm sep splits stdin lines by sep
+ * pgm str sep splits str by sep
+ * pgm str sep n splits str by sep n times
+ */
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ char buf[512];
+ register int n;
+# define MNF 10
+ char *fields[MNF];
+
+ if (argc > 4)
+ for (n = atoi(argv[3]); n > 0; n--) {
+ (void) strcpy(buf, argv[1]);
+ }
+ else if (argc > 3)
+ for (n = atoi(argv[3]); n > 0; n--) {
+ (void) strcpy(buf, argv[1]);
+ (void) split(buf, fields, MNF, argv[2]);
+ }
+ else if (argc > 2)
+ dosplit(argv[1], argv[2]);
+ else if (argc > 1)
+ while (fgets(buf, sizeof(buf), stdin) != NULL) {
+ buf[strlen(buf)-1] = '\0'; /* stomp newline */
+ dosplit(buf, argv[1]);
+ }
+ else
+ regress();
+
+ exit(0);
+}
+
+dosplit(string, seps)
+char *string;
+char *seps;
+{
+# define NF 5
+ char *fields[NF];
+ register int nf;
+
+ nf = split(string, fields, NF, seps);
+ print(nf, NF, fields);
+}
+
+print(nf, nfp, fields)
+int nf;
+int nfp;
+char *fields[];
+{
+ register int fn;
+ register int bound;
+
+ bound = (nf > nfp) ? nfp : nf;
+ printf("%d:\t", nf);
+ for (fn = 0; fn < bound; fn++)
+ printf("\"%s\"%s", fields[fn], (fn+1 < nf) ? ", " : "\n");
+}
+
+#define RNF 5 /* some table entries know this */
+struct {
+ char *str;
+ char *seps;
+ int nf;
+ char *fi[RNF];
+} tests[] = {
+ "", " ", 0, { "" },
+ " ", " ", 2, { "", "" },
+ "x", " ", 1, { "x" },
+ "xy", " ", 1, { "xy" },
+ "x y", " ", 2, { "x", "y" },
+ "abc def g ", " ", 5, { "abc", "def", "", "g", "" },
+ " a bcd", " ", 4, { "", "", "a", "bcd" },
+ "a b c d e f", " ", 6, { "a", "b", "c", "d", "e f" },
+ " a b c d ", " ", 6, { "", "a", "b", "c", "d " },
+
+ "", " _", 0, { "" },
+ " ", " _", 2, { "", "" },
+ "x", " _", 1, { "x" },
+ "x y", " _", 2, { "x", "y" },
+ "ab _ cd", " _", 2, { "ab", "cd" },
+ " a_b c ", " _", 5, { "", "a", "b", "c", "" },
+ "a b c_d e f", " _", 6, { "a", "b", "c", "d", "e f" },
+ " a b c d ", " _", 6, { "", "a", "b", "c", "d " },
+
+ "", " _~", 0, { "" },
+ " ", " _~", 2, { "", "" },
+ "x", " _~", 1, { "x" },
+ "x y", " _~", 2, { "x", "y" },
+ "ab _~ cd", " _~", 2, { "ab", "cd" },
+ " a_b c~", " _~", 5, { "", "a", "b", "c", "" },
+ "a b_c d~e f", " _~", 6, { "a", "b", "c", "d", "e f" },
+ "~a b c d ", " _~", 6, { "", "a", "b", "c", "d " },
+
+ "", " _~-", 0, { "" },
+ " ", " _~-", 2, { "", "" },
+ "x", " _~-", 1, { "x" },
+ "x y", " _~-", 2, { "x", "y" },
+ "ab _~- cd", " _~-", 2, { "ab", "cd" },
+ " a_b c~", " _~-", 5, { "", "a", "b", "c", "" },
+ "a b_c-d~e f", " _~-", 6, { "a", "b", "c", "d", "e f" },
+ "~a-b c d ", " _~-", 6, { "", "a", "b", "c", "d " },
+
+ "", " ", 0, { "" },
+ " ", " ", 2, { "", "" },
+ "x", " ", 1, { "x" },
+ "xy", " ", 1, { "xy" },
+ "x y", " ", 2, { "x", "y" },
+ "abc def g ", " ", 4, { "abc", "def", "g", "" },
+ " a bcd", " ", 3, { "", "a", "bcd" },
+ "a b c d e f", " ", 6, { "a", "b", "c", "d", "e f" },
+ " a b c d ", " ", 6, { "", "a", "b", "c", "d " },
+
+ "", "", 0, { "" },
+ " ", "", 0, { "" },
+ "x", "", 1, { "x" },
+ "xy", "", 1, { "xy" },
+ "x y", "", 2, { "x", "y" },
+ "abc def g ", "", 3, { "abc", "def", "g" },
+ "\t a bcd", "", 2, { "a", "bcd" },
+ " a \tb\t c ", "", 3, { "a", "b", "c" },
+ "a b c d e ", "", 5, { "a", "b", "c", "d", "e" },
+ "a b\tc d e f", "", 6, { "a", "b", "c", "d", "e f" },
+ " a b c d e f ", "", 6, { "a", "b", "c", "d", "e f " },
+
+ NULL, NULL, 0, { NULL },
+};
+
+regress()
+{
+ char buf[512];
+ register int n;
+ char *fields[RNF+1];
+ register int nf;
+ register int i;
+ register int printit;
+ register char *f;
+
+ for (n = 0; tests[n].str != NULL; n++) {
+ (void) strcpy(buf, tests[n].str);
+ fields[RNF] = NULL;
+ nf = split(buf, fields, RNF, tests[n].seps);
+ printit = 0;
+ if (nf != tests[n].nf) {
+ printf("split `%s' by `%s' gave %d fields, not %d\n",
+ tests[n].str, tests[n].seps, nf, tests[n].nf);
+ printit = 1;
+ } else if (fields[RNF] != NULL) {
+ printf("split() went beyond array end\n");
+ printit = 1;
+ } else {
+ for (i = 0; i < nf && i < RNF; i++) {
+ f = fields[i];
+ if (f == NULL)
+ f = "(NULL)";
+ if (strcmp(f, tests[n].fi[i]) != 0) {
+ printf("split `%s' by `%s', field %d is `%s', not `%s'\n",
+ tests[n].str, tests[n].seps,
+ i, fields[i], tests[n].fi[i]);
+ printit = 1;
+ }
+ }
+ }
+ if (printit)
+ print(nf, RNF, fields);
+ }
+}
+#endif
--- /dev/null
+# regular expression test set
+# Lines are at least three fields, separated by one or more tabs. "" stands
+# for an empty field. First field is an RE. Second field is flags. If
+# C flag given, regcomp() is expected to fail, and the third field is the
+# error name (minus the leading REG_).
+#
+# Otherwise it is expected to succeed, and the third field is the string to
+# try matching it against. If there is no fourth field, the match is
+# expected to fail. If there is a fourth field, it is the substring that
+# the RE is expected to match. If there is a fifth field, it is a comma-
+# separated list of what the subexpressions should match, with - indicating
+# no match for that one. In both the fourth and fifth fields, a (sub)field
+# starting with @ indicates that the (sub)expression is expected to match
+# a null string followed by the stuff after the @; this provides a way to
+# test where null strings match. The character `N' in REs and strings
+# is newline, `S' is space, `T' is tab, `Z' is NUL.
+#
+# The full list of flags:
+# - placeholder, does nothing
+# b RE is a BRE, not an ERE
+# & try it as both an ERE and a BRE
+# C regcomp() error expected, third field is error name
+# i REG_ICASE
+# m ("mundane") REG_NOSPEC
+# s REG_NOSUB (not really testable)
+# n REG_NEWLINE
+# ^ REG_NOTBOL
+# $ REG_NOTEOL
+# # REG_STARTEND (see below)
+# p REG_PEND
+#
+# For REG_STARTEND, the start/end offsets are those of the substring
+# enclosed in ().
+
+# basics
+a & a a
+abc & abc abc
+abc|de - abc abc
+a|b|c - abc a
+
+# parentheses and perversions thereof
+a(b)c - abc abc
+a\(b\)c b abc abc
+a( C EPAREN
+a( b a( a(
+a\( - a( a(
+a\( bC EPAREN
+a\(b bC EPAREN
+a(b C EPAREN
+a(b b a(b a(b
+# gag me with a right parenthesis -- 1003.2 goofed here (my fault, partly)
+a) - a) a)
+) - ) )
+# end gagging (in a just world, those *should* give EPAREN)
+a) b a) a)
+a\) bC EPAREN
+\) bC EPAREN
+a()b - ab ab
+a\(\)b b ab ab
+
+# anchoring and REG_NEWLINE
+^abc$ & abc abc
+a^b - a^b
+a^b b a^b a^b
+a$b - a$b
+a$b b a$b a$b
+^ & abc @abc
+$ & abc @
+^$ & "" @
+$^ - "" @
+\($\)\(^\) b "" @
+# stop retching, those are legitimate (although disgusting)
+^^ - "" @
+$$ - "" @
+b$ & abNc
+b$ &n abNc b
+^b$ & aNbNc
+^b$ &n aNbNc b
+^$ &n aNNb @Nb
+^$ n abc
+^$ n abcN @
+$^ n aNNb @Nb
+\($\)\(^\) bn aNNb @Nb
+^^ n^ aNNb @Nb
+$$ n aNNb @NN
+^a ^ a
+a$ $ a
+^a ^n aNb
+^b ^n aNb b
+a$ $n bNa
+b$ $n bNa b
+a*(^b$)c* - b b
+a*\(^b$\)c* b b b
+
+# certain syntax errors and non-errors
+| C EMPTY
+| b | |
+* C BADRPT
+* b * *
++ C BADRPT
+? C BADRPT
+"" &C EMPTY
+() - abc @abc
+\(\) b abc @abc
+a||b C EMPTY
+|ab C EMPTY
+ab| C EMPTY
+(|a)b C EMPTY
+(a|)b C EMPTY
+(*a) C BADRPT
+(+a) C BADRPT
+(?a) C BADRPT
+({1}a) C BADRPT
+\(\{1\}a\) bC BADRPT
+(a|*b) C BADRPT
+(a|+b) C BADRPT
+(a|?b) C BADRPT
+(a|{1}b) C BADRPT
+^* C BADRPT
+^* b * *
+^+ C BADRPT
+^? C BADRPT
+^{1} C BADRPT
+^\{1\} bC BADRPT
+
+# metacharacters, backslashes
+a.c & abc abc
+a[bc]d & abd abd
+a\*c & a*c a*c
+a\\b & a\b a\b
+a\\\*b & a\*b a\*b
+a\bc & abc abc
+a\ &C EESCAPE
+a\\bc & a\bc a\bc
+\{ bC BADRPT
+a\[b & a[b a[b
+a[b &C EBRACK
+# trailing $ is a peculiar special case for the BRE code
+a$ & a a
+a$ & a$
+a\$ & a
+a\$ & a$ a$
+a\\$ & a
+a\\$ & a$
+a\\$ & a\$
+a\\$ & a\ a\
+
+# back references, ugh
+a\(b\)\2c bC ESUBREG
+a\(b\1\)c bC ESUBREG
+a\(b*\)c\1d b abbcbbd abbcbbd bb
+a\(b*\)c\1d b abbcbd
+a\(b*\)c\1d b abbcbbbd
+^\(.\)\1 b abc
+a\([bc]\)\1d b abcdabbd abbd b
+a\(\([bc]\)\2\)*d b abbccd abbccd
+a\(\([bc]\)\2\)*d b abbcbd
+# actually, this next one probably ought to fail, but the spec is unclear
+a\(\(b\)*\2\)*d b abbbd abbbd
+# here is a case that no NFA implementation does right
+\(ab*\)[ab]*\1 b ababaaa ababaaa a
+# check out normal matching in the presence of back refs
+\(a\)\1bcd b aabcd aabcd
+\(a\)\1bc*d b aabcd aabcd
+\(a\)\1bc*d b aabd aabd
+\(a\)\1bc*d b aabcccd aabcccd
+\(a\)\1bc*[ce]d b aabcccd aabcccd
+^\(a\)\1b\(c\)*cd$ b aabcccd aabcccd
+
+# ordinary repetitions
+ab*c & abc abc
+ab+c - abc abc
+ab?c - abc abc
+a\(*\)b b a*b a*b
+a\(**\)b b ab ab
+a\(***\)b bC BADRPT
+*a b *a *a
+**a b a a
+***a bC BADRPT
+
+# the dreaded bounded repetitions
+{ & { {
+{abc & {abc {abc
+{1 C BADRPT
+{1} C BADRPT
+a{b & a{b a{b
+a{1}b - ab ab
+a\{1\}b b ab ab
+a{1,}b - ab ab
+a\{1,\}b b ab ab
+a{1,2}b - aab aab
+a\{1,2\}b b aab aab
+a{1 C EBRACE
+a\{1 bC EBRACE
+a{1a C EBRACE
+a\{1a bC EBRACE
+a{1a} C BADBR
+a\{1a\} bC BADBR
+a{,2} - a{,2} a{,2}
+a\{,2\} bC BADBR
+a{,} - a{,} a{,}
+a\{,\} bC BADBR
+a{1,x} C BADBR
+a\{1,x\} bC BADBR
+a{1,x C EBRACE
+a\{1,x bC EBRACE
+a{300} C BADBR
+a\{300\} bC BADBR
+a{1,0} C BADBR
+a\{1,0\} bC BADBR
+ab{0,0}c - abcac ac
+ab\{0,0\}c b abcac ac
+ab{0,1}c - abcac abc
+ab\{0,1\}c b abcac abc
+ab{0,3}c - abbcac abbc
+ab\{0,3\}c b abbcac abbc
+ab{1,1}c - acabc abc
+ab\{1,1\}c b acabc abc
+ab{1,3}c - acabc abc
+ab\{1,3\}c b acabc abc
+ab{2,2}c - abcabbc abbc
+ab\{2,2\}c b abcabbc abbc
+ab{2,4}c - abcabbc abbc
+ab\{2,4\}c b abcabbc abbc
+((a{1,10}){1,10}){1,10} - a a a,a
+
+# multiple repetitions
+a** &C BADRPT
+a++ C BADRPT
+a?? C BADRPT
+a*+ C BADRPT
+a*? C BADRPT
+a+* C BADRPT
+a+? C BADRPT
+a?* C BADRPT
+a?+ C BADRPT
+a{1}{1} C BADRPT
+a*{1} C BADRPT
+a+{1} C BADRPT
+a?{1} C BADRPT
+a{1}* C BADRPT
+a{1}+ C BADRPT
+a{1}? C BADRPT
+a*{b} - a{b} a{b}
+a\{1\}\{1\} bC BADRPT
+a*\{1\} bC BADRPT
+a\{1\}* bC BADRPT
+
+# brackets, and numerous perversions thereof
+a[b]c & abc abc
+a[ab]c & abc abc
+a[^ab]c & adc adc
+a[]b]c & a]c a]c
+a[[b]c & a[c a[c
+a[-b]c & a-c a-c
+a[^]b]c & adc adc
+a[^-b]c & adc adc
+a[b-]c & a-c a-c
+a[b &C EBRACK
+a[] &C EBRACK
+a[1-3]c & a2c a2c
+a[3-1]c &C ERANGE
+a[1-3-5]c &C ERANGE
+a[[.-.]--]c & a-c a-c
+a[1- &C ERANGE
+a[[. &C EBRACK
+a[[.x &C EBRACK
+a[[.x. &C EBRACK
+a[[.x.] &C EBRACK
+a[[.x.]] & ax ax
+a[[.x,.]] &C ECOLLATE
+a[[.one.]]b & a1b a1b
+a[[.notdef.]]b &C ECOLLATE
+a[[.].]]b & a]b a]b
+a[[:alpha:]]c & abc abc
+a[[:notdef:]]c &C ECTYPE
+a[[: &C EBRACK
+a[[:alpha &C EBRACK
+a[[:alpha:] &C EBRACK
+a[[:alpha,:] &C ECTYPE
+a[[:]:]]b &C ECTYPE
+a[[:-:]]b &C ECTYPE
+a[[:alph:]] &C ECTYPE
+a[[:alphabet:]] &C ECTYPE
+[[:alnum:]]+ - -%@a0X- a0X
+[[:alpha:]]+ - -%@aX0- aX
+[[:blank:]]+ - aSSTb SST
+[[:cntrl:]]+ - aNTb NT
+[[:digit:]]+ - a019b 019
+[[:graph:]]+ - Sa%bS a%b
+[[:lower:]]+ - AabC ab
+[[:print:]]+ - NaSbN aSb
+[[:punct:]]+ - S%-&T %-&
+[[:space:]]+ - aSNTb SNT
+[[:upper:]]+ - aBCd BC
+[[:xdigit:]]+ - p0f3Cq 0f3C
+a[[=b=]]c & abc abc
+a[[= &C EBRACK
+a[[=b &C EBRACK
+a[[=b= &C EBRACK
+a[[=b=] &C EBRACK
+a[[=b,=]] &C ECOLLATE
+a[[=one=]]b & a1b a1b
+
+# complexities
+a(((b)))c - abc abc
+a(b|(c))d - abd abd
+a(b*|c)d - abbd abbd
+# just gotta have one DFA-buster, of course
+a[ab]{20} - aaaaabaaaabaaaabaaaab aaaaabaaaabaaaabaaaab
+# and an inline expansion in case somebody gets tricky
+a[ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab] - aaaaabaaaabaaaabaaaab aaaaabaaaabaaaabaaaab
+# and in case somebody just slips in an NFA...
+a[ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab](wee|week)(knights|night) - aaaaabaaaabaaaabaaaabweeknights aaaaabaaaabaaaabaaaabweeknights
+# fish for anomalies as the number of states passes 32
+12345678901234567890123456789 - a12345678901234567890123456789b 12345678901234567890123456789
+123456789012345678901234567890 - a123456789012345678901234567890b 123456789012345678901234567890
+1234567890123456789012345678901 - a1234567890123456789012345678901b 1234567890123456789012345678901
+12345678901234567890123456789012 - a12345678901234567890123456789012b 12345678901234567890123456789012
+123456789012345678901234567890123 - a123456789012345678901234567890123b 123456789012345678901234567890123
+# and one really big one, beyond any plausible word width
+1234567890123456789012345678901234567890123456789012345678901234567890 - a1234567890123456789012345678901234567890123456789012345678901234567890b 1234567890123456789012345678901234567890123456789012345678901234567890
+# fish for problems as brackets go past 8
+[ab][cd][ef][gh][ij][kl][mn] - xacegikmoq acegikm
+[ab][cd][ef][gh][ij][kl][mn][op] - xacegikmoq acegikmo
+[ab][cd][ef][gh][ij][kl][mn][op][qr] - xacegikmoqy acegikmoq
+[ab][cd][ef][gh][ij][kl][mn][op][q] - xacegikmoqy acegikmoq
+
+# subtleties of matching
+abc & xabcy abc
+a\(b\)?c\1d b acd
+aBc i Abc Abc
+a[Bc]*d i abBCcd abBCcd
+0[[:upper:]]1 &i 0a1 0a1
+0[[:lower:]]1 &i 0A1 0A1
+a[^b]c &i abc
+a[^b]c &i aBc
+a[^b]c &i adc adc
+[a]b[c] - abc abc
+[a]b[a] - aba aba
+[abc]b[abc] - abc abc
+[abc]b[abd] - abd abd
+a(b?c)+d - accd accd
+(wee|week)(knights|night) - weeknights weeknights
+(we|wee|week|frob)(knights|night|day) - weeknights weeknights
+a[bc]d - xyzaaabcaababdacd abd
+a[ab]c - aaabc abc
+abc s abc abc
+a* & b @b
+
+# Let's have some fun -- try to match a C comment.
+# first the obvious, which looks okay at first glance...
+/\*.*\*/ - /*x*/ /*x*/
+# but...
+/\*.*\*/ - /*x*/y/*z*/ /*x*/y/*z*/
+# okay, we must not match */ inside; try to do that...
+/\*([^*]|\*[^/])*\*/ - /*x*/ /*x*/
+/\*([^*]|\*[^/])*\*/ - /*x*/y/*z*/ /*x*/
+# but...
+/\*([^*]|\*[^/])*\*/ - /*x**/y/*z*/ /*x**/y/*z*/
+# and a still fancier version, which does it right (I think)...
+/\*([^*]|\*+[^*/])*\*+/ - /*x*/ /*x*/
+/\*([^*]|\*+[^*/])*\*+/ - /*x*/y/*z*/ /*x*/
+/\*([^*]|\*+[^*/])*\*+/ - /*x**/y/*z*/ /*x**/
+/\*([^*]|\*+[^*/])*\*+/ - /*x****/y/*z*/ /*x****/
+/\*([^*]|\*+[^*/])*\*+/ - /*x**x*/y/*z*/ /*x**x*/
+/\*([^*]|\*+[^*/])*\*+/ - /*x***x/y/*z*/ /*x***x/y/*z*/
+
+# subexpressions
+.* - abc abc -
+a(b)(c)d - abcd abcd b,c
+a(((b)))c - abc abc b,b,b
+a(b|(c))d - abd abd b,-
+a(b*|c|e)d - abbd abbd bb
+a(b*|c|e)d - acd acd c
+a(b*|c|e)d - ad ad @d
+a(b?)c - abc abc b
+a(b?)c - ac ac @c
+a(b+)c - abc abc b
+a(b+)c - abbbc abbbc bbb
+a(b*)c - ac ac @c
+(a|ab)(bc([de]+)f|cde) - abcdef abcdef a,bcdef,de
+# the regression tester only asks for 9 subexpressions
+a(b)(c)(d)(e)(f)(g)(h)(i)(j)k - abcdefghijk abcdefghijk b,c,d,e,f,g,h,i,j
+a(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)l - abcdefghijkl abcdefghijkl b,c,d,e,f,g,h,i,j,k
+a([bc]?)c - abc abc b
+a([bc]?)c - ac ac @c
+a([bc]+)c - abc abc b
+a([bc]+)c - abcc abcc bc
+a([bc]+)bc - abcbc abcbc bc
+a(bb+|b)b - abb abb b
+a(bbb+|bb+|b)b - abb abb b
+a(bbb+|bb+|b)b - abbb abbb bb
+a(bbb+|bb+|b)bb - abbb abbb b
+(.*).* - abcdef abcdef abcdef
+(a*)* - bc @b @b
+
+# do we get the right subexpression when it is used more than once?
+a(b|c)*d - ad ad -
+a(b|c)*d - abcd abcd c
+a(b|c)+d - abd abd b
+a(b|c)+d - abcd abcd c
+a(b|c?)+d - ad ad @d
+a(b|c?)+d - abcd abcd @d
+a(b|c){0,0}d - ad ad -
+a(b|c){0,1}d - ad ad -
+a(b|c){0,1}d - abd abd b
+a(b|c){0,2}d - ad ad -
+a(b|c){0,2}d - abcd abcd c
+a(b|c){0,}d - ad ad -
+a(b|c){0,}d - abcd abcd c
+a(b|c){1,1}d - abd abd b
+a(b|c){1,1}d - acd acd c
+a(b|c){1,2}d - abd abd b
+a(b|c){1,2}d - abcd abcd c
+a(b|c){1,}d - abd abd b
+a(b|c){1,}d - abcd abcd c
+a(b|c){2,2}d - acbd acbd b
+a(b|c){2,2}d - abcd abcd c
+a(b|c){2,4}d - abcd abcd c
+a(b|c){2,4}d - abcbd abcbd b
+a(b|c){2,4}d - abcbcd abcbcd c
+a(b|c){2,}d - abcd abcd c
+a(b|c){2,}d - abcbd abcbd b
+a(b+|((c)*))+d - abd abd @d,@d,-
+a(b+|((c)*))+d - abcd abcd @d,@d,-
+
+# check out the STARTEND option
+[abc] &# a(b)c b
+[abc] &# a(d)c
+[abc] &# a(bc)d b
+[abc] &# a(dc)d c
+. &# a()c
+b.*c &# b(bc)c bc
+b.* &# b(bc)c bc
+.*c &# b(bc)c bc
+
+# plain strings, with the NOSPEC flag
+abc m abc abc
+abc m xabcy abc
+abc m xyz
+a*b m aba*b a*b
+a*b m ab
+"" mC EMPTY
+
+# cases involving NULs
+aZb & a a
+aZb &p a
+aZb &p# (aZb) aZb
+aZ*b &p# (ab) ab
+a.b &# (aZb) aZb
+a.* &# (aZb)c aZb
+
+# word boundaries (ick)
+[[:<:]]a & a a
+[[:<:]]a & ba
+[[:<:]]a & -a a
+a[[:>:]] & a a
+a[[:>:]] & ab
+a[[:>:]] & a- a
+[[:<:]]a.c[[:>:]] & axcd-dayc-dazce-abc abc
+[[:<:]]a.c[[:>:]] & axcd-dayc-dazce-abc-q abc
+[[:<:]]a.c[[:>:]] & axc-dayc-dazce-abc axc
+[[:<:]]b.c[[:>:]] & a_bxc-byc_d-bzc-q bzc
+[[:<:]].x..[[:>:]] & y_xa_-_xb_y-_xc_-axdc _xc_
+[[:<:]]a_b[[:>:]] & x_a_b
+
+# past problems, and suspected problems
+(A[1])|(A[2])|(A[3])|(A[4])|(A[5])|(A[6])|(A[7])|(A[8])|(A[9])|(A[A]) - A1 A1
+abcdefghijklmnop i abcdefghijklmnop abcdefghijklmnop
+abcdefghijklmnopqrstuv i abcdefghijklmnopqrstuv abcdefghijklmnopqrstuv
+(ALAK)|(ALT[AB])|(CC[123]1)|(CM[123]1)|(GAMC)|(LC[23][EO ])|(SEM[1234])|(SL[ES][12])|(SLWW)|(SLF )|(SLDT)|(VWH[12])|(WH[34][EW])|(WP1[ESN]) - CC11 CC11
+CC[13]1|a{21}[23][EO][123][Es][12]a{15}aa[34][EW]aaaaaaa[X]a - CC11 CC11
+Char \([a-z0-9_]*\)\[.* b Char xyz[k Char xyz[k xyz
+a?b - ab ab
+-\{0,1\}[0-9]*$ b -5 -5
+a*a*a*a*a*a*a* & aaaaaa aaaaaa
--- /dev/null
+/* utility definitions */
+#ifdef _POSIX2_RE_DUP_MAX
+#define DUPMAX _POSIX2_RE_DUP_MAX
+#else
+#define DUPMAX 255
+#endif
+#define INFINITY (DUPMAX + 1)
+#define NC (CHAR_MAX - CHAR_MIN + 1)
+typedef unsigned char uch;
+
+/* switch off assertions (if not already off) if no REDEBUG */
+#ifndef REDEBUG
+#ifndef NDEBUG
+#define NDEBUG /* no assertions please */
+#endif
+#endif
+#include <assert.h>
+
+/* for old systems with bcopy() but no memmove() */
+#ifdef USEBCOPY
+#define memmove(d, s, c) bcopy(s, d, c)
+#endif