Removed some compiler warnings by casting the buffer properly
[infodrom/dtaus] / dtaus.c
1 /*
2     dtaus.c - Belegloser Datenträgeraustausch mit einer Bank
3     Copyright (c) 1996,8,2001,2,3  Martin Schulze <joey@infodrom.org>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
18
19     $Id$
20  */
21
22 #include "dtaus.h"
23 #include "bigint.h"
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <ctype.h>
28 #include <time.h>
29 #include <malloc.h>
30
31 #define DEFAULT_EURO
32 #ifndef DEFAULT_EURO
33 int use_euro = 0;
34 #else
35 int use_euro = 1;
36 #endif
37
38 /*
39  *  First: Some control structures
40  */
41
42 typedef struct
43 {
44   char *name;
45   unsigned short int pos;
46   unsigned short int len;
47   int type;
48 } dtaus_record;
49
50 #define REC_A   1
51 #define REC_C   2
52 #define REC_E   3
53
54 #define REQ     1
55 #define OPT     2
56 #define IGN     3
57
58 dtaus_record recA[] = {
59   {"Art", 5, 2, REQ},
60   {"Name", 23, 27, REQ},
61   {"Konto", 60, 10, REQ},
62   {"BLZ", 7, 8, REQ},
63   {"Referenz", 70, 10, OPT},
64   {"Datum", 50, 6, IGN},
65   {"Ausfuehrung", 95, 8, OPT},
66   {"Currency", 127, 1, OPT},
67   {"Euro", 127, 1, OPT},
68   {"DM", 127, 1, OPT},
69   {NULL, 0, 0}
70 };
71
72 #define A_TRANS 0
73 #define A_NAME  1
74 #define A_KTO   2
75 #define A_BLZ   3
76 #define A_REF   4
77 #define A_DATE  5
78 #define A_TODO  6
79 #define A_CURR  7
80 #define A_EURO  8
81 #define A_DM    9
82 #define A_LEN   10
83 #define A_LOOP  7
84
85 dtaus_record recC[] = {
86   {"Name", 93, 27, REQ},
87   {"Konto", 21, 10, REQ},
88   {"BLZ", 13, 8, REQ},
89   {"Transaktion", 44, 5, REQ},
90 #ifndef DEFAULT_EURO
91   {"Betrag", 50, 11, REQ},
92 #else
93   {"Betrag", 79, 11, REQ},
94 #endif
95   {"Zweck", 155, 27, REQ},
96   {"myName", 128, 27, OPT},
97   {"myKonto", 69, 10, OPT},
98   {"myBLZ", 61, 8, OPT},
99   {"Text", 187, 29, OPT},
100   {"Extension", 216, 29, OPT},
101   {"Currency", 182, 1, IGN},
102 #ifndef DEFAULT_EURO
103   {"Betrag-Euro", 79, 11, IGN},
104 #else
105   {"Betrag-DM", 50, 11, IGN},
106 #endif
107   {NULL, 0, 0}
108 };
109
110 #define C_NAME  0
111 #define C_KTO   1
112 #define C_BLZ   2
113 #define C_TRANS 3
114 #define C_VAL   4
115 #define C_ZWECK 5
116 #define C_MYNAM 6
117 #define C_MYKTO 7
118 #define C_MYBLZ 8
119 #define C_TEXT  9
120 #define C_EXT  10
121 #define C_EURO 11
122 #ifndef DEFAULT_EURO
123 #define C_EUR  12
124 #else
125 #define C_DM   12
126 #endif
127 #define C_LEN  13
128 #define C_LOOP 11
129
130 #define MAX_TEXT 14
131
132 dtaus_record recE[] = {
133   {"Anzahl", 10, 7, IGN},
134 #ifndef DEFAULT_EURO
135   {"Summe", 17, 13, IGN},
136 #else
137   {"Summe", 64, 13, IGN},
138 #endif
139   {"Kontos", 30, 17, IGN},
140   {"BLZs", 47, 17, IGN},
141 #ifndef DEFAULT_EURO
142   {"Summe-Euro", 64, 13, IGN},
143 #else
144   {"Summe-DM", 17, 13, IGN},
145 #endif
146   {NULL, 0, 0}
147 };
148
149 #define E_COUNT 0
150 #define E_VAL   1
151 #define E_KTO   2
152 #define E_BLZ   3
153 #ifndef DEFAULT_EURO
154 #define E_EUR   4
155 #else
156 #define E_DM    4
157 #endif
158 #define E_LEN   5
159
160 /*
161  *  Second: Some low level routines
162  */
163
164 size_t dtaus_nextrec (void **buf, FILE *f)
165 {
166   memset (buf, 0, 128);
167   return fread(buf, 128, 1, f);
168 }
169
170 char *upcase(char *s)
171 {
172   static char x[100];
173   static char *xp;
174   char *cp;
175
176   for (cp=s,xp=x; *cp; cp++,xp++) {
177     if (strchr(" 0123456789.,&-/+*$%ABCDEFGHIJKLMNOPQRSTUVWXYZ",*cp)) {
178         *xp = *cp;
179     } else if (strchr("abcdefghijklmnopqrstuvwxyz",*cp)) {
180       *xp = toupper(*cp);
181     } else if (strchr ("üÜäÄöÖß", *cp)) {
182       switch (*cp) {
183       case 'ü': *(xp++) = 'U'; *xp='E'; break;
184       case 'Ü': *(xp++) = 'U'; *xp='E'; break;
185       case 'ä': *(xp++) = 'A'; *xp='E'; break;
186       case 'Ä': *(xp++) = 'A'; *xp='E'; break;
187       case 'ö': *(xp++) = 'O'; *xp='E'; break;
188       case 'Ö': *(xp++) = 'O'; *xp='E'; break;
189       case 'ß': *(xp++) = 'S'; *xp='S'; break;
190       }
191     } else
192       /*
193        * Filter out all other characters since credit institutes won't
194        * accept the file otherwise.
195        */
196       *xp = ' ';
197   }
198   *xp = '\0';
199
200   return x;
201 }
202
203 char *downcase(char *s)
204 {
205   static char x[100];
206   char *cp;
207
208   memset (x, 0, sizeof (x));
209   strncpy (x, s, 99);
210   
211   for (cp=x;*cp;cp++)
212     if (isupper(*cp))
213       *cp = tolower(*cp);
214   return x;
215 }
216
217 char *strip_spaces (char *s)
218 {
219   int i;
220   char *p;
221
222   for (i=strlen(s);(s[i-1] == ' '||s[i-1] == '\t')&&i>0; i--)
223     s[i-1] = '\0';
224   for (p=s; *p==' '; p++);
225   return p;
226 }
227
228 char *strip_zeros (char *s)
229 {
230   char *p;
231
232   for (p=s; *p=='0'; p++);
233   return p;
234 }
235
236 char *strip_nondigits (char *s)
237 {
238   char *p;
239   char *x;
240
241   for (x=s,p=s;*x;x++)
242     if (isdigit (*x))
243       *(p++) = *x;
244   *(p++) = '\0';
245
246   return s;
247 }
248
249 char dtaus_char (void *buf, unsigned int pos)
250 {
251   static char res;
252   char *bufp = (char *)buf;
253
254   bufp+=pos;
255   memcpy(&res, bufp, 1);
256   return res;
257 }
258
259 char *string2real(char *s)
260 {
261   static char res[20];
262   char *cp = s;
263
264   cp+=strlen(s)-2;
265   strncpy(res, s, strlen(s)-2);
266   res[strlen(s)-2] = '.';
267   res[strlen(s)-1] = s[strlen(s)-2];
268   res[strlen(s)] = s[strlen(s)-1];
269   return res;
270 }
271
272 char *real2string(char *s)
273 {
274   static char res[20];
275   char *cp;
276
277   strncpy(res, s, sizeof(res)-1);
278   res[sizeof(res)-1] = 0;
279   for (cp=res; *cp&&!(*cp == ',')&&!(*cp == '.');cp++);
280
281   if ((cp-res) >= (sizeof(res)-3)) { 
282     /* Bail out, since the number is too large, shouldn't be possible though. */
283     fprintf (stderr, "Value %s too large.\n", res);
284     exit (1);
285   }
286
287   if (*cp == '.' || *cp == ',') {
288     if (*(cp+1)) {
289       /* 1st decimal place */
290       if (isdigit(*(cp+1)))
291         *(cp++) = *(cp+1);
292       else
293         *(cp++) = '0';
294       /* 2nd decimal place */
295       if (*(cp+1) && isdigit(*(cp+1)))
296         *(cp++) = *(cp+1);
297       else
298         *(cp++) = '0';
299     } else {
300       *(cp++) = '0';
301       *(cp++) = '0';
302     }
303   } else {
304     *(cp++) = '0';
305     *(cp++) = '0';
306   }
307   *cp = '\0';
308   return res;
309 }
310
311 char *string2trans (char *s)
312 {
313   static char res[30];
314
315   res[0] = '\0';
316   if (!strcmp(s, "04000"))
317     sprintf (res, "Abbuchung");
318   else if (!strcmp(s, "05000"))
319     sprintf (res, "Einzug");
320   else if (!strcmp(s, "05005"))
321     sprintf (res, "E-Cash");
322   else if (!strcmp(s, "05006"))
323     sprintf (res, "E-Cash-A");
324   else if (!strcmp(s, "51000"))
325     sprintf (res, "Gutschrift");
326   else if (!strcmp(s, "53000"))
327     sprintf (res, "Lohn");
328   else if (!strncmp(s, "5400", 4))
329     sprintf (res, "Vermögen");
330   /*  else if (!strcmp(s, "56000"))
331     sprintf (res, ""); / * Überweisung öffentlicher Kassen */
332   return res;
333 }
334
335 char *trans2string (char *s)
336 {
337   static char res[30];
338
339   res[0] = '\0';
340   if (!strcmp(s, "Abbuchung"))
341     sprintf (res, "04000");
342   else if (!strcmp(s, "Einzug"))
343     sprintf (res, "05000");
344   else if (!strcmp(s, "E-Cash"))
345     sprintf (res, "05005");
346   else if (!strcmp(s, "E-Cash-A"))
347     sprintf (res, "05006");
348   else if (!strcmp(s, "Gutschrift"))
349     sprintf (res, "51000");
350   else if (!strcmp(s, "Lohn"))
351     sprintf (res, "53000");
352   else if (!strncmp(s, "Vermögen", 4))
353     sprintf (res, "5400");
354   /*  else if (!strcmp(s, ""))
355     sprintf (res, "56000"); / * Überweisung öffentlicher Kassen */
356   return res;
357 }
358
359 char *string2ext (char *s)
360 {
361   static char res[30];
362
363   res[0] = '\0';
364   if (!strcmp(s, "01"))
365     sprintf (res, "Kunde");
366   else if (!strcmp(s, "02"))
367     sprintf (res, "Text");
368   else if (!strcmp(s, "03"))
369     sprintf (res, "Auftraggeber");
370   return res;
371 }
372
373 char *ext2string (char *s)
374 {
375   static char res[3];
376
377   res[0] = '\0';
378   if (!strcmp(s, "Kunde"))
379     sprintf (res, "01");
380   else if (!strcmp(s, "Text"))
381     sprintf (res, "02");
382   else if (!strcmp(s, "Auftraggeber"))
383     sprintf (res, "03");
384   return res;
385 }
386     
387 unsigned long int dtaus_int(void *buf, unsigned int pos, unsigned int len)
388 {
389   char tmp[30];
390   char *bufp = (char *)buf;
391   static unsigned long int res;
392
393   bufp+=pos;
394   memcpy(tmp, bufp, len);
395   tmp[len] = '\0';
396   sscanf(tmp, "%lu", &res);
397   return res;
398 }
399
400 /*
401  * returns the first word in this line, returns it and shortens the
402  * line.
403  */
404 char *extract_ident (char *line)
405 {
406   char *c, *x, *y;
407   static char word[30];
408
409   if (strlen(line) > 0) {
410     x = strchr (line, ' ');
411     y = strchr (line, '\t');
412
413     if (!x && !y) {
414         strncpy(word, line, 29);
415         line[0] = '\0';
416         return word;
417     }
418
419     /* Check which index returns the lower value, and check if the
420        value is non-NULL */
421     if ((c = (x && x<y)?x:(y?y:x))) { 
422       strncpy(word, line, c - line);
423       word[c-line] = '\0';
424       for (;*c == '\t' || *c == ' '; c++);
425       for (x=line; *c; c++,x++)
426         *x = *c;
427       *x = '\0';
428       strcpy(word, downcase(word));
429       return word;
430     }
431     return NULL;
432   }
433   return line;
434 }
435
436 /*
437  * Pads a string with zero's on the left side.
438  */
439 char *padzeroclip (char *s, int len)
440 {
441   char *p, *q;
442
443   if (strlen(s) == len) return s;
444   if (strlen(s) > len) {
445       q=s+len;
446       *(q--) = '\0';
447       return s;
448   }
449
450   q=s+len;
451   *(q--) = '\0';
452   for (p=s+strlen(s)-1;p>=s;p--)
453     *(q--)=*p;
454   for (;q>=s;) *(q--)='0';
455   return s;
456 }
457
458 int rec_index(char *ident, int type)
459 {
460   int i;
461   dtaus_record *rec = NULL;
462
463   switch (type) {
464   case REC_A:   rec = recA; break;
465   case REC_C:   rec = recC; break;
466   case REC_E:   rec = recE; break;
467   }
468
469   for (i=0; (rec[i].name); i++) {
470     if (!strcmp(ident, downcase(rec[i].name)))
471       return i;
472   }
473
474   return -1;
475 }
476
477 size_t control_nextline (void **buf, int len, FILE *f)
478 {
479   char line[100];
480   char tmp[100];
481   char *cp;
482   int i;
483
484   memset (line, 0, sizeof(line));
485   memset (buf, 0, len);
486   cp = line;
487
488   while (!strlen(line) && (cp = fgets(line, 100, f))) {
489     if (strlen(line)) {
490       if (line[0] != '#') {
491         if (line[strlen(line)-1] != '\n') { 
492           strcpy(tmp, line);
493           while (tmp[strlen(tmp)-1] != '\n' && (cp = fgets(tmp, 100, f)));
494         } else
495           line[strlen(line)-1] = '\0';
496         if (line[strlen(line)-1] == '\r')
497           line[strlen(line)-1] = '\0';
498         for (i=strlen(line);(line[i-1] == ' '||line[i-1] == '\t')&&i>0; i--)
499           line[i-1] = '\0';
500         if (line[0] == '#')
501           line[0] = '\0';
502       } else
503         line[0] = '\0';
504     }
505   }
506   for (cp=line; *cp==' '; cp++);
507
508   if (strlen(cp)) {
509     memcpy(buf, cp, strlen(cp));
510     return 1;
511   } else
512     return 0;
513 }
514
515 char *get_date()
516 {
517   static char res[10];
518   time_t timer;
519   struct tm *loctime;
520
521   timer = time ( NULL );
522   loctime = localtime(&timer);
523   sprintf(res, "%02d.%02d.%02d", loctime->tm_mday, loctime->tm_mon+1, loctime->tm_year % 100);
524   return res;
525 }
526
527 /*
528  *  Prepare a record A according to the specs.
529  *  See dtaus.txt for explanation
530  */
531 void dtaus_prepareA (char *buf)
532 {
533   int i;
534   time_t timer;
535   struct tm *loctime;
536   char tmp[10];
537
538   memset (buf, 0, 129);
539   timer = time ( NULL );
540   loctime = localtime(&timer);
541
542   buf[0] = '0';
543   buf[1] = '1';
544   buf[2] = '2';
545   buf[3] = '8';
546   buf[4] = 'A';
547   for (i=15;i<15+8; i++) buf[i] = '0';          /* A5 */
548   sprintf(tmp, "%02d%02d%02d", loctime->tm_mday, loctime->tm_mon+1, loctime->tm_year % 100);
549   for (i=0; i<6; i++) buf[50+i] = tmp[i];       /* A7 (Date) */
550   for (i=56;i<56+4; i++) buf[i] = ' ';          /* A8 */
551   for (i=70;i<70+10; i++) buf[i] = '0';         /* A10 */
552   for (i=80;i<80+48; i++) buf[i] = ' ';         /* A11 */
553   if (use_euro)
554     buf[recA[A_CURR].pos] = '1';                                /* A12 (Currency) */
555   else
556     buf[recA[A_CURR].pos] = ' ';                                /* A12 (Currency) */
557 }
558
559 /*
560  *  Prepare a record C according to the specs.
561  *  See dtaus.txt for explanation
562  */
563 void dtaus_prepareC (char *buf, int normaltext, int maxtext)
564 {
565   int i;
566   int appendix = 0;
567
568   memset (buf, 0, 257);
569
570   if (normaltext)
571     appendix = 1;
572   appendix += maxtext;
573   i = 187 + (appendix * 29);
574
575   /* Bail out if the number is too large, shouldn't be possible though */
576   if (i >= 1000)
577     exit (1);
578
579   buf[0] = (i/1000)+48;i-=(i/1000)*100;
580   buf[1] = (i/100)+48;i-=(i/100)*100;
581   buf[2] = (i/10)+48;i-=(i/10)*10;
582   buf[3] = i+48;
583   buf[4] = 'C';
584
585   for (i=31;i<31+13; i++) buf[i] = '0';         /* C6 */
586   buf[49] = ' ';                                /* C8 */
587   for (i=50;i<50+11; i++) buf[i] = '0';         /* C9 (Betrag) */
588   for (i=79;i<79+11; i++) buf[i] = '0';         /* C12 (Betrag Euro) */
589   for (i=90;i<90+3; i++) buf[i] = ' ';          /* C13 */
590   for (i=93;i<90+27; i++) buf[i] = ' ';         /* C14a (Kunde) */
591   for (i=120;i<120+8; i++) buf[i] = ' ';        /* C14b */
592   if (use_euro)
593     buf[recC[C_EURO].pos] = '1';                                /* C17a (Currency) */
594   else
595     buf[recC[C_EURO].pos] = ' ';                                /* C17a (Currency) */
596   for (i=183;i<183+2; i++) buf[i] = ' ';        /* C17b */
597   for (i=187;i<187+(29*2); i++) buf[i] = ' ';   /* C19-C22 (misc text) */
598   for (i=245;i<245+11; i++) buf[i] = ' ';       /* C23 */
599
600   buf[185+0] = (appendix/10)+48;appendix-=(appendix/10)*10;
601   buf[185+1] = appendix+48;
602 }
603
604 /*
605  *  Prepare a record E according to the specs.
606  *  See dtaus.txt for explanation
607  */
608 void dtaus_prepareE (char *buf)
609 {
610   int i;
611
612   memset (buf, 0, 129);
613   buf[0] = '0';
614   buf[1] = '1';
615   buf[2] = '2';
616   buf[3] = '8';
617   buf[4] = 'E';
618   for (i=5;i<5+5; i++) buf[i] = ' ';    /* E3 */
619   for (i=17;i<17+13; i++) buf[i] = '0'; /* E8 (Check Betrag) */
620   for (i=64;i<64+13; i++) buf[i] = '0'; /* E8 (Check Euro) */
621   for (i=77;i<77+51; i++) buf[i] = ' '; /* E9 */
622 }
623
624 int dtaus_writeA(FILE *f, char **values)
625 {
626   char buf[129];
627   char tmp[30];
628   int i;
629   
630   for (i=0; (recA[i].name); i++)
631     if ((recA[i].type == REQ) && !values[i]) {
632       fprintf (stderr, "Anfangsdatensatz ist nicht vollständig, kein %s.\n", recA[i].name);
633       return 0;
634     }
635   if (!(((values[A_TRANS][0] == 'L')||(values[A_TRANS][0] == 'G'))
636         &&((values[A_TRANS][1] == 'B')||(values[A_TRANS][1] == 'K')))) {
637     fprintf (stderr, "Ungültiger Typ, nur LK, GK, LB oder GB erlaubt.\n");
638     return 0;
639   }
640
641   i=A_NAME;if (values[i] && strlen(values[i]) > recA[i].len)
642     values[i][recA[i].len] = '\0';
643
644   dtaus_prepareA(buf);
645   buf[5] = values[A_TRANS][0];
646   buf[6] = values[A_TRANS][1];
647   sprintf (tmp, "%s", padzeroclip (strip_nondigits (values[A_BLZ]),recA[A_BLZ].len));
648   for (i=0; i<recA[A_BLZ].len; i++) buf[recA[A_BLZ].pos+i] = tmp[i];
649   sprintf (tmp, "%-27.27s", upcase(values[A_NAME]));
650   for (i=0; i<27; i++) buf[recA[A_NAME].pos+i] = tmp[i];
651   if (values[A_TODO]) {
652     sprintf (tmp, "%s", padzeroclip (strip_nondigits (values[A_TODO]),recA[A_TODO].len));
653     for (i=0; i<recA[A_TODO].len; i++) buf[recA[A_TODO].pos+i] = tmp[i];
654   }
655   sprintf (tmp, "%s", padzeroclip (strip_nondigits (values[A_KTO]),recA[A_KTO].len));
656   for (i=0; i<recA[A_KTO].len; i++) buf[recA[A_KTO].pos+i] = tmp[i];
657
658   fputs(buf, f);
659   return 1;
660 }
661
662 int dtaus_writeC(FILE *f, char **valuesA, char **values, char **text)
663 {
664   char buf[257];
665   char appendix[129];
666   char tmp[30];
667   int i, k;
668   int maxtext = 0;
669   int fieldnr;
670
671   /* Just count */
672   if (text) for (maxtext=0;text[maxtext];maxtext++);
673
674 #if DEBUG
675   for (i=0; (recC[i].name); i++)
676     if (values[i])
677       printf ("%s: %s\n", recC[i].name, values[i]);
678 #endif
679
680   for (i=0; (recC[i].name); i++)
681     if ((recC[i].type == REQ) && !values[i]) {
682       fprintf (stderr, "Datensatz ist nicht vollständig, kein %s.\n", recC[i].name);
683       return 0;
684     }
685   sprintf (tmp, "%s", trans2string(values[C_TRANS]));
686   if (!strlen(tmp)) {
687     fprintf (stderr, "Ungültiger Typ, nur Abbuchung, Einzug, E-Cash, E-Cash-A, Gutschrift und Lohn erlaubt.\n");
688     return 0;
689   }
690
691   i=C_TEXT;if (values[i] && strlen(values[i]) > recC[i].len)
692     values[i][recC[i].len-2] = '\0';
693   i=C_ZWECK;if (values[i] && strlen(values[i]) > recC[i].len)
694     values[i][recC[i].len] = '\0';
695   i=C_MYNAM;if (values[i] && strlen(values[i]) > recC[i].len)
696     values[i][recC[i].len] = '\0';
697   i=C_TEXT;if (values[i] && strlen(values[i]) > recC[i].len)
698     values[i][recC[i].len] = '\0';
699
700   dtaus_prepareC (buf, values[C_TEXT] != NULL, maxtext);
701   for (i=0; i<5; i++) buf[recC[C_TRANS].pos+i] = tmp[i];
702   if (values[C_MYBLZ])
703     sprintf (tmp, "%s", padzeroclip (strip_nondigits (values[C_MYBLZ]),8));
704   else
705     sprintf (tmp, "%s", padzeroclip (strip_nondigits (valuesA[A_BLZ]),8));
706   for (i=0; i<recC[C_MYBLZ].len; i++) buf[5+i] = tmp[i];
707   for (i=0; i<recC[C_MYBLZ].len; i++) buf[recC[C_MYBLZ].pos+i] = tmp[i];
708   sprintf (tmp, "%s", padzeroclip (strip_nondigits (values[C_BLZ]),8));
709   for (i=0; i<recC[C_BLZ].len; i++) buf[recC[C_BLZ].pos+i] = tmp[i];
710   sprintf (tmp, "%s", padzeroclip (strip_nondigits (values[C_KTO]),10));
711   for (i=0; i<recC[C_KTO].len; i++) buf[recC[C_KTO].pos+i] = tmp[i];
712   sprintf (tmp, "%s", padzeroclip (real2string(values[C_VAL]),11));
713 #ifndef DEFAULT_EURO
714   if (!use_euro)
715     for (i=0; i<recC[C_VAL].len; i++) buf[recC[C_VAL].pos+i] = tmp[i];
716   else
717     for (i=0; i<recC[C_EUR].len; i++) buf[recC[C_EUR].pos+i] = tmp[i];
718 #else
719   if (use_euro)
720     for (i=0; i<recC[C_VAL].len; i++) buf[recC[C_VAL].pos+i] = tmp[i];
721   else
722     for (i=0; i<recC[C_DM].len; i++) buf[recC[C_DM].pos+i] = tmp[i];
723 #endif
724   if (values[C_MYKTO])
725     sprintf (tmp, "%s", padzeroclip (strip_nondigits (values[C_MYKTO]),10));
726   else
727     sprintf (tmp, "%s", padzeroclip (strip_nondigits (valuesA[A_KTO]),10));
728   for (i=0; i<recC[C_MYKTO].len; i++) buf[recC[C_MYKTO].pos+i] = tmp[i];
729   sprintf (tmp, "%-27.27s", upcase(values[C_NAME]));
730   for (i=0; i<recC[C_NAME].len; i++) buf[recC[C_NAME].pos+i] = tmp[i];
731   if (values[C_MYNAM])
732     sprintf (tmp, "%-27.27s", upcase(values[C_MYNAM]));
733   else
734     sprintf (tmp, "%-27.27s", upcase(valuesA[A_NAME]));
735   for (i=0; i<recC[C_MYNAM].len; i++) buf[recC[C_MYNAM].pos+i] = tmp[i];
736   sprintf (tmp, "%-27.27s", upcase(values[C_ZWECK]));
737   for (i=0; i<recC[C_ZWECK].len; i++) buf[recC[C_ZWECK].pos+i] = tmp[i];
738
739   if (values[C_TEXT]) {
740     buf[recC[C_TEXT].pos+0] = '0';
741     buf[recC[C_TEXT].pos+1] = '2';
742     sprintf (tmp, "%-27.27s", upcase(values[C_TEXT]));
743     for (i=0; i<recC[C_TEXT].len-2; i++) buf[recC[C_TEXT].pos+2+i] = tmp[i];
744   }
745
746   if (text) {
747     buf[recC[C_EXT].pos+0] = '0';
748     buf[recC[C_EXT].pos+1] = '2';
749     sprintf (tmp, "%-27.27s", upcase(text[0]));
750     for (i=0; i<recC[C_EXT].len-2; i++) buf[recC[C_EXT].pos+2+i] = tmp[i];
751   }
752
753   fputs(buf, f);
754
755   if (text && maxtext > 1) {
756     fieldnr=1;
757     while (fieldnr<maxtext) {
758       memset (appendix, ' ', 128);
759       appendix[128] = '\0';
760       for (k=0; k<4 && (fieldnr+k)<maxtext; k++) {
761         sprintf (tmp, "%-27.27s", upcase(text[fieldnr+k]));
762         appendix[k*29] = '0';
763         appendix[(k*29)+1] = '2';
764         for (i=0; i<recC[C_TEXT].len-2; i++) appendix[(k*29)+2+i] = tmp[i];
765       }
766       fputs(appendix, f);
767       fieldnr += k;
768     }
769   }
770
771   return 1;
772 }
773
774 int dtaus_writeE(FILE *f, int count, bigint sum, bigint blz, bigint kto)
775 {
776   char buf[129];
777   char tmp[30];
778   int i;
779   
780   dtaus_prepareE(buf);
781
782   sprintf (tmp, "%07d", count);
783   for (i=0; i<recE[E_COUNT].len; i++) buf[recE[E_COUNT].pos+i] = tmp[i];
784   bigint_sprintf (tmp, "%s", sum);
785   padzeroclip (tmp,13);
786 #ifndef DEFAULT_EURO
787   if (!use_euro)
788     for (i=0; i<recE[E_VAL].len; i++) buf[recE[E_VAL].pos+i] = tmp[i];
789   else
790     for (i=0; i<recE[E_EUR].len; i++) buf[recE[E_EUR].pos+i] = tmp[i];
791 #else
792   if (use_euro)
793     for (i=0; i<recE[E_VAL].len; i++) buf[recE[E_VAL].pos+i] = tmp[i];
794   else
795     for (i=0; i<recE[E_DM].len; i++) buf[recE[E_DM].pos+i] = tmp[i];
796 #endif
797   bigint_sprintf (tmp, "%s", kto);
798   padzeroclip (tmp,17);
799   for (i=0; i<recE[E_KTO].len; i++) buf[recE[E_KTO].pos+i] = tmp[i];
800   bigint_sprintf (tmp, "%s", blz);
801   padzeroclip (tmp,17);
802   for (i=0; i<recE[E_BLZ].len; i++) buf[recE[E_BLZ].pos+i] = tmp[i];
803
804   fputs(buf, f);
805   return 1;
806 }
807
808 void printctln(FILE *f, char *field, char *value)
809 {
810   if (strlen(field) && strlen(value))
811     fprintf(f, "  %s\t%s\n", field, value);
812 }
813
814 /*
815  * one date line, format it properly
816  */
817 void printctlndate(FILE *f, char *field, char *value)
818 {
819   char mydate[11];
820   int i;
821
822   if (!strlen(field) || !strlen(value))
823     return;
824
825   for (i=0;isspace (value[i]) && i<= strlen (value); i++);
826   if (i == strlen (value))
827     return;
828
829   memset (mydate, 0, sizeof (mydate));
830   if (strlen (value) == 6) {
831     mydate[0] = value[0];
832     mydate[1] = value[1];
833     mydate[2] = '.';
834     mydate[3] = value[2];
835     mydate[4] = value[3];
836     mydate[5] = '.';
837     mydate[6] = value[4];
838     mydate[7] = value[5];
839     fprintf(f, "  %s\t%s\n", field, mydate);
840   } else if (strlen (value) == 8) {
841     mydate[0] = value[0];
842     mydate[1] = value[1];
843     mydate[2] = '.';
844     mydate[3] = value[2];
845     mydate[4] = value[3];
846     mydate[5] = '.';
847     mydate[6] = value[4];
848     mydate[7] = value[5];
849     mydate[8] = value[6];
850     mydate[9] = value[7];
851     fprintf(f, "  %s\t%s\n", field, mydate);
852   } else {
853     fprintf (stderr, "Broken date field: %s\n", value);
854     fprintf(f, "  %s\t%s\n", field, value);
855   }
856 }
857
858
859 /*
860  *  Third: Some high level routines
861  */
862
863 void dtaus2control (char *cdtaus, char *ccontrol)
864 {
865   FILE *fdtaus, *fcontrol;
866   char *buf;
867   char *bufp;
868   char tmp[30];
869   char x[30];
870   int index;
871   int extC;
872   div_t res;
873
874   if (!cdtaus) {
875     if (!(fdtaus = fopen("DTAUS0.TXT", "r")))
876       if (!(fdtaus = fopen("dtaus0.txt", "r")))
877         return;
878   } else {
879     if (!strcmp (cdtaus, "-"))
880       fdtaus = stdin;
881     else
882       if (!(fdtaus = fopen(cdtaus, "r")))
883         return;
884   }
885   if (!ccontrol) 
886     fcontrol = stdout;
887   else
888     if (!strcmp (ccontrol, "-"))
889       fcontrol = stdout;
890     else
891       if (!(fcontrol = fopen(ccontrol, "w")))
892         return;
893   if (!(buf = (char *)malloc (512)))
894     return;
895
896   /* 
897    * Record A lesen
898    */
899   if (dtaus_nextrec((void *)buf, fdtaus) == 1) {
900     if (dtaus_char(buf,4) == 'A') {
901       fprintf(fcontrol, "BEGIN {\n");
902       bufp = buf;
903
904       for (index=A_TRANS; index < A_LOOP; index++) {
905         bufp = buf + recA[index].pos;
906         memcpy(tmp, bufp, recA[index].len); tmp[recA[index].len] = '\0';
907         if (index == A_DATE || index == A_TODO)
908           printctlndate(fcontrol, recA[index].name, tmp);
909         else
910           printctln(fcontrol, recA[index].name, strip_zeros(strip_spaces(tmp)));
911       }
912
913       bufp = buf + recA[A_CURR].pos;
914       if (*bufp == '1') {
915         use_euro = 1;
916         fprintf(fcontrol, "  Euro\n");
917       } else {
918         use_euro = 0;
919         fprintf(fcontrol, "  DM\n");
920       }
921
922       fprintf(fcontrol, "}\n\n");
923     } else {
924       fprintf (stderr, "Datei fängt nicht mit dem Anfangsdatensatz an.\n");
925       return;
926     }
927   } else {
928     fprintf (stderr, "Der Anfangsdatensatz ist kaputt.\n");
929     return;
930   }
931
932   /*
933    * Record C lesen
934    */
935   if (dtaus_nextrec((void *)buf, fdtaus) == 1) {
936     while (dtaus_char(buf,4) == 'C') {
937       bufp = buf + 128;
938       if (dtaus_nextrec((void *)bufp, fdtaus) != 1) {
939         fprintf (stderr, "Der zweite Teil der Transaktion ist kaputt.\n");
940         return;
941       } else {
942         fprintf(fcontrol, "{\n");
943
944         for (index=C_NAME; index < C_LOOP; index++) {
945 #ifndef DEFAULT_EURO
946           if (use_euro && index == C_VAL)
947             index = C_EUR;
948 #else
949           if (!use_euro && index == C_VAL)
950             index = C_DM;
951 #endif
952           bufp = buf + recC[index].pos;
953           memcpy(tmp, bufp, recC[index].len); tmp[recC[index].len] = '\0';
954
955           /*
956            * C_EUR and C_DM are outside of the loop, can only be
957            * selected for the non-default currency, but the value
958            * should be stored in the normal record field.
959            */
960 #ifndef DEFAULT_EURO
961           if (index == C_EUR)
962 #else
963           if (index == C_DM)
964 #endif
965             printctln(fcontrol, recC[C_VAL].name, strip_zeros(string2real(tmp)));
966           else if (index == C_VAL)
967             printctln(fcontrol, recC[index].name, strip_zeros(string2real(tmp)));
968           else if (index == C_TRANS)
969             printctln(fcontrol, recC[index].name, strip_zeros(string2trans(tmp)));
970           else
971             printctln(fcontrol, recC[index].name, strip_zeros(strip_spaces(tmp)));
972 #ifndef DEFAULT_EURO
973           if (use_euro && index == C_EUR)
974             index = C_VAL;
975 #else
976           if (!use_euro && index == C_DM)
977             index = C_VAL;
978 #endif
979         }
980
981         for (index=C_TEXT; index <= C_EXT; index++) {
982           if (!(dtaus_char(buf,recC[index].pos) == ' ')) {
983             bufp = buf + recC[index].pos;
984             memcpy(x, bufp, 2); tmp[2] = '\0'; bufp+=2;
985             memcpy(tmp, bufp, recC[index].len-2); tmp[recC[index].len-2] = '\0';
986             printctln(fcontrol, string2ext(x), strip_spaces(tmp));
987           }
988         }
989
990         /* Number of extension records for this C record */
991         extC = dtaus_int(buf, 185, 2);
992         extC -= 2;
993         if (extC > 0) {
994           res = div (extC, 4);
995           extC = res.quot;
996           if (res.rem) extC++;
997         }
998       }
999       if (dtaus_nextrec((void *)buf, fdtaus) != 1)
1000         memset (buf, 0, sizeof(buf));
1001
1002       /*
1003        * Are there extension records that we have to check?
1004        *
1005        * 2nd half of the AND is wrong, but since dtaus < 0.5 wrote 01
1006        *     instead of 00 we should let it in so it can read its own
1007        *     old files...  *sigh*
1008        */
1009       while (extC > 0 && dtaus_char(buf,4) != 'C' && dtaus_char(buf,4) != 'E') {
1010         for (index=0; index < 4; index++) {
1011           if ((dtaus_char(buf,index*29) != ' ')) {
1012             bufp = buf + index*29;
1013             memcpy(x, bufp, 2); tmp[2] = '\0'; bufp+=2;
1014             memcpy(tmp, bufp, recC[C_TEXT].len-2); tmp[recC[C_TEXT].len-2] = '\0';
1015             printctln(fcontrol, string2ext(x), strip_spaces(tmp));
1016           }
1017         }
1018         if (dtaus_nextrec((void *)buf, fdtaus) != 1)
1019           memset (buf, 0, sizeof(buf));
1020         extC--;
1021       }
1022       fprintf(fcontrol, "}\n");
1023     }
1024   }
1025
1026   /*
1027    * Record E lesen
1028    *   (gelesen ist er eigentlich schon...)
1029    */
1030   if (dtaus_char(buf,4) == 'E') {
1031     if (dtaus_char(buf,4) == 'E') {
1032       fprintf(fcontrol, "\nEND {\n");
1033
1034       for (index=E_COUNT; index <= E_BLZ; index++) {
1035 #ifndef DEFAULT_EURO
1036         if (use_euro && index == E_VAL)
1037           index = E_EUR;
1038 #else
1039         if (!use_euro && index == E_VAL)
1040           index = E_DM;
1041 #endif
1042
1043         bufp = buf + recE[index].pos;
1044         memcpy(tmp, bufp, recE[index].len); tmp[recE[index].len] = '\0';
1045
1046 #ifndef DEFAULT_EURO
1047         if (index == E_VAL || index == E_EUR)
1048 #else
1049         if (index == E_VAL || index == E_DM)
1050 #endif
1051           printctln(fcontrol, recE[E_VAL].name, strip_zeros(string2real(tmp)));
1052         else
1053           printctln(fcontrol, recE[index].name, strip_zeros(tmp));
1054 #ifndef DEFAULT_EURO
1055           if (use_euro && index == E_EUR)
1056             index = E_VAL;
1057 #else
1058           if (!use_euro && index == E_DM)
1059             index = E_VAL;
1060 #endif
1061       }
1062
1063       fprintf(fcontrol, "}\n");
1064     } else {
1065       fprintf (stderr, "Das ist kein Abschlußdatensatz.\n");
1066       return;
1067     }
1068   } else {
1069     fprintf (stderr, "Der Abschlußdatensatz ist leer oder kaputt.\n");
1070     return;
1071   }
1072   fclose(fcontrol);
1073   fclose(fdtaus);
1074 }
1075
1076 int control2dtaus (char *ccontrol, char *cdtaus, char *cbeleg, char *ccheck)
1077 {
1078   FILE *fdtaus, *fcontrol, *fbeleg, *fcheck;
1079   void *buf;
1080   char *ident;
1081   int  recindex;
1082   char tmp[30];
1083   char line[100];
1084   char *valA[A_LEN], *valC[C_LEN];
1085   int count;
1086   bigint sum_val, sum_blz, sum_kto, bi;
1087   char **text = NULL;
1088   char *cp;
1089   int textindex = 0;
1090   int len, i;
1091
1092   if (!cdtaus) {
1093     if (!(fdtaus = fopen("dtaus0.txt", "w")))
1094       return 0;
1095   } else {
1096     if (!strcmp (cdtaus, "-"))
1097       fdtaus = stdout;
1098     else
1099       if (!(fdtaus = fopen(cdtaus, "w")))
1100         return 0;
1101   }
1102   if (!ccontrol) {
1103     if (!(fcontrol = fopen("dtaus0.ctl", "r")))
1104       if (!(fcontrol = fopen("DTAUS0.CTL", "r")))
1105         return 0;
1106   } else {
1107     if (!strcmp (ccontrol, "-"))
1108       fcontrol = stdin;
1109     else
1110       if (!(fcontrol = fopen(ccontrol, "r")))
1111         return 0;
1112   }
1113   if (!cbeleg) {
1114     if (!(fbeleg = fopen("dtaus0.doc", "w")))
1115       return 0;
1116   } else {
1117     if (!(fbeleg = fopen(cbeleg, "w")))
1118       return 0;
1119   }
1120   if (!ccheck)
1121     fcheck = stdout;
1122   else
1123     if (!(fcheck = fopen(ccheck, "w")))
1124       return 0;
1125
1126
1127   if (!(buf = (char *)malloc (512)))
1128     return 0;
1129
1130   /* 
1131    * Record A lesen
1132    */
1133   memset (valA, 0, sizeof(valA));
1134   control_nextline ((void *)line, 100, fcontrol);
1135   ident = extract_ident(line);
1136   if (!strcmp(ident, "begin") && (line[0] == '{')) {
1137     control_nextline ((void *)line, 100, fcontrol);
1138     while (strlen(line) && line[0] != '}') {
1139       ident = extract_ident(line);
1140       if ((recindex = rec_index(ident, REC_A)) != -1)
1141         {
1142         if (recA[recindex].type != IGN)
1143           if ((valA[recindex] = (char *)malloc (strlen(line)+1)))
1144             strcpy(valA[recindex], line);
1145         } else {
1146           if (! strcasecmp (ident, "euro"))
1147             use_euro = 1;
1148           if (! strcasecmp (ident, "dm"))
1149             use_euro = 0;
1150         }
1151       control_nextline ((void *)line, 100, fcontrol);
1152     }
1153     if (((recindex = rec_index("art", REC_A)) != -1) && valA[recindex] && strlen(valA[recindex])) {
1154       fprintf(fbeleg, "\n\n");
1155       fprintf(fbeleg, "\n    Begleitzettel\n\n");
1156       fprintf(fbeleg, "\n    Belegloser Datentraegeraustausch\n\n");
1157       if (valA[recindex][0] == 'L')
1158         fprintf(fbeleg, "\n    Sammeleinziehungsauftrag\n\n");
1159       else if (valA[recindex][0] == 'G')
1160         fprintf(fbeleg, "\n    Sammelueberweisungsauftrag\n\n");
1161       else
1162         fprintf(fbeleg, "\n    Sammelauftrag\n\n");
1163       fprintf(fbeleg, "\n    VOL ........................:\n");
1164       fprintf(fbeleg, "\n    Erstellungsdatum ...........: %s\n", get_date());
1165       if (valA[A_TODO]) {
1166         fprintf(fbeleg, "\n    Ausfuehrugsdatum ...........: %s\n", valA[A_TODO]);
1167       }
1168       if (use_euro)
1169         fprintf(fbeleg, "\n    Waehrung ...................: Euro\n");
1170       else
1171         fprintf(fbeleg, "\n    Waehrung ...................: DM\n");
1172     }
1173     if (!dtaus_writeA(fdtaus, valA)) {
1174       fprintf (stderr, "Konnte den Anfangsdatensatz nicht schreiben.\n");
1175       return 0;
1176     }
1177
1178     fprintf (fcheck, "\n\n\n");
1179     if (valA[recindex][0] == 'L')
1180       fprintf (fcheck, "    Sammeleinziehungsauftrag\n\n");
1181     else if (valA[recindex][0] == 'G')
1182       fprintf (fcheck, "    Sammelueberweisungsauftrag\n\n");
1183     else
1184       fprintf (fcheck, "    Sammelauftrag\n\n");
1185     fprintf (fcheck, "    Erstellungsdatum : %s\n\n", get_date());
1186     if (use_euro)
1187       fprintf (fcheck, "    Waehrung         : Euro\n\n\n");
1188     else
1189       fprintf (fcheck, "    Waehrung         : DM\n\n\n");
1190     fprintf (fcheck, "     %-10s  %-8s  %-30s   %12s\n", "Kontonr.", "BLZ", "Name", "Betrag");
1191     fprintf (fcheck, "    --------------------------------------------------------------------\n");
1192   } else {
1193     fprintf (stderr, "Datei fängt nicht mit dem Anfangsdatensatz (BEGIN) an.\n");
1194     return 0;
1195   }
1196
1197   /* 
1198    * Record C lesen
1199    */
1200   count = 0;
1201   sum_val = bigint_int(0);
1202   sum_blz = bigint_int(0);
1203   sum_kto = bigint_int(0);
1204   memset (valC, 0, sizeof(valC));
1205   control_nextline ((void *)line, 100, fcontrol);
1206   if (line[0] == '{') {
1207     while (strlen(line) && line[0] == '{') {
1208       control_nextline ((void *)line, 100, fcontrol);
1209       if (text) {
1210         for (textindex=0; textindex < MAX_TEXT && text[textindex]; textindex++)
1211           free (text[textindex]);
1212         free (text);
1213         text = NULL;
1214       }
1215       while (strlen(line) && line[0] != '}') {
1216         ident = extract_ident(line);
1217         if ((recindex = rec_index(ident, REC_C)) != -1)
1218           if (recC[recindex].type != IGN) {
1219             /*
1220              * Special exception to support multiple Text fields
1221              */
1222             if (recindex == C_TEXT && valC[recindex]) {
1223               if (!text) {
1224                 if ((text = (char **)malloc ((MAX_TEXT+1) * sizeof (char *))) == NULL)
1225                   return 0;
1226                 else {
1227                   textindex = 0;
1228                   memset (text, 0, (MAX_TEXT+1) * sizeof (char *));
1229                 }
1230               }
1231               if (textindex < MAX_TEXT) {
1232                 if ((cp = (char *)malloc (strlen (line) + 1))) {
1233                   strcpy (cp, line);
1234                   cp[strlen (line)] = '\0';
1235                   text[textindex++] = cp;
1236                 }
1237               }
1238             } else {
1239               len = strlen(line);
1240               if (recindex == C_VAL) {
1241                 /* Convert commast to dots for later processing */
1242                 for (i=0; line[i]; i++) if (line[i] == ',') line[i] = '.';
1243
1244                 if ((cp = index (line, '.')) == NULL) {
1245                   if (!(valC[recindex] = (char *)malloc (strlen(line)+4)))
1246                     return 0;
1247                   sprintf (valC[recindex], "%s.00", line);
1248                 } else if ( ((len = cp - line + 3)) < strlen (line)) {
1249                   if (!(valC[recindex] = (char *)malloc (len+1)))
1250                     return 0;
1251                   strncpy (valC[recindex], line, len);
1252                   valC[recindex][len] = '\0';
1253                 } else {
1254                   if (!(valC[recindex] = (char *)malloc (strlen(line)+1)))
1255                     return 0;
1256                   strcpy(valC[recindex], line);
1257                 }
1258               } else {
1259                 if ((valC[recindex] = (char *)malloc (strlen(line)+1)))
1260                   strcpy(valC[recindex], line);
1261                 else
1262                   return 0;
1263               }
1264             }
1265           }
1266         control_nextline ((void *)line, 100, fcontrol);
1267       }
1268       if (!dtaus_writeC(fdtaus, valA, valC, text)) {
1269         fprintf (stderr, "Konnte den regulären Datensatz nicht schreiben.\n");
1270         return 0;
1271       }
1272       count++;
1273       bi = bigint_string(real2string(valC[C_VAL])); sum_val = bigint_add(sum_val, bi);
1274       bi = bigint_string(valC[C_BLZ]); sum_blz = bigint_add(sum_blz, bi);
1275       bi = bigint_string(valC[C_KTO]); sum_kto = bigint_add(sum_kto, bi);
1276
1277       fprintf (fcheck, "     %10s  %8s  %-30s   %12s\n", valC[C_KTO], valC[C_BLZ], valC[C_NAME], valC[C_VAL]);
1278       for (recindex=0; recindex<C_LEN; recindex++)
1279         if (valC[recindex])
1280           free(valC[recindex]);
1281       memset (valC, 0, sizeof(valC));
1282       control_nextline ((void *)line, 100, fcontrol);
1283     }
1284   } else {
1285     fprintf (stderr, "Kein regulärer Datensatz?\n");
1286     return 0;
1287   }
1288
1289   /* 
1290    * Record E lesen
1291    */
1292   dtaus_writeE(fdtaus, count, sum_val, sum_blz, sum_kto);
1293   fprintf (fcheck, "    --------------------------------------------------------------------\n");
1294   bigint_sprintf (tmp, "%s", sum_val);
1295   fprintf (fbeleg, "\n    Anzahl .....................: %d\n", count);
1296   recindex=strlen(tmp);
1297   tmp[recindex+1] = '\0';
1298   tmp[recindex] = tmp[recindex-1];
1299   tmp[recindex-1] = tmp[recindex-2];
1300   tmp[recindex-2] = '.';
1301   fprintf (fcheck, "     %-52s %14s\n", "Summe", tmp);
1302   fprintf (fbeleg, "\n    Summe ......................: %s\n", tmp);
1303   bigint_sprintf (tmp, "%s", sum_kto);
1304   fprintf (fbeleg, "\n    Kontrollsumme Kontonummern .: %s\n", tmp);
1305   bigint_sprintf (tmp, "%s", sum_blz);
1306   fprintf (fbeleg, "\n    Kontrollsumme Bankleitzahlen: %s\n", tmp);
1307   fprintf (fbeleg, "\n    Unsere Kontonummer .........: %s\n", valA[A_KTO]);
1308   fprintf (fbeleg, "\n    Unsere Bankleitzahl ........: %s\n", valA[A_BLZ]);
1309   fprintf (fbeleg, "\n\n\n\n\n    __________________________________________________\n");
1310   fprintf (fbeleg, "    Ort, Datum                     Unterschrift\n");
1311   for (recindex=0; recindex<A_LEN; recindex++)
1312     if (valA[recindex])
1313       free(valA[recindex]);
1314   fclose(fdtaus);
1315   fclose(fcontrol);
1316   fclose(fbeleg);
1317   if (ccheck)
1318     fclose(fcheck);
1319   return count;
1320 }