int rd_dealloc(int target) { unsigned int i, j; #ifdef DEBUG int a = 0; #endif i = rd_info[target].index; debug3("RD: dealloc target = %d, first index = %d, size = %d blocks\n", target, i, rd_info[target].size); while ((rd_segment[i].seg_size != 0) && (i != MAX_ENTRIES + 1)) { j = i; debug5("RD: dealloc pass: %d, purging rd_segment[%d].segment = 0x%x, next index %d, size = %d\n", a, j, rd_segment[j].segment, rd_segment[j].next, rd_segment[j].seg_size); mm_free(rd_segment[j].segment); rd_segment[j].segment = 0; rd_segment[j].seg_size = 0; i = rd_segment[j].next; rd_segment[j].next = MAX_ENTRIES + 1; debug5("RD: dealloc pass: %d, status rd_segment[%d].segment = 0x%x, next index %d, size = %d\n", a++, j, rd_segment[j].segment, rd_segment[j].next, rd_segment[j].seg_size); } rd_info[target].flags = 0; return 0; }
/* Throw away buffies that we passed. */ static void bc_forget(struct bufferchain *bc) { struct buffy *b = bc->first; /* free all buffers that are def'n'tly outdated */ /* we have buffers until filepos... delete all buffers fully below it */ if(b) debug2("bc_forget: block %lu pos %lu", (unsigned long)b->size, (unsigned long)bc->pos); else debug("forget with nothing there!"); while(b != NULL && bc->pos >= b->size) { struct buffy *n = b->next; /* != NULL or this is indeed the end and the last cycle anyway */ if(n == NULL) bc->last = NULL; /* Going to delete the last buffy... */ bc->fileoff += b->size; bc->pos -= b->size; bc->size -= b->size; debug5("bc_forget: forgot %p with %lu, pos=%li, size=%li, fileoff=%li", (void*)b->data, (long)b->size, (long)bc->pos, (long)bc->size, (long)bc->fileoff); free(b->data); free(b); b = n; } bc->first = b; bc->firstpos = bc->pos; }
bool cSatipRtsp::Teardown(const char *uriP) { debug1("%s (%s) [device %d]", __PRETTY_FUNCTION__, uriP, tunerM.GetId()); bool result = false; if (handleM && !isempty(uriP)) { long rc = 0; cTimeMs processing(0); CURLcode res = CURLE_OK; SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, uriP); SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_TEARDOWN); SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipRtsp::DataCallback); SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this); SATIP_CURL_EASY_PERFORM(handleM); SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, NULL); SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, NULL); if (dataBufferM.Size() > 0) { ParseData(); dataBufferM.Reset(); } SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_CLIENT_CSEQ, 1L); SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_SESSION_ID, NULL); result = ValidateLatestResponse(&rc); debug5("%s (%s) Response %ld in %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, uriP, rc, processing.Elapsed(), tunerM.GetId()); } return result; }
/* Adds character c, waiting if wait=1 (or otherwise throws out new char) */ int chq_addch(register struct ch_queue *q, unsigned char c, int wait) { unsigned int nhead; debug5("CHQ: chq_addch(%d, %c, %d) q->len=%d q->tail=%d\n", q, c, 0, q->len, q->tail); if (q->len == q->size) { if (wait) { debug("CHQ: addch sleeping\n"); interruptible_sleep_on(&q->wq); debug("CHQ: addch waken up\n"); } } if (q->len == q->size) return -1; nhead = (unsigned int) ((q->tail + q->len) & (q->size - 1)); q->buf[nhead] = (char) c; q->len++; wake_up(&q->wq); return 0; }
static void PDF_PrintUnderline(FONT_NUM fnum, COLOUR_NUM col, FULL_LENGTH xstart, FULL_LENGTH xstop, FULL_LENGTH ymk) { debug5(DPF, DD, "PDF_PrintUnderline(ft %d, co %d, xstrt %s, xstp %s, ymk %s)", fnum, col, EchoLength(xstart), EchoLength(xstop), EchoLength(ymk)); PDFPage_PrintUnderline(out_fp, xstart, xstop, ymk - finfo[fnum].underline_pos, finfo[fnum].underline_thick); debug0(DPF, DD, "PrintUnderline returning."); } /* end PDF_PrintUnderline */
static void do_rd_request(void) { register char *buff; rd_sector_t start; /* absolute offset from start of device */ seg_t segnum; /* segment index; segment = rd_segment[segnum].segment */ segext_t offset; /* relative offset (from start of segment) */ int target; while (1) { if (!CURRENT || CURRENT->rq_dev < 0) return; INIT_REQUEST; if (CURRENT == NULL || CURRENT->rq_sector == (sector_t) - 1) return; if (rd_initialised != 1) { end_request(0, CURRENT->rq_dev); continue; } start = (rd_sector_t) CURRENT->rq_sector; buff = CURRENT->rq_buffer; target = DEVICE_NR(CURRENT->rq_dev); debug2("RD: request target: %d, start: %ld\n", target, (long) start); if ((rd_info[target].flags != RD_BUSY) || (start >= rd_info[target].size)) { debug4("RD: bad request on ram%d, flags: %d, size: %d, start: %d\n", target, rd_info[target].flags, rd_info[target].size, start); end_request(0, CURRENT->rq_dev); continue; } offset = start; /* offset from segment start */ segnum = rd_info[target].index; /* we want to know our starting index nr. */ debug1("RD: request index = %d\n", segnum); while (offset > rd_segment[segnum].seg_size) { offset -= rd_segment[segnum].seg_size; /* recalculate offset */ segnum = rd_segment[segnum].next; /* point to next segment in linked list */ } debug5("RD: request entry = %d, segment = 0x%x, offset = %d (%x %x)\n", segnum, rd_segment[segnum].segment, offset, CURRENT->rq_seg, buff); if (CURRENT->rq_cmd == WRITE) { debug1("RD: request writing to %ld\n", (long) start); fmemcpy(rd_segment[segnum].segment, offset * SECTOR_SIZE, CURRENT->rq_seg, buff, 1024); } if (CURRENT->rq_cmd == READ) { debug1("RD_REQUEST reading from %ld\n", start); fmemcpy(CURRENT->rq_seg, buff, rd_segment[segnum].segment, offset * SECTOR_SIZE, 1024); } end_request(1, CURRENT->rq_dev); } }
static void PDF_LinkDest(OBJECT name, FULL_LENGTH llx, FULL_LENGTH lly, FULL_LENGTH urx, FULL_LENGTH ury) { debug5(DPF, D, "PDF_LinkDest(%s, %d, %d, %d, %d)", EchoObject(name), llx, lly, urx, ury); /* still to do */ debug0(DPF, D, "PDF_LinkDest returning."); } /* end PDF_LinkDest */
/* Adds character c if there is room (or otherwise throws out new char) */ void chq_addch(register struct ch_queue *q, unsigned char c) { debug5("CHQ: chq_addch(%d, %c, %d) q->len=%d q->start=%d\n", q, c, 0, q->len, q->start); if (q->len < q->size) { q->base[(unsigned int)((q->start + q->len) & (q->size - 1))] = (char)c; q->len++; wake_up(&q->wait); } }
bool cSatipRtsp::Setup(const char *uriP, int rtpPortP, int rtcpPortP) { debug1("%s (%s, %d, %d) [device %d]", __PRETTY_FUNCTION__, uriP, rtpPortP, rtcpPortP, tunerM.GetId()); bool result = false; if (handleM && !isempty(uriP)) { cString transport; long rc = 0; cTimeMs processing(0); CURLcode res = CURLE_OK; switch (modeM) { case cmMulticast: // RTP/AVP;multicast;destination=<IP multicast address>;port=<RTP port>-<RTCP port>;ttl=<ttl> transport = cString::sprintf("RTP/AVP;multicast;port=%d-%d", rtpPortP, rtcpPortP); break; default: case cmUnicast: // RTP/AVP;unicast;client_port=<client RTP port>-<client RTCP port> transport = cString::sprintf("RTP/AVP;unicast;client_port=%d-%d", rtpPortP, rtcpPortP); break; } // Setup media stream SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, uriP); SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_TRANSPORT, *transport); SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_SETUP); // Set header callback for catching the session and timeout SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_HEADERFUNCTION, cSatipRtsp::HeaderCallback); SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEHEADER, this); SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipRtsp::DataCallback); SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this); SATIP_CURL_EASY_PERFORM(handleM); // Session id is now known - disable header parsing SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_HEADERFUNCTION, NULL); SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEHEADER, NULL); SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, NULL); SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, NULL); if (headerBufferM.Size() > 0) { ParseHeader(); headerBufferM.Reset(); } if (dataBufferM.Size() > 0) { ParseData(); dataBufferM.Reset(); } result = ValidateLatestResponse(&rc); debug5("%s (%s, %d, %d) Response %ld in %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, uriP, rtpPortP, rtcpPortP, rc, processing.Elapsed(), tunerM.GetId()); } return result; }
void arch_setup_sighandler_stack(register struct task_struct *t, __sighandler_t addr,unsigned signr) { debug5("Stack %x was %x %x %x %x\n", addr, get_ustack(t,0), get_ustack(t,2), get_ustack(t,4), get_ustack(t,6)); put_ustack(t, -4, (int)get_ustack(t,0)); put_ustack(t, -2, (int)addr); put_ustack(t, 0, (int)get_ustack(t,4)); put_ustack(t, 4, (int)get_ustack(t,2)); put_ustack(t, 2, (int)get_ustack(t,6)); put_ustack(t, 6, (int)signr); t->t_regs.sp -= 4; debug6("Stack is %x %x %x %x %x %x\n", get_ustack(t,0), get_ustack(t,2), get_ustack(t,4), get_ustack(t,6), get_ustack(t,8), get_ustack(t,10)); }
OBJECT SearchGalley(OBJECT start, OBJECT sym, BOOLEAN forwards, BOOLEAN subgalleys, BOOLEAN closures, BOOLEAN input) { OBJECT y, res, z, zlink, link; debug5(DGA, DD, "[ SearchGalley(start, %s, %s, %s, %s, %s)", SymName(sym), forwards ? "fwd" : "back", subgalleys ? "subgalleys" : "nosubgalleys", closures ? "closures" : "noclosures", input ? "input" : "noinput"); assert( type(start) == LINK || type(start) == HEAD, "SearchGalley: start!" ); link = forwards ? NextDown(start) : PrevDown(start); res = nilobj; while( res == nilobj && type(link) != HEAD ) { Child(y, link); switch( type(y) ) { case UNATTACHED: case RECEIVING: debug1(DGA, DD, " examining %s", EchoIndex(y)); if( subgalleys ) for( zlink = Down(y); zlink!=y && res==nilobj; zlink=NextDown(zlink) ) { Child(z, zlink); res = SearchGalley(z, sym, TRUE, TRUE, TRUE, input); } if( res == nilobj && input && type(y) == RECEIVING && actual(actual(y)) == InputSym ) res = y; break; case RECEPTIVE: debug1(DGA, DD, " examining %s", EchoIndex(y)); if( closures && type(actual(y)) == CLOSURE && SearchUses(actual(actual(y)), sym) ) res = y; else if( input && actual(actual(y)) == InputSym ) res = y; break; default: break; } link = forwards ? NextDown(link) : PrevDown(link); } debug1(DGA, DD, "] SearchGalley returning %s", EchoIndex(res)); return res; } /* end SearchGalley */
bool cSatipRtsp::Play(const char *uriP) { debug1("%s (%s) [device %d]", __PRETTY_FUNCTION__, uriP, tunerM.GetId()); bool result = false; if (handleM && !isempty(uriP)) { long rc = 0; cTimeMs processing(0); CURLcode res = CURLE_OK; SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, uriP); SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_PLAY); SATIP_CURL_EASY_PERFORM(handleM); result = ValidateLatestResponse(&rc); debug5("%s (%s) Response %ld in %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, uriP, rc, processing.Elapsed(), tunerM.GetId()); } return result; }
/* This needs to have block_state_mutex locked before hand. */ extern int bridge_status_update_block_list_state(List block_list) { int updated = 0; #if defined HAVE_BG_FILES int rc; rm_partition_t *block_ptr = NULL; rm_partition_state_t state; uint16_t real_state; char *name = NULL; bg_record_t *bg_record = NULL; ListIterator itr = NULL; itr = list_iterator_create(block_list); while ((bg_record = (bg_record_t *) list_next(itr)) != NULL) { if (bg_record->magic != BLOCK_MAGIC) { /* block is gone */ list_remove(itr); continue; } else if (!bg_record->bg_block_id) continue; name = bg_record->bg_block_id; real_state = bg_record->state & (~BG_BLOCK_ERROR_FLAG); if ((rc = bridge_get_block_info(name, &block_ptr)) != SLURM_SUCCESS) { if (bg_conf->layout_mode == LAYOUT_DYNAMIC) { switch(rc) { case BG_ERROR_INCONSISTENT_DATA: debug2("got inconsistent data when " "querying block %s", name); continue; break; case BG_ERROR_BLOCK_NOT_FOUND: debug("block %s not found, removing " "from slurm", name); /* Just set to free, everything will be cleaned up outside this. */ bg_record->state = BG_BLOCK_FREE; continue; break; default: break; } } /* If the call was busy, just skip this iteration. It usually means something like rm_get_BG was called which can be a very long call */ if (rc == EBUSY) { debug5("lock was busy, aborting"); break; } error("bridge_get_block_info(%s): %s", name, bg_err_str(rc)); continue; } if ((rc = bridge_get_data(block_ptr, RM_PartitionState, &state)) != SLURM_SUCCESS) { error("bridge_get_data(RM_PartitionState): %s", bg_err_str(rc)); updated = -1; goto next_block; } else if (real_state != state) { debug("freeing state of Block %s was %d and now is %d", bg_record->bg_block_id, bg_record->state, state); if (bg_record->state & BG_BLOCK_ERROR_FLAG) state |= BG_BLOCK_ERROR_FLAG; bg_record->state = state; updated = 1; } next_block: if ((rc = bridge_free_block(block_ptr)) != SLURM_SUCCESS) { error("bridge_free_block(): %s", bg_err_str(rc)); } } list_iterator_destroy(itr); #endif return updated; }
static int _do_block_poll(void) { int updated = 0; #if defined HAVE_BG_FILES int rc; rm_partition_t *block_ptr = NULL; #ifdef HAVE_BGL rm_partition_mode_t node_use; #endif rm_partition_state_t state; char *name = NULL; bg_record_t *bg_record = NULL; ListIterator itr = NULL; if (!bg_lists->main) return updated; lock_slurmctld(job_read_lock); slurm_mutex_lock(&block_state_mutex); itr = list_iterator_create(bg_lists->main); while ((bg_record = (bg_record_t *) list_next(itr)) != NULL) { if (bg_record->magic != BLOCK_MAGIC) { /* block is gone */ list_remove(itr); continue; } else if (!bg_record->bg_block_id) continue; name = bg_record->bg_block_id; if ((rc = bridge_get_block_info(name, &block_ptr)) != SLURM_SUCCESS) { if (bg_conf->layout_mode == LAYOUT_DYNAMIC) { switch(rc) { case BG_ERROR_INCONSISTENT_DATA: debug2("got inconsistent data when " "querying block %s", name); continue; break; case BG_ERROR_BLOCK_NOT_FOUND: debug("block %s not found, removing " "from slurm", name); list_remove(itr); destroy_bg_record(bg_record); continue; break; default: break; } } /* If the call was busy, just skip this iteration. It usually means something like rm_get_BG was called which can be a very long call */ if (rc == EBUSY) { debug5("lock was busy, aborting"); break; } error("bridge_get_block_info(%s): %s", name, bg_err_str(rc)); continue; } #ifdef HAVE_BGL if ((rc = bridge_get_data(block_ptr, RM_PartitionMode, &node_use)) != SLURM_SUCCESS) { error("bridge_get_data(RM_PartitionMode): %s", bg_err_str(rc)); if (!updated) updated = -1; goto next_block; } else if (bg_record->node_use != node_use) { debug("node_use of Block %s was %d " "and now is %d", bg_record->bg_block_id, bg_record->node_use, node_use); bg_record->node_use = node_use; updated = 1; } #else if ((bg_record->cnode_cnt < bg_conf->mp_cnode_cnt) || (bg_conf->mp_cnode_cnt == bg_conf->nodecard_cnode_cnt)) { char *mode = NULL; uint16_t conn_type = SELECT_SMALL; if ((rc = bridge_get_data(block_ptr, RM_PartitionOptions, &mode)) != SLURM_SUCCESS) { error("bridge_get_data(RM_PartitionOptions): " "%s", bg_err_str(rc)); if (!updated) updated = -1; goto next_block; } else if (mode) { switch(mode[0]) { case 's': conn_type = SELECT_HTC_S; break; case 'd': conn_type = SELECT_HTC_D; break; case 'v': conn_type = SELECT_HTC_V; break; case 'l': conn_type = SELECT_HTC_L; break; default: conn_type = SELECT_SMALL; break; } free(mode); } if (bg_record->conn_type[0] != conn_type) { debug("mode of small Block %s was %u " "and now is %u", bg_record->bg_block_id, bg_record->conn_type[0], conn_type); bg_record->conn_type[0] = conn_type; updated = 1; } } #endif if ((rc = bridge_get_data(block_ptr, RM_PartitionState, &state)) != SLURM_SUCCESS) { error("bridge_get_data(RM_PartitionState): %s", bg_err_str(rc)); if (!updated) updated = -1; goto next_block; } else if (bg_status_update_block_state( bg_record, state, kill_job_list) == 1) updated = 1; next_block: if ((rc = bridge_free_block(block_ptr)) != SLURM_SUCCESS) { error("bridge_free_block(): %s", bg_err_str(rc)); } } list_iterator_destroy(itr); slurm_mutex_unlock(&block_state_mutex); unlock_slurmctld(job_read_lock); bg_status_process_kill_job_list(kill_job_list, JOB_FAILED, 0); #endif return updated; }
void FlushGalley(OBJECT hd) { OBJECT dest; /* the target galley hd empties into */ OBJECT dest_index; /* the index of dest */ OBJECT inners; /* list of galleys and PRECEDES to flush */ OBJECT link, y; /* for scanning through the components of hd */ int dim; /* direction of galley */ CONSTRAINT dest_par_constr; /* the parallel size constraint on dest */ CONSTRAINT dest_perp_constr; /* the perpendicular size constraint on dest */ int pb, pf, f; /* candidate replacement sizes for dest */ OBJECT dest_encl; /* the VCAT or ACAT enclosing dest, if any */ int dest_side; /* if dest_encl != nilobj, side dest is on */ BOOLEAN need_adjust; /* TRUE as soon as dest_encl needs adjusting */ FULL_LENGTH dest_back, dest_fwd; /* the current size of dest_encl or dest */ FULL_LENGTH frame_size; /* the total constraint of dest_encl */ OBJECT prec_gap; /* the gap preceding dest if any else nilobj */ OBJECT prec_def; /* the component preceding dest, if any */ OBJECT succ_gap; /* the gap following dest if any else nilobj */ OBJECT succ_def; /* the component following dest, if any */ OBJECT stop_link; /* most recently seen gap link of hd */ FULL_LENGTH stop_back; /* back(dest_encl) incl all before stop_link */ FULL_LENGTH stop_fwd; /* fwd(dest_encl) incl. all before stop_link */ FULL_LENGTH stop_perp_back; /* back(dest_encl) in other direction */ FULL_LENGTH stop_perp_fwd; /* fwd(dest_encl) in other direction */ BOOLEAN prnt_flush; /* TRUE when the parent of hd needs a flush */ BOOLEAN target_is_internal; /* TRUE if flushing into an internal target */ BOOLEAN headers_seen; /* TRUE if a header is seen at all */ OBJECT zlink, z, tmp, prnt; int attach_status; BOOLEAN remove_target; OBJECT why; FULL_LENGTH perp_back, perp_fwd; /* current perp size of dest_encl */ debug1(DGF, D, "[ FlushGalley %s (hd)", SymName(actual(hd))); prnt_flush = FALSE; dim = gall_dir(hd); RESUME: assert( type(hd) == HEAD, "FlushGalley: type(hd) != HEAD!" ); debug1(DGF, D, " resuming FlushGalley %s, hd =", SymName(actual(hd))); ifdebugcond(DGF, DD, actual(hd) == nilobj, DebugGalley(hd, nilobj, 4)); assert( Up(hd) != hd, "FlushGalley: resume found no parent to hd!" ); /*@@************************************************************************/ /* */ /* The first step is to examine the parent of galley hd to determine the */ /* status of the galley. If this is not suitable for flushing, we do */ /* what we can to change the status. If still no good, return; so if */ /* this code does not return, then the galley is ready to flush into a */ /* destination in the normal way, and the following variables are set: */ /* */ /* dest_index the parent of the galley and index of its destination */ /* dest the destination of the galley, a @Galley object */ /* */ /***************************************************************************/ Parent(dest_index, Up(hd)); switch( type(dest_index) ) { case DEAD: /* the galley has been killed off while this process was sleeping */ debug1(DGF, D, "] FlushGalley %s returning (DEAD)", SymName(actual(hd))); return; case UNATTACHED: /* the galley is currently not attached to a destination */ attach_status = AttachGalley(hd, &inners, &y); debug1(DGF, DD, " ex-AttachGalley inners: %s", DebugInnersNames(inners)); Parent(dest_index, Up(hd)); switch( attach_status ) { case ATTACH_KILLED: assert(inners==nilobj, "FlushGalley/ATTACH_KILLED: inners!=nilobj!"); debug1(DGF, D, "] FlushGalley %s returning (ATTACH_KILLED)", SymName(actual(hd))); debug1(DGF, D, " prnt_flush = %s", bool(prnt_flush)); return; case ATTACH_INPUT: ParentFlush(prnt_flush, dest_index, FALSE); assert(inners==nilobj, "FlushGalley/ATTACH_INPUT: inners!=nilobj!"); debug1(DGF, D, "] FlushGalley %s returning (ATTACH_INPUT)", SymName(actual(hd))); return; case ATTACH_NOTARGET: ParentFlush(prnt_flush, dest_index, FALSE); assert(inners==nilobj, "FlushGalley/ATTACH_NOTARG: inners!=nilobj!"); debug1(DGF, D, "] FlushGalley %s returning (ATTACH_NOTARGET)", SymName(actual(hd))); return; case ATTACH_SUSPEND: /* AttachGalley only returns inners here if they really need to */ /* be flushed; in particular the galley must be unsized before */ if( inners != nilobj ) { debug0(DGF, DD, " calling FlushInners() from FlushGalley (a)"); FlushInners(inners, nilobj); goto RESUME; } stop_link = nilobj; goto SUSPEND; /* nb y will be set by AttachGalley in this case */ case ATTACH_NULL: /* hd will have been linked to the unexpanded target in this case */ remove_target = (actual(actual(dest_index)) == whereto(hd)); if( force_gall(hd) ) { /* if hd is a forcing galley, close all predecessors */ debug3(DGA, D, " forcing ATTACH_NULL case for %s into %s (%s)", SymName(actual(hd)), SymName(whereto(hd)), remove_target ? "remove_target" : "not remove_target"); Parent(prnt, Up(dest_index)); if( !non_blocking(dest_index) && remove_target ) { /* *** prnt_flush = TRUE; *** */ prnt_flush = non_blocking(dest_index) = TRUE; } FreeGalley(prnt, Up(dest_index), &inners, Up(dest_index), whereto(hd)); } else { debug3(DGA, D, " non-force ATTACH_NULL case for %s into %s (%s)", SymName(actual(hd)), SymName(whereto(hd)), remove_target ? "remove_target" : "not remove_target"); if( blocked(dest_index) && remove_target ) prnt_flush = TRUE; } DetachGalley(hd); KillGalley(hd, TRUE); if( inners != nilobj ) { debug0(DGF, DD, " calling FlushInners() from FlushGalley (b)"); FlushInners(inners, nilobj); } else ParentFlush(prnt_flush, dest_index, remove_target); debug0(DGF, D, "] FlushGalley returning ATTACH_NULL"); return; case ATTACH_ACCEPT: /* if hd is a forcing galley, or actual(dest_index) is */ /* @ForceGalley, then close all predecessors */ if( force_gall(hd) || actual(actual(dest_index)) == ForceGalleySym ) { Parent(prnt, Up(dest_index)); debug1(DGA, D, " forcing ATTACH_ACCEPT case for %s", SymName(actual(hd))); /* debug0(DGA, DD, " force: prnt ="); */ /* ifdebug(DGA, DD, DebugObject(prnt)); */ /* debug1(DGA, D," calling FreeGalley from FlushGalley(%s)", */ /* SymName(actual(hd))); */ if( !non_blocking(dest_index) ) prnt_flush = TRUE; /* bug fix */ FreeGalley(prnt, Up(dest_index), &inners, Up(dest_index), whereto(hd)); /* debug0(DGA, DD, " force: after FreeGalley, prnt ="); */ /* ifdebug(DGA, DD, DebugObject(prnt)); */ } else prnt_flush = prnt_flush || blocked(dest_index); debug1(DGF, DD, " force: prnt_flush = %s", bool(prnt_flush)); if( inners != nilobj ) { debug0(DGF, DD, " calling FlushInners() from FlushGalley (c)"); FlushInners(inners, nilobj); } goto RESUME; default: assert(FALSE, "FlushGalley: attach_status"); break; } break; case RECEIVING: if( actual(actual(dest_index)) == InputSym ) { ParentFlush(prnt_flush, dest_index, FALSE); debug1(DGF, D, "] FlushGalley %s retn, input", SymName(actual(hd))); return; } break; default: assert1(FALSE, "FlushGalley: dest_index", Image(type(dest_index))); break; } dest = actual(dest_index); if( underline(dest) == UNDER_UNDEF ) underline(dest) = UNDER_OFF; target_is_internal = (dim==ROWM && !external_ver(dest)) || (dim==COLM && !external_hor(dest)); headers_seen = FALSE; debug1(DGF, DD, " dest_index: %s", EchoObject(dest_index)); /*@@************************************************************************/ /* */ /* The second step is to examine the components of the galley one by one */ /* to determine if they can be promoted. Each component has the format */ /* */ /* { <index> } <object> */ /* */ /* and is always followed by a gap object (except the last component). */ /* An index indicates that the following object has some interesting */ /* feature, and it points to that feature inside the object. There are */ /* two possible actions for each component, in addition to accepting it: */ /* */ /* REJECT: The component does not fit, so detach the galley */ /* SUSPEND: The component is incomplete; go to sleep and wait */ /* */ /***************************************************************************/ stop_link = dest_encl = inners = nilobj; need_adjust = FALSE; /***************************************************************************/ /* */ /* Loop invariant */ /* */ /* The children of hd up to but not including Child(link) have been */ /* examined and pronounced to be promotable, if unbreakable gaps are */ /* ignored. When unbreakable gaps are taken into account, the most */ /* recent gap where a break is possible is at Child(stop_link), or */ /* nowhere if stop_link == nilobj. */ /* */ /* Case 1: target_is_internal == FALSE */ /* */ /* If this flag is FALSE, it means that the target of this galley is */ /* external. Consequently, there is no need to calculate sizes because */ /* there is no constraint on them. Also, a REJECT action is impossible */ /* so unbreakable gaps are no impediment. Variable dest_encl is nilobj. */ /* */ /* Case 2: target_is_internal == TRUE */ /* */ /* If this flag is TRUE, it means that the target of this galley is */ /* internal. Consequently, sizes need to be calculated, and unbreakable */ /* gaps need to be taken into account. Variable dest_encl may be not */ /* nilobj, in which case the following variables are defined: */ /* */ /* dest_encl the object enclosing dest (which must exist) */ /* prec_gap gap object preceding dest (which must exist) */ /* prec_def first definite object preceding dest (must exist) */ /* dest_back back(dest_encl) including effect of accepted compts */ /* dest_fwd fwd(dest_encl) including effect of accepted compts */ /* dest_side BACK or FWD, i.e. which side of the mark dest is on */ /* dest_par_constr the parallel size constraint on dest */ /* dest_perp_constr the perpendicular size constraint on dest */ /* frame_size size of frame enclosing dest_encl */ /* perp_back back(dest_encl) in other direction, incl accepteds */ /* perp_fwd fwd(dest_encl) in other direction, incl accepteds */ /* */ /* if dest_encl is nilobj, these variables are not defined. */ /* */ /* If stop_link is non-nilobj, then in the internal case dest_encl must */ /* be non-nilobj, and the following variables are defined: */ /* */ /* stop_back back(dest_encl) including all before stop_link */ /* stop_fwd fwd(dest_encl) including all before stop_link */ /* stop_perp_back back(dest_encl) in other direction */ /* stop_perp_fwd fwd(dest_encl) in other direction */ /* */ /* need_adjust is true if at least one definite component has been */ /* accepted for promotion and the destination is internal; hence, */ /* dest_encl is defined and its size needs to be adjusted. */ /* */ /* inners is the set of all PRECEDES and UNATTACHED indexes found. */ /* */ /***************************************************************************/ for( link = Down(hd); link != hd; link = NextDown(link) ) { Child(y, link); if( type(y) == SPLIT ) Child(y, DownDim(y, dim)); debug2(DGF, DD, " examining %s %s", Image(type(y)), EchoObject(y)); switch( type(y) ) { case GAP_OBJ: underline(y) = underline(dest); prec_gap = y; if( target_is_internal ) { /* *** not necessarily true assert( dest_encl != nilobj, "FlushGalley/GAP_OBJ: dest_encl!" ); *** */ if( dest_encl != nilobj && !nobreak(gap(prec_gap)) ) { stop_link = link; stop_back = dest_back; stop_fwd = dest_fwd; stop_perp_back = perp_back; stop_perp_fwd = perp_fwd; } } else stop_link = link; if( !join(gap(y)) ) seen_nojoin(hd) = TRUE; break; case SCALE_IND: case COVER_IND: case EXPAND_IND: case GALL_PREC: case GALL_FOLL: case GALL_FOLL_OR_PREC: case GALL_TARG: case CROSS_PREC: case CROSS_FOLL: case CROSS_FOLL_OR_PREC: case CROSS_TARG: case PAGE_LABEL_IND: underline(y) = underline(dest); break; case PRECEDES: case UNATTACHED: if( inners == nilobj ) New(inners, ACAT); Link(inners, y); break; case RECEIVING: case RECEPTIVE: goto SUSPEND; case FOLLOWS: Child(tmp, Down(y)); if( Up(tmp) == LastUp(tmp) ) { link = PrevDown(link); DisposeChild(NextDown(link)); break; } Parent(tmp, Up(tmp)); assert(type(tmp) == PRECEDES, "Flush: PRECEDES!"); switch( CheckComponentOrder(tmp, dest_index) ) { case CLEAR: DeleteNode(tmp); link = PrevDown(link); DisposeChild(NextDown(link)); break; case PROMOTE: break; case BLOCK: goto SUSPEND; case CLOSE: if( opt_components(hd) != nilobj ) { DisposeObject(opt_components(hd)); opt_components(hd) = nilobj; debug2(DOG, D, "FlushGalley(%s) de-optimizing %s", "(CLOSE problem)", SymName(actual(hd))); } debug1(DGF, DD, " reject (a) %s", EchoObject(y)); goto REJECT; } break; case BEGIN_HEADER: case END_HEADER: case SET_HEADER: case CLEAR_HEADER: /* do nothing except take note, until actually promoted out of here */ headers_seen = TRUE; break; case NULL_CLOS: case PAGE_LABEL: case WORD: case QWORD: case ONE_COL: case ONE_ROW: case WIDE: case HIGH: case HSHIFT: case VSHIFT: case HSCALE: case VSCALE: case HCOVER: case VCOVER: case HCONTRACT: case VCONTRACT: case HLIMITED: case VLIMITED: case HEXPAND: case VEXPAND: case START_HVSPAN: case START_HSPAN: case START_VSPAN: case HSPAN: case VSPAN: case ROTATE: case BACKGROUND: case SCALE: case KERN_SHRINK: case INCGRAPHIC: case SINCGRAPHIC: case PLAIN_GRAPHIC: case GRAPHIC: case LINK_SOURCE: case LINK_DEST: case ACAT: case HCAT: case VCAT: case ROW_THR: case CLOSURE: case CROSS: case FORCE_CROSS: underline(y) = underline(dest); if( dim == ROWM ) { /* make sure y is not joined to a target below (vertical case only) */ for( zlink = NextDown(link); zlink != hd; zlink = NextDown(zlink) ) { Child(z, zlink); switch( type(z) ) { case RECEPTIVE: case RECEIVING: y = z; goto SUSPEND; case GAP_OBJ: if( !join(gap(z)) ) zlink = PrevDown(hd); break; default: break; } } /* try vertical hyphenation before anything else */ if( type(y) == HCAT ) VerticalHyphenate(y); } /* check size constraint */ if( target_is_internal ) { /* initialise dest_encl etc if not done yet */ if( dest_encl == nilobj ) { assert( UpDim(dest,1-dim) == UpDim(dest,dim), "FlushG: UpDims!" ); /* *** weird old code, trying for UpDim(dest, ROWM)? Parent(dest_encl, NextDown(Up(dest))); *** */ Parent(dest_encl, Up(dest)); debug4(DGF, DD, " flush dest = %s %s, dest_encl = %s %s", Image(type(dest)), EchoObject(dest), Image(type(dest_encl)), EchoObject(dest_encl)); assert( (dim==ROWM && type(dest_encl)==VCAT) || (dim==COLM && type(dest_encl)==ACAT), "FlushGalley: dest != VCAT or ACAT!" ); SetNeighbours(Up(dest), FALSE, &prec_gap, &prec_def, &succ_gap, &succ_def, &dest_side); assert(prec_gap != nilobj || is_indefinite(type(y)), "FlushGalley: prec_gap == nilobj && !is_indefinite(type(y))!" ); assert(succ_gap == nilobj, "FlushGalley: succ_gap != nilobj!" ); assert(dest_side == FWD || is_indefinite(type(y)), "FlushGalley: dest_side != FWD || !is_indefinite(type(y))!"); dest_back = back(dest_encl, dim); dest_fwd = fwd(dest_encl, dim); perp_back = back(dest_encl, 1-dim); perp_fwd = fwd(dest_encl, 1-dim); Constrained(dest_encl, &dest_par_constr, dim, &why); Constrained(dest_encl, &dest_perp_constr, 1-dim, &why); debug1(DGF, DD, " setting dest_perp_constr = %s", EchoConstraint(&dest_perp_constr)); frame_size = constrained(dest_par_constr) ? bfc(dest_par_constr) :0; } if( !is_indefinite(type(y)) ) { ifdebugcond(DGF, DD, mode(gap(prec_gap)) == NO_MODE, DebugGalley(hd, y, 4)); /* calculate parallel effect of adding y to dest */ f = dest_fwd + fwd(y, dim) - fwd(prec_def, dim) + ActualGap(fwd(prec_def, dim), back(y, dim), fwd(y, dim), &gap(prec_gap), frame_size, dest_back + dest_fwd - fwd(prec_def, dim)); debug5(DGF, DD, " f = %s + %s - %s + %s (prec_gap %s)", EchoLength(dest_fwd), EchoLength(fwd(y, dim)), EchoLength(fwd(prec_def, dim)), EchoLength( ActualGap(fwd(prec_def, dim), back(y, dim), fwd(y, dim), &gap(prec_gap), frame_size, dest_back + dest_fwd - fwd(prec_def, dim)) ), EchoGap(&gap(prec_gap))); debug3(DGF, DD, " b,f: %s,%s; dest_encl: %s", EchoLength(dest_back), EchoLength(f), EchoConstraint(&dest_par_constr)); /* check new size against parallel constraint */ if( (units(gap(prec_gap))==FRAME_UNIT && width(gap(prec_gap)) > FR) || !FitsConstraint(dest_back, f, dest_par_constr) || (opt_components(hd) != nilobj && opt_comps_permitted(hd)<=0) ) { if( opt_components(hd) != nilobj ) { OBJECT z; /* record the size of this just-completed target area for hd */ New(z, WIDE); CopyConstraint(constraint(z), dest_par_constr); Link(opt_constraints(hd), z); ifdebug(DOG, D, debug2(DOG, D, "FlushGalley(%s) adding constraint %s", SymName(actual(hd)), EchoConstraint(&constraint(z))); if( units(gap(prec_gap))==FRAME_UNIT && width(gap(prec_gap)) > FR ) { debug1(DOG, D, " prec_gap = %s", EchoGap(&gap(prec_gap))); } if( !FitsConstraint(dest_back, f, dest_par_constr) ) { debug3(DOG, D, " !FitsConstraint(%s, %s, %s)", EchoLength(dest_back), EchoLength(f), EchoConstraint(&dest_par_constr)); } if( opt_comps_permitted(hd) <= 0 ) { debug1(DOG, D, " opt_comps_permitted = %2d", opt_comps_permitted(hd)); } debug4(DOG, D, "prec_gap = %s; y = %s (%s,%s):", EchoGap(&gap(prec_gap)), Image(type(y)), EchoLength(back(y, dim)), EchoLength(fwd(y, dim))); DebugObject(y); ) /* refresh the number of components permitted into the next target */ if( opt_counts(hd) != nilobj && Down(opt_counts(hd)) != opt_counts(hd) ) { Child(z, Down(opt_counts(hd))); opt_comps_permitted(hd) += comp_count(z) - 1; DisposeChild(Up(z)); } else opt_comps_permitted(hd) = MAX_FILES; /* a large number */ debug1(DOG, D, " REJECT permitted = %2d", opt_comps_permitted(hd)); } debug1(DGF, DD, " reject (b) %s", EchoObject(y)); goto REJECT; } /* calculate perpendicular effect of adding y to dest */ if( seen_nojoin(hd) ) { pb = 0; pf = find_max(perp_fwd, size(y, 1-dim)); } else { pb = find_max(perp_back, back(y, 1-dim)); pf = find_max(perp_fwd, fwd(y, 1-dim)); } /* check new size against perpendicular constraint */ if( !FitsConstraint(pb, pf, dest_perp_constr) ) { if( opt_components(hd) != nilobj ) { DisposeObject(opt_components(hd)); opt_components(hd) = nilobj; debug1(DOG, D, "FlushGalley(%s) de-optimizing (perp problem)", SymName(actual(hd))); } if( dim == ROWM ) { Error(20, 3, "component too wide for available space", WARN, &fpos(y)); debug6(DGF, DD, " %s,%s [%s,%s] too wide for %s, y = %s", EchoLength(pb), EchoLength(pf), EchoLength(back(y, 1-dim)), EchoLength(fwd(y, 1-dim)), EchoConstraint(&dest_perp_constr), EchoObject(y)); } debug1(DGF, DD, " reject (c) %s", EchoObject(y)); goto REJECT; } /* accept definite component */ dest_fwd = f; prec_def = y; perp_back = pb; perp_fwd = pf; need_adjust = TRUE; if( opt_components(hd) != nilobj ) { opt_comps_permitted(hd)--; debug1(DOG, D, " ACCEPT permitted = %2d", opt_comps_permitted(hd)); } } /* accept indefinite component */ } /* end if( target_is_internal ) */