PROFILE.CPP 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. /*
  2. ** Command & Conquer Red Alert(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /****************************************************************************
  19. *
  20. * C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
  21. *
  22. *----------------------------------------------------------------------------
  23. *
  24. * FILE
  25. * profile.c
  26. *
  27. * DESCRIPTION
  28. * INI file processing. (32-Bit protected mode)
  29. *
  30. * PROGRAMMER
  31. * Bill Randolph
  32. * Denzil E. Long, Jr.
  33. *
  34. * DATE
  35. * January 26, 1995
  36. *
  37. *----------------------------------------------------------------------------
  38. *
  39. * PUBLIC
  40. * Get_Frame_Pathname - Get pathname for a given frame and file type.
  41. * GetINIInt - Get an integer value from an INI file.
  42. * GetINIString - Get a string from the INI file.
  43. *
  44. ****************************************************************************/
  45. #include <stdio.h>
  46. #include <stdlib.h>
  47. #include <string.h>
  48. #include "profile.h"
  49. /*---------------------------------------------------------------------------
  50. * PRIVATE DECLARATIONS
  51. *-------------------------------------------------------------------------*/
  52. #ifndef max
  53. #define max(a,b) (((a)>(b))?(a):(b))
  54. #endif
  55. #ifndef min
  56. #define min(a,b) (((a)<(b))?(a):(b))
  57. #endif
  58. #define isspace(c) ((c==' ')||(c=='\t')||(c=='\n')||(c=='\r')?1:0)
  59. static char *strtrim(char *string);
  60. static long FileGets(FILE *fp, char *buf, long buflen);
  61. /****************************************************************************
  62. *
  63. * NAME
  64. * Get_Frame_Pathname - Get pathname for a given frame and file type.
  65. *
  66. * SYNOPSIS
  67. * Error = Get_Frame_Pathname(IniFile, Frame, Extension, Buffer)
  68. *
  69. * long Get_Frame_Pathname(char *, long, char *, char *);
  70. *
  71. * FUNCTION
  72. *
  73. * INPUTS
  74. * IniFile - Pointer to INI filename.
  75. * Frame - Number of frame to get filename for.
  76. * Extension - File extension type.
  77. * Buffer - Pointer to buffer to put pathname into.
  78. *
  79. * RESULT
  80. * Error - 0 if successful, or -1 if error.
  81. *
  82. ***************************************************************************/
  83. long Get_Frame_Pathname(char *inifile, long anim_frame, char *ext,
  84. char *outbuf)
  85. {
  86. char rootdir[_MAX_PATH]; // Root directory from INI file
  87. char extdir[_MAX_PATH]; // this extension's directory
  88. char entry_name[40]; // INI entry name
  89. char inibuf[80]; // string returned from INI file
  90. char *prefix; // 4-char prefix for this scene
  91. char *startstr; // starting frame #, string
  92. char *endstr; // ending frame #, string
  93. char *palstr; // palette filename string
  94. long startnum; // scene's starting frame #
  95. long endnum; // scene's ending frame #
  96. long total_frames; // accumulated frame total
  97. long scene_frames; // # frames in a given scene
  98. long scene_num; // scene #
  99. long file_frame; // file's frame #
  100. long rc;
  101. /* Get directory for this file type */
  102. GetINIString("Path", "Root", "", rootdir, 80, inifile);
  103. if (rootdir[strlen (rootdir) - 1] != '\\') {
  104. strcat(rootdir,"\\");
  105. }
  106. GetINIString("Path", ext, "", extdir, 80, inifile);
  107. if (extdir[strlen (extdir) - 1] != '\\') {
  108. strcat(extdir,"\\");
  109. }
  110. /* VQG is a special case:
  111. *
  112. * The VQG files are named based upon the 1st 4 characters of the 'Name'
  113. * entry in the INI file, and their numbers match the actual animation
  114. * frame numbers, not the scene frame numbers.
  115. */
  116. if (!stricmp(ext, "VQG")) {
  117. GetINIString("Common", "Name", "", inibuf, 80, inifile);
  118. if (strlen(inibuf) > 4) {
  119. inibuf[4] = 0;
  120. }
  121. sprintf(outbuf,"%s%s%s%04d.%s",rootdir,extdir,inibuf,anim_frame,ext);
  122. return (0);
  123. }
  124. /*-------------------------------------------------------------------------
  125. * Loop through scenes until the desired frame # is found
  126. *-----------------------------------------------------------------------*/
  127. total_frames = 0;
  128. scene_num = 1;
  129. while (1) {
  130. /* Get this scene's entry */
  131. sprintf(entry_name, "Scene%d", scene_num);
  132. rc = GetINIString("Scenes",entry_name,"",inibuf,80,inifile);
  133. if (rc == 0) {
  134. return (-1);
  135. }
  136. /* Parse the INI entry */
  137. prefix = strtok(inibuf, ",");
  138. startstr = strtok(NULL, ",");
  139. endstr = strtok(NULL, ",");
  140. palstr = strtok(NULL, ",");
  141. if ((prefix == NULL) || (startstr == NULL) || (endstr == NULL)) {
  142. return (-1);
  143. }
  144. startnum = atoi(startstr);
  145. endnum = atoi(endstr);
  146. scene_frames = ((endnum - startnum) + 1);
  147. /* requested frame is found */
  148. if (anim_frame < (total_frames + scene_frames)) {
  149. /* Palette is a special case */
  150. if (!stricmp(ext, "PAL")) {
  151. if (palstr == NULL) {
  152. return (-1);
  153. } else {
  154. sprintf(outbuf, "%s%s%s.PAL", rootdir, extdir, palstr);
  155. return (0);
  156. }
  157. } else {
  158. file_frame = ((anim_frame - total_frames) + startnum);
  159. sprintf(outbuf,"%s%s%s%04d.%s",rootdir,extdir,prefix,file_frame,ext);
  160. return (0);
  161. }
  162. }
  163. /* Frame not found; go to next scene */
  164. total_frames += scene_frames;
  165. scene_num++;
  166. }
  167. }
  168. /****************************************************************************
  169. *
  170. * NAME
  171. * GetINIInt - Get an integer value from an INI file.
  172. *
  173. * SYNOPSIS
  174. * Value = GetINIInt(Section, Entry, Default, ININame)
  175. *
  176. * long GetINIInt(char *, char *, long, char *);
  177. *
  178. * FUNCTION
  179. * Retrieve an integer value from the INI file at the specified 'Section'
  180. * and 'Entry' fields. If no value is defined then return the passed in
  181. * 'Default' value.
  182. *
  183. * INPUTS
  184. * Section - Pointer to section name.
  185. * Entry - Pointer to entry name.
  186. * Default - Default value.
  187. * ININame - Pointer to INI filename.
  188. *
  189. * RESULT
  190. * Value - Integer value from INI file or 'Default'.
  191. *
  192. ****************************************************************************/
  193. long GetINIInt(char const *section, char const *entry, long deflt,
  194. char *fname)
  195. {
  196. char buffer[20];
  197. sprintf(buffer, "%d", deflt);
  198. GetINIString(section, entry, buffer, buffer, sizeof(buffer),
  199. fname);
  200. return (atoi(buffer));
  201. }
  202. /****************************************************************************
  203. *
  204. * NAME
  205. * GetINIString - Get a string from the INI file.
  206. *
  207. * SYNOPSIS
  208. * Length = GetINIString(Section, Entry, Default, Buffer,
  209. * Length, ININame)
  210. *
  211. * long GetINIString(char *, char *, char *, char *, long,
  212. * char *);
  213. *
  214. * FUNCTION
  215. *
  216. * INPUTS
  217. * Section - Pointer to section name.
  218. * Entry - Pointer to entry name.
  219. * Default - Pointer to default string.
  220. * Buffer - Pointer to buffer to copy string into.
  221. * Length - Maximum length of string.
  222. * ININame - Pointer to INI filename.
  223. *
  224. * RESULT
  225. * Length - Length of string copied into the buffer.
  226. *
  227. ****************************************************************************/
  228. long GetINIString(char const *section, char const *entry,
  229. char const *def, char *retbuffer, long retlen, char *fname)
  230. {
  231. FILE *fp;
  232. long retval;
  233. char txt[80];
  234. char secname[40];
  235. long len;
  236. char *workptr;
  237. /* Copy default value in case entry isn't found */
  238. strncpy(retbuffer, def, (retlen - 1));
  239. retbuffer[retlen - 1] = 0;
  240. retval = min(strlen(def), (unsigned)retlen);
  241. /* Open the file */
  242. if ((fp = fopen(fname, "rt")) == NULL) {
  243. return (retval);
  244. }
  245. /* Generate section name for search */
  246. sprintf(secname, "[%s]", section);
  247. len = strlen(secname);
  248. /* Scan file for section name */
  249. while (1) {
  250. /* Read line; return if end-of-file */
  251. if (FileGets(fp,txt,80)!=0) {
  252. fclose(fp);
  253. return (retval);
  254. }
  255. /* Skip comments */
  256. if (txt[0] == ';') continue;
  257. /* Parse a section name */
  258. if (txt[0] == '[') {
  259. if (!memicmp(secname, txt, len)) break;
  260. }
  261. }
  262. /* Scan file for desired entry */
  263. len = strlen(entry);
  264. while (1) {
  265. /* Read line; return if end-of-file */
  266. if (FileGets(fp, txt, 80) != 0) {
  267. fclose(fp);
  268. return (retval);
  269. }
  270. /* Skip comments */
  271. if (txt[0] == ';') continue;
  272. /* Return if start of next section reached */
  273. if (txt[0] == '[') {
  274. fclose(fp);
  275. return (retval);
  276. }
  277. /* Entry found; parse it */
  278. if (!memicmp(entry, txt, len) && (isspace(txt[len])
  279. || txt[len] == '=')) {
  280. fclose(fp);
  281. /* Find '=' character */
  282. workptr = strchr(txt, '=');
  283. /* Return if not found */
  284. if (workptr == NULL) return (retval);
  285. /* Skip past '=' */
  286. workptr++;
  287. /* Skip white space */
  288. while (isspace(*workptr) && strlen(workptr) > 0) {
  289. workptr++;
  290. }
  291. /* Return if no string left */
  292. if ((*workptr) == 0) return (retval);
  293. strtrim(workptr);
  294. strcpy(retbuffer,workptr);
  295. return (strlen(workptr));
  296. }
  297. }
  298. }
  299. /****************************************************************************
  300. *
  301. * NAME
  302. * strtrim - Trim off trailing spaces from a string.
  303. *
  304. * SYNOPSIS
  305. * String = strtrim(String)
  306. *
  307. * char *strtrim(char *);
  308. *
  309. * FUNCTION
  310. *
  311. * INPUTS
  312. * String - Pointer to string to trim.
  313. *
  314. * RESULT
  315. * String - Pointer to trimmed string.
  316. *
  317. ****************************************************************************/
  318. static char *strtrim(char *string)
  319. {
  320. long i;
  321. /* Return if NULL ptr or zero-length string */
  322. if ((string == NULL) || (strlen(string) == 0)) {
  323. return (string);
  324. }
  325. /* Find 1st non-white-space character from the right */
  326. i = (strlen(string) - 1);
  327. while ((i > 0) && isspace(string[i])) {
  328. i--;
  329. }
  330. /* Set end of string */
  331. i++;
  332. string[i] = 0;
  333. return (string);
  334. }
  335. /****************************************************************************
  336. *
  337. * NAME
  338. * FileGets - A better fgets.
  339. *
  340. * SYNOPSIS
  341. * Error = FileGets(FilePtr, Buffer, Length)
  342. *
  343. * long FileGets(FILE *, char *, long);
  344. *
  345. * FUNCTION
  346. *
  347. * INPUTS
  348. * FilePtr - File pointer.
  349. * Buffer - Pointer to buffer to fill.
  350. * Length - Maximum length of buffer.
  351. *
  352. * RESULT
  353. * Error = 0 if successfull, or -1 if error.
  354. *
  355. ****************************************************************************/
  356. static long FileGets(FILE *fp, char *buf, long buflen)
  357. {
  358. if (fgets(buf, buflen, fp)) {
  359. buf[(strlen(buf) - 1)] = 0;
  360. return (0);
  361. } else {
  362. return (-1);
  363. }
  364. }