1 /*
2 Copyright (C) 2013-2019 Free Software Foundation, Inc.
3 Written by Ron Norman, Simon Sobisch
4
5 This file is part of GnuCOBOL.
6
7 The GnuCOBOL runtime library is free software: you can redistribute it
8 and/or modify it under the terms of the GNU Lesser General Public License
9 as published by the Free Software Foundation, either version 3 of the
10 License, or (at your option) any later version.
11
12 GnuCOBOL is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with GnuCOBOL. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21
22 #include <config.h>
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <stddef.h>
27 #include <string.h>
28 #include <ctype.h>
29 #include <errno.h>
30
31 /* Force symbol exports */
32 #define COB_LIB_EXPIMP
33 #include "libcob.h"
34 #include "coblocal.h"
35
36 #ifdef WORDS_BIGENDIAN
37 #define COB_MAYSWAP_16(x) ((unsigned short)(x))
38 #define COB_MAYSWAP_32(x) ((unsigned int)(x))
39 #else
40 #define COB_MAYSWAP_16(x) (COB_BSWAP_16((unsigned short)(x)))
41 #define COB_MAYSWAP_32(x) (COB_BSWAP_32((unsigned int)(x)))
42 #endif
43
44 static cob_global *cobglobptr= NULL;
45 static cob_settings *cobsetptr= NULL;
46 static int bDidReportInit = 0;
47
48 #ifndef TRUE
49 #define TRUE 1
50 #endif
51 #ifndef FALSE
52 #define FALSE 0
53 #endif
54
55 #define ND1 COB_REPORT_HEADING|COB_REPORT_FOOTING|COB_REPORT_PAGE_HEADING|COB_REPORT_PAGE_FOOTING
56 #define ND2 COB_REPORT_CONTROL_HEADING|COB_REPORT_CONTROL_HEADING_FINAL
57 #define ND3 COB_REPORT_CONTROL_FOOTING|COB_REPORT_CONTROL_FOOTING_FINAL
58 #define NOTDETAIL(f) ( f & (ND1|ND2|ND3))
59
60 static int report_line_type(cob_report *r, cob_report_line *l, int type);
61
62 static const cob_field_attr const_alpha_attr =
63 {COB_TYPE_ALPHANUMERIC, 0, 0, 0, NULL};
64 static const cob_field_attr const_num_attr =
65 {COB_TYPE_NUMERIC, 0, 0, 0, NULL};
66 #define MAX_ACTIVE_REPORTS 10
67 static cob_report *active_reports[MAX_ACTIVE_REPORTS];
68 /*
69 * Move "String" to 'dst' field
70 */
71 static void
cob_str_move(cob_field * dst,unsigned char * src,const int size)72 cob_str_move (cob_field *dst, unsigned char *src, const int size)
73 {
74 cob_field temp;
75
76 temp.size = size;
77 temp.data = src;
78 temp.attr = &const_alpha_attr;
79 cob_move (&temp, dst);
80 }
81
82 /*
83 * Initialize data field
84 */
85 static cob_field *
cob_field_init(cob_field * f)86 cob_field_init (cob_field *f)
87 {
88 cob_field temp;
89
90 if(f == NULL)
91 return NULL;
92 temp.size = 1;
93 if(COB_FIELD_IS_NUMERIC(f)) {
94 temp.data = (unsigned char*)"0"; /* MOVE ZERO to field */
95 temp.attr = &const_num_attr;
96 } else {
97 temp.data = (unsigned char*)" "; /* MOVE SPACES to field */
98 temp.attr = &const_alpha_attr;
99 }
100 cob_move (&temp, f);
101 return f;
102 }
103
104
105 /*
106 * Make a new field the same format as that given
107 */
108 static cob_field *
cob_field_dup(cob_field * f,int incr)109 cob_field_dup (cob_field *f, int incr)
110 {
111 cob_field temp;
112 cob_field *fld = cob_malloc(sizeof(cob_field));
113 size_t dsize = f->size + incr;
114
115 fld->size = dsize;
116 fld->data = cob_malloc((size_t)(dsize < COB_MAX_DIGITS ? COB_MAX_DIGITS : dsize) + 1);
117 fld->attr = f->attr;
118
119 temp.size = 1;
120 if (COB_FIELD_IS_NUMERIC (f)) {
121 temp.data = (unsigned char*)"0"; /* MOVE ZERO to new field */
122 temp.attr = &const_num_attr;
123 } else {
124 temp.data = (unsigned char*)" "; /* MOVE SPACES to new field */
125 temp.attr = &const_alpha_attr;
126 }
127 cob_move (&temp, fld);
128 return fld;
129 }
130
131 /*
132 * Free a field created by cob_field_dup
133 */
134 static void
cob_field_free(cob_field * f)135 cob_field_free (cob_field *f)
136 {
137 if(f == NULL)
138 return;
139 if(f->data)
140 cob_free((void*)f->data);
141 cob_free((void*)f);
142 return ;
143 }
144
145 /*
146 * Free control temp areas
147 */
148 static void
free_control_fields(cob_report * r)149 free_control_fields (cob_report *r)
150 {
151 cob_report_control *rc;
152 cob_report_control_ref *rr;
153 int k;
154
155 for(rc = r->controls; rc; rc = rc->next) {
156 if(rc->val) {
157 cob_field_free(rc->val);
158 rc->val = NULL;
159 }
160 if(rc->sf) {
161 cob_field_free(rc->sf);
162 rc->sf = NULL;
163 }
164 rc->has_heading = FALSE;
165 rc->has_footing = FALSE;
166 for(rr = rc->control_ref; rr; rr = rr->next) {
167 if (rr->ref_line->flags & COB_REPORT_CONTROL_HEADING
168 || rr->ref_line->flags & COB_REPORT_CONTROL_HEADING_FINAL)
169 rc->has_heading = TRUE;
170 if (rr->ref_line->flags & COB_REPORT_CONTROL_FOOTING
171 || rr->ref_line->flags & COB_REPORT_CONTROL_FOOTING_FINAL)
172 rc->has_footing = TRUE;
173 }
174 }
175 for(k=0; k < MAX_ACTIVE_REPORTS; k++) {
176 if (active_reports[k] == r) {
177 active_reports[k] = NULL;
178 }
179 }
180 }
181
182 /*
183 * Clear the 'group_indicate' flag for all fields
184 */
185 static void
clear_group_indicate(cob_report_line * l)186 clear_group_indicate(cob_report_line *l)
187 {
188 cob_report_field *f;
189 for(f=l->fields; f; f=f->next) {
190 f->group_indicate = FALSE;
191 }
192 if(l->child)
193 clear_group_indicate(l->child);
194 if(l->sister)
195 clear_group_indicate(l->sister);
196 }
197
198 /*
199 * Clear the 'suppress' flag for all fields
200 */
201 static void
clear_suppress(cob_report_line * l)202 clear_suppress(cob_report_line *l)
203 {
204 cob_report_field *f;
205 l->suppress = FALSE;
206 for(f=l->fields; f; f=f->next) {
207 if((f->flags & COB_REPORT_GROUP_ITEM))
208 continue;
209 f->suppress = FALSE;
210 }
211 if(l->child)
212 clear_suppress(l->child);
213 if(l->sister)
214 clear_suppress(l->sister);
215 }
216
217 /*
218 * Return control field sequence value for given report line
219 * else return -1
220 */
221 static int
get_control_sequence(cob_report * r,cob_report_line * l)222 get_control_sequence(cob_report *r, cob_report_line *l)
223 {
224 cob_report_control *c;
225 cob_report_control_ref *rr;
226 if(r->controls) {
227 for(c=r->controls; c; c = c->next) {
228 for(rr=c->control_ref; rr; rr=rr->next) {
229 if(rr->ref_line == l) {
230 return c->sequence;
231 }
232 }
233 }
234 }
235 return -1;
236 }
237
238 /*
239 * If this line has NEXT GROUP .... then set info in report header
240 */
241 static void
set_next_info(cob_report * r,cob_report_line * l)242 set_next_info(cob_report *r, cob_report_line *l)
243 {
244 if(l->flags & COB_REPORT_NEXT_GROUP_LINE) {
245 r->next_value = l->next_group_line;
246 r->next_line = TRUE;
247 r->next_just_set = TRUE;
248 r->next_line_plus = FALSE;
249 DEBUG_LOG("rw",(" Save NEXT GROUP LINE %d\n",r->next_value));
250 }
251 if(l->flags & COB_REPORT_NEXT_GROUP_PLUS) {
252 r->next_value = l->next_group_line;
253 r->next_line = FALSE;
254 r->next_line_plus = TRUE;
255 r->next_just_set = TRUE;
256 DEBUG_LOG("rw",(" Save NEXT GROUP PLUS %d\n",r->next_value));
257 }
258 if(l->flags & COB_REPORT_NEXT_GROUP_PAGE) {
259 r->next_value = l->next_group_line;
260 r->next_line = FALSE;
261 r->next_page = TRUE;
262 r->next_just_set = TRUE;
263 DEBUG_LOG("rw",(" Save NEXT GROUP PAGE\n"));
264 }
265 }
266
267 static cob_report_line *
get_print_line(cob_report_line * l)268 get_print_line(cob_report_line *l)
269 {
270 while(l
271 && l->fields == NULL
272 && l->child != NULL)
273 l = l->child; /* Find line with data fields */
274 return l;
275 }
276
277 /*
278 * Do any global initialization needed
279 */
280 static void
reportInitialize()281 reportInitialize()
282 {
283 if(bDidReportInit)
284 return;
285 bDidReportInit = 1;
286 }
287
288 /*
289 * Add Two Fields together giving Result
290 */
291 static void
cob_add_fields(cob_field * op1,cob_field * op2,cob_field * rslt)292 cob_add_fields(cob_field *op1, cob_field *op2, cob_field *rslt)
293 {
294 cob_field_attr attr1, attr2;
295 char data1[30],data2[30];
296 cob_field fld1,fld2;
297 #ifdef COB_DEBUG_LOG
298 char wrk[32];
299 #endif
300
301 /* Copy data to local PIC 9 DISPLAY fields */
302 /* As cob_add does not handle NUMERIC_EDITED very well */
303 fld1.size = op1->size;
304 attr1 = *op1->attr;
305 fld1.attr = &attr1;
306 attr1.type = COB_TYPE_NUMERIC_DISPLAY;
307 fld1.data = (unsigned char*)data1;
308 memset(data1,'0',fld1.size);
309 cob_move(op1, &fld1);
310
311 #ifdef COB_DEBUG_LOG
312 if(DEBUG_ISON("rw")) {
313 cob_field_to_string(op1, wrk, sizeof(wrk)-1);
314 DEBUG_LOG("rw",(" Add '%s' ",wrk));
315 }
316 #endif
317
318 fld2.size = op2->size;
319 attr2 = *op2->attr;
320 fld2.attr = &attr2;
321 attr2.type = COB_TYPE_NUMERIC_DISPLAY;
322 fld2.data = (unsigned char*)data2;
323 memset(data2,'0',fld2.size);
324 cob_move(op2, &fld2);
325
326 #ifdef COB_DEBUG_LOG
327 if(DEBUG_ISON("rw")) {
328 cob_field_to_string(op2, wrk, sizeof(wrk)-1);
329 DEBUG_LOG("rw",("TO '%s' ",wrk));
330 }
331 #endif
332
333 cob_add(&fld1,&fld2,0);
334
335 cob_move(&fld1, rslt); /* Copy SUM back to result field */
336
337 #ifdef COB_DEBUG_LOG
338 if(DEBUG_ISON("rw")) {
339 cob_field_to_string(&fld1, wrk, sizeof(wrk)-1);
340 DEBUG_LOG("rw",("GIVING '%s' ",wrk));
341 DEBUG_LOG("rw",(" PIC 9(%d)",rslt->attr->digits));
342 if(rslt->attr->scale > 0)
343 DEBUG_LOG("rw",("V9(%d)",rslt->attr->scale));
344 DEBUG_LOG("rw",("\n"));
345 }
346 #endif
347 }
348
349 #ifdef COB_DEBUG_LOG
350 static void
dumpFlags(int flags,int ln,char * name)351 dumpFlags(int flags, int ln, char *name)
352 {
353 if (!DEBUG_ISON("rw")) {
354 return;
355 }
356
357 if(name == NULL)
358 name = (char*)"";
359 if(flags & COB_REPORT_HEADING) DEBUG_LOG("rw",("REPORT HEADING "));
360 if(flags & COB_REPORT_FOOTING) DEBUG_LOG("rw",("REPORT FOOTING "));
361 if(flags & COB_REPORT_PAGE_HEADING) DEBUG_LOG("rw",("PAGE HEADING "));
362 if(flags & COB_REPORT_PAGE_FOOTING) DEBUG_LOG("rw",("PAGE FOOTING "));
363 if(flags & COB_REPORT_CONTROL_HEADING) DEBUG_LOG("rw",("CONTROL HEADING %s ",name));
364 if(flags & COB_REPORT_CONTROL_HEADING_FINAL) DEBUG_LOG("rw",("CONTROL HEADING FINAL "));
365 if(flags & COB_REPORT_CONTROL_FOOTING) {
366 if(flags & COB_REPORT_ALL)
367 DEBUG_LOG("rw",("CONTROL FOOTING %s ",name));
368 else
369 DEBUG_LOG("rw",("CONTROL FOOTING ALL "));
370 }
371 if(flags & COB_REPORT_CONTROL_FOOTING_FINAL) DEBUG_LOG("rw",("CONTROL FOOTING FINAL "));
372 if(flags & COB_REPORT_DETAIL) DEBUG_LOG("rw",("DETAIL "));
373 if(flags & COB_REPORT_LINE_PLUS) {if(ln > 0) DEBUG_LOG("rw",("LINE PLUS %d ",ln));}
374 else if(flags & COB_REPORT_LINE) DEBUG_LOG("rw",("LINE %d ",ln));
375 if(flags & COB_REPORT_LINE_NEXT_PAGE) DEBUG_LOG("rw",("LINE NEXT PAGE "));
376 if(flags & COB_REPORT_NEXT_PAGE) DEBUG_LOG("rw",("NEXT PAGE "));
377 if(flags & COB_REPORT_GROUP_INDICATE) DEBUG_LOG("rw",("GROUP INDICATE "));
378 if(flags & COB_REPORT_COLUMN_PLUS) DEBUG_LOG("rw",("COLUMN PLUS "));
379 if(flags & COB_REPORT_RESET_FINAL) DEBUG_LOG("rw",("RESET FINAL "));
380 if(flags & COB_REPORT_COLUMN_LEFT) DEBUG_LOG("rw",("LEFT "));
381 if(flags & COB_REPORT_COLUMN_RIGHT) DEBUG_LOG("rw",("RIGHT "));
382 if(flags & COB_REPORT_COLUMN_CENTER) DEBUG_LOG("rw",("CENTER "));
383 if(flags & COB_REPORT_GROUP_ITEM) DEBUG_LOG("rw",("GROUP "));
384 if(flags & COB_REPORT_PRESENT) {
385 if(flags & COB_REPORT_NEGATE) {
386 if(flags & COB_REPORT_BEFORE) {
387 DEBUG_LOG("rw",("ABSENT BEFORE "));
388 } else {
389 DEBUG_LOG("rw",("ABSENT AFTER "));
390 }
391 } else {
392 if(flags & COB_REPORT_BEFORE) {
393 DEBUG_LOG("rw",("PRESENT BEFORE "));
394 } else {
395 DEBUG_LOG("rw",("PRESENT AFTER "));
396 }
397 }
398 if(flags & COB_REPORT_PAGE) DEBUG_LOG("rw",("PAGE "));
399 if(flags & COB_REPORT_ALL) DEBUG_LOG("rw",("ALL "));
400 }
401 else if(flags & COB_REPORT_HAD_WHEN) DEBUG_LOG("rw",("WHEN "));
402 }
403 #endif
404
405 #ifdef COB_DEBUG_LOG
406 static void
reportDumpOneLine(const cob_report * r,cob_report_line * fl,int indent,int dumpdata)407 reportDumpOneLine(const cob_report *r, cob_report_line *fl, int indent, int dumpdata)
408 {
409 cob_report_field *rf;
410 cob_report_control *c;
411 cob_report_control_ref *rr;
412 cob_report_control *rc;
413 int sequence = -1;
414 char idnt[48], wrk[200];
415
416 if (!DEBUG_ISON("rw")) {
417 return;
418 }
419 sprintf(idnt,"%.*s",indent>30?30:indent,"..................................");
420 DEBUG_LOG("rw",("%s ",idnt));
421 if (dumpdata) {
422 DEBUG_LOG("rw",("Line# %d of Page# %d; ",r->curr_line,r->curr_page));
423 }
424 if (r->controls) {
425 for(c=r->controls; c; c = c->next) {
426 for(rr=c->control_ref; rr; rr=rr->next) {
427 if(rr->ref_line == fl) {
428 strcpy(wrk,c->name);
429 sequence = c->sequence;
430 break;
431 }
432 }
433 }
434 }
435 dumpFlags(fl->report_flags,fl->line,wrk);
436 if(fl->step_count) DEBUG_LOG("rw",("Step %3d ",fl->step_count));
437 if(fl->suppress) DEBUG_LOG("rw",("Suppress Line "));
438 if(fl->next_group_line) {
439 DEBUG_LOG("rw",("NEXT ",fl->next_group_line));
440 if(fl->report_flags & COB_REPORT_NEXT_GROUP_LINE) DEBUG_LOG("rw",("GROUP LINE "));
441 if(fl->report_flags & COB_REPORT_NEXT_GROUP_PLUS) DEBUG_LOG("rw",("GROUP PLUS "));
442 if(fl->report_flags & COB_REPORT_NEXT_GROUP_PAGE) DEBUG_LOG("rw",("GROUP PAGE "));
443 DEBUG_LOG("rw",("%d ",fl->next_group_line));
444 } else {
445 if(fl->report_flags & COB_REPORT_NEXT_GROUP_PAGE) DEBUG_LOG("rw",("NEXT GROUP PAGE "));
446 }
447 if(fl->control) {
448 cob_field_to_string(fl->control, wrk, sizeof(wrk)-1);
449 if(wrk[0] >= ' ')
450 DEBUG_LOG("rw",("Line Control %d is '%s' ",sequence,wrk));
451 }
452 DEBUG_LOG("rw",("\n"));
453 if(!(fl->flags & COB_REPORT_DETAIL)) dumpdata = 1;
454 for(rf = fl->fields; rf; rf = rf->next) {
455 DEBUG_LOG("rw",("%s %02d Field ",idnt,rf->level));
456 if(rf->line) DEBUG_LOG("rw",("Line %2d ",rf->line));
457 if(rf->column) DEBUG_LOG("rw",("Col %3d ",rf->column));
458 if(rf->step_count) DEBUG_LOG("rw",("Step %3d ",rf->step_count));
459 if(rf->next_group_line) DEBUG_LOG("rw",("NextGrp %d ",rf->next_group_line));
460 if(dumpdata) {
461 if(!(rf->flags & COB_REPORT_GROUP_ITEM)) {
462 if(rf->f) {
463 if(rf->litval) {
464 DEBUG_LOG("rw",(" \"%s\" ",rf->litval));
465 } else {
466 cob_field_to_string(rf->f, wrk, sizeof(wrk)-1);
467 DEBUG_LOG("rw",(" '%s' ",wrk));
468 }
469 }
470 }
471 if(rf->source
472 && cob_cmp(rf->f,rf->source) != 0) {
473 if(rf->source == r->page_counter) {
474 DEBUG_LOG("rw",("Source PAGE-COUNTER "));
475 } else if(rf->source == r->line_counter) {
476 DEBUG_LOG("rw",("Source LINE-COUNTER "));
477 }
478 }
479 if((rf->flags & COB_REPORT_PRESENT)
480 && !rf->present_now
481 && r->initiate_done) {
482 dumpFlags(rf->flags& ~(COB_REPORT_PRESENT|COB_REPORT_HAD_WHEN),rf->line,NULL);
483 if((rf->flags & COB_REPORT_NEGATE))
484 DEBUG_LOG("rw",("ABSENT"));
485 else
486 DEBUG_LOG("rw",("Not PRESENT"));
487 } else
488 if((rf->flags & COB_REPORT_GROUP_ITEM)
489 && rf->suppress) {
490 dumpFlags(rf->flags& ~(COB_REPORT_GROUP_ITEM|COB_REPORT_HAD_WHEN),rf->line,NULL);
491 DEBUG_LOG("rw",("Suppress group"));
492 } else {
493 dumpFlags(rf->flags,rf->line,NULL);
494 }
495 if(rf->control
496 && (!(rf->flags & COB_REPORT_PRESENT) || rf->present_now || !r->initiate_done) ) {
497 strcpy(wrk,"");
498 for(rc = r->controls; rc; rc = rc->next) {
499 if(rc->f == rf->control) {
500 strcpy(wrk,rc->name);
501 break;
502 }
503 }
504 if(wrk[0] >= ' ')
505 DEBUG_LOG("rw",("Control %s ",wrk));
506 }
507 }
508 if(!(rf->flags & COB_REPORT_GROUP_ITEM)
509 && rf->suppress)
510 DEBUG_LOG("rw",("Suppress field"));
511 DEBUG_LOG("rw",("\n"));
512 }
513 }
514 #endif
515
516 #ifdef COB_DEBUG_LOG
517 /*
518 * Dump REPORT line and walk down tree
519 */
520 static void
reportDumpLine(const cob_report * r,cob_report_line * fl,int indent)521 reportDumpLine(const cob_report *r, cob_report_line *fl, int indent)
522 {
523 if(!DEBUG_ISON("rw"))
524 return;
525 reportDumpOneLine(r,fl,indent,0);
526 if(fl->child)
527 reportDumpLine(r,fl->child,indent+2);
528 if(fl->sister)
529 reportDumpLine(r,fl->sister,indent);
530 }
531 #endif
532
533 #ifdef COB_DEBUG_LOG
534 /*
535 * Dump entire REPORT definition tables
536 */
537 static void
reportDump(const cob_report * r,const char * msg)538 reportDump(const cob_report *r, const char *msg)
539 {
540 cob_report_control *c;
541 char wrk[80];
542
543 if (!DEBUG_ISON("rw")) {
544 return;
545 }
546 DEBUG_LOG("rw",("Dump of Report '%s' for %s\n",r->report_name,msg));
547 if (r->report_file) {
548 DEBUG_LOG("rw",("Using File %s ",r->report_file->select_name));
549 if(r->report_file->assign
550 && r->report_file->assign->data) {
551 DEBUG_LOG("rw",(" ASSIGNed to %s",r->report_file->assign->data));
552 }
553 DEBUG_LOG("rw",(" Rcsz min %d max %d ",r->report_file->record_min,r->report_file->record_max));
554 #if 0
555 /*
556 * TODO: This needs more work. Cross check how fileio.c handles print files
557 * and exactly what operations should be used
558 */
559 if(r->report_file->flag_select_features & COB_SELECT_LINAGE) {
560 DEBUG_LOG("rw",("has LINAGE"));
561 } else {
562 /*
563 * Create LINAGE clause fields for fileio.c so that
564 * the output file looks more like what Micro Focus would create
565 */
566 cob_linage *lingptr;
567 if(r->report_file->linorkeyptr == NULL) {
568 r->report_file->linorkeyptr = cob_malloc(sizeof(cob_linage));
569 lingptr = r->report_file->linorkeyptr;
570 lingptr->lin_top = r->def_heading;
571 lingptr->lin_bot = r->def_footing;
572 lingptr->linage = cob_field_dup(r->line_counter,0);
573 lingptr->linage_ctr = cob_field_dup(r->line_counter,0);
574 r->report_file->flag_select_features |= COB_SELECT_LINAGE;
575 }
576 DEBUG_LOG("rw",("had NO LINAGE!"));
577 }
578 #endif
579 DEBUG_LOG("rw",("\n"));
580 }
581 DEBUG_LOG("rw",("\n"));
582 DEBUG_LOG("rw",("Default Lines: %4d Columns: %4d\n",r->def_lines,r->def_cols));
583 DEBUG_LOG("rw",(" Heading: %4d Footing: %4d\n",r->def_heading,r->def_footing));
584 DEBUG_LOG("rw",(" Detail: %4d Control: %4d Last detail: %4d\n",r->def_first_detail,
585 r->def_last_control,r->def_last_detail));
586 if((r->curr_page+r->curr_status+r->curr_line+r->curr_cols) > 0) {
587 DEBUG_LOG("rw",("Current Page: %4d Status: %4d\n",r->curr_page,r->curr_status));
588 DEBUG_LOG("rw",(" Line: %4d Column: %4d\n",r->curr_line,r->curr_cols));
589 }
590 DEBUG_LOG("rw",("\n"));
591 if(r->controls) {
592 for(c=r->controls; c; c = c->next) {
593 DEBUG_LOG("rw",(" Control %s ",c->name));
594 if(c->f) {
595 cob_field_to_string(c->f, wrk, sizeof(wrk)-1);
596 if(wrk[0] >= ' ')
597 DEBUG_LOG("rw",("has '%s' ",wrk));
598 }
599 if(c->val) {
600 cob_field_to_string(c->val, wrk, sizeof(wrk)-1);
601 if(wrk[0] >= ' ')
602 DEBUG_LOG("rw",("Value '%s' ",wrk));
603 }
604 DEBUG_LOG("rw",("\n"));
605 }
606 }
607 reportDumpLine(r,r->first_line,0);
608 DEBUG_LOG("rw",("\n"));
609 }
610 #endif
611
612 /*
613 * Verify that each LINE # is within PAGE LIMITS
614 */
615 static void
limitCheckOneLine(cob_report * r,cob_report_line * fl)616 limitCheckOneLine(cob_report *r, cob_report_line *fl)
617 {
618 cob_report_field *rf;
619
620 if((fl->line > 0 && r->def_lines > 0 && fl->line > r->def_lines)) {
621 cob_runtime_error (_("INITIATE %s LINE %d exceeds PAGE LIMIT %d"),r->report_name,fl->line,r->def_lines);
622 DEBUG_LOG("rw",("PAGE LIMITs is incorrect; LINE %d > LIMIT %d\n",fl->line,r->def_lines));
623 cob_set_exception (COB_EC_REPORT_PAGE_LIMIT);
624 r->initiate_done = FALSE;
625 return;
626 }
627 if((fl->next_group_line > 0 && r->def_lines > 0 && fl->next_group_line > r->def_lines)) {
628 cob_runtime_error (_("INITIATE %s NEXT GROUP %d exceeds PAGE LIMIT"),r->report_name,fl->next_group_line);
629 DEBUG_LOG("rw",("PAGE LIMITs is incorrect; NEXT GROUP %d > LIMIT %d\n",fl->next_group_line,r->def_lines));
630 cob_set_exception (COB_EC_REPORT_PAGE_LIMIT);
631 r->initiate_done = FALSE;
632 return;
633 }
634 for(rf = fl->fields; rf; rf = rf->next) {
635 if((rf->line && rf->line > r->def_lines)) {
636 cob_runtime_error (_("INITIATE %s LINE %d exceeds PAGE LIMIT"),r->report_name,rf->line);
637 DEBUG_LOG("rw",("PAGE LIMITs is incorrect; LINE %d > LIMIT %d\n",rf->line,r->def_lines));
638 cob_set_exception (COB_EC_REPORT_PAGE_LIMIT);
639 r->initiate_done = FALSE;
640 return;
641 }
642 if((rf->next_group_line && rf->next_group_line > r->def_lines)) {
643 cob_runtime_error (_("INITIATE %s NEXT GROUP %d exceeds PAGE LIMIT"),r->report_name,rf->next_group_line);
644 DEBUG_LOG("rw",("PAGE LIMITs is incorrect; NEXT GROUP %d > LIMIT %d\n",rf->next_group_line,r->def_lines));
645 cob_set_exception (COB_EC_REPORT_PAGE_LIMIT);
646 r->initiate_done = FALSE;
647 return;
648 }
649 }
650 }
651
652 /*
653 * Verify that LINE # is within PAGE LIMITS
654 */
655 static void
limitCheckLine(cob_report * r,cob_report_line * fl)656 limitCheckLine(cob_report *r, cob_report_line *fl)
657 {
658 limitCheckOneLine(r,fl);
659 if(fl->child)
660 limitCheckLine(r,fl->child);
661 if(fl->sister)
662 limitCheckLine(r,fl->sister);
663 }
664
665 /*
666 * Verify that all LINE # are within PAGE LIMITS
667 */
668 static void
limitCheck(cob_report * r)669 limitCheck(cob_report *r)
670 {
671 limitCheckLine(r,r->first_line);
672 }
673
674 static void
saveLineCounter(cob_report * r)675 saveLineCounter(cob_report *r)
676 {
677 int ln = r->curr_line;
678 if(ln > r->def_lines)
679 ln = 0;
680 if(ln < 0)
681 ln = 0;
682
683 cob_set_int(r->page_counter,r->curr_page);
684 cob_set_int(r->line_counter,ln);
685 }
686
687 /*
688 * Search one LINE for Control field
689 */
690 static void
line_control_one(cob_report * r,cob_report_line * l,cob_field * f)691 line_control_one (cob_report *r, cob_report_line *l, cob_field *f)
692 {
693 cob_report_field *rf;
694 cob_report_control *rc;
695 char fld[COB_MAX_WORDLEN + 1];
696 if (l == NULL)
697 return;
698 for(rf = l->fields; rf; rf = rf->next) {
699 if(!(rf->flags & COB_REPORT_PRESENT))
700 continue;
701 fld[0] = 0;
702 for (rc = r->controls; rc; rc = rc->next) {
703 if (rc->f == rf->control) {
704 strncpy (fld, rc->name, COB_MAX_WORDLEN);
705 fld[COB_MAX_WORDLEN] = 0;
706 break;
707 }
708 }
709 if(!(rf->flags & COB_REPORT_NEGATE)
710 && !rf->present_now) {
711 if(f == NULL) { /* New Page */
712 DEBUG_LOG("rw",("PRESENT NOW: %s NEW PAGE\n",fld));
713 if(rf->flags & COB_REPORT_PAGE) { /* PRESENT After New Page */
714 rf->present_now = 1;
715 }
716 } else if(rf->control == f) { /* Control field changed */
717 DEBUG_LOG("rw",("PRESENT NOW: %s control change\n",fld));
718 rf->present_now = 1;
719 }
720 } else
721 if((rf->flags & COB_REPORT_NEGATE)
722 && rf->present_now) {
723 if(f == NULL) { /* New Page */
724 DEBUG_LOG("rw",("ABSENT NOW: %s NEW PAGE\n",fld));
725 if(rf->flags & COB_REPORT_PAGE) { /* PRESENT After New Page */
726 rf->present_now = 0;
727 }
728 } else if(rf->control == f) { /* Control field changed */
729 DEBUG_LOG("rw",("ABSENT NOW: %s control change\n",fld));
730 rf->present_now = 0;
731 }
732 }
733 }
734 }
735
736 /*
737 * Search Report for Control field
738 */
739 static void
line_control_chg(cob_report * r,cob_report_line * l,cob_field * f)740 line_control_chg(cob_report *r, cob_report_line *l, cob_field *f)
741 {
742 line_control_one(r,l,f);
743 if(l->child)
744 line_control_chg(r,l->child,f);
745 if(l->sister)
746 line_control_chg(r,l->sister,f);
747 }
748
749 /*
750 * Write one line of report
751 */
752 static void
write_rec(cob_report * r,int opt)753 write_rec(cob_report *r, int opt)
754 {
755 cob_file *f = r->report_file;
756 int num = opt & COB_WRITE_MASK;
757
758 if (f->record->size > (unsigned int)r->def_cols) /* Truncate line if needed */
759 f->record->size = r->def_cols;
760
761 if (r->code_is_present
762 && r->code_len > 0) { /* Insert CODE IS value */
763 if (f->file) {
764 if (num > 1
765 && (opt & COB_WRITE_LINES)) {
766 opt = (opt & ~COB_WRITE_MASK) | 1;
767 while (num > 0) {
768 fwrite(r->code_is, r->code_len, 1, (FILE*)f->file);
769 cob_write(f, f->record, opt, NULL, 0);
770 memset(f->record->data,' ',f->record->size);
771 num--;
772 }
773 } else {
774 fwrite(r->code_is, r->code_len, 1, (FILE*)f->file);
775 cob_write(f, f->record, opt, NULL, 0);
776 }
777 }
778 } else {
779 cob_write(f, f->record, opt, NULL, 0);
780 }
781 }
782
783 /*
784 * Write the Page Footing
785 */
786 static void
do_page_footing(cob_report * r)787 do_page_footing(cob_report *r)
788 {
789 cob_file *f = r->report_file;
790 char *rec;
791
792 if(r->in_page_footing)
793 return;
794 rec = (char *)f->record->data;
795 r->in_page_footing = TRUE;
796 report_line_type(r,r->first_line,COB_REPORT_PAGE_FOOTING);
797 memset(rec,' ',f->record_max);
798 if(r->curr_line < r->def_lines) {
799 write_rec(r, COB_WRITE_BEFORE|COB_WRITE_LINES|(r->def_lines-r->curr_line));
800 r->curr_line = r->def_lines;
801 r->incr_line = FALSE;
802 } else {
803 r->curr_line = 1;
804 }
805 saveLineCounter(r);
806 r->first_detail = TRUE;
807 r->in_page_footing = FALSE;
808 }
809
810 /*
811 * Write the Page Heading
812 */
813 static void
do_page_heading(cob_report * r)814 do_page_heading(cob_report *r)
815 {
816 cob_file *f = r->report_file;
817 char *rec;
818 int opt;
819
820 if(r->in_page_heading)
821 return;
822 opt = COB_WRITE_BEFORE | COB_WRITE_LINES | 1;
823 rec = (char *)f->record->data;
824 memset(rec,' ',f->record_max);
825 if(!r->in_page_heading
826 && !r->first_generate
827 && r->def_lines > 0
828 && r->def_heading > 0
829 && r->curr_line <= r->def_lines
830 && r->curr_line > r->def_heading) { /* Skip to end of page */
831 while(r->curr_line <= r->def_lines) {
832 write_rec(r, opt);
833 r->curr_line++;
834 }
835 if(r->curr_line > r->def_lines) /* Reset line to 1 */
836 r->curr_line = 1;
837 saveLineCounter(r);
838 }
839 r->in_page_heading = TRUE;
840 if(!r->first_generate) {
841 r->curr_page++;
842 }
843 r->first_detail = FALSE;
844 while(r->curr_line < r->def_heading) { /* Skip to Heading position on page */
845 write_rec(r, opt);
846 r->curr_line++;
847 saveLineCounter(r);
848 }
849 report_line_type(r,r->first_line,COB_REPORT_PAGE_HEADING);
850 memset(rec,' ',f->record_max);
851 while(r->curr_line < r->def_first_detail) {
852 write_rec(r, opt);
853 r->curr_line++;
854 saveLineCounter(r);
855 }
856 clear_group_indicate(r->first_line);
857 r->in_page_heading = FALSE;
858 line_control_chg(r, r->first_line, NULL);
859 }
860
861 /*
862 * Format one field into print line
863 */
864 static void
print_field(cob_report_field * rf,char * rec)865 print_field(cob_report_field *rf, char *rec)
866 {
867 char wrk[COB_SMALL_BUFF];
868 size_t ln, k, i;
869 size_t dest_pos = (size_t)rf->column - 1;
870
871 cob_field_to_string(rf->f, wrk, sizeof(wrk)-1);
872 wrk[COB_SMALL_MAX] = 0; /* keep analyzer happy */
873 ln = strlen(wrk);
874 if(cobsetptr
875 && !cobsetptr->cob_col_just_lrc) {
876 /* Data justify is turned off, no adjustment */
877 } else
878 if((rf->flags & COB_REPORT_COLUMN_RIGHT)
879 && ln < rf->f->size) {
880 dest_pos += rf->f->size - ln;
881 } else
882 if((rf->flags & COB_REPORT_COLUMN_CENTER)) {
883 for(k=0; k < rf->f->size && wrk[0] == ' ' && ln > 0; k++) { /* remove leading spaces */
884 memmove(wrk,&wrk[1],ln);
885 ln--;
886 }
887 i = 1- (ln & 1);
888 if (ln < rf->f->size) {
889 dest_pos += (rf->f->size - ln - i) / 2;
890 }
891 } else
892 if((rf->flags & COB_REPORT_COLUMN_LEFT)) {
893 for(k=0; k < rf->f->size && wrk[0] == ' ' && ln > 0; k++) { /* remove leading spaces */
894 memmove(wrk,&wrk[1],ln);
895 ln--;
896 }
897 }
898 memcpy (&rec[dest_pos], wrk, ln);
899 }
900
901 /*
902 * GENERATE one report-line
903 */
904 static void
report_line(cob_report * r,cob_report_line * l)905 report_line(cob_report *r, cob_report_line *l)
906 {
907 cob_report_field *rf,*nrf,*prf;
908 cob_file *f = r->report_file;
909 char *rec,wrk[COB_SMALL_BUFF];
910 int bChkLinePlus = FALSE;
911 int opt;
912
913 opt = COB_WRITE_BEFORE | COB_WRITE_LINES | 1;
914 rec = (char *)f->record->data;
915 if(rec) {
916 memset(rec,' ',f->record_max);
917 memset(wrk,0,sizeof(wrk));
918 if(r->curr_line > r->def_last_detail
919 && !r->in_report_footing
920 && !r->in_page_footing) { /* Page overflow */
921 do_page_footing(r);
922 do_page_heading(r);
923 }
924 if(!r->next_just_set && r->next_line_plus) {
925 DEBUG_LOG("rw",(" Line# %d of Page# %d; ",r->curr_line,r->curr_page));
926 DEBUG_LOG("rw",("Execute NEXT GROUP PLUS %d\n",r->next_value));
927 opt = COB_WRITE_BEFORE | COB_WRITE_LINES | (r->next_value);
928 write_rec(r, opt);
929 r->curr_line += r->next_value;
930 r->next_line_plus = FALSE;
931 bChkLinePlus = TRUE;
932 } else
933 if(!r->next_just_set && r->next_line) {
934 DEBUG_LOG("rw",(" Line# %d of Page# %d; ",r->curr_line,r->curr_page));
935 DEBUG_LOG("rw",("Execute NEXT GROUP LINE %d\n",r->next_value));
936 r->next_line = FALSE;
937 if(r->curr_line > r->next_value) {
938 do_page_footing(r);
939 do_page_heading(r);
940 }
941 while(r->curr_line < r->next_value) {
942 write_rec(r, opt);
943 r->curr_line++;
944 }
945 bChkLinePlus = TRUE;
946 } else
947 if(!r->next_just_set && r->next_page) {
948 DEBUG_LOG("rw",(" Line# %d of Page# %d; ",r->curr_line,r->curr_page));
949 DEBUG_LOG("rw",(" Execute NEXT GROUP PAGE\n"));
950 r->next_page = FALSE;
951 do_page_footing(r);
952 do_page_heading(r);
953 DEBUG_LOG("rw",(" Line# %d of Page# %d; after foot/head\n",r->curr_line,r->curr_page));
954 } else
955 if( !(l->flags & COB_REPORT_LINE_PLUS)
956 && (l->flags & COB_REPORT_LINE)) {
957 if(r->curr_line > l->line) {
958 DEBUG_LOG("rw",(" Eject Page %d from line %d for Line %d\n",r->curr_page,r->curr_line,l->line));
959 do_page_footing(r);
960 if(r->in_report_footing) {
961 r->curr_page++; /* Now on next page */
962 r->curr_line = 1;
963 } else {
964 do_page_heading(r);
965 }
966 r->first_detail = FALSE;
967 }
968 while(r->curr_line < l->line) {
969 write_rec(r, opt);
970 r->curr_line++;
971 }
972 } else {
973 bChkLinePlus = TRUE;
974 }
975
976 if(bChkLinePlus
977 && (l->flags & COB_REPORT_LINE_PLUS)
978 && l->line > 1) {
979 if(r->curr_line != r->def_first_detail
980 || r->def_first_detail == 0) {
981 opt = COB_WRITE_BEFORE | COB_WRITE_LINES | (l->line - 1);
982 write_rec(r, opt);
983 r->curr_line += l->line - 1;
984 }
985 }
986 bChkLinePlus = FALSE;
987 if(r->curr_line > r->def_last_detail
988 && !r->in_report_footing
989 && !r->in_page_heading
990 && !r->in_page_footing) { /* Page overflow */
991 do_page_footing(r);
992 do_page_heading(r);
993 }
994 saveLineCounter(r);
995 if(l->fields == NULL) {
996 set_next_info(r,l);
997 return;
998 }
999 if(l->suppress) {
1000 #ifdef COB_DEBUG_LOG
1001 if(DEBUG_ISON("rw")) {
1002 reportDumpOneLine(r,l,0,1);
1003 DEBUG_LOG("rw",(" ^^^ Complete line Suppressed ^^^\n\n"));
1004 }
1005 #endif
1006 set_next_info(r,l);
1007 return;
1008 }
1009
1010 /*
1011 * Copy fields to print line area
1012 */
1013 for(rf = l->fields; rf; rf = rf->next) {
1014 if((rf->flags & COB_REPORT_GROUP_ITEM)) {
1015 if(rf->suppress) {
1016 /* group item SUPPRESSed printing, so skip to next field */
1017 rf->suppress = FALSE;
1018 prf = rf;
1019 for(nrf = rf->next; nrf && nrf->level > rf->level; nrf = nrf->next) {
1020 prf = nrf;
1021 }
1022 if(prf) {
1023 rf = prf; /* Continue from here */
1024 continue;
1025 }
1026 break; /* No more so, end of print line */
1027 }
1028 continue; /* Group items are not printed */
1029 }
1030 if( (rf->flags & COB_REPORT_PRESENT)
1031 && !rf->present_now) {
1032 continue;
1033 }
1034 if(rf->suppress
1035 || rf->group_indicate) {
1036 if(rf->source) { /* Copy source field in */
1037 cob_field_to_string(rf->source, wrk, sizeof(wrk)-1);
1038 }
1039 continue;
1040 }
1041 if(rf->source) { /* Copy source field in */
1042 cob_move(rf->source,rf->f);
1043 print_field(rf, rec);
1044 } else if(rf->litval) { /* Refresh literal value */
1045 if(rf->f) {
1046 cob_str_move(rf->f, (unsigned char*)rf->litval, rf->litlen);
1047 }
1048 memcpy(&rec[rf->column-1], rf->litval, rf->litlen);
1049 } else if(rf->f) {
1050 print_field(rf, rec);
1051 }
1052 if((rf->flags & COB_REPORT_GROUP_INDICATE)) { /* Suppress subsequent printings */
1053 rf->group_indicate = TRUE;
1054 }
1055 }
1056 }
1057 #ifdef COB_DEBUG_LOG
1058 if(DEBUG_ISON("rw")) {
1059 reportDumpOneLine(r,l,0,1);
1060 for(opt = f->record_max; opt > 1 && rec[opt-1] == ' '; opt--);
1061 DEBUG_LOG("rw",("%.*s\n\n",opt,rec));
1062 }
1063 #endif
1064 for(rf = l->fields; rf; rf = rf->next) {
1065 rf->present_now = (rf->flags & COB_REPORT_NEGATE)?1:0;
1066 }
1067 if(rec) {
1068 opt = COB_WRITE_BEFORE | COB_WRITE_LINES | 1;
1069 write_rec(r, opt);
1070 r->curr_line ++;
1071 saveLineCounter(r);
1072 }
1073
1074 set_next_info(r,l);
1075 }
1076
1077 /*
1078 * GENERATE one report-line
1079 */
1080 static void
report_line_and(cob_report * r,cob_report_line * l,int type)1081 report_line_and(cob_report *r, cob_report_line *l, int type)
1082 {
1083 if(l == NULL)
1084 return;
1085 if(l->fields == NULL
1086 && l->child != NULL) {
1087 if(l->flags & type) {
1088 report_line(r,l);
1089 if(l->child) {
1090 report_line_type(r,l->child,COB_REPORT_LINE);
1091 }
1092 return;
1093 }
1094 l = l->child;
1095 }
1096 report_line_type(r,l,type);
1097 }
1098
1099 /*
1100 * Find Report Line of given type
1101 */
1102 static cob_report_line *
get_line_type(cob_report * r,cob_report_line * l,int type)1103 get_line_type(cob_report *r, cob_report_line *l, int type)
1104 {
1105 cob_report_line *t;
1106 if(l == NULL)
1107 return NULL;
1108 if(l->flags & type) {
1109 return l;
1110 }
1111 if(l->child)
1112 if ((t = get_line_type(r,l->child,type)) != NULL)
1113 return t;
1114 if(l->sister)
1115 return get_line_type(r,l->sister,type);
1116 return NULL;
1117 }
1118
1119
1120 /*
1121 * GENERATE report-line(s) of type
1122 */
1123 static int
report_line_type(cob_report * r,cob_report_line * l,int type)1124 report_line_type(cob_report *r, cob_report_line *l, int type)
1125 {
1126 int curseq,sisseq;
1127 if(l == NULL)
1128 return 0;
1129 if(l->flags & type) {
1130 report_line(r,l);
1131 if(l->child) {
1132 report_line_type(r,l->child,COB_REPORT_LINE);
1133 }
1134 if(l->sister) {
1135 if((type == COB_REPORT_CONTROL_FOOTING)
1136 && (l->sister->flags & COB_REPORT_CONTROL_FOOTING)) {
1137 curseq = get_control_sequence(r,l);
1138 sisseq = get_control_sequence(r,l->sister);
1139 if(curseq > 0
1140 && sisseq > 0
1141 && sisseq > curseq) {
1142 #ifdef COB_DEBUG_LOG
1143 reportDumpOneLine(r,l->sister,0,1);
1144 #endif
1145 return 1;
1146 }
1147 }
1148 report_line_type(r,l->sister,type);
1149 }
1150 return 1;
1151 }
1152 if(l->child)
1153 if(report_line_type(r,l->child,type))
1154 return 1;
1155 if(l->sister)
1156 return report_line_type(r,l->sister,type);
1157 return 0;
1158 }
1159
1160 /*
1161 * SUM all DETAIL counters
1162 */
1163 static void
sum_all_detail(cob_report * r)1164 sum_all_detail(cob_report *r)
1165 {
1166 cob_report_sum_ctr *sc;
1167 cob_report_sum *rs;
1168 int bHasSum = FALSE;
1169
1170 /*
1171 * Add up all SUM counter values
1172 */
1173 for(sc = r->sum_counters; sc; sc = sc->next) {
1174 for(rs = sc->sum; rs && !sc->subtotal; rs = rs->next) {
1175 if(!bHasSum) {
1176 bHasSum = TRUE;
1177 DEBUG_LOG("rw",(" Do SUM detail counters:\n"));
1178 }
1179 DEBUG_LOG("rw",(" .. %-20s ",sc->name));
1180 cob_add_fields(sc->counter,rs->f,sc->counter);
1181 }
1182 }
1183 }
1184
1185 /*
1186 * If the counter is part of another SUM then it is 'rolling forward'
1187 */
1188 static void
sum_this_counter(cob_report * r,cob_field * counter)1189 sum_this_counter(cob_report *r, cob_field *counter)
1190 {
1191 cob_report_sum_ctr *sc;
1192 cob_report_sum *rs;
1193
1194 for(sc = r->sum_counters; sc; sc = sc->next) {
1195 for(rs = sc->sum; rs; rs = rs->next) {
1196 if(rs->f == counter) {
1197 DEBUG_LOG("rw",("SUM %s forward ",sc->name));
1198 for(rs = sc->sum; rs; rs = rs->next) {
1199 cob_add_fields(sc->counter,rs->f,sc->counter);
1200 }
1201 break;
1202 }
1203 }
1204 }
1205 }
1206
1207 /*
1208 * ZERO counters for a given control level
1209 */
1210 static void
zero_all_counters(cob_report * r,int flag,cob_report_line * l)1211 zero_all_counters(cob_report *r, int flag, cob_report_line *l)
1212 {
1213 cob_report_sum_ctr *sc;
1214 cob_report_sum *rs;
1215 cob_report_control *rc;
1216 cob_report_control_ref *rr;
1217
1218 l = get_print_line(l);
1219 /*
1220 * ZERO SUM counter
1221 */
1222 for(sc = r->sum_counters; sc; sc = sc->next) {
1223 for(rs = sc->sum; rs; rs = rs->next) {
1224 if((flag & COB_REPORT_CONTROL_FOOTING_FINAL)) {
1225 if(sc->control_final) {
1226 DEBUG_LOG("rw",("ZERO SUM Counter %s for FOOTING FINAL\n",sc->name));
1227 cob_field_init(sc->counter);
1228 }
1229 } else if(sc->control) {
1230 rc = sc->control;
1231 for(rr = rc->control_ref; rr; rr=rr->next) {
1232 if(rr->ref_line
1233 && (rr->ref_line->flags & COB_REPORT_CONTROL_HEADING))
1234 continue;
1235 if(rr->ref_line
1236 && (rr->ref_line->flags & COB_REPORT_CONTROL_HEADING_FINAL))
1237 continue;
1238 if(l != NULL
1239 && l != get_print_line(rr->ref_line))
1240 continue;
1241 if(rr->ref_line
1242 && (rr->ref_line->flags & flag)) {
1243 sum_this_counter(r,sc->counter);
1244 #if defined(COB_DEBUG_LOG)
1245 DEBUG_LOG("rw",("ZERO SUM counter %s for ",sc->name));
1246 dumpFlags(rr->ref_line->flags,0,(char*)rc->name);
1247 DEBUG_LOG("rw",("\n"));
1248 #endif
1249 cob_field_init(sc->counter);
1250 }
1251 }
1252 }
1253 }
1254 }
1255 }
1256
1257 /*
1258 * Runtime starting up
1259 */
1260 void
cob_init_reportio(cob_global * gptr,cob_settings * sptr)1261 cob_init_reportio(cob_global *gptr, cob_settings *sptr)
1262 {
1263 int k;
1264 cobglobptr = gptr;
1265 cobsetptr = sptr;
1266 for(k=0; k < MAX_ACTIVE_REPORTS; k++)
1267 active_reports[k] = NULL;
1268 }
1269
1270 /*
1271 * Runtime exiting
1272 */
1273 void
cob_exit_reportio()1274 cob_exit_reportio()
1275 {
1276 int k;
1277 for(k=0; k < MAX_ACTIVE_REPORTS; k++) {
1278 if(active_reports[k] != NULL) {
1279 free_control_fields (active_reports[k]);
1280 }
1281 }
1282 }
1283
1284 /*
1285 * INITIATE report
1286 */
1287 void
cob_report_initiate(cob_report * r)1288 cob_report_initiate(cob_report *r)
1289 {
1290 cob_report_control *rc;
1291 cob_report_control_ref *rr;
1292 cob_report_sum_ctr *sc;
1293 int k;
1294
1295 reportInitialize();
1296 if(r->initiate_done) {
1297 cob_runtime_error (_("INITIATE %s was already done"),r->report_name);
1298 DEBUG_LOG("rw",("REPORT was already INITIATEd\n"));
1299 cob_set_exception (COB_EC_REPORT_ACTIVE);
1300 return;
1301 }
1302 if (r->def_lines > 9999)
1303 r->def_lines = 9999;
1304 if (r->def_cols > 999
1305 || r->def_cols < 1)
1306 r->def_cols = 999;
1307 if((r->def_first_detail > 0 && !(r->def_first_detail >= r->def_heading))
1308 || (r->def_last_detail > 0 && !(r->def_last_detail >= r->def_first_detail))
1309 || (r->def_footing > 0 && !(r->def_footing >= r->def_heading))
1310 || (r->def_footing > 0 && !(r->def_footing >= r->def_last_detail))
1311 || (r->def_lines > 0 && !(r->def_lines >= r->def_heading))
1312 || (r->def_lines > 0 && !(r->def_lines >= r->def_footing))) {
1313 cob_runtime_error (_("INITIATE %s PAGE LIMIT problem"),r->report_name);
1314 #if defined(COB_DEBUG_LOG)
1315 DEBUG_LOG("rw",("PAGE LIMITs is incorrect\n"));
1316 reportDump(r,"INITIATE");
1317 #endif
1318 cob_set_exception (COB_EC_REPORT_PAGE_LIMIT);
1319 return;
1320 }
1321 r->curr_page = 1;
1322 r->curr_line = 0;
1323 r->incr_line = TRUE;
1324 saveLineCounter(r);
1325 #if defined(COB_DEBUG_LOG)
1326 reportDump(r,"INITIATE");
1327 #endif
1328 r->initiate_done = TRUE;
1329 limitCheck(r);
1330 if(!r->initiate_done) /* Problem during LIMIT check */
1331 return;
1332 r->first_detail = TRUE;
1333 r->first_generate = TRUE;
1334 r->next_value = 0;
1335 r->next_line = 0;
1336 r->next_line_plus = FALSE;
1337 r->next_page = FALSE;
1338 /*
1339 * Allocate temp area for each control field
1340 */
1341 for(rc = r->controls; rc; rc = rc->next) {
1342 if(rc->val) {
1343 cob_field_free(rc->val);
1344 rc->val = NULL;
1345 }
1346 if(rc->sf) {
1347 cob_field_free(rc->sf);
1348 rc->sf = NULL;
1349 }
1350 rc->val = cob_field_dup(rc->f,0);
1351 rc->sf = cob_field_dup(rc->f,0);
1352 for(k=0; k < MAX_ACTIVE_REPORTS; k++) {
1353 if (active_reports[k] == r)
1354 break;
1355 if (active_reports[k] == NULL) {
1356 active_reports[k] = r;
1357 break;
1358 }
1359 }
1360 rc->has_heading = FALSE;
1361 rc->has_footing = FALSE;
1362 for(rr = rc->control_ref; rr; rr = rr->next) {
1363 if(rr->ref_line->flags & COB_REPORT_CONTROL_HEADING)
1364 rc->has_heading = TRUE;
1365 if(rr->ref_line->flags & COB_REPORT_CONTROL_HEADING_FINAL)
1366 rc->has_heading = TRUE;
1367 if(rr->ref_line->flags & COB_REPORT_CONTROL_FOOTING)
1368 rc->has_footing = TRUE;
1369 if(rr->ref_line->flags & COB_REPORT_CONTROL_FOOTING_FINAL)
1370 rc->has_footing = TRUE;
1371 }
1372 }
1373 for(sc = r->sum_counters; sc; sc = sc->next) {
1374 cob_field_init(sc->counter);
1375 }
1376 }
1377
1378 /*
1379 * TERMINATE report
1380 */
1381 int
cob_report_terminate(cob_report * r,int ctl)1382 cob_report_terminate (cob_report *r, int ctl)
1383 {
1384 cob_report_control *rc;
1385 cob_report_control_ref *rr;
1386 cob_report_line *pl;
1387
1388 if (!r->initiate_done) {
1389 DEBUG_LOG("rw",("INITIATE was never done!\n"));
1390 cob_runtime_error (_("TERMINATE %s but no INITIATE was done"),r->report_name);
1391 cob_set_exception (COB_EC_REPORT_INACTIVE);
1392 #if 0 /* TODO: if not enabled: ignore, if enabled and PROPAGATE ON (or TRY) active: handle */
1393 return 0;
1394 #else
1395 cob_stop_run (1);
1396 #endif
1397 }
1398 if (r->first_generate) {
1399 DEBUG_LOG("rw",("No GENERATE was ever done!\n"));
1400 return 0;
1401 }
1402 if (ctl > 0) { /* Continue Processing Footings from last point */
1403 for (rc = r->controls; rc; rc = rc->next) {
1404 for (rr = rc->control_ref; rr; rr = rr->next) {
1405 if (rr->ref_line->flags & COB_REPORT_CONTROL_FOOTING) {
1406 pl = get_print_line(rr->ref_line);
1407 if (rr->ref_line->use_decl == ctl) {
1408 DEBUG_LOG("rw",(" Continue after Declaratives %d\n",ctl));
1409 goto PrintFooting; /* Continue Footings */
1410 }
1411 if (pl != rr->ref_line
1412 && pl->use_decl == ctl) {
1413 DEBUG_LOG("rw",(" Continue after Declaratives %d\n",ctl));
1414 goto PrintFooting; /* Continue Footings */
1415 }
1416 }
1417 if (rr->ref_line->flags & COB_REPORT_CONTROL_FOOTING_FINAL) {
1418 pl = get_print_line(rr->ref_line);
1419 if (rr->ref_line->use_decl == ctl) {
1420 DEBUG_LOG("rw",(" Continue after Declaratives %d\n",ctl));
1421 goto PrintFootingFinal; /* Continue Footings */
1422 }
1423 if (pl != rr->ref_line
1424 && pl->use_decl == ctl) {
1425 DEBUG_LOG("rw",(" Continue after Declaratives %d\n",ctl));
1426 goto PrintFootingFinal; /* Continue Footings */
1427 }
1428 }
1429 if (rr->ref_line->flags & COB_REPORT_FOOTING) {
1430 pl = get_print_line(rr->ref_line);
1431 if (rr->ref_line->use_decl == ctl) {
1432 DEBUG_LOG("rw",(" Continue after Declaratives %d\n",ctl));
1433 goto PrintReportFooting;/* Continue Footings */
1434 }
1435 if (pl != rr->ref_line
1436 && pl->use_decl == ctl) {
1437 DEBUG_LOG("rw",(" Continue after Declaratives %d\n",ctl));
1438 goto PrintReportFooting;/* Continue Footings */
1439 }
1440 }
1441 }
1442 }
1443 DEBUG_LOG("rw",("Could not find Declarative %d\n",ctl));
1444 pl = get_line_type(r, r->first_line,COB_REPORT_CONTROL_FOOTING_FINAL);
1445 if( pl
1446 && pl->use_decl == ctl) {
1447 DEBUG_LOG("rw",(" Continue after Final Declaratives %d\n",ctl));
1448 goto PrintFootingFinal; /* Continue Footings */
1449 }
1450 pl = get_line_type(r, r->first_line,COB_REPORT_FOOTING);
1451 if (pl
1452 && pl->use_decl == ctl) {
1453 DEBUG_LOG("rw",(" Continue after Report Declaratives %d\n",ctl));
1454 goto PrintReportFooting; /* Continue Footings */
1455 }
1456 } else {
1457 reportInitialize();
1458 #if defined(COB_DEBUG_LOG)
1459 reportDump(r,"TERMINATE");
1460 #endif
1461 /* Do CONTROL FOOTING breaks */
1462 for(rc = r->controls; rc; rc = rc->next) {
1463 for(rr = rc->control_ref; rr; rr = rr->next) {
1464 if(rr->ref_line->flags & COB_REPORT_CONTROL_FOOTING) {
1465 if(rr->ref_line->use_decl) {
1466 DEBUG_LOG("rw",(" Return for %s Footing Declaratives %d\n",
1467 rc->name,rr->ref_line->use_decl));
1468 return rr->ref_line->use_decl;
1469 }
1470 pl = get_print_line(rr->ref_line);
1471 if(pl != rr->ref_line
1472 && pl->use_decl) {
1473 DEBUG_LOG("rw",(" Return for %s Footing Declaratives %d.\n",
1474 rc->name,pl->use_decl));
1475 return pl->use_decl; /* Back for DECLARATIVES */
1476 }
1477 PrintFooting:
1478 if(!rc->suppress)
1479 report_line_and(r,rr->ref_line,COB_REPORT_CONTROL_FOOTING);
1480 rc->suppress = FALSE;
1481 zero_all_counters(r, COB_REPORT_CONTROL_FOOTING,pl);
1482 }
1483 }
1484 }
1485
1486 }
1487
1488 /* Do CONTROL FOOTING FINAL */
1489 pl = get_line_type(r, r->first_line,COB_REPORT_CONTROL_FOOTING_FINAL);
1490 if(pl) {
1491 if(pl->use_decl) {
1492 DEBUG_LOG("rw",(" Return for Footing Final Declaratives %d.\n", pl->use_decl));
1493 return pl->use_decl; /* Back for DECLARATIVES */
1494 }
1495 PrintFootingFinal:
1496 report_line_type(r,r->first_line,COB_REPORT_CONTROL_FOOTING_FINAL);
1497 }
1498 zero_all_counters(r, COB_REPORT_CONTROL_FOOTING_FINAL,NULL);
1499
1500 do_page_footing(r);
1501
1502 pl = get_line_type(r, r->first_line,COB_REPORT_FOOTING);
1503 if(pl) {
1504 if(pl->use_decl) {
1505 DEBUG_LOG("rw",(" Return for Report Footing Declaratives %d.\n", pl->use_decl));
1506 return pl->use_decl; /* Back for DECLARATIVES */
1507 }
1508 PrintReportFooting:
1509 r->in_report_footing = TRUE;
1510 report_line_type(r,r->first_line,COB_REPORT_FOOTING);
1511 r->in_report_footing = FALSE;
1512 }
1513
1514 free_control_fields (r);
1515 r->initiate_done = FALSE;
1516 return 0;
1517 }
1518
1519 /*
1520 * GENERATE report-line
1521 */
1522 int
cob_report_generate(cob_report * r,cob_report_line * l,int ctl)1523 cob_report_generate (cob_report *r, cob_report_line *l, int ctl)
1524 {
1525 cob_report_control *rc, *rp;
1526 cob_report_control_ref *rr;
1527 cob_report_line *pl;
1528 int maxctl,ln,num,gengrp;
1529 #if defined(COB_DEBUG_LOG)
1530 char wrk[256];
1531 #endif
1532
1533 reportInitialize();
1534 if (!r->initiate_done) {
1535 cob_runtime_error (_("GENERATE %s but no INITIATE was done"),r->report_name);
1536 cob_set_exception (COB_EC_REPORT_INACTIVE);
1537 #if 0 /* TODO: if not enabled: ignore, if enabled and PROPAGATE ON (or TRY) active: handle */
1538 return 0;
1539 #else
1540 cob_stop_run (1);
1541 #endif
1542 }
1543
1544 r->foot_next_page = FALSE;
1545 DEBUG_LOG("rw",("~ Enter %sGENERATE with ctl == %d\n",r->first_generate?"first ":"",ctl));
1546 if (ctl > 0) { /* Continue Processing Footings from last point */
1547 for (rc = r->controls; rc; rc = rc->next) {
1548 for (rr = rc->control_ref; rr; rr = rr->next) {
1549 if (rr->ref_line->flags & COB_REPORT_CONTROL_FOOTING) {
1550 pl = get_print_line(rr->ref_line);
1551 if (rr->ref_line->use_decl == ctl) {
1552 DEBUG_LOG("rw",(" Continue after Declaratives %d\n",ctl));
1553 goto PrintFooting; /* Continue Footings */
1554 }
1555 if (pl != rr->ref_line
1556 && pl->use_decl == ctl) {
1557 DEBUG_LOG("rw",(" Continue after Declaratives %d\n",ctl));
1558 goto PrintFooting; /* Continue Footings */
1559 }
1560 }
1561 if (rr->ref_line->flags & COB_REPORT_CONTROL_HEADING) {
1562 pl = get_print_line(rr->ref_line);
1563 if (rr->ref_line->use_decl == ctl) {
1564 DEBUG_LOG("rw",(" Continue after Declaratives %d\n",ctl));
1565 if(r->first_generate)
1566 goto PrintFirstHeading;
1567 goto PrintHeading; /* Continue Footings */
1568 }
1569 if (pl != rr->ref_line
1570 && pl->use_decl == ctl) {
1571 DEBUG_LOG("rw",(" Continue after Declaratives %d\n",ctl));
1572 if (r->first_generate) {
1573 goto PrintFirstHeading;
1574 }
1575 goto PrintHeading; /* Continue Headings */
1576 }
1577 }
1578 }
1579 }
1580 DEBUG_LOG("rw",("Could not find Declarative %d\n",ctl));
1581 }
1582
1583 if (r->incr_line) {
1584 r->incr_line = FALSE;
1585 r->curr_line++;
1586 saveLineCounter(r);
1587 }
1588 if (r->first_generate) {
1589 /*
1590 * First GENERATE of the report
1591 */
1592 DEBUG_LOG("rw",("Process First GENERATE\n"));
1593 report_line_type(r,r->first_line,COB_REPORT_HEADING);
1594 do_page_heading(r);
1595 /* do CONTROL Headings */
1596 for(rc = r->controls; rc; rc = rc->next) {
1597 for(rr = rc->control_ref; rr; rr = rr->next) {
1598 if(rr->ref_line->flags & COB_REPORT_CONTROL_HEADING) {
1599 if(rr->ref_line->use_decl) {
1600 DEBUG_LOG("rw",(" Return first %s Heading Declaratives %d\n",
1601 rc->name,rr->ref_line->use_decl));
1602 return rr->ref_line->use_decl;
1603 }
1604 pl = get_print_line(rr->ref_line);
1605 if(pl != rr->ref_line
1606 && pl->use_decl) {
1607 DEBUG_LOG("rw",(" Return first %s Heading Declaratives %d.\n",
1608 rc->name,pl->use_decl));
1609 return pl->use_decl; /* Back for DECLARATIVES */
1610 }
1611 PrintFirstHeading:
1612 report_line_and(r,rr->ref_line,COB_REPORT_CONTROL_HEADING);
1613 }
1614 }
1615 cob_move (rc->f,rc->val); /* Save current field data */
1616 rc->data_change = FALSE;
1617 }
1618 DEBUG_LOG("rw",("Finished First GENERATE\n"));
1619
1620 } else {
1621
1622 if(r->curr_line > r->def_last_detail) { /* Page overflow */
1623 do_page_footing(r);
1624 r->curr_line = 1;
1625 do_page_heading(r);
1626 r->first_detail = FALSE;
1627 } else
1628 if(r->curr_line <= 1
1629 || r->first_detail) {
1630 if(r->first_detail) {
1631 r->curr_line = 1;
1632 }
1633 do_page_heading(r);
1634 r->first_detail = FALSE;
1635 }
1636
1637 /*
1638 * Check for FOOTINGs on other GENERATEs
1639 */
1640 maxctl = 0;
1641 for(rc = r->controls; rc; rc = rc->next) {
1642 rc->data_change = (cob_cmp(rc->f,rc->val) != 0);
1643 if(rc->data_change) { /* Data change, implies control break at lower levels */
1644 #if defined(COB_DEBUG_LOG)
1645 DEBUG_LOG("rw",(" Control Break %s order %d changed from ",
1646 rc->name,rc->sequence));
1647 cob_field_to_string(rc->val, wrk, sizeof(wrk)-1);
1648 DEBUG_LOG("rw",("'%s' to ",wrk));
1649 cob_field_to_string(rc->f, wrk, sizeof(wrk)-1);
1650 DEBUG_LOG("rw",("'%s'\n",wrk));
1651 #endif
1652 cob_move(rc->f, rc->sf); /* Save new CONTROL value */
1653 cob_move(rc->val,rc->f); /* Prev value for FOOTING */
1654 if(rc->sequence > maxctl)
1655 maxctl = rc->sequence;
1656
1657 }
1658 }
1659 if(maxctl > 0) {
1660 for(rp = r->controls; rp; rp = rp->next) {
1661 if(rp->sequence < maxctl
1662 && !rp->data_change) {
1663 rp->data_change = TRUE;
1664 DEBUG_LOG("rw",(" Control Break %s order %d also ...\n",
1665 rp->name,rp->sequence));
1666 cob_move(rp->f, rp->sf); /* Save CONTROL value */
1667 cob_move(rp->val,rp->f); /* Prev value for FOOTING */
1668 }
1669 }
1670 }
1671
1672 for(rc = r->controls; rc; rc = rc->next) {
1673 if(rc->data_change) { /* Data change, Check for PRESENT WHEN control-id */
1674 line_control_chg(r, r->first_line, rc->f);
1675 }
1676 }
1677
1678 for(rc = r->controls; rc; rc = rc->next) {
1679 if(rc->data_change) {
1680 for(rr = rc->control_ref; rr; rr = rr->next) {
1681 if(rr->ref_line->flags & COB_REPORT_CONTROL_FOOTING) {
1682 if(rr->ref_line->use_decl) {
1683 DEBUG_LOG("rw",(" Return for %s Footing Declaratives %d\n",
1684 rc->name,rr->ref_line->use_decl));
1685 return rr->ref_line->use_decl;
1686 }
1687 pl = get_print_line(rr->ref_line);
1688 if(pl != rr->ref_line
1689 && pl->use_decl) {
1690 DEBUG_LOG("rw",(" Return for %s Footing Declaratives %d.\n",
1691 rc->name,pl->use_decl));
1692 return pl->use_decl; /* Back for DECLARATIVES */
1693 }
1694 PrintFooting:
1695 if(!rc->suppress
1696 && !rr->ref_line->suppress)
1697 report_line_and(r,rr->ref_line,COB_REPORT_CONTROL_FOOTING);
1698 rc->suppress = FALSE;
1699 rr->ref_line->suppress = FALSE;
1700 zero_all_counters(r, COB_REPORT_CONTROL_FOOTING,pl);
1701 clear_group_indicate(r->first_line);
1702 r->next_just_set = FALSE;
1703 if(r->next_page) {
1704 r->foot_next_page = TRUE;
1705 r->next_page = FALSE;
1706 }
1707 }
1708 }
1709 cob_move(rc->sf,rc->f); /* Put new CONTROL value back */
1710 }
1711 }
1712 if(r->foot_next_page) {
1713 DEBUG_LOG("rw",(" Line# %d of Page# %d; ",r->curr_line,r->curr_page));
1714 DEBUG_LOG("rw",(" Execute NEXT GROUP PAGE after footings\n"));
1715 r->next_page = FALSE;
1716 r->foot_next_page = FALSE;
1717 do_page_footing(r);
1718 do_page_heading(r);
1719 }
1720 /*
1721 * Check for Control Headings
1722 */
1723 for(rc = r->controls; rc; rc = rc->next) {
1724 if(rc->data_change) {
1725 for(rr = rc->control_ref; rr; rr = rr->next) {
1726 if(rr->ref_line->flags & COB_REPORT_CONTROL_HEADING) {
1727 if(rr->ref_line->use_decl) {
1728 DEBUG_LOG("rw",(" Return for %s Heading Declaratives %d\n",
1729 rc->name,rr->ref_line->use_decl));
1730 return rr->ref_line->use_decl;
1731 }
1732 pl = get_print_line(rr->ref_line);
1733 if(pl != rr->ref_line
1734 && pl->use_decl) {
1735 DEBUG_LOG("rw",(" Return for %s Heading Declaratives %d.\n",
1736 rc->name,pl->use_decl));
1737 return pl->use_decl; /* Back for DECLARATIVES */
1738 }
1739 PrintHeading:
1740 if(!rr->ref_line->suppress)
1741 report_line_and(r,rr->ref_line,COB_REPORT_CONTROL_HEADING);
1742 rr->ref_line->suppress = FALSE;
1743 }
1744 }
1745 cob_move (rc->f,rc->val); /* Save current field data */
1746 }
1747 rc->data_change = FALSE;
1748 }
1749 }
1750
1751 sum_all_detail(r); /* SUM detail counters */
1752 if(l == NULL) { /* GENERATE <report-name> */
1753
1754 } else if(l->suppress) {
1755 l->suppress = FALSE;
1756 } else {
1757 gengrp = 0;
1758 if(l->fields == NULL
1759 && l->child != NULL
1760 && l->child->sister != NULL) {
1761 l = l->child; /* Multiple Detail Lines in group */
1762 gengrp = 1;
1763 }
1764
1765 num = ln = 0;
1766 for(pl = l; pl; pl = pl->sister) {
1767 if( NOTDETAIL(pl->flags) )
1768 break;
1769 if((pl->flags & COB_REPORT_LINE_PLUS)
1770 && pl->line > 1) {
1771 ln += pl->line;
1772 }
1773 num++;
1774 if(!gengrp) break;
1775 }
1776 if(num > 1
1777 && (r->curr_line + ln) > r->def_last_detail) { /* Page overflow */
1778 do_page_footing(r);
1779 r->curr_line = 1;
1780 do_page_heading(r);
1781 r->first_detail = FALSE;
1782 saveLineCounter(r);
1783 }
1784
1785 for(pl = l; pl; pl = pl->sister) {
1786 if( NOTDETAIL(pl->flags) )
1787 break;
1788 l = get_print_line(pl); /* Find line with data fields */
1789 if(!l->suppress) {
1790 r->next_just_set = FALSE;
1791 report_line(r,l); /* Generate this DETAIL line */
1792 }
1793 l->suppress = FALSE;
1794 if(!gengrp) break;
1795 }
1796 }
1797
1798 /*
1799 * Zero out SUM counters
1800 */
1801 zero_all_counters(r, COB_REPORT_DETAIL, NULL);
1802 clear_suppress(r->first_line);
1803 r->first_generate = FALSE;
1804 r->next_just_set = FALSE;
1805 r->curr_line--;
1806 r->incr_line = TRUE;
1807 saveLineCounter(r);
1808 return 0;
1809 }
1810
1811 /*
1812 * SUPPRESS printing of this CONTROL level
1813 */
1814 void
cob_report_suppress(cob_report * r,cob_report_line * l)1815 cob_report_suppress(cob_report *r, cob_report_line *l)
1816 {
1817 cob_report_control *rc;
1818 cob_report_control_ref *rr;
1819 cob_report_line *pl;
1820
1821 for(rc = r->controls; rc; rc = rc->next) {
1822 for(rr = rc->control_ref; rr; rr = rr->next) {
1823 if(rr->ref_line == l) {
1824 rc->suppress = TRUE;
1825 return;
1826 }
1827 pl = get_print_line(rr->ref_line);
1828 if(pl == l) {
1829 rc->suppress = TRUE;
1830 return;
1831 }
1832 }
1833 }
1834 cob_runtime_error (_("could not find line to SUPPRESS in report %s"),r->report_name);
1835 }
1836