2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 // common.c -- misc functions used in client and server
30 cvar_t registered = {0, "registered","0"};
31 cvar_t cmdline = {0, "cmdline","0"};
33 extern qboolean fs_modified; // set true if using non-id files
37 const char **com_argv;
39 // LordHavoc: made commandline 1024 characters instead of 256
40 #define CMDLINE_LENGTH 1024
41 char com_cmdline[CMDLINE_LENGTH];
45 const char *gamedirname;
46 const char *gamescreenshotname;
47 char com_modname[MAX_OSPATH] = "";
51 ============================================================================
55 ============================================================================
58 short ShortSwap (short l)
77 return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
80 float FloatSwap (float f)
90 dat2.b[0] = dat1.b[3];
91 dat2.b[1] = dat1.b[2];
92 dat2.b[2] = dat1.b[1];
93 dat2.b[3] = dat1.b[0];
98 // Extract integers from buffers
100 unsigned int BuffBigLong (const qbyte *buffer)
102 return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
105 unsigned short BuffBigShort (const qbyte *buffer)
107 return (buffer[0] << 8) | buffer[1];
110 unsigned int BuffLittleLong (const qbyte *buffer)
112 return (buffer[3] << 24) | (buffer[2] << 16) | (buffer[1] << 8) | buffer[0];
115 unsigned short BuffLittleShort (const qbyte *buffer)
117 return (buffer[1] << 8) | buffer[0];
122 ==============================================================================
126 Handles byte ordering and avoids alignment errors
127 ==============================================================================
134 void MSG_WriteChar (sizebuf_t *sb, int c)
138 buf = SZ_GetSpace (sb, 1);
142 void MSG_WriteByte (sizebuf_t *sb, int c)
146 buf = SZ_GetSpace (sb, 1);
150 void MSG_WriteShort (sizebuf_t *sb, int c)
154 buf = SZ_GetSpace (sb, 2);
159 void MSG_WriteLong (sizebuf_t *sb, int c)
163 buf = SZ_GetSpace (sb, 4);
165 buf[1] = (c>>8)&0xff;
166 buf[2] = (c>>16)&0xff;
170 void MSG_WriteFloat (sizebuf_t *sb, float f)
180 dat.l = LittleLong (dat.l);
182 SZ_Write (sb, &dat.l, 4);
185 void MSG_WriteString (sizebuf_t *sb, const char *s)
188 SZ_Write (sb, "", 1);
190 SZ_Write (sb, s, strlen(s)+1);
193 void MSG_WriteCoord13i (sizebuf_t *sb, float f)
196 MSG_WriteShort (sb, (int)(f * 8.0 + 0.5));
198 MSG_WriteShort (sb, (int)(f * 8.0 - 0.5));
201 void MSG_WriteCoord16i (sizebuf_t *sb, float f)
204 MSG_WriteShort (sb, (int)(f + 0.5));
206 MSG_WriteShort (sb, (int)(f - 0.5));
209 void MSG_WriteCoord32f (sizebuf_t *sb, float f)
211 MSG_WriteFloat (sb, f);
214 void MSG_WriteCoord (sizebuf_t *sb, float f, int protocol)
216 if (protocol == PROTOCOL_QUAKE)
217 MSG_WriteCoord13i (sb, f);
218 else if (protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES5)
219 MSG_WriteCoord32f (sb, f);
220 else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
221 MSG_WriteCoord16i (sb, f);
223 Host_Error("MSG_WriteCoord: unknown protocol\n");
226 void MSG_WriteVector (sizebuf_t *sb, float *v, int protocol)
228 MSG_WriteCoord (sb, v[0], protocol);
229 MSG_WriteCoord (sb, v[1], protocol);
230 MSG_WriteCoord (sb, v[2], protocol);
233 // LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
234 void MSG_WriteAngle8i (sizebuf_t *sb, float f)
237 MSG_WriteByte (sb, (int)(f*(256.0/360.0) + 0.5) & 255);
239 MSG_WriteByte (sb, (int)(f*(256.0/360.0) - 0.5) & 255);
242 void MSG_WriteAngle16i (sizebuf_t *sb, float f)
245 MSG_WriteShort (sb, (int)(f*(65536.0/360.0) + 0.5) & 65535);
247 MSG_WriteShort (sb, (int)(f*(65536.0/360.0) - 0.5) & 65535);
250 void MSG_WriteAngle32f (sizebuf_t *sb, float f)
252 MSG_WriteFloat (sb, f);
255 void MSG_WriteAngle (sizebuf_t *sb, float f, int protocol)
257 if (protocol == PROTOCOL_DARKPLACES5)
258 MSG_WriteAngle16i (sb, f);
260 MSG_WriteAngle8i (sb, f);
267 qboolean msg_badread;
269 void MSG_BeginReading (void)
275 int MSG_ReadLittleShort (void)
277 if (msg_readcount+2 > net_message.cursize)
283 return (short)(net_message.data[msg_readcount-2] | (net_message.data[msg_readcount-1]<<8));
286 int MSG_ReadBigShort (void)
288 if (msg_readcount+2 > net_message.cursize)
294 return (short)((net_message.data[msg_readcount-2]<<8) + net_message.data[msg_readcount-1]);
297 int MSG_ReadLittleLong (void)
299 if (msg_readcount+4 > net_message.cursize)
305 return net_message.data[msg_readcount-4] | (net_message.data[msg_readcount-3]<<8) | (net_message.data[msg_readcount-2]<<16) | (net_message.data[msg_readcount-1]<<24);
308 int MSG_ReadBigLong (void)
310 if (msg_readcount+4 > net_message.cursize)
316 return (net_message.data[msg_readcount-4]<<24) + (net_message.data[msg_readcount-3]<<16) + (net_message.data[msg_readcount-2]<<8) + net_message.data[msg_readcount-1];
319 float MSG_ReadLittleFloat (void)
326 if (msg_readcount+4 > net_message.cursize)
332 dat.l = net_message.data[msg_readcount-4] | (net_message.data[msg_readcount-3]<<8) | (net_message.data[msg_readcount-2]<<16) | (net_message.data[msg_readcount-1]<<24);
336 float MSG_ReadBigFloat (void)
343 if (msg_readcount+4 > net_message.cursize)
349 dat.l = (net_message.data[msg_readcount-4]<<24) | (net_message.data[msg_readcount-3]<<16) | (net_message.data[msg_readcount-2]<<8) | net_message.data[msg_readcount-1];
353 char *MSG_ReadString (void)
355 static char string[2048];
357 for (l = 0;l < (int) sizeof(string) - 1 && (c = MSG_ReadChar()) != -1 && c != 0;l++)
363 int MSG_ReadBytes (int numbytes, unsigned char *out)
366 for (l = 0;l < numbytes && (c = MSG_ReadChar()) != -1;l++)
371 float MSG_ReadCoord13i (void)
373 return MSG_ReadLittleShort() * (1.0/8.0);
376 float MSG_ReadCoord16i (void)
378 return (signed short) MSG_ReadLittleShort();
381 float MSG_ReadCoord32f (void)
383 return MSG_ReadLittleFloat();
386 float MSG_ReadCoord (int protocol)
388 if (protocol == PROTOCOL_QUAKE || protocol == 250)
389 return MSG_ReadCoord13i();
390 else if (protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES5)
391 return MSG_ReadCoord32f();
392 else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
393 return MSG_ReadCoord16i();
394 Host_Error("MSG_ReadCoord: unknown protocol\n");
398 void MSG_ReadVector (float *v, int protocol)
400 v[0] = MSG_ReadCoord(protocol);
401 v[1] = MSG_ReadCoord(protocol);
402 v[2] = MSG_ReadCoord(protocol);
405 // LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
406 float MSG_ReadAngle8i (void)
408 return (signed char) MSG_ReadByte () * (360.0/256.0);
411 float MSG_ReadAngle16i (void)
413 return (signed short)MSG_ReadShort () * (360.0/65536.0);
416 float MSG_ReadAngle32f (void)
418 return MSG_ReadFloat ();
421 float MSG_ReadAngle (int protocol)
423 if (protocol == PROTOCOL_DARKPLACES5)
424 return MSG_ReadAngle16i ();
426 return MSG_ReadAngle8i ();
430 //===========================================================================
432 void SZ_Alloc (sizebuf_t *buf, int startsize, const char *name)
436 buf->mempool = Mem_AllocPool(name, 0, NULL);
437 buf->data = Mem_Alloc(buf->mempool, startsize);
438 buf->maxsize = startsize;
443 void SZ_Free (sizebuf_t *buf)
445 Mem_FreePool(&buf->mempool);
451 void SZ_Clear (sizebuf_t *buf)
456 void *SZ_GetSpace (sizebuf_t *buf, int length)
460 if (buf->cursize + length > buf->maxsize)
462 if (!buf->allowoverflow)
463 Host_Error ("SZ_GetSpace: overflow without allowoverflow set\n");
465 if (length > buf->maxsize)
466 Host_Error ("SZ_GetSpace: %i is > full buffer size\n", length);
468 buf->overflowed = true;
469 Con_Print("SZ_GetSpace: overflow\n");
473 data = buf->data + buf->cursize;
474 buf->cursize += length;
479 void SZ_Write (sizebuf_t *buf, const void *data, int length)
481 memcpy (SZ_GetSpace(buf,length),data,length);
484 // LordHavoc: thanks to Fuh for bringing the pure evil of SZ_Print to my
485 // attention, it has been eradicated from here, its only (former) use in
486 // all of darkplaces.
488 static char *hexchar = "0123456789ABCDEF";
489 void Com_HexDumpToConsole(const qbyte *data, int size)
493 char *cur, *flushpointer;
496 flushpointer = text + 512;
497 for (i = 0;i < size;)
504 *cur++ = hexchar[(i >> 12) & 15];
505 *cur++ = hexchar[(i >> 8) & 15];
506 *cur++ = hexchar[(i >> 4) & 15];
507 *cur++ = hexchar[(i >> 0) & 15];
510 for (j = 0;j < 16;j++)
514 *cur++ = hexchar[(d[j] >> 4) & 15];
515 *cur++ = hexchar[(d[j] >> 0) & 15];
526 for (j = 0;j < 16;j++)
530 if (d[j] >= ' ' && d[j] <= 127)
540 if (cur >= flushpointer || i >= size)
549 void SZ_HexDumpToConsole(const sizebuf_t *buf)
551 Com_HexDumpToConsole(buf->data, buf->cursize);
555 //============================================================================
562 Parse a token out of a string
565 int COM_ParseToken(const char **datapointer, int returnnewline)
568 const char *data = *datapointer;
581 for (;*data <= ' ' && (*data != '\n' || !returnnewline);data++)
591 if (data[0] == '/' && data[1] == '/')
594 while (*data && *data != '\n')
598 else if (data[0] == '/' && data[1] == '*')
602 while (*data && (data[0] != '*' || data[1] != '/'))
607 else if (*data == '\"')
610 for (data++;*data != '\"';data++)
612 if (!*data || len >= (int)sizeof(com_token) - 1)
618 com_token[len++] = *data;
621 *datapointer = data+1;
624 else if (*data == '\n' || *data == '{' || *data == '}' || *data == ')' || *data == '(' || *data == ']' || *data == '[' || *data == '\'' || *data == ':' || *data == ',' || *data == ';')
627 com_token[len++] = *data++;
635 for (;*data > ' ' && *data != '{' && *data != '}' && *data != ')' && *data != '(' && *data != ']' && *data != '[' && *data != '\'' && *data != ':' && *data != ',' && *data != ';';data++)
637 if (len >= (int)sizeof(com_token) - 1)
643 com_token[len++] = *data;
653 COM_ParseTokenConsole
655 Parse a token out of a string, behaving like the qwcl console
658 int COM_ParseTokenConsole(const char **datapointer)
661 const char *data = *datapointer;
674 for (;*data <= ' ';data++)
684 if (*data == '/' && data[1] == '/')
687 while (*data && *data != '\n')
691 else if (*data == '\"')
694 for (data++;*data != '\"';data++)
696 if (!*data || len >= (int)sizeof(com_token) - 1)
702 com_token[len++] = *data;
705 *datapointer = data+1;
711 for (;*data > ' ';data++)
713 if (len >= (int)sizeof(com_token) - 1)
719 com_token[len++] = *data;
732 Returns the position (1 to argc-1) in the program's argument list
733 where the given parameter apears, or 0 if not present
736 int COM_CheckParm (const char *parm)
740 for (i=1 ; i<com_argc ; i++)
743 continue; // NEXTSTEP sometimes clears appkit vars.
744 if (!strcmp (parm,com_argv[i]))
755 Looks for the pop.txt file and verifies it.
756 Sets the "registered" cvar.
757 Immediately exits out if an alternate game was attempted to be started without
761 void COM_CheckRegistered (void)
763 Cvar_Set ("cmdline", com_cmdline);
765 if (!FS_FileExists("gfx/pop.lmp"))
768 Con_Print("Playing shareware version, with modification.\nwarning: most mods require full quake data.\n");
770 Con_Print("Playing shareware version.\n");
774 Cvar_Set ("registered", "1");
775 Con_Print("Playing registered version.\n");
784 void COM_InitArgv (void)
787 // reconstitute the command line for the cmdline externally visible cvar
789 for (j = 0;(j < MAX_NUM_ARGVS) && (j < com_argc);j++)
792 if (strstr(com_argv[j], " "))
794 // arg contains whitespace, store quotes around it
795 com_cmdline[n++] = '\"';
796 while ((n < (CMDLINE_LENGTH - 1)) && com_argv[j][i])
797 com_cmdline[n++] = com_argv[j][i++];
798 com_cmdline[n++] = '\"';
802 while ((n < (CMDLINE_LENGTH - 1)) && com_argv[j][i])
803 com_cmdline[n++] = com_argv[j][i++];
805 if (n < (CMDLINE_LENGTH - 1))
806 com_cmdline[n++] = ' ';
814 //===========================================================================
820 const char* prog_name;
822 const char* gamename;
823 const char* gamedirname;
824 const char* gamescreenshotname;
827 static const gamemode_info_t gamemode_info [] =
828 {// prog_name cmdline gamename gamedirname gamescreenshotname
831 // COMMANDLINEOPTION: Game: -quake runs the game Quake (default)
832 { "", "-quake", "DarkPlaces-Quake", "", "dp" },
834 // COMMANDLINEOPTION: Game: -hipnotic runs Quake mission pack 1: The Scourge of Armagon
835 { "hipnotic", "-hipnotic", "Darkplaces-Hipnotic", "hipnotic", "dp" },
837 // COMMANDLINEOPTION: Game: -rogue runs Quake mission pack 2: The Dissolution of Eternity
838 { "rogue", "-rogue", "Darkplaces-Rogue", "rogue", "dp" },
840 // COMMANDLINEOPTION: Game: -nehahra runs The Seal of Nehahra movie and game
841 { "nehahra", "-nehahra", "DarkPlaces-Nehahra", "nehahra", "dp" },
843 // COMMANDLINEOPTION: Game: -nexuiz runs the multiplayer game Nexuiz
844 { "nexuiz", "-nexuiz", "Nexuiz", "data", "nexuiz" },
846 // COMMANDLINEOPTION: Game: -transfusion runs Transfusion (the recreation of Blood in Quake)
847 { "transfusion", "-transfusion", "Transfusion", "basetf", "transfusion" },
849 // COMMANDLINEOPTION: Game: -goodvsbad2 runs the psychadelic RTS FPS game Good Vs Bad 2
850 { "gvb2", "-goodvsbad2", "GoodVs.Bad2", "rts", "gvb2" },
852 // COMMANDLINEOPTION: Game: -teu runs The Evil Unleashed (this option is obsolete as they are not using darkplaces)
853 { "teu", "-teu", "TheEvilUnleashed", "baseteu", "teu" },
855 // COMMANDLINEOPTION: Game: -battlemech runs the multiplayer topdown deathmatch game BattleMech
856 { "battlemech", "-battlemech", "Battlemech", "base", "battlemech" },
858 // COMMANDLINEOPTION: Game: -zymotic runs the singleplayer game Zymotic
859 { "zymotic", "-zymotic", "Zymotic", "data", "zymotic" },
861 // COMMANDLINEOPTION: Game: -fniggium runs the post apocalyptic melee RPG Fniggium
862 { "fniggium", "-fniggium", "Fniggium", "data", "fniggium" },
864 // COMMANDLINEOPTION: Game: -setheral runs the multiplayer game Setheral
865 { "setheral", "-setheral", "Setheral", "data", "setheral" },
867 // COMMANDLINEOPTION: Game: -som runs the multiplayer game Son Of Man
868 { "som", "-som", "Son of Man", "sonofman", "som" },
870 // COMMANDLINEOPTION: Game: -tenebrae runs the graphics test mod known as Tenebrae (some features not implemented)
871 { "tenebrae", "-tenebrae", "DarkPlaces-Tenebrae", "tenebrae", "dp" },
873 // COMMANDLINEOPTION: Game: -neoteric runs the game Neoteric
874 { "neoteric", "-neoteric", "Neoteric", "neobase", "neo" },
876 // COMMANDLINEOPTION: Game: -openquartz runs the game OpenQuartz, a standalone GPL replacement of the quake content
877 { "openquartz", "-openquartz", "OpenQuartz", "id1", "openquartz"},
879 // COMMANDLINEOPTION: Game: -prydon runs the topdown point and click action-RPG Prydon Gate
880 { "prydon", "-prydon", "PrydonGate", "prydon", "prydon"},
882 // COMMANDLINEOPTION: Game: -netherworld runs the game Netherworld: Dark Masters
883 { "netherworld", "-netherworld", "Dark Masters", "netherworld", "nw"},
886 void COM_InitGameType (void)
888 char name [MAX_OSPATH];
891 FS_StripExtension (com_argv[0], name, sizeof (name));
892 COM_ToLowerString (name, name, sizeof (name));
894 // Check the binary name; default to GAME_NORMAL (0)
895 gamemode = GAME_NORMAL;
896 for (i = 1; i < sizeof (gamemode_info) / sizeof (gamemode_info[0]); i++)
897 if (strstr (name, gamemode_info[i].prog_name))
903 // Look for a command-line option
904 for (i = 0; i < sizeof (gamemode_info) / sizeof (gamemode_info[0]); i++)
905 if (COM_CheckParm (gamemode_info[i].cmdline))
911 gamename = gamemode_info[gamemode].gamename;
912 gamedirname = gamemode_info[gamemode].gamedirname;
913 gamescreenshotname = gamemode_info[gamemode].gamescreenshotname;
917 extern void Mathlib_Init(void);
918 extern void FS_Init (void);
927 Cvar_RegisterVariable (®istered);
928 Cvar_RegisterVariable (&cmdline);
934 COM_CheckRegistered ();
942 does a varargs printf into a temp buffer, so I don't need to have
943 varargs versions of all text functions.
944 FIXME: make this buffer size safe someday
947 char *va(const char *format, ...)
950 // LordHavoc: now cycles through 8 buffers to avoid problems in most cases
951 static char string[8][1024], *s;
952 static int stringindex = 0;
954 s = string[stringindex];
955 stringindex = (stringindex + 1) & 7;
956 va_start (argptr, format);
957 vsnprintf (s, sizeof (string[0]), format,argptr);
964 //======================================
966 void COM_ToLowerString (const char *in, char *out, size_t size_out)
971 while (*in && size_out > 1)
973 if (*in >= 'A' && *in <= 'Z')
974 *out++ = *in++ + 'a' - 'A';
982 void COM_ToUpperString (const char *in, char *out, size_t size_out)
987 while (*in && size_out > 1)
989 if (*in >= 'a' && *in <= 'z')
990 *out++ = *in++ + 'A' - 'a';
998 int COM_StringBeginsWith(const char *s, const char *match)
1000 for (;*s && *match;s++, match++)
1006 int COM_ReadAndTokenizeLine(const char **text, char **argv, int maxargc, char *tokenbuf, int tokenbufsize, const char *commentprefix)
1008 int argc, commentprefixlength;
1012 tokenbufend = tokenbuf + tokenbufsize;
1014 commentprefixlength = 0;
1016 commentprefixlength = strlen(commentprefix);
1017 while (*l && *l != '\n')
1021 if (commentprefixlength && !strncmp(l, commentprefix, commentprefixlength))
1023 while (*l && *l != '\n')
1027 if (argc >= maxargc)
1029 argv[argc++] = tokenbuf;
1033 while (*l && *l != '"')
1035 if (tokenbuf >= tokenbufend)
1046 if (tokenbuf >= tokenbufend)
1051 if (tokenbuf >= tokenbufend)
1064 // written by Elric, thanks Elric!
1065 char *SearchInfostring(const char *infostring, const char *key)
1067 static char value [256];
1069 size_t value_ind, key_ind;
1072 if (*infostring++ != '\\')
1087 if (c == '\\' || key_ind == sizeof (crt_key) - 1)
1089 crt_key[key_ind] = '\0';
1093 crt_key[key_ind++] = c;
1096 // If it's the key we are looking for, save it in "value"
1097 if (!strcmp(crt_key, key))
1103 if (c == '\0' || c == '\\' || value_ind == sizeof (value) - 1)
1105 value[value_ind] = '\0';
1109 value[value_ind++] = c;
1113 // Else, skip the value
1127 //========================================================
1128 // strlcat and strlcpy, from OpenBSD
1131 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
1133 * Permission to use, copy, modify, and distribute this software for any
1134 * purpose with or without fee is hereby granted, provided that the above
1135 * copyright notice and this permission notice appear in all copies.
1137 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1138 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1139 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1140 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1141 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1142 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1143 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1146 /* $OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $ */
1147 /* $OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $ */
1150 #ifndef HAVE_STRLCAT
1152 strlcat(char *dst, const char *src, size_t siz)
1154 register char *d = dst;
1155 register const char *s = src;
1156 register size_t n = siz;
1159 /* Find the end of dst and adjust bytes left but don't go past end */
1160 while (n-- != 0 && *d != '\0')
1166 return(dlen + strlen(s));
1167 while (*s != '\0') {
1176 return(dlen + (s - src)); /* count does not include NUL */
1178 #endif // #ifndef HAVE_STRLCAT
1181 #ifndef HAVE_STRLCPY
1183 strlcpy(char *dst, const char *src, size_t siz)
1185 register char *d = dst;
1186 register const char *s = src;
1187 register size_t n = siz;
1189 /* Copy as many bytes as will fit */
1190 if (n != 0 && --n != 0) {
1192 if ((*d++ = *s++) == 0)
1197 /* Not enough room in dst, add NUL and traverse rest of src */
1200 *d = '\0'; /* NUL-terminate dst */
1205 return(s - src - 1); /* count does not include NUL */
1208 #endif // #ifndef HAVE_STRLCPY