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