Benutzer-Werkzeuge

Webseiten-Werkzeuge


prt_progs

Programme für die Verarbeitung von Drucklisten und Kartenstapeln

In den letzten Jahren habe ich den Austausch von Kartenstapeln und Drucklisten v.a. über eMail realisiert. Inzwischen erscheint das eher unsinnig. Der derzeitige Ansatz ist der, Drucklisten und Magnetbänder über html zum Download anzubieten und Möglichkeiten des Upload von Kartenstapeln und Magnetbändern zu realisieren. Als Web Plattform wird DokuWiki genutzt. In dieses System einschließlich seiner Medienverwaltung sind die folgenden Funktionen eingepasst.

Drucklisten

Drucklisten aus dem Mainframe Betriebssystem sind in zwei Hinsichten schwierig.

  1. sind sie für den Hercules Emulator einfache PC Dateien. Eine Segmentierung nach Batches oder Jobs erfolgt nicht. Man könnte dies durch Bedienkommandos realisieren, braucht dafür aber erhebliche administrative Rechte für einfache Benutzer. In Anlehnung an ein Programm von Tim Pinkawa für MVS Drucklistendateien gibt es hier das Programm prtspool aus dem Paket PDFlib-Lite-7.0.5p3, mit dem die Aufteilung in eine Datei pro Batch erfolgt. Das Programm wird als Pipe mit dem Drucker 00E verbunden.
  2. haben die Drucklisten ein etwas seltsames Format (Druckbreite, Steuerzeichen usw.). Das Programm text2pdf konvertiert die Drucklisten in eine normale PDF Datei, wobei das Übereinanderdrucken von Zeilen mit unterstützt wird („hübsche“ Bildchen in EBCDIC Art usw.)

In der aktuellen Hercules Konfiguration wird mit

000E	1403	"|/usr/local/bin/prtspool ./spool /usr/local/bin/savepdf nosep"

erreicht, dass alle Drucklisten separiert und als getrennte PDF Dateien im Spool Verzeichnis abgelegt werden. Ein Link im Wiki Verzeichnis ermöglicht die Ansicht und das Herunterladen der Listen im Browser über Ablage für Drucklisten in der sidebar bzw. hier.

Programm prtspool

Das Programm ist im Original von Tim Pinkawa und hat die Aufgabe einen Drucklisten-Stream zu separieren. In der hier veränderten Form erwartet das Programm die Standard Separatorseiten des DOS-5/ES. Es ruft bei entsprechender Parameterisierung für jedes der Segmente, die zunächst nach /tmp gespeichert werden, ein Programm auf, welches die Weiterverarbeitung bzw. das Abspeichern an einem gewünschten Ort übernimmt. Zu gegebenen Zeitpunkt könnte für das unter VM/DOS laufende SVS 7.2 ebenfalls ein Direktdrucker eingerichtet werden, bei dem dann die originale Segmentierung benutzt werden sollte.

#include <stdio.h>
#include <string.h>

/* prtspool by Tim Pinkawa (http://timpinkawa.net/hercules)
 * Written in December 2006, released in June 2007
 */

int main(int argc, char* argv[])
{
  if(argc != 3 && argc != 4)
  {
	  printf("prtspool - a simple print spooler for emulated 1403 printers\n");
	  printf("By Tim Pinkawa (http://www.timpinkawa.net/hercules)\n\n");
	  printf("usage: %s {output_directory} [command]\n", argv[0]);
	  return 0;
  }
  char batchname[9];
  char batchtime[15];
  char tmpFile [L_tmpnam];
  char cmd[225] = " ";
  char path[250];
  char jobEnd1[] = "*** DOS-50.50/CS";
  char jobEnd2[] = " E N D ";
  char line[200];
  char ss[200];
  
  int job = 1;
  while(!feof(stdin))
  {
    int endCount = 0;
    fgets(line, 200, stdin);
    if(strcmp(line, "\f") == 0)
      break;
	 
    int i;
    for(i = 1; i < 200; i++)
      ss[i - 1] = line[i];

    FILE* jobfp;
    tmpnam (tmpFile);
    jobfp = fopen(tmpFile, "w");

    /*fprintf(jobfp, ss);*/
    fputs(ss, jobfp);
    int endOfJob = 0;
    while(!endOfJob && !feof(stdin))
    {
      fgets(line, 200, stdin);
      if( (strstr(line, jobEnd1) != NULL) && (strstr(line, jobEnd2) != NULL) )
        {
        endCount++;
        }
      if(endCount == 10)
        {
        endOfJob = 1;
        /* Einsammeln Batchname und Zeit */
        strncpy(batchname, line+59, 8);
        batchname[8]='\0';
        for (i = 0; i < 8; i++)
	{
		if (batchname[i] == ' ')
		{
			batchname[i] = '\0';
		}
	}
        int i=0;
        while (batchname[i])
        {
           batchname[i]=tolower(batchname[i]);
           i++;
        }
        batchtime[0] = line[106];
        batchtime[1] = line[107];
        batchtime[2] = line[103];
        batchtime[3] = line[104];
        batchtime[4] = line[100];
        batchtime[5] = line[101];
        batchtime[6] = '_';
        batchtime[7] = line[110];
        batchtime[8] = line[111];
        batchtime[9] = line[113];
        batchtime[10] = line[114];
        batchtime[11] = line[116];
        batchtime[12] = line[117];
        batchtime[13] = '\0';
        }
      fputs(line, jobfp);
      /*fprintf(jobfp, line);*/
    }
    fclose(jobfp);

 
   if(argc == 3)
       {
       snprintf(cmd, 225, "%s %s/%s_%s.pdf %s\n", argv[2], argv[1], batchtime, batchname, tmpFile);
       /*printf(cmd);*/
       system(cmd);
       cmd[0] = '\0';
       remove(tmpFile);
       fgets(line, 200, stdin);
       fgets(line, 200, stdin);
       fgets(line, 200, stdin);
       }

    job++;
  }
}

