dw_fluffos_v2/
dw_fluffos_v2/fluffos-2.9-ds2.05/
dw_fluffos_v2/fluffos-2.9-ds2.05/ChangeLog.old/
dw_fluffos_v2/fluffos-2.9-ds2.05/Win32/
dw_fluffos_v2/fluffos-2.9-ds2.05/compat/
dw_fluffos_v2/fluffos-2.9-ds2.05/compat/simuls/
dw_fluffos_v2/fluffos-2.9-ds2.05/include/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/clone/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/command/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/data/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/etc/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/include/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/inherit/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/inherit/master/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/log/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/single/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/single/tests/compiler/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/single/tests/efuns/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/single/tests/operators/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/u/
dw_fluffos_v2/fluffos-2.9-ds2.05/tmp/
dw_fluffos_v2/fluffos-2.9-ds2.05/windows/
dw_fluffos_v2/lib/
dw_fluffos_v2/lib/binaries/cmds/
dw_fluffos_v2/lib/binaries/cmds/creator/
dw_fluffos_v2/lib/binaries/cmds/living/
dw_fluffos_v2/lib/binaries/cmds/player/
dw_fluffos_v2/lib/binaries/d/admin/obj/
dw_fluffos_v2/lib/binaries/d/liaison/
dw_fluffos_v2/lib/binaries/global/virtual/
dw_fluffos_v2/lib/binaries/global/virtual/setup_compiler/
dw_fluffos_v2/lib/binaries/obj/handlers/autodoc/
dw_fluffos_v2/lib/binaries/obj/handlers/terrain_things/
dw_fluffos_v2/lib/binaries/obj/misc/
dw_fluffos_v2/lib/binaries/obj/misc/buckets/
dw_fluffos_v2/lib/binaries/obj/monster/
dw_fluffos_v2/lib/binaries/obj/reactions/
dw_fluffos_v2/lib/binaries/obj/reagents/
dw_fluffos_v2/lib/binaries/secure/cmds/creator/
dw_fluffos_v2/lib/binaries/secure/master/
dw_fluffos_v2/lib/binaries/std/
dw_fluffos_v2/lib/binaries/std/dom/
dw_fluffos_v2/lib/binaries/std/effects/object/
dw_fluffos_v2/lib/binaries/std/guilds/
dw_fluffos_v2/lib/binaries/std/languages/
dw_fluffos_v2/lib/binaries/std/races/
dw_fluffos_v2/lib/binaries/std/room/
dw_fluffos_v2/lib/binaries/std/room/basic/
dw_fluffos_v2/lib/binaries/std/shops/
dw_fluffos_v2/lib/binaries/std/shops/inherit/
dw_fluffos_v2/lib/binaries/www/
dw_fluffos_v2/lib/cmds/guild-race/
dw_fluffos_v2/lib/cmds/guild-race/crafts/
dw_fluffos_v2/lib/cmds/guild-race/other/
dw_fluffos_v2/lib/cmds/playtester/
dw_fluffos_v2/lib/cmds/playtester/senior/
dw_fluffos_v2/lib/d/admin/
dw_fluffos_v2/lib/d/admin/log/
dw_fluffos_v2/lib/d/admin/mapper/31-10-01/mapmaker/event/
dw_fluffos_v2/lib/d/admin/meetings/
dw_fluffos_v2/lib/d/admin/obj/
dw_fluffos_v2/lib/d/admin/room/we_care/
dw_fluffos_v2/lib/d/admin/save/
dw_fluffos_v2/lib/d/dist/
dw_fluffos_v2/lib/d/dist/mtf/
dw_fluffos_v2/lib/d/dist/pumpkin/
dw_fluffos_v2/lib/d/dist/pumpkin/chars/
dw_fluffos_v2/lib/d/dist/pumpkin/desert/
dw_fluffos_v2/lib/d/dist/pumpkin/gumboot/
dw_fluffos_v2/lib/d/dist/pumpkin/hospital/
dw_fluffos_v2/lib/d/dist/pumpkin/inherit/
dw_fluffos_v2/lib/d/dist/pumpkin/map/
dw_fluffos_v2/lib/d/dist/pumpkin/plain/
dw_fluffos_v2/lib/d/dist/pumpkin/pumpkin/
dw_fluffos_v2/lib/d/dist/pumpkin/save/
dw_fluffos_v2/lib/d/dist/pumpkin/squash/
dw_fluffos_v2/lib/d/dist/pumpkin/terrain/
dw_fluffos_v2/lib/d/dist/pumpkin/woods/
dw_fluffos_v2/lib/d/dist/start/
dw_fluffos_v2/lib/d/learning/TinyTown/buildings/
dw_fluffos_v2/lib/d/learning/TinyTown/map/
dw_fluffos_v2/lib/d/learning/TinyTown/roads/
dw_fluffos_v2/lib/d/learning/add_command/
dw_fluffos_v2/lib/d/learning/arms_and_weps/
dw_fluffos_v2/lib/d/learning/chars/
dw_fluffos_v2/lib/d/learning/cutnpaste/
dw_fluffos_v2/lib/d/learning/examples/npcs/
dw_fluffos_v2/lib/d/learning/examples/player_houses/npcs/
dw_fluffos_v2/lib/d/learning/examples/terrain_map/basic/
dw_fluffos_v2/lib/d/learning/functions/
dw_fluffos_v2/lib/d/learning/handlers/
dw_fluffos_v2/lib/d/learning/help_topics/npcs/
dw_fluffos_v2/lib/d/learning/help_topics/objects/
dw_fluffos_v2/lib/d/learning/help_topics/rcs_demo/
dw_fluffos_v2/lib/d/learning/help_topics/rooms/
dw_fluffos_v2/lib/d/learning/help_topics/rooms/crowd/
dw_fluffos_v2/lib/d/learning/help_topics/rooms/situations/
dw_fluffos_v2/lib/d/learning/items/
dw_fluffos_v2/lib/d/learning/save/
dw_fluffos_v2/lib/d/liaison/
dw_fluffos_v2/lib/d/liaison/NEWBIE/doc/
dw_fluffos_v2/lib/d/liaison/NEWBIE/save/oldlog/
dw_fluffos_v2/lib/db/
dw_fluffos_v2/lib/doc/
dw_fluffos_v2/lib/doc/creator/
dw_fluffos_v2/lib/doc/creator/autodoc/include/reaction/
dw_fluffos_v2/lib/doc/creator/autodoc/include/ritual_system/
dw_fluffos_v2/lib/doc/creator/autodoc/include/talker/
dw_fluffos_v2/lib/doc/creator/autodoc/include/terrain_map/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/baggage/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/clock/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/clothing/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/cont_save/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/corpse/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/money/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/monster/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/scabbard/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/service_provider/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/state_changer/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/wand/
dw_fluffos_v2/lib/doc/creator/autodoc/std/book_dir/
dw_fluffos_v2/lib/doc/creator/autodoc/std/key/
dw_fluffos_v2/lib/doc/creator/autodoc/std/learning/
dw_fluffos_v2/lib/doc/creator/autodoc/std/map/
dw_fluffos_v2/lib/doc/creator/autodoc/std/race/
dw_fluffos_v2/lib/doc/creator/autodoc/std/weapon_logic/
dw_fluffos_v2/lib/doc/creator/files/
dw_fluffos_v2/lib/doc/creator/policy/
dw_fluffos_v2/lib/doc/creator/room/
dw_fluffos_v2/lib/doc/effects/
dw_fluffos_v2/lib/doc/ideas/
dw_fluffos_v2/lib/doc/known_command/
dw_fluffos_v2/lib/doc/lpc/basic_manual/
dw_fluffos_v2/lib/doc/lpc/intermediate/
dw_fluffos_v2/lib/doc/new/add_command/
dw_fluffos_v2/lib/doc/new/handlers/
dw_fluffos_v2/lib/doc/new/living/
dw_fluffos_v2/lib/doc/new/living/race/
dw_fluffos_v2/lib/doc/new/living/spells/
dw_fluffos_v2/lib/doc/new/player/
dw_fluffos_v2/lib/doc/new/room/guild/
dw_fluffos_v2/lib/doc/new/room/outside/
dw_fluffos_v2/lib/doc/new/room/storeroom/
dw_fluffos_v2/lib/doc/object/
dw_fluffos_v2/lib/doc/playtesters/
dw_fluffos_v2/lib/doc/policy/
dw_fluffos_v2/lib/doc/weapons/
dw_fluffos_v2/lib/global/handlers/
dw_fluffos_v2/lib/global/virtual/setup_compiler/
dw_fluffos_v2/lib/include/
dw_fluffos_v2/lib/include/cmds/
dw_fluffos_v2/lib/include/effects/
dw_fluffos_v2/lib/include/npc/
dw_fluffos_v2/lib/include/shops/
dw_fluffos_v2/lib/net/daemon/chars/
dw_fluffos_v2/lib/net/inherit/
dw_fluffos_v2/lib/net/intermud3/
dw_fluffos_v2/lib/net/intermud3/services/
dw_fluffos_v2/lib/net/obj/
dw_fluffos_v2/lib/net/save/
dw_fluffos_v2/lib/net/smnmp/
dw_fluffos_v2/lib/net/snmp/
dw_fluffos_v2/lib/obj/amulets/
dw_fluffos_v2/lib/obj/b_day/
dw_fluffos_v2/lib/obj/examples/
dw_fluffos_v2/lib/obj/food/alcohol/
dw_fluffos_v2/lib/obj/food/chocolates/
dw_fluffos_v2/lib/obj/food/fruits/
dw_fluffos_v2/lib/obj/food/meat/
dw_fluffos_v2/lib/obj/food/nuts/
dw_fluffos_v2/lib/obj/food/seafood/
dw_fluffos_v2/lib/obj/food/vegetables/
dw_fluffos_v2/lib/obj/fungi/
dw_fluffos_v2/lib/obj/furnitures/artwork/
dw_fluffos_v2/lib/obj/furnitures/bathroom/
dw_fluffos_v2/lib/obj/furnitures/beds/
dw_fluffos_v2/lib/obj/furnitures/cabinets/
dw_fluffos_v2/lib/obj/furnitures/chairs/
dw_fluffos_v2/lib/obj/furnitures/chests/
dw_fluffos_v2/lib/obj/furnitures/clocks/
dw_fluffos_v2/lib/obj/furnitures/crockery/
dw_fluffos_v2/lib/obj/furnitures/cupboards/
dw_fluffos_v2/lib/obj/furnitures/cushions/
dw_fluffos_v2/lib/obj/furnitures/fake_plants/
dw_fluffos_v2/lib/obj/furnitures/lamps/
dw_fluffos_v2/lib/obj/furnitures/mirrors/
dw_fluffos_v2/lib/obj/furnitures/outdoor/
dw_fluffos_v2/lib/obj/furnitures/safes/
dw_fluffos_v2/lib/obj/furnitures/shelves/
dw_fluffos_v2/lib/obj/furnitures/sideboards/
dw_fluffos_v2/lib/obj/furnitures/sofas/
dw_fluffos_v2/lib/obj/furnitures/stoves/
dw_fluffos_v2/lib/obj/furnitures/tables/
dw_fluffos_v2/lib/obj/furnitures/wardrobes/
dw_fluffos_v2/lib/obj/handlers/
dw_fluffos_v2/lib/obj/handlers/autodoc/
dw_fluffos_v2/lib/obj/jewellery/anklets/
dw_fluffos_v2/lib/obj/jewellery/bracelets/
dw_fluffos_v2/lib/obj/jewellery/earrings/
dw_fluffos_v2/lib/obj/jewellery/misc/
dw_fluffos_v2/lib/obj/jewellery/necklaces/
dw_fluffos_v2/lib/obj/jewellery/rings/
dw_fluffos_v2/lib/obj/media/
dw_fluffos_v2/lib/obj/misc/buckets/
dw_fluffos_v2/lib/obj/misc/jars/
dw_fluffos_v2/lib/obj/misc/papers/
dw_fluffos_v2/lib/obj/misc/player_shop/
dw_fluffos_v2/lib/obj/misc/shops/
dw_fluffos_v2/lib/obj/misc/traps/
dw_fluffos_v2/lib/obj/monster/
dw_fluffos_v2/lib/obj/monster/godmother/
dw_fluffos_v2/lib/obj/monster/transport/
dw_fluffos_v2/lib/obj/plants/inherit/
dw_fluffos_v2/lib/obj/potions/
dw_fluffos_v2/lib/open/boards/
dw_fluffos_v2/lib/save/autodoc/
dw_fluffos_v2/lib/save/bank_accounts/
dw_fluffos_v2/lib/save/boards/frog/
dw_fluffos_v2/lib/save/books/bed_catalog/
dw_fluffos_v2/lib/save/creators/
dw_fluffos_v2/lib/save/mail/
dw_fluffos_v2/lib/save/mail/p/
dw_fluffos_v2/lib/save/soul/data/
dw_fluffos_v2/lib/save/tasks/
dw_fluffos_v2/lib/save/vaults/
dw_fluffos_v2/lib/secure/cmds/lord/
dw_fluffos_v2/lib/secure/config/
dw_fluffos_v2/lib/secure/items/
dw_fluffos_v2/lib/secure/player/
dw_fluffos_v2/lib/soul/
dw_fluffos_v2/lib/soul/i/
dw_fluffos_v2/lib/soul/j/
dw_fluffos_v2/lib/soul/k/
dw_fluffos_v2/lib/soul/o/
dw_fluffos_v2/lib/soul/q/
dw_fluffos_v2/lib/soul/to_approve/
dw_fluffos_v2/lib/soul/u/
dw_fluffos_v2/lib/soul/v/
dw_fluffos_v2/lib/soul/wish_list/
dw_fluffos_v2/lib/soul/y/
dw_fluffos_v2/lib/soul/z/
dw_fluffos_v2/lib/std/creator/
dw_fluffos_v2/lib/std/effects/
dw_fluffos_v2/lib/std/effects/attached/
dw_fluffos_v2/lib/std/effects/external/
dw_fluffos_v2/lib/std/effects/fighting/
dw_fluffos_v2/lib/std/effects/other/
dw_fluffos_v2/lib/std/environ/
dw_fluffos_v2/lib/std/guilds/
dw_fluffos_v2/lib/std/hospital/
dw_fluffos_v2/lib/std/house/
dw_fluffos_v2/lib/std/house/onebedhouse/
dw_fluffos_v2/lib/std/house/onebedhut/
dw_fluffos_v2/lib/std/house/tworoomflat/
dw_fluffos_v2/lib/std/languages/
dw_fluffos_v2/lib/std/liquids/
dw_fluffos_v2/lib/std/nationality/
dw_fluffos_v2/lib/std/nationality/accents/
dw_fluffos_v2/lib/std/nationality/accents/national/
dw_fluffos_v2/lib/std/nationality/accents/regional/
dw_fluffos_v2/lib/std/npc/goals/
dw_fluffos_v2/lib/std/npc/goals/basic/
dw_fluffos_v2/lib/std/npc/goals/misc/
dw_fluffos_v2/lib/std/npc/inherit/
dw_fluffos_v2/lib/std/npc/plans/
dw_fluffos_v2/lib/std/npc/plans/basic/
dw_fluffos_v2/lib/std/outsides/
dw_fluffos_v2/lib/std/races/shadows/
dw_fluffos_v2/lib/std/room/basic/topography/
dw_fluffos_v2/lib/std/room/controller/
dw_fluffos_v2/lib/std/room/controller/topography/
dw_fluffos_v2/lib/std/room/furniture/games/
dw_fluffos_v2/lib/std/room/furniture/inherit/
dw_fluffos_v2/lib/std/room/inherit/carriage/
dw_fluffos_v2/lib/std/room/inherit/topography/
dw_fluffos_v2/lib/std/room/punishments/
dw_fluffos_v2/lib/std/room/topography/area/
dw_fluffos_v2/lib/std/room/topography/iroom/
dw_fluffos_v2/lib/std/room/topography/milestone/
dw_fluffos_v2/lib/std/shadows/
dw_fluffos_v2/lib/std/shadows/attached/
dw_fluffos_v2/lib/std/shadows/curses/
dw_fluffos_v2/lib/std/shadows/disease/
dw_fluffos_v2/lib/std/shadows/fighting/
dw_fluffos_v2/lib/std/shadows/room/
dw_fluffos_v2/lib/std/shops/controllers/
dw_fluffos_v2/lib/std/shops/objs/
dw_fluffos_v2/lib/std/shops/player_shop/
dw_fluffos_v2/lib/std/shops/player_shop/office_code/
dw_fluffos_v2/lib/std/socket/
dw_fluffos_v2/lib/www/
dw_fluffos_v2/lib/www/external/autodoc/
dw_fluffos_v2/lib/www/external/java/telnet/Documentation/
dw_fluffos_v2/lib/www/external/java/telnet/Documentation/images/
dw_fluffos_v2/lib/www/external/java/telnet/examples/
dw_fluffos_v2/lib/www/external/java/telnet/tools/
dw_fluffos_v2/lib/www/pics/
dw_fluffos_v2/lib/www/secure/creator/
dw_fluffos_v2/lib/www/secure/editors/
dw_fluffos_v2/lib/www/secure/survey_results/
dw_fluffos_v2/win32/
/*  -*- LPC -*-  */
/*
 * $Locker:  $
 * $Id: nroff.c,v 1.9 2003/01/29 17:23:50 wyvyrn Exp $
 * $Log: nroff.c,v $
 * Revision 1.9  2003/01/29 17:23:50  wyvyrn
 * Fixed up justification on document title (.DT) for mud and web viewing
 *
 * Revision 1.7  2001/06/13 22:58:51  pinkfish
 * Fix up the columns stuff for the nroffing of files
 *
 * Revision 1.6  2001/02/05 20:20:02  pinkfish
 * Fix up columns.
 *
 * Revision 1.5  1999/10/28 02:22:21  ceres
 * can't remember
 *
 * Revision 1.4  1998/03/26 10:23:32  pinkfish
 * Make it handle html files neater.
 *
 * Revision 1.3  1998/03/26 10:11:54  pinkfish
 * Change the nroff system to not break when there is no
 * this_)player and doing a cat_file
 *
 * Revision 1.2  1998/03/06 10:22:50  pinkfish
 * Make the header stuff look better in html files.
 *
 * Revision 1.1  1998/01/06 05:03:33  ceres
 * Initial revision
 * 
*/
/**
 * An nroff like object for formating text files.
 *<p>
 * This creates a saveable file format thingy.
 *
 * @author Pinkfish
 */
