/* This file is generated by "mtxrun --script "mtx-wtoc.lua" from the metapost cweb files. */ # include "mpconfig.h" # include "mp.h" # include "mpmath.h" # include "mpmathdouble.h" # include "mpmathbinary.h" # include "mpmathdecimal.h" # include "mpstrings.h" # define default_banner "This is MPLIB for LuaMetaTeX, version 3.14" # define odd(A) (abs(A) % 2 == 1) # define loc mp->cur_input.loc_field # define inf_t mp->math->md_inf_t # define negative_inf_t mp->math->md_negative_inf_t # define check_arith() \ if (mp->arith_error) { \ mp_clear_arith(mp); \ } # define arc_tol_k mp->math->md_arc_tol_k # define coef_bound_k mp->math->md_coef_bound_k # define coef_bound_minus_1 mp->math->md_coef_bound_minus_1 # define sqrt_8_e_k mp->math->md_sqrt_8_e_k # define twelve_ln_2_k mp->math->md_twelve_ln_2_k # define twelvebits_3 mp->math->md_twelvebits_3 # define one_k mp->math->md_one_k # define epsilon_t mp->math->md_epsilon_t # define unity_t mp->math->md_unity_t # define zero_t mp->math->md_zero_t # define two_t mp->math->md_two_t # define three_t mp->math->md_three_t # define half_unit_t mp->math->md_half_unit_t # define three_quarter_unit_t mp->math->md_three_quarter_unit_t # define twentysixbits_sqrt2_t mp->math->md_twentysixbits_sqrt2_t # define twentyeightbits_d_t mp->math->md_twentyeightbits_d_t # define twentysevenbits_sqrt2_d_t mp->math->md_twentysevenbits_sqrt2_d_t # define warning_limit_t mp->math->md_warning_limit_t # define precision_default mp->math->md_precision_default # define precision_min mp->math->md_precision_min # define precision_max mp->math->md_precision_max # define fraction_one_t mp->math->md_fraction_one_t # define fraction_half_t mp->math->md_fraction_half_t # define fraction_three_t mp->math->md_fraction_three_t # define fraction_four_t mp->math->md_fraction_four_t # define one_eighty_deg_t mp->math->md_one_eighty_deg_t # define negative_one_eighty_deg_t mp->math->md_negative_one_eighty_deg_t # define three_sixty_deg_t mp->math->md_three_sixty_deg_t # define max_quarterword 0x3FFF # define max_halfword 0xFFFFFFF # define max_num_token_nodes 8000 # define max_num_pair_nodes 1000 # define max_num_knot_nodes 1000 # define max_num_value_nodes 1000 # define max_num_symbolic_nodes 1000 //define mp_link(A) (A)->link //define mp_type(A) (A)->type //define mp_name_type(A) (A)->name_type # define mp_set_link(A,B) (A)->link = (mp_node) (B) # define mp_max_command_code mp_stop # define mp_max_pre_command mp_etex_command # define mp_min_command (mp_defined_macro_command+1) # define mp_max_statement_command mp_type_name_command # define mp_min_primary_command mp_type_name_command # define mp_min_suffix_token mp_internal_command # define mp_max_suffix_token mp_numeric_command # define mp_max_primary_command mp_plus_or_minus_command # define mp_min_tertiary_command mp_plus_or_minus_command # define mp_max_tertiary_command mp_tertiary_binary_command # define mp_min_expression_command mp_left_brace_command # define mp_max_expression_command mp_equals_command # define mp_min_secondary_command mp_and_command # define mp_max_secondary_command mp_secondary_binary_command # define mp_end_of_statement (cur_cmd>mp_comma_command) # define unknown_tag 1 # define mp_min_of_operation mp_substring_operation # define max_given_internal mp_restore_clip_color_internal # define set_text(A) { \ (A)->text = (B) ; \ } # define set_eq_type(A,B) { \ (A)->type = (B) ; \ } # define set_eq_property(A,B) { \ (A)->property = (B) ; \ } # define set_equiv(A,B) { \ (A)->v.data.node = NULL ; \ (A)->v.data.indep.serial = (B); \ } # define set_equiv_node(A,B) { \ (A)->v.data.node = (B) ; \ (A)->v.data.indep.serial = 0; \ } # define set_equiv_sym(A,B) { \ (A)->v.data.node = (mp_node) (B); \ (A)->v.data.indep.serial = 0; \ } # define mp_id_lookup(A,B,C,D) mp_do_id_lookup((A), mp->symbols, (B), (C), (D)) # define mp_set_value_sym(A,B) do_set_value_sym (mp, (mp_token_node) (A), (B)) # define mp_set_value_number(A,B) do_set_value_number(mp, (mp_token_node) (A), &(B)) # define mp_set_value_node(A,B) do_set_value_node (mp, (mp_token_node) (A), (B)) # define mp_set_value_str(A,B) do_set_value_str (mp, (mp_token_node) (A), (B)) # define mp_set_value_knot(A,B) do_set_value_knot (mp, (mp_token_node) (A), (B)) # define mp_get_ref_count(A) mp_get_indep_value(A) # define mp_set_ref_count(A,B) mp_set_indep_value(A,B) # define mp_add_mac_ref(A) mp_set_ref_count((A), mp_get_ref_count((A))+1) # define mp_decr_mac_ref(A) mp_set_ref_count((A), mp_get_ref_count((A))-1) # define mp_get_attribute_head(A) mp_do_get_attribute_head(mp, (mp_value_node) (A)) # define mp_set_attribute_head(A,B) mp_do_set_attribute_head(mp, (mp_value_node) (A),(mp_node) (B)) # define mp_get_subscr_head(A) mp_do_get_subscr_head(mp,(mp_value_node) (A)) # define mp_set_subscr_head(A,B) mp_do_set_subscr_head(mp,(mp_value_node) (A),(mp_node) (B)) # define mp_collective_subscript (void *)0 # define mp_subscript(A) ((mp_value_node)(A))->subscript # define mp_x_part(A) ((mp_pair_node) (A))->x_part # define mp_y_part(A) ((mp_pair_node) (A))->y_part # define mp_tx_part(A) ((mp_transform_node) (A))->tx_part # define mp_ty_part(A) ((mp_transform_node) (A))->ty_part # define mp_xx_part(A) ((mp_transform_node) (A))->xx_part # define mp_xy_part(A) ((mp_transform_node) (A))->xy_part # define mp_yx_part(A) ((mp_transform_node) (A))->yx_part # define mp_yy_part(A) ((mp_transform_node) (A))->yy_part # define mp_red_part(A) ((mp_color_node) (A))->red_part # define mp_green_part(A) ((mp_color_node) (A))->green_part # define mp_blue_part(A) ((mp_color_node) (A))->blue_part # define mp_grey_part(A) ((mp_color_node) (A))->grey_part # define mp_cyan_part(A) ((mp_color_node) (A))->cyan_part # define mp_magenta_part(A) ((mp_color_node) (A))->magenta_part # define mp_yellow_part(A) ((mp_color_node) (A))->yellow_part # define mp_black_part(A) ((mp_color_node) (A))->black_part # define mp_next_knot(A) (A)->next # define mp_left_type(A) (A)->left_type # define mp_right_type(A) (A)->right_type # define mp_prev_knot(A) (A)->prev # define mp_knot_info(A) (A)->info # define mp_originator(A) (A)->originator # define mp_knotstate(A) (A)->state # define mp_minx mp->bbmin[mp_x_code] # define mp_maxx mp->bbmax[mp_x_code] # define mp_miny mp->bbmin[mp_y_code] # define mp_maxy mp->bbmax[mp_y_code] # define one_third_inf_t mp->math->md_one_third_inf_t # define mp_copy_pen(mp,A) mp_make_pen(mp, mp_copy_path(mp, (A)),0) # define mp_pen_is_elliptical(A) ((A)==mp_next_knot((A))) # define new_number(A) mp->math->md_allocate(mp, &(A), mp_scaled_type) # define new_fraction(A) mp->math->md_allocate(mp, &(A), mp_fraction_type) # define new_angle(A) mp->math->md_allocate(mp, &(A), mp_angle_type) # define new_number_clone(A,B) mp->math->md_allocate_clone(mp, &(A), mp_scaled_type, &(B)) # define new_fraction_clone(A,B) mp->math->md_allocate_clone(mp, &(A), mp_fraction_type, &(B)) # define new_angle_clone(A,B) mp->math->md_allocate_clone(mp, &(A), mp_angle_type, &(B)) # define new_number_from_double(mp,A,B) mp->math->md_allocate_double(mp, &(A), B) # define new_number_abs(A,B) mp->math->md_allocate_abs(mp, &(A), mp_scaled_type, &(B)) # define free_number(A) mp->math->md_free(mp, &(A)) # define set_precision() mp->math->md_set_precision(mp) # define free_math() mp->math->md_free_math(mp) # define scan_numeric_token(A) mp->math->md_scan_numeric(mp,A) # define scan_fractional_token(A) mp->math->md_scan_fractional(mp,A) # define set_number_from_of_the_way(A,t,B,C) mp->math->md_from_oftheway(mp,&(A),&(t),&(B),&(C)) # define set_number_from_int(A,B) mp->math->md_from_int(&(A),B) # define set_number_from_scaled(A,B) mp->math->md_from_scaled(&(A),B) # define set_number_from_boolean(A,B) mp->math->md_from_boolean(&(A),B) # define set_number_from_double(A,B) mp->math->md_from_double(&(A),B) # define set_number_from_addition(A,B,C) mp->math->md_from_addition(&(A),&(B),&(C)) # define set_number_half_from_addition(A,B,C) mp->math->md_half_from_addition(&(A),&(B),&(C)) # define set_number_from_subtraction(A,B,C) mp->math->md_from_subtraction(&(A),&(B),&(C)) # define set_number_half_from_subtraction(A,B,C) mp->math->md_half_from_subtraction(&(A),&(B),&(C)) # define set_number_from_div(A,B,C) mp->math->md_from_div(&(A),&(B),&(C)) # define set_number_from_mul(A,B,C) mp->math->md_from_mul(&(A),&(B),&(C)) # define number_int_div(A,C) mp->math->md_from_int_div(&(A),&(A),C) # define set_number_from_int_mul(A,B,C) mp->math->md_from_int_mul(&(A),&(B),C) # define set_number_to_unity(A) mp->math->md_clone(&(A), &unity_t) # define set_number_to_zero(A) mp->math->md_clone(&(A), &zero_t) # define set_number_to_inf(A) mp->math->md_clone(&(A), &inf_t) # define set_number_to_negative_inf(A) mp->math->md_clone(&(A), &negative_inf_t) # define old_set_number_to_neg_inf(A) do { set_number_to_inf(A); number_negate(A); } while (0) # define init_randoms(A) mp->math->md_init_randoms(mp,A) # define print_number(A) mp->math->md_print(mp,&(A)) # define number_tostring(A) mp->math->md_tostring(mp,&(A)) # define make_scaled(R,A,B) mp->math->md_make_scaled(mp,&(R),&(A),&(B)) # define take_scaled(R,A,B) mp->math->md_take_scaled(mp,&(R),&(A),&(B)) # define make_fraction(R,A,B) mp->math->md_make_fraction(mp,&(R),&(A),&(B)) # define take_fraction(R,A,B) mp->math->md_take_fraction(mp,&(R),&(A),&(B)) # define pyth_add(R,A,B) mp->math->md_pyth_add(mp,&(R),&(A),&(B)) # define pyth_sub(R,A,B) mp->math->md_pyth_sub(mp,&(R),&(A),&(B)) # define power_of(R,A,B) mp->math->md_power_of(mp,&(R),&(A),&(B)) # define n_arg(R,A,B) mp->math->md_n_arg(mp,&(R),&(A),&(B)) # define m_log(R,A) mp->math->md_m_log(mp,&(R),&(A)) # define m_exp(R,A) mp->math->md_m_exp(mp,&(R),&(A)) # define m_unif_rand(R,A) mp->math->md_m_unif_rand(mp,&(R),&(A)) # define m_norm_rand(R) mp->math->md_m_norm_rand(mp,&(R)) # define velocity(R,A,B,C,D,E) mp->math->md_velocity(mp,&(R),&(A),&(B),&(C),&(D),&(E)) # define ab_vs_cd(A,B,C,D) mp->math->md_ab_vs_cd(&(A),&(B),&(C),&(D)) # define crossing_point(R,A,B,C) mp->math->md_crossing_point(mp,&(R),&(A),&(B),&(C)) # define n_sin_cos(A,S,C) mp->math->md_sin_cos(mp,&(A),&(S),&(C)) # define square_rt(A,S) mp->math->md_sqrt(mp,&(A),&(S)) # define slow_add(R,A,B) mp->math->md_slow_add(mp,&(R),&(A),&(B)) # define round_unscaled(A) mp->math->md_round_unscaled(&(A)) # define floor_scaled(A) mp->math->md_floor_scaled(&(A)) # define fraction_to_round_scaled(A) mp->math->md_fraction_to_round_scaled(&(A)) # define number_to_int(A) mp->math->md_to_int(&(A)) # define number_to_boolean(A) mp->math->md_to_boolean(&(A)) # define number_to_scaled(A) mp->math->md_to_scaled(&(A)) # define number_to_double(A) mp->math->md_to_double(&(A)) # define number_negate(A) mp->math->md_negate(&(A)) # define number_add(A,B) mp->math->md_add(&(A),&(B)) # define number_subtract(A,B) mp->math->md_subtract(&(A),&(B)) # define number_half(A) mp->math->md_half(&(A)) # define number_double(A) mp->math->md_do_double(&(A)) # define number_add_scaled(A,B) mp->math->md_add_scaled(&(A),B) # define number_multiply_int(A,B) mp->math->md_multiply_int(&(A),B) # define number_divide_int(A,B) mp->math->md_divide_int(&(A),B) # define number_abs(A) mp->math->md_abs(&(A)) # define number_modulo(A,B) mp->math->md_modulo(&(A),&(B)) # define number_nonequalabs(A,B) mp->math->md_nonequalabs(&(A),&(B)) # define number_odd(A) mp->math->md_odd(&(A)) # define number_equal(A,B) mp->math->md_equal(&(A),&(B)) # define number_greater(A,B) mp->math->md_greater(&(A),&(B)) # define number_less(A,B) mp->math->md_less(&(A),&(B)) # define number_clone(A,B) mp->math->md_clone(&(A),&(B)) # define number_negated_clone(A,B) mp->math->md_negated_clone(&(A),&(B)) # define number_abs_clone(A,B) mp->math->md_abs_clone(&(A),&(B)) # define number_swap(A,B) mp->math->md_swap(&(A),&(B)); # define convert_scaled_to_angle(A) mp->math->md_scaled_to_angle(&(A)); # define convert_angle_to_scaled(A) mp->math->md_angle_to_scaled(&(A)); # define convert_fraction_to_scaled(A) mp->math->md_fraction_to_scaled(&(A)); # define convert_scaled_to_fraction(A) mp->math->md_scaled_to_fraction(&(A)); # define number_zero(A) number_equal(A, zero_t) # define number_infinite(A) number_equal(A, inf_t) # define number_unity(A) number_equal(A, unity_t) # define number_negative(A) number_less(A, zero_t) # define number_nonnegative(A) (! number_negative(A)) # define number_positive(A) number_greater(A, zero_t) # define number_nonpositive(A) (! number_positive(A)) # define number_nonzero(A) (! number_zero(A)) # define number_greaterequal(A,B) (! number_less(A,B)) # define number_lessequal(A,B) (! number_greater(A,B)) # define mp_path_ptr(A) (A)->path # define mp_pen_ptr(A) (A)->pen # define mp_dash_ptr(A) ((mp_shape_node) (A))->dash # define mp_line_cap(A) ((mp_shape_node) (A))->linecap # define mp_line_join(A) ((mp_shape_node) (A))->linejoin # define mp_miterlimit(A) ((mp_shape_node) (A))->miterlimit # define mp_set_linecap(A,B) ((mp_shape_node) (A))->linecap = (unsigned char) (B) # define mp_set_linejoin(A,B) ((mp_shape_node) (A))->linejoin = (unsigned char) (B) # define mp_pre_script(A) ((mp_shape_node) (A))->pre_script # define mp_post_script(A) ((mp_shape_node) (A))->post_script # define mp_color_model(A) ((mp_shape_node) (A))->color_model # define mp_stacking(A) ((mp_shape_node) (A))->stacking # define mp_pen_type(A) ((mp_shape_node) (A))->pen_type # define mp_cyan_color(A) ((mp_shape_node) (A))->cyan # define mp_magenta_color(A) ((mp_shape_node) (A))->magenta # define mp_yellow_color(A) ((mp_shape_node) (A))->yellow # define mp_black_color(A) ((mp_shape_node) (A))->black # define mp_red_color(A) ((mp_shape_node) (A))->red # define mp_green_color(A) ((mp_shape_node) (A))->green # define mp_blue_color(A) ((mp_shape_node) (A))->blue # define mp_gray_color(A) ((mp_shape_node) (A))->grey # define mp_grey_color(A) ((mp_shape_node) (A))->grey # define mp_has_color(A) ((A)->type < mp_start_clip_node_type) # define mp_has_script(A) ((A)->type <= mp_start_bounds_node_type) # define mp_has_pen(A) ((A)->type <= mp_stroked_node_type) # define mp_is_start_or_stop(A) ((A)->type >= mp_start_clip_node_type) # define mp_is_stop(A) ((A)->type >= mp_stop_clip_node_type) # define mp_get_dash_list(A) (mp_dash_node) (((mp_dash_node) (A))->link) # define mp_set_dash_list(A,B) ((mp_dash_node) (A))->link = (mp_node) ((B)) # define mp_bblast(A) ((mp_edge_header_node) (A))->bblast # define mp_edge_list(A) ((mp_edge_header_node) (A))->list # define mp_obj_tail(A) ((mp_edge_header_node) (A))->obj_tail # define mp_edge_ref_count(A) ((mp_edge_header_node) (A))->ref_count # define mp_add_edge_ref(mp,A) mp_edge_ref_count((A)) += 1 # define mp_delete_edge_ref(mp,A) { \ if (mp_edge_ref_count((A)) == 0) { \ mp_toss_edges(mp, (mp_edge_header_node) (A)); \ } else { \ mp_edge_ref_count((A)) -= 1; \ } \ } # define mp_dash_info(A) ((mp_dash_node) (A))->dash_info # define zero_off 0 # define near_zero_angle_k mp->math->md_near_zero_angle_t # define stack_1(A) mp->bisect_stack[(A)] # define stack_2(A) mp->bisect_stack[(A)+1] # define stack_3(A) mp->bisect_stack[(A)+2] # define stack_min(A) mp->bisect_stack[(A)+3] # define stack_max(A) mp->bisect_stack[(A)+4] # define int_packets 20 # define u_packet(A) ((A)- 5) # define v_packet(A) ((A)-10) # define x_packet(A) ((A)-15) # define y_packet(A) ((A)-20) # define l_packets (mp->bisect_ptr-int_packets) # define r_packets mp->bisect_ptr # define ul_packet u_packet(l_packets) # define vl_packet v_packet(l_packets) # define xl_packet x_packet(l_packets) # define yl_packet y_packet(l_packets) # define ur_packet u_packet(r_packets) # define vr_packet v_packet(r_packets) # define xr_packet x_packet(r_packets) # define yr_packet y_packet(r_packets) # define u1l stack_1(ul_packet) # define u2l stack_2(ul_packet) # define u3l stack_3(ul_packet) # define v1l stack_1(vl_packet) # define v2l stack_2(vl_packet) # define v3l stack_3(vl_packet) # define x1l stack_1(xl_packet) # define x2l stack_2(xl_packet) # define x3l stack_3(xl_packet) # define y1l stack_1(yl_packet) # define y2l stack_2(yl_packet) # define y3l stack_3(yl_packet) # define u1r stack_1(ur_packet) # define u2r stack_2(ur_packet) # define u3r stack_3(ur_packet) # define v1r stack_1(vr_packet) # define v2r stack_2(vr_packet) # define v3r stack_3(vr_packet) # define x1r stack_1(xr_packet) # define x2r stack_2(xr_packet) # define x3r stack_3(xr_packet) # define y1r stack_1(yr_packet) # define y2r stack_2(yr_packet) # define y3r stack_3(yr_packet) # define stack_dx mp->bisect_stack[mp->bisect_ptr] # define stack_dy mp->bisect_stack[mp->bisect_ptr+1] # define stack_tol mp->bisect_stack[mp->bisect_ptr+2] # define stack_uv mp->bisect_stack[mp->bisect_ptr+3] # define stack_xy mp->bisect_stack[mp->bisect_ptr+4] # define int_increment (int_packets+int_packets+5) # define max_patience 5000 # define half(A) ((A)/2) # define intersection_run_shift 8 # define mp_get_indep_scale(A) ((mp_value_node) (A))->data.indep.scale # define mp_set_indep_scale(A,B) ((mp_value_node) (A))->data.indep.scale = (B) # define mp_get_indep_value(A) ((mp_value_node) (A))->data.indep.serial # define mp_set_indep_value(A,B) ((mp_value_node) (A))->data.indep.serial = (B) # define mp_get_dep_value(A) ((mp_value_node) (A))->data.n # define mp_get_dep_list(A) ((mp_value_node) (A))->attr_head # define mp_get_prev_dep(A) ((mp_value_node) (A))->subscr_head # define mp_get_dep_info(A) do_get_dep_info(mp, (A)) # define mp_set_dep_value(A,B) do_set_dep_value(mp,(A),&(B)) # define mp_set_dep_list(A,B) ((mp_value_node) (A))->attr_head = (mp_node) (B) # define mp_set_prev_dep(A,B) ((mp_value_node) (A))->subscr_head = (mp_node) (B) # define mp_set_dep_info(A,B) ((mp_value_node) (A))->parent = (mp_node) (B) # define independent_needing_fix 0 # define fraction_threshold_k mp->math->md_fraction_threshold_t # define half_fraction_threshold_k mp->math->md_half_fraction_threshold_t # define scaled_threshold_k mp->math->md_scaled_threshold_t # define half_scaled_threshold_k mp->math->md_half_scaled_threshold_t # define p_over_v_threshold_k mp->math->md_p_over_v_threshold_t # define independent_being_fixed 1 # define two_to_the(A) (1<<(unsigned)(A)) # define cur_cmd mp->cur_mod_->command # define cur_mod number_to_scaled(mp->cur_mod_->data.n) # define cur_mod_number mp->cur_mod_->data.n # define cur_mod_node mp->cur_mod_->data.node # define cur_mod_str mp->cur_mod_->data.str # define cur_sym mp->cur_mod_->data.sym # define cur_sym_mod mp->cur_mod_->name_type # define set_cur_cmd(A) mp->cur_mod_->command = (A) # define set_cur_mod(A) set_number_from_scaled(mp->cur_mod_->data.n, (A)) # define set_cur_mod_number(A) number_clone(mp->cur_mod_->data.n, (A)) # define set_cur_mod_node(A) mp->cur_mod_->data.node = (A) # define set_cur_mod_str(A) mp->cur_mod_->data.str = (A) # define set_cur_sym(A) mp->cur_mod_->data.sym = (A) # define set_cur_sym_mod(A) mp->cur_mod_->name_type = (A) # define iindex mp->cur_input.index_field # define start mp->cur_input.start_field # define limit mp->cur_input.limit_field # define name mp->cur_input.name_field # define is_term (mp_string) 0 # define is_read (mp_string) 1 # define is_scantok (mp_string) 2 # define max_spec_src is_scantok # define terminal_input (name == is_term) # define cur_file mp->input_file[iindex] # define line mp->line_stack[iindex] # define nloc mp->cur_input.nloc_field # define nstart mp->cur_input.nstart_field # define token_type iindex # define token_state (iindex<=mp_macro_text) # define file_state (iindex>mp_macro_text) # define param_start limit # define get_t_next(mp) do { \ mp_get_next(mp); \ if (cur_cmd <= mp_max_pre_command) { \ mp_t_next(mp); \ } \ } while (0) # define mp_if_line_field(A) ((mp_if_node) (A))->if_line_field # define MP_VOID (mp_node) (1) # define MP_PROGRESSION_FLAG (mp_node) (2) # define cur_exp_value_boolean number_to_int(mp->cur_exp.data.n) # define cur_exp_value_number mp->cur_exp.data.n # define cur_exp_node mp->cur_exp.data.node # define cur_exp_str mp->cur_exp.data.str # define cur_exp_knot mp->cur_exp.data.p # define min_tension three_quarter_unit_t # define mp_floor(a) ((a) >= 0 ? (int) (a) : -(int) (-(a))) # define bezier_error (720*(256*256*16))+1 # define mp_sign(v) ((v) > 0 ? 1 : ((v)<0 ? -1 : 0 )) # define mp_out(A) (double)((A)/16) # define p_nextnext mp_next_knot(mp_next_knot(p)) # define p_next mp_next_knot(p) # define equation_threshold_k mp->math->md_equation_threshold_t # define make_cp_a_colored_object(cp,p) do { \ cp = p; \ while (cp != NULL) { \ if (mp_has_color(cp)) { \ break; \ } else { \ cp = cp->link; \ } \ } \ } while (0) # define set_color_val(A,B) do { \ if (number_negative(A)) { \ set_number_to_zero(A); \ } else if (number_greater(A,unity_t)) { \ set_number_to_unity(A); \ } else { \ number_clone(A, (B)); \ } \ } while (0) # define message_code 0 # define err_message_code 1 # define err_help_code 2 # define max_integer 0x7FFFFFFF # define gr_next_knot(A) (A)->next # define gr_originator(A) (A)->originator # define mp_knotstate(A) (A)->state # define gr_type(A) (A)->type # define gr_link(A) (A)->next # define gr_color_model(A) (A)->color_model # define gr_red_val(A) (A)->color.a_val # define gr_green_val(A) (A)->color.b_val # define gr_blue_val(A) (A)->color.c_val # define gr_cyan_val(A) (A)->color.a_val # define gr_magenta_val(A) (A)->color.b_val # define gr_yellow_val(A) (A)->color.c_val # define gr_black_val(A) (A)->color.d_val # define gr_grey_val(A) (A)->color.d_val # define gr_path_ptr(A) (A)->path # define gr_htap_ptr(A) (A)->htap # define gr_pen_ptr(A) (A)->pen # define gr_linejoin_val(A) (A)->linejoin # define gr_linecap_val(A) (A)->linecap # define gr_stacking_val(A) (A)->stacking # define gr_miterlimit_val(A) (A)->miterlimit # define gr_pre_script(A) (A)->pre_script # define gr_post_script(A) (A)->post_script # define gr_pre_length(A) (A)->pre_length # define gr_post_length(A) (A)->post_length # define gr_dash_ptr(A) (A)->dash # define mp_gr_export_color(q,p) \ if (mp_color_model(p) == mp_uninitialized_model) { \ gr_color_model(q) = (unsigned char) (number_to_scaled(internal_value(mp_default_color_model_internal))/65536); \ gr_cyan_val(q) = 0; \ gr_magenta_val(q) = 0; \ gr_yellow_val(q) = 0; \ gr_black_val(q) = gr_color_model(q) == mp_cmyk_model ? (number_to_scaled(unity_t)/65536.0) : 0; \ } else { \ gr_color_model(q) = (unsigned char) mp_color_model(p); \ gr_cyan_val(q) = number_to_double(p->cyan); \ gr_magenta_val(q) = number_to_double(p->magenta); \ gr_yellow_val(q) = number_to_double(p->yellow); \ gr_black_val(q) = number_to_double(p->black); \ } # define mp_gr_export_scripts(q,p) \ if (mp_pre_script (p)) { \ gr_pre_script(q) = mp_strndup((const char *) mp_pre_script(p)->str, mp_pre_script(p)->len); \ gr_pre_length(q) = mp_pre_script(p)->len; \ } \ if (mp_post_script(p)) { \ gr_post_script(q) = mp_strndup((const char *) mp_post_script(p)->str, mp_post_script(p)->len); \ gr_post_length(q) = mp_post_script(p)->len; \ } MP_options *mp_options (void); MP mp_initialize (MP_options * opt); static char *mp_find_file (MP mp, const char *fname, const char *fmode, int ftype); static void *mp_open_file (MP mp, const char *fname, const char *fmode, int ftype); static char *mp_read_file (MP mp, void *f, size_t * size); static void mp_close_file (MP mp, void *f); static void mp_write_file (MP mp, void *f, const char *s); static char *mp_run_script (MP mp, const char *str, size_t len, int n); static void mp_run_internal (MP mp, int action, int n, int type, const char *iname); static void mp_run_logger (MP mp, int target, const char *s, size_t l); static int mp_run_overload (MP mp, int property, const char *, int); static void mp_run_error (MP mp, const char *, const char *, int); static void mp_run_warning (MP mp, const char *); static char *mp_make_text (MP mp, const char *str, size_t len, int mode); static void mp_print_str (MP mp, const char *s); static void mp_print_nl (MP mp, const char *s); static void mp_print_fmt (MP mp, const char *s, ...); static void mp_print_ln (MP mp); static void mp_print_chr (MP mp, unsigned char k); static void mp_print_mp_str (MP mp, mp_string s); static void mp_print_nl (MP mp, const char *s); static void mp_print_two (MP mp, mp_number *x, mp_number *y); static void mp_print_nl_only (MP mp); static void mp_print_int (MP mp, int n); static void mp_get_next (MP mp); static void mp_begin_file_reading (MP mp); static void mp_free_node (MP mp, mp_node p, size_t siz); static void mp_free_symbolic_node (MP mp, mp_node p); static void mp_free_value_node (MP mp, mp_node p); static void mp_print_type (MP mp, int t); static void mp_fix_date_and_time (MP mp); static void mp_begin_diagnostic (MP mp); static void mp_end_diagnostic (MP mp, int blank_line); static void mp_print_diagnostic (MP mp, const char *s, const char *t, int nuline); static int mp_compare_symbols_entry (void *p, const void *pa, const void *pb); static void *mp_copy_symbols_entry (const void *p); static void *mp_delete_symbols_entry (void *p); static mp_sym new_symbols_entry (MP mp, unsigned char *nam, size_t len); inline static void do_set_value_sym (MP mp, mp_token_node A, mp_sym B); inline static void do_set_value_number (MP mp, mp_token_node A, mp_number *B); inline static void do_set_value_str (MP mp, mp_token_node A, mp_string B); inline static void do_set_value_node (MP mp, mp_token_node A, mp_node B); inline static void do_set_value_knot (MP mp, mp_token_node A, mp_knot B); static void mp_free_token_node (MP mp, mp_node p); static void mp_flush_token_list (MP mp, mp_node p); static void mp_show_token_list (MP mp, mp_node p, mp_node q); static void mp_show_token_list_space (MP mp, mp_node p, mp_node q); static void mp_print_capsule (MP mp, mp_node p); static mp_node mp_do_get_subscr_head (MP mp, mp_value_node A); static mp_node mp_do_get_attribute_head (MP mp, mp_value_node A); static void mp_do_set_attribute_head (MP mp, mp_value_node A, mp_node d); static void mp_do_set_subscr_head (MP mp, mp_value_node A, mp_node d); static mp_node mp_new_value_node (MP mp); static void mp_print_variable_name (MP mp, mp_node p); static void mp_flush_cur_exp (MP mp, mp_value v); static void mp_flush_below_variable (MP mp, mp_node p); static void mp_pr_path (MP mp, mp_knot h); static void mp_print_path (MP mp, mp_knot h, const char *s, int nuline); static mp_knot mp_new_knot (MP mp); static mp_gr_knot mp_gr_new_knot (MP mp); static void mp_toss_knot_list (MP mp, mp_knot p); static void mp_toss_knot (MP mp, mp_knot p); static void mp_free_knot (MP mp, mp_knot p); static void mp_reallocate_paths (MP mp, int l); static void mp_solve_choices (MP mp, mp_knot p, mp_knot q, int n); static void mp_reduce_angle (MP mp, mp_number *a); static void mp_curl_ratio (MP mp, mp_number *ret, mp_number *gamma, mp_number *a_tension, mp_number *b_tension); static void mp_set_controls (MP mp, mp_knot p, mp_knot q, int k); static void mp_solve_rising_cubic (MP mp, mp_number *ret, mp_number *a_orig, mp_number *b_orig, mp_number *c_orig, mp_number *x_orig); static void mp_pr_pen (MP mp, mp_knot h); static void mp_print_pen (MP mp, mp_knot h, const char *s, int nuline); static mp_knot mp_convex_hull (MP mp, mp_knot h); void mp_simplify_path (MP mp, mp_knot h); static void mp_move_knot (MP mp, mp_knot p, mp_knot q); static void mp_sqrt_det (MP mp, mp_number *ret, mp_number *a_orig, mp_number *b_orig, mp_number *c_orig, mp_number *d_orig); static void mp_flush_dash_list (MP mp, mp_edge_header_node h); static mp_edge_header_node mp_toss_gr_object (MP mp, mp_node p); static void mp_toss_edges (MP mp, mp_edge_header_node h); static mp_edge_header_node mp_copy_objects (MP mp, mp_node p, mp_node q); static void mp_print_edges (MP mp, mp_node h, const char *s, int nuline); static void mp_print_obj_color (MP mp, mp_node p); static void mp_dash_offset (MP mp, mp_number *x, mp_dash_node h); static void mp_x_retrace_error (MP mp); static void mp_set_bbox (MP mp, mp_edge_header_node h, int top_level); static void mp_split_cubic (MP mp, mp_knot p, mp_number *t); static mp_knot mp_split_cubic_knot (MP mp, mp_knot p, mp_number *t); static void mp_remove_cubic (MP mp, mp_knot p); static mp_knot mp_pen_walk (MP mp, mp_knot w, int k); static void mp_fin_offset_prep (MP mp, mp_knot p, mp_knot w, mp_number *x0, mp_number *x1, mp_number *x2, mp_number *y0, mp_number *y1, mp_number *y2, int rise, int turn_amt); static int mp_get_turn_amt (MP mp, mp_knot w, mp_number *dx, mp_number *dy, int ccw); static mp_knot mp_insert_knot (MP mp, mp_knot q, mp_number *x, mp_number *y); static void mp_set_min_max (MP mp, int v); static void mp_new_indep (MP mp, mp_node p); inline static mp_node do_get_dep_info (MP mp, mp_value_node p); inline static void do_set_dep_value (MP mp, mp_value_node p, mp_number *q); static void mp_free_dep_node (MP mp, mp_value_node p); static void mp_print_dependency (MP mp, mp_value_node p, int t); static mp_value_node mp_p_plus_fq (MP mp, mp_value_node p, mp_number *f, mp_value_node q, mp_variable_type t, mp_variable_type tt); static mp_value_node mp_p_over_v (MP mp, mp_value_node p, mp_number *v, int t0, int t1); static void mp_val_too_big (MP mp, mp_number *x); static void mp_make_known (MP mp, mp_value_node p, mp_value_node q); static void mp_fix_dependencies (MP mp); static void mp_ring_delete (MP mp, mp_node p); static void mp_exclaim_redundant_equation (MP mp); static const char *mp_cmd_mod_string (MP mp, int c, int m); static void mp_print_cmd_mod (MP mp, int c, int m); static void mp_reallocate_input_stack (MP mp, int newsize); static int mp_true_line (MP mp); static void mp_push_input (MP mp); static void mp_pop_input (MP mp); static void mp_back_input (MP mp); static void mp_back_error (MP mp, const char *msg, const char *hlp) ; static void mp_runaway (MP mp); static void mp_firm_up_the_line (MP mp); static int mp_move_to_next_line (MP mp); static void mp_t_next (MP mp); static void mp_scan_primary (MP mp); static void mp_scan_secondary (MP mp); static void mp_scan_tertiary (MP mp); static void mp_scan_expression (MP mp); static void mp_scan_suffix (MP mp); static void mp_pass_text (MP mp); static void mp_conditional (MP mp); static void mp_start_input (MP mp); static void mp_begin_iteration (MP mp); static void mp_resume_iteration (MP mp); static void mp_stop_iteration (MP mp); static void check_script_result (MP mp, char *s); static void mp_get_x_next (MP mp); static void mp_macro_call (MP mp, mp_node def_ref, mp_node arg_list, mp_sym macro_name); static void mp_print_macro_name (MP mp, mp_node a, mp_sym n); static void mp_print_arg (MP mp, mp_node q, int n, int b, int bb); static void mp_scan_text_arg (MP mp, mp_sym l_delim, mp_sym r_delim); static void mp_push_condition_stack (MP mp); static void mp_pop_condition_stack (MP mp); static void mp_begin_name (MP mp); static int mp_more_name (MP mp, unsigned char c); static void mp_end_name (MP mp); static void mp_open_write_file (MP mp, char *s, int n); static void mp_set_cur_exp_knot (MP mp, mp_knot n); static void mp_set_cur_exp_node (MP mp, mp_node n); static void mp_set_cur_exp_value_boolean (MP mp, int b); static void mp_set_cur_exp_value_scaled (MP mp, int s); static void mp_set_cur_exp_value_number (MP mp, mp_number *n); static void mp_set_cur_exp_str (MP mp, mp_string s); static mp_node mp_stash_cur_exp (MP mp); static void mp_print_dp (MP mp, int t, mp_value_node p, int verbosity); static void mp_unstash_cur_exp (MP mp, mp_node p); static void mp_print_exp (MP mp, mp_node p, int verbosity); static void mp_print_big_node (MP mp, mp_node p, int verbosity); static void mp_disp_err (MP mp, mp_node p); static void mp_recycle_value (MP mp, mp_node p); static void mp_recycle_independent_value (MP mp, mp_node p); static void mp_show_transformed_dependency (MP mp, mp_number *v, mp_variable_type t, mp_node p); static void mp_known_pair (MP mp); static void do_boolean_error (MP mp); static void push_of_path_result (MP mp, int what, mp_knot p); static mp_knot mp_simple_knot(MP mp, mp_number *x, mp_number *y); static mp_knot mp_complex_knot(MP mp, mp_knot o); static int mp_pict_color_type (MP mp, int c); static void mp_bad_color_part (MP mp, int c); static mp_edge_header_node mp_scale_edges (MP mp, mp_number *se_sf, mp_edge_header_node se_pic); static void mp_path_length (MP mp, mp_number *n); static void mp_pair_value (MP mp, mp_number *x, mp_number *y); static void mp_do_type_declaration (MP mp); static void mp_do_max_knot_pool (MP mp); static void mp_do_random_seed (MP mp); static void mp_do_protection (MP mp); static void mp_do_property (MP mp); static void mp_def_delims (MP mp); static void mp_do_statement (MP mp); static void mp_do_interim (MP mp); static void mp_do_let (MP mp); static void mp_do_show (MP mp); static void mp_disp_token (MP mp); static void mp_do_show_token (MP mp); static void mp_do_show_stats (MP mp); static void mp_disp_var (MP mp, mp_node p); static void mp_do_show_var (MP mp); static void mp_do_show_dependencies (MP mp); static void mp_do_show_whatever (MP mp); static void mp_scan_with_list (MP mp, mp_node p, mp_node pp); static mp_edge_header_node mp_find_edges_var (MP mp, mp_node t); static mp_node mp_start_draw_cmd (MP mp, int sep); static void mp_do_bounds (MP mp); static void mp_do_add_to (MP mp); static void mp_ship_out (MP mp, mp_node h); static void mp_do_ship_out (MP mp); static void mp_do_message (MP mp); static void mp_no_string_err (MP mp, const char *s); static void mp_do_write (MP mp); static void mp_do_write_string (MP mp, mp_string t); static void mp_make_eq (MP mp, mp_node lhs); static void mp_do_equation (MP mp); static void mp_do_assignment (MP mp); static void mp_try_eq (MP mp, mp_node l, mp_node r); static mp_node mp_scan_declared_variable (MP mp); static void mp_check_delimiter (MP mp, mp_sym l_delim, mp_sym r_delim); static void mp_do_new_internal (MP mp); static void mp_shipout_backend (MP mp, void *h); static void mp_close_files (MP mp); static void mp_close_files_and_terminate (MP mp); static void mp_final_cleanup (MP mp); static void mp_init_prim (MP mp); static void mp_init_tab (MP mp); void mp_jump_out (MP mp) { if (mp->internal != NULL && mp->history < mp_system_error_stop) { mp_close_files_and_terminate(mp); } longjmp(*(mp->jump_buf), 1); } void mp_warn (MP mp, const char *msg) { int selector = mp->selector; mp_normalize_selector(mp); mp_print_nl(mp, "Warning: "); mp_print_str(mp, msg); mp_print_ln(mp); mp->selector = selector; } void mp_fatal_error (MP mp, const char *s) { mp_normalize_selector(mp); if (mp->interaction == mp_error_stop_mode) { mp->interaction = mp_scroll_mode; } mp_error(mp, "Emergency stop", s); mp->history = mp_fatal_error_stop; mp_jump_out(mp); } void mp_confusion (MP mp, const char *s) { char msg[256]; const char *hlp = NULL; mp_normalize_selector(mp); if (mp->history < mp_error_message_issued) { mp_snprintf(msg, 256, "This can't happen (%s)", s); hlp = "I'm broken. Please show this to someone who can fix can fix it and try\n" "again"; } else { hlp = "One of your faux pas seems to have wounded me deeply ... in fact, I'm barely\n" "conscious. Please fix it and try again."; mp_snprintf(msg, 256, "I can't go on meeting you like this"); } if (mp->interaction == mp_error_stop_mode) { mp->interaction = mp_scroll_mode; } mp_error(mp, msg, hlp); mp->history=mp_fatal_error_stop; mp_jump_out(mp); } MP_options *mp_options (void) { MP_options *opt = mp_memory_clear_allocate(sizeof(MP_options)); return opt; } static MP mp_do_new (jmp_buf *buf) { MP mp = mp_memory_clear_allocate(sizeof(MP_instance)); if (mp == NULL) { mp_memory_free(buf); return NULL; } else { mp->jump_buf = buf; return mp; } } static void mp_free (MP mp) { mp_memory_free(mp->banner); mp_memory_free(mp->buffer); mp_dealloc_strings(mp); for (int i = 0; i < 55; i++) { free_number(mp->randoms[i]); } while (mp->value_nodes) { mp_node p = mp->value_nodes; mp->value_nodes = p->link; mp_free_node(mp, p, sizeof(mp_value_node_data)); } while (mp->symbolic_nodes) { mp_node p = mp->symbolic_nodes; mp->symbolic_nodes = p->link; mp_free_node(mp, p, sizeof(mp_node_data)); } while (mp->pair_nodes) { mp_node p = mp->pair_nodes; mp->pair_nodes = p->link; mp_free_node(mp, p, sizeof(mp_pair_node_data)); } while (mp->token_nodes) { mp_node p = mp->token_nodes; mp->token_nodes = p->link; mp_free_node(mp, p, sizeof(mp_node_data)); } while (mp->knot_nodes) { mp_knot p = mp->knot_nodes; mp->knot_nodes = p->next; mp_free_knot(mp, p); } if (mp->symbols != NULL) { avl_destroy (mp->symbols); } if (mp->frozen_symbols != NULL) { avl_destroy (mp->frozen_symbols); } for (int k = 0; kpath_size; k++) { free_number(mp->delta_x[k]); free_number(mp->delta_y[k]); free_number(mp->delta[k]); free_number(mp->psi[k]); } mp_memory_free(mp->delta_x); mp_memory_free(mp->delta_y); mp_memory_free(mp->delta); mp_memory_free(mp->psi); for (int k = 0; k < mp->path_size; k++) { free_number(mp->theta[k]); free_number(mp->uu[k]); free_number(mp->vv[k]); free_number(mp->ww[k]); } mp_memory_free(mp->theta); mp_memory_free(mp->uu); mp_memory_free(mp->vv); mp_memory_free(mp->ww); free_number(mp->st); free_number(mp->ct); free_number(mp->sf); free_number(mp->cf); for (int i = 0; i <= mp_y_code; i++) { free_number(mp->bbmin[i]); free_number(mp->bbmax[i]); } for (int k = 0; k <= 7; k++) { free_number(mp->half_cos[k]); free_number(mp->d_cos[k]); } free_number(mp->cur_x); free_number(mp->cur_y); for (int i=0; ibisect_stack[i]); } mp_memory_free(mp->bisect_stack); free_number(mp->cur_t); free_number(mp->cur_tt); free_number(mp->max_t); free_number(mp->delx); free_number(mp->dely); free_number(mp->appr_t); free_number(mp->appr_tt); mp_memory_free(mp->input_stack); mp_memory_free(mp->input_file); mp_memory_free(mp->line_stack); mp_memory_free(mp->param_stack); mp_memory_free(mp->cur_name); mp_memory_free(mp->job_name); for (int i = 0; i < mp_proto_dependent_type + 1; i++) { free_number(mp->max_c[i]); } for (int k = 0; k <= mp->max_internal; k++) { free_number(mp->internal[k].v.data.n); mp_memory_free(internal_name(k)); } mp_memory_free(mp->internal); mp_close_files(mp); if (mp->rd_fname != NULL) { mp_memory_free(mp->rd_file); mp_memory_free(mp->rd_fname); mp->rd_file = NULL; mp->rd_fname = NULL; } if (mp->wr_fname != NULL) { mp_memory_free(mp->wr_file); mp_memory_free(mp->wr_fname); mp->wr_file = NULL; mp->wr_fname = NULL; } mp_memory_free(mp->term_in); mp->term_in = NULL; mp_memory_free(mp->jump_buf); mp_free_symbolic_node(mp, mp->spec_head); mp_free_symbolic_node(mp, mp->temp_head); mp_free_symbolic_node(mp, mp->hold_head); mp_free_value_node(mp, mp->end_attr); mp_free_node(mp, (mp_node) mp->null_dash, sizeof(mp_dash_node_data)); mp_free_dep_node(mp, mp->dep_head); mp_free_symbolic_node(mp, mp->cur_mod_); mp_free_value_node(mp, mp->bad_vardef); free_number(mp->cur_exp.data.n); mp_free_value_node(mp, mp->temp_val); free_number(mp->txx); free_number(mp->txy); free_number(mp->tyx); free_number(mp->tyy); free_number(mp->tx); free_number(mp->ty); mp_free_value_node(mp, mp->inf_val); mp_free_value_node(mp, mp->zero_val); free_math(); mp_memory_free(mp); } static void mp_do_initialize (MP mp) { mp->int_ptr = max_given_internal; for (int k = '0'; k <= '9'; k++) { mp->char_class[k] = mp_digit_class; } for (int k = 'A'; k <= 'Z'; k++) { mp->char_class[k] = mp_letter_class; } for (int k = 'a'; k <= 'z'; k++) { mp->char_class[k] = mp_letter_class; } mp->char_class['.'] = mp_period_class; mp->char_class[' '] = mp_space_class; mp->char_class['%'] = mp_percent_class; mp->char_class['"'] = mp_string_class; mp->char_class[','] = mp_comma_class; mp->char_class[';'] = mp_semicolon_class; mp->char_class['('] = mp_left_parenthesis_class; mp->char_class[')'] = mp_right_parenthesis_class; mp->char_class['_'] = mp_letter_class; mp->char_class['<'] = 10; mp->char_class['='] = 10; mp->char_class['>'] = 10; mp->char_class[':'] = 10; mp->char_class['|'] = 10; mp->char_class['`'] = 11; mp->char_class['\''] = 11; mp->char_class['+'] = 12; mp->char_class['-'] = 12; mp->char_class['/'] = 13; mp->char_class['*'] = 13; mp->char_class['\\'] = 13; mp->char_class['^'] = 13; mp->char_class['!'] = 14; mp->char_class['?'] = 14; mp->char_class['#'] = mp_suffix_class; mp->char_class['&'] = mp_suffix_class; mp->char_class['@'] = mp_suffix_class; mp->char_class['$'] = mp_suffix_class; mp->char_class['^'] = 16; mp->char_class['~'] = 16; mp->char_class['['] = mp_left_bracket_class; mp->char_class[']'] = mp_right_bracket_class; mp->char_class['{'] = mp_brace_class; mp->char_class['}'] = mp_brace_class; for (int k = 0; k < ' '; k++) { mp->char_class[k] = mp_invalid_class; } mp->char_class['\r'] = mp_space_class; mp->char_class['\n'] = mp_space_class; mp->char_class['\t'] = mp_space_class; mp->char_class['\f'] = mp_space_class; for (int k = 127; k <= 255; k++) { mp->char_class[k] = mp->utf8_mode ? mp_letter_class : mp_invalid_class; } if (mp->text_mode) { mp->char_class[2] = mp_string_class; } mp->save_ptr = NULL; for (int k = 0; k <= 7; k++) { new_fraction(mp->half_cos[k]); new_fraction(mp->d_cos[k]); } number_clone(mp->half_cos[0], fraction_half_t); number_clone(mp->half_cos[1], twentysixbits_sqrt2_t); number_clone(mp->half_cos[2], zero_t); number_clone(mp->d_cos[0], twentyeightbits_d_t); number_clone(mp->d_cos[1], twentysevenbits_sqrt2_d_t); number_clone(mp->d_cos[2], zero_t); for (int k = 3; k <= 4; k++) { number_negated_clone(mp->half_cos[k], mp->half_cos[4 - k]); number_negated_clone(mp->d_cos[k], mp->d_cos[4 - k]); } for (int k = 5; k <= 7; k++) { number_clone(mp->half_cos[k], mp->half_cos[8 - k]); number_clone(mp->d_cos[k], mp->d_cos[8 - k]); } mp->spec_p1 = NULL; mp->spec_p2 = NULL; mp->fix_needed = 0; mp->watch_coefs = 1; mp->expand_depth = 10000; mp->cond_ptr = NULL; mp->if_limit = mp_no_if_code; mp->cur_if = 0; mp->if_line = 0; mp->loop_ptr = NULL; mp->cur_name = mp_strdup(""); memset(&mp->cur_exp.data, 0, sizeof(mp_value)); new_number(mp->cur_exp.data.n); mp->var_flag = 0; mp->eof_line = mp_rtsl (mp, "\0", 1); mp->eof_line->refs = MAX_STR_REF; mp->eof_file = mp_rtsl (mp, "%", 1); mp->eof_file->refs = MAX_STR_REF; mp->every_job_sym = NULL; mp->long_help_seen = 0; mp->ten_pow[0] = 1; for (int i = 1; i <= 9; i++) { mp->ten_pow[i] = 10 * mp->ten_pow[i - 1]; } } MP mp_initialize (MP_options * opt) { MP mp; jmp_buf *buf = mp_memory_allocate(sizeof(jmp_buf)); if (buf == NULL || setjmp(*buf) != 0) { return NULL; } mp = mp_do_new(buf); if (mp == NULL) { return NULL; } if (opt->job_name == NULL || ! *(opt->job_name)) { return NULL; } mp->job_name = mp_strdup(opt->job_name); mp->userdata = opt->userdata; mp->extensions = opt->extensions; mp->find_file = mp_find_file; mp->open_file = mp_open_file; mp->close_file = mp_close_file; mp->write_file = mp_write_file; mp->read_file = mp_read_file; mp->run_script = mp_run_script; mp->run_internal = mp_run_internal; mp->run_logger = mp_run_logger; mp->run_overload = mp_run_overload; mp->run_error = mp_run_error; mp->run_warning = mp_run_warning; mp->make_text = mp_make_text; mp->shipout_backend = mp_shipout_backend; mp->find_file_id = 0; mp->run_script_id = 0; mp->run_logger_id = 0; mp->run_error_id = 0; mp->run_warning_id = 0; mp->run_overload_id = 0; mp->make_text_id = 0; mp->open_file_id = 0; mp->find_file = opt->find_file ? opt->find_file : mp_find_file ; mp->open_file = opt->open_file ? opt->open_file : mp_open_file ; mp->read_file = opt->read_file ? opt->read_file : mp_read_file ; mp->close_file = opt->close_file ? opt->close_file : mp_close_file ; mp->write_file = opt->write_file ? opt->write_file : mp_write_file ; mp->shipout_backend = opt->shipout_backend ? opt->shipout_backend : mp_shipout_backend; mp->run_script = opt->run_script ? opt->run_script : mp_run_script ; mp->run_internal = opt->run_internal ? opt->run_internal : mp_run_internal ; mp->run_logger = opt->run_logger ? opt->run_logger : mp_run_logger ; mp->run_overload = opt->run_overload ? opt->run_overload : mp_run_overload ; mp->run_error = opt->run_error ? opt->run_error : mp_run_error ; mp->run_warning = opt->run_warning ? opt->run_warning : mp_run_warning ; mp->make_text = opt->make_text ? opt->make_text : mp_make_text ; mp->find_file_id = opt->find_file_id; mp->run_script_id = opt->run_script_id; mp->run_internal_id = opt->run_internal_id; mp->run_logger_id = opt->run_logger_id; mp->run_overload_id = opt->run_overload_id; mp->run_error_id = opt->run_error_id; mp->run_warning_id = opt->run_warning_id; mp->make_text_id = opt->make_text_id; mp->open_file_id = opt->open_file_id; if (opt->banner && *(opt->banner)) { mp->banner = mp_strdup(opt->banner); } else { mp->banner = mp_strdup(default_banner); } switch (opt->math_mode) { case mp_math_scaled_mode: mp->math = mp_initialize_scaled_math(mp); break; case mp_math_decimal_mode: mp->math = mp_initialize_decimal_math(mp); break; case mp_math_binary_mode: mp->math = mp_initialize_binary_math(mp); break; default: mp->math = mp_initialize_double_math(mp); break; } mp->param_size = 4; mp->max_in_open = 0; mp->halt_on_error = opt->halt_on_error ? 1 : 0; mp->utf8_mode = opt->utf8_mode ? 1 : 0; mp->text_mode = opt->text_mode ? 1 : 0; mp->show_mode = opt->show_mode ? 1 : 0; mp->buf_size = 200; mp->buffer = mp_memory_allocate((size_t) (mp->buf_size + 1) * sizeof(unsigned char)); mp_initialize_strings(mp); mp->interaction = opt->interaction; if (mp->interaction == mp_unspecified_mode || mp->interaction > mp_silent_mode) { mp->interaction = mp_error_stop_mode; } if (mp->interaction < mp_unspecified_mode) { mp->interaction = mp_batch_mode; } mp->use_err_help = 0; mp->finished = 0; mp->arith_error = 0; mp->random_seed = opt->random_seed; for (int i = 0; i < 55; i++) { new_fraction(mp->randoms[i]); } mp->math_mode = opt->math_mode; mp->token_nodes = NULL; mp->num_token_nodes = 0; mp->pair_nodes = NULL; mp->num_pair_nodes = 0; mp->knot_nodes = NULL; mp->max_knot_nodes = max_num_knot_nodes; mp->num_knot_nodes = 0; mp->value_nodes = NULL; mp->num_value_nodes = 0; mp->symbolic_nodes = NULL; mp->num_symbolic_nodes = 0; mp->max_internal = 1000 + max_given_internal; mp->internal = mp_memory_allocate((size_t) (mp->max_internal + 1) * sizeof(mp_internal)); memset(mp->internal, 0, (size_t) (mp->max_internal + 1) * sizeof(mp_internal)); for (int i = 1; i <= mp->max_internal; i++) { new_number(mp->internal[i].v.data.n); } for (int i = 1; i <= max_given_internal; i++) { set_internal_type(i, mp_known_type); } set_internal_type(mp_number_system_internal, mp_string_type); set_internal_type(mp_job_name_internal, mp_string_type); mp->symbols = avl_create(mp_compare_symbols_entry, mp_copy_symbols_entry, mp_delete_symbols_entry, mp_memory_allocate, mp_memory_free, NULL); mp->frozen_symbols = avl_create(mp_compare_symbols_entry, mp_copy_symbols_entry, mp_delete_symbols_entry, mp_memory_allocate, mp_memory_free, NULL); mp->bisect_stack = mp_memory_allocate((size_t) (bistack_size + 1) * sizeof(mp_number)); for (int i=0; ibisect_stack[i]); } mp->stack_size = 16; mp->input_stack = mp_memory_allocate((size_t) (mp->stack_size + 1) * sizeof(mp_in_state_record)); mp_reallocate_input_stack(mp, mp_file_bottom_text + 4); mp->param_stack = mp_memory_allocate((size_t) (mp->param_size + 1) * sizeof(mp_node)); mp->max_read_files = 8; mp->rd_file = mp_memory_allocate((size_t) (mp->max_read_files + 1) * sizeof(void *)); mp->rd_fname = mp_memory_allocate((size_t) (mp->max_read_files + 1) * sizeof(char *)); mp->max_write_files = 8; mp->wr_file = mp_memory_allocate((size_t) (mp->max_write_files + 1) * sizeof(void *)); mp->wr_fname = mp_memory_allocate((size_t) (mp->max_write_files + 1) * sizeof(char *)); memset(mp->rd_fname, 0, sizeof(char *) * (mp->max_read_files + 1)); memset(mp->wr_fname, 0, sizeof(char *) * (mp->max_write_files + 1)); mp_reallocate_paths(mp, 1000); mp->history = mp_fatal_error_stop; mp_do_initialize(mp); mp_init_tab(mp); switch (opt->math_mode) { case mp_math_scaled_mode: set_internal_string(mp_number_system_internal, mp_intern(mp, "scaled")); break; case mp_math_decimal_mode: set_internal_string(mp_number_system_internal, mp_intern(mp, "decimal")); break; case mp_math_binary_mode: set_internal_string(mp_number_system_internal, mp_intern(mp, "binary")); break; default: set_internal_string(mp_number_system_internal, mp_intern(mp, "double")); break; } mp_init_prim(mp); mp_fix_date_and_time(mp); mp->history = mp_spotless; set_precision(); if (mp->job_name != NULL) { if (internal_string(mp_job_name_internal) != 0) { delete_str_ref(internal_string(mp_job_name_internal)); } set_internal_string(mp_job_name_internal, mp_rts(mp, mp->job_name)); } return mp; } int mp_status (MP mp) { return mp->history; } int mp_finished (MP mp) { return mp->finished; } void *mp_userdata (MP mp) { return mp->userdata; } static char *mp_find_file (MP mp, const char *fname, const char *fmode, int ftype) { (void) mp; (void) fname; (void) fmode; (void) ftype; mp_fatal_error(mp, "no 'find_file' callback set"); return NULL; } static char *mp_run_script (MP mp, const char *str, size_t len, int n) { (void) mp; (void) str; (void) len; (void) n; mp_fatal_error(mp, "no 'run_script' callback set"); return NULL; } void mp_run_internal (MP mp, int action, int n, int type, const char *iname) { (void) mp; (void) action; (void) n; (void) type; (void) iname; mp_fatal_error(mp, "no 'run_internal' callback set"); } static void mp_run_logger (MP mp, int target, const char *s, size_t l) { (void) mp; (void) target; (void) s; (void) l; mp_fatal_error(mp, "no 'run_logger' callback set"); } static int mp_run_overload (MP mp, int property, const char *str, int mode) { (void) mp; (void) property; (void) str; (void) mode; mp_fatal_error(mp, "no 'run_overload' callback set"); return 0; } static void mp_check_overload (MP mp, mp_sym p) { if (number_nonzero(internal_value(mp_overloadmode_internal))) { if (mp->run_overload(mp, p->property, (const char *) p->text->str, number_to_int(internal_value(mp_overloadmode_internal)))) { p->property = 0; } else { } } else { p->property = 0; } } static void mp_run_error (MP mp, const char *msg, const char *hlp, int interaction) { (void) mp; (void) msg; (void) hlp; (void) interaction; mp_fatal_error(mp, "no 'run_error' callback set"); } static void mp_run_warning (MP mp, const char *msg) { (void) mp; (void) msg; mp_fatal_error(mp, "no 'run_warning' callback set"); } static char *mp_make_text (MP mp, const char *str, size_t len, int mode) { (void) mp; (void) mode; (void) str; (void) len; mp_fatal_error(mp, "no 'make_text' callback set"); return NULL; } static void *mp_open_file (MP mp, const char *fname, const char *fmode, int ftype) { (void) mp; (void) fname; (void) fmode; (void) ftype; mp_fatal_error(mp, "no 'open_file' callback set"); return NULL; } static int mp_do_open_file (MP mp, void **f, int ftype, const char *mode) { char *s = (mp->find_file)(mp, mp->name_of_file, mode, ftype); if (s != NULL) { mp_memory_free(mp->name_of_file); mp->name_of_file = mp_strdup(s); lmt_memory_free(s); *f = (mp->open_file)(mp, mp->name_of_file, mode, ftype); } else { *f = NULL; } return (*f ? 1 : 0); } static int mp_open_in (MP mp, void **f, int ftype) { return mp_do_open_file(mp, f, ftype, "r"); } static int mp_open_out (MP mp, void **f, int ftype) { return mp_do_open_file(mp, f, ftype, "w"); } static char *mp_read_file (MP mp, void *f, size_t *size) { (void) mp; (void) f; (void) size; mp_fatal_error(mp, "no 'read_file' callback set"); return NULL; } static void mp_write_file (MP mp, void *f, const char *s) { (void) mp; (void) f; (void) s; mp_fatal_error(mp, "no 'read_file' callback set"); } static void mp_close_file (MP mp, void *f) { (void) mp; (void) f; mp_fatal_error(mp, "no 'close_file' callback set"); } static void mp_reallocate_buffer (MP mp, size_t l) { if (l > max_halfword) { mp_confusion(mp, "buffer size"); } else { unsigned char *buffer = mp_memory_allocate((size_t) (l + 1) * sizeof(unsigned char)); memcpy(buffer, mp->buffer, (mp->buf_size + 1)); mp_memory_free(mp->buffer); mp->buffer = buffer; mp->buf_size = l; } } static int mp_input_ln (MP mp, void *f) { char *s; size_t size = 0; mp->last = mp->first; s = (mp->read_file)(mp, f, &size); if (s == NULL) { return 0; } else if (size > 0) { mp->last = mp->first + size; if (mp->last >= mp->max_buf_stack) { mp->max_buf_stack = mp->last + 1; while (mp->max_buf_stack > mp->buf_size) { mp_reallocate_buffer(mp, (mp->buf_size + (mp->buf_size >> 2))); } } memcpy((mp->buffer + mp->first), s, size); } lmt_memory_free(s); return 1; } static void mp_print_ln (MP mp) { switch (mp->selector) { case mp_term_and_log_selector: mp_log_cr(mp_both_logging_target); mp->term_offset = 0; mp->file_offset = 0; break; case mp_log_only_selector: mp_log_cr(mp_file_logging_target); mp->file_offset = 0; break; case mp_term_only_selector: mp_log_cr(mp_term_logging_target); mp->term_offset = 0; break; case mp_no_print_selector: case mp_new_string_selector: break; default: mp_fputs("\n", mp->wr_file[mp->selector - mp_first_file_selector]); } } static void mp_print_chr (MP mp, unsigned char s) { switch (mp->selector) { case mp_term_and_log_selector: mp_log_chr(mp_both_logging_target, s); mp->term_offset = 1; mp->file_offset = 1; break; case mp_log_only_selector: mp_log_chr(mp_file_logging_target, s); mp->file_offset = 1; break; case mp_term_only_selector: mp_log_chr(mp_term_logging_target, s); mp->term_offset = 1; break; case mp_no_print_selector: break; case mp_new_string_selector: mp_str_room(mp, 1); mp_append_char(mp, s); break; default: { unsigned char ss[2] = { s, 0 }; mp_fputs((char *) ss, mp->wr_file[mp->selector - mp_first_file_selector]); } } } void mp_print_e_chr (MP mp, unsigned char s) { mp_print_chr(mp, s); } static void mp_do_print (MP mp, const char *s, size_t len) { if (len == 0) { return; } else if (mp->selector == mp_new_string_selector) { mp_str_room(mp, (int) len); memcpy((mp->cur_string + mp->cur_length), s, len); mp->cur_length += len; } else { switch (mp->selector) { case mp_term_and_log_selector: mp_log_mpstr(mp_both_logging_target, s, (int) len); mp->term_offset = 1; mp->file_offset = 1; break; case mp_log_only_selector: mp_log_mpstr(mp_file_logging_target, s, (int) len); mp->file_offset = 1; break; case mp_term_only_selector: mp_log_mpstr(mp_term_logging_target, s, (int) len); mp->term_offset = 1; break; case mp_no_print_selector: break; case mp_new_string_selector: mp_str_room(mp, (int) len); mp_append_str(mp, s); break; default: mp_fputs(s, mp->wr_file[mp->selector - mp_first_file_selector]); break; } } } static void mp_print_str (MP mp, const char *s) { mp_do_print(mp, s, strlen(s)); } void mp_print_e_str (MP mp, const char *s) { mp_print_str(mp,s); } static void mp_print_fmt (MP mp, const char *s, ...) { va_list ap; char pval[256]; va_start(ap, s); vsnprintf(pval, 256, s, ap); mp_do_print(mp, pval, strlen(pval)); va_end(ap); } static void mp_print_mp_str (MP mp, mp_string s) { mp_do_print(mp, (const char *) s->str, s->len); } static void mp_print_nl_only (MP mp) { switch (mp->selector) { case mp_term_and_log_selector: if (mp->file_offset > 0) { mp_log_cr(mp_file_logging_target); mp->file_offset = 0; } if (mp->term_offset > 0) { mp_log_cr(mp_term_logging_target); mp->term_offset = 0; } break; case mp_log_only_selector: if (mp->file_offset > 0) { mp_log_cr(mp_file_logging_target); mp->file_offset = 0; } break; case mp_term_only_selector: if (mp->term_offset > 0) { mp_log_cr(mp_term_logging_target); mp->term_offset = 0; } break; case mp_no_print_selector: case mp_new_string_selector: break; } } static void mp_print_nl (MP mp, const char *s) { mp_print_nl_only(mp); mp_print_str(mp, s); } static void mp_print_int (MP mp, int n) { char s[12]; mp_snprintf(s, 12, "%d", (int) n); mp_print_str(mp, s); } void mp_error (MP mp, const char *msg, const char *hlp) { int selector = mp->selector; mp_normalize_selector(mp); mp->run_error(mp, msg, hlp, mp->interaction); if (mp->history < mp_error_message_issued) { mp->history = mp_error_message_issued; } if (mp->halt_on_error) { mp->history = mp_fatal_error_stop; mp_jump_out(mp); } ++mp->error_count; if (mp->error_count == 100) { mp_print_nl(mp, "(That makes 100 errors; please try again.)"); mp->history = mp_fatal_error_stop; mp_jump_out(mp); } mp->selector = selector; } void mp_normalize_selector (MP mp) { mp->selector = mp->interaction == mp_batch_mode ? mp_log_only_selector : mp_term_and_log_selector; } static void mp_clear_arith (MP mp) { mp_error( mp, "Arithmetic overflow", "Uh, oh. A little while ago one of the quantities that I was computing got too\n" "large, so I'm afraid your answers will be somewhat askew. You'll probably have to\n" "adopt different tactics next time. But I shall try to carry on anyway." ); mp->arith_error = 0; } static void mp_print_two (MP mp, mp_number *x, mp_number *y) { mp_print_chr(mp, '('); print_number(*x); mp_print_chr(mp, ','); print_number(*y); mp_print_chr(mp, ')'); } void mp_new_randoms (MP mp) { mp_number x; new_number(x); for (int k = 0; k <= 23; k++) { set_number_from_subtraction(x, mp->randoms[k], mp->randoms[k + 31]); if (number_negative(x)) { number_add(x, fraction_one_t); } number_clone(mp->randoms[k], x); } for (int k = 24; k <= 54; k++) { set_number_from_subtraction(x, mp->randoms[k], mp->randoms[k - 24]); if (number_negative(x)) { number_add(x, fraction_one_t); } number_clone(mp->randoms[k], x); } free_number(x); mp->j_random = 54; } void *mp_allocate_node (MP mp, size_t size) { void *p = mp_memory_allocate(size); ((mp_node) p)->link = NULL; ((mp_node) p)->hasnumber = 0; mp->var_used += size; if (mp->var_used > mp->var_used_max) { mp->var_used_max = mp->var_used; } return p; } void *mp_allocate_dash (MP mp) { void *p = mp_memory_allocate(sizeof(mp_dash_object)); mp->var_used += sizeof(mp_dash_object); if (mp->var_used > mp->var_used_max) { mp->var_used_max = mp->var_used; } return p; } void *mp_memory_allocate (size_t size) { void *w = lmt_memory_malloc(size); if (! w) { printf("mplib ran out of memory, case 1"); exit(EXIT_FAILURE); } return w; } void *mp_memory_clear_allocate (size_t size) { void *w = lmt_memory_calloc(1, size); if (! w) { printf("mplib ran out of memory, case 2"); exit(EXIT_FAILURE); } return w; } void *mp_memory_reallocate (void *p, size_t size) { void *w = lmt_memory_realloc(p, size); if (! w) { printf("mplib ran out of memory, case 3"); exit(EXIT_FAILURE); } return w; } void mp_memory_free (void *p) { lmt_memory_free(p); } # define mp_get_sym_info(A) mp_get_indep_value(A) # define mp_set_sym_info(A,B) mp_set_indep_value(A, (B)) # define mp_get_sym_sym(A) (A)->data.sym # define mp_set_sym_sym(A,B) (A)->data.sym = (mp_sym)(B) static mp_node mp_new_symbolic_node (MP mp) { mp_symbolic_node p; if (mp->symbolic_nodes) { p = (mp_symbolic_node) mp->symbolic_nodes; mp->symbolic_nodes = p->link; mp->num_symbolic_nodes--; p->link = NULL; } else { p = mp_allocate_node(mp, sizeof(mp_node_data)); new_number(p->data.n); p->hasnumber = 1; } p->type = mp_symbol_node_type; p->name_type = mp_normal_operation; return (mp_node) p; } static void mp_free_node (MP mp, mp_node p, size_t siz) { if (p) { mp->var_used -= siz; if (mp->math_mode > mp_math_double_mode) { if (p->hasnumber >= 1 && is_number(((mp_symbolic_node) p)->data.n)) { free_number(((mp_symbolic_node) p)->data.n); } if (p->hasnumber == 2 && is_number(((mp_value_node) p)->subscript)) { free_number(((mp_value_node) p)->subscript); } if (p->type == mp_dash_node_type) { free_number(((mp_dash_node) p)->start_x); free_number(((mp_dash_node) p)->stop_x); free_number(((mp_dash_node) p)->dash_y); } } mp_memory_free(p); } } static void mp_free_symbolic_node (MP mp, mp_node p) { if (p) { if (mp->num_symbolic_nodes < max_num_symbolic_nodes) { p->link = mp->symbolic_nodes; mp->symbolic_nodes = p; mp->num_symbolic_nodes++; } else { mp->var_used -= sizeof(mp_node_data); mp_memory_free(p); } } } static void mp_free_value_node (MP mp, mp_node p) { if (p) { if (mp->num_value_nodes < max_num_value_nodes) { p->link = mp->value_nodes; mp->value_nodes = p; mp->num_value_nodes++; } else { mp->var_used -= sizeof(mp_value_node_data); if (mp->math_mode > mp_math_double_mode) { free_number(((mp_value_node) p)->data.n); free_number(((mp_value_node) p)->subscript); } mp_memory_free(p); } } } static void mp_flush_node_list (MP mp, mp_node p) { while (p != NULL) { mp_node q = p; p = p->link; if (q->type != mp_symbol_node_type) { mp_free_token_node(mp, q); } else { mp_free_symbolic_node(mp, q); } } } static const char *mp_type_string(int t) { const char *s = NULL; switch (t) { case mp_undefined_type: s = "undefined"; break; case mp_vacuous_type: s = "vacuous"; break; case mp_boolean_type: s = "boolean"; break; case mp_unknown_boolean_type: s = "unknown boolean"; break; case mp_string_type: s = "string"; break; case mp_unknown_string_type: s = "unknown string"; break; case mp_pen_type: s = "pen"; break; case mp_unknown_pen_type: s = "unknown pen"; break; case mp_nep_type: s = "pen"; break; case mp_unknown_nep_type: s = "unknown pen"; break; case mp_path_type: s = "path"; break; case mp_unknown_path_type: s = "unknown path"; break; case mp_picture_type: s = "picture"; break; case mp_unknown_picture_type: s = "unknown picture"; break; case mp_transform_type: s = "transform"; break; case mp_color_type: s = "color"; break; case mp_cmykcolor_type: s = "cmykcolor"; break; case mp_pair_type: s = "pair"; break; case mp_known_type: s = "known numeric"; break; case mp_dependent_type: s = "dependent"; break; case mp_proto_dependent_type: s = "proto-dependent"; break; case mp_numeric_type: s = "numeric"; break; case mp_independent_type: s = "independent"; break; case mp_token_list_type: s = "token list"; break; case mp_structured_type: s = "mp_structured"; break; case mp_unsuffixed_macro_type: s = "unsuffixed macro"; break; case mp_suffixed_macro_type: s = "suffixed macro"; break; case mp_symbol_node_type: s = "symbol node"; break; case mp_token_node_type: s = "token node"; break; case mp_value_node_type: s = "value node"; break; case mp_attribute_node_type: s = "attribute node"; break; case mp_subscript_node_type: s = "subscript node"; break; case mp_pair_node_type: s = "pair node"; break; case mp_transform_node_type: s = "transform node"; break; case mp_color_node_type: s = "color node"; break; case mp_cmykcolor_node_type: s = "cmykcolor node"; break; case mp_fill_node_type: s = "fill node"; break; case mp_stroked_node_type: s = "stroked node"; break; case mp_start_clip_node_type: s = "start clip node"; break; case mp_start_group_node_type: s = "start group node"; break; case mp_start_bounds_node_type: s = "start bounds node"; break; case mp_stop_clip_node_type: s = "stop clip node"; break; case mp_stop_group_node_type: s = "stop group node"; break; case mp_stop_bounds_node_type: s = "stop bounds node"; break; case mp_dash_node_type: s = "dash node"; break; case mp_dep_node_type: s = "dependency node"; break; case mp_if_node_type: s = "if node"; break; case mp_edge_header_node_type: s = "edge header node"; break; default: { char ss[256]; mp_snprintf(ss, 256, "", t); s = mp_strdup(ss); } break; } return s; } void mp_print_type (MP mp, int t) { if (t >= 0 && t <= mp_edge_header_node_type) { mp_print_str(mp, mp_type_string(t)); } else { mp_print_str(mp, "unknown"); } } static const char *mp_op_string (int c) { if (c <= mp_numeric_type) { return mp_type_string(c); } else { switch (c) { case mp_true_operation : return "true"; case mp_false_operation : return "false"; case mp_null_picture_operation : return "nullpicture"; case mp_null_pen_operation : return "nullpen"; case mp_read_string_operation : return "readstring"; case mp_pen_circle_operation : return "pencircle"; case mp_normal_deviate_operation : return "normaldeviate"; case mp_read_from_operation : return "readfrom"; case mp_close_from_operation : return "closefrom"; case mp_odd_operation : return "odd"; case mp_known_operation : return "known"; case mp_unknown_operation : return "unknown"; case mp_not_operation : return "not"; case mp_decimal_operation : return "decimal"; case mp_reverse_operation : return "reverse"; case mp_uncycle_operation : return "uncycle"; case mp_make_path_operation : return "makepath"; case mp_make_pen_operation : return "makepen"; case mp_make_nep_operation : return "makenep"; case mp_convexed_operation : return "convexed"; case mp_uncontrolled_operation : return "uncontrolled"; case mp_oct_operation : return "oct"; case mp_hex_operation : return "hex"; case mp_ASCII_operation : return "ASCII"; case mp_char_operation : return "char"; case mp_length_operation : return "length"; case mp_turning_operation : return "turningnumber"; case mp_x_part_operation : return "xpart"; case mp_y_part_operation : return "ypart"; case mp_xx_part_operation : return "xxpart"; case mp_xy_part_operation : return "xypart"; case mp_yx_part_operation : return "yxpart"; case mp_yy_part_operation : return "yypart"; case mp_red_part_operation : return "redpart"; case mp_green_part_operation : return "greenpart"; case mp_blue_part_operation : return "bluepart"; case mp_cyan_part_operation : return "cyanpart"; case mp_magenta_part_operation : return "magentapart"; case mp_yellow_part_operation : return "yellowpart"; case mp_black_part_operation : return "blackpart"; case mp_grey_part_operation : return "greypart"; case mp_color_model_operation : return "colormodel"; case mp_prescript_part_operation : return "prescriptpart"; case mp_postscript_part_operation : return "postscriptpart"; case mp_stacking_part_operation : return "stackingpart"; case mp_path_part_operation : return "pathpart"; case mp_pen_part_operation : return "penpart"; case mp_dash_part_operation : return "dashpart"; case mp_sqrt_operation : return "sqrt"; case mp_m_exp_operation : return "mexp"; case mp_m_log_operation : return "mlog"; case mp_sin_d_operation : return "sind"; case mp_cos_d_operation : return "cosd"; case mp_floor_operation : return "floor"; case mp_uniform_deviate_operation : return "uniformdeviate"; case mp_ll_corner_operation : return "llcorner"; case mp_lr_corner_operation : return "lrcorner"; case mp_ul_corner_operation : return "ulcorner"; case mp_ur_corner_operation : return "urcorner"; case mp_center_of_operation : return "centerof"; case mp_center_of_mass_operation : return "centerofmass"; case mp_corners_operation : return "corners"; case mp_x_range_operation : return "xrange"; case mp_y_range_operation : return "yrange"; case mp_delta_point_operation : return "deltapoint"; case mp_delta_precontrol_operation : return "deltaprecontrol"; case mp_delta_postcontrol_operation: return "deltapostcontrol"; case mp_delta_direction_operation : return "deltadirection"; case mp_arc_length_operation : return "arclength"; case mp_angle_operation : return "angle"; case mp_cycle_operation : return "cycle"; case mp_no_cycle_operation : return "nocycle"; case mp_filled_operation : return "filled"; case mp_stroked_operation : return "stroked"; case mp_clipped_operation : return "clipped"; case mp_grouped_operation : return "grouped"; case mp_bounded_operation : return "bounded"; case mp_plus_operation : return "+"; case mp_minus_operation : return "-"; case mp_times_operation : return "*"; case mp_over_operation : return "/"; case mp_power_operation : return "^"; case mp_pythag_add_operation : return "++"; case mp_pythag_sub_operation : return "+-+"; case mp_or_operation : return "or"; case mp_and_operation : return "and"; case mp_less_than_operation : return "<"; case mp_less_or_equal_operation : return "<="; case mp_greater_than_operation : return ">"; case mp_greater_or_equal_operation : return ">="; case mp_equal_operation : return "="; case mp_unequal_operation : return "<>"; case mp_concatenate_operation : return "&"; case mp_just_append_operation : return "&&"; case mp_tolerant_concat_operation : return "&&&"; case mp_tolerant_append_operation : return "&&&&"; case mp_rotated_operation : return "rotated"; case mp_slanted_operation : return "slanted"; case mp_scaled_operation : return "scaled"; case mp_shifted_operation : return "shifted"; case mp_transformed_operation : return "transformed"; case mp_x_scaled_operation : return "xscaled"; case mp_y_scaled_operation : return "yscaled"; case mp_z_scaled_operation : return "zscaled"; case mp_intertimes_operation : return "intersectiontimes"; case mp_intertimes_list_operation : return "intersectiontimeslist"; case mp_substring_operation : return "substring"; case mp_subpath_operation : return "subpath"; case mp_direction_time_operation : return "directiontime"; case mp_point_operation : return "point"; case mp_precontrol_operation : return "precontrol"; case mp_postcontrol_operation : return "postcontrol"; case mp_direction_operation : return "direction"; case mp_path_point_operation : return "pathpoint"; case mp_path_precontrol_operation : return "pathprecontrol"; case mp_path_postcontrol_operation : return "pathpostcontrol"; case mp_path_direction_operation : return "pathdirection"; case mp_pen_offset_operation : return "penoffset"; case mp_arc_time_operation : return "arctime"; case mp_arc_point_operation : return "arcpoint"; case mp_arc_point_list_operation : return "arcpointlist"; case mp_subarc_length_operation : return "subarclength"; case mp_version_operation : return "mpversion"; case mp_envelope_operation : return "envelope"; case mp_boundingpath_operation : return "boundingpath"; case mp_pen_type_operation : return "pen"; case mp_nep_type_operation : return "nep"; case mp_path_type_operation : return "path"; case mp_picture_type_operation : return "picture"; case mp_transform_type_operation : return "transform"; case mp_color_type_operation : return "color"; case mp_cmykcolor_type_operation : return "cmykcolor"; case mp_pair_type_operation : return "pair"; case mp_numeric_type_operation : return "numeric"; default : return ".."; } } } static void mp_print_op (MP mp, int c) { mp_print_str(mp, mp_op_string(c)); } static void mp_fix_date_and_time (MP mp) { time_t aclock = time ((time_t *) 0); struct tm *tmptr = localtime (&aclock); number_clone(internal_value(mp_time_internal), unity_t); number_multiply_int(internal_value(mp_time_internal), (tmptr->tm_hour * 60 + tmptr->tm_min)); number_clone(internal_value(mp_hour_internal), unity_t); number_multiply_int(internal_value(mp_hour_internal), (tmptr->tm_hour)); number_clone(internal_value(mp_minute_internal), unity_t); number_multiply_int(internal_value(mp_minute_internal), (tmptr->tm_min)); number_clone(internal_value(mp_day_internal), unity_t); number_multiply_int(internal_value(mp_day_internal), (tmptr->tm_mday)); number_clone(internal_value(mp_month_internal), unity_t); number_multiply_int(internal_value(mp_month_internal), (tmptr->tm_mon + 1)); number_clone(internal_value(mp_year_internal), unity_t); number_multiply_int(internal_value(mp_year_internal), (tmptr->tm_year + 1900)); } static void mp_begin_diagnostic (MP mp) { mp->old_selector = mp->selector; if (number_nonpositive(internal_value(mp_tracing_online_internal)) && (mp->selector == mp_term_and_log_selector)) { mp->selector = mp_log_only_selector; if (mp->history == mp_spotless) { mp->history = mp_warning_issued; } } } void mp_end_diagnostic (MP mp, int blank_line) { mp_print_nl(mp, ""); if (blank_line) { mp_print_ln(mp); } mp->selector = mp->old_selector; } static void mp_print_diagnostic (MP mp, const char *s, const char *t, int nuline) { mp_begin_diagnostic(mp); if (nuline) { mp_print_nl(mp, s); } else { mp_print_str(mp, s); } mp_print_str(mp, " at line "); mp_print_int(mp, mp_true_line(mp)); mp_print_str(mp, t); mp_print_chr(mp, ':'); } # define text(A) (A)->text # define eq_type(A) (A)->type # define eq_property(A) (A)->property # define equiv(A) (A)->v.data.indep.serial # define equiv_node(A) (A)->v.data.node # define equiv_sym(A) (mp_sym)(A)->v.data.node static int mp_compare_symbols_entry (void *p, const void *pa, const void *pb) { const mp_symbol_entry *a = (const mp_symbol_entry *) pa; const mp_symbol_entry *b = (const mp_symbol_entry *) pb; (void) p; if (a->text->len != b->text->len) { return (a->text->len > b->text->len ? 1 : -1); } return strncmp ((const char *) a->text->str, (const char *) b->text->str, a->text->len); } static void *mp_copy_symbols_entry (const void *p) { mp_symbol_entry *fp = (mp_symbol_entry *) p; MP mp = (MP)fp->parent; mp_sym ff = mp_memory_allocate(sizeof(mp_symbol_entry)); if (ff == NULL) { return NULL; } ff->text = mp_aux_copy_strings_entry(fp->text); if (ff->text == NULL) { return NULL; } ff->v = fp->v; ff->type = fp->type; ff->property = fp->property; ff->parent = mp; new_number_clone(ff->v.data.n, fp->v.data.n); return ff; } static void *mp_delete_symbols_entry (void *p) { mp_sym ff = (mp_sym) p; MP mp = (MP) ff->parent; free_number(ff->v.data.n); mp_memory_free(ff->text->str); mp_memory_free(ff->text); mp_memory_free(ff); return NULL; } static mp_sym new_symbols_entry (MP mp, unsigned char *nam, size_t len) { mp_sym ff = mp_memory_clear_allocate(sizeof(mp_symbol_entry)); ff->parent = mp; ff->text = mp_memory_allocate(sizeof(mp_lstring)); ff->text->str = nam; ff->text->len = len; ff->type = mp_tag_command; ff->v.type = mp_known_type; new_number(ff->v.data.n); return ff; } static mp_sym mp_do_id_lookup (MP mp, avl_tree symbols, char *j, size_t l, int insert_new) { mp_sym str; mp->id_lookup_test->text->str = (unsigned char *) j; mp->id_lookup_test->text->len = l; str = (mp_sym) avl_find(mp->id_lookup_test, symbols); if (str == NULL && insert_new) { unsigned char *nam = (unsigned char *) mp_strndup(j, l); mp_sym s = new_symbols_entry(mp, nam, l); mp->st_count++; avl_ins(s, symbols, avl_false); str = (mp_sym) avl_find(s, symbols); mp_delete_symbols_entry(s); } return str; } int mp_initialize_symbol_traverse (MP mp) { mp->symbol_iterator = avl_iterator_new(mp->symbols, AVL_ITERATOR_INI_PRE); return (mp->symbol_iterator != NULL); } void mp_kill_symbol_traverse (MP mp) { avl_iterator_kill(mp->symbol_iterator); } void *mp_fetch_symbol_traverse (MP mp) { return avl_iterator_next(mp->symbol_iterator); } void *mp_fetch_symbol (MP mp, char *s) { return mp_id_lookup(mp, s, strlen(s), 0); } static void mp_primitive (MP mp, const char *ss, int c, int o) { set_cur_sym(mp_id_lookup(mp, (char *) ss, strlen(ss), 1)); set_eq_type(cur_sym, c); set_eq_property(cur_sym, 0x1); set_equiv(cur_sym, o); } static mp_sym mp_frozen_primitive (MP mp, const char *ss, int c, int o) { mp_sym str = mp_do_id_lookup(mp, mp->frozen_symbols, (char *) ss, strlen(ss), 1); str->type = c; str->property = 0x1; str->v.data.indep.serial = o; return str; } static int mp_is_frozen (MP mp, mp_sym sym) { mp_sym temp = mp_do_id_lookup(mp, mp->frozen_symbols, (char *) sym->text->str, sym->text->len, 0); if (temp == mp->frozen_inaccessible) { return 0; } else { return (temp == sym); } } # define mp_get_value_sym(A) ((mp_token_node) (A))->data.sym # define mp_get_value_number(A) ((mp_token_node) (A))->data.n # define mp_get_value_node(A) ((mp_token_node) (A))->data.node # define mp_get_value_str(A) ((mp_token_node) (A))->data.str # define mp_get_value_knot(A) ((mp_token_node) (A))->data.p inline static void do_set_value_sym (MP mp, mp_token_node A, mp_sym B) { (void) mp; A->data.sym=(B); } inline static void do_set_value_number (MP mp, mp_token_node A, mp_number *B) { (void) mp; A->data.p = NULL; A->data.str = NULL; A->data.node = NULL; number_clone(A->data.n, *B); } inline static void do_set_value_str (MP mp, mp_token_node A, mp_string B) { (void) mp; A->data.p = NULL; A->data.str = (B); add_str_ref((B)); A->data.node = NULL; number_clone(A->data.n, zero_t); } inline static void do_set_value_node (MP mp, mp_token_node A, mp_node B) { (void) mp; A->data.p = NULL; A->data.str = NULL; A->data.node = B; number_clone(A->data.n, zero_t); } inline static void do_set_value_knot (MP mp, mp_token_node A, mp_knot B) { (void) mp; A->data.p = (B); A->data.str = NULL; A->data.node = NULL; number_clone(A->data.n, zero_t); } static mp_node mp_new_token_node (MP mp) { mp_node p; if (mp->token_nodes) { p = mp->token_nodes; mp->token_nodes = p->link; mp->num_token_nodes--; p->link = NULL; } else { p = mp_allocate_node(mp, sizeof(mp_node_data)); new_number(p->data.n); p->hasnumber = 1; } p->type = mp_token_node_type; return (mp_node) p; } static void mp_free_token_node (MP mp, mp_node p) { if (p) { if (mp->num_token_nodes < max_num_token_nodes) { p->link = mp->token_nodes; mp->token_nodes = p; mp->num_token_nodes++; } else { mp->var_used -= sizeof(mp_node_data); if (mp->math_mode > mp_math_double_mode) { free_number(((mp_value_node) p)->data.n); } mp_memory_free(p); } } } static mp_node mp_new_num_tok (MP mp, mp_number *v) { mp_node p = mp_new_token_node(mp); mp_set_value_number(p, *v); p->type = mp_known_type; p->name_type = mp_token_operation; return p; } static void mp_flush_token_list (MP mp, mp_node p) { while (p != NULL) { mp_node q = p; p = p->link; switch (q->type) { case mp_symbol_node_type: mp_free_symbolic_node(mp, q); continue; case mp_vacuous_type: case mp_boolean_type: case mp_known_type: break; case mp_string_type: delete_str_ref(mp_get_value_str(q)); break; case mp_unknown_boolean_type: case mp_unknown_string_type: case mp_unknown_pen_type: case mp_unknown_nep_type: case mp_unknown_path_type: case mp_unknown_picture_type: case mp_pen_type: case mp_nep_type: case mp_path_type: case mp_picture_type: case mp_pair_type: case mp_color_type: case mp_cmykcolor_type: case mp_transform_type: case mp_dependent_type: case mp_proto_dependent_type: case mp_independent_type: mp_recycle_value(mp, q); break; default: mp_confusion(mp, "token"); } mp_free_token_node(mp, q); } } void mp_show_token_list (MP mp, mp_node p, mp_node q) { int cclass = mp_percent_class; (void) q; while (p != NULL) { int c = mp_letter_class; if (p->type != mp_symbol_node_type) { if (p->name_type == mp_token_operation) { if (p->type == mp_known_type) { if (cclass == mp_digit_class) { mp_print_chr(mp, ' '); } if (number_negative(mp_get_value_number(p))) { if (cclass == mp_left_bracket_class) { mp_print_chr(mp, ' '); } mp_print_chr(mp, '['); print_number(mp_get_value_number(p)); mp_print_chr(mp, ']'); c = mp_right_bracket_class; } else { print_number(mp_get_value_number(p)); c = mp_digit_class; } } else if (p->type == mp_string_type) { mp_print_chr(mp, '"'); mp_print_mp_str(mp, mp_get_value_str(p)); mp_print_chr(mp, '"'); c = mp_string_class; } else { mp_print_str(mp, " BAD"); } } else if ((p->name_type != mp_capsule_operation) || (p->type < mp_vacuous_type) || (p->type > mp_independent_type)) { mp_print_str(mp, " BAD"); } else { mp_print_capsule(mp, p); c = mp_right_parenthesis_class; } } else if (p->name_type == mp_expr_operation || p->name_type == mp_suffix_operation || p->name_type == mp_text_operation) { int r = mp_get_sym_info(p); if (p->name_type == mp_expr_operation) { mp_print_str(mp, "(EXPR"); } else if (p->name_type == mp_suffix_operation) { mp_print_str(mp, "(SUFFIX"); } else { mp_print_str(mp, "(TEXT"); } mp_print_int(mp, r); mp_print_chr(mp, ')'); c = mp_right_parenthesis_class; } else { mp_sym sr = mp_get_sym_sym(p); if (sr == mp_collective_subscript) { if (cclass == mp_left_bracket_class) { mp_print_chr(mp, ' '); } mp_print_str(mp, "[]"); c = mp_right_bracket_class; } else { mp_string rr = text(sr); if (rr == NULL || rr->str == NULL) { mp_print_str(mp, " NONEXISTENT"); } else { c = mp->char_class[(rr->str[0])]; if (c == cclass) { switch (c) { case mp_letter_class: mp_print_chr(mp, '.'); break; case mp_comma_class: case mp_semicolon_class: case mp_left_parenthesis_class: case mp_right_parenthesis_class: break; default: mp_print_chr(mp, ' '); break; } } mp_print_mp_str(mp, rr); } } } cclass = c; p = p->link; } return; } void mp_show_token_list_space (MP mp, mp_node p, mp_node q) { (void) q; while (p != NULL) { if (p->type != mp_symbol_node_type) { if (p->name_type == mp_token_operation) { if (p->type == mp_known_type) { if (number_negative(mp_get_value_number(p))) { mp_print_str(mp, "[ "); print_number(mp_get_value_number(p)); mp_print_str(mp, " ]"); } else { print_number(mp_get_value_number(p)); } } else if (p->type == mp_string_type) { mp_print_chr(mp, '"'); mp_print_mp_str(mp, mp_get_value_str(p)); mp_print_chr(mp, '"'); } else { mp_print_str(mp, "BAD"); } } else if ((p->name_type != mp_capsule_operation) || (p->type < mp_vacuous_type) || (p->type > mp_independent_type)) { mp_print_str(mp, "BAD"); } else { mp_print_capsule(mp, p); } } else if (p->name_type == mp_expr_operation || p->name_type == mp_suffix_operation || p->name_type == mp_text_operation) { int r = mp_get_sym_info(p); if (p->name_type == mp_expr_operation) { mp_print_str(mp, "(EXPR "); } else if (p->name_type == mp_suffix_operation) { mp_print_str(mp, "(SUFFIX "); } else { mp_print_str(mp, "(TEXT "); } mp_print_int(mp, r); mp_print_chr(mp, ')'); } else { mp_sym sr = mp_get_sym_sym(p); if (sr == mp_collective_subscript) { mp_print_str(mp, "[]"); } else { mp_string rr = text(sr); if (rr == NULL || rr->str == NULL) { mp_print_str(mp, "NONEXISTENT"); } else { mp_print_mp_str(mp, rr); } } } p = p->link; if (p) { mp_print_chr(mp, ' '); } } return; } static void mp_delete_mac_ref (MP mp, mp_node p) { if (mp_get_ref_count(p) == 0) { mp_flush_token_list(mp, p); } else { mp_decr_mac_ref(p); } } static void mp_show_macro (MP mp, mp_node p, mp_node q) { p = p->link; while (p->name_type != mp_macro_operation) { mp_node r = p->link; p->link = NULL; mp_show_token_list(mp, p, NULL); p->link = r; p = r; } switch (mp_get_sym_info(p)) { case mp_general_macro: mp_print_str(mp, "-> "); break; case mp_primary_macro: case mp_secondary_macro: case mp_tertiary_macro: mp_print_str(mp, "<"); mp_print_cmd_mod(mp, mp_parameter_commmand, mp_get_sym_info(p)); mp_print_str(mp, "> -> "); break; case mp_expr_macro: mp_print_str(mp, " -> "); break; case mp_of_macro: mp_print_str(mp, " of -> "); break; case mp_suffix_macro: mp_print_str(mp, " -> "); break; case mp_text_macro: mp_print_str(mp, " -> "); break; } mp_show_token_list(mp, p->link, q); } static mp_node mp_do_get_attribute_head (MP mp, mp_value_node A) { (void) mp; return A->attr_head; } static mp_node mp_do_get_subscr_head (MP mp, mp_value_node A) { return A->subscr_head; (void) mp; } static void mp_do_set_attribute_head (MP mp, mp_value_node A, mp_node d) { (void) mp; A->attr_head = d; } static void mp_do_set_subscr_head (MP mp, mp_value_node A, mp_node d) { (void) mp; A->subscr_head = d; } static mp_node mp_new_value_node (MP mp) { mp_value_node p; if (mp->value_nodes) { p = (mp_value_node) mp->value_nodes; mp->value_nodes = p->link; mp->num_value_nodes--; p->link = NULL; } else { p = mp_allocate_node(mp, sizeof(mp_value_node_data)); new_number(p->data.n); new_number(p->subscript); p->hasnumber = 2; } p->type = mp_value_node_type; return (mp_node) p; } # define mp_get_hashloc(A) ((mp_value_node)(A))->hashloc_ # define mp_set_hashloc(A,B) ((mp_value_node)(A))->hashloc_ = B # define mp_get_parent(A) ((mp_value_node)(A))->parent # define mp_set_parent(A,B) ((mp_value_node)(A))->parent = B static mp_value_node mp_get_attribute_node (MP mp) { mp_value_node p = (mp_value_node) mp_new_value_node(mp); p->type = mp_attribute_node_type; return p; } static mp_value_node mp_get_subscr_node (MP mp) { mp_value_node p = (mp_value_node) mp_new_value_node(mp); p->type = mp_subscript_node_type; return p; } static mp_node mp_get_pair_node (MP mp) { mp_node p; if (mp->pair_nodes) { p = mp->pair_nodes; mp->pair_nodes = p->link; mp->num_pair_nodes--; p->link = NULL; } else { p = mp_allocate_node(mp, sizeof(mp_pair_node_data)); } p->type = mp_pair_node_type; return (mp_node) p; } static void mp_free_pair_node (MP mp, mp_node p) { if (p) { if (mp->num_pair_nodes < max_num_pair_nodes) { p->link = mp->pair_nodes; mp->pair_nodes = p; mp->num_pair_nodes++; } else { mp->var_used -= sizeof(mp_pair_node_data); mp_memory_free(p); } } } static void mp_init_pair_node (MP mp, mp_node p) { mp_node q; p->type = mp_pair_type; q = mp_get_pair_node(mp); mp_y_part(q) = mp_new_value_node(mp); mp_new_indep(mp, mp_y_part(q)); mp_y_part(q)->name_type = mp_y_part_operation; mp_y_part(q)->link = p; mp_x_part(q) = mp_new_value_node(mp); mp_new_indep(mp, mp_x_part(q)); mp_x_part(q)->name_type = mp_x_part_operation; mp_x_part(q)->link = p; mp_set_value_node(p, q); } static mp_node mp_get_transform_node (MP mp) { mp_transform_node p = (mp_transform_node) mp_allocate_node(mp, sizeof(mp_transform_node_data)); p->type = mp_transform_node_type; return (mp_node) p; } static void mp_init_transform_node (MP mp, mp_node p) { mp_node q; p->type = mp_transform_type; q = mp_get_transform_node(mp); mp_yy_part(q) = mp_new_value_node(mp); mp_new_indep(mp, mp_yy_part(q)); mp_yy_part(q)->name_type = mp_yy_part_operation; mp_yy_part(q)->link = p; mp_yx_part(q) = mp_new_value_node(mp); mp_new_indep(mp, mp_yx_part(q)); mp_yx_part(q)->name_type = mp_yx_part_operation; mp_yx_part(q)->link = p; mp_xy_part(q) = mp_new_value_node(mp); mp_new_indep(mp, mp_xy_part(q)); mp_xy_part(q)->name_type = mp_xy_part_operation; mp_xy_part(q)->link = p; mp_xx_part(q) = mp_new_value_node(mp); mp_new_indep(mp, mp_xx_part(q)); mp_xx_part(q)->name_type = mp_xx_part_operation; mp_xx_part(q)->link = p; mp_ty_part(q) = mp_new_value_node(mp); mp_new_indep(mp, mp_ty_part(q)); mp_ty_part(q)->name_type = mp_y_part_operation; mp_ty_part(q)->link = p; mp_tx_part(q) = mp_new_value_node(mp); mp_new_indep(mp, mp_tx_part(q)); mp_tx_part(q)->name_type = mp_x_part_operation; mp_tx_part(q)->link = p; mp_set_value_node(p, q); } static void mp_init_color_node (MP mp, mp_node p, int type) { mp_node q = (mp_node) mp_allocate_node(mp, sizeof(mp_color_node_data)); p->type = type; switch (type) { case mp_color_type: q->type = mp_color_node_type; mp_red_part(q) = mp_new_value_node(mp); mp_new_indep(mp, mp_red_part(q)); mp_red_part(q)->name_type = mp_red_part_operation; mp_red_part(q)->link = p; mp_green_part(q) = mp_new_value_node(mp); mp_new_indep(mp, mp_green_part(q)); mp_green_part(q)->name_type = mp_green_part_operation; mp_green_part(q)->link = p; mp_blue_part(q) = mp_new_value_node(mp); mp_new_indep(mp, mp_blue_part(q)); mp_blue_part(q)->name_type = mp_blue_part_operation; mp_blue_part(q)->link = p; break; case mp_cmykcolor_type: q->type = mp_cmykcolor_node_type; mp_cyan_part(q) = mp_new_value_node(mp); mp_new_indep(mp, mp_cyan_part(q)); mp_cyan_part(q)->name_type = mp_cyan_part_operation; mp_cyan_part(q)->link = p; mp_magenta_part(q) = mp_new_value_node(mp); mp_new_indep(mp, mp_magenta_part(q)); mp_magenta_part(q)->name_type = mp_magenta_part_operation; mp_magenta_part(q)->link = p; mp_yellow_part(q) = mp_new_value_node(mp); mp_new_indep(mp, mp_yellow_part(q)); mp_yellow_part(q)->name_type = mp_yellow_part_operation; mp_yellow_part(q)->link = p; mp_black_part(q) = mp_new_value_node(mp); mp_new_indep(mp, mp_black_part(q)); mp_black_part(q)->name_type = mp_black_part_operation; mp_black_part(q)->link = p; break; } mp_set_value_node(p, q); } static mp_node mp_id_transform (MP mp) { mp_node q; mp_node p = mp_new_value_node(mp); p->name_type = mp_capsule_operation; mp_set_value_number(p, zero_t); mp_init_transform_node(mp, p); q = mp_get_value_node(p); mp_tx_part(q)->type = mp_known_type; mp_set_value_number(mp_tx_part(q), zero_t); mp_ty_part(q)->type = mp_known_type; mp_set_value_number(mp_ty_part(q), zero_t); mp_xy_part(q)->type = mp_known_type; mp_set_value_number(mp_xy_part(q), zero_t); mp_yx_part(q)->type = mp_known_type; mp_set_value_number(mp_yx_part(q), zero_t); mp_xx_part(q)->type = mp_known_type; mp_set_value_number(mp_xx_part(q), unity_t); mp_yy_part(q)->type = mp_known_type; mp_set_value_number(mp_yy_part(q), unity_t); return p; } static void mp_new_root (MP mp, mp_sym x) { mp_node p = mp_new_value_node(mp); p->type = mp_undefined_type; p->name_type = mp_root_operation; mp_set_value_sym(p, x); set_equiv_node(x, p); } void mp_print_variable_name (MP mp, mp_node p) { mp_node q = NULL; mp_node r = NULL; while (p->name_type >= mp_x_part_operation) { switch (p->name_type) { case mp_x_part_operation : mp_print_str(mp, "xpart "); break; case mp_y_part_operation : mp_print_str(mp, "ypart "); break; case mp_xx_part_operation : mp_print_str(mp, "xxpart "); break; case mp_xy_part_operation : mp_print_str(mp, "xypart "); break; case mp_yx_part_operation : mp_print_str(mp, "yxpart "); break; case mp_yy_part_operation : mp_print_str(mp, "yypart "); break; case mp_red_part_operation : mp_print_str(mp, "redpart "); break; case mp_green_part_operation : mp_print_str(mp, "greenpart "); break; case mp_blue_part_operation : mp_print_str(mp, "bluepart "); break; case mp_cyan_part_operation : mp_print_str(mp, "cyanpart "); break; case mp_magenta_part_operation: mp_print_str(mp, "magentapart "); break; case mp_yellow_part_operation : mp_print_str(mp, "yellowpart "); break; case mp_black_part_operation : mp_print_str(mp, "blackpart "); break; case mp_grey_part_operation : mp_print_str(mp, "greypart "); break; case mp_capsule_operation : mp_print_fmt(mp, "%%CAPSULE%p", p); return; default : break; } p = p->link; } while (p->name_type > mp_saved_root_operation) { if (p->name_type == mp_subscript_operation) { r = mp_new_num_tok(mp, &(mp_subscript(p))); do { p = p->link; } while (p->name_type != mp_attribute_operation); } else if (p->name_type == mp_structured_root_operation) { p = p->link; goto FOUND; } else if (p->name_type != mp_attribute_operation) { mp_confusion(mp, "variable"); } else { r = mp_new_symbolic_node(mp); mp_set_sym_sym(r, mp_get_hashloc(p)); } mp_set_link(r, q); q = r; FOUND: p = mp_get_parent((mp_value_node) p); } r = mp_new_symbolic_node(mp); mp_set_sym_sym(r, mp_get_value_sym(p)); r->link = q; if (p->name_type == mp_saved_root_operation) { mp_print_str(mp, "(SAVED)"); } mp_show_token_list(mp, r, NULL); mp_flush_token_list(mp, r); } static int mp_interesting (MP mp, mp_node p) { if (number_positive(internal_value(mp_tracing_capsules_internal))) { return 1; } else { mp_name_type_type t = p->name_type; if (t >= mp_x_part_operation && t != mp_capsule_operation) { mp_node tt = mp_get_value_node(p->link); switch (t) { case mp_x_part_operation: t = mp_x_part (tt)->name_type; break; case mp_y_part_operation: t = mp_y_part (tt)->name_type; break; case mp_xx_part_operation: t = mp_xx_part (tt)->name_type; break; case mp_xy_part_operation: t = mp_xy_part (tt)->name_type; break; case mp_yx_part_operation: t = mp_yx_part (tt)->name_type; break; case mp_yy_part_operation: t = mp_yy_part (tt)->name_type; break; case mp_red_part_operation: t = mp_red_part (tt)->name_type; break; case mp_green_part_operation: t = mp_green_part (tt)->name_type; break; case mp_blue_part_operation: t = mp_blue_part (tt)->name_type; break; case mp_cyan_part_operation: t = mp_cyan_part (tt)->name_type; break; case mp_magenta_part_operation: t = mp_magenta_part(tt)->name_type; break; case mp_yellow_part_operation: t = mp_yellow_part (tt)->name_type; break; case mp_black_part_operation: t = mp_black_part (tt)->name_type; break; case mp_grey_part_operation: t = mp_grey_part (tt)->name_type; break; default: break; } } return (t != mp_capsule_operation); } } static mp_node mp_new_structure (MP mp, mp_node p) { mp_node r = NULL; switch (p->name_type) { case mp_root_operation: { mp_sym q = mp_get_value_sym(p); r = mp_new_value_node(mp); set_equiv_node(q, r); } break; case mp_subscript_operation: { mp_node q_new; mp_node q = p; do { q = q->link; } while (q->name_type != mp_attribute_operation); q = mp_get_parent((mp_value_node) q); r = mp->temp_head; mp_set_link(r, mp_get_subscr_head(q)); do { q_new = r; r = r->link; } while (r != p); r = (mp_node) mp_get_subscr_node(mp); if (q_new == mp->temp_head) { mp_set_subscr_head(q, r); } else { mp_set_link(q_new, r); } number_clone(mp_subscript(r), mp_subscript(p)); } break; case mp_attribute_operation: { mp_value_node rr; mp_node q = mp_get_parent((mp_value_node) p); r = mp_get_attribute_head(q); do { q = r; r = r->link; } while (r != p); rr = mp_get_attribute_node(mp); r = (mp_node) rr; mp_set_link(q, rr); mp_set_hashloc(rr, mp_get_hashloc(p)); mp_set_parent(rr, mp_get_parent((mp_value_node) p)); if (mp_get_hashloc(p) == mp_collective_subscript) { q = mp->temp_head; mp_set_link(q, mp_get_subscr_head(mp_get_parent((mp_value_node) p))); while (q->link != p) { q = q->link; } if (q == mp->temp_head) { mp_set_subscr_head(mp_get_parent((mp_value_node) p), (mp_node) rr); } else { mp_set_link(q, rr); } } } break; default: mp_confusion(mp, "structure"); break; } if (r) { mp_value_node q; mp_set_link(r, p->link); mp_set_value_sym(r, mp_get_value_sym(p)); r->type = mp_structured_type; r->name_type = p->name_type; mp_set_attribute_head(r, p); p->name_type = mp_structured_root_operation; q = mp_get_attribute_node(mp); mp_set_link(p, q); mp_set_subscr_head(r, (mp_node) q); mp_set_parent(q, r); q->type = mp_undefined_type; q->name_type = mp_attribute_operation; mp_set_link(q, mp->end_attr); mp_set_hashloc(q, mp_collective_subscript); } return r; } static mp_node mp_find_variable (MP mp, mp_node t) { mp_sym p_sym = mp_get_sym_sym(t); if (eq_type(p_sym) != mp_tag_command) { return NULL; } else { mp_node p, q, r, s; mp_node pp, qq, rr, ss; t = t->link; if (equiv_node(p_sym) == NULL) { mp_new_root (mp, p_sym); } p = equiv_node(p_sym); pp = p; while (t != NULL) { if (pp->type != mp_structured_type) { if (pp->type > mp_structured_type) { return NULL; } else { ss = mp_new_structure(mp, pp); if (p == pp) { p = ss; } pp = ss; } } if (p->type != mp_structured_type) { p = mp_new_structure(mp, p); } if (t->type != mp_symbol_node_type) { mp_number nn, save_subscript; new_number_clone(nn, mp_get_value_number(t)); pp = mp_get_attribute_head(pp)->link; q = mp_get_attribute_head(p)->link; new_number_clone(save_subscript, mp_subscript(q)); set_number_to_inf(mp_subscript(q)); s = mp->temp_head; mp_set_link(s, mp_get_subscr_head(p)); do { r = s; s = s->link; } while (number_greater(nn, mp_subscript(s))); if (number_equal(nn, mp_subscript(s))) { p = s; } else { mp_value_node p1 = mp_get_subscr_node(mp); if (r == mp->temp_head) { mp_set_subscr_head(p, (mp_node) p1); } else { mp_set_link(r, p1); } mp_set_link(p1, s); number_clone(mp_subscript(p1), nn); p1->name_type = mp_subscript_operation; p1->type = mp_undefined_type; p = (mp_node) p1; } number_clone(mp_subscript(q), save_subscript); free_number(save_subscript); free_number(nn); } else { mp_sym nn1 = mp_get_sym_sym(t); ss = mp_get_attribute_head(pp); do { rr = ss; ss = ss->link; } while (nn1 > mp_get_hashloc(ss)); if (nn1 < mp_get_hashloc(ss)) { qq = (mp_node) mp_get_attribute_node(mp); mp_set_link(rr, qq); mp_set_link(qq, ss); mp_set_hashloc(qq, nn1); qq->name_type = mp_attribute_operation; qq->type = mp_undefined_type; mp_set_parent((mp_value_node) qq, pp); ss = qq; } if (p == pp) { p = ss; pp = ss; } else { pp = ss; s = mp_get_attribute_head(p); do { r = s; s = s->link; } while (nn1 > mp_get_hashloc(s)); if (nn1 == mp_get_hashloc(s)) { p = s; } else { q = (mp_node) mp_get_attribute_node(mp); mp_set_link(r, q); mp_set_link(q, s); mp_set_hashloc(q, nn1); q->name_type = mp_attribute_operation; q->type = mp_undefined_type; mp_set_parent((mp_value_node) q, p); p = q; } } } t = t->link; } if (pp->type >= mp_structured_type) { if (pp->type == mp_structured_type) { pp = mp_get_attribute_head(pp); } else { return NULL; } } if (p->type == mp_structured_type) { p = mp_get_attribute_head(p); } if (p->type == mp_undefined_type) { if (pp->type == mp_undefined_type) { pp->type = mp_numeric_type; mp_set_value_number(pp, zero_t); } p->type = pp->type; mp_set_value_number(p, zero_t); } return p; } } static void mp_flush_variable (MP mp, mp_node p, mp_node t, int discard_suffixes) { while (t != NULL) { if (p->type != mp_structured_type) { return; } else { mp_sym n = mp_get_sym_sym(t); t = t->link; if (n == mp_collective_subscript) { mp_node q = mp_get_subscr_head(p); mp_node r = NULL; while (q->name_type == mp_subscript_operation) { mp_flush_variable(mp, q, t, discard_suffixes); if (t != NULL) { r = q; } else if (q->type == mp_structured_type) { r = q; } else { if (r == NULL) { mp_set_subscr_head(p, q->link); } else { mp_set_link(r, q->link); } mp_free_value_node(mp, q); } q = r == NULL ? mp_get_subscr_head(p) : r->link; } } p = mp_get_attribute_head(p); do { p = p->link; } while (mp_get_hashloc(p) < n); if (mp_get_hashloc(p) != n) { return; } } } if (discard_suffixes) { mp_flush_below_variable(mp, p); } else { if (p->type == mp_structured_type) { p = mp_get_attribute_head(p); } mp_recycle_value(mp, p); } } void mp_flush_below_variable (MP mp, mp_node p) { if (p->type != mp_structured_type) { mp_recycle_value(mp, p); } else { mp_node r; mp_node q = mp_get_subscr_head(p); while (q->name_type == mp_subscript_operation) { mp_flush_below_variable(mp, q); r = q; q = q->link; mp_free_value_node(mp, r); } r = mp_get_attribute_head(p); q = r->link; mp_recycle_value(mp, r); mp_free_value_node(mp, r); do { mp_flush_below_variable(mp, q); r = q; q = q->link; mp_free_value_node(mp, r); } while (q != mp->end_attr); p->type = mp_undefined_type; } } static int mp_und_type (MP mp, mp_node p) { (void) mp; switch (p->type) { case mp_vacuous_type: return mp_undefined_type; case mp_boolean_type: case mp_unknown_boolean_type: return mp_unknown_boolean_type; case mp_string_type: case mp_unknown_string_type: return mp_unknown_string_type; case mp_pen_type: case mp_unknown_pen_type: return mp_unknown_pen_type; case mp_nep_type: case mp_unknown_nep_type: return mp_unknown_nep_type; case mp_path_type: case mp_unknown_path_type: return mp_unknown_path_type; case mp_picture_type: case mp_unknown_picture_type: return mp_unknown_picture_type; case mp_transform_type: case mp_color_type: case mp_cmykcolor_type: case mp_pair_type: case mp_numeric_type: return p->type; case mp_known_type: case mp_dependent_type: case mp_proto_dependent_type: case mp_independent_type: return mp_numeric_type; default: return 0; } } static void mp_clear_symbol (MP mp, mp_sym p, int saving) { mp_node q = equiv_node(p); if (eq_property(p) > 0) { mp_check_overload(mp, p); } switch (eq_type(p)) { case mp_defined_macro_command: case mp_primary_def_command: case mp_secondary_def_command: case mp_tertiary_def_command: if (!saving) { mp_delete_mac_ref(mp, q); } break; case mp_tag_command: if (q != NULL) { if (saving) { q->name_type = mp_saved_root_operation; } else { mp_flush_below_variable(mp, q); mp_free_value_node(mp, q); } } break; default: break; } set_equiv(p, mp->frozen_undefined->v.data.indep.serial); set_eq_type(p, mp->frozen_undefined->type); } static void mp_save_boundary (MP mp) { mp_save_data *p = mp_memory_allocate(sizeof(mp_save_data)); p->type = 0; p->link = mp->save_ptr; mp->save_ptr = p; } static void mp_save_variable (MP mp, mp_sym q) { if (mp->save_ptr != NULL) { mp_save_data *p = mp_memory_allocate(sizeof(mp_save_data)); p->type = mp_normal_operation; p->link = mp->save_ptr; p->value.v.data.indep.scale = eq_type(q); p->value.v.data.indep.serial = equiv(q); p->value.v.data.node = equiv_node(q); p->value.v.data.p = (mp_knot)q; mp->save_ptr = p; } mp_clear_symbol(mp, q, (mp->save_ptr != NULL)); } static void mp_unsave_variable (MP mp) { mp_sym q = (mp_sym)mp->save_ptr->value.v.data.p; if (number_positive(internal_value(mp_tracing_restores_internal))) { mp_begin_diagnostic(mp); mp_print_nl(mp, "{restoring "); mp_print_mp_str(mp,text(q)); mp_print_chr(mp, '}'); mp_end_diagnostic(mp, 0); } mp_clear_symbol(mp, q, 0); set_eq_type(q, mp->save_ptr->value.v.data.indep.scale); set_equiv(q,mp->save_ptr->value.v.data.indep.serial); q->v.data.node = mp->save_ptr->value.v.data.node; if (eq_type(q) == mp_tag_command) { mp_node pp = q->v.data.node; if (pp != NULL) { pp->name_type = mp_root_operation; } } } static void mp_save_internal (MP mp, int q) { if (mp->save_ptr != NULL) { mp_save_data *p = mp_memory_allocate(sizeof(mp_save_data)); p->type = mp_internal_operation; p->link = mp->save_ptr; p->value = mp->internal[q]; p->value.v.data.indep.serial = q; if (internal_run(q) == 1) { mp->run_internal(mp, 1, q, internal_type(q), internal_name(q)); } new_number_clone(p->value.v.data.n, mp->internal[q].v.data.n); mp->save_ptr = p; } } static void mp_unsave_internal (MP mp) { int q = mp->save_ptr->value.v.data.indep.serial; mp_internal saved = mp->save_ptr->value; if (number_positive(internal_value(mp_tracing_restores_internal))) { mp_begin_diagnostic(mp); mp_print_nl(mp, "{restoring "); mp_print_str(mp, internal_name(q)); mp_print_chr(mp, '='); switch (internal_type(q)) { case mp_known_type: case mp_numeric_type: print_number(saved.v.data.n); break; case mp_boolean_type: mp_print_str(mp, number_to_boolean(saved.v.data.n) == mp_true_operation ? "true" : "false"); break; case mp_string_type: { char *s = mp_str(mp, saved.v.data.str); mp_print_str(mp, s); break; } default: mp_confusion(mp, "internal restore"); break; } mp_print_chr(mp, '}'); mp_end_diagnostic(mp, 0); } free_number(mp->internal[q].v.data.n); if (internal_run(q) == 1) { mp->run_internal(mp, 2, q, internal_type(q), internal_name(q)); } mp->internal[q] = saved; } static void mp_unsave (MP mp) { mp_save_data *p; while (mp->save_ptr->type != 0) { if (mp->save_ptr->type == mp_internal_operation) { mp_unsave_internal(mp); } else { mp_unsave_variable(mp); } p = mp->save_ptr->link; mp_memory_free(mp->save_ptr); mp->save_ptr = p; } p = mp->save_ptr->link; mp_memory_free(mp->save_ptr); mp->save_ptr = p; } void mp_pr_path (MP mp, mp_knot h) { mp_knot p = h; do { mp_knot q = mp_next_knot(p); if ((p == NULL) || (q == NULL)) { mp_print_nl(mp, "???"); return; } else { mp_print_two(mp, &(p->x_coord), &(p->y_coord)); switch (mp_knotstate(p)) { case mp_begin_knot: mp_print_str(mp, " {begin}"); break; case mp_end_knot: mp_print_str(mp, " {end}"); break; } switch (mp_right_type(p)) { case mp_endpoint_knot: { if (mp_left_type(p) == mp_open_knot) { mp_print_str(mp, " {open?}"); } if ((mp_left_type(q) != mp_endpoint_knot) || (q != h)) { q = NULL; } goto DONE1; } break; case mp_explicit_knot: { mp_print_str(mp, " .. controls "); mp_print_two(mp, &(p->right_x), &(p->right_y)); mp_print_str(mp, " and "); if (mp_left_type(q) != mp_explicit_knot) { mp_print_str(mp, "??"); } else { mp_print_two(mp, &(q->left_x), &(q->left_y)); } goto DONE1; } break; case mp_open_knot: { if ((mp_left_type(p) != mp_explicit_knot) && (mp_left_type(p) != mp_open_knot)) { mp_print_str(mp, " {open?}"); } } break; case mp_curl_knot: case mp_given_knot: { if (mp_left_type(p) == mp_open_knot) { mp_print_str(mp, " ??"); } if (mp_right_type(p) == mp_curl_knot) { mp_print_str(mp, " {curl"); print_number(p->right_curl); } else { mp_number n_sin, n_cos; new_fraction(n_sin); new_fraction(n_cos); n_sin_cos(p->right_given, n_cos, n_sin); mp_print_str(mp, " {"); print_number(n_cos); mp_print_chr(mp, ','); print_number(n_sin); free_number(n_sin); free_number(n_cos); } mp_print_str(mp, "} "); } break; default: { mp_print_str(mp, "???"); } break; } if (mp_left_type(q) <= mp_explicit_knot) { mp_print_str(mp, " .. control ?"); } else if ((! number_equal(p->right_tension, unity_t)) || (! number_equal(q->left_tension, unity_t))) { mp_number v1; mp_print_str(mp, " .. tension"); if (number_negative(p->right_tension)) { mp_print_str(mp, " atleast"); } new_number_abs(v1, p->right_tension); print_number(v1); if (! number_equal(p->right_tension, q->left_tension)) { mp_print_str(mp, " and"); if (number_negative(q->left_tension)) { mp_print_str(mp, " atleast"); } number_abs_clone(v1, p->left_tension); print_number(v1); } free_number(v1); } DONE1: p = q; if (p && ((p != h) || (mp_left_type(h) != mp_endpoint_knot))) { mp_number n_sin, n_cos; new_fraction(n_sin); new_fraction(n_cos); mp_print_nl(mp, " .. "); if (mp_left_type(p) == mp_given_knot) { n_sin_cos(p->left_given, n_cos, n_sin); mp_print_str(mp, "{"); print_number(n_cos); mp_print_chr(mp, ','); print_number(n_sin); mp_print_chr(mp, '}'); } else if (mp_left_type(p) == mp_curl_knot) { mp_print_str(mp, "{curl "); print_number(p->left_curl); mp_print_chr(mp, '}'); } free_number(n_sin); free_number(n_cos); } } } while (p != h); if (mp_left_type(h) != mp_endpoint_knot) { mp_print_str(mp, " cycle"); } } void mp_print_path (MP mp, mp_knot h, const char *s, int nuline) { mp_print_diagnostic(mp, "Path", s, nuline); mp_print_ln(mp); mp_pr_path(mp, h); mp_end_diagnostic(mp, 1); } static mp_knot mp_new_knot (MP mp) { mp_knot q; if (mp->knot_nodes) { q = mp->knot_nodes; mp->knot_nodes = q->next; mp->num_knot_nodes--; } else { q = mp_memory_clear_allocate(sizeof(struct mp_knot_data)); } new_number(q->x_coord); new_number(q->y_coord); new_number(q->left_x); new_number(q->left_y); new_number(q->right_x); new_number(q->right_y); return q; } static mp_gr_knot mp_gr_new_knot (MP mp) { mp_gr_knot q = mp_memory_allocate(sizeof(struct mp_gr_knot_data)); (void) mp; return q; } static mp_knot mp_copy_knot (MP mp, mp_knot p) { mp_knot q; if (mp->knot_nodes) { q = mp->knot_nodes; mp->knot_nodes = q->next; mp->num_knot_nodes--; } else { q = mp_memory_allocate(sizeof(struct mp_knot_data)); } memcpy(q, p, sizeof(struct mp_knot_data)); if (mp->math_mode > mp_math_double_mode) { new_number_clone(q->x_coord, p->x_coord); new_number_clone(q->y_coord, p->y_coord); new_number_clone(q->left_x, p->left_x); new_number_clone(q->left_y, p->left_y); new_number_clone(q->right_x, p->right_x); new_number_clone(q->right_y, p->right_y); } mp_prev_knot(q) = NULL; mp_next_knot(q) = NULL; return q; } static mp_gr_knot mp_export_knot (MP mp, mp_knot p) { mp_gr_knot q = mp_gr_new_knot(mp); q->x_coord = number_to_double(p->x_coord); q->y_coord = number_to_double(p->y_coord); q->left_x = number_to_double(p->left_x); q->left_y = number_to_double(p->left_y); q->right_x = number_to_double(p->right_x); q->right_y = number_to_double(p->right_y); q->left_type = p->left_type; q->right_type = p->right_type; q->info = p->info; q->originator = p->originator; q->state = p->state; q->prev = NULL; q->next = NULL; return q; } static mp_knot mp_copy_path (MP mp, mp_knot p) { if (p == NULL) { return NULL; } else { mp_knot q = mp_copy_knot(mp, p); mp_knot qq = q; mp_knot pp = mp_next_knot(p); while (pp != p) { mp_knot k = mp_copy_knot(mp, pp); mp_next_knot(qq) = k; mp_prev_knot(k) = qq; qq = mp_next_knot(qq); pp = mp_next_knot(pp); } mp_next_knot(qq) = q; mp_prev_knot(q) = qq; return q; } } static mp_gr_knot mp_export_path (MP mp, mp_knot p) { if (p == NULL) { return NULL; } else { mp_gr_knot q = mp_export_knot(mp, p); mp_gr_knot qq = q; mp_knot pp = mp_next_knot(p); while (pp != p) { mp_gr_knot k = mp_export_knot(mp, pp); mp_prev_knot(k) = qq; mp_next_knot(qq) = k; qq = k; pp = mp_next_knot(pp); } mp_prev_knot(q) = qq; mp_next_knot(qq) = q; return q; } } static mp_gr_knot mp_export_knot_list (MP mp, mp_knot p) { if (p == NULL) { return NULL; } else { mp_gr_knot q = mp_export_path(mp, p); return q; } } static mp_knot mp_htap_ypoc (MP mp, mp_knot p) { mp_knot q = mp_new_knot(mp); mp_knot qq = q; mp_knot pp = p; while (1) { mp_right_type(qq) = mp_left_type(pp); mp_left_type(qq) = mp_right_type(pp); number_clone(qq->x_coord, pp->x_coord); number_clone(qq->y_coord, pp->y_coord); number_clone(qq->right_x, pp->left_x); number_clone(qq->right_y, pp->left_y); number_clone(qq->left_x, pp->right_x); number_clone(qq->left_y, pp->right_y); mp_originator(qq) = mp_originator(pp); mp_knotstate(qq) = mp_knotstate(pp); if (mp_next_knot(pp) == p) { mp_prev_knot(qq) = q; mp_next_knot(q) = qq; mp->path_tail = pp; return q; } else { mp_knot rr = mp_new_knot(mp); mp_prev_knot(qq) = rr; mp_next_knot(rr) = qq; qq = rr; pp = mp_next_knot(pp); } } } static void mp_free_knot (MP mp, mp_knot q) { if (mp->math_mode > mp_math_double_mode) { free_number(q->x_coord); free_number(q->y_coord); free_number(q->left_x); free_number(q->left_y); free_number(q->right_x); free_number(q->right_y); } mp_memory_free(q); } static void mp_toss_knot (MP mp, mp_knot q) { if (mp->num_knot_nodes < mp->max_knot_nodes) { mp_next_knot(q) = mp->knot_nodes; mp->knot_nodes = q; mp->num_knot_nodes++; if (mp->math_mode > mp_math_double_mode) { free_number(q->x_coord); free_number(q->y_coord); free_number(q->left_x); free_number(q->left_y); free_number(q->right_x); free_number(q->right_y); } } else { mp_free_knot(mp, q); } } static void mp_toss_knot_list (MP mp, mp_knot p) { if (p == NULL) { return; } else { mp_knot q = p; do { mp_knot r = mp_next_knot(q); mp_toss_knot(mp, q); q = r; } while (q != p); } } void mp_make_choices (MP mp, mp_knot knots) { mp_knot h; mp_knot p, q; int k, n; mp_knot s, t; check_arith(); if (number_positive(internal_value(mp_tracing_choices_internal))) { mp_print_path(mp, knots, ", before choices", 1); } p = knots; do { q = mp_next_knot(p); if (number_equal(p->x_coord, q->x_coord) && number_equal(p->y_coord, q->y_coord) && mp_right_type(p) > mp_explicit_knot) { mp_right_type(p) = mp_explicit_knot; if (mp_left_type(p) == mp_open_knot) { mp_left_type(p) = mp_curl_knot; set_number_to_unity(p->left_curl); } mp_left_type(q) = mp_explicit_knot; if (mp_right_type(q) == mp_open_knot) { mp_right_type(q) = mp_curl_knot; set_number_to_unity(q->right_curl); } number_clone(p->right_x, p->x_coord); number_clone(q->left_x, p->x_coord); number_clone(p->right_y, p->y_coord); number_clone(q->left_y, p->y_coord); } p = q; } while (p != knots); h = knots; while (1) { if (mp_left_type(h) != mp_open_knot) { break; } else if (mp_right_type(h) != mp_open_knot) { break; } else { h = mp_next_knot(h); if (h == knots) { mp_left_type(h) = mp_end_cycle_knot; break; } } } p = h; do { q = mp_next_knot(p); if (mp_right_type(p) >= mp_given_knot) { while ((mp_left_type(q) == mp_open_knot) && (mp_right_type(q) == mp_open_knot)) { q = mp_next_knot(q); } mp_number sine, cosine; mp_number arg1, arg2, r1, r2; mp_number delx, dely; new_fraction(sine); new_fraction(cosine); new_number(arg1); new_number(arg2); new_fraction(r1); new_fraction(r2); new_number(delx); new_number(dely); { RESTART: k = 0; s = p; n = mp->path_size; do { t = mp_next_knot(s); set_number_from_subtraction(mp->delta_x[k], t->x_coord, s->x_coord); set_number_from_subtraction(mp->delta_y[k], t->y_coord, s->y_coord); pyth_add(mp->delta[k], mp->delta_x[k], mp->delta_y[k]); if (k > 0) { make_fraction(r1, mp->delta_y[k - 1], mp->delta[k - 1]); number_clone(sine, r1); make_fraction(r2, mp->delta_x[k - 1], mp->delta[k - 1]); number_clone(cosine, r2); take_fraction(r1, mp->delta_x[k], cosine); take_fraction(r2, mp->delta_y[k], sine); set_number_from_addition(arg1, r1, r2); take_fraction(r1, mp->delta_y[k], cosine); take_fraction(r2, mp->delta_x[k], sine); set_number_from_subtraction(arg2, r1, r2); n_arg(mp->psi[k], arg1, arg2 ); } ++k; s = t; if (k == mp->path_size) { mp_reallocate_paths(mp, mp->path_size + (mp->path_size / 4)); goto RESTART; } else if (s == q) { n = k; } } while (! ((k >= n) && (mp_left_type(s) != mp_end_cycle_knot))); if (k == n) { set_number_to_zero(mp->psi[k]); } else { number_clone(mp->psi[k], mp->psi[1]); } } { if (mp_left_type(q) == mp_open_knot) { set_number_from_subtraction(delx, q->right_x, q->x_coord); set_number_from_subtraction(dely, q->right_y, q->y_coord); if (number_zero(delx) && number_zero(dely)) { mp_left_type(q) = mp_curl_knot; set_number_to_unity(q->left_curl); } else { mp_left_type(q) = mp_given_knot; n_arg(q->left_given, delx, dely); } } if ((mp_right_type(p) == mp_open_knot) && (mp_left_type(p) == mp_explicit_knot)) { set_number_from_subtraction(delx, p->x_coord, p->left_x); set_number_from_subtraction(dely, p->y_coord, p->left_y); if (number_zero(delx) && number_zero(dely)) { mp_right_type(p) = mp_curl_knot; set_number_to_unity(p->right_curl); } else { mp_right_type(p) = mp_given_knot; n_arg(p->right_given, delx, dely); } } } free_number(sine); free_number(cosine); free_number(arg1); free_number(arg2); free_number(r1); free_number(r2); free_number(delx); free_number(dely); mp_solve_choices(mp, p, q, n); } else if (mp_right_type(p) == mp_endpoint_knot) { number_clone(p->right_x, p->x_coord); number_clone(p->right_y, p->y_coord); number_clone(q->left_x, q->x_coord); number_clone(q->left_y, q->y_coord); } p = q; } while (p != h); if (number_positive(internal_value(mp_tracing_choices_internal))) { mp_print_path(mp, knots, ", after choices", 1); } if (mp->arith_error) { mp_back_error( mp, "Some number got too big", "The path that I just computed is out of range. So it will probably look funny.\n" "Proceed, for a laugh." ); mp_get_x_next(mp); mp->arith_error = 0; } } void mp_reallocate_paths (MP mp, int l) { mp->delta_x = mp_memory_reallocate(mp->delta_x, (size_t) (l + 1) * sizeof(mp_number)); mp->delta_y = mp_memory_reallocate(mp->delta_y, (size_t) (l + 1) * sizeof(mp_number)); mp->delta = mp_memory_reallocate(mp->delta, (size_t) (l + 1) * sizeof(mp_number)); mp->psi = mp_memory_reallocate(mp->psi, (size_t) (l + 1) * sizeof(mp_number)); mp->theta = mp_memory_reallocate(mp->theta, (size_t) (l + 1) * sizeof(mp_number)); mp->uu = mp_memory_reallocate(mp->uu, (size_t) (l + 1) * sizeof(mp_number)); mp->vv = mp_memory_reallocate(mp->vv, (size_t) (l + 1) * sizeof(mp_number)); mp->ww = mp_memory_reallocate(mp->ww, (size_t) (l + 1) * sizeof(mp_number)); for (int k = mp->path_size; kdelta_x[k]); new_number(mp->delta_y[k]); new_number(mp->delta[k]); new_angle(mp->psi[k]); new_angle(mp->theta[k]); new_fraction(mp->uu[k]); new_angle(mp->vv[k]); new_fraction(mp->ww[k]); } mp->path_size = l; } void mp_solve_choices (MP mp, mp_knot p, mp_knot q, int n) { int k = 0; mp_knot r = 0; mp_knot s = p; mp_number ff; new_fraction(ff); while (1) { mp_knot t = mp_next_knot(s); if (k == 0) { switch (mp_right_type(s)) { case mp_given_knot: if (mp_left_type(t) == mp_given_knot) { { mp_number arg1; mp_number narg; new_angle(narg); n_arg(narg, mp->delta_x[0], mp->delta_y[0]); new_number(arg1); set_number_from_subtraction(arg1, p->right_given, narg); n_sin_cos(arg1, mp->ct, mp->st); set_number_from_subtraction(arg1, q->left_given, narg); n_sin_cos(arg1, mp->cf, mp->sf); number_negate(mp->sf); mp_set_controls (mp, p, q, 0); free_number(narg); free_number(arg1); free_number(ff); return; } } else { { mp_number narg; new_angle(narg); n_arg(narg, mp->delta_x[0], mp->delta_y[0]); set_number_from_subtraction(mp->vv[0], s->right_given, narg); free_number(narg); mp_reduce_angle(mp, &mp->vv[0]); set_number_to_zero(mp->uu[0]); set_number_to_zero(mp->ww[0]); } } break; case mp_curl_knot: if (mp_left_type(t) == mp_curl_knot) { { mp_number lt, rt; mp_right_type(p) = mp_explicit_knot; mp_left_type(q) = mp_explicit_knot; new_number_abs(lt, q->left_tension); new_number_abs(rt, p->right_tension); if (number_unity(rt)) { mp_number arg2; new_number(arg2); if (number_nonnegative(mp->delta_x[0])) { set_number_from_addition(arg2, mp->delta_x[0], epsilon_t); } else { set_number_from_subtraction(arg2, mp->delta_x[0], epsilon_t); } number_int_div(arg2, 3); set_number_from_addition(p->right_x, p->x_coord, arg2); if (number_nonnegative(mp->delta_y[0])) { set_number_from_addition(arg2, mp->delta_y[0], epsilon_t); } else { set_number_from_subtraction(arg2, mp->delta_y[0], epsilon_t); } number_int_div(arg2, 3); set_number_from_addition(p->right_y, p->y_coord, arg2); free_number(arg2); } else { mp_number arg2, r1; new_fraction(r1); new_number_clone(arg2, rt); number_multiply_int(arg2, 3); make_fraction(ff, unity_t, arg2); free_number(arg2); take_fraction(r1, mp->delta_x[0], ff); set_number_from_addition(p->right_x, p->x_coord, r1); take_fraction(r1, mp->delta_y[0], ff); set_number_from_addition(p->right_y, p->y_coord, r1); } if (number_unity(lt)) { mp_number arg2; new_number(arg2); if (number_nonnegative(mp->delta_x[0])) { set_number_from_addition(arg2, mp->delta_x[0], epsilon_t); } else { set_number_from_subtraction(arg2, mp->delta_x[0], epsilon_t); } number_int_div(arg2, 3); set_number_from_subtraction(q->left_x, q->x_coord, arg2); if (number_nonnegative(mp->delta_y[0])) { set_number_from_addition(arg2, mp->delta_y[0], epsilon_t); } else { set_number_from_subtraction(arg2, mp->delta_y[0], epsilon_t); } number_int_div(arg2, 3); set_number_from_subtraction(q->left_y, q->y_coord, arg2); free_number(arg2); } else { mp_number arg2, r1; new_fraction(r1); new_number_clone(arg2, lt); number_multiply_int(arg2, 3); make_fraction(ff, unity_t, arg2); free_number(arg2); take_fraction(r1, mp->delta_x[0], ff); set_number_from_subtraction(q->left_x, q->x_coord, r1); take_fraction(r1, mp->delta_y[0], ff); set_number_from_subtraction(q->left_y, q->y_coord, r1); free_number(r1); } free_number(ff); free_number(lt); free_number(rt); return; } } else { { mp_number lt, rt, cc; new_number_clone(cc, s->right_curl); new_number_abs(lt, t->left_tension); new_number_abs(rt, s->right_tension); if (number_unity(rt) && number_unity(lt)) { mp_number arg1, arg2; new_number_clone(arg1, cc); new_number_clone(arg2, cc); number_double(arg1); number_add(arg1, unity_t); number_add(arg2, two_t); make_fraction(mp->uu[0], arg1, arg2); free_number(arg1); free_number(arg2); } else { mp_curl_ratio(mp, &mp->uu[0], &cc, &rt, <); } take_fraction(mp->vv[0], mp->psi[1], mp->uu[0]); number_negate(mp->vv[0]); set_number_to_zero(mp->ww[0]); free_number(rt); free_number(lt); free_number(cc); } } break; case mp_open_knot: set_number_to_zero(mp->uu[0]); set_number_to_zero(mp->vv[0]); number_clone(mp->ww[0], fraction_one_t); break; } } else { switch (mp_left_type(s)) { case mp_end_cycle_knot: case mp_open_knot: { mp_number aa, bb, cc, acc; mp_number dd, ee; new_fraction(aa); new_fraction(bb); new_fraction(cc); new_fraction(acc); new_number(dd); new_number(ee); { mp_number absval; new_number_abs(absval, r->right_tension); if (number_equal(absval, unity_t)) { number_clone(aa, fraction_half_t); number_clone(dd, mp->delta[k]); number_double(dd); } else { mp_number arg1, arg2, ret; new_number(arg1); new_number_abs(arg2, r->right_tension); number_multiply_int(arg2, 3); number_subtract(arg2, unity_t); make_fraction(aa, unity_t, arg2); number_abs_clone(arg2, r->right_tension); new_fraction(ret); make_fraction(ret, unity_t, arg2); set_number_from_subtraction(arg1, fraction_three_t, ret); take_fraction(arg2, mp->delta[k], arg1); number_clone(dd, arg2); free_number(ret); free_number(arg1); free_number(arg2); } number_abs_clone(absval, t->left_tension); if (number_equal(absval, unity_t)) { number_clone(bb, fraction_half_t); number_clone(ee, mp->delta[k - 1]); number_double(ee); } else { mp_number arg1, arg2, ret; new_number(arg1); new_number_abs(arg2, t->left_tension); number_multiply_int(arg2, 3); number_subtract(arg2, unity_t); make_fraction(bb, unity_t, arg2); number_abs_clone(arg2, t->left_tension); new_fraction(ret); make_fraction(ret, unity_t, arg2); set_number_from_subtraction(arg1, fraction_three_t, ret); take_fraction(ee, mp->delta[k - 1], arg1); free_number(ret); free_number(arg1); free_number(arg2); } free_number(absval); } { mp_number r1; new_number(r1); take_fraction(r1, mp->uu[k - 1], aa); set_number_from_subtraction(cc, fraction_one_t, r1); free_number(r1); } { mp_number rt, lt; mp_number arg2; new_number_clone(arg2, dd); take_fraction(dd, arg2, cc); new_number_abs(lt, s->left_tension); new_number_abs(rt, s->right_tension); if (! number_equal(lt, rt)) { mp_number r1; new_number(r1); if (number_less(lt, rt)) { make_fraction(r1, lt, rt); take_fraction(ff, r1, r1); number_clone(r1, dd); take_fraction(dd, r1, ff); } else { make_fraction(r1, rt, lt); take_fraction(ff, r1, r1); number_clone(r1, ee); take_fraction(ee, r1, ff); } free_number(r1); } free_number(rt); free_number(lt); set_number_from_addition(arg2, dd, ee); make_fraction(ff, ee, arg2); free_number(arg2); } take_fraction(mp->uu[k], ff, bb); take_fraction(acc, mp->psi[k + 1], mp->uu[k]); number_negate(acc); if (mp_right_type(r) == mp_curl_knot) { mp_number r1, arg2; new_fraction(r1); new_number(arg2); set_number_from_subtraction(arg2, fraction_one_t, ff); take_fraction(r1, mp->psi[1], arg2); set_number_to_zero(mp->ww[k]); set_number_from_subtraction(mp->vv[k], acc, r1); free_number(r1); free_number(arg2); } else { mp_number arg1, r1; new_fraction(r1); new_number(arg1); set_number_from_subtraction(arg1, fraction_one_t, ff); make_fraction(ff, arg1, cc); free_number(arg1); take_fraction(r1, mp->psi[k], ff); number_subtract(acc, r1); number_clone(r1, ff); take_fraction(ff, r1, aa); take_fraction(r1, mp->vv[k - 1], ff); set_number_from_subtraction(mp->vv[k], acc, r1 ); if (number_zero(mp->ww[k - 1])) { set_number_to_zero(mp->ww[k]); } else { take_fraction(mp->ww[k], mp->ww[k - 1], ff); number_negate(mp->ww[k]); } free_number(r1); } if (mp_left_type(s) == mp_end_cycle_knot) { mp_number arg2, r1; new_number(arg2); new_number(r1); set_number_to_zero(aa); number_clone(bb, fraction_one_t); do { --k; if (k == 0) { k = n; } take_fraction(r1, aa, mp->uu[k]); set_number_from_subtraction(aa, mp->vv[k], r1); take_fraction(r1, bb, mp->uu[k]); set_number_from_subtraction(bb, mp->ww[k], r1); } while (k != n); set_number_from_subtraction(arg2, fraction_one_t, bb); make_fraction(r1, aa, arg2); number_clone(aa, r1); number_clone(mp->theta[n], aa); number_clone(mp->vv[0], aa); for (k = 1; k < n; k++) { take_fraction(r1, aa, mp->ww[k]); number_add(mp->vv[k], r1); } free_number(arg2); free_number(r1); free_number(aa); free_number(bb); free_number(cc); free_number(acc); free_number(dd); free_number(ee); goto FOUND; } free_number(aa); free_number(bb); free_number(cc); free_number(acc); free_number(dd); free_number(ee); } break; case mp_curl_knot: { mp_number lt, rt, cc; new_number_clone(cc, s->left_curl); new_number_abs(lt, s->left_tension); new_number_abs(rt, r->right_tension); if (number_unity(rt) && number_unity(lt)) { mp_number arg1, arg2; new_number_clone(arg1, cc); new_number_clone(arg2, cc); number_double(arg1); number_add(arg1, unity_t); number_add(arg2, two_t); make_fraction(ff, arg1, arg2); free_number(arg1); free_number(arg2); } else { mp_curl_ratio(mp, &ff, &cc, <, &rt); } { mp_number arg1, arg2, r1; new_fraction(r1); new_fraction(arg1); new_number(arg2); take_fraction(arg1, mp->vv[n - 1], ff); take_fraction(r1, ff, mp->uu[n - 1]); set_number_from_subtraction(arg2, fraction_one_t, r1); make_fraction(mp->theta[n], arg1, arg2); number_negate(mp->theta[n]); free_number(r1); free_number(arg1); free_number(arg2); } free_number(rt); free_number(lt); free_number(cc); goto FOUND; } break; case mp_given_knot: { mp_number narg; new_angle(narg); n_arg(narg, mp->delta_x[n - 1], mp->delta_y[n - 1]); set_number_from_subtraction(mp->theta[n], s->left_given, narg); free_number(narg); mp_reduce_angle(mp, &mp->theta[n]); goto FOUND; } break; } } r = s; s = t; ++k; } FOUND: { mp_number r1; new_number(r1); for (k = n - 1; k >= 0; k--) { take_fraction(r1, mp->theta[k + 1], mp->uu[k]); set_number_from_subtraction(mp->theta[k], mp->vv[k], r1); } free_number(r1); } s = p; k = 0; { mp_number arg; new_number(arg); do { mp_knot t = mp_next_knot(s); n_sin_cos(mp->theta[k], mp->ct, mp->st); number_negated_clone(arg, mp->psi[k + 1]); number_subtract(arg, mp->theta[k + 1]); n_sin_cos(arg, mp->cf, mp->sf); mp_set_controls (mp, s, t, k); ++k; s = t; } while (k != n); free_number(arg); } free_number(ff); } static void mp_reduce_angle (MP mp, mp_number *a) { mp_number abs_a; new_number_abs(abs_a, *a); if (number_greater(abs_a, one_eighty_deg_t)) { if (number_positive(*a)) { number_subtract(*a, three_sixty_deg_t); } else { number_add(*a, three_sixty_deg_t); } } free_number(abs_a); } void mp_curl_ratio (MP mp, mp_number *ret, mp_number *gamma_orig, mp_number *a_tension, mp_number *b_tension) { mp_number alpha, beta, gamma, num, denom, ff; mp_number arg1; new_number(arg1); new_fraction(alpha); new_fraction(beta); new_fraction(gamma); new_fraction(ff); new_fraction(denom); new_fraction(num); make_fraction(alpha, unity_t, *a_tension); make_fraction(beta, unity_t, *b_tension); number_clone(gamma, *gamma_orig); if (number_lessequal(alpha, beta)) { make_fraction(ff, alpha, beta); number_clone(arg1, ff); take_fraction(ff, arg1, arg1); number_clone(arg1, gamma); take_fraction(gamma, arg1, ff); convert_fraction_to_scaled(beta); take_fraction(denom, gamma, alpha); number_add(denom, three_t); } else { make_fraction(ff, beta, alpha); number_clone(arg1, ff); take_fraction(ff, arg1, arg1); take_fraction(arg1, beta, ff); convert_fraction_to_scaled(arg1); number_clone(beta, arg1); take_fraction(denom, gamma, alpha); set_number_from_div(arg1, ff, twelvebits_3); number_add(denom, arg1); } number_subtract(denom, beta); set_number_from_subtraction(arg1, fraction_three_t, alpha); take_fraction(num, gamma, arg1); number_add(num, beta); number_clone(arg1, denom); number_double(arg1); number_double(arg1); if (number_greaterequal(num, arg1)) { number_clone(*ret, fraction_four_t); } else { make_fraction(*ret, num, denom); } free_number(alpha); free_number(beta); free_number(gamma); free_number(num); free_number(denom); free_number(ff); free_number(arg1); } void mp_set_controls (MP mp, mp_knot p, mp_knot q, int k) { mp_number rr, ss; mp_number lt, rt; mp_number sine; mp_number tmp; mp_number r1, r2; new_number(tmp); new_number(r1); new_number(r2); new_number_abs(lt, q->left_tension); new_number_abs(rt, p->right_tension); new_fraction(sine); new_fraction(rr); new_fraction(ss); velocity(rr, mp->st, mp->ct, mp->sf, mp->cf, rt); velocity(ss, mp->sf, mp->cf, mp->st, mp->ct, lt); if (number_negative(p->right_tension) || number_negative(q->left_tension)) { if ((number_nonnegative(mp->st) && number_nonnegative(mp->sf)) || (number_nonpositive(mp->st) && number_nonpositive(mp->sf))) { mp_number r1, r2, arg1; new_fraction(r1); new_fraction(r2); new_number_abs(arg1, mp->st); take_fraction(r1, arg1, mp->cf); number_abs_clone(arg1, mp->sf); take_fraction(r2, arg1, mp->ct); set_number_from_addition(sine, r1, r2); if (number_positive(sine)) { set_number_from_addition(arg1, fraction_one_t, unity_t); number_clone(r1, sine); take_fraction(sine, r1, arg1); if (number_negative(p->right_tension)) { number_abs_clone(arg1, mp->sf); if (ab_vs_cd(arg1, fraction_one_t, rr, sine) < 0) { number_abs_clone(arg1, mp->sf); make_fraction(rr, arg1, sine); } } if (number_negative(q->left_tension)) { number_abs_clone(arg1, mp->st); if (ab_vs_cd(arg1, fraction_one_t, ss, sine) < 0) { number_abs_clone(arg1, mp->st); make_fraction(ss, arg1, sine); } } } free_number(arg1); free_number(r1); free_number(r2); } } take_fraction(r1, mp->delta_x [k], mp->ct); take_fraction(r2, mp->delta_y [k], mp->st); number_subtract(r1, r2); take_fraction(tmp, r1, rr); set_number_from_addition(p->right_x, p->x_coord, tmp); take_fraction(r1, mp->delta_y[k], mp->ct); take_fraction(r2, mp->delta_x[k], mp->st); number_add(r1, r2); take_fraction(tmp, r1, rr); set_number_from_addition(p->right_y, p->y_coord, tmp); take_fraction(r1, mp->delta_x[k], mp->cf); take_fraction(r2, mp->delta_y[k], mp->sf); number_add(r1, r2); take_fraction(tmp, r1, ss); set_number_from_subtraction(q->left_x, q->x_coord, tmp); take_fraction(r1, mp->delta_y[k], mp->cf); take_fraction(r2, mp->delta_x[k], mp->sf); number_subtract(r1, r2); take_fraction(tmp, r1, ss); set_number_from_subtraction(q->left_y, q->y_coord, tmp); mp_right_type(p) = mp_explicit_knot; mp_left_type(q) = mp_explicit_knot; free_number(tmp); free_number(r1); free_number(r2); free_number(lt); free_number(rt); free_number(rr); free_number(ss); free_number(sine); } # define TOO_LARGE(a) (fabs((a))>4096.0) # define PI 3.1415926535897932384626433832795028841971 static int out_of_range (MP mp, double a) { (void) mp; mp_number t; new_number_from_double(mp, t, fabs(a)); if (number_greaterequal(t, inf_t)) { free_number(t); return 1; } else { free_number(t); return 0; } } static int mp_link_knotpair (MP mp, mp_knot p, mp_knot q) { (void) mp; if (p == NULL || q == NULL) { return 0; } else { mp_prev_knot(q) = p; mp_next_knot(p) = q; set_number_from_double(p->right_tension, 1.0); if (mp_right_type(p) == mp_endpoint_knot) { mp_right_type(p) = mp_open_knot; } set_number_from_double(q->left_tension, 1.0); if (mp_left_type(q) == mp_endpoint_knot) { mp_left_type(q) = mp_open_knot; } return 1; } } static int mp_link_knotpair_xy (MP mp, mp_knot p, mp_knot q) { (void) mp; if (p == NULL || q == NULL) { return 0; } else { mp_prev_knot(q) = p; mp_next_knot(p) = q; return 1; } } int mp_close_path_cycle (MP mp, mp_knot p, mp_knot q) { return mp_link_knotpair(mp, p, q); } int mp_close_path (MP mp, mp_knot q, mp_knot first) { if (q == NULL || first == NULL) { return 0; } else { mp_prev_knot(first) = q; mp_next_knot(q) = first; mp_right_type(q) = mp_endpoint_knot; set_number_from_double(q->right_tension, 1.0); mp_left_type(first) = mp_endpoint_knot; set_number_from_double(first->left_tension, 1.0); return 1; } } mp_knot mp_create_knot (MP mp) { mp_knot q = mp_new_knot(mp); mp_left_type(q) = mp_endpoint_knot; mp_right_type(q) = mp_endpoint_knot; return q; } int mp_set_knot (MP mp, mp_knot p, double x, double y) { if (p == NULL) { return 0; } else if (out_of_range(mp, x)) { return 0; } else if (out_of_range(mp, y)) { return 0; } else { set_number_from_double(p->x_coord, x); set_number_from_double(p->y_coord, y); return 1; } } mp_knot mp_append_knot (MP mp, mp_knot p, double x, double y) { mp_knot q = mp_create_knot(mp); if (q == NULL) { return NULL; } else if (! mp_set_knot(mp, q, x, y)) { mp_memory_free(q); return NULL; } else if (p == NULL) { return q; } else if (mp_link_knotpair(mp, p, q)) { return q; } else { mp_memory_free(q); return NULL; } } mp_knot mp_append_knot_xy (MP mp, mp_knot p, double x, double y) { mp_knot q = mp_create_knot(mp); if (q == NULL) { return NULL; } else if (! mp_set_knot(mp, q, x, y)) { mp_memory_free(q); return NULL; } else if (p == NULL) { return q; } else if (mp_link_knotpair_xy(mp, p, q)) { mp_right_type(p) = mp_explicit_knot; mp_left_type(p) = mp_explicit_knot; return q; } else { mp_memory_free(q); return NULL; } } int mp_set_knot_curl (MP mp, mp_knot q, double value) { if (q == NULL) { return 0; } else if (TOO_LARGE(value)) { return 0; } else { mp_right_type(q) = mp_curl_knot; set_number_from_double(q->right_curl, value); if (mp_left_type(q) == mp_open_knot) { mp_left_type(q) = mp_curl_knot; set_number_from_double(q->left_curl, value); } return 1; } } int mp_set_knot_left_curl (MP mp, mp_knot q, double value) { if (q == NULL) { return 0; } else if (TOO_LARGE(value)) { return 0; } else { mp_left_type(q) = mp_curl_knot; set_number_from_double(q->left_curl, value); if (mp_right_type(q) == mp_open_knot) { mp_right_type(q) = mp_curl_knot; set_number_from_double(q->right_curl, value); } return 1; } } int mp_set_knot_right_curl (MP mp, mp_knot q, double value) { if (q == NULL) { return 0; } else if (TOO_LARGE(value)) { return 0; } else { mp_right_type(q) = mp_curl_knot; set_number_from_double(q->right_curl, value); if (mp_left_type(q) == mp_open_knot) { mp_left_type(q) = mp_curl_knot; set_number_from_double(q->left_curl, value); } return 1; } } int mp_set_knot_simple_curl (MP mp, mp_knot q) { if (q == NULL) { return 0; } else { mp_right_type(q) = mp_curl_knot; set_number_from_double(q->right_curl, 1.0); mp_left_type(q) = mp_curl_knot; set_number_from_double(q->left_curl, 1.0); return 1; } } int mp_set_knotpair_curls (MP mp, mp_knot p, mp_knot q, double t1, double t2) { if (p == NULL || q == NULL) { return 0; } else if (mp_set_knot_curl(mp, p, t1)) { return mp_set_knot_curl(mp, q, t2); } else { return 0; } } int mp_set_knotpair_tensions (MP mp, mp_knot p, mp_knot q, double t1, double t2) { if (p == NULL || q == NULL) { return 0; } else if (TOO_LARGE(t1)) { return 0; } else if (TOO_LARGE(t2)) { return 0; } else if ((fabs(t1) < 0.75)) { return 0; } else if ((fabs(t2) < 0.75)) { return 0; } else { set_number_from_double(p->right_tension, t1); set_number_from_double(q->left_tension, t2); return 1; } } int mp_set_knot_left_tension (MP mp, mp_knot p, double t1) { if (p == NULL) { return 0; } else if (TOO_LARGE(t1)) { return 0; } else if ((fabs(t1) < 0.75)) { return 0; } else { set_number_from_double(p->left_tension, t1); return 1; } } int mp_set_knot_right_tension (MP mp, mp_knot p, double t1) { if (p == NULL) { return 0; } else if (TOO_LARGE(t1)) { return 0; } else if ((fabs(t1) < 0.75)) { return 0; } else { set_number_from_double(p->right_tension, t1); return 1; } } int mp_set_knotpair_controls (MP mp, mp_knot p, mp_knot q, double x1, double y1, double x2, double y2) { if (p == NULL || q == NULL) { return 0; } else if (out_of_range(mp, x1)) { return 0; } else if (out_of_range(mp, y1)) { return 0; } else if (out_of_range(mp, x2)) { return 0; } else if (out_of_range(mp, y2)) { return 0; } else { mp_right_type(p) = mp_explicit_knot; set_number_from_double(p->right_x, x1); set_number_from_double(p->right_y, y1); mp_left_type(q) = mp_explicit_knot; set_number_from_double(q->left_x, x2); set_number_from_double(q->left_y, y2); return 1; } } int mp_set_knot_left_control (MP mp, mp_knot p, double x1, double y1) { if (p == NULL) { return 0; } else if (out_of_range(mp, x1)) { return 0; } else if (out_of_range(mp, y1)) { return 0; } else { mp_left_type(p) = mp_explicit_knot; set_number_from_double(p->left_x, x1); set_number_from_double(p->left_y, y1); return 1; } } int mp_set_knot_right_control (MP mp, mp_knot p, double x1, double y1) { if (p == NULL) { return 0; } else if (out_of_range(mp, x1)) { return 0; } else if (out_of_range(mp, y1)) { return 0; } else { mp_right_type(p) = mp_explicit_knot; set_number_from_double(p->right_x, x1); set_number_from_double(p->right_y, y1); return 1; } } int mp_set_knot_direction (MP mp, mp_knot q, double x, double y) { if (q == NULL) { return 0; } else if (TOO_LARGE(x)) { return 0; } else if (TOO_LARGE(y)) { return 0; } else { double value = 0; if (!(x == 0 && y == 0)) { value = atan2(y, x) * (180.0 / PI) * 16.0; } mp_right_type(q) = mp_given_knot; set_number_from_double(q->right_curl, value); if (mp_left_type(q) == mp_open_knot) { mp_left_type(q) = mp_given_knot; set_number_from_double(q->left_curl, value); } return 1; } } int mp_set_knotpair_directions (MP mp, mp_knot p, mp_knot q, double x1, double y1, double x2, double y2) { if (p == NULL || q == NULL) { return 0; } else if (mp_set_knot_direction(mp,p, x1, y1)) { return mp_set_knot_direction(mp,q, x2, y2); } else { return 0; } } static int path_needs_fixing(mp_knot source) { mp_knot sourcehead = source; do { source = source->next; } while (source && source != sourcehead); if (! source) { return 1; } else { return 0; } } int mp_solve_path (MP mp, mp_knot first) { if (first == NULL) { return 0; } else if (path_needs_fixing(first)) { return 0; } else { int saved_arith_error = mp->arith_error; int retval = 1; jmp_buf *saved_jump_buf = mp->jump_buf; mp->jump_buf = mp_memory_allocate(sizeof(jmp_buf)); if (mp->jump_buf == NULL || setjmp(*(mp->jump_buf)) != 0) { return 0; } else { mp->arith_error = 0; mp_make_choices(mp, first); if (mp->arith_error) { retval = 0; } mp->arith_error = saved_arith_error; mp_memory_free(mp->jump_buf); mp->jump_buf = saved_jump_buf; return retval; } } } void mp_free_path (MP mp, mp_knot p) { mp_toss_knot_list(mp, p); } double mp_number_as_double (MP mp, mp_number n) { (void) mp; return number_to_double(n); } static void mp_eval_cubic (MP mp, mp_number *r, mp_knot p, mp_knot q, int c, mp_number *t) { mp_number x1, x2, x3; new_number(x1); new_number(x2); new_number(x3); if (c == mp_x_code) { set_number_from_of_the_way(x1, *t, p->x_coord, p->right_x); set_number_from_of_the_way(x2, *t, p->right_x, q->left_x); set_number_from_of_the_way(x3, *t, q->left_x, q->x_coord); } else { set_number_from_of_the_way(x1, *t, p->y_coord, p->right_y); set_number_from_of_the_way(x2, *t, p->right_y, q->left_y); set_number_from_of_the_way(x3, *t, q->left_y, q->y_coord); } set_number_from_of_the_way(x1, *t, x1, x2); set_number_from_of_the_way(x2, *t, x2, x3); set_number_from_of_the_way(*r, *t, x1, x2); free_number(x1); free_number(x2); free_number(x3); } static void mp_bound_cubic (MP mp, mp_knot p, mp_knot q, int c) { int wavy; mp_number del1, del2, del3, del, dmax; mp_number t, tt; mp_number x; new_fraction(t); new_fraction(tt); if (c == mp_x_code) { new_number_clone(x, q->x_coord); } else { new_number_clone(x, q->y_coord); } new_number(del1); new_number(del2); new_number(del3); new_number(del); new_number(dmax); if (number_less(x, mp->bbmin[c])) { number_clone(mp->bbmin[c], x); } if (number_greater(x, mp->bbmax[c])) { number_clone(mp->bbmax[c], x); } wavy = 1; if (c == mp_x_code) { if (number_lessequal(mp->bbmin[c], p->right_x) && number_lessequal(p->right_x, mp->bbmax[c])) { if (number_lessequal(mp->bbmin[c], q->left_x) && number_lessequal(q->left_x, mp->bbmax[c])) { wavy = 0; } } } else { if (number_lessequal(mp->bbmin[c], p->right_y) && number_lessequal(p->right_y, mp->bbmax[c])) { if (number_lessequal(mp->bbmin[c], q->left_y) && number_lessequal(q->left_y, mp->bbmax[c])) { wavy = 0; } } } if (wavy) { if (c == mp_x_code) { set_number_from_subtraction(del1, p->right_x, p->x_coord); set_number_from_subtraction(del2, q->left_x, p->right_x); set_number_from_subtraction(del3, q->x_coord, q->left_x); } else { set_number_from_subtraction(del1, p->right_y, p->y_coord); set_number_from_subtraction(del2, q->left_y, p->right_y); set_number_from_subtraction(del3, q->y_coord, q->left_y); } if (number_nonzero(del1)) { number_clone(del, del1); } else if (number_nonzero(del2)) { number_clone(del, del2); } else { number_clone(del, del3); } if (number_nonzero(del)) { mp_number absval1; new_number(absval1); number_abs_clone(dmax, del1); number_abs_clone(absval1, del2); if (number_greater(absval1, dmax)) { number_clone(dmax, absval1); } number_abs_clone(absval1, del3); if (number_greater(absval1, dmax)) { number_clone(dmax, absval1); } while (number_less(dmax, fraction_half_t)) { number_double(dmax); number_double(del1); number_double(del2); number_double(del3); } free_number(absval1); } if (number_negative(del)) { number_negate(del1); number_negate(del2); number_negate(del3); } crossing_point(t, del1, del2, del3); if (number_less(t, fraction_one_t)) { { mp_eval_cubic(mp, &x, p, q, c, &t); if (number_less(x, mp->bbmin[c])) { number_clone(mp->bbmin[c], x); } if (number_greater(x, mp->bbmax[c])) { number_clone(mp->bbmax[c], x); } set_number_from_of_the_way(del2, t, del2, del3); if (number_positive(del2)) { set_number_to_zero(del2); } { mp_number arg2, arg3; new_number(arg2); new_number(arg3); number_negated_clone(arg2, del2); number_negated_clone(arg3, del3); crossing_point(tt, zero_t, arg2, arg3); free_number(arg2); free_number(arg3); } if (number_less(tt, fraction_one_t)) { mp_number arg; new_number(arg); set_number_from_of_the_way(arg, t, tt, fraction_one_t); mp_eval_cubic(mp, &x, p, q, c, &arg); free_number(arg); if (number_less(x, mp->bbmin[c])) { number_clone(mp->bbmin[c], x); } if (number_greater(x, mp->bbmax[c])) { number_clone(mp->bbmax[c], x); } } } } } free_number(del3); free_number(del2); free_number(del1); free_number(del); free_number(dmax); free_number(x); free_number(t); free_number(tt); } static void mp_path_bbox (MP mp, mp_knot h) { mp_knot p = h; number_clone(mp_minx, h->x_coord); number_clone(mp_miny, h->y_coord); number_clone(mp_maxx, mp_minx); number_clone(mp_maxy, mp_miny); do { if (mp_right_type(p) == mp_endpoint_knot) { return; } else { mp_knot q = mp_next_knot(p); mp_bound_cubic(mp, p, q, mp_x_code); mp_bound_cubic(mp, p, q, mp_y_code); p = q; } } while (p != h); } static void mp_path_xbox (MP mp, mp_knot h) { mp_knot p = h; number_clone(mp_minx, h->x_coord); number_clone(mp_maxx, mp_minx); set_number_to_zero(mp_miny); set_number_to_zero(mp_maxy); do { if (mp_right_type(p) == mp_endpoint_knot) { return; } else { mp_knot q = mp_next_knot(p); mp_bound_cubic(mp, p, q, mp_x_code); p = q; } } while (p != h); } static void mp_path_ybox (MP mp, mp_knot h) { mp_knot p = h; set_number_to_zero(mp_minx); set_number_to_zero(mp_maxx); number_clone(mp_miny, h->y_coord); number_clone(mp_maxy, mp_miny); do { if (mp_right_type(p) == mp_endpoint_knot) { return; } else { mp_knot q = mp_next_knot(p); mp_bound_cubic(mp, p, q, mp_y_code); p = q; } } while (p != h); } static void mp_arc_test (MP mp, mp_number *ret, mp_number *dx0, mp_number *dy0, mp_number *dx1, mp_number *dy1, mp_number *dx2, mp_number *dy2, mp_number *v0, mp_number *v02, mp_number *v2, mp_number *a_goal, mp_number *tol_orig ) { int simple; mp_number dx01, dy01, dx12, dy12, dx02, dy02; mp_number v002, v022; mp_number arc; mp_number arc1; mp_number simply; mp_number tol; new_number(arc ); new_number(arc1); new_number(dx01); new_number(dy01); new_number(dx12); new_number(dy12); new_number(dx02); new_number(dy02); new_number(v002); new_number(v022); new_number(simply); new_number_clone(tol, *tol_orig); set_number_half_from_addition(dx01, *dx0, *dx1); set_number_half_from_addition(dx12, *dx1, *dx2); set_number_half_from_addition(dx02, dx01, dx12); set_number_half_from_addition(dy01, *dy0, *dy1); set_number_half_from_addition(dy12, *dy1, *dy2); set_number_half_from_addition(dy02, dy01, dy12); { mp_number tmp, arg1, arg2 ; new_number(tmp); new_number(arg1); new_number(arg2); set_number_half_from_addition(arg1, *dx0, dx02); number_add(arg1, dx01); set_number_half_from_addition(arg2, *dy0, dy02); number_add(arg2, dy01); pyth_add(v002, arg1, arg2); set_number_half_from_addition(arg1, dx02, *dx2); number_add(arg1, dx12); set_number_half_from_addition(arg2, dy02, *dy2); number_add(arg2, dy12); pyth_add(v022, arg1, arg2); free_number(arg1); free_number(arg2); number_clone(tmp, *v02); number_add_scaled(tmp, 2); number_half(tmp); set_number_half_from_addition(arc1, *v0, tmp); number_subtract(arc1, v002); number_half(arc1); set_number_from_addition(arc1, v002, arc1); set_number_half_from_addition(arc, *v2, tmp); number_subtract(arc, v022); number_half(arc); set_number_from_addition(arc, v022, arc); set_number_to_inf(tmp); number_subtract(tmp,arc1); if (number_less(arc, tmp)) { free_number(tmp); number_add(arc, arc1); } else { free_number(tmp); mp->arith_error = 1; if (number_infinite(*a_goal)) { set_number_to_inf(*ret); } else { set_number_to_unity(*ret); number_double(*ret); number_negate(*ret); } goto DONE; } } simple = (number_nonnegative(*dx0) && number_nonnegative(*dx1) && number_nonnegative(*dx2)) || (number_nonpositive(*dx0) && number_nonpositive(*dx1) && number_nonpositive(*dx2)); if (simple) { simple = (number_nonnegative(*dy0) && number_nonnegative(*dy1) && number_nonnegative(*dy2)) || (number_nonpositive(*dy0) && number_nonpositive(*dy1) && number_nonpositive(*dy2)); } if (!simple) { simple = (number_greaterequal(*dx0, *dy0) && number_greaterequal(*dx1, *dy1) && number_greaterequal(*dx2, *dy2)) || (number_lessequal (*dx0, *dy0) && number_lessequal (*dx1, *dy1) && number_lessequal (*dx2, *dy2)); if (simple) { mp_number neg_dx0, neg_dx1, neg_dx2; new_number(neg_dx0); new_number(neg_dx1); new_number(neg_dx2); number_negated_clone(neg_dx0, *dx0); number_negated_clone(neg_dx1, *dx1); number_negated_clone(neg_dx2, *dx2); simple = (number_greaterequal(neg_dx0, *dy0) && number_greaterequal(neg_dx1, *dy1) && number_greaterequal(neg_dx2, *dy2)) || (number_lessequal (neg_dx0, *dy0) && number_lessequal (neg_dx1, *dy1) && number_lessequal (neg_dx2, *dy2)); free_number(neg_dx0); free_number(neg_dx1); free_number(neg_dx2); } } set_number_half_from_addition(simply, *v0, *v2); number_negate(simply); number_add(simply, arc); number_subtract(simply, *v02); number_abs(simply); if (simple && number_lessequal(simply, tol)) { if (number_less(arc, *a_goal)){ number_clone(*ret, arc); } else { mp_number tmp; mp_number tmp2; mp_number tmp3; mp_number tmp4; mp_number tmp5; new_number_clone(tmp, *v02); new_number(tmp2); new_number(tmp3); new_number(tmp4); new_number(tmp5); number_add_scaled(tmp, 2); number_half(tmp); number_half(tmp); if (number_lessequal(*a_goal, arc1)) { number_clone(tmp2, *v0); number_half(tmp2); set_number_from_subtraction(tmp3, arc1, tmp2); number_subtract(tmp3, tmp); mp_solve_rising_cubic(mp, &tmp5, &tmp2, &tmp3, &tmp, a_goal); number_half(tmp5); set_number_to_unity(tmp3); number_subtract(tmp5, tmp3); number_subtract(tmp5, tmp3); number_clone(*ret, tmp5); } else { number_clone(tmp2, *v2); number_half(tmp2); set_number_from_subtraction(tmp3, arc, arc1); number_subtract(tmp3, tmp); number_subtract(tmp3, tmp2); set_number_from_subtraction(tmp4, *a_goal, arc1); mp_solve_rising_cubic(mp, &tmp5, &tmp, &tmp3, &tmp2, &tmp4); number_half(tmp5); set_number_to_unity(tmp2); set_number_to_unity(tmp3); number_half(tmp2); number_subtract(tmp2, tmp3); number_subtract(tmp2, tmp3); set_number_from_addition(*ret, tmp2, tmp5); } free_number(tmp); free_number(tmp2); free_number(tmp3); free_number(tmp4); free_number(tmp5); } } else { mp_number a_new, a_aux; mp_number a, b; mp_number half_v02; new_number(a_new); new_number(a_aux); new_number(half_v02); set_number_to_inf(a_aux); number_subtract(a_aux, *a_goal); if (number_greater(*a_goal, a_aux)) { set_number_from_subtraction(a_aux, *a_goal, a_aux); set_number_to_inf(a_new); } else { set_number_from_addition(a_new, *a_goal, *a_goal); set_number_to_zero(a_aux); } { mp_number half_tol; new_number_clone(half_tol, tol); number_half(half_tol); number_add(tol, half_tol); free_number(half_tol); } number_clone(half_v02, *v02); number_half(half_v02); new_number(a); mp_arc_test(mp, &a, dx0, dy0, &dx01, &dy01, &dx02, &dy02, v0, &v002, &half_v02, &a_new, &tol); if (number_negative(a)) { set_number_to_unity(*ret); number_double(*ret); number_subtract(*ret, a); number_half(*ret); number_negate(*ret); } else { if (number_greater(a, a_aux)) { number_subtract(a_aux, a); number_add(a_new, a_aux); } new_number(b); mp_arc_test(mp, &b, &dx02, &dy02, &dx12, &dy12, dx2, dy2, &half_v02, &v022, v2, &a_new, &tol); if (number_negative(b)) { mp_number tmp ; new_number(tmp); number_negated_clone(tmp, b); number_half(tmp); number_negate(tmp); number_clone(*ret, tmp); set_number_to_unity(tmp); number_half(tmp); number_subtract(*ret, tmp); free_number(tmp); } else { set_number_from_subtraction(*ret, b, a); number_half(*ret); set_number_from_addition(*ret, a, *ret); } free_number(b); } free_number(half_v02); free_number(a_aux); free_number(a_new); free_number(a); } DONE: free_number(arc); free_number(arc1); free_number(dx01); free_number(dy01); free_number(dx12); free_number(dy12); free_number(dx02); free_number(dy02); free_number(v002); free_number(v022); free_number(simply); free_number(tol); } void mp_solve_rising_cubic (MP mp, mp_number *ret, mp_number *a_orig, mp_number *b_orig, mp_number *c_orig, mp_number *x_orig) { mp_number abc; mp_number a, b, c, x; mp_number ab, bc, ac; mp_number t; mp_number xx; mp_number neg_x; if (number_negative(*a_orig) || number_negative(*c_orig)) { mp_confusion(mp, "rising cubic"); } new_number(t); new_number(abc); new_number_clone(a, *a_orig); new_number_clone(b, *b_orig); new_number_clone(c, *c_orig); new_number_clone(x, *x_orig); new_number(ab); new_number(bc); new_number(ac); new_number(xx); new_number(neg_x); set_number_from_addition(abc, a, b); number_add(abc, c); if (number_nonpositive(x)) { set_number_to_zero(*ret); } else if (number_greaterequal(x, abc)) { set_number_to_unity(*ret); } else { number_clone(t, epsilon_t); while (number_greater(a, one_third_inf_t) || number_greater(b, one_third_inf_t) || number_greater(c, one_third_inf_t)) { number_half(a); number_half(b); number_half(c); number_half(x); } do { number_add(t, t); set_number_half_from_addition(ab, a, b); set_number_half_from_addition(bc, b, c); set_number_half_from_addition(ac, ab, bc); number_clone(xx,x); number_subtract(xx, a); number_subtract(xx, ab); number_subtract(xx, ac); number_negated_clone(neg_x, x); if (number_less(xx, neg_x)) { number_double(x); number_clone(b, ab); number_clone(c, ac); } else { number_add(x, xx); number_clone(a, ac); number_clone(b, bc); number_add(t, epsilon_t); } } while (number_less(t, unity_t)); set_number_from_subtraction(*ret, t, unity_t); } free_number(abc); free_number(t); free_number(a); free_number(b); free_number(c); free_number(ab); free_number(bc); free_number(ac); free_number(xx); free_number(x); free_number(neg_x); } static void mp_do_arc_test (MP mp, mp_number *ret, mp_number *dx0, mp_number *dy0, mp_number *dx1, mp_number *dy1, mp_number *dx2, mp_number *dy2, mp_number *a_goal ) { mp_number v0, v1, v2; mp_number v02; new_number(v0); new_number(v1); new_number(v2); pyth_add(v0, *dx0, *dy0); pyth_add(v1, *dx1, *dy1); pyth_add(v2, *dx2, *dy2); if ((number_greaterequal(v0, fraction_four_t)) || (number_greaterequal(v1, fraction_four_t)) || (number_greaterequal(v2, fraction_four_t))) { mp->arith_error = 1; if (number_infinite(*a_goal)) { set_number_to_inf(*ret); } else { set_number_to_unity(*ret); number_double(*ret); number_negate(*ret); } } else { mp_number arg1, arg2; new_number(v02); new_number(arg1); new_number(arg2); set_number_half_from_addition(arg1, *dx0, *dx2); number_add(arg1, *dx1); set_number_half_from_addition(arg2, *dy0, *dy2); number_add(arg2, *dy1); pyth_add(v02, arg1, arg2); free_number(arg1); free_number(arg2); mp_arc_test(mp, ret, dx0, dy0, dx1, dy1, dx2, dy2, &v0, &v02, &v2, a_goal, &arc_tol_k); free_number(v02); } free_number(v0); free_number(v1); free_number(v2); } static void mp_get_arc_length (MP mp, mp_number *ret, mp_knot h) { mp_number a; mp_number a_tot; mp_number arg1, arg2, arg3, arg4, arg5, arg6; mp_number arcgoal; mp_knot p = h; new_number(a_tot); new_number(arg1); new_number(arg2); new_number(arg3); new_number(arg4); new_number(arg5); new_number(arg6); new_number(a); new_number(arcgoal); set_number_to_inf(arcgoal); while (mp_right_type(p) != mp_endpoint_knot) { mp_knot q = mp_next_knot(p); set_number_from_subtraction(arg1, p->right_x, p->x_coord); set_number_from_subtraction(arg2, p->right_y, p->y_coord); set_number_from_subtraction(arg3, q->left_x, p->right_x); set_number_from_subtraction(arg4, q->left_y, p->right_y); set_number_from_subtraction(arg5, q->x_coord, q->left_x); set_number_from_subtraction(arg6, q->y_coord, q->left_y); mp_do_arc_test(mp, &a, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arcgoal); slow_add(a_tot, a, a_tot); if (q == h) { break; } else { p = q; } } free_number(arcgoal); free_number(a); free_number(arg1); free_number(arg2); free_number(arg3); free_number(arg4); free_number(arg5); free_number(arg6); check_arith(); number_clone(*ret, a_tot); free_number(a_tot); } static void mp_get_subarc_length (MP mp, mp_number *ret, mp_knot h, mp_number *first, mp_number *last) { mp_number a; mp_number a_tot, a_cnt; mp_number arg1, arg2, arg3, arg4, arg5, arg6; mp_number arcgoal; mp_knot p = h; new_number(a_tot); new_number(a_cnt); new_number(arg1); new_number(arg2); new_number(arg3); new_number(arg4); new_number(arg5); new_number(arg6); new_number(a); new_number(arcgoal); set_number_to_inf(arcgoal); while (mp_right_type(p) != mp_endpoint_knot) { mp_knot q = mp_next_knot(p); if (number_greaterequal(a_cnt, *last)) { break; } else if (number_greaterequal(a_cnt, *first)) { set_number_from_subtraction(arg1, p->right_x, p->x_coord); set_number_from_subtraction(arg2, p->right_y, p->y_coord); set_number_from_subtraction(arg3, q->left_x, p->right_x); set_number_from_subtraction(arg4, q->left_y, p->right_y); set_number_from_subtraction(arg5, q->x_coord, q->left_x); set_number_from_subtraction(arg6, q->y_coord, q->left_y); mp_do_arc_test(mp, &a, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arcgoal); slow_add(a_tot, a, a_tot); } if (q == h) { break; } else { p = q; number_add(a_cnt, unity_t); } } free_number(arcgoal); free_number(a); free_number(arg1); free_number(arg2); free_number(arg3); free_number(arg4); free_number(arg5); free_number(arg6); check_arith(); number_clone(*ret, a_tot); free_number(a_cnt); free_number(a_tot); } static mp_knot mp_get_arc_time(MP mp, mp_number *ret, mp_knot h, mp_number *arc0_orig, int local) { if (number_negative(*arc0_orig)) { if (mp_left_type(h) == mp_endpoint_knot) { set_number_to_zero(*ret); } else { mp_number neg_arc0; mp_knot p = mp_htap_ypoc(mp, h); new_number(neg_arc0); number_negated_clone(neg_arc0, *arc0_orig); mp_get_arc_time(mp, ret, p, &neg_arc0, 0); number_negate(*ret); mp_toss_knot_list(mp, p); free_number(neg_arc0); } check_arith(); } else { mp_knot p, q, k; mp_number t_tot; mp_number t; mp_number arc, arc0; mp_number arg1, arg2, arg3, arg4, arg5, arg6; new_number(t_tot); new_number_clone(arc0, *arc0_orig); if (number_infinite(arc0)) { number_add_scaled(arc0, -1); } new_number_clone(arc, arc0); p = h; k = h; new_number(arg1); new_number(arg2); new_number(arg3); new_number(arg4); new_number(arg5); new_number(arg6); new_number(t); while ((mp_right_type(p) != mp_endpoint_knot) && number_positive(arc)) { k = p; q = mp_next_knot(p); set_number_from_subtraction(arg1, p->right_x, p->x_coord); set_number_from_subtraction(arg2, p->right_y, p->y_coord); set_number_from_subtraction(arg3, q->left_x, p->right_x); set_number_from_subtraction(arg4, q->left_y, p->right_y); set_number_from_subtraction(arg5, q->x_coord, q->left_x); set_number_from_subtraction(arg6, q->y_coord, q->left_y); mp_do_arc_test(mp, &t, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arc); if (number_negative(t)) { number_add(t_tot, t); number_add(t_tot, two_t); set_number_to_zero(arc); } else { number_add(t_tot, unity_t); number_subtract(arc, t); } if (q == h) { if (number_positive(arc)) { mp_number n, n1, d1, v1; new_number(n); new_number(n1); new_number(d1); new_number(v1); set_number_from_subtraction(d1, arc0, arc); set_number_from_div(n1, arc, d1); number_clone(n, n1); set_number_from_mul(n1, n1, d1); number_subtract(arc, n1); number_clone(d1, inf_t); number_clone(v1, n); number_add(v1, epsilon_t); set_number_from_div(d1, d1, v1); if (number_greater(t_tot, d1)) { mp->arith_error = 1; check_arith(); set_number_to_inf(*ret); free_number(n); free_number(n1); free_number(d1); free_number(v1); goto RETURN; } set_number_from_mul(t_tot, t_tot, v1); free_number(n); free_number(n1); free_number(d1); free_number(v1); } } p = q; } check_arith(); if (local) { number_add(t, two_t); number_clone(*ret, t); } else { number_clone(*ret, t_tot); } h = k; RETURN: free_number(t_tot); free_number(t); free_number(arc); free_number(arc0); free_number(arg1); free_number(arg2); free_number(arg3); free_number(arg4); free_number(arg5); free_number(arg6); } return h; } static mp_knot mp_make_pen (MP mp, mp_knot h, int need_hull) { mp_knot q = h; do { mp_knot p = q; q = mp_next_knot(q); mp_prev_knot(q) = p; } while (q != h); if (need_hull) { h = mp_convex_hull(mp, h); if (mp_pen_is_elliptical(h)) { number_clone(h->left_x, h->x_coord); number_clone(h->left_y, h->y_coord); number_clone(h->right_x, h->x_coord); number_clone(h->right_y, h->y_coord); } } return h; } static mp_knot mp_get_pen_circle (MP mp, mp_number *diam) { mp_knot h = mp_new_knot(mp); mp_next_knot(h) = h; mp_prev_knot(h) = h; mp_originator(h) = mp_program_code; mp_knotstate(h) = mp_regular_knot; set_number_to_zero(h->x_coord); set_number_to_zero(h->y_coord); number_clone(h->left_x, *diam); set_number_to_zero(h->left_y); set_number_to_zero(h->right_x); number_clone(h->right_y, *diam); return h; } void mp_pr_pen (MP mp, mp_knot h) { if (mp_pen_is_elliptical(h)) { { mp_number v1; new_number(v1); mp_print_str(mp, "pencircle transformed ("); print_number(h->x_coord); mp_print_chr(mp, ','); print_number(h->y_coord); mp_print_chr(mp, ','); set_number_from_subtraction(v1, h->left_x, h->x_coord); print_number(v1); mp_print_chr(mp, ','); set_number_from_subtraction(v1, h->right_x, h->x_coord); print_number(v1); mp_print_chr(mp, ','); set_number_from_subtraction(v1, h->left_y, h->y_coord); print_number(v1); mp_print_chr(mp, ','); set_number_from_subtraction(v1, h->right_y, h->y_coord); print_number(v1); mp_print_chr(mp, ')'); free_number(v1); } } else { mp_knot p = h; do { mp_knot q = mp_next_knot(p); mp_print_two(mp, &(p->x_coord), &(p->y_coord)); mp_print_nl(mp, " .. "); if ((q == NULL) || (mp_prev_knot(q) != p)) { mp_print_nl(mp, "???"); return; } p = q; } while (p != h); mp_print_str(mp, "cycle"); } } void mp_print_pen (MP mp, mp_knot h, const char *s, int nuline) { mp_print_diagnostic(mp, "Pen", s, nuline); mp_print_ln(mp); mp_pr_pen(mp, h); mp_end_diagnostic(mp, 1); } static void mp_make_path (MP mp, mp_knot h) { if (mp_pen_is_elliptical(h)) { mp_knot p; mp_number center_x, center_y; mp_number width_x, width_y; mp_number height_x, height_y; mp_number dx, dy; new_number(width_x); new_number(width_y); new_number(height_x); new_number(height_y); new_number(dx); new_number(dy); new_number_clone(center_x, h->x_coord); new_number_clone(center_y, h->y_coord); set_number_from_subtraction(width_x, h->left_x, center_x); set_number_from_subtraction(width_y, h->left_y, center_y); set_number_from_subtraction(height_x, h->right_x, center_x); set_number_from_subtraction(height_y, h->right_y, center_y); p = h; for (int k = 0; k <= 7; k++) { int kk = (k + 6) % 8; mp_number r1, r2; new_fraction(r1); new_fraction(r2); take_fraction(r1, mp->half_cos[k], width_x); take_fraction(r2, mp->half_cos[kk], height_x); number_add(r1, r2); set_number_from_addition(p->x_coord, center_x, r1); take_fraction(r1, mp->half_cos[k], width_y); take_fraction(r2, mp->half_cos[kk], height_y); number_add(r1, r2); set_number_from_addition(p->y_coord, center_y, r1); take_fraction(r1, mp->d_cos[kk], width_x); take_fraction(r2, mp->d_cos[k], height_x); number_negated_clone(dx, r1); number_add(dx, r2); take_fraction(r1, mp->d_cos[kk], width_y); take_fraction(r2, mp->d_cos[k], height_y); number_negated_clone(dy, r1); number_add(dy, r2); set_number_from_addition(p->right_x, p->x_coord, dx); set_number_from_addition(p->right_y, p->y_coord, dy); set_number_from_subtraction(p->left_x, p->x_coord, dx); set_number_from_subtraction(p->left_y, p->y_coord, dy); free_number(r1); free_number(r2); mp_left_type(p) = mp_explicit_knot; mp_right_type(p) = mp_explicit_knot; mp_originator(p) = mp_program_code; mp_knotstate(p) = mp_regular_knot; if (k == 7) { mp_prev_knot(h) = p; mp_next_knot(p) = h; } else { mp_knot k = mp_new_knot(mp); mp_prev_knot(k) = p; mp_next_knot(p) = k; } p = mp_next_knot(p); } free_number(dx); free_number(dy); free_number(center_x); free_number(center_y); free_number(width_x); free_number(width_y); free_number(height_x); free_number(height_y); } else { mp_knot p = h; do { mp_left_type(p) = mp_explicit_knot; mp_right_type(p) = mp_explicit_knot; number_clone(p->left_x, p->x_coord); number_clone(p->left_y, p->y_coord); number_clone(p->right_x, p->x_coord); number_clone(p->right_y, p->y_coord); p = mp_next_knot(p); } while (p != h); } } mp_knot mp_convex_hull (MP mp, mp_knot h) { if (mp_pen_is_elliptical(h)) { return h; } else { mp_knot l, r; mp_knot p, q; mp_knot s; mp_number dx, dy; new_number(dx); new_number(dy); l = h; p = mp_next_knot(h); while (p != h) { if (number_lessequal(p->x_coord, l->x_coord) && (number_less(p->x_coord, l->x_coord) || number_less(p->y_coord, l->y_coord))) { l = p; } p = mp_next_knot(p); } r = h; p = mp_next_knot(h); while (p != h) { if (number_greaterequal(p->x_coord, r->x_coord) && (number_greater(p->x_coord, r->x_coord) || number_greater(p->y_coord, r->y_coord))) { r = p; } p = mp_next_knot(p); } if (l != r) { mp_knot s = mp_next_knot(r); { mp_number arg1, arg2; new_number(arg1); new_number(arg2); set_number_from_subtraction(dx, r->x_coord, l->x_coord); set_number_from_subtraction(dy, r->y_coord, l->y_coord); p = mp_next_knot(l); while (p != r) { q = mp_next_knot(p); set_number_from_subtraction(arg1, p->y_coord, l->y_coord); set_number_from_subtraction(arg2, p->x_coord, l->x_coord); if (ab_vs_cd(dx, arg1, dy, arg2) > 0) { mp_move_knot(mp, p, r); } p = q; } free_number(arg1); free_number(arg2); } { mp_number arg1, arg2; new_number(arg1); new_number(arg2); p = s; while (p != l) { q = mp_next_knot(p); set_number_from_subtraction(arg1, p->y_coord, l->y_coord); set_number_from_subtraction(arg2, p->x_coord, l->x_coord); if (ab_vs_cd(dx, arg1, dy, arg2) < 0) { mp_move_knot(mp, p, l); } p = q; } free_number(arg1); free_number(arg2); } p = mp_next_knot(l); while (p != r) { q = mp_prev_knot(p); while (number_greater(q->x_coord, p->x_coord)) { q = mp_prev_knot(q); } while (number_equal(q->x_coord, p->x_coord)) { if (number_greater(q->y_coord, p->y_coord)) { q = mp_prev_knot(q); } else { break; } } if (q == mp_prev_knot(p)) { p = mp_next_knot(p); } else { p = mp_next_knot(p); mp_move_knot(mp, mp_prev_knot(p), q); } } p = mp_next_knot(r); while (p != l) { q = mp_prev_knot(p); while (number_less(q->x_coord, p->x_coord)) { q = mp_prev_knot(q); } while (number_equal(q->x_coord, p->x_coord)) { if (number_less(q->y_coord, p->y_coord)) { q = mp_prev_knot(q); } else { break; } } if (q == mp_prev_knot(p)) { p = mp_next_knot(p); } else { p = mp_next_knot(p); mp_move_knot(mp, mp_prev_knot(p), q); } } } if (l != mp_next_knot(l)) { mp_number arg1, arg2; new_number(arg1); new_number(arg2); p = l; q = mp_next_knot(l); while (1) { set_number_from_subtraction(dx, q->x_coord, p->x_coord); set_number_from_subtraction(dy, q->y_coord, p->y_coord); p = q; q = mp_next_knot(q); if (p == l) { break; } else if (p != r) { set_number_from_subtraction(arg1, q->y_coord, p->y_coord); set_number_from_subtraction(arg2, q->x_coord, p->x_coord); if (ab_vs_cd(dx, arg1, dy, arg2) <= 0) { s = mp_prev_knot(p); mp_memory_free(p); mp_next_knot(s) = q; mp_prev_knot(q) = s; if (s == l) { p = s; } else { p = mp_prev_knot(s); q = s; } } } } free_number(arg1); free_number(arg2); } free_number(dx); free_number(dy); return l; } } void mp_simplify_path (MP mp, mp_knot h) { mp_knot p = h; (void) mp; do { p->left_x = p->x_coord; p->left_y = p->y_coord; p->right_x = p->x_coord; p->right_y = p->y_coord; p = mp_next_knot(p); } while (p != h); } void mp_move_knot (MP mp, mp_knot p, mp_knot q) { (void) mp; mp_next_knot(mp_prev_knot(p)) = mp_next_knot(p); mp_prev_knot(mp_next_knot(p)) = mp_prev_knot(p); mp_prev_knot(p) = q; mp_next_knot(p) = mp_next_knot(q); mp_next_knot(q) = p; mp_prev_knot(mp_next_knot(p)) = p; } static void mp_find_offset (MP mp, mp_number *x_orig, mp_number *y_orig, mp_knot h) { if (mp_pen_is_elliptical(h)) { mp_number xx, yy; mp_number wx, wy, hx, hy; mp_number d; new_fraction(xx); new_fraction(yy); new_number(wx); new_number(wy); new_number(hx); new_number(hy); new_fraction(d); if (number_zero(*x_orig) && number_zero(*y_orig)) { number_clone(mp->cur_x, h->x_coord); number_clone(mp->cur_y, h->y_coord); } else { mp_number x, y, abs_x, abs_y; new_number_clone(x, *x_orig); new_number_clone(y, *y_orig); set_number_from_subtraction(wx, h->left_x, h->x_coord); set_number_from_subtraction(wy, h->left_y, h->y_coord); set_number_from_subtraction(hx, h->right_x, h->x_coord); set_number_from_subtraction(hy, h->right_y, h->y_coord); new_number_abs(abs_x, x); new_number_abs(abs_y, y); while (number_less(abs_x, fraction_half_t) && number_less(abs_y, fraction_half_t)) { number_double(x); number_double(y); number_abs_clone(abs_x, x); number_abs_clone(abs_y, y); } { mp_number r1, r2, arg1; new_number(arg1); new_fraction(r1); new_fraction(r2); take_fraction(r1, x, hy); number_negated_clone(arg1, hx); take_fraction(r2, y, arg1); number_add(r1, r2); number_negate(r1); number_clone(yy, r1); number_negated_clone(arg1, wy); take_fraction(r1, x, arg1); take_fraction(r2, y, wx); number_add(r1, r2); number_clone(xx, r1); free_number(arg1); free_number(r1); free_number(r2); } pyth_add(d, xx, yy); if (number_positive(d)) { mp_number ret; new_fraction(ret); make_fraction(ret, xx, d); number_half(ret); number_clone(xx, ret); make_fraction(ret, yy, d); number_half(ret); number_clone(yy, ret); free_number(ret); } { mp_number r1, r2; new_fraction(r1); new_fraction(r2); take_fraction(r1, xx, wx); take_fraction(r2, yy, hx); number_add(r1, r2); set_number_from_addition(mp->cur_x, h->x_coord, r1); take_fraction(r1, xx, wy); take_fraction(r2, yy, hy); number_add(r1, r2); set_number_from_addition(mp->cur_y, h->y_coord, r1); free_number(r1); free_number(r2); } free_number(abs_x); free_number(abs_y); free_number(x); free_number(y); } free_number(xx); free_number(yy); free_number(wx); free_number(wy); free_number(hx); free_number(hy); free_number(d); } else { mp_knot p, q; mp_number arg1, arg2; new_number(arg1); new_number(arg2); q = h; do { p = q; q = mp_next_knot(q); set_number_from_subtraction(arg1, q->x_coord, p->x_coord); set_number_from_subtraction(arg2, q->y_coord, p->y_coord); } while (ab_vs_cd(arg1, *y_orig, arg2, *x_orig) < 0); do { p = q; q = mp_next_knot(q); set_number_from_subtraction(arg1, q->x_coord, p->x_coord); set_number_from_subtraction(arg2, q->y_coord, p->y_coord); } while (ab_vs_cd(arg1, *y_orig, arg2, *x_orig) > 0); number_clone(mp->cur_x, p->x_coord); number_clone(mp->cur_y, p->y_coord); free_number(arg1); free_number(arg2); } } static void mp_pen_bbox (MP mp, mp_knot h) { if (mp_pen_is_elliptical(h)) { mp_number arg1, arg2; new_number(arg1); new_fraction(arg2); number_clone(arg2, fraction_one_t); mp_find_offset(mp, &arg1, &arg2, h); number_clone(mp_maxx, mp->cur_x); number_clone(mp_minx, h->x_coord); number_double(mp_minx); number_subtract(mp_minx, mp->cur_x); number_negate(arg2); mp_find_offset(mp, &arg2, &arg1, h); number_clone(mp_maxy, mp->cur_y); number_clone(mp_miny, h->y_coord); number_double(mp_miny); number_subtract(mp_miny, mp->cur_y); free_number(arg1); free_number(arg2); } else { mp_knot p = mp_next_knot(h); number_clone(mp_minx, h->x_coord); number_clone(mp_maxx, mp_minx); number_clone(mp_miny, h->y_coord); number_clone(mp_maxy, mp_miny); while (p != h) { if (number_less(p->x_coord, mp_minx)) { number_clone(mp_minx, p->x_coord); } if (number_less(p->y_coord, mp_miny)) { number_clone(mp_miny, p->y_coord); } if (number_greater(p->x_coord, mp_maxx)) { number_clone(mp_maxx, p->x_coord); } if (number_greater(p->y_coord, mp_maxy)) { number_clone(mp_maxy, p->y_coord); } p = mp_next_knot(p); } } } static mp_node mp_new_shape_node (MP mp, mp_knot p, int type) { mp_shape_node t = mp_allocate_node(mp, sizeof(mp_shape_node_data)); t->type = type; mp_path_ptr(t) = p; mp_pen_ptr(t) = NULL; mp_dash_ptr(t) = NULL; new_number(t->red); new_number(t->green); new_number(t->blue); new_number(t->black); new_number(t->miterlimit); new_number(t->dashscale); set_number_to_unity(t->dashscale); mp_color_model(t) = mp_uninitialized_model; mp_pen_type(t) = 0; mp_pre_script(t) = NULL; mp_post_script(t) = NULL; if (number_greater(internal_value(mp_linejoin_internal), unity_t)) { t->linejoin = mp_beveled_linejoin_code; } else if (number_positive(internal_value(mp_linejoin_internal))) { t->linejoin = mp_rounded_linejoin_code; } else { t->linejoin = mp_mitered_linejoin_code; } t->stacking = round_unscaled(internal_value(mp_stacking_internal)); if (number_less(internal_value(mp_miterlimit_internal), unity_t)) { set_number_to_unity(t->miterlimit); } else { number_clone(t->miterlimit, internal_value(mp_miterlimit_internal)); } if (number_greater(internal_value(mp_linecap_internal), unity_t)) { t->linecap = mp_squared_linecap_code; } else if (number_positive(internal_value(mp_linecap_internal))) { t->linecap = mp_rounded_linecap_code; } else { t->linecap = mp_butt_linecap_code; } return (mp_node) t; } static mp_edge_header_node mp_free_shape_node (MP mp, mp_shape_node p) { mp_edge_header_node e = NULL; mp_toss_knot_list(mp, mp_path_ptr(p)); if (mp_pen_ptr(p) != NULL) { mp_toss_knot_list(mp, mp_pen_ptr(p)); } if (mp_pre_script(p) != NULL) { delete_str_ref(mp_pre_script(p)); } if (mp_post_script(p) != NULL) { delete_str_ref(mp_post_script(p)); } e = (mp_edge_header_node) mp_dash_ptr(p); free_number(p->red); free_number(p->green); free_number(p->blue); free_number(p->black); free_number(p->miterlimit); free_number(p->dashscale); mp_free_node(mp, (mp_node) p, sizeof(mp_shape_node_data)); return e ; } void mp_sqrt_det (MP mp, mp_number *ret, mp_number *a_orig, mp_number *b_orig, mp_number *c_orig, mp_number *d_orig) { mp_number a, b, c, d; mp_number maxabs; unsigned s = 64; mp_number tmp; new_number_clone(a, *a_orig); new_number_clone(b, *b_orig); new_number_clone(c, *c_orig); new_number_clone(d, *d_orig); new_number_abs(maxabs, a); new_number_abs(tmp, b); if (number_greater(tmp, maxabs)) { number_clone(maxabs, tmp); } number_abs_clone(tmp, c); if (number_greater(tmp, maxabs)) { number_clone(maxabs, tmp); } number_abs_clone(tmp, d); if (number_greater(tmp, maxabs)) { number_clone(maxabs, tmp); } free_number(tmp); while ((number_less(maxabs, fraction_one_t)) && (s > 1)) { number_double(a); number_double(b); number_double(c); number_double(d); number_double(maxabs); s = s/2; } { mp_number r1, r2; new_fraction(r1); new_fraction(r2); take_fraction(r1, a, d); take_fraction(r2, b, c); number_subtract(r1, r2); number_abs(r1); square_rt(*ret, r1); number_multiply_int(*ret, s); free_number(r1); free_number(r2); } free_number(a); free_number(b); free_number(c); free_number(d); free_number(maxabs); } static void mp_get_pen_scale (MP mp, mp_number *ret, mp_knot p) { if (p == NULL) { set_number_to_zero(*ret); } else { mp_number a, b, c, d; new_number(a); new_number(b); new_number(c); new_number(d); set_number_from_subtraction(a, p->left_x, p->x_coord); set_number_from_subtraction(b, p->right_x, p->x_coord); set_number_from_subtraction(c, p->left_y, p->y_coord); set_number_from_subtraction(d, p->right_y, p->y_coord); mp_sqrt_det(mp, ret, &a, &b, &c, &d); free_number(a); free_number(b); free_number(c); free_number(d); } } static mp_node mp_new_bounds_node (MP mp, mp_knot p, int c) { switch (c) { case mp_start_clip_node_type: case mp_start_group_node_type: case mp_start_bounds_node_type: { mp_start_node t = (mp_start_node) mp_allocate_node(mp, sizeof(mp_start_node_data)); t->type = c; t->path = p; t->stacking = round_unscaled(internal_value(mp_stacking_internal)); mp_pre_script(t) = NULL; mp_post_script(t) = NULL; return (mp_node) t; } break; case mp_stop_clip_node_type: case mp_stop_group_node_type: case mp_stop_bounds_node_type: { mp_stop_node t = (mp_stop_node) mp_allocate_node(mp, sizeof(mp_stop_node_data)); t->type = c; t->stacking = round_unscaled(internal_value(mp_stacking_internal)); return (mp_node) t; } break; default: break; } return NULL; } static void mp_free_start_node (MP mp, mp_start_node p) { mp_toss_knot_list(mp, mp_path_ptr(p)); if (mp_pre_script(p) != NULL) { delete_str_ref(mp_pre_script(p)); } if (mp_post_script(p) != NULL) { delete_str_ref(mp_post_script(p)); } mp_free_node(mp, (mp_node) p, sizeof(mp_start_node_data)); } static void mp_free_stop_node (MP mp, mp_stop_node p) { mp_free_node(mp, (mp_node) p, sizeof(mp_stop_node_data)); } static mp_dash_node mp_get_dash_node (MP mp) { mp_dash_node p = (mp_dash_node) mp_allocate_node(mp, sizeof(mp_dash_node_data)); p->hasnumber = 0; new_number(p->start_x); new_number(p->stop_x); new_number(p->dash_y); p->type = mp_dash_node_type; return p; } static void mp_init_bbox (MP mp, mp_edge_header_node h) { (void) mp; mp_bblast(h) = mp_edge_list(h); h->bbtype = mp_no_bounds_code; set_number_to_inf(h->minx); set_number_to_inf(h->miny); set_number_to_negative_inf(h->maxx); set_number_to_negative_inf(h->maxy); } static mp_edge_header_node mp_get_edge_header_node (MP mp) { mp_edge_header_node p = (mp_edge_header_node) mp_allocate_node(mp, sizeof(mp_edge_header_node_data)); p->type = mp_edge_header_node_type; new_number(p->start_x); new_number(p->stop_x); new_number(p->dash_y); new_number(p->minx); new_number(p->miny); new_number(p->maxx); new_number(p->maxy); p->list = mp_new_token_node(mp); return p; } static void mp_init_edges (MP mp, mp_edge_header_node h) { mp_set_dash_list(h, mp->null_dash); mp_obj_tail(h) = mp_edge_list(h); mp_edge_list(h)->link = NULL; mp_edge_ref_count(h) = 0; mp_init_bbox(mp, h); } void mp_toss_edges (MP mp, mp_edge_header_node h) { mp_node q; mp_edge_header_node r; mp_flush_dash_list(mp, h); q = mp_edge_list(h)->link; while (q != NULL) { mp_node p = q; q = q->link; r = mp_toss_gr_object(mp, p); if (r != NULL) { mp_delete_edge_ref(mp, r); } } free_number(h->start_x); free_number(h->stop_x); free_number(h->dash_y); free_number(h->minx); free_number(h->miny); free_number(h->maxx); free_number(h->maxy); mp_free_token_node(mp, h->list); mp_free_node(mp, (mp_node) h, sizeof(mp_edge_header_node_data)); } void mp_flush_dash_list (MP mp, mp_edge_header_node h) { mp_dash_node q = mp_get_dash_list(h); while (q != mp->null_dash) { mp_dash_node p = q; q = (mp_dash_node) q->link; mp_free_node(mp, (mp_node) p, sizeof(mp_dash_node_data)); } mp_set_dash_list(h, mp->null_dash); } mp_edge_header_node mp_toss_gr_object (MP mp, mp_node p) { switch (p->type) { case mp_fill_node_type: case mp_stroked_node_type: return mp_free_shape_node(mp, (mp_shape_node) p); case mp_start_clip_node_type: case mp_start_group_node_type: case mp_start_bounds_node_type: mp_free_start_node(mp, (mp_start_node) p); return NULL; case mp_stop_clip_node_type: case mp_stop_group_node_type: case mp_stop_bounds_node_type: mp_free_stop_node(mp, (mp_stop_node) p); return NULL; default: return NULL; } } static mp_edge_header_node mp_private_edges (MP mp, mp_edge_header_node h) { if (mp_edge_ref_count(h) == 0) { return h; } else { mp_edge_header_node hh; mp_dash_node p, pp; mp_edge_ref_count(h) -= 1; hh = (mp_edge_header_node) mp_copy_objects (mp, mp_edge_list(h)->link, NULL); pp = (mp_dash_node) hh; p = mp_get_dash_list(h); while ((p != mp->null_dash)) { pp->link = (mp_node) mp_get_dash_node(mp); pp = (mp_dash_node) pp->link; number_clone(pp->start_x, p->start_x); number_clone(pp->stop_x, p->stop_x); p = (mp_dash_node) p->link; } pp->link = (mp_node) mp->null_dash; number_clone(hh->dash_y, h->dash_y); number_clone(hh->minx, h->minx); number_clone(hh->miny, h->miny); number_clone(hh->maxx, h->maxx); number_clone(hh->maxy, h->maxy); hh->bbtype = h->bbtype; p = (mp_dash_node) mp_edge_list(h); pp = (mp_dash_node) mp_edge_list(hh); while ((p != (mp_dash_node) mp_bblast(h))) { if (p == NULL) { mp_confusion(mp, "boundingbox last"); } else { p = (mp_dash_node) p->link; pp = (mp_dash_node) pp->link; } } mp_bblast(hh) = (mp_node) pp; return hh; } } static mp_dash_object *mp_export_dashes (MP mp, mp_shape_node q, mp_number *w) { mp_dash_node h = (mp_dash_node) mp_dash_ptr(q); if (h == NULL || mp_get_dash_list(h) == mp->null_dash) { return NULL; } else { mp_dash_object *d; mp_dash_node p; mp_number scf; mp_number dashoff; double *dashes = NULL; int num_dashes = 1; new_number(scf); p = mp_get_dash_list(h); mp_get_pen_scale(mp, &scf, mp_pen_ptr(q)); if (number_zero(scf)) { if (number_zero(*w)) { number_clone(scf, q->dashscale); } else { free_number(scf); return NULL; } } else { mp_number ret; new_number(ret); make_scaled(ret, *w, scf); take_scaled(scf, ret, q->dashscale); free_number(ret); } number_clone(*w, scf); d = mp_allocate_dash(mp); set_number_from_addition(mp->null_dash->start_x, p->start_x, h->dash_y); { mp_number ret, arg1; new_number(ret); new_number(arg1); new_number(dashoff); while (p != mp->null_dash) { dashes = mp_memory_reallocate(dashes, (size_t) (num_dashes + 2) * sizeof(double)); set_number_from_subtraction(arg1, p->stop_x, p->start_x); take_scaled(ret, arg1, scf); dashes[(num_dashes - 1)] = number_to_double(ret); set_number_from_subtraction(arg1, ((mp_dash_node) p->link)->start_x, p->stop_x); take_scaled(ret, arg1, scf); dashes[(num_dashes)] = number_to_double(ret); dashes[(num_dashes + 1)] = -1.0; num_dashes += 2; p = (mp_dash_node) p->link; } d->array = dashes; mp_dash_offset(mp, &dashoff, h); take_scaled(ret, dashoff, scf); d->offset = number_to_double(ret); free_number(ret); free_number(arg1); } free_number(dashoff); free_number(scf); return d; } } mp_edge_header_node mp_copy_objects (MP mp, mp_node p, mp_node q) { mp_node pp; int k = 0; mp_edge_header_node hh = mp_get_edge_header_node(mp); mp_set_dash_list(hh, mp->null_dash); mp_edge_ref_count(hh) = 0; pp = mp_edge_list(hh); while (p != q) { { switch (p->type) { case mp_fill_node_type: case mp_stroked_node_type: k = sizeof(mp_shape_node_data); break; case mp_start_clip_node_type: case mp_start_group_node_type: case mp_start_bounds_node_type: k = sizeof(mp_start_node_data); break; case mp_stop_clip_node_type: case mp_stop_group_node_type: case mp_stop_bounds_node_type: k = sizeof(mp_stop_node_data); break; default: break; } pp->link = mp_allocate_node(mp, (size_t) k); pp = pp->link; memcpy(pp, p, (size_t) k); pp->link = NULL; switch (p->type) { case mp_fill_node_type: case mp_stroked_node_type: { mp_shape_node tt = (mp_shape_node) pp; mp_shape_node t = (mp_shape_node) p; new_number_clone(tt->red, t->red); new_number_clone(tt->green, t->green); new_number_clone(tt->blue, t->blue); new_number_clone(tt->black, t->black); new_number_clone(tt->miterlimit, t->miterlimit); new_number_clone(tt->dashscale, t->dashscale); mp_path_ptr(tt) = mp_copy_path(mp, mp_path_ptr(t)); if (mp_pre_script(p) != NULL) { add_str_ref(mp_pre_script(p)); } if (mp_post_script(p) != NULL) { add_str_ref(mp_post_script(p)); } if (mp_pen_ptr(t) != NULL) { mp_pen_ptr(tt) = mp_copy_pen(mp, mp_pen_ptr(t)); } if (mp_dash_ptr(p) != NULL) { mp_add_edge_ref(mp, mp_dash_ptr(pp)); } } break; case mp_start_clip_node_type: case mp_start_group_node_type: case mp_start_bounds_node_type: { mp_start_node tt = (mp_start_node) pp; mp_start_node t = (mp_start_node) p; mp_path_ptr(tt) = mp_copy_path(mp, mp_path_ptr(t)); if (mp_pre_script(p) != NULL) { add_str_ref(mp_pre_script(p)); } if (mp_post_script(p) != NULL) { add_str_ref(mp_post_script(p)); } } break; case mp_stop_clip_node_type: case mp_stop_group_node_type: case mp_stop_bounds_node_type: break; default: break; } p = p->link; } } mp_obj_tail(hh) = pp; pp->link = NULL; return hh; } static mp_node mp_skip_1component (MP mp, mp_node p) { int lev = 0; (void) mp; do { if (mp_is_start_or_stop (p)) { if (mp_is_stop(p)) { --lev; } else { ++lev; } } p = p->link; } while (lev != 0); return p; } void mp_print_edges (MP mp, mp_node h, const char *s, int nuline) { mp_node p = mp_edge_list(h); mp_number scf; new_number(scf); mp_print_diagnostic(mp, "Edge structure", s, nuline); while (p->link != NULL) { p = p->link; mp_print_ln(mp); switch (p->type) { case mp_fill_node_type: mp_print_str(mp, "Filled contour "); mp_print_obj_color (mp, p); mp_print_chr(mp, ':'); mp_print_ln(mp); mp_pr_path(mp, mp_path_ptr((mp_shape_node) p)); mp_print_ln(mp); if ((mp_pen_ptr((mp_shape_node) p) != NULL)) { switch (((mp_shape_node) p)->linejoin) { case mp_mitered_linejoin_code: mp_print_str(mp, "mitered joins limited "); print_number(((mp_shape_node) p)->miterlimit); break; case mp_rounded_linejoin_code: mp_print_str(mp, "round joins"); break; case mp_beveled_linejoin_code: mp_print_str(mp, "beveled joins"); break; default: mp_print_str(mp, "?? joins"); break; } mp_print_str(mp, " with pen"); mp_print_ln(mp); mp_pr_pen(mp, mp_pen_ptr((mp_shape_node) p)); } break; case mp_stroked_node_type: mp_print_str(mp, "Filled pen stroke "); mp_print_obj_color (mp, p); mp_print_chr(mp, ':'); mp_print_ln(mp); mp_pr_path(mp, mp_path_ptr((mp_shape_node) p)); if (mp_dash_ptr(p) != NULL) { mp_dash_node ppd, hhd; int ok_to_dash = mp_pen_is_elliptical(mp_pen_ptr((mp_shape_node) p)); mp_print_nl(mp, "dashed ("); if (! ok_to_dash) { set_number_to_unity(scf); } else { number_clone(scf, ((mp_shape_node) p)->dashscale); } hhd = (mp_dash_node) mp_dash_ptr(p); ppd = mp_get_dash_list(hhd); if ((ppd == mp->null_dash) || number_negative(hhd->dash_y)) { mp_print_str(mp, " ??"); } else { mp_number dashoff; mp_number ret, arg1; new_number(ret); new_number(arg1); new_number(dashoff); set_number_from_addition(mp->null_dash->start_x, ppd->start_x, hhd->dash_y ); while (ppd != mp->null_dash) { mp_print_str(mp, "on "); set_number_from_subtraction(arg1, ppd->stop_x, ppd->start_x); take_scaled(ret, arg1, scf); print_number( ret); mp_print_str(mp, " off "); set_number_from_subtraction(arg1, ((mp_dash_node) ppd->link)->start_x, ppd->stop_x); take_scaled(ret, arg1, scf); print_number(ret); ppd = (mp_dash_node) ppd->link; if (ppd != mp->null_dash) { mp_print_chr(mp, ' '); } } mp_print_str(mp, ") shifted "); mp_dash_offset(mp, &dashoff, hhd); take_scaled(ret, dashoff, scf); number_negate(ret); print_number(ret); free_number(dashoff); free_number(ret); free_number(arg1); if (!ok_to_dash || number_zero(hhd->dash_y)) { mp_print_str(mp, " (this will be ignored)"); } } } mp_print_ln(mp); switch (((mp_shape_node) p)->linecap) { case mp_butt_linecap_code: mp_print_str(mp, "butt"); break; case mp_rounded_linecap_code: mp_print_str(mp, "round"); break; case mp_squared_linecap_code: mp_print_str(mp, "square"); break; default: mp_print_str(mp, "??"); break; } mp_print_str(mp, " ends, "); switch (((mp_shape_node) p)->linejoin) { case mp_mitered_linejoin_code: mp_print_str(mp, "mitered joins limited "); print_number(((mp_shape_node) p)->miterlimit); break; case mp_rounded_linejoin_code: mp_print_str(mp, "round joins"); break; case mp_beveled_linejoin_code: mp_print_str(mp, "beveled joins"); break; default: mp_print_str(mp, "?? joins"); break; } mp_print_str(mp, " with pen"); mp_print_ln(mp); if (mp_pen_ptr((mp_shape_node) p) == NULL) { mp_print_str(mp, "???"); } else { mp_pr_pen(mp, mp_pen_ptr((mp_shape_node) p)); } break; case mp_start_clip_node_type: mp_print_str(mp, "clipping path:"); goto COMMONSTART; case mp_start_group_node_type: mp_print_str(mp, "setgroup path:"); goto COMMONSTART; case mp_start_bounds_node_type: mp_print_str(mp, "setbounds path:"); COMMONSTART: mp_print_ln(mp); mp_pr_path(mp, mp_path_ptr((mp_start_node) p)); break; case mp_stop_clip_node_type: mp_print_str(mp, "stop clipping"); break; case mp_stop_group_node_type: mp_print_str(mp, "stop group"); break; case mp_stop_bounds_node_type: mp_print_str(mp, "end of setbounds"); break; default: mp_print_str(mp, "[unknown object type!]"); break; } } mp_print_nl(mp, "End edges"); if (p != mp_obj_tail(h)) { mp_print_str(mp, "?"); } mp_end_diagnostic(mp, 1); free_number(scf); } void mp_print_obj_color (MP mp, mp_node p) { mp_shape_node p0 = (mp_shape_node) p; switch (mp_color_model(p)) { case mp_grey_model: if (number_positive(p0->grey)) { mp_print_str(mp, "greyed "); mp_print_chr(mp, '('); print_number(p0->grey); mp_print_chr(mp, ')'); }; break; case mp_cmyk_model: if (number_positive(p0->cyan) || number_positive(p0->magenta) || number_positive(p0->yellow) || number_positive(p0->black)) { mp_print_str(mp, "processcolored "); mp_print_chr(mp, '('); print_number(p0->cyan); mp_print_chr(mp, ','); print_number(p0->magenta); mp_print_chr(mp, ','); print_number(p0->yellow); mp_print_chr(mp, ','); print_number(p0->black); mp_print_chr(mp, ')'); }; break; case mp_rgb_model: if (number_positive(p0->red) || number_positive(p0->green) || number_positive(p0->blue)) { mp_print_str(mp, "colored "); mp_print_chr(mp, '('); print_number(p0->red); mp_print_chr(mp, ','); print_number(p0->green); mp_print_chr(mp, ','); print_number(p0->blue); mp_print_chr(mp, ')'); } break; default: break; } } void mp_dash_offset (MP mp, mp_number *x, mp_dash_node h) { if (mp_get_dash_list(h) == mp->null_dash || number_negative(h->dash_y)) { mp_confusion(mp, "dash offset"); } else if (number_zero(h->dash_y)) { set_number_to_zero(*x); } else { number_clone(*x, (mp_get_dash_list(h))->start_x); number_modulo(*x, h->dash_y); number_negate(*x); if (number_negative(*x)) { number_add(*x, h->dash_y); } } } static mp_edge_header_node mp_make_dashes (MP mp, mp_edge_header_node h) { if (mp_get_dash_list(h) != mp->null_dash) { return h; } else { mp_node p; mp_node p0; mp_knot pp, qq, rr; mp_dash_node d, dd; mp_number y0; mp_dash_node dln; mp_edge_header_node hh; mp_node ds; new_number(y0); p0 = NULL; p = mp_edge_list(h)->link; while (p != NULL) { if (p->type != mp_stroked_node_type) { mp_back_error( mp, "Picture is too complicated to use as a dash pattern", "When you say 'dashed p', picture p should not contain any text, filled regions,\n" "or clipping paths. This time it did so I'll just make it a solid line instead." ); mp_get_x_next(mp); goto NOT_FOUND; } pp = mp_path_ptr((mp_shape_node) p); if (p0 == NULL) { p0 = p; number_clone(y0, pp->y_coord); } if (! number_equal(((mp_shape_node) p)->red, ((mp_shape_node) p0)->red) || ! number_equal(((mp_shape_node) p)->black, ((mp_shape_node) p0)->black) || ! number_equal(((mp_shape_node) p)->green, ((mp_shape_node) p0)->green) || ! number_equal(((mp_shape_node) p)->blue, ((mp_shape_node) p0)->blue) ) { mp_back_error( mp, "Picture is too complicated to use as a dash pattern", "When you say 'dashed p', everything in picture p should be the same color. I\n" "can't handle your color changes so I'll just make it a solid line instead." ); mp_get_x_next(mp); goto NOT_FOUND; } rr = pp; if (mp_next_knot(pp) != pp) { do { qq = rr; rr = mp_next_knot(rr); { mp_number x0, x1, x2, x3; new_number_clone(x0, qq->x_coord); new_number_clone(x1, qq->right_x); new_number_clone(x2, rr->left_x); new_number_clone(x3, rr->x_coord); if (number_greater(x0, x1) || number_greater(x1, x2) || number_greater(x2, x3)) { if (number_less(x0, x1) || number_less(x1, x2) || number_less(x2, x3)) { mp_number a1, a2, a3, a4; int test; new_number(a1); new_number(a2); new_number(a3); new_number(a4); set_number_from_subtraction(a1, x2, x1); set_number_from_subtraction(a2, x2, x1); set_number_from_subtraction(a3, x1, x0); set_number_from_subtraction(a4, x3, x2); test = ab_vs_cd(a1, a2, a3, a4); free_number(a1); free_number(a2); free_number(a3); free_number(a4); if (test > 0) { mp_x_retrace_error(mp); free_number(x0); free_number(x1); free_number(x2); free_number(x3); goto NOT_FOUND; } } } if (number_greater(pp->x_coord, x0) || number_greater(x0, x3)) { if (number_less(pp->x_coord, x0) || number_less(x0, x3)) { mp_x_retrace_error(mp); free_number(x0); free_number(x1); free_number(x2); free_number(x3); goto NOT_FOUND; } } free_number(x0); free_number(x1); free_number(x2); free_number(x3); } } while (mp_right_type(rr) != mp_endpoint_knot); } d = (mp_dash_node) mp_get_dash_node(mp); if (mp_dash_ptr(p) == NULL) { mp_dash_info(d) = NULL; } else { mp_dash_info(d) = p; } if (number_less(pp->x_coord, rr->x_coord)) { number_clone(d->start_x, pp->x_coord); number_clone(d->stop_x, rr->x_coord); } else { number_clone(d->start_x, rr->x_coord); number_clone(d->stop_x, pp->x_coord); } number_clone(mp->null_dash->start_x, d->stop_x); dd = (mp_dash_node) h; while (number_less(((mp_dash_node) dd->link)->start_x, d->stop_x)) { dd = (mp_dash_node) dd->link; } if ((dd != (mp_dash_node) h) && number_greater(dd->stop_x, d->start_x)) { mp_x_retrace_error(mp); goto NOT_FOUND; } d->link = dd->link; dd->link = (mp_node) d; p = p->link; } if (mp_get_dash_list(h) == mp->null_dash) { goto NOT_FOUND; } else { { mp_number hsf; new_number(hsf); d = (mp_dash_node) h; while (d->link != (mp_node) mp->null_dash) { ds = mp_dash_info(d->link); if (ds == NULL) { d = (mp_dash_node) d->link; } else { hh = (mp_edge_header_node) mp_dash_ptr(ds); number_clone(hsf, ((mp_shape_node) ds)->dashscale); if (hh == NULL) { mp_confusion(mp, "dash pattern"); return NULL; } else if (number_zero(((mp_dash_node) hh)->dash_y )) { d = (mp_dash_node) d->link; } else if (mp_get_dash_list (hh) == NULL) { mp_confusion(mp, "dash list"); return NULL; } else { mp_number xoff; mp_number dashoff; mp_number r1, r2; new_number(r1); new_number(r2); dln = (mp_dash_node) d->link; dd = mp_get_dash_list(hh); new_number(xoff); new_number(dashoff); mp_dash_offset(mp, &dashoff, (mp_dash_node) hh); take_scaled(r1, hsf, dd->start_x); take_scaled(r2, hsf, dashoff); number_add(r1, r2); set_number_from_subtraction(xoff, dln->start_x, r1); free_number(dashoff); take_scaled(r1, hsf, dd->start_x); take_scaled(r2, hsf, hh->dash_y); set_number_from_addition(mp->null_dash->start_x, r1, r2); number_clone(mp->null_dash->stop_x, mp->null_dash->start_x); { mp_number r1; new_number(r1); take_scaled(r1, hsf, dd->stop_x); number_add(r1, xoff); while (number_less(r1, dln->start_x)) { dd = (mp_dash_node) dd->link; take_scaled(r1, hsf, dd->stop_x); number_add(r1, xoff); } free_number(r1); } while (number_lessequal(dln->start_x, dln->stop_x)) { if (dd == mp->null_dash) { mp_number ret; new_number(ret); dd = mp_get_dash_list(hh); take_scaled(ret, hsf, hh->dash_y); number_add(xoff, ret); free_number(ret); } { mp_number r1; new_number(r1); take_scaled(r1, hsf, dd->start_x); number_add(r1, xoff); if (number_lessequal(r1, dln->stop_x)) { d->link = (mp_node) mp_get_dash_node(mp); d = (mp_dash_node) d->link; d->link = (mp_node) dln; take_scaled(r1, hsf, dd->start_x ); number_add(r1, xoff); if (number_greater(dln->start_x, r1)) { number_clone(d->start_x, dln->start_x); } else { number_clone(d->start_x, r1); } take_scaled(r1, hsf, dd->stop_x); number_add(r1, xoff); if (number_less(dln->stop_x, r1)) { number_clone(d->stop_x, dln->stop_x ); } else { number_clone(d->stop_x, r1); } } free_number(r1); } dd = (mp_dash_node) dd->link; take_scaled(r1, hsf, dd->start_x); set_number_from_addition(dln->start_x , xoff, r1); } free_number(xoff); free_number(r1); free_number(r2); d->link = dln->link; mp_free_node(mp, (mp_node) dln, sizeof(mp_dash_node_data)); } } } free_number(hsf); } d = mp_get_dash_list(h); while (d->link != (mp_node) mp->null_dash) { d = (mp_dash_node) d->link; } dd = mp_get_dash_list(h); set_number_from_subtraction(h->dash_y, d->stop_x, dd->start_x); { mp_number absval; new_number(absval); number_abs_clone(absval, y0); if (number_greater(absval, h->dash_y) ) { number_clone(h->dash_y, absval); } else if (d != dd) { mp_set_dash_list(h, dd->link); set_number_from_addition(d->stop_x, dd->stop_x, h->dash_y); mp_free_node(mp, (mp_node) dd, sizeof(mp_dash_node_data)); } free_number(absval); } free_number(y0); return h; } NOT_FOUND: free_number(y0); mp_flush_dash_list(mp, h); mp_delete_edge_ref(mp, h); return NULL; } } void mp_x_retrace_error (MP mp) { mp_back_error( mp, "Picture is too complicated to use as a dash pattern", "When you say 'dashed p', every path in p should be monotone in x and there must\n" "be no overlapping. This failed so I'll just make it a solid line instead." ); mp_get_x_next(mp); } static void mp_adjust_bbox (MP mp, mp_edge_header_node h) { if (number_less(mp_minx, h->minx)) { number_clone(h->minx, mp_minx); } if (number_less(mp_miny, h->miny)) { number_clone(h->miny, mp_miny); } if (number_greater(mp_maxx, h->maxx)) { number_clone(h->maxx, mp_maxx); } if (number_greater(mp_maxy, h->maxy)) { number_clone(h->maxy, mp_maxy); } } static void mp_box_ends (MP mp, mp_knot p, mp_knot pp, mp_edge_header_node h) { if (mp_right_type(p) != mp_endpoint_knot) { mp_number dx, dy; mp_number d; mp_number z; mp_number xx, yy; new_fraction(dx); new_fraction(dy); new_number(xx); new_number(yy); new_number(z); new_number(d); mp_knot q = mp_next_knot(p); while (1) { if (q == mp_next_knot(p)) { set_number_from_subtraction(dx, p->x_coord, p->right_x); set_number_from_subtraction(dy, p->y_coord, p->right_y); if (number_zero(dx) && number_zero(dy)) { set_number_from_subtraction(dx, p->x_coord, q->left_x); set_number_from_subtraction(dy, p->y_coord, q->left_y); } } else { set_number_from_subtraction(dx, p->x_coord, p->left_x); set_number_from_subtraction(dy, p->y_coord, p->left_y); if (number_zero(dx) && number_zero(dy)) { set_number_from_subtraction(dx, p->x_coord, q->right_x); set_number_from_subtraction(dy, p->y_coord, q->right_y); } } set_number_from_subtraction(dx, p->x_coord, q->x_coord); set_number_from_subtraction(dy, p->y_coord, q->y_coord); pyth_add(d, dx, dy); if (number_positive(d)) { mp_number arg1, r; new_fraction(r); new_number(arg1); make_fraction(r, dx, d); number_clone(dx, r); make_fraction(r, dy, d); number_clone(dy, r); free_number(r); number_negated_clone(arg1, dy); mp_find_offset(mp, &arg1, &dx, pp); free_number(arg1); number_clone(xx, mp->cur_x); number_clone(yy, mp->cur_y); for (int i = 1; i <= 2; i++) { mp_number r1, r2, arg1; new_number(arg1); new_fraction(r1); new_fraction(r2); mp_find_offset(mp, &dx, &dy, pp); set_number_from_subtraction(arg1, xx, mp->cur_x); take_fraction(r1, arg1, dx); set_number_from_subtraction(arg1, yy, mp->cur_y); take_fraction(r2, arg1, dy); set_number_from_addition(d, r1, r2); if ((number_negative(d) && (i == 1)) || (number_positive(d) && (i == 2))) { mp_confusion(mp, "box ends"); } take_fraction(r1, d, dx); set_number_from_addition(z, p->x_coord, mp->cur_x); number_add(z, r1); if (number_less(z, h->minx)) { number_clone(h->minx, z); } if (number_greater(z, h->maxx)) { number_clone(h->maxx, z); } take_fraction(r1, d, dy); set_number_from_addition(z, p->y_coord, mp->cur_y); number_add(z, r1); if (number_less(z, h->miny)) { number_clone(h->miny, z); } if (number_greater(z, h->maxy)) { number_clone(h->maxy, z); } free_number(r1); free_number(r2); free_number(arg1); number_negate(dx); number_negate(dy); } } if (mp_right_type(p) == mp_endpoint_knot) { goto DONE; } else { do { q = p; p = mp_next_knot(p); } while (mp_right_type(p) != mp_endpoint_knot); } } DONE: free_number(dx); free_number(dy); free_number(xx); free_number(yy); free_number(z); free_number(d); } } void mp_set_bbox (MP mp, mp_edge_header_node h, int top_level) { switch (h->bbtype ) { case mp_no_bounds_code: break; case mp_bounds_set_code: if (number_positive(internal_value(mp_true_corners_internal))) { mp_init_bbox(mp, h); } break; case mp_bounds_unset_code: if (number_nonpositive(internal_value(mp_true_corners_internal))) { mp_init_bbox(mp, h); } break; } while (mp_bblast(h)->link != NULL) { mp_node p = mp_bblast(h)->link; mp_bblast(h) = p; switch (p->type) { case mp_stop_clip_node_type: if (top_level) { mp_confusion(mp, "clip"); break; } else { return; } case mp_start_bounds_node_type: if (number_positive(internal_value(mp_true_corners_internal))) { h->bbtype = mp_bounds_unset_code; } else { h->bbtype = mp_bounds_set_code; mp_path_bbox(mp, mp_path_ptr((mp_start_node) p)); mp_adjust_bbox(mp, h); { int lev = 1; while (lev != 0) { if (p->link == NULL) { mp_confusion(mp, "bounds"); } else { p = p->link; if (p->type == mp_start_bounds_node_type) { ++lev; } else if (p->type == mp_stop_bounds_node_type) { --lev; } } } mp_bblast(h) = p; } } break; case mp_stop_bounds_node_type: if (number_nonpositive (internal_value(mp_true_corners_internal))) { mp_confusion(mp, "bounds"); } break; case mp_fill_node_type: case mp_stroked_node_type: { mp_number x0a, y0a, x1a, y1a; mp_path_bbox(mp, mp_path_ptr((mp_shape_node) p)); if (mp_pen_ptr((mp_shape_node) p) != NULL) { new_number_clone(x0a, mp_minx); new_number_clone(y0a, mp_miny); new_number_clone(x1a, mp_maxx); new_number_clone(y1a, mp_maxy); mp_pen_bbox(mp, mp_pen_ptr((mp_shape_node) p)); number_add(mp_minx, x0a); number_add(mp_miny, y0a); number_add(mp_maxx, x1a); number_add(mp_maxy, y1a); free_number(x0a); free_number(y0a); free_number(x1a); free_number(y1a); } mp_adjust_bbox(mp, h); if ((mp_left_type(mp_path_ptr((mp_shape_node) p)) == mp_endpoint_knot) && (((mp_shape_node) p)->linecap == 2)) { mp_box_ends(mp, mp_path_ptr((mp_shape_node) p), mp_pen_ptr((mp_shape_node) p), h); } } break; case mp_start_clip_node_type: { mp_number sminx, sminy, smaxx, smaxy; mp_number x0a, y0a, x1a, y1a; mp_path_bbox(mp, mp_path_ptr((mp_start_node) p)); new_number_clone(x0a, mp_minx); new_number_clone(y0a, mp_miny); new_number_clone(x1a, mp_maxx); new_number_clone(y1a, mp_maxy); new_number_clone(sminx, h->minx); new_number_clone(sminy, h->miny); new_number_clone(smaxx, h->maxx); new_number_clone(smaxy, h->maxy); set_number_to_inf(h->minx); set_number_to_inf(h->miny); set_number_to_negative_inf(h->maxx); set_number_to_negative_inf(h->maxy); mp_set_bbox(mp, h, 0); if (number_less(h->minx, x0a)) { number_clone(h->minx, x0a); } if (number_less(h->miny, y0a)) { number_clone(h->miny, y0a); } if (number_greater(h->maxx, x1a)) { number_clone(h->maxx, x1a); } if (number_greater(h->maxy, y1a)) { number_clone(h->maxy, y1a); } number_clone(mp_minx, sminx); number_clone(mp_miny, sminy); number_clone(mp_maxx, smaxx); number_clone(mp_maxy, smaxy); mp_adjust_bbox(mp, h); free_number(sminx); free_number(sminy); free_number(smaxx); free_number(smaxy); free_number(x0a); free_number(y0a); free_number(x1a); free_number(y1a); } break; default: break; } } if (! top_level) { mp_confusion(mp, "boundingbox"); } } static mp_knot mp_offset_prep (MP mp, mp_knot c, mp_knot h) { int n; mp_knot c0, p, q, q0, r, w, ww; int k_needed; mp_knot w0; mp_number dxin, dyin; int turn_amt; mp_number max_coef; mp_number ss; mp_number x0, x1, x2, y0, y1, y2; mp_number t0, t1, t2; mp_number du, dv, dx, dy; mp_number dx0, dy0; mp_number x0a, x1a,x2a, y0a, y1a, y2a; mp_number t; mp_number s; mp_number dx_m; mp_number dy_m; mp_number dxin_m; mp_number u0, u1, v0, v1; int d_sign; new_number(max_coef); new_number(dxin); new_number(dyin); new_number(dx0); new_number(dy0); new_number(x0); new_number(y0); new_number(x1); new_number(y1); new_number(x2); new_number(y2); new_number(du); new_number(dv); new_number(dx); new_number(dy); new_number(x0a); new_number(y0a); new_number(x1a); new_number(y1a); new_number(x2a); new_number(y2a); new_number(t0); new_number(t1); new_number(t2); new_number(u0); new_number(u1); new_number(v0); new_number(v1); new_number(dx_m); new_number(dy_m); new_number(dxin_m); new_fraction(ss); new_fraction(s); new_fraction(t); n = 0; p = h; do { ++n; p = mp_next_knot(p); } while (p != h); { mp_knot hn = mp_next_knot(h); mp_knot hp = mp_prev_knot(h); set_number_from_subtraction(dxin, hn->x_coord, hp->x_coord); set_number_from_subtraction(dyin, hn->y_coord, hp->y_coord); if (number_zero(dxin) && number_zero(dyin)) { set_number_from_subtraction(dxin, hp->y_coord, h->y_coord); set_number_from_subtraction(dyin, h->x_coord, hp->x_coord); } } w0 = h; p = c; c0 = c; k_needed = 0; do { q = mp_next_knot(p); mp_knot_info(p) = zero_off + k_needed; k_needed = 0; set_number_from_subtraction(x0, p->right_x, p->x_coord); set_number_from_subtraction(x2, q->x_coord, q->left_x); set_number_from_subtraction(x1, q->left_x, p->right_x); set_number_from_subtraction(y0, p->right_y, p->y_coord); set_number_from_subtraction(y2, q->y_coord, q->left_y); set_number_from_subtraction(y1, q->left_y, p->right_y); { mp_number absval; new_number_abs(absval, x1); number_abs_clone(max_coef, x0); if (number_greater(absval, max_coef)) { number_clone(max_coef, absval); } number_abs_clone(absval, x2); if (number_greater(absval, max_coef)) { number_clone(max_coef, absval); } number_abs_clone(absval, y0); if (number_greater(absval, max_coef)) { number_clone(max_coef, absval); } number_abs_clone(absval, y1); if (number_greater(absval, max_coef)) { number_clone(max_coef, absval); } number_abs_clone(absval, y2); if (number_greater(absval, max_coef)) { number_clone(max_coef, absval); } free_number(absval); if (number_zero(max_coef)) { goto NOT_FOUND; } } while (number_less(max_coef, fraction_half_t)) { number_double(max_coef); number_double(x0); number_double(x1); number_double(x2); number_double(y0); number_double(y1); number_double(y2); } number_clone(dx_m, zero_t); number_clone(dy_m, zero_t); number_clone(dx, x0); number_clone(dy, y0); if (number_zero(dx) && number_zero(dy)) { number_clone(dx, x1); number_clone(dy, y1); if (number_zero(dx) && number_zero(dy)) { number_clone(dx, x2); number_clone(dy, y2); } } if (p == c) { number_clone(dx0, dx); number_clone(dy0, dy); } { turn_amt = mp_get_turn_amt(mp, w0, &dx, &dy, ab_vs_cd(dy, dxin, dx, dyin) >= 0); w = mp_pen_walk(mp, w0, turn_amt); w0 = w; mp_knot_info(p) = mp_knot_info(p) + turn_amt; } number_clone(dxin, x2); number_clone(dyin, y2); if (number_zero(dxin) && number_zero(dyin)) { number_clone(dxin, x1); number_clone(dyin, y1); if (number_zero(dxin) && number_zero(dyin)) { number_clone(dxin, x0); number_clone(dyin, y0); } } { int sign = ab_vs_cd(dx, dyin, dxin, dy); if (sign < 0) { d_sign = -1; } else if (sign == 0) { d_sign = 0; } else { d_sign = 1; } } if (d_sign == 0) { { int t; set_number_from_subtraction(u0, q->x_coord, p->x_coord); set_number_from_subtraction(u1, q->y_coord, p->y_coord); t = ab_vs_cd(dx, u1, u0, dy) + ab_vs_cd(u0, dyin, dxin, u1); if (t < 0) { d_sign = -1; } else if (t == 0) { d_sign = 0; } else { d_sign = 1; } } } if (d_sign == 0) { if (number_zero(dx)) { d_sign = number_positive(dy) ? 1 : -1; } else { d_sign = number_positive(dx) ? 1 : -1; } } { mp_number r1, r2, arg1; new_number(arg1); new_fraction(r1); new_fraction(r2); take_fraction(r1, x0, y2); take_fraction(r2, x2, y0); number_half(r1); number_half(r2); set_number_from_subtraction(t0, r1, r2); set_number_from_addition(arg1, y0, y2); take_fraction(r1, x1, arg1); set_number_from_addition(arg1, x0, x2); take_fraction(r2, y1, arg1); number_half(r1); number_half(r2); set_number_from_subtraction(t1, r1, r2); free_number(arg1); free_number(r1); free_number(r2); } if (number_zero(t0)) { set_number_from_scaled(t0, d_sign); } if (number_positive(t0)) { mp_number arg3; new_number(arg3); number_negated_clone(arg3, t0); crossing_point(t, t0, t1, arg3); free_number(arg3); set_number_from_of_the_way(u0, t, x0, x1); set_number_from_of_the_way(u1, t, x1, x2); set_number_from_of_the_way(v0, t, y0, y1); set_number_from_of_the_way(v1, t, y1, y2); } else { mp_number arg1; new_number(arg1); number_negated_clone(arg1, t0); crossing_point(t, arg1, t1, t0); free_number(arg1); set_number_from_of_the_way(u0, t, x2, x1); set_number_from_of_the_way(u1, t, x1, x0); set_number_from_of_the_way(v0, t, y2, y1); set_number_from_of_the_way(v1, t, y1, y0); } { mp_number tmp1, tmp2, r1, r2, arg1; new_fraction(r1); new_fraction(r2); new_number(arg1); new_number(tmp1); new_number(tmp2); set_number_from_of_the_way(tmp1, t, u0, u1); set_number_from_of_the_way(tmp2, t, v0, v1); set_number_from_addition(arg1, x0, x2); take_fraction(r1, arg1, tmp1); set_number_from_addition(arg1, y0, y2); take_fraction(r2, arg1, tmp2); set_number_from_addition(ss, r1, r2); free_number(arg1); free_number(r1); free_number(r2); free_number(tmp1); free_number(tmp2); } turn_amt = mp_get_turn_amt(mp, w, &dxin, &dyin, (d_sign > 0)); if (number_negative(ss)) { turn_amt = turn_amt - d_sign * n; } ww = mp_prev_knot(w); { mp_number abs_du, abs_dv; new_number(abs_du); new_number(abs_dv); set_number_from_subtraction(du, ww->x_coord, w->x_coord); set_number_from_subtraction(dv, ww->y_coord, w->y_coord); number_abs_clone(abs_du, du); number_abs_clone(abs_dv, dv); if (number_greaterequal(abs_du, abs_dv)) { mp_number r1; new_fraction(r1); make_fraction(s, dv, du); take_fraction(r1, x0, s); set_number_from_subtraction(t0, r1, y0); take_fraction(r1, x1, s); set_number_from_subtraction(t1, r1, y1); take_fraction(r1, x2, s); set_number_from_subtraction(t2, r1, y2); if (number_negative(du)) { number_negate(t0); number_negate(t1); number_negate(t2); } free_number(r1); } else { mp_number r1; new_fraction(r1); make_fraction(s, du, dv); take_fraction(r1, y0, s); set_number_from_subtraction(t0, x0, r1); take_fraction(r1, y1, s); set_number_from_subtraction(t1, x1, r1); take_fraction(r1, y2, s); set_number_from_subtraction(t2, x2, r1); if (number_negative(dv)) { number_negate(t0); number_negate(t1); number_negate(t2); } free_number(r1); } free_number(abs_du); free_number(abs_dv); if (number_negative(t0)) { set_number_to_zero(t0); } } crossing_point(t, t0, t1, t2); if (turn_amt >= 0) { if (number_negative(t2)) { number_clone(t, fraction_one_t); number_add_scaled(t, 1); } else { mp_number tmp, arg1, r1; new_fraction(r1); new_number(tmp); new_number(arg1); set_number_from_of_the_way(u0, t, x0, x1); set_number_from_of_the_way(u1, t, x1, x2); set_number_from_of_the_way(tmp, t, u0, u1); number_negated_clone(arg1, du); take_fraction(ss, arg1, tmp); set_number_from_of_the_way(v0, t, y0, y1); set_number_from_of_the_way(v1, t, y1, y2); set_number_from_of_the_way(tmp, t, v0, v1); number_negated_clone(arg1, dv); take_fraction(r1, arg1, tmp); number_add(ss, r1); free_number(tmp); if (number_negative(ss)) { number_clone(t, fraction_one_t); number_add_scaled(t, 1); } free_number(arg1); free_number(r1); } } else if (number_greater(t, fraction_one_t)) { number_clone(t, fraction_one_t); } if (number_greater(t, fraction_one_t)) { mp_fin_offset_prep(mp, p, w, &x0, &x1, &x2, &y0, &y1, &y2, 1, turn_amt); } else { mp_split_cubic(mp, p, &t); r = mp_next_knot(p); set_number_from_of_the_way(x1a, t, x0, x1); set_number_from_of_the_way(x1, t, x1, x2); set_number_from_of_the_way(x2a, t, x1a, x1); set_number_from_of_the_way(y1a, t, y0, y1); set_number_from_of_the_way(y1, t, y1, y2); set_number_from_of_the_way(y2a, t, y1a, y1); mp_fin_offset_prep (mp, p, w, &x0, &x1a, &x2a, &y0, &y1a, &y2a, 1, 0); number_clone(x0, x2a); number_clone(y0, y2a); mp_knot_info(r) = zero_off - 1; if (turn_amt >= 0) { mp_number arg1, arg2, arg3; new_number(arg1); new_number(arg2); new_number(arg3); set_number_from_of_the_way(t1, t, t1, t2); if (number_positive(t1)) { set_number_to_zero(t1); } number_negated_clone(arg2, t1); number_negated_clone(arg3, t2); crossing_point(t, arg1, arg2, arg3); free_number(arg1); free_number(arg2); free_number(arg3); if (number_greater(t, fraction_one_t)) { number_clone(t, fraction_one_t); } mp_split_cubic(mp, r, &t); mp_knot_info(mp_next_knot(r)) = zero_off + 1; set_number_from_of_the_way(x1a, t, x1, x2); set_number_from_of_the_way(x1, t, x0, x1); set_number_from_of_the_way(x0a, t, x1, x1a); set_number_from_of_the_way(y1a, t, y1, y2); set_number_from_of_the_way(y1, t, y0, y1); set_number_from_of_the_way(y0a, t, y1, y1a); mp_fin_offset_prep (mp, mp_next_knot(r), w, &x0a, &x1a, &x2, &y0a, &y1a, &y2, 1, turn_amt); number_clone(x2, x0a); number_clone(y2, y0a); mp_fin_offset_prep(mp, r, ww, &x0, &x1, &x2, &y0, &y1, &y2, -1, 0); } else { mp_fin_offset_prep(mp, r, ww, &x0, &x1, &x2, &y0, &y1, &y2, -1, (-1 - turn_amt)); } } w0 = mp_pen_walk (mp, w0, turn_amt); NOT_FOUND: q0 = q; do { r = mp_next_knot(p); if (r != p && r != q && number_equal(p->x_coord, p->right_x) && number_equal(p->y_coord, p->right_y) && number_equal(p->x_coord, r->left_x) && number_equal(p->y_coord, r->left_y) && number_equal(p->x_coord, r->x_coord) && number_equal(p->y_coord, r->y_coord)) { { k_needed = mp_knot_info(p) - zero_off; if (r == q) { q = p; } else { mp_knot_info(p) = k_needed + mp_knot_info(r); k_needed = 0; } if (r == c) { mp_knot_info(p) = mp_knot_info(c); c = p; } if (r == mp->spec_p1) { mp->spec_p1 = p; } if (r == mp->spec_p2) { mp->spec_p2 = p; } r = p; mp_remove_cubic(mp, p); } } p = r; } while (p != q); if ((q != q0) && (q != c || c == c0)) { q = mp_next_knot(q); } } while (q != c); mp->spec_offset = mp_knot_info(c) - zero_off; if (mp_next_knot(c) == c) { mp_knot_info(c) = zero_off + n; } else { mp_knot_info(c) += k_needed; while (w0 != h) { mp_knot_info(c) += 1; w0 = mp_next_knot(w0); } while (mp_knot_info(c) <= zero_off - n) { mp_knot_info(c) += n; } while (mp_knot_info(c) > zero_off) { mp_knot_info(c) -= n; } ; if ((mp_knot_info(c) != zero_off) && ab_vs_cd(dy0, dxin, dx0, dyin) >= 0) { mp_knot_info(c) += n; } } free_number(ss); free_number(s); free_number(dxin); free_number(dyin); free_number(dx0); free_number(dy0); free_number(x0); free_number(y0); free_number(x1); free_number(y1); free_number(x2); free_number(y2); free_number(max_coef); free_number(du); free_number(dv); free_number(dx); free_number(dy); free_number(x0a); free_number(y0a); free_number(x1a); free_number(y1a); free_number(x2a); free_number(y2a); free_number(t0); free_number(t1); free_number(t2); free_number(u0); free_number(u1); free_number(v0); free_number(v1); free_number(dx_m); free_number(dy_m); free_number(dxin_m); free_number(t); return c; } void mp_split_cubic (MP mp, mp_knot p, mp_number *t) { mp_number v; mp_knot q = mp_next_knot(p); mp_knot r = mp_new_knot(mp); mp_prev_knot(r) = p; mp_next_knot(p) = r; mp_prev_knot(q) = r; mp_next_knot(r) = q; mp_originator(r) = mp_program_code; mp_knotstate(r) = mp_regular_knot; mp_left_type(r) = mp_explicit_knot; mp_right_type(r) = mp_explicit_knot; new_number(v); set_number_from_of_the_way(v, *t, p->right_x, q->left_x); set_number_from_of_the_way(p->right_x, *t, p->x_coord, p->right_x); set_number_from_of_the_way(q->left_x, *t, q->left_x, q->x_coord); set_number_from_of_the_way(r->left_x, *t, p->right_x, v); set_number_from_of_the_way(r->right_x, *t, v, q->left_x); set_number_from_of_the_way(r->x_coord, *t, r->left_x, r->right_x); set_number_from_of_the_way(v, *t, p->right_y, q->left_y); set_number_from_of_the_way(p->right_y, *t, p->y_coord, p->right_y); set_number_from_of_the_way(q->left_y, *t, q->left_y, q->y_coord); set_number_from_of_the_way(r->left_y, *t, p->right_y, v); set_number_from_of_the_way(r->right_y, *t, v, q->left_y); set_number_from_of_the_way(r->y_coord, *t, r->left_y, r->right_y); free_number(v); } static mp_knot mp_split_cubic_knot (MP mp, mp_knot p, mp_number *t) { mp_number v; mp_knot k = mp_new_knot(mp); mp_knot r = mp_copy_knot(mp, mp_next_knot(p)); mp_knot l = mp_copy_knot(mp, p); mp_originator(k) = mp_program_code; mp_knotstate(k) = mp_regular_knot; mp_left_type(k) = mp_explicit_knot; mp_right_type(k) = mp_explicit_knot; new_number(v); set_number_from_of_the_way(v, *t, l->right_x, r->left_x); set_number_from_of_the_way(l->right_x, *t, l->x_coord, l->right_x); set_number_from_of_the_way(r->left_x, *t, r->left_x, r->x_coord); set_number_from_of_the_way(k->left_x, *t, l->right_x, v); set_number_from_of_the_way(k->right_x, *t, v, r->left_x); set_number_from_of_the_way(k->x_coord, *t, k->left_x, k->right_x); set_number_from_of_the_way(v, *t, l->right_y, r->left_y); set_number_from_of_the_way(l->right_y, *t, l->y_coord, l->right_y); set_number_from_of_the_way(r->left_y, *t, r->left_y, r->y_coord); set_number_from_of_the_way(k->left_y, *t, l->right_y, v); set_number_from_of_the_way(k->right_y, *t, v, r->left_y); set_number_from_of_the_way(k->y_coord, *t, k->left_y, k->right_y); free_number(v); mp_toss_knot(mp, l); mp_toss_knot(mp, r); return k; } void mp_remove_cubic (MP mp, mp_knot p) { mp_knot q = mp_next_knot(p); mp_prev_knot(q) = mp_next_knot(p); mp_next_knot(p) = mp_next_knot(q); number_clone(p->right_x, q->right_x); number_clone(p->right_y, q->right_y); mp_toss_knot(mp, q); } mp_knot mp_pen_walk (MP mp, mp_knot w, int k) { (void) mp; while (k > 0) { w = mp_next_knot(w); --k; } while (k < 0) { w = mp_prev_knot(w); ++k; } return w; } void mp_fin_offset_prep (MP mp, mp_knot p, mp_knot w, mp_number *x0, mp_number *x1, mp_number *x2, mp_number *y0, mp_number *y1, mp_number *y2, int rise, int turn_amt) { mp_number du, dv; mp_number t0, t1, t2; mp_number t; mp_number s; mp_number v; mp_knot q = mp_next_knot(p); new_number(du); new_number(dv); new_number(v); new_number(t0); new_number(t1); new_number(t2); new_fraction(s); new_fraction(t); while (1) { mp_knot ww = rise > 0 ? mp_next_knot(w) : mp_prev_knot(w); { mp_number abs_du, abs_dv; new_number(abs_du); new_number(abs_dv); set_number_from_subtraction(du, ww->x_coord, w->x_coord); set_number_from_subtraction(dv, ww->y_coord, w->y_coord); number_abs_clone(abs_du, du); number_abs_clone(abs_dv, dv); if (number_greaterequal(abs_du, abs_dv)) { mp_number r1; new_fraction(r1); make_fraction(s, dv, du); take_fraction(r1, *x0, s); set_number_from_subtraction(t0, r1, *y0); take_fraction(r1, *x1, s); set_number_from_subtraction(t1, r1, *y1); take_fraction(r1, *x2, s); set_number_from_subtraction(t2, r1, *y2); if (number_negative(du)) { number_negate(t0); number_negate(t1); number_negate(t2); } free_number(r1); } else { mp_number r1; new_fraction(r1); make_fraction(s, du, dv); take_fraction(r1, *y0, s); set_number_from_subtraction(t0, *x0, r1); take_fraction(r1, *y1, s); set_number_from_subtraction(t1, *x1, r1); take_fraction(r1, *y2, s); set_number_from_subtraction(t2, *x2, r1); if (number_negative(dv)) { number_negate(t0); number_negate(t1); number_negate(t2); } free_number(r1); } free_number(abs_du); free_number(abs_dv); if (number_negative(t0)) { set_number_to_zero(t0); } } crossing_point(t, t0, t1, t2); if (number_greaterequal(t, fraction_one_t)) { if (turn_amt > 0) { number_clone(t, fraction_one_t); } else { goto RETURN; } } { mp_split_cubic(mp, p, &t); p = mp_next_knot(p); mp_knot_info(p) = zero_off + rise; --turn_amt; set_number_from_of_the_way(v, t, *x0, *x1); set_number_from_of_the_way(*x1, t, *x1, *x2); set_number_from_of_the_way(*x0, t, v, *x1); set_number_from_of_the_way(v, t, *y0, *y1); set_number_from_of_the_way(*y1, t, *y1, *y2); set_number_from_of_the_way(*y0, t, v, *y1); if (turn_amt < 0) { mp_number arg1, arg2, arg3; new_number(arg1); new_number(arg2); new_number(arg3); set_number_from_of_the_way(t1, t, t1, t2); if (number_positive(t1)) { set_number_to_zero(t1); } number_negated_clone(arg2, t1); number_negated_clone(arg3, t2); crossing_point(t, arg1, arg2, arg3); free_number(arg1); free_number(arg2); free_number(arg3); if (number_greater(t, fraction_one_t)) { number_clone(t, fraction_one_t); } ++turn_amt; if (number_equal(t,fraction_one_t) && (mp_next_knot(p) != q)) { mp_knot_info(mp_next_knot(p)) = mp_knot_info(mp_next_knot(p)) - rise; } else { mp_split_cubic(mp, p, &t); mp_knot_info(mp_next_knot(p)) = zero_off - rise; set_number_from_of_the_way(v, t, *x1, *x2); set_number_from_of_the_way(*x1, t, *x0, *x1); set_number_from_of_the_way(*x2, t, *x1, v); set_number_from_of_the_way(v, t, *y1, *y2); set_number_from_of_the_way(*y1, t, *y0, *y1); set_number_from_of_the_way(*y2, t, *y1, v); } } } w = ww; } RETURN: free_number(s); free_number(t); free_number(du); free_number(dv); free_number(v); free_number(t0); free_number(t1); free_number(t2); } int mp_get_turn_amt (MP mp, mp_knot w, mp_number *dx, mp_number *dy, int ccw) { int s = 0; mp_number arg1, arg2; new_number(arg1); new_number(arg2); if (ccw) { int t; mp_knot ww = mp_next_knot(w); do { set_number_from_subtraction(arg1, ww->x_coord, w->x_coord); set_number_from_subtraction(arg2, ww->y_coord, w->y_coord); t = ab_vs_cd(*dy, arg1, *dx, arg2); if (t < 0) { break; } else { ++s; w = ww; ww = mp_next_knot(ww); } } while (t > 0); } else { mp_knot ww = mp_prev_knot(w); set_number_from_subtraction(arg1, w->x_coord, ww->x_coord); set_number_from_subtraction(arg2, w->y_coord, ww->y_coord); while (ab_vs_cd(*dy, arg1, *dx, arg2) < 0) { --s; w = ww; ww = mp_prev_knot(ww); set_number_from_subtraction(arg1, w->x_coord, ww->x_coord); set_number_from_subtraction(arg2, w->y_coord, ww->y_coord); } } free_number(arg1); free_number(arg2); return s; } static void mp_print_spec (MP mp, mp_knot cur_spec, mp_knot cur_pen, const char *s) { mp_knot w; mp_knot p = cur_spec; mp_print_diagnostic(mp, "Envelope spec", s, 1); w = mp_pen_walk(mp, cur_pen, mp->spec_offset); mp_print_ln(mp); mp_print_two(mp, &(cur_spec->x_coord), &(cur_spec->y_coord)); mp_print_str(mp, " % beginning with offset "); mp_print_two(mp, &(w->x_coord), &(w->y_coord)); do { while (1) { mp_knot q = mp_next_knot(p); mp_print_nl(mp, " .. controls "); mp_print_two(mp, &(p->right_x), &(p->right_y)); mp_print_str(mp, " and "); mp_print_two(mp, &(q->left_x), &(q->left_y)); mp_print_nl(mp, " .. "); mp_print_two(mp, &(q->x_coord), &(q->y_coord)); p = q; if ((p == cur_spec) || (mp_knot_info(p) != zero_off)) { break; } } if (mp_knot_info(p) != zero_off) { w = mp_pen_walk (mp, w, (mp_knot_info(p) - zero_off)); mp_print_str(mp, " % "); if (mp_knot_info(p) > zero_off) { mp_print_str(mp, "counter"); } mp_print_str(mp, "clockwise to offset "); mp_print_two(mp, &(w->x_coord), &(w->y_coord)); } } while (p != cur_spec); mp_print_nl(mp, " & cycle"); mp_end_diagnostic(mp, 1); } static mp_knot mp_make_envelope (MP mp, mp_knot c, mp_knot h, int linejoin, int linecap, mp_number *miterlimit) { mp_knot p, q, r, q0; mp_knot w, w0; int k, k0; mp_number qx, qy; mp_number dxin, dyin, dxout, dyout; int join_type = 0; mp_number tmp; mp_number max_ht; int kk; mp_knot ww; new_number(max_ht); new_number(tmp); new_fraction(dxin); new_fraction(dyin); new_fraction(dxout); new_fraction(dyout); mp->spec_p1 = NULL; mp->spec_p2 = NULL; new_number(qx); new_number(qy); if (mp_left_type(c) == mp_endpoint_knot) { mp->spec_p1 = mp_htap_ypoc(mp, c); mp->spec_p2 = mp->path_tail; mp_originator(mp->spec_p1) = mp_program_code; mp_knotstate(mp->spec_p1) = mp_regular_knot; mp_prev_knot(mp->spec_p1) = mp_next_knot(mp->spec_p2); mp_next_knot(mp->spec_p2) = mp_next_knot(mp->spec_p1); mp_prev_knot(c) = mp->spec_p1; mp_next_knot(mp->spec_p1) = c; mp_remove_cubic(mp, mp->spec_p1); c = mp->spec_p1; if (c != mp_next_knot(c)) { mp_originator(mp->spec_p2) = mp_program_code; mp_knotstate(mp->spec_p2) = mp_regular_knot; mp_remove_cubic(mp, mp->spec_p2); } else { mp_left_type(c) = mp_explicit_knot; mp_right_type(c) = mp_explicit_knot; number_clone(c->left_x, c->x_coord); number_clone(c->left_y, c->y_coord); number_clone(c->right_x, c->x_coord); number_clone(c->right_y, c->y_coord); } } c = mp_offset_prep (mp, c, h); if (number_positive(internal_value(mp_tracing_specs_internal))) { mp_print_spec(mp, c, h, ""); } h = mp_pen_walk (mp, h, mp->spec_offset); w = h; p = c; do { q = mp_next_knot(p); q0 = q; number_clone(qx, q->x_coord); number_clone(qy, q->y_coord); k = mp_knot_info(q); k0 = k; w0 = w; if (k != zero_off) { if (k < zero_off) { join_type = 2; } else { if ((q != mp->spec_p1) && (q != mp->spec_p2)) { join_type = linejoin; } else if (linecap == mp_squared_linecap_code) { join_type = 3; } else { join_type = 2 - linecap; } if ((join_type == 0) || (join_type == 3)) { set_number_from_subtraction(dxin, q->x_coord, q->left_x); set_number_from_subtraction(dyin, q->y_coord, q->left_y); if (number_zero(dxin) && number_zero(dyin)) { set_number_from_subtraction(dxin, q->x_coord, p->right_x); set_number_from_subtraction(dyin, q->y_coord, p->right_y); if (number_zero(dxin) && number_zero(dyin)) { set_number_from_subtraction(dxin, q->x_coord, p->x_coord); set_number_from_subtraction(dyin, q->y_coord, p->y_coord); if (p != c) { number_add(dxin, w->x_coord); number_add(dyin, w->y_coord); } } } pyth_add(tmp, dxin, dyin); if (number_zero(tmp)) { join_type = 2; } else { mp_number r1; new_fraction(r1); make_fraction(r1, dxin, tmp); number_clone(dxin, r1); make_fraction(r1, dyin, tmp); number_clone(dyin, r1); free_number(r1); set_number_from_subtraction(dxout, q->right_x, q->x_coord); set_number_from_subtraction(dyout, q->right_y, q->y_coord); if (number_zero(dxout) && number_zero(dyout)) { r = mp_next_knot(q); set_number_from_subtraction(dxout, r->left_x, q->x_coord); set_number_from_subtraction(dyout, r->left_y, q->y_coord); if (number_zero(dxout) && number_zero(dyout)) { set_number_from_subtraction(dxout, r->x_coord, q->x_coord); set_number_from_subtraction(dyout, r->y_coord, q->y_coord); } } if (q == c) { number_subtract(dxout, h->x_coord); number_subtract(dyout, h->y_coord); } pyth_add(tmp, dxout, dyout); if (number_zero(tmp)) { } else { mp_number r1; new_fraction(r1); make_fraction(r1, dxout, tmp); number_clone(dxout, r1); make_fraction(r1, dyout, tmp); number_clone(dyout, r1); free_number(r1); } } if (join_type == 0) { mp_number r1, r2; new_fraction(r1); new_fraction(r2); take_fraction(r1, dxin, dxout); take_fraction(r2, dyin, dyout); number_add(r1, r2); number_half(r1); number_add(r1, fraction_half_t); take_fraction(tmp, *miterlimit, r1); if (number_less(tmp, unity_t)) { mp_number ret; new_number(ret); take_scaled(ret, *miterlimit, tmp); if (number_less(ret, unity_t)) { join_type = 2; } free_number(ret); } free_number(r1); free_number(r2); } } } } number_add(p->right_x, w->x_coord); number_add(p->right_y, w->y_coord); number_add(q->left_x, w->x_coord); number_add(q->left_y, w->y_coord); number_add(q->x_coord, w->x_coord); number_add(q->y_coord, w->y_coord); mp_left_type(q) = mp_explicit_knot; mp_right_type(q) = mp_explicit_knot; while (k != zero_off) { if (k > zero_off) { w = mp_next_knot(w); --k; } else { w = mp_prev_knot(w); ++k; } if ((join_type == 1) || (k == zero_off)) { mp_number xtot, ytot; new_number(xtot); new_number(ytot); set_number_from_addition(xtot, qx, w->x_coord); set_number_from_addition(ytot, qy, w->y_coord); q = mp_insert_knot(mp, q, &xtot, &ytot); free_number(xtot); free_number(ytot); } } if (q != mp_next_knot(p)) { p = mp_next_knot(p); if ((join_type == 0) || (join_type == 3)) { if (join_type == 0) { mp_number det; mp_number absdet; mp_number r1, r2; new_fraction(r1); new_fraction(r2); new_fraction(det); new_fraction(absdet); take_fraction(r1, dyout, dxin); take_fraction(r2, dxout, dyin); set_number_from_subtraction(det, r1, r2); number_abs_clone(absdet, det); if (number_less(absdet, near_zero_angle_k)) { r = NULL; } else { mp_number xtot, ytot, xsub, ysub; new_fraction(xsub); new_fraction(ysub); new_number(xtot); new_number(ytot); set_number_from_subtraction(tmp, q->x_coord, p->x_coord); take_fraction(r1, tmp, dyout); set_number_from_subtraction(tmp, q->y_coord, p->y_coord); take_fraction(r2, tmp, dxout); set_number_from_subtraction(tmp, r1, r2); make_fraction(r1, tmp, det); number_clone(tmp, r1); take_fraction(xsub, tmp, dxin); take_fraction(ysub, tmp, dyin); set_number_from_addition(xtot, p->x_coord, xsub); set_number_from_addition(ytot, p->y_coord, ysub); r = mp_insert_knot(mp, p, &xtot, &ytot); free_number(xtot); free_number(ytot); free_number(xsub); free_number(ysub); } free_number(r1); free_number(r2); free_number(det); free_number(absdet); } else { mp_number ht_x, ht_y; mp_number ht_x_abs, ht_y_abs; mp_number xtot, ytot, xsub, ysub; new_fraction(xsub); new_fraction(ysub); new_number(xtot); new_number(ytot); new_fraction(ht_x); new_fraction(ht_y); new_fraction(ht_x_abs); new_fraction(ht_y_abs); set_number_from_subtraction(ht_x, w->y_coord, w0->y_coord); set_number_from_subtraction(ht_y, w0->x_coord, w->x_coord); number_abs_clone(ht_x_abs, ht_x); number_abs_clone(ht_y_abs, ht_y); while (number_less(ht_x_abs, fraction_half_t) && number_less(ht_y_abs, fraction_half_t)) { number_double(ht_x); number_double(ht_y); number_abs_clone(ht_x_abs, ht_x); number_abs_clone(ht_y_abs, ht_y); } set_number_to_zero(max_ht); kk = zero_off; ww = w; while (1) { if (kk > k0) { ww = mp_next_knot(ww); --kk; } else { ww = mp_prev_knot(ww); ++kk; } if (kk == k0) { break; } else { mp_number r1, r2; new_fraction(r1); new_fraction(r2); set_number_from_subtraction(tmp, ww->x_coord, w0->x_coord); take_fraction(r1, tmp, ht_x); set_number_from_subtraction(tmp, ww->y_coord, w0->y_coord); take_fraction(r2, tmp, ht_y); set_number_from_addition(tmp, r1, r2); free_number(r1); free_number(r2); if (number_greater(tmp, max_ht)) { number_clone(max_ht, tmp); } } } { mp_number r1 ,r2; new_fraction(r1); new_fraction(r2); take_fraction(r1, dxin, ht_x); take_fraction(r2, dyin, ht_y); number_add(r1, r2); make_fraction(tmp, max_ht, r1); free_number(r1); free_number(r2); } take_fraction(xsub, tmp, dxin); take_fraction(ysub, tmp, dyin); set_number_from_addition(xtot, p->x_coord, xsub); set_number_from_addition(ytot, p->y_coord, ysub); r = mp_insert_knot(mp, p, &xtot, &ytot); { mp_number r1 ,r2; new_fraction(r1); new_fraction(r2); take_fraction(r1, dxout, ht_x); take_fraction(r2, dyout, ht_y); number_add(r1, r2); make_fraction(tmp, max_ht, r1); free_number(r1); free_number(r2); } take_fraction(xsub, tmp, dxout); take_fraction(ysub, tmp, dyout); set_number_from_addition(xtot, q->x_coord, xsub); set_number_from_addition(ytot, q->y_coord, ysub); r = mp_insert_knot(mp, r, &xtot, &ytot); free_number(xsub); free_number(ysub); free_number(xtot); free_number(ytot); free_number(ht_x); free_number(ht_y); free_number(ht_x_abs); free_number(ht_y_abs); } if (r != NULL) { number_clone(r->right_x, r->x_coord); number_clone(r->right_y, r->y_coord); } } } p = q; } while (q0 != c); free_number(max_ht); free_number(tmp); free_number(qx); free_number(qy); free_number(dxin); free_number(dyin); free_number(dxout); free_number(dyout); return c; } mp_knot mp_insert_knot (MP mp, mp_knot q, mp_number *x, mp_number *y) { mp_knot r = mp_new_knot(mp); mp_knot n = mp_next_knot(q); mp_next_knot(r) = n; mp_prev_knot(n) = r; mp_prev_knot(r) = q; mp_next_knot(q) = r; number_clone(r->right_x, q->right_x); number_clone(r->right_y, q->right_y); number_clone(r->x_coord, *x); number_clone(r->y_coord, *y); number_clone(q->right_x, q->x_coord); number_clone(q->right_y, q->y_coord); number_clone(r->left_x, r->x_coord); number_clone(r->left_y, r->y_coord); mp_left_type(r) = mp_explicit_knot; mp_right_type(r) = mp_explicit_knot; mp_originator(r) = mp_program_code; mp_knotstate(r) = mp_regular_knot; return r; } static void mp_find_direction_time (MP mp, mp_number *ret, mp_number *x_orig, mp_number *y_orig, mp_knot h) { mp_number max; mp_knot p, q; mp_number n; mp_number tt; mp_number abs_x, abs_y; mp_number x1, x2, x3, y1, y2, y3; mp_number phi; mp_number t; mp_number x, y; new_number(max); new_number(x1); new_number(x2); new_number(x3); new_number(y1); new_number(y2); new_number(y3); new_fraction(t); new_angle(phi); set_number_to_zero(*ret); new_number(x); new_number(y); new_number(abs_x); new_number(abs_y); new_number(n); new_fraction(tt); number_clone(x, *x_orig); number_clone(y, *y_orig); number_abs_clone(abs_x, *x_orig); number_abs_clone(abs_y, *y_orig); if (number_less(abs_x, abs_y)) { mp_number r1; new_fraction(r1); make_fraction(r1, x, abs_y); number_clone(x, r1); free_number(r1); if (number_positive(y)) { number_clone(y, fraction_one_t); } else { number_negated_clone(y, fraction_one_t); } } else if (number_zero(x)) { goto FREE; } else { mp_number r1; new_fraction(r1); make_fraction(r1, y, abs_x); number_clone(y, r1); free_number(r1); if (number_positive(x)) { number_clone(x, fraction_one_t); } else { number_negated_clone(x, fraction_one_t); } } p = h; while (1) { if (mp_right_type(p) == mp_endpoint_knot) { break; } else { q = mp_next_knot(p); set_number_to_zero(tt); { mp_number absval; new_number(absval); set_number_from_subtraction(x1, p->right_x, p->x_coord); set_number_from_subtraction(x2, q->left_x, p->right_x); set_number_from_subtraction(x3, q->x_coord, q->left_x); set_number_from_subtraction(y1, p->right_y, p->y_coord); set_number_from_subtraction(y2, q->left_y, p->right_y); set_number_from_subtraction(y3, q->y_coord, q->left_y); number_abs_clone(absval, x2); number_abs_clone(max, x1); if (number_greater(absval, max)) { number_clone(max, absval); } number_abs_clone(absval, x3); if (number_greater(absval, max)) { number_clone(max, absval); } number_abs_clone(absval, y1); if (number_greater(absval, max)) { number_clone(max, absval); } number_abs_clone(absval, y2); if (number_greater(absval, max)) { number_clone(max, absval); } number_abs_clone(absval, y3); if (number_greater(absval, max)) { number_clone(max, absval); } free_number(absval); if (number_zero(max)) { goto FOUND; } while (number_less(max, fraction_half_t)) { number_double(max); number_double(x1); number_double(x2); number_double(x3); number_double(y1); number_double(y2); number_double(y3); } number_clone(t, x1); { mp_number r1, r2; new_fraction(r1); new_fraction(r2); take_fraction(r1, x1, x); take_fraction(r2, y1, y); set_number_from_addition(x1, r1, r2); take_fraction(r1, y1, x); take_fraction(r2, t, y); set_number_from_subtraction(y1, r1, r2); number_clone(t, x2); take_fraction(r1, x2, x); take_fraction(r2, y2, y); set_number_from_addition(x2, r1, r2); take_fraction(r1, y2, x); take_fraction(r2, t, y); set_number_from_subtraction(y2, r1, r2); number_clone(t, x3); take_fraction(r1, x3 ,x); take_fraction(r2, y3, y); set_number_from_addition(x3, r1, r2); take_fraction(r1, y3, x); take_fraction(r2, t, y); set_number_from_subtraction(y3, r1, r2); free_number(r1); free_number(r2); } } if (number_zero(y1) && (number_zero(x1) || number_positive(x1))) { goto FOUND; } if (number_positive(n)) { mp_number theta; mp_number tmp; new_angle(theta); n_arg(theta, x1, y1); new_angle(tmp); set_number_from_subtraction(tmp, theta, one_eighty_deg_t); if (number_nonnegative(theta) && number_nonpositive(phi) && number_greaterequal(phi, tmp)) { free_number(tmp); free_number(theta); goto FOUND; } set_number_from_addition(tmp, theta, one_eighty_deg_t); if (number_nonpositive(theta) && number_nonnegative(phi) && number_lessequal(phi, tmp)) { free_number(tmp); free_number(theta); goto FOUND; } free_number(tmp); free_number(theta); if (p == h) { break; } } if (number_nonzero(x3) || number_nonzero(y3)) { n_arg(phi, x3, y3); } if (number_negative(x1) && number_negative(x2) && number_negative(x3)) { goto DONE; } { if (ab_vs_cd(y1, y3, y2, y2) == 0) { { if (ab_vs_cd(y1, y2, zero_t, zero_t) < 0) { mp_number tmp, arg2; new_number(tmp); new_number(arg2); set_number_from_subtraction(arg2, y1, y2); make_fraction(t, y1, arg2); free_number(arg2); set_number_from_of_the_way(x1, t, x1, x2); set_number_from_of_the_way(x2, t, x2, x3); set_number_from_of_the_way(tmp, t, x1, x2); if (number_zero(tmp) || number_positive(tmp)) { free_number(tmp); number_clone(tt, t); fraction_to_round_scaled(tt); goto FOUND; } else { free_number(tmp); } } else if (number_zero(y3)) { if (number_zero(y1)) { { mp_number arg1, arg2, arg3; new_number(arg1); new_number(arg2); new_number(arg3); number_negated_clone(arg1, x1); number_negated_clone(arg2, x2); number_negated_clone(arg3, x3); crossing_point(t, arg1, arg2, arg3); free_number(arg1); free_number(arg2); free_number(arg3); if (number_lessequal(t, fraction_one_t)) { number_clone(tt, t); fraction_to_round_scaled(tt); goto FOUND; } else if (ab_vs_cd(x1, x3, x2, x2) <= 0) { mp_number arg2; new_number(arg2); set_number_from_subtraction(arg2, x1, x2); make_fraction(t, x1, arg2); free_number(arg2); number_clone(tt, t); fraction_to_round_scaled(tt); goto FOUND; } } } else if (number_zero(x3) || number_positive(x3)) { set_number_to_unity(tt); goto FOUND; } } goto DONE; } } } if (number_zero(y1) || number_negative(y1)) { if (number_negative(y1)) { number_negate(y1); number_negate(y2); number_negate(y3); } else if (number_positive(y2)) { number_negate(y2); number_negate(y3); } } crossing_point(t, y1, y2, y3); if (number_greater(t, fraction_one_t)) { goto DONE; } set_number_from_of_the_way(y2, t, y2, y3); set_number_from_of_the_way(x1, t, x1, x2); set_number_from_of_the_way(x2, t, x2, x3); set_number_from_of_the_way(x1, t, x1, x2); if (number_zero(x1) || number_positive(x1)) { number_clone(tt, t); fraction_to_round_scaled(tt); goto FOUND; } if (number_positive(y2)) { set_number_to_zero(y2); } number_clone(tt, t); { mp_number arg1, arg2, arg3; new_number(arg1); new_number(arg2); new_number(arg3); number_negated_clone(arg2, y2); number_negated_clone(arg3, y3); crossing_point(t, arg1, arg2, arg3); free_number(arg1); free_number(arg2); free_number(arg3); } if (number_greater(t, fraction_one_t)) { goto DONE; } else { mp_number tmp; new_number(tmp); set_number_from_of_the_way(x1, t, x1, x2); set_number_from_of_the_way(x2, t, x2, x3); set_number_from_of_the_way(tmp, t, x1, x2); if (number_nonnegative(tmp)) { free_number(tmp); set_number_from_of_the_way(t, t, tt, fraction_one_t); number_clone(tt, t); fraction_to_round_scaled(tt); goto FOUND; } free_number(tmp); } DONE: p = q; number_add(n, unity_t); } } set_number_to_unity(*ret); number_negate(*ret); goto FREE; FOUND: set_number_from_addition(*ret, n, tt); goto FREE; FREE: free_number(x); free_number(y); free_number(abs_x); free_number(abs_y); free_number(x1); free_number(x2); free_number(x3); free_number(y1); free_number(y2); free_number(y3); free_number(t); free_number(phi); free_number(n); free_number(max); free_number(tt); } void mp_set_min_max (MP mp, int v) { if (number_negative(stack_1(v))) { if (number_nonnegative (stack_3(v))) { if (number_negative(stack_2(v))) { set_number_from_addition(stack_min(v), stack_1(v), stack_2(v)); } else { number_clone(stack_min(v), stack_1(v)); } set_number_from_addition(stack_max(v), stack_1(v), stack_2(v)); number_add(stack_max(v), stack_3(v)); if (number_negative(stack_max(v))) { set_number_to_zero(stack_max(v)); } } else { set_number_from_addition(stack_min(v), stack_1(v), stack_2(v)); number_add(stack_min(v), stack_3(v)); if (number_greater(stack_min(v), stack_1(v))) { number_clone(stack_min(v), stack_1(v)); } set_number_from_addition(stack_max(v), stack_1(v), stack_2(v)); if (number_negative(stack_max(v))) { set_number_to_zero(stack_max(v)); } } } else if (number_nonpositive(stack_3(v))) { if (number_positive(stack_2(v))) { set_number_from_addition(stack_max(v), stack_1(v), stack_2(v)); } else { number_clone(stack_max(v), stack_1(v)); } set_number_from_addition(stack_min(v), stack_1(v), stack_2(v)); number_add(stack_min(v), stack_3(v)); if (number_positive(stack_min(v))) { set_number_to_zero(stack_min(v)); } } else { set_number_from_addition(stack_max(v), stack_1(v), stack_2(v)); number_add(stack_max(v), stack_3(v)); if (number_less(stack_max(v), stack_1(v))) { number_clone(stack_max(v), stack_1(v)); } set_number_from_addition(stack_min(v), stack_1(v), stack_2(v)); if (number_positive(stack_min(v))) { set_number_to_zero(stack_min(v)); } } } static int mp_cubic_intersection(MP mp, mp_knot p, mp_knot pp, int run) { mp_knot q, qq; mp_number x_two_t; mp_number x_two_t_low_precision; mp->time_to_go = max_patience; set_number_from_scaled(mp->max_t, 2); new_number_clone(x_two_t, two_t); new_number(x_two_t_low_precision); number_double(x_two_t); number_double(x_two_t); set_number_from_double(x_two_t_low_precision, -0.5); number_add(x_two_t_low_precision, x_two_t); q = mp_next_knot(p); qq = mp_next_knot(pp); mp->bisect_ptr = int_packets; set_number_from_subtraction(u1r, p->right_x, p->x_coord); set_number_from_subtraction(u2r, q->left_x, p->right_x); set_number_from_subtraction(u3r, q->x_coord, q->left_x); mp_set_min_max(mp, ur_packet); set_number_from_subtraction(v1r, p->right_y, p->y_coord); set_number_from_subtraction(v2r, q->left_y, p->right_y); set_number_from_subtraction(v3r, q->y_coord, q->left_y); mp_set_min_max(mp, vr_packet); set_number_from_subtraction(x1r, pp->right_x, pp->x_coord); set_number_from_subtraction(x2r, qq->left_x, pp->right_x); set_number_from_subtraction(x3r, qq->x_coord, qq->left_x); mp_set_min_max(mp, xr_packet); set_number_from_subtraction(y1r, pp->right_y, pp->y_coord); set_number_from_subtraction(y2r, qq->left_y, pp->right_y); set_number_from_subtraction(y3r, qq->y_coord, qq->left_y); mp_set_min_max(mp, yr_packet); set_number_from_subtraction(mp->delx, p->x_coord, pp->x_coord); set_number_from_subtraction(mp->dely, p->y_coord, pp->y_coord); mp->tol = 0; mp->uv = r_packets; mp->xy = r_packets; mp->three_l = 0; set_number_from_scaled(mp->cur_t, 1); set_number_from_scaled(mp->cur_tt, 1); CONTINUE: while (1) { if (((x_packet (mp->xy))+4)>bistack_size || ((u_packet (mp->uv))+4)>bistack_size || ((y_packet (mp->xy))+4)>bistack_size || ((v_packet (mp->uv))+4)>bistack_size){ set_number_from_scaled(mp->cur_t,1); set_number_from_scaled(mp->cur_tt,1); goto NOT_FOUND; } if (number_greater(mp->max_t, x_two_t)){ set_number_from_scaled(mp->cur_t,1); set_number_from_scaled(mp->cur_tt,1); goto NOT_FOUND; } if (number_to_scaled(mp->delx) - mp->tol <= number_to_scaled(stack_max (x_packet (mp->xy))) - number_to_scaled(stack_min (u_packet (mp->uv)))) { if (number_to_scaled(mp->delx) + mp->tol >= number_to_scaled(stack_min (x_packet (mp->xy))) - number_to_scaled(stack_max (u_packet (mp->uv)))) { if (number_to_scaled(mp->dely) - mp->tol <= number_to_scaled(stack_max (y_packet (mp->xy))) - number_to_scaled(stack_min (v_packet (mp->uv)))) { if (number_to_scaled(mp->dely) + mp->tol >= number_to_scaled(stack_min (y_packet (mp->xy))) - number_to_scaled(stack_max (v_packet (mp->uv)))) { if (number_to_scaled(mp->cur_t) >= number_to_scaled(mp->max_t)) { if (number_equal(mp->max_t, x_two_t) || number_greater(mp->max_t, x_two_t_low_precision)) { if (run == 1) { number_divide_int(mp->cur_t,1<<2); number_divide_int(mp->cur_tt,1<<2); set_number_from_scaled(mp->cur_t, ((number_to_scaled(mp->cur_t) + 1)/2)); set_number_from_scaled(mp->cur_tt, ((number_to_scaled(mp->cur_tt) + 1)/2)); free_number(x_two_t); free_number(x_two_t_low_precision); return 1; } else { run--; goto NOT_FOUND; } } number_double(mp->max_t); number_clone(mp->appr_t, mp->cur_t); number_clone(mp->appr_tt, mp->cur_tt); } number_clone(stack_dx, mp->delx); number_clone(stack_dy, mp->dely); set_number_from_scaled(stack_tol, mp->tol); set_number_from_scaled(stack_uv, mp->uv); set_number_from_scaled(stack_xy, mp->xy); mp->bisect_ptr = mp->bisect_ptr + int_increment; number_double(mp->cur_t); number_double(mp->cur_tt); number_clone(u1l, stack_1(u_packet (mp->uv))); number_clone(u3r, stack_3(u_packet (mp->uv))); set_number_half_from_addition(u2l, u1l, stack_2(u_packet(mp->uv))); set_number_half_from_addition(u2r, u3r, stack_2(u_packet(mp->uv))); set_number_half_from_addition(u3l, u2l, u2r); number_clone(u1r, u3l); mp_set_min_max(mp, ul_packet); mp_set_min_max(mp, ur_packet); number_clone(v1l, stack_1(v_packet (mp->uv))); number_clone(v3r, stack_3(v_packet (mp->uv))); set_number_half_from_addition(v2l, v1l, stack_2(v_packet(mp->uv))); set_number_half_from_addition(v2r, v3r, stack_2(v_packet(mp->uv))); set_number_half_from_addition(v3l, v2l, v2r); number_clone(v1r, v3l); mp_set_min_max(mp, vl_packet); mp_set_min_max(mp, vr_packet); number_clone(x1l, stack_1(x_packet (mp->xy))); number_clone(x3r, stack_3(x_packet (mp->xy))); set_number_half_from_addition(x2l, x1l, stack_2(x_packet(mp->xy))); set_number_half_from_addition(x2r, x3r, stack_2(x_packet(mp->xy))); set_number_half_from_addition(x3l, x2l, x2r); number_clone(x1r, x3l); mp_set_min_max(mp, xl_packet); mp_set_min_max(mp, xr_packet); number_clone(y1l, stack_1(y_packet (mp->xy))); number_clone(y3r, stack_3(y_packet (mp->xy))); set_number_half_from_addition(y2l, y1l, stack_2(y_packet(mp->xy))); set_number_half_from_addition(y2r, y3r, stack_2(y_packet(mp->xy))); set_number_half_from_addition(y3l, y2l, y2r); number_clone(y1r, y3l); mp_set_min_max(mp, yl_packet); mp_set_min_max(mp, yr_packet); mp->uv = l_packets; mp->xy = l_packets; number_double(mp->delx); number_double(mp->dely); mp->tol = mp->tol - mp->three_l + (int) mp->tol_step; mp->tol += mp->tol; mp->three_l = mp->three_l + (int) mp->tol_step; goto CONTINUE; } } } } if (mp->time_to_go > 0) { --mp->time_to_go; } else { number_divide_int(mp->appr_t, 1<<2); number_divide_int(mp->appr_tt, 1<<2); while (number_less(mp->appr_t, unity_t)) { number_double(mp->appr_t); number_double(mp->appr_tt); } number_clone(mp->cur_t, mp->appr_t); number_clone(mp->cur_tt, mp->appr_tt); free_number(x_two_t); free_number(x_two_t_low_precision); return 2; } NOT_FOUND: if (odd(number_to_scaled(mp->cur_tt))) { if (odd(number_to_scaled(mp->cur_t))) { set_number_from_scaled(mp->cur_t, half (number_to_scaled(mp->cur_t))); set_number_from_scaled(mp->cur_tt, half (number_to_scaled(mp->cur_tt))); if (number_to_scaled(mp->cur_t) == 0) { free_number(x_two_t); free_number(x_two_t_low_precision); return 3; } else { mp->bisect_ptr -= int_increment; mp->three_l -= (int) mp->tol_step; number_clone(mp->delx, stack_dx); number_clone(mp->dely, stack_dy); mp->tol = number_to_scaled(stack_tol); mp->uv = number_to_scaled(stack_uv); mp->xy = number_to_scaled(stack_xy); goto NOT_FOUND; } } else { set_number_from_scaled(mp->cur_t, number_to_scaled(mp->cur_t) + 1); number_add(mp->delx, stack_1(u_packet (mp->uv))); number_add(mp->delx, stack_2(u_packet (mp->uv))); number_add(mp->delx, stack_3(u_packet (mp->uv))); number_add(mp->dely, stack_1(v_packet (mp->uv))); number_add(mp->dely, stack_2(v_packet (mp->uv))); number_add(mp->dely, stack_3(v_packet (mp->uv))); mp->uv = mp->uv + int_packets; set_number_from_scaled(mp->cur_tt, number_to_scaled(mp->cur_tt) - 1); mp->xy = mp->xy - int_packets; number_add(mp->delx, stack_1(x_packet (mp->xy))); number_add(mp->delx, stack_2(x_packet (mp->xy))); number_add(mp->delx, stack_3(x_packet (mp->xy))); number_add(mp->dely, stack_1(y_packet (mp->xy))); number_add(mp->dely, stack_2(y_packet (mp->xy))); number_add(mp->dely, stack_3(y_packet (mp->xy))); } } else { set_number_from_scaled(mp->cur_tt, number_to_scaled(mp->cur_tt) + 1); mp->tol = mp->tol + mp->three_l; number_subtract(mp->delx, stack_1(x_packet (mp->xy))); number_subtract(mp->delx, stack_2(x_packet (mp->xy))); number_subtract(mp->delx, stack_3(x_packet (mp->xy))); number_subtract(mp->dely, stack_1(y_packet (mp->xy))); number_subtract(mp->dely, stack_2(y_packet (mp->xy))); number_subtract(mp->dely, stack_3(y_packet (mp->xy))); mp->xy = mp->xy + int_packets; } } free_number(x_two_t); free_number(x_two_t_low_precision); } static mp_knot mp_path_intersection_add(MP mp, mp_knot list, mp_knot *last, mp_number *t, mp_number *tt) { int a = number_to_scaled(*t) >> intersection_run_shift; int aa = number_to_scaled(*tt) >> intersection_run_shift; int b = (list ? number_to_scaled((*last)->x_coord) : -1) >> intersection_run_shift ; int bb = (list ? number_to_scaled((*last)->y_coord) : -1) >> intersection_run_shift ; if (a == b && aa == bb) { } else { mp_knot k = mp_new_knot(mp); mp_left_type(k) = mp_explicit_knot; mp_right_type(k) = mp_explicit_knot; number_clone(k->x_coord, *t); number_clone(k->y_coord, *tt); if (list) { mp_prev_knot(k) = *last; mp_next_knot(*last) = k; mp_prev_knot(list) = k; mp_next_knot(k) = list; } else { list = k; mp_prev_knot(k) = k; mp_next_knot(k) = k; } *last = k; } return list; } static mp_knot mp_path_intersection(MP mp, mp_knot h, mp_knot hh, int path, mp_knot *last) { mp_number n, nn; int done = 0; mp_knot list = NULL; mp_knot l = NULL; mp_knot ll = NULL; if (last) { *last = NULL; } if (mp_right_type(h) == mp_endpoint_knot) { number_clone(h->right_x, h->x_coord); number_clone(h->left_x, h->x_coord); number_clone(h->right_y, h->y_coord); number_clone(h->left_y, h->y_coord); mp_right_type(h) = mp_explicit_knot; } if (mp_right_type(hh) == mp_endpoint_knot) { number_clone(hh->right_x, hh->x_coord); number_clone(hh->left_x, hh->x_coord); number_clone(hh->right_y, hh->y_coord); number_clone(hh->left_y, hh->y_coord); mp_right_type(hh) = mp_explicit_knot; } new_number(n); new_number(nn); mp->tol_step = 0; do { mp_knot p, pp; int t = -1; int tt = -1; number_negated_clone(n, unity_t); p = h; do { if (mp_right_type(p) != mp_endpoint_knot) { number_negated_clone(nn, unity_t); pp = hh; do { if (mp_right_type(pp) != mp_endpoint_knot) { int run = 0; int retrials = 0; RETRY: ++run; mp_cubic_intersection(mp, p, pp, run); if (number_positive(mp->cur_t)) { number_add(mp->cur_t, n); number_add(mp->cur_tt, nn); done = 1; if (path) { list = mp_path_intersection_add(mp, list, last, &(mp->cur_t), &(mp->cur_tt)); if (t == number_to_scaled(mp->cur_t) && tt == number_to_scaled(mp->cur_tt)) { if (retrials == 8) { break; } else { retrials += 1; goto RETRY; } } else { retrials = 0; t = number_to_scaled(mp->cur_t); tt = number_to_scaled(mp->cur_tt); goto RETRY; } } else { goto DONE; } } } number_add(nn, unity_t); ll = pp; pp = mp_next_knot(pp); } while (pp != hh); } number_add(n, unity_t); l = p; p = mp_next_knot(p); } while (p != h); mp->tol_step = mp->tol_step + 3; if (done) { goto DONE; } } while (mp->tol_step <= 3); DONE: if (path && l && ll && number_equal(l->x_coord, ll->x_coord) && number_equal(l->y_coord, ll->y_coord)) { list = mp_path_intersection_add(mp, list, last, &n, &nn); } if (! done) { number_negated_clone(mp->cur_t, unity_t); number_negated_clone(mp->cur_tt, unity_t); if (path && ! list) { mp_knot k = mp_new_knot(mp); number_clone(k->x_coord, mp->cur_t); number_clone(k->y_coord, mp->cur_tt); mp_prev_knot(k) = k; mp_next_knot(k) = k; list = k; if (last) { *last = k; } } } free_number(n); free_number(nn); return list; } static void mp_new_indep (MP mp, mp_node p) { (void) mp; if (mp->serial_no >= max_integer) { mp_fatal_error(mp, "Variable instance identifiers exhausted"); } p->type = mp_independent_type; mp->serial_no = mp->serial_no + 1; mp_set_indep_scale(p, 0); mp_set_indep_value(p, mp->serial_no); } inline static mp_node do_get_dep_info (MP mp, mp_value_node p) { (void) mp; mp_node d; d = p->parent; return d; } inline static void do_set_dep_value (MP mp, mp_value_node p, mp_number *q) { number_clone(p->data.n, *q); p->attr_head = NULL; p->subscr_head = NULL; } static mp_value_node mp_get_dep_node (MP mp) { mp_value_node p = (mp_value_node) mp_new_value_node(mp); p->type = mp_dep_node_type; return p; } static void mp_free_dep_node (MP mp, mp_value_node p) { mp_free_value_node(mp, (mp_node) p); } void mp_print_dependency (MP mp, mp_value_node p, int t) { mp_number v; mp_node q; mp_value_node pp = p; new_number(v); while (1) { number_abs_clone(v, mp_get_dep_value(p)); q = mp_get_dep_info(p); if (q == NULL) { if (number_nonzero(v) || (p == pp)) { if (number_positive(mp_get_dep_value(p)) && p != pp) { mp_print_chr(mp, '+'); } print_number(mp_get_dep_value(p)); } return; } if (number_negative(mp_get_dep_value(p))) { mp_print_chr(mp, '-'); } else if (p != pp) { mp_print_chr(mp, '+'); } if (t == mp_dependent_type) { fraction_to_round_scaled(v); } if (! number_equal(v, unity_t)) { print_number(v); } if (q->type != mp_independent_type) { mp_confusion(mp, "dependency"); } else { mp_print_variable_name(mp, q); set_number_from_scaled(v, mp_get_indep_scale(q)); while (number_positive(v)) { mp_print_str(mp, "*4"); number_add_scaled(v, -2); } p = (mp_value_node) p->link; } } } static void mp_max_coef (MP mp, mp_number *x, mp_value_node p) { mp_number absv; new_number(absv); set_number_to_zero(*x); while (mp_get_dep_info(p) != NULL) { number_abs_clone(absv, mp_get_dep_value(p)); if (number_greater(absv, *x)) { number_clone(*x, absv); } p = (mp_value_node) p->link; } free_number(absv); } static mp_value_node mp_p_plus_fq (MP mp, mp_value_node p, mp_number *f, mp_value_node q, mp_variable_type t, mp_variable_type tt ) { mp_node pp, qq; mp_value_node r, s; mp_number threshold; mp_number half_threshold; mp_number v, vv; new_number(v); new_number(vv); if (t == mp_dependent_type) { new_number_clone(threshold, fraction_threshold_k); new_number_clone(half_threshold, half_fraction_threshold_k); } else { new_number_clone(threshold, scaled_threshold_k); new_number_clone(half_threshold, half_scaled_threshold_k); } r = (mp_value_node) mp->temp_head; pp = mp_get_dep_info(p); qq = mp_get_dep_info(q); while (1) { if (pp == qq) { if (pp == NULL) { break; } else { mp_number r1; mp_number absv; new_fraction(r1); new_number(absv); if (tt == mp_dependent_type) { take_fraction(r1, *f, mp_get_dep_value(q)); } else { take_scaled(r1, *f, mp_get_dep_value(q)); } set_number_from_addition(v, mp_get_dep_value(p), r1); free_number(r1); mp_set_dep_value(p, v); s = p; p = (mp_value_node) p->link; number_abs_clone(absv, v); if (number_less(absv, threshold)) { mp_free_dep_node(mp, s); } else { if (number_greaterequal(absv, coef_bound_k) && mp->watch_coefs) { qq->type = independent_needing_fix; mp->fix_needed = 1; } mp_set_link(r, s); r = s; } free_number(absv); pp = mp_get_dep_info(p); q = (mp_value_node) q->link; qq = mp_get_dep_info(q); } } else { if (pp == NULL) { set_number_to_negative_inf(v); } else if (pp->type == mp_independent_type || (pp->type == independent_needing_fix && mp->fix_needed)) { set_number_from_scaled(v, mp_get_indep_value(pp)); } else { number_clone(v, mp_get_value_number(pp)); } if (qq == NULL) { set_number_to_negative_inf(vv); } else if (qq->type == mp_independent_type || (qq->type == independent_needing_fix && mp->fix_needed)) { set_number_from_scaled(vv, mp_get_indep_value(qq)); } else { number_clone(vv, mp_get_value_number(qq)); } if (number_less(v, vv)) { mp_number absv; { mp_number r1; mp_number arg1, arg2; new_fraction(r1); new_number_clone(arg1, *f); new_number_clone(arg2, mp_get_dep_value(q)); if (tt == mp_dependent_type) { take_fraction(r1, arg1, arg2); } else { take_scaled(r1, arg1, arg2); } number_clone(v, r1); free_number(r1); free_number(arg1); free_number(arg2); } new_number_abs(absv, v); if (number_greater(absv, half_threshold)) { s = mp_get_dep_node(mp); mp_set_dep_info(s, qq); mp_set_dep_value(s, v); if (number_greaterequal(absv, coef_bound_k) && mp->watch_coefs) { qq->type = independent_needing_fix; mp->fix_needed = 1; } mp_set_link(r, s); r = s; } q = (mp_value_node) q->link; qq = mp_get_dep_info(q); free_number(absv); } else { mp_set_link(r, p); r = p; p = (mp_value_node) p->link; pp = mp_get_dep_info(p); } } } { mp_number r1; mp_number arg1, arg2; new_fraction(r1); new_number(arg1); new_number(arg2); number_clone(arg1, mp_get_dep_value(q)); number_clone(arg2, *f); if (t == mp_dependent_type) { take_fraction(r1, arg1, arg2); } else { take_scaled(r1, arg1, arg2); } slow_add(arg1, mp_get_dep_value(p), r1); mp_set_dep_value(p, arg1); free_number(r1); free_number(arg1); free_number(arg2); } mp_set_link(r, p); mp->dep_final = p; free_number(threshold); free_number(half_threshold); free_number(v); free_number(vv); return (mp_value_node) mp->temp_head->link; } static mp_value_node mp_p_plus_q (MP mp, mp_value_node p, mp_value_node q, mp_variable_type t) { mp_node pp, qq; mp_value_node s; mp_value_node r; mp_number threshold; mp_number v, vv; new_number(v); new_number(vv); new_number(threshold); if (t == mp_dependent_type) { number_clone(threshold, fraction_threshold_k); } else { number_clone(threshold, scaled_threshold_k); } r = (mp_value_node) mp->temp_head; pp = mp_get_dep_info(p); qq = mp_get_dep_info(q); while (1) { if (pp == qq) { if (pp == NULL) { break; } else { mp_number test; new_number(test); set_number_from_addition(v, mp_get_dep_value(p), mp_get_dep_value(q)); mp_set_dep_value(p, v); s = p; p = (mp_value_node) p->link; pp = mp_get_dep_info(p); number_abs_clone(test, v); if (number_less(test, threshold)) { mp_free_dep_node(mp, s); } else { if (number_greaterequal(test, coef_bound_k) && mp->watch_coefs) { qq->type = independent_needing_fix; mp->fix_needed = 1; } mp_set_link(r, s); r = s; } free_number(test); q = (mp_value_node) q->link; qq = mp_get_dep_info(q); } } else { if (pp == NULL) { set_number_to_zero(v); } else if (pp->type == mp_independent_type || (pp->type == independent_needing_fix && mp->fix_needed)) { set_number_from_scaled(v, mp_get_indep_value(pp)); } else { number_clone(v, mp_get_value_number(pp)); } if (qq == NULL) { set_number_to_zero(vv); } else if (qq->type == mp_independent_type || (qq->type == independent_needing_fix && mp->fix_needed)) { set_number_from_scaled(vv, mp_get_indep_value(qq)); } else { number_clone(vv, mp_get_value_number(qq)); } if (number_less(v, vv)) { s = mp_get_dep_node(mp); mp_set_dep_info(s, qq); mp_set_dep_value(s, mp_get_dep_value(q)); q = (mp_value_node) q->link; qq = mp_get_dep_info(q); mp_set_link(r, s); r = s; } else { mp_set_link(r, p); r = p; p = (mp_value_node) p->link; pp = mp_get_dep_info(p); } } } { mp_number r1; new_number(r1); slow_add(r1, mp_get_dep_value(p), mp_get_dep_value(q)); mp_set_dep_value(p, r1); free_number(r1); } mp_set_link(r, p); mp->dep_final = p; free_number(v); free_number(vv); free_number(threshold); return (mp_value_node) mp->temp_head->link; } static mp_value_node mp_p_times_v (MP mp, mp_value_node p, mp_number *v, int t0, int t1, int v_is_scaled) { mp_value_node r, s; mp_number w; mp_number threshold; int scaling_down = (t0 != t1) ? 1 : (! v_is_scaled); new_number(threshold); new_number(w); if (t1 == mp_dependent_type) { number_clone(threshold, half_fraction_threshold_k); } else { number_clone(threshold, half_scaled_threshold_k); } r = (mp_value_node) mp->temp_head; while (mp_get_dep_info(p) != NULL) { mp_number test; new_number(test); if (scaling_down) { take_fraction(w, *v, mp_get_dep_value(p)); } else { take_scaled(w, *v, mp_get_dep_value(p)); } number_abs_clone(test, w); if (number_lessequal(test, threshold)) { s = (mp_value_node) p->link; mp_free_dep_node(mp, p); p = s; } else { if (number_greaterequal(test, coef_bound_k)) { mp->fix_needed = 1; mp_get_dep_info(p)->type = independent_needing_fix; } mp_set_link(r, p); r = p; mp_set_dep_value(p, w); p = (mp_value_node) p->link; } free_number(test); } mp_set_link(r, p); { mp_number r1; new_number(r1); if (v_is_scaled) { take_scaled(r1, mp_get_dep_value(p), *v); } else { take_fraction(r1, mp_get_dep_value(p), *v); } mp_set_dep_value(p, r1); free_number(r1); } free_number(w); free_number(threshold); return (mp_value_node) mp->temp_head->link; } mp_value_node mp_p_over_v (MP mp, mp_value_node p, mp_number *v_orig, int t0, int t1) { mp_value_node r, s; mp_number w; mp_number threshold; mp_number v; int scaling_down = (t0 != t1); new_number(w); new_number(threshold); new_number_clone(v, *v_orig); if (t1 == mp_dependent_type) { number_clone(threshold, half_fraction_threshold_k); } else { number_clone(threshold, half_scaled_threshold_k); } r = (mp_value_node) mp->temp_head; while (mp_get_dep_info(p) != NULL) { if (scaling_down) { mp_number x, absv; new_number_abs(absv, v); if (number_less(absv, p_over_v_threshold_k)) { new_number_clone(x, v); convert_scaled_to_fraction(x); make_scaled(w, mp_get_dep_value(p), x); } else { new_number_clone(x, mp_get_dep_value(p)); fraction_to_round_scaled(x); make_scaled(w, x, v); } free_number(x); free_number(absv); } else { make_scaled(w, mp_get_dep_value(p), v); } { mp_number test; new_number(test); number_abs_clone(test, w); if (number_lessequal(test, threshold)) { s = (mp_value_node) p->link; mp_free_dep_node(mp, p); p = s; } else { if (number_greaterequal(test, coef_bound_k)) { mp->fix_needed = 1; mp_get_dep_info(p)->type = independent_needing_fix; } mp_set_link(r, p); r = p; mp_set_dep_value(p, w); p = (mp_value_node) p->link; } free_number(test); } } mp_set_link(r, p); { mp_number ret; new_number(ret); make_scaled(ret, mp_get_dep_value(p), v); mp_set_dep_value(p, ret); free_number(ret); } free_number(v); free_number(w); free_number(threshold); return (mp_value_node) mp->temp_head->link; } static mp_value_node mp_p_with_x_becoming_q (MP mp, mp_value_node p, mp_node x, mp_node q, int t) { mp_value_node s = p; mp_value_node r = (mp_value_node) mp->temp_head; int sx = mp_get_indep_value(x); while (mp_get_dep_info(s) != NULL && mp_get_indep_value(mp_get_dep_info(s)) > sx) { r = s; s = (mp_value_node) s->link; } if (mp_get_dep_info(s) == NULL || mp_get_dep_info(s) != x) { return p; } else { mp_value_node ret; mp_number v1; mp_set_link(mp->temp_head, p); mp_set_link(r, s->link); new_number_clone(v1, mp_get_dep_value(s)); mp_free_dep_node(mp, s); ret = mp_p_plus_fq(mp, (mp_value_node) mp->temp_head->link, &v1, (mp_value_node) q, t, mp_dependent_type); free_number(v1); return ret; } } static void mp_val_too_big (MP mp, mp_number *x) { if (number_positive(internal_value(mp_warning_check_internal))) { char msg[256]; mp_snprintf(msg, 256, "Value is too large (%s)", number_tostring(*x)); mp_error( mp, msg, "The equation I just processed has given some variable a value outside of the\n" "safetyp range. Continue and I'll try to cope with that big value; but it might be\n" "dangerous. (Set 'warningcheck := 0' to suppress this message.)" ); } } void mp_make_known (MP mp, mp_value_node p, mp_value_node q) { mp_variable_type t = p->type; mp_number absp; new_number(absp); mp_set_prev_dep(q->link, mp_get_prev_dep(p)); mp_set_link(mp_get_prev_dep(p), q->link); p->type = mp_known_type; mp_set_value_number(p, mp_get_dep_value(q)); mp_free_dep_node(mp, q); number_abs_clone(absp, mp_get_value_number(p)); if (number_greaterequal(absp, warning_limit_t)) { mp_val_too_big (mp, &(mp_get_value_number(p))); } if ((number_positive(internal_value(mp_tracing_equations_internal))) && mp_interesting(mp, (mp_node) p)) { mp_begin_diagnostic(mp); mp_print_nl(mp, "#### "); mp_print_variable_name(mp, (mp_node) p); mp_print_chr(mp, '='); print_number(mp_get_value_number(p)); mp_end_diagnostic(mp, 0); } if (cur_exp_node == (mp_node) p && mp->cur_exp.type == t) { mp->cur_exp.type = mp_known_type; mp_set_cur_exp_value_number(mp, &(mp_get_value_number(p))); mp_free_value_node(mp, (mp_node) p); } free_number(absp); } static void mp_fix_dependencies (MP mp) { mp_value_node r = (mp_value_node) mp->dep_head->link; mp_value_node s = NULL; while (r != mp->dep_head) { mp_value_node t = r; mp_value_node q; while (1) { mp_node x; if (t == r) { q = (mp_value_node) mp_get_dep_list(t); } else { q = (mp_value_node) r->link; } x = mp_get_dep_info(q); if (x == NULL) { break; } else if (x->type <= independent_being_fixed) { if (x->type < independent_being_fixed) { mp_value_node p = mp_get_dep_node(mp); mp_set_link(p, s); s = p; mp_set_dep_info(s, x); x->type = independent_being_fixed; } mp_set_dep_value(q, mp_get_dep_value(q)); number_divide_int(mp_get_dep_value(q), 4); if (number_zero(mp_get_dep_value(q))) { mp_set_link(r, q->link); mp_free_dep_node(mp, q); q = r; } } r = q; } r = (mp_value_node) q->link; if (q == (mp_value_node) mp_get_dep_list(t)) { mp_make_known(mp, t, q); } } while (s != NULL) { mp_value_node p = (mp_value_node) s->link; mp_node x = mp_get_dep_info(s); mp_free_dep_node(mp, s); s = p; x->type = mp_independent_type; mp_set_indep_scale(x, mp_get_indep_scale(x) + 2); } mp->fix_needed = 0; } static void mp_new_dep (MP mp, mp_node q, mp_variable_type newtype, mp_value_node p) { mp_node r; q->type = newtype; mp_set_dep_list(q, p); mp_set_prev_dep(q, (mp_node) mp->dep_head); r = mp->dep_head->link; mp_set_link(mp->dep_final, r); mp_set_prev_dep(r, (mp_node) mp->dep_final); mp_set_link(mp->dep_head, q); } static mp_value_node mp_const_dependency (MP mp, mp_number *v) { mp->dep_final = mp_get_dep_node(mp); mp_set_dep_value(mp->dep_final, *v); mp_set_dep_info(mp->dep_final, NULL); return mp->dep_final; } static mp_value_node mp_single_dependency (MP mp, mp_node p) { mp_value_node q; int m = mp_get_indep_scale(p); if (m > 28) { q = mp_const_dependency(mp, &zero_t); } else { mp_value_node rr; q = mp_get_dep_node(mp); mp_set_dep_value(q, zero_t); set_number_from_scaled(mp_get_dep_value(q), (int) two_to_the(28 - m)); mp_set_dep_info(q, p); rr = mp_const_dependency(mp, &zero_t); mp_set_link(q, rr); } return q; } static mp_value_node mp_copy_dep_list (MP mp, mp_value_node p) { mp_value_node q = mp_get_dep_node(mp); mp->dep_final = q; while (1) { mp_set_dep_info(mp->dep_final, mp_get_dep_info(p)); mp_set_dep_value(mp->dep_final, mp_get_dep_value(p)); if (mp_get_dep_info(mp->dep_final) == NULL) { break; } else { mp_set_link(mp->dep_final, mp_get_dep_node(mp)); mp->dep_final = (mp_value_node) mp->dep_final->link; p = (mp_value_node) p->link; } } return q; } static mp_value_node find_node_with_largest_coefficient (MP mp, mp_value_node p, mp_number *v); static void display_new_dependency (MP mp, mp_value_node p, mp_node x, int n); static void change_to_known (MP mp, mp_value_node p, mp_node x, mp_value_node final_node, int n); static mp_value_node divide_p_by_minusv_removing_q (MP mp, mp_value_node p, mp_value_node q, mp_value_node *final_node, mp_number *v, int t ); static mp_value_node divide_p_by_2_n (MP mp, mp_value_node p, int n); static void mp_linear_eq (MP mp, mp_value_node p, int t) { mp_value_node r; mp_node x; int n; mp_number v; mp_value_node prev_r; mp_value_node final_node; mp_value_node qq; new_number(v); qq = find_node_with_largest_coefficient(mp, p, &v); x = mp_get_dep_info(qq); n = mp_get_indep_scale(x); p = divide_p_by_minusv_removing_q(mp, p, qq, &final_node, &v, t); if (number_positive(internal_value(mp_tracing_equations_internal))) { display_new_dependency(mp, p, (mp_node) x, n); } prev_r = (mp_value_node) mp->dep_head; r = (mp_value_node) mp->dep_head->link; while (r != mp->dep_head) { mp_value_node s = (mp_value_node) mp_get_dep_list(r); mp_value_node q = mp_p_with_x_becoming_q(mp, s, x, (mp_node) p, r->type); if (mp_get_dep_info(q) == NULL) { mp_make_known(mp, r, q); } else { mp_set_dep_list(r, q); do { q = (mp_value_node) q->link; } while (mp_get_dep_info(q) != NULL); prev_r = q; } r = (mp_value_node) prev_r->link; } if (n > 0) { p = divide_p_by_2_n(mp, p, n); } change_to_known(mp, p, (mp_node) x, final_node, n); if (mp->fix_needed) { mp_fix_dependencies(mp); } free_number(v); } static mp_value_node find_node_with_largest_coefficient (MP mp, mp_value_node p, mp_number *v) { mp_number vabs; mp_number rabs; mp_value_node q = p; mp_value_node r = (mp_value_node) p->link; new_number(vabs); new_number(rabs); number_clone(*v, mp_get_dep_value(q)); while (mp_get_dep_info(r) != NULL) { number_abs_clone(vabs, *v); number_abs_clone(rabs, mp_get_dep_value(r)); if (number_greater(rabs, vabs)) { q = r; number_clone(*v, mp_get_dep_value(r)); } r = (mp_value_node) r->link; } free_number(vabs); free_number(rabs); return q; } static mp_value_node divide_p_by_minusv_removing_q (MP mp, mp_value_node p, mp_value_node q, mp_value_node *final_node, mp_number *v, int t ) { mp_value_node r = p; mp_value_node s = (mp_value_node) mp->temp_head; mp_set_link(s, p); do { if (r == q) { mp_set_link(s, r->link); mp_free_dep_node(mp, r); } else { mp_number w; mp_number absw; new_number(w); new_number(absw); make_fraction(w, mp_get_dep_value(r), *v); number_abs_clone(absw, w); if (number_lessequal(absw, half_fraction_threshold_k)) { mp_set_link(s, r->link); mp_free_dep_node(mp, r); } else { number_negate(w); mp_set_dep_value(r, w); s = r; } free_number(w); free_number(absw); } r = (mp_value_node) s->link; } while (mp_get_dep_info(r) != NULL); if (t == mp_proto_dependent_type) { mp_number ret; new_number(ret); make_scaled(ret, mp_get_dep_value(r), *v); number_negate(ret); mp_set_dep_value(r, ret); free_number(ret); } else if (number_to_scaled(*v) != -number_to_scaled(fraction_one_t)) { mp_number ret; new_fraction(ret); make_fraction(ret, mp_get_dep_value(r), *v); number_negate(ret); mp_set_dep_value(r, ret); free_number(ret); } *final_node = r; return (mp_value_node) mp->temp_head->link; } static void display_new_dependency (MP mp, mp_value_node p, mp_node x, int n) { if (mp_interesting(mp, x)) { mp_begin_diagnostic(mp); mp_print_nl(mp, "## "); mp_print_variable_name(mp, x); while (n > 0) { mp_print_str(mp, "*4"); n = n - 2; } mp_print_chr(mp, '='); mp_print_dependency(mp, p, mp_dependent_type); mp_end_diagnostic(mp, 0); } } static mp_value_node divide_p_by_2_n (MP mp, mp_value_node p, int n) { mp_value_node pp = NULL; if (n > 0) { mp_value_node r; mp_value_node s; mp_number absw; mp_number w; new_number(w); new_number(absw); s = (mp_value_node) mp->temp_head; mp_set_link(mp->temp_head, p); r = p; do { if (n > 30) { set_number_to_zero(w); } else { number_clone(w, mp_get_dep_value(r)); number_divide_int(w, two_to_the(n)); } number_abs_clone(absw, w); if (number_lessequal(absw, half_fraction_threshold_k) && (mp_get_dep_info(r) != NULL)) { mp_set_link(s, r->link); mp_free_dep_node(mp, r); } else { mp_set_dep_value(r, w); s = r; } r = (mp_value_node) s->link; } while (mp_get_dep_info(s) != NULL); pp = (mp_value_node) mp->temp_head->link; free_number(absw); free_number(w); } return pp; } static void change_to_known (MP mp, mp_value_node p, mp_node x, mp_value_node final_node, int n) { (void) n; if (mp_get_dep_info(p) == NULL) { mp_number absx; x->type = mp_known_type; mp_set_value_number(x, mp_get_dep_value(p)); new_number_abs(absx, mp_get_value_number(x)); if (number_greaterequal(absx, warning_limit_t)) { mp_val_too_big(mp, &(mp_get_value_number(x))); } free_number(absx); mp_free_dep_node(mp, p); if (cur_exp_node == x && mp->cur_exp.type == mp_independent_type) { mp_set_cur_exp_value_number(mp, &(mp_get_value_number(x))); mp->cur_exp.type = mp_known_type; mp_free_value_node(mp, x); } } else { mp->dep_final = final_node; mp_new_dep(mp, x, mp_dependent_type, p); if (cur_exp_node == x && mp->cur_exp.type == mp_independent_type) { mp->cur_exp.type = mp_dependent_type; } } } static mp_node mp_new_ring_entry (MP mp, mp_node p) { mp_node q = mp_new_value_node(mp); q->name_type = mp_capsule_operation; q->type = p->type; if (mp_get_value_node(p) == NULL) { mp_set_value_node(q, p); } else { mp_set_value_node(q, mp_get_value_node(p)); } mp_set_value_node(p, q); return q; } void mp_ring_delete (MP mp, mp_node p) { (void) mp; mp_node q = mp_get_value_node(p); if (q != NULL && q != p) { while (mp_get_value_node(q) != p) { q = mp_get_value_node(q); } mp_set_value_node(q, mp_get_value_node(p)); } } static void mp_nonlinear_eq (MP mp, mp_value v, mp_node p, int flush_p) { mp_variable_type t = p->type - unknown_tag; mp_node q = mp_get_value_node(p); if (flush_p) { p->type = mp_vacuous_type; } else { p = q; } do { mp_node r = mp_get_value_node(q); q->type = t; switch (t) { case mp_boolean_type: mp_set_value_number(q, v.data.n); break; case mp_string_type: mp_set_value_str(q, v.data.str); add_str_ref(v.data.str); break; case mp_pen_type: case mp_nep_type: mp_set_value_knot(q, mp_copy_pen(mp, v.data.p)); break; case mp_path_type: mp_set_value_knot(q, mp_copy_path(mp, v.data.p)); break; case mp_picture_type: mp_set_value_node(q, v.data.node); mp_add_edge_ref(mp, v.data.node); break; default: break; } q = r; } while (q != p); } static void mp_ring_merge (MP mp, mp_node p, mp_node q) { mp_node r = mp_get_value_node(p); while (r != p) { if (r == q) { mp_exclaim_redundant_equation(mp); return; } else { r = mp_get_value_node(r); } } r = mp_get_value_node(p); mp_set_value_node(p, mp_get_value_node(q)); mp_set_value_node(q, r); } static void mp_exclaim_redundant_equation (MP mp) { mp_back_error( mp, "Redundant equation", "I already knew that this equation was true. But perhaps no harm has been done;\n" "let's continue." ); mp_get_x_next(mp); } const char *mp_cmd_mod_string (MP mp, int c, int m) { switch (c) { case mp_add_to_command: return "addto"; case mp_assignment_command: return ":="; case mp_at_least_command: return "atleast"; case mp_begin_group_command: return "begingroup"; case mp_colon_command: return ":"; case mp_comma_command: return ","; case mp_controls_command: return "controls"; case mp_curl_command: return "curl"; case mp_delimiters_command: return "delimiters"; case mp_end_group_command: return "endgroup"; case mp_every_job_command: return "everyjob"; case mp_exit_test_command: return "exitif"; case mp_expand_after_command: return "expandafter"; case mp_interim_command: return "interim"; case mp_left_brace_command: return "{"; case mp_left_bracket_command: return "["; case mp_let_command: return "let"; case mp_new_internal_command: return "newinternal"; case mp_of_command: return "of"; case mp_path_join_command: return ".."; case mp_relax_command: return "\\"; case mp_right_brace_command: return "}"; case mp_right_bracket_command: return "]"; case mp_save_command: return "save"; case mp_scan_tokens_command: return "scantokens"; case mp_runscript_command: return "runscript"; case mp_maketext_command: return "maketext"; case mp_semicolon_command: return ";"; case mp_ship_out_command: return "shipout"; case mp_step_command: return "step"; case mp_str_command: return "str"; case mp_void_command: return "void"; case mp_tension_command: return "tension"; case mp_to_command: return "to"; case mp_until_command: return "until"; case mp_within_command: return "within"; case mp_write_command: return "write"; case mp_btex_command: return m == mp_btex_code ? "btex" : "verbatimtex"; case mp_etex_command: return "etex"; case mp_macro_def_command: switch (m) { case mp_end_def_code : return "enddef"; case mp_def_code : return "def"; case mp_var_def_code : return "vardef"; case mp_primary_def_code : return "primarydef"; case mp_secondary_def_code: return "secondarydef"; case mp_tertiary_def_code : return "tertiarydef"; default: return "?def"; } break; case mp_iteration_command: switch (m) { case mp_end_for_code : return "endfor"; case mp_start_forever_code : return "forever"; case mp_start_for_code : return "for"; case mp_start_forsuffixes_code: return "forsuffixes"; } break; case mp_only_set_command: switch (m) { case mp_random_seed_code : return"randomseed"; case mp_max_knot_pool_code: return"maxknotpool"; } break; case mp_macro_special_command: switch (m) { case mp_macro_prefix_code: return "#@"; case mp_macro_at_code : return "@"; case mp_macro_suffix_code: return "@#"; case mp_macro_quote_code : return "quote"; } break; case mp_parameter_commmand: switch (m) { case mp_expr_parameter : return "expr"; case mp_suffix_parameter: return "suffix"; case mp_text_parameter : return "text"; case mp_primary_macro : return "primary"; case mp_secondary_macro : return "secondary"; default : return "tertiary"; } break; case mp_input_command: return m == 0 ? "input" : "endinput"; case mp_if_test_command: case mp_fi_or_else_command: switch (m) { case mp_if_code : return "if"; case mp_fi_code : return "fi"; case mp_else_code : return "else"; case mp_else_if_code: return "elseif"; } break; case mp_nullary_command: case mp_unary_command: case mp_of_binary_command: case mp_secondary_binary_command: case mp_tertiary_binary_command: case mp_primary_binary_command: case mp_cycle_command: case mp_plus_or_minus_command: case mp_slash_command: case mp_ampersand_command: case mp_equals_command: case mp_and_command: return mp_op_string((int) m); case mp_type_name_command: return ""; case mp_stop_command: return cur_mod == 0 ? "end" : "dump"; case mp_mode_command: switch (m) { case mp_batch_mode : return "batchmode"; case mp_nonstop_mode : return "nonstopmode"; case mp_scroll_mode : return "scrollmode"; case mp_error_stop_mode: return "errorstopmode"; default : return "silentmode"; } break; case mp_protection_command: switch (m) { case 0: return "inner"; case 1: return "outer"; } break; case mp_property_command: return "setproperty"; case mp_show_command: switch (m) { case mp_show_token_code : return "showtoken"; case mp_show_stats_code : return "showstats"; case mp_show_code : return "show"; case mp_show_var_code : return "showvariable"; case mp_show_dependencies_code: return "showdependencies"; } break; case mp_left_delimiter_command: case mp_right_delimiter_command: return c == mp_left_delimiter_command ? "left delimiter" : "right delimiter"; case mp_tag_command: return m == 0 ? "tag" : "variable"; case mp_defined_macro_command: return "macro:"; case mp_primary_def_command: return "primarydef"; case mp_secondary_def_command: return "secondarydef"; case mp_tertiary_def_command: return "tertiarydef"; case mp_repeat_loop_command: return "[repeat the loop]"; case mp_internal_command: return internal_name(m); case mp_thing_to_add_command: switch (m) { case mp_add_contour_code : return "contour"; case mp_add_double_path_code: return "doublepath"; case mp_add_also_code : return "also"; } break; case mp_with_option_command: switch (m) { case mp_with_pen_code : return "withpen"; case mp_with_pre_script_code : return "withprescript"; case mp_with_post_script_code : return "withpostscript"; case mp_with_stacking_code : return "withstacking"; case mp_with_no_model_code : return "withoutcolor"; case mp_with_rgb_model_code : return "withrgbcolor"; case mp_with_uninitialized_model_code: return "withcolor"; case mp_with_cmyk_model_code : return "withcmykcolor"; case mp_with_grey_model_code : return "withgreyscale"; case mp_with_linecap_code : return "withlinecap"; case mp_with_linejoin_code : return "withlinejoin"; case mp_with_miterlimit_code : return "withmiterlimit"; default : return "dashed"; } break; case mp_bounds_command: switch (m) { case mp_start_clip_node_type : return "clip"; case mp_start_group_node_type : return "setgroup"; case mp_start_bounds_node_type: return "setbounds"; } break; case mp_message_command: if (m < err_message_code) { return "message"; } else if (m == err_message_code) { return "errmessage"; } else { return "errhelp"; } } return "[unknown command code!]"; } void mp_print_cmd_mod (MP mp, int c, int m) { mp_print_str(mp, mp_cmd_mod_string(mp, c, m)); } static void mp_show_cmd_mod (MP mp, int c, int m) { mp_begin_diagnostic(mp); mp_print_nl(mp, "{"); switch (c) { case mp_primary_def_command: case mp_secondary_def_command: case mp_tertiary_def_command: mp_print_cmd_mod(mp, mp_macro_def_command, c); mp_print_str(mp, "'d macro:"); mp_print_ln(mp); mp_show_token_list(mp, cur_mod_node->link->link,0); break; default: mp_print_cmd_mod(mp, c, m); break; } mp_print_chr(mp, '}'); mp_end_diagnostic(mp, 0); } static void mp_reallocate_input_stack (MP mp, int newsize) { int n = newsize + 1; mp->input_file = mp_memory_reallocate(mp->input_file, (size_t) (n + 1) * sizeof(void *)); mp->line_stack = mp_memory_reallocate(mp->line_stack, (size_t) (n + 1) * sizeof(int)); for (int k = mp->max_in_open; k <= n; k++) { mp->input_file[k] = NULL; mp->line_stack[k] = 0; } mp->max_in_open = newsize; } static void mp_check_param_size (MP mp, int k) { while (k >= mp->param_size) { mp->param_stack = mp_memory_reallocate(mp->param_stack, (size_t) ((k + k / 4) + 1) * sizeof(mp_node)); mp->param_size = k + k / 4; } } int mp_true_line (MP mp) { int k; if (file_state && (name > max_spec_src)) { return line; } else { k = mp->input_ptr; while ((k > 0) && ((mp->input_stack[(k - 1)].index_field < mp_file_bottom_text) || (mp->input_stack[(k - 1)].name_field <= max_spec_src))) { --k; } return (k > 0 ? mp->line_stack[(k - 1) + mp_file_bottom_text] : 0); } } void mp_show_context (MP mp) { mp->file_ptr = mp->input_ptr; mp->input_stack[mp->file_ptr] = mp->cur_input; while (1) { mp->cur_input = mp->input_stack[mp->file_ptr]; if ((mp->file_ptr == mp->input_ptr) || file_state || (token_type != mp_backed_up_text) || (nloc != NULL)) { if (file_state) { if (name > max_spec_src) { mp_print_nl(mp, "'); } else if (terminal_input) { if (mp->file_ptr == 0) { mp_print_nl(mp, ""); } else { mp_print_nl(mp, ""); } } else if (name == is_scantok) { mp_print_nl(mp, ""); } else { mp_print_nl(mp, ""); } mp_print_chr(mp, ' '); if (limit > 0) { for (int i = start; i <= limit - 1; i++) { mp_print_chr(mp, mp->buffer[i]); } } } else { { switch (token_type) { case mp_forever_text: mp_print_nl(mp, " "); break; case mp_loop_text: { mp_node pp = mp->param_stack[param_start]; mp_print_nl(mp, "link == MP_VOID) { mp_print_exp(mp, pp, 0); } else { mp_show_token_list(mp, pp, NULL); } } mp_print_str(mp, ")> "); } break; case mp_parameter_text: mp_print_nl(mp, " "); break; case mp_backed_up_text: mp_print_nl(mp, nloc == NULL ? " " : " "); break; case mp_inserted_text: mp_print_nl(mp, " "); break; case mp_macro_text: mp_print_nl(mp, " "); if (name != NULL) { mp_print_mp_str(mp, name); } else { { mp_node pp = mp->param_stack[param_start]; if (pp == NULL) { mp_show_token_list(mp, mp->param_stack[param_start + 1], NULL); } else { mp_node qq = pp; while (qq->link != NULL) { qq = qq->link; } qq->link = mp->param_stack[param_start + 1]; mp_show_token_list(mp, pp, NULL); qq->link = NULL; } } } mp_print_str(mp, " -> "); break; default: mp_print_nl(mp, "?"); break; } } if (token_type == mp_macro_text) { mp_show_macro(mp, nstart, nloc); } else if (mp->show_mode) { mp_show_token_list_space(mp, nstart, nloc); } else { mp_show_token_list(mp, nstart, nloc); } } } if (file_state && (name > max_spec_src || mp->file_ptr == 0)) { break; } else { --mp->file_ptr; } } mp->cur_input = mp->input_stack[mp->input_ptr]; } void mp_push_input (MP mp) { if (mp->input_ptr > mp->max_in_stack) { mp->max_in_stack = mp->input_ptr; if (mp->input_ptr == mp->stack_size) { int l = (mp->stack_size + (mp->stack_size/4)); if (l > 1000) { mp_fatal_error(mp, "job aborted, more than 1000 input levels"); } else { mp_in_state_record *s = mp_memory_reallocate(mp->input_stack, (size_t) (l + 1) * sizeof(mp_in_state_record)); if (s) { mp->input_stack = s; mp->stack_size = l; } else { mp_fatal_error(mp, "job aborted, out of memory"); } } } } mp->input_stack[mp->input_ptr] = mp->cur_input; ++mp->input_ptr; } void mp_pop_input (MP mp) { --mp->input_ptr; mp->cur_input = mp->input_stack[mp->input_ptr]; } static void mp_begin_token_list (MP mp, mp_node p, int t) { mp_push_input(mp); nstart = p; token_type = t; param_start = mp->param_ptr; nloc = p; } static void mp_end_token_list (MP mp) { if (token_type >= mp_backed_up_text) { if (token_type <= mp_inserted_text) { mp_flush_token_list(mp, nstart); goto DONE; } else { mp_delete_mac_ref(mp, nstart); } } while (mp->param_ptr > param_start) { mp_node p; --mp->param_ptr; p = mp->param_stack[mp->param_ptr]; if (p != NULL) { if (p->link == MP_VOID) { mp_recycle_value(mp, p); mp_free_value_node(mp, p); } else { mp_flush_token_list(mp, p); } } } DONE: mp_pop_input(mp); } static void mp_encapsulate (MP mp, mp_value_node p) { mp_node q = mp_new_value_node(mp); q->name_type = mp_capsule_operation; mp_new_dep(mp, q, mp->cur_exp.type, p); mp_set_cur_exp_node(mp, q); } static void mp_install (MP mp, mp_node r, mp_node q) { if (q->type == mp_known_type) { r->type = mp_known_type; mp_set_value_number(r, mp_get_value_number(q)); } else if (q->type == mp_independent_type) { mp_value_node p = mp_single_dependency(mp, q); if (p == mp->dep_final) { r->type = mp_known_type; mp_set_value_number(r, zero_t); mp_free_dep_node(mp, p); } else { mp_new_dep(mp, r, mp_dependent_type, p); } } else { mp_new_dep(mp, r, q->type, mp_copy_dep_list(mp, (mp_value_node) mp_get_dep_list((mp_value_node) q))); } } static void mp_make_exp_copy (MP mp, mp_node p) { RESTART: mp->cur_exp.type = p->type; switch (mp->cur_exp.type) { case mp_vacuous_type: case mp_boolean_type: case mp_known_type: mp_set_cur_exp_value_number(mp, &(mp_get_value_number(p))); break; case mp_unknown_boolean_type: case mp_unknown_string_type: case mp_unknown_pen_type: case mp_unknown_nep_type: case mp_unknown_path_type: case mp_unknown_picture_type: { mp_node t = mp_new_ring_entry(mp, p); mp_set_cur_exp_node(mp, t); } break; case mp_string_type: mp_set_cur_exp_str(mp, mp_get_value_str(p)); break; case mp_picture_type: mp_set_cur_exp_node(mp, mp_get_value_node(p)); mp_add_edge_ref(mp, cur_exp_node); break; case mp_pen_type: case mp_nep_type: mp_set_cur_exp_knot(mp, mp_copy_pen(mp, mp_get_value_knot(p))); break; case mp_path_type: mp_set_cur_exp_knot(mp, mp_copy_path(mp, mp_get_value_knot(p))); break; case mp_transform_type: case mp_color_type: case mp_cmykcolor_type: case mp_pair_type: { mp_node t; mp_value_node q; if (mp_get_value_node(p) == NULL) { switch (p->type) { case mp_pair_type: mp_init_pair_node(mp, p); break; case mp_color_type: mp_init_color_node(mp, p, mp_color_type); break; case mp_cmykcolor_type: mp_init_color_node(mp, p, mp_cmykcolor_type); break; case mp_transform_type: mp_init_transform_node(mp, p); break; default: break; } } t = mp_new_value_node(mp); t->name_type = mp_capsule_operation; q = (mp_value_node) mp_get_value_node(p); switch (mp->cur_exp.type) { case mp_pair_type: mp_init_pair_node(mp, t); mp_install(mp, mp_y_part(mp_get_value_node(t)), mp_y_part(q)); mp_install(mp, mp_x_part(mp_get_value_node(t)), mp_x_part(q)); break; case mp_color_type: mp_init_color_node(mp, t, mp_color_type); mp_install(mp, mp_blue_part(mp_get_value_node(t)), mp_blue_part(q)); mp_install(mp, mp_green_part(mp_get_value_node(t)), mp_green_part(q)); mp_install(mp, mp_red_part(mp_get_value_node(t)), mp_red_part(q)); break; case mp_cmykcolor_type: mp_init_color_node(mp, t, mp_cmykcolor_type); mp_install(mp, mp_black_part(mp_get_value_node(t)), mp_black_part(q)); mp_install(mp, mp_yellow_part(mp_get_value_node(t)), mp_yellow_part(q)); mp_install(mp, mp_magenta_part(mp_get_value_node(t)), mp_magenta_part(q)); mp_install(mp, mp_cyan_part(mp_get_value_node(t)), mp_cyan_part(q)); break; case mp_transform_type: mp_init_transform_node(mp, t); mp_install(mp, mp_yy_part(mp_get_value_node(t)), mp_yy_part(q)); mp_install(mp, mp_yx_part(mp_get_value_node(t)), mp_yx_part(q)); mp_install(mp, mp_xy_part(mp_get_value_node(t)), mp_xy_part(q)); mp_install(mp, mp_xx_part(mp_get_value_node(t)), mp_xx_part(q)); mp_install(mp, mp_ty_part(mp_get_value_node(t)), mp_ty_part(q)); mp_install(mp, mp_tx_part(mp_get_value_node(t)), mp_tx_part(q)); break; default: break; } mp_set_cur_exp_node(mp, t); } break; case mp_dependent_type: case mp_proto_dependent_type: mp_encapsulate (mp, mp_copy_dep_list(mp, (mp_value_node) mp_get_dep_list((mp_value_node) p))); break; case mp_numeric_type: mp_new_indep(mp, p); goto RESTART; case mp_independent_type: { mp_value_node q = mp_single_dependency(mp, p); if (q == mp->dep_final) { mp->cur_exp.type = mp_known_type; mp_set_cur_exp_value_number(mp, &zero_t); mp_free_dep_node(mp, q); } else { mp->cur_exp.type = mp_dependent_type; mp_encapsulate (mp, q); } } break; case mp_undefined_type: mp_confusion(mp, "undefined copy"); break; default: mp_confusion(mp, "copy"); break; } } static mp_node mp_cur_tok (MP mp) { mp_node p; if (cur_sym == NULL && (cur_sym_mod == 0 || cur_sym_mod == mp_normal_operation)) { if (cur_cmd == mp_capsule_command) { mp_number save_exp_num; mp_value save_exp = mp->cur_exp; new_number(save_exp_num); number_clone(save_exp_num, cur_exp_value_number); mp_make_exp_copy(mp, cur_mod_node); p = mp_stash_cur_exp(mp); p->link = NULL; mp->cur_exp = save_exp; number_clone(mp->cur_exp.data.n, save_exp_num); free_number(save_exp_num); } else { p = mp_new_token_node(mp); p->name_type = mp_token_operation; if (cur_cmd == mp_numeric_command) { mp_set_value_number(p, cur_mod_number); p->type = mp_known_type; } else { mp_set_value_str(p, cur_mod_str); p->type = mp_string_type; } } } else { p = mp_new_symbolic_node(mp); mp_set_sym_sym(p, cur_sym); p->name_type = cur_sym_mod; } return p; } void mp_back_input (MP mp) { mp_node p = mp_cur_tok(mp); while (token_state && (nloc == NULL)) { mp_end_token_list(mp); } mp_begin_token_list(mp, p, mp_backed_up_text); } static void mp_back_error (MP mp, const char *msg, const char *hlp) { mp_back_input(mp); mp_error(mp, msg, hlp); } static void mp_ins_error (MP mp, const char *msg, const char *hlp) { mp_back_input(mp); token_type = mp_inserted_text; mp_error(mp, msg, hlp); } void mp_begin_file_reading (MP mp) { if (mp->in_open == (mp->max_in_open-1)) { mp_reallocate_input_stack (mp, (mp->max_in_open + mp->max_in_open / 4)); } if (mp->first == mp->buf_size) { mp_reallocate_buffer(mp, (mp->buf_size + mp->buf_size / 4)); } mp->in_open++; mp_push_input(mp); iindex = (int) mp->in_open; if (mp->in_open_max < mp->in_open) { mp->in_open_max = mp->in_open; } start = (int) mp->first; name = is_term; } static void mp_end_file_reading (MP mp) { if (mp->in_open > iindex) { if ((name <= max_spec_src)) { mp_confusion(mp, "endinput"); } else { (mp->close_file) (mp, mp->input_file[mp->in_open]); --mp->in_open; } } mp->first = (size_t) start; if (iindex != mp->in_open) { mp_confusion(mp, "endinput"); } else { if (name > max_spec_src) { (mp->close_file) (mp, cur_file); } mp_pop_input(mp); --mp->in_open; } } static int mp_check_outer_validity (MP mp) { if (mp->scanner_status == mp_normal_state) { return 1; } else if (mp->scanner_status == mp_tex_flushing_state) { if (cur_sym != NULL) { return 1; } else { char msg[256]; mp_snprintf(msg, 256, "TeX mode didn't end; all text was ignored after line %d", (int) mp->warning_line); set_cur_sym(mp->frozen_etex); mp_ins_error( mp, msg, "The file ended while I was looking for the 'etex' to finish this TeX material.\n" "I've inserted 'etex' now." ); return 0; } } else { if (mp->scanner_status > mp_skipping_state) { { char msg[256]; const char *mst = NULL; const char *hlp = "I suspect you have forgotten an 'enddef', causing me to read past where you\n" "wanted me to stop. I'll try to recover."; mp_runaway(mp); if (cur_sym == NULL) { mst = "File ended while scanning"; } else { mst = "Forbidden token found while scanning"; } switch (mp->scanner_status) { case mp_flushing_state: { mp_snprintf(msg, 256, "%s to the end of the statement", mst); hlp = "A previous error seems to have propagated, causing me to read past where\n" "you wanted me to stop. I'll try to recover."; set_cur_sym(mp->frozen_semicolon); } break; case mp_absorbing_state: { mp_snprintf(msg, 256, "%s a text argument", mst); hlp = "It seems that a right delimiter was left out, causing me to read past where\n" "you wanted me to stop. I'll try to recover."; if (mp->warning_info == NULL) { set_cur_sym(mp->frozen_end_group); } else { set_cur_sym(mp->frozen_right_delimiter); set_equiv_sym(cur_sym, mp->warning_info); } } break; case mp_var_defining_state: { mp_string s; int selector = mp->selector; mp->selector = mp_new_string_selector; mp_print_variable_name(mp, mp->warning_info_node); s = mp_make_string(mp); mp->selector = selector; mp_snprintf(msg, 256, "%s the definition of %s", mst, s->str); delete_str_ref(s); set_cur_sym(mp->frozen_end_def); } break; case mp_op_defining_state: { char *s = mp_str(mp, text(mp->warning_info)); mp_snprintf(msg, 256, "%s the definition of %s", mst, s); set_cur_sym(mp->frozen_end_def); } break; case mp_loop_defining_state: { char *s = mp_str(mp, text(mp->warning_info)); mp_snprintf(msg, 256, "%s the text of a %s loop", mst, s); hlp = "I suspect you have forgotten an 'endfor', causing me to read past where\n" "you wanted me to stop. I'll try to recover."; set_cur_sym(mp->frozen_end_for); } break; } mp_ins_error(mp, msg, hlp); } } else { char msg[256]; const char *hlp = NULL; mp_snprintf(msg, 256, "Incomplete if; all text was ignored after line %d", (int) mp->warning_line); if (cur_sym == NULL) { hlp = "The file ended while I was skipping conditional text. This kind of error happens\n" "when you say 'if ...' and forget the matching 'fi'. I've inserted a 'fi'; this\n" "might work."; } else { hlp = "A forbidden 'outer' token occurred in skipped text. This kind of error happens\n" "when you say 'if ...' and forget the matching 'fi'. I've inserted a 'fi'; this\n" "might work."; } set_cur_sym(mp->frozen_fi); mp_ins_error(mp, msg, hlp); } return 0; } } void mp_runaway (MP mp) { if (mp->scanner_status > mp_flushing_state) { mp_print_nl(mp, "Runaway "); switch (mp->scanner_status) { case mp_absorbing_state: mp_print_str(mp, "text?"); break; case mp_var_defining_state: case mp_op_defining_state: mp_print_str(mp, "definition?"); break; case mp_loop_defining_state: mp_print_str(mp, "loop?"); break; } mp_print_ln(mp); mp_show_token_list(mp, mp->hold_head->link, NULL); } } void mp_get_next (MP mp) { mp_sym cur_sym_; RESTART: set_cur_sym(NULL); set_cur_sym_mod(0); if (file_state) { int k; unsigned char c; int cclass; SWITCH: c = mp->buffer[loc]; ++loc; cclass = mp->char_class[c]; switch (cclass) { case mp_digit_class: scan_numeric_token((c - '0')); return; case mp_period_class: cclass = mp->char_class[mp->buffer[loc]]; if (cclass > mp_period_class) { goto SWITCH; } else if (cclass < mp_period_class) { scan_fractional_token(0); return; } else { break; } case mp_space_class: goto SWITCH; case mp_percent_class: if (mp->scanner_status == mp_tex_flushing_state && loc < limit) { goto SWITCH; } if (mp_move_to_next_line(mp)) { goto RESTART; } else { goto SWITCH; } case mp_string_class: if (mp->scanner_status == mp_tex_flushing_state) { goto SWITCH; } else { unsigned char cend = c == '"' ? '"' : 3 ; if (mp->buffer[loc] == cend) { set_cur_mod_str(mp_rts(mp,"")); } else { k = loc; mp->buffer[limit + 1] = cend; do { ++loc; } while (mp->buffer[loc] != cend); if (loc > limit) { loc = limit; mp_error( mp, "Incomplete string token has been flushed", "Strings should finish on the same line as they began. I've deleted the partial\n" "string." ); goto RESTART; } mp_str_room(mp, loc - k); do { mp_append_char(mp, mp->buffer[k]); ++k; } while (k != loc); set_cur_mod_str(mp_make_string(mp)); } ++loc; set_cur_cmd(mp_string_command); return; } case mp_comma_class: case mp_semicolon_class: case mp_left_parenthesis_class: case mp_right_parenthesis_class: k = loc - 1; goto FOUND; case mp_invalid_class: if (mp->scanner_status == mp_tex_flushing_state) { goto SWITCH; } else { mp_error( mp, "Text line contains an invalid character", "A funny symbol that I can\'t read has just been input. Continue, and I'll forget\n" "that it ever happened." ); goto RESTART; } default: break; } k = loc - 1; while (mp->char_class[mp->buffer[loc]] == cclass) { ++loc; } FOUND: set_cur_sym(mp_id_lookup(mp, (char *) (mp->buffer + k), (size_t) (loc - k), 1)); } else { if (nloc != NULL && nloc->type == mp_symbol_node_type) { int cur_sym_mod_ = nloc->name_type; int cur_info = mp_get_sym_info(nloc); set_cur_sym(mp_get_sym_sym(nloc)); set_cur_sym_mod(cur_sym_mod_); nloc = nloc->link; if (cur_sym_mod_ == mp_expr_operation) { set_cur_cmd(mp_capsule_command); set_cur_mod_node(mp->param_stack[param_start + cur_info]); set_cur_sym_mod(0); set_cur_sym(NULL); return; } else if (cur_sym_mod_ == mp_suffix_operation || cur_sym_mod_ == mp_text_operation) { mp_begin_token_list(mp, mp->param_stack[param_start + cur_info], (int) mp_parameter_text); goto RESTART; } } else if (nloc != NULL) { if (nloc->name_type == mp_token_operation) { if (nloc->type == mp_known_type) { set_cur_mod_number(mp_get_value_number(nloc)); set_cur_cmd(mp_numeric_command); } else { set_cur_mod_str(mp_get_value_str(nloc)); set_cur_cmd(mp_string_command); add_str_ref(cur_mod_str); } } else { set_cur_mod_node(nloc); set_cur_cmd(mp_capsule_command); } nloc = nloc->link; return; } else { mp_end_token_list(mp); goto RESTART; } } cur_sym_ = cur_sym; set_cur_cmd(eq_type(cur_sym_)); set_cur_mod(equiv(cur_sym_)); set_cur_mod_node(equiv_node(cur_sym_)); } static int mp_move_to_next_line (MP mp) { if (name > max_spec_src) { ++line; mp->first = (size_t) start; if (! mp->force_eof) { if (mp_input_ln(mp, cur_file)) { mp_firm_up_the_line(mp); } else { mp->force_eof = 1; } }; if (mp->force_eof) { mp->force_eof = 0; --loc; if (mp->interaction < mp_silent_mode) { mp_print_chr(mp, ')'); --mp->open_parens; update_terminal(); } mp_end_file_reading(mp); mp_check_outer_validity(mp); return 1; } else { mp->buffer[limit] = '%'; mp->first = (size_t) (limit + 1); loc = start; } } else if (mp->input_ptr > 0) { mp_end_file_reading(mp); return 1; } else if (mp->interaction > mp_nonstop_mode) { if (limit == start && mp->interaction < mp_silent_mode) { mp_print_nl(mp, "(Please type a command or say `end')"); } mp_print_ln(mp); mp->first = (size_t) start; if (! mp_input_ln(mp, mp->term_in)) { longjmp(*(mp->jump_buf), 1); } mp->buffer[mp->last] = '%'; limit = (int) mp->last; mp->buffer[limit] = '%'; mp->first = (size_t) (limit + 1); loc = start; } else { mp_fatal_error(mp, "job aborted, no legal end found"); } return 0; } void mp_firm_up_the_line (MP mp) { limit = (int) mp->last; } static void mp_t_next (MP mp) { if ((mp->extensions == 1) && (cur_cmd == mp_btex_command)) { char *txt = NULL; char *ptr = NULL; int slin = line; int size = 0; int done = 0; int mode = round_unscaled(internal_value(mp_texscriptmode_internal)) ; int verb = cur_mod == mp_verbatim_code; int first; if (loc <= limit && mp->char_class[mp->buffer[loc]] == mp_space_class) { ++loc; } else { } first = loc; while (1) { if (loc < limit - 4) { if (mp->buffer[loc] == 'e') { ++loc; if (mp->buffer[loc] == 't') { ++loc; if (mp->buffer[loc] == 'e') { ++loc; if (mp->buffer[loc] == 'x') { if (first == (loc - 3)) { done = 1; } else if (mp->char_class[mp->buffer[loc - 4]] == mp_space_class) { done = 2; } if (done) { if ((loc + 1) <= limit) { int c = mp->char_class[mp->buffer[loc + 1]] ; if (c != mp_letter_class) { ++loc; break; } else { done = 0; } } else { ++loc; break; } } } } } } } if (loc >= limit) { if (size) { txt = mp_memory_reallocate(txt, (size_t) (size + limit - first + 1)); } else { txt = mp_memory_allocate((size_t) (limit - first + 1)); } memcpy(txt + size, mp->buffer + first, limit - first); size += limit - first + 1; if (mode <= 0) { txt[size - 1] = ' '; } else if (verb) { txt[size - 1] = '\n'; } else if (mode >= 2) { txt[size - 1] = '\n'; } else { txt[size - 1] = ' '; } if (mp_move_to_next_line(mp)) { goto FATAL_ERROR; } first = loc; } else { ++loc; } } if (done) { int l = loc - 5 ; int n = l - first + 1 ; if (done == 2) { l -= 1; n -= 1; } if (size) { txt = mp_memory_reallocate(txt, (size_t) (size + n + 1)); } else { txt = mp_memory_allocate((size_t) (n + 1)); } memcpy(txt + size, mp->buffer + first, n); size += n; if (verb && mode >= 3) { txt[size] = '\0'; ptr = txt; } else if (mode >= 4) { txt[size] = '\0'; ptr = txt; } else { while ((size > 1) && (mp->char_class[(unsigned char) txt[size-1]] == mp_space_class || txt[size-1] == '\n')) { --size; } txt[size] = '\0'; ptr = txt; while ((size > 1) && (mp->char_class[(unsigned char) ptr[0]] == mp_space_class || ptr[0] == '\n')) { ++ptr; --size; } } check_script_result(mp, mp->make_text(mp, ptr, size, verb)); mp_memory_free(txt); mp_get_next(mp); return; } FATAL_ERROR: { char msg[256]; if (slin > 0) { mp_snprintf(msg, 256, "No matching 'etex' for '%stex'.", verb ? "verbatim" : "b"); } else { mp_snprintf(msg, 256, "No matching 'etex' for '%stex' in line %d.", verb ? "verbatim" : "b",slin); } mp_error(mp, msg, "An 'etex' is missing at this input level, nothing gets done."); mp_memory_free(txt); } } else { { mp_error( mp, "A 'btex/verbatimtex ... etex' definition needs an extension", "This file contains picture expressions for 'btex ... etex' blocks. Such files\n" "need an extension (plugin) that seems to be absent." ); } } } static mp_node mp_scan_toks (MP mp, mp_command_code terminator, mp_subst_list_item * subst_list, mp_node tail_end, int suffix_count) { int cur_data; int cur_data_mod = 0; mp_node p = mp->hold_head; int balance = 1; mp->hold_head->link = NULL; while (1) { get_t_next(mp); cur_data = -1; if (cur_sym != NULL) { { mp_subst_list_item *q = subst_list; while (q != NULL) { if (q->info == cur_sym && q->info_mod == cur_sym_mod) { cur_data = q->value_data; cur_data_mod = q->value_mod; set_cur_cmd(mp_relax_command); break; } q = q->link; } } if (cur_cmd == terminator) { if (cur_mod > 0) { ++balance; } else { --balance; if (balance == 0) break; } } else if (cur_cmd == mp_macro_special_command) { if (cur_mod == mp_macro_quote_code) { get_t_next(mp); } else if (cur_mod <= suffix_count) { cur_data = cur_mod - 1; cur_data_mod = mp_suffix_operation; } } } if (cur_data != -1) { mp_node pp = mp_new_symbolic_node(mp); mp_set_sym_info(pp, cur_data); pp->name_type = cur_data_mod; p->link = pp; } else { p->link = mp_cur_tok(mp); } p = p->link; } p->link = tail_end; while (subst_list) { mp_subst_list_item *q = subst_list->link; mp_memory_free(subst_list); subst_list = q; } return mp->hold_head->link; } static void mp_get_symbol (MP mp) { RESTART: get_t_next(mp); if ((cur_sym == NULL) || mp_is_frozen(mp, cur_sym)) { const char *hlp = NULL; if (cur_sym != NULL) { hlp = "Sorry: You can't redefine my error-recovery tokens. I've inserted an\n" "inaccessible symbol so that your definition will be completed without\n" "mixing me up too badly."; } else { hlp = "Sorry: You can't redefine a number, string, or expr. I've inserted an\n" "inaccessible symbol so that your definition will be completed without\n" "mixing me up too badly."; if (cur_cmd == mp_string_command) { delete_str_ref(cur_mod_str); } } set_cur_sym(mp->frozen_inaccessible); mp_ins_error(mp, "Missing symbolic token inserted", hlp); goto RESTART; } } static void mp_get_clear_symbol (MP mp) { mp_get_symbol(mp); mp_clear_symbol(mp, cur_sym, 0); } static void mp_check_equals (MP mp) { if (cur_cmd != mp_equals_command && cur_cmd != mp_assignment_command) { mp_back_error( mp, "Missing '=' has been inserted", "The next thing in this 'def' should have been '=', because I've already looked at\n" "the definition heading. But don't worry; I'll pretend that an equals sign was\n" "present. Everything from here to 'enddef' will be the replacement text of this\n" "macro." ); } } static void mp_make_op_def (MP mp, int code) { mp_node q, r; mp_command_code m = (code == mp_primary_def_code) ? mp_primary_def_command : (code == mp_secondary_def_code ? mp_secondary_def_command : mp_tertiary_def_command); mp_subst_list_item *qm = NULL; mp_subst_list_item *qn = NULL; mp_get_symbol(mp); qm = mp_memory_allocate(sizeof(mp_subst_list_item)); qm->link = NULL; qm->info = cur_sym; qm->info_mod = cur_sym_mod; qm->value_data = 0; qm->value_mod = mp_expr_operation; mp_get_clear_symbol(mp); mp->warning_info = cur_sym; mp_get_symbol(mp); qn = mp_memory_allocate(sizeof(mp_subst_list_item)); qn->link = qm; qn->info = cur_sym; qn->info_mod = cur_sym_mod; qn->value_data = 1; qn->value_mod = mp_expr_operation; get_t_next(mp); mp_check_equals(mp); mp->scanner_status = mp_op_defining_state; q = mp_new_symbolic_node(mp); mp_set_ref_count(q, 0); r = mp_new_symbolic_node(mp); q->link = r; mp_set_sym_info(r, mp_general_macro); r->name_type = mp_macro_operation; r->link = mp_scan_toks(mp, mp_macro_def_command, qn, NULL, 0); mp->scanner_status = mp_normal_state; set_eq_type(mp->warning_info, m); set_equiv_node(mp->warning_info, q); mp_get_x_next(mp); } static void mp_scan_def (MP mp, int code) { int n; int k; mp_subst_list_item *r = NULL; mp_subst_list_item *rp = NULL; mp_node q; mp_node p; int sym_type; mp_sym l_delim, r_delim; int c = mp_general_macro; mp->hold_head->link = NULL; q = mp_new_symbolic_node(mp); mp_set_ref_count(q, 0); r = NULL; if (code == mp_def_code) { mp_get_clear_symbol(mp); mp->warning_info = cur_sym; get_t_next(mp); mp->scanner_status = mp_op_defining_state; n = 0; set_eq_type(mp->warning_info, mp_defined_macro_command); set_equiv_node(mp->warning_info, q); } else { p = mp_scan_declared_variable(mp); mp_flush_variable(mp, equiv_node(mp_get_sym_sym(p)), p->link, 1); mp->warning_info_node = mp_find_variable(mp, p); mp_flush_node_list(mp, p); if (mp->warning_info_node == NULL) { mp_error( mp, "This variable already starts with a macro", "After 'vardef a' you can't say 'vardef a.b'. So I'll have to discard this\n" "definition." ); mp->warning_info_node = mp->bad_vardef; } mp->scanner_status = mp_var_defining_state; n = 2; if (cur_cmd == mp_macro_special_command && cur_mod == mp_macro_suffix_code) { n = 3; get_t_next(mp); } mp->warning_info_node->type = mp_unsuffixed_macro_type - 2 + n; mp_set_value_node(mp->warning_info_node, q); } k = n; if (cur_cmd == mp_left_delimiter_command) { do { l_delim = cur_sym; r_delim = equiv_sym(cur_sym); get_t_next(mp); if (cur_cmd == mp_parameter_commmand) { switch (cur_mod) { case mp_expr_parameter: sym_type = mp_expr_operation; goto OKAY; break; case mp_suffix_parameter: sym_type = mp_suffix_operation; goto OKAY; break; case mp_text_parameter: sym_type = mp_text_operation; goto OKAY; break; default: break; } } mp_back_error( mp, "Missing parameter type; 'expr' will be assumed", "You should've had 'expr' or 'suffix' or 'text' here." ); sym_type = mp_expr_operation; OKAY: do { q->link = mp_new_symbolic_node(mp); q = q->link; q->name_type = sym_type; mp_set_sym_info(q, k); mp_get_symbol(mp); rp = mp_memory_allocate(sizeof(mp_subst_list_item)); rp->link = NULL; rp->value_data = k; rp->value_mod = sym_type; rp->info = cur_sym; rp->info_mod = cur_sym_mod; mp_check_param_size(mp, k); ++k; rp->link = r; r = rp; get_t_next(mp); } while (cur_cmd == mp_comma_command); mp_check_delimiter(mp, l_delim, r_delim); get_t_next(mp); } while (cur_cmd == mp_left_delimiter_command); } if (cur_cmd == mp_parameter_commmand) { rp = mp_memory_allocate(sizeof(mp_subst_list_item)); rp->link = NULL; rp->value_data = k; switch (cur_mod) { case mp_expr_parameter: rp->value_mod = mp_expr_operation; c = mp_expr_macro; break; case mp_suffix_parameter: rp->value_mod = mp_suffix_operation; c = mp_suffix_macro; break; case mp_text_parameter: rp->value_mod = mp_text_operation; c = mp_text_macro; break; default: c = cur_mod; rp->value_mod = mp_expr_operation; break; } mp_check_param_size(mp, k); ++k; mp_get_symbol(mp); rp->info = cur_sym; rp->info_mod = cur_sym_mod; rp->link = r; r = rp; get_t_next(mp); if (c == mp_expr_macro && cur_cmd == mp_of_command) { c = mp_of_macro; rp = mp_memory_allocate(sizeof(mp_subst_list_item)); rp->link = NULL; mp_check_param_size(mp, k); rp->value_data = k; rp->value_mod = mp_expr_operation; mp_get_symbol(mp); rp->info = cur_sym; rp->info_mod = cur_sym_mod; rp->link = r; r = rp; get_t_next(mp); } } mp_check_equals(mp); p = mp_new_symbolic_node(mp); mp_set_sym_info(p, c); p->name_type = mp_macro_operation; q->link = p; if (code == mp_def_code) { p->link = mp_scan_toks(mp, mp_macro_def_command, r, NULL, (int) n); } else { mp_node qq = mp_new_symbolic_node(mp); mp_set_sym_sym(qq, mp->bg_loc); p->link = qq; p = mp_new_symbolic_node(mp); mp_set_sym_sym(p, mp->eg_loc); qq->link = mp_scan_toks(mp, mp_macro_def_command, r, p, (int) n); } if (mp->warning_info_node == mp->bad_vardef) { mp_flush_token_list(mp, mp_get_value_node(mp->bad_vardef)); } mp->scanner_status = mp_normal_state; mp_get_x_next(mp); } static void mp_check_expansion_depth (MP mp) { if (++mp->expand_depth_count >= mp->expand_depth) { if (mp->interaction >= mp_error_stop_mode) { mp->interaction=mp_scroll_mode; } mp_error( mp, "Maximum expansion depth reached", "Recursive macro expansion cannot be unlimited because of runtime stack\n" "constraints. The limit is 10000 recursion levels in total." ); mp->history=mp_fatal_error_stop; mp_jump_out(mp); } } static void mp_expand (MP mp) { mp_check_expansion_depth(mp); if (number_greater(internal_value(mp_tracing_commands_internal), unity_t) && cur_cmd != mp_defined_macro_command) { mp_show_cmd_mod(mp, cur_cmd, cur_mod); } switch (cur_cmd) { case mp_if_test_command: mp_conditional(mp); break; case mp_fi_or_else_command: if (cur_mod > mp->if_limit) { if (mp->if_limit == mp_if_code) { mp_back_input(mp); set_cur_sym(mp->frozen_colon); mp_ins_error(mp, "Missing ':' has been inserted", "Something was missing here"); } else { const char *hlp = "I'm ignoring this; it doesn't match any if."; switch (cur_mod) { case mp_fi_code: mp_error(mp, "Extra 'fi'", hlp); break; case mp_else_code: mp_error(mp, "Extra 'else'", hlp); break; default: mp_error(mp, "Extra 'elseif'", hlp); break; } } } else { while (cur_mod != mp_fi_code) { mp_pass_text(mp); } mp_pop_condition_stack(mp); } break; case mp_input_command: if (cur_mod > 0) { mp->force_eof = 1; } else { mp_start_input(mp); } break; case mp_iteration_command: if (cur_mod == mp_end_for_code) { { mp_error( mp, "Extra 'endfor'", "I'm not currently working on a for loop, so I had better not try to end anything." ); } } else { mp_begin_iteration(mp); } break; case mp_repeat_loop_command: { while (token_state && (nloc == NULL)) { mp_end_token_list(mp); } if (mp->loop_ptr == NULL) { mp_error( mp, "Lost loop", "I'm confused; after exiting from a loop, I still seem to want to repeat it. I'll\n" "try to forget the problem." ); } else { mp_resume_iteration(mp); } } break; case mp_exit_test_command: { mp_get_x_next(mp); mp_scan_expression(mp); if (mp->cur_exp.type != mp_boolean_type) { do_boolean_error(mp); } if (number_greater(internal_value(mp_tracing_commands_internal), unity_t)) { mp_show_cmd_mod(mp, mp_nullary_command, cur_exp_value_boolean); } if (cur_exp_value_boolean == mp_true_operation) { if (mp->loop_ptr != NULL) { mp_node p = NULL; do { if (file_state) { mp_end_file_reading(mp); } else { if (token_type <= mp_loop_text) { p = nstart; } mp_end_token_list(mp); } } while (p == NULL); if (p != mp->loop_ptr->info) { mp_fatal_error(mp, "*** (loop confusion)"); } mp_stop_iteration(mp); } else if (cur_cmd == mp_semicolon_command) { mp_error( mp, "No loop is in progress", "Why say 'exitif' when there's nothing to exit from?" ); } else { mp_back_error( mp, "No loop is in progress", "Why say 'exitif' when there's nothing to exit from?" ); } } else if (cur_cmd != mp_semicolon_command) { mp_back_error( mp, "Missing ';' has been inserted", "After 'exitif ' I expect to see a semicolon. I shall pretend that\n" "one was there." ); } } break; case mp_relax_command: break; case mp_expand_after_command: { mp_node p; get_t_next(mp); p = mp_cur_tok(mp); get_t_next(mp); if (cur_cmd < mp_min_command) { mp_expand(mp); } else { mp_back_input(mp); } mp_begin_token_list(mp, p, mp_backed_up_text); } break; case mp_scan_tokens_command: { mp_get_x_next(mp); mp_scan_primary(mp); if (mp->cur_exp.type != mp_string_type) { mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); mp_disp_err(mp, NULL); mp_back_error( mp, "Not a string", "I'm going to flush this expression, since scantokens should be followed by a\n" "known string." ); mp_get_x_next(mp); mp_flush_cur_exp(mp, new_expr); } else { mp_back_input(mp); if (cur_exp_str->len > 0) { size_t k; size_t j; mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); mp_begin_file_reading(mp); name = is_scantok; k = mp->first + (size_t) cur_exp_str->len; if (k >= mp->max_buf_stack) { while (k >= mp->buf_size) { mp_reallocate_buffer(mp, (mp->buf_size + (mp->buf_size / 4))); } mp->max_buf_stack = k + 1; } j = 0; limit = (int) k; while (mp->first < (size_t) limit) { mp->buffer[mp->first] = *(cur_exp_str->str + j); j++; ++mp->first; } mp->buffer[limit] = '%'; mp->first = (size_t) (limit + 1); loc = start; mp_flush_cur_exp(mp, new_expr); } } } break; case mp_runscript_command: { if (mp->extensions) { mp_get_x_next(mp); mp_scan_primary(mp); switch (mp->cur_exp.type) { case mp_string_type: { mp_back_input(mp); if (cur_exp_str->len > 0) { check_script_result(mp, mp->run_script(mp, (const char*) cur_exp_str->str, cur_exp_str->len, 0)); } } break; case mp_numeric_type: case mp_known_type: { int n = 0 ; mp_back_input(mp); n = (int) number_to_scaled (cur_exp_value_number) / 65536; if (n > 0) { check_script_result(mp, mp->run_script(mp, NULL, 0, n)); } } break; default: { mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); mp_disp_err(mp, NULL); mp_back_error( mp, "Not a string", "I'm going to flush this expression, since runscript should be followed by a known\n" "string or number." ); mp_get_x_next(mp); mp_flush_cur_exp(mp, new_expr); } break; } } } break; case mp_maketext_command: { if (mp->extensions) { mp_get_x_next(mp); mp_scan_primary(mp); if (mp->cur_exp.type == mp_string_type) { mp_back_input(mp); if (cur_exp_str->len > 0) { check_script_result(mp, mp->make_text(mp, (const char*) cur_exp_str->str, cur_exp_str->len, 0)); } } else { mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); mp_disp_err(mp, NULL); mp_back_error( mp, "Not a string", "I'm going to flush this expression, since 'maketext' should be followed by a\n" "known string." ); mp_get_x_next(mp); mp_flush_cur_exp(mp, new_expr); } } } break; case mp_defined_macro_command: mp_macro_call(mp, cur_mod_node, NULL, cur_sym); break; default: break; }; mp->expand_depth_count--; } void check_script_result (MP mp, char *s) { if (s) { size_t size = strlen(s); if (size > 0) { size_t k ; mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); mp_begin_file_reading(mp); name = is_scantok; mp->last = mp->first; k = mp->first + size; if (k >= mp->max_buf_stack) { while (k >= mp->buf_size) { mp_reallocate_buffer(mp, (mp->buf_size + (mp->buf_size / 4))); } mp->max_buf_stack = k + 1; } limit = (int) k; memcpy((mp->buffer + mp->first), s, size); mp->buffer[limit] = '%'; mp->first = (size_t) (limit + 1); loc = start; mp_flush_cur_exp(mp, new_expr); } lmt_memory_free(s); } } static void mp_get_x_next (MP mp) { get_t_next(mp); if (cur_cmd < mp_min_command) { mp_node save_exp = mp_stash_cur_exp(mp); do { if (cur_cmd == mp_defined_macro_command) { mp_macro_call(mp, cur_mod_node, NULL, cur_sym); } else { mp_expand(mp); } get_t_next(mp); } while (cur_cmd < mp_min_command); mp_unstash_cur_exp(mp, save_exp); } } static void mp_macro_call (MP mp, mp_node def_ref, mp_node arg_list, mp_sym macro_name) { int n; mp_node tail = 0; mp_sym l_delim = NULL; mp_sym r_delim = NULL; mp_node r = def_ref->link; mp_add_mac_ref(def_ref); if (arg_list == NULL) { n = 0; } else { n = 1; tail = arg_list; while (tail->link != NULL) { ++n; tail = tail->link; } } if (number_positive(internal_value(mp_tracing_macros_internal))) { mp_begin_diagnostic(mp); mp_print_ln(mp); mp_print_macro_name(mp, arg_list, macro_name); if (n == 3) { mp_print_str(mp, "@#"); } mp_show_macro (mp, def_ref, NULL); if (arg_list != NULL) { mp_node p = arg_list; n = 0; do { mp_node q = (mp_node) mp_get_sym_sym(p); mp_print_arg(mp, q, n, 0, 0); ++n; p = p->link; } while (p != NULL); } mp_end_diagnostic(mp, 0); } set_cur_cmd(mp_comma_command + 1); while (r->name_type == mp_expr_operation || r->name_type == mp_suffix_operation || r->name_type == mp_text_operation) { if (cur_cmd != mp_comma_command) { mp_get_x_next(mp); if (cur_cmd != mp_left_delimiter_command) { char msg[256]; mp_string sname; int selector = mp->selector; mp->selector = mp_new_string_selector; mp_print_macro_name(mp, arg_list, macro_name); sname = mp_make_string(mp); mp->selector = selector; mp_snprintf(msg, 256, "Missing argument to %s", mp_str(mp, sname)); delete_str_ref(sname); if (r->name_type == mp_suffix_operation || r->name_type == mp_text_operation) { mp_set_cur_exp_value_number(mp, &zero_t); mp->cur_exp.type = mp_token_list_type; } else { mp_set_cur_exp_value_number(mp, &zero_t); mp->cur_exp.type = mp_known_type; } mp_back_error( mp, msg, "That macro has more parameters than you thought. I'll continue by pretending that\n" "each missing argument is either zero or null." ); set_cur_cmd(mp_right_delimiter_command); goto FOUND; } l_delim = cur_sym; r_delim = equiv_sym(cur_sym); } if (r->name_type == mp_text_operation) { mp_scan_text_arg(mp, l_delim, r_delim); } else { mp_get_x_next(mp); if (r->name_type == mp_suffix_operation) { mp_scan_suffix(mp); } else { mp_scan_expression(mp); } } if ((cur_cmd != mp_comma_command) && ((cur_cmd != mp_right_delimiter_command) || (equiv_sym(cur_sym) != l_delim))) { switch (r->link->name_type) { case mp_expr_operation: case mp_suffix_operation: case mp_text_operation: { mp_back_error( mp, "Missing ',' has been inserted", "I've finished reading a macro argument and am about to read another; the\n" "arguments weren't delimited correctly." ); set_cur_cmd(mp_comma_command); } break; default: { char msg[256]; mp_snprintf(msg, 256, "Missing '%s' has been inserted", mp_str(mp, text(r_delim))); mp_back_error(mp, msg, "I've gotten to the end of the macro parameter list."); } break; } } FOUND: { mp_node p = mp_new_symbolic_node(mp); if (mp->cur_exp.type == mp_token_list_type) { mp_set_sym_sym(p, mp->cur_exp.data.node); } else { mp_set_sym_sym(p, mp_stash_cur_exp(mp)); } if (number_positive(internal_value(mp_tracing_macros_internal))) { mp_begin_diagnostic(mp); mp_print_arg(mp, (mp_node) mp_get_sym_sym(p), n, mp_get_sym_info(r), r->name_type); mp_end_diagnostic(mp, 0); } if (arg_list == NULL) { arg_list = p; } else { tail->link = p; } tail = p; ++n; } r = r->link; } if (cur_cmd == mp_comma_command) { char msg[256]; mp_string rname; int selector = mp->selector; mp->selector = mp_new_string_selector; mp_print_macro_name(mp, arg_list, macro_name); rname = mp_make_string(mp); mp->selector = selector; mp_snprintf(msg, 256, "Too many arguments to %s; Missing '%s' has been inserted", mp_str(mp, rname), mp_str(mp, text(r_delim))); delete_str_ref(rname); mp_error( mp, msg, "I'm going to assume that the comma I just read was a right delimiter, and then:\n" "I'll begin expanding the macro." ); } if (mp_get_sym_info(r) != mp_general_macro) { if (mp_get_sym_info(r) < mp_text_macro) { mp_get_x_next(mp); if (mp_get_sym_info(r) != mp_suffix_macro) { if ((cur_cmd == mp_equals_command) || (cur_cmd == mp_assignment_command)) { mp_get_x_next(mp); } } } switch (mp_get_sym_info(r)) { case mp_primary_macro: mp_scan_primary(mp); break; case mp_secondary_macro: mp_scan_secondary(mp); break; case mp_tertiary_macro: mp_scan_tertiary(mp); break; case mp_expr_macro: mp_scan_expression(mp); break; case mp_of_macro: { mp_node p; mp_scan_expression(mp); p = mp_new_symbolic_node(mp); mp_set_sym_sym(p, mp_stash_cur_exp(mp)); if (number_positive(internal_value(mp_tracing_macros_internal))) { mp_begin_diagnostic(mp); mp_print_arg(mp, (mp_node) mp_get_sym_sym(p), n, 0, 0); mp_end_diagnostic(mp, 0); } if (arg_list == NULL) { arg_list = p; } else { tail->link = p; } tail = p; ++n; if (cur_cmd != mp_of_command) { char msg[256]; mp_string sname; int selector = mp->selector; mp->selector = mp_new_string_selector; mp_print_macro_name(mp, arg_list, macro_name); sname = mp_make_string(mp); mp->selector = selector; mp_snprintf(msg, 256, "Missing 'of' has been inserted for %s", mp_str(mp, sname)); delete_str_ref(sname); mp_back_error(mp, msg, "I've got the first argument; will look now for the other."); } mp_get_x_next(mp); mp_scan_primary(mp); } break; case mp_suffix_macro: { if (cur_cmd != mp_left_delimiter_command) { l_delim = NULL; } else { l_delim = cur_sym; r_delim = equiv_sym(cur_sym); mp_get_x_next(mp); } mp_scan_suffix(mp); if (l_delim != NULL) { if ((cur_cmd != mp_right_delimiter_command) || (equiv_sym(cur_sym) != l_delim)) { char msg[256]; mp_snprintf(msg, 256, "Missing '%s' has been inserted", mp_str(mp, text(r_delim))); mp_back_error(mp, msg, "I've gotten to the end of the macro parameter list."); } mp_get_x_next(mp); } } break; case mp_text_macro: mp_scan_text_arg(mp, NULL, NULL); break; } mp_back_input(mp); { mp_node p = mp_new_symbolic_node(mp); if (mp->cur_exp.type == mp_token_list_type) { mp_set_sym_sym(p, mp->cur_exp.data.node); } else { mp_set_sym_sym(p, mp_stash_cur_exp(mp)); } if (number_positive(internal_value(mp_tracing_macros_internal))) { mp_begin_diagnostic(mp); mp_print_arg(mp, (mp_node) mp_get_sym_sym(p), n, mp_get_sym_info(r), r->name_type); mp_end_diagnostic(mp, 0); } if (arg_list == NULL) { arg_list = p; } else { tail->link = p; } tail = p; ++n; } } r = r->link; while (token_state && (nloc == NULL)) { mp_end_token_list(mp); } if (mp->param_ptr + n > mp->max_param_stack) { mp->max_param_stack = mp->param_ptr + n; mp_check_param_size(mp, mp->max_param_stack); } mp_begin_token_list(mp, def_ref, mp_macro_text); name = macro_name ? text(macro_name) : NULL; nloc = r; if (n > 0) { mp_node p = arg_list; do { mp->param_stack[mp->param_ptr] = (mp_node) mp_get_sym_sym(p); ++mp->param_ptr; p = p->link; } while (p != NULL); mp_flush_node_list(mp, arg_list); } } static void mp_print_macro_name (MP mp, mp_node a, mp_sym n) { if (n) { mp_print_mp_str(mp,text(n)); } else { mp_node p = (mp_node) mp_get_sym_sym(a); if (p) { mp_node q = p; while (q->link != NULL) { q = q->link; } q->link = (mp_node) mp_get_sym_sym(a->link); mp_show_token_list(mp, p, NULL); q->link = NULL; } else { mp_print_mp_str(mp,text(mp_get_sym_sym((mp_node) mp_get_sym_sym(a->link)))); } } } static void mp_print_arg (MP mp, mp_node q, int n, int b, int bb) { if (q && q->link == MP_VOID) { mp_print_nl(mp, "(EXPR"); } else if ((bb < mp_text_operation) && (b != mp_text_macro)) { mp_print_nl(mp, "(SUFFIX"); } else { mp_print_nl(mp, "(TEXT"); } mp_print_int(mp, n); mp_print_str(mp, ")<-"); if (q && q->link == MP_VOID) { mp_print_exp(mp, q, 1); } else { mp_show_token_list(mp, q, NULL); } } void mp_scan_text_arg (MP mp, mp_sym l_delim, mp_sym r_delim) { int balance = 1; mp->warning_info = l_delim; mp->scanner_status = mp_absorbing_state; mp_node p = mp->hold_head; mp->hold_head->link = NULL; while (1) { get_t_next(mp); if (l_delim == NULL) { if (mp_end_of_statement) { if (balance == 1) { break; } else if (cur_cmd == mp_end_group_command) { --balance; } } else if (cur_cmd == mp_begin_group_command) { ++balance; } } else { if (cur_cmd == mp_right_delimiter_command) { if (equiv_sym(cur_sym) == l_delim) { --balance; if (balance == 0) { break; } } } else if (cur_cmd == mp_left_delimiter_command) { if (equiv_sym(cur_sym) == r_delim) { ++balance; } } } p->link = mp_cur_tok(mp); p = p->link; } mp_set_cur_exp_node(mp, mp->hold_head->link); mp->cur_exp.type = mp_token_list_type; mp->scanner_status = mp_normal_state; } static void mp_stack_argument (MP mp, mp_node p) { if (mp->param_ptr == mp->max_param_stack) { ++mp->max_param_stack; mp_check_param_size(mp, mp->max_param_stack); } mp->param_stack[mp->param_ptr] = p; ++mp->param_ptr; } static mp_node mp_get_if_node (MP mp) { mp_if_node p = (mp_if_node) mp_allocate_node(mp, sizeof(mp_if_node_data)); p->type = mp_if_node_type; return (mp_node) p; } void mp_pass_text (MP mp) { int level = 0; mp->scanner_status = mp_skipping_state; mp->warning_line = mp_true_line(mp); while (1) { get_t_next(mp); if (cur_cmd <= mp_fi_or_else_command) { if (cur_cmd < mp_fi_or_else_command) { ++level; } else if (level == 0) { break; } else if (cur_mod == mp_fi_code) { --level; } } else { if (cur_cmd == mp_string_command) { delete_str_ref(cur_mod_str); } } } mp->scanner_status = mp_normal_state; } static void mp_push_condition_stack (MP mp) { mp_node p = mp_get_if_node(mp); p->link = mp->cond_ptr; p->type = (int) mp->if_limit; p->name_type = mp->cur_if; mp_if_line_field(p) = mp->if_line; mp->cond_ptr = p; mp->if_limit = mp_if_code; mp->if_line = mp_true_line(mp); mp->cur_if = mp_if_code; } static void mp_pop_condition_stack (MP mp) { mp_node p = mp->cond_ptr; mp->if_line = mp_if_line_field(p); mp->cur_if = p->name_type; mp->if_limit = p->type; mp->cond_ptr = p->link; mp_free_node(mp, p, sizeof(mp_if_node_data)); } static void mp_change_if_limit (MP mp, int l, mp_node p) { if (p == mp->cond_ptr) { mp->if_limit = l; } else { mp_node q = mp->cond_ptr; while (1) { if (q == NULL) { mp_confusion(mp, "if"); return; } else if (q->link == p) { q->type = l; return; } else { q = q->link; } } } } static void mp_check_colon (MP mp) { if (cur_cmd != mp_colon_command) { mp_back_error( mp, "Missing ':' has been inserted", "There should've been a colon after the condition. I shall pretend that one was\n" "there." ); } } void mp_conditional (MP mp) { mp_node save_cond_ptr; int new_if_limit; mp_push_condition_stack(mp); save_cond_ptr = mp->cond_ptr; RESWITCH: mp_get_x_next(mp); mp_scan_expression(mp); if (mp->cur_exp.type != mp_boolean_type) { do_boolean_error(mp); } new_if_limit = mp_else_if_code; if (number_greater(internal_value(mp_tracing_commands_internal), unity_t)) { mp_begin_diagnostic(mp); mp_print_str(mp, cur_exp_value_boolean == mp_true_operation ? "{true}" : "{false}"); mp_end_diagnostic(mp, 0); } FOUND: mp_check_colon(mp); if (cur_exp_value_boolean == mp_true_operation) { mp_change_if_limit (mp, (int) new_if_limit, save_cond_ptr); return; } while (1) { mp_pass_text(mp); if (mp->cond_ptr == save_cond_ptr) { goto DONE; } else if (cur_mod == mp_fi_code) { mp_pop_condition_stack(mp); } } DONE: mp->cur_if = (int) cur_mod; mp->if_line = mp_true_line(mp); if (cur_mod == mp_fi_code) { mp_pop_condition_stack(mp); } else if (cur_mod == mp_else_if_code) { goto RESWITCH; } else { mp_set_cur_exp_value_boolean(mp, mp_true_operation); new_if_limit = mp_fi_code; mp_get_x_next(mp); goto FOUND; } } static void mp_bad_for (MP mp, const char *s) { char msg[256]; mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); mp_disp_err(mp, NULL); mp_snprintf(msg, 256, "Improper %s has been replaced by 0", s); mp_back_error( mp, msg, "When you say 'for x=a step b until c', the initial value 'a' and the step size\n" "'b' and the final value 'c' must have known numeric values. I'm zeroing this one.\n" "Proceed, with fingers crossed." ); mp_get_x_next(mp); mp_flush_cur_exp(mp, new_expr); } void mp_begin_iteration (MP mp) { mp_node q; mp_sym n = cur_sym; mp_subst_list_item *p = NULL; int m = cur_mod; mp_loop_data *s = mp_memory_allocate(sizeof(mp_loop_data)); s->type = NULL; s->list = NULL; s->info = NULL; s->list_start = NULL; s->link = NULL; s->var = NULL; s->point = NULL; new_number(s->value); new_number(s->old_value); new_number(s->step_size); new_number(s->final_value); if (m == mp_start_forever_code) { s->type = MP_VOID; mp_get_x_next(mp); } else { mp_get_symbol(mp); p = mp_memory_allocate(sizeof(mp_subst_list_item)); p->link = NULL; p->info = cur_sym; s->var = cur_sym; p->info_mod = cur_sym_mod; p->value_data = 0; if (m == mp_start_for_code) { p->value_mod = mp_expr_operation; } else { p->value_mod = mp_suffix_operation; } mp_get_x_next(mp); if (p->value_mod == mp_expr_operation && cur_cmd == mp_within_command) { mp_get_x_next(mp); mp_scan_expression(mp); if (mp->cur_exp.type == mp_path_type) { number_clone(s->value, zero_t); number_clone(s->old_value, zero_t); number_clone(s->step_size, unity_t); { mp_knot p = cur_exp_knot; int l = 0; while (1) { mp_knot n = mp_next_knot(p); if (n == cur_exp_knot) { s->point = p; set_number_from_int(s->final_value, l); break; } else { p = n; ++l; } } } s->type = MP_PROGRESSION_FLAG; s->list = mp_new_symbolic_node(mp); s->list_start = s->list; q = s->list; } else { if (mp->cur_exp.type != mp_picture_type) { mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); new_expr.data.node = (mp_node) mp_get_edge_header_node(mp); mp_disp_err(mp, NULL); mp_back_error( mp, "Improper iteration spec has been replaced by nullpicture", "When you say 'for x in p', p must be a known picture." ); mp_get_x_next(mp); mp_flush_cur_exp(mp, new_expr); mp_init_edges(mp, (mp_edge_header_node) mp->cur_exp.data.node); mp->cur_exp.type = mp_picture_type; } s->type = mp->cur_exp.data.node; mp->cur_exp.type = mp_vacuous_type; q = mp_edge_list(mp->cur_exp.data.node)->link; if (q != NULL && mp_is_start_or_stop (q) && mp_skip_1component(mp, q) == NULL) { q = q->link; } s->list = q; } } else { if ((cur_cmd != mp_equals_command) && (cur_cmd != mp_assignment_command)) { mp_back_error( mp, "Missing '=' has been inserted", "The next thing in this loop should have been '=' or ':='. But don't worry; I'll\n" "pretend that an equals sign was present, and I'll look for the values next." ); } s->type = NULL; s->list = mp_new_symbolic_node(mp); s->list_start = s->list; q = s->list; do { mp_get_x_next(mp); if (m != mp_start_for_code) { mp_scan_suffix(mp); } else { if (cur_cmd >= mp_colon_command && cur_cmd <= mp_comma_command) { goto CONTINUE; } mp_scan_expression(mp); if (cur_cmd == mp_step_command && q == s->list) { { if (mp->cur_exp.type != mp_known_type) { mp_bad_for (mp, "initial value"); } number_clone(s->value, cur_exp_value_number); number_clone(s->old_value, cur_exp_value_number); mp_get_x_next(mp); mp_scan_expression(mp); if (mp->cur_exp.type != mp_known_type) { mp_bad_for (mp, "step size"); } number_clone(s->step_size, cur_exp_value_number); if (cur_cmd != mp_until_command) { mp_back_error( mp, "Missing 'until' has been inserted", "I assume you meant to say 'until' after 'step'. So I'll look for the final value\n" "and colon next." ); } mp_get_x_next(mp); mp_scan_expression(mp); if (mp->cur_exp.type != mp_known_type) { mp_bad_for (mp, "final value"); } number_clone(s->final_value, cur_exp_value_number); s->type = MP_PROGRESSION_FLAG; break; } } mp_set_cur_exp_node(mp, mp_stash_cur_exp(mp)); } q->link = mp_new_symbolic_node(mp); q = q->link; mp_set_sym_sym(q, mp->cur_exp.data.node); if (m == mp_start_for_code) { q->name_type = mp_expr_operation; } else if (m == mp_start_forsuffixes_code) { q->name_type = mp_suffix_operation; } mp->cur_exp.type = mp_vacuous_type; CONTINUE: ; } while (cur_cmd == mp_comma_command); } } if (cur_cmd != mp_colon_command) { mp_back_error( mp, "Missing ':' has been inserted", "The next thing in this loop should have been a ':'. So I'll pretend that a colon\n" "was present; everything from here to 'endfor' will be iterated." ); } q = mp_new_symbolic_node(mp); mp_set_sym_sym(q, mp->frozen_repeat_loop); mp->scanner_status = mp_loop_defining_state; mp->warning_info = n; s->info = mp_scan_toks(mp, mp_iteration_command, p, q, 0); mp->scanner_status = mp_normal_state; s->link = mp->loop_ptr; mp->loop_ptr = s; mp_resume_iteration(mp); } void mp_resume_iteration (MP mp) { mp_node p, q; p = mp->loop_ptr->type; if (p == MP_PROGRESSION_FLAG) { mp_set_cur_exp_value_number(mp, &(mp->loop_ptr->value)); if ((number_positive(mp->loop_ptr->step_size) && number_greater(cur_exp_value_number, mp->loop_ptr->final_value)) || (number_negative(mp->loop_ptr->step_size) && number_less (cur_exp_value_number, mp->loop_ptr->final_value))) { mp_stop_iteration(mp); return; } mp->cur_exp.type = mp_known_type; q = mp_stash_cur_exp(mp); number_clone(mp->loop_ptr->old_value, cur_exp_value_number); set_number_from_addition(mp->loop_ptr->value, cur_exp_value_number, mp->loop_ptr->step_size); if (number_positive(mp->loop_ptr->step_size) && number_less(mp->loop_ptr->value, cur_exp_value_number)) { if (number_positive(mp->loop_ptr->final_value)) { number_clone(mp->loop_ptr->value, mp->loop_ptr->final_value); number_add_scaled(mp->loop_ptr->final_value, -1); } else { number_clone(mp->loop_ptr->value, mp->loop_ptr->final_value); number_add_scaled(mp->loop_ptr->value, 1); } } else if (number_negative(mp->loop_ptr->step_size) && number_greater(mp->loop_ptr->value, cur_exp_value_number)) { if (number_negative(mp->loop_ptr->final_value)) { number_clone(mp->loop_ptr->value, mp->loop_ptr->final_value); number_add_scaled(mp->loop_ptr->final_value, 1); } else { number_clone(mp->loop_ptr->value, mp->loop_ptr->final_value); number_add_scaled(mp->loop_ptr->value, -1); } } if (mp->loop_ptr->point != NULL) { mp->loop_ptr->point = mp_next_knot(mp->loop_ptr->point); } } else if (p == NULL) { p = mp->loop_ptr->list; if (p != NULL && p == mp->loop_ptr->list_start) { q = p; p = p->link; mp_free_symbolic_node(mp, q); mp->loop_ptr->list = p; } if (p == NULL) { mp_stop_iteration(mp); return; } mp->loop_ptr->list = p->link; q = (mp_node) mp_get_sym_sym(p); if (q) { number_clone(mp->loop_ptr->old_value, q->data.n); } mp_free_symbolic_node(mp, p); } else if (p == MP_VOID) { mp_begin_token_list(mp, mp->loop_ptr->info, mp_forever_text); return; } else { q = mp->loop_ptr->list; if (q == NULL) { goto NOT_FOUND; } else if (! mp_is_start_or_stop(q)) { q = q->link; } else if (! mp_is_stop(q)) { q = mp_skip_1component(mp, q); } else { goto NOT_FOUND; } mp_set_cur_exp_node(mp, (mp_node) mp_copy_objects (mp, mp->loop_ptr->list, q)); mp_init_bbox(mp, (mp_edge_header_node) cur_exp_node); mp->cur_exp.type = mp_picture_type; mp->loop_ptr->list = q; q = mp_stash_cur_exp(mp); } mp_begin_token_list(mp, mp->loop_ptr->info, mp_loop_text); mp_stack_argument(mp, q); if (number_greater(internal_value(mp_tracing_commands_internal), unity_t)) { mp_begin_diagnostic(mp); mp_print_nl(mp, "{loop value="); if ((q != NULL) && (q->link == MP_VOID)) { mp_print_exp(mp, q, 1); } else { mp_show_token_list(mp, q, NULL); } mp_print_chr(mp, '}'); mp_end_diagnostic(mp, 0); } return; NOT_FOUND: mp_stop_iteration(mp); } void mp_stop_iteration (MP mp) { mp_node p = mp->loop_ptr->type; if (p == MP_PROGRESSION_FLAG) { mp_free_symbolic_node(mp, mp->loop_ptr->list); if (mp->loop_ptr->point) { mp_toss_knot_list(mp, mp->loop_ptr->point); } } else if (p == NULL) { mp_node q = mp->loop_ptr->list; while (q != NULL) { p = (mp_node) mp_get_sym_sym(q); if (p != NULL) { if (p->link == MP_VOID) { mp_recycle_value(mp, p); mp_free_value_node(mp, p); } else { mp_flush_token_list(mp, p); } } p = q; q = q->link; mp_free_symbolic_node(mp, p); } } else if (p > MP_PROGRESSION_FLAG) { mp_delete_edge_ref(mp, p); } { mp_loop_data *tmp = mp->loop_ptr; mp->loop_ptr = tmp->link; mp_flush_token_list(mp, tmp->info); free_number(tmp->value); free_number(tmp->step_size); free_number(tmp->final_value); mp_memory_free(tmp); } } void mp_begin_name (MP mp) { mp_memory_free(mp->cur_name); mp->cur_name = NULL; mp->quoted_filename = 0; } int mp_more_name (MP mp, unsigned char c) { if (c == '"') { mp->quoted_filename = ! mp->quoted_filename; } else if ((c == ' ' || c == '\t') && (mp->quoted_filename == 0)) { return 0; } else { mp_str_room(mp, 1); mp_append_char(mp, c); } return 1; } void mp_end_name (MP mp) { mp->cur_name = mp_memory_allocate((size_t) (mp->cur_length + 1) * sizeof(char)); (void) memcpy(mp->cur_name, (char *) (mp->cur_string), mp->cur_length); mp->cur_name[mp->cur_length] = 0; mp_reset_cur_string(mp); } void mp_pack_file_name (MP mp, const char *n) { mp_memory_free(mp->name_of_file); mp->name_of_file = mp_strdup(n); } static mp_string mp_make_name_string (MP mp) { int name_length = (int) strlen(mp->name_of_file); mp_str_room(mp, name_length); for (int k = 0; k < name_length; k++) { mp_append_char(mp, (unsigned char) mp->name_of_file[k]); } return mp_make_string(mp); } static void mp_scan_file_name (MP mp) { mp_begin_name(mp); while (mp->buffer[loc] == ' ') { ++loc; } while (1) { if ((mp->buffer[loc] == ';') || (mp->buffer[loc] == '%')) { break; } else if (! mp_more_name(mp, mp->buffer[loc])) { break; } else { ++loc; } } mp_end_name(mp); } static void mp_ptr_scan_file (MP mp, char *s) { char *p = s; char *q = p + strlen(s); mp_begin_name(mp); while (p < q) { if (! mp_more_name(mp, (unsigned char) (*p))) { break; } else { p++; } } mp_end_name(mp); } void mp_start_input (MP mp) { while (token_state && (nloc == NULL)) { mp_end_token_list(mp); } if (token_state) { mp_error( mp, "File names can't appear within macros", "Sorry ... I've converted what follows to tokens, possibly garbaging the name you\n" "gave. Please delete the tokens and insert the name again." ); } if (file_state) { mp_scan_file_name(mp); } else { mp_memory_free(mp->cur_name); mp->cur_name = mp_strdup(""); } mp_begin_file_reading(mp); mp_pack_file_name(mp, mp->cur_name); if (mp_open_in(mp, &cur_file, mp_filetype_program)) { char *fname = NULL; name = mp_make_name_string(mp); fname = mp_strdup(mp->name_of_file); if (mp->interaction < mp_silent_mode) { if ((mp->term_offset > 0) || (mp->file_offset > 0)) { mp_print_chr(mp, ' '); } mp_print_chr(mp, '('); ++mp->open_parens; mp_print_str(mp, fname); } mp_memory_free(fname); update_terminal(); mp_flush_string(mp, name); name = mp_rts(mp, mp->cur_name); mp_memory_free(mp->cur_name); mp->cur_name = NULL; line = 1; mp_input_ln(mp, cur_file); mp_firm_up_the_line(mp); mp->buffer[limit] = '%'; mp->first = (size_t) (limit + 1); loc = start; } else { mp_fatal_error(mp, "invalid input file"); mp_end_file_reading(mp); } } static int mp_start_read_input (MP mp, char *s, int n) { mp_ptr_scan_file(mp, s); mp_pack_file_name(mp, mp->cur_name); mp_begin_file_reading(mp); if (! mp_open_in(mp, &mp->rd_file[n], mp_filetype_text + n)) { mp_end_file_reading(mp); return 0; } else if (! mp_input_ln(mp, mp->rd_file[n])) { (mp->close_file)(mp, mp->rd_file[n]); mp_end_file_reading(mp); return 0; } else { mp->rd_fname[n] = mp_strdup(s); return 1; } } void mp_open_write_file (MP mp, char *s, int n) { mp_ptr_scan_file(mp, s); mp_pack_file_name(mp, mp->cur_name); if (mp_open_out(mp, &mp->wr_file[n], mp_filetype_text + n)) { mp->wr_fname[n] = mp_strdup(s); } else { mp_fatal_error(mp, "invalid write file"); } } void mp_set_cur_exp_node (MP mp, mp_node n) { if (cur_exp_str) { delete_str_ref(cur_exp_str); } cur_exp_node = n; cur_exp_str = NULL; cur_exp_knot = NULL; set_number_to_zero(mp->cur_exp.data.n); } void mp_set_cur_exp_knot (MP mp, mp_knot n) { if (cur_exp_str) { delete_str_ref(cur_exp_str); } cur_exp_knot = n; cur_exp_node = NULL; cur_exp_str = NULL; set_number_to_zero(mp->cur_exp.data.n); } void mp_set_cur_exp_value_boolean (MP mp, int b) { if (cur_exp_str) { delete_str_ref(cur_exp_str); } set_number_from_boolean(mp->cur_exp.data.n, b); cur_exp_node = NULL; cur_exp_str = NULL; cur_exp_knot = NULL; } void mp_set_cur_exp_value_scaled (MP mp, int s) { if (cur_exp_str) { delete_str_ref(cur_exp_str); } set_number_from_scaled(mp->cur_exp.data.n, s); cur_exp_node = NULL; cur_exp_str = NULL; cur_exp_knot = NULL; } void mp_set_cur_exp_value_number (MP mp, mp_number *n) { if (cur_exp_str) { delete_str_ref(cur_exp_str); } number_clone(mp->cur_exp.data.n, *n); cur_exp_node = NULL; cur_exp_str = NULL; cur_exp_knot = NULL; } void mp_set_cur_exp_str (MP mp, mp_string s) { if (cur_exp_str) { delete_str_ref(cur_exp_str); } cur_exp_str = s; add_str_ref(cur_exp_str); cur_exp_node = NULL; cur_exp_knot = NULL; set_number_to_zero(mp->cur_exp.data.n); } static mp_node mp_stash_cur_exp (MP mp) { mp_node p; mp_variable_type exp_type = mp->cur_exp.type; switch (exp_type) { case mp_unknown_boolean_type: case mp_unknown_string_type: case mp_unknown_pen_type: case mp_unknown_nep_type: case mp_unknown_path_type: case mp_unknown_picture_type: case mp_transform_type: case mp_color_type: case mp_pair_type: case mp_dependent_type: case mp_proto_dependent_type: case mp_independent_type: case mp_cmykcolor_type: p = cur_exp_node; break; default: p = mp_new_value_node(mp); p->name_type = mp_capsule_operation; p->type = mp->cur_exp.type; mp_set_value_number(p, cur_exp_value_number); if (cur_exp_str) { mp_set_value_str(p, cur_exp_str); } else if (cur_exp_knot) { mp_set_value_knot(p, cur_exp_knot); } else if (cur_exp_node) { mp_set_value_node(p, cur_exp_node); } break; } mp->cur_exp.type = mp_vacuous_type; p->link = MP_VOID; return p; } void mp_unstash_cur_exp (MP mp, mp_node p) { mp->cur_exp.type = p->type; switch (mp->cur_exp.type) { case mp_unknown_boolean_type: case mp_unknown_string_type: case mp_unknown_pen_type: case mp_unknown_nep_type: case mp_unknown_path_type: case mp_unknown_picture_type: case mp_transform_type: case mp_color_type: case mp_pair_type: case mp_dependent_type: case mp_proto_dependent_type: case mp_independent_type: case mp_cmykcolor_type: mp_set_cur_exp_node(mp, p); break; case mp_token_list_type: mp_set_cur_exp_node(mp, mp_get_value_node(p)); mp_free_value_node(mp, p); break; case mp_path_type: case mp_pen_type: case mp_nep_type: mp_set_cur_exp_knot(mp, mp_get_value_knot(p)); mp_free_value_node(mp, p); break; case mp_string_type: mp_set_cur_exp_str(mp, mp_get_value_str(p)); mp_free_value_node(mp, p); break; case mp_picture_type: mp_set_cur_exp_node(mp, mp_get_value_node(p)); mp_free_value_node(mp, p); break; case mp_boolean_type: case mp_known_type: mp_set_cur_exp_value_number(mp, &(mp_get_value_number(p))); mp_free_value_node(mp, p); break; default: mp_set_cur_exp_value_number(mp, &(mp_get_value_number(p))); if (mp_get_value_knot(p)) { mp_set_cur_exp_knot(mp, mp_get_value_knot(p)); } else if (mp_get_value_node(p)) { mp_set_cur_exp_node(mp, mp_get_value_node(p)); } else if (mp_get_value_str(p)) { mp_set_cur_exp_str(mp, mp_get_value_str(p)); } mp_free_value_node(mp, p); break; } } void mp_print_exp (MP mp, mp_node p, int verbosity) { int restore_cur_exp; mp_variable_type t; mp_number vv; mp_node v = NULL; new_number(vv); if (p != NULL) { restore_cur_exp = 0; } else { p = mp_stash_cur_exp(mp); restore_cur_exp = 1; } t = p->type; if (t < mp_dependent_type) { if (t != mp_vacuous_type && t != mp_known_type && mp_get_value_node(p) != NULL) { v = mp_get_value_node(p); } else { number_clone(vv, mp_get_value_number(p)); } } else if (t < mp_independent_type) { v = (mp_node) mp_get_dep_list((mp_value_node) p); } switch (t) { case mp_vacuous_type: mp_print_str(mp, "vacuous"); break; case mp_boolean_type: mp_print_str(mp, number_to_boolean(vv) == mp_true_operation ? "true": "false"); break; case mp_unknown_boolean_type: case mp_unknown_string_type: case mp_unknown_pen_type: case mp_unknown_nep_type: case mp_unknown_path_type: case mp_unknown_picture_type: case mp_numeric_type: { { mp_print_type(mp, t); if (v != NULL) { mp_print_chr(mp, ' '); while ((v->name_type == mp_capsule_operation) && (v != p)) { v = mp_get_value_node(v); } mp_print_variable_name(mp, v); }; } } break; case mp_string_type: mp_print_chr(mp, '"'); mp_print_mp_str(mp, mp_get_value_str(p)); mp_print_chr(mp, '"'); break; case mp_pen_type: case mp_nep_type: case mp_path_type: case mp_picture_type: { if (verbosity <= 1) { mp_print_type(mp, t); } else { if (mp->selector == mp_term_and_log_selector) if (number_nonpositive(internal_value(mp_tracing_online_internal))) { mp->selector = mp_term_only_selector; mp_print_type(mp, t); mp_print_str(mp, " (see the transcript file)"); mp->selector = mp_term_and_log_selector; }; switch (t) { case mp_pen_type: case mp_nep_type: mp_print_pen(mp, mp_get_value_knot(p), "", 0); break; case mp_path_type: mp_print_path(mp, mp_get_value_knot(p), "", 0); break; case mp_picture_type: mp_print_edges(mp, v, "", 0); break; default: break; } } } break; case mp_transform_type: if (number_zero(vv) && v == NULL) { mp_print_type(mp, t); } else { mp_print_chr(mp, '('); mp_print_big_node(mp, mp_tx_part(v), verbosity); mp_print_chr(mp, ','); mp_print_big_node(mp, mp_ty_part(v), verbosity); mp_print_chr(mp, ','); mp_print_big_node(mp, mp_xx_part(v), verbosity); mp_print_chr(mp, ','); mp_print_big_node(mp, mp_xy_part(v), verbosity); mp_print_chr(mp, ','); mp_print_big_node(mp, mp_yx_part(v), verbosity); mp_print_chr(mp, ','); mp_print_big_node(mp, mp_yy_part(v), verbosity); mp_print_chr(mp, ')'); } break; case mp_color_type: if (number_zero(vv) && v == NULL) { mp_print_type(mp, t); } else { mp_print_chr(mp, '('); mp_print_big_node(mp, mp_red_part(v), verbosity); mp_print_chr(mp, ','); mp_print_big_node(mp, mp_green_part(v), verbosity); mp_print_chr(mp, ','); mp_print_big_node(mp, mp_blue_part(v), verbosity); mp_print_chr(mp, ')'); } break; case mp_pair_type: if (number_zero(vv) && v == NULL) { mp_print_type(mp, t); } else { mp_print_chr(mp, '('); mp_print_big_node(mp, mp_x_part(v), verbosity); mp_print_chr(mp, ','); mp_print_big_node(mp, mp_y_part(v), verbosity); mp_print_chr(mp, ')'); } break; case mp_cmykcolor_type: if (number_zero(vv) && v == NULL) { mp_print_type(mp, t); } else { mp_print_chr(mp, '('); mp_print_big_node(mp, mp_cyan_part(v), verbosity); mp_print_chr(mp, ','); mp_print_big_node(mp, mp_magenta_part(v), verbosity); mp_print_chr(mp, ','); mp_print_big_node(mp, mp_yellow_part(v), verbosity); mp_print_chr(mp, ','); mp_print_big_node(mp, mp_black_part(v), verbosity); mp_print_chr(mp, ')'); } break; case mp_known_type: print_number(vv); break; case mp_dependent_type: case mp_proto_dependent_type: mp_print_dp(mp, t, (mp_value_node) v, verbosity); break; case mp_independent_type: mp_print_variable_name(mp, p); break; default: mp_confusion(mp, "expression"); break; } if (restore_cur_exp) { mp_unstash_cur_exp(mp, p); } free_number(vv); } void mp_print_big_node (MP mp, mp_node v, int verbosity) { switch (v->type) { case mp_known_type: print_number(mp_get_value_number(v)); break; case mp_independent_type: mp_print_variable_name(mp, v); break; default: mp_print_dp(mp, v->type, (mp_value_node) mp_get_dep_list((mp_value_node) v), verbosity); break; } } static void mp_print_dp (MP mp, int t, mp_value_node p, int verbosity) { mp_value_node q = (mp_value_node) p->link; if ((mp_get_dep_info(q) == NULL) || (verbosity > 0)) { mp_print_dependency(mp, p, t); } else { mp_print_str(mp, "linearform"); } } void mp_disp_err (MP mp, mp_node p) { if (mp->interaction >= mp_error_stop_mode) { wake_up_terminal(); } mp_print_nl(mp, " "); mp_print_exp(mp, p, 1); } void mp_flush_cur_exp (MP mp, mp_value v) { if (is_number(mp->cur_exp.data.n)) { free_number(mp->cur_exp.data.n); } switch (mp->cur_exp.type) { case mp_unknown_boolean_type: case mp_unknown_string_type: case mp_unknown_pen_type: case mp_unknown_nep_type: case mp_unknown_path_type: case mp_unknown_picture_type: case mp_transform_type: case mp_color_type: case mp_pair_type: case mp_dependent_type: case mp_proto_dependent_type: case mp_independent_type: case mp_cmykcolor_type: mp_recycle_value(mp, cur_exp_node); mp_free_value_node(mp, cur_exp_node); break; case mp_string_type: delete_str_ref(cur_exp_str); break; case mp_pen_type: case mp_nep_type: case mp_path_type: mp_toss_knot_list(mp, cur_exp_knot); break; case mp_picture_type: mp_delete_edge_ref(mp, cur_exp_node); break; default: break; } mp->cur_exp = v; mp->cur_exp.type = mp_known_type; } static void mp_recycle_value (MP mp, mp_node p) { if (p != NULL && p != MP_VOID) { mp_variable_type t = p->type; switch (t) { case mp_vacuous_type: case mp_boolean_type: case mp_known_type: case mp_numeric_type: break; case mp_unknown_boolean_type: case mp_unknown_string_type: case mp_unknown_pen_type: case mp_unknown_nep_type: case mp_unknown_path_type: case mp_unknown_picture_type: mp_ring_delete (mp, p); break; case mp_string_type: delete_str_ref(mp_get_value_str(p)); break; case mp_path_type: case mp_pen_type: case mp_nep_type: mp_toss_knot_list(mp, mp_get_value_knot(p)); break; case mp_picture_type: mp_delete_edge_ref(mp, mp_get_value_node(p)); break; case mp_cmykcolor_type: if (mp_get_value_node(p) != NULL) { mp_recycle_value(mp, mp_cyan_part(mp_get_value_node(p))); mp_recycle_value(mp, mp_magenta_part(mp_get_value_node(p))); mp_recycle_value(mp, mp_yellow_part(mp_get_value_node(p))); mp_recycle_value(mp, mp_black_part(mp_get_value_node(p))); mp_free_value_node(mp, mp_cyan_part(mp_get_value_node(p))); mp_free_value_node(mp, mp_magenta_part(mp_get_value_node(p))); mp_free_value_node(mp, mp_black_part(mp_get_value_node(p))); mp_free_value_node(mp, mp_yellow_part(mp_get_value_node(p))); mp_free_node(mp, mp_get_value_node(p), sizeof(mp_color_node_data)); } break; case mp_pair_type: if (mp_get_value_node(p) != NULL) { mp_recycle_value(mp, mp_x_part(mp_get_value_node(p))); mp_recycle_value(mp, mp_y_part(mp_get_value_node(p))); mp_free_value_node(mp, mp_x_part(mp_get_value_node(p))); mp_free_value_node(mp, mp_y_part(mp_get_value_node(p))); mp_free_pair_node(mp, mp_get_value_node(p)); } break; case mp_color_type: if (mp_get_value_node(p) != NULL) { mp_recycle_value(mp, mp_red_part(mp_get_value_node(p))); mp_recycle_value(mp, mp_green_part(mp_get_value_node(p))); mp_recycle_value(mp, mp_blue_part(mp_get_value_node(p))); mp_free_value_node(mp, mp_red_part(mp_get_value_node(p))); mp_free_value_node(mp, mp_green_part(mp_get_value_node(p))); mp_free_value_node(mp, mp_blue_part(mp_get_value_node(p))); mp_free_node(mp, mp_get_value_node(p), sizeof(mp_color_node_data)); } break; case mp_transform_type: if (mp_get_value_node(p) != NULL) { mp_recycle_value(mp, mp_tx_part(mp_get_value_node(p))); mp_recycle_value(mp, mp_ty_part(mp_get_value_node(p))); mp_recycle_value(mp, mp_xx_part(mp_get_value_node(p))); mp_recycle_value(mp, mp_xy_part(mp_get_value_node(p))); mp_recycle_value(mp, mp_yx_part(mp_get_value_node(p))); mp_recycle_value(mp, mp_yy_part(mp_get_value_node(p))); mp_free_value_node(mp, mp_tx_part(mp_get_value_node(p))); mp_free_value_node(mp, mp_ty_part(mp_get_value_node(p))); mp_free_value_node(mp, mp_xx_part(mp_get_value_node(p))); mp_free_value_node(mp, mp_xy_part(mp_get_value_node(p))); mp_free_value_node(mp, mp_yx_part(mp_get_value_node(p))); mp_free_value_node(mp, mp_yy_part(mp_get_value_node(p))); mp_free_node(mp, mp_get_value_node(p), sizeof(mp_transform_node_data)); } break; case mp_dependent_type: case mp_proto_dependent_type: { mp_value_node qq = (mp_value_node) mp_get_dep_list((mp_value_node) p); while (mp_get_dep_info(qq) != NULL) { qq = (mp_value_node) qq->link; } mp_set_link(mp_get_prev_dep((mp_value_node) p), qq->link); mp_set_prev_dep(qq->link, mp_get_prev_dep((mp_value_node) p)); mp_set_link(qq, NULL); mp_flush_node_list(mp, (mp_node) mp_get_dep_list((mp_value_node) p)); } break; case mp_independent_type: mp_recycle_independent_value(mp, p); break; case mp_token_list_type: case mp_structured_type: mp_confusion(mp, "recycle"); break; case mp_unsuffixed_macro_type: case mp_suffixed_macro_type: mp_delete_mac_ref(mp, mp_get_value_node(p)); break; default: break; } p->type = mp_undefined_type; } } static void mp_recycle_independent_value (MP mp, mp_node p) { mp_value_node q, r, s; mp_node pp; mp_number v ; mp_number test; mp_variable_type t = p->type; new_number(test); new_number(v); if (t < mp_dependent_type) { number_clone(v, mp_get_value_number(p)); } set_number_to_zero(mp->max_c[mp_dependent_type]); set_number_to_zero(mp->max_c[mp_proto_dependent_type]); mp->max_link[mp_dependent_type] = NULL; mp->max_link[mp_proto_dependent_type] = NULL; q = (mp_value_node) mp->dep_head->link; while (q != mp->dep_head) { s = (mp_value_node) mp->temp_head; mp_set_link(s, mp_get_dep_list(q)); while (1) { r = (mp_value_node) s->link; if (mp_get_dep_info(r) == NULL) { break; } else if (mp_get_dep_info(r) != p) { s = r; } else { t = q->type; if (s->link == mp_get_dep_list(q)) { mp_set_dep_list(q, r->link); } mp_set_link(s, r->link); mp_set_dep_info(r, (mp_node) q); number_abs_clone(test, mp_get_dep_value(r)); if (number_greater(test, mp->max_c[t])) { if (number_positive(mp->max_c[t])) { mp_set_link(mp->max_ptr[t], (mp_node) mp->max_link[t]); mp->max_link[t] = mp->max_ptr[t]; } number_clone(mp->max_c[t], test); mp->max_ptr[t] = r; } else { mp_set_link(r, mp->max_link[t]); mp->max_link[t] = r; } } } q = (mp_value_node) r->link; } if (number_positive(mp->max_c[mp_dependent_type]) || number_positive(mp->max_c[mp_proto_dependent_type])) { mp_number test, ret; new_number(ret); new_number_clone(test, mp->max_c[mp_dependent_type]); number_divide_int(test, 4096); if (number_greaterequal(test, mp->max_c[mp_proto_dependent_type])) { t = mp_dependent_type; } else { t = mp_proto_dependent_type; } s = mp->max_ptr[t]; pp = (mp_node) mp_get_dep_info(s); number_clone(v, mp_get_dep_value(s)); if (t == mp_dependent_type) { mp_set_dep_value(s, fraction_one_t); } else { mp_set_dep_value(s, unity_t); } number_negate(mp_get_dep_value(s)); r = (mp_value_node) mp_get_dep_list((mp_value_node) pp); mp_set_link(s, r); while (mp_get_dep_info(r) != NULL) { r = (mp_value_node) r->link; } q = (mp_value_node) r->link; mp_set_link(r, NULL); mp_set_prev_dep(q, mp_get_prev_dep((mp_value_node) pp)); mp_set_link(mp_get_prev_dep((mp_value_node) pp), (mp_node) q); mp_new_indep(mp, pp); if (cur_exp_node == pp && mp->cur_exp.type == t) { mp->cur_exp.type = mp_independent_type; } if (number_positive(internal_value(mp_tracing_equations_internal)) && mp_interesting(mp, p)) { mp_begin_diagnostic(mp); mp_show_transformed_dependency(mp, &v, t, p); mp_print_dependency(mp, s, t); mp_end_diagnostic(mp, 0); } t = mp_dependent_type + mp_proto_dependent_type - t; if (number_positive(mp->max_c[t])) { mp_set_link(mp->max_ptr[t], (mp_node) mp->max_link[t]); mp->max_link[t] = mp->max_ptr[t]; } if (t != mp_dependent_type) { for (t = mp_dependent_type; t <= mp_proto_dependent_type; t=t+1) { r = mp->max_link[t]; while (r != NULL) { q = (mp_value_node) mp_get_dep_info(r); number_negated_clone(test, v); make_fraction(ret, mp_get_dep_value(r), test); mp_set_dep_list(q, mp_p_plus_fq(mp, (mp_value_node) mp_get_dep_list(q), &ret, s, t, mp_dependent_type)); if (mp_get_dep_list(q) == (mp_node) mp->dep_final) { mp_make_known(mp, q, mp->dep_final); } q = r; r = (mp_value_node) r->link; mp_free_dep_node(mp, q); } } } else { for (t = mp_dependent_type; t <= mp_proto_dependent_type; t++) { r = mp->max_link[t]; while (r != NULL) { q = (mp_value_node) mp_get_dep_info(r); if (t == mp_dependent_type) { if (cur_exp_node == (mp_node) q && mp->cur_exp.type == mp_dependent_type) { mp->cur_exp.type = mp_proto_dependent_type; } mp_set_dep_list(q, mp_p_over_v(mp, (mp_value_node) mp_get_dep_list(q), &unity_t, mp_dependent_type, mp_proto_dependent_type)); q->type = mp_proto_dependent_type; fraction_to_round_scaled(mp_get_dep_value(r)); } number_negated_clone(test, v); make_scaled(ret, mp_get_dep_value(r), test); mp_set_dep_list(q, mp_p_plus_fq(mp, (mp_value_node) mp_get_dep_list(q), &ret, s, mp_proto_dependent_type, mp_proto_dependent_type)); if (mp_get_dep_list(q) == (mp_node) mp->dep_final) { mp_make_known(mp, q, mp->dep_final); } q = r; r = (mp_value_node) r->link; mp_free_dep_node(mp, q); } } } mp_flush_node_list(mp, (mp_node) s); if (mp->fix_needed) { mp_fix_dependencies(mp); } check_arith(); free_number(ret); } free_number(v); free_number(test); } static void mp_show_transformed_dependency (MP mp, mp_number *v, mp_variable_type t, mp_node p) { mp_number vv; mp_print_nl(mp, "### "); if (number_positive(*v)) { mp_print_chr(mp, '-'); } if (t == mp_dependent_type) { new_number_clone(vv, mp->max_c[mp_dependent_type]); fraction_to_round_scaled(vv); } else { new_number_clone(vv, mp->max_c[mp_proto_dependent_type]); } if (! number_equal(vv, unity_t)) { print_number(vv); } mp_print_variable_name(mp, p); while (mp_get_indep_scale(p) > 0) { mp_print_str(mp, "*4"); mp_set_indep_scale(p, mp_get_indep_scale(p)-2); } if (t == mp_dependent_type) { mp_print_chr(mp, '='); } else { mp_print_str(mp, " = "); } free_number(vv); } static void mp_bad_exp (MP mp, const char *s) { char msg[256]; int save_flag; { mp_string cm; int selector = mp->selector; mp->selector = mp_new_string_selector; mp_print_cmd_mod(mp, cur_cmd, cur_mod); mp->selector = selector; cm = mp_make_string(mp); mp_snprintf(msg, 256, "%s expression can't begin with '%s'", s, mp_str(mp, cm)); delete_str_ref(cm); } mp_back_input(mp); set_cur_sym(NULL); set_cur_cmd(mp_numeric_command); set_cur_mod_number(zero_t); mp_ins_error( mp, msg, "I'm afraid I need some sort of value in order to continue, so I've tentatively\n" "inserted '0'." ); save_flag = mp->var_flag; mp->var_flag = 0; mp_get_x_next(mp); mp->var_flag = save_flag; } static void mp_stash_in (MP mp, mp_node p) { p->type = mp->cur_exp.type; if (mp->cur_exp.type == mp_known_type) { mp_set_value_number(p, cur_exp_value_number); } else if (mp->cur_exp.type == mp_independent_type) { mp_value_node q = mp_single_dependency(mp, cur_exp_node); if (q == mp->dep_final) { p->type = mp_known_type; mp_set_value_number(p, zero_t); mp_free_dep_node(mp, q); } else { mp_new_dep(mp, p, mp_dependent_type, q); } mp_recycle_value(mp, cur_exp_node); mp_free_value_node(mp, cur_exp_node); } else { mp_set_dep_list((mp_value_node) p, mp_get_dep_list((mp_value_node) cur_exp_node)); mp_set_prev_dep((mp_value_node) p, mp_get_prev_dep((mp_value_node) cur_exp_node)); mp_set_link(mp_get_prev_dep((mp_value_node) p), p); mp_free_dep_node(mp, (mp_value_node) cur_exp_node); } mp->cur_exp.type = mp_vacuous_type; } static void mp_back_expr (MP mp) { mp_node p = mp_stash_cur_exp(mp); p->link = NULL; mp_begin_token_list(mp, p, mp_backed_up_text); } static void mp_bad_subscript (MP mp) { mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); mp_disp_err(mp, NULL); mp_error( mp, "Improper subscript has been replaced by zero", "A bracketed subscript must have a known numeric value; unfortunately, what I\n" "found was the value that appears just above this error message. So I'll try a\n" "zero subscript." ); mp_flush_cur_exp(mp, new_expr); } static char *mp_obliterated (MP mp, mp_node q) { char msg[256]; mp_string sname; int selector = mp->selector; mp->selector = mp_new_string_selector; mp_show_token_list(mp, q, NULL); sname = mp_make_string(mp); mp->selector = selector; mp_snprintf(msg, 256, "Variable %s has been obliterated", mp_str(mp, sname)); delete_str_ref(sname); return mp_strdup(msg); } static void mp_binary_mac (MP mp, mp_node p, mp_node c, mp_sym n) { mp_node q = mp_new_symbolic_node(mp); mp_node r = mp_new_symbolic_node(mp); q->link = r; mp_set_sym_sym(q, p); mp_set_sym_sym(r, mp_stash_cur_exp(mp)); mp_macro_call(mp, c, q, n); } static mp_knot mp_pair_to_knot (MP mp) { mp_knot q = mp_new_knot(mp); mp_left_type(q) = mp_endpoint_knot; mp_right_type(q) = mp_endpoint_knot; mp_originator(q) = mp_metapost_user; mp_knotstate(q) = mp_regular_knot; mp_prev_knot(q) = q; mp_next_knot(q) = q; mp_known_pair(mp); number_clone(q->x_coord, mp->cur_x); number_clone(q->y_coord, mp->cur_y); return q; } void mp_known_pair (MP mp) { mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); if (mp->cur_exp.type != mp_pair_type) { mp_disp_err(mp, NULL); mp_back_error( mp, "Undefined coordinates have been replaced by (0,0)", "I need x and y numbers for this part of the path. The value I found (see above)\n" "was no good; so I'll try to keep going by using zero instead." ); mp_get_x_next(mp); mp_flush_cur_exp(mp, new_expr); set_number_to_zero(mp->cur_x); set_number_to_zero(mp->cur_y); } else { mp_node p = mp_get_value_node(cur_exp_node); if (mp_x_part(p)->type == mp_known_type) { number_clone(mp->cur_x, mp_get_value_number(mp_x_part(p))); } else { mp_disp_err(mp, mp_x_part(p)); mp_back_error( mp, "Undefined x coordinate has been replaced by 0", "I need a 'known' x value for this part of the path. The value I found (see above)\n" "was no good; so I'll try to keep going by using zero instead." ); mp_get_x_next(mp); mp_recycle_value(mp, mp_x_part(p)); set_number_to_zero(mp->cur_x); } if (mp_y_part(p)->type == mp_known_type) { number_clone(mp->cur_y, mp_get_value_number(mp_y_part(p))); } else { mp_disp_err(mp, mp_y_part(p)); mp_back_error( mp, "Undefined y coordinate has been replaced by 0", "I need a 'known' y value for this part of the path. The value I found (see above)\n" "was no good; so I'll try to keep going by using zero instead." ); mp_get_x_next(mp); mp_recycle_value(mp, mp_y_part(p)); set_number_to_zero(mp->cur_y); } mp_flush_cur_exp(mp, new_expr); } } static int mp_scan_direction (MP mp) { int t; mp_get_x_next(mp); if (cur_cmd == mp_curl_command) { mp_get_x_next(mp); mp_scan_expression(mp); if ((mp->cur_exp.type != mp_known_type) || (number_negative(cur_exp_value_number))) { mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); set_number_to_unity(new_expr.data.n); mp_disp_err(mp, NULL); mp_back_error( mp, "Improper curl has been replaced by 1", "A curl must be a known, nonnegative number." ); mp_get_x_next(mp); mp_flush_cur_exp(mp, new_expr); } t = mp_curl_knot; } else { mp_scan_expression(mp); if (mp->cur_exp.type > mp_pair_type) { mp_number xx; new_number(xx); if (mp->cur_exp.type != mp_known_type) { mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); mp_disp_err(mp, NULL); mp_back_error( mp, "Undefined x coordinate has been replaced by 0", "I need a 'known' x value for this part of the path. The value I found (see above)\n" "was no good; so I'll try to keep going by using zero instead." ); mp_get_x_next(mp); mp_flush_cur_exp(mp, new_expr); } number_clone(xx, cur_exp_value_number); if (cur_cmd != mp_comma_command) { mp_back_error( mp, "Missing ',' has been inserted", "I've got the x coordinate of a path direction; will look for the y coordinate\n" "next." ); } mp_get_x_next(mp); mp_scan_expression(mp); if (mp->cur_exp.type != mp_known_type) { mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); mp_disp_err(mp, NULL); mp_back_error( mp, "Undefined y coordinate has been replaced by 0", "I need a 'known' y value for this part of the path. The value I found (see above)\n" "was no good; so I'll try to keep going by using zero instead." ); mp_get_x_next(mp); mp_flush_cur_exp(mp, new_expr); } number_clone(mp->cur_y, cur_exp_value_number); number_clone(mp->cur_x, xx); free_number(xx); } else { mp_known_pair(mp); } if (number_zero(mp->cur_x) && number_zero(mp->cur_y)) { t = mp_open_knot; } else { mp_number narg; new_angle(narg); n_arg(narg, mp->cur_x, mp->cur_y); t = mp_given_knot; mp_set_cur_exp_value_number(mp, &narg); free_number(narg); } } if (cur_cmd != mp_right_brace_command) { mp_back_error( mp, "Missing '}' has been inserted", "I've scanned a direction spec for part of a path, so a right brace should have\n" "come next. I shall pretend that one was there." ); } mp_get_x_next(mp); return t; } static void push_of_path_result (MP mp, int what, mp_knot p) { switch (what) { case 0: mp_pair_value(mp, &(p->x_coord), &(p->y_coord)); break; case 1: if (mp_left_type(p) == mp_endpoint_knot) { mp_pair_value(mp, &(p->x_coord), &(p->y_coord)); } else { mp_pair_value(mp, &(p->left_x), &(p->left_y)); } break; case 2: if (mp_right_type(p) == mp_endpoint_knot) { mp_pair_value(mp, &(p->x_coord), &(p->y_coord)); } else { mp_pair_value(mp, &(p->right_x), &(p->right_y)); } break; case 3: { mp_number x, y; if (mp_right_type(p) == mp_endpoint_knot) { new_number_clone(x, p->x_coord); new_number_clone(y, p->y_coord); } else { new_number_clone(x, p->right_x); new_number_clone(y, p->right_y); } if (mp_left_type(p) == mp_endpoint_knot) { number_subtract(x, p->x_coord); number_subtract(y, p->y_coord); } else { number_subtract(x, p->left_x); number_subtract(y, p->left_y); } mp_pair_value(mp, &x, &y); free_number(x); free_number(y); } break; } } static void mp_finish_read (MP mp) { mp_str_room(mp, (int) mp->last - (int) start); for (size_t k = (size_t) start; k < mp->last; k++) { mp_append_char(mp, mp->buffer[k]); } mp_end_file_reading(mp); mp->cur_exp.type = mp_string_type; mp_set_cur_exp_str(mp, mp_make_string(mp)); } static void mp_do_nullary (MP mp, int c) { check_arith(); if (number_greater(internal_value(mp_tracing_commands_internal), two_t)) { mp_show_cmd_mod(mp, mp_nullary_command, c); } switch (c) { case mp_true_operation: case mp_false_operation: mp->cur_exp.type = mp_boolean_type; mp_set_cur_exp_value_boolean(mp, c); break; case mp_null_picture_operation: mp->cur_exp.type = mp_picture_type; mp_set_cur_exp_node(mp, (mp_node) mp_get_edge_header_node(mp)); mp_init_edges(mp, (mp_edge_header_node) cur_exp_node); break; case mp_null_pen_operation: mp->cur_exp.type = mp_pen_type; mp_set_cur_exp_knot(mp, mp_get_pen_circle(mp, &zero_t)); break; case mp_normal_deviate_operation: { mp_number r; new_number(r); m_norm_rand(r); mp->cur_exp.type = mp_known_type; mp_set_cur_exp_value_number(mp, &r); free_number(r); } break; case mp_pen_circle_operation: mp->cur_exp.type = mp_pen_type; mp_set_cur_exp_knot(mp, mp_get_pen_circle(mp, &unity_t)); break; case mp_version_operation: mp->cur_exp.type = mp_string_type; mp_set_cur_exp_str(mp, mp_intern(mp, metapost_version)); break; case mp_path_point_operation: case mp_path_precontrol_operation: case mp_path_postcontrol_operation: case mp_path_direction_operation: if (mp->loop_ptr && mp->loop_ptr->point != NULL) { push_of_path_result(mp, c - mp_path_point_operation, mp->loop_ptr->point); } else { mp_pair_value(mp, &zero_t, &zero_t); } break; } check_arith(); } static int mp_pict_color_type (MP mp, int c) { return ( (mp_edge_list(cur_exp_node)->link != NULL) && ( (! mp_has_color(mp_edge_list(cur_exp_node)->link)) || (( (mp_color_model(mp_edge_list(cur_exp_node)->link) == c) || ( (mp_color_model(mp_edge_list(cur_exp_node)->link) == mp_uninitialized_model) && (number_to_scaled(internal_value(mp_default_color_model_internal))/number_to_scaled(unity_t)) == c ) )) ) ); } static mp_knot mp_simple_knot(MP mp, mp_number *x, mp_number *y) { mp_knot k = mp_new_knot(mp); mp_left_type(k) = mp_explicit_knot; mp_right_type(k) = mp_explicit_knot; mp_originator(k) = mp_program_code; mp_knotstate(k) = mp_regular_knot; number_clone(k->x_coord, *x); number_clone(k->y_coord, *y); number_clone(k->left_x, *x); number_clone(k->left_y, *y); number_clone(k->right_x, *x); number_clone(k->right_y, *y); return k; } static mp_knot mp_complex_knot(MP mp, mp_knot o) { mp_knot k = mp_new_knot(mp); mp_left_type(k) = mp_explicit_knot; mp_right_type(k) = mp_explicit_knot; mp_originator(k) = mp_program_code; mp_knotstate(k) = mp_regular_knot; number_clone(k->x_coord, o->x_coord); number_clone(k->y_coord, o->y_coord); number_clone(k->left_x, o->left_x); number_clone(k->left_y, o->left_y); number_clone(k->right_x, o->right_x); number_clone(k->right_y, o->right_y); return k; } static int mp_nice_pair (MP mp, mp_node p, int t) { (void) mp; if (t == mp_pair_type) { p = mp_get_value_node(p); if (mp_x_part(p)->type == mp_known_type && mp_y_part(p)->type == mp_known_type) return 1; } return 0; } static int mp_nice_color_or_pair (MP mp, mp_node p, int t) { mp_node q; (void) mp; switch (t) { case mp_pair_type: q = mp_get_value_node(p); if (mp_x_part(q)->type == mp_known_type && mp_y_part(q)->type == mp_known_type) { return 1; } else { break; } case mp_color_type: q = mp_get_value_node(p); if (mp_red_part (q)->type == mp_known_type && mp_green_part(q)->type == mp_known_type && mp_blue_part (q)->type == mp_known_type) return 1; break; case mp_cmykcolor_type: q = mp_get_value_node(p); if (mp_cyan_part (q)->type == mp_known_type && mp_magenta_part(q)->type == mp_known_type && mp_yellow_part (q)->type == mp_known_type && mp_black_part (q)->type == mp_known_type) return 1; break; } return 0; } static void mp_print_known_or_unknown_type (MP mp, int t, mp_node v) { mp_print_chr(mp, '('); if (t > mp_known_type) { mp_print_str(mp, "unknown numeric"); } else { switch (t) { case mp_pair_type: case mp_color_type: case mp_cmykcolor_type: if (! mp_nice_color_or_pair (mp, v, t)) { mp_print_str(mp, "unknown "); } break; } mp_print_type(mp, t); } mp_print_chr(mp, ')'); } static void mp_bad_unary (MP mp, int c) { char msg[256]; mp_string sname; int selector = mp->selector; mp->selector = mp_new_string_selector; mp_print_op(mp, c); mp_print_known_or_unknown_type(mp, mp->cur_exp.type, cur_exp_node); sname = mp_make_string(mp); mp->selector = selector; mp_snprintf(msg, 256, "Not implemented: %s", mp_str(mp, sname)); delete_str_ref(sname); mp_disp_err(mp, NULL); mp_back_error( mp, msg, "I'm afraid I don't know how to apply that operation to that particular type.\n" "Continue, and I'll simply return the argument (shown above) as the result of the\n" "operation." ); mp_get_x_next(mp); } static void mp_negate_dep_list (MP mp, mp_value_node p) { (void) mp; while (1) { number_negate(mp_get_dep_value(p)); if (mp_get_dep_info(p) == NULL) return; p = (mp_value_node) p->link; } } static void mp_negate_value(MP mp, mp_node r) { if (r->type == mp_known_type) { mp_set_value_number(r, mp_get_value_number(r)); number_negate(mp_get_value_number(r)); } else { mp_negate_dep_list(mp, (mp_value_node) mp_get_dep_list((mp_value_node) r)); } } static void negate_cur_expr (MP mp) { switch (mp->cur_exp.type) { case mp_color_type: case mp_cmykcolor_type: case mp_pair_type: case mp_independent_type: { mp_node q = cur_exp_node; mp_make_exp_copy(mp, q); if (mp->cur_exp.type == mp_dependent_type) { mp_negate_dep_list(mp, (mp_value_node) mp_get_dep_list((mp_value_node) cur_exp_node)); } else if (mp->cur_exp.type <= mp_pair_type) { mp_node p = mp_get_value_node(cur_exp_node); switch (mp->cur_exp.type) { case mp_pair_type: mp_negate_value(mp, mp_x_part(p)); mp_negate_value(mp, mp_y_part(p)); break; case mp_color_type: mp_negate_value(mp, mp_red_part(p)); mp_negate_value(mp, mp_green_part(p)); mp_negate_value(mp, mp_blue_part(p)); break; case mp_cmykcolor_type: mp_negate_value(mp, mp_cyan_part(p)); mp_negate_value(mp, mp_magenta_part(p)); mp_negate_value(mp, mp_yellow_part(p)); mp_negate_value(mp, mp_black_part(p)); break; default: break; } } mp_recycle_value(mp, q); mp_free_value_node(mp, q); } break; case mp_dependent_type: case mp_proto_dependent_type: mp_negate_dep_list(mp, (mp_value_node) mp_get_dep_list((mp_value_node) cur_exp_node)); break; case mp_known_type: if (is_number(cur_exp_value_number)) { number_negate(cur_exp_value_number); } break; default: mp_bad_unary(mp, mp_minus_operation); break; } } static void mp_pair_to_path (MP mp) { mp_set_cur_exp_knot(mp, mp_pair_to_knot(mp)); mp->cur_exp.type = mp_path_type; } static void mp_take_part (MP mp, int c) { mp_node p = mp_get_value_node(cur_exp_node); mp_set_value_node(mp->temp_val, p); mp->temp_val->type = mp->cur_exp.type; p->link= mp->temp_val; mp_free_value_node(mp, cur_exp_node); switch (c) { case mp_x_part_operation: if (mp->cur_exp.type == mp_pair_type) { mp_make_exp_copy(mp, mp_x_part(p)); } else { mp_make_exp_copy(mp, mp_tx_part(p)); } break; case mp_y_part_operation: if (mp->cur_exp.type == mp_pair_type) { mp_make_exp_copy(mp, mp_y_part(p)); } else { mp_make_exp_copy(mp, mp_ty_part(p)); } break; case mp_xx_part_operation: mp_make_exp_copy(mp, mp_xx_part(p)); break; case mp_xy_part_operation: mp_make_exp_copy(mp, mp_xy_part(p)); break; case mp_yx_part_operation: mp_make_exp_copy(mp, mp_yx_part(p)); break; case mp_yy_part_operation: mp_make_exp_copy(mp, mp_yy_part(p)); break; case mp_red_part_operation: mp_make_exp_copy(mp, mp_red_part(p)); break; case mp_green_part_operation: mp_make_exp_copy(mp, mp_green_part(p)); break; case mp_blue_part_operation: mp_make_exp_copy(mp, mp_blue_part(p)); break; case mp_cyan_part_operation: mp_make_exp_copy(mp, mp_cyan_part(p)); break; case mp_magenta_part_operation: mp_make_exp_copy(mp, mp_magenta_part(p)); break; case mp_yellow_part_operation: mp_make_exp_copy(mp, mp_yellow_part(p)); break; case mp_black_part_operation: mp_make_exp_copy(mp, mp_black_part(p)); break; case mp_grey_part_operation: mp_make_exp_copy(mp, mp_grey_part(p)); break; } mp_recycle_value(mp, mp->temp_val); } static void mp_take_pict_part (MP mp, int c) { mp_node p; mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); p = mp_edge_list(cur_exp_node)->link; if (p != NULL) { switch (c) { case mp_x_part_operation: case mp_y_part_operation: case mp_xx_part_operation: case mp_xy_part_operation: case mp_yx_part_operation: case mp_yy_part_operation: goto NOT_FOUND; case mp_red_part_operation: case mp_green_part_operation: case mp_blue_part_operation: if (mp_has_color(p)) { switch (c) { case mp_red_part_operation: number_clone(new_expr.data.n, ((mp_shape_node) p)->red); break; case mp_green_part_operation: number_clone(new_expr.data.n, ((mp_shape_node) p)->green); break; case mp_blue_part_operation: number_clone(new_expr.data.n, ((mp_shape_node) p)->blue); break; } mp_flush_cur_exp(mp, new_expr); } else goto NOT_FOUND; break; case mp_cyan_part_operation: case mp_magenta_part_operation: case mp_yellow_part_operation: case mp_black_part_operation: if (mp_has_color(p)) { if (mp_color_model(p) == mp_uninitialized_model && c == mp_black_part_operation) { set_number_to_unity(new_expr.data.n); } else { switch (c) { case mp_cyan_part_operation: number_clone(new_expr.data.n, ((mp_shape_node) p)->cyan); break; case mp_magenta_part_operation: number_clone(new_expr.data.n, ((mp_shape_node) p)->magenta); break; case mp_yellow_part_operation: number_clone(new_expr.data.n, ((mp_shape_node) p)->yellow); break; case mp_black_part_operation: number_clone(new_expr.data.n, ((mp_shape_node) p)->black); break; } } mp_flush_cur_exp(mp, new_expr); } else goto NOT_FOUND; break; case mp_grey_part_operation: if (mp_has_color(p)) { number_clone(new_expr.data.n, ((mp_shape_node) p)->grey); mp_flush_cur_exp(mp, new_expr); } else goto NOT_FOUND; break; case mp_color_model_operation: if (mp_has_color(p)) { if (mp_color_model(p) == mp_uninitialized_model) { number_clone(new_expr.data.n, internal_value(mp_default_color_model_internal)); } else { number_clone(new_expr.data.n, unity_t); number_multiply_int(new_expr.data.n, mp_color_model(p)); } mp_flush_cur_exp(mp, new_expr); } else goto NOT_FOUND; break; case mp_prescript_part_operation: if (! mp_has_script(p)) { goto NOT_FOUND; } else { if (mp_pre_script(p)) { new_expr.data.str = mp_pre_script(p); add_str_ref(new_expr.data.str); } else { new_expr.data.str = mp_rts(mp,""); } mp_flush_cur_exp(mp, new_expr); mp->cur_exp.type = mp_string_type; }; break; case mp_postscript_part_operation: if (! mp_has_script(p)) { goto NOT_FOUND; } else { if (mp_post_script(p)) { new_expr.data.str = mp_post_script(p); add_str_ref(new_expr.data.str); } else { new_expr.data.str = mp_rts(mp,""); } mp_flush_cur_exp(mp, new_expr); mp->cur_exp.type = mp_string_type; }; break; case mp_stacking_part_operation: number_clone(new_expr.data.n, unity_t); number_multiply_int(new_expr.data.n, mp_stacking(p)); mp_flush_cur_exp(mp, new_expr); break; case mp_path_part_operation: if (mp_is_stop(p)) { mp_confusion(mp, "picture"); } else { new_expr.data.node = NULL; switch (p->type) { case mp_fill_node_type: case mp_stroked_node_type: new_expr.data.p = mp_copy_path(mp, mp_path_ptr((mp_shape_node) p)); break; case mp_start_clip_node_type: case mp_start_group_node_type: case mp_start_bounds_node_type: new_expr.data.p = mp_copy_path(mp, mp_path_ptr((mp_start_node) p)); break; default: break; } mp_flush_cur_exp(mp, new_expr); mp->cur_exp.type = mp_path_type; } break; case mp_pen_part_operation: if (! mp_has_pen(p)) { goto NOT_FOUND; } else { switch (p->type) { case mp_fill_node_type: case mp_stroked_node_type: if (mp_pen_ptr((mp_shape_node) p) == NULL) { goto NOT_FOUND; } else { new_expr.data.p = mp_copy_pen(mp, mp_pen_ptr((mp_shape_node) p)); mp_flush_cur_exp(mp, new_expr); mp->cur_exp.type = mp_pen_type((mp_shape_node) p) ? mp_nep_type : mp_pen_type ; } break; default: break; } } break; case mp_dash_part_operation: if (p->type != mp_stroked_node_type) { goto NOT_FOUND; } else if (mp_dash_ptr(p) == NULL) { goto NOT_FOUND; } else { mp_add_edge_ref(mp, mp_dash_ptr(p)); new_expr.data.node = (mp_node) mp_scale_edges(mp, &(((mp_shape_node) p)->dashscale), (mp_edge_header_node) mp_dash_ptr(p)); mp_flush_cur_exp(mp, new_expr); mp->cur_exp.type = mp_picture_type; } break; } return; }; NOT_FOUND: switch (c) { case mp_prescript_part_operation: case mp_postscript_part_operation: new_expr.data.str = mp_rts(mp,""); mp_flush_cur_exp(mp, new_expr); mp->cur_exp.type = mp_string_type; break; case mp_path_part_operation: new_expr.data.p = mp_new_knot(mp); mp_flush_cur_exp(mp, new_expr); mp_left_type(cur_exp_knot) = mp_endpoint_knot; mp_right_type(cur_exp_knot) = mp_endpoint_knot; mp_prev_knot(cur_exp_knot) = cur_exp_knot; mp_next_knot(cur_exp_knot) = cur_exp_knot; set_number_to_zero(cur_exp_knot->x_coord); set_number_to_zero(cur_exp_knot->y_coord); mp_originator(cur_exp_knot) = mp_metapost_user; mp_knotstate(cur_exp_knot) = mp_regular_knot; mp->cur_exp.type = mp_path_type; break; case mp_pen_part_operation: new_expr.data.p = mp_get_pen_circle(mp, &zero_t); mp_flush_cur_exp(mp, new_expr); mp->cur_exp.type = mp_pen_type; break; case mp_dash_part_operation: new_expr.data.node = (mp_node) mp_get_edge_header_node(mp); mp_flush_cur_exp(mp, new_expr); mp_init_edges(mp, (mp_edge_header_node) cur_exp_node); mp->cur_exp.type = mp_picture_type; break; default: set_number_to_zero(new_expr.data.n); mp_flush_cur_exp(mp, new_expr); break; } } static void mp_str_to_num (MP mp) { int n; mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); if (cur_exp_str->len == 0) { n = -1; } else { n = cur_exp_str->str[0]; } number_clone(new_expr.data.n, unity_t); number_multiply_int(new_expr.data.n, n); mp_flush_cur_exp(mp, new_expr); } static void mp_path_length (MP mp, mp_number *n) { mp_knot p = cur_exp_knot; int l = mp_left_type(p) == mp_endpoint_knot ? -1 : 0; do { p = mp_next_knot(p); ++l; } while (p != cur_exp_knot); set_number_from_int(*n, l); } static void mp_picture_length (MP mp, mp_number *n) { mp_node p = mp_edge_list(cur_exp_node)->link; int l = 0; if (p != NULL) { if (mp_is_start_or_stop(p) && mp_skip_1component(mp, p) == NULL) { p = p->link; } while (p != NULL) { if (! mp_is_start_or_stop(p)) { p = p->link; } else if (! mp_is_stop(p)) { p = mp_skip_1component(mp, p); } else { break; } ++l; } } set_number_from_int(*n, l); } static void mp_an_angle (MP mp, mp_number *ret, mp_number *xpar, mp_number *ypar) { set_number_to_zero(*ret); if (! (number_zero(*xpar) && number_zero(*ypar))) { n_arg(*ret, *xpar, *ypar); } } static void mp_bezier_slope (MP mp, mp_number *ret, mp_number *AX, mp_number *AY, mp_number *BX, mp_number *BY, mp_number *CX, mp_number *CY, mp_number *DX, mp_number *DY ); static void mp_turn_cycles (MP mp, mp_number *turns, mp_knot c) { int selector; mp_number res, ang; mp_knot p; mp_number xp, yp; mp_number x, y; mp_number arg1, arg2; mp_number in_angle, out_angle; mp_number seven_twenty_deg_t; set_number_to_zero(*turns); new_number(arg1); new_number(arg2); new_number(xp); new_number(yp); new_number(x); new_number(y); new_angle(in_angle); new_angle(out_angle); new_angle(ang); new_angle(res); new_angle(seven_twenty_deg_t); number_clone(seven_twenty_deg_t, three_sixty_deg_t); number_double(seven_twenty_deg_t); p = c; selector = mp->selector; mp->selector = mp_term_only_selector; if (number_greater(internal_value(mp_tracing_commands_internal), unity_t)) { mp_begin_diagnostic(mp); mp_print_nl(mp, ""); mp_end_diagnostic(mp, 0); } do { number_clone(xp, p_next->x_coord); number_clone(yp, p_next->y_coord); mp_bezier_slope(mp, &ang, &(p->x_coord), &(p->y_coord), &(p->right_x), &(p->right_y), &(p_next->left_x), &(p_next->left_y), &xp, &yp); if (number_greater(ang, seven_twenty_deg_t)) { mp_error(mp, "Strange path", NULL); mp->selector = selector; set_number_to_zero(*turns); goto DONE; } number_add(res, ang); if (number_greater(res, one_eighty_deg_t)) { number_subtract(res, three_sixty_deg_t); number_add(*turns, unity_t); } if (number_lessequal(res, negative_one_eighty_deg_t)) { number_add(res, three_sixty_deg_t); number_subtract(*turns, unity_t); } number_clone(x, p_next->left_x); number_clone(y, p_next->left_y); if (number_equal(xp, x) && number_equal(yp, y)) { number_clone(x, p->right_x); number_clone(y, p->right_y); } if (number_equal(xp, x) && number_equal(yp, y)) { number_clone(x, p->x_coord); number_clone(y, p->y_coord); } set_number_from_subtraction(arg1, xp, x); set_number_from_subtraction(arg2, yp, y); mp_an_angle(mp, &in_angle, &arg1, &arg2); number_clone(x, p_next->right_x); number_clone(y, p_next->right_y); if (number_equal(xp, x) && number_equal(yp, y)) { number_clone(x, p_nextnext->left_x); number_clone(y, p_nextnext->left_y); } if (number_equal(xp, x) && number_equal(yp, y)) { number_clone(x, p_nextnext->x_coord); number_clone(y, p_nextnext->y_coord); } set_number_from_subtraction(arg1, x, xp); set_number_from_subtraction(arg2, y, yp); mp_an_angle(mp, &out_angle, &arg1, &arg2); set_number_from_subtraction(ang, out_angle, in_angle); mp_reduce_angle(mp, &ang); if (number_nonzero(ang)) { number_add(res, ang); if (number_greaterequal(res, one_eighty_deg_t)) { number_subtract(res, three_sixty_deg_t); number_add(*turns, unity_t); } if (number_lessequal(res, negative_one_eighty_deg_t)) { number_add(res, three_sixty_deg_t); number_subtract(*turns, unity_t); } } p = mp_next_knot(p); } while (p != c); mp->selector = selector; DONE: free_number(xp); free_number(yp); free_number(x); free_number(y); free_number(seven_twenty_deg_t); free_number(in_angle); free_number(out_angle); free_number(ang); free_number(res); free_number(arg1); free_number(arg2); } static void mp_turn_cycles_wrapper (MP mp, mp_number *ret, mp_knot c) { if (mp_next_knot(c) == c) { set_number_to_unity(*ret); } else { mp_turn_cycles (mp, ret, c); } } static int mp_test_known (MP mp, int c) { int b = mp_false_operation; switch (mp->cur_exp.type) { case mp_vacuous_type: case mp_boolean_type: case mp_string_type: case mp_pen_type: case mp_nep_type: case mp_path_type: case mp_picture_type: case mp_known_type: b = mp_true_operation; break; case mp_transform_type: { mp_node p = mp_get_value_node(cur_exp_node); if ( (mp_tx_part(p)->type == mp_known_type) && (mp_ty_part(p)->type == mp_known_type) && (mp_xx_part(p)->type == mp_known_type) && (mp_xy_part(p)->type== mp_known_type) && (mp_yx_part(p)->type == mp_known_type) && (mp_yy_part(p)->type == mp_known_type) ) { b = mp_true_operation; } } break; case mp_color_type: { mp_node p = mp_get_value_node(cur_exp_node); if ( (mp_red_part (p)->type == mp_known_type) && (mp_green_part(p)->type == mp_known_type) && (mp_blue_part (p)->type == mp_known_type) ) { b = mp_true_operation; } } break; case mp_cmykcolor_type: { mp_node p = mp_get_value_node(cur_exp_node); if ( (mp_cyan_part (p)->type == mp_known_type) && (mp_magenta_part(p)->type == mp_known_type) && (mp_yellow_part (p)->type == mp_known_type) && (mp_black_part (p)->type == mp_known_type) ) { b = mp_true_operation; } } break; case mp_pair_type: { mp_node p = mp_get_value_node(cur_exp_node); if ( (mp_x_part(p)->type == mp_known_type) && (mp_y_part(p)->type == mp_known_type) ) { b = mp_true_operation; } } break; default: break; } if (c == mp_known_operation) { return b; } else { return b == mp_true_operation ? mp_false_operation : mp_true_operation; } } static void mp_pair_value (MP mp, mp_number *x, mp_number *y) { mp_node p; mp_value new_expr; mp_number x1, y1; new_number_clone(x1, *x); new_number_clone(y1, *y); memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); p = mp_new_value_node(mp); new_expr.type = p->type; new_expr.data.node = p; mp_flush_cur_exp(mp, new_expr); mp->cur_exp.type = mp_pair_type; p->name_type = mp_capsule_operation; mp_init_pair_node(mp, p); p = mp_get_value_node(p); mp_x_part(p)->type = mp_known_type; mp_set_value_number(mp_x_part(p), x1); mp_y_part(p)->type = mp_known_type; mp_set_value_number(mp_y_part(p), y1); free_number(x1); free_number(y1); } static int mp_get_cur_bbox (MP mp) { switch (mp->cur_exp.type) { case mp_picture_type: { mp_edge_header_node p = (mp_edge_header_node) cur_exp_node; mp_set_bbox(mp, p, 1); if (number_greater(p->minx, p->maxx)) { set_number_to_zero(mp_minx); set_number_to_zero(mp_maxx); set_number_to_zero(mp_miny); set_number_to_zero(mp_maxy); } else { number_clone(mp_minx, p->minx); number_clone(mp_maxx, p->maxx); number_clone(mp_miny, p->miny); number_clone(mp_maxy, p->maxy); } } break; case mp_path_type: mp_path_bbox(mp, cur_exp_knot); break; case mp_pen_type: case mp_nep_type: mp_pen_bbox(mp, cur_exp_knot); break; default: return 0; } return 1; } static int mp_get_cur_xbox (MP mp) { if (mp->cur_exp.type == mp_path_type) { mp_path_xbox(mp, cur_exp_knot); return 1; } else { return mp_get_cur_bbox(mp); } } static int mp_get_cur_ybox (MP mp) { if (mp->cur_exp.type == mp_path_type) { mp_path_ybox(mp, cur_exp_knot); return 1; } else { return mp_get_cur_bbox(mp); } } static void mp_do_read_or_close (MP mp, int c) { int n = mp->read_files; int n0 = mp->read_files; char *fn = mp_strdup(mp_str(mp, cur_exp_str)); mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); while (mp_strcmp(fn, mp->rd_fname[n]) != 0) { if (n > 0) { --n; } else if (c == mp_close_from_operation) { goto CLOSE_FILE; } else { if (n0 == mp->read_files) { if (mp->read_files < mp->max_read_files) { ++mp->read_files; } else { void **rd_file; char **rd_fname; int l; l = mp->max_read_files + (mp->max_read_files / 4); rd_file = mp_memory_allocate((size_t) (l + 1) * sizeof(void *)); rd_fname = mp_memory_allocate((size_t) (l + 1) * sizeof(char *)); for (int k = 0; k <= l; k++) { if (k <= mp->max_read_files) { rd_file[k] = mp->rd_file[k]; rd_fname[k] = mp->rd_fname[k]; } else { rd_file[k] = 0; rd_fname[k] = NULL; } } mp_memory_free(mp->rd_file); mp_memory_free(mp->rd_fname); mp->max_read_files = l; mp->rd_file = rd_file; mp->rd_fname = rd_fname; } } n = n0; if (mp_start_read_input(mp, fn, n)) { goto FOUND; } else { goto NOT_FOUND; } } if (mp->rd_fname[n] == NULL) { n0 = n; } } if (c == mp_close_from_operation) { (mp->close_file) (mp, mp->rd_file[n]); goto NOT_FOUND; } mp_begin_file_reading(mp); name = is_read; if (mp_input_ln(mp, mp->rd_file[n])) { goto FOUND; } mp_end_file_reading(mp); NOT_FOUND: mp_memory_free(mp->rd_fname[n]); mp->rd_fname[n] = NULL; if (n == mp->read_files - 1) { mp->read_files = n; } if (c == mp_close_from_operation) { goto CLOSE_FILE; } new_expr.data.str = mp->eof_file; add_str_ref(new_expr.data.str); mp_flush_cur_exp(mp, new_expr); mp->cur_exp.type = mp_string_type; return; CLOSE_FILE: mp_flush_cur_exp(mp, new_expr); mp->cur_exp.type = mp_vacuous_type; return; FOUND: mp_flush_cur_exp(mp, new_expr); mp_finish_read(mp); } static void mp_do_unary (MP mp, int c) { check_arith(); if (number_greater(internal_value(mp_tracing_commands_internal), two_t)) { mp_begin_diagnostic(mp); mp_print_nl(mp, "{"); mp_print_op(mp, c); mp_print_chr(mp, '('); mp_print_exp(mp, NULL, 0); mp_print_str(mp, ")}"); mp_end_diagnostic(mp, 0); } switch (c) { case mp_plus_operation: if (mp->cur_exp.type < mp_color_type) { mp_bad_unary(mp, mp_plus_operation); } break; case mp_minus_operation: negate_cur_expr(mp); break; case mp_not_operation: if (mp->cur_exp.type != mp_boolean_type) { mp_bad_unary(mp, mp_not_operation); } else { mp_set_cur_exp_value_boolean(mp, (cur_exp_value_boolean == mp_true_operation) ? mp_false_operation : mp_true_operation); } break; case mp_sqrt_operation: if (mp->cur_exp.type != mp_known_type) { mp_bad_unary(mp, c); } else { mp_number n; new_number(n); square_rt(n, cur_exp_value_number); mp_set_cur_exp_value_number(mp, &n); free_number(n); } break; case mp_m_exp_operation: if (mp->cur_exp.type != mp_known_type) { mp_bad_unary(mp, c); } else { mp_number n; new_number(n); m_exp(n, cur_exp_value_number); mp_set_cur_exp_value_number(mp, &n); free_number(n); } break; case mp_m_log_operation: if (mp->cur_exp.type != mp_known_type) { mp_bad_unary(mp, c); } else { mp_number n; new_number(n); m_log(n, cur_exp_value_number); mp_set_cur_exp_value_number(mp, &n); free_number(n); } break; case mp_sin_d_operation: case mp_cos_d_operation: if (mp->cur_exp.type != mp_known_type) { mp_bad_unary(mp, c); } else { mp_number n_sin, n_cos, arg1, arg2; new_number(arg1); new_number(arg2); new_fraction(n_sin); new_fraction(n_cos); number_clone(arg1, cur_exp_value_number); number_clone(arg2, unity_t); number_multiply_int(arg2, 360); number_modulo(arg1, arg2); convert_scaled_to_angle(arg1); n_sin_cos(arg1, n_cos, n_sin); if (c == mp_sin_d_operation) { fraction_to_round_scaled(n_sin); mp_set_cur_exp_value_number(mp, &n_sin); } else { fraction_to_round_scaled(n_cos); mp_set_cur_exp_value_number(mp, &n_cos); } free_number(arg1); free_number(arg2); free_number(n_sin); free_number(n_cos); } break; case mp_floor_operation: if (mp->cur_exp.type != mp_known_type) { mp_bad_unary(mp, c); } else { mp_number n; new_number(n); number_clone(n, cur_exp_value_number); floor_scaled(n); mp_set_cur_exp_value_number(mp, &n); free_number(n); } break; case mp_uniform_deviate_operation: if (mp->cur_exp.type != mp_known_type) { mp_bad_unary(mp, c); } else { mp_number n; new_number(n); m_unif_rand(n, cur_exp_value_number); mp_set_cur_exp_value_number(mp, &n); free_number(n); } break; case mp_odd_operation: if (mp->cur_exp.type != mp_known_type) { mp_bad_unary(mp, c); } else { mp_set_cur_exp_value_boolean(mp, number_odd(cur_exp_value_number) ? mp_true_operation : mp_false_operation); mp->cur_exp.type = mp_boolean_type; } break; case mp_angle_operation: if (mp_nice_pair (mp, cur_exp_node, mp->cur_exp.type)) { mp_value expr; mp_node p; mp_number narg; memset(&expr, 0, sizeof(mp_value)); new_number(expr.data.n); new_angle(narg); p = mp_get_value_node(cur_exp_node); n_arg(narg, mp_get_value_number(mp_x_part(p)), mp_get_value_number(mp_y_part(p))); number_clone(expr.data.n, narg); convert_angle_to_scaled(expr.data.n); free_number(narg); mp_flush_cur_exp(mp, expr); } else { mp_bad_unary(mp, mp_angle_operation); } break; case mp_x_part_operation: case mp_y_part_operation: switch (mp->cur_exp.type) { case mp_pair_type: case mp_transform_type: mp_take_part(mp, c); break; case mp_picture_type: mp_take_pict_part(mp, c); break; default: mp_bad_unary(mp, c); break; } break; case mp_xx_part_operation: case mp_xy_part_operation: case mp_yx_part_operation: case mp_yy_part_operation: switch (mp->cur_exp.type) { case mp_transform_type: mp_take_part(mp, c); break; case mp_picture_type: mp_take_pict_part(mp, c); break; default: mp_bad_unary(mp, c); break; } break; case mp_red_part_operation: case mp_green_part_operation: case mp_blue_part_operation: switch (mp->cur_exp.type) { case mp_color_type: mp_take_part(mp, c); break; case mp_picture_type: if (mp_pict_color_type(mp, mp_rgb_model)) { mp_take_pict_part(mp, c); } else { mp_bad_color_part(mp, c); } break; default: mp_bad_unary(mp, c); break; } break; case mp_cyan_part_operation: case mp_magenta_part_operation: case mp_yellow_part_operation: case mp_black_part_operation: switch (mp->cur_exp.type) { case mp_cmykcolor_type: mp_take_part(mp, c); break; case mp_picture_type: if (mp_pict_color_type(mp, mp_cmyk_model)) { mp_take_pict_part(mp, c); } else { mp_bad_color_part(mp, c); } break; default: mp_bad_unary(mp, c); break; } break; case mp_grey_part_operation: switch (mp->cur_exp.type) { case mp_known_type: break; case mp_picture_type: if (mp_pict_color_type(mp, mp_grey_model)) { mp_take_pict_part(mp, c); } else { mp_bad_color_part(mp, c); } break; default: mp_bad_unary(mp, c); break; } break; case mp_color_model_operation: case mp_path_part_operation: case mp_pen_part_operation: case mp_dash_part_operation: case mp_prescript_part_operation: case mp_postscript_part_operation: case mp_stacking_part_operation: if (mp->cur_exp.type == mp_picture_type) { mp_take_pict_part(mp, c); } else { mp_bad_unary(mp, c); } break; case mp_char_operation: if (mp->cur_exp.type != mp_known_type) { mp_bad_unary(mp, mp_char_operation); } else { int n = round_unscaled(cur_exp_value_number) % 256; unsigned char s[2]; mp_set_cur_exp_value_scaled(mp, n); mp->cur_exp.type = mp_string_type; if (number_negative(cur_exp_value_number)) { n = number_to_scaled(cur_exp_value_number) + 256; mp_set_cur_exp_value_scaled(mp, n); } s[0] = (unsigned char) number_to_scaled(cur_exp_value_number); s[1] = '\0'; mp_set_cur_exp_str(mp, mp_rtsl (mp, (char *) s, 1)); } break; case mp_decimal_operation: if (mp->cur_exp.type != mp_known_type) { mp_bad_unary(mp, mp_decimal_operation); } else { int selector = mp->selector; mp->selector = mp_new_string_selector; print_number(cur_exp_value_number); mp_set_cur_exp_str(mp, mp_make_string(mp)); mp->selector = selector; mp->cur_exp.type = mp_string_type; } break; case mp_oct_operation: case mp_hex_operation: case mp_ASCII_operation: if (mp->cur_exp.type != mp_string_type) { mp_bad_unary(mp, c); } else { mp_str_to_num(mp); } break; case mp_length_operation: switch (mp->cur_exp.type) { case mp_string_type: { mp_value expr; memset(&expr, 0, sizeof(mp_value)); new_number(expr.data.n); number_clone(expr.data.n, unity_t); number_multiply_int(expr.data.n, (int) cur_exp_str->len); mp_flush_cur_exp(mp, expr); break; } case mp_path_type: { mp_value expr; memset(&expr, 0, sizeof(mp_value)); new_number(expr.data.n); mp_path_length(mp, &expr.data.n); mp_flush_cur_exp(mp, expr); break; } case mp_known_type: { mp_set_cur_exp_value_number(mp, &cur_exp_value_number); number_abs(cur_exp_value_number); break; } case mp_picture_type: { mp_value expr; memset(&expr, 0, sizeof(mp_value)); new_number(expr.data.n); mp_picture_length(mp, &expr.data.n); mp_flush_cur_exp(mp, expr); break; } default: if (mp_nice_pair (mp, cur_exp_node, mp->cur_exp.type)) { mp_value expr; memset(&expr, 0, sizeof(mp_value)); new_number(expr.data.n); pyth_add(expr.data.n, mp_get_value_number(mp_x_part(mp_get_value_node(cur_exp_node))), mp_get_value_number(mp_y_part(mp_get_value_node(cur_exp_node))) ); mp_flush_cur_exp(mp, expr); } else { mp_bad_unary(mp, c); } break; } break; case mp_turning_operation: if (mp->cur_exp.type == mp_pair_type) { mp_value expr; memset(&expr, 0, sizeof(mp_value)); new_number(expr.data.n); mp_flush_cur_exp(mp, expr); } else if (mp->cur_exp.type != mp_path_type) { mp_bad_unary(mp, mp_turning_operation); } else if (mp_left_type(cur_exp_knot) == mp_endpoint_knot) { mp_value expr; memset(&expr, 0, sizeof(mp_value)); new_number(expr.data.n); expr.data.p = NULL; mp_flush_cur_exp(mp, expr); } else { mp_value expr; memset(&expr, 0, sizeof(mp_value)); new_number(expr.data.n); mp_turn_cycles_wrapper(mp, &expr.data.n, cur_exp_knot); mp_flush_cur_exp(mp, expr); } break; case mp_boolean_type_operation: case mp_string_type_operation: case mp_pen_type_operation: case mp_nep_type_operation: case mp_path_type_operation: case mp_picture_type_operation: { mp_value expr; int type = (c - mp_boolean_type_operation) * 2 + mp_boolean_type ; memset(&expr, 0, sizeof(mp_value)); new_number(expr.data.n); set_number_from_boolean(expr.data.n, (mp->cur_exp.type == type || mp->cur_exp.type == (type + 1)) ? mp_true_operation : mp_false_operation); mp_flush_cur_exp(mp, expr); mp->cur_exp.type = mp_boolean_type; break; } case mp_transform_type_operation: case mp_color_type_operation: case mp_cmykcolor_type_operation: case mp_pair_type_operation: { mp_value expr; int type = (c - mp_transform_type_operation) + mp_transform_type; memset(&expr, 0, sizeof(mp_value)); new_number(expr.data.n); set_number_from_boolean(expr.data.n, mp->cur_exp.type == type ? mp_true_operation : mp_false_operation); mp_flush_cur_exp(mp, expr); mp->cur_exp.type = mp_boolean_type; break; } case mp_numeric_type_operation: { mp_value expr; memset(&expr, 0, sizeof(mp_value)); new_number(expr.data.n); set_number_from_boolean(expr.data.n, (mp->cur_exp.type >= mp_known_type && mp->cur_exp.type <= mp_independent_type) ? mp_true_operation : mp_false_operation); mp_flush_cur_exp(mp, expr); mp->cur_exp.type = mp_boolean_type; break; } case mp_known_operation: case mp_unknown_operation: { mp_value expr; memset(&expr, 0, sizeof(mp_value)); new_number(expr.data.n); set_number_from_boolean(expr.data.n, mp_test_known(mp, c)); mp_flush_cur_exp(mp, expr); cur_exp_node = NULL; mp->cur_exp.type = mp_boolean_type; break; } case mp_cycle_operation: case mp_no_cycle_operation: { mp_value expr; int b = 0; memset(&expr, 0, sizeof(mp_value)); new_number(expr.data.n); if (mp->cur_exp.type != mp_path_type) { b = (c == mp_cycle_operation) ? mp_false_operation : mp_true_operation; } else if (mp_left_type(cur_exp_knot) != mp_endpoint_knot) { b = (c == mp_cycle_operation) ? mp_true_operation : mp_false_operation; } else { b = (c == mp_cycle_operation) ? mp_false_operation : mp_true_operation; } set_number_from_boolean(expr.data.n, b); mp_flush_cur_exp(mp, expr); mp->cur_exp.type = mp_boolean_type; break; } case mp_arc_length_operation: if (mp->cur_exp.type == mp_pair_type) { mp_pair_to_path(mp); } if (mp->cur_exp.type != mp_path_type) { mp_bad_unary(mp, mp_arc_length_operation); } else { mp_value expr; memset(&expr, 0, sizeof(mp_value)); new_number(expr.data.n); mp_get_arc_length(mp, &expr.data.n, cur_exp_knot); mp_flush_cur_exp(mp, expr); } break; case mp_filled_operation: case mp_stroked_operation: case mp_clipped_operation: case mp_grouped_operation: case mp_bounded_operation: { mp_value expr; memset(&expr, 0, sizeof(mp_value)); new_number(expr.data.n); if (mp->cur_exp.type != mp_picture_type) { set_number_from_boolean(expr.data.n, mp_false_operation); } else if (mp_edge_list(cur_exp_node)->link == NULL) { set_number_from_boolean(expr.data.n, mp_false_operation); } else { int type = c - mp_filled_operation + mp_fill_node_type; set_number_from_boolean(expr.data.n, mp_edge_list(cur_exp_node)->link->type == type ? mp_true_operation: mp_false_operation); } mp_flush_cur_exp(mp, expr); mp->cur_exp.type = mp_boolean_type; break; } case mp_make_pen_operation: if (mp->cur_exp.type == mp_pair_type) { mp_pair_to_path(mp); } if (mp->cur_exp.type != mp_path_type) { mp_bad_unary(mp, mp_make_pen_operation); } else { mp->cur_exp.type = mp_pen_type; mp_set_cur_exp_knot(mp, mp_make_pen(mp, cur_exp_knot, 1)); } break; case mp_make_nep_operation: if (mp->cur_exp.type == mp_pair_type) { mp_pair_to_path(mp); } if (mp->cur_exp.type != mp_path_type) { mp_bad_unary(mp, c); } else { mp->cur_exp.type = mp_nep_type; mp_set_cur_exp_knot(mp, cur_exp_knot); } break; case mp_convexed_operation: if (mp->cur_exp.type != mp_path_type) { mp_bad_unary(mp, mp_convexed_operation); } else { mp->cur_exp.type = mp_path_type; mp_set_cur_exp_knot(mp, mp_convex_hull(mp, cur_exp_knot)); mp_simplify_path(mp, cur_exp_knot); } break; case mp_uncontrolled_operation: if (mp->cur_exp.type != mp_path_type) { mp_bad_unary(mp, mp_uncontrolled_operation); } else { mp->cur_exp.type = mp_path_type; mp_simplify_path(mp, cur_exp_knot); } break; case mp_make_path_operation: if (mp->cur_exp.type != mp_pen_type && mp->cur_exp.type != mp_nep_type) { mp_bad_unary(mp, mp_make_path_operation); } else { mp->cur_exp.type = mp_path_type; mp_make_path(mp, cur_exp_knot); } break; case mp_reverse_operation: switch (mp->cur_exp.type) { case mp_path_type: { mp_knot pk = mp_htap_ypoc(mp, cur_exp_knot); if (mp_right_type(pk) == mp_endpoint_knot) { pk = mp_next_knot(pk); } mp_toss_knot_list(mp, cur_exp_knot); mp_set_cur_exp_knot(mp, pk); } break; case mp_pair_type: mp_pair_to_path(mp); break; default: mp_bad_unary(mp, mp_reverse_operation); break; } break; case mp_uncycle_operation: switch (mp->cur_exp.type) { case mp_path_type: mp_right_type(mp_prev_knot(cur_exp_knot)) = mp_endpoint_knot; mp_left_type(cur_exp_knot) = mp_endpoint_knot; break; case mp_pair_type: mp_pair_to_path(mp); break; default: mp_bad_unary(mp, mp_uncycle_operation); break; } break; case mp_ll_corner_operation: if (mp_get_cur_bbox(mp)) { mp_pair_value(mp, &mp_minx, &mp_miny); } else { mp_bad_unary(mp, mp_ll_corner_operation); } break; case mp_lr_corner_operation: if (mp_get_cur_bbox(mp)) { mp_pair_value(mp, &mp_maxx, &mp_miny); } else { mp_bad_unary(mp, mp_lr_corner_operation); } break; case mp_ul_corner_operation: if (mp_get_cur_bbox(mp)) { mp_pair_value(mp, &mp_minx, &mp_maxy); } else { mp_bad_unary(mp, mp_ul_corner_operation); } break; case mp_ur_corner_operation: if (! mp_get_cur_bbox(mp)) { mp_bad_unary(mp, mp_ur_corner_operation); } else { mp_pair_value(mp, &mp_maxx, &mp_maxy); } break; case mp_center_of_operation: if (mp->cur_exp.type == mp_pair_type) { } else if (mp_get_cur_bbox(mp)) { mp_number x, y; new_number(x); new_number(y); set_number_half_from_subtraction(x, mp_maxx, mp_minx); set_number_half_from_subtraction(y, mp_maxy, mp_miny); number_add(x, mp_minx); number_add(y, mp_miny); mp_pair_value(mp, &x, &y); } else { mp_bad_unary(mp, mp_center_of_operation); } break; case mp_center_of_mass_operation: if (mp->cur_exp.type == mp_pair_type) { } else if (mp->cur_exp.type == mp_path_type) { mp_knot p = cur_exp_knot; int l = 0; mp_number x, y; new_number(x); new_number(y); do { ++l; p = mp_next_knot(p); number_add(x, p->x_coord); number_add(y, p->y_coord); } while (p != cur_exp_knot); number_divide_int(x, l); number_divide_int(y, l); mp_pair_value(mp, &x, &y); free_number(x); free_number(y); } else { mp_bad_unary(mp, mp_center_of_mass_operation); } break; case mp_corners_operation: if (! mp_get_cur_bbox(mp)) { mp_bad_unary(mp, mp_corners_operation); } else { mp_knot ll = mp_simple_knot(mp, &mp_minx, &mp_miny); mp_knot lr = mp_simple_knot(mp, &mp_maxx, &mp_miny); mp_knot ur = mp_simple_knot(mp, &mp_maxx, &mp_maxy); mp_knot ul = mp_simple_knot(mp, &mp_minx, &mp_maxy); mp_prev_knot(lr) = ll; mp_next_knot(ll) = lr; mp_prev_knot(ur) = lr; mp_next_knot(lr) = ur; mp_prev_knot(ul) = ur; mp_next_knot(ur) = ul; mp_prev_knot(ll) = ul; mp_next_knot(ul) = ll; mp->cur_exp.type = mp_path_type; mp_set_cur_exp_knot(mp, ll); } break; case mp_x_range_operation: if (mp_get_cur_xbox(mp)) { mp_pair_value(mp, &mp_minx, &mp_maxx); } else { mp_bad_unary(mp, mp_x_range_operation); } break; case mp_y_range_operation: if (mp_get_cur_ybox(mp)) { mp_pair_value(mp, &mp_miny, &mp_maxy); } else { mp_bad_unary(mp, mp_y_range_operation); } break; case mp_delta_point_operation: case mp_delta_precontrol_operation: case mp_delta_postcontrol_operation: case mp_delta_direction_operation: if (mp->cur_exp.type == mp_known_type) { mp_set_cur_exp_value_number(mp, &cur_exp_value_number); if (mp->loop_ptr && mp->loop_ptr->point != NULL) { mp_knot p = mp->loop_ptr->point; int n = round_unscaled(cur_exp_value_number); if (n > 0) { while (n--) { p = mp_next_knot(p); } } else if (n < 0) { while (n++) { p = mp_prev_knot(p); } } push_of_path_result(mp, c - mp_delta_point_operation, p); } } else { mp_bad_unary(mp, c); } break; case mp_read_from_operation: case mp_close_from_operation: if (mp->cur_exp.type != mp_string_type) { mp_bad_unary(mp, c); } else { mp_do_read_or_close(mp, c); } break; } check_arith(); } static void mp_bad_color_part (MP mp, int c) { mp_node p; mp_value new_expr; char msg[256]; int selector; mp_string sname; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); p = mp_edge_list(cur_exp_node)->link; mp_disp_err(mp, NULL); selector = mp->selector; mp->selector = mp_new_string_selector; mp_print_op(mp, c); sname = mp_make_string(mp); mp->selector = selector; switch (mp_color_model(p)) { case mp_grey_model: mp_snprintf(msg, 256, "Wrong picture color model: %s of grey object", mp_str(mp, sname)); break; case mp_cmyk_model: mp_snprintf(msg, 256, "Wrong picture color model: %s of cmyk object", mp_str(mp, sname)); break; case mp_rgb_model: mp_snprintf(msg, 256, "Wrong picture color model: %s of rgb object", mp_str(mp, sname)); break; case mp_no_model: mp_snprintf(msg, 256, "Wrong picture color model: %s of marking object", mp_str(mp, sname)); break; default: mp_snprintf(msg, 256, "Wrong picture color model: %s of defaulted object", mp_str(mp, sname)); break; } delete_str_ref(sname); mp_error( mp, msg, "You can only ask for the redpart, greenpart, bluepart of a rgb object, the\n" "cyanpart, magentapart, yellowpart or blackpart of a cmyk object, or the greypart\n" "of a grey object. No mixing and matching, please." ); if (c == mp_black_part_operation) { number_clone(new_expr.data.n, unity_t); } else { set_number_to_zero(new_expr.data.n); } mp_flush_cur_exp(mp, new_expr); } static void mp_bezier_slope (MP mp, mp_number *ret, mp_number *AX, mp_number *AY, mp_number *BX, mp_number *BY, mp_number *CX, mp_number *CY, mp_number *DX, mp_number *DY ) { double a, b, c; mp_number deltax, deltay; mp_number xi, xo, xm; double res = 0.0; double ax = number_to_double(*AX); double ay = number_to_double(*AY); double bx = number_to_double(*BX); double by = number_to_double(*BY); double cx = number_to_double(*CX); double cy = number_to_double(*CY); double dx = number_to_double(*DX); double dy = number_to_double(*DY); new_number(deltax); new_number(deltay); set_number_from_subtraction(deltax, *BX, *AX); set_number_from_subtraction(deltay, *BY, *AY); if (number_zero(deltax) && number_zero(deltay)) { set_number_from_subtraction(deltax, *CX, *AX); set_number_from_subtraction(deltay, *CY, *AY); } if (number_zero(deltax) && number_zero(deltay)) { set_number_from_subtraction(deltax, *DX, *AX); set_number_from_subtraction(deltay, *DY, *AY); } new_number(xi); new_number(xm); new_number(xo); mp_an_angle(mp, &xi, &deltax, &deltay); set_number_from_subtraction(deltax, *CX, *BX); set_number_from_subtraction(deltay, *CY, *BY); mp_an_angle(mp, &xm, &deltax, &deltay); set_number_from_subtraction(deltax, *DX, *CX); set_number_from_subtraction(deltay, *DY, *CY); if (number_zero(deltax) && number_zero(deltay)) { set_number_from_subtraction(deltax, *DX, *BX); set_number_from_subtraction(deltay, *DY, *BY); } if (number_zero(deltax) && number_zero(deltay)) { set_number_from_subtraction(deltax, *DX, *AX); set_number_from_subtraction(deltay, *DY, *AY); } mp_an_angle(mp, &xo, &deltax, &deltay); a = (bx - ax) * (cy - by) - (cx - bx) * (by - ay); b = (bx - ax) * (dy - cy) - (by - ay) * (dx - cx); c = (cx - bx) * (dy - cy) - (dx - cx) * (cy - by); if ((a == 0.0) && (c == 0.0)) { res = (b == 0.0 ? 0.0 : (mp_out(number_to_double(xo)) - mp_out(number_to_double(xi)))); } else if ((a == 0.0) || (c == 0.0)) { if ((mp_sign (b) == mp_sign (a)) || (mp_sign (b) == mp_sign (c))) { res = mp_out(number_to_double(xo)) - mp_out(number_to_double(xi)); if (res < -180.0) { res += 360.0; } else if (res > 180.0) { res -= 360.0; } } else { res = mp_out(number_to_double(xo)) - mp_out(number_to_double(xi)); } } else if ((mp_sign (a) * mp_sign (c)) < 0.0) { res = mp_out(number_to_double(xo)) - mp_out(number_to_double(xi)); if (res < -180.0) { res += 360.0; } else if (res > 180.0) { res -= 360.0; } } else if (mp_sign (a) == mp_sign (b)) { res = mp_out(number_to_double(xo)) - mp_out(number_to_double(xi)); if (res < -180.0) { res += 360.0; } else if (res > 180.0) { res -= 360.0; } } else if ((b * b) == (4.0 * a * c)) { res = (double) bezier_error; } else if ((b * b) < (4.0 * a * c)) { res = mp_out(number_to_double(xo)) - mp_out(number_to_double(xi)); if (res <= 0.0 && res > -180.0) { res += 360.0; } else if (res >= 0.0 && res < 180.0) { res -= 360.0; } } else { res = mp_out(number_to_double(xo)) - mp_out(number_to_double(xi)); if (res < -180.0) { res += 360.0; } else if (res > 180.0) { res -= 360.0; } } free_number(deltax); free_number(deltay); free_number(xi); free_number(xo); free_number(xm); set_number_from_double(*ret, res); convert_scaled_to_angle(*ret); } static void mp_bad_binary (MP mp, mp_node p, int c) { char msg[256]; mp_string sname; int selector = mp->selector; mp->selector = mp_new_string_selector; if (c >= mp_min_of_operation) { mp_print_op(mp, c); } mp_print_known_or_unknown_type(mp, p->type, p); if (c >= mp_min_of_operation) { mp_print_str(mp, "of"); } else { mp_print_op(mp, c); } mp_print_known_or_unknown_type(mp, mp->cur_exp.type, cur_exp_node); sname = mp_make_string(mp); mp->selector = selector; mp_snprintf(msg, 256, "Not implemented: %s", mp_str(mp, sname)); delete_str_ref(sname); mp_disp_err(mp, p); mp_disp_err(mp, NULL); mp_back_error( mp, msg, "I'm afraid I don't know how to apply that operation to that combination of types.\n" "Continue, and I'll return the second argument (see above) as the result of the" "operation." ); mp_get_x_next(mp); } static void mp_bad_envelope_pen (MP mp) { mp_disp_err(mp, NULL); mp_disp_err(mp, NULL); mp_back_error( mp, "Not implemented: 'envelope(elliptical pen) of (path)'", "I'm afraid I don't know how to apply that operation to that combination of types.\n" "Continue, and I'll return the second argument (see above) as the result of the\n" "operation." ); mp_get_x_next(mp); } static mp_node mp_tarnished (MP mp, mp_node p) { mp_node q = mp_get_value_node(p); (void) mp; switch (p->type) { case mp_pair_type: return ( (mp_x_part(q)->type == mp_independent_type) || (mp_y_part(q)->type == mp_independent_type) ) ? MP_VOID : NULL; case mp_color_type: return ( (mp_red_part (q)->type == mp_independent_type) || (mp_green_part(q)->type == mp_independent_type) || (mp_blue_part (q)->type == mp_independent_type) ) ? MP_VOID : NULL; case mp_cmykcolor_type: return ( (mp_cyan_part (q)->type == mp_independent_type) || (mp_magenta_part(q)->type == mp_independent_type) || (mp_yellow_part (q)->type == mp_independent_type) || (mp_black_part (q)->type == mp_independent_type) ) ? MP_VOID : NULL; case mp_transform_type: return ( (mp_tx_part(q)->type == mp_independent_type) || (mp_ty_part(q)->type == mp_independent_type) || (mp_xx_part(q)->type == mp_independent_type) || (mp_xy_part(q)->type == mp_independent_type) || (mp_yx_part(q)->type == mp_independent_type) || (mp_yy_part(q)->type == mp_independent_type) ) ? MP_VOID : NULL; default: return NULL; } } static void mp_dep_finish (MP mp, mp_value_node v, mp_value_node q, int t) { mp_value_node p = (q == NULL) ? (mp_value_node) cur_exp_node : q; mp_set_dep_list(p, v); p->type = t; if (mp_get_dep_info(v) == NULL) { mp_number vv; new_number_clone(vv, mp_get_value_number(v)); if (q == NULL) { mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); new_number_clone(new_expr.data.n, vv); mp_flush_cur_exp(mp, new_expr); } else { mp_recycle_value(mp, (mp_node) p); q->type = mp_known_type; mp_set_value_number(q, vv); } free_number(vv); } else if (q == NULL) { mp->cur_exp.type = t; } if (mp->fix_needed) { mp_fix_dependencies(mp); } } static void mp_add_or_subtract (MP mp, mp_node p, mp_node q, int c) { mp_variable_type s, t; mp_value_node r; mp_value_node v = NULL; mp_number vv; new_number(vv); if (q == NULL) { t = mp->cur_exp.type; if (t < mp_dependent_type) { number_clone(vv, cur_exp_value_number); } else { v = (mp_value_node) mp_get_dep_list((mp_value_node) cur_exp_node); } } else { t = q->type; if (t < mp_dependent_type) { number_clone(vv, mp_get_value_number(q)); } else { v = (mp_value_node) mp_get_dep_list((mp_value_node) q); } } if (t == mp_known_type) { mp_value_node qq = (mp_value_node) q; if (c == mp_minus_operation) { number_negate(vv); } if (p->type == mp_known_type) { slow_add(vv, mp_get_value_number(p), vv); if (q == NULL) { mp_set_cur_exp_value_number(mp, &vv); } else { mp_set_value_number(q, vv); } free_number(vv); return; } else { r = (mp_value_node) mp_get_dep_list((mp_value_node) p); while (mp_get_dep_info(r) != NULL) { r = (mp_value_node) r->link; } slow_add(vv, mp_get_dep_value(r), vv); mp_set_dep_value(r, vv); if (qq == NULL) { qq = mp_get_dep_node(mp); mp_set_cur_exp_node(mp, (mp_node) qq); mp->cur_exp.type = p->type; qq->name_type = mp_capsule_operation; } mp_set_dep_list(qq, mp_get_dep_list((mp_value_node) p)); qq->type = p->type; mp_set_prev_dep(qq, mp_get_prev_dep((mp_value_node) p)); mp_get_prev_dep((mp_value_node) p)->link = (mp_node) qq; p->type = mp_known_type; } } else { if (c == mp_minus_operation) { mp_negate_dep_list(mp, v); } if (p->type == mp_known_type) { while (mp_get_dep_info(v) != NULL) { v = (mp_value_node) v->link; } slow_add(vv, mp_get_value_number(p), mp_get_dep_value(v)); mp_set_dep_value(v, vv); } else { s = p->type; r = (mp_value_node) mp_get_dep_list((mp_value_node) p); if (t == mp_dependent_type) { if (s == mp_dependent_type) { int b; mp_number ret1, ret2; new_fraction(ret1); new_fraction(ret2); mp_max_coef(mp, &ret1, r); mp_max_coef(mp, &ret2, v); number_add(ret1, ret2); b = number_less(ret1, coef_bound_k); free_number(ret1); free_number(ret2); if (b) { v = mp_p_plus_q(mp, v, r, mp_dependent_type); goto DONE; } } t = mp_proto_dependent_type; v = mp_p_over_v(mp, v, &unity_t, mp_dependent_type, mp_proto_dependent_type); } if (s == mp_proto_dependent_type) { v = mp_p_plus_q(mp, v, r, mp_proto_dependent_type); } else { v = mp_p_plus_fq(mp, v, &unity_t, r, mp_proto_dependent_type, mp_dependent_type); } DONE: if (q != NULL) { mp_dep_finish(mp, v, (mp_value_node) q, t); } else { mp->cur_exp.type = t; mp_dep_finish(mp, v, NULL, t); } } } free_number(vv); } static void mp_dep_mult (MP mp, mp_value_node p, mp_number *v, int v_is_scaled) { mp_value_node q; int s, t; if (p == NULL) { q = (mp_value_node) cur_exp_node; } else if (p->type != mp_known_type) { q = p; } else { mp_number r1, arg1; new_number_clone(arg1, mp_get_dep_value(p)); if (v_is_scaled) { new_number(r1); take_scaled(r1, arg1, *v); } else { new_fraction(r1); take_fraction(r1, arg1, *v); } mp_set_dep_value(p, r1); free_number(r1); free_number(arg1); return; } t = q->type; q = (mp_value_node) mp_get_dep_list(q); s = t; if (t == mp_dependent_type && v_is_scaled) { mp_number arg1, arg2; new_fraction(arg1); mp_max_coef(mp, &arg1, q); new_number_abs(arg2, *v); if (ab_vs_cd(arg1, arg2, coef_bound_minus_1, unity_t) >= 0) { t = mp_proto_dependent_type; } free_number(arg1); free_number(arg2); } q = mp_p_times_v(mp, q, v, s, t, v_is_scaled); mp_dep_finish(mp, q, p, t); } static void mp_hard_times (MP mp, mp_node p) { mp_value_node q; mp_value_node pp; mp_number v; new_number(v); if (p->type <= mp_pair_type) { q = (mp_value_node) mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, p); p = (mp_node) q; } pp = (mp_value_node) p; switch (mp->cur_exp.type) { case mp_pair_type: { mp_node r = mp_x_part(mp_get_value_node(cur_exp_node)); number_clone(v, mp_get_value_number(r)); mp_new_dep(mp, r, pp->type, mp_copy_dep_list(mp, (mp_value_node) mp_get_dep_list(pp))); mp_dep_mult(mp, (mp_value_node) r, &v, 1); r = mp_y_part(mp_get_value_node(cur_exp_node)); number_clone(v, mp_get_value_number(r)); mp_new_dep(mp, r, pp->type, mp_copy_dep_list(mp, (mp_value_node) mp_get_dep_list(pp))); mp_dep_mult(mp, (mp_value_node) r, &v, 1); } break; case mp_color_type: { mp_node r = mp_red_part(mp_get_value_node(cur_exp_node)); number_clone(v, mp_get_value_number(r)); mp_new_dep(mp, r, pp->type, mp_copy_dep_list(mp, (mp_value_node) mp_get_dep_list(pp))); mp_dep_mult(mp, (mp_value_node) r, &v, 1); r = mp_green_part(mp_get_value_node(cur_exp_node)); number_clone(v, mp_get_value_number(r)); mp_new_dep(mp, r, pp->type, mp_copy_dep_list(mp, (mp_value_node) mp_get_dep_list(pp))); mp_dep_mult(mp, (mp_value_node) r, &v, 1); r = mp_blue_part(mp_get_value_node(cur_exp_node)); number_clone(v, mp_get_value_number(r)); mp_new_dep(mp, r, pp->type, mp_copy_dep_list(mp, (mp_value_node) mp_get_dep_list(pp))); mp_dep_mult(mp, (mp_value_node) r, &v, 1); } break; case mp_cmykcolor_type: { mp_node r = mp_cyan_part(mp_get_value_node(cur_exp_node)); number_clone(v, mp_get_value_number(r)); mp_new_dep(mp, r, pp->type, mp_copy_dep_list(mp, (mp_value_node) mp_get_dep_list(pp))); mp_dep_mult(mp, (mp_value_node) r, &v, 1); r = mp_yellow_part(mp_get_value_node(cur_exp_node)); number_clone(v, mp_get_value_number(r)); mp_new_dep(mp, r, pp->type, mp_copy_dep_list(mp, (mp_value_node) mp_get_dep_list(pp))); mp_dep_mult(mp, (mp_value_node) r, &v, 1); r = mp_magenta_part(mp_get_value_node(cur_exp_node)); number_clone(v, mp_get_value_number(r)); mp_new_dep(mp, r, pp->type, mp_copy_dep_list(mp, (mp_value_node) mp_get_dep_list(pp))); mp_dep_mult(mp, (mp_value_node) r, &v, 1); r = mp_black_part(mp_get_value_node(cur_exp_node)); number_clone(v, mp_get_value_number(r)); mp_new_dep(mp, r, pp->type, mp_copy_dep_list(mp, (mp_value_node) mp_get_dep_list(pp))); mp_dep_mult(mp, (mp_value_node) r, &v, 1); } break; default: break; } free_number(v); } static void mp_dep_div (MP mp, mp_value_node p, mp_number *v) { mp_value_node q; int s, t; if (p == NULL) { q = (mp_value_node) cur_exp_node; } else if (p->type != mp_known_type) { q = p; } else { mp_number ret; new_number(ret); make_scaled(ret, mp_get_value_number(p), *v); mp_set_value_number(p, ret); free_number(ret); return; } t = q->type; q = (mp_value_node) mp_get_dep_list(q); s = t; if (t == mp_dependent_type) { mp_number arg1, arg2; new_number(arg2); new_fraction(arg1); mp_max_coef(mp, &arg1, q); number_abs_clone(arg2, *v); if (ab_vs_cd(arg1, unity_t, coef_bound_minus_1, arg2) >= 0) { t = mp_proto_dependent_type; } free_number(arg1); free_number(arg2); } q = mp_p_over_v(mp, q, v, s, t); mp_dep_finish(mp, q, p, t); } static void mp_set_up_trans (MP mp, int c) { mp_node p, q, r; mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); if ((c != mp_transformed_operation) || (mp->cur_exp.type != mp_transform_type)) { p = mp_stash_cur_exp(mp); mp_set_cur_exp_node(mp, mp_id_transform(mp)); mp->cur_exp.type = mp_transform_type; q = mp_get_value_node(cur_exp_node); switch (c) { case mp_rotated_operation: if (p->type == mp_known_type) { mp_number n_sin, n_cos, arg1, arg2; new_fraction(n_sin); new_fraction(n_cos); new_number_clone(arg2, unity_t); new_number_clone(arg1, mp_get_value_number(p)); number_multiply_int(arg2, 360); number_modulo(arg1, arg2); convert_scaled_to_angle(arg1); n_sin_cos(arg1, n_cos, n_sin); fraction_to_round_scaled(n_sin); fraction_to_round_scaled(n_cos); mp_set_value_number(mp_xx_part(q), n_cos); mp_set_value_number(mp_yx_part(q), n_sin); mp_set_value_number(mp_xy_part(q), mp_get_value_number(mp_yx_part(q))); number_negate(mp_get_value_number(mp_xy_part(q))); mp_set_value_number(mp_yy_part(q), mp_get_value_number(mp_xx_part(q))); free_number(arg1); free_number(arg2); free_number(n_sin); free_number(n_cos); goto DONE; } break; case mp_slanted_operation: if (p->type > mp_pair_type) { mp_install(mp, mp_xy_part(q), p); goto DONE; } break; case mp_scaled_operation: if (p->type > mp_pair_type) { mp_install(mp, mp_xx_part(q), p); mp_install(mp, mp_yy_part(q), p); goto DONE; } break; case mp_shifted_operation: if (p->type == mp_pair_type) { r = mp_get_value_node(p); mp_install(mp, mp_tx_part(q), mp_x_part(r)); mp_install(mp, mp_ty_part(q), mp_y_part(r)); goto DONE; } break; case mp_x_scaled_operation: if (p->type > mp_pair_type) { mp_install(mp, mp_xx_part(q), p); goto DONE; } break; case mp_y_scaled_operation: if (p->type > mp_pair_type) { mp_install(mp, mp_yy_part(q), p); goto DONE; } break; case mp_z_scaled_operation: if (p->type == mp_pair_type) { { r = mp_get_value_node(p); mp_install(mp, mp_xx_part(q), mp_x_part(r)); mp_install(mp, mp_yy_part(q), mp_x_part(r)); mp_install(mp, mp_yx_part(q), mp_y_part(r)); if (mp_y_part(r)->type == mp_known_type) { mp_set_value_number(mp_y_part(r), mp_get_value_number(mp_y_part(r))); number_negate(mp_get_value_number(mp_y_part(r))); } else { mp_negate_dep_list(mp, (mp_value_node) mp_get_dep_list((mp_value_node) mp_y_part(r))); } mp_install(mp, mp_xy_part(q), mp_y_part(r)); goto DONE; } } break; case mp_transformed_operation: break; } mp_disp_err(mp, p); mp_back_error( mp, "Improper transformation argument", "The expression shown above has the wrong type, so I can't transform anything\n" "using it. Proceed, and I'll omit the transformation." ); mp_get_x_next(mp); DONE: mp_recycle_value(mp, p); mp_free_value_node(mp, p); } q = mp_get_value_node(cur_exp_node); if ( (mp_tx_part(q)->type == mp_known_type) && (mp_ty_part(q)->type == mp_known_type) && (mp_xx_part(q)->type == mp_known_type) && (mp_xy_part(q)->type == mp_known_type) && (mp_yx_part(q)->type == mp_known_type) && (mp_yy_part(q)->type == mp_known_type) ) { number_clone(mp->txx, mp_get_value_number(mp_xx_part(q))); number_clone(mp->txy, mp_get_value_number(mp_xy_part(q))); number_clone(mp->tyx, mp_get_value_number(mp_yx_part(q))); number_clone(mp->tyy, mp_get_value_number(mp_yy_part(q))); number_clone(mp->tx, mp_get_value_number(mp_tx_part(q))); number_clone(mp->ty, mp_get_value_number(mp_ty_part(q))); new_number(new_expr.data.n); mp_flush_cur_exp(mp, new_expr); } } static void mp_set_up_known_trans (MP mp, int c) { mp_set_up_trans(mp, c); if (mp->cur_exp.type != mp_known_type) { mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); mp_disp_err(mp, NULL); mp_back_error( mp, "Transform components aren't all known", "I'm unable to apply a partially specified transformation except to a fully known\n" "pair or transform. Proceed, and I'll omit the transformation." ); mp_get_x_next(mp); mp_flush_cur_exp(mp, new_expr); set_number_to_unity(mp->txx); set_number_to_zero(mp->txy); set_number_to_zero(mp->tyx); set_number_to_unity(mp->tyy); set_number_to_zero(mp->tx); set_number_to_zero(mp->ty); } } static void mp_number_trans (MP mp, mp_number *p, mp_number *q) { mp_number r1, r2, v; new_number(r1); new_number(r2); new_number(v); take_scaled(r1, *p, mp->txx); take_scaled(r2, *q, mp->txy); number_add(r1, r2); set_number_from_addition(v, r1, mp->tx); take_scaled(r1, *p, mp->tyx); take_scaled(r2, *q, mp->tyy); number_add(r1, r2); set_number_from_addition(*q, r1, mp->ty); number_clone(*p,v); free_number(r1); free_number(r2); free_number(v); } static void mp_do_path_trans (MP mp, mp_knot p) { mp_knot q = p; do { if (mp_left_type(q) != mp_endpoint_knot) { mp_number_trans(mp, &q->left_x, &q->left_y); } mp_number_trans(mp, &q->x_coord, &q->y_coord); if (mp_right_type(q) != mp_endpoint_knot) { mp_number_trans(mp, &q->right_x, &q->right_y); } q = mp_next_knot(q); } while (q != p); } static void mp_do_pen_trans (MP mp, mp_knot p) { mp_knot q = p; if (mp_pen_is_elliptical(p)) { mp_number_trans(mp, &p->left_x, &p->left_y); mp_number_trans(mp, &p->right_x, &p->right_y); } do { mp_number_trans(mp, &q->x_coord, &q->y_coord); q = mp_next_knot(q); } while (q != p); } static void mp_do_path_pen_trans (MP mp, mp_shape_node p, mp_number *sqdet, int sgndet) { mp_number sx, sy; if (mp_pen_ptr(p) != NULL) { new_number_clone(sx, mp->tx); new_number_clone(sy, mp->ty); set_number_to_zero(mp->tx); set_number_to_zero(mp->ty); mp_do_pen_trans(mp, mp_pen_ptr(p)); if (number_nonzero(*sqdet) && ((p->type == mp_stroked_node_type) && (mp_dash_ptr(p) != NULL))) { mp_number ret; new_number(ret); take_scaled(ret, ((mp_shape_node) p)->dashscale, *sqdet); number_clone(((mp_shape_node) p)->dashscale, ret); free_number(ret); } if (! mp_pen_is_elliptical(mp_pen_ptr(p)) && sgndet < 0) { mp_pen_ptr(p) = mp_make_pen(mp, mp_copy_path(mp, mp_pen_ptr(p)), 1); } number_clone(mp->tx, sx); number_clone(mp->ty, sy); free_number(sx); free_number(sy); } } static mp_edge_header_node mp_edges_trans (MP mp, mp_edge_header_node h) { mp_node q; mp_dash_node r, s; mp_number sqdet; int sgndet; h = mp_private_edges(mp, h); new_number(sqdet); mp_sqrt_det(mp, &sqdet, &(mp->txx), &(mp->txy), &(mp->tyx), &(mp->tyy)); sgndet = ab_vs_cd(mp->txx, mp->tyy, mp->txy, mp->tyx); if (mp_get_dash_list(h) != mp->null_dash) { if (number_nonzero(mp->txy) || number_nonzero(mp->tyx) || number_nonzero(mp->ty) || number_nonequalabs(mp->txx, mp->tyy)) { mp_flush_dash_list(mp, h); } else { mp_number abs_tyy, ret; new_number(abs_tyy); if (number_negative(mp->txx)) { { r = mp_get_dash_list(h); mp_set_dash_list(h, mp->null_dash); while (r != mp->null_dash) { s = r; r = (mp_dash_node) r->link; number_swap(s->start_x, s->stop_x ); s->link = (mp_node) mp_get_dash_list(h); mp_set_dash_list(h, s); } } } r = mp_get_dash_list(h); { mp_number arg1; new_number(arg1); while (r != mp->null_dash) { take_scaled(arg1, r->start_x, mp->txx); set_number_from_addition(r->start_x, arg1, mp->tx); take_scaled(arg1, r->stop_x, mp->txx); set_number_from_addition(r->stop_x, arg1, mp->tx); r = (mp_dash_node) r->link; } free_number(arg1); } number_abs_clone(abs_tyy, mp->tyy); new_number(ret); take_scaled(ret, h->dash_y, abs_tyy); number_clone(h->dash_y, ret); free_number(ret); free_number(abs_tyy); } } if (number_zero(mp->txx) && number_zero(mp->tyy)) { number_swap(h->minx, h->miny); number_swap(h->maxx, h->maxy); } else if (number_nonzero(mp->txy) || number_nonzero(mp->tyx)) { mp_init_bbox(mp, h); goto DONE1; } if (number_lessequal(h->minx, h->maxx)) { mp_number tot, ret; new_number(tot); new_number(ret); set_number_from_addition(tot,mp->txx,mp->txy); take_scaled(ret, h->minx, tot); set_number_from_addition(h->minx,ret, mp->tx); take_scaled(ret, h->maxx, tot); set_number_from_addition(h->maxx,ret, mp->tx); set_number_from_addition(tot,mp->tyx,mp->tyy); take_scaled(ret, h->miny, tot); set_number_from_addition(h->miny, ret, mp->ty); take_scaled(ret, h->maxy, tot); set_number_from_addition(h->maxy, ret, mp->ty); set_number_from_addition(tot, mp->txx, mp->txy); if (number_negative(tot)) { number_swap(h->minx, h->maxx); } set_number_from_addition(tot, mp->tyx, mp->tyy); if (number_negative(tot)) { number_swap(h->miny, h->maxy); } free_number(ret); free_number(tot); } DONE1: q = mp_edge_list(h)->link; while (q != NULL) { switch (q->type) { case mp_fill_node_type: case mp_stroked_node_type: mp_do_path_trans(mp, mp_path_ptr((mp_shape_node) q)); mp_do_path_pen_trans(mp, (mp_shape_node) q, &sqdet, sgndet); break; case mp_start_clip_node_type: case mp_start_group_node_type: case mp_start_bounds_node_type: mp_do_path_trans(mp, mp_path_ptr((mp_start_node) q)); break; case mp_stop_clip_node_type: case mp_stop_group_node_type: case mp_stop_bounds_node_type: break; default: break; } q = q->link; } free_number(sqdet); return h; } static void mp_do_edges_trans (MP mp, mp_node p, int c) { mp_set_up_known_trans (mp, c); mp_set_value_node(p, (mp_node) mp_edges_trans(mp, (mp_edge_header_node) mp_get_value_node(p))); mp_unstash_cur_exp(mp, p); } static mp_edge_header_node mp_scale_edges (MP mp, mp_number *se_sf, mp_edge_header_node se_pic) { number_clone(mp->txx, *se_sf); number_clone(mp->tyy, *se_sf); set_number_to_zero(mp->txy); set_number_to_zero(mp->tyx); set_number_to_zero(mp->tx); set_number_to_zero(mp->ty); return mp_edges_trans(mp, se_pic); } static void mp_bilin1 (MP mp, mp_node p, mp_number *t, mp_node q, mp_number *u, mp_number *delta_orig) { mp_number delta; new_number_clone(delta, *delta_orig); if (! number_equal(*t, unity_t)) { mp_dep_mult(mp, (mp_value_node) p, t, 1); } if (number_nonzero(*u)) { if (q->type == mp_known_type) { mp_number tmp; new_number(tmp); take_scaled(tmp, mp_get_value_number(q), *u); number_add(delta, tmp); free_number(tmp); } else { if (p->type != mp_proto_dependent_type) { if (p->type == mp_known_type) { mp_new_dep(mp, p, p->type, mp_const_dependency(mp, &(mp_get_value_number(p)))); } else { mp_set_dep_list((mp_value_node) p, mp_p_times_v(mp, (mp_value_node) mp_get_dep_list((mp_value_node) p), &unity_t, mp_dependent_type, mp_proto_dependent_type, 1)); } p->type = mp_proto_dependent_type; } mp_set_dep_list((mp_value_node) p, mp_p_plus_fq(mp, (mp_value_node) mp_get_dep_list((mp_value_node) p), u, (mp_value_node) mp_get_dep_list((mp_value_node) q), mp_proto_dependent_type, q->type)); } } if (p->type == mp_known_type) { mp_set_value_number(p, mp_get_value_number(p)); number_add(mp_get_value_number(p), delta); } else { mp_number tmp; mp_value_node r = (mp_value_node) mp_get_dep_list((mp_value_node) p); while (mp_get_dep_info(r) != NULL) { r = (mp_value_node) r->link; } new_number_clone(tmp, mp_get_value_number(r)); number_add(delta, tmp); if (r != (mp_value_node) mp_get_dep_list((mp_value_node) p)) { mp_set_value_number(r, delta); } else { mp_recycle_value(mp, p); p->type = mp_known_type; mp_set_value_number(p, delta); } free_number(tmp); } if (mp->fix_needed) { mp_fix_dependencies(mp); } free_number(delta); } static void mp_add_mult_dep (MP mp, mp_value_node p, mp_number *v, mp_node r) { if (r->type == mp_known_type) { mp_number ret; new_number(ret); take_scaled(ret, mp_get_value_number(r), *v); mp_set_dep_value(mp->dep_final, mp_get_dep_value(mp->dep_final)); number_add(mp_get_dep_value(mp->dep_final), ret); free_number(ret); } else { mp_set_dep_list(p, mp_p_plus_fq(mp, (mp_value_node) mp_get_dep_list(p), v, (mp_value_node) mp_get_dep_list((mp_value_node) r), mp_proto_dependent_type, r->type)); if (mp->fix_needed) { mp_fix_dependencies(mp); } } } static void mp_bilin2 (MP mp, mp_node p, mp_node t, mp_number *v, mp_node u, mp_node q) { mp_number vv; new_number_clone(vv, mp_get_value_number(p)); mp_new_dep(mp, p, mp_proto_dependent_type, mp_const_dependency(mp, &zero_t)); if (number_nonzero(vv)) { mp_add_mult_dep(mp, (mp_value_node) p, &vv, t); } if (number_nonzero(*v)) { mp_number arg1; new_number_clone(arg1, *v); mp_add_mult_dep(mp, (mp_value_node) p, &arg1, u); free_number(arg1); } if (q != NULL) { mp_add_mult_dep(mp, (mp_value_node) p, &unity_t, q); } if (mp_get_dep_list((mp_value_node) p) == (mp_node) mp->dep_final) { number_clone(vv, mp_get_dep_value(mp->dep_final)); mp_recycle_value(mp, p); p->type = mp_known_type; mp_set_value_number(p, vv); } free_number(vv); } static void mp_bilin3 (MP mp, mp_node p, mp_number *t, mp_number *v, mp_number *u, mp_number *delta_orig) { mp_number delta; mp_number tmp; new_number(tmp); new_number_clone(delta, *delta_orig); if (! number_equal(*t, unity_t)) { take_scaled(tmp, mp_get_value_number(p), *t); } else { number_clone(tmp, mp_get_value_number(p)); } number_add(delta, tmp); if (number_nonzero(*u)) { mp_number ret; new_number(ret); take_scaled(ret, *v, *u); mp_set_value_number(p, delta); number_add(mp_get_value_number(p), ret); free_number(ret); } else { mp_set_value_number(p, delta); } free_number(tmp); free_number(delta); } static void mp_big_trans (MP mp, mp_node p, int c) { mp_node q = mp_get_value_node(p); if (q->type == mp_pair_node_type) { if (mp_x_part(q)->type != mp_known_type || mp_y_part(q)->type != mp_known_type) { goto UNKNOWN; } } else if (mp_tx_part(q)->type != mp_known_type || mp_ty_part(q)->type != mp_known_type || mp_xx_part(q)->type != mp_known_type || mp_xy_part(q)->type != mp_known_type || mp_yx_part(q)->type != mp_known_type || mp_yy_part(q)->type != mp_known_type) { goto UNKNOWN; } { mp_node r, pp, qq; mp_set_up_trans(mp, c); if (mp->cur_exp.type == mp_known_type) { mp_make_exp_copy(mp, p); r = mp_get_value_node(cur_exp_node); if (mp->cur_exp.type == mp_transform_type) { mp_bilin3(mp, mp_yy_part(r), &(mp->tyy), &(mp_get_value_number(mp_xy_part(q))), &(mp->tyx), &zero_t); mp_bilin3(mp, mp_yx_part(r), &(mp->tyy), &(mp_get_value_number(mp_xx_part(q))), &(mp->tyx), &zero_t); mp_bilin3(mp, mp_xy_part(r), &(mp->txx), &(mp_get_value_number(mp_yy_part(q))), &(mp->txy), &zero_t); mp_bilin3(mp, mp_xx_part(r), &(mp->txx), &(mp_get_value_number(mp_yx_part(q))), &(mp->txy), &zero_t); } mp_bilin3(mp, mp_y_part(r), &(mp->tyy), &(mp_get_value_number(mp_x_part(q))), &(mp->tyx), &(mp->ty)); mp_bilin3(mp, mp_x_part(r), &(mp->txx), &(mp_get_value_number(mp_y_part(q))), &(mp->txy), &(mp->tx)); } else { pp = mp_stash_cur_exp(mp); qq = mp_get_value_node(pp); mp_make_exp_copy(mp, p); r = mp_get_value_node(cur_exp_node); if (mp->cur_exp.type == mp_transform_type) { mp_bilin2(mp, mp_yy_part(r), mp_yy_part(qq), &(mp_get_value_number(mp_xy_part(q))), mp_yx_part(qq), NULL); mp_bilin2(mp, mp_yx_part(r), mp_yy_part(qq), &(mp_get_value_number(mp_xx_part(q))), mp_yx_part(qq), NULL); mp_bilin2(mp, mp_xy_part(r), mp_xx_part(qq), &(mp_get_value_number(mp_yy_part(q))), mp_xy_part(qq), NULL); mp_bilin2(mp, mp_xx_part(r), mp_xx_part(qq), &(mp_get_value_number(mp_yx_part(q))), mp_xy_part(qq), NULL); } mp_bilin2(mp, mp_y_part(r), mp_yy_part(qq), &(mp_get_value_number(mp_x_part(q))), mp_yx_part(qq), mp_y_part(qq)); mp_bilin2(mp, mp_x_part(r), mp_xx_part(qq), &(mp_get_value_number(mp_y_part(q))), mp_xy_part(qq), mp_x_part(qq)); mp_recycle_value(mp, pp); mp_free_value_node(mp, pp); } return; } UNKNOWN: { mp_node r; mp_set_up_known_trans(mp, c); mp_make_exp_copy(mp, p); r = mp_get_value_node(cur_exp_node); if (mp->cur_exp.type == mp_transform_type) { mp_bilin1(mp, mp_yy_part(r), &(mp->tyy), mp_xy_part(q), &(mp->tyx), &zero_t); mp_bilin1(mp, mp_yx_part(r), &(mp->tyy), mp_xx_part(q), &(mp->tyx), &zero_t); mp_bilin1(mp, mp_xy_part(r), &(mp->txx), mp_yy_part(q), &(mp->txy), &zero_t); mp_bilin1(mp, mp_xx_part(r), &(mp->txx), mp_yx_part(q), &(mp->txy), &zero_t); } mp_bilin1(mp, mp_y_part(r), &(mp->tyy), mp_x_part(q), &(mp->tyx), &(mp->ty)); mp_bilin1(mp, mp_x_part(r), &(mp->txx), mp_y_part(q), &(mp->txy), &(mp->tx)); return; } } static void mp_chop_path (MP mp, mp_node p) { mp_knot q; mp_knot pp, qq; mp_number a, b; mp_number l; int reversed; new_number(l); mp_path_length(mp, &l); new_number_clone(a, mp_get_value_number(mp_x_part(p))); new_number_clone(b, mp_get_value_number(mp_y_part(p))); if (number_lessequal(a, b)) { reversed = 0; } else { reversed = 1; number_swap (a, b); } if (number_negative(a)) { if (mp_left_type(cur_exp_knot) == mp_endpoint_knot) { set_number_to_zero(a); if (number_negative(b)) { set_number_to_zero(b); } } else { do { number_add(a, l); number_add(b, l); } while (number_negative(a)); } } if (number_greater(b, l)) { if (mp_left_type(cur_exp_knot) == mp_endpoint_knot) { number_clone(b, l); if (number_greater(a, l)) { number_clone(a, l); } } else { while (number_greaterequal(a, l)) { number_subtract(a, l); number_subtract(b, l); } } } q = cur_exp_knot; while (number_greaterequal(a, unity_t)) { q = mp_next_knot(q); number_subtract(a, unity_t); number_subtract(b, unity_t); } if (number_equal(b, a)) { if (number_positive(a)) { mp_number arg1; new_number_clone(arg1, a); convert_scaled_to_fraction(arg1); mp_split_cubic(mp, q, &arg1); free_number(arg1); q = mp_next_knot(q); } pp = mp_copy_knot(mp, q); qq = pp; } else { mp_knot rr; pp = mp_copy_knot(mp, q); qq = pp; do { q = mp_next_knot(q); rr = qq; qq = mp_copy_knot(mp, q); mp_prev_knot(qq) = rr; mp_next_knot(rr) = qq; number_subtract(b, unity_t); } while (number_positive(b)); if (number_positive(a)) { mp_knot ss = pp; mp_number arg1; new_number_clone(arg1, a); convert_scaled_to_fraction(arg1); mp_split_cubic(mp, ss, &arg1); free_number(arg1); pp = mp_next_knot(ss); mp_toss_knot(mp, ss); if (rr == ss) { mp_number arg1, arg2; new_number(arg1); set_number_from_subtraction(arg1, unity_t, a); new_number_clone(arg2, b); make_scaled(b, arg2, arg1); free_number(arg1); free_number(arg2); rr = pp; } } if (number_negative(b)) { mp_number arg1; new_number(arg1); set_number_from_addition(arg1, b, unity_t); convert_scaled_to_fraction(arg1); mp_split_cubic(mp, rr, &arg1); free_number(arg1); mp_toss_knot(mp, qq); qq = mp_next_knot(rr); } } mp_left_type(pp) = mp_endpoint_knot; mp_right_type(qq) = mp_endpoint_knot; mp_prev_knot(pp) = qq; mp_next_knot(qq) = pp; mp_toss_knot_list(mp, cur_exp_knot); if (reversed) { mp_set_cur_exp_knot(mp, mp_next_knot(mp_htap_ypoc(mp, pp))); mp_toss_knot_list(mp, pp); } else { mp_set_cur_exp_knot(mp, pp); } free_number(l); free_number(a); free_number(b); } static void mp_set_up_offset (MP mp, mp_node p) { mp_find_offset(mp, &(mp_get_value_number(mp_x_part(p))), &(mp_get_value_number(mp_y_part(p))), cur_exp_knot); mp_pair_value(mp, &(mp->cur_x), &(mp->cur_y)); } static void mp_set_up_direction_time (MP mp, mp_node p) { mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); mp_find_direction_time(mp, &new_expr.data.n, &(mp_get_value_number(mp_x_part(p))), &(mp_get_value_number(mp_y_part(p))), cur_exp_knot); mp_flush_cur_exp(mp, new_expr); } static void mp_set_up_envelope (MP mp, mp_node p) { mp_knot q = mp_copy_path(mp, cur_exp_knot); if (mp_pen_is_elliptical(mp_get_value_knot(p))) { mp_bad_envelope_pen(mp); mp_set_cur_exp_knot(mp, q); mp->cur_exp.type = mp_path_type; } else { int linejoin = mp_mitered_linejoin_code; int linecap = mp_butt_linecap_code; mp_number miterlimit; new_number(miterlimit); if (number_greater(internal_value(mp_linejoin_internal), unity_t)) { linejoin = mp_beveled_linejoin_code; } else if (number_positive(internal_value(mp_linejoin_internal))) { linejoin = mp_rounded_linejoin_code; } if (number_greater(internal_value(mp_linecap_internal), unity_t)) { linecap = mp_squared_linecap_code; } else if (number_positive(internal_value(mp_linecap_internal))) { linecap = mp_rounded_linecap_code; } if (number_less(internal_value(mp_miterlimit_internal), unity_t)) { set_number_to_unity(miterlimit); } else { number_clone(miterlimit, internal_value(mp_miterlimit_internal)); } mp_set_cur_exp_knot(mp, mp_make_envelope(mp, q, mp_get_value_knot(p), linejoin, linecap, &miterlimit)); mp->cur_exp.type = mp_path_type; } } static void mp_set_up_boundingpath (MP mp, mp_node p) { mp_number miterlimit; mp_knot q = mp_copy_path(mp, cur_exp_knot); mp_knot qq; int linejoin = mp_mitered_linejoin_code; int linecap = mp_butt_linecap_code; mp_knot pen = mp_get_value_knot(p); new_number(miterlimit); if (mp_pen_is_elliptical(mp_get_value_knot(p))) { mp_knot kp, kq; pen = mp_copy_pen(mp, mp_get_value_knot(p)); mp_make_path(mp, pen); kq = pen; do { kp = kq; kq = mp_next_knot(kq); mp_prev_knot(kq) = kp; } while (kq != pen); mp_close_path_cycle(mp, kp, pen); } if (number_greater(internal_value(mp_linejoin_internal), unity_t)) { linejoin = mp_beveled_linejoin_code; } else if (number_positive(internal_value(mp_linejoin_internal))) { linejoin = mp_rounded_linejoin_code; } if (number_greater(internal_value(mp_linecap_internal), unity_t)) { linecap = mp_squared_linecap_code; } else if (number_positive(internal_value(mp_linecap_internal))) { linecap = mp_rounded_linecap_code; } if (number_less(internal_value(mp_miterlimit_internal), unity_t)) { set_number_to_unity(miterlimit); } else { number_clone(miterlimit, internal_value(mp_miterlimit_internal)); } qq = mp_make_envelope(mp, q, pen, linejoin, linecap, &miterlimit); mp_set_cur_exp_knot(mp, qq); mp->cur_exp.type = mp_path_type; if (! mp_get_cur_bbox(mp)) { mp_bad_binary(mp, p, mp_boundingpath_operation); mp_set_cur_exp_knot(mp, q); mp->cur_exp.type = mp_path_type; return; } else { mp_knot ll = mp_new_knot(mp); mp_knot lr = mp_new_knot(mp); mp_knot ur = mp_new_knot(mp); mp_knot ul = mp_new_knot(mp); if (ll == NULL || lr == NULL || ur == NULL || ul == NULL){ mp_bad_binary(mp, p, mp_boundingpath_operation); mp_set_cur_exp_knot(mp, q); mp->cur_exp.type = mp_path_type; return; } else { mp_left_type(ll) = mp_endpoint_knot; mp_right_type(ll) = mp_endpoint_knot; mp_originator(ll) = mp_program_code; mp_knotstate(ll) = mp_regular_knot; number_clone(ll->x_coord, mp_minx); number_clone(ll->y_coord, mp_miny); mp_originator(lr) = mp_program_code; mp_knotstate(lr) = mp_regular_knot; number_clone(lr->x_coord, mp_maxx); number_clone(lr->y_coord, mp_miny); mp_originator(ur) = mp_program_code; mp_knotstate(ur) = mp_regular_knot; number_clone(ur->x_coord, mp_maxx); number_clone(ur->y_coord, mp_maxy); mp_originator(ul) = mp_program_code; mp_knotstate(ul) = mp_regular_knot; number_clone(ul->x_coord, mp_minx); number_clone(ul->y_coord, mp_maxy); mp_prev_knot(lr) = ll; mp_next_knot(ll) = lr; mp_prev_knot(ur) = lr; mp_next_knot(lr) = ur; mp_prev_knot(ul) = ur; mp_next_knot(ur) = ul; mp_close_path_cycle(mp, ul, ll); mp_make_path(mp,ll); mp->cur_exp.type = mp_path_type; mp_set_cur_exp_knot(mp, ll); mp_free_path(mp,qq); } } } static void mp_find_point (MP mp, mp_number *v_orig, int c) { mp_knot p; mp_number n; mp_number v; new_number(n); new_number_clone(v, *v_orig); p = cur_exp_knot; if (mp_left_type(p) == mp_endpoint_knot) { set_number_to_unity(n); number_negate(n); } do { p = mp_next_knot(p); number_add(n, unity_t); } while (p != cur_exp_knot); if (number_zero(n)) { set_number_to_zero(v); } else if (number_negative(v)) { if (mp_left_type(p) == mp_endpoint_knot) { set_number_to_zero(v); } else { number_negate(v); number_add_scaled(v, -1); number_modulo(v, n); number_negate(v); number_add_scaled(v, -1); number_add(v, n); } } else if (number_greater(v, n)) { if (mp_left_type(p) == mp_endpoint_knot) { number_clone(v, n); } else { number_modulo(v, n); } } p = cur_exp_knot; while (number_greaterequal(v, unity_t)) { p = mp_next_knot(p); number_subtract(v, unity_t); } if (number_nonzero(v)) { convert_scaled_to_fraction(v); mp_split_cubic(mp, p, &v); p = mp_next_knot(p); } push_of_path_result(mp, c - mp_point_operation, p); free_number(v); free_number(n); } static void mp_finish_binary (MP mp, mp_node old_p, mp_node old_exp) { check_arith(); if (old_p != NULL) { mp_recycle_value(mp, old_p); mp_free_value_node(mp, old_p); } if (old_exp != NULL) { mp_recycle_value(mp, old_exp); mp_free_value_node(mp, old_exp); } } static void mp_do_binary (MP mp, mp_node p, int c) { mp_node old_p, old_exp; mp_value new_expr; check_arith(); if (number_greater(internal_value(mp_tracing_commands_internal), two_t)) { mp_begin_diagnostic(mp); mp_print_nl(mp, "{("); mp_print_exp(mp, p, 0); mp_print_chr(mp, ')'); mp_print_op(mp, (int) c); mp_print_chr(mp, '('); mp_print_exp(mp, NULL, 0); mp_print_str(mp, ")}"); mp_end_diagnostic(mp, 0); } switch (p->type) { case mp_transform_type: case mp_color_type: case mp_cmykcolor_type: case mp_pair_type: old_p = mp_tarnished(mp, p); break; case mp_independent_type: old_p = MP_VOID; break; default: old_p = NULL; break; } if (old_p != NULL) { mp_node q = mp_stash_cur_exp(mp); old_p = p; mp_make_exp_copy(mp, old_p); p = mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, q); } switch (mp->cur_exp.type) { case mp_transform_type: case mp_color_type: case mp_cmykcolor_type: case mp_pair_type: old_exp = mp_tarnished(mp, cur_exp_node); break; case mp_independent_type: old_exp = MP_VOID; break; default: old_exp = NULL; break; } if (old_exp != NULL) { old_exp = cur_exp_node; mp_make_exp_copy(mp, old_exp); } switch (c) { case mp_plus_operation: case mp_minus_operation: if ((mp->cur_exp.type < mp_color_type) || (p->type < mp_color_type)) { mp_bad_binary(mp, p, c); } else { if ((mp->cur_exp.type > mp_pair_type) && (p->type > mp_pair_type)) { mp_add_or_subtract(mp, p, NULL, c); } else if (mp->cur_exp.type != p->type) { mp_bad_binary(mp, p, c); } else { mp_node q = mp_get_value_node(p); mp_node r = mp_get_value_node(cur_exp_node); switch (mp->cur_exp.type) { case mp_pair_type: mp_add_or_subtract(mp, mp_x_part(q), mp_x_part(r), c); mp_add_or_subtract(mp, mp_y_part(q), mp_y_part(r), c); break; case mp_color_type: mp_add_or_subtract(mp, mp_red_part(q), mp_red_part(r), c); mp_add_or_subtract(mp, mp_green_part(q), mp_green_part(r), c); mp_add_or_subtract(mp, mp_blue_part(q), mp_blue_part(r), c); break; case mp_cmykcolor_type: mp_add_or_subtract(mp, mp_cyan_part(q), mp_cyan_part(r), c); mp_add_or_subtract(mp, mp_magenta_part(q), mp_magenta_part(r), c); mp_add_or_subtract(mp, mp_yellow_part(q), mp_yellow_part(r), c); mp_add_or_subtract(mp, mp_black_part(q), mp_black_part(r), c); break; case mp_transform_type: mp_add_or_subtract(mp, mp_tx_part(q), mp_tx_part(r), c); mp_add_or_subtract(mp, mp_ty_part(q), mp_ty_part(r), c); mp_add_or_subtract(mp, mp_xx_part(q), mp_xx_part(r), c); mp_add_or_subtract(mp, mp_xy_part(q), mp_xy_part(r), c); mp_add_or_subtract(mp, mp_yx_part(q), mp_yx_part(r), c); mp_add_or_subtract(mp, mp_yy_part(q), mp_yy_part(r), c); break; default: break; } } } break; case mp_less_than_operation: case mp_less_or_equal_operation: case mp_greater_than_operation: case mp_greater_or_equal_operation: case mp_equal_operation: case mp_unequal_operation: check_arith(); if ((mp->cur_exp.type > mp_pair_type) && (p->type > mp_pair_type)) { mp_add_or_subtract(mp, p, NULL, mp_minus_operation); } else if (mp->cur_exp.type != p->type) { mp_bad_binary(mp, p, (int) c); goto DONE; } else { switch (mp->cur_exp.type) { case mp_string_type: { memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); set_number_from_scaled(new_expr.data.n, mp_str_vs_str(mp, mp_get_value_str(p), cur_exp_str)); mp_flush_cur_exp(mp, new_expr); } break; case mp_unknown_string_type: case mp_unknown_boolean_type: { mp_node q = mp_get_value_node(cur_exp_node); while ((q != cur_exp_node) && (q != p)) { q = mp_get_value_node(q); } if (q == p) { memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); mp_set_cur_exp_node(mp, NULL); mp_flush_cur_exp(mp, new_expr); } } break; case mp_pair_type: { int part_type = 0; mp_node q = mp_get_value_node(p); mp_node r = mp_get_value_node(cur_exp_node); while (part_type == 0) { mp_node rr = mp_x_part(r); part_type = mp_x_part_operation; mp_add_or_subtract(mp, mp_x_part(q), rr, mp_minus_operation); if (rr->type != mp_known_type || ! number_zero(mp_get_value_number(rr))) { break; } rr = mp_y_part(r); part_type = mp_y_part_operation; mp_add_or_subtract(mp, mp_y_part(q), rr, mp_minus_operation); if (rr->type != mp_known_type || ! number_zero(mp_get_value_number(rr))) { break; } } mp_take_part(mp, part_type); } break; case mp_color_type: { int part_type = 0; mp_node q = mp_get_value_node(p); mp_node r = mp_get_value_node(cur_exp_node); while (part_type == 0) { mp_node rr = mp_red_part(r); part_type = mp_red_part_operation; mp_add_or_subtract(mp, mp_red_part(q), rr, mp_minus_operation); if (rr->type != mp_known_type || ! number_zero(mp_get_value_number(rr))) { break; } rr = mp_green_part(r); part_type = mp_green_part_operation; mp_add_or_subtract(mp, mp_green_part(q), rr, mp_minus_operation); if (rr->type != mp_known_type || ! number_zero(mp_get_value_number(rr))) { break; } rr = mp_blue_part(r); part_type = mp_blue_part_operation; mp_add_or_subtract(mp, mp_blue_part(q), rr, mp_minus_operation); if (rr->type != mp_known_type || ! number_zero(mp_get_value_number(rr))) { break; } } mp_take_part(mp, part_type); } break; case mp_cmykcolor_type: { int part_type = 0; mp_node q = mp_get_value_node(p); mp_node r = mp_get_value_node(cur_exp_node); while (part_type == 0) { mp_node rr = mp_cyan_part(r); part_type = mp_cyan_part_operation; mp_add_or_subtract(mp, mp_cyan_part(q), rr, mp_minus_operation); if (rr->type != mp_known_type || ! number_zero(mp_get_value_number(rr))) { break; } rr = mp_magenta_part(r); part_type = mp_magenta_part_operation; mp_add_or_subtract(mp, mp_magenta_part(q), rr, mp_minus_operation); if (rr->type != mp_known_type || ! number_zero(mp_get_value_number(rr))) { break; } rr = mp_yellow_part(r); part_type = mp_yellow_part_operation; mp_add_or_subtract(mp, mp_yellow_part(q), rr, mp_minus_operation); if (rr->type != mp_known_type || ! number_zero(mp_get_value_number(rr))) { break; } rr = mp_black_part(r); part_type = mp_black_part_operation; mp_add_or_subtract(mp, mp_black_part(q), rr, mp_minus_operation); if (rr->type != mp_known_type || ! number_zero(mp_get_value_number(rr))) { break; } } mp_take_part(mp, part_type); } break; case mp_transform_type: { int part_type = 0; mp_node q = mp_get_value_node(p); mp_node r = mp_get_value_node(cur_exp_node); while (part_type == 0) { mp_node rr = mp_tx_part(r); part_type = mp_x_part_operation; mp_add_or_subtract(mp, mp_tx_part(q), rr, mp_minus_operation); if (rr->type != mp_known_type || ! number_zero(mp_get_value_number(rr))) { break; } rr = mp_ty_part(r); part_type = mp_y_part_operation; mp_add_or_subtract(mp, mp_ty_part(q), rr, mp_minus_operation); if (rr->type != mp_known_type || ! number_zero(mp_get_value_number(rr))) { break; } rr = mp_xx_part(r); part_type = mp_xx_part_operation; mp_add_or_subtract(mp, mp_xx_part(q), rr, mp_minus_operation); if (rr->type != mp_known_type || ! number_zero(mp_get_value_number(rr))) { break; } rr = mp_xy_part(r); part_type = mp_xy_part_operation; mp_add_or_subtract(mp, mp_xy_part(q), rr, mp_minus_operation); if (rr->type != mp_known_type || ! number_zero(mp_get_value_number(rr))) { break; } rr = mp_yx_part(r); part_type = mp_yx_part_operation; mp_add_or_subtract(mp, mp_yx_part(q), rr, mp_minus_operation); if (rr->type != mp_known_type || ! number_zero(mp_get_value_number(rr))) { break; } rr = mp_yy_part(r); part_type = mp_yy_part_operation; mp_add_or_subtract(mp, mp_yy_part(q), rr, mp_minus_operation); if (rr->type != mp_known_type || ! number_zero(mp_get_value_number(rr))) { break; } } mp_take_part(mp, part_type); } break; case mp_boolean_type: { memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); set_number_from_boolean(new_expr.data.n, number_to_scaled(cur_exp_value_number) - number_to_scaled(mp_get_value_number(p))); mp_flush_cur_exp(mp, new_expr); } break; default: mp_bad_binary(mp, p, (int) c); goto DONE; break; } } if (mp->cur_exp.type != mp_known_type) { const char *hlp = NULL; if (mp->cur_exp.type < mp_known_type) { mp_disp_err(mp, p); hlp = "The quantities shown above have not been equated."; } else { hlp = "Oh dear. I can't decide if the expression above is positive, negative, or zero.\n" "So this comparison test won't be 'true'."; } mp_disp_err(mp, NULL); memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); set_number_from_boolean(new_expr.data.n, mp_false_operation); mp_back_error(mp, "Unknown relation will be considered false", hlp); mp_get_x_next(mp); mp_flush_cur_exp(mp, new_expr); } else { int b = 0; switch (c) { case mp_less_than_operation: b = number_negative(cur_exp_value_number); break; case mp_less_or_equal_operation: b = number_nonpositive(cur_exp_value_number); break; case mp_greater_than_operation: b = number_positive(cur_exp_value_number); break; case mp_greater_or_equal_operation: b = number_nonnegative(cur_exp_value_number); break; case mp_equal_operation: b = number_zero(cur_exp_value_number); break; case mp_unequal_operation: b = number_nonzero(cur_exp_value_number); break; }; mp_set_cur_exp_value_boolean(mp, b ? mp_true_operation : mp_false_operation); } mp->cur_exp.type = mp_boolean_type; DONE: mp->arith_error = 0; break; case mp_and_operation: case mp_or_operation: if ((p->type != mp_boolean_type) || (mp->cur_exp.type != mp_boolean_type)) { mp_bad_binary(mp, p, (int) c); } else if (number_to_boolean(p->data.n) == c + mp_false_operation - mp_and_operation) { mp_set_cur_exp_value_boolean(mp, number_to_boolean(p->data.n)); } break; case mp_times_operation: if ((mp->cur_exp.type < mp_color_type) || (p->type < mp_color_type)) { mp_bad_binary(mp, p, mp_times_operation); } else if ((mp->cur_exp.type == mp_known_type) || (p->type == mp_known_type)) { mp_number vv; new_fraction(vv); if (p->type == mp_known_type) { number_clone(vv, mp_get_value_number(p)); mp_free_value_node(mp, p); } else { number_clone(vv, cur_exp_value_number); mp_unstash_cur_exp(mp, p); } switch (mp->cur_exp.type) { case mp_known_type: { mp_number ret; new_number(ret); take_scaled(ret, cur_exp_value_number, vv); mp_set_cur_exp_value_number(mp, &ret); free_number(ret); } break; case mp_pair_type: { mp_dep_mult(mp, (mp_value_node) mp_x_part(mp_get_value_node(cur_exp_node)), &vv, 1); mp_dep_mult(mp, (mp_value_node) mp_y_part(mp_get_value_node(cur_exp_node)), &vv, 1); } break; case mp_color_type: { mp_dep_mult(mp, (mp_value_node) mp_red_part (mp_get_value_node(cur_exp_node)), &vv, 1); mp_dep_mult(mp, (mp_value_node) mp_green_part(mp_get_value_node(cur_exp_node)), &vv, 1); mp_dep_mult(mp, (mp_value_node) mp_blue_part (mp_get_value_node(cur_exp_node)), &vv, 1); } break; case mp_cmykcolor_type: { mp_dep_mult(mp, (mp_value_node) mp_cyan_part (mp_get_value_node(cur_exp_node)), &vv, 1); mp_dep_mult(mp, (mp_value_node) mp_magenta_part(mp_get_value_node(cur_exp_node)), &vv, 1); mp_dep_mult(mp, (mp_value_node) mp_yellow_part (mp_get_value_node(cur_exp_node)), &vv, 1); mp_dep_mult(mp, (mp_value_node) mp_black_part (mp_get_value_node(cur_exp_node)), &vv, 1); } break; default: { mp_dep_mult(mp, NULL, &vv, 1); } break; } free_number(vv); mp_finish_binary(mp, old_p, old_exp); return; } else if ((mp_nice_color_or_pair(mp, p, p->type) && (mp->cur_exp.type > mp_pair_type)) || (mp_nice_color_or_pair(mp, cur_exp_node, mp->cur_exp.type) && (p->type > mp_pair_type))) { mp_hard_times(mp, p); mp_finish_binary(mp, old_p, old_exp); return; } else { mp_bad_binary(mp, p, mp_times_operation); } break; case mp_over_operation: if ((mp->cur_exp.type != mp_known_type) || (p->type < mp_color_type)) { mp_bad_binary(mp, p, mp_over_operation); } else { mp_number v_n; new_number_clone(v_n, cur_exp_value_number); mp_unstash_cur_exp(mp, p); if (number_zero(v_n)) { mp_disp_err(mp, NULL); mp_back_error( mp, "Division by zero", "You're trying to divide the quantity shown above the error message by zero. I'm\n" "going to divide it by one instead." ); mp_get_x_next(mp); } else { switch (mp->cur_exp.type) { case mp_known_type: { mp_number ret; new_number(ret); make_scaled(ret, cur_exp_value_number, v_n); mp_set_cur_exp_value_number(mp, &ret); free_number(ret); } break; case mp_pair_type: { mp_dep_div(mp, (mp_value_node) mp_x_part(mp_get_value_node(cur_exp_node)), &v_n); mp_dep_div(mp, (mp_value_node) mp_y_part(mp_get_value_node(cur_exp_node)), &v_n); } break; case mp_color_type: { mp_dep_div(mp, (mp_value_node) mp_red_part (mp_get_value_node(cur_exp_node)), &v_n); mp_dep_div(mp, (mp_value_node) mp_green_part(mp_get_value_node(cur_exp_node)), &v_n); mp_dep_div(mp, (mp_value_node) mp_blue_part (mp_get_value_node(cur_exp_node)), &v_n); } break; case mp_cmykcolor_type: { mp_dep_div(mp, (mp_value_node) mp_cyan_part (mp_get_value_node(cur_exp_node)), &v_n); mp_dep_div(mp, (mp_value_node) mp_magenta_part(mp_get_value_node(cur_exp_node)), &v_n); mp_dep_div(mp, (mp_value_node) mp_yellow_part (mp_get_value_node(cur_exp_node)), &v_n); mp_dep_div(mp, (mp_value_node) mp_black_part (mp_get_value_node(cur_exp_node)), &v_n); } break; default: { mp_dep_div(mp, NULL, &v_n); } break; } } free_number(v_n); mp_finish_binary(mp, old_p, old_exp); return; } break; case mp_power_operation: if ((mp->cur_exp.type == mp_known_type) && (p->type == mp_known_type)) { mp_number r; new_number(r); power_of(r, mp_get_value_number(p), cur_exp_value_number); check_arith(); mp_set_cur_exp_value_number(mp, &r); free_number(r); } else mp_bad_binary(mp, p, (int) c); break; case mp_pythag_add_operation: case mp_pythag_sub_operation: if ((mp->cur_exp.type == mp_known_type) && (p->type == mp_known_type)) { mp_number r; new_number(r); if (c == mp_pythag_add_operation) { pyth_add(r, mp_get_value_number(p), cur_exp_value_number); } else { pyth_sub(r, mp_get_value_number(p), cur_exp_value_number); } mp_set_cur_exp_value_number(mp, &r); free_number(r); } else mp_bad_binary(mp, p, (int) c); break; case mp_rotated_operation: case mp_slanted_operation: case mp_scaled_operation: case mp_shifted_operation: case mp_transformed_operation: case mp_x_scaled_operation: case mp_y_scaled_operation: case mp_z_scaled_operation: switch (p->type) { case mp_path_type: mp_set_up_known_trans(mp, (int) c); mp_unstash_cur_exp(mp, p); mp_do_path_trans(mp, cur_exp_knot); mp_finish_binary(mp, old_p, old_exp); return; case mp_pen_type: mp_set_up_known_trans(mp, (int) c); mp_unstash_cur_exp(mp, p); mp_do_pen_trans(mp, cur_exp_knot); mp_set_cur_exp_knot(mp, mp_convex_hull(mp, cur_exp_knot)); mp_finish_binary(mp, old_p, old_exp); return; case mp_nep_type: mp_set_up_known_trans(mp, (int) c); mp_unstash_cur_exp(mp, p); mp_do_pen_trans(mp, cur_exp_knot); mp_set_cur_exp_knot(mp, cur_exp_knot); mp_finish_binary(mp, old_p, old_exp); return; case mp_pair_type: case mp_transform_type: mp_big_trans(mp, p, (int) c); break; case mp_picture_type: mp_do_edges_trans(mp, p, (int) c); mp_finish_binary(mp, old_p, old_exp); return; default: mp_bad_binary(mp, p, (int) c); break; } break; case mp_concatenate_operation: case mp_just_append_operation: case mp_tolerant_concat_operation: case mp_tolerant_append_operation: if ((mp->cur_exp.type == mp_string_type) && (p->type == mp_string_type)) { mp_string str = mp_cat(mp, mp_get_value_str(p), cur_exp_str); delete_str_ref(cur_exp_str) ; mp_set_cur_exp_str(mp, str); } else { mp_bad_binary(mp, p, c); } break; case mp_substring_operation: if (mp_nice_pair(mp, p, p->type) && (mp->cur_exp.type == mp_string_type)) { mp_string str = mp_chop_string (mp, cur_exp_str, round_unscaled(mp_get_value_number(mp_x_part(mp_get_value_node(p)))), round_unscaled(mp_get_value_number(mp_y_part(mp_get_value_node(p)))) ); delete_str_ref(cur_exp_str) ; mp_set_cur_exp_str(mp, str); } else { mp_bad_binary(mp, p, mp_substring_operation); } break; case mp_subpath_operation: if (mp->cur_exp.type == mp_pair_type) { mp_pair_to_path(mp); } if (mp_nice_pair(mp, p, p->type) && (mp->cur_exp.type == mp_path_type)) { mp_chop_path(mp, mp_get_value_node(p)); } else { mp_bad_binary(mp, p, mp_subpath_operation); } break; case mp_point_operation: case mp_precontrol_operation: case mp_postcontrol_operation: case mp_direction_operation: if (mp->cur_exp.type == mp_pair_type) { mp_pair_to_path(mp); } if ((mp->cur_exp.type == mp_path_type) && (p->type == mp_known_type)) { mp_find_point(mp, &(mp_get_value_number(p)), (int) c); } else { mp_bad_binary(mp, p, c); } break; case mp_pen_offset_operation: if ((mp->cur_exp.type == mp_pen_type || mp->cur_exp.type == mp_nep_type) && mp_nice_pair(mp, p, p->type)) { mp_set_up_offset(mp, mp_get_value_node(p)); } else { mp_bad_binary(mp, p, mp_pen_offset_operation); } break; case mp_direction_time_operation: if (mp->cur_exp.type == mp_pair_type) { mp_pair_to_path(mp); } if ((mp->cur_exp.type == mp_path_type) && mp_nice_pair(mp, p, p->type)) { mp_set_up_direction_time(mp, mp_get_value_node(p)); } else { mp_bad_binary(mp, p, mp_direction_time_operation); } break; case mp_envelope_operation: if ((p->type != mp_pen_type && p->type != mp_nep_type) || (mp->cur_exp.type != mp_path_type)) { mp_bad_binary(mp, p, mp_envelope_operation); } else { mp_set_up_envelope(mp, p); } break; case mp_boundingpath_operation: if ((p->type != mp_pen_type && p->type != mp_nep_type) || (mp->cur_exp.type != mp_path_type)) { mp_bad_binary(mp, p, mp_boundingpath_operation); } else { mp_set_up_boundingpath(mp, p); } break; case mp_arc_time_operation: if (mp->cur_exp.type == mp_pair_type) { mp_pair_to_path(mp); } if ((mp->cur_exp.type == mp_path_type) && (p->type == mp_known_type)) { memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); mp_get_arc_time(mp, &new_expr.data.n, cur_exp_knot, &(mp_get_value_number(p)), 0); mp_flush_cur_exp(mp, new_expr); } else { mp_bad_binary(mp, p, (int) c); } break; case mp_arc_point_operation: if (mp->cur_exp.type == mp_pair_type) { mp_pair_to_path(mp); } if ((mp->cur_exp.type == mp_path_type) && (p->type == mp_known_type || p->type == mp_pair_type)) { mp_knot k; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); if (p->type == mp_pair_type) { mp_knot f = cur_exp_knot; mp_node q = mp_get_value_node(p); mp_number x; new_number_clone(x, mp_get_value_number(mp_x_part(q))); if (number_greater(x, zero_t)) { while (number_greater(x, zero_t)) { f = mp_next_knot(f); number_subtract(x, unity_t); } } else { while (number_less(x, zero_t)) { f = mp_next_knot(f); number_add(x, unity_t); } } k = mp_get_arc_time(mp, &new_expr.data.n, f, &(mp_get_value_number(mp_y_part(q))), 1); free_number(x); } else { k = mp_get_arc_time(mp, &new_expr.data.n, cur_exp_knot, &(mp_get_value_number(p)), 1); } if (k) { int toss = 0; if (number_equal(new_expr.data.n, unity_t)) { k = mp_next_knot(k); } else if (! number_equal(new_expr.data.n, zero_t)) { convert_scaled_to_fraction(new_expr.data.n); k = mp_split_cubic_knot(mp, k, &new_expr.data.n); toss = 1; } mp_pair_value(mp, &(k->x_coord), &(k->y_coord)); if (toss) { mp_toss_knot(mp, k); } } else { mp_bad_unary(mp, mp_arc_point_operation); } } else { mp_bad_unary(mp, mp_arc_point_operation); } break; case mp_arc_point_list_operation: if (mp->cur_exp.type == mp_pair_type) { mp_pair_to_path(mp); } if ((mp->cur_exp.type == mp_path_type) && p->type == mp_known_type) { mp_knot cur = cur_exp_knot; mp_number len, aln, seg, tot, tim, stp, acc, tmp; mp_knot last = NULL; mp_knot list = NULL; int iscycle = mp_left_type(cur_exp_knot) == mp_explicit_knot; new_number(len); mp_path_length(mp, &len); new_number(aln); mp_get_arc_length(mp, &aln, cur_exp_knot); new_number(seg); new_number(tot); new_number(tim); new_number(stp); set_number_from_div(stp, aln, mp_get_value_number(p)); new_number(acc); mp_get_subarc_length(mp, &acc, cur_exp_knot, &zero_t, &unity_t); new_number(tmp); memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); list = mp_complex_knot(mp, cur_exp_knot); mp_prev_knot(list) = list; mp_next_knot(list) = list; last = list; number_clone(tot, stp); while (number_lessequal(tot, aln)) { mp_knot k; while (1) { if (number_lessequal(tot, acc)) { break; } else { number_add(seg, unity_t); number_clone(tim, acc); cur = mp_next_knot(cur); mp_get_subarc_length(mp, &tmp, cur, &zero_t, &unity_t); number_add(acc, tmp) ; } } number_clone(tmp, tot); number_subtract(tmp, tim); k = mp_get_arc_time(mp, &new_expr.data.n, cur, &tmp, 1); if (k) { int toss = 0; mp_knot kk; if (number_equal(new_expr.data.n, unity_t)) { k = mp_next_knot(k); } else if (! number_equal(new_expr.data.n, zero_t)) { convert_scaled_to_fraction(new_expr.data.n); k = mp_split_cubic_knot(mp, k, &new_expr.data.n); toss = 1; } kk = mp_complex_knot(mp, k); mp_prev_knot(list) = kk; mp_next_knot(kk) = list; mp_prev_knot(kk) = last; mp_next_knot(last) = kk; last = kk; if (toss) { mp_toss_knot(mp, k); } number_add(tot, stp); } else { break; } } free_number(len); free_number(aln); free_number(seg); free_number(tot); free_number(tim); free_number(stp); free_number(acc); free_number(tmp); if (list) { if (iscycle) { mp_left_type(list) = mp_explicit_knot; mp_right_type(last) = mp_explicit_knot; } else { mp_left_type(list) = mp_endpoint_knot; mp_right_type(last) = mp_endpoint_knot; } mp->cur_exp.type = mp_path_type; mp_set_cur_exp_knot(mp, list); } else { mp_bad_unary(mp, mp_arc_point_list_operation); } } else { mp_bad_unary(mp, mp_arc_point_list_operation); } break; case mp_subarc_length_operation: if (mp->cur_exp.type == mp_pair_type) { mp_pair_to_path(mp); } if ((mp->cur_exp.type == mp_path_type) && p->type == mp_pair_type) { memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); mp_node q = mp_get_value_node(p); mp_get_subarc_length(mp, &new_expr.data.n, cur_exp_knot, &(mp_get_value_number(mp_x_part(q))), &(mp_get_value_number(mp_y_part(q)))); mp_flush_cur_exp(mp, new_expr); } else { mp_bad_unary(mp, mp_subarc_length_operation); } break; case mp_intertimes_operation: case mp_intertimes_list_operation: if (p->type == mp_pair_type) { mp_node q = mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, p); mp_pair_to_path(mp); p = mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, q); } if (mp->cur_exp.type == mp_pair_type) { mp_pair_to_path(mp); } if ((mp->cur_exp.type == mp_path_type) && (p->type == mp_path_type)) { if (c == mp_intertimes_operation) { mp_path_intersection(mp, mp_get_value_knot(p), cur_exp_knot, 0, NULL); mp_pair_value(mp, &mp->cur_t, &mp->cur_tt); } else { mp_knot last = NULL; mp_knot list = mp_path_intersection(mp, mp_get_value_knot(p), cur_exp_knot, 1, &last); mp_left_type(list) = mp_endpoint_knot; mp_right_type(last) = mp_endpoint_knot; mp->cur_exp.type = mp_path_type; mp_set_cur_exp_knot(mp, list); } } else { mp_bad_binary(mp, p, c); } break; } mp_recycle_value(mp, p); mp_free_value_node(mp, p); mp_finish_binary(mp, old_p, old_exp); } static void mp_frac_mult (MP mp, mp_number *n, mp_number *d) { mp_node old_exp; mp_number v; new_fraction(v); if (number_greater(internal_value(mp_tracing_commands_internal), two_t)) { mp_begin_diagnostic(mp); mp_print_nl(mp, "{("); print_number(*n); mp_print_chr(mp, '/'); print_number(*d); mp_print_str(mp, ")*("); mp_print_exp(mp, NULL, 0); mp_print_str(mp, ")}"); mp_end_diagnostic(mp, 0); } switch (mp->cur_exp.type) { case mp_transform_type: case mp_color_type: case mp_cmykcolor_type: case mp_pair_type: old_exp = mp_tarnished(mp, cur_exp_node); break; case mp_independent_type: old_exp = MP_VOID; break; default: old_exp = NULL; break; } if (old_exp != NULL) { old_exp = cur_exp_node; mp_make_exp_copy(mp, old_exp); } make_fraction(v, *n, *d); switch (mp->cur_exp.type) { case mp_known_type: { mp_number r1, arg1; new_fraction(r1); new_number_clone(arg1, cur_exp_value_number); take_fraction(r1, arg1, v); mp_set_cur_exp_value_number(mp, &r1); free_number(r1); free_number(arg1); } break; case mp_pair_type: { mp_dep_mult(mp, (mp_value_node) mp_x_part(mp_get_value_node(cur_exp_node)), &v, 0); mp_dep_mult(mp, (mp_value_node) mp_y_part(mp_get_value_node(cur_exp_node)), &v, 0); } break; case mp_color_type: { mp_dep_mult(mp, (mp_value_node) mp_red_part (mp_get_value_node(cur_exp_node)), &v, 0); mp_dep_mult(mp, (mp_value_node) mp_green_part(mp_get_value_node(cur_exp_node)), &v, 0); mp_dep_mult(mp, (mp_value_node) mp_blue_part (mp_get_value_node(cur_exp_node)), &v, 0); } break; case mp_cmykcolor_type: { mp_dep_mult(mp, (mp_value_node) mp_cyan_part (mp_get_value_node(cur_exp_node)), &v, 0); mp_dep_mult(mp, (mp_value_node) mp_magenta_part(mp_get_value_node(cur_exp_node)), &v, 0); mp_dep_mult(mp, (mp_value_node) mp_yellow_part (mp_get_value_node(cur_exp_node)), &v, 0); mp_dep_mult(mp, (mp_value_node) mp_black_part (mp_get_value_node(cur_exp_node)), &v, 0); } break; default: { mp_dep_mult(mp, NULL, &v, 0); } break; } if (old_exp != NULL) { mp_recycle_value(mp, old_exp); mp_free_value_node(mp, old_exp); } free_number(v); } static void worry_about_bad_statement (MP mp); static void flush_unparsable_junk_after_statement (MP mp); void mp_do_statement (MP mp) { mp->cur_exp.type = mp_vacuous_type; mp_get_x_next(mp); if (cur_cmd > mp_max_primary_command) { worry_about_bad_statement(mp); } else if (cur_cmd > mp_max_statement_command) { mp_value new_expr; mp->var_flag = mp_assignment_command; mp_scan_expression(mp); if (cur_cmd < mp_end_group_command) { if (cur_cmd == mp_equals_command) { mp_do_equation(mp); } else if (cur_cmd == mp_assignment_command) { mp_do_assignment(mp); } else if (mp->cur_exp.type == mp_string_type) { if (number_positive(internal_value(mp_tracing_titles_internal))) { mp_print_nl(mp, ""); mp_print_mp_str(mp, cur_exp_str); update_terminal(); } } else if (mp->cur_exp.type != mp_vacuous_type) { mp_disp_err(mp, NULL); mp_back_error( mp, "Isolated expression", "I couldn't find an '=' or ':=' after the expression that is shown above this\n" "error message, so I guess I'll just ignore it and carry on." ); mp_get_x_next(mp); } memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); mp_flush_cur_exp(mp, new_expr); mp->cur_exp.type = mp_vacuous_type; } } else { if (number_positive(internal_value(mp_tracing_commands_internal))) { mp_show_cmd_mod(mp, cur_cmd, cur_mod); } switch (cur_cmd) { case mp_type_name_command: mp_do_type_declaration(mp); break; case mp_macro_def_command: switch (cur_mod) { case mp_def_code: case mp_var_def_code: mp_scan_def(mp, cur_mod); break; case mp_primary_def_code: case mp_secondary_def_code: case mp_tertiary_def_code: mp_make_op_def(mp, cur_mod); break; } break; case mp_only_set_command: switch (cur_mod) { case mp_random_seed_code: mp_do_random_seed(mp); break; case mp_max_knot_pool_code: mp_do_max_knot_pool(mp); break; } break; case mp_mode_command: mp_print_ln(mp); mp->interaction = cur_mod; mp->selector = mp->interaction == mp_batch_mode ? mp_log_only_selector : mp_term_and_log_selector; mp_get_x_next(mp); break; case mp_protection_command: mp_do_protection(mp); break; case mp_property_command: mp_do_property(mp); break; case mp_delimiters_command: mp_def_delims(mp); break; case mp_save_command: do { mp_get_symbol(mp); mp_save_variable(mp, cur_sym); mp_get_x_next(mp); } while (cur_cmd == mp_comma_command); break; case mp_interim_command: mp_do_interim(mp); break; case mp_let_command: mp_do_let(mp); break; case mp_new_internal_command: mp_do_new_internal(mp); break; case mp_show_command: mp_do_show_whatever(mp); break; case mp_add_to_command: mp_do_add_to(mp); break; case mp_bounds_command: mp_do_bounds(mp); break; case mp_ship_out_command: mp_do_ship_out(mp); break; case mp_every_job_command: mp_get_symbol(mp); mp->every_job_sym = cur_sym; mp_get_x_next(mp); break; case mp_message_command: mp_do_message(mp); break; case mp_write_command: mp_do_write(mp); break; default: break; } mp->cur_exp.type = mp_vacuous_type; } if (cur_cmd < mp_semicolon_command) { flush_unparsable_junk_after_statement(mp); } mp->error_count = 0; } static void worry_about_bad_statement (MP mp) { if (cur_cmd < mp_semicolon_command) { char msg[256]; mp_string sname; int selector = mp->selector; mp->selector = mp_new_string_selector; mp_print_cmd_mod(mp, cur_cmd, cur_mod); sname = mp_make_string(mp); mp->selector = selector; mp_snprintf(msg, 256, "A statement can't begin with '%s'", mp_str(mp, sname)); delete_str_ref(sname); mp_back_error( mp, msg, "I was looking for the beginning of a new statement. If you just proceed without\n" "changing anything, I'll ignore everything up to the next ';'." ); mp_get_x_next(mp); } } static void flush_unparsable_junk_after_statement (MP mp) { mp_back_error( mp, "Extra tokens will be flushed", "I've just read as much of that statement as I could fathom, so a semicolon should\n" "have been next. It's very puzzling ... but I'll try to get myself back together,\n" "by ignoring everything up to the next ';'." ); mp->scanner_status = mp_flushing_state; do { get_t_next(mp); if (cur_cmd == mp_string_command) { delete_str_ref(cur_mod_str); } } while (! mp_end_of_statement); mp->scanner_status = mp_normal_state; } static void trace_equation (MP mp, mp_node lhs) { mp_begin_diagnostic(mp); mp_print_nl(mp, "{("); mp_print_exp(mp, lhs, 0); mp_print_str(mp, ")=("); mp_print_exp(mp, NULL, 0); mp_print_str(mp, ")}"); mp_end_diagnostic(mp, 0); } void mp_do_equation (MP mp) { mp_node lhs = mp_stash_cur_exp(mp); mp_get_x_next(mp); mp->var_flag = mp_assignment_command; mp_scan_expression(mp); if (cur_cmd == mp_equals_command) { mp_do_equation(mp); } else if (cur_cmd == mp_assignment_command) { mp_do_assignment(mp); } if (number_greater(internal_value(mp_tracing_commands_internal), two_t)) { trace_equation(mp, lhs); } if (mp->cur_exp.type == mp_unknown_path_type) { if (lhs->type == mp_pair_type) { mp_node p; p = mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, lhs); lhs = p; } } mp_make_eq(mp, lhs); } static void bad_lhs (MP mp) { mp_disp_err(mp, NULL); mp_error( mp, "Improper ':=' will be changed to '='", "I didn't find a variable name at the left of the ':=', so I'm going to pretend\n" "that you said '=' instead." ); mp_do_equation(mp); } static void bad_internal_assignment (MP mp, mp_node lhs) { char msg[256]; mp_disp_err(mp, NULL); if (internal_type(mp_get_sym_info(lhs)) == mp_known_type) { mp_snprintf(msg, 256, "Internal quantity '%s' must receive a known numeric value", internal_name(mp_get_sym_info(lhs)) ); mp_back_error( mp, msg, "I can't set this internal quantity to anything but a known numeric value, so I'll\n" "have to ignore this assignment." ); } else if (internal_type(mp_get_sym_info(lhs)) == mp_boolean_type) { mp_snprintf(msg, 256, "Internal quantity '%s' must receive a known boolean value", internal_name(mp_get_sym_info(lhs)) ); mp_back_error( mp, msg, "I can't set this internal quantity to anything but a known boolean value, so I'll\n" "have to ignore this assignment." ); } else { mp_snprintf(msg, 256, "Internal quantity '%s' must receive a known string", internal_name(mp_get_sym_info(lhs)) ); mp_back_error( mp, msg, "I can't set this internal quantity to anything but a known string value, so I'll\n" "have to ignore this assignment." ); } mp_get_x_next(mp); } static void forbidden_internal_assignment (MP mp, mp_node lhs) { char msg[256]; mp_snprintf(msg, 256,"Internal quantity '%s' is read-only", internal_name(mp_get_sym_info(lhs))); mp_back_error( mp, msg, "I can't set this internal quantity to anything just yet (it is read-only), so\n" "I'll have to ignore this assignment." ); mp_get_x_next(mp); } static void bad_internal_assignment_precision (MP mp, mp_node lhs, mp_number *min, mp_number *max) { char msg[256]; char hlp[256]; mp_snprintf(msg, 256, "Bad '%s' has been ignored", internal_name(mp_get_sym_info(lhs))); mp_snprintf(hlp, 256, "Precision values are limited by the current numbersystem.\n" "Currently I am using '%s'; the allowed precision range is [%s,%s].", mp_str(mp, internal_string(mp_number_system_internal)), number_tostring(*min), number_tostring(*max)); mp_back_error(mp, msg, hlp); mp_get_x_next(mp); } static void bad_expression_assignment (MP mp, mp_node lhs) { char *msg = mp_obliterated(mp, lhs); mp_back_error( mp, msg, "It seems you did a nasty thing --- probably by accident, but nevertheless you\n" "nearly hornswoggled me ... While I was evaluating the right-hand side of this\n" "command, something happened, and the left-hand side is no longer a variable! So I\n" "won't change anything." ); mp_memory_free(msg); mp_get_x_next(mp); } static void trace_assignment (MP mp, mp_node lhs) { mp_begin_diagnostic(mp); mp_print_nl(mp, "{"); if (lhs->name_type == mp_internal_operation) { mp_print_str(mp, internal_name(mp_get_sym_info(lhs))); } else { mp_show_token_list(mp, lhs, NULL); } mp_print_str(mp, ":="); mp_print_exp(mp, NULL, 0); mp_print_chr(mp, '}'); mp_end_diagnostic(mp, 0); } void mp_do_assignment (MP mp) { if (mp->cur_exp.type != mp_token_list_type) { bad_lhs(mp); } else { mp_node lhs = cur_exp_node; mp->cur_exp.type = mp_vacuous_type; mp_get_x_next(mp); mp->var_flag = mp_assignment_command; mp_scan_expression(mp); if (cur_cmd == mp_equals_command) { mp_do_equation(mp); } else if (cur_cmd == mp_assignment_command) { mp_do_assignment(mp); } if (number_greater(internal_value(mp_tracing_commands_internal), two_t)) { trace_assignment (mp, lhs); } if (lhs->name_type == mp_internal_operation) { switch (mp->cur_exp.type) { case mp_known_type: case mp_string_type: case mp_boolean_type: if (internal_type(mp_get_sym_info(lhs)) == mp->cur_exp.type) { switch (mp_get_sym_info(lhs)) { case mp_number_system_internal: forbidden_internal_assignment(mp, lhs); break; case mp_number_precision_internal: if (mp->cur_exp.type == mp_known_type && (! number_less (cur_exp_value_number, precision_min)) && (! number_greater(cur_exp_value_number, precision_max)) ) { if (internal_type(mp_get_sym_info(lhs)) == mp_string_type) { add_str_ref(cur_exp_str); set_internal_string(mp_get_sym_info(lhs), cur_exp_str); } else { number_clone(internal_value(mp_get_sym_info(lhs)), cur_exp_value_number); } set_precision(); } else { bad_internal_assignment_precision(mp, lhs, &precision_min, &precision_max); } default: if (internal_type(mp_get_sym_info(lhs)) == mp_string_type) { add_str_ref(cur_exp_str); set_internal_string(mp_get_sym_info(lhs), cur_exp_str); } else { number_clone(internal_value(mp_get_sym_info(lhs)), cur_exp_value_number); } break; } } else { bad_internal_assignment(mp, lhs); } break; default: bad_internal_assignment(mp, lhs); } } else { mp_node p = mp_find_variable(mp, lhs); if (p != NULL) { mp_node q = mp_stash_cur_exp(mp); mp->cur_exp.type = mp_und_type(mp, p); mp_recycle_value(mp, p); p->type = mp->cur_exp.type; mp_set_value_number(p, zero_t); mp_make_exp_copy(mp, p); p = mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, q); mp_make_eq(mp, p); } else { bad_expression_assignment(mp, lhs); } } mp_flush_node_list(mp, lhs); } } static void announce_bad_equation (MP mp, mp_node lhs) { char msg[256]; mp_snprintf(msg, 256, "Equation cannot be performed (%s=%s)", (lhs->type <= mp_pair_type ? mp_type_string(lhs->type) : "numeric"), (mp->cur_exp.type <= mp_pair_type ? mp_type_string(mp->cur_exp.type) : "numeric")); mp_disp_err(mp, lhs); mp_disp_err(mp, NULL); mp_back_error( mp, msg, "I'm sorry, but I don't know how to make such things equal. (See the two\n" "expressions just above the error message.)" ); mp_get_x_next(mp); } static void mp_exclaim_inconsistent_equation (MP mp) { mp_back_error( mp, "Inconsistent equation", "The equation I just read contradicts what was said before. But don't worry;\n" "continue and I'll just ignore it." ); mp_get_x_next(mp); } static void mp_exclaim_redundant_or_inconsistent_equation (MP mp) { mp_back_error( mp, "Redundant or inconsistent equation", "An equation between already-known quantities can't help. But don't worry;\n" "continue and I'll just ignore it." ); mp_get_x_next(mp); } static void report_redundant_or_inconsistent_equation (MP mp, mp_node lhs, mp_number *v) { if (mp->cur_exp.type <= mp_string_type) { if (mp->cur_exp.type == mp_string_type) { if (mp_str_vs_str(mp, mp_get_value_str(lhs), cur_exp_str) != 0) { mp_exclaim_inconsistent_equation(mp); } else { mp_exclaim_redundant_equation(mp); } } else if (number_equal(*v, cur_exp_value_number)) { mp_exclaim_redundant_equation(mp); } else { mp_exclaim_inconsistent_equation(mp); } } else { mp_exclaim_redundant_or_inconsistent_equation(mp); } } void mp_make_eq (MP mp, mp_node lhs) { mp_value new_expr; mp_variable_type t; mp_number v; memset(&new_expr, 0, sizeof(mp_value)); new_number(v); RESTART: t = lhs->type; if (t <= mp_pair_type) { number_clone(v, mp_get_value_number(lhs)); } switch (t) { case mp_boolean_type: case mp_string_type: case mp_pen_type: case mp_nep_type: case mp_path_type: case mp_picture_type: if (mp->cur_exp.type == t + unknown_tag) { new_number(new_expr.data.n); switch (t) { case mp_boolean_type: number_clone(new_expr.data.n, v); break; case mp_string_type: new_expr.data.str = mp_get_value_str(lhs); break; case mp_picture_type: new_expr.data.node = mp_get_value_node(lhs); break; default: new_expr.data.p = mp_get_value_knot(lhs); break; } mp_nonlinear_eq(mp, new_expr, cur_exp_node, 0); mp_unstash_cur_exp(mp, cur_exp_node); } else if (mp->cur_exp.type == t) { report_redundant_or_inconsistent_equation(mp, lhs, &v); } else { announce_bad_equation(mp, lhs); } break; case mp_unknown_boolean_type: case mp_unknown_string_type: case mp_unknown_pen_type: case mp_unknown_nep_type: case mp_unknown_path_type: case mp_unknown_picture_type: if (mp->cur_exp.type == t - unknown_tag) { mp_nonlinear_eq(mp, mp->cur_exp, lhs, 1); } else if (mp->cur_exp.type == t) { mp_ring_merge (mp, lhs, cur_exp_node); } else if (mp->cur_exp.type == mp_pair_type) { if (t == mp_unknown_path_type) { mp_pair_to_path(mp); goto RESTART; } } else { announce_bad_equation(mp, lhs); } break; case mp_transform_type: case mp_color_type: case mp_cmykcolor_type: case mp_pair_type: if (mp->cur_exp.type == t) { mp_node q = mp_get_value_node(cur_exp_node); mp_node p = mp_get_value_node(lhs); switch (t) { case mp_transform_type: mp_try_eq(mp, mp_yy_part(p), mp_yy_part(q)); mp_try_eq(mp, mp_yx_part(p), mp_yx_part(q)); mp_try_eq(mp, mp_xy_part(p), mp_xy_part(q)); mp_try_eq(mp, mp_xx_part(p), mp_xx_part(q)); mp_try_eq(mp, mp_ty_part(p), mp_ty_part(q)); mp_try_eq(mp, mp_tx_part(p), mp_tx_part(q)); break; case mp_color_type: mp_try_eq(mp, mp_blue_part(p), mp_blue_part(q)); mp_try_eq(mp, mp_green_part(p), mp_green_part(q)); mp_try_eq(mp, mp_red_part(p), mp_red_part(q)); break; case mp_cmykcolor_type: mp_try_eq(mp, mp_black_part(p), mp_black_part(q)); mp_try_eq(mp, mp_yellow_part(p), mp_yellow_part(q)); mp_try_eq(mp, mp_magenta_part(p), mp_magenta_part(q)); mp_try_eq(mp, mp_cyan_part(p), mp_cyan_part(q)); break; case mp_pair_type: mp_try_eq(mp, mp_y_part(p), mp_y_part(q)); mp_try_eq(mp, mp_x_part(p), mp_x_part(q)); break; default: break; } } else { announce_bad_equation(mp, lhs); } break; case mp_known_type: case mp_dependent_type: case mp_proto_dependent_type: case mp_independent_type: if (mp->cur_exp.type >= mp_known_type) { mp_try_eq(mp, lhs, NULL); } else { announce_bad_equation(mp, lhs); } break; case mp_vacuous_type: announce_bad_equation(mp, lhs); break; default: announce_bad_equation(mp, lhs); break; } check_arith(); mp_recycle_value(mp, lhs); free_number(v); mp_free_value_node(mp, lhs); } static void deal_with_redundant_or_inconsistent_equation (MP mp, mp_value_node p, mp_node r) { mp_number absp; new_number_abs(absp, mp_get_value_number(p)); if (number_greater(absp, equation_threshold_k)) { char msg[256]; mp_snprintf(msg, 256, "Inconsistent equation (off by %s)", number_tostring (mp_get_value_number(p))); mp_back_error( mp, msg, "The equation I just read contradicts what was said before. But don't worry;\n" "continue and I'll just ignore it." ); mp_get_x_next(mp); } else if (r == NULL) { mp_exclaim_redundant_equation(mp); } free_number(absp); mp_free_dep_node(mp, p); } void mp_try_eq (MP mp, mp_node l, mp_node r) { mp_value_node p; mp_value_node q; mp_value_node pp; mp_variable_type tt; int copied; mp_variable_type t = l->type; switch (t) { case mp_known_type: { mp_number arg1; new_number(arg1); number_negated_clone(arg1, mp_get_value_number(l)); t = mp_dependent_type; p = mp_const_dependency(mp, &arg1); q = p; free_number(arg1); } break; case mp_independent_type: { t = mp_dependent_type; p = mp_single_dependency(mp, l); number_negate(mp_get_dep_value(p)); q = mp->dep_final; } break; default: { mp_value_node ll = (mp_value_node) l; p = (mp_value_node) mp_get_dep_list(ll); q = p; while (1) { number_negate(mp_get_dep_value(q)); if (mp_get_dep_info(q) == NULL) { break; } else { q = (mp_value_node) q->link; } } mp_get_prev_dep(ll)->link = q->link; mp_set_prev_dep((mp_value_node) q->link, mp_get_prev_dep(ll)); ll->type = mp_known_type; } break; } if (r == NULL) { if (mp->cur_exp.type == mp_known_type) { number_add(mp_get_value_number(q), cur_exp_value_number); goto DONE1; } else { tt = mp->cur_exp.type; if (tt == mp_independent_type) { pp = mp_single_dependency(mp, cur_exp_node); } else { pp = (mp_value_node) mp_get_dep_list((mp_value_node) cur_exp_node); } } } else if (r->type == mp_known_type) { number_add(mp_get_dep_value(q), mp_get_value_number(r)); goto DONE1; } else { tt = r->type; if (tt == mp_independent_type) { pp = mp_single_dependency(mp, r); } else { pp = (mp_value_node) mp_get_dep_list((mp_value_node) r); } } if (tt != mp_independent_type) { copied = 0; } else { copied = 1; tt = mp_dependent_type; } mp->watch_coefs = 0; if (t == tt) { p = mp_p_plus_q(mp, p, pp, (int) t); } else if (t == mp_proto_dependent_type) { p = mp_p_plus_fq(mp, p, &unity_t, pp, mp_proto_dependent_type, mp_dependent_type); } else { mp_number x; new_number(x); q = p; while (mp_get_dep_info(q) != NULL) { number_clone(x, mp_get_dep_value(q)); fraction_to_round_scaled(x); mp_set_dep_value(q, x); q = (mp_value_node) q->link; } free_number(x); t = mp_proto_dependent_type; p = mp_p_plus_q(mp, p, pp, (int) t); } mp->watch_coefs = 1; if (copied) { mp_flush_node_list(mp, (mp_node) pp); } DONE1: if (mp_get_dep_info(p) == NULL) { deal_with_redundant_or_inconsistent_equation(mp, p, r); } else { mp_linear_eq(mp, p, (int) t); if (r == NULL && mp->cur_exp.type != mp_known_type && cur_exp_node->type == mp_known_type) { mp_node pp = cur_exp_node; mp_set_cur_exp_value_number(mp, &(mp_get_value_number(pp))); mp->cur_exp.type = mp_known_type; mp_free_value_node(mp, pp); } } } mp_node mp_scan_declared_variable (MP mp) { mp_sym x; mp_node h, t; mp_get_symbol(mp); x = cur_sym; if (cur_cmd != mp_tag_command) { mp_clear_symbol(mp, x, 0); } h = mp_new_symbolic_node(mp); mp_set_sym_sym(h, x); t = h; while (1) { mp_get_x_next(mp); if (cur_sym == NULL) { break; } else if (cur_cmd != mp_tag_command) { if (cur_cmd != mp_internal_command) { if (cur_cmd == mp_left_bracket_command) { mp_sym ll = cur_sym; mp_get_x_next(mp); if (cur_cmd == mp_right_bracket_command) { set_cur_sym(mp_collective_subscript); } else { mp_back_input(mp); set_cur_sym(ll); set_cur_cmd(mp_left_bracket_command); break; } } else { break; } } } t->link = mp_new_symbolic_node(mp); t = t->link; mp_set_sym_sym(t, cur_sym); t->name_type = cur_sym_mod; } if (eq_property(x) != 0) { mp_check_overload(mp, x); } if (eq_type(x) != mp_tag_command) { mp_clear_symbol(mp, x, 0); } if (equiv_node(x) == NULL) { mp_new_root (mp, x); } return h; } static void flush_spurious_symbols_after_declared_variable (MP mp); void mp_do_type_declaration (MP mp) { int t = mp_numeric_type; switch (cur_mod) { case mp_string_type_operation: t = mp_unknown_string_type; break; case mp_boolean_type_operation: t = mp_unknown_boolean_type; break; case mp_path_type_operation: t = mp_unknown_path_type; break; case mp_pen_type_operation: t = mp_unknown_pen_type; break; case mp_nep_type_operation: t = mp_unknown_nep_type; break; case mp_picture_type_operation: t = mp_unknown_picture_type; break; case mp_transform_type_operation: t = mp_transform_type; break; case mp_color_type_operation: t = mp_color_type; break; case mp_cmykcolor_type_operation: t = mp_cmykcolor_type; break; case mp_pair_type_operation: t = mp_pair_type; break; case mp_numeric_type_operation: t = mp_numeric_type; break; } do { mp_node p = mp_scan_declared_variable(mp); mp_node q; mp_flush_variable(mp, equiv_node(mp_get_sym_sym(p)), p->link, 0); q = mp_find_variable(mp, p); if (q != NULL) { q->type = t; mp_set_value_number(q, zero_t); } else { mp_back_error( mp, "Declared variable conflicts with previous vardef", "You can't use, e.g., 'numeric foo[]' after 'vardef foo'. Proceed, and I'll ignore\n" "the illegal redeclaration." ); mp_get_x_next(mp); } mp_flush_node_list(mp, p); if (cur_cmd < mp_comma_command) { flush_spurious_symbols_after_declared_variable(mp); } } while (! mp_end_of_statement); } static void flush_spurious_symbols_after_declared_variable (MP mp) { const char *hlp = NULL; if (cur_cmd == mp_numeric_command) { hlp = "Variables in declarations must consist entirely of names and explicit subscripts\n" "like 'x15a' aren't permitted. I'm going to discard the junk I found here, up to the\n" "next comma or the end of the declaration."; } else { hlp = "Variables in declarations must consist entirely of names and collective\n" "subscripts, e.g., 'x[]a'. Are you trying to use a reserved word in a variable\n" "name? I'm going to discard the junk I found here, up to the next comma or the end\n" "of the declaration."; } mp_back_error( mp, "Illegal suffix of declared variable will be flushed", hlp ); mp_get_x_next(mp); mp->scanner_status = mp_flushing_state; do { get_t_next(mp); if (cur_cmd == mp_string_command) { delete_str_ref(cur_mod_str); } } while (cur_cmd < mp_comma_command); mp->scanner_status = mp_normal_state; } static void mp_main_control (MP mp) { do { mp_do_statement(mp); if (cur_cmd == mp_end_group_command) { mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); mp_error( mp, "Extra 'endgroup'", "I'm not currently working on a 'begingroup', so I had better not try to end\n" "anything." ); mp_flush_cur_exp(mp, new_expr); } } while (cur_cmd != mp_stop_command); } int mp_run (MP mp) { if (mp->history < mp_fatal_error_stop) { mp_memory_free(mp->jump_buf); mp->jump_buf = mp_memory_allocate(sizeof(jmp_buf)); if (mp->jump_buf == NULL || setjmp (*(mp->jump_buf)) != 0) { return mp->history; } mp_main_control(mp); mp_final_cleanup(mp); mp_close_files_and_terminate(mp); } return mp->history; } void mp_set_internal (MP mp, char *n, char *v, int isstring) { size_t l = strlen(n); char err[256]; const char *errid = NULL; if (l > 0) { mp_sym p = mp_id_lookup(mp, n, l, 0); if (p == NULL) { errid = "variable does not exist"; } else if (eq_type(p) != mp_internal_command) { errid = "variable is not an internal"; } else if ((internal_type(equiv(p)) == mp_string_type) && (isstring)) { set_internal_string(equiv(p), mp_rts(mp, v)); } else if ((internal_type(equiv(p)) == mp_known_type) && (! isstring)) { int test = atoi(v); if (test > 16383 && mp->math_mode == mp_math_scaled_mode) { errid = "value is too large"; } else if (test < -16383 && mp->math_mode == mp_math_scaled_mode) { errid = "value is too small"; } else { number_clone(internal_value(equiv(p)), unity_t); number_multiply_int(internal_value(equiv(p)), test); } } else { errid = "value has the wrong type"; } } if (errid != NULL) { if (isstring) { mp_snprintf(err, 256, "%s=\"%s\": %s, assignment ignored.", n, v, errid); } else { mp_snprintf(err, 256, "%s=%d: %s, assignment ignored.", n, atoi (v), errid); } mp_warn(mp, err); } } void mplib_shipout_backend (MP mp, void *voidh) { mp_edge_header_node h = (mp_edge_header_node) voidh; mp_edge_object *hh = mp_gr_export (mp, h); if (hh) { mp_run_data *run = mp_rundata(mp); if (run->edges == NULL) { run->edges = hh; } else { mp_edge_object *p = run->edges; while (p->next != NULL) { p = p->next; } p->next = hh; } } } mp_run_data *mp_rundata (MP mp) { return &(mp->run_data); } int mp_execute (MP mp, const char *s, size_t l) { (void) l; if (mp->finished) { return mp->history; } else if (mp->history < mp_fatal_error_stop) { mp_memory_free(mp->jump_buf); mp->jump_buf = mp_memory_allocate(sizeof(jmp_buf)); if (mp->jump_buf == NULL || setjmp (*(mp->jump_buf)) != 0) { return mp->history; } else { mp->term_offset = 0; mp->file_offset = 0; if (mp->term_in == NULL) { mp->term_in = (mp->open_file)(mp,"terminal", "r", mp_filetype_terminal); mp->last = 0; } if (s && l > 0) { (mp->write_file)(mp, mp->term_in, s); } else { } if (mp->run_state == 0) { mp->term_offset = 0; mp->file_offset = 0; mp_log_string(mp_term_logging_target, mp->banner); mp_log_string(mp_term_logging_target, ", running in "); mp_log_string(mp_term_logging_target, mp_str(mp, internal_string(mp_number_system_internal))); mp_log_string(mp_term_logging_target, " mode."); mp_print_ln(mp); update_terminal(); mp->input_ptr = 0; mp->max_in_stack = mp_file_bottom_text; mp->in_open = mp_file_bottom_text; mp->open_parens = 0; mp->max_buf_stack = 0; mp->param_ptr = 0; mp->max_param_stack = 0; start = loc = 0; iindex = mp_file_bottom_text; nloc = nstart = NULL; mp->first = 0; line = 0; name = is_term; mp->force_eof = 0; if (mp->term_in == NULL) { mp->term_in = (mp->open_file)(mp,"terminal", "r", mp_filetype_terminal); } mp->last = 0; mp->scanner_status = mp_normal_state; mp_fix_date_and_time(mp); if (mp->random_seed == 0) { mp->random_seed = (number_to_scaled(internal_value(mp_time_internal))/number_to_scaled(unity_t)) + number_to_scaled(internal_value(mp_day_internal)); } init_randoms(mp->random_seed); mp->selector = mp->interaction == mp_batch_mode ? mp_no_print_selector : mp_term_only_selector; mp->history = mp_spotless; if (mp->every_job_sym != NULL) { set_cur_sym(mp->every_job_sym); mp_back_input(mp); } } mp->run_state = 1; mp_input_ln(mp, mp->term_in); mp_firm_up_the_line(mp); mp->buffer[limit] = '%'; mp->first = (size_t) (limit + 1); loc = start; do { mp_do_statement(mp); } while (cur_cmd != mp_stop_command); mp_final_cleanup(mp); mp_close_files_and_terminate(mp); } } return mp->history; } int mp_finish (MP mp) { int history = 0; if (mp->finished || mp->history >= mp_fatal_error_stop) { history = mp->history; mp_free(mp); } else { mp_memory_free(mp->jump_buf); mp->jump_buf = mp_memory_allocate(sizeof(jmp_buf)); if (mp->jump_buf == NULL || setjmp (*(mp->jump_buf)) != 0) { history = mp->history; } else { history = mp->history; mp_final_cleanup(mp); } mp_close_files_and_terminate(mp); mp_free(mp); } return history; } char *mp_metapost_version(void) { return mp_strdup(metapost_version); } void mp_do_max_knot_pool (MP mp) { mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); mp_get_x_next(mp); if (cur_cmd != mp_assignment_command) { mp_back_error( mp, "Missing ':=' has been inserted", "Always say 'maxknotpool := '." ); }; mp_get_x_next(mp); mp_scan_expression(mp); if (mp->cur_exp.type != mp_known_type) { mp_disp_err(mp, NULL); mp_back_error( mp, "Unknown value will be ignored", "Your expression was too random for me to handle, so I won't change the maximum\n" "seed just now." ); mp_get_x_next(mp); mp_flush_cur_exp(mp, new_expr); } else { int p = (int) number_to_scaled (cur_exp_value_number) / 65536; if (p > mp->max_knot_nodes) { mp->max_knot_nodes = p; } else if (p > max_num_knot_nodes) { } else { } } } void mp_do_random_seed (MP mp) { mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); mp_get_x_next(mp); if (cur_cmd != mp_assignment_command) { mp_back_error( mp, "Missing ':=' has been inserted", "Always say 'randomseed := '." ); }; mp_get_x_next(mp); mp_scan_expression(mp); if (mp->cur_exp.type != mp_known_type) { mp_disp_err(mp, NULL); mp_back_error( mp, "Unknown value will be ignored", "Your expression was too random for me to handle, so I won't change the random\n" "seed just now." ); mp_get_x_next(mp); mp_flush_cur_exp(mp, new_expr); } else { init_randoms(number_to_scaled(cur_exp_value_number)); if (mp->interaction < mp_silent_mode && (mp->selector == mp_log_only_selector || mp->selector == mp_term_and_log_selector)) { int selector = mp->selector; mp->selector = mp_log_only_selector; mp_print_nl(mp, "{randomseed:="); print_number(cur_exp_value_number); mp_print_chr(mp, '}'); mp_print_nl(mp, ""); mp->selector = selector; } } } void mp_do_protection (MP mp) { do { mp_get_symbol(mp); mp_get_x_next(mp); } while (cur_cmd == mp_comma_command); } void mp_do_property (MP mp) { int p = 0; mp_get_x_next(mp); mp_scan_primary(mp); switch (mp->cur_exp.type) { case mp_numeric_type: case mp_known_type: { mp_back_input(mp); p = (int) number_to_scaled (cur_exp_value_number) / 65536; } break; default: mp_back_error(mp, "Bad property value", NULL); break; } mp_get_x_next(mp); if (cur_cmd == mp_colon_command) { do { mp_get_symbol(mp); set_eq_property(cur_sym, p); mp_get_x_next(mp); } while (cur_cmd == mp_comma_command); } else { mp_back_error(mp, "Bad property specification, colon expected", NULL); } } void mp_def_delims (MP mp) { mp_sym l_delim, r_delim; mp_get_clear_symbol(mp); l_delim = cur_sym; mp_get_clear_symbol(mp); r_delim = cur_sym; set_eq_type(l_delim, mp_left_delimiter_command); set_equiv_sym(l_delim, r_delim); set_eq_type(r_delim, mp_right_delimiter_command); set_equiv_sym(r_delim, l_delim); mp_get_x_next(mp); } void mp_check_delimiter (MP mp, mp_sym l_delim, mp_sym r_delim) { if (cur_cmd == mp_right_delimiter_command && equiv_sym(cur_sym) == l_delim) { return; } else if (cur_sym != r_delim) { char msg[256]; mp_snprintf(msg, 256, "Missing '%s' has been inserted", mp_str(mp, text(r_delim))); mp_back_error( mp, msg, "I found no right delimiter to match a left one. So I've put one in, behind the\n" "scenes; this may fix the problem." ); } else { char msg[256]; mp_snprintf(msg, 256, "The token '%s' is no longer a right delimiter", mp_str(mp, text(r_delim))); mp_error( mp, msg, "Strange: This token has lost its former meaning! I'll read it as a right\n" "delimiter this time; but watch out, I'll probably miss it later." ); } } void mp_do_interim (MP mp) { mp_get_x_next(mp); if (cur_cmd != mp_internal_command) { char msg[256]; mp_snprintf(msg, 256, "The token '%s' isn't an internal quantity", (cur_sym == NULL ? "(%CAPSULE)" : mp_str(mp, text(cur_sym))) ); mp_back_error(mp, msg, "Something like 'tracingonline' should follow 'interim'."); } else { mp_save_internal(mp, cur_mod); mp_back_input(mp); } mp_do_statement(mp); } void mp_do_let (MP mp) { mp_sym l; mp_get_symbol(mp); l = cur_sym; mp_get_x_next(mp); if (cur_cmd != mp_equals_command && cur_cmd != mp_assignment_command) { mp_back_error( mp, "Missing '=' has been inserted", "You should have said 'let symbol = something'. But don't worry; I'll pretend that\n" "an equals sign was present. The next token I read will be 'something'." ); } mp_get_symbol(mp); switch (cur_cmd) { case mp_defined_macro_command: case mp_primary_def_command: case mp_secondary_def_command: case mp_tertiary_def_command: mp_add_mac_ref(cur_mod_node); break; default: break; } mp_clear_symbol(mp, l, 0); set_eq_type(l, cur_cmd); switch (cur_cmd) { case mp_tag_command: set_equiv(l, 0); break; case mp_defined_macro_command: case mp_primary_def_command: case mp_secondary_def_command: case mp_tertiary_def_command: set_equiv_node(l, cur_mod_node); break; case mp_left_delimiter_command: case mp_right_delimiter_command: set_equiv_sym(l, equiv_sym(cur_sym)); break; default: set_equiv(l, cur_mod); break; } mp_get_x_next(mp); } void mp_grow_internals (MP mp, int l) { if (l > max_halfword) { mp_confusion(mp, "out of memory"); } else { mp_internal *internal = mp_memory_allocate((size_t) (l + 1) * sizeof(mp_internal)); for (int k = 0; k <= l; k++) { if (k <= mp->max_internal) { memcpy(internal + k, mp->internal + k, sizeof(mp_internal)); } else { memset(internal + k, 0, sizeof(mp_internal)); new_number(((mp_internal *)(internal + k))->v.data.n); } } mp_memory_free(mp->internal); mp->internal = internal; mp->max_internal = l; } } void mp_do_new_internal (MP mp) { int the_type = mp_known_type; int run_script = 0; mp_get_next(mp); if (cur_cmd == mp_type_name_command && cur_mod == mp_string_type_operation) { the_type = mp_string_type; } else if (cur_cmd == mp_type_name_command && cur_mod == mp_boolean_type_operation) { the_type = mp_boolean_type; } else if (cur_cmd == mp_type_name_command && cur_mod == mp_numeric_type_operation) { the_type = mp_numeric_type; } else if (! (cur_cmd == mp_type_name_command && cur_mod == mp_numeric_type_operation)) { mp_back_input(mp); } if (mp_numeric_type == mp_known_type) { } else { if (the_type == mp_numeric_type) { the_type = mp_known_type; } mp_get_next(mp); if (cur_cmd == mp_runscript_command) { run_script = 1; } else { mp_back_input(mp); } } do { if (mp->int_ptr == mp->max_internal) { mp_grow_internals(mp, (mp->max_internal + (mp->max_internal / 4))); } mp_get_clear_symbol(mp); ++mp->int_ptr; set_eq_type(cur_sym, mp_internal_command); set_equiv(cur_sym, mp->int_ptr); mp_memory_free(internal_name(mp->int_ptr)); set_internal_name(mp->int_ptr, mp_strdup(mp_str(mp, text(cur_sym)))); if (the_type == mp_string_type) { set_internal_string(mp->int_ptr, mp_rts(mp,"")); } else { set_number_to_zero(internal_value(mp->int_ptr)); } set_internal_type(mp->int_ptr, the_type); set_internal_run(mp->int_ptr, run_script); if (run_script) { mp->run_internal(mp, 0, mp->int_ptr, the_type, internal_name(mp->int_ptr)); } mp_get_x_next(mp); } while (cur_cmd == mp_comma_command); } void mp_do_show (MP mp) { do { mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); mp_get_x_next(mp); mp_scan_expression(mp); mp_print_nl(mp, ">> "); mp_print_exp(mp, NULL, 2); mp_flush_cur_exp(mp, new_expr); } while (cur_cmd == mp_comma_command); } void mp_disp_token (MP mp) { mp_print_nl(mp, "> "); if (cur_sym == NULL) { switch (cur_cmd) { case mp_numeric_command: print_number(cur_mod_number); break; case mp_capsule_command: mp_print_capsule(mp, cur_mod_node); break; default: mp_print_chr(mp, '"'); mp_print_mp_str(mp, cur_mod_str); mp_print_chr(mp, '"'); delete_str_ref(cur_mod_str); break; } } else { mp_print_mp_str(mp,text(cur_sym)); mp_print_chr(mp, '='); mp_print_cmd_mod(mp, cur_cmd, cur_mod); if (cur_cmd == mp_defined_macro_command) { mp_print_ln(mp); mp_show_macro (mp, cur_mod_node, NULL); } } } void mp_do_show_token (MP mp) { do { get_t_next(mp); mp_disp_token(mp); mp_get_x_next(mp); } while (cur_cmd == mp_comma_command); } void mp_do_show_stats (MP mp) { mp_print_nl(mp, "Memory usage "); mp_print_int(mp, (int) mp->var_used); mp_print_ln(mp); mp_print_nl(mp, "String usage "); mp_print_int(mp, (int) mp->strs_in_use); mp_print_chr(mp, '&'); mp_print_int(mp, (int) mp->pool_in_use); mp_print_ln(mp); mp_get_x_next(mp); } void mp_disp_var (MP mp, mp_node p) { if (p->type == mp_structured_type) { mp_node q = mp_get_attribute_head(p); do { mp_disp_var(mp, q); q = q->link; } while (q != mp->end_attr); q = mp_get_subscr_head(p); while (q->name_type == mp_subscript_operation) { mp_disp_var(mp, q); q = q->link; } } else if (p->type >= mp_unsuffixed_macro_type) { mp_print_nl(mp, ""); mp_print_variable_name(mp, p); if (p->type > mp_unsuffixed_macro_type) { mp_print_str(mp, "@#"); } mp_print_str(mp, "=macro:"); mp_show_macro(mp, mp_get_value_node(p), NULL); } else if (p->type != mp_undefined_type) { mp_print_nl(mp, ""); mp_print_variable_name(mp, p); mp_print_chr(mp, '='); mp_print_exp(mp, p, 0); } } void mp_do_show_var (MP mp) { do { get_t_next(mp); if (cur_sym != NULL && cur_sym_mod == 0 && cur_cmd == mp_tag_command) { if (cur_mod != 0 || cur_mod_node != NULL) { mp_disp_var(mp, cur_mod_node); goto DONE; } } mp_disp_token(mp); DONE: mp_get_x_next(mp); } while (cur_cmd == mp_comma_command); } void mp_do_show_dependencies (MP mp) { mp_value_node p = (mp_value_node) mp->dep_head->link; while (p != mp->dep_head) { if (mp_interesting(mp, (mp_node) p)) { mp_print_nl(mp, ""); mp_print_variable_name(mp, (mp_node) p); if (p->type == mp_dependent_type) { mp_print_chr(mp, '='); } else { mp_print_str(mp, " = "); } mp_print_dependency(mp, (mp_value_node) mp_get_dep_list(p), p->type); } p = (mp_value_node) mp_get_dep_list(p); while (mp_get_dep_info(p) != NULL) { p = (mp_value_node) p->link; } p = (mp_value_node) p->link; } mp_get_x_next(mp); } void mp_do_show_whatever (MP mp) { if (mp->interaction == mp_error_stop_mode) { wake_up_terminal(); } switch (cur_mod) { case mp_show_token_code: mp_do_show_token(mp); break; case mp_show_stats_code: mp_do_show_stats(mp); break; case mp_show_code: mp_do_show(mp); break; case mp_show_var_code: mp_do_show_var(mp); break; case mp_show_dependencies_code: mp_do_show_dependencies(mp); break; } if (number_positive(internal_value(mp_showstopping_internal))) { const char *hlp = NULL; if (mp->interaction < mp_error_stop_mode) { --mp->error_count; } else { hlp = "This isn't an error message; I'm just showing something."; } if (cur_cmd == mp_semicolon_command) { mp_error(mp, "OK", hlp); } else { mp_back_error(mp, "OK", hlp); mp_get_x_next(mp); } } } static void complain_invalid_with_list (MP mp, mp_variable_type t) { mp_value new_expr; const char *hlp = NULL; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); mp_disp_err(mp, NULL); switch (t) { case mp_with_pre_script_code: hlp = "Next time say 'withprescript '; I'll ignore the bad\n" "'with' clause and look for another."; break; case mp_with_post_script_code: hlp = "Next time say 'withpostscript '; I'll ignore the bad\n" "'with' clause and look for another."; break; case mp_with_stacking_code: hlp = "Next time say 'withstacking '; I'll ignore the bad\n" "'with' clause and look for another."; break; case mp_with_dashed_code: hlp = "Next time say 'dashed '; I'll ignore the bad 'with'\n" "clause and look for another."; break; case mp_with_uninitialized_model_code: hlp = "Next time say 'withcolor '; I'll ignore the bad 'with'\n" "clause and look for another."; break; case mp_with_rgb_model_code: hlp = "Next time say 'withrgbcolor '; I'll ignore the bad 'with'\n" "clause and look for another."; break; case mp_with_cmyk_model_code: hlp = "Next time say 'withcmykcolor '; I'll ignore the bad\n" "'with' clause and look for another."; break; case mp_with_grey_model_code: hlp = "Next time say 'withgreyscale '; I'll ignore the bad\n" " with' clause and look for another."; break; case mp_with_linecap_code: hlp = "Next time say 'withlinecap '; I'll ignore the bad\n" "'with' clause and look for another."; break; case mp_with_linejoin_code: hlp = "Next time say 'withlinejoin '; I'll ignore the bad\n" "'with' clause and look for another."; break; case mp_with_miterlimit_code: hlp = "Next time say 'miterlimit '; I'll ignore the bad\n" "'with' clause and look for another."; break; default: hlp = "Next time say 'withpen '; I'll ignore the bad 'with' clause\n" "and look for another."; break; } mp_back_error(mp, "Improper type", hlp); mp_get_x_next(mp); mp_flush_cur_exp(mp, new_expr); } void mp_scan_with_list (MP mp, mp_node p, mp_node pstop) { mp_node cp = MP_VOID; mp_node pp = MP_VOID; mp_node dp = MP_VOID; mp_node ap = MP_VOID; mp_node bp = MP_VOID; mp_node sp = MP_VOID; mp_node spstop = MP_VOID; mp_number ml; int miterlimit = 0; int linecap = -1; int linejoin = -1; while (cur_cmd == mp_with_option_command) { int t; CONTINUE: t = cur_mod; mp_get_x_next(mp); if (t != mp_with_no_model_code) { mp_scan_expression(mp); } switch (t) { case mp_with_uninitialized_model_code : switch (mp->cur_exp.type) { case mp_cmykcolor_type: case mp_color_type: case mp_known_type: case mp_boolean_type: { mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); if (cp == MP_VOID) { make_cp_a_colored_object(cp, p); } if (cp != NULL) { switch (mp->cur_exp.type) { case mp_color_type: { mp_node q = mp_get_value_node(cur_exp_node); mp_color_model(cp) = mp_rgb_model; set_color_val(mp_red_color(cp), mp_get_value_number(mp_red_part(q))); set_color_val(mp_green_color(cp), mp_get_value_number(mp_green_part(q))); set_color_val(mp_blue_color(cp), mp_get_value_number(mp_blue_part(q))); set_number_to_zero(mp_black_color(cp)); } break; case mp_cmykcolor_type: { mp_node q = mp_get_value_node(cur_exp_node); mp_color_model(cp) = mp_cmyk_model; set_color_val(mp_cyan_color(cp), mp_get_value_number(mp_cyan_part(q))); set_color_val(mp_magenta_color(cp), mp_get_value_number(mp_magenta_part(q))); set_color_val(mp_yellow_color(cp), mp_get_value_number(mp_yellow_part(q))); set_color_val(mp_black_color(cp), mp_get_value_number(mp_black_part(q))); } break; case mp_known_type: { mp_color_model(cp) = mp_grey_model; set_number_to_zero(mp_cyan_color(cp)); set_number_to_zero(mp_magenta_color(cp)); set_number_to_zero(mp_yellow_color(cp)); set_color_val(mp_grey_color(cp), cur_exp_value_number); } break; default: switch (cur_exp_value_boolean) { case mp_false_operation: mp_color_model(cp) = mp_no_model; break; case mp_true_operation: mp_color_model(cp) = mp_uninitialized_model; break; default: break; } set_number_to_zero(mp_cyan_color(cp)); set_number_to_zero(mp_magenta_color(cp)); set_number_to_zero(mp_yellow_color(cp)); set_number_to_zero(mp_black_color(cp)); break; } } mp_flush_cur_exp(mp, new_expr); } break; default: complain_invalid_with_list(mp, t); goto CONTINUE; } break; case mp_with_rgb_model_code: if (mp->cur_exp.type != mp_color_type) { complain_invalid_with_list(mp, t); goto CONTINUE; } else { mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); if (cp == MP_VOID) { make_cp_a_colored_object(cp, p); } if (cp != NULL) { mp_node q = mp_get_value_node(cur_exp_node); mp_color_model(cp) = mp_rgb_model; set_color_val(mp_red_color(cp), mp_get_value_number(mp_red_part(q))); set_color_val(mp_green_color(cp), mp_get_value_number(mp_green_part(q))); set_color_val(mp_blue_color(cp), mp_get_value_number(mp_blue_part(q))); set_number_to_zero(mp_black_color(cp)); } mp_flush_cur_exp(mp, new_expr); } break; case mp_with_cmyk_model_code: if (mp->cur_exp.type != mp_cmykcolor_type) { complain_invalid_with_list(mp, t); goto CONTINUE; } else { mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); if (cp == MP_VOID) { make_cp_a_colored_object(cp, p); } if (cp != NULL) { mp_node q = mp_get_value_node(cur_exp_node); mp_color_model(cp) = mp_cmyk_model; set_color_val(mp_cyan_color(cp), mp_get_value_number(mp_cyan_part(q))); set_color_val(mp_magenta_color(cp), mp_get_value_number(mp_magenta_part(q))); set_color_val(mp_yellow_color(cp), mp_get_value_number(mp_yellow_part(q))); set_color_val(mp_black_color(cp), mp_get_value_number(mp_black_part(q))); } mp_flush_cur_exp(mp, new_expr); } break; case mp_with_grey_model_code: if (mp->cur_exp.type != mp_known_type) { complain_invalid_with_list(mp, t); goto CONTINUE; } else { mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); if (cp == MP_VOID) { make_cp_a_colored_object(cp, p); } if (cp != NULL) { mp_color_model(cp) = mp_grey_model; set_number_to_zero(mp_cyan_color(cp)); set_number_to_zero(mp_magenta_color(cp)); set_number_to_zero(mp_yellow_color(cp)); set_color_val(mp_grey_color(cp), cur_exp_value_number); } mp_flush_cur_exp(mp, new_expr); } break; case mp_with_no_model_code: if (cp == MP_VOID) { make_cp_a_colored_object(cp, p); } if (cp != NULL) { mp_color_model(cp) = mp_no_model; set_number_to_zero(mp_cyan_color(cp)); set_number_to_zero(mp_magenta_color(cp)); set_number_to_zero(mp_yellow_color(cp)); set_number_to_zero(mp_grey_color(cp)); } break; case mp_with_pen_code: if (mp->cur_exp.type != mp_pen_type && mp->cur_exp.type != mp_nep_type) { complain_invalid_with_list(mp, t); goto CONTINUE; } else { if (pp == MP_VOID) { pp = p; while (pp != NULL) { if (mp_has_pen(pp)) { break; } else { pp = pp->link; } } } if (pp != NULL) { switch (pp->type) { case mp_fill_node_type: case mp_stroked_node_type: if (mp_pen_ptr((mp_shape_node) pp) != NULL) { mp_toss_knot_list(mp, mp_pen_ptr((mp_shape_node) pp)); } mp_pen_ptr((mp_shape_node) pp) = cur_exp_knot; mp_pen_type((mp_shape_node) pp) = mp->cur_exp.type == mp_nep_type; break; default: break; } mp->cur_exp.type = mp_vacuous_type; } } break; case mp_with_pre_script_code: if (mp->cur_exp.type != mp_string_type) { complain_invalid_with_list(mp, t); goto CONTINUE; } else if (cur_exp_str->len) { if (ap == MP_VOID) { ap = p; } while ((ap != NULL) && (! mp_has_script(ap))) { ap = ap->link; } if (ap != NULL) { if (mp_pre_script(ap) != NULL) { int selector = mp->selector; mp_string s = mp_pre_script(ap); mp->selector = mp_new_string_selector; mp_str_room(mp, (int) (mp_pre_script(ap)->len + cur_exp_str->len + 2)); mp_print_mp_str(mp, cur_exp_str); mp_str_room(mp, 1); mp_append_char(mp, 13); mp_print_mp_str(mp, mp_pre_script(ap)); mp_pre_script(ap) = mp_make_string(mp); delete_str_ref(s); mp->selector = selector; } else { mp_pre_script(ap) = cur_exp_str; } add_str_ref(mp_pre_script(ap)); mp->cur_exp.type = mp_vacuous_type; } } break; case mp_with_post_script_code: if (mp->cur_exp.type != mp_string_type) { complain_invalid_with_list(mp, t); goto CONTINUE; } else if (cur_exp_str->len) { if (bp == MP_VOID) { bp = p; } while ((bp != NULL) && (! mp_has_script(bp))) { bp = bp->link; } if (bp != NULL) { if (mp_post_script(bp) != NULL) { int selector = mp->selector; mp_string s = mp_post_script(bp); mp->selector = mp_new_string_selector; mp_str_room(mp, (int) (mp_post_script(bp)->len + cur_exp_str->len + 2)); mp_print_mp_str(mp, mp_post_script(bp)); mp_str_room(mp, 1); mp_append_char(mp, 13); mp_print_mp_str(mp, cur_exp_str); mp_post_script(bp) = mp_make_string(mp); delete_str_ref(s); mp->selector = selector; } else { mp_post_script(bp) = cur_exp_str; } add_str_ref(mp_post_script(bp)); mp->cur_exp.type = mp_vacuous_type; } } break; case mp_with_stacking_code: switch (mp->cur_exp.type) { case mp_known_type: { if (sp == MP_VOID) { sp = p; } if (pp && spstop == MP_VOID) { spstop = pstop; } if (sp != NULL) { mp_stacking(sp) = round_unscaled(cur_exp_value_number); } if (pp && spstop != NULL) { mp_stacking(spstop) = round_unscaled(cur_exp_value_number); } mp->cur_exp.type = mp_vacuous_type; } break; case mp_pair_type: { if (pp && mp_nice_pair(mp, cur_exp_node, mp->cur_exp.type)) { if (sp == MP_VOID) { sp = p; } if (spstop == MP_VOID) { spstop = pstop; } if (sp != NULL) { mp_stacking(sp) = round_unscaled(mp_get_value_number(mp_x_part(mp_get_value_node(cur_exp_node)))); } if (spstop != NULL) { mp_stacking(spstop) = round_unscaled(mp_get_value_number(mp_y_part(mp_get_value_node(cur_exp_node)))); } mp->cur_exp.type = mp_vacuous_type; } else { complain_invalid_with_list(mp, t); goto CONTINUE; } } break; default: { complain_invalid_with_list(mp, t); goto CONTINUE; } } break; case mp_with_linecap_code: switch (mp->cur_exp.type) { case mp_known_type: { linecap = round_unscaled(cur_exp_value_number); mp->cur_exp.type = mp_vacuous_type; break; } default: { complain_invalid_with_list(mp, t); goto CONTINUE; } } break; case mp_with_linejoin_code: switch (mp->cur_exp.type) { case mp_known_type: { linejoin = round_unscaled(cur_exp_value_number); mp->cur_exp.type = mp_vacuous_type; break; } default: { complain_invalid_with_list(mp, t); goto CONTINUE; } } break; case mp_with_miterlimit_code: switch (mp->cur_exp.type) { case mp_known_type: { miterlimit = 1; new_number_clone(ml, cur_exp_value_number); mp->cur_exp.type = mp_vacuous_type; break; } default: { complain_invalid_with_list(mp, t); goto CONTINUE; } } break; case mp_with_dashed_code: if (mp->cur_exp.type != mp_picture_type) { complain_invalid_with_list(mp, t); goto CONTINUE; } // fall through default: if (dp == MP_VOID) { dp = p; while (dp != NULL) { if (dp->type == mp_stroked_node_type) { break; } else { dp = dp->link; } } } if (dp != NULL) { if (mp_dash_ptr(dp) != NULL) { mp_delete_edge_ref(mp, mp_dash_ptr(dp)); } mp_dash_ptr(dp) = (mp_node) mp_make_dashes(mp, (mp_edge_header_node) cur_exp_node); set_number_to_unity(((mp_shape_node) dp)->dashscale); mp->cur_exp.type = mp_vacuous_type; } break; } } if (cp > MP_VOID) { mp_node q = cp->link; while (q != NULL) { if (mp_has_color(q)) { mp_shape_node q0 = (mp_shape_node) q; mp_shape_node cp0 = (mp_shape_node) cp; number_clone(q0->red, cp0->red); number_clone(q0->green, cp0->green); number_clone(q0->blue, cp0->blue); number_clone(q0->black, cp0->black); mp_color_model(q) = mp_color_model(cp); } q = q->link; } } if (pp > MP_VOID) { mp_node q = pp->link; while (q != NULL) { if (mp_has_pen(q)) { switch (q->type) { case mp_fill_node_type: case mp_stroked_node_type: if (mp_pen_ptr((mp_shape_node) q) != NULL) { mp_toss_knot_list(mp, mp_pen_ptr((mp_shape_node) q)); } mp_pen_ptr((mp_shape_node) q) = mp_copy_pen(mp, mp_pen_ptr((mp_shape_node) pp)); break; default: break; } } q = q->link; } } if (dp > MP_VOID) { mp_node q = dp->link; while (q != NULL) { if (q->type == mp_stroked_node_type) { if (mp_dash_ptr(q) != NULL) { mp_delete_edge_ref(mp, mp_dash_ptr(q)); } mp_dash_ptr(q) = mp_dash_ptr(dp); set_number_to_unity(((mp_shape_node) q)->dashscale); if (mp_dash_ptr(q) != NULL) { mp_add_edge_ref(mp, mp_dash_ptr(q)); } } q = q->link; } } if (linecap >= 0 && linecap < mp_weird_linecap_code) { mp_node q = p; while (q != NULL) { switch (q->type) { case mp_fill_node_type: case mp_stroked_node_type: mp_set_linecap(q, linecap); break; default: break; } q = q->link; } } if (linejoin >= 0 && linejoin < mp_weird_linejoin_code) { mp_node q = p; while (q != NULL) { switch (q->type) { case mp_fill_node_type: case mp_stroked_node_type: mp_set_linejoin(q, linejoin); break; default: break; } q = q->link; } } if (miterlimit) { mp_node q = p; while (q != NULL) { switch (q->type) { case mp_fill_node_type: case mp_stroked_node_type: number_clone(mp_miterlimit(q), ml); break; default: break; } q = q->link; } free_number(ml); } if (! pp && sp > MP_VOID) { mp_node q = sp->link; while (q != NULL) { mp_stacking(q) = mp_stacking(sp); q = q->link; } } } mp_edge_header_node mp_find_edges_var (MP mp, mp_node t) { mp_edge_header_node cur_edges = NULL; mp_node p = mp_find_variable(mp, t); if (p == NULL) { char *msg = mp_obliterated(mp, t); mp_back_error( mp, msg, "It seems you did a nasty thing --- probably by accident, but nevertheless you\n" "nearly hornswoggled me ... While I was evaluating the right-hand side of thisn" "command, something happened, and the left-hand side is no longer a variable! So In" "won't change anything." ); mp_memory_free(msg); mp_get_x_next(mp); } else if (p->type != mp_picture_type) { char msg[256]; mp_string sname; int selector = mp->selector; mp->selector = mp_new_string_selector; mp_show_token_list(mp, t, NULL); sname = mp_make_string(mp); mp->selector = selector; mp_snprintf(msg, 256, "Variable %s is the wrong type(%s)", mp_str(mp, sname), mp_type_string(p->type)); delete_str_ref(sname); mp_back_error( mp, msg, "I was looking for a 'known' picture variable. So I'll not change anything just\n" "now." ); mp_get_x_next(mp); } else { mp_set_value_node(p, (mp_node) mp_private_edges(mp, (mp_edge_header_node) mp_get_value_node(p))); cur_edges = (mp_edge_header_node) mp_get_value_node(p); } mp_flush_node_list(mp, t); return cur_edges; } mp_node mp_start_draw_cmd (MP mp, int sep) { mp_node lhv = NULL; int add_type = 0; mp_get_x_next(mp); mp->var_flag = sep; mp_scan_primary(mp); if (mp->cur_exp.type != mp_token_list_type) { mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); mp_disp_err(mp, NULL); mp_back_error( mp, "Not a suitable variable", "At this point I needed to see the name of a picture variable. (Or perhaps you\n" "have indeed presented me with one; I might have missed it, if it wasn't followed\n" "by the proper token.) So I'll not change anything just now.\n" ); mp_get_x_next(mp); mp_flush_cur_exp(mp, new_expr); } else { lhv = cur_exp_node; add_type = (int) cur_mod; mp->cur_exp.type = mp_vacuous_type; mp_get_x_next(mp); mp_scan_expression(mp); } mp->last_add_type = add_type; return lhv; } void mp_do_bounds (MP mp) { mp_edge_header_node lhe; int c = cur_cmd; int m = cur_mod; mp_node lhv = mp_start_draw_cmd(mp, mp_to_command); if (lhv != NULL) { mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); lhe = mp_find_edges_var(mp, lhv); if (lhe == NULL) { new_number(new_expr.data.n); mp_flush_cur_exp(mp, new_expr); } else if (mp->cur_exp.type != mp_path_type) { char msg[256]; mp_disp_err(mp, NULL); new_number(new_expr.data.n); mp_snprintf(msg, 256, "Improper '%s'", mp_cmd_mod_string(mp, c, m)); mp_back_error( mp, msg, "This expression should have specified a known path. So I'll not change anything\n" "just now." ); mp_get_x_next(mp); mp_flush_cur_exp(mp, new_expr); } else if (mp_left_type(cur_exp_knot) == mp_endpoint_knot) { mp_back_error( mp, "Not a cycle", "That contour should have ended with '..cycle' or '&cycle'. So I'll not change\n" "anything just now." ); mp_get_x_next(mp); } else { mp_node p = mp_new_bounds_node(mp, cur_exp_knot, (int) m); mp_node pp; int mm = 0; switch (m) { case mp_start_clip_node_type : mm = mp_stop_clip_node_type; break; case mp_start_group_node_type : mm = mp_stop_group_node_type; break; case mp_start_bounds_node_type: mm = mp_stop_bounds_node_type; break; } pp = mp_new_bounds_node(mp, NULL, mm); mp_scan_with_list(mp, p, pp); p->link = mp_edge_list(lhe)->link; mp_edge_list(lhe)->link = p; if (mp_obj_tail(lhe) == mp_edge_list(lhe)) { mp_obj_tail(lhe) = p; } mp_obj_tail(lhe)->link = pp; mp_obj_tail(lhe) = pp; mp_init_bbox(mp, lhe); } } } void mp_do_add_to (MP mp) { mp_node lhv = mp_start_draw_cmd(mp, mp_thing_to_add_command); if (lhv != NULL) { mp_edge_header_node lhe; mp_node p; mp_edge_header_node e; int add_type = mp->last_add_type; if (add_type == mp_add_also_code) { p = NULL; e = NULL; if (mp->cur_exp.type != mp_picture_type) { mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); mp_disp_err(mp, NULL); mp_back_error( mp, "Improper 'addto'", "This expression should have specified a known picture. So I'll not change\n" "anything just now." ); mp_get_x_next(mp); mp_flush_cur_exp(mp, new_expr); } else { e = mp_private_edges(mp, (mp_edge_header_node) cur_exp_node); mp->cur_exp.type = mp_vacuous_type; p = mp_edge_list(e)->link; } } else { e = NULL; p = NULL; if (mp->cur_exp.type == mp_pair_type) { mp_pair_to_path(mp); } if (mp->cur_exp.type != mp_path_type) { mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); mp_disp_err(mp, NULL); mp_back_error( mp, "Improper 'addto'", "This expression should have specified a known path. So I'll not change anything\n" "just now." ); mp_get_x_next(mp); mp_flush_cur_exp(mp, new_expr); } else if (add_type != mp_add_contour_code) { p = mp_new_shape_node(mp, cur_exp_knot, mp_stroked_node_type); mp->cur_exp.type = mp_vacuous_type; } else if (mp_left_type(cur_exp_knot) == mp_endpoint_knot) { mp_back_error( mp, "Not a cycle", "That contour should have ended with '.. cycle' or '& cycle'. So I'll not change\n" "anything just now." ); mp_get_x_next(mp); } else { p = mp_new_shape_node(mp, cur_exp_knot, mp_fill_node_type); mp->cur_exp.type = mp_vacuous_type; } } mp_scan_with_list(mp, p, NULL); lhe = mp_find_edges_var(mp, lhv); if (lhe == NULL) { if ((e == NULL) && (p != NULL)) { e = mp_toss_gr_object(mp, p); } if (e != NULL) { mp_delete_edge_ref(mp, e); } } else if (add_type == mp_add_also_code) { if (e != NULL) { if (mp_edge_list(e)->link != NULL) { mp_obj_tail(lhe)->link = mp_edge_list(e)->link; mp_obj_tail(lhe) = mp_obj_tail(e); mp_obj_tail(e) = mp_edge_list(e); mp_edge_list(e)->link = NULL; mp_flush_dash_list(mp, lhe); } mp_toss_edges(mp, e); } } else if (p != NULL) { mp_obj_tail(lhe)->link = p; mp_obj_tail(lhe) = p; if (add_type == mp_add_double_path_code) { if (mp_pen_ptr((mp_shape_node) p) == NULL) { mp_pen_ptr((mp_shape_node) p) = mp_get_pen_circle(mp, &zero_t); } } } } } void mp_do_ship_out (MP mp) { mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); mp_get_x_next(mp); mp_scan_expression(mp); if (mp->cur_exp.type != mp_picture_type) { mp_disp_err(mp, NULL); set_number_to_zero(new_expr.data.n); mp_back_error(mp, "Not a known picture", "I can only output known pictures."); mp_get_x_next(mp); mp_flush_cur_exp(mp, new_expr); } else { mp_ship_out(mp, cur_exp_node); set_number_to_zero(new_expr.data.n); mp_flush_cur_exp(mp, new_expr); } } void mp_do_message (MP mp) { mp_value new_expr; int m = cur_mod; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); mp_get_x_next(mp); mp_scan_expression(mp); if (mp->cur_exp.type != mp_string_type) { mp_no_string_err(mp, "A message should be a known string expression."); } else { switch (m) { case message_code: mp_print_nl(mp, ""); mp_print_mp_str(mp, cur_exp_str); break; case err_message_code: { char msg[256]; mp_snprintf(msg, 256, "%s", mp_str(mp, cur_exp_str)); if (mp->err_help != NULL) { mp->use_err_help = 1; mp_back_error(mp, msg, NULL); } else if (mp->long_help_seen) { mp_back_error(mp, msg, "(That was another 'errmessage'.)"); } else { if (mp->interaction < mp_error_stop_mode) { mp->long_help_seen = 1; } mp_back_error( mp, msg, "This error message was generated by an 'errmessage' command, so I can't give any\n" "explicit help. Pretend that you're Miss Marple: Examine all clues, and deduce the\n" "truth by inspired guesses." ); } mp_get_x_next(mp); mp->use_err_help = 0; } break; case err_help_code: { if (mp->err_help != NULL) { delete_str_ref(mp->err_help); } if (cur_exp_str->len == 0) { mp->err_help = NULL; } else { mp->err_help = cur_exp_str; add_str_ref(mp->err_help); } } break; } } set_number_to_zero(new_expr.data.n); mp_flush_cur_exp(mp, new_expr); } static void mp_no_string_err (MP mp, const char *s) { mp_disp_err(mp, NULL); mp_back_error(mp, "Not a string", s); mp_get_x_next(mp); } void mp_do_write (MP mp) { mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); mp_get_x_next(mp); mp_scan_expression(mp); if (mp->cur_exp.type != mp_string_type) { mp_no_string_err(mp, "The text to be written should be a known string expression"); } else if (cur_cmd != mp_to_command) { mp_back_error(mp, "Missing 'to' clause", "A write command should end with 'to '"); mp_get_x_next(mp); } else { mp_string t = cur_exp_str; mp->cur_exp.type = mp_vacuous_type; mp_get_x_next(mp); mp_scan_expression(mp); if (mp->cur_exp.type != mp_string_type) { mp_no_string_err(mp, "I can\'t write to that file name. It isn't a known string"); } else { mp_do_write_string(mp, t); } } set_number_to_zero(new_expr.data.n); mp_flush_cur_exp(mp, new_expr); } static void mp_do_write_string (MP mp, mp_string t) { char *fn = mp_str(mp, cur_exp_str); int n = mp->write_files; int n0 = mp->write_files; while (mp_strcmp(fn, mp->wr_fname[n]) != 0) { if (n == 0) { if (n0 == mp->write_files) { if (mp->write_files < mp->max_write_files) { ++mp->write_files; } else { int l = mp->max_write_files + (mp->max_write_files / 4); void **wr_file = mp_memory_allocate((size_t) (l + 1) * sizeof(void *)); char **wr_fname = mp_memory_allocate((size_t) (l + 1) * sizeof(char *)); for (int k = 0; k <= l; k++) { if (k <= mp->max_write_files) { wr_file[k] = mp->wr_file[k]; wr_fname[k] = mp->wr_fname[k]; } else { wr_file[k] = 0; wr_fname[k] = NULL; } } mp_memory_free(mp->wr_file); mp_memory_free(mp->wr_fname); mp->max_write_files = l; mp->wr_file = wr_file; mp->wr_fname = wr_fname; } } n = n0; mp_open_write_file(mp, fn, n); } else { --n; if (mp->wr_fname[n] == NULL) { n0 = n; } } } if (mp_str_vs_str(mp, t, mp->eof_line) == 0) { (mp->close_file)(mp, mp->wr_file[n]); mp_memory_free(mp->wr_fname[n]); mp->wr_fname[n] = NULL; if (n == mp->write_files - 1) { mp->write_files = n; } } else { int selector = mp->selector; mp->selector = n + mp_first_file_selector; mp_print_mp_str(mp, t); mp_print_ln(mp); mp->selector = selector; } } struct mp_edge_object *mp_gr_export (MP mp, mp_edge_header_node h) { mp_node p; mp_edge_object *hh = mp_memory_allocate(sizeof(mp_edge_object)); mp_graphic_object *hp = NULL; mp_set_bbox(mp, h, 1); hh->parent = mp; hh->body = NULL; hh->next = NULL; hh->minx = number_to_double(h->minx); hh->minx = fabs(hh->minx) < 0.00001 ? 0 : hh->minx; hh->miny = number_to_double(h->miny); hh->miny = fabs(hh->miny) < 0.00001 ? 0 : hh->miny; hh->maxx = number_to_double(h->maxx); hh->maxx = fabs(hh->maxx) < 0.00001 ? 0 : hh->maxx; hh->maxy = number_to_double(h->maxy); hh->maxy = fabs(hh->maxy) < 0.00001 ? 0 : hh->maxy; hh->charcode = round_unscaled(internal_value(mp_char_code_internal)); hh->width = number_to_double(internal_value(mp_char_wd_internal)); hh->height = number_to_double(internal_value(mp_char_ht_internal)); hh->depth = number_to_double(internal_value(mp_char_dp_internal)); hh->italic = number_to_double(internal_value(mp_char_ic_internal)); p = mp_edge_list(h)->link; while (p != NULL) { mp_graphic_object *hq = mp_new_graphic_object(mp, (int) ((p->type - mp_fill_node_type) + 1)); switch (p->type) { case mp_fill_node_type: { mp_number d_width; mp_shape_node p0 = (mp_shape_node) p; mp_shape_object *tf = (mp_shape_object *) hq; gr_pen_ptr(tf) = mp_export_knot_list(mp, mp_pen_ptr(p0)); new_number(d_width); mp_get_pen_scale(mp, &d_width, mp_pen_ptr(p0)); free_number(d_width); if ((mp_pen_ptr(p0) == NULL) || mp_pen_is_elliptical(mp_pen_ptr(p0))) { gr_path_ptr(tf) = mp_export_knot_list(mp, mp_path_ptr(p0)); } else { mp_knot pc = mp_copy_path(mp, mp_path_ptr(p0)); mp_knot pp = mp_make_envelope(mp, pc, mp_pen_ptr(p0), p0->linejoin, 0, &(p0->miterlimit)); gr_path_ptr(tf) = mp_export_knot_list(mp, pp); mp_toss_knot_list(mp, pp); pc = mp_htap_ypoc(mp, mp_path_ptr(p0)); pp = mp_make_envelope(mp, pc, mp_pen_ptr((mp_shape_node) p), p0->linejoin, 0, &(p0->miterlimit)); gr_htap_ptr(tf) = mp_export_knot_list(mp, pp); mp_toss_knot_list(mp, pp); } mp_gr_export_color(tf, p0); mp_gr_export_scripts(tf, p); gr_linejoin_val(tf) = p0->linejoin; gr_stacking_val(tf) = p0->stacking; gr_miterlimit_val(tf) = number_to_double(p0->miterlimit); } break; case mp_stroked_node_type: { mp_number d_width; mp_shape_node p0 = (mp_shape_node) p; mp_shape_object *ts = (mp_shape_object *) hq; gr_pen_ptr(ts) = mp_export_knot_list(mp, mp_pen_ptr(p0)); new_number(d_width); mp_get_pen_scale(mp, &d_width, mp_pen_ptr(p0)); if (mp_pen_is_elliptical(mp_pen_ptr(p0))) { gr_path_ptr(ts) = mp_export_knot_list(mp, mp_path_ptr(p0)); } else { mp_knot pc = mp_copy_path(mp, mp_path_ptr(p0)); int t = p0->linecap; if (mp_left_type(pc) != mp_endpoint_knot) { mp_left_type(mp_insert_knot(mp, pc, &(pc->x_coord), &(pc->y_coord))) = mp_endpoint_knot; mp_right_type(pc) = mp_endpoint_knot; pc = mp_next_knot(pc); t = 1; } pc = mp_make_envelope(mp, pc, mp_pen_ptr(p0), p0->linejoin, (int) t, &(p0->miterlimit)); gr_path_ptr(ts) = mp_export_knot_list(mp, pc); mp_toss_knot_list(mp, pc); } mp_gr_export_color(ts, p0); mp_gr_export_scripts(ts, p); gr_linejoin_val(ts) = p0->linejoin; gr_miterlimit_val(ts) = number_to_double(p0->miterlimit); gr_linecap_val(ts) = p0->linecap; gr_stacking_val(ts) = p0->stacking; gr_dash_ptr(ts) = mp_export_dashes(mp, p0, &d_width); free_number(d_width); } break; case mp_start_clip_node_type: case mp_start_group_node_type: case mp_start_bounds_node_type: { mp_start_node p0 = (mp_start_node) p; mp_start_object *tb = (mp_start_object *) hq; gr_path_ptr(tb) = mp_export_knot_list(mp, mp_path_ptr((mp_start_node) p)); gr_stacking_val(tb) = p0->stacking; mp_gr_export_scripts(tb, p); } break; case mp_stop_clip_node_type: case mp_stop_group_node_type: case mp_stop_bounds_node_type: { mp_stop_node p0 = (mp_stop_node) p; mp_stop_object *tb = (mp_stop_object *) hq; gr_stacking_val(tb) = p0->stacking; } break; default: break; } if (hh->body == NULL) { hh->body = hq; } else { gr_link(hp) = hq; } hp = hq; p = p->link; } return hh; } static void mp_do_gr_toss_dashes (mp_dash_object *dl) { if (dl) { mp_memory_free(dl->array); mp_memory_free(dl); } } static void mp_do_gr_toss_knot_list (mp_gr_knot p) { if (p) { mp_gr_knot q = p; do { mp_gr_knot r = gr_next_knot(q); mp_memory_free(q); q = r; } while (q != p); } } mp_graphic_object *mp_new_graphic_object (MP mp, int type) { mp_graphic_object *p; size_t size; (void) mp; switch (type) { case mp_fill_code: case mp_stroked_code: size = sizeof(mp_shape_object); break; case mp_start_clip_code: case mp_start_group_code: case mp_start_bounds_code: size = sizeof(mp_start_object); break; default: size = sizeof(mp_graphic_object); break; } p = (mp_graphic_object *) mp_memory_allocate(size); memset(p, 0, size); gr_type(p) = type; return p; } void mp_gr_toss_object (mp_graphic_object *p) { switch (gr_type(p)) { case mp_fill_code: case mp_stroked_code: { mp_shape_object *o = (mp_shape_object *) p; mp_memory_free(gr_pre_script(o)); mp_memory_free(gr_post_script(o)); mp_do_gr_toss_knot_list(gr_pen_ptr(o)); mp_do_gr_toss_knot_list(gr_path_ptr(o)); if (gr_htap_ptr(o)) { mp_do_gr_toss_knot_list(gr_htap_ptr(o)); } if (gr_dash_ptr(o)) { mp_do_gr_toss_dashes(gr_dash_ptr(o)); } } break; case mp_start_clip_code: case mp_start_group_code: case mp_start_bounds_code: { mp_start_object *o = (mp_start_object *) p; mp_memory_free(gr_pre_script(o)); mp_memory_free(gr_post_script(o)); mp_do_gr_toss_knot_list(gr_path_ptr(o)); } break; case mp_stop_clip_code: case mp_stop_group_code: case mp_stop_bounds_code: break; } mp_memory_free(p); } void mp_gr_toss_objects (mp_edge_object *hh) { mp_graphic_object *p = hh->body; while (p) { mp_graphic_object *q = gr_link(p); mp_gr_toss_object(p); p = q; } mp_memory_free(hh); } void mp_ship_out (MP mp, mp_node h) { (mp->shipout_backend)(mp, h); } static void mp_shipout_backend (MP mp, void *voidh) { (void) mp; (void) voidh; } void mp_scan_symbol_value (MP mp, int keep, char **s, int expand) { if (mp->extensions) { if (expand) { mp_get_x_next(mp); } else { mp_get_next(mp); } if (keep) { mp_back_input(mp); } if (cur_sym == NULL && (cur_sym_mod == 0 || cur_sym_mod == mp_normal_operation)) { *s = NULL; } else { unsigned char *r = NULL; mp_node p = mp_new_symbolic_node(mp); mp_set_sym_sym(p, cur_sym); p->name_type = cur_sym_mod; if (p->type == mp_symbol_node_type) { mp_sym sr = mp_get_sym_sym(p); mp_string rr = text(sr); if (rr && rr->str) { r = rr->str; } } else if (p->name_type == mp_token_operation) { if (p->type == mp_string_type) { r = mp_get_value_str(p)->str; } } mp_free_symbolic_node(mp, p); if (r) { *s = (char *) mp_strdup((char *) r); } else { *s = NULL; } } } } void mp_scan_property_value (MP mp, int keep, int *kind, char **str, int *property, int *detail) { if (mp->extensions) { mp_symbol_entry *entry; mp_get_symbol(mp); entry = cur_sym; if (entry) { mp_node node = entry->type == mp_tag_command ? entry->v.data.node : NULL; *kind = entry->type; *str = (char *) mp_strdup((char *) entry->text->str); *property = entry->property; if (node) { *detail = node->type; } if (keep) { mp_back_input(mp); } } } } void mp_scan_next_value (MP mp, int keep, int *token, int *mode, int *kind) { if (mp->extensions) { mp_get_next(mp); if (keep) { mp_back_input(mp); } *token = cur_cmd; *mode = cur_mod; *kind = mp->cur_exp.type; } } void mp_scan_expr_value (MP mp, int keep, int *kind) { if (mp->extensions) { mp_get_next(mp); mp_scan_primary(mp); *kind = mp->cur_exp.type; if (keep) { mp_back_input(mp); mp_back_expr(mp); } } } void mp_scan_token_value (MP mp, int keep, int *token, int *mode, int *kind) { if (mp->extensions) { mp_get_x_next(mp); if (keep) { mp_back_input(mp); } *token = cur_cmd; *mode = cur_mod; *kind = mp->cur_exp.type; } } int mp_skip_token_value (MP mp, int token) { if (mp->extensions) { mp_get_x_next(mp); if (token == cur_cmd) { return 1; } else { mp_back_input(mp); } } return 0; } static void mp_scan_something (MP mp, int primary) { mp_get_x_next(mp); switch (primary) { case 0: mp_scan_expression(mp); break; case 1: mp_scan_primary(mp); break; case 2: mp_scan_secondary(mp); break; case 3: mp_scan_tertiary(mp); break; default: mp_scan_expression(mp); break; } } void mp_scan_numeric_value (MP mp, int primary, double *d) { if (mp->extensions) { mp_scan_something(mp, primary); if (mp->cur_exp.type != mp_known_type) { mp_back_input(mp); } else { mp_back_input(mp); *d = number_to_double(cur_exp_value_number); } } } # define mp_set_double_value(mp,target,what) \ if (what->type == mp_known_type) { \ *target = number_to_double(mp_get_value_number(what)); \ } void mp_scan_pair_value (MP mp, int primary, double *x, double *y) { if (mp->extensions) { mp_scan_something(mp, primary); if (mp->cur_exp.type != mp_pair_type) { mp_back_input(mp); } else { mp_node p ; mp_back_input(mp); p = mp_get_value_node(cur_exp_node); mp_set_double_value(mp, x, mp_x_part(p)); mp_set_double_value(mp, y, mp_y_part(p)); } } } void mp_scan_color_value (MP mp, int primary, double *r, double *g, double *b) { if (mp->extensions) { mp_scan_something(mp, primary); if (mp->cur_exp.type != mp_color_type) { mp_back_input(mp); } else { mp_node p ; mp_back_input(mp); p = mp_get_value_node(cur_exp_node); mp_set_double_value(mp, r, mp_red_part(p)); mp_set_double_value(mp, g, mp_green_part(p)); mp_set_double_value(mp, b, mp_blue_part(p)); } } } void mp_scan_cmykcolor_value (MP mp, int primary, double *c, double *m, double *y, double *k) { if (mp->extensions) { mp_scan_something(mp, primary); if (mp->cur_exp.type != mp_cmykcolor_type) { mp_back_input(mp); } else { mp_node p ; mp_back_input(mp); p = mp_get_value_node(cur_exp_node); mp_set_double_value(mp, c, mp_cyan_part(p)); mp_set_double_value(mp, m, mp_magenta_part(p)); mp_set_double_value(mp, y, mp_yellow_part(p)); mp_set_double_value(mp, k, mp_black_part(p)); } } } void mp_scan_transform_value (MP mp, int primary, double *x, double *y, double *xx, double *xy, double *yx, double *yy) { if (mp->extensions) { mp_scan_something(mp, primary); if (mp->cur_exp.type != mp_transform_type) { mp_back_input(mp); } else { mp_node p ; mp_back_input(mp); p = mp_get_value_node(cur_exp_node); mp_set_double_value(mp, x, mp_x_part(p)); mp_set_double_value(mp, y, mp_y_part(p)); mp_set_double_value(mp, xx, mp_xx_part(p)); mp_set_double_value(mp, xy, mp_xy_part(p)); mp_set_double_value(mp, yx, mp_yx_part(p)); mp_set_double_value(mp, yy, mp_yy_part(p)); } } } void mp_scan_path_value (MP mp, int primary, mp_knot *k) { if (mp->extensions) { mp_scan_something(mp, primary); if (mp->cur_exp.type != mp_path_type && mp->cur_exp.type != mp_pen_type) { mp_back_input(mp); } else { mp_back_input(mp); *k = cur_exp_knot; } } } void mp_scan_boolean_value (MP mp, int primary, int *b) { if (mp->extensions) { mp_scan_something(mp, primary); if (mp->cur_exp.type != mp_boolean_type) { mp_back_input(mp); } else { mp_back_input(mp); *b = cur_exp_value_boolean == mp_true_operation ? 1 : 0 ; } } } void mp_scan_string_value (MP mp, int primary, char **s, size_t *l) { if (mp->extensions) { mp_scan_something(mp, primary); if (mp->cur_exp.type != mp_string_type) { mp_back_input(mp); *s = NULL ; *l = 0; } else { mp_back_input(mp); *s = (char *) cur_exp_str->str ; *l = cur_exp_str->len; } } } void mp_push_numeric_value (MP mp, double n) { mp_number m; new_number_from_double(mp, m, n); mp->cur_exp.type = mp_known_type; mp_set_cur_exp_value_number(mp, &m); mp_back_expr(mp); } void mp_push_integer_value (MP mp, int i) { mp_number m; new_number(m); set_number_from_int(m, i); mp->cur_exp.type = mp_known_type; mp_set_cur_exp_value_number(mp, &m); mp_back_expr(mp); } void mp_push_boolean_value (MP mp, int b) { mp->cur_exp.type = mp_boolean_type; mp_set_cur_exp_value_boolean(mp, b ? mp_true_operation : mp_false_operation); mp_back_expr(mp); } void mp_push_string_value (MP mp, const char *s, int l) { mp->cur_exp.type = mp_string_type; mp_set_cur_exp_str(mp, mp_rtsl(mp, (char *) s, l)); mp_back_expr(mp); } void mp_push_pair_value (MP mp, double x, double y) { mp_number px, py; mp_node p = mp_new_value_node(mp); mp_node v; mp_init_pair_node(mp, p); v = mp_get_value_node(p); new_number_from_double(mp, px, x); new_number_from_double(mp, py, y); mp_x_part(v)->type = mp_known_type; mp_y_part(v)->type = mp_known_type; mp_set_value_number(mp_x_part(v), px); mp_set_value_number(mp_y_part(v), py); free_number(px); free_number(py); p->name_type = mp_capsule_operation; mp->cur_exp.type = mp_pair_type; mp_set_cur_exp_node(mp, p); mp_back_expr(mp); } void mp_push_color_value (MP mp, double r, double g, double b) { mp_number pr, pg, pb; mp_node p = mp_new_value_node(mp); mp_node v; mp_init_color_node(mp, p, mp_color_type); v = mp_get_value_node(p); new_number_from_double(mp, pr, r); new_number_from_double(mp, pg, g); new_number_from_double(mp, pb, b); mp_red_part (v)->type = mp_known_type; mp_green_part(v)->type = mp_known_type; mp_blue_part (v)->type = mp_known_type; mp_set_value_number(mp_red_part (v), pr); mp_set_value_number(mp_green_part(v), pg); mp_set_value_number(mp_blue_part (v), pb); free_number(pr); free_number(pg); free_number(pb); p->name_type = mp_capsule_operation; mp->cur_exp.type = mp_color_type; mp_set_cur_exp_node(mp, p); mp_back_expr(mp); } void mp_push_cmykcolor_value (MP mp, double c, double m, double y, double k) { mp_number pc, pm, py, pk; mp_node p = mp_new_value_node(mp); mp_node v; mp_init_color_node(mp, p, mp_cmykcolor_type); v = mp_get_value_node(p); new_number_from_double(mp, pc, c); new_number_from_double(mp, pm, m); new_number_from_double(mp, py, y); new_number_from_double(mp, pk, k); mp_cyan_part (v)->type = mp_known_type; mp_magenta_part(v)->type = mp_known_type; mp_yellow_part (v)->type = mp_known_type; mp_black_part (v)->type = mp_known_type; mp_set_value_number(mp_cyan_part (v), pc); mp_set_value_number(mp_magenta_part(v), pm); mp_set_value_number(mp_yellow_part (v), py); mp_set_value_number(mp_black_part (v), pk); free_number(pc); free_number(pm); free_number(py); free_number(pk); p->name_type = mp_capsule_operation; mp->cur_exp.type = mp_cmykcolor_type; mp_set_cur_exp_node(mp, p); mp_back_expr(mp); } void mp_push_transform_value (MP mp, double x, double y, double xx, double xy, double yx, double yy) { mp_number px, py, pxx, pxy, pyx, pyy ; mp_node p = mp_new_value_node(mp); mp_node v; mp_init_transform_node(mp, p); v = mp_get_value_node(p); new_number_from_double(mp, px, x); new_number_from_double(mp, py, y); new_number_from_double(mp, pxx, xx); new_number_from_double(mp, pxy, xy); new_number_from_double(mp, pyx, yx); new_number_from_double(mp, pyy, yy); mp_x_part (v)->type = mp_known_type; mp_y_part (v)->type = mp_known_type; mp_xx_part(v)->type = mp_known_type; mp_xy_part(v)->type = mp_known_type; mp_yx_part(v)->type = mp_known_type; mp_yy_part(v)->type = mp_known_type; mp_set_value_number(mp_x_part (v), px); mp_set_value_number(mp_y_part (v), py); mp_set_value_number(mp_xx_part(v), pxx); mp_set_value_number(mp_xy_part(v), pxy); mp_set_value_number(mp_yx_part(v), pyx); mp_set_value_number(mp_yy_part(v), pyy); free_number(px); free_number(py); free_number(pxx); free_number(pxy); free_number(pyx); free_number(pyy); p->name_type = mp_capsule_operation; mp->cur_exp.type = mp_transform_type; mp_set_cur_exp_node(mp, p); mp_back_expr(mp); } void mp_push_path_value (MP mp, mp_knot k) { mp->cur_exp.type = mp_path_type; mp_set_cur_exp_knot(mp, k); mp_back_expr(mp); } static void check_for_mediation (MP mp); static void mp_primary_error(MP mp) { mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); mp_disp_err(mp, NULL); new_number(new_expr.data.n); mp_back_error( mp, "Nonnumeric part has been replaced by 0", "I've started to scan a pair (x,y), color (r,g,b), cmykcolor (c,m,y,k) or\n" "transform (tx,ty,xx,xy,yx,yy) but ran into a non-numeric type. I'll recover\n" "as good as possible." ); mp_get_x_next(mp); mp_flush_cur_exp(mp, new_expr); } void mp_scan_primary (MP mp) { mp_command_code my_var_flag = mp->var_flag; mp->var_flag = 0; RESTART: check_arith(); switch (cur_cmd) { case mp_left_delimiter_command: { mp_sym l_delim = cur_sym; mp_sym r_delim = equiv_sym(cur_sym); mp_get_x_next(mp); mp_scan_expression(mp); if ((cur_cmd == mp_comma_command) && (mp->cur_exp.type >= mp_known_type)) { mp_node q = mp_new_value_node(mp); mp_node p1 = mp_stash_cur_exp(mp); mp_node r; q->name_type = mp_capsule_operation; mp_get_x_next(mp); mp_scan_expression(mp); if (mp->cur_exp.type < mp_known_type) { mp_primary_error(mp); } if (cur_cmd != mp_comma_command) { mp_init_pair_node(mp, q); r = mp_get_value_node(q); mp_stash_in(mp, mp_y_part(r)); mp_unstash_cur_exp(mp, p1); mp_stash_in(mp, mp_x_part(r)); } else { mp_node p2 = mp_stash_cur_exp(mp); mp_get_x_next(mp); mp_scan_expression(mp); if (mp->cur_exp.type < mp_known_type) { mp_primary_error(mp); } if (cur_cmd != mp_comma_command) { mp_init_color_node(mp, q, mp_color_type); r = mp_get_value_node(q); mp_stash_in(mp, mp_blue_part(r)); mp_unstash_cur_exp(mp, p1); mp_stash_in(mp, mp_red_part(r)); mp_unstash_cur_exp(mp, p2); mp_stash_in(mp, mp_green_part(r)); } else { mp_node p3 = mp_stash_cur_exp(mp); mp_get_x_next(mp); mp_scan_expression(mp); if (mp->cur_exp.type < mp_known_type) { mp_primary_error(mp); } if (cur_cmd != mp_comma_command) { mp_init_color_node(mp, q, mp_cmykcolor_type); r = mp_get_value_node(q); mp_stash_in(mp, mp_black_part(r)); mp_unstash_cur_exp(mp, p1); mp_stash_in(mp, mp_cyan_part(r)); mp_unstash_cur_exp(mp, p2); mp_stash_in(mp, mp_magenta_part(r)); mp_unstash_cur_exp(mp, p3); mp_stash_in(mp, mp_yellow_part(r)); } else { mp_node p4 = mp_stash_cur_exp(mp); mp_node p5; mp_get_x_next(mp); mp_scan_expression(mp); if (mp->cur_exp.type < mp_known_type) { mp_primary_error(mp); p5 = mp_stash_cur_exp(mp); goto HERE; } if (cur_cmd != mp_comma_command) { mp_primary_error(mp); p5 = mp_stash_cur_exp(mp); goto HERE; } p5 = mp_stash_cur_exp(mp); mp_get_x_next(mp); mp_scan_expression(mp); if (mp->cur_exp.type < mp_known_type) { mp_primary_error(mp); } HERE: mp_init_transform_node(mp, q); r = mp_get_value_node(q); mp_stash_in(mp, mp_ty_part(r)); mp_unstash_cur_exp(mp, p5); mp_stash_in(mp, mp_tx_part(r)); mp_unstash_cur_exp(mp, p4); mp_stash_in(mp, mp_yy_part(r)); mp_unstash_cur_exp(mp, p3); mp_stash_in(mp, mp_yx_part(r)); mp_unstash_cur_exp(mp, p2); mp_stash_in(mp, mp_xy_part(r)); mp_unstash_cur_exp(mp, p1); mp_stash_in(mp, mp_xx_part(r)); } } } mp_check_delimiter(mp, l_delim, r_delim); mp->cur_exp.type = q->type; mp_set_cur_exp_node(mp, q); } else { mp_check_delimiter(mp, l_delim, r_delim); } } break; case mp_begin_group_command: { int group_line = mp_true_line(mp); if (number_positive(internal_value(mp_tracing_commands_internal))) { mp_show_cmd_mod(mp, cur_cmd, cur_mod); } mp_save_boundary(mp); do { mp_do_statement(mp); } while (cur_cmd == mp_semicolon_command); if (cur_cmd != mp_end_group_command) { char msg[256]; mp_snprintf(msg, 256, "A group begun on line %d never ended", (int) group_line); mp_back_error( mp, msg, "I saw a 'begingroup' back there that hasn't been matched by 'endgroup'. So I've\n" "inserted 'endgroup' now." ); set_cur_cmd(mp_end_group_command); } mp_unsave(mp); if (number_positive(internal_value(mp_tracing_commands_internal))) { mp_show_cmd_mod(mp, cur_cmd, cur_mod); } } break; case mp_string_command: mp->cur_exp.type = mp_string_type; mp_set_cur_exp_str(mp, cur_mod_str); break; case mp_numeric_command: { mp_number num, denom; mp_set_cur_exp_value_number(mp, &cur_mod_number); mp->cur_exp.type = mp_known_type; mp_get_x_next(mp); if (cur_cmd != mp_slash_command) { new_number(num); new_number(denom); } else { mp_get_x_next(mp); if (cur_cmd != mp_numeric_command) { mp_back_input(mp); set_cur_cmd(mp_slash_command); set_cur_mod(mp_over_operation); set_cur_sym(mp->frozen_slash); goto DONE; } else { new_number_clone(num, cur_exp_value_number); new_number_clone(denom, cur_mod_number); if (number_zero(denom)) { mp_error(mp, "Division by zero", "I'll pretend that you meant to divide by 1."); } else { mp_number ret; new_number(ret); make_scaled(ret, num, denom); mp_set_cur_exp_value_number(mp, &ret); free_number(ret); } check_arith(); mp_get_x_next(mp); } } if (cur_cmd >= mp_min_primary_command && cur_cmd < mp_numeric_command) { mp_number absnum, absdenom; mp_node p = mp_stash_cur_exp(mp); mp_scan_primary(mp); new_number_abs(absnum, num); new_number_abs(absdenom, denom); if (number_greaterequal(absnum, absdenom) || (mp->cur_exp.type < mp_color_type)) { mp_do_binary(mp, p, mp_times_operation); } else { mp_frac_mult(mp, &num, &denom); mp_free_value_node(mp, p); } free_number(absnum); free_number(absdenom); } free_number(num); free_number(denom); goto DONE; } case mp_nullary_command: mp_do_nullary(mp, (int) cur_mod); break; case mp_unary_command: case mp_type_name_command: case mp_cycle_command: case mp_plus_or_minus_command: { int c = (int) cur_mod; mp_get_x_next(mp); mp_scan_primary(mp); mp_do_unary(mp, c); goto DONE; } case mp_of_binary_command: { mp_node p; int c = (int) cur_mod; mp_get_x_next(mp); mp_scan_expression(mp); if (cur_cmd != mp_of_command) { char msg[256]; mp_string sname; int selector = mp->selector; mp->selector = mp_new_string_selector; mp_print_cmd_mod(mp, mp_of_binary_command, c); mp->selector = selector; sname = mp_make_string(mp); mp_snprintf(msg, 256, "Missing 'of' has been inserted for %s", mp_str(mp, sname)); delete_str_ref(sname); mp_back_error(mp, msg, "I've got the first argument; will look now for the other."); } p = mp_stash_cur_exp(mp); mp_get_x_next(mp); mp_scan_primary(mp); mp_do_binary(mp, p, c); goto DONE; } case mp_str_command: { int selector = mp->selector; mp_get_x_next(mp); mp_scan_suffix(mp); mp->selector = mp_new_string_selector; mp_show_token_list(mp, cur_exp_node, NULL); mp_flush_token_list(mp, cur_exp_node); mp_set_cur_exp_str(mp, mp_make_string(mp)); mp->selector = selector; mp->cur_exp.type = mp_string_type; goto DONE; } case mp_void_command: { mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); mp_get_x_next(mp); mp_scan_suffix(mp); if (cur_exp_node == NULL) { set_number_from_boolean(new_expr.data.n, mp_true_operation); } else { set_number_from_boolean(new_expr.data.n, mp_false_operation); } mp_flush_cur_exp(mp, new_expr); cur_exp_node = NULL; mp->cur_exp.type = mp_boolean_type; goto DONE; } case mp_internal_command: { int qq = cur_mod; if (my_var_flag == mp_assignment_command) { mp_get_x_next(mp); if (cur_cmd == mp_assignment_command) { mp_set_cur_exp_node(mp, mp_new_symbolic_node(mp)); mp_set_sym_info(cur_exp_node, qq); cur_exp_node->name_type = mp_internal_operation; mp->cur_exp.type = mp_token_list_type; goto DONE; } mp_back_input(mp); } if (internal_type(qq) == mp_string_type) { mp_set_cur_exp_str(mp, internal_string(qq)); } else { mp_set_cur_exp_value_number(mp, &(internal_value(qq))); } mp->cur_exp.type = internal_type(qq); } break; case mp_capsule_command: mp_make_exp_copy(mp, cur_mod_node); break; case mp_tag_command: { mp_node p = 0; mp_node q = 0; mp_node t = 0; mp_node macro_ref = 0; int tt = mp_vacuous_type; mp_node pre_head = mp_new_symbolic_node(mp); mp_node tail = pre_head; mp_node post_head = NULL; while (1) { t = mp_cur_tok(mp); tail->link = t; if (tt != mp_undefined_type) { mp_sym qq; p = pre_head->link; qq = mp_get_sym_sym(p); tt = mp_undefined_type; if (eq_type(qq) == mp_tag_command) { q = equiv_node(qq); if (q == NULL) { goto DONE2; } while (1) { p = p->link; if (p == NULL) { tt = q->type; goto DONE2; } if (q->type != mp_structured_type) { goto DONE2; } q = mp_get_attribute_head(q)->link; if (p->type == mp_symbol_node_type) { do { q = q->link; } while (! (mp_get_hashloc(q) >= mp_get_sym_sym(p))); if (mp_get_hashloc(q) > mp_get_sym_sym(p)) { goto DONE2; } } } } DONE2: if (tt >= mp_unsuffixed_macro_type) { tail->link = NULL; if (tt > mp_unsuffixed_macro_type) { post_head = mp_new_symbolic_node(mp); tail = post_head; tail->link = t; tt = mp_undefined_type; macro_ref = mp_get_value_node(q); mp_add_mac_ref(macro_ref); } else { p = mp_new_symbolic_node(mp); mp_set_sym_sym(pre_head, pre_head->link); pre_head->link = p; mp_set_sym_sym(p, t); mp_macro_call(mp, mp_get_value_node(q), pre_head, NULL); mp_get_x_next(mp); goto RESTART; } } } mp_get_x_next(mp); tail = t; if (cur_cmd == mp_left_bracket_command) { mp_get_x_next(mp); mp_scan_expression(mp); if (cur_cmd != mp_right_bracket_command) { mp_back_input(mp); mp_back_expr(mp); set_cur_cmd(mp_left_bracket_command); set_cur_mod_number(zero_t); set_cur_sym(mp->frozen_left_bracket); } else { if (mp->cur_exp.type != mp_known_type) { mp_bad_subscript(mp); } set_cur_cmd(mp_numeric_command); set_cur_mod_number(cur_exp_value_number); set_cur_sym(NULL); } } if (cur_cmd > mp_max_suffix_token) { break; } else if (cur_cmd < mp_min_suffix_token) { break; } } if (post_head != NULL) { mp_back_input(mp); p = mp_new_symbolic_node(mp); q = post_head->link; mp_set_sym_sym(pre_head, pre_head->link); pre_head->link = post_head; mp_set_sym_sym(post_head, q); post_head->link = p; mp_set_sym_sym(p, q->link); q->link = NULL; mp_macro_call(mp, macro_ref, pre_head, NULL); mp_decr_mac_ref(macro_ref); mp_get_x_next(mp); goto RESTART; } q = pre_head->link; mp_free_symbolic_node(mp, pre_head); if (cur_cmd == my_var_flag) { mp->cur_exp.type = mp_token_list_type; mp_set_cur_exp_node(mp, q); goto DONE; } p = mp_find_variable(mp, q); if (p != NULL) { mp_make_exp_copy(mp, p); } else { mp_value new_expr; char *msg = mp_obliterated (mp, q); memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); mp_back_error( mp, msg, "While I was evaluating the suffix of this variable, something was redefined, and\n" "it's no longer a variable! In order to get back on my feet, I've inserted '0'\n" "instead." ); mp_memory_free(msg); mp_get_x_next(mp); mp_flush_cur_exp(mp, new_expr); } mp_flush_node_list(mp, q); goto DONE; } break; default: mp_bad_exp(mp, "A primary"); goto RESTART; break; } mp_get_x_next(mp); DONE: check_for_mediation(mp); } static void check_for_mediation (MP mp) { if (cur_cmd == mp_left_bracket_command && mp->cur_exp.type >= mp_known_type) { mp_node p = mp_stash_cur_exp(mp); mp_get_x_next(mp); mp_scan_expression(mp); if (cur_cmd != mp_comma_command) { mp_back_input(mp); mp_back_expr(mp); set_cur_cmd(mp_left_bracket_command); set_cur_mod_number(zero_t); set_cur_sym(mp->frozen_left_bracket); mp_unstash_cur_exp(mp, p); } else { mp_node q = mp_stash_cur_exp(mp); mp_node r; mp_get_x_next(mp); mp_scan_expression(mp); if (cur_cmd != mp_right_bracket_command) { mp_back_error( mp, "Missing ']' has been inserted", "I've scanned an expression of the form 'a[b,c', so a right bracket should have\n" "come next. I shall pretend that one was there." ); } r = mp_stash_cur_exp(mp); mp_make_exp_copy(mp, q); mp_do_binary(mp, r, mp_minus_operation); mp_do_binary(mp, p, mp_times_operation); mp_do_binary(mp, q, mp_plus_operation); mp_get_x_next(mp); } } } static void mp_scan_suffix (MP mp) { mp_node h = mp_new_symbolic_node(mp); mp_node t = h; while (1) { mp_node p; if (cur_cmd == mp_left_bracket_command) { mp_get_x_next(mp); mp_scan_expression(mp); if (mp->cur_exp.type != mp_known_type) { mp_bad_subscript(mp); } if (cur_cmd != mp_right_bracket_command) { mp_back_error( mp, "Missing ']' has been inserted", "I've seen a '[' and a subscript value, in a suffix, so a right bracket should\n" "have come next. I shall pretend that one was there." ); } set_cur_cmd(mp_numeric_command); set_cur_mod_number(cur_exp_value_number); } if (cur_cmd == mp_numeric_command) { mp_number arg1; new_number_clone(arg1, cur_mod_number); p = mp_new_num_tok(mp, &arg1); free_number(arg1); } else if ((cur_cmd == mp_tag_command) || (cur_cmd == mp_internal_command)) { p = mp_new_symbolic_node(mp); mp_set_sym_sym(p, cur_sym); p->name_type = cur_sym_mod; } else { break; } t->link = p; t = p; mp_get_x_next(mp); } mp_set_cur_exp_node(mp, h->link); mp_free_symbolic_node(mp, h); mp->cur_exp.type = mp_token_list_type; } static void mp_scan_secondary (MP mp) { mp_node cc = NULL; mp_sym mac_name = NULL; RESTART: if ((cur_cmd < mp_min_primary_command) || (cur_cmd > mp_max_primary_command)) { mp_bad_exp(mp, "A secondary"); } mp_scan_primary(mp); CONTINUE: if (cur_cmd <= mp_max_secondary_command && cur_cmd >= mp_min_secondary_command) { mp_node p = mp_stash_cur_exp(mp); int d = cur_cmd; int c = cur_mod; if (d == mp_primary_def_command) { cc = cur_mod_node; mac_name = cur_sym; mp_add_mac_ref(cc); } mp_get_x_next(mp); mp_scan_primary(mp); if (d != mp_primary_def_command) { mp_do_binary(mp, p, c); } else { mp_back_input(mp); mp_binary_mac(mp, p, cc, mac_name); mp_decr_mac_ref(cc); mp_get_x_next(mp); goto RESTART; } goto CONTINUE; } } static void mp_scan_tertiary (MP mp) { mp_node cc = NULL; mp_sym mac_name = NULL; RESTART: if ((cur_cmd < mp_min_primary_command) || (cur_cmd > mp_max_primary_command)) { mp_bad_exp(mp, "A tertiary"); } mp_scan_secondary(mp); CONTINUE: if (cur_cmd <= mp_max_tertiary_command && cur_cmd >= mp_min_tertiary_command) { mp_node p = mp_stash_cur_exp(mp); int c = cur_mod; int d = cur_cmd; if (d == mp_secondary_def_command) { cc = cur_mod_node; mac_name = cur_sym; mp_add_mac_ref(cc); } mp_get_x_next(mp); mp_scan_secondary(mp); if (d != mp_secondary_def_command) { mp_do_binary(mp, p, c); } else { mp_back_input(mp); mp_binary_mac(mp, p, cc, mac_name); mp_decr_mac_ref(cc); mp_get_x_next(mp); goto RESTART; } goto CONTINUE; } } static int mp_scan_path (MP mp); static void mp_scan_expression (MP mp) { int my_var_flag = mp->var_flag; mp_check_expansion_depth(mp); RESTART: if ((cur_cmd < mp_min_primary_command) || (cur_cmd > mp_max_primary_command)) { mp_bad_exp(mp, "An"); } mp_scan_tertiary(mp); CONTINUE: if (cur_cmd <= mp_max_expression_command) { if (cur_cmd >= mp_min_expression_command) { if ((cur_cmd != mp_equals_command) || (my_var_flag != mp_assignment_command)) { mp_node cc = NULL; mp_sym mac_name; mac_name = NULL; mp_node p = mp_stash_cur_exp(mp); int d = cur_cmd; int c = cur_mod; if (d == mp_tertiary_def_command) { cc = cur_mod_node; mac_name = cur_sym; mp_add_mac_ref(cc); } if ((d < mp_ampersand_command) || ((d == mp_ampersand_command) && ((p->type == mp_pair_type) || (p->type == mp_path_type)))) { mp_unstash_cur_exp(mp, p); if (! mp_scan_path(mp)) { mp->expand_depth_count--; return; } } else { mp_get_x_next(mp); mp_scan_tertiary(mp); if (d != mp_tertiary_def_command) { mp_do_binary(mp, p, c); } else { mp_back_input(mp); mp_binary_mac(mp, p, cc, mac_name); mp_decr_mac_ref(cc); mp_get_x_next(mp); goto RESTART; } } goto CONTINUE; } } } mp->expand_depth_count--; } static void force_valid_tension_setting (MP mp) { if ((mp->cur_exp.type != mp_known_type) || number_less(cur_exp_value_number, min_tension)) { mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); mp_disp_err(mp, NULL); number_clone(new_expr.data.n, unity_t); mp_back_error( mp, "Improper tension has been set to 1", "The expression above should have been a number >= 3/4." ); mp_get_x_next(mp); mp_flush_cur_exp(mp, new_expr); } } static int mp_scan_path (MP mp) { mp_knot path_p, path_q, r; mp_knot pp = NULL; mp_knot qq = NULL; int d, dd; int cycle_hit = 0; mp_number x, y; int t = mp_endpoint_knot; if (mp->cur_exp.type == mp_pair_type) { path_p = mp_pair_to_knot(mp); } else if (mp->cur_exp.type == mp_path_type) { path_p = cur_exp_knot; } else { return 0; } path_q = path_p; while (mp_next_knot(path_q) != path_p) { path_q = mp_next_knot(path_q); } if (mp_left_type(path_p) != mp_endpoint_knot) { r = mp_copy_knot(mp, path_p); mp_prev_knot(r) = path_q; mp_next_knot(path_q) = r; path_q = r; } mp_left_type(path_p) = mp_open_knot; mp_right_type(path_q) = mp_open_knot; new_number(y); new_number(x); CONTINUE_PATH: if (cur_cmd == mp_left_brace_command) { t = mp_scan_direction(mp); if (t != mp_open_knot) { mp_right_type(path_q) = (unsigned char) t; number_clone(path_q->right_given, cur_exp_value_number); if (mp_left_type(path_q) == mp_open_knot) { mp_left_type(path_q) = (unsigned char) t; number_clone(path_q->left_given, cur_exp_value_number); } } } d = cur_cmd; dd = cur_mod; if (d == mp_path_join_command) { mp_get_x_next(mp); switch (cur_cmd) { case mp_tension_command: mp_get_x_next(mp); set_number_from_scaled(y, cur_cmd); if (cur_cmd == mp_at_least_command) { mp_get_x_next(mp); } mp_scan_primary(mp); force_valid_tension_setting(mp); if (number_to_scaled(y) == mp_at_least_command && is_number(cur_exp_value_number)) { number_negate(cur_exp_value_number); } number_clone(path_q->right_tension, cur_exp_value_number); if (cur_cmd == mp_and_command) { mp_get_x_next(mp); set_number_from_scaled(y, cur_cmd); if (cur_cmd == mp_at_least_command) { mp_get_x_next(mp); } mp_scan_primary(mp); force_valid_tension_setting(mp); if (number_to_scaled(y) == mp_at_least_command && is_number(cur_exp_value_number)) { number_negate(cur_exp_value_number); } } number_clone(y, cur_exp_value_number); break; case mp_controls_command: mp_right_type(path_q) = mp_explicit_knot; t = mp_explicit_knot; mp_get_x_next(mp); mp_scan_primary(mp); mp_known_pair(mp); number_clone(path_q->right_x, mp->cur_x); number_clone(path_q->right_y, mp->cur_y); if (cur_cmd != mp_and_command) { number_clone(x, path_q->right_x); number_clone(y, path_q->right_y); } else { mp_get_x_next(mp); mp_scan_primary(mp); mp_known_pair(mp); number_clone(x, mp->cur_x); number_clone(y, mp->cur_y); } break; default: set_number_to_unity(path_q->right_tension); set_number_to_unity(y); mp_back_input(mp); goto DONE; break; } if (cur_cmd != mp_path_join_command) { mp_back_error( mp, "Missing '..' has been inserted", "A path join command should end with two dots." ); } DONE: ; } else if (d != mp_ampersand_command) { goto FINISH_PATH; } mp_get_x_next(mp); if (cur_cmd == mp_left_brace_command) { t = mp_scan_direction(mp); if (mp_right_type(path_q) != mp_explicit_knot) { number_clone(x, cur_exp_value_number); } else { t = mp_explicit_knot; } } else if (mp_right_type(path_q) != mp_explicit_knot) { t = mp_open_knot; set_number_to_zero(x); } if (cur_cmd == mp_cycle_command) { if (cur_mod == mp_cycle_operation) { cycle_hit = 1; mp_get_x_next(mp); pp = path_p; qq = path_p; if (d == mp_ampersand_command && path_p == path_q) { d = mp_path_join_command; set_number_to_unity(path_q->right_tension); set_number_to_unity(y); } } else { mp_get_x_next(mp); qq = pp; goto FINISH_PATH; } } else { mp_scan_tertiary(mp); if (mp->cur_exp.type != mp_path_type) { pp = mp_pair_to_knot(mp); } else { pp = cur_exp_knot; } qq = pp; while (mp_next_knot(qq) != pp) { qq = mp_next_knot(qq); } if (mp_left_type(pp) != mp_endpoint_knot) { r = mp_copy_knot(mp, pp); mp_prev_knot(r) = qq; mp_next_knot(qq) = r; qq = r; } mp_left_type(pp) = mp_open_knot; mp_right_type(qq) = mp_open_knot; } if (d == mp_ampersand_command && dd != mp_just_append_operation && dd != mp_tolerant_concat_operation && dd != mp_tolerant_append_operation) { if (! (number_equal(path_q->x_coord, pp->x_coord)) || ! (number_equal(path_q->y_coord, pp->y_coord))) { mp_back_error( mp, "Paths don't touch; '&' will be changed to '..'", "When you join paths 'p & q', the ending point of p must be exactly equal to the\n" "starting point of q. So I'm going to pretend that you said 'p .. q' instead." ); mp_get_x_next(mp); d = mp_path_join_command; set_number_to_unity(path_q->right_tension); set_number_to_unity(y); } } if (mp_right_type(pp) == mp_open_knot && ((t == mp_curl_knot) || (t == mp_given_knot))) { mp_right_type(pp) = (unsigned char) t; number_clone(pp->right_given, x); } if (d == mp_ampersand_command) { if (dd == mp_tolerant_concat_operation || dd == mp_tolerant_append_operation) { mp_number dx, dy; set_number_from_subtraction(dx, path_q->x_coord, pp->x_coord); set_number_from_subtraction(dy, path_q->y_coord, pp->y_coord); number_abs(dx); number_abs(dy); if (number_lessequal(dx, epsilon_t) && number_lessequal(dy, epsilon_t)) { set_number_half_from_addition(dx, path_q->x_coord, pp->x_coord); set_number_half_from_addition(dy, path_q->y_coord, pp->y_coord); number_clone(pp->left_x, dx); number_clone(path_q->right_x, dx); number_clone(pp->left_y, dy); number_clone(path_q->right_y, dy); } dd = dd == mp_tolerant_concat_operation ? mp_concatenate_operation : mp_just_append_operation; } if (dd == mp_just_append_operation) { mp_left_type(pp) = mp_explicit_knot; mp_right_type(path_q) = mp_explicit_knot; mp_prev_knot(pp) = path_q; mp_next_knot(path_q) = pp; number_clone(pp->left_x, path_q->x_coord); number_clone(pp->left_y, path_q->y_coord); number_clone(path_q->right_x, pp->x_coord); number_clone(path_q->right_y, pp->y_coord); mp_knotstate(pp) = mp_begin_knot; mp_knotstate(path_q) = mp_end_knot; path_q = pp; } else { if (mp_left_type(path_q) == mp_open_knot && mp_right_type(path_q) == mp_open_knot) { mp_left_type(path_q) = mp_curl_knot; set_number_to_unity(path_q->left_curl); } if (mp_right_type(pp) == mp_open_knot && t == mp_open_knot) { mp_right_type(pp) = mp_curl_knot; set_number_to_unity(pp->right_curl); } mp_right_type(path_q) = mp_right_type(pp); mp_prev_knot(pp) = mp_next_knot(path_q); mp_next_knot(path_q) = mp_next_knot(pp); number_clone(path_q->right_x, pp->right_x); number_clone(path_q->right_y, pp->right_y); mp_memory_free(pp); } if (qq == pp) { qq = path_q; } } else { if (mp_right_type(path_q) == mp_open_knot && ((mp_left_type(path_q) == mp_curl_knot) || (mp_left_type(path_q) == mp_given_knot))) { mp_right_type(path_q) = mp_left_type(path_q); number_clone(path_q->right_given, path_q->left_given); } mp_prev_knot(pp) = path_q; mp_next_knot(path_q) = pp; number_clone(pp->left_y, y); if (t != mp_open_knot) { number_clone(pp->left_x, x); mp_left_type(pp) = (unsigned char) t; }; } path_q = qq; if (cur_cmd >= mp_min_expression_command && cur_cmd <= mp_ampersand_command && ! cycle_hit) { goto CONTINUE_PATH; } FINISH_PATH: if (cycle_hit) { if (d == mp_ampersand_command) { path_p = path_q; } } else { mp_left_type(path_p) = mp_endpoint_knot; if (mp_right_type(path_p) == mp_open_knot) { mp_right_type(path_p) = mp_curl_knot; set_number_to_unity(path_p->right_curl); } mp_right_type(path_q) = mp_endpoint_knot; if (mp_left_type(path_q) == mp_open_knot) { mp_left_type(path_q) = mp_curl_knot; set_number_to_unity(path_q->left_curl); } mp_prev_knot(path_p) = path_q; mp_next_knot(path_q) = path_p; } mp_make_choices(mp, path_p); mp->cur_exp.type = mp_path_type; mp_set_cur_exp_knot(mp, path_p); free_number(x); free_number(y); return 1; } static void do_boolean_error (MP mp) { mp_value new_expr; memset(&new_expr, 0, sizeof(mp_value)); new_number(new_expr.data.n); mp_disp_err(mp, NULL); set_number_from_boolean(new_expr.data.n, mp_false_operation); mp_back_error( mp, "Undefined condition will be treated as 'false'", "The expression shown above should have had a definite true-or-false value. I'm\n" "changing it to 'false'." ); mp_get_x_next(mp); mp_flush_cur_exp(mp, new_expr); mp->cur_exp.type = mp_boolean_type; } void mp_print_capsule (MP mp, mp_node p) { mp_print_chr(mp, '('); mp_print_exp(mp, p, 0); mp_print_chr(mp, ')'); } static void mp_close_files (MP mp) { if (mp->rd_fname != NULL) { for (int k = 0; k < (int) mp->read_files; k++) { if (mp->rd_fname[k] != NULL) { (mp->close_file)(mp, mp->rd_file[k]); mp_memory_free(mp->rd_fname[k]); mp->rd_fname[k] = NULL; } } } if (mp->wr_fname != NULL) { for (int k = 0; k < (int) mp->write_files; k++) { if (mp->wr_fname[k] != NULL) { (mp->close_file)(mp, mp->wr_file[k]); mp_memory_free(mp->wr_fname[k]); mp->wr_fname[k] = NULL; } } } } void mp_close_files_and_terminate (MP mp) { if (mp->finished) { return; } else { mp_close_files(mp); wake_up_terminal(); mp_print_ln(mp); mp->finished = 1; } } void mp_final_cleanup (MP mp) { while (mp->input_ptr > 0) { if (token_state) { mp_end_token_list(mp); } else { mp_end_file_reading(mp); } } while (mp->loop_ptr != NULL) { mp_stop_iteration(mp); } if (mp->interaction < mp_silent_mode) { while (mp->open_parens > 0) { mp_print_str(mp, " )"); --mp->open_parens; } } while (mp->cond_ptr != NULL) { mp_print_nl(mp, "(end occurred when "); mp_print_cmd_mod(mp, mp_fi_or_else_command, mp->cur_if); if (mp->if_line != 0) { mp_print_str(mp, " on line "); mp_print_int(mp, mp->if_line); } mp_print_str(mp, " was incomplete)"); mp->if_line = mp_if_line_field(mp->cond_ptr); mp->cur_if = mp->cond_ptr->name_type; mp->cond_ptr = mp->cond_ptr->link; } if (mp->history != mp_spotless) { if (((mp->history == mp_warning_issued) || (mp->interaction < mp_error_stop_mode))) { if (mp->selector == mp_term_and_log_selector) { mp->selector = mp_term_only_selector; mp_print_nl(mp, "(see the transcript file for additional information)"); mp->selector = mp_term_and_log_selector; } } } } void mp_init_prim (MP mp) { mp_primitive(mp, "tracingtitles", mp_internal_command, mp_tracing_titles_internal); mp_primitive(mp, "tracingequations", mp_internal_command, mp_tracing_equations_internal); mp_primitive(mp, "tracingcapsules", mp_internal_command, mp_tracing_capsules_internal); mp_primitive(mp, "tracingchoices", mp_internal_command, mp_tracing_choices_internal); mp_primitive(mp, "tracingspecs", mp_internal_command, mp_tracing_specs_internal); mp_primitive(mp, "tracingcommands", mp_internal_command, mp_tracing_commands_internal); mp_primitive(mp, "tracingrestores", mp_internal_command, mp_tracing_restores_internal); mp_primitive(mp, "tracingmacros", mp_internal_command, mp_tracing_macros_internal); mp_primitive(mp, "tracingoutput", mp_internal_command, mp_tracing_output_internal); mp_primitive(mp, "tracingstats", mp_internal_command, mp_tracing_stats_internal); mp_primitive(mp, "tracingonline", mp_internal_command, mp_tracing_online_internal); mp_primitive(mp, "year", mp_internal_command, mp_year_internal); mp_primitive(mp, "month", mp_internal_command, mp_month_internal); mp_primitive(mp, "day", mp_internal_command, mp_day_internal); mp_primitive(mp, "time", mp_internal_command, mp_time_internal); mp_primitive(mp, "hour", mp_internal_command, mp_hour_internal); mp_primitive(mp, "minute", mp_internal_command, mp_minute_internal); mp_primitive(mp, "charcode", mp_internal_command, mp_char_code_internal); mp_primitive(mp, "charwd", mp_internal_command, mp_char_wd_internal); mp_primitive(mp, "charht", mp_internal_command, mp_char_ht_internal); mp_primitive(mp, "chardp", mp_internal_command, mp_char_dp_internal); mp_primitive(mp, "charic", mp_internal_command, mp_char_ic_internal); mp_primitive(mp, "pausing", mp_internal_command, mp_pausing_internal); mp_primitive(mp, "showstopping", mp_internal_command, mp_showstopping_internal); mp_primitive(mp, "texscriptmode", mp_internal_command, mp_texscriptmode_internal); mp_primitive(mp, "overloadmode", mp_internal_command, mp_overloadmode_internal); mp_primitive(mp, "linejoin", mp_internal_command, mp_linejoin_internal); mp_primitive(mp, "linecap", mp_internal_command, mp_linecap_internal); mp_primitive(mp, "stacking", mp_internal_command, mp_stacking_internal); mp_primitive(mp, "miterlimit", mp_internal_command, mp_miterlimit_internal); mp_primitive(mp, "warningcheck", mp_internal_command, mp_warning_check_internal); mp_primitive(mp, "truecorners", mp_internal_command, mp_true_corners_internal); mp_primitive(mp, "defaultcolormodel", mp_internal_command, mp_default_color_model_internal); mp_primitive(mp, "restoreclipcolor", mp_internal_command, mp_restore_clip_color_internal); mp_primitive(mp, "numbersystem", mp_internal_command, mp_number_system_internal); mp_primitive(mp, "numberprecision", mp_internal_command, mp_number_precision_internal); mp_primitive(mp, "jobname", mp_internal_command, mp_job_name_internal); mp_primitive(mp, "..", mp_path_join_command, 0); mp_primitive(mp, "[", mp_left_bracket_command, 0); mp->frozen_left_bracket = mp_frozen_primitive (mp, "[", mp_left_bracket_command, 0); mp_primitive(mp, "]", mp_right_bracket_command, 0); mp_primitive(mp, "}", mp_right_brace_command, 0); mp_primitive(mp, "{", mp_left_brace_command, 0); mp_primitive(mp, ":", mp_colon_command, 0); mp->frozen_colon = mp_frozen_primitive (mp, ":", mp_colon_command, 0); mp_primitive(mp, ":=", mp_assignment_command, 0); mp_primitive(mp, ",", mp_comma_command, 0); mp_primitive(mp, ";", mp_semicolon_command, 0); mp->frozen_semicolon = mp_frozen_primitive (mp, ";", mp_semicolon_command, 0); mp_primitive(mp, "\\", mp_relax_command, 0); mp_primitive(mp, "addto", mp_add_to_command, 0); mp_primitive(mp, "atleast", mp_at_least_command, 0); mp_primitive(mp, "begingroup", mp_begin_group_command, 0); mp->bg_loc = cur_sym; mp_primitive(mp, "controls", mp_controls_command, 0); mp_primitive(mp, "curl", mp_curl_command, 0); mp_primitive(mp, "delimiters", mp_delimiters_command, 0); mp_primitive(mp, "endgroup", mp_end_group_command, 0); mp->eg_loc = cur_sym; mp->frozen_end_group = mp_frozen_primitive (mp, "endgroup", mp_end_group_command, 0); mp_primitive(mp, "everyjob", mp_every_job_command, 0); mp_primitive(mp, "exitif", mp_exit_test_command, 0); mp_primitive(mp, "expandafter", mp_expand_after_command, 0); mp_primitive(mp, "interim", mp_interim_command, 0); mp_primitive(mp, "let", mp_let_command, 0); mp_primitive(mp, "newinternal", mp_new_internal_command, 0); mp_primitive(mp, "of", mp_of_command, 0); mp_primitive(mp, "randomseed", mp_only_set_command, mp_random_seed_code); mp_primitive(mp, "maxknotpool", mp_only_set_command, mp_max_knot_pool_code); mp_primitive(mp, "save", mp_save_command, 0); mp_primitive(mp, "scantokens", mp_scan_tokens_command, 0); mp_primitive(mp, "runscript", mp_runscript_command, 0); mp_primitive(mp, "maketext", mp_maketext_command, 0); mp_primitive(mp, "shipout", mp_ship_out_command, 0); mp_primitive(mp, "step", mp_step_command, 0); mp_primitive(mp, "str", mp_str_command, 0); mp_primitive(mp, "void", mp_void_command, 0); mp_primitive(mp, "tension", mp_tension_command, 0); mp_primitive(mp, "to", mp_to_command, 0); mp_primitive(mp, "until", mp_until_command, 0); mp_primitive(mp, "within", mp_within_command, 0); mp_primitive(mp, "write", mp_write_command, 0); mp_primitive(mp, "btex", mp_btex_command, mp_btex_code); mp_primitive(mp, "verbatimtex", mp_btex_command, mp_verbatim_code); mp_primitive(mp, "etex", mp_etex_command, 0); mp->frozen_etex = mp_frozen_primitive (mp, "etex", mp_etex_command, 0); mp_primitive(mp, "def", mp_macro_def_command, mp_def_code); mp_primitive(mp, "vardef", mp_macro_def_command, mp_var_def_code); mp_primitive(mp, "primarydef", mp_macro_def_command, mp_primary_def_code); mp_primitive(mp, "secondarydef", mp_macro_def_command, mp_secondary_def_code); mp_primitive(mp, "tertiarydef", mp_macro_def_command, mp_tertiary_def_code); mp_primitive(mp, "enddef", mp_macro_def_command, mp_end_def_code); mp->frozen_end_def = mp_frozen_primitive(mp, "enddef", mp_macro_def_command, mp_end_def_code); mp_primitive(mp, "for", mp_iteration_command, mp_start_for_code); mp_primitive(mp, "forsuffixes", mp_iteration_command, mp_start_forsuffixes_code); mp_primitive(mp, "forever", mp_iteration_command, mp_start_forever_code); mp_primitive(mp, "endfor", mp_iteration_command, mp_end_for_code); mp->frozen_end_for = mp_frozen_primitive (mp, "endfor", mp_iteration_command, mp_end_for_code); mp_primitive(mp, "quote", mp_macro_special_command, mp_macro_quote_code); mp_primitive(mp, "#@", mp_macro_special_command, mp_macro_prefix_code); mp_primitive(mp, "@", mp_macro_special_command, mp_macro_at_code); mp_primitive(mp, "@#", mp_macro_special_command, mp_macro_suffix_code); mp_primitive(mp, "expr", mp_parameter_commmand, mp_expr_parameter); mp_primitive(mp, "suffix", mp_parameter_commmand, mp_suffix_parameter); mp_primitive(mp, "text", mp_parameter_commmand, mp_text_parameter); mp_primitive(mp, "primary", mp_parameter_commmand, mp_primary_macro); mp_primitive(mp, "secondary", mp_parameter_commmand, mp_secondary_macro); mp_primitive(mp, "tertiary", mp_parameter_commmand, mp_tertiary_macro); mp_primitive(mp, "input", mp_input_command, 0); mp_primitive(mp, "endinput", mp_input_command, 1); mp_primitive(mp, "if", mp_if_test_command, mp_if_code); mp_primitive(mp, "fi", mp_fi_or_else_command, mp_fi_code); mp->frozen_fi = mp_frozen_primitive (mp, "fi", mp_fi_or_else_command, mp_fi_code); mp_primitive(mp, "else", mp_fi_or_else_command, mp_else_code); mp_primitive(mp, "elseif", mp_fi_or_else_command, mp_else_if_code); mp_primitive(mp, "true", mp_nullary_command, mp_true_operation); mp_primitive(mp, "false", mp_nullary_command, mp_false_operation); mp_primitive(mp, "nullpicture", mp_nullary_command, mp_null_picture_operation); mp_primitive(mp, "nullpen", mp_nullary_command, mp_null_pen_operation); mp_primitive(mp, "readstring", mp_nullary_command, mp_read_string_operation); mp_primitive(mp, "pencircle", mp_nullary_command, mp_pen_circle_operation); mp_primitive(mp, "normaldeviate", mp_nullary_command, mp_normal_deviate_operation); mp_primitive(mp, "readfrom", mp_unary_command, mp_read_from_operation); mp_primitive(mp, "closefrom", mp_unary_command, mp_close_from_operation); mp_primitive(mp, "odd", mp_unary_command, mp_odd_operation); mp_primitive(mp, "known", mp_unary_command, mp_known_operation); mp_primitive(mp, "unknown", mp_unary_command, mp_unknown_operation); mp_primitive(mp, "not", mp_unary_command, mp_not_operation); mp_primitive(mp, "decimal", mp_unary_command, mp_decimal_operation); mp_primitive(mp, "reverse", mp_unary_command, mp_reverse_operation); mp_primitive(mp, "uncycle", mp_unary_command, mp_uncycle_operation); mp_primitive(mp, "makepath", mp_unary_command, mp_make_path_operation); mp_primitive(mp, "makepen", mp_unary_command, mp_make_pen_operation); mp_primitive(mp, "makenep", mp_unary_command, mp_make_nep_operation); mp_primitive(mp, "convexed", mp_unary_command, mp_convexed_operation); mp_primitive(mp, "uncontrolled", mp_unary_command, mp_uncontrolled_operation); mp_primitive(mp, "oct", mp_unary_command, mp_oct_operation); mp_primitive(mp, "hex", mp_unary_command, mp_hex_operation); mp_primitive(mp, "ASCII", mp_unary_command, mp_ASCII_operation); mp_primitive(mp, "char", mp_unary_command, mp_char_operation); mp_primitive(mp, "length", mp_unary_command, mp_length_operation); mp_primitive(mp, "turningnumber", mp_unary_command, mp_turning_operation); mp_primitive(mp, "xpart", mp_unary_command, mp_x_part_operation); mp_primitive(mp, "ypart", mp_unary_command, mp_y_part_operation); mp_primitive(mp, "xxpart", mp_unary_command, mp_xx_part_operation); mp_primitive(mp, "xypart", mp_unary_command, mp_xy_part_operation); mp_primitive(mp, "yxpart", mp_unary_command, mp_yx_part_operation); mp_primitive(mp, "yypart", mp_unary_command, mp_yy_part_operation); mp_primitive(mp, "redpart", mp_unary_command, mp_red_part_operation); mp_primitive(mp, "greenpart", mp_unary_command, mp_green_part_operation); mp_primitive(mp, "bluepart", mp_unary_command, mp_blue_part_operation); mp_primitive(mp, "cyanpart", mp_unary_command, mp_cyan_part_operation); mp_primitive(mp, "magentapart", mp_unary_command, mp_magenta_part_operation); mp_primitive(mp, "yellowpart", mp_unary_command, mp_yellow_part_operation); mp_primitive(mp, "blackpart", mp_unary_command, mp_black_part_operation); mp_primitive(mp, "greypart", mp_unary_command, mp_grey_part_operation); mp_primitive(mp, "colormodel", mp_unary_command, mp_color_model_operation); mp_primitive(mp, "prescriptpart", mp_unary_command, mp_prescript_part_operation); mp_primitive(mp, "postscriptpart", mp_unary_command, mp_postscript_part_operation); mp_primitive(mp, "stackingpart", mp_unary_command, mp_stacking_part_operation); mp_primitive(mp, "pathpart", mp_unary_command, mp_path_part_operation); mp_primitive(mp, "penpart", mp_unary_command, mp_pen_part_operation); mp_primitive(mp, "dashpart", mp_unary_command, mp_dash_part_operation); mp_primitive(mp, "sqrt", mp_unary_command, mp_sqrt_operation); mp_primitive(mp, "mexp", mp_unary_command, mp_m_exp_operation); mp_primitive(mp, "mlog", mp_unary_command, mp_m_log_operation); mp_primitive(mp, "sind", mp_unary_command, mp_sin_d_operation); mp_primitive(mp, "cosd", mp_unary_command, mp_cos_d_operation); mp_primitive(mp, "floor", mp_unary_command, mp_floor_operation); mp_primitive(mp, "uniformdeviate", mp_unary_command, mp_uniform_deviate_operation); mp_primitive(mp, "llcorner", mp_unary_command, mp_ll_corner_operation); mp_primitive(mp, "lrcorner", mp_unary_command, mp_lr_corner_operation); mp_primitive(mp, "ulcorner", mp_unary_command, mp_ul_corner_operation); mp_primitive(mp, "urcorner", mp_unary_command, mp_ur_corner_operation); mp_primitive(mp, "centerof", mp_unary_command, mp_center_of_operation); mp_primitive(mp, "centerofmass", mp_unary_command, mp_center_of_mass_operation); mp_primitive(mp, "corners", mp_unary_command, mp_corners_operation); mp_primitive(mp, "xrange", mp_unary_command, mp_x_range_operation); mp_primitive(mp, "yrange", mp_unary_command, mp_y_range_operation); mp_primitive(mp, "deltapoint", mp_unary_command, mp_delta_point_operation); mp_primitive(mp, "deltaprecontrol", mp_unary_command, mp_delta_precontrol_operation); mp_primitive(mp, "deltapostcontrol", mp_unary_command, mp_delta_postcontrol_operation); mp_primitive(mp, "deltadirection", mp_unary_command, mp_delta_direction_operation); mp_primitive(mp, "arclength", mp_unary_command, mp_arc_length_operation); mp_primitive(mp, "angle", mp_unary_command, mp_angle_operation); mp_primitive(mp, "cycle", mp_cycle_command, mp_cycle_operation); mp_primitive(mp, "nocycle", mp_cycle_command, mp_no_cycle_operation); mp_primitive(mp, "stroked", mp_unary_command, mp_stroked_operation); mp_primitive(mp, "filled", mp_unary_command, mp_filled_operation); mp_primitive(mp, "clipped", mp_unary_command, mp_clipped_operation); mp_primitive(mp, "grouped", mp_unary_command, mp_grouped_operation); mp_primitive(mp, "bounded", mp_unary_command, mp_bounded_operation); mp_primitive(mp, "+", mp_plus_or_minus_command, mp_plus_operation); mp_primitive(mp, "-", mp_plus_or_minus_command, mp_minus_operation); mp_primitive(mp, "*", mp_secondary_binary_command, mp_times_operation); mp_primitive(mp, "/", mp_slash_command, mp_over_operation); mp->frozen_slash = mp_frozen_primitive (mp, "/", mp_slash_command, mp_over_operation); mp_primitive(mp, "^", mp_secondary_binary_command, mp_power_operation); mp_primitive(mp, "++", mp_tertiary_binary_command, mp_pythag_add_operation); mp_primitive(mp, "+-+", mp_tertiary_binary_command, mp_pythag_sub_operation); mp_primitive(mp, "or", mp_tertiary_binary_command, mp_or_operation); mp_primitive(mp, "and", mp_and_command, mp_and_operation); mp_primitive(mp, "<", mp_primary_binary_command, mp_less_than_operation); mp_primitive(mp, "<=", mp_primary_binary_command, mp_less_or_equal_operation); mp_primitive(mp, ">", mp_primary_binary_command, mp_greater_than_operation); mp_primitive(mp, ">=", mp_primary_binary_command, mp_greater_or_equal_operation); mp_primitive(mp, "=", mp_equals_command, mp_equal_operation); mp_primitive(mp, "<>", mp_primary_binary_command, mp_unequal_operation); mp_primitive(mp, "substring", mp_of_binary_command, mp_substring_operation); mp_primitive(mp, "subpath", mp_of_binary_command, mp_subpath_operation); mp_primitive(mp, "directiontime", mp_of_binary_command, mp_direction_time_operation); mp_primitive(mp, "point", mp_of_binary_command, mp_point_operation); mp_primitive(mp, "precontrol", mp_of_binary_command, mp_precontrol_operation); mp_primitive(mp, "postcontrol", mp_of_binary_command, mp_postcontrol_operation); mp_primitive(mp, "direction", mp_of_binary_command, mp_direction_operation); mp_primitive(mp, "pathpoint", mp_nullary_command, mp_path_point_operation); mp_primitive(mp, "pathprecontrol", mp_nullary_command, mp_path_precontrol_operation); mp_primitive(mp, "pathpostcontrol", mp_nullary_command, mp_path_postcontrol_operation); mp_primitive(mp, "pathdirection", mp_nullary_command, mp_path_direction_operation); mp_primitive(mp, "penoffset", mp_of_binary_command, mp_pen_offset_operation); mp_primitive(mp, "arctime", mp_of_binary_command, mp_arc_time_operation); mp_primitive(mp, "arcpoint", mp_of_binary_command, mp_arc_point_operation); mp_primitive(mp, "arcpointlist", mp_of_binary_command, mp_arc_point_list_operation); mp_primitive(mp, "subarclength", mp_of_binary_command, mp_subarc_length_operation); mp_primitive(mp, "mpversion", mp_nullary_command, mp_version_operation); mp_primitive(mp, "&", mp_ampersand_command, mp_concatenate_operation); mp_primitive(mp, "&&", mp_ampersand_command, mp_just_append_operation); mp_primitive(mp, "&&&", mp_ampersand_command, mp_tolerant_concat_operation); mp_primitive(mp, "&&&&", mp_ampersand_command, mp_tolerant_append_operation); mp_primitive(mp, "rotated", mp_secondary_binary_command, mp_rotated_operation); mp_primitive(mp, "slanted", mp_secondary_binary_command, mp_slanted_operation); mp_primitive(mp, "scaled", mp_secondary_binary_command, mp_scaled_operation); mp_primitive(mp, "shifted", mp_secondary_binary_command, mp_shifted_operation); mp_primitive(mp, "transformed", mp_secondary_binary_command, mp_transformed_operation); mp_primitive(mp, "xscaled", mp_secondary_binary_command, mp_x_scaled_operation); mp_primitive(mp, "yscaled", mp_secondary_binary_command, mp_y_scaled_operation); mp_primitive(mp, "zscaled", mp_secondary_binary_command, mp_z_scaled_operation); mp_primitive(mp, "intersectiontimes", mp_tertiary_binary_command, mp_intertimes_operation); mp_primitive(mp, "intersectiontimeslist", mp_tertiary_binary_command, mp_intertimes_list_operation); mp_primitive(mp, "envelope", mp_of_binary_command, mp_envelope_operation); mp_primitive(mp, "boundingpath", mp_of_binary_command, mp_boundingpath_operation); mp_primitive(mp, "numeric", mp_type_name_command, mp_numeric_type_operation); mp_primitive(mp, "string", mp_type_name_command, mp_string_type_operation); mp_primitive(mp, "boolean", mp_type_name_command, mp_boolean_type_operation); mp_primitive(mp, "path", mp_type_name_command, mp_path_type_operation); mp_primitive(mp, "pen", mp_type_name_command, mp_pen_type_operation); mp_primitive(mp, "nep", mp_type_name_command, mp_nep_type_operation); mp_primitive(mp, "picture", mp_type_name_command, mp_picture_type_operation); mp_primitive(mp, "transform", mp_type_name_command, mp_transform_type_operation); mp_primitive(mp, "color", mp_type_name_command, mp_color_type_operation); mp_primitive(mp, "rgbcolor", mp_type_name_command, mp_color_type_operation); mp_primitive(mp, "cmykcolor", mp_type_name_command, mp_cmykcolor_type_operation); mp_primitive(mp, "pair", mp_type_name_command, mp_pair_type_operation); mp_primitive(mp, "end", mp_stop_command, 0); mp_primitive(mp, "dump", mp_stop_command, 1); mp->frozen_dump = mp_frozen_primitive (mp, "dump", mp_stop_command, 1); mp_primitive(mp, "batchmode", mp_mode_command, mp_batch_mode); mp_primitive(mp, "nonstopmode", mp_mode_command, mp_nonstop_mode); mp_primitive(mp, "scrollmode", mp_mode_command, mp_scroll_mode); mp_primitive(mp, "errorstopmode", mp_mode_command, mp_error_stop_mode); mp_primitive(mp, "silentmode", mp_mode_command, mp_silent_mode); mp_primitive(mp, "inner", mp_protection_command, 0); mp_primitive(mp, "outer", mp_protection_command, 1); mp_primitive(mp, "setproperty", mp_property_command, 1); mp_primitive(mp, "showtoken", mp_show_command, mp_show_token_code); mp_primitive(mp, "showstats", mp_show_command, mp_show_stats_code); mp_primitive(mp, "show", mp_show_command, mp_show_code); mp_primitive(mp, "showvariable", mp_show_command, mp_show_var_code); mp_primitive(mp, "showdependencies", mp_show_command, mp_show_dependencies_code); mp_primitive(mp, "doublepath", mp_thing_to_add_command, mp_add_double_path_code); mp_primitive(mp, "contour", mp_thing_to_add_command, mp_add_contour_code); mp_primitive(mp, "also", mp_thing_to_add_command, mp_add_also_code); mp_primitive(mp, "withpen", mp_with_option_command, mp_with_pen_code); mp_primitive(mp, "dashed", mp_with_option_command, mp_with_dashed_code); mp_primitive(mp, "withprescript", mp_with_option_command, mp_with_pre_script_code); mp_primitive(mp, "withpostscript", mp_with_option_command, mp_with_post_script_code); mp_primitive(mp, "withstacking", mp_with_option_command, mp_with_stacking_code); mp_primitive(mp, "withlinecap", mp_with_option_command, mp_with_linecap_code); mp_primitive(mp, "withlinejoin", mp_with_option_command, mp_with_linejoin_code); mp_primitive(mp, "withmiterlimit", mp_with_option_command, mp_with_miterlimit_code); mp_primitive(mp, "withoutcolor", mp_with_option_command, mp_with_no_model_code); mp_primitive(mp, "withgreyscale", mp_with_option_command, mp_with_grey_model_code); mp_primitive(mp, "withcolor", mp_with_option_command, mp_with_uninitialized_model_code); mp_primitive(mp, "withrgbcolor", mp_with_option_command, mp_with_rgb_model_code); mp_primitive(mp, "withcmykcolor", mp_with_option_command, mp_with_cmyk_model_code); mp_primitive(mp, "clip", mp_bounds_command, mp_start_clip_node_type); mp_primitive(mp, "setgroup", mp_bounds_command, mp_start_group_node_type); mp_primitive(mp, "setbounds", mp_bounds_command, mp_start_bounds_node_type); mp_primitive(mp, "message", mp_message_command, message_code); mp_primitive(mp, "errmessage", mp_message_command, err_message_code); mp_primitive(mp, "errhelp", mp_message_command, err_help_code); } void mp_init_tab (MP mp) { mp->spec_head = mp_new_symbolic_node(mp); mp->temp_head = mp_new_symbolic_node(mp); mp->hold_head = mp_new_symbolic_node(mp); number_clone(internal_value(mp_default_color_model_internal),unity_t); number_multiply_int(internal_value(mp_default_color_model_internal), mp_rgb_model); number_clone(internal_value(mp_restore_clip_color_internal), unity_t); set_internal_string(mp_number_system_internal, mp_intern (mp, "scaled")); number_clone(internal_value(mp_number_precision_internal), precision_default); number_clone(internal_value(mp_texscriptmode_internal), unity_t); number_clone(internal_value(mp_overloadmode_internal), zero_t); set_internal_name(mp_tracing_titles_internal, mp_strdup("tracingtitles")); set_internal_name(mp_tracing_equations_internal, mp_strdup("tracingequations")); set_internal_name(mp_tracing_capsules_internal, mp_strdup("tracingcapsules")); set_internal_name(mp_tracing_choices_internal, mp_strdup("tracingchoices")); set_internal_name(mp_tracing_specs_internal, mp_strdup("tracingspecs")); set_internal_name(mp_tracing_commands_internal, mp_strdup("tracingcommands")); set_internal_name(mp_tracing_restores_internal, mp_strdup("tracingrestores")); set_internal_name(mp_tracing_macros_internal, mp_strdup("tracingmacros")); set_internal_name(mp_tracing_output_internal, mp_strdup("tracingoutput")); set_internal_name(mp_tracing_stats_internal, mp_strdup("tracingstats")); set_internal_name(mp_tracing_online_internal, mp_strdup("tracingonline")); set_internal_name(mp_year_internal, mp_strdup("year")); set_internal_name(mp_month_internal, mp_strdup("month")); set_internal_name(mp_day_internal, mp_strdup("day")); set_internal_name(mp_time_internal, mp_strdup("time")); set_internal_name(mp_hour_internal, mp_strdup("hour")); set_internal_name(mp_minute_internal, mp_strdup("minute")); set_internal_name(mp_char_code_internal, mp_strdup("charcode")); set_internal_name(mp_char_wd_internal, mp_strdup("charwd")); set_internal_name(mp_char_ht_internal, mp_strdup("charht")); set_internal_name(mp_char_dp_internal, mp_strdup("chardp")); set_internal_name(mp_char_ic_internal, mp_strdup("charic")); set_internal_name(mp_pausing_internal, mp_strdup("pausing")); set_internal_name(mp_showstopping_internal, mp_strdup("showstopping")); set_internal_name(mp_texscriptmode_internal, mp_strdup("texscriptmode")); set_internal_name(mp_overloadmode_internal, mp_strdup("overloadmode")); set_internal_name(mp_linejoin_internal, mp_strdup("linejoin")); set_internal_name(mp_linecap_internal, mp_strdup("linecap")); set_internal_name(mp_stacking_internal, mp_strdup("stacking")); set_internal_name(mp_miterlimit_internal, mp_strdup("miterlimit")); set_internal_name(mp_warning_check_internal, mp_strdup("warningcheck")); set_internal_name(mp_true_corners_internal, mp_strdup("truecorners")); set_internal_name(mp_default_color_model_internal, mp_strdup("defaultcolormodel")); set_internal_name(mp_restore_clip_color_internal, mp_strdup("restoreclipcolor")); set_internal_name(mp_job_name_internal, mp_strdup("jobname")); set_internal_name(mp_number_system_internal, mp_strdup("numbersystem")); set_internal_name(mp_number_precision_internal, mp_strdup("numberprecision")); mp->id_lookup_test = new_symbols_entry(mp, NULL, 0); mp->st_count = 0; mp->frozen_bad_vardef = mp_frozen_primitive(mp, "a bad variable", mp_tag_command, 0); mp->frozen_right_delimiter = mp_frozen_primitive(mp, ")", mp_right_delimiter_command, 0); mp->frozen_inaccessible = mp_frozen_primitive(mp, " INACCESSIBLE", mp_tag_command, 0); mp->frozen_undefined = mp_frozen_primitive(mp, " UNDEFINED", mp_tag_command, 0); mp->end_attr = (mp_node) mp_get_attribute_node(mp); mp_set_hashloc(mp->end_attr, (mp_sym)-1); mp_set_parent((mp_value_node) mp->end_attr, NULL); new_fraction(mp->st); new_fraction(mp->ct); new_fraction(mp->sf); new_fraction(mp->cf); for (int i = 0; i <= mp_y_code; i++) { new_number(mp->bbmin[i]); new_number(mp->bbmax[i]); } new_number(mp->cur_x); new_number(mp->cur_y); mp->null_dash = mp_get_dash_node(mp); new_number(mp->cur_t); new_number(mp->cur_tt); new_number(mp->max_t); new_number(mp->delx); new_number(mp->dely); new_number(mp->appr_t); new_number(mp->appr_tt); mp->serial_no = 0; mp->dep_head = mp_get_dep_node(mp); mp_set_link(mp->dep_head, mp->dep_head); mp_set_prev_dep(mp->dep_head, mp->dep_head); mp_set_dep_info(mp->dep_head, NULL); mp_set_dep_list(mp->dep_head, NULL); mp->cur_mod_ = mp_new_symbolic_node(mp); mp->bad_vardef = mp_new_value_node(mp); mp->bad_vardef->name_type = mp_root_operation; mp_set_value_sym(mp->bad_vardef, mp->frozen_bad_vardef); mp->frozen_repeat_loop = mp_frozen_primitive (mp, " ENDFOR", mp_repeat_loop_command, 0); for (int i = 0; i < mp_proto_dependent_type + 1; i++) { new_number(mp->max_c[i]); } mp->temp_val = mp_new_value_node(mp); mp->temp_val->name_type = mp_capsule_operation; new_number(mp->txx); new_number(mp->txy); new_number(mp->tyx); new_number(mp->tyy); new_number(mp->tx); new_number(mp->ty); mp->inf_val = mp_new_value_node(mp); mp_set_value_number(mp->inf_val, fraction_four_t); mp->zero_val = mp_new_value_node(mp); mp_set_value_number(mp->zero_val, zero_t); }