Entfernen der Separatorseiten

Nach dem Separieren und vor der Umwandlung in PDF werden die Separatorseiten mit dem folgenden Einzeiler im Script savepdf entfernt, sofern beim Aufruf nosep als zweiter Parameter übergeben wird.

sed "s/\x0C/\x0A\x0C\x0A/"|sed "1,/\x0C/d"|tac|sed "1,/\x0C/d"|tac|sed "s/\x0A\x0C/\x0C/"

Programm text2pdf

Das Programm wandelt eine Datei aus einem Textformat mit diversen Steuerzeichen in eine PDF Datei. Das Original liest zeilenweise bis jeweils Zeilenumbruch. Dies ist für Drucklisten mit übereinandergedruckten Zeilen (Unterschied zwischen CR und LF) nicht ok. Deswegen ist das Programm auf zeichenweise Verarbeitung umgestellt. Gleichzeitig sind die Font Parameter auf sinnvolle Standards angepasst.
[roman]Beim Übereinanderdrucken gleicher Zeichen werden diese (noch) nicht fett dargestellt. Dafür müsste jede Überdruckzeile um 1-2 Pixel in der Höhe oder Breite verschoben werden.
Vor dem Compilieren muss zunächst einmal das komplette Paket mit

./configure
make

vorbereitet werden, weil sonst die Bibliotheken nicht aufgebaut werden.

/*---------------------------------------------------------------------------*
 |              PDFlib - A library for generating PDF on the fly             |
 +---------------------------------------------------------------------------+
 | Copyright (c) 1997-2005 Thomas Merz and PDFlib GmbH. All rights reserved. |
 +---------------------------------------------------------------------------+
 |                                                                           |
 |    This software is subject to the PDFlib license. It is NOT in the       |
 |    public domain. Extended versions and commercial licenses are           |
 |    available, please check http://www.pdflib.com.                         |
 |                                                                           |
 *---------------------------------------------------------------------------*/
 
/* $Id: text2pdf.c,v 1.13 2005/06/08 21:03:44 tm Exp $
 * 
 * Convert text files to PDF
 *
 */
 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
 
#if defined(__CYGWIN32__)
#include <getopt.h>
#elif defined(WIN32)
int getopt(int argc, char * const argv[], const char *optstring);
extern char *optarg;
extern int optind;
#elif !defined(WIN32) && !defined(MAC)
#include <unistd.h>
#endif
 
 
#ifdef WIN32
#include <process.h>
#endif
 
#ifdef NeXT
#include <libc.h>	/* for getopt(), optind, optarg */
#endif
 
#ifdef __CYGWIN32__
#include <getopt.h>	/* for getopt(), optind, optarg */
#endif
 
#if defined WIN32 || defined __DJGPP__ || \
    defined __OS2__ || defined __IBMC__ || defined __IBMCPP__ || \
    defined __POWERPC__ || defined __CFM68K__ || defined __MC68K__ || \
    defined AS400 || defined __ILEC400__
 
#define READMODE	"rb"
 
#else
 
#define READMODE	"r"
 
#endif	/* Mac, Windows, and OS/2 platforms */
 
/* figure out whether or not we're running on an EBCDIC-based machine */
#define ASCII_A                 0x41
#define PLATFORM_A              'A'
#define EBCDIC_BRACKET          0x4A
#define PLATFORM_BRACKET        '['
 