#include <nroff.h>

mixed *nroffed_file;
string nroffed_file_name;
int modified_time;
nosave int new_string;
nosave int force_string;

void create() {
  nroffed_file = ({ });
  seteuid("Root"); /* Security risk?  nahhhhh */
} /* create() */

#define do_bounds(bing) (bing<0?bing+cols:bing)

/**
 * Creates a string from a nroffed file.
 * <p>
 * If update is non zero it will look to see if the source file has been 
 * modified since the saved nroff file was created.  If it has, this
 * function returns 0 and the nroff file needs to be recreated.
 *
 * @param fname the file to process
 * @param update force update if file is newer?
 * @return the string representation of the nroff file
 */
string cat_file(string fname, int update) {
   int i;
   int k;
   int cols;
   string ret;
   string pat;
   mixed* tmp;
   
   if (!master()->valid_read(fname, geteuid(previous_object()),
                             "restore_object")) {
      return 0;
   }
   nroffed_file_name = 0;
   modified_time = 0;
   if (!restore_object(fname))
      return 0;
   if (!nroffed_file_name && update)
      return 0;
   if (update) {
      mixed *something;
      
      if (!master()->valid_read(nroffed_file_name,
                                geteuid(previous_object()),
                                "restore_object"))
         return 0;
      if (file_size(nroffed_file_name) <= 0)
         return 0;
      something = stat(nroffed_file_name);
      if (something[1] > modified_time)
         return 0;
   }
   ret = "";
   if (this_player()) {
      cols = (int)this_player()->query_cols();
   } else {
      cols = 79;
   }
   for (i=0;i<sizeof(nroffed_file);i++) {
      if (stringp(nroffed_file[i])) {
         ret += nroffed_file[i];
      } else {     
         switch (nroffed_file[i]) {
          case V_HEADER :
            ret += sprintf("%%^BOLD%%^%s%%^RESET%%^\n", nroffed_file[i+1]);
            i++;
            break;
          case V_CENTER :
            ret += sprintf("%|=*s", cols, nroffed_file[i+1]);
            i++;
            break;
          case V_ALL :
            ret += "%^BOLD%^\n" + sprintf("%-s%*|s%*s\n",
                           nroffed_file[i+2],
                           cols - nroffed_file[i+1]*2,
                           nroffed_file[i+3],
                           nroffed_file[i+1],
                           nroffed_file[i+4]) + "%^RESET%^\n";
//if (this_player() == find_player("presto"))  write("middle == :" + nroffed_file[i + 3] + ":\n" + nroffed_file[i + 1] + "\n");
//if (this_player() == find_player("wyvyrn"))  write( "file: '" + nroffed_file[i+1] + "', left: '" + nroffed_file[i+2] + "', centre: '" + nroffed_file[i+3] + "', right: '" + nroffed_file[i+4] + "'\n");
            i += 4;
            break;
          case V_INDENT :
            ret += sprintf( "%*=s%-=*s", nroffed_file[ i + 1 ], "",
                           cols - nroffed_file[ i + 1 ], nroffed_file[ i + 2 ] );
            i += 2;
            break;
          case V_PARA :
            if (nroffed_file[i+1])
            ret += sprintf("%*=s%-=*s%=*s\n", nroffed_file[i+1], "",
                           cols-nroffed_file[i+1]-
                           nroffed_file[i+2], nroffed_file[i+3],
                           nroffed_file[i+2], "");
            else if (nroffed_file[i+2])
            ret += sprintf("%-=*s%=*s\n", cols-nroffed_file[i+2],
                           nroffed_file[i+3],
                           nroffed_file[i+2], "");
            else
            ret += sprintf("%-=*s\n", cols, nroffed_file[i+3]);
            i += 3;
            break;
          case V_LEFT :
            ret += sprintf("%-=*s", cols, nroffed_file[i+1]);
            i++;
            break;
          case V_TABLE :
            ret += sprintf("%-#*s", cols, nroffed_file[i+1]);
            i++;
            break;
          case V_COLUMN : {
             int j;
             
             switch (sizeof(nroffed_file[i+1])) {
              case 2 :
                for (j=0;j<sizeof(nroffed_file[i+2]);j++) {
                   ret += sprintf("%*-=s%*-=s\n", do_bounds(nroffed_file[i+1][0]),
                                  nroffed_file[i+2][j],
                                  do_bounds(nroffed_file[i+1][1]),
                                  nroffed_file[i+3][j]);
                }
                i += 3;
                break;
              case 3 :
                for (j=0;j<sizeof(nroffed_file[i+2]);j++) {
                   ret += sprintf("%*-=s%*-=s%*-=s\n",
                               do_bounds(nroffed_file[i+1][0]),
                               nroffed_file[i+2][j],
                               do_bounds(nroffed_file[i+1][1]),
                               nroffed_file[i+3][j],
                               do_bounds(nroffed_file[i+1][2]),
                               nroffed_file[i+4][j]);
                }
                i += 4;
                break;
             default :
                pat = implode(allocate(sizeof(nroffed_file[i+1]), "%*-=s"), "");
                for (j=0;j<sizeof(nroffed_file[i+2]);j++) {
                   tmp = ({ });
                   for (k = 0; k < sizeof(nroffed_file[i+1]); k++) {
                      tmp += ({ do_bounds(nroffed_file[i+1][k]),
                                nroffed_file[i+2+k][j] });
                   }
                   ret += sprintf(pat + "\n", tmp ... );
                }
                i += sizeof(nroffed_file[i+1]) + 1;
                break;
             }
             break;
          }
         }
      }
   }
   return " \n"+ret;
} /* cat_file() */

