This post isn't a question. Instead I am posting an example in the hope that doing so will help others. My need was to read a large text file (gigabytes in size) a line at a time. I created a bridging header to call the C getline function. Calling get line is interesting because it relies on pointers. Here is how it works.
Code Block // Author: David Cox // Example to illustrate how to call the C function // getline from Swift // // This is the definition of getline as viewed from // Swift: // // public func getline(_ linep: // UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>!, // _ linecapp: UnsafeMutablePointer<Int>!, // _ __stream: UnsafeMutablePointer<FILE>!) -> Int // // readFile will call getline to read a file // line-by-line func readFile(fileName: String) { // In this example, I am creating a buffer that // getline will fill with characters. // Technically, I don't have to do this. // getline will accept a NULL pointer and will // allocate memory for the incoming line. // However, that approach requires that the // memory be freed by the user program. // I find that creating the buffer in advance // is simpler to understand. // So, here is the first step. Create a pointer // and point it to an area of memory. // Think of this memory as a C array. // In this example, the area of memory will // have a capacity of 200 Int8 elements // and the pointer will be called buffer: let buffer = UnsafeMutablePointer<Int8>.allocate(capacity: 200) // Initialize the memory. In this case I am // initializing the memory to 200 zeros: buffer.initialize(repeating: 0, count: 200) // Next, create another UnsafeMutablePointer // and point it to the buffer. // Because buffer is also an // UnsafeMutablePointer the type of this // pointer will be UnsafeMutablePointer // This pointer will point to an area of memory // containing 1 element. let bufferPtr = UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>. allocate(capacity: 1) // Initialize this area of memory to hold buffer // (which is an UnsafeMutablePointer) bufferPtr.initialize(to: buffer) // Create another pointer to an area of // memory that will hold the size of the buffer // The size is an stored as 1 Int. Hence, the // capacity is 1. let bufferSize = UnsafeMutablePointer<Int>.allocate(capacity: 1) bufferSize.initialize(to: 200) // Now we are ready to open the file let fp = fopen(fileName, "r") // loop to read the file while (true) { let r = getline(bufferPtr, bufferSize, fp) if r == -1 { break } // convert the buffer contents to a string let line = String(cString: bufferPtr.pointee!) // do something with the line print(line) } // deinitialize the pointers bufferPtr.deinitialize(count: 1) buffer.deinitialize(count: 200) // deallocate the pointers bufferPtr.deallocate() buffer.deallocate() }
Just for information, if you ever wanted to call Swift from C, you may be interested by this discussion about Formalizing @cdecl …
https://forums.swift.org/t/formalizing-cdecl/40677
https://forums.swift.org/t/formalizing-cdecl/40677