#if (ASCII_A != PLATFORM_A && EBCDIC_BRACKET == PLATFORM_BRACKET)
#define PDFLIB_EBCDIC
#endif
 
#include "pdflib.h"
 
static void
usage(void)
{
    fprintf(stderr, "text2pdf - convert text files to PDF.\n");
    fprintf(stderr,
    "(c) PDFlib GmbH and Thomas Merz 1997-2005 www.pdflib.com\n\n");
    fprintf(stderr, "usage: text2pdf [options] [textfile]\n");
    fprintf(stderr, "Available options:\n");
    fprintf(stderr,
    "-e encoding   font encoding to use. Common encoding names:\n");
    fprintf(stderr,
    "              winansi, macroman, ebcdic, or user-defined\n");
    fprintf(stderr, "              host = default encoding of this platform\n");
    fprintf(stderr, "-f fontname   name of font to use\n");
    fprintf(stderr, "-h height     page height in points\n");
    fprintf(stderr, "-m margin     margin size in points\n");
    fprintf(stderr, "-o filename   PDF output file name\n");
    fprintf(stderr, "-s size       font size\n");
    fprintf(stderr, "-w width      page width in points\n");
 
    exit(1);
}
 
#define BUFLEN 		512
 
int
main(int argc, char *argv[])
{
    char	buf[BUFLEN], *s;
    char	*pdffilename = NULL;
    FILE	*textfile = stdin;
    PDF		*p;
    int		opt;
    int		font;
    char	*fontname, *encoding;
    double	fontsize, fontwidth;
    double	x, y, z, width = a4_width, height = a4_height, margin = 20;
    char	ff, nl, cr;
    int		c;
    int		tof;
    int		verbosity;
 
    fontname	= "Courier";
    fontsize	= 7;
    fontwidth	= 4.2;
    encoding	= "host";
    nl		= '\n';
    ff		= '\f';
    cr		= '\r';
    verbosity	= 0;
 
    while ((opt = getopt(argc, argv, "e:f:h:m:o:s:w:v")) != -1)
    switch (opt) {
	case 'v':
	verbosity = 1;
	break;
 
        case 'e':
	encoding = optarg;
	break;
 
        case 'f':
	fontname = optarg;
	break;
 
        case 'h':
	height = atof(optarg);
	if (height < 0) {
	    fprintf(stderr, "Error: bad page height %f!\n", height);
	    usage();
	}
	break;
 
        case 'm':
	margin = atof(optarg);
	if (margin < 0) {
	    fprintf(stderr, "Error: bad margin %f!\n", margin);
	    usage();
	}
	break;
 
        case 'o':
	pdffilename = optarg;
	break;
 
        case 's':
	fontsize = atof(optarg);
	if (fontsize < 0) {
	    fprintf(stderr, "Error: bad font size %f!\n", fontsize);
	    usage();
	}
	break;
 
        case 'w':
	width = atof(optarg);
	if (width < 0) {
	    fprintf(stderr, "Error: bad page width %f!\n", width);
	    usage();
	}
	break;
 
        case '?':
        default:
	usage();
    }
 
    if (!strcmp(encoding, "ebcdic")) {
    /* form feed is 0x0C in both ASCII and EBCDIC */
    nl = 0x15;
    }
 
    if (pdffilename == NULL)
    usage();
 
    if (optind < argc) {
    if ((textfile = fopen(argv[optind], READMODE)) == NULL) {
        fprintf(stderr, "Error: cannot open input file %s.\n",argv[optind]);
        exit(2);
    }
    } else
    textfile = stdin;
 
    p = PDF_new();
    if (p == NULL) {
    fprintf(stderr, "Error: cannot open output file %s.\n", pdffilename);
    exit(1);
    }
 
    PDF_begin_document(p, pdffilename, 0, "");
    tof = 1; /* top of form*/
    PDF_set_info(p, "Title", "Converted text");
    PDF_set_info(p, "Creator", "text2pdf");
    if ( verbosity == 1) fprintf(stderr, "s-doc\n");
    x = margin;
    y = height - margin;
    z = 0;
    s = &buf;
 
    while ((c = fgetc(textfile)) != EOF)
    {
    if (c == ff) {
	if ( verbosity == 1) fprintf(stderr, "ff\n");
        if (tof == 1) {
        if ( verbosity == 1) fprintf(stderr, "ff-begin-page\n");
	PDF_begin_page_ext(p, width, height, "");
	}
        PDF_end_page_ext(p, "");
	tof = 1;
        y = height - margin;
        z = 0;
        continue;
    }
    if (y < margin) {		/* page break necessary? */
        y = height - margin;
        z = 0;
        PDF_end_page_ext(p, "");
        tof = 1;
    }
    if ((tof == 1)){
        if ( verbosity == 1) fprintf(stderr, "tof\n");
        PDF_begin_page_ext(p, width, height, "");
        font = PDF_load_font(p, fontname, 0, encoding, "");
        PDF_setfont(p, font, fontsize);
        tof = 0;
    }
    if (c == nl) {
        if ( verbosity == 1) fprintf(stderr, "\n");
        y -= fontsize;
        z = 0;
        continue;
    }
    if (c == cr) {
        z = 0;
        continue;
    }
    s[0] = c;
    s[1] = '\0';
    if ( verbosity == 1) fprintf(stderr, "%c", c);
    PDF_set_text_pos(p, x+z, y);
    PDF_continue_text(p, s);
    z += fontwidth;
    tof = 0;
    }
    if (tof == 0) {
    PDF_end_page_ext(p, "");
    }
 
    PDF_end_document(p, "");
    PDF_delete(p);
 
    exit(0);
}

Prozedur savepdf

/usr/local/bin/savepdf
#!/bin/bash
if [ "$3" == "nosep" ]; then
#cat $2|sed "s/\x0C/\x0C\x0A/"|sed "1,/\x0C/d"|tac|sed "1,/\x0c/d"|tac|/usr/local/bin/text2pdf -o $1.pdf
cat $2|sed "s/\x0C/\x0A\x0C\x0A/"|sed "1,/\x0C/d"|tac|sed "1,/\x0C/d"|tac|sed "s/\x0A\x0C/\x0C/"|/usr/local/bin/text2pdf -o $1.pdf
else
/usr/local/bin/text2pdf -o $1.pdf $2
fi

Kartenstapel

Definition des Kartenlesers

In der Hercules Konfiguration wird der Kartenleser als Socket Device definiert. Es ist eingestellt, dass alle Zeichen in Großbuchstaben gewandelt,abgeschnitten bzw. rechtsbündig mit Leerzeichen auf 80 Zeichen aufgefüllt und von ASCII nach EBCDIC übersetzt werden. Der Kartenleser 00A wird an das OS durchgereicht, der Leser 00C ist im DOS gestartet. Wegen der unterschiedlichen Behandlung in den beiden Systemen werden die Stapel zum DOS mit EOF beendet, die zum OS mit Intervention Required.

000A	3505	1442 sockdev ascii ucase trunc
000C	3505	2501 sockdev ascii ucase trunc eof

Hilfsfunktion für das Submit von Kartenstapeln, die im Spool Verzeichnis stehen

Das Bash Script wird als Cron Job jede Minute gestartet. Es sucht nach Dateien die vor mehr als einer Minute das letzte Mal geändert wurden und der Namenskonvention entsprechen. Wird eine solche Datei gefunden, dann wird sie mit dem Hilfsprogramm Netcat an den Socket des Kartenlesers übertragen. Dabei werden .bch Dateien an das DOS-5, .job Dateien an das SVS gesendet.

#! /bin/bash
find /var/www/wiki/data/media/spool/ -name "*.bch" -amin +1 -exec bash -c "nc -v -q 0 127.0.0.1 2501 < {} && rm {}" \;
find /var/www/wiki/data/media/spool/ -name "*.job" -amin +1 -exec bash -c "nc -v -q 0 127.0.0.1 1442 < {} && rm {}" \;

Kartenstanzer

Das Stanzen von Karten ist eigentlich eine ideale Möglichkeit, speziell Programme und Batches aus dem DOS-5 ins Wirtssystem zu übertragen. Problematisch ist, dass die Separation der einzelnen Stapel durch Trennkarten mit Blockbuchstaben erfolgte. Erstens stellt der virtuelle Puncher im Hercules kein binäres Stanzen bereit und zweitens wäre es schwierig, diese Karten dann fruchtbringend auszuwerten.
Ein Ansatz ist, einen Drucker als Stanzer zu starten:

S cuu PUN

Wird dort JSEP=1 in der SPOOL Anweisung angegeben, wird die normale Separatorseite mit der Information PUN FROM ausgedruckt. Diese ließe sich wieder analog durch PRTSPOOL auswerten. Das Script /usr/local/bin/savepun entfernt die Separatorseiten und kopiert die Datei aus Parameter 2 in das Verzeichnis, welches im Parameter 1 angegeben ist. Kurze Erläuterung:

#!/bin/bash
cat $2|sed "s/\x0C/\x0C\x0A/"|sed "1,/\x0C/d"|tac|sed "1,/\x0c/d"|tac>$1
prt_progs.txt · Zuletzt geändert: 2017/01/22 19:07 von roman