/**
 * @ignore yes
 */
private string htmlify(string  str) {
  return replace(str, ({ "&", "&amp;", "<", "&lt;", ">", "&gt;"}));
} /* htmlify() */

/**
 * Turns the nroff file into a html output.  This works on nroff files
 * creating a html output from the mud source.
 *
 * @param file the name to process
 * @param title the title to give the document
 * @return the html file
 */
string html_file(string file, string title) {
   int i, j, cols, in_bold, in_italic;
   int k;
   string ret, *bits;
   
   if (!master()->valid_read(file, geteuid(previous_object()),
                             "restore_object"))
      return 0;
   nroffed_file_name = 0;
   modified_time = 0;
   if (!restore_object(file))
      return 0;
   ret = "";
   cols = 78;

   for (i=0;i<sizeof(nroffed_file);i++)
     if (stringp(nroffed_file[i]))
       nroffed_file[i] = htmlify(nroffed_file[i]);
     else if(arrayp(nroffed_file[i])) {
       for (j=0;j<sizeof(nroffed_file[i]);j++)
         if(stringp(nroffed_file[i][j]))
           nroffed_file[i][j] = htmlify(nroffed_file[i][j]);
     }           

   
   for (i=0;i<sizeof(nroffed_file);i++) {
      if (stringp(nroffed_file[i])) {
         ret += "<h3>"+nroffed_file[i]+"</h3>";

#ifdef UNUSED         
         if(strsrch(nroffed_file[i], "See also") > -1) {
           for(j=i+1; j < sizeof(nroffed_file); j++) {
             if(stringp(nroffed_file[j])) {
               nroffed_file[j] = make_links(nroffed_file[j]);
             }
           }
         }
#endif         
      } else {
         switch (nroffed_file[i]) {
          case V_HEADER :
            ret += "<h3>"+replace_string(nroffed_file[i+1], "\n", "<br>")+
              "</h3>";
            i++;
            break;
          case V_CENTER :
            ret += "<center>"+replace(nroffed_file[i+1], "\n", "<br>")+
            "</center>";
            i++;
            break;
          case V_ALL :
            ret += "\n<table width=100%><tr>\n" + 
                   "<td nowrap width=* align=left><h2>" + 
                   nroffed_file[i+2] + "</h2></td>\n" + 
                   "<td nowrap align=center><h2>" + 
                   nroffed_file[i+3] + "</h2></td>\n" + 
                   "<td nowrap width=* align=right><h2>" + 
                   nroffed_file[i+4] + "</h2></td>\n" + 
                   "</tr></table>\n";
            i += 4;
            break;
          case V_INDENT :
            ret += replace(nroffed_file[i+2], ({"<", "&lt;", ">",
               "&gt;", "\n", "<br>"}));
            i += 2;
            break;
          case V_PARA :
            ret += replace(nroffed_file[i+3], "\n", "<p>");
            i += 3;
            break;
          case V_LEFT :
            ret += "<left>"+nroffed_file[i+1]+"</left>";
            i++;
            break;
          case V_TABLE :
            ret += "<ul><li>"+replace(nroffed_file[i+1], "\n", "<li>")+"</ul>";
            i++;
            break;
          case V_COLUMN : {
             ret += "<table cellpadding=10>";
             switch (sizeof(nroffed_file[i+1])) {
              case 2 :
                for (j=0;j<sizeof(nroffed_file[i+2]);j++) {
                  ret += "<tr>\n";
                  ret += "<td nowrap>"+nroffed_file[i+2][j] + "</td>";
                  ret += "<td>"+nroffed_file[i+3][j] + "</td>";
                  ret += "</tr>";
                }
                i += 3;
                break;
              case 3 :
                for (j=0;j<sizeof(nroffed_file[i+2]);j++) {
                  ret += "<tr>\n";
                  ret += "<td nowrap>"+nroffed_file[i+2][j] + "</td>";
                  ret += "<td nowrap>"+nroffed_file[i+3][j] + "</td>";
                  ret += "<td>"+nroffed_file[i+4][j] + "</td>";
                  ret += "</tr>";
                }
                i += 4;
                break;
             default :
                for (j=0;j<sizeof(nroffed_file[i+2]);j++) {
                   ret += "<tr>\n";
                   for (k = 0; k < sizeof(nroffed_file[i+1]); k++) {
                      ret += "<td nowrap>" + nroffed_file[i+2+k][j] + "</td>\n";
                   }
                   ret += "</tr>\n";
                }
                i += sizeof(nroffed_file[i+1]) + 1;
                break;
             }
             ret += "</table>";
             break;
          }
         }
      }
   }
   
   bits = explode(ret, "%^");
   ret = "";
   for (i=0;i<sizeof(bits);i+=2) {
      ret += bits[i];
    if (i+1 < sizeof(bits)) {
       switch (bits[i+1]) {
        case "BOLD" :
          if (!in_bold)
             ret += "<strong>";
          else
             ret += "</strong>";
          in_bold = !in_bold;
          break;
        case "RESET" :
          if (in_bold)
             ret += "</strong>";
          if (in_italic)
             ret += "</i>";
          in_bold = 0;
          in_italic = 0;
          break;
        default :
          if (!in_italic)
             ret += "<i>";
          else
             ret += "</i>";
          in_italic = !in_italic;
          break;
       }
    }
   }
   return ret;
} /* html_file() */

