static void finish_banners( void ) { banner_lay_tag * cur_ban; region_lay_tag * cur_reg; region_lay_tag * top_line_reg; font_number s_font; uint32_t ban_line; uint32_t max_reg_depth; font_number max_reg_font; uint32_t min_top_line; s_font = g_curr_font; for( cur_ban = layout_work.banner; cur_ban != NULL; cur_ban = cur_ban->next ) { ban_line = 0; max_reg_depth = 0; max_reg_font = 0; min_top_line = UINT32_MAX; // start at very large positive number top_line_reg = NULL; for( cur_reg = cur_ban->region; cur_reg != NULL; cur_reg = cur_reg->next ) { g_curr_font = s_font; // horizontal attributes use default font cur_reg->reg_indent = conv_hor_unit( &cur_reg->indent ); cur_reg->reg_hoffset = conv_hor_unit( &cur_reg->hoffset ); cur_reg->reg_width = conv_hor_unit( &cur_reg->width ); g_curr_font = cur_reg->font; // vertical attributes use the banregion font cur_reg->reg_voffset = conv_vert_unit( &cur_reg->voffset, 1 ); cur_reg->reg_depth = conv_vert_unit( &cur_reg->depth, 1 ); if( max_reg_depth < cur_reg->reg_voffset + cur_reg->reg_depth ) { max_reg_depth = cur_reg->reg_voffset + cur_reg->reg_depth; } if( ban_line < wgml_fonts[cur_reg->font].line_height ) { max_reg_font = cur_reg->font; ban_line = wgml_fonts[max_reg_font].line_height; } if( min_top_line > cur_reg->reg_voffset + cur_reg->reg_depth ) { min_top_line = cur_reg->reg_voffset + cur_reg->reg_depth; top_line_reg = cur_reg; } } g_curr_font = s_font; // horizontal attributes use default font cur_ban->ban_left_adjust = conv_hor_unit( &cur_ban->left_adjust ); cur_ban->ban_right_adjust = conv_hor_unit( &cur_ban->right_adjust ); g_curr_font = max_reg_font; // vertical attribute uses the largest banregion font cur_ban->ban_depth = conv_vert_unit( &cur_ban->depth, 1 ); cur_ban->top_line = top_line_reg; if( cur_ban->ban_depth < max_reg_depth ) { xx_err( err_banreg_too_deep ); cur_ban->ban_depth = max_reg_depth; } } g_curr_font = s_font; return; }
void insert_page_width( doc_element * a_element ) { uint32_t depth; /* depth is used to update t_page.cur_depth and so must be kept separate */ if( !ProcFlags.page_started ) { depth = a_element->top_skip; ProcFlags.page_started = true; } else { depth = a_element->subs_skip; } depth += a_element->depth; /****************************************************************/ /* Does the first line minimum apply here? If so, it needs to */ /* be implemented. Note that cur_el->depth does not reflect it */ /* because there is no way to tell if it will apply when the */ /* is computed. */ /****************************************************************/ switch( a_element->type ) { // TOP FIG processing goes here case el_text : // section heading: must go on t_page if( (depth + t_page.cur_depth) <= t_page.max_depth ) { if( t_page.page_width == NULL ) { // must be empty t_page.page_width = a_element; t_page.last_col_main = t_page.page_width; t_page.cur_depth += depth; if( bin_driver->y_positive == 0 ) { t_page.main_top -= depth; } else { t_page.main_top += depth; } } else { // discard second section heading g_err( err_intern, __FILE__, __LINE__ ); } } else { xx_err( err_heading_too_deep ); g_suicide(); // it won't fit on any page if not on this } break; default: g_err( err_intern, __FILE__, __LINE__ ); } return; }
static bool check_att_value( gaentry * ga ) { gavalentry * gaval; char * valp; long attval; bool msg_done; int rc; scan_err = true; msg_done = false; for( gaval = ga->vals; gaval != NULL; gaval = gaval->next ) { if( gaval->valflags & val_any ) { scan_err = false; // any value is allowed break; } valp = NULL; if( gaval->valflags & val_value ) { valp = gaval->a.value; } else { if( gaval->valflags & val_valptr ) { valp = gaval->a.valptr; } } if( valp != NULL ) { if( !strcmp( token_buf, valp ) ) { scan_err = false; // value is allowed break; } } else { if( gaval->valflags & val_range ) { attval = strtol( token_buf, NULL, 10 ); if( attval < gaval->a.range[0] || attval > gaval->a.range[1] ) { xx_err( ERR_ATT_RANGE_INV );// value outside range msg_done = true; break; } } else { if( gaval->valflags & val_length ) { if( strlen( token_buf ) > gaval->a.length ) { xx_err( err_att_len_inv ); // value too long msg_done = true; } else { scan_err = false; } break; } } } } if( !scan_err ) { rc = add_symvar( &loc_dict, ga->name, token_buf, no_subscript, local_var ); } else { if( !msg_done ) { att_val_err( ga->name ); } } return( scan_err ); }
void gml_binclude( gml_tag gtag ) { bool depth_found = false; bool file_found = false; bool has_rec_type = false; bool reposition; bool reposition_found = false; char file[FILENAME_MAX]; char rt_buff[MAX_FILE_ATTR]; char * p; doc_element * cur_el; su depth_su; uint32_t depth; size_t len; if( (ProcFlags.doc_sect < doc_sect_gdoc) ) { if( (ProcFlags.doc_sect_nxt < doc_sect_gdoc) ) { xx_tag_err( err_tag_before_gdoc, gml_tagname( gtag ) ); scan_start = scan_stop; return; } } len = 0; file[0] = '\0'; rt_buff[0] = '\0'; p = scan_start; for( ;; ) { while( *p == ' ' ) { // over WS to attribute p++; } if( *p == '\0' ) { // end of line: get new line if( !(input_cbs->fmflags & II_eof) ) { if( get_line( true ) ) { // next line for missing attribute process_line(); if( (*scan_start == SCR_char) || // cw found: end-of-tag (*scan_start == GML_char) ) { // tag found: end-of-tag ProcFlags.tag_end_found = true; break; } else { p = scan_start; // new line is part of current tag continue; } } } } if( !strnicmp( "file", p, 4 ) ) { p += 4; p = get_att_value( p ); if( val_start == NULL ) { break; } file_found = true; len = val_len; if( len >= FILENAME_MAX ) len = FILENAME_MAX - 1; memcpy( file, val_start, len ); file[len] = '\0'; split_attr_file( file, rt_buff, MAX_FILE_ATTR ); if( (rt_buff[0] != '\0') ) { has_rec_type = true; if( rt_buff[0] != 't' ) { xx_warn( wng_rec_type_binclude ); } } if( ProcFlags.tag_end_found ) { break; } } else if( !strnicmp( "depth", p, 5 ) ) { p += 5; p = get_att_value( p ); if( val_start == NULL ) { break; } depth_found = true; if( att_val_to_su( &depth_su, true ) ) { return; } depth = conv_vert_unit( &depth_su, g_spacing_ln ); if( ProcFlags.tag_end_found ) { break; } } else if( !strnicmp( "reposition", p, 10 ) ) { p += 10; p = get_att_value( p ); if( val_start == NULL ) { break; } reposition_found = true; if( !strnicmp( "start", val_start, 5 ) ) { reposition = true; // moving following text down by depth } else if( !strnicmp( "end", val_start, 3 ) ) { reposition = false; // device at proper position after insertion } else { xx_line_err( err_inv_att_val, val_start ); scan_start = scan_stop; return; } if( ProcFlags.tag_end_found ) { break; } } else { // no match = end-of-tag in wgml 4.0 ProcFlags.tag_end_found = true; break; } } // detect missing required attributes if( !depth_found || !file_found || !reposition_found ) { xx_err( err_att_missing ); scan_start = scan_stop; return; } scr_process_break(); // flush existing text start_doc_sect(); // if not already done cur_el = alloc_doc_el( el_binc ); if( reposition && depth ) { cur_el->depth = depth; // otherwise, it will be "0" } if( depth > 0 ) { set_skip_vars( NULL, NULL, NULL, 1, g_curr_font ); cur_el->blank_lines = g_blank_lines; g_blank_lines = 0; cur_el->subs_skip = g_subs_skip; cur_el->top_skip = g_top_skip; } cur_el->element.binc.depth = depth; cur_el->element.binc.cur_left = g_cur_h_start; cur_el->element.binc.has_rec_type = has_rec_type; ProcFlags.skips_valid = false; memcpy( cur_el->element.binc.file, file, len + 1 ); insert_col_main( cur_el ); scan_start = scan_stop; // skip following text }
void scr_gt( void ) { char * p; char * pn; char savetag; int k; int len; char macname[MAC_NAME_LENGTH + 1]; condcode cc; gtentry * wk; gtflags tag_flags; enum { f_add = 1, f_change, f_delete, f_off, f_on, f_print } function; garginit(); // find end of CW /***********************************************************************/ /* isolate tagname or use previous if tagname * */ /***********************************************************************/ cc = getarg(); // Tagname if( cc == omit ) { // no operands tag_name_missing_err(); return; } p = tok_start; if( *p == '*' ) { // single * as tagname if( arg_flen > 1 ) { xx_err( err_tag_name_inv ); return; } savetag = '*'; // remember for possible global delete / print if( GlobalFlags.firstpass && input_cbs->fmflags & II_research ) { if( tag_entry != NULL ) { out_msg(" using tagname %s %s\n", tagname, tag_entry->name ); } } } else { savetag = ' '; // no global function for delete / print init_tag_att(); // forget previous values for quick access attname[0] = '*'; pn = tagname; len = 0; while( *p && is_macro_char( *p ) ) { if( len < TAG_NAME_LENGTH ) { *pn++ = tolower( *p++ );// copy lowercase tagname *pn = '\0'; } else { break; } len++; } for( k = len; k < TAG_NAME_LENGTH; k++ ) { tagname[k] = '\0'; } tagname[TAG_NAME_LENGTH] = '\0'; if( len < arg_flen ) { xx_err( err_tag_name_inv ); return; } } /***********************************************************************/ /* get function operand add, change, ... */ /***********************************************************************/ cc = getarg(); if( cc == omit ) { xx_err( err_tag_func_inv ); return; } p = tok_start; function = 0; switch( tolower( *p ) ) { case 'a': if( !strnicmp( "ADD ", p, 4 ) ) { function = f_add; } break; case 'c' : if( (arg_flen > 2) && (arg_flen < 7) && !strnicmp( "CHANGE", p, arg_flen ) ) { function = f_change; } break; case 'o' : if( !strnicmp( "OFF", p, 3 ) ) { function = f_off; } else { if( !strnicmp( "ON", p, 2 ) ) { function = f_on; } } break; case 'd' : if( (arg_flen > 2) && (arg_flen < 7) && !strnicmp( "DELETE", p, arg_flen ) ) { function = f_delete; } break; case 'p' : if( (arg_flen > 1) && (arg_flen < 6) && !strnicmp( "PRINT", p, arg_flen ) ) { function = f_print; } break; default: // nothing break; } if( function == 0 ) { // no valid function specified xx_err( err_tag_func_inv ); return; } cc = getarg(); // get possible next parm /***********************************************************************/ /* for add and change get macroname */ /***********************************************************************/ if( function == f_add || function == f_change ) { // need macroname if( cc == omit ) { xx_err( err_tag_mac_name ); return; } p = tok_start; pn = macname; len = 0; while( *p && is_macro_char( *p ) ) { if( len < MAC_NAME_LENGTH ) { *pn++ = tolower( *p++ ); // copy lowercase macroname *pn = '\0'; } else { break; } len++; } for( k = len; k < MAC_NAME_LENGTH; k++ ) { macname[k] = '\0'; } macname[MAC_NAME_LENGTH] = '\0'; tag_flags = 0; if( function == f_add ) { // collect tag options cc = scan_tag_options( &tag_flags ); if( cc != omit ) { // not all processed error xx_err( err_tag_opt_inv ); } tag_entry = add_tag( &tag_dict, tagname, macname, tag_flags ); // add to dictionary // if tag_entry is now NULL, error (+ msg) was output in add_tag } else { // is function change tag_entry = change_tag( &tag_dict, tagname, macname ); } } else { /***********************************************************************/ /* after delete, off, on, print nothing allowed */ /***********************************************************************/ if( cc != omit ) { xx_err( err_tag_toomany ); // nothing more allowed } switch( function ) { case f_print : if( savetag == '*' ) { print_tag_dict( tag_dict ); } else { print_tag_entry( find_tag( &tag_dict, tagname ) ); } break; case f_delete : if( savetag == '*' ) { free_tag_dict( &tag_dict ); } else { free_tag( &tag_dict, find_tag( &tag_dict, tagname ) ); } break; case f_off : if( savetag == '*' && tag_entry != NULL ) {// off for last defined tag_entry->tagflags |= tag_off; } else { wk = find_tag( &tag_dict, tagname ); if( wk != NULL ) { wk->tagflags |= tag_off; } } break; case f_on : if( savetag == '*' && tag_entry != NULL ) {// on for last defined tag_entry->tagflags |= tag_off; } else { wk = find_tag( &tag_dict, tagname ); if( wk != NULL ) { wk->tagflags &= ~tag_off; } } break; default: break; } } scan_restart = scan_stop +1; return; }
void init_page_geometry( void ) { int k; uint32_t page_depth_org; uint32_t net_top_margin; uint32_t net_y_start; uint32_t rm_test; uint32_t top_margin; uint32_t y_start_correction; #if 0 // activate for multi column TBD uint32_t offset; #endif g_resh = bin_device->horizontal_base_units; // hor resolution &sysresh g_resv = bin_device->vertical_base_units; // vert resolution &sysresv spacing = layout_work.defaults.spacing; g_cur_threshold = layout_work.widow.threshold; g_max_char_width = 0; g_max_line_height = 0; for( k = 0; k < wgml_font_cnt; k++ ) { if( g_max_char_width < wgml_fonts[k].default_width ) g_max_char_width = wgml_fonts[k].default_width; if( g_max_line_height < wgml_fonts[k].line_height ) g_max_line_height = wgml_fonts[k].line_height; } g_curr_font = layout_work.defaults.font; lm = conv_hor_unit( &layout_work.page.left_margin ) - bin_device->x_offset; // left margin &syspagelm if( lm < 0 ) { // wgml 4.0 limits value lm = 0; } rm = conv_hor_unit( &layout_work.page.right_margin ) - bin_device->x_offset; // right margin &syspagerm rm_test = bin_device->horizontal_base_units / 4; if( (bin_device->horizontal_base_units % 4) > 0 ) { rm_test++; // round up if any remainder } if( rm < rm_test ) { // wgml 4.0 limits value xx_err( err_right_margin_2_small ); // candidate Severe Error g_suicide(); // no recovery possible } g_page_left_org = lm + bin_device->x_start; if( g_page_left_org < bin_device->x_start ) g_page_left_org = bin_device->x_start; g_page_left = g_page_left_org; g_cur_left = g_page_left; // set initial value g_page_right_org = rm + bin_device->x_start; if( g_page_right_org > bin_device->page_width ) g_page_right_org = bin_device->page_width; g_page_right = g_page_right_org; if( g_page_right > bin_device->page_width ) {// output must appear on page xx_err( err_margins_inverted ); // candidate Severe Error g_suicide(); // no recovery possible } if( g_page_left >= g_page_right ) { // margins cannot be inverted xx_err( err_margins_inverted ); // candidate Severe Error g_suicide(); // no recovery possible } g_net_page_width = rm - lm; g_ll = g_net_page_width * CPI / bin_device->horizontal_base_units; // &sysll top_margin = conv_vert_unit( &layout_work.page.top_margin, 1 ); page_depth_org = conv_vert_unit( &layout_work.page.depth, 1 ); if( bin_device->y_offset > page_depth_org ) { xx_err( err_page_depth_too_small ); // candidate Severe Error g_suicide(); // no recovery possible } else { g_page_depth = page_depth_org - bin_device->y_offset; // &syspaged } if( bin_device->y_offset < top_margin ) { net_top_margin = top_margin - bin_device->y_offset; } else { net_top_margin = 0; } if( bin_driver->y_positive == 0 ) { g_page_top = bin_device->y_start - net_top_margin; if( g_page_depth > bin_device->y_start ) { /* see Wiki for discussion, wgml 4.0 differs here */ xx_err( err_page_depth_too_big ); // candidate Severe Error g_suicide(); // no recovery possible } else { g_page_bottom = bin_device->y_start - g_page_depth;// end of text area } g_net_page_depth = g_page_top - g_page_bottom; lcmax = 1 + (g_net_page_depth + bin_device->y_offset) / wgml_fonts[g_curr_font].line_height; // usable no of lines } else { net_y_start = bin_device->y_start; if( net_y_start < net_top_margin ) net_y_start = net_top_margin; if( bin_device->y_start > net_top_margin ) { y_start_correction = bin_device->y_start - net_top_margin; if( y_start_correction > wgml_fonts[g_curr_font].line_height ) { y_start_correction = wgml_fonts[g_curr_font].line_height; } } else { y_start_correction = 0; } g_page_top = net_y_start - y_start_correction; g_page_bottom = g_page_top + g_page_depth; g_net_page_depth = g_page_bottom - g_page_top; lcmax = g_net_page_depth; } g_page_bottom_org = g_page_bottom;// save for possible bot banner calculation g_page_top_org = g_page_top;// save top for possible bot banner calculation g_cd = layout_work.defaults.columns;// no of columns &syscd g_gutter = conv_hor_unit( &layout_work.defaults.gutter ); // &sysgutter #if 0 // activate for multi column TBD if( g_cd > 1 ) { // multi column layout if( g_cd > 9 ) { // no more than 9 columns g_cd = 9; // this limit is found in script_tso.txt // for .cd control word } g_cl = (g_net_page_width - (g_cd - 1) * g_gutter ) / (g_cd - 1); // column length offset = g_page_left; for( k = 0; k < g_cd; ++k ) { g_offset[k] = offset; // start of each column offset += g_cl + g_gutter; } for( ; k < 9; ++k ) { g_offset[k] = 0; // dummy start of undefined columns } } else { g_cl = g_ll; } #else g_cl = g_ll; // column length &syscl // This is what wgml 4 does, even if in multi column mode TBD #endif // if( GlobalFlags.firstpass && GlobalFlags.research ) { // show values TBD if( GlobalFlags.firstpass ) { out_msg( "\ntm:%d lm:%d rm:%d top margin:%d depth:%d\n\n", tm, lm, rm, top_margin, g_page_depth ); out_msg( "dev:%s page_w:%d page_d:%d hor_u:%d ver_u:%d x_s:%d y_s:%d" " x_o:%d y_o:%d\n\n", bin_device->driver_name, bin_device->page_width, bin_device->page_depth, bin_device->horizontal_base_units, bin_device->vertical_base_units, bin_device->x_start, bin_device->y_start, bin_device->x_offset, bin_device->y_offset ); out_msg( "default font number:%d font_count:%d\n", g_curr_font, wgml_font_cnt ); for( k = 0; k < wgml_font_cnt; ++k ) { out_msg( "font:%d def_width:%d em:%d font_h:%d font_s:%d" " line_h:%d line_s:%d spc_w:%d\n", k, wgml_fonts[k].default_width, wgml_fonts[k].em_base, wgml_fonts[k].font_height, wgml_fonts[k].font_space, wgml_fonts[k].line_height, wgml_fonts[k].line_space, wgml_fonts[k].spc_width ); } out_msg( "\npage top:%d bottom:%d left:%d right:%d lines:%d\n", g_page_top, g_page_bottom, g_page_left, g_page_right, lcmax ); out_msg( "page net depth:%d width:%d line height:%d char width:%d\n\n", g_net_page_depth, g_net_page_width, g_max_line_height, g_max_char_width ); } g_indent = 0; g_indentr = 0; init_nest_cb(); }
void insert_col_main( doc_element * a_element ) { bool page_full; bool splittable; uint32_t cur_skip; uint32_t depth; /****************************************************************/ /* alternate procesing: accumulate elements for later */ /* submission */ /* used currenlty by ADDRESS/eADDRESS */ /****************************************************************/ if( ProcFlags.group_elements ) { if( t_doc_el_group.first == NULL ) { t_doc_el_group.first = a_element; t_doc_el_group.last = t_doc_el_group.first; } else { t_doc_el_group.last->next = a_element; t_doc_el_group.last = t_doc_el_group.last->next; } t_doc_el_group.depth += a_element->depth; return; } /****************************************************************/ /* test version until things get a bit more clear */ /* the theory here is that only one processing step should be */ /* here, the rest being done in update_t_page() */ /****************************************************************/ page_full = false; /****************************************************************/ /* this section sets page_full to "true" if any of the skips */ /* or blank_lines finishes the page, alone or in various */ /* combinations */ /* element field values are adjusted as needed */ /****************************************************************/ if( a_element->blank_lines > 0 ) { if( (t_page.cur_depth + a_element->blank_lines) >= t_page.max_depth ) { a_element->blank_lines -= (t_page.max_depth - t_page.cur_depth); page_full = true; } else if( !ProcFlags.page_started && ((t_page.cur_depth + a_element->blank_lines + a_element->top_skip) >= t_page.max_depth) ) { a_element->top_skip -= (t_page.max_depth - t_page.cur_depth); a_element->top_skip += a_element->blank_lines; a_element->blank_lines = 0; page_full = true; } else if( (t_page.cur_depth + a_element->blank_lines + a_element->subs_skip) >= t_page.max_depth ) { a_element->blank_lines = 0; page_full = true; } } else if( !ProcFlags.page_started ) { if( a_element->top_skip >= t_page.max_depth ) { a_element->top_skip -= t_page.max_depth; page_full = true; } } if( !page_full ) { /****************************************************************/ /* this test is done separately because an element may fail to */ /* set page_full to "true" above but the skip actually used */ /* may still fill the page */ /****************************************************************/ if( !ProcFlags.page_started ) { if( a_element->blank_lines > 0 ) { cur_skip = a_element->blank_lines + a_element->subs_skip; } else { cur_skip = a_element->top_skip; } ProcFlags.page_started = true; } else { cur_skip = a_element->blank_lines + a_element->subs_skip; } if( (cur_skip + t_page.cur_depth) > t_page.max_depth ) { page_full = true; } } if( !page_full ) { /****************************************************************/ /* at least part of the element should fit on the page */ /* Does the first line minimum apply here? If so, it needs to */ /* be implemented. Note that cur_el->depth does not reflect it */ /* because there is no way to tell if it will apply when the */ /* is computed. */ /****************************************************************/ depth = cur_skip + a_element->depth; if( (depth + t_page.cur_depth) > t_page.max_depth ) { // a_element fills the page splittable = split_element( a_element, t_page.max_depth - t_page.cur_depth - cur_skip ); if( a_element->next != NULL ) { // a_element was split if( t_page.main == NULL ) { t_page.main = alloc_doc_col(); } if( t_page.main->main == NULL ) { t_page.main->main = a_element; t_page.last_col_main = t_page.main->main; } else { t_page.last_col_main->next = a_element; t_page.last_col_main = t_page.last_col_main->next; } t_page.cur_depth += depth; a_element = a_element->next; t_page.last_col_main->next = NULL; page_full = true; } else { // a_element could not be split if( t_page.main == NULL ) { // adapt when FIG/FN done xx_err( err_text_line_too_deep ); g_suicide(); // no line will fit on any page } if( t_page.main->main == NULL ) { // adapt when FIG/FN done xx_err( err_text_line_too_deep ); g_suicide(); // no line will fit on any page } page_full = true; } } else { // the entire element fits on the current page if( t_page.main == NULL ) { t_page.main = alloc_doc_col(); } if( t_page.main->main == NULL ) { t_page.main->main = a_element; t_page.last_col_main = t_page.main->main; } else { t_page.last_col_main->next = a_element; t_page.last_col_main = t_page.last_col_main->next; } t_page.cur_depth += depth; } } if( page_full ) { /****************************************************************/ /* if page_full is true then a_element goes to n_page and */ /* t_page must be output */ /****************************************************************/ if( n_page.last_col_main == NULL ) { n_page.col_main = a_element; n_page.last_col_main = n_page.col_main; } else { n_page.last_col_main->next = a_element; n_page.last_col_main = n_page.last_col_main->next; } text_page_out(); } return; }
static void update_t_page( void ) { bool fig_placed; bool splittable; doc_element * cur_el; uint32_t depth; reset_t_page(); /* some section headings are placed in t_page.page_width when */ /* processed. One FIG in n_page.col_top goes into t_page.page_width */ /* if it is empty */ /* t_page.page_width can only hold one doc_element */ /* This is preliminary and may be changed as needed. */ depth = t_page.cur_depth; fig_placed = false; if( t_page.page_width == NULL ) { // skip if section full if( n_page.col_top != NULL ) { // at most one item can be placed switch( n_page.col_top->type ) { // add code for FIG when needed case el_text : // all elements should be FIGs default : internal_err( __FILE__, __LINE__ ); } } } /* one FIG in n_page.col_top goes into t_page.main->top_fig if none */ /* was placed in t_page.page_width */ /* this is preliminary and may be changed as needed */ /* Note: t_page.main is NULL at this point, initialize if needed */ if( !fig_placed ) { if( n_page.col_top != NULL ) { // at most one item can be placed switch( n_page.col_top->type ) { // add code for FIG when needed case el_text : // all elements should be FIGs default : internal_err( __FILE__, __LINE__ ); } } } /***********************************************************************/ /* The order here is not clear. */ /* That shown is based on filling the t_page.main->bot_fig and the */ /* t_page.main->footnote parts before filling t_page.main->main, thus */ /* having a firm depth for t_page.main->main to start with. */ /* However, if there is no top_fig, then the first doc_element in */ /* t_page.main->main must set its pre_skip to 0, and then what */ /* happens if there is no room for anything to be placed there? */ /* So this may need to be rethought when FN and FIG are implemented. */ /***********************************************************************/ /* one FIG in n_page.col_bot goes into t_page.main->bot_fig */ /* entrained footnotes need to be moved to n_page.col_fn */ /* this is preliminary and may be changed as needed */ /* Note: t_page.main may be NULL at this point, initialize if needed */ if( n_page.col_bot != NULL ) { // at most one item can be placed switch( n_page.col_bot->type ) { // add code for FIG & entrained footnotes when needed case el_text : // all elements should be FIGs or footnotes default : internal_err( __FILE__, __LINE__ ); } } /* all footnotes in n_page.col_fn go into t_page.main->footnote */ /* this is preliminary and may be changed as needed */ /* Note: t_page.main may be NULL at this point, initialize if needed */ if( n_page.col_fn != NULL ) { // at most one item can be placed switch( n_page.col_fn->type ) { // add code for footnotes when needed case el_text : // all elements should be footnotes default : internal_err( __FILE__, __LINE__ ); } } /* t_page.main->main is used for the bulk of the elements */ /* it is filled last because the other deferred items are believed to */ /* have priority; this may change as the situation is clarified. */ /* unless the section is ended, there must be at least on element left */ /* in n_page.col_main for the page to be full */ /* Note: when FIG/FN processing is implemented, t_page.main may not be */ /* NULL at this point */ /****************************************************************/ /* test version until things get a bit more clear */ /* the theory here is that only one processing step should be */ /* here, and then the function calling update_t_page() */ /* should be relied on to output the page */ /****************************************************************/ while( n_page.col_main != NULL ) { cur_el = n_page.col_main; n_page.col_main = n_page.col_main->next; if( n_page.col_main == NULL ) { n_page.last_col_main = NULL; } /****************************************************************/ /* this section identifies skips and blank lines that finish */ /* the current page and then exits the loop after adjusting */ /* the element field values as needed */ /****************************************************************/ if( cur_el->blank_lines > 0 ) { if( (t_page.cur_depth + cur_el->blank_lines) >= t_page.max_depth ) { cur_el->blank_lines -= (t_page.max_depth - t_page.cur_depth); break; } else if( !ProcFlags.page_started && ((t_page.cur_depth + cur_el->blank_lines + cur_el->top_skip) >= t_page.max_depth) ) { cur_el->top_skip -= (t_page.max_depth - t_page.cur_depth); cur_el->top_skip += cur_el->blank_lines; cur_el->blank_lines = 0; break; } else if( (t_page.cur_depth + cur_el->blank_lines + cur_el->subs_skip) >= t_page.max_depth ) { cur_el->blank_lines = 0; break; } } if( !ProcFlags.page_started ) { if( cur_el->blank_lines > 0 ) { depth += cur_el->blank_lines + cur_el->subs_skip; } else { depth += cur_el->top_skip; } ProcFlags.page_started = true; } else { depth += cur_el->blank_lines + cur_el->subs_skip; } if( depth >= t_page.max_depth ) { // skip fills page break; } /****************************************************************/ /* Does the first line minimum apply here? If so, it needs to */ /* be implemented. Note that cur_el->depth does not reflect it */ /* because there is no way to tell if it will apply when the */ /* cur_el->depth is computed. */ /****************************************************************/ if( (depth + cur_el->depth) > t_page.max_depth ) { // cur_el will fill the page splittable = split_element( cur_el, t_page.max_depth - t_page.cur_depth - depth ); if( splittable ) { if( cur_el->next != NULL ) { // cur_el was split n_page.col_main = cur_el->next; if( n_page.last_col_main == NULL ) { n_page.last_col_main = n_page.col_main; } cur_el->next = NULL; } if( t_page.main == NULL ) { t_page.main = alloc_doc_col(); } if( t_page.main->main == NULL ) { t_page.main->main = cur_el; t_page.last_col_main = t_page.main->main; } else { t_page.last_col_main->next = cur_el; t_page.last_col_main = t_page.last_col_main->next; } t_page.last_col_main->next = NULL; t_page.cur_depth += cur_el->depth; } else { if( (t_page.main == NULL) || (t_page.main->main == NULL) ) { // adapt when FIG/FN done xx_err( err_text_line_too_deep ); g_suicide(); // no line will fit on any page } n_page.col_main = cur_el->next; if( n_page.last_col_main == NULL ) { n_page.last_col_main = n_page.col_main; } cur_el->next = NULL; } } else { // cur_el fits as-is if( t_page.main == NULL ) { t_page.main = alloc_doc_col(); } if( t_page.main->main == NULL ) { t_page.main->main = cur_el; t_page.last_col_main = t_page.main->main; } else { t_page.last_col_main->next = cur_el; t_page.last_col_main = t_page.last_col_main->next; } t_page.last_col_main->next = NULL; t_page.cur_depth += cur_el->depth; } } return; }
void gml_graphic( gml_tag gtag ) { bool depth_found = false; bool file_found = false; char file[FILENAME_MAX]; char rt_buff[MAX_FILE_ATTR]; char * p; char * pa; doc_element * cur_el; su cur_su; uint32_t depth; uint32_t scale = 100; // the initial value of width is only correct for one-column pages. uint32_t width = g_net_page_width; int32_t xoff = 0; int32_t yoff = 0; size_t len; if( (ProcFlags.doc_sect < doc_sect_gdoc) ) { if( (ProcFlags.doc_sect_nxt < doc_sect_gdoc) ) { xx_tag_err( err_tag_before_gdoc, gml_tagname( gtag ) ); scan_start = scan_stop; return; } } len = 0; file[0] = '\0'; rt_buff[0] = '\0'; p = scan_start; for( ;; ) { while( *p == ' ' ) { // over WS to attribute p++; } if( *p == '\0' ) { // end of line: get new line if( !(input_cbs->fmflags & II_eof) ) { if( get_line( true ) ) { // next line for missing attribute process_line(); if( (*scan_start == SCR_char) || // cw found: end-of-tag (*scan_start == GML_char) ) { // tag found: end-of-tag ProcFlags.tag_end_found = true; break; } else { p = scan_start; // new line is part of current tag continue; } } } } if( !strnicmp( "file", p, 4 ) ) { p += 4; p = get_att_value( p ); if( val_start == NULL ) { break; } file_found = true; len = val_len; if( len >= FILENAME_MAX ) len = FILENAME_MAX - 1; memcpy( file, val_start, len ); file[len] = '\0'; split_attr_file( file, rt_buff, sizeof( rt_buff ) ); if( (rt_buff[0] != '\0') ) { xx_warn( wng_rec_type_graphic ); } if( ProcFlags.tag_end_found ) { break; } } else if( !strnicmp( "depth", p, 5 ) ) { p += 5; p = get_att_value( p ); if( val_start == NULL ) { break; } depth_found = true; pa = val_start; if( att_val_to_su( &cur_su, true ) ) { return; } depth = conv_vert_unit( &cur_su, g_spacing_ln ); if( depth == 0 ) { xx_line_err( err_inv_depth_graphic, pa ); scan_start = scan_stop; return; } if( ProcFlags.tag_end_found ) { break; } } else if( !strnicmp( "width", p, 5 ) ) { p += 5; p = get_att_value( p ); if( val_start == NULL ) { break; } if( !strnicmp( "page", val_start, 4 ) ) { // default value is the correct value to use } else if( !strnicmp( "column", val_start, 6 ) ) { // default value is the correct value to use } else { // value actually specifies the width pa = val_start; if( att_val_to_su( &cur_su, true ) ) { return; } width = conv_hor_unit( &cur_su ); if( width == 0 ) { xx_line_err( err_inv_width_graphic, pa ); scan_start = scan_stop; return; } /* there should be a check somewhere for width > page width */ } if( ProcFlags.tag_end_found ) { break; } } else if( !strnicmp( "scale", p, 5 ) ) { p += 5; p = get_att_value( p ); if( val_start == NULL ) { break; } pa = val_start; if( (*pa == '+') || (*pa == '-') ) { // signs not allowed xx_line_err( err_num_too_large, pa ); scan_start = scan_stop; return; } scale = 0; while( (*pa >= '0') && (*pa <= '9') ) { // convert to number scale = (10 * scale) + (*pa - '0'); pa++; if( (pa - val_start) > val_len ) { // value end reached break; } } if( scale > 0x7fffffff ) { // wgml 4.0 limit xx_line_err( err_num_too_large, val_start ); scan_start = scan_stop; return; } if( (pa - val_start) < val_len ) { // value continues on xx_line_err( err_num_too_large, val_start ); scan_start = scan_stop; return; } if( ProcFlags.tag_end_found ) { break; } } else if( !strnicmp( "xoff", p, 4 ) ) { p += 4; p = get_att_value( p ); if( val_start == NULL ) { break; } if( att_val_to_su( &cur_su, false ) ) { return; } xoff = conv_hor_unit( &cur_su ); if( ProcFlags.tag_end_found ) { break; } } else if( !strnicmp( "yoff", p, 4 ) ) { p += 4; p = get_att_value( p ); if( val_start == NULL ) { break; } if( att_val_to_su( &cur_su, false ) ) { return; } yoff = conv_vert_unit( &cur_su, g_spacing_ln ); if( ProcFlags.tag_end_found ) { break; } } else { // no match = end-of-tag in wgml 4.0 ProcFlags.tag_end_found = true; break; } } if( !depth_found || !file_found ) { // detect missing required attributes xx_err( err_att_missing ); scan_start = scan_stop; return; } scr_process_break(); // flush existing text start_doc_sect(); // if not already done cur_el = alloc_doc_el( el_graph ); cur_el->depth = depth; // always used with GRAPHIC if( !ProcFlags.ps_device ) { // character devices ignore SK & post_skip g_skip = 0; g_post_skip = 0; } set_skip_vars( NULL, NULL, NULL, 1, g_curr_font ); cur_el->blank_lines = g_blank_lines; g_blank_lines = 0; cur_el->subs_skip = g_subs_skip; g_subs_skip = 0; cur_el->top_skip = g_top_skip; g_top_skip = 0; cur_el->element.graph.cur_left = g_cur_h_start; cur_el->element.graph.depth = depth; cur_el->element.graph.scale = scale; cur_el->element.graph.width = width; cur_el->element.graph.xoff = xoff; cur_el->element.graph.yoff = yoff; ProcFlags.skips_valid = false; memcpy( cur_el->element.graph.file, file, len + 1 ); insert_col_main( cur_el ); if( *p == '.' ) { p++; } scan_start = p; // process following text }
void scr_ga( void ) { char * p; char * pn; char savetag; char saveatt; int k; int len; condcode cc; gaflags att_flags; gavalflags val_flags; gavalentry * gaval; gaentry * gawk; savetag = ' '; saveatt = ' '; att_flags = 0; val_flags = 0; garginit(); // find end of CW cc = getarg(); // Tagname or * if( cc == omit || (*tok_start == '*' && tag_entry == NULL) ) { // no operands or tagname * and no previous definition tag_name_missing_err(); } if( tag_entry == NULL ) { // error during previous .gt scan_restart = scan_stop + 1; // ignore .ga return; } /***********************************************************************/ /* isolate tagname use previous if tagname * */ /***********************************************************************/ p = tok_start; if( *p == '*' ) { // single * as tagname if( arg_flen > 1 ) { xx_err( err_tag_name_inv ); return; } savetag = '*'; // remember for possible quick access if( GlobalFlags.firstpass && input_cbs->fmflags & II_research ) { out_msg(" using tagname %s\n", tagname ); } } else { savetag = ' '; // no quick access init_tag_att(); // forget previous values for quick access pn = tagname; len = 0; while( *p && is_macro_char( *p ) ) { if( len < TAG_NAME_LENGTH ) { *pn++ = tolower( *p++ );// copy lowercase tagname *pn = '\0'; } else { break; } len++; } for( k = len; k < TAG_NAME_LENGTH; k++ ) { tagname[k] = '\0'; } tagname[TAG_NAME_LENGTH] = '\0'; if( len < arg_flen ) { xx_err( err_tag_name_inv );// name contains invalid or too many chars return; } tag_entry = find_tag( &tag_dict, tagname ); if( tag_entry == NULL ) { nottag_err(); // tagname not defined return; } } /***********************************************************************/ /* isolate attname use previous if attname * */ /***********************************************************************/ cc = getarg(); // Attribute name or * if( cc == omit || (*tok_start == '*' && att_entry == NULL) ) { // no operands or attname * and no previous definition xx_err( err_att_name_inv ); return; } p = tok_start; if( *p == '*' ) { // single * as attname if( arg_flen > 1 ) { xx_err( err_att_name_inv ); return; } saveatt = '*'; // remember for possible quick access if( GlobalFlags.firstpass && input_cbs->fmflags & II_research ) { out_msg(" using attname %s\n", attname ); } att_flags = att_entry->attflags; } else { saveatt = ' '; // no quick access att_entry = NULL; pn = attname; len = 0; while( *p && is_macro_char( *p ) ) { if( len < ATT_NAME_LENGTH ) { *pn++ = tolower( *p++ );// copy lowercase tagname *pn = '\0'; } else { break; } len++; } for( k = len; k < ATT_NAME_LENGTH; k++ ) { attname[k] = '\0'; } attname[ATT_NAME_LENGTH] = '\0'; if( len < arg_flen ) { xx_err( err_att_name_inv );// attname with invalid or too many chars cc = neg; return; } } /***********************************************************************/ /* process options A and options B */ /***********************************************************************/ if( cc != omit ) { if( saveatt != '*' ) { // no quickaccess for attribute gawk = NULL; for( gawk = tag_entry->attribs; gawk != NULL; gawk = gawk->next ) { if( !stricmp( attname, gawk->name ) ) { att_flags = gawk->attflags; // get possible uppercase option break; } } } else { att_flags = att_entry->attflags; } cc = scan_att_optionsA( &att_flags ); // process options A if( cc != omit ) { cc = scan_att_optionsB( &val_flags, cc, &att_flags );// process option B if( cc != omit ) { xx_err( err_tag_toomany ); // excess parameters return; } } } /***********************************************************************/ /* scanning complete add/modify attribute in dictionary */ /***********************************************************************/ if( saveatt != '*' ) { // no quickaccess for attribute for( att_entry = tag_entry->attribs; att_entry != NULL; att_entry = att_entry->next ) { if( !stricmp( attname, att_entry->name ) ) { break; } } } if( att_entry == NULL ) { // new attribute att_entry = mem_alloc( sizeof( gaentry ) ); att_entry->next = tag_entry->attribs; tag_entry->attribs = att_entry; att_entry->vals = NULL; att_entry->attflags = att_flags; strcpy( att_entry->name, attname ); } else { att_entry->attflags = att_flags;// update flags } gaval = mem_alloc( sizeof (gavalentry ) ); if( att_entry->vals == NULL ) { att_entry->vals = gaval; } else { gavalentry * valwk; for( valwk = att_entry->vals; valwk != NULL; valwk = valwk->next ) { if( valwk->next == NULL ) { break; // last entry found } } valwk->next = gaval; } gaval->next = NULL; gaval->valflags = val_flags; if( val_flags & val_length ) { gaval->a.length = ranges[0]; } else if( val_flags & val_range ) { for( k = 0; k < 4; k++ ) { gaval->a.range[k] = ranges[k]; } } else if( val_flags & val_value ) { strcpy_s( gaval->a.value, sizeof( gaval->a.value ), stringval ); } else if( val_flags & val_valptr ) { gaval->a.valptr = valptr; } scan_restart = scan_stop + 1; return; }
static condcode scan_att_optionsB( gavalflags * val_flags, condcode cca, gaflags * att_flags ) { condcode cc; getnum_block gn; int k; if( cca == omit ) { return( cca ); // no more parms } stringval[0] = '\0'; cc = pos; switch( tolower( *tok_start ) ) { case 'a' : if( !strnicmp( "ANY", tok_start, arg_flen ) ) { *val_flags |= val_any; *att_flags |= att_any; } else { if( (arg_flen > 3) && (arg_flen < 10) && !strnicmp( "AUTOmatic", tok_start, arg_flen ) ) { *val_flags |= val_auto; *att_flags |= att_auto; } else { xx_err( err_att_val_inv ); cc = neg; } } if( cc != neg ) { // any or auto found now scan string cc = getarg(); if( cc == quotes || cc == pos || cc == quotes0) { if( arg_flen < sizeof( stringval ) ) { strncpy_s( stringval, sizeof( stringval), tok_start, arg_flen ); *val_flags |= val_value; } else { valptr = mem_alloc( arg_flen + 1 ); strncpy_s( valptr, arg_flen + 1, tok_start, arg_flen ); *val_flags |= val_valptr; } if( *att_flags & att_any ) { // default for any specified *val_flags |= val_def; *att_flags |= att_def; } } } break; case 'r' : if( (arg_flen > 2) && (arg_flen < 6) && !strnicmp( "RANge", tok_start, arg_flen ) ) { *val_flags |= val_range; *att_flags |= att_range; gn.argstart = scan_start; gn.argstop = scan_stop; gn.ignore_blanks = false; ranges[2] = LONG_MIN; ranges[3] = LONG_MIN; for( k = 0; k < 4; k++ ) { // scan max 4 numbers cc = getnum( &gn ); if( cc == omit ) { break; } if( cc == notnum ) { xx_err( err_att_val_inv ); cc = neg; return( cc ); } ranges[k] = gn.result; } scan_start = gn.argstart; if( (k < 2) || (ranges[0] > ranges[1]) ) {// need 2 or more values xx_err( err_att_range_inv );// ... second <= first cc = neg; return( cc ); } if( k == 3 ) { ranges[3] = ranges[2]; // only 1 default specified } if( k > 2 ) { // default specified if( (ranges[0] > ranges[2]) // default less min || (ranges[1] < ranges[2]) // default gt max || (ranges[0] > ranges[3]) // default2 less min || (ranges[1] < ranges[3]) ) { // default2 gt max xx_err( err_att_default ); cc = neg; return( cc ); } } if( ranges[2] > LONG_MIN ) { *val_flags |= val_def; // we have default *att_flags |= att_def; // we have default } } else { if( (arg_flen == 5) && !strnicmp( "RESET", tok_start, arg_flen ) ) { *val_flags |= val_reset; /* no further processing */ } else { cc = neg; } } break; case 'l' : if( (arg_flen > 2) && (arg_flen < 7) && !strnicmp( "LENgth", tok_start, arg_flen ) ) { *val_flags |= val_length; gn.argstart = scan_start; gn.argstop = scan_stop; gn.ignore_blanks = false; cc = getnum( &gn ); if( cc == notnum || cc == omit ) { xx_err( err_att_val_inv ); cc = neg; return( cc ); } else { scan_start = gn.argstart; ranges [0] = gn.result; } } else { cc = neg; } break; case 'v' : if( (arg_flen > 2) && (arg_flen < 6) && !strnicmp( "VALue", tok_start, arg_flen ) ) { cc = getarg(); if( (cc == pos) || (cc == quotes) || (cc == quotes0) ) { if( arg_flen <= VAL_LENGTH ) { *val_flags |= val_value; strncpy_s( stringval, VAL_LENGTH + 1, tok_start, arg_flen ); if( *att_flags & att_upper ) { strupr( stringval ); } } else { #if 1 xx_err( err_att_val_inv ); // only short string allowed cc = neg; // this is a restriction from wgml 4.0 break; // can be removed if neccessary #else *val_flags |= val_valptr; valptr = mem_alloc( arg_flen + 1 ); strncpy_s( valptr, arg_flen + 1, tok_start, arg_flen ); if( *att_flags & att_upper ) { strupr( valptr ); } #endif } } else { xx_err( err_att_val_inv ); cc = neg; break; } cc = getarg(); if( cc == omit ) { // nothing more break; } if( cc == pos && (arg_flen > 2) && (arg_flen < 8) && !strnicmp( "DEFault", tok_start, arg_flen ) ) { *val_flags |= val_def; *att_flags |= att_def; } else { xx_err( err_att_val_inv ); cc = neg; break; } } else { cc = neg; } break; default: cc = neg; // invalid option break; } if( cc == omit || cc == neg ) { ; /* empty pass thru cc */ } else { cc = getarg(); // set new cc omit is expected } return( cc ); }