This question already has answers here:
std::string formatting like sprintf
(44 answers)
Closed 7 years ago.
I don't have much experience working with C++. Rather I have worked more in C# and so, I wanted to ask my question by relating to what I would have done in there. I have to generate a specific format of the string, which I have to pass to another function. In C#, I would have easily generated the string through the below simple code.
string a = "test";
string b = "text.txt";
string c = "text1.txt";
String.Format("{0} {1} > {2}", a, b, c);
By generating such an above string, I should be able to pass this in system(). However, system only accepts char*
I am on Win32 C++ (not C++/CLI), and cannot use boost since it would include too much inclusion of all the files for a project which itself is very small. Something like sprintf() looks useful to me, but sprintf does not accept string as the a, b and c parameters. Any suggestions how I can generate these formatted strings to pass to system in my program?
The C++ way would be to use a std::stringstream object as:
std::stringstream fmt;
fmt << a << " " << b << " > " << c;
The C way would be to use sprintf.
The C way is difficult to get right since:
It is type unsafe
Requires buffer management
Of course, you may want to fall back on the C way if performance is an issue (imagine you are creating fixed-size million little stringstream objects and then throwing them away).
For the sake of completeness, you may use std::stringstream:
#include <iostream>
#include <sstream>
#include <string>
int main() {
std::string a = "a", b = "b", c = "c";
// apply formatting
std::stringstream s;
s << a << " " << b << " > " << c;
// assign to std::string
std::string str = s.str();
std::cout << str << "\n";
}
Or (in this case) std::string's very own string concatenation capabilities:
#include <iostream>
#include <string>
int main() {
std::string a = "a", b = "b", c = "c";
std::string str = a + " " + b + " > " + c;
std::cout << str << "\n";
}
For reference:
http://en.cppreference.com/w/cpp/string/basic_string/operator+
If you really want to go the C way, here you are:
#include <iostream>
#include <string>
#include <vector>
#include <cstdio>
int main() {
std::string a = "a", b = "b", c = "c";
const char fmt[] = "%s %s > %s";
// use std::vector for memory management (to avoid memory leaks)
std::vector<char>::size_type size = 256;
std::vector<char> buf;
do {
// use snprintf instead of sprintf (to avoid buffer overflows)
// snprintf returns the required size (without terminating null)
// if buffer is too small initially: loop should run at most twice
buf.resize(size+1);
size = std::snprintf(
&buf[0], buf.size(),
fmt, a.c_str(), b.c_str(), c.c_str());
} while (size+1 > buf.size());
// assign to std::string
std::string str = &buf[0];
std::cout << str << "\n";
}
For reference:
http://en.cppreference.com/w/cpp/io/c/fprintf
Since C++11, you can "simplify" this to:
#include <iostream>
#include <string>
#include <vector>
#include <cstdio>
int main() {
std::string a = "a", b = "b", c = "c";
const char fmt[] = "%s %s > %s";
// can use std::string as buffer directly (since C++11)
std::string::size_type size = 256;
std::string str;
do {
str.resize(size+1);
// use snprintf instead of sprintf (to avoid buffer overflows)
// snprintf returns the required size (without terminating null)
// if buffer is too small initially: loop should run at most twice
size = std::snprintf(
&str[0], str.size(),
fmt, a.c_str(), b.c_str(), c.c_str());
} while (size+1 > str.size());
// can strip off null-terminator, as std::string adds their own
str.resize(size);
// done
std::cout << str << "\n";
}
For reference:
Directly write into char* buffer of std::string
Then, there's the Boost Format Library. For the sake of your example:
#include <iostream>
#include <string>
#include <boost/format.hpp>
int main() {
std::string a = "a", b = "b", c = "c";
// apply format
boost::format fmt = boost::format("%s %s > %s") % a % b % c;
// assign to std::string
std::string str = fmt.str();
std::cout << str << "\n";
}
In addition to options suggested by others I can recommend the fmt library which implements string formatting similar to str.format in Python and String.Format in C#. Here's an example:
std::string a = "test";
std::string b = "text.txt";
std::string c = "text1.txt";
std::string result = fmt::format("{0} {1} > {2}", a, b, c);
Disclaimer: I'm the author of this library.
You can use sprintf in combination with std::string.c_str().
c_str() returns a const char* and works with sprintf:
string a = "test";
string b = "text.txt";
string c = "text1.txt";
char* x = new char[a.length() + b.length() + c.length() + 32];
sprintf(x, "%s %s > %s", a.c_str(), b.c_str(), c.c_str() );
string str = x;
delete[] x;
or you can use a pre-allocated char array if you know the size:
string a = "test";
string b = "text.txt";
string c = "text1.txt";
char x[256];
sprintf(x, "%s %s > %s", a.c_str(), b.c_str(), c.c_str() );
For completeness, the boost way would be to use boost::format
cout << boost::format("%s %s > %s") % a % b % c;
Take your pick. The boost solution has the advantage of type safety with the sprintf format (for those who find the << syntax a bit clunky).
As already mentioned the C++ way is using stringstreams.
#include <sstream>
string a = "test";
string b = "text.txt";
string c = "text1.txt";
std::stringstream ostr;
ostr << a << " " << b << " > " << c;
Note that you can get the C string from the string stream object like so.
std::string formatted_string = ostr.str();
const char* c_str = formatted_string.c_str();
You can just concatenate the strings and build a command line.
std::string command = a + ' ' + b + " > " + c;
system(command.c_str());
You don't need any extra libraries for this.
Related
I have a project that is almost near completion aside from a couple of stubborn but probably simple error Im receiving. I am by know means knowledgeable of C and me getting this project this far is a miracle. Im hoping someone can detect what it is I am missing in my code. Here is the view of the errors and below is the code.
private void button1_Click(object sender, EventArgs e)
{
Random rnd = new Random();
StringBuilder bin = new StringBuilder();
int buf = 0;
int bufLen = 0;
int left = 53;
for (int i = 106; i >= 1; i += -1)
{
buf <<= 1;
if (rnd.Next(i) < left)
{
buf += 1;
left -= 1;
}
bufLen += 1;
if (bufLen == 4)
{
bin.Append("0123456789ABCDEF"(buf));
bufLen = 0;
buf = 0;
}
}
string b = bin.ToString();
bin.Append("048c"(buf));
System.Security.Cryptography.SHA1Managed m = new System.Security.Cryptography.SHA1Managed();
byte[] hash = m.ComputeHash(Encoding.UTF8.GetBytes(b));
//replace first two bits in hash with bits from buf
hash(0) = Convert.ToByte(hash(0) & 0x3f | (buf * 64));
//append 24 bits from hash
b = b.Substring(0, 26) + BitConverter.ToString(hash, 0, 3).Replace("-", string.Empty);
}
}
}
x(y) means "call x with y as a parameter".
You have written "0123456789ABCDEF"(buf). "0123456789ABCDEF" isn't a function (or a functor) so you can't call it.
Perhaps you meant to index it, with "0123456789ABCDEF"[buf]? This returns the buf'th character from "0123456789ABCDEF", which is buf in hexadecimal as long as buf is between 0 and 15.
You can't concatenate a string literal with a string variable.
#include <iostream>
using std::cout;
void concatenate(const std::string& s)
{
cout << "In concatenate, string passed is: "
<< s
<< "\n";
}
int main(void)
{
std::string world = " World!\n";
concatenate("Hello"(world));
return 0;
}
Thomas#HastaLaVista ~/concatenation
# g++ -o main.exe main.cpp
main.cpp: In function `int main()':
**main.cpp:15: error: `"Hello"' cannot be used as a function**
Thomas#HastaLaVista ~/concatenation
# g++ --version
g++ (GCC) 3.4.4 (cygming special, gdc 0.12, using dmd 0.125)
Copyright (C) 2004 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
You will need a temporary string variable:
if (bufLen == 4)
{
std::string temp("01234567890ABCDEF");
temp += buf;
bin.Append(temp);
bufLen = 0;
buf = 0;
}
It seams confusing but I'm gonna try to explain it the best I can!
I'm trying to run a C++ DLL on my C# code.
On this DLL I have a method that should return a 20 characters unsigned char*. Representing 5 "words" of 4 bytes. ( The output of a sha-1 algorithm)
I'm using DLLIMPORT on my C# project like this:
[DllImport("hashLibrary.dll", CharSet = CharSet.Ansi)]
static private extern string CallReturnString(IntPtr pHashClassObject);
This should return the 5 WORDS string.
And this is my C++ method that should give away the string:
unsigned char* SHA1::Result(/*unsigned *message_digest_array*/)
{
int i; // Counter
int j = 0;
static int s_chString[5];
static unsigned char s_out[20]; // 4 * 5 + 10 de bob
if (Corrupted)
{
return false;
}
if (!Computed)
{
PadMessage();
Computed = true;
}
unsigned int a = 0;
a = H[0];
s_out[0] = (a >> (8*0)) & 0xff;
a = H[0];
s_out[1] = (a >> (8*1)) & 0xff;
a = H[0];
s_out[2] = (a >> (8*2)) & 0xff;
a = H[0];
s_out[3] = (a >> (8*3)) & 0xff;
a = H[1];
s_out[4] = (a >> (8*0)) & 0xff;
s_out[5] = (a >> (8*1)) & 0xff;
s_out[6] = (a >> (8*2)) & 0xff;
s_out[7] = (a >> (8*3)) & 0xff;
a = H[2];
s_out[8] = (a >> (8*0)) & 0xff;
s_out[9] = (a >> (8*1)) & 0xff;
s_out[10] = (a >> (8*2)) & 0xff;
s_out[11] = (a >> (8*3)) & 0xff;
a = H[3];
s_out[12] = (a >> (8*0)) & 0xff;
s_out[13] = (a >> (8*1)) & 0xff;
s_out[14] = (a >> (8*2)) & 0xff;
s_out[15] = (a >> (8*3)) & 0xff;
a = H[4];
s_out[16] = (a >> (8*0)) & 0xff;
s_out[17] = (a >> (8*1)) & 0xff;
s_out[18] = (a >> (8*2)) & 0xff;
s_out[19] = (a >> (8*3)) & 0xff;
s_out[20] = '\0';
return s_out;
}
In this code I try to get all bytes from H and put on a char that will be passed to the C# code.
H declaration is : unsigned H[5];
It almost works, but for some reason some combinations gives me crazy results like a 22 members string on C# and with the values all wrong.
I think it has to do with some different types of varibles on C# and C++. If I could only get all the bytes from the char* exacly as they were in the the C++ code it would be awesome.
Does anyone knows how to do that?
Thanks a lot guys!
EDIT :
The general workflow is:
My Windows form app creates a new class from the C++ class : HashWrapper hash = new HashWrapper();
My windows form app send a seed to the C++ ( which is a SHA-1 algorithm class ) : hash.SendInput("abc");
My windows form app asks for the result of the c++ algorithm : string output = hash.ReturnString();
Here Im gonna put the methods I called on the list on top:
public HashWrapper()
{
// We have to Create an instance of this class through an exported function
this.m_pNativeObject = CreateSHA1Class();
}
public void SendInput(string inp )
{
CallInput(this.m_pNativeObject, inp, inp.Length);
}
public string ReturnString()
{
string ans = CallReturnString(this.m_pNativeObject);
return ConvertStringToHex(ans); // Converts to Hex
}
public string ConvertStringToHex(string asciiString)
{
string hex = "";
foreach (char c in asciiString)
{
int tmp = c;
hex += String.Format("{0:x2}", (uint)System.Convert.ToUInt32(tmp.ToString()));
}
return hex;
}
Unfortunately, you cannot simply marshal array from return value. If you need to call it many times, I'd start with a custom marshaller:
private class ReturnArrayMarshaller : ICustomMarshaler
{
public static ICustomMarshaler GetInstance(string cookie)
{
return new ReturnArrayMarshaller(cookie);
}
private readonly int byteCount;
private ReturnArrayMarshaller(string cookie)
{
byteCount = int.Parse(cookie);
}
public void CleanUpManagedData(object ManagedObj) { throw new NotImplementedException(); }
public void CleanUpNativeData(IntPtr pNativeData)
{
// release unmanaged return value if needed
}
public int GetNativeDataSize() { throw new NotImplementedException(); }
public IntPtr MarshalManagedToNative(object ManagedObj) { throw new NotImplementedException(); }
public object MarshalNativeToManaged(IntPtr pNativeData)
{
byte[] data = new byte[byteCount];
Marshal.Copy(pNativeData, data, 0, data.Length);
return data;
}
}
And use it in signature declaration:
[DllImport(#"hashLibrary.dll", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(ReturnArrayMarshaller), MarshalCookie = "20")]
public static extern byte[] CallReturnString(IntPtr pHashClassObject);
Do not forget to specify CallingConvention.Cdecl in DllImport, because you're not using __stdcall modifier in C++ code.
P.S. I beleive you're using unmanaged library not because of just SHA1 hash, because most of cryptography is available as managed classes.
Don't Reinvent the Wheel
Is there any reason why you cannot use the class provided by Microsoft? There are some problems with your answer, such as recreating the memcpy function which would have allowed you to do your memory copy function in around 6 lines of code, or trying to marshal a data string as a null terminated string. You should just use the SHA1 implementation provided by .NET, unless there is a requirement saying you must make your own.
How to solve your problem in .NET
The problem you are trying to solve literally takes 3 lines of code in .NET, unless you have a requirement to make your own SHA1 implementation using .NET's makes a lot more sense.
public static byte[] HashString(string inputString)
{
inputData = Encoding.ASCII.GetBytes("abc");
var sha1 = new SHA1Managed();
return sha1.ComputeHash(inputData);
}
Am trying to use functions from a dll file i built in c++ in c#; below is the c++ .h codes
#pragma once
#pragma unmanaged
#ifndef _DLL_H_
#define _DLL_H_
#if BUILDING_DLL
# define DLLIMPORT __declspec (dllexport)
#else /* Not BUILDING_DLL */
# define DLLIMPORT __declspec (dllimport)
#endif /* Not BUILDING_DLL */
#include <list>
#include <string>
using namespace std;
extern "C"
{
string DLLIMPORT encrypt(string keeper);
string DLLIMPORT decrypt(string keeper);
}
#endif /* _DLL_H_ */
the c++ .cpp codes are below
#pragma managed
#include "cenH.h"
#include <windows.h>
#include <iostream>
using namespace std;
const char alphabets[] = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n',
'o','p','q','r','s','t','u','v','w','x','y','z'};
string encrypt(string keeper)
{
string keep;
string m = keeper;
cout << keeper.length() << endl;
for(int count = 0; count < m.length(); count++)
{
for(int c = 0; c < 26; c++)
{
if(m[count] == alphabets[c])
{
int counter = c - 8;
if(counter < 0)
{
counter = counter + 26;
keep += alphabets[counter];
}
else
{
keep += alphabets[counter];
}
}
else if(m[count] == ' ')
{
keep+=".";
break;
}
}//end of second loop
//end first loop
cout << keep << endl;
return keep;
}
string decrypt(string keeper)
{
//cout << "\n" << endl;
string keep;
string m = keeper;
for(int count = 0; count < m.length(); count++)
{
for(int c = 0; c < 26; c++)
{
if(m[count] == alphabets[c])
{
int counter = c + 8;
if(counter >= 26)
{
counter = counter - 26;
keep += alphabets[counter];
}
else
{
keep += alphabets[counter];
}
}else if(m[count] == '.')
{
keep+=" ";
break;
}
}//end of third loop
}//end second loop
//cout << keep << endl;
return keep;
}
BOOL APIENTRY DllMain (HINSTANCE hInst /* Library instance handle. */ ,
DWORD reason /* Reason this function is being called. */ ,
LPVOID reserved /* Not used. */ )
{
switch (reason)
{
case DLL_PROCESS_ATTACH:
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
/* Returns TRUE on success, FALSE on failure */
return TRUE;
}
i compile this codes and they dont give errors, i even test run them in a c++ console app by calling the dll file and it works fine but when i call this dll file into my c# programs it give me the AccessViolationException Attempted to read or write protected memory. This is often an indication that other memory is corrupt. The dll is complied in the MinGW GCC 4.6.2 32-bit and my c# runs on x86(32-bit).can someone please point to me what i have done wrong.
This is how i imported the dll inside my c# code
[DllImport("cen.dll",CallingConvention = CallingConvention.StdCall)]
internal static extern string decrypt(String keeper);
string line = decrypt("savethemonkeys");
I have the following code in c# which reverses a string:
char[] charArray = s.ToCharArray();
int len = s.Length - 1;
for (int i = 0; i < len; i++, len--)
{
charArray[i] ^= charArray[len];
charArray[len] ^= charArray[i];
charArray[i] ^= charArray[len];
}
return new string(charArray);
I am trying to convert it to C++ as an intellectual exercise more than anything. Here is what I have so far:
void main(void)
{
char* str = "testing";
char* result;
int len;
len = strlen(str);
if (len <= 12)
{
result = new char[strlen(str)];
for (int i = 0; i < len; i++, len--)
{
result[i] ^= str[len];
result[len] ^= str[i];
result[i] ^= str[len];
}
}
else{
std::reverse(str, &str[strlen(str)]);
}
cout << endl << result << endl;
// cleanup
str = NULL;
result = NULL;
}
In .Net if the string is <= 12 (I think it's twelve) xor is faster than array reverse. Source - Sam Saffron I am basically trying to see if it still holds up in C++.
The string comes out in a weird format (════╣¥¿ë²²² to be precise).
Any ideas?
Note: I know the else statement doesn't work, I'll figure that bit out after ;)
Note 2: I am probably doing this completely wrong, so feel free to point absolutely anything out
Update
Thanks to everyone that has participated. I haven't played with c++ in a fair few years (and it shows) and thought it would be quiet easy to convert but obviously not. Think it's best I abandon this idea. Thanks again
A few things:
result = new char[strlen(str)];
Should be
result = new char[len + 1];
len because you've already calculated the length of str, and + 1 to make room for the NUL terminator.
Secondly, you need to copy the string into result before operating on it, because otherwise your array is full of garbage otherwise:
strcpy(result, str);
Thirdly,
std::reverse(str, &str[strlen(str)]);
Is wrong for two reasons: one, because you can't modify string literals, and two, because you should be using result:
std::reverse(result, result + len);
But if you do that, you also need to copy str into result first.
And lastly, setting a pointer to NULL does not deallocate the memory it points to. You have to
delete[] result; // delete[] because new[]
Note that for this to work even when the else is taken (and therefore result is not made to point to allocated memory), you need to do
char* result = NULL; // delete[] is defined as a nop on NULL pointers
All the above applies if you're sure you want to use C-strings. Once you get the hang of pointers, you can graduate to std::string:
std::string str("testing");
std::reverse(std::begin(str), std::end(str)); // or if you don't want to do it in-place,
// std::string result(str.rbegin(), str.rend());
xor swap is for swapping. If you're copying into a result array then that's assigning, not swapping. Also, you must only iterate half-way through the array, otherwise you swap it twice.
Here is a translation of the C# code:
#include <iostream>
#include <algorithm>
int main(void)
{
char str[] = "testing"; // arrays have automatic storage - no need to new/delete
const size_t str_len = sizeof(str)-1; // sizeof(str) returns size of the array
if (str_len <= 12) // because str_len is a constant expression, the other branch will be compiled-out
{
// this should probably use iterators (pointers) but oh well
for (size_t i = 0, len = str_len-1; i < str_len/2; i++, len--)
{
str[i] ^= str[len];
str[len] ^= str[i];
str[i] ^= str[len];
}
}
else{
std::reverse(str, str + str_len); // str decays to a pointer
}
std::cout << str << '\n'; // don't use endl if you don't need to flush
}
This is pretty bad code. Just use std::string and std::reverse. It is faster than xor and only 2 lines long.
std::string str = "testing"
std::reverse(str.begin(), str.end());
A better way of doing it, more C++, less C
std::string mystring = "testing";
std::string reversed;
for(std::string::iterator str_it = mystring.rbegin(); str_it != mystring.rend(); ++str_it)
{
reversed += *str_it;
}
std::cout << reversed << std::endl;
I'm trying to figure out how to get a string from an array starting at some given position. Say we have an array that's arbitrarily long and my string starts at location 1000. If I wanted to get a string from a file I would simply use something like getc or scanf or something. How do I carry out these same functions on an array instead of a file?
*oh, keep in mind that the array is of type int and is full of numerical representations of ASCII characters.
If you were dealing with a byte[] array then you could just do this:
string yourString = Encoding.ASCII.GetString(yourArray, startIndex, length);
Since your array is of type int[] then -- assuming that each element represents a single ASCII character -- you'll need to convert those ints to bytes first. If the array is "arbitrarily long" then you may not want to convert the whole thing to a byte[] array, in which case just convert the section that you need:
byte[] temp =
yourArray.Skip(startIndex).Take(length).Select(i => (byte)i).ToArray();
string yourString = Encoding.ASCII.GetString(temp);
If each element of your int[] array doesn't actually represent a single ASCII character then you'll need to give us more info about the precise format that it uses.
Assuming the string is null terminated (you don't specify how you know the end of the string) then a bit of Linq should do the trick:
var chars = ints.Skip(1000).TakeWhile(i => i != 0).Select(i => (char)i);
var str = new string(chars.ToArray());
The first like skips 1000 ints, takes them while they're not a null-terminator, and then converts them to a char as appropriate for ints representing ASCII codes. The second line simply makes them into a string.
If the string has no null terminator, and just ends when the array ends, then just remove the call to TakeWhile.
Here is an alternative (similar to the solution provided by LukeH) that might be faster (since it uses built in array methods rather than LINQ):
public static string GetString(int[] array, int startIndex, int length)
{
var subarray = new int[length];
Array.Copy(array, startIndex, subarray, 0, length);
return Encoding.ASCII.GetString(Array.ConvertAll(subarray, i => (byte)i));
}
Could you slice the elements from the array and call ASCIIEncoding.GetString() on it
LINQ can be pretty hand at times...
var ints = Enumerable.Range(0, 255).ToArray();
var start = 65;
var length = 26;
var value = new string(ints.Select(i => (char)i)
.Skip(start)
.Take(length)
.ToArray());
Console.WriteLine(value); //ABCDEFGHIJKLMNOPQRSTUVWXYZ
Here is my code just for reference. If you goto the "SYSCALL" section you will find an if statement pertaining to "open 4" this is where I'm stuck. Oh, by the way, I'm not using visual studio, I'm using a program called "Verilator" which allows me to interface Verilog Code with C++ code.
#include "VMIPS.h"
#include "VMIPS_MIPS.h"//required to explicitly access signals from submodules
#include <verilated.h>
#include <cstdio>
#include <cmath>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <cstdlib>
#include <vector>
using namespace std;
unsigned int main_time = 0;
static inline int hexCharValue(char ch)
{
if (ch>='0' && ch<='9')return ch-'0';
if (ch>='a' && ch<='f')return ch-'a'+10;
return 0;
}
int main(int argc, char **argv)
{
///////////////////////////////////////// Instruction Capture /////////////////////////////////////////////
ifstream inClientFile( "TEXT.txt",ios::in ); //stream object
//test if instruction file can be opened
if ( !inClientFile )
{
cerr << "File couldn't be opened" << endl;
return 1; //no point using exit inside main
}
//fill string array with all file values and determines length of program
vector<string> words;
words.reserve(274815);
string word;
while (inClientFile >> word)words.push_back(word); //helper function is unnecessary
cout << "Number of words:" << words.size() << endl;
const int wordCount=words.size();
vector<int> InstructionMemory;
vector<string> tempInstructionMemory;
tempInstructionMemory.reserve(wordCount);
//cut out undesired strings from vector
for(int i=0; i<wordCount; i++)
{
if (words[i].length()==8 && words[i].find("fs24")==string::npos) //f0 can exist at pos 1 in a valid hex string
{
tempInstructionMemory.push_back(words[i]);
}
}
//convert string hex to numerical decimal
InstructionMemory.resize(tempInstructionMemory.size());
for( int j=0; j<tempInstructionMemory.size(); j++ )
{
for( int y=0; y<8; y++)
{
InstructionMemory[j]+=hexCharValue(tempInstructionMemory[j][y])<<(4*(7-y));//4194608+4*
}
}
//printf("Amortized Instruction Vector Size:%d\n",InstructionMemory.size());
////////////////////////////////////// Data Capture ////////////////////////////////////////////////
ifstream inClientDataFile( "DATA.txt",ios::in ); //stream object
//test if instruction file can be opened
if ( !inClientDataFile )
{
cerr << "File couldn't be opened" << endl;
return 1; //no point using exit inside main
}
//fill string array with all file values and determines length of program
vector<string> datas;
datas.reserve(274815);
string data;
while (inClientDataFile >> data)datas.push_back(data); //helper function is unnecessary
cout << "Number of data packets:" << datas.size() << endl;
const int dataCount=datas.size();
vector<int> DataMemory;
vector<string> tempDataMemory;
tempDataMemory.reserve(dataCount);
//cut out undesired strings from vector
for( int i=0; i<dataCount; i++)
{
if (datas[i].length()==8 && datas[i].find("fs24")==string::npos) //f0 can exist at pos 1 in a valid hex string
{
tempDataMemory.push_back(datas[i]);
}
}
//convert string hex to numerical decimal
DataMemory.resize(tempDataMemory.size());
for( int j=0; j<tempDataMemory.size(); j++ )
{
for( int y=0; y<8; y++)
{
DataMemory[j]+=hexCharValue(tempDataMemory[j][y])<<(4*(7-y));
}
}
//printf("Amortized Data Vector Size:%d\n",DataMemory.size());
/////////////////////////////////////////// MIPS I processor interface /////////////////////////////////////////////
Verilated::commandArgs(argc, argv);
VMIPS *top = new VMIPS;
top->CLK = 0;
vector<int> HS0,HS1,HS2;
vector<string> FDT_filename;
vector<int> FDT_state;//1 = open, 0 = closed
int FileDescriptorIndex = 3;//start of non-reserved indecies
FILE *f;
//first 3 positions reserved for stdin, stdout, and stderr
FDT_filename.push_back("stdin");
FDT_filename.push_back("stdout");
FDT_filename.push_back("stderr");
FDT_state.push_back(0);
FDT_state.push_back(0);
FDT_state.push_back(0);
//int FDT[100];
printf("IMAddr:%d IM:%d \n***************\n",top->Iaddr,InstructionMemory[(top->Iaddr)/4]);
while (!Verilated::gotFinish())
{
//clock generation
top->CLK=!(top->CLK);
//vector mapping
if ( ( top->Daddr >= 0 ) && ( top->Daddr <= 419604 ) )
{
if(top->MemRead)
top->Din = HS0[(top->Daddr)/4];
if(top->MemWrite)
HS0[(top->Daddr)/4] = top->Dout;
}
else if ( ( top->Daddr >= (419608+InstructionMemory.size()+4) ) && ( top->Daddr <= 268435452 ) )
{
if(top->MemRead)
top->Din = HS1[(top->Daddr-419608)/4];
if(top->MemWrite)
HS1[(top->Daddr-419608)/4] = top->Dout;
}
else if ( ( top->Daddr >= 268435456 ) && ( top->Daddr <= (268435456+DataMemory.size()) ) )
{
if(top->MemRead)
top->Din = DataMemory[(top->Daddr-2668435456)/4];
if(top->MemWrite)
DataMemory[(top->Daddr-2668435456)/4] = top->Dout;
}
else if ( top->Daddr >=(268435456+DataMemory.size()+4) )
{
if(top->MemRead)
top->Din = HS2[(top->Daddr-(268435456+DataMemory.size()+4))/4];
if(top->MemWrite)
HS2[(top->Daddr-(268435456+DataMemory.size()+4))/4] = top->Dout;
}
//instruction supply mapping
if ( top->Iaddr < 4194608 )
{
top->Iin = InstructionMemory[(top->Iaddr)/4];
}
else
{
top->Iin = InstructionMemory[(top->Iaddr-4194608)/4];
}
//instruction split
if(main_time%2)
printf("IMAddr:%d IM:%d \n***************\n",top->Iaddr,InstructionMemory[(top->Iaddr)/4]);//-4194608)/4]);
//evaluate instruction call and increment time counter
top->eval();
main_time++;
//exit loop
if(main_time>=2)
{
return 0;
}
top->Iin = 3690987776;
//SYSCALL
if ( top->Iin == 3690987584 )//exit 1
{
cout << "Exit" << endl;
return 0;
}
else if ( top->Iin == 3690987776 )//open 4
{
cout << endl << endl << "Open File" << endl << endl;
string filename;
filename = "DATA.txt";
//fill filename with characters from memory
//FDT_filename(top->a0) is the string start pointer
FDT_filename.push_back(filename);//add new filename to newest location
FDT_state.push_back(1);//add new open indicator to newest location
top->v0 = FileDescriptorIndex;//place file descriptor into register
FileDescriptorIndex++;//ready the next file descriptor
//printf("Filename:%d FileDescriptorIndex:%d",FDT_filename.at3(FileDescriptorIndex),FileDescriptorIndex);
}
else if ( top->Iin == 3690987648 )//read 2
{
cout << "Read" << endl;
int max_char_count = top->a2;
int char_CTR = 0;
//create file object and open filename
//read chars from file
//place in
//FILE *f = fopen(filename,"rb");
//scanf("%s %top->a2",&FDT_filename(top->a0) >> top->a1;
//top->v0 = char_CTR;
}
else if ( top->Iin == 3690987712 )//write 3
{
cout << "Write" << endl;
int max_char_count = top->a2;
int char_CTR = 0;
//f fopen(FDT_filename(top->a0));
}
else if ( top->Iin == 3690987840 )//close 5
{
cout << "Close File" << endl;
//FDT_state(top->v0)=0;
}
else if ( top->Iin == 3690987904 )//time 6
{
cout << "Time:" << main_time << endl;
top->a0 = main_time;
top->a1 = main_time;
}
}
}