private void add_array(mixed *i) {
  if (!sizeof(nroffed_file)) {
    nroffed_file += ({ i });
  } else if (force_string) {
    nroffed_file += ({ "", i });
  } else {
    nroffed_file += ({ i });
  }
  force_string = 0;
  new_string = 0;
} /* add_array() */

private void add_int(int i) {
  if (!sizeof(nroffed_file)) {
    nroffed_file += ({ i });
  } else if (force_string) {
    nroffed_file += ({ "", i });
  } else {
    nroffed_file += ({ i });
  }
  force_string = 0;
  new_string = 0;
} /* add_int() */

private void add_string(string s) {
  if (!sizeof(nroffed_file) || new_string) {
    nroffed_file += ({ s });
  } else if (stringp(nroffed_file[<1])) {
    nroffed_file[<1] += s;
  } else {
    nroffed_file += ({ s });
  }
  new_string = 0;
  force_string = 0;
} /* add_string() */

/**
 * Makes the nroff saveable file.  Turns the input nroff file into a saved
 * output format.
 *
 * @param in_file the file name been processed
 * @param out_file the file to save it as
 * @return 1 if the operation was successful
 */
int create_nroff(string in_file, string out_file) {
  string text,
         tmp,
         *bits;
  string *bing;
  mixed  *cols;
  int strip_crs,
      col_mode,
      conv_tabs,
      i, j, k, fluff,
      num_cols;

  if (!master()->valid_read(in_file, geteuid(previous_object()),
                            "read_file"))
    return 0;
  nroffed_file_name = in_file;
  modified_time = time();
  text = read_file(in_file);
  if (!text) {
    return 0;
  }
  bits = explode("#\n"+text, "\n.");
  bits[0] = bits[0][1..];
  nroffed_file = ({ 0 });
  if (strlen(bits[0])) {
    add_string(bits[0]);
  }
  for (i=1;i<sizeof(bits);i++) {
     if (sscanf(bits[i], "%s\n%s", tmp, bits[i]) != 2) {
        tmp = bits[i];
        bits[i] = "";
        fluff = 1;
     } else {
        fluff = 0;
     }
     switch (tmp[0..1]) {
      case "SH" : /* Section header */
        add_int(V_HEADER);
        add_string(tmp[3..]);
        new_string = 1;
        break;
      case "SI" : /* Start indent */
        add_int(V_INDENT);
        j = 0;
        sscanf(tmp[2..], "%d%s", j, tmp);
        add_int(j);
        force_string = 1;
        break;
      case "EI" : /* End indent */
        add_string("");
        new_string = 1;
        break;
      case "SP" : /* Start paragraph */
        add_int(V_PARA);
        j = 0;
        sscanf(tmp[2..], "%d%s", j, tmp);
        add_int(j);
        j = 0;
        sscanf(tmp, " %d%s", j, tmp);
        add_int(j);
        force_string = 1;
        strip_crs = 1;
        break;
      case "EP" : /* End paragraph */
        add_string("");
        new_string = 1;
        strip_crs = 0;
        break;
      case "SC" : /* start centering */
        add_int(V_CENTER);
        force_string = 1;
        break;
      case "EC" : /* End centering */
        new_string = 1;
        break;
      case "SL" : /* Start left justify */
        add_int(V_LEFT);
        force_string = 1;
        break;
      case "EL " : /* End left justify */
        new_string = 1;
        break;
      case "ST" : /* Start table mode (Turn tabs into new lines) */
        add_int(V_TABLE);
        force_string = 1;
        conv_tabs = 1;
        break;
      case "ET" : /* End table mode */
        new_string = 1;
        conv_tabs = 0;
        break;
      case "DT" : /* Do title.  Take the next three lines... */
        bing = explode(bits[i], "\n");
        if (sizeof(bing) < 3) {
           if (this_player()->query_creator()) {
              tell_object(this_player(), "Text file "+in_file+
                          " did not have enough lines after the .DT directive.\n");
              tell_object(this_player(), sprintf("%O\n", bing));
           }
           return 0; /* failed! */
        }
        add_int(V_ALL);
        if (strlen(bing[0]) > strlen(bing[2]))
           add_int(strlen(bing[0]));
        else
           add_int(strlen(bing[2]));
        new_string = 1;
        add_string(bing[0]);
        new_string = 1;
        add_string(bing[1]);
        new_string = 1;
        add_string(bing[2]);
        new_string = 1;
        bits[i] = implode(bing[3..], "\n");
        break;
      case "SO" : /* starts column mode. The numbers after it
                   * are column size */
        num_cols = 0;
        tmp = tmp[2..];
        cols = ({ });
        while (sscanf(tmp, "%d%s", j, tmp) == 2) {
           cols += ({ j });
           num_cols++;
           while (strlen(tmp) && tmp[0] == ' ')
           tmp = tmp[1..];
        }
        add_int(V_COLUMN);
        if (sscanf(tmp, "%d", j) == 1) {
           cols += ({ j });
           num_cols++;
        }
        add_array(cols);
        cols = allocate(num_cols);
        for (j=0;j<num_cols;j++) {
           cols[j] = ({ });
        }
        col_mode = 1;
        break;
      case "EO" : /* End column mode */
        for (j=0;j<num_cols;j++) {
           add_array(cols[j]);
        }
        col_mode = 0;
        break;
      case "NF" : /* New File.  Take the next line and ignore everything
                   * else in the file */
        bing = explode(bits[i], "\n");
        if (sizeof(bing) < 1) {
           if (this_player()->query_creator()) {
              tell_object(this_player(), "Text file "+in_file+
                          " did not have enough lines after the .NF directive.\n");
              tell_object(this_player(), sprintf("%O\n", bing));
           }
           return 0; /* failed! */
        }
        /* read the new file and start again, but keep the old name */
        text = read_file(bing[ 0 ]);
        if (!text) {
          return 0;
        }
        bits = explode("#\n"+text, "\n.");
        bits[0] = bits[0][1..];
        nroffed_file = ({ 0 });
        if (strlen(bits[0])) {
           add_string(bits[0]);
        }
        strip_crs = col_mode = conv_tabs = fluff = num_cols = i = 0;
        break;
     }
     if (fluff) {
        continue;
     }
     if (conv_tabs) {
        bits[i] = replace(bits[i], "\t", "\n");
     }
     if (col_mode) {
        string *frog;
        
        frog = explode(bits[i], "\n");
        for (k = 0; k < sizeof(frog); k++) {
           bing = explode("#"+frog[k], "\t");
           bing[0] = bing[0][1..];
           for (j = 0; j < num_cols && j < sizeof(bing); j++) {
              cols[j] += ({ bing[j] });
           }
           for (j = sizeof(bing);j < num_cols; j++) {
              cols[j] += ({ "\n" });
           }
        }
     } else if (strip_crs) {
        bits[i] = replace_string(bits[i], "\n\n", "$%^NeW_LiNe^%$");
        bits[i] = replace_string(bits[i], ".\n", ".  ");
        bits[i] = replace_string(bits[i], "\n", " ");
        bits[i] = replace_string(bits[i], "$%^NeW_LiNe^%$", "\n\n");
        add_string(bits[i]+" ");
     } else {
        add_string(bits[i]+"\n");
     }
  }
  new_string = 0;
  force_string = 0;
  unguarded((: save_object, out_file :));
  return 1;
} /* create_nroff() */

/**
 * Will attempt to find the name of the nroffed file.  Will attempt to
 * find the name of the source file associated with the save file.
 *
 * @param fname the name of the file to check
 * @return the source file name or 0
 */
string query_file_name( string fname ) {
   if (!master()->valid_read(fname, geteuid(previous_object()),
                             "restore_object")) {
      return 0;
   }
   nroffed_file_name = 0;
   modified_time = 0;
   if (!restore_object(fname)) {
      return 0;
   }
   return nroffed_file_name;
} /* query_file_name() */