+ ed_fieldx = (ed_xsize < MAX_ED_FIELDX ? ed_xsize : max_ed_fieldx);
+ ed_fieldy = (ed_ysize < MAX_ED_FIELDY ? ed_ysize : max_ed_fieldy);
+
+ ModifyGadget(level_editor_gadget[GADGET_ID_DRAWING_LEVEL],
+ GDI_WIDTH, ed_fieldx * MINI_TILEX,
+ GDI_HEIGHT, ed_fieldy * MINI_TILEY,
+ GDI_AREA_SIZE, ed_fieldx, ed_fieldy,
+ GDI_END);
+
+ xoffset = (ed_fieldx == MAX_ED_FIELDX ? ED_SCROLLBUTTON_XSIZE : 0);
+ yoffset = (ed_fieldy == MAX_ED_FIELDY ? ED_SCROLLBUTTON_YSIZE : 0);
+
+ x = SX + scrollbutton_info[ED_SCROLLBUTTON_ID_AREA_RIGHT].x + xoffset;
+ y = SX + scrollbutton_info[ED_SCROLLBUTTON_ID_AREA_DOWN].y + yoffset;
+
+ ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_RIGHT], GDI_X, x, GDI_END);
+ ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_DOWN], GDI_Y, y, GDI_END);
+
+ width = scrollbar_info[ED_SCROLLBAR_ID_AREA_HORIZONTAL].width + xoffset;
+ height = scrollbar_info[ED_SCROLLBAR_ID_AREA_VERTICAL].height + yoffset;
+
+ ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
+ GDI_WIDTH, width,
+ GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldx,
+ GDI_END);
+ ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
+ GDI_HEIGHT, height,
+ GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldy,
+ GDI_END);
+}
+
+static void AdjustLevelScrollPosition()
+{
+ if (level_xpos < -1)
+ level_xpos = -1;
+ if (level_xpos > lev_fieldx - ed_fieldx + 1)
+ level_xpos = lev_fieldx - ed_fieldx + 1;
+ if (lev_fieldx < ed_fieldx - 2)
+ level_xpos = -1;
+
+ if (level_ypos < -1)
+ level_ypos = -1;
+ if (level_ypos > lev_fieldy - ed_fieldy + 1)
+ level_ypos = lev_fieldy - ed_fieldy + 1;
+ if (lev_fieldy < ed_fieldy - 2)
+ level_ypos = -1;
+}
+
+static void AdjustEditorScrollbar(int id)
+{
+ struct GadgetInfo *gi = level_editor_gadget[id];
+ int items_max, items_visible, item_position;
+
+ if (id == GADGET_ID_SCROLL_HORIZONTAL)
+ {
+ items_max = MAX(lev_fieldx + 2, ed_fieldx);
+ items_visible = ed_fieldx;
+ item_position = level_xpos + 1;
+ }
+ else
+ {
+ items_max = MAX(lev_fieldy + 2, ed_fieldy);
+ items_visible = ed_fieldy;
+ item_position = level_ypos + 1;
+ }
+
+ if (item_position > items_max - items_visible)
+ item_position = items_max - items_visible;
+
+ ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
+ GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
+}
+
+static void ModifyEditorCounter(int counter_id, int new_value)
+{
+ int *counter_value = counterbutton_info[counter_id].value;
+ int gadget_id = counterbutton_info[counter_id].gadget_id_text;
+ struct GadgetInfo *gi = level_editor_gadget[gadget_id];
+
+ ModifyGadget(gi, GDI_NUMBER_VALUE, new_value, GDI_END);
+
+ if (counter_value != NULL)
+ *counter_value = gi->text.number_value;
+}
+
+static void ModifyEditorCounterLimits(int counter_id, int min, int max)
+{
+ int gadget_id = counterbutton_info[counter_id].gadget_id_text;
+ struct GadgetInfo *gi = level_editor_gadget[gadget_id];
+
+ ModifyGadget(gi, GDI_NUMBER_MIN, min, GDI_NUMBER_MAX, max, GDI_END);
+}
+
+static void ModifyEditorSelectbox(int selectbox_id, int new_value)
+{
+ int gadget_id = selectbox_info[selectbox_id].gadget_id;
+ struct GadgetInfo *gi = level_editor_gadget[gadget_id];
+ int new_index_value = 0;
+ int i;
+
+ for(i=0; selectbox_info[selectbox_id].options[i].text != NULL; i++)
+ if (selectbox_info[selectbox_id].options[i].value == new_value)
+ new_index_value = i;
+
+ *selectbox_info[selectbox_id].value =
+ selectbox_info[selectbox_id].options[new_index_value].value;
+
+ ModifyGadget(gi, GDI_SELECTBOX_INDEX, new_index_value, GDI_END);
+}
+
+static void ModifyEditorElementList()
+{
+ int i;
+
+ for (i=0; i<ED_NUM_ELEMENTLIST_BUTTONS; i++)
+ {
+ int gadget_id = GADGET_ID_ELEMENTLIST_FIRST + i;
+ struct GadgetInfo *gi = level_editor_gadget[gadget_id];
+ struct GadgetDesign *gd = &gi->deco.design;
+ int element = editor_elements[element_shift + i];
+
+ UnmapGadget(gi);
+ getMiniGraphicSource(el2edimg(element), &gd->bitmap, &gd->x, &gd->y);
+ ModifyGadget(gi, GDI_INFO_TEXT, getElementInfoText(element), GDI_END);
+ MapGadget(gi);
+ }
+}
+
+static void PickDrawingElement(int button, int element)
+{
+ if (button < 1 || button > 3)
+ return;
+
+ if (button == 1)
+ {
+ new_element1 = element;
+ DrawMiniGraphicExt(drawto,
+ DX + ED_WIN_MB_LEFT_XPOS, DY + ED_WIN_MB_LEFT_YPOS,
+ el2edimg(new_element1));
+ }
+ else if (button == 2)
+ {
+ new_element2 = element;
+ DrawMiniGraphicExt(drawto,
+ DX + ED_WIN_MB_MIDDLE_XPOS, DY + ED_WIN_MB_MIDDLE_YPOS,
+ el2edimg(new_element2));
+ }
+ else
+ {
+ new_element3 = element;
+ DrawMiniGraphicExt(drawto,
+ DX + ED_WIN_MB_RIGHT_XPOS, DY + ED_WIN_MB_RIGHT_YPOS,
+ el2edimg(new_element3));
+ }
+
+ redraw_mask |= REDRAW_DOOR_1;
+}
+
+static void RedrawDrawingElements()
+{
+ PickDrawingElement(1, new_element1);
+ PickDrawingElement(2, new_element2);
+ PickDrawingElement(3, new_element3);
+}
+
+static void DrawDrawingWindow()
+{
+ stick_element_properties_window = FALSE;
+
+ SetMainBackgroundImage(IMG_UNDEFINED);
+ ClearWindow();
+ UnmapLevelEditorWindowGadgets();
+
+ AdjustDrawingAreaGadgets();
+ AdjustLevelScrollPosition();
+ AdjustEditorScrollbar(GADGET_ID_SCROLL_HORIZONTAL);
+ AdjustEditorScrollbar(GADGET_ID_SCROLL_VERTICAL);
+
+ DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
+ MapMainDrawingArea();
+}
+
+static void DrawElementBorder(int dest_x, int dest_y, int width, int height,
+ boolean input)
+{
+ int border_graphic =
+ (input ? IMG_EDITOR_ELEMENT_BORDER_INPUT : IMG_EDITOR_ELEMENT_BORDER);
+ Bitmap *src_bitmap;
+ int src_x, src_y;
+ int num_mini_tilex = width / MINI_TILEX + 1;
+ int num_mini_tiley = width / MINI_TILEY + 1;
+ int x, y;
+
+ getMiniGraphicSource(border_graphic, &src_bitmap, &src_x, &src_y);
+
+ for (y=0; y < num_mini_tiley; y++)
+ for (x=0; x < num_mini_tilex; x++)
+ BlitBitmap(src_bitmap, drawto, src_x, src_y, MINI_TILEX, MINI_TILEY,
+ dest_x - MINI_TILEX / 2 + x * MINI_TILEX,
+ dest_y - MINI_TILEY / 2 + y * MINI_TILEY);
+
+ ClearRectangle(drawto, dest_x - 1, dest_y - 1, width + 2, height + 2);
+}
+
+static void DrawRandomPlacementBackgroundArea()
+{
+ struct GadgetInfo *gi = level_editor_gadget[GADGET_ID_RANDOM_BACKGROUND];
+#if 0
+ int area_x = ED_AREA_RANDOM_BACKGROUND_XPOS / MINI_TILEX;
+ int area_y = ED_AREA_RANDOM_BACKGROUND_YPOS / MINI_TILEY;
+ int area_sx = SX + ED_AREA_RANDOM_BACKGROUND_XPOS;
+ int area_sy = SY + ED_AREA_RANDOM_BACKGROUND_YPOS;
+#endif
+
+ DrawElementBorder(gi->x, gi->y, MINI_TILEX, MINI_TILEY, TRUE);
+ DrawMiniElement(gi->x, gi->y, random_placement_background_element);
+
+ MapDrawingArea(ED_DRAWING_ID_RANDOM_BACKGROUND);
+}
+
+static void DrawLevelInfoWindow()
+{
+ int i;
+
+ stick_element_properties_window = FALSE;
+
+ SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
+ ClearWindow();
+ UnmapLevelEditorWindowGadgets();
+
+ DrawText(SX + ED_SETTINGS2_XPOS, SY + ED_SETTINGS1_YPOS,
+ "Level Settings", FONT_TITLE_1);
+ DrawText(SX + ED_SETTINGS2_XPOS, SY + ED_SETTINGS2_YPOS,
+ "Editor Settings", FONT_TITLE_1);
+
+ /* draw counter gadgets */
+ for (i=ED_COUNTER_ID_LEVEL_FIRST; i<=ED_COUNTER_ID_LEVEL_LAST; i++)
+ MapCounterButtons(i);
+
+ /* draw checkbutton gadgets */
+ for (i=ED_CHECKBUTTON_ID_LEVEL_FIRST; i<=ED_CHECKBUTTON_ID_LEVEL_LAST; i++)
+ MapCheckbuttonGadget(i);
+
+ /* draw radiobutton gadgets */
+ for (i=ED_RADIOBUTTON_ID_LEVEL_FIRST; i<=ED_RADIOBUTTON_ID_LEVEL_LAST; i++)
+ MapRadiobuttonGadget(i);
+
+ /* draw text input gadgets */
+ for (i=ED_TEXTINPUT_ID_LEVEL_FIRST; i<=ED_TEXTINPUT_ID_LEVEL_LAST; i++)
+ MapTextInputGadget(i);
+
+ /* draw drawing area */
+ DrawRandomPlacementBackgroundArea();
+}
+
+static void DrawAmoebaContentArea()
+{
+ int area_x = ED_AREA_ELEM_CONTENT_XPOS / MINI_TILEX;
+ int area_y = ED_AREA_ELEM_CONTENT_YPOS / MINI_TILEY;
+ int area_sx = SX + ED_AREA_ELEM_CONTENT_XPOS;
+ int area_sy = SY + ED_AREA_ELEM_CONTENT_YPOS;
+
+ DrawElementBorder(area_sx, area_sy, MINI_TILEX, MINI_TILEY, TRUE);
+ DrawMiniElement(area_x, area_y, level.amoeba_content);
+
+ DrawText(area_sx + TILEX, area_sy + 1, "Content of amoeba", FONT_TEXT_1);
+
+ MapDrawingArea(ED_DRAWING_ID_AMOEBA_CONTENT);
+}
+
+static void DrawCustomGraphicElementArea()
+{
+ struct GadgetInfo *gi = level_editor_gadget[GADGET_ID_CUSTOM_GRAPHIC];
+#if 0
+ int xpos = ED_AREA_ELEM_CONTENT3_XPOS;
+ int ypos = ED_AREA_ELEM_CONTENT3_YPOS;
+ int area_sx = SX + xpos;
+ int area_sy = SY + ypos;
+#endif
+
+ if (!IS_CUSTOM_ELEMENT(properties_element))
+ {
+ /* this should never happen */
+ Error(ERR_WARN, "element %d is no custom element", properties_element);
+
+ return;
+ }
+
+ DrawElementBorder(gi->x, gi->y, MINI_TILEX, MINI_TILEY, TRUE);
+ DrawMiniGraphicExt(drawto, gi->x, gi->y,
+ el2edimg(custom_element.gfx_element));
+
+ MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
+}
+
+static void DrawCustomContentArea()
+{
+ struct GadgetInfo *gi = level_editor_gadget[GADGET_ID_CUSTOM_CONTENT];
+#if 0
+ int area_sx = SX + ED_AREA_ELEM_CONTENT4_XPOS;
+ int area_sy = SY + ED_AREA_ELEM_CONTENT4_YPOS;
+#endif
+ int x1 = right_gadget_border[GADGET_ID_CUSTOM_DEADLINESS];
+ int x2 = right_gadget_border[GADGET_ID_CUSTOM_CONSISTENCY];
+ int x3 = right_gadget_border[GADGET_ID_CUSTOM_EXPLODE_IMPACT];
+ int xoffset = ED_GADGET_TEXT_DISTANCE + MINI_TILEX / 2;
+ int x, y;
+
+ if (!IS_CUSTOM_ELEMENT(properties_element))
+ {
+ /* this should never happen */
+ Error(ERR_WARN, "element %d is no custom element", properties_element);
+
+ return;
+ }
+
+ ModifyGadget(gi, GDI_X, MAX(x1, MAX(x2, x3)) + xoffset, GDI_END);
+
+ DrawElementBorder(gi->x, gi->y, 3 * MINI_TILEX, 3 * MINI_TILEY, TRUE);
+
+ for (y=0; y<3; y++)
+ for (x=0; x<3; x++)
+ DrawMiniGraphicExt(drawto, gi->x + x * MINI_TILEX,gi->y + y * MINI_TILEY,
+ el2edimg(custom_element.content[x][y]));
+
+ MapDrawingArea(ED_DRAWING_ID_CUSTOM_CONTENT);
+}
+
+static void DrawCustomChangeTargetArea()
+{
+ int id = ED_DRAWING_ID_CUSTOM_CHANGE_TARGET;
+ int gadget_id = drawingarea_info[id].gadget_id;
+ struct GadgetInfo *gi = level_editor_gadget[gadget_id];
+#if 0
+ int xpos = ED_AREA_ELEM_CONTENT2_XPOS;
+ int ypos = ED_AREA_ELEM_CONTENT2_YPOS;
+ int area_sx = SX + xpos;
+ int area_sy = SY + ypos;
+#endif
+ int xoffset_left = 0;
+ int yoffset_left = ED_BORDER_AREA_YSIZE;
+ int xoffset_right = ED_GADGET_TEXT_DISTANCE + MINI_TILEX / 2;
+ int yoffset_right = ED_BORDER_AREA_YSIZE;
+ int x = drawingarea_info[id].x + xoffset_left;
+ int y = drawingarea_info[id].y + yoffset_left;
+
+ if (!IS_CUSTOM_ELEMENT(properties_element))
+ {
+ /* this should never happen */
+ Error(ERR_WARN, "element %d is no custom element", properties_element);
+
+ return;
+ }
+
+ DrawElementBorder(gi->x, gi->y, MINI_TILEX, MINI_TILEY, TRUE);
+ DrawMiniGraphicExt(drawto, gi->x, gi->y,
+ el2edimg(custom_element.change.target_element));
+
+ MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TARGET);
+
+ if (drawingarea_info[id].text_left)
+ DrawTextF(x, y, FONT_TEXT_1, drawingarea_info[id].text_left);
+
+ if (drawingarea_info[id].text_right)
+ {
+ x = gi->x + gi->width + xoffset_right;
+ y = SY + drawingarea_info[id].y + yoffset_right;
+
+ DrawText(x, y, drawingarea_info[id].text_right, FONT_TEXT_1);
+ }
+}
+
+static void DrawCustomChangeContentArea()
+{
+ struct GadgetInfo *gi = level_editor_gadget[GADGET_ID_CUSTOM_CHANGE_CONTENT];
+#if 0
+ int area_sx = SX + ED_AREA_ELEM_CONTENT6_XPOS;
+ int area_sy = SY + ED_AREA_ELEM_CONTENT6_YPOS;
+#endif
+ int x1 = right_gadget_border[GADGET_ID_CHANGE_USE_CONTENT];
+ int x2 = right_gadget_border[GADGET_ID_CHANGE_POWER];
+ int x3 = right_gadget_border[GADGET_ID_CHANGE_ONLY_COMPLETE];
+ int xoffset = ED_GADGET_TEXT_DISTANCE + MINI_TILEX / 2;
+ int x, y;
+
+ if (!IS_CUSTOM_ELEMENT(properties_element))
+ {
+ /* this should never happen */
+ Error(ERR_WARN, "element %d is no custom element", properties_element);
+
+ return;
+ }
+
+ ModifyGadget(gi, GDI_X, MAX(x1, MAX(x2, x3)) + xoffset, GDI_END);
+
+ DrawElementBorder(gi->x, gi->y, 3 * MINI_TILEX, 3 * MINI_TILEY, TRUE);
+
+ for (y=0; y<3; y++)
+ for (x=0; x<3; x++)
+ DrawMiniGraphicExt(drawto, gi->x + x * MINI_TILEX,gi->y + y * MINI_TILEY,
+ el2edimg(custom_element.change.content[x][y]));
+
+ MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT);
+}
+
+static void DrawCustomChangeTriggerArea()
+{
+ struct GadgetInfo *gi = level_editor_gadget[GADGET_ID_CUSTOM_CHANGE_TRIGGER];
+#if 0
+ int xpos = ED_AREA_ELEM_CONTENT5_XPOS;
+ int ypos = ED_AREA_ELEM_CONTENT5_YPOS;
+ int area_sx = SX + xpos;
+ int area_sy = SY + ypos;
+#endif
+
+ if (!IS_CUSTOM_ELEMENT(properties_element))
+ {
+ /* this should never happen */
+ Error(ERR_WARN, "element %d is no custom element", properties_element);
+
+ return;
+ }
+
+ DrawElementBorder(gi->x, gi->y, MINI_TILEX, MINI_TILEY, TRUE);
+ DrawMiniGraphicExt(drawto, gi->x, gi->y,
+ el2edimg(custom_element.change.trigger_element));
+
+ MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER);
+}
+
+static void DrawElementContentAreas()
+{
+ int area_x = ED_AREA_ELEM_CONTENT_XPOS / MINI_TILEX;
+ int area_y = ED_AREA_ELEM_CONTENT_YPOS / MINI_TILEY;
+ int area_sx = SX + ED_AREA_ELEM_CONTENT_XPOS;
+ int area_sy = SY + ED_AREA_ELEM_CONTENT_YPOS;
+ int i, x, y;
+
+ for (i=0; i<MAX_ELEMENT_CONTENTS; i++)
+ UnmapDrawingArea(GADGET_ID_ELEMENT_CONTENT_0 + i);
+
+ /* display counter to choose number of element content areas */
+ MapCounterButtons(ED_COUNTER_ID_ELEMENT_CONTENT);
+
+ /* delete content areas in case of reducing number of them */
+ DrawBackground(SX, area_sy - MINI_TILEX, SXSIZE, 12 * MINI_TILEY);
+
+ for (i=0; i<level.num_yamyam_contents; i++)
+ DrawElementBorder(area_sx + 5 * (i % 4) * MINI_TILEX,
+ area_sy + 6 * (i / 4) * MINI_TILEY,
+ 3 * MINI_TILEX, 3 * MINI_TILEY, TRUE);
+
+ DrawText(area_sx + (5 * 4 - 1) * MINI_TILEX, area_sy + 0 * MINI_TILEY + 1,
+ "Content", FONT_TEXT_1);
+ DrawText(area_sx + (5 * 4 - 1) * MINI_TILEX, area_sy + 1 * MINI_TILEY + 1,
+ "when", FONT_TEXT_1);
+ DrawText(area_sx + (5 * 4 - 1) * MINI_TILEX, area_sy + 2 * MINI_TILEY + 1,
+ "smashed", FONT_TEXT_1);
+
+ for (i=0; i<level.num_yamyam_contents; i++)
+ {
+ for (y=0; y<3; y++)
+ for (x=0; x<3; x++)
+ DrawMiniElement(area_x + 5 * (i % 4) + x, area_y + 6 * (i / 4) + y,
+ level.yamyam_content[i][x][y]);
+
+ DrawTextF(area_sx - SX + 5 * (i % 4) * MINI_TILEX + MINI_TILEX + 1,
+ area_sy - SY + 6 * (i / 4) * MINI_TILEY + 4 * MINI_TILEY - 4,
+ FONT_TEXT_1, "%d", i + 1);
+ }
+
+ for (i=0; i<level.num_yamyam_contents; i++)
+ MapDrawingArea(ED_DRAWING_ID_ELEMENT_CONTENT_0 + i);
+}
+
+char *getElementDescriptionFilename(int element)
+{
+ char *docs_dir = options.docs_directory;
+ char *elements_subdir = "elements";
+ static char *filename = NULL;
+ char basename[MAX_FILENAME_LEN];
+
+ if (filename != NULL)
+ free(filename);
+
+ /* 1st try: look for element description file for exactly this element */
+ sprintf(basename, "%s.txt", element_info[element].token_name);
+ filename = getPath3(docs_dir, elements_subdir, basename);
+ if (fileExists(filename))
+ return filename;
+
+ free(filename);
+
+ /* 2nd try: look for element description file for this element's class */
+ sprintf(basename, "%s.txt", element_info[element].class_name);
+ filename = getPath3(docs_dir, elements_subdir, basename);
+ if (fileExists(filename))
+ return filename;
+
+ return NULL;
+}
+
+static boolean PrintInfoText(char *text, int font_nr, int screen_line)
+{
+ int font_height = getFontHeight(font_nr);
+ int pad_x = ED_SETTINGS_XPOS(0);
+ int pad_y = ED_SETTINGS_YPOS(0) + ED_BORDER_SIZE;
+ int sx = SX + pad_x;
+ int sy = SY + pad_y;
+ int max_lines_per_screen = (SYSIZE - pad_y) / font_height - 1;
+
+ if (screen_line >= max_lines_per_screen)
+ return FALSE;
+
+ DrawText(sx, sy + screen_line * font_height, text, font_nr);
+
+ return TRUE;
+}
+
+static int PrintElementDescriptionFromFile(char *filename, int screen_line)
+{
+ int font_nr = FONT_TEXT_2;
+ int font_width = getFontWidth(font_nr);
+ int pad_x = ED_SETTINGS_XPOS(0);
+ int max_chars_per_line = (SXSIZE - 2 * pad_x) / font_width;
+ char line[MAX_LINE_LEN];
+ char buffer[max_chars_per_line + 1];
+ int buffer_len;
+ int lines_printed = 0;
+ FILE *file;
+
+ if (filename == NULL)
+ return 0;
+
+ if (!(file = fopen(filename, MODE_READ)))
+ return 0;
+
+ buffer[0] = '\0';
+ buffer_len = 0;
+
+ while(!feof(file))
+ {
+ char *line_ptr, *word_ptr;
+ boolean last_line_was_empty = TRUE;
+
+ /* read next line of input file */
+ if (!fgets(line, MAX_LINE_LEN, file))
+ break;
+
+ /* skip comments (lines directly beginning with '#') */
+ if (line[0] == '#')
+ continue;
+
+ /* cut trailing newline from input line */
+ for (line_ptr = line; *line_ptr; line_ptr++)
+ {
+ if (*line_ptr == '\n' || *line_ptr == '\r')
+ {
+ *line_ptr = '\0';
+ break;
+ }
+ }
+
+ if (strlen(line) == 0) /* special case: force empty line */
+ strcpy(line, "\n");
+
+ word_ptr = line;
+
+ while (*word_ptr)
+ {
+ boolean print_buffer = FALSE;
+ int word_len;
+
+ /* skip leading whitespaces */
+ while (*word_ptr == ' ' || *word_ptr == '\t')
+ word_ptr++;
+
+ line_ptr = word_ptr;
+ word_len = 0;
+
+ /* look for end of next word */
+ while (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != '\0')
+ {
+ line_ptr++;
+ word_len++;
+ }
+
+ if (word_len == 0)
+ {
+ continue;
+ }
+ else if (*word_ptr == '\n') /* special case: force empty line */
+ {
+ if (buffer_len == 0)
+ word_ptr++;
+
+ /* prevent printing of multiple empty lines */
+ if (buffer_len > 0 || !last_line_was_empty)
+ print_buffer = TRUE;
+ }
+ else if (word_len < max_chars_per_line - buffer_len)
+ {
+ /* word fits into text buffer -- add word */
+
+ if (buffer_len > 0)
+ buffer[buffer_len++] = ' ';
+
+ strncpy(&buffer[buffer_len], word_ptr, word_len);
+ buffer_len += word_len;
+ buffer[buffer_len] = '\0';
+ word_ptr += word_len;
+ }
+ else if (buffer_len > 0)
+ {
+ /* not enough space left for word in text buffer -- print buffer */
+
+ print_buffer = TRUE;
+ }
+ else
+ {
+ /* word does not fit at all into empty text buffer -- cut word */
+
+ strncpy(buffer, word_ptr, max_chars_per_line);
+ buffer[max_chars_per_line] = '\0';
+ word_ptr += max_chars_per_line;
+ print_buffer = TRUE;